From cdd980e1eb82e60029a7d5e8a4cbf2d5392ea337 Mon Sep 17 00:00:00 2001 From: FrameBridge release automation Date: Thu, 29 Oct 2026 11:53:40 -0400 Subject: [PATCH] FrameBridge 0.3.4 corresponding-source release Snapshot assembled only from the signed corresponding-source archive. Source archive SHA-256: db91a270cdefc4be79056ed38a0b4a16747e1ab130592645eac40fa3809809df --- LICENSE-STATUS.md | 4 +- LICENSING.md | 4 +- README-SOURCE-ARCHIVE.md | 60 +- README.md | 14 +- RELEASE-NOTES-0.3.3.md | 24 - RELEASE-NOTES.md | 4 + TARGET-VENDOR-PROVENANCE.json | 451 + docs/CLAIMS-AND-LIMITS.md | 39 +- docs/COMMAND-REFERENCE.md | 17 +- docs/FRAMEBRIDGE-AGENT-START.md | 10 +- docs/OPERATIONS-ROADMAP.md | 29 + docs/RELEASE-NOTES-0.3.4-dev.md | 34 + docs/RELEASE-NOTES-0.3.4.md | 29 + docs/THIRD-PARTY-RELEASE-REVIEW.md | 4 +- licensing/SOURCE-LICENSE-SCOPE.json | 1 + licensing/third-party/SOURCE-AVAILABILITY.md | 6 +- source/docs/COMMAND-GUIDE.json | 58 +- source/docs/COMMAND-REFERENCE.md | 17 +- source/docs/DEBIAN-TUTORIAL.md | 17 +- source/docs/framebridge.1 | 15 +- .../expanded/framebridge_expanded/__init__.py | 2 +- .../framebridge_expanded/autostart.py | 73 +- source/expanded/framebridge_expanded/cli.py | 19 +- .../framebridge_expanded/compatibility.py | 6 +- .../connection_background.py | 69 +- source/expanded/framebridge_expanded/fleet.py | 49 +- .../framebridge_expanded/guide_data.py | 14 +- .../expanded/framebridge_expanded/health.py | 234 + source/packaging/archive_sources.py | 57 +- source/packaging/build_expanded.py | 44 +- source/packaging/build_profiles.py | 2 +- source/packaging/generate_command_docs.py | 2 +- source/packaging/release_metadata.py | 87 + source/portable/front_door_mcp.py | 2 +- ...fi_backend.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 348856 bytes .../annotated_types-0.8.0.dist-info/METADATA | 295 + .../annotated_types-0.8.0.dist-info/RECORD | 7 + .../annotated_types-0.8.0.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../cp312/annotated_types/__init__.py | 416 + .../cp312/annotated_types/py.typed | 0 .../cp312/annotated_types/test_cases.py | 146 + .../cp312/anyio-4.15.1.dist-info/METADATA | 108 + .../cp312/anyio-4.15.1.dist-info/RECORD | 53 + .../cp312/anyio-4.15.1.dist-info/WHEEL | 5 + .../anyio-4.15.1.dist-info/entry_points.txt | 2 + .../anyio-4.15.1.dist-info/licenses/LICENSE | 20 + .../anyio-4.15.1.dist-info/top_level.txt | 1 + source/target-vendors/cp312/anyio/__init__.py | 154 + .../cp312/anyio/_backends/__init__.py | 0 .../cp312/anyio/_backends/_asyncio.py | 3201 +++ .../cp312/anyio/_backends/_trio.py | 1473 ++ .../cp312/anyio/_core/__init__.py | 0 .../anyio/_core/_asyncio_selector_thread.py | 167 + .../cp312/anyio/_core/_concurrency_utils.py | 156 + .../cp312/anyio/_core/_contextmanagers.py | 200 + .../cp312/anyio/_core/_eventloop.py | 240 + .../cp312/anyio/_core/_exceptions.py | 205 + .../cp312/anyio/_core/_fileio.py | 1045 + .../cp312/anyio/_core/_futures.py | 191 + .../cp312/anyio/_core/_resources.py | 18 + .../cp312/anyio/_core/_signals.py | 29 + .../cp312/anyio/_core/_sockets.py | 1011 + .../cp312/anyio/_core/_streams.py | 52 + .../cp312/anyio/_core/_subprocesses.py | 196 + .../cp312/anyio/_core/_synchronization.py | 778 + .../cp312/anyio/_core/_tasks.py | 464 + .../cp312/anyio/_core/_tempfile.py | 615 + .../cp312/anyio/_core/_testing.py | 82 + .../cp312/anyio/_core/_typedattr.py | 85 + .../target-vendors/cp312/anyio/_lazyimport.py | 176 + .../cp312/anyio/abc/__init__.py | 63 + .../cp312/anyio/abc/_eventloop.py | 428 + .../cp312/anyio/abc/_resources.py | 39 + .../cp312/anyio/abc/_sockets.py | 401 + .../cp312/anyio/abc/_streams.py | 237 + .../cp312/anyio/abc/_subprocesses.py | 82 + .../target-vendors/cp312/anyio/abc/_tasks.py | 223 + .../cp312/anyio/abc/_testing.py | 79 + .../target-vendors/cp312/anyio/from_thread.py | 588 + .../target-vendors/cp312/anyio/functools.py | 400 + .../target-vendors/cp312/anyio/itertools.py | 629 + source/target-vendors/cp312/anyio/lowlevel.py | 228 + source/target-vendors/cp312/anyio/py.typed | 0 .../cp312/anyio/pytest_plugin.py | 404 + .../cp312/anyio/streams/__init__.py | 0 .../cp312/anyio/streams/buffered.py | 201 + .../cp312/anyio/streams/file.py | 157 + .../cp312/anyio/streams/memory.py | 326 + .../cp312/anyio/streams/stapled.py | 160 + .../cp312/anyio/streams/text.py | 176 + .../target-vendors/cp312/anyio/streams/tls.py | 436 + .../cp312/anyio/to_interpreter.py | 246 + .../target-vendors/cp312/anyio/to_process.py | 269 + .../target-vendors/cp312/anyio/to_thread.py | 80 + source/target-vendors/cp312/attr/__init__.py | 104 + source/target-vendors/cp312/attr/__init__.pyi | 389 + source/target-vendors/cp312/attr/_cmp.py | 160 + source/target-vendors/cp312/attr/_cmp.pyi | 13 + source/target-vendors/cp312/attr/_compat.py | 99 + source/target-vendors/cp312/attr/_config.py | 31 + source/target-vendors/cp312/attr/_funcs.py | 497 + source/target-vendors/cp312/attr/_make.py | 3406 +++ source/target-vendors/cp312/attr/_next_gen.py | 674 + .../cp312/attr/_typing_compat.pyi | 15 + .../cp312/attr/_version_info.py | 89 + .../cp312/attr/_version_info.pyi | 9 + .../target-vendors/cp312/attr/converters.py | 162 + .../target-vendors/cp312/attr/converters.pyi | 19 + .../target-vendors/cp312/attr/exceptions.py | 95 + .../target-vendors/cp312/attr/exceptions.pyi | 17 + source/target-vendors/cp312/attr/filters.py | 72 + source/target-vendors/cp312/attr/filters.pyi | 6 + source/target-vendors/cp312/attr/py.typed | 0 source/target-vendors/cp312/attr/setters.py | 79 + source/target-vendors/cp312/attr/setters.pyi | 20 + .../target-vendors/cp312/attr/validators.py | 750 + .../target-vendors/cp312/attr/validators.pyi | 140 + .../cp312/attrs-26.1.0.dist-info/METADATA | 199 + .../cp312/attrs-26.1.0.dist-info/RECORD | 35 + .../cp312/attrs-26.1.0.dist-info/WHEEL | 4 + .../attrs-26.1.0.dist-info/licenses/LICENSE | 21 + source/target-vendors/cp312/attrs/__init__.py | 72 + .../target-vendors/cp312/attrs/__init__.pyi | 314 + .../target-vendors/cp312/attrs/converters.py | 3 + .../target-vendors/cp312/attrs/exceptions.py | 3 + source/target-vendors/cp312/attrs/filters.py | 3 + source/target-vendors/cp312/attrs/py.typed | 0 source/target-vendors/cp312/attrs/setters.py | 3 + .../target-vendors/cp312/attrs/validators.py | 3 + .../certifi-2026.7.22.dist-info/METADATA | 78 + .../cp312/certifi-2026.7.22.dist-info/RECORD | 12 + .../cp312/certifi-2026.7.22.dist-info/WHEEL | 5 + .../licenses/LICENSE | 20 + .../certifi-2026.7.22.dist-info/top_level.txt | 1 + .../target-vendors/cp312/certifi/__init__.py | 4 + .../target-vendors/cp312/certifi/__main__.py | 12 + .../target-vendors/cp312/certifi/cacert.pem | 3959 ++++ source/target-vendors/cp312/certifi/core.py | 83 + source/target-vendors/cp312/certifi/py.typed | 0 .../cp312/certifi/tests/__init__.py | 0 .../cp312/certifi/tests/test_certify.py | 18 + .../cp312/cffi-2.1.1.dist-info/METADATA | 67 + .../cp312/cffi-2.1.1.dist-info/RECORD | 31 + .../cp312/cffi-2.1.1.dist-info/WHEEL | 6 + .../cffi-2.1.1.dist-info/entry_points.txt | 5 + .../cffi-2.1.1.dist-info/licenses/LICENSE | 23 + .../cp312/cffi-2.1.1.dist-info/top_level.txt | 2 + source/target-vendors/cp312/cffi/__init__.py | 14 + .../target-vendors/cp312/cffi/_cffi_errors.h | 135 + .../cp312/cffi/_cffi_gen_src.py | 216 + .../target-vendors/cp312/cffi/_cffi_include.h | 397 + source/target-vendors/cp312/cffi/_embedding.h | 512 + .../cp312/cffi/_imp_emulation.py | 83 + .../cp312/cffi/_shimmed_dist_utils.py | 45 + source/target-vendors/cp312/cffi/api.py | 960 + .../cp312/cffi/backend_ctypes.py | 1120 + .../target-vendors/cp312/cffi/cffi_opcode.py | 187 + .../target-vendors/cp312/cffi/commontypes.py | 82 + source/target-vendors/cp312/cffi/cparser.py | 1014 + source/target-vendors/cp312/cffi/error.py | 31 + .../target-vendors/cp312/cffi/ffiplatform.py | 113 + source/target-vendors/cp312/cffi/gen_src.py | 5 + source/target-vendors/cp312/cffi/lock.py | 30 + source/target-vendors/cp312/cffi/model.py | 617 + .../target-vendors/cp312/cffi/parse_c_type.h | 181 + source/target-vendors/cp312/cffi/pkgconfig.py | 121 + .../target-vendors/cp312/cffi/recompiler.py | 1586 ++ .../cp312/cffi/setuptools_ext.py | 231 + .../target-vendors/cp312/cffi/vengine_cpy.py | 1058 + .../target-vendors/cp312/cffi/vengine_gen.py | 679 + source/target-vendors/cp312/cffi/verifier.py | 306 + .../cp312/click-8.5.0.dist-info/METADATA | 83 + .../cp312/click-8.5.0.dist-info/RECORD | 22 + .../cp312/click-8.5.0.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 28 + source/target-vendors/cp312/click/__init__.py | 144 + source/target-vendors/cp312/click/_compat.py | 590 + .../cp312/click/_termui_impl.py | 972 + .../target-vendors/cp312/click/_textwrap.py | 188 + source/target-vendors/cp312/click/_utils.py | 36 + .../target-vendors/cp312/click/_winconsole.py | 297 + source/target-vendors/cp312/click/core.py | 3799 ++++ .../target-vendors/cp312/click/decorators.py | 627 + .../target-vendors/cp312/click/exceptions.py | 378 + .../target-vendors/cp312/click/formatting.py | 320 + source/target-vendors/cp312/click/globals.py | 67 + source/target-vendors/cp312/click/parser.py | 533 + source/target-vendors/cp312/click/py.typed | 0 .../cp312/click/shell_completion.py | 801 + source/target-vendors/cp312/click/termui.py | 1014 + source/target-vendors/cp312/click/testing.py | 798 + source/target-vendors/cp312/click/types.py | 1422 ++ source/target-vendors/cp312/click/utils.py | 688 + .../cryptography-50.0.1.dist-info/METADATA | 110 + .../cryptography-50.0.1.dist-info/RECORD | 120 + .../cp312/cryptography-50.0.1.dist-info/WHEEL | 5 + .../licenses/LICENSE | 3 + .../licenses/LICENSE.APACHE | 202 + .../licenses/LICENSE.BSD | 27 + .../sboms/cryptography-rust.cyclonedx.json | 1365 ++ .../sboms/sbom.json | 43 + .../cp312/cryptography/__about__.py | 17 + .../cp312/cryptography/__init__.py | 13 + .../cp312/cryptography/cobblestone.py | 21 + .../cp312/cryptography/exceptions.py | 52 + .../cp312/cryptography/fernet.py | 240 + .../cp312/cryptography/hazmat/__init__.py | 13 + .../cp312/cryptography/hazmat/_oid.py | 373 + .../cryptography/hazmat/asn1/__init__.py | 47 + .../cp312/cryptography/hazmat/asn1/asn1.py | 533 + .../cryptography/hazmat/backends/__init__.py | 13 + .../hazmat/backends/openssl/__init__.py | 9 + .../hazmat/backends/openssl/backend.py | 309 + .../cryptography/hazmat/bindings/__init__.py | 5 + .../hazmat/bindings/_rust.abi3.so | Bin 0 -> 14389392 bytes .../hazmat/bindings/_rust/__init__.pyi | 67 + .../hazmat/bindings/_rust/_openssl.pyi | 8 + .../hazmat/bindings/_rust/asn1.pyi | 7 + .../hazmat/bindings/_rust/cobblestone.pyi | 33 + .../bindings/_rust/declarative_asn1.pyi | 133 + .../hazmat/bindings/_rust/exceptions.pyi | 17 + .../hazmat/bindings/_rust/ocsp.pyi | 117 + .../bindings/_rust/openssl/__init__.pyi | 82 + .../hazmat/bindings/_rust/openssl/aead.pyi | 189 + .../hazmat/bindings/_rust/openssl/ciphers.pyi | 38 + .../hazmat/bindings/_rust/openssl/cmac.pyi | 18 + .../hazmat/bindings/_rust/openssl/dh.pyi | 51 + .../hazmat/bindings/_rust/openssl/dsa.pyi | 41 + .../hazmat/bindings/_rust/openssl/ec.pyi | 52 + .../hazmat/bindings/_rust/openssl/ed25519.pyi | 13 + .../hazmat/bindings/_rust/openssl/ed448.pyi | 13 + .../hazmat/bindings/_rust/openssl/hashes.pyi | 30 + .../hazmat/bindings/_rust/openssl/hmac.pyi | 22 + .../hazmat/bindings/_rust/openssl/hpke.pyi | 109 + .../hazmat/bindings/_rust/openssl/kdf.pyi | 205 + .../hazmat/bindings/_rust/openssl/keys.pyi | 34 + .../hazmat/bindings/_rust/openssl/keywrap.pyi | 28 + .../hazmat/bindings/_rust/openssl/mldsa.pyi | 35 + .../hazmat/bindings/_rust/openssl/mlkem.pyi | 18 + .../bindings/_rust/openssl/poly1305.pyi | 15 + .../hazmat/bindings/_rust/openssl/rsa.pyi | 55 + .../hazmat/bindings/_rust/openssl/x25519.pyi | 13 + .../hazmat/bindings/_rust/openssl/x448.pyi | 13 + .../hazmat/bindings/_rust/pkcs12.pyi | 52 + .../hazmat/bindings/_rust/pkcs7.pyi | 50 + .../hazmat/bindings/_rust/test_support.pyi | 23 + .../hazmat/bindings/_rust/x509.pyi | 313 + .../hazmat/bindings/openssl/__init__.py | 5 + .../hazmat/bindings/openssl/_conditional.py | 199 + .../hazmat/bindings/openssl/binding.py | 107 + .../cryptography/hazmat/decrepit/__init__.py | 5 + .../hazmat/decrepit/ciphers/__init__.py | 5 + .../hazmat/decrepit/ciphers/algorithms.py | 145 + .../hazmat/decrepit/ciphers/modes.py | 53 + .../hazmat/primitives/__init__.py | 5 + .../hazmat/primitives/_asymmetric.py | 19 + .../hazmat/primitives/_cipheralgorithm.py | 60 + .../cryptography/hazmat/primitives/_modes.py | 105 + .../hazmat/primitives/_serialization.py | 136 + .../hazmat/primitives/asymmetric/__init__.py | 5 + .../hazmat/primitives/asymmetric/dh.py | 253 + .../hazmat/primitives/asymmetric/dsa.py | 179 + .../hazmat/primitives/asymmetric/ec.py | 369 + .../hazmat/primitives/asymmetric/ed25519.py | 116 + .../hazmat/primitives/asymmetric/ed448.py | 143 + .../hazmat/primitives/asymmetric/mldsa.py | 505 + .../hazmat/primitives/asymmetric/mlkem.py | 278 + .../hazmat/primitives/asymmetric/padding.py | 141 + .../hazmat/primitives/asymmetric/rsa.py | 295 + .../hazmat/primitives/asymmetric/types.py | 94 + .../hazmat/primitives/asymmetric/utils.py | 28 + .../hazmat/primitives/asymmetric/x25519.py | 134 + .../hazmat/primitives/asymmetric/x448.py | 137 + .../hazmat/primitives/ciphers/__init__.py | 27 + .../hazmat/primitives/ciphers/aead.py | 23 + .../hazmat/primitives/ciphers/algorithms.py | 138 + .../hazmat/primitives/ciphers/base.py | 146 + .../hazmat/primitives/ciphers/modes.py | 192 + .../cryptography/hazmat/primitives/cmac.py | 10 + .../hazmat/primitives/constant_time.py | 14 + .../cryptography/hazmat/primitives/hashes.py | 357 + .../cryptography/hazmat/primitives/hmac.py | 13 + .../cryptography/hazmat/primitives/hpke.py | 27 + .../hazmat/primitives/kdf/__init__.py | 32 + .../hazmat/primitives/kdf/argon2.py | 17 + .../hazmat/primitives/kdf/concatkdf.py | 16 + .../hazmat/primitives/kdf/hkdf.py | 16 + .../hazmat/primitives/kdf/kbkdf.py | 26 + .../hazmat/primitives/kdf/pbkdf2.py | 13 + .../hazmat/primitives/kdf/scrypt.py | 19 + .../hazmat/primitives/kdf/x963kdf.py | 13 + .../cryptography/hazmat/primitives/keywrap.py | 25 + .../cryptography/hazmat/primitives/padding.py | 69 + .../hazmat/primitives/poly1305.py | 11 + .../primitives/serialization/__init__.py | 85 + .../hazmat/primitives/serialization/base.py | 16 + .../hazmat/primitives/serialization/pkcs12.py | 176 + .../hazmat/primitives/serialization/pkcs7.py | 412 + .../hazmat/primitives/serialization/ssh.py | 1615 ++ .../hazmat/primitives/twofactor/__init__.py | 9 + .../hazmat/primitives/twofactor/hotp.py | 101 + .../hazmat/primitives/twofactor/totp.py | 56 + .../cp312/cryptography/py.typed | 0 .../cp312/cryptography/utils.py | 136 + .../cp312/cryptography/x509/__init__.py | 270 + .../cp312/cryptography/x509/base.py | 834 + .../x509/certificate_transparency.py | 35 + .../cp312/cryptography/x509/extensions.py | 2533 +++ .../cp312/cryptography/x509/general_name.py | 281 + .../cp312/cryptography/x509/name.py | 489 + .../cp312/cryptography/x509/ocsp.py | 379 + .../cp312/cryptography/x509/oid.py | 37 + .../cp312/cryptography/x509/verification.py | 34 + .../target-vendors/cp312/dotenv/__init__.py | 51 + .../target-vendors/cp312/dotenv/__main__.py | 6 + source/target-vendors/cp312/dotenv/cli.py | 247 + source/target-vendors/cp312/dotenv/ipython.py | 50 + source/target-vendors/cp312/dotenv/main.py | 487 + source/target-vendors/cp312/dotenv/parser.py | 184 + source/target-vendors/cp312/dotenv/py.typed | 1 + .../target-vendors/cp312/dotenv/variables.py | 86 + source/target-vendors/cp312/dotenv/version.py | 1 + .../cp312/h11-0.16.0.dist-info/METADATA | 202 + .../cp312/h11-0.16.0.dist-info/RECORD | 17 + .../cp312/h11-0.16.0.dist-info/WHEEL | 5 + .../h11-0.16.0.dist-info/licenses/LICENSE.txt | 22 + .../cp312/h11-0.16.0.dist-info/top_level.txt | 1 + source/target-vendors/cp312/h11/__init__.py | 62 + source/target-vendors/cp312/h11/_abnf.py | 132 + .../target-vendors/cp312/h11/_connection.py | 659 + source/target-vendors/cp312/h11/_events.py | 369 + source/target-vendors/cp312/h11/_headers.py | 282 + source/target-vendors/cp312/h11/_readers.py | 250 + .../cp312/h11/_receivebuffer.py | 153 + source/target-vendors/cp312/h11/_state.py | 365 + source/target-vendors/cp312/h11/_util.py | 135 + source/target-vendors/cp312/h11/_version.py | 16 + source/target-vendors/cp312/h11/_writers.py | 145 + source/target-vendors/cp312/h11/py.typed | 1 + .../cp312/httpcore-1.0.9.dist-info/METADATA | 625 + .../cp312/httpcore-1.0.9.dist-info/RECORD | 36 + .../cp312/httpcore-1.0.9.dist-info/WHEEL | 4 + .../licenses/LICENSE.md | 27 + .../target-vendors/cp312/httpcore/__init__.py | 141 + source/target-vendors/cp312/httpcore/_api.py | 94 + .../cp312/httpcore/_async/__init__.py | 39 + .../cp312/httpcore/_async/connection.py | 222 + .../cp312/httpcore/_async/connection_pool.py | 420 + .../cp312/httpcore/_async/http11.py | 379 + .../cp312/httpcore/_async/http2.py | 592 + .../cp312/httpcore/_async/http_proxy.py | 367 + .../cp312/httpcore/_async/interfaces.py | 137 + .../cp312/httpcore/_async/socks_proxy.py | 341 + .../cp312/httpcore/_backends/__init__.py | 0 .../cp312/httpcore/_backends/anyio.py | 146 + .../cp312/httpcore/_backends/auto.py | 52 + .../cp312/httpcore/_backends/base.py | 101 + .../cp312/httpcore/_backends/mock.py | 143 + .../cp312/httpcore/_backends/sync.py | 241 + .../cp312/httpcore/_backends/trio.py | 159 + .../cp312/httpcore/_exceptions.py | 81 + .../target-vendors/cp312/httpcore/_models.py | 516 + source/target-vendors/cp312/httpcore/_ssl.py | 9 + .../cp312/httpcore/_sync/__init__.py | 39 + .../cp312/httpcore/_sync/connection.py | 222 + .../cp312/httpcore/_sync/connection_pool.py | 420 + .../cp312/httpcore/_sync/http11.py | 379 + .../cp312/httpcore/_sync/http2.py | 592 + .../cp312/httpcore/_sync/http_proxy.py | 367 + .../cp312/httpcore/_sync/interfaces.py | 137 + .../cp312/httpcore/_sync/socks_proxy.py | 341 + .../cp312/httpcore/_synchronization.py | 318 + .../target-vendors/cp312/httpcore/_trace.py | 107 + .../target-vendors/cp312/httpcore/_utils.py | 37 + source/target-vendors/cp312/httpcore/py.typed | 0 .../cp312/httpx-0.28.1.dist-info/METADATA | 203 + .../cp312/httpx-0.28.1.dist-info/RECORD | 29 + .../cp312/httpx-0.28.1.dist-info/WHEEL | 4 + .../httpx-0.28.1.dist-info/entry_points.txt | 2 + .../licenses/LICENSE.md | 12 + source/target-vendors/cp312/httpx/__init__.py | 105 + .../target-vendors/cp312/httpx/__version__.py | 3 + source/target-vendors/cp312/httpx/_api.py | 438 + source/target-vendors/cp312/httpx/_auth.py | 348 + source/target-vendors/cp312/httpx/_client.py | 2019 ++ source/target-vendors/cp312/httpx/_config.py | 248 + source/target-vendors/cp312/httpx/_content.py | 240 + .../target-vendors/cp312/httpx/_decoders.py | 393 + .../target-vendors/cp312/httpx/_exceptions.py | 379 + source/target-vendors/cp312/httpx/_main.py | 506 + source/target-vendors/cp312/httpx/_models.py | 1277 ++ .../target-vendors/cp312/httpx/_multipart.py | 300 + .../cp312/httpx/_status_codes.py | 162 + .../cp312/httpx/_transports/__init__.py | 15 + .../cp312/httpx/_transports/asgi.py | 187 + .../cp312/httpx/_transports/base.py | 86 + .../cp312/httpx/_transports/default.py | 406 + .../cp312/httpx/_transports/mock.py | 43 + .../cp312/httpx/_transports/wsgi.py | 149 + source/target-vendors/cp312/httpx/_types.py | 114 + .../target-vendors/cp312/httpx/_urlparse.py | 527 + source/target-vendors/cp312/httpx/_urls.py | 641 + source/target-vendors/cp312/httpx/_utils.py | 242 + source/target-vendors/cp312/httpx/py.typed | 0 .../cp312/httpx_sse-0.4.3.dist-info/METADATA | 351 + .../cp312/httpx_sse-0.4.3.dist-info/RECORD | 11 + .../cp312/httpx_sse-0.4.3.dist-info/WHEEL | 5 + .../licenses/LICENSE | 21 + .../httpx_sse-0.4.3.dist-info/top_level.txt | 1 + .../cp312/httpx_sse/__init__.py | 14 + source/target-vendors/cp312/httpx_sse/_api.py | 93 + .../cp312/httpx_sse/_decoders.py | 139 + .../cp312/httpx_sse/_exceptions.py | 5 + .../target-vendors/cp312/httpx_sse/_models.py | 54 + .../target-vendors/cp312/httpx_sse/py.typed | 0 .../cp312/idna-3.20.dist-info/METADATA | 176 + .../cp312/idna-3.20.dist-info/RECORD | 16 + .../cp312/idna-3.20.dist-info/WHEEL | 4 + .../idna-3.20.dist-info/entry_points.txt | 3 + .../idna-3.20.dist-info/licenses/LICENSE.md | 31 + source/target-vendors/cp312/idna/__init__.py | 47 + source/target-vendors/cp312/idna/__main__.py | 6 + source/target-vendors/cp312/idna/cli.py | 132 + source/target-vendors/cp312/idna/codec.py | 225 + source/target-vendors/cp312/idna/compat.py | 43 + source/target-vendors/cp312/idna/core.py | 863 + source/target-vendors/cp312/idna/idnadata.py | 1933 ++ source/target-vendors/cp312/idna/intranges.py | 55 + .../target-vendors/cp312/idna/package_data.py | 1 + source/target-vendors/cp312/idna/py.typed | 0 source/target-vendors/cp312/idna/uts46data.py | 17117 ++++++++++++++++ .../jsonschema-4.26.0.dist-info/METADATA | 170 + .../cp312/jsonschema-4.26.0.dist-info/RECORD | 43 + .../cp312/jsonschema-4.26.0.dist-info/WHEEL | 4 + .../entry_points.txt | 2 + .../licenses/COPYING | 19 + .../cp312/jsonschema/__init__.py | 120 + .../cp312/jsonschema/__main__.py | 6 + .../cp312/jsonschema/_format.py | 546 + .../cp312/jsonschema/_keywords.py | 449 + .../cp312/jsonschema/_legacy_keywords.py | 449 + .../target-vendors/cp312/jsonschema/_types.py | 204 + .../cp312/jsonschema/_typing.py | 29 + .../target-vendors/cp312/jsonschema/_utils.py | 355 + .../cp312/jsonschema/benchmarks/__init__.py | 5 + .../jsonschema/benchmarks/const_vs_enum.py | 30 + .../cp312/jsonschema/benchmarks/contains.py | 28 + .../jsonschema/benchmarks/import_benchmark.py | 31 + .../cp312/jsonschema/benchmarks/issue232.py | 25 + .../jsonschema/benchmarks/issue232/issue.json | 2653 +++ .../benchmarks/json_schema_test_suite.py | 12 + .../jsonschema/benchmarks/nested_schemas.py | 56 + .../jsonschema/benchmarks/subcomponents.py | 42 + .../jsonschema/benchmarks/unused_registry.py | 35 + .../benchmarks/useless_applicator_schemas.py | 106 + .../jsonschema/benchmarks/useless_keywords.py | 32 + .../benchmarks/validator_creation.py | 14 + source/target-vendors/cp312/jsonschema/cli.py | 292 + .../cp312/jsonschema/exceptions.py | 490 + .../cp312/jsonschema/protocols.py | 230 + .../cp312/jsonschema/tests/__init__.py | 0 .../cp312/jsonschema/tests/_suite.py | 285 + .../cp312/jsonschema/tests/fuzz_validate.py | 50 + .../cp312/jsonschema/tests/test_cli.py | 904 + .../jsonschema/tests/test_deprecations.py | 432 + .../cp312/jsonschema/tests/test_exceptions.py | 759 + .../cp312/jsonschema/tests/test_format.py | 91 + .../tests/test_jsonschema_test_suite.py | 262 + .../cp312/jsonschema/tests/test_types.py | 221 + .../cp312/jsonschema/tests/test_utils.py | 138 + .../cp312/jsonschema/tests/test_validators.py | 2573 +++ .../cp312/jsonschema/tests/typing/__init__.py | 0 ..._all_concrete_validators_match_protocol.py | 38 + .../cp312/jsonschema/validators.py | 1410 ++ .../METADATA | 54 + .../RECORD | 28 + .../WHEEL | 4 + .../licenses/COPYING | 19 + .../jsonschema_specifications/__init__.py | 12 + .../cp312/jsonschema_specifications/_core.py | 38 + .../schemas/draft201909/metaschema.json | 42 + .../draft201909/vocabularies/applicator | 56 + .../schemas/draft201909/vocabularies/content | 17 + .../schemas/draft201909/vocabularies/core | 57 + .../schemas/draft201909/vocabularies/format | 14 + .../draft201909/vocabularies/meta-data | 37 + .../draft201909/vocabularies/validation | 98 + .../schemas/draft202012/metaschema.json | 58 + .../draft202012/vocabularies/applicator | 48 + .../schemas/draft202012/vocabularies/content | 17 + .../schemas/draft202012/vocabularies/core | 51 + .../vocabularies/format-annotation | 14 + .../draft202012/vocabularies/format-assertion | 14 + .../draft202012/vocabularies/meta-data | 37 + .../draft202012/vocabularies/unevaluated | 15 + .../draft202012/vocabularies/validation | 98 + .../schemas/draft3/metaschema.json | 172 + .../schemas/draft4/metaschema.json | 149 + .../schemas/draft6/metaschema.json | 153 + .../schemas/draft7/metaschema.json | 166 + .../tests/__init__.py | 0 .../tests/test_jsonschema_specifications.py | 41 + source/target-vendors/cp312/jwt/__init__.py | 78 + source/target-vendors/cp312/jwt/algorithms.py | 1111 + source/target-vendors/cp312/jwt/api_jwk.py | 193 + source/target-vendors/cp312/jwt/api_jws.py | 472 + source/target-vendors/cp312/jwt/api_jwt.py | 595 + source/target-vendors/cp312/jwt/exceptions.py | 113 + source/target-vendors/cp312/jwt/help.py | 66 + .../target-vendors/cp312/jwt/jwk_set_cache.py | 31 + .../target-vendors/cp312/jwt/jwks_client.py | 302 + source/target-vendors/cp312/jwt/py.typed | 0 source/target-vendors/cp312/jwt/types.py | 69 + source/target-vendors/cp312/jwt/utils.py | 146 + source/target-vendors/cp312/jwt/warnings.py | 11 + .../cp312/mcp-1.26.0.dist-info/METADATA | 2606 +++ .../cp312/mcp-1.26.0.dist-info/RECORD | 115 + .../cp312/mcp-1.26.0.dist-info/WHEEL | 4 + .../mcp-1.26.0.dist-info/entry_points.txt | 2 + .../mcp-1.26.0.dist-info/licenses/LICENSE | 21 + source/target-vendors/cp312/mcp/__init__.py | 135 + .../target-vendors/cp312/mcp/cli/__init__.py | 6 + source/target-vendors/cp312/mcp/cli/claude.py | 148 + source/target-vendors/cp312/mcp/cli/cli.py | 488 + .../cp312/mcp/client/__init__.py | 0 .../cp312/mcp/client/__main__.py | 85 + .../cp312/mcp/client/auth/__init__.py | 21 + .../cp312/mcp/client/auth/exceptions.py | 10 + .../mcp/client/auth/extensions/__init__.py | 0 .../auth/extensions/client_credentials.py | 487 + .../cp312/mcp/client/auth/oauth2.py | 616 + .../cp312/mcp/client/auth/utils.py | 336 + .../cp312/mcp/client/experimental/__init__.py | 9 + .../mcp/client/experimental/task_handlers.py | 290 + .../cp312/mcp/client/experimental/tasks.py | 224 + .../cp312/mcp/client/session.py | 615 + .../cp312/mcp/client/session_group.py | 447 + source/target-vendors/cp312/mcp/client/sse.py | 164 + .../cp312/mcp/client/stdio/__init__.py | 278 + .../cp312/mcp/client/streamable_http.py | 722 + .../cp312/mcp/client/websocket.py | 86 + .../target-vendors/cp312/mcp/os/__init__.py | 1 + .../cp312/mcp/os/posix/__init__.py | 1 + .../cp312/mcp/os/posix/utilities.py | 60 + .../cp312/mcp/os/win32/__init__.py | 1 + .../cp312/mcp/os/win32/utilities.py | 338 + source/target-vendors/cp312/mcp/py.typed | 0 .../cp312/mcp/server/__init__.py | 5 + .../cp312/mcp/server/__main__.py | 50 + .../cp312/mcp/server/auth/__init__.py | 3 + .../cp312/mcp/server/auth/errors.py | 5 + .../mcp/server/auth/handlers/__init__.py | 3 + .../mcp/server/auth/handlers/authorize.py | 224 + .../mcp/server/auth/handlers/metadata.py | 29 + .../mcp/server/auth/handlers/register.py | 136 + .../cp312/mcp/server/auth/handlers/revoke.py | 91 + .../cp312/mcp/server/auth/handlers/token.py | 241 + .../cp312/mcp/server/auth/json_response.py | 10 + .../mcp/server/auth/middleware/__init__.py | 3 + .../server/auth/middleware/auth_context.py | 48 + .../mcp/server/auth/middleware/bearer_auth.py | 128 + .../mcp/server/auth/middleware/client_auth.py | 115 + .../cp312/mcp/server/auth/provider.py | 301 + .../cp312/mcp/server/auth/routes.py | 253 + .../cp312/mcp/server/auth/settings.py | 30 + .../cp312/mcp/server/elicitation.py | 190 + .../cp312/mcp/server/experimental/__init__.py | 11 + .../server/experimental/request_context.py | 238 + .../server/experimental/session_features.py | 220 + .../mcp/server/experimental/task_context.py | 612 + .../experimental/task_result_handler.py | 235 + .../mcp/server/experimental/task_support.py | 115 + .../cp312/mcp/server/fastmcp/__init__.py | 11 + .../cp312/mcp/server/fastmcp/exceptions.py | 21 + .../mcp/server/fastmcp/prompts/__init__.py | 4 + .../cp312/mcp/server/fastmcp/prompts/base.py | 183 + .../mcp/server/fastmcp/prompts/manager.py | 60 + .../mcp/server/fastmcp/resources/__init__.py | 23 + .../mcp/server/fastmcp/resources/base.py | 50 + .../fastmcp/resources/resource_manager.py | 115 + .../mcp/server/fastmcp/resources/templates.py | 122 + .../mcp/server/fastmcp/resources/types.py | 203 + .../cp312/mcp/server/fastmcp/server.py | 1349 ++ .../mcp/server/fastmcp/tools/__init__.py | 4 + .../cp312/mcp/server/fastmcp/tools/base.py | 126 + .../mcp/server/fastmcp/tools/tool_manager.py | 93 + .../mcp/server/fastmcp/utilities/__init__.py | 1 + .../fastmcp/utilities/context_injection.py | 68 + .../server/fastmcp/utilities/func_metadata.py | 533 + .../mcp/server/fastmcp/utilities/logging.py | 43 + .../mcp/server/fastmcp/utilities/types.py | 101 + .../cp312/mcp/server/lowlevel/__init__.py | 3 + .../cp312/mcp/server/lowlevel/experimental.py | 288 + .../mcp/server/lowlevel/func_inspection.py | 54 + .../cp312/mcp/server/lowlevel/helper_types.py | 11 + .../cp312/mcp/server/lowlevel/server.py | 803 + .../target-vendors/cp312/mcp/server/models.py | 20 + .../cp312/mcp/server/session.py | 691 + source/target-vendors/cp312/mcp/server/sse.py | 249 + .../target-vendors/cp312/mcp/server/stdio.py | 88 + .../cp312/mcp/server/streamable_http.py | 1067 + .../mcp/server/streamable_http_manager.py | 297 + .../cp312/mcp/server/transport_security.py | 127 + .../cp312/mcp/server/validation.py | 104 + .../cp312/mcp/server/websocket.py | 62 + .../cp312/mcp/shared/__init__.py | 0 .../cp312/mcp/shared/_httpx_utils.py | 87 + .../target-vendors/cp312/mcp/shared/auth.py | 159 + .../cp312/mcp/shared/auth_utils.py | 85 + .../cp312/mcp/shared/context.py | 32 + .../cp312/mcp/shared/exceptions.py | 71 + .../cp312/mcp/shared/experimental/__init__.py | 7 + .../mcp/shared/experimental/tasks/__init__.py | 12 + .../shared/experimental/tasks/capabilities.py | 115 + .../mcp/shared/experimental/tasks/context.py | 101 + .../mcp/shared/experimental/tasks/helpers.py | 181 + .../tasks/in_memory_task_store.py | 219 + .../experimental/tasks/message_queue.py | 241 + .../mcp/shared/experimental/tasks/polling.py | 45 + .../mcp/shared/experimental/tasks/resolver.py | 60 + .../mcp/shared/experimental/tasks/store.py | 156 + .../target-vendors/cp312/mcp/shared/memory.py | 98 + .../cp312/mcp/shared/message.py | 50 + .../cp312/mcp/shared/metadata_utils.py | 45 + .../cp312/mcp/shared/progress.py | 58 + .../cp312/mcp/shared/response_router.py | 63 + .../cp312/mcp/shared/session.py | 550 + .../cp312/mcp/shared/tool_name_validation.py | 129 + .../cp312/mcp/shared/version.py | 3 + source/target-vendors/cp312/mcp/types.py | 1999 ++ .../cp312/multipart/__init__.py | 38 + .../cp312/multipart/decoders.py | 1 + .../cp312/multipart/exceptions.py | 1 + .../cp312/multipart/multipart.py | 1 + .../cp312/pycparser-3.0.dist-info/METADATA | 244 + .../cp312/pycparser-3.0.dist-info/RECORD | 13 + .../cp312/pycparser-3.0.dist-info/WHEEL | 5 + .../pycparser-3.0.dist-info/licenses/LICENSE | 27 + .../pycparser-3.0.dist-info/top_level.txt | 1 + .../cp312/pycparser/__init__.py | 99 + .../cp312/pycparser/_ast_gen.py | 355 + .../target-vendors/cp312/pycparser/_c_ast.cfg | 195 + .../cp312/pycparser/ast_transforms.py | 174 + .../target-vendors/cp312/pycparser/c_ast.py | 1341 ++ .../cp312/pycparser/c_generator.py | 573 + .../target-vendors/cp312/pycparser/c_lexer.py | 706 + .../cp312/pycparser/c_parser.py | 2376 +++ .../cp312/pydantic-2.13.5.dist-info/METADATA | 1307 ++ .../cp312/pydantic-2.13.5.dist-info/RECORD | 111 + .../cp312/pydantic-2.13.5.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../target-vendors/cp312/pydantic/__init__.py | 456 + .../cp312/pydantic/_internal/__init__.py | 0 .../cp312/pydantic/_internal/_config.py | 386 + .../pydantic/_internal/_core_metadata.py | 97 + .../cp312/pydantic/_internal/_core_utils.py | 174 + .../cp312/pydantic/_internal/_dataclasses.py | 315 + .../cp312/pydantic/_internal/_decorators.py | 873 + .../pydantic/_internal/_decorators_v1.py | 174 + .../_internal/_discriminated_union.py | 494 + .../pydantic/_internal/_docs_extraction.py | 113 + .../cp312/pydantic/_internal/_fields.py | 729 + .../cp312/pydantic/_internal/_forward_ref.py | 23 + .../pydantic/_internal/_generate_schema.py | 2934 +++ .../cp312/pydantic/_internal/_generics.py | 530 + .../cp312/pydantic/_internal/_git.py | 27 + .../cp312/pydantic/_internal/_import_utils.py | 20 + .../pydantic/_internal/_internal_dataclass.py | 7 + .../_internal/_known_annotated_metadata.py | 403 + .../cp312/pydantic/_internal/_mock_val_ser.py | 228 + .../pydantic/_internal/_model_construction.py | 868 + .../pydantic/_internal/_namespace_utils.py | 293 + .../cp312/pydantic/_internal/_repr.py | 124 + .../pydantic/_internal/_schema_gather.py | 212 + .../_internal/_schema_generation_shared.py | 125 + .../cp312/pydantic/_internal/_serializers.py | 53 + .../cp312/pydantic/_internal/_signature.py | 189 + .../cp312/pydantic/_internal/_typing_extra.py | 785 + .../cp312/pydantic/_internal/_utils.py | 446 + .../pydantic/_internal/_validate_call.py | 141 + .../cp312/pydantic/_internal/_validators.py | 534 + .../cp312/pydantic/_migration.py | 316 + .../cp312/pydantic/alias_generators.py | 62 + .../target-vendors/cp312/pydantic/aliases.py | 135 + .../cp312/pydantic/annotated_handlers.py | 122 + .../cp312/pydantic/class_validators.py | 5 + source/target-vendors/cp312/pydantic/color.py | 604 + .../target-vendors/cp312/pydantic/config.py | 1296 ++ .../cp312/pydantic/dataclasses.py | 413 + .../cp312/pydantic/datetime_parse.py | 5 + .../cp312/pydantic/decorator.py | 5 + .../cp312/pydantic/deprecated/__init__.py | 0 .../pydantic/deprecated/class_validators.py | 256 + .../cp312/pydantic/deprecated/config.py | 72 + .../pydantic/deprecated/copy_internals.py | 224 + .../cp312/pydantic/deprecated/decorator.py | 284 + .../cp312/pydantic/deprecated/json.py | 141 + .../cp312/pydantic/deprecated/parse.py | 80 + .../cp312/pydantic/deprecated/tools.py | 103 + .../cp312/pydantic/env_settings.py | 5 + .../cp312/pydantic/error_wrappers.py | 5 + .../target-vendors/cp312/pydantic/errors.py | 189 + .../cp312/pydantic/experimental/__init__.py | 1 + .../pydantic/experimental/arguments_schema.py | 44 + .../pydantic/experimental/missing_sentinel.py | 5 + .../cp312/pydantic/experimental/pipeline.py | 663 + .../target-vendors/cp312/pydantic/fields.py | 1892 ++ .../cp312/pydantic/functional_serializers.py | 470 + .../cp312/pydantic/functional_validators.py | 889 + .../target-vendors/cp312/pydantic/generics.py | 5 + source/target-vendors/cp312/pydantic/json.py | 5 + .../cp312/pydantic/json_schema.py | 2911 +++ source/target-vendors/cp312/pydantic/main.py | 1838 ++ source/target-vendors/cp312/pydantic/mypy.py | 1414 ++ .../target-vendors/cp312/pydantic/networks.py | 1332 ++ source/target-vendors/cp312/pydantic/parse.py | 5 + .../cp312/pydantic/plugin/__init__.py | 193 + .../cp312/pydantic/plugin/_loader.py | 58 + .../pydantic/plugin/_schema_validator.py | 152 + source/target-vendors/cp312/pydantic/py.typed | 0 .../cp312/pydantic/root_model.py | 157 + .../target-vendors/cp312/pydantic/schema.py | 5 + source/target-vendors/cp312/pydantic/tools.py | 5 + .../cp312/pydantic/type_adapter.py | 801 + source/target-vendors/cp312/pydantic/types.py | 3310 +++ .../target-vendors/cp312/pydantic/typing.py | 5 + source/target-vendors/cp312/pydantic/utils.py | 5 + .../cp312/pydantic/v1/__init__.py | 131 + .../cp312/pydantic/v1/_hypothesis_plugin.py | 391 + .../cp312/pydantic/v1/annotated_types.py | 72 + .../cp312/pydantic/v1/class_validators.py | 361 + .../target-vendors/cp312/pydantic/v1/color.py | 494 + .../cp312/pydantic/v1/config.py | 191 + .../cp312/pydantic/v1/dataclasses.py | 500 + .../cp312/pydantic/v1/datetime_parse.py | 248 + .../cp312/pydantic/v1/decorator.py | 264 + .../cp312/pydantic/v1/env_settings.py | 350 + .../cp312/pydantic/v1/error_wrappers.py | 161 + .../cp312/pydantic/v1/errors.py | 646 + .../cp312/pydantic/v1/fields.py | 1253 ++ .../cp312/pydantic/v1/generics.py | 400 + .../target-vendors/cp312/pydantic/v1/json.py | 112 + .../target-vendors/cp312/pydantic/v1/main.py | 1130 + .../target-vendors/cp312/pydantic/v1/mypy.py | 949 + .../cp312/pydantic/v1/networks.py | 747 + .../target-vendors/cp312/pydantic/v1/parse.py | 66 + .../target-vendors/cp312/pydantic/v1/py.typed | 0 .../cp312/pydantic/v1/schema.py | 1163 ++ .../target-vendors/cp312/pydantic/v1/tools.py | 92 + .../target-vendors/cp312/pydantic/v1/types.py | 1205 ++ .../cp312/pydantic/v1/typing.py | 627 + .../target-vendors/cp312/pydantic/v1/utils.py | 807 + .../cp312/pydantic/v1/validators.py | 768 + .../cp312/pydantic/v1/version.py | 38 + .../cp312/pydantic/validate_call_decorator.py | 116 + .../cp312/pydantic/validators.py | 5 + .../target-vendors/cp312/pydantic/version.py | 113 + .../target-vendors/cp312/pydantic/warnings.py | 122 + .../pydantic_core-2.46.5.dist-info/METADATA | 173 + .../pydantic_core-2.46.5.dist-info/RECORD | 10 + .../pydantic_core-2.46.5.dist-info/WHEEL | 5 + .../licenses/LICENSE | 21 + .../sboms/pydantic-core.cyclonedx.json | 3961 ++++ .../cp312/pydantic_core/__init__.py | 171 + ...antic_core.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 4692312 bytes .../cp312/pydantic_core/_pydantic_core.pyi | 1056 + .../cp312/pydantic_core/core_schema.py | 4461 ++++ .../cp312/pydantic_core/py.typed | 0 .../METADATA | 70 + .../pydantic_settings-2.15.0.dist-info/RECORD | 27 + .../pydantic_settings-2.15.0.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../cp312/pydantic_settings/__init__.py | 70 + .../cp312/pydantic_settings/exceptions.py | 10 + .../cp312/pydantic_settings/main.py | 978 + .../cp312/pydantic_settings/py.typed | 0 .../pydantic_settings/sources/__init__.py | 88 + .../cp312/pydantic_settings/sources/base.py | 639 + .../sources/providers/__init__.py | 45 + .../sources/providers/aws.py | 87 + .../sources/providers/azure.py | 162 + .../sources/providers/cli.py | 1700 ++ .../sources/providers/dotenv.py | 210 + .../sources/providers/env.py | 382 + .../sources/providers/gcp.py | 349 + .../sources/providers/json.py | 53 + .../sources/providers/nested_secrets.py | 214 + .../sources/providers/pyproject.py | 64 + .../sources/providers/secrets.py | 143 + .../sources/providers/toml.py | 100 + .../sources/providers/yaml.py | 147 + .../cp312/pydantic_settings/sources/types.py | 108 + .../cp312/pydantic_settings/sources/utils.py | 376 + .../cp312/pydantic_settings/utils.py | 55 + .../cp312/pydantic_settings/version.py | 1 + .../cp312/pyjwt-2.14.0.dist-info/METADATA | 93 + .../cp312/pyjwt-2.14.0.dist-info/RECORD | 19 + .../cp312/pyjwt-2.14.0.dist-info/WHEEL | 5 + .../licenses/AUTHORS.rst | 7 + .../pyjwt-2.14.0.dist-info/licenses/LICENSE | 21 + .../pyjwt-2.14.0.dist-info/top_level.txt | 1 + .../python_dotenv-1.2.3.dist-info/METADATA | 820 + .../python_dotenv-1.2.3.dist-info/RECORD | 15 + .../cp312/python_dotenv-1.2.3.dist-info/WHEEL | 5 + .../entry_points.txt | 2 + .../licenses/LICENSE | 27 + .../top_level.txt | 1 + .../METADATA | 43 + .../python_multipart-0.0.32.dist-info/RECORD | 13 + .../python_multipart-0.0.32.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 202 + .../cp312/python_multipart/__init__.py | 35 + .../cp312/python_multipart/decoders.py | 185 + .../cp312/python_multipart/exceptions.py | 34 + .../cp312/python_multipart/multipart.py | 1925 ++ .../cp312/python_multipart/py.typed | 0 .../referencing-0.37.0.dist-info/METADATA | 64 + .../cp312/referencing-0.37.0.dist-info/RECORD | 19 + .../cp312/referencing-0.37.0.dist-info/WHEEL | 4 + .../licenses/COPYING | 19 + .../cp312/referencing/__init__.py | 7 + .../cp312/referencing/_attrs.py | 31 + .../cp312/referencing/_attrs.pyi | 21 + .../target-vendors/cp312/referencing/_core.py | 739 + .../cp312/referencing/exceptions.py | 165 + .../cp312/referencing/jsonschema.py | 642 + .../target-vendors/cp312/referencing/py.typed | 0 .../cp312/referencing/retrieval.py | 94 + .../cp312/referencing/tests/__init__.py | 0 .../cp312/referencing/tests/test_core.py | 1057 + .../referencing/tests/test_exceptions.py | 34 + .../referencing/tests/test_jsonschema.py | 382 + .../tests/test_referencing_suite.py | 66 + .../cp312/referencing/tests/test_retrieval.py | 106 + .../cp312/referencing/typing.py | 61 + source/target-vendors/cp312/rpds/__init__.py | 5 + source/target-vendors/cp312/rpds/__init__.pyi | 79 + source/target-vendors/cp312/rpds/py.typed | 0 .../rpds/rpds.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 966896 bytes .../cp312/rpds_py-2026.6.3.dist-info/METADATA | 99 + .../cp312/rpds_py-2026.6.3.dist-info/RECORD | 9 + .../cp312/rpds_py-2026.6.3.dist-info/WHEEL | 5 + .../licenses/LICENSE | 19 + .../sboms/rpds-py.cyclonedx.json | 680 + .../sse_starlette-3.4.11.dist-info/METADATA | 493 + .../sse_starlette-3.4.11.dist-info/RECORD | 11 + .../sse_starlette-3.4.11.dist-info/WHEEL | 5 + .../licenses/AUTHORS | 10 + .../licenses/LICENSE | 27 + .../top_level.txt | 1 + .../cp312/sse_starlette/__init__.py | 5 + .../cp312/sse_starlette/_utils.py | 37 + .../cp312/sse_starlette/event.py | 96 + .../cp312/sse_starlette/py.typed | 0 .../target-vendors/cp312/sse_starlette/sse.py | 531 + .../cp312/starlette-1.7.0.dist-info/METADATA | 182 + .../cp312/starlette-1.7.0.dist-info/RECORD | 41 + .../cp312/starlette-1.7.0.dist-info/WHEEL | 4 + .../licenses/LICENSE.md | 27 + .../cp312/starlette/__init__.py | 1 + .../cp312/starlette/_exception_handler.py | 65 + .../target-vendors/cp312/starlette/_utils.py | 155 + .../cp312/starlette/applications.py | 124 + .../cp312/starlette/authentication.py | 157 + .../cp312/starlette/background.py | 36 + .../cp312/starlette/concurrency.py | 59 + .../target-vendors/cp312/starlette/config.py | 140 + .../cp312/starlette/convertors.py | 89 + .../cp312/starlette/datastructures.py | 704 + .../cp312/starlette/endpoints.py | 127 + .../cp312/starlette/exceptions.py | 43 + .../cp312/starlette/formparsers.py | 301 + .../cp312/starlette/middleware/__init__.py | 37 + .../starlette/middleware/authentication.py | 52 + .../cp312/starlette/middleware/base.py | 248 + .../cp312/starlette/middleware/body_limit.py | 132 + .../cp312/starlette/middleware/cors.py | 177 + .../cp312/starlette/middleware/errors.py | 259 + .../cp312/starlette/middleware/exceptions.py | 73 + .../cp312/starlette/middleware/gzip.py | 222 + .../starlette/middleware/httpsredirect.py | 22 + .../starlette/middleware/opentelemetry.py | 126 + .../cp312/starlette/middleware/sessions.py | 137 + .../cp312/starlette/middleware/trustedhost.py | 66 + .../cp312/starlette/middleware/wsgi.py | 157 + .../target-vendors/cp312/starlette/py.typed | 0 .../cp312/starlette/requests.py | 348 + .../cp312/starlette/responses.py | 579 + .../target-vendors/cp312/starlette/routing.py | 765 + .../target-vendors/cp312/starlette/schemas.py | 152 + .../cp312/starlette/staticfiles.py | 231 + .../target-vendors/cp312/starlette/status.py | 211 + .../cp312/starlette/templating.py | 156 + .../cp312/starlette/testclient.py | 568 + .../target-vendors/cp312/starlette/types.py | 26 + .../cp312/starlette/websockets.py | 202 + .../METADATA | 73 + .../typing_extensions-4.16.0.dist-info/RECORD | 5 + .../typing_extensions-4.16.0.dist-info/WHEEL | 4 + .../licenses/LICENSE | 279 + .../target-vendors/cp312/typing_extensions.py | 4422 ++++ .../METADATA | 49 + .../typing_inspection-0.4.4.dist-info/RECORD | 9 + .../typing_inspection-0.4.4.dist-info/WHEEL | 4 + .../licenses/LICENSE | 21 + .../cp312/typing_inspection/__init__.py | 0 .../cp312/typing_inspection/introspection.py | 587 + .../cp312/typing_inspection/py.typed | 0 .../cp312/typing_inspection/typing_objects.py | 620 + .../typing_inspection/typing_objects.pyi | 421 + .../cp312/uvicorn-0.53.0.dist-info/METADATA | 189 + .../cp312/uvicorn-0.53.0.dist-info/RECORD | 51 + .../cp312/uvicorn-0.53.0.dist-info/WHEEL | 4 + .../uvicorn-0.53.0.dist-info/entry_points.txt | 2 + .../licenses/LICENSE.md | 27 + .../target-vendors/cp312/uvicorn/__init__.py | 5 + .../target-vendors/cp312/uvicorn/__main__.py | 4 + source/target-vendors/cp312/uvicorn/_ansi.py | 29 + .../target-vendors/cp312/uvicorn/_compat.py | 91 + .../cp312/uvicorn/_subprocess.py | 84 + source/target-vendors/cp312/uvicorn/_types.py | 274 + source/target-vendors/cp312/uvicorn/config.py | 618 + .../target-vendors/cp312/uvicorn/importer.py | 34 + .../cp312/uvicorn/lifespan/__init__.py | 0 .../cp312/uvicorn/lifespan/off.py | 17 + .../cp312/uvicorn/lifespan/on.py | 137 + .../target-vendors/cp312/uvicorn/logging.py | 117 + .../cp312/uvicorn/loops/__init__.py | 0 .../cp312/uvicorn/loops/asyncio.py | 11 + .../cp312/uvicorn/loops/auto.py | 17 + .../cp312/uvicorn/loops/uvloop.py | 10 + .../cp312/uvicorn/loops/zuvloop.py | 10 + source/target-vendors/cp312/uvicorn/main.py | 656 + .../cp312/uvicorn/middleware/__init__.py | 0 .../cp312/uvicorn/middleware/asgi2.py | 15 + .../uvicorn/middleware/message_logger.py | 87 + .../cp312/uvicorn/middleware/proxy_headers.py | 187 + .../cp312/uvicorn/middleware/wsgi.py | 199 + .../cp312/uvicorn/protocols/__init__.py | 0 .../cp312/uvicorn/protocols/http/__init__.py | 0 .../cp312/uvicorn/protocols/http/auto.py | 15 + .../uvicorn/protocols/http/auto_zttp_impl.py | 89 + .../uvicorn/protocols/http/flow_control.py | 54 + .../cp312/uvicorn/protocols/http/h11_impl.py | 540 + .../uvicorn/protocols/http/httptools_impl.py | 581 + .../uvicorn/protocols/http/zttp_h2_impl.py | 521 + .../cp312/uvicorn/protocols/http/zttp_impl.py | 537 + .../cp312/uvicorn/protocols/utils.py | 62 + .../uvicorn/protocols/websockets/__init__.py | 0 .../uvicorn/protocols/websockets/auto.py | 21 + .../protocols/websockets/websockets_impl.py | 390 + .../websockets/websockets_sansio_impl.py | 556 + .../protocols/websockets/wsproto_impl.py | 500 + source/target-vendors/cp312/uvicorn/py.typed | 1 + source/target-vendors/cp312/uvicorn/server.py | 356 + .../cp312/uvicorn/supervisors/__init__.py | 16 + .../cp312/uvicorn/supervisors/basereload.py | 124 + .../cp312/uvicorn/supervisors/multiprocess.py | 282 + .../cp312/uvicorn/supervisors/statreload.py | 52 + .../uvicorn/supervisors/watchfilesreload.py | 86 + .../target-vendors/cp312/uvicorn/workers.py | 111 + source/tests/test_archive_targets.py | 22 +- source/tests/test_autostart.py | 240 +- source/tests/test_build_privacy_paths.py | 33 + source/tests/test_cli_health.py | 70 + source/tests/test_connection_background.py | 5 + source/tests/test_fleet_routing.py | 96 + source/tests/test_health.py | 196 + source/tests/test_idle_state_io.py | 152 + source/tests/test_linux_compatibility.py | 40 + source/tests/test_node_helper_cleanup.py | 79 + source/tests/test_package_maintainer.py | 34 +- source/tests/test_package_upgrade.py | 52 + source/tests/test_public_release_metadata.py | 133 + tools/README-APT.md | 134 - tools/build_apt_repository.py | 299 - tools/publish_gitea.py | 227 - tools/run_tests.py | 31 - tools/test_build_apt_repository.py | 185 - tools/test_publish_gitea.py | 72 - website/.gitignore | 6 - website/README.md | 49 - website/assets/favicon.svg | 1 - website/assets/logo.svg | 1 - website/assets/video-poster.svg | 1 - website/build_site.py | 116 - website/qa_site.py | 125 - website/release.example.json | 74 - website/release_catalog.py | 132 - website/src/site.css | 11 - website/src/site.js | 12 - website/test_release_catalog.py | 73 - 993 files changed, 255481 insertions(+), 1720 deletions(-) delete mode 100644 RELEASE-NOTES-0.3.3.md create mode 100644 TARGET-VENDOR-PROVENANCE.json create mode 100644 docs/OPERATIONS-ROADMAP.md create mode 100644 docs/RELEASE-NOTES-0.3.4-dev.md create mode 100644 docs/RELEASE-NOTES-0.3.4.md create mode 100644 source/expanded/framebridge_expanded/health.py create mode 100644 source/packaging/release_metadata.py create mode 100644 source/target-vendors/cp312/_cffi_backend.cpython-312-x86_64-linux-gnu.so create mode 100644 source/target-vendors/cp312/annotated_types-0.8.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/annotated_types-0.8.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/annotated_types-0.8.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/annotated_types-0.8.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/annotated_types/__init__.py create mode 100644 source/target-vendors/cp312/annotated_types/py.typed create mode 100644 source/target-vendors/cp312/annotated_types/test_cases.py create mode 100644 source/target-vendors/cp312/anyio-4.15.1.dist-info/METADATA create mode 100644 source/target-vendors/cp312/anyio-4.15.1.dist-info/RECORD create mode 100644 source/target-vendors/cp312/anyio-4.15.1.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/anyio-4.15.1.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/anyio-4.15.1.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/anyio-4.15.1.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/anyio/__init__.py create mode 100644 source/target-vendors/cp312/anyio/_backends/__init__.py create mode 100644 source/target-vendors/cp312/anyio/_backends/_asyncio.py create mode 100644 source/target-vendors/cp312/anyio/_backends/_trio.py create mode 100644 source/target-vendors/cp312/anyio/_core/__init__.py create mode 100644 source/target-vendors/cp312/anyio/_core/_asyncio_selector_thread.py create mode 100644 source/target-vendors/cp312/anyio/_core/_concurrency_utils.py create mode 100644 source/target-vendors/cp312/anyio/_core/_contextmanagers.py create mode 100644 source/target-vendors/cp312/anyio/_core/_eventloop.py create mode 100644 source/target-vendors/cp312/anyio/_core/_exceptions.py create mode 100644 source/target-vendors/cp312/anyio/_core/_fileio.py create mode 100644 source/target-vendors/cp312/anyio/_core/_futures.py create mode 100644 source/target-vendors/cp312/anyio/_core/_resources.py create mode 100644 source/target-vendors/cp312/anyio/_core/_signals.py create mode 100644 source/target-vendors/cp312/anyio/_core/_sockets.py create mode 100644 source/target-vendors/cp312/anyio/_core/_streams.py create mode 100644 source/target-vendors/cp312/anyio/_core/_subprocesses.py create mode 100644 source/target-vendors/cp312/anyio/_core/_synchronization.py create mode 100644 source/target-vendors/cp312/anyio/_core/_tasks.py create mode 100644 source/target-vendors/cp312/anyio/_core/_tempfile.py create mode 100644 source/target-vendors/cp312/anyio/_core/_testing.py create mode 100644 source/target-vendors/cp312/anyio/_core/_typedattr.py create mode 100644 source/target-vendors/cp312/anyio/_lazyimport.py create mode 100644 source/target-vendors/cp312/anyio/abc/__init__.py create mode 100644 source/target-vendors/cp312/anyio/abc/_eventloop.py create mode 100644 source/target-vendors/cp312/anyio/abc/_resources.py create mode 100644 source/target-vendors/cp312/anyio/abc/_sockets.py create mode 100644 source/target-vendors/cp312/anyio/abc/_streams.py create mode 100644 source/target-vendors/cp312/anyio/abc/_subprocesses.py create mode 100644 source/target-vendors/cp312/anyio/abc/_tasks.py create mode 100644 source/target-vendors/cp312/anyio/abc/_testing.py create mode 100644 source/target-vendors/cp312/anyio/from_thread.py create mode 100644 source/target-vendors/cp312/anyio/functools.py create mode 100644 source/target-vendors/cp312/anyio/itertools.py create mode 100644 source/target-vendors/cp312/anyio/lowlevel.py create mode 100644 source/target-vendors/cp312/anyio/py.typed create mode 100644 source/target-vendors/cp312/anyio/pytest_plugin.py create mode 100644 source/target-vendors/cp312/anyio/streams/__init__.py create mode 100644 source/target-vendors/cp312/anyio/streams/buffered.py create mode 100644 source/target-vendors/cp312/anyio/streams/file.py create mode 100644 source/target-vendors/cp312/anyio/streams/memory.py create mode 100644 source/target-vendors/cp312/anyio/streams/stapled.py create mode 100644 source/target-vendors/cp312/anyio/streams/text.py create mode 100644 source/target-vendors/cp312/anyio/streams/tls.py create mode 100644 source/target-vendors/cp312/anyio/to_interpreter.py create mode 100644 source/target-vendors/cp312/anyio/to_process.py create mode 100644 source/target-vendors/cp312/anyio/to_thread.py create mode 100644 source/target-vendors/cp312/attr/__init__.py create mode 100644 source/target-vendors/cp312/attr/__init__.pyi create mode 100644 source/target-vendors/cp312/attr/_cmp.py create mode 100644 source/target-vendors/cp312/attr/_cmp.pyi create mode 100644 source/target-vendors/cp312/attr/_compat.py create mode 100644 source/target-vendors/cp312/attr/_config.py create mode 100644 source/target-vendors/cp312/attr/_funcs.py create mode 100644 source/target-vendors/cp312/attr/_make.py create mode 100644 source/target-vendors/cp312/attr/_next_gen.py create mode 100644 source/target-vendors/cp312/attr/_typing_compat.pyi create mode 100644 source/target-vendors/cp312/attr/_version_info.py create mode 100644 source/target-vendors/cp312/attr/_version_info.pyi create mode 100644 source/target-vendors/cp312/attr/converters.py create mode 100644 source/target-vendors/cp312/attr/converters.pyi create mode 100644 source/target-vendors/cp312/attr/exceptions.py create mode 100644 source/target-vendors/cp312/attr/exceptions.pyi create mode 100644 source/target-vendors/cp312/attr/filters.py create mode 100644 source/target-vendors/cp312/attr/filters.pyi create mode 100644 source/target-vendors/cp312/attr/py.typed create mode 100644 source/target-vendors/cp312/attr/setters.py create mode 100644 source/target-vendors/cp312/attr/setters.pyi create mode 100644 source/target-vendors/cp312/attr/validators.py create mode 100644 source/target-vendors/cp312/attr/validators.pyi create mode 100644 source/target-vendors/cp312/attrs-26.1.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/attrs-26.1.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/attrs-26.1.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/attrs-26.1.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/attrs/__init__.py create mode 100644 source/target-vendors/cp312/attrs/__init__.pyi create mode 100644 source/target-vendors/cp312/attrs/converters.py create mode 100644 source/target-vendors/cp312/attrs/exceptions.py create mode 100644 source/target-vendors/cp312/attrs/filters.py create mode 100644 source/target-vendors/cp312/attrs/py.typed create mode 100644 source/target-vendors/cp312/attrs/setters.py create mode 100644 source/target-vendors/cp312/attrs/validators.py create mode 100644 source/target-vendors/cp312/certifi-2026.7.22.dist-info/METADATA create mode 100644 source/target-vendors/cp312/certifi-2026.7.22.dist-info/RECORD create mode 100644 source/target-vendors/cp312/certifi-2026.7.22.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/certifi-2026.7.22.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/certifi-2026.7.22.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/certifi/__init__.py create mode 100644 source/target-vendors/cp312/certifi/__main__.py create mode 100644 source/target-vendors/cp312/certifi/cacert.pem create mode 100644 source/target-vendors/cp312/certifi/core.py create mode 100644 source/target-vendors/cp312/certifi/py.typed create mode 100644 source/target-vendors/cp312/certifi/tests/__init__.py create mode 100644 source/target-vendors/cp312/certifi/tests/test_certify.py create mode 100644 source/target-vendors/cp312/cffi-2.1.1.dist-info/METADATA create mode 100644 source/target-vendors/cp312/cffi-2.1.1.dist-info/RECORD create mode 100644 source/target-vendors/cp312/cffi-2.1.1.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/cffi-2.1.1.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/cffi-2.1.1.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/cffi-2.1.1.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/cffi/__init__.py create mode 100644 source/target-vendors/cp312/cffi/_cffi_errors.h create mode 100644 source/target-vendors/cp312/cffi/_cffi_gen_src.py create mode 100644 source/target-vendors/cp312/cffi/_cffi_include.h create mode 100644 source/target-vendors/cp312/cffi/_embedding.h create mode 100644 source/target-vendors/cp312/cffi/_imp_emulation.py create mode 100644 source/target-vendors/cp312/cffi/_shimmed_dist_utils.py create mode 100644 source/target-vendors/cp312/cffi/api.py create mode 100644 source/target-vendors/cp312/cffi/backend_ctypes.py create mode 100644 source/target-vendors/cp312/cffi/cffi_opcode.py create mode 100644 source/target-vendors/cp312/cffi/commontypes.py create mode 100644 source/target-vendors/cp312/cffi/cparser.py create mode 100644 source/target-vendors/cp312/cffi/error.py create mode 100644 source/target-vendors/cp312/cffi/ffiplatform.py create mode 100644 source/target-vendors/cp312/cffi/gen_src.py create mode 100644 source/target-vendors/cp312/cffi/lock.py create mode 100644 source/target-vendors/cp312/cffi/model.py create mode 100644 source/target-vendors/cp312/cffi/parse_c_type.h create mode 100644 source/target-vendors/cp312/cffi/pkgconfig.py create mode 100644 source/target-vendors/cp312/cffi/recompiler.py create mode 100644 source/target-vendors/cp312/cffi/setuptools_ext.py create mode 100644 source/target-vendors/cp312/cffi/vengine_cpy.py create mode 100644 source/target-vendors/cp312/cffi/vengine_gen.py create mode 100644 source/target-vendors/cp312/cffi/verifier.py create mode 100644 source/target-vendors/cp312/click-8.5.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/click-8.5.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/click-8.5.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/click-8.5.0.dist-info/licenses/LICENSE.txt create mode 100644 source/target-vendors/cp312/click/__init__.py create mode 100644 source/target-vendors/cp312/click/_compat.py create mode 100644 source/target-vendors/cp312/click/_termui_impl.py create mode 100644 source/target-vendors/cp312/click/_textwrap.py create mode 100644 source/target-vendors/cp312/click/_utils.py create mode 100644 source/target-vendors/cp312/click/_winconsole.py create mode 100644 source/target-vendors/cp312/click/core.py create mode 100644 source/target-vendors/cp312/click/decorators.py create mode 100644 source/target-vendors/cp312/click/exceptions.py create mode 100644 source/target-vendors/cp312/click/formatting.py create mode 100644 source/target-vendors/cp312/click/globals.py create mode 100644 source/target-vendors/cp312/click/parser.py create mode 100644 source/target-vendors/cp312/click/py.typed create mode 100644 source/target-vendors/cp312/click/shell_completion.py create mode 100644 source/target-vendors/cp312/click/termui.py create mode 100644 source/target-vendors/cp312/click/testing.py create mode 100644 source/target-vendors/cp312/click/types.py create mode 100644 source/target-vendors/cp312/click/utils.py create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/METADATA create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/RECORD create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.APACHE create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.BSD create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json create mode 100644 source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/sbom.json create mode 100644 source/target-vendors/cp312/cryptography/__about__.py create mode 100644 source/target-vendors/cp312/cryptography/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/cobblestone.py create mode 100644 source/target-vendors/cp312/cryptography/exceptions.py create mode 100644 source/target-vendors/cp312/cryptography/fernet.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/_oid.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/asn1/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/asn1/asn1.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/backends/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/backends/openssl/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/backends/openssl/backend.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust.abi3.so create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/__init__.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/_openssl.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/asn1.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/cobblestone.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/exceptions.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/ocsp.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/aead.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dh.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ec.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keys.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keywrap.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x448.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs12.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs7.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/test_support.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/x509.pyi create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/_conditional.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/binding.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/decrepit/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/algorithms.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/modes.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/_asymmetric.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/_cipheralgorithm.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/_modes.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/_serialization.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dh.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dsa.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ec.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed25519.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed448.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mldsa.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mlkem.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/padding.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/rsa.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/types.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/utils.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x25519.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x448.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/aead.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/algorithms.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/base.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/modes.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/cmac.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/constant_time.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/hashes.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/hmac.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/hpke.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/argon2.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/concatkdf.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/hkdf.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/kbkdf.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/pbkdf2.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/scrypt.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/x963kdf.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/keywrap.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/padding.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/poly1305.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/base.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs12.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs7.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/ssh.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/hotp.py create mode 100644 source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/totp.py create mode 100644 source/target-vendors/cp312/cryptography/py.typed create mode 100644 source/target-vendors/cp312/cryptography/utils.py create mode 100644 source/target-vendors/cp312/cryptography/x509/__init__.py create mode 100644 source/target-vendors/cp312/cryptography/x509/base.py create mode 100644 source/target-vendors/cp312/cryptography/x509/certificate_transparency.py create mode 100644 source/target-vendors/cp312/cryptography/x509/extensions.py create mode 100644 source/target-vendors/cp312/cryptography/x509/general_name.py create mode 100644 source/target-vendors/cp312/cryptography/x509/name.py create mode 100644 source/target-vendors/cp312/cryptography/x509/ocsp.py create mode 100644 source/target-vendors/cp312/cryptography/x509/oid.py create mode 100644 source/target-vendors/cp312/cryptography/x509/verification.py create mode 100644 source/target-vendors/cp312/dotenv/__init__.py create mode 100644 source/target-vendors/cp312/dotenv/__main__.py create mode 100644 source/target-vendors/cp312/dotenv/cli.py create mode 100644 source/target-vendors/cp312/dotenv/ipython.py create mode 100644 source/target-vendors/cp312/dotenv/main.py create mode 100644 source/target-vendors/cp312/dotenv/parser.py create mode 100644 source/target-vendors/cp312/dotenv/py.typed create mode 100644 source/target-vendors/cp312/dotenv/variables.py create mode 100644 source/target-vendors/cp312/dotenv/version.py create mode 100644 source/target-vendors/cp312/h11-0.16.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/h11-0.16.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/h11-0.16.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/h11-0.16.0.dist-info/licenses/LICENSE.txt create mode 100644 source/target-vendors/cp312/h11-0.16.0.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/h11/__init__.py create mode 100644 source/target-vendors/cp312/h11/_abnf.py create mode 100644 source/target-vendors/cp312/h11/_connection.py create mode 100644 source/target-vendors/cp312/h11/_events.py create mode 100644 source/target-vendors/cp312/h11/_headers.py create mode 100644 source/target-vendors/cp312/h11/_readers.py create mode 100644 source/target-vendors/cp312/h11/_receivebuffer.py create mode 100644 source/target-vendors/cp312/h11/_state.py create mode 100644 source/target-vendors/cp312/h11/_util.py create mode 100644 source/target-vendors/cp312/h11/_version.py create mode 100644 source/target-vendors/cp312/h11/_writers.py create mode 100644 source/target-vendors/cp312/h11/py.typed create mode 100644 source/target-vendors/cp312/httpcore-1.0.9.dist-info/METADATA create mode 100644 source/target-vendors/cp312/httpcore-1.0.9.dist-info/RECORD create mode 100644 source/target-vendors/cp312/httpcore-1.0.9.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/httpcore-1.0.9.dist-info/licenses/LICENSE.md create mode 100644 source/target-vendors/cp312/httpcore/__init__.py create mode 100644 source/target-vendors/cp312/httpcore/_api.py create mode 100644 source/target-vendors/cp312/httpcore/_async/__init__.py create mode 100644 source/target-vendors/cp312/httpcore/_async/connection.py create mode 100644 source/target-vendors/cp312/httpcore/_async/connection_pool.py create mode 100644 source/target-vendors/cp312/httpcore/_async/http11.py create mode 100644 source/target-vendors/cp312/httpcore/_async/http2.py create mode 100644 source/target-vendors/cp312/httpcore/_async/http_proxy.py create mode 100644 source/target-vendors/cp312/httpcore/_async/interfaces.py create mode 100644 source/target-vendors/cp312/httpcore/_async/socks_proxy.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/__init__.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/anyio.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/auto.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/base.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/mock.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/sync.py create mode 100644 source/target-vendors/cp312/httpcore/_backends/trio.py create mode 100644 source/target-vendors/cp312/httpcore/_exceptions.py create mode 100644 source/target-vendors/cp312/httpcore/_models.py create mode 100644 source/target-vendors/cp312/httpcore/_ssl.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/__init__.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/connection.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/connection_pool.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/http11.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/http2.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/http_proxy.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/interfaces.py create mode 100644 source/target-vendors/cp312/httpcore/_sync/socks_proxy.py create mode 100644 source/target-vendors/cp312/httpcore/_synchronization.py create mode 100644 source/target-vendors/cp312/httpcore/_trace.py create mode 100644 source/target-vendors/cp312/httpcore/_utils.py create mode 100644 source/target-vendors/cp312/httpcore/py.typed create mode 100644 source/target-vendors/cp312/httpx-0.28.1.dist-info/METADATA create mode 100644 source/target-vendors/cp312/httpx-0.28.1.dist-info/RECORD create mode 100644 source/target-vendors/cp312/httpx-0.28.1.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/httpx-0.28.1.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/httpx-0.28.1.dist-info/licenses/LICENSE.md create mode 100644 source/target-vendors/cp312/httpx/__init__.py create mode 100644 source/target-vendors/cp312/httpx/__version__.py create mode 100644 source/target-vendors/cp312/httpx/_api.py create mode 100644 source/target-vendors/cp312/httpx/_auth.py create mode 100644 source/target-vendors/cp312/httpx/_client.py create mode 100644 source/target-vendors/cp312/httpx/_config.py create mode 100644 source/target-vendors/cp312/httpx/_content.py create mode 100644 source/target-vendors/cp312/httpx/_decoders.py create mode 100644 source/target-vendors/cp312/httpx/_exceptions.py create mode 100644 source/target-vendors/cp312/httpx/_main.py create mode 100644 source/target-vendors/cp312/httpx/_models.py create mode 100644 source/target-vendors/cp312/httpx/_multipart.py create mode 100644 source/target-vendors/cp312/httpx/_status_codes.py create mode 100644 source/target-vendors/cp312/httpx/_transports/__init__.py create mode 100644 source/target-vendors/cp312/httpx/_transports/asgi.py create mode 100644 source/target-vendors/cp312/httpx/_transports/base.py create mode 100644 source/target-vendors/cp312/httpx/_transports/default.py create mode 100644 source/target-vendors/cp312/httpx/_transports/mock.py create mode 100644 source/target-vendors/cp312/httpx/_transports/wsgi.py create mode 100644 source/target-vendors/cp312/httpx/_types.py create mode 100644 source/target-vendors/cp312/httpx/_urlparse.py create mode 100644 source/target-vendors/cp312/httpx/_urls.py create mode 100644 source/target-vendors/cp312/httpx/_utils.py create mode 100644 source/target-vendors/cp312/httpx/py.typed create mode 100644 source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/METADATA create mode 100644 source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/RECORD create mode 100644 source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/httpx_sse/__init__.py create mode 100644 source/target-vendors/cp312/httpx_sse/_api.py create mode 100644 source/target-vendors/cp312/httpx_sse/_decoders.py create mode 100644 source/target-vendors/cp312/httpx_sse/_exceptions.py create mode 100644 source/target-vendors/cp312/httpx_sse/_models.py create mode 100644 source/target-vendors/cp312/httpx_sse/py.typed create mode 100644 source/target-vendors/cp312/idna-3.20.dist-info/METADATA create mode 100644 source/target-vendors/cp312/idna-3.20.dist-info/RECORD create mode 100644 source/target-vendors/cp312/idna-3.20.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/idna-3.20.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/idna-3.20.dist-info/licenses/LICENSE.md create mode 100644 source/target-vendors/cp312/idna/__init__.py create mode 100644 source/target-vendors/cp312/idna/__main__.py create mode 100644 source/target-vendors/cp312/idna/cli.py create mode 100644 source/target-vendors/cp312/idna/codec.py create mode 100644 source/target-vendors/cp312/idna/compat.py create mode 100644 source/target-vendors/cp312/idna/core.py create mode 100644 source/target-vendors/cp312/idna/idnadata.py create mode 100644 source/target-vendors/cp312/idna/intranges.py create mode 100644 source/target-vendors/cp312/idna/package_data.py create mode 100644 source/target-vendors/cp312/idna/py.typed create mode 100644 source/target-vendors/cp312/idna/uts46data.py create mode 100644 source/target-vendors/cp312/jsonschema-4.26.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/jsonschema-4.26.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/jsonschema-4.26.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/jsonschema-4.26.0.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/jsonschema-4.26.0.dist-info/licenses/COPYING create mode 100644 source/target-vendors/cp312/jsonschema/__init__.py create mode 100644 source/target-vendors/cp312/jsonschema/__main__.py create mode 100644 source/target-vendors/cp312/jsonschema/_format.py create mode 100644 source/target-vendors/cp312/jsonschema/_keywords.py create mode 100644 source/target-vendors/cp312/jsonschema/_legacy_keywords.py create mode 100644 source/target-vendors/cp312/jsonschema/_types.py create mode 100644 source/target-vendors/cp312/jsonschema/_typing.py create mode 100644 source/target-vendors/cp312/jsonschema/_utils.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/__init__.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/const_vs_enum.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/contains.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/import_benchmark.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/issue232.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/issue232/issue.json create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/json_schema_test_suite.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/nested_schemas.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/subcomponents.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/unused_registry.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/useless_applicator_schemas.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/useless_keywords.py create mode 100644 source/target-vendors/cp312/jsonschema/benchmarks/validator_creation.py create mode 100644 source/target-vendors/cp312/jsonschema/cli.py create mode 100644 source/target-vendors/cp312/jsonschema/exceptions.py create mode 100644 source/target-vendors/cp312/jsonschema/protocols.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/__init__.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/_suite.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/fuzz_validate.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_cli.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_deprecations.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_exceptions.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_format.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_jsonschema_test_suite.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_types.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_utils.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/test_validators.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/typing/__init__.py create mode 100644 source/target-vendors/cp312/jsonschema/tests/typing/test_all_concrete_validators_match_protocol.py create mode 100644 source/target-vendors/cp312/jsonschema/validators.py create mode 100644 source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/METADATA create mode 100644 source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/RECORD create mode 100644 source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/licenses/COPYING create mode 100644 source/target-vendors/cp312/jsonschema_specifications/__init__.py create mode 100644 source/target-vendors/cp312/jsonschema_specifications/_core.py create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/metaschema.json create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/applicator create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/content create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/core create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/format create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/validation create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/metaschema.json create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/applicator create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/content create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/core create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/validation create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft3/metaschema.json create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft4/metaschema.json create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft6/metaschema.json create mode 100644 source/target-vendors/cp312/jsonschema_specifications/schemas/draft7/metaschema.json create mode 100644 source/target-vendors/cp312/jsonschema_specifications/tests/__init__.py create mode 100644 source/target-vendors/cp312/jsonschema_specifications/tests/test_jsonschema_specifications.py create mode 100644 source/target-vendors/cp312/jwt/__init__.py create mode 100644 source/target-vendors/cp312/jwt/algorithms.py create mode 100644 source/target-vendors/cp312/jwt/api_jwk.py create mode 100644 source/target-vendors/cp312/jwt/api_jws.py create mode 100644 source/target-vendors/cp312/jwt/api_jwt.py create mode 100644 source/target-vendors/cp312/jwt/exceptions.py create mode 100644 source/target-vendors/cp312/jwt/help.py create mode 100644 source/target-vendors/cp312/jwt/jwk_set_cache.py create mode 100644 source/target-vendors/cp312/jwt/jwks_client.py create mode 100644 source/target-vendors/cp312/jwt/py.typed create mode 100644 source/target-vendors/cp312/jwt/types.py create mode 100644 source/target-vendors/cp312/jwt/utils.py create mode 100644 source/target-vendors/cp312/jwt/warnings.py create mode 100644 source/target-vendors/cp312/mcp-1.26.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/mcp-1.26.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/mcp-1.26.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/mcp-1.26.0.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/mcp-1.26.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/mcp/__init__.py create mode 100644 source/target-vendors/cp312/mcp/cli/__init__.py create mode 100644 source/target-vendors/cp312/mcp/cli/claude.py create mode 100644 source/target-vendors/cp312/mcp/cli/cli.py create mode 100644 source/target-vendors/cp312/mcp/client/__init__.py create mode 100644 source/target-vendors/cp312/mcp/client/__main__.py create mode 100644 source/target-vendors/cp312/mcp/client/auth/__init__.py create mode 100644 source/target-vendors/cp312/mcp/client/auth/exceptions.py create mode 100644 source/target-vendors/cp312/mcp/client/auth/extensions/__init__.py create mode 100644 source/target-vendors/cp312/mcp/client/auth/extensions/client_credentials.py create mode 100644 source/target-vendors/cp312/mcp/client/auth/oauth2.py create mode 100644 source/target-vendors/cp312/mcp/client/auth/utils.py create mode 100644 source/target-vendors/cp312/mcp/client/experimental/__init__.py create mode 100644 source/target-vendors/cp312/mcp/client/experimental/task_handlers.py create mode 100644 source/target-vendors/cp312/mcp/client/experimental/tasks.py create mode 100644 source/target-vendors/cp312/mcp/client/session.py create mode 100644 source/target-vendors/cp312/mcp/client/session_group.py create mode 100644 source/target-vendors/cp312/mcp/client/sse.py create mode 100644 source/target-vendors/cp312/mcp/client/stdio/__init__.py create mode 100644 source/target-vendors/cp312/mcp/client/streamable_http.py create mode 100644 source/target-vendors/cp312/mcp/client/websocket.py create mode 100644 source/target-vendors/cp312/mcp/os/__init__.py create mode 100644 source/target-vendors/cp312/mcp/os/posix/__init__.py create mode 100644 source/target-vendors/cp312/mcp/os/posix/utilities.py create mode 100644 source/target-vendors/cp312/mcp/os/win32/__init__.py create mode 100644 source/target-vendors/cp312/mcp/os/win32/utilities.py create mode 100644 source/target-vendors/cp312/mcp/py.typed create mode 100644 source/target-vendors/cp312/mcp/server/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/__main__.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/errors.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/handlers/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/handlers/authorize.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/handlers/metadata.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/handlers/register.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/handlers/revoke.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/handlers/token.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/json_response.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/middleware/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/middleware/auth_context.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/middleware/bearer_auth.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/middleware/client_auth.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/provider.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/routes.py create mode 100644 source/target-vendors/cp312/mcp/server/auth/settings.py create mode 100644 source/target-vendors/cp312/mcp/server/elicitation.py create mode 100644 source/target-vendors/cp312/mcp/server/experimental/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/experimental/request_context.py create mode 100644 source/target-vendors/cp312/mcp/server/experimental/session_features.py create mode 100644 source/target-vendors/cp312/mcp/server/experimental/task_context.py create mode 100644 source/target-vendors/cp312/mcp/server/experimental/task_result_handler.py create mode 100644 source/target-vendors/cp312/mcp/server/experimental/task_support.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/exceptions.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/prompts/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/prompts/base.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/prompts/manager.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/resources/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/resources/base.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/resources/resource_manager.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/resources/templates.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/resources/types.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/server.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/tools/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/tools/base.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/tools/tool_manager.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/utilities/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/utilities/context_injection.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/utilities/func_metadata.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/utilities/logging.py create mode 100644 source/target-vendors/cp312/mcp/server/fastmcp/utilities/types.py create mode 100644 source/target-vendors/cp312/mcp/server/lowlevel/__init__.py create mode 100644 source/target-vendors/cp312/mcp/server/lowlevel/experimental.py create mode 100644 source/target-vendors/cp312/mcp/server/lowlevel/func_inspection.py create mode 100644 source/target-vendors/cp312/mcp/server/lowlevel/helper_types.py create mode 100644 source/target-vendors/cp312/mcp/server/lowlevel/server.py create mode 100644 source/target-vendors/cp312/mcp/server/models.py create mode 100644 source/target-vendors/cp312/mcp/server/session.py create mode 100644 source/target-vendors/cp312/mcp/server/sse.py create mode 100644 source/target-vendors/cp312/mcp/server/stdio.py create mode 100644 source/target-vendors/cp312/mcp/server/streamable_http.py create mode 100644 source/target-vendors/cp312/mcp/server/streamable_http_manager.py create mode 100644 source/target-vendors/cp312/mcp/server/transport_security.py create mode 100644 source/target-vendors/cp312/mcp/server/validation.py create mode 100644 source/target-vendors/cp312/mcp/server/websocket.py create mode 100644 source/target-vendors/cp312/mcp/shared/__init__.py create mode 100644 source/target-vendors/cp312/mcp/shared/_httpx_utils.py create mode 100644 source/target-vendors/cp312/mcp/shared/auth.py create mode 100644 source/target-vendors/cp312/mcp/shared/auth_utils.py create mode 100644 source/target-vendors/cp312/mcp/shared/context.py create mode 100644 source/target-vendors/cp312/mcp/shared/exceptions.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/__init__.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/__init__.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/capabilities.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/context.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/helpers.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/in_memory_task_store.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/message_queue.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/polling.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/resolver.py create mode 100644 source/target-vendors/cp312/mcp/shared/experimental/tasks/store.py create mode 100644 source/target-vendors/cp312/mcp/shared/memory.py create mode 100644 source/target-vendors/cp312/mcp/shared/message.py create mode 100644 source/target-vendors/cp312/mcp/shared/metadata_utils.py create mode 100644 source/target-vendors/cp312/mcp/shared/progress.py create mode 100644 source/target-vendors/cp312/mcp/shared/response_router.py create mode 100644 source/target-vendors/cp312/mcp/shared/session.py create mode 100644 source/target-vendors/cp312/mcp/shared/tool_name_validation.py create mode 100644 source/target-vendors/cp312/mcp/shared/version.py create mode 100644 source/target-vendors/cp312/mcp/types.py create mode 100644 source/target-vendors/cp312/multipart/__init__.py create mode 100644 source/target-vendors/cp312/multipart/decoders.py create mode 100644 source/target-vendors/cp312/multipart/exceptions.py create mode 100644 source/target-vendors/cp312/multipart/multipart.py create mode 100644 source/target-vendors/cp312/pycparser-3.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/pycparser-3.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/pycparser-3.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/pycparser-3.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/pycparser-3.0.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/pycparser/__init__.py create mode 100644 source/target-vendors/cp312/pycparser/_ast_gen.py create mode 100644 source/target-vendors/cp312/pycparser/_c_ast.cfg create mode 100644 source/target-vendors/cp312/pycparser/ast_transforms.py create mode 100644 source/target-vendors/cp312/pycparser/c_ast.py create mode 100644 source/target-vendors/cp312/pycparser/c_generator.py create mode 100644 source/target-vendors/cp312/pycparser/c_lexer.py create mode 100644 source/target-vendors/cp312/pycparser/c_parser.py create mode 100644 source/target-vendors/cp312/pydantic-2.13.5.dist-info/METADATA create mode 100644 source/target-vendors/cp312/pydantic-2.13.5.dist-info/RECORD create mode 100644 source/target-vendors/cp312/pydantic-2.13.5.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/pydantic-2.13.5.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/pydantic/__init__.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/__init__.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_config.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_core_metadata.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_core_utils.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_dataclasses.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_decorators.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_decorators_v1.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_discriminated_union.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_docs_extraction.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_fields.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_forward_ref.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_generate_schema.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_generics.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_git.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_import_utils.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_internal_dataclass.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_known_annotated_metadata.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_mock_val_ser.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_model_construction.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_namespace_utils.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_repr.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_schema_gather.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_schema_generation_shared.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_serializers.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_signature.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_typing_extra.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_utils.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_validate_call.py create mode 100644 source/target-vendors/cp312/pydantic/_internal/_validators.py create mode 100644 source/target-vendors/cp312/pydantic/_migration.py create mode 100644 source/target-vendors/cp312/pydantic/alias_generators.py create mode 100644 source/target-vendors/cp312/pydantic/aliases.py create mode 100644 source/target-vendors/cp312/pydantic/annotated_handlers.py create mode 100644 source/target-vendors/cp312/pydantic/class_validators.py create mode 100644 source/target-vendors/cp312/pydantic/color.py create mode 100644 source/target-vendors/cp312/pydantic/config.py create mode 100644 source/target-vendors/cp312/pydantic/dataclasses.py create mode 100644 source/target-vendors/cp312/pydantic/datetime_parse.py create mode 100644 source/target-vendors/cp312/pydantic/decorator.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/__init__.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/class_validators.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/config.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/copy_internals.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/decorator.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/json.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/parse.py create mode 100644 source/target-vendors/cp312/pydantic/deprecated/tools.py create mode 100644 source/target-vendors/cp312/pydantic/env_settings.py create mode 100644 source/target-vendors/cp312/pydantic/error_wrappers.py create mode 100644 source/target-vendors/cp312/pydantic/errors.py create mode 100644 source/target-vendors/cp312/pydantic/experimental/__init__.py create mode 100644 source/target-vendors/cp312/pydantic/experimental/arguments_schema.py create mode 100644 source/target-vendors/cp312/pydantic/experimental/missing_sentinel.py create mode 100644 source/target-vendors/cp312/pydantic/experimental/pipeline.py create mode 100644 source/target-vendors/cp312/pydantic/fields.py create mode 100644 source/target-vendors/cp312/pydantic/functional_serializers.py create mode 100644 source/target-vendors/cp312/pydantic/functional_validators.py create mode 100644 source/target-vendors/cp312/pydantic/generics.py create mode 100644 source/target-vendors/cp312/pydantic/json.py create mode 100644 source/target-vendors/cp312/pydantic/json_schema.py create mode 100644 source/target-vendors/cp312/pydantic/main.py create mode 100644 source/target-vendors/cp312/pydantic/mypy.py create mode 100644 source/target-vendors/cp312/pydantic/networks.py create mode 100644 source/target-vendors/cp312/pydantic/parse.py create mode 100644 source/target-vendors/cp312/pydantic/plugin/__init__.py create mode 100644 source/target-vendors/cp312/pydantic/plugin/_loader.py create mode 100644 source/target-vendors/cp312/pydantic/plugin/_schema_validator.py create mode 100644 source/target-vendors/cp312/pydantic/py.typed create mode 100644 source/target-vendors/cp312/pydantic/root_model.py create mode 100644 source/target-vendors/cp312/pydantic/schema.py create mode 100644 source/target-vendors/cp312/pydantic/tools.py create mode 100644 source/target-vendors/cp312/pydantic/type_adapter.py create mode 100644 source/target-vendors/cp312/pydantic/types.py create mode 100644 source/target-vendors/cp312/pydantic/typing.py create mode 100644 source/target-vendors/cp312/pydantic/utils.py create mode 100644 source/target-vendors/cp312/pydantic/v1/__init__.py create mode 100644 source/target-vendors/cp312/pydantic/v1/_hypothesis_plugin.py create mode 100644 source/target-vendors/cp312/pydantic/v1/annotated_types.py create mode 100644 source/target-vendors/cp312/pydantic/v1/class_validators.py create mode 100644 source/target-vendors/cp312/pydantic/v1/color.py create mode 100644 source/target-vendors/cp312/pydantic/v1/config.py create mode 100644 source/target-vendors/cp312/pydantic/v1/dataclasses.py create mode 100644 source/target-vendors/cp312/pydantic/v1/datetime_parse.py create mode 100644 source/target-vendors/cp312/pydantic/v1/decorator.py create mode 100644 source/target-vendors/cp312/pydantic/v1/env_settings.py create mode 100644 source/target-vendors/cp312/pydantic/v1/error_wrappers.py create mode 100644 source/target-vendors/cp312/pydantic/v1/errors.py create mode 100644 source/target-vendors/cp312/pydantic/v1/fields.py create mode 100644 source/target-vendors/cp312/pydantic/v1/generics.py create mode 100644 source/target-vendors/cp312/pydantic/v1/json.py create mode 100644 source/target-vendors/cp312/pydantic/v1/main.py create mode 100644 source/target-vendors/cp312/pydantic/v1/mypy.py create mode 100644 source/target-vendors/cp312/pydantic/v1/networks.py create mode 100644 source/target-vendors/cp312/pydantic/v1/parse.py create mode 100644 source/target-vendors/cp312/pydantic/v1/py.typed create mode 100644 source/target-vendors/cp312/pydantic/v1/schema.py create mode 100644 source/target-vendors/cp312/pydantic/v1/tools.py create mode 100644 source/target-vendors/cp312/pydantic/v1/types.py create mode 100644 source/target-vendors/cp312/pydantic/v1/typing.py create mode 100644 source/target-vendors/cp312/pydantic/v1/utils.py create mode 100644 source/target-vendors/cp312/pydantic/v1/validators.py create mode 100644 source/target-vendors/cp312/pydantic/v1/version.py create mode 100644 source/target-vendors/cp312/pydantic/validate_call_decorator.py create mode 100644 source/target-vendors/cp312/pydantic/validators.py create mode 100644 source/target-vendors/cp312/pydantic/version.py create mode 100644 source/target-vendors/cp312/pydantic/warnings.py create mode 100644 source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/METADATA create mode 100644 source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/RECORD create mode 100644 source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/sboms/pydantic-core.cyclonedx.json create mode 100644 source/target-vendors/cp312/pydantic_core/__init__.py create mode 100644 source/target-vendors/cp312/pydantic_core/_pydantic_core.cpython-312-x86_64-linux-gnu.so create mode 100644 source/target-vendors/cp312/pydantic_core/_pydantic_core.pyi create mode 100644 source/target-vendors/cp312/pydantic_core/core_schema.py create mode 100644 source/target-vendors/cp312/pydantic_core/py.typed create mode 100644 source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/pydantic_settings/__init__.py create mode 100644 source/target-vendors/cp312/pydantic_settings/exceptions.py create mode 100644 source/target-vendors/cp312/pydantic_settings/main.py create mode 100644 source/target-vendors/cp312/pydantic_settings/py.typed create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/__init__.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/base.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/__init__.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/aws.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/azure.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/cli.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/dotenv.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/env.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/gcp.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/json.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/nested_secrets.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/pyproject.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/secrets.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/toml.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/providers/yaml.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/types.py create mode 100644 source/target-vendors/cp312/pydantic_settings/sources/utils.py create mode 100644 source/target-vendors/cp312/pydantic_settings/utils.py create mode 100644 source/target-vendors/cp312/pydantic_settings/version.py create mode 100644 source/target-vendors/cp312/pyjwt-2.14.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/pyjwt-2.14.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/pyjwt-2.14.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/AUTHORS.rst create mode 100644 source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/pyjwt-2.14.0.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/METADATA create mode 100644 source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/RECORD create mode 100644 source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/python_multipart-0.0.32.dist-info/METADATA create mode 100644 source/target-vendors/cp312/python_multipart-0.0.32.dist-info/RECORD create mode 100644 source/target-vendors/cp312/python_multipart-0.0.32.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/python_multipart-0.0.32.dist-info/licenses/LICENSE.txt create mode 100644 source/target-vendors/cp312/python_multipart/__init__.py create mode 100644 source/target-vendors/cp312/python_multipart/decoders.py create mode 100644 source/target-vendors/cp312/python_multipart/exceptions.py create mode 100644 source/target-vendors/cp312/python_multipart/multipart.py create mode 100644 source/target-vendors/cp312/python_multipart/py.typed create mode 100644 source/target-vendors/cp312/referencing-0.37.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/referencing-0.37.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/referencing-0.37.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/referencing-0.37.0.dist-info/licenses/COPYING create mode 100644 source/target-vendors/cp312/referencing/__init__.py create mode 100644 source/target-vendors/cp312/referencing/_attrs.py create mode 100644 source/target-vendors/cp312/referencing/_attrs.pyi create mode 100644 source/target-vendors/cp312/referencing/_core.py create mode 100644 source/target-vendors/cp312/referencing/exceptions.py create mode 100644 source/target-vendors/cp312/referencing/jsonschema.py create mode 100644 source/target-vendors/cp312/referencing/py.typed create mode 100644 source/target-vendors/cp312/referencing/retrieval.py create mode 100644 source/target-vendors/cp312/referencing/tests/__init__.py create mode 100644 source/target-vendors/cp312/referencing/tests/test_core.py create mode 100644 source/target-vendors/cp312/referencing/tests/test_exceptions.py create mode 100644 source/target-vendors/cp312/referencing/tests/test_jsonschema.py create mode 100644 source/target-vendors/cp312/referencing/tests/test_referencing_suite.py create mode 100644 source/target-vendors/cp312/referencing/tests/test_retrieval.py create mode 100644 source/target-vendors/cp312/referencing/typing.py create mode 100644 source/target-vendors/cp312/rpds/__init__.py create mode 100644 source/target-vendors/cp312/rpds/__init__.pyi create mode 100644 source/target-vendors/cp312/rpds/py.typed create mode 100644 source/target-vendors/cp312/rpds/rpds.cpython-312-x86_64-linux-gnu.so create mode 100644 source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/METADATA create mode 100644 source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/RECORD create mode 100644 source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/sboms/rpds-py.cyclonedx.json create mode 100644 source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/METADATA create mode 100644 source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/RECORD create mode 100644 source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/AUTHORS create mode 100644 source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/top_level.txt create mode 100644 source/target-vendors/cp312/sse_starlette/__init__.py create mode 100644 source/target-vendors/cp312/sse_starlette/_utils.py create mode 100644 source/target-vendors/cp312/sse_starlette/event.py create mode 100644 source/target-vendors/cp312/sse_starlette/py.typed create mode 100644 source/target-vendors/cp312/sse_starlette/sse.py create mode 100644 source/target-vendors/cp312/starlette-1.7.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/starlette-1.7.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/starlette-1.7.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/starlette-1.7.0.dist-info/licenses/LICENSE.md create mode 100644 source/target-vendors/cp312/starlette/__init__.py create mode 100644 source/target-vendors/cp312/starlette/_exception_handler.py create mode 100644 source/target-vendors/cp312/starlette/_utils.py create mode 100644 source/target-vendors/cp312/starlette/applications.py create mode 100644 source/target-vendors/cp312/starlette/authentication.py create mode 100644 source/target-vendors/cp312/starlette/background.py create mode 100644 source/target-vendors/cp312/starlette/concurrency.py create mode 100644 source/target-vendors/cp312/starlette/config.py create mode 100644 source/target-vendors/cp312/starlette/convertors.py create mode 100644 source/target-vendors/cp312/starlette/datastructures.py create mode 100644 source/target-vendors/cp312/starlette/endpoints.py create mode 100644 source/target-vendors/cp312/starlette/exceptions.py create mode 100644 source/target-vendors/cp312/starlette/formparsers.py create mode 100644 source/target-vendors/cp312/starlette/middleware/__init__.py create mode 100644 source/target-vendors/cp312/starlette/middleware/authentication.py create mode 100644 source/target-vendors/cp312/starlette/middleware/base.py create mode 100644 source/target-vendors/cp312/starlette/middleware/body_limit.py create mode 100644 source/target-vendors/cp312/starlette/middleware/cors.py create mode 100644 source/target-vendors/cp312/starlette/middleware/errors.py create mode 100644 source/target-vendors/cp312/starlette/middleware/exceptions.py create mode 100644 source/target-vendors/cp312/starlette/middleware/gzip.py create mode 100644 source/target-vendors/cp312/starlette/middleware/httpsredirect.py create mode 100644 source/target-vendors/cp312/starlette/middleware/opentelemetry.py create mode 100644 source/target-vendors/cp312/starlette/middleware/sessions.py create mode 100644 source/target-vendors/cp312/starlette/middleware/trustedhost.py create mode 100644 source/target-vendors/cp312/starlette/middleware/wsgi.py create mode 100644 source/target-vendors/cp312/starlette/py.typed create mode 100644 source/target-vendors/cp312/starlette/requests.py create mode 100644 source/target-vendors/cp312/starlette/responses.py create mode 100644 source/target-vendors/cp312/starlette/routing.py create mode 100644 source/target-vendors/cp312/starlette/schemas.py create mode 100644 source/target-vendors/cp312/starlette/staticfiles.py create mode 100644 source/target-vendors/cp312/starlette/status.py create mode 100644 source/target-vendors/cp312/starlette/templating.py create mode 100644 source/target-vendors/cp312/starlette/testclient.py create mode 100644 source/target-vendors/cp312/starlette/types.py create mode 100644 source/target-vendors/cp312/starlette/websockets.py create mode 100644 source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/typing_extensions.py create mode 100644 source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/METADATA create mode 100644 source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/RECORD create mode 100644 source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/licenses/LICENSE create mode 100644 source/target-vendors/cp312/typing_inspection/__init__.py create mode 100644 source/target-vendors/cp312/typing_inspection/introspection.py create mode 100644 source/target-vendors/cp312/typing_inspection/py.typed create mode 100644 source/target-vendors/cp312/typing_inspection/typing_objects.py create mode 100644 source/target-vendors/cp312/typing_inspection/typing_objects.pyi create mode 100644 source/target-vendors/cp312/uvicorn-0.53.0.dist-info/METADATA create mode 100644 source/target-vendors/cp312/uvicorn-0.53.0.dist-info/RECORD create mode 100644 source/target-vendors/cp312/uvicorn-0.53.0.dist-info/WHEEL create mode 100644 source/target-vendors/cp312/uvicorn-0.53.0.dist-info/entry_points.txt create mode 100644 source/target-vendors/cp312/uvicorn-0.53.0.dist-info/licenses/LICENSE.md create mode 100644 source/target-vendors/cp312/uvicorn/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/__main__.py create mode 100644 source/target-vendors/cp312/uvicorn/_ansi.py create mode 100644 source/target-vendors/cp312/uvicorn/_compat.py create mode 100644 source/target-vendors/cp312/uvicorn/_subprocess.py create mode 100644 source/target-vendors/cp312/uvicorn/_types.py create mode 100644 source/target-vendors/cp312/uvicorn/config.py create mode 100644 source/target-vendors/cp312/uvicorn/importer.py create mode 100644 source/target-vendors/cp312/uvicorn/lifespan/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/lifespan/off.py create mode 100644 source/target-vendors/cp312/uvicorn/lifespan/on.py create mode 100644 source/target-vendors/cp312/uvicorn/logging.py create mode 100644 source/target-vendors/cp312/uvicorn/loops/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/loops/asyncio.py create mode 100644 source/target-vendors/cp312/uvicorn/loops/auto.py create mode 100644 source/target-vendors/cp312/uvicorn/loops/uvloop.py create mode 100644 source/target-vendors/cp312/uvicorn/loops/zuvloop.py create mode 100644 source/target-vendors/cp312/uvicorn/main.py create mode 100644 source/target-vendors/cp312/uvicorn/middleware/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/middleware/asgi2.py create mode 100644 source/target-vendors/cp312/uvicorn/middleware/message_logger.py create mode 100644 source/target-vendors/cp312/uvicorn/middleware/proxy_headers.py create mode 100644 source/target-vendors/cp312/uvicorn/middleware/wsgi.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/auto.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/auto_zttp_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/flow_control.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/h11_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/httptools_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/zttp_h2_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/http/zttp_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/utils.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/websockets/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/websockets/auto.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_sansio_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/protocols/websockets/wsproto_impl.py create mode 100644 source/target-vendors/cp312/uvicorn/py.typed create mode 100644 source/target-vendors/cp312/uvicorn/server.py create mode 100644 source/target-vendors/cp312/uvicorn/supervisors/__init__.py create mode 100644 source/target-vendors/cp312/uvicorn/supervisors/basereload.py create mode 100644 source/target-vendors/cp312/uvicorn/supervisors/multiprocess.py create mode 100644 source/target-vendors/cp312/uvicorn/supervisors/statreload.py create mode 100644 source/target-vendors/cp312/uvicorn/supervisors/watchfilesreload.py create mode 100644 source/target-vendors/cp312/uvicorn/workers.py create mode 100644 source/tests/test_build_privacy_paths.py create mode 100644 source/tests/test_cli_health.py create mode 100644 source/tests/test_health.py create mode 100644 source/tests/test_idle_state_io.py create mode 100644 source/tests/test_node_helper_cleanup.py create mode 100644 source/tests/test_public_release_metadata.py delete mode 100644 tools/README-APT.md delete mode 100755 tools/build_apt_repository.py delete mode 100755 tools/publish_gitea.py delete mode 100755 tools/run_tests.py delete mode 100644 tools/test_build_apt_repository.py delete mode 100644 tools/test_publish_gitea.py delete mode 100644 website/.gitignore delete mode 100644 website/README.md delete mode 100644 website/assets/favicon.svg delete mode 100644 website/assets/logo.svg delete mode 100644 website/assets/video-poster.svg delete mode 100644 website/build_site.py delete mode 100644 website/qa_site.py delete mode 100644 website/release.example.json delete mode 100644 website/release_catalog.py delete mode 100644 website/src/site.css delete mode 100644 website/src/site.js delete mode 100644 website/test_release_catalog.py diff --git a/LICENSE-STATUS.md b/LICENSE-STATUS.md index b195cf2..4676d00 100644 --- a/LICENSE-STATUS.md +++ b/LICENSE-STATUS.md @@ -2,9 +2,9 @@ The owner-approved first-party license is GNU GPL version 3 only (GPL-3.0-only), selected October 25, 2026. Apache-2.0 was an earlier first-party proposal and remains applicable to third-party components that use it. The complete GPL is in [LICENSE](LICENSE), with scope in [LICENSING.md](LICENSING.md). -The current release target is FrameBridge 0.3.1, installer FrameBridge-0.3.1.deb. Historical RC7 and Community Preview artifacts retain their separate identities. +FrameBridge 0.3.4 has separate Debian 13, Ubuntu 24.04 and Linux Mint 22.x amd64 release profiles. Signature and publication status belong to its accompanying release record. The [official download page](https://framebridge.betancourt.one/download/) and each artifact's release record identify its source and signatures. Historical 0.3.3, 0.3.1, RC7 and Community Preview artifacts retain their separate identities; their versioned filenames do not identify the current installer. -The pinned Python/Rust dependency notices and source delivery were reconciled in the retained native terms review. The 0.3.1 preparation additionally identifies the OpenAI tunnel-client as third-party Apache-2.0 material, retains its notices, and supplies exact h1-verified source archives and notices for its 47 embedded Go modules. Its own development-build source commit is not embedded and remains a provenance limit. +The pinned Python/Rust dependency notices and source delivery were reconciled in the retained native terms review. The retained OpenAI tunnel-client is third-party Apache-2.0 material. Its notices and exact h1-verified source archives and notices for its 47 embedded Go modules remain included. Its own development-build source commit is not embedded and remains a provenance limit. The dependency-source assets retain their historical 0.3.1 filenames; this does not change the FrameBridge release version or assert an independent rebuild of those components. Public delivery is complete only when the actual matching installer, FrameBridge source, dependency-source assets, supplements and notices are downloadable with verified hashes. Private collection does not establish public availability. The final release delivery record is authoritative for staged or public status; this file does not assert that the port is open or public downloads are live. diff --git a/LICENSING.md b/LICENSING.md index f8145bf..affa31a 100644 --- a/LICENSING.md +++ b/LICENSING.md @@ -6,7 +6,7 @@ The owner selected GNU General Public License version 3 only, SPDX identifier GP The grant covers original FrameBridge code and project documentation that the rightsholders are entitled to license. Recipients may use, study, modify and redistribute that material under the GPL. Modified private copies and lawful independent distributions do not require submitting a pull request to this project. Original blog article text explicitly marked for that purpose uses CC-BY-SA-4.0 under [blog/LICENSING.md](blog/LICENSING.md); media and separately licensed components retain their own terms. -[licensing/SOURCE-LICENSE-SCOPE.json](licensing/SOURCE-LICENSE-SCOPE.json) records classification and provenance. File location is not proof of ownership. Preserve [COPYRIGHT.md](COPYRIGHT.md) and applicable notices. +[licensing/SOURCE-LICENSE-SCOPE.json](licensing/SOURCE-LICENSE-SCOPE.json) records historical classification and provenance; the matching release SOURCE-ARCHIVE-MANIFEST.json identifies the complete current source set. File location is not proof of ownership. Preserve [COPYRIGHT.md](COPYRIGHT.md) and applicable notices. ## Third-party material @@ -18,7 +18,7 @@ The tunnel executable identifies its own module as a development build without a ## Source delivery -Distribute the matching FrameBridge 0.3.1 source archive beside its installer, the immutable shared Python/Rust dependency-source asset, the new tunnel-client dependency-source supplement and retained notices. [Source availability](licensing/third-party/SOURCE-AVAILABILITY.md) identifies the files and hashes. +Distribute the matching FrameBridge 0.3.4 source archive beside each of its three distribution-profile installers, the immutable shared Python/Rust dependency-source asset, the new tunnel-client dependency-source supplement and retained notices. [Source availability](licensing/third-party/SOURCE-AVAILABILITY.md) identifies the files and hashes. The unchanged Certifi source arrangement retains its exact upstream source assets, original notice, full MPL-2.0 text and recipient access instructions. The historical Mozilla certdata revision remains unidentified. No independent native-wheel or tunnel-client rebuild is claimed. These are provenance and reproducibility limits, not claims that unavailable proof has been obtained. diff --git a/README-SOURCE-ARCHIVE.md b/README-SOURCE-ARCHIVE.md index 06075e6..fa73134 100644 --- a/README-SOURCE-ARCHIVE.md +++ b/README-SOURCE-ARCHIVE.md @@ -1,37 +1,37 @@ -# FrameBridge 0.3.1 source archive +# FrameBridge 0.3.4 corresponding source -This archive preserves the repository layout needed by the offline builder. -From this directory, run python3 source/packaging/build_expanded.py to build -FrameBridge-0.3.1.deb. The builder writes source/build and source/release; -it does not install or start FrameBridge. Debian's dpkg-deb and the documented -build prerequisites must already be available. +This archive supplies the project source and the reviewed cp313 and cp312 vendor +inputs for Debian 13, Ubuntu 24.04 and Linux Mint 22.x on amd64. Keep its matching +SOURCE-ARCHIVE-MANIFEST.json sidecar beside the archive. Signatures, publication +and actual OS lifecycle acceptance are recorded separately; assembly alone does +not certify them. Historical signed assets retain their immutable identities. -Original FrameBridge material is GNU GPL version 3 only. Read LICENSE, -LICENSING.md, COPYRIGHT.md, LICENSE-STATUS.md and OFFICIAL-RELEASES.md for -scope, attribution, third-party terms and the official-release trust model. +The offline builder needs Python 3, dpkg/dpkg-deb and the documented host build +prerequisites. It never fetches dependencies, installs packages or starts services. +Extract the archive beside its matching sidecar and run from the extracted root: -The project source asset is accompanied by these separate dependency assets: + python3 source/packaging/build_expanded.py --target debian13-amd64-py313 --public-release --source-manifest ../SOURCE-ARCHIVE-MANIFEST.json + python3 source/packaging/build_expanded.py --target ubuntu24.04-amd64-py312 --vendor-dir source/target-vendors/cp312 --public-release --source-manifest ../SOURCE-ARCHIVE-MANIFEST.json + python3 source/packaging/build_expanded.py --target mint22-amd64-py312 --vendor-dir source/target-vendors/cp312 --public-release --source-manifest ../SOURCE-ARCHIVE-MANIFEST.json + +Public-release mode verifies the archive hash, every current project source file +and the selected reviewed vendor identity before assembling a package. It does +not assert an independent rebuild of third-party native wheels or tunnel-client. +--check-vendor validates inputs without staging a package. + +Original FrameBridge material is GNU GPL version 3 only. Third-party material +retains its applicable terms. Read LICENSE, LICENSING.md, COPYRIGHT.md and the +source-delivery records. Distribute these separate, unchanged dependency assets +with the release; their historical names do not identify the installer version: - FrameBridge-0.3.1-Community-Preview1-dependency-sources.tar.gz - 82,606,998 bytes - SHA-256 64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a + Bytes: 82606998 + SHA-256: 64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a - FrameBridge-0.3.1-tunnel-client-dependency-sources.tar.gz - 26,941,745 bytes - SHA-256 6445d4f0e773aba833fe5c610fbae54102b92de2ce636438f769f21e890c2bd9 + Bytes: 26941745 + SHA-256: 6445d4f0e773aba833fe5c610fbae54102b92de2ce636438f769f21e890c2bd9 -The Preview1 filename deliberately preserves the identity of an immutable -shared asset. Retain licensing/third-party/R2-SUPPLEMENTS.json and its referenced -source notices with the dependency sources. The source indices and -SOURCE-AVAILABILITY.md there record scope and provenance. Do not substitute -unrelated archives. The retained tunnel executable is not claimed to have been -independently rebuilt from an identified own-source revision. - -The blog directory contains licensing policies and the post template. -Editorial article drafts are omitted because they are not source build inputs. - -Only source/evidence/BASELINE.json is included from technical evidence. Runtime -profiles, private QA logs, generated build/release files and Git history are -outside the source archive allowlist. - -A completed archive or builder run is not a declaration of public readiness. -Release checksums, signatures and publication status are recorded separately. +The exact own-source revision of the retained tunnel executable is not asserted. +Retain the R2 source-notice supplements, both dependency indices and original +notices. Private profiles, credentials, QA logs, build outputs, Git history and +unpublished blog drafts are excluded from the archive allowlist. diff --git a/README.md b/README.md index 5503cf6..eb19665 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ Use a central gateway and enrolled nodes to administer Linux computers you control. Run commands and return to persistent Bash terminals; an existing X11 desktop adds optional graphical tools. ChatGPT remains hosted; FrameBridge runs the tools on your Linux computers. -> **Latest signed release: `0.3.3`.** Packages and signed APT repositories are published for Debian 13, Ubuntu 24.04 and Linux Mint 22.x on amd64. Choose the exact distribution profile on the [official download page](https://framebridge.betancourt.one/download/). The signed `v0.3.3` tag and corresponding-source archive identify the released code; the default branch can receive later documentation updates. +> **FrameBridge 0.3.4.** Release builds cover Debian 13, Ubuntu 24.04 and Linux Mint 22.x on amd64. Choose the exact distribution profile on the [official download page](https://framebridge.betancourt.one/download/). Verify the matching release record, package signatures and signed APT metadata before installation. + +This release adds `fb health` / `fb --json health`, confirmed destination identity in Fleet results, native persistent startup improvements and reduced disk writes while idle. The source archive, release packages and external acceptance record identify the exact released code. See the [0.3.4 release notes](docs/RELEASE-NOTES-0.3.4.md). ## Start here @@ -26,14 +28,14 @@ The release has three native Python builds. Choose the package matching the dist | Ubuntu 24.04 | amd64 / x86_64 | 3.12 | `ubuntu24.04-amd64-py312` | | Linux Mint 22.x | amd64 / x86_64 | 3.12 | `mint22-amd64-py312` | -The 0.3.3 packages passed actual signed APT updates and managed-service lifecycle checks on Debian 13, Ubuntu 24.04 and Linux Mint 22.3 VMs. The updates preserved profiles and boot policy, and the services remained ready after the installer exited. Ubuntu 26.04, LMDE 7, other distributions, older releases and other CPU architectures are outside the validated scope of this release. Earlier compatibility experiments are recorded in the [compatibility history](docs/LINUX-COMPATIBILITY-CANDIDATE.md). +Version-specific signed APT update and managed-service lifecycle results belong to the accompanying release acceptance record. Ubuntu 26.04, LMDE 7, other distributions, older releases and other CPU architectures are outside the validated scope of this release. Earlier compatibility experiments are recorded in the [compatibility history](docs/LINUX-COMPATIBILITY-CANDIDATE.md). Verify the signing-key fingerprint, package checksum and detached signature using the instructions on the [official download page](https://framebridge.betancourt.one/download/). Historical release records remain in [Official releases](OFFICIAL-RELEASES.md). A checksum identifies a file; the release signature authenticates it with the independently trusted project key. -For example, with the **Mint** 0.3.3 package downloaded into the current directory: +For example, with the **Mint** 0.3.4 package downloaded into the current directory: ~~~bash -sudo apt install ./FrameBridge-0.3.3-mint22-amd64-py312.deb +sudo apt install ./FrameBridge-0.3.4-mint22-amd64-py312.deb ~~~ Use the corresponding profile filename on Debian or Ubuntu. Review APT's proposed changes for the actual computer. Installation places the software on disk; it does not establish a ChatGPT connection or replace the system Python. @@ -81,6 +83,8 @@ fb help commands --json JSON output is versioned and never prompts. `INTERACTION_REQUIRED` gives an action for the owner's normal terminal. The agent workflow helps an existing shell-based assistant install and diagnose FrameBridge; it does not claim every AI client is a tested replacement for ChatGPT. +For remote work, identify the receiver and execution target separately. `LOCAL` means the current FrameBridge receiver, not a fixed ASUS destination or the computer displaying the conversation. Read the enrolled-node inventory and use a confirmed alias or ID when selecting another computer. Legacy connectors can have different defaults; verify routing before replacing one with another. + `fb` and `framebridge` are names for the same program. Read `fb help` for the English guide and `fb help compatibility` for legacy commands. ## Pause, stop or remove @@ -106,6 +110,8 @@ Use `python3 source/packaging/build_expanded.py --help` for package build profil Read [CONTRIBUTING.md](CONTRIBUTING.md) to propose a change and [SECURITY.md](SECURITY.md) for security reports. Useful compatibility reports name the exact distribution, version, Python version, package profile and tests actually performed. Independent copies retain their applicable software freedoms; they must not be presented as maintainer-approved releases. +The [claims and evidence boundaries](docs/CLAIMS-AND-LIMITS.md) distinguish package installation, connection and operation results. The [operations roadmap](docs/OPERATIONS-ROADMAP.md) describes proposed follow-up work and acceptance checks; it is not a list of features already delivered. + Project home: https://framebridge.betancourt.one/ The public Git repository is `https://framebridge.betancourt.one/git/gerardo/framebridge.git`. For the exact 0.3.3 release, use the signed `v0.3.3` tag or its signed corresponding-source archive from the download page. The repositories, package downloads and source archive are published; normal owner authentication and connection setup are still required on a newly installed computer. diff --git a/RELEASE-NOTES-0.3.3.md b/RELEASE-NOTES-0.3.3.md deleted file mode 100644 index 7f22fd4..0000000 --- a/RELEASE-NOTES-0.3.3.md +++ /dev/null @@ -1,24 +0,0 @@ -# FrameBridge 0.3.3 - -FrameBridge administers Linux computers on a home network through a shared command-line interface for the human administrator and authorized agents. The language model remains hosted. - -## Changes - -- The desktop console reconnects to the existing official console window when the same tmux session contains other windows. It preserves the working shell and unrelated windows, and displays jobs from the selected profile. Recognized legacy desktop entries and console wrappers can be migrated to the packaged command with private backups. -- Forward package upgrades record active managed profiles before replacing files. A detached upgrade worker waits for DPKG to finish, then restarts only those profiles in independent user services. It preserves existing connection processes, profile settings, enrollment and boot policy, and records readiness separately from package installation. Stopped profiles remain stopped. -- The release provides separate amd64 builds and signed APT suites for Debian 13 (`trixie`), Ubuntu 24.04 (`noble`) and Linux Mint 22.x (`mint22`). Use the package for the distribution actually installed; keep its system Python. -- The public documentation uses the canonical website and Gitea repository under `framebridge.betancourt.one` and describes network administration as the primary workflow. Desktop tools remain auxiliary. - -## Updating - -After configuring the matching signed APT source, use the normal package manager to install or update `framebridge-original-expanded`. Inspect `fb status` after an upgrade. A successful APT command confirms package installation; the upgrade worker records runtime restart and readiness independently. An upgrade from a stopped profile does not connect it automatically. - -## Compatibility - -Physical desktop input requires a compatible active X11 session. Native Wayland control is not certified. The guarded x86-64 X11 text backend supports active keyboard group 0 and its documented modifier restrictions. - -Legacy integrations can have a different default execution target from the current receiver. Preserve explicit target routing or use a compatibility adapter when migrating existing clients. Replacing an endpoint without checking its default target is not a compatibility guarantee. - -## Validation - -The release is being validated against the three distribution profiles. Build, signature, APT and live upgrade results are recorded in the accompanying release verification manifest; publication and installation must be verified against the actual signed artifacts. diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index abede3c..05eff48 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,9 @@ # FrameBridge release notes +## 0.3.4 + +Native persistent startup improvements, lower idle disk writes, local health reporting and confirmed Fleet destinations. The release has three amd64 distribution profiles and matching source with both Python ABIs. See [the complete 0.3.4 notes](docs/RELEASE-NOTES-0.3.4.md); signatures and actual lifecycle results are recorded with the release artifacts. + ## Unreleased — private production pilot fixes Private pilot validation remains in progress; these changes are not a public release. diff --git a/TARGET-VENDOR-PROVENANCE.json b/TARGET-VENDOR-PROVENANCE.json new file mode 100644 index 0000000..7075050 --- /dev/null +++ b/TARGET-VENDOR-PROVENANCE.json @@ -0,0 +1,451 @@ +{ + "omitted_vendor_abis": [ + "cp314" + ], + "release_profiles": [ + "debian13-amd64-py313", + "ubuntu24.04-amd64-py312", + "mint22-amd64-py312" + ], + "schema": 1, + "validation_status": "release_source", + "vendors": { + "cp312": { + "native_extensions": [ + "_cffi_backend.cpython-312-x86_64-linux-gnu.so", + "cryptography/hazmat/bindings/_rust.abi3.so", + "pydantic_core/_pydantic_core.cpython-312-x86_64-linux-gnu.so", + "rpds/rpds.cpython-312-x86_64-linux-gnu.so" + ], + "packages": [ + { + "name": "annotated-types", + "version": "0.8.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "anyio", + "version": "4.15.1", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "attrs", + "version": "26.1.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "certifi", + "version": "2026.7.22", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "cffi", + "version": "2.1.1", + "wheel_tags": [ + "cp312-cp312-manylinux_2_17_x86_64", + "cp312-cp312-manylinux2014_x86_64" + ] + }, + { + "name": "click", + "version": "8.5.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "cryptography", + "version": "50.0.1", + "wheel_tags": [ + "cp311-abi3-manylinux_2_34_x86_64" + ] + }, + { + "name": "h11", + "version": "0.16.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "httpcore", + "version": "1.0.9", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "httpx", + "version": "0.28.1", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "httpx-sse", + "version": "0.4.3", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "idna", + "version": "3.20", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "jsonschema", + "version": "4.26.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "mcp", + "version": "1.26.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pycparser", + "version": "3.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pydantic", + "version": "2.13.5", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pydantic-core", + "version": "2.46.5", + "wheel_tags": [ + "cp312-cp312-manylinux_2_17_x86_64", + "cp312-cp312-manylinux2014_x86_64" + ] + }, + { + "name": "pydantic-settings", + "version": "2.15.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pyjwt", + "version": "2.14.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "python-dotenv", + "version": "1.2.3", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "python-multipart", + "version": "0.0.32", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "referencing", + "version": "0.37.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "rpds-py", + "version": "2026.6.3", + "wheel_tags": [ + "cp312-cp312-manylinux_2_17_x86_64", + "cp312-cp312-manylinux2014_x86_64" + ] + }, + { + "name": "sse-starlette", + "version": "3.4.11", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "starlette", + "version": "1.7.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "typing-extensions", + "version": "4.16.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "typing-inspection", + "version": "0.4.4", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "uvicorn", + "version": "0.53.0", + "wheel_tags": [ + "py3-none-any" + ] + } + ], + "path": "source/target-vendors/cp312", + "vendor_sha256": "f4ea1dfb4f71b11eb1a9963bfe55dc6f94e6b10e927f77a7bd9b62433a29ddf1" + }, + "cp313": { + "native_extensions": [ + "_cffi_backend.cpython-313-x86_64-linux-gnu.so", + "cryptography/hazmat/bindings/_rust.abi3.so", + "pydantic_core/_pydantic_core.cpython-313-x86_64-linux-gnu.so", + "rpds/rpds.cpython-313-x86_64-linux-gnu.so" + ], + "packages": [ + { + "name": "annotated-types", + "version": "0.8.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "anyio", + "version": "4.15.1", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "attrs", + "version": "26.1.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "certifi", + "version": "2026.7.22", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "cffi", + "version": "2.1.1", + "wheel_tags": [ + "cp313-cp313-manylinux_2_17_x86_64", + "cp313-cp313-manylinux2014_x86_64" + ] + }, + { + "name": "click", + "version": "8.5.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "cryptography", + "version": "50.0.1", + "wheel_tags": [ + "cp311-abi3-manylinux_2_34_x86_64" + ] + }, + { + "name": "h11", + "version": "0.16.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "httpcore", + "version": "1.0.9", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "httpx", + "version": "0.28.1", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "httpx-sse", + "version": "0.4.3", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "idna", + "version": "3.20", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "jsonschema", + "version": "4.26.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "jsonschema-specifications", + "version": "2025.9.1", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "mcp", + "version": "1.26.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pycparser", + "version": "3.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pydantic", + "version": "2.13.5", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pydantic-core", + "version": "2.46.5", + "wheel_tags": [ + "cp313-cp313-manylinux_2_17_x86_64", + "cp313-cp313-manylinux2014_x86_64" + ] + }, + { + "name": "pydantic-settings", + "version": "2.15.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "pyjwt", + "version": "2.14.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "python-dotenv", + "version": "1.2.3", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "python-multipart", + "version": "0.0.32", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "referencing", + "version": "0.37.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "rpds-py", + "version": "2026.6.3", + "wheel_tags": [ + "cp313-cp313-manylinux_2_17_x86_64", + "cp313-cp313-manylinux2014_x86_64" + ] + }, + { + "name": "sse-starlette", + "version": "3.4.11", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "starlette", + "version": "1.7.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "typing-extensions", + "version": "4.16.0", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "typing-inspection", + "version": "0.4.4", + "wheel_tags": [ + "py3-none-any" + ] + }, + { + "name": "uvicorn", + "version": "0.53.0", + "wheel_tags": [ + "py3-none-any" + ] + } + ], + "path": "source/sources/original-geranas/FrameBridge-Fleet-Hub/vendor", + "vendor_sha256": "80e2917f19003e95f74a6250ee08043cb90681100faf510c0e034843740c0950" + } + }, + "version": "0.3.4" +} diff --git a/docs/CLAIMS-AND-LIMITS.md b/docs/CLAIMS-AND-LIMITS.md index 38629b7..74caf57 100644 --- a/docs/CLAIMS-AND-LIMITS.md +++ b/docs/CLAIMS-AND-LIMITS.md @@ -1,23 +1,36 @@ # Claims and evidence boundaries -The current version is `0.3.1~community.20261026.2`, a separate candidate from RC7 and Preview 1. +The latest signed release is **FrameBridge 0.3.3**, with separate amd64 packages for Debian 13, Ubuntu 24.04 and Linux Mint 22.x. The [official download page](https://framebridge.betancourt.one/download/) identifies the actual artifacts, signatures and corresponding source. A later default-branch documentation change does not rewrite the signed tag or an installed package. + +## Current release scope | Statement | Evidence and boundary | | --- | --- | -| Preview 2 unit suite | 376 tests passed in 22.351 seconds; focused peer regression also passed. | -| Preview 2 package and VM | Pending at documentation freeze; no new VM acceptance or artifact hash is invented here. | -| Preview 1 | Historical record: 368 tests and a reproducible package build. | -| RC7 | Historical record: 361 tests, reproducible package, Debian 13 VM lifecycle and real ChatGPT/console acceptance. | -| ChatGPT connection | Manual owner account consent; the model remains hosted while tools run on selected owner-controlled computers. | -| Persistent console | Session continuity is not a promise that every process survives reboot. | -| Independent FBEXEC tasks | Repeated maintainer experience with non-overlapping work; no certified isolation or simultaneous execution of every command. | -| Graphical control | One controller per shared desktop is a recommendation, not an automatic lock. | +| Distribution profiles | Debian 13 / CPython 3.13, Ubuntu 24.04 / CPython 3.12 and Mint 22.x / CPython 3.12, all amd64. Ubuntu 26.04, LMDE 7, other architectures and other distributions are outside this release's validated scope. | +| Signed APT updates | Actual update and managed-service lifecycle checks passed on Debian 13, Ubuntu 24.04 and Mint 22.3 VMs. This is not acceptance of every physical installation or every future package. | +| Release identity | The signed tag and release record identify released source and bytes. A source checkout, successful build or checksum alone does not establish an official signed release. | +| Source tests | Run `python3 tools/run_tests.py` from a source checkout. A test result applies to the source revision and environment actually tested; historical test counts are not current results. | +| Installed documentation | Read the guide matching the installed version. A newer repository README cannot update an older installed manual. Report contradictory release labels with the package version and file path. | + +## Operation results + +| Statement | Evidence and boundary | +| --- | --- | +| ChatGPT connection | Manual owner account consent; the model remains hosted while tools run on selected owner-controlled computers. Installing the package or assigning an account label does not prove connection. | +| Receiver and target | `LOCAL` denotes the current receiver. Another computer must be selected using a confirmed enrolled alias or ID. A legacy endpoint's default destination is not a routing guarantee for a replacement endpoint. | +| Query and task success | A successful status query or outer tool wrapper does not prove readiness or successful inner execution. Read the target, exit code and operation result, then verify the intended effect. | +| Persistent console | Bash continuity lasts while the session survives; it does not promise survival across reboot. Preserve the existing console and unrelated work unless changing them is authorized. | +| Independent FBEXEC tasks | Repeated maintainer experience with non-overlapping work; no certified isolation or guarantee that every command can run concurrently. | +| Graphical control | Requires a compatible active X11 session and observed capture/input success. Native Wayland control is not certified. One controller per shared desktop is an operating recommendation, not an automatic lock. | +| Real images and demonstrations | Use complete authentic captures. Identify virtual displays and terminal text separately. Conceptual animation is illustration, not evidence of execution. | | sudo | Actual privileges depend on the Unix account and normal authentication; an authorization flag does not grant root. | -| Real images and demo | Use complete authentic captures. A fresh Preview 2 real recording is pending; conceptual animation is illustration. | -| Dependency terms/source | Scoped technical terms review and exact source availability recorded with delivery conditions; component terms remain in force. | +| Recovery | Pause, stop, boot policy, revocation and removal have different effects. A package downgrade can revoke administrative helper grants; retaining a previous package is not proof of automatic rollback. | +| Dependency terms/source | Scoped technical terms review and exact source availability are recorded with delivery conditions; component terms and provenance limits remain in force. | + +Earlier RC7 and Community Preview results remain historical records. They must not be substituted for the build, signature, installation or acceptance evidence of a later artifact. The [operations roadmap](OPERATIONS-ROADMAP.md) distinguishes proposed work from delivered capabilities. ## Retained control components -The retained development broker defaults to its existing 127.0.0.1 peer only. Repeatable --control-peer IP_LITERAL arguments add explicit peers. Invalid entries fail before Store creation/binding; checks use the real client address, not proxy headers. Retained RPC UID, host, client/socket and administrator identity guards remain unchanged. Normal Expanded handling uses the generic terminal entrypoint; FRAMEBRIDGE_ENABLE_GERAMEG_CUA_TTY=0 is not an effective guard. +The retained development broker defaults to its existing 127.0.0.1 peer only. Repeatable `--control-peer IP_LITERAL` arguments add explicit peers. Invalid entries fail before Store creation/binding; checks use the real client address, not proxy headers. Retained RPC UID, host, client/socket and administrator identity guards remain unchanged. Normal Expanded handling uses the generic terminal entrypoint; `FRAMEBRIDGE_ENABLE_GERAMEG_CUA_TTY=0` is not an effective guard. -The classic lab-target map is empty, while the compatibility route remains available for explicit integrator configuration. Do not describe retained code as entirely inactive. Further executable edits require identifiable source and candidate-specific validation. +The classic lab-target map is empty, while the compatibility route remains available for explicit integrator configuration. Do not describe retained code as entirely inactive. Executable changes require an identifiable source revision and validation of the changed behavior. diff --git a/docs/COMMAND-REFERENCE.md b/docs/COMMAND-REFERENCE.md index b7b26a6..4c521cf 100644 --- a/docs/COMMAND-REFERENCE.md +++ b/docs/COMMAND-REFERENCE.md @@ -1,6 +1,6 @@ # FrameBridge — command guide -Version: 0.3.3 | Guide schema: 1 +Version: 0.3.4 | Guide schema: 1 This reference is generated from the shared CLI/MCP guide. Use the matching installed version. @@ -36,7 +36,6 @@ fb --json status Install the package built for your exact Debian 13, Ubuntu 24.04 or Linux Mint 22.x amd64 profile. These are the three release profiles; other distributions and architectures are outside this release. Keep the distribution system Python: 3.13 on Debian 13, 3.12 on Ubuntu 24.04 and Mint 22.x. Use the matching signed APT suite: trixie, noble or mint22. Normal first connection does not require a separate setup, doctor or start sequence. Run connect in a normal interactive terminal; advanced setup is optional for central/node roles and public settings. ~~~sh -sudo apt install ./framebridge-expanded_0.3.3_amd64.deb fb connect ~~~ @@ -80,6 +79,7 @@ fb status runtime fb status boot fb status console fb doctor +fb health fb setup fb console fb help @@ -231,7 +231,7 @@ fb nodes status ### Targets -LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. +LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Fleet results include requested_target, resolved_target, node_id, hostname and transport from the confirmed descriptor. The compatibility target field can remain LOCAL; resolved_target names the actual local computer. Unknown targets never fall back to LOCAL. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. ### Transport trust @@ -344,12 +344,21 @@ fb status boot ### Doctor -doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Candidate eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. Debian 13/LMDE 7 use cp313, Ubuntu 24.04/Mint 22.x use cp312, and Ubuntu 26.04 uses cp314. A matching profile does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. +doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. The published 0.3.3 scope is Debian 13 with cp313 and Ubuntu 24.04/Mint 22.x with cp312. LMDE 7 and Ubuntu 26.04 builder experiments remain outside that validated scope. A matching profile or a successful development build does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. ~~~sh fb doctor ~~~ +### Local health summary + +health combines this local profile's existing status and prerequisite observations into an allowlisted report. It identifies LOCAL as this computer and reports the profile, role, connection intent, local tools, boot policy and desktop availability. It never starts, repairs, connects, changes boot policy or creates an absent profile. It does not scan the fleet or probe terminal commands, screen capture or input. States are healthy, paused, degraded, unavailable and unconfigured. An intentional connection pause can be healthy; missing information cannot. JSON result.ok describes observation completeness; result.health.healthy describes health. Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. The CLI version is not proof of the running version. Detailed troubleshooting remains local in status and doctor. + +~~~sh +fb health +fb --json health +~~~ + ### Logs and progress Normal connection presents concise progress and a final result, then returns to the prompt. Detailed diagnostics belong in protected application logs. Share only the minimum relevant redacted result; never expose credentials, private keys, browser session data or unrelated personal paths. Avoid rerunning setup, enrollment or broad lifecycle tests merely because a view is confusing. diff --git a/docs/FRAMEBRIDGE-AGENT-START.md b/docs/FRAMEBRIDGE-AGENT-START.md index 72b5b0f..5ed8e7d 100644 --- a/docs/FRAMEBRIDGE-AGENT-START.md +++ b/docs/FRAMEBRIDGE-AGENT-START.md @@ -4,12 +4,14 @@ This is a setup and verification workflow for an assistant that **already has au The currently tested connection is the manual ChatGPT workflow. A coding assistant can help prepare it through the CLI; this document does not claim drop-in integration with every AI client. -Source preparation: **0.3.2, unsigned release candidate**, promoted from compatibility revision `0.3.2~compat.20261027.3` after its Debian 13, Ubuntu 24.04 and Mint 22.3 VM checks passed. Check the exact artifact release record before installation; this prior behavior evidence does not verify the final package bytes or claim public availability. +Latest signed release: **0.3.3**, published for Debian 13, Ubuntu 24.04 and Linux Mint 22.x on amd64. Use the exact profile, signatures and source record from the [official download page](https://framebridge.betancourt.one/download/). A later source checkout can contain unreleased changes; it is not evidence that a new package has been built, signed or published. Historical compatibility-candidate checks remain separate from validation of the actual release artifacts. ## Before handing over Give the assistant the computer you want to work on, the intended task, and the local path of the reviewed matching package. Use the [README's package matrix](../README.md#1-install-the-matching-package). If this is a pilot beside an existing installation, identify a new isolated `--state-dir` and the existing services that must remain running. +Name both the computer receiving the assistant's tool call and the intended execution target. `LOCAL` means the current FrameBridge receiver, not a fixed computer called ASUS or the computer displaying the chat. Discover enrolled nodes and use their confirmed aliases or IDs. A legacy connector can have a different default target; changing endpoints does not preserve that default automatically. + Do not put passwords, tunnel IDs, server access keys or browser codes in the prompt. The owner will enter them in the local hidden prompts. An MCP server access key is not an OpenAI API key. ## Copy this into your assistant @@ -20,12 +22,16 @@ Help me install and verify FrameBridge on this Linux computer. Target computer: [the computer to which you already have authorized shell access] Reviewed package: [absolute local path to the matching FrameBridge .deb] Scope: [new installation, or the specifically authorized pilot/profile] +Receiver and execution target: [identify both; do not assume LOCAL means ASUS] First establish where you are running. Inspect the distribution/version, architecture and system Python. Match them to the package's release profile. Read the project's README and the installed versioned help where available. Reuse FrameBridge's existing CLI and package; do not invent a replacement transport or rewrite the application to complete setup. +Confirm the receiver and selected target before the first remote operation. +Use an enrolled alias or ID for another computer and inspect the effective +target in the response. Do not fall back to a different computer on error. Use my existing task authorization. Complete the authorized preparatory work before asking for information or a decision that is actually missing. @@ -70,6 +76,8 @@ If desktop access is in scope, first identify the actual X11 session and use a new test window. A virtual display must be described as virtual. Terminal text is not a screen capture, and a VM's desktop is not the owner's physical display. Do not claim a screenshot or successful input unless it was observed. +Coordinate one controller at a time for a shared desktop. Preserve existing +console windows and their work unless changing them is part of the task. Check actual command exit codes and operation results. An outer tool wrapper's success flag is not proof that its inner command succeeded. Distinguish local diff --git a/docs/OPERATIONS-ROADMAP.md b/docs/OPERATIONS-ROADMAP.md new file mode 100644 index 0000000..16892f7 --- /dev/null +++ b/docs/OPERATIONS-ROADMAP.md @@ -0,0 +1,29 @@ +# Small Linux fleet operations: development scope + +This document records proposed follow-up work after the signed 0.3.3 release. It is not a feature-availability statement, a release announcement or a promise of unattended administration. The initial scope remains owner-controlled Debian 13, Ubuntu 24.04 and Mint 22.x amd64 computers administered by one responsible person. + +The `0.3.4` release source implements an initial **local-only** `health` summary and additive confirmed destination identity in Fleet results. It also consolidates the installed documentation, permits secure administrator-owned ancestors of the user's service directory and reduces durable idle status writes. These changes do not complete the wider acceptance items below. See [release notes](RELEASE-NOTES-0.3.4.md). + +## Acceptance order + +| Priority | Intended improvement | Acceptance evidence required | +| --- | --- | --- | +| 1 | Coherent installation and diagnosis | The package, CLI, MCP guide and website agree on version and supported profiles. An administrator outside the project completes installation, connection and a first harmless query using the documentation; record time and assistance needed. | +| 2 | Unambiguous execution destination | Show receiver and effective target separately. An explicit target never falls back to another machine. Cover unknown and duplicate names and differences from legacy defaults. | +| 3 | Unified read-only health | Reuse existing status, doctor and inventory tools. Report observation time, source and unavailable/error states. Distinguish disk capacity from free space, package presence from readiness and screenshot availability from input control. | +| 4 | Five versioned procedures | Begin with general diagnosis, a failed service, DNS diagnosis, APT diagnosis and a FrameBridge update. Record prerequisites, exact procedure version, proposed change, applicable authorization, post-check and a recovery route where supported. Read-only checks must not repair implicitly. | +| 5 | Jobs and technical history | A later conversation can identify the target, operation, result and remaining work without reconstructing the entire chat. Test disconnect/reconnect behavior and duplicate submissions. Export useful records without secrets. | +| 6 | Small external pilot | Use a separate installation per customer initially. Record installation effort, incidents, completed tasks, support time and willingness to renew before extending the platform. | + +## Preserve the current operating model + +- Keep `fb` / `framebridge` as the shared interface for the administrator and authorized agents. +- Retain the indicative console and existing work. A health view complements it. +- Use terminal and command tools for routine administration, with graphical CUA available for tasks that need a real desktop. Describe actual session and display limits. +- Keep normal OS/browser authentication in the owner's normal interface. Reuse task authorization; do not add repetitive approvals to harmless observations. +- Retain explicit connection intent and boot policy. An update must not start a profile that was intentionally stopped. +- Treat transport as a component. Another MCP client or platform is supported only after a documented interoperability test. + +## Deferred expansion + +Shared multi-customer hosting, broad Windows/macOS/DSM support, native Wayland control, a new tunnel/VPN and an autonomous always-on technician are separate projects. They need their own requirements and acceptance evidence. The initial commercial experiment is a scoped installation and maintenance service, not a claim that FrameBridge already supplies a full enterprise RMM platform. diff --git a/docs/RELEASE-NOTES-0.3.4-dev.md b/docs/RELEASE-NOTES-0.3.4-dev.md new file mode 100644 index 0000000..8c96980 --- /dev/null +++ b/docs/RELEASE-NOTES-0.3.4-dev.md @@ -0,0 +1,34 @@ +# Historical FrameBridge 0.3.4 development notes + +This record describes the earlier private I/O candidate. The final 0.3.4 source and current scope are documented in [the release notes](RELEASE-NOTES-0.3.4.md). + +Version: `0.3.4~dev.20261029.3`. + +This is a development candidate following the signed 0.3.3 release. It does not replace the signed tag, public downloads or stable APT channels. Build success is not installation, reboot, independent-user or multi-customer acceptance. + +This I/O candidate is based on `0.3.4~dev.20261029.1`. The separate `.2` node-initialization experiment is not included. + +## Changes + +- `fb health` and `fb --json health` combine existing local status and prerequisite observations. The report names the receiving computer and profile, separates query success from health and connection intent, and leaves unknown values unknown. It does not create an absent profile, start a service, repair configuration or probe terminal/desktop control. +- Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. JSON `result.ok` describes observation completeness; `result.health.healthy` describes health. A requested pause is not healthy when the observed tunnel still runs. +- Fleet read, EXEC, screen and CUA results include `requested_target`, `resolved_target`, `node_id`, `hostname` and `transport` from the confirmed route. Existing `target` semantics remain compatible. Upstream result fields cannot replace the confirmed identity. Errors after resolution retain that identity; unresolved targets never acquire an invented local identity. +- Installed documentation is assembled from the reviewed current source, including the corrected signed 0.3.3 publication record, support scope, first-connection instructions and canonical homepage. Shared CLI/MCP/manpage references are regenerated for this development version. +- Managed connection setup accepts administrator-owned `.config` and `.config/systemd` ancestors when they are directories without group/other write permission. The final `systemd/user` directory must still belong to the connecting user. Symbolic links, other-account ownership and unsafe permissions are rejected. Setup does not change existing directory ownership or permissions. +- Managed-worker state is persisted on transitions instead of repeatedly syncing the same state while idle. Connection liveness heartbeats use the account's validated `/run/user/` runtime directory when available; profiles without it retain a bounded durable fallback. Status still requires a fresh heartbeat bound to the same worker identity. Existing permissions and credentials are unchanged. These changes do not claim that all application or system disk activity stops. + +## Native startup and the GERANAS deployment gap + +Normal `fb connect` already installs the managed user service, protects the connection credential, enables startup without an interactive login and records connection intent. Installation of a package without connection setup cannot establish a new authenticated tunnel. APT preserves a manual profile's existing policy rather than silently enabling it. + +The affected GERANAS deployment had been left as a manually started central profile without the native managed connection setup. External recovery services did not complete that setup and did not share the CLI's lifecycle controls. This candidate fixes the service-account directory compatibility issue needed for native setup; it does not add another external startup mechanism or fabricate managed installation records. + +Source tests and package builds do not prove reconnection after a reboot. Acceptance must separately record a real changed boot ID, native service startup, connection availability and execution through the intended route. No reboot acceptance is claimed by these release notes. + +## Scope + +The three build profiles remain Debian 13 amd64/cp313, Ubuntu 24.04 amd64/cp312 and Linux Mint 22.x amd64/cp312. The new health command observes one selected **local profile**, not the fleet. Invoke it on the intended host and pass `--state-dir` when using a nondefault profile. Runtime readiness and capability availability are not fresh proofs that a command, screenshot or input operation succeeded. + +The existing indicative console, connection intent, boot policy, user profiles, privileged-helper lifecycle and authentication workflow are preserved. Normal browser and operating-system authentication stay in the owner's normal interface. No new enrollment, transport, GUI or recurring approval mechanism is introduced. + +The next product acceptance items are documented in [the operations roadmap](OPERATIONS-ROADMAP.md). Versioned repair workflows, a multi-host health dashboard, customer isolation and other MCP clients remain proposed work until separately implemented and tested. diff --git a/docs/RELEASE-NOTES-0.3.4.md b/docs/RELEASE-NOTES-0.3.4.md new file mode 100644 index 0000000..8d6f9d4 --- /dev/null +++ b/docs/RELEASE-NOTES-0.3.4.md @@ -0,0 +1,29 @@ +# FrameBridge 0.3.4 + +Release profiles: Debian 13 amd64/Python 3.13, Ubuntu 24.04 amd64/Python 3.12 and Linux Mint 22.x amd64/Python 3.12. + +## Network administration and observation + +- `fb health` and `fb --json health` summarize the selected local profile without starting, repairing or connecting it. Query completeness, health, connection intent and unknown observations remain distinct. +- Fleet command, terminal, screen and CUA results identify the confirmed receiving computer, node and transport. Result fields cannot replace the destination identity established by routing. +- Transient broker failures recover with bounded backoff and fresh signed nonces. Acknowledgement retries retain the computed result and do not reexecute commands. Authentication, TLS and malformed-response failures remain terminal. + +## Persistent startup and idle writes + +- Native managed startup accepts secure administrator-owned service-directory ancestors without changing their ownership or permissions. The final user-service directory remains private to its account. +- Node startup avoids redundant privileged setup when the required account settings already exist. Existing credential grants still follow the privileged cleanup lifecycle. +- The managed supervisor persists worker-state transitions instead of repeatedly syncing identical state. Connection heartbeats use the validated account runtime directory when available, with the same process identity and 15-second freshness checks. A bounded durable fallback remains for environments without a user runtime directory. +- APT upgrades preserve profiles and existing startup policy. Normal connection setup provisions the native managed service; installing a package alone cannot establish an authenticated ChatGPT connection. + +## Console, compatibility and delivery + +- The indicative console and persistent terminal remain available. Real-screen capture, terminal transcripts and explicitly selected virtual displays are identified separately. +- The same English command guide serves the CLI, MCP help, installed manual and tutorial. Other distributions, Wayland and CPU architectures are outside this release's validated scope. +- One corresponding-source archive includes the reviewed cp313 and cp312 vendor inputs for all three packages. Public-release assembly requires its matching manifest and checks the archive, current source and selected vendor hashes. +- Original material remains GPL-3.0-only. Preserve both immutable dependency-source assets, third-party notices and stated provenance limits. No new independent native-wheel or tunnel-client rebuild is claimed. + +## Validation and release identity + +Artifact hashes, signatures, signed APT metadata and actual distribution lifecycle results belong to the accompanying release record. Build assembly does not assert that those external checks passed or that a download has been published. Retain the source archive and its sidecar manifest together when rebuilding official release profiles. + +Programming: ChatGPT. Original concept and project coordination: Gerardo Betancourt. diff --git a/docs/THIRD-PARTY-RELEASE-REVIEW.md b/docs/THIRD-PARTY-RELEASE-REVIEW.md index 8e8c236..1949e93 100644 --- a/docs/THIRD-PARTY-RELEASE-REVIEW.md +++ b/docs/THIRD-PARTY-RELEASE-REVIEW.md @@ -1,4 +1,4 @@ -# Third-party terms and source delivery — FrameBridge 0.3.1 +# Third-party terms and source delivery — FrameBridge 0.3.4 This scoped release record combines the retained Python/Rust review with the 0.3.1 OpenAI tunnel-client notice supplement. It does not relabel incorporated components as FrameBridge-owned GPL material. @@ -20,7 +20,7 @@ The executable's own module is marked (devel) and has no embedded VCS revision. ## Delivery conditions and limits -Provide FrameBridge-0.3.1.deb, its exact corresponding FrameBridge source archive, both dependency-source assets, R2 supplement and retained notices through actual working download paths. Verify file hashes at staging and public delivery. Private collection or a future URL is not public availability. +Provide all three FrameBridge 0.3.4 distribution-profile packages, their exact corresponding FrameBridge-0.3.4-source.tar.gz and SOURCE-ARCHIVE-MANIFEST.json, both dependency-source assets, R2 supplement and retained notices through actual working download paths. Verify file hashes at staging and public delivery. Private collection or a future URL is not public availability. The unchanged Certifi arrangement retains its exact source assets, original notice, full MPL-2.0 text and recipient access instructions. The original historical Mozilla certdata revision remains unidentified. No independent native-wheel rebuild is claimed. These provenance/reproducibility limits remain explicit. diff --git a/licensing/SOURCE-LICENSE-SCOPE.json b/licensing/SOURCE-LICENSE-SCOPE.json index a3f3663..d537440 100644 --- a/licensing/SOURCE-LICENSE-SCOPE.json +++ b/licensing/SOURCE-LICENSE-SCOPE.json @@ -1,5 +1,6 @@ { "schema_version": 4, + "historical_snapshot_notice": "This classification snapshot retains its original counts, hashes and version. The matching release SOURCE-ARCHIVE-MANIFEST.json identifies the complete current source set; historical path classifications do not prove ownership.", "project_license": "GPL-3.0-only", "basis": "Owner decision for original FrameBridge material the rightsholders are entitled to license.", "scope_notice": "../LICENSING.md", diff --git a/licensing/third-party/SOURCE-AVAILABILITY.md b/licensing/third-party/SOURCE-AVAILABILITY.md index 0db7213..edf938e 100644 --- a/licensing/third-party/SOURCE-AVAILABILITY.md +++ b/licensing/third-party/SOURCE-AVAILABILITY.md @@ -1,9 +1,9 @@ -# Sources accompanying FrameBridge 0.3.1 +# Sources accompanying FrameBridge 0.3.4 The matching release set is intended to be delivered together through the project download area. This record identifies the required assets; it does not assert that external access has already been opened. -- FrameBridge-0.3.1.deb, Debian version 0.3.1. -- FrameBridge-0.3.1-source.tar.gz: the corresponding FrameBridge implementation, build scripts, tests and legal records. +- FrameBridge-0.3.4-debian13-amd64-py313.deb, FrameBridge-0.3.4-ubuntu24.04-amd64-py312.deb and FrameBridge-0.3.4-mint22-amd64-py312.deb; Debian package version 0.3.4. +- FrameBridge-0.3.4-source.tar.gz and its matching SOURCE-ARCHIVE-MANIFEST.json: the corresponding FrameBridge implementation, reviewed cp313 and cp312 vendor inputs, build scripts, tests and legal records. - FrameBridge-0.3.1-Community-Preview1-dependency-sources.tar.gz: immutable shared Python/Rust dependency source asset, 82,606,998 bytes, SHA-256 64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a. The historical filename is deliberately retained; verify bytes rather than inferring the current project version from that name. - FrameBridge-0.3.1-tunnel-client-dependency-sources.tar.gz: exact source module archives for the 47 Go dependencies embedded in the retained OpenAI tunnel executable, plus retained notices and provenance records. Its release hash is recorded in the adjacent release checksum manifest and TUNNEL-DEPENDENCY-SOURCES.json. diff --git a/source/docs/COMMAND-GUIDE.json b/source/docs/COMMAND-GUIDE.json index 178c94f..3d5cbd8 100644 --- a/source/docs/COMMAND-GUIDE.json +++ b/source/docs/COMMAND-GUIDE.json @@ -1,12 +1,12 @@ { "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topics": { "start": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "start", "title": "Start with FrameBridge", @@ -24,7 +24,6 @@ "heading": "Install and connect", "body": "Install the package built for your exact Debian 13, Ubuntu 24.04 or Linux Mint 22.x amd64 profile. These are the three release profiles; other distributions and architectures are outside this release. Keep the distribution system Python: 3.13 on Debian 13, 3.12 on Ubuntu 24.04 and Mint 22.x. Use the matching signed APT suite: trixie, noble or mint22. Normal first connection does not require a separate setup, doctor or start sequence. Run connect in a normal interactive terminal; advanced setup is optional for central/node roles and public settings.", "commands": [ - "sudo apt install ./framebridge-expanded_0.3.3_amd64.deb", "fb connect" ] }, @@ -64,12 +63,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "23abd7eec3efb77ca160c97fec9b8bacc7040419946e75584ed563a509577a57" + "guide_sha256": "e2e7a61e9ba53021c155f3fc4d8ffad95ffbdb6e5ac253b171b6ce21a5dd42b4" }, "commands": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "commands", "title": "Command reference", @@ -86,6 +85,7 @@ "fb status boot", "fb status console", "fb doctor", + "fb health", "fb setup", "fb console", "fb help" @@ -136,12 +136,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "432ab37e7249793cbe72e42d27582d70c2d2c1394ac1f5418b5d3e211e6a7c06" + "guide_sha256": "d218df5cdc9e9053f461e4a3807e5e9fa45b6194e4b45bf05b6fc2e6258d5d0d" }, "connection": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "connection", "title": "Connect and disconnect ChatGPT", @@ -190,12 +190,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "c41d5c436a7039cfacd9cde4933e24c9f7d6235d43e2e9f4fe106f1a4c631764" + "guide_sha256": "418bad3914a250d4c734e0d0a60fcbfcd7e52cd6c5d4dfacc9da236cc4d45e53" }, "lifecycle": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "lifecycle", "title": "Services, connection intent and boot policy", @@ -256,12 +256,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "084358c9d1d41e0639b49d01c7e40b613127e3ead77e156cc2624850c7ebdb16" + "guide_sha256": "943322bb685d2dd37fd306bff8b6aed6c85fb54f95af95b986c3448a45dd96b7" }, "nodes": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "nodes", "title": "Central and node operation", @@ -285,7 +285,7 @@ }, { "heading": "Targets", - "body": "LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination.", + "body": "LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Fleet results include requested_target, resolved_target, node_id, hostname and transport from the confirmed descriptor. The compatibility target field can remain LOCAL; resolved_target names the actual local computer. Unknown targets never fall back to LOCAL. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination.", "commands": [] }, { @@ -310,12 +310,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "ec2adb6ba2cb36e3747bcb4975a6b777ad88d4fe2b9b1cfb1a2f6ec1e8dab43a" + "guide_sha256": "79f6875d2d2486557092cbc5e5a4888f8661f00eddb13d93437737893eb343a5" }, "terminals": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "terminals", "title": "Persistent Bash terminals", @@ -376,12 +376,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "0aba231493d9ecae071ecdf5197440e0714393364948079fc4d163ff70cc67e3" + "guide_sha256": "41e9e1c93bb6c8cc2d84c55d33d70d71693ddf835b5d4c199810db59af932139" }, "screens": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "screens", "title": "Authentic screen observation and input", @@ -431,12 +431,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "eeaf9cfed9e7a84d59a727c4388b0869b02a6ed870647e87b333d318a3584c9a" + "guide_sha256": "506c7fcba592ccc473774a809871871285a199e8a8f72b9e230eb23481fd8a85" }, "diagnostics": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "diagnostics", "title": "Status and diagnosis", @@ -453,11 +453,19 @@ }, { "heading": "Doctor", - "body": "doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Candidate eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. Debian 13/LMDE 7 use cp313, Ubuntu 24.04/Mint 22.x use cp312, and Ubuntu 26.04 uses cp314. A matching profile does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies.", + "body": "doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. The published 0.3.3 scope is Debian 13 with cp313 and Ubuntu 24.04/Mint 22.x with cp312. LMDE 7 and Ubuntu 26.04 builder experiments remain outside that validated scope. A matching profile or a successful development build does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies.", "commands": [ "fb doctor" ] }, + { + "heading": "Local health summary", + "body": "health combines this local profile's existing status and prerequisite observations into an allowlisted report. It identifies LOCAL as this computer and reports the profile, role, connection intent, local tools, boot policy and desktop availability. It never starts, repairs, connects, changes boot policy or creates an absent profile. It does not scan the fleet or probe terminal commands, screen capture or input. States are healthy, paused, degraded, unavailable and unconfigured. An intentional connection pause can be healthy; missing information cannot. JSON result.ok describes observation completeness; result.health.healthy describes health. Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. The CLI version is not proof of the running version. Detailed troubleshooting remains local in status and doctor.", + "commands": [ + "fb health", + "fb --json health" + ] + }, { "heading": "Logs and progress", "body": "Normal connection presents concise progress and a final result, then returns to the prompt. Detailed diagnostics belong in protected application logs. Share only the minimum relevant redacted result; never expose credentials, private keys, browser session data or unrelated personal paths. Avoid rerunning setup, enrollment or broad lifecycle tests merely because a view is confusing.", @@ -481,12 +489,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "77a65897aacfeaa2b06dd184ac78d366d28980847b0cbdd1429c889e0e2898a6" + "guide_sha256": "6f91c71b82e945767d98f113ae1b958f2222939bf94c0657d1ada047b43d6932" }, "security": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "security", "title": "Authorization, distribution and safe operation", @@ -521,12 +529,12 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "f257fcbbdec39395a15655b0a5123fb385ce7eaba2a256de07a5da65eab3ec8e" + "guide_sha256": "0b7c6e55958911306a71f0d0ea5a504df7b1447967b424b5e8a03b4b53275211" }, "compatibility": { "ok": true, "product": "FrameBridge", - "version": "0.3.3", + "version": "0.3.4", "guide_schema": 1, "topic": "compatibility", "title": "Compatibility with earlier commands", @@ -569,8 +577,8 @@ ], "read_only": true, "capabilities_verified": false, - "guide_sha256": "9056f77b27f326bebfdbb54dd10b748d6315797b07afe1aee29f42d6210dae36" + "guide_sha256": "970ed8c5f509e78adc6fd9d99fd14a3edc93fc597184e9de54723763d7807544" } }, - "guide_sha256": "5dc6ed2744e53d7d2ce1f471e2ab94d50f9c52f83ae85abe495bacad34b1b96c" + "guide_sha256": "aecf94c39b17d53be24aecd67089ed5cfa52e3b0499e6a615b3a4e04cfb6e319" } diff --git a/source/docs/COMMAND-REFERENCE.md b/source/docs/COMMAND-REFERENCE.md index b7b26a6..4c521cf 100644 --- a/source/docs/COMMAND-REFERENCE.md +++ b/source/docs/COMMAND-REFERENCE.md @@ -1,6 +1,6 @@ # FrameBridge — command guide -Version: 0.3.3 | Guide schema: 1 +Version: 0.3.4 | Guide schema: 1 This reference is generated from the shared CLI/MCP guide. Use the matching installed version. @@ -36,7 +36,6 @@ fb --json status Install the package built for your exact Debian 13, Ubuntu 24.04 or Linux Mint 22.x amd64 profile. These are the three release profiles; other distributions and architectures are outside this release. Keep the distribution system Python: 3.13 on Debian 13, 3.12 on Ubuntu 24.04 and Mint 22.x. Use the matching signed APT suite: trixie, noble or mint22. Normal first connection does not require a separate setup, doctor or start sequence. Run connect in a normal interactive terminal; advanced setup is optional for central/node roles and public settings. ~~~sh -sudo apt install ./framebridge-expanded_0.3.3_amd64.deb fb connect ~~~ @@ -80,6 +79,7 @@ fb status runtime fb status boot fb status console fb doctor +fb health fb setup fb console fb help @@ -231,7 +231,7 @@ fb nodes status ### Targets -LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. +LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Fleet results include requested_target, resolved_target, node_id, hostname and transport from the confirmed descriptor. The compatibility target field can remain LOCAL; resolved_target names the actual local computer. Unknown targets never fall back to LOCAL. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. ### Transport trust @@ -344,12 +344,21 @@ fb status boot ### Doctor -doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Candidate eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. Debian 13/LMDE 7 use cp313, Ubuntu 24.04/Mint 22.x use cp312, and Ubuntu 26.04 uses cp314. A matching profile does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. +doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. The published 0.3.3 scope is Debian 13 with cp313 and Ubuntu 24.04/Mint 22.x with cp312. LMDE 7 and Ubuntu 26.04 builder experiments remain outside that validated scope. A matching profile or a successful development build does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. ~~~sh fb doctor ~~~ +### Local health summary + +health combines this local profile's existing status and prerequisite observations into an allowlisted report. It identifies LOCAL as this computer and reports the profile, role, connection intent, local tools, boot policy and desktop availability. It never starts, repairs, connects, changes boot policy or creates an absent profile. It does not scan the fleet or probe terminal commands, screen capture or input. States are healthy, paused, degraded, unavailable and unconfigured. An intentional connection pause can be healthy; missing information cannot. JSON result.ok describes observation completeness; result.health.healthy describes health. Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. The CLI version is not proof of the running version. Detailed troubleshooting remains local in status and doctor. + +~~~sh +fb health +fb --json health +~~~ + ### Logs and progress Normal connection presents concise progress and a final result, then returns to the prompt. Detailed diagnostics belong in protected application logs. Share only the minimum relevant redacted result; never expose credentials, private keys, browser session data or unrelated personal paths. Avoid rerunning setup, enrollment or broad lifecycle tests merely because a view is confusing. diff --git a/source/docs/DEBIAN-TUTORIAL.md b/source/docs/DEBIAN-TUTORIAL.md index f6c0f9d..8d1c998 100644 --- a/source/docs/DEBIAN-TUTORIAL.md +++ b/source/docs/DEBIAN-TUTORIAL.md @@ -1,6 +1,6 @@ # FrameBridge — Debian, Ubuntu and Linux Mint installation and first use -Version: 0.3.3 | Guide schema: 1 +Version: 0.3.4 | Guide schema: 1 This reference is generated from the shared CLI/MCP guide. Use the matching installed version. @@ -36,7 +36,6 @@ fb --json status Install the package built for your exact Debian 13, Ubuntu 24.04 or Linux Mint 22.x amd64 profile. These are the three release profiles; other distributions and architectures are outside this release. Keep the distribution system Python: 3.13 on Debian 13, 3.12 on Ubuntu 24.04 and Mint 22.x. Use the matching signed APT suite: trixie, noble or mint22. Normal first connection does not require a separate setup, doctor or start sequence. Run connect in a normal interactive terminal; advanced setup is optional for central/node roles and public settings. ~~~sh -sudo apt install ./framebridge-expanded_0.3.3_amd64.deb fb connect ~~~ @@ -80,6 +79,7 @@ fb status runtime fb status boot fb status console fb doctor +fb health fb setup fb console fb help @@ -231,7 +231,7 @@ fb nodes status ### Targets -LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. +LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Fleet results include requested_target, resolved_target, node_id, hostname and transport from the confirmed descriptor. The compatibility target field can remain LOCAL; resolved_target names the actual local computer. Unknown targets never fall back to LOCAL. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty --node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. ### Transport trust @@ -344,12 +344,21 @@ fb status boot ### Doctor -doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Candidate eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. Debian 13/LMDE 7 use cp313, Ubuntu 24.04/Mint 22.x use cp312, and Ubuntu 26.04 uses cp314. A matching profile does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. +doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. The published 0.3.3 scope is Debian 13 with cp313 and Ubuntu 24.04/Mint 22.x with cp312. LMDE 7 and Ubuntu 26.04 builder experiments remain outside that validated scope. A matching profile or a successful development build does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. ~~~sh fb doctor ~~~ +### Local health summary + +health combines this local profile's existing status and prerequisite observations into an allowlisted report. It identifies LOCAL as this computer and reports the profile, role, connection intent, local tools, boot policy and desktop availability. It never starts, repairs, connects, changes boot policy or creates an absent profile. It does not scan the fleet or probe terminal commands, screen capture or input. States are healthy, paused, degraded, unavailable and unconfigured. An intentional connection pause can be healthy; missing information cannot. JSON result.ok describes observation completeness; result.health.healthy describes health. Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. The CLI version is not proof of the running version. Detailed troubleshooting remains local in status and doctor. + +~~~sh +fb health +fb --json health +~~~ + ### Logs and progress Normal connection presents concise progress and a final result, then returns to the prompt. Detailed diagnostics belong in protected application logs. Share only the minimum relevant redacted result; never expose credentials, private keys, browser session data or unrelated personal paths. Avoid rerunning setup, enrollment or broad lifecycle tests merely because a view is confusing. diff --git a/source/docs/framebridge.1 b/source/docs/framebridge.1 index 0b50fca..b39b29f 100644 --- a/source/docs/framebridge.1 +++ b/source/docs/framebridge.1 @@ -1,4 +1,4 @@ -.TH FRAMEBRIDGE 1 "2026-10-28" "FrameBridge 0.3.3" "User Commands" +.TH FRAMEBRIDGE 1 "2026-10-29" "FrameBridge 0.3.4" "User Commands" .SH NAME framebridge, fb \- use local Linux tools and enrolled nodes with ChatGPT .SH SYNOPSIS @@ -21,7 +21,6 @@ fb \-\-json status Install the package built for your exact Debian 13, Ubuntu 24.04 or Linux Mint 22.x amd64 profile. These are the three release profiles; other distributions and architectures are outside this release. Keep the distribution system Python: 3.13 on Debian 13, 3.12 on Ubuntu 24.04 and Mint 22.x. Use the matching signed APT suite: trixie, noble or mint22. Normal first connection does not require a separate setup, doctor or start sequence. Run connect in a normal interactive terminal; advanced setup is optional for central/node roles and public settings. .PP .nf -sudo apt install ./framebridge\-expanded_0.3.3_amd64.deb fb connect .fi .SS Updating and removal @@ -53,6 +52,7 @@ fb status runtime fb status boot fb status console fb doctor +fb health fb setup fb console fb help @@ -162,7 +162,7 @@ fb nodes pending fb nodes status .fi .SS Targets -LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty \-\-node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. +LOCAL means the actual receiving machine. Use enrolled, confirmed aliases or IDs and inspect the selected target before work. Fleet results include requested_target, resolved_target, node_id, hostname and transport from the confirmed descriptor. The compatibility target field can remain LOCAL; resolved_target names the actual local computer. Unknown targets never fall back to LOCAL. Do not guess SSH identities or use historical lab hostnames as defaults. CLI tty \-\-node can use the authenticated node transport. The interactive console command is local; run it at the destination or use an explicitly configured SSH destination. .SS Transport trust certificates create manages a private central/node transport CA, not a public website certificate or ChatGPT account authentication. Private keys stay protected on the central host; distribute only the required public trust material. Off\-loopback broker use requires correctly configured verified TLS. Do not recreate trust merely to work around a connection symptom. .PP @@ -237,11 +237,18 @@ fb status runtime fb status boot .fi .SS Doctor -doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Candidate eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. Debian 13/LMDE 7 use cp313, Ubuntu 24.04/Mint 22.x use cp312, and Ubuntu 26.04 uses cp314. A matching profile does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. +doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. The published 0.3.3 scope is Debian 13 with cp313 and Ubuntu 24.04/Mint 22.x with cp312. LMDE 7 and Ubuntu 26.04 builder experiments remain outside that validated scope. A matching profile or a successful development build does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies. .PP .nf fb doctor .fi +.SS Local health summary +health combines this local profile's existing status and prerequisite observations into an allowlisted report. It identifies LOCAL as this computer and reports the profile, role, connection intent, local tools, boot policy and desktop availability. It never starts, repairs, connects, changes boot policy or creates an absent profile. It does not scan the fleet or probe terminal commands, screen capture or input. States are healthy, paused, degraded, unavailable and unconfigured. An intentional connection pause can be healthy; missing information cannot. JSON result.ok describes observation completeness; result.health.healthy describes health. Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. The CLI version is not proof of the running version. Detailed troubleshooting remains local in status and doctor. +.PP +.nf +fb health +fb \-\-json health +.fi .SS Logs and progress Normal connection presents concise progress and a final result, then returns to the prompt. Detailed diagnostics belong in protected application logs. Share only the minimum relevant redacted result; never expose credentials, private keys, browser session data or unrelated personal paths. Avoid rerunning setup, enrollment or broad lifecycle tests merely because a view is confusing. .PP diff --git a/source/expanded/framebridge_expanded/__init__.py b/source/expanded/framebridge_expanded/__init__.py index e19434e..334b899 100644 --- a/source/expanded/framebridge_expanded/__init__.py +++ b/source/expanded/framebridge_expanded/__init__.py @@ -1 +1 @@ -__version__ = "0.3.3" +__version__ = "0.3.4" diff --git a/source/expanded/framebridge_expanded/autostart.py b/source/expanded/framebridge_expanded/autostart.py index add27b0..a5eed99 100644 --- a/source/expanded/framebridge_expanded/autostart.py +++ b/source/expanded/framebridge_expanded/autostart.py @@ -132,6 +132,39 @@ def _prune_helpers(state, keep=()): _command(["sudo", "-n", "--", str(HELPER), "prune", _profile_id(state), ",".join(values) or "-"]) +def _node_helper_cleanup_required(state): + """Only omit privileged cleanup when no managed grant can authorize it. + + The encrypted registry is deliberately private to root. Its orphaned + ciphertext does not grant access without a matching sudo policy. Inspect + only policy names in the secured, root-owned policy directory; never read + rule contents or treat a failed/incomplete inspection as an empty registry. + """ + from .credential_helper import SUDOERS, _root_path + _helper_ready() + uid, profile = str(os.getuid()), _profile_id(state) + prefixes = ("framebridge-credential-" + uid + "-" + profile + "-", + "framebridge-credential-authorize-" + uid + "-" + profile + "-") + patterns = (re.escape(prefixes[0]) + r"[0-9a-f]{64}", + re.escape(prefixes[1]) + r"(?:host|user)") + try: + directory = _root_path(SUDOERS, directory=True) + names = [path.name for path in directory.iterdir()] + except (OSError, RuntimeError): + return True + cleanup_required = False + for name in names: + if any(re.fullmatch(pattern, name) for pattern in patterns): + cleanup_required = True + continue + # A malformed entry in this exact owner's/profile's managed namespace + # is ambiguous. The helper's normal cleanup does not recognize every + # malformed authorization name, so require explicit review instead. + if name.startswith(prefixes): + raise RuntimeError("An ambiguous managed credential policy needs administrator review before node startup can be configured.") + return cleanup_required + + @contextmanager def _credential_transaction(state, encrypted, backend): transaction = {"committed": False} @@ -270,10 +303,17 @@ def _check_unit_directory(path): for directory in [Path.home() / ".config", Path.home() / ".config/systemd", path.parent]: if directory.is_symlink(): raise RuntimeError("User service directories must not be symbolic links.") - directory.mkdir(mode=0o700, exist_ok=True) - info = directory.stat() - if info.st_uid != os.getuid() or info.st_mode & 0o022: - raise RuntimeError("User service directories must be owned by this user and not writable by others.") + try: + directory.mkdir(mode=0o700, exist_ok=True) + except PermissionError: + raise RuntimeError("This account cannot create its user service directory; existing ownership and permissions were left unchanged.") from None + info = directory.lstat() + # Service accounts can have administrator-owned .config ancestors. + # Those ancestors are safe when immutable to other accounts; the + # directory containing the unit must still belong to this owner. + allowed_owner = info.st_uid == os.getuid() or (directory != path.parent and info.st_uid == 0) + if not stat.S_ISDIR(info.st_mode) or not allowed_owner or info.st_mode & 0o022: + raise RuntimeError("User service directories must have a safe owner and not be writable by others; the final directory must belong to this user.") def _manifest(directory): @@ -653,9 +693,15 @@ def _enable(state, *, start_now=True, confirm=True): _check_unit_directory(unit) if unit.exists() or unit.is_symlink() or (directory / "credential.cred").exists() or (directory / "credential.cred").is_symlink(): raise RuntimeError("Existing unowned service or encrypted credential; nothing was replaced.") - _command(["sudo", "-v"], timeout=180) user = pwd.getpwuid(os.getuid()).pw_name linger_before = _linger(user) + helper_cleanup_required = (node and _helper_present() and + (not linger_before or _node_helper_cleanup_required(state))) + # An administrator may already have enabled this node owner's user + # services at boot. Installing its own unit then needs no new privilege. + # Central profiles still authenticate before protecting connection input. + if not node or not linger_before or helper_cleanup_required: + _command(["sudo", "-v"], timeout=180) units_before = _enabled_units() encrypted = b"" print("[2/3] Preparing this node..." if node else "[2/3] Protecting the connection key...", flush=True) @@ -672,7 +718,7 @@ def _enable(state, *, start_now=True, confirm=True): runtime_key = "" if len(encrypted) < 80 or len(encrypted) > 131072: raise RuntimeError("Credential encryption returned an invalid result.") - elif _helper_present(): + elif helper_cleanup_required: _prune_helpers(state) with _credential_transaction(state, encrypted, backend) as transaction: blob = directory / "credential.cred" @@ -693,7 +739,8 @@ def _enable(state, *, start_now=True, confirm=True): record["changed_config_sha256"] = hashlib.sha256(_read(state / "config.json")).hexdigest() _json(directory / "installation.json", record); created.append(directory / "installation.json") print("[3/3] Enabling automatic startup...", flush=True) - _command(["sudo", "-n", "--", "loginctl", "enable-linger", user]) + if not node or not linger_before: + _command(["sudo", "-n", "--", "loginctl", "enable-linger", user]) _systemctl("daemon-reload") if start_now: _systemctl("enable", "--now", unit.name) @@ -946,7 +993,17 @@ def _connection_action(state, action): def _worker_status(directory, name): - _json(directory / "worker-status.json", {"state": name, "updated_at": time.time()}, replace=True) + path = directory / "worker-status.json" + try: + previous = json.loads(_read(path)) + except (FileNotFoundError, ValueError): + previous = None + # This is a transition timestamp, not a liveness heartbeat. systemd and the + # owned process identity report liveness separately. Avoid a durable fsync + # every two seconds while the worker remains in the same state. + if isinstance(previous, dict) and previous.get("state") == name: + return + _json(path, {"state": name, "updated_at": time.time()}, replace=True) def worker(state): diff --git a/source/expanded/framebridge_expanded/cli.py b/source/expanded/framebridge_expanded/cli.py index 8bb3d35..826d9f1 100644 --- a/source/expanded/framebridge_expanded/cli.py +++ b/source/expanded/framebridge_expanded/cli.py @@ -451,6 +451,18 @@ def _doctor_command(args, state): return _result_code(value) +def _health_command(args, state): + health = _module("health") + value = health.collect(state) + if args.json: + _show(value) + else: + print(health.render(value)) + # Query success and operational health are deliberately separate. An + # intentional pause can be healthy; missing/unknown state cannot pass. + return 0 if value.get("ok") is True and value.get("health", {}).get("healthy") is True else 1 + + def _service_command(args, state): action = args.service_action lifecycle = _module("lifecycle") @@ -540,6 +552,7 @@ def build_parser(): status = sub.add_parser("status", help="Observe local tools, ChatGPT connection and startup policy without changing them.") status.add_argument("scope", nargs="?", choices=("connection", "runtime", "boot", "console")) sub.add_parser("doctor", help="Diagnose prerequisites and problems; does not repair or connect.") + sub.add_parser("health", help="Read one local profile's health, identity and prerequisites; no repair or connection.") sub.add_parser("setup", help="Optional advanced role/profile setup; does not start services or connect.") help_parser = sub.add_parser("help", help="Read the installed, versioned English guide.") help_parser.add_argument("topic", nargs="?", default="start", help="Guide topic; use all for the complete reference.") @@ -665,14 +678,14 @@ def _dispatch(parser, args): return _help_command(argparse.Namespace(command="help", topic="start", json=True, non_interactive=True)) parser.print_help() return 0 - print("FrameBridge\n1. Connect\n2. Status\n3. Doctor\n4. Open console\n5. Help\n6. Advanced setup\n0. Exit") + print("FrameBridge\n1. Connect\n2. Status\n3. Doctor\n4. Open console\n5. Help\n6. Advanced setup\n7. Health summary\n0. Exit") try: choice = input("Choose an action: ").strip() except (EOFError, KeyboardInterrupt): print("\nCancelled.", file=sys.stderr) return 130 action = {"1":["connect"], "2":["status"], "3":["doctor"], "4":["console"], - "5":["help"], "6":["setup"]}.get(choice) + "5":["help"], "6":["setup"], "7":["health"]}.get(choice) if choice == "0": return 0 if action is None: @@ -712,6 +725,8 @@ def _dispatch(parser, args): return _status_command(args, state) if args.command == "doctor": return _doctor_command(args, state) + if args.command == "health": + return _health_command(args, state) if args.command == "service": return _service_command(args, state) if args.command == "connection": diff --git a/source/expanded/framebridge_expanded/compatibility.py b/source/expanded/framebridge_expanded/compatibility.py index 2c0f0c6..f701d14 100644 --- a/source/expanded/framebridge_expanded/compatibility.py +++ b/source/expanded/framebridge_expanded/compatibility.py @@ -111,7 +111,7 @@ def assess(prefix, *, os_release=None, machine=None, python_version=None, libc=N expected = PROFILES[manifest["profile_id"]] if (manifest.get("architecture"), manifest.get("python_minor"), manifest.get("python_abi")) != ("amd64", expected[2], expected[3]): raise ValueError("inconsistent profile ABI") - if manifest.get("validation_status") not in {"candidate", "validated"}: + if manifest.get("validation_status") not in {"candidate", "release_build", "validated"}: raise ValueError("missing validation status") if manifest["profile_id"] != selected or manifest["python_minor"] != minor or manifest["python_abi"] != abi: issues.append("Installed artifact profile/ABI does not match this operating system and interpreter.") @@ -126,7 +126,9 @@ def assess(prefix, *, os_release=None, machine=None, python_version=None, libc=N warnings.append("Source checkout has no artifact manifest; only the legacy Debian 13/cp313 profile is eligible.") issues.extend(_vendor_issues(prefix, abi)) validation = manifest.get("validation_status") if manifest else "source-unvalidated" - if validation != "validated": + if validation == "release_build": + warnings.append("Release assembly does not establish a tested installation on this target; consult the external release acceptance record.") + elif validation != "validated": warnings.append("Candidate compatibility checks do not establish a tested installation on this target.") return {"ok": not issues, "profile_id": selected, "artifact_profile_id": manifest.get("profile_id") if manifest else None, "architecture": machine, "python_minor": minor, "python_abi": abi, "python_implementation": implementation, "python_abi_flags": abi_flags, diff --git a/source/expanded/framebridge_expanded/connection_background.py b/source/expanded/framebridge_expanded/connection_background.py index 7c4a498..4fcc07b 100644 --- a/source/expanded/framebridge_expanded/connection_background.py +++ b/source/expanded/framebridge_expanded/connection_background.py @@ -1,6 +1,7 @@ """Profile-scoped detached ChatGPT supervision without a persistent credential.""" from __future__ import annotations import fcntl +import hashlib import json import os import resource @@ -17,6 +18,10 @@ from .config import private_dir, state_path _BOOTSTRAP = "import sys;sys.path.insert(0,sys.argv[1]);from framebridge_expanded.connection_background import worker_main;worker_main(sys.argv[2],int(sys.argv[3]))" _PACKAGE_PARENT = str(Path(__file__).resolve().parents[1]) _STATES = {"starting", "checking", "access", "ready", "retrying", "rejected", "unverified", "error", "stopped", "closed"} +_RUNTIME_PARENT = Path("/run/user") +_HEARTBEAT_BACKEND = "user-runtime-v1" +_IDENTITY_FIELDS = ("pid", "uid", "start_ticks", "boot_id", "session_id", "process_group", "state_dir", "lock_fd") +_DURABLE_HEARTBEAT_INTERVAL = 5.0 _MESSAGES = { "starting": "[1/3] Starting the background tunnel client.", "checking": "[2/3] Verifying the local MCP service.", @@ -59,6 +64,40 @@ def _checked_fd(path, flags, create=False): raise +def _heartbeat_directory(state, create=False): + """Keep disposable liveness updates out of the durable profile filesystem. + + Do not create a login runtime directory, follow symlinks, change existing + permissions, or trust an arbitrary XDG_RUNTIME_DIR supplied by a caller. + Hosts without a user runtime directory retain bounded durable heartbeats. + """ + root = _RUNTIME_PARENT / str(os.getuid()) + for parent in (_RUNTIME_PARENT.parent, _RUNTIME_PARENT): + try: + parent_info = parent.lstat() + except FileNotFoundError: + return None + if not stat.S_ISDIR(parent_info.st_mode) or parent_info.st_uid not in (0, os.getuid()) or stat.S_IMODE(parent_info.st_mode) & 0o022: + raise RuntimeError("The user runtime parent directory is unsafe.") + try: + info = root.lstat() + except FileNotFoundError: + return None + if not stat.S_ISDIR(info.st_mode) or info.st_uid != os.getuid() or stat.S_IMODE(info.st_mode) & 0o077: + raise RuntimeError("The user runtime directory is not private and owned by this user.") + name = "framebridge-connection-" + hashlib.sha256(str(state_path(state)).encode()).hexdigest() + directory = root / name + if create: + return private_dir(directory) + try: + info = directory.lstat() + except FileNotFoundError: + return None + if not stat.S_ISDIR(info.st_mode) or info.st_uid != os.getuid() or stat.S_IMODE(info.st_mode) & 0o077: + raise RuntimeError("The connection heartbeat directory is not private and owned by this user.") + return directory + + def _read(path): try: fd = _checked_fd(path, os.O_RDONLY) @@ -146,6 +185,11 @@ def status(state): if not alive and phase not in {"error", "closed", "stopped"}: phase = "stopped" checked = record.get("verified_at") + if record.get("heartbeat_backend") == _HEARTBEAT_BACKEND: + heartbeat_directory = _heartbeat_directory(state) + heartbeat = _read(heartbeat_directory / "status.json") if heartbeat_directory else {} + same_worker = all(heartbeat.get(key) == record.get(key) for key in _IDENTITY_FIELDS) + checked = heartbeat.get("verified_at") if same_worker and heartbeat.get("state") == phase else None verified = alive and phase == "ready" and type(checked) in (int, float) and 0 <= time.time() - checked <= 15 if alive and phase == "ready" and not verified: phase = "retrying" @@ -185,9 +229,14 @@ def disconnect(state, *, timeout=16): class _StatusOutput: """Progress destination owned by the worker, with no parent pipe or terminal.""" - def __init__(self, path, identity): + def __init__(self, path, identity, heartbeat_path=None): self.path = path self.record = dict(identity) + self.heartbeat_path = heartbeat_path + if heartbeat_path is not None: + self.record["heartbeat_backend"] = _HEARTBEAT_BACKEND + self.last_observed = None + self.last_durable_write = 0.0 self.pending = "" self.change("starting", "[1/3] Starting the background tunnel client.") @@ -198,13 +247,25 @@ class _StatusOutput: pass def change(self, state, message): + if self.record.get("state") == state and self.record.get("message") == message: + return self.record.update(state=state, message=message, updated_at=time.time()) _write(self.path, self.record) + self.last_durable_write = time.monotonic() def observe(self, state): self.record["checked_at"] = time.time() self.record["verified_at"] = time.time() if state == "ready" else None - _write(self.path, self.record) + if self.heartbeat_path is not None: + heartbeat = {key: self.record[key] for key in _IDENTITY_FIELDS} + heartbeat.update(state=state, checked_at=self.record["checked_at"], verified_at=self.record["verified_at"]) + _write(self.heartbeat_path, heartbeat) + elif state != self.last_observed or time.monotonic() - self.last_durable_write >= _DURABLE_HEARTBEAT_INTERVAL: + # Legacy/manual sessions can run without systemd's user runtime + # directory. Preserve the 15-second freshness contract there too. + _write(self.path, self.record) + self.last_durable_write = time.monotonic() + self.last_observed = state def write(self, text): self.pending += text @@ -243,7 +304,9 @@ def worker_main(state, lock_fd): return if not isinstance(command, list) or not command or any(not isinstance(v, str) or "\0" in v for v in command): return - sink = _StatusOutput(directory / "status.json", _identity(os.getpid(), state, lock_fd)) + heartbeat_directory = _heartbeat_directory(state, create=True) + heartbeat_path = heartbeat_directory / "status.json" if heartbeat_directory else None + sink = _StatusOutput(directory / "status.json", _identity(os.getpid(), state, lock_fd), heartbeat_path) from .tunnel import run_foreground rc = run_foreground(command, credential, state=state, output=sink, observe=sink.observe) except BaseException: diff --git a/source/expanded/framebridge_expanded/fleet.py b/source/expanded/framebridge_expanded/fleet.py index 393aa11..f05677b 100644 --- a/source/expanded/framebridge_expanded/fleet.py +++ b/source/expanded/framebridge_expanded/fleet.py @@ -164,6 +164,19 @@ def resolve_node(alias: str) -> dict[str, Any]: return matches[0] +def _target_identity(requested: str, node: dict[str, Any]) -> dict[str, Any]: + """Describe the confirmed route, never identity claimed by a node response.""" + return { + "requested_target": requested, + "resolved_target": node["alias"], + "node": node["alias"], + "target": "LOCAL" if node["transport"] == "local" else node["alias"], + "node_id": node["node_id"], + "hostname": node.get("hostname"), + "transport": node["transport"], + } + + def _normalize_read(capability: str, args: dict[str, Any]) -> dict[str, Any]: bootstrap_original() from framebridge_linux_chatgpt.fleet_routing import ReadCapability, normalize_read_args @@ -185,6 +198,7 @@ def read_local(capability: str, args: dict[str, Any]) -> dict[str, Any]: def node_read(alias: str, capability: str, args: dict[str, Any]) -> dict[str, Any]: + node = None try: normalized = _normalize_read(capability, args) node = resolve_node(alias) @@ -196,10 +210,13 @@ def node_read(alias: str, capability: str, args: dict[str, Any]) -> dict[str, An result = broker.request(node["node_id"], capability, normalized, timeout_s=30) _require(type(result) is dict, "NODE_READ_RESPONSE_INVALID") response = dict(result) - response.update(node=node["alias"], hostname=node["hostname"], transport=node["transport"]) + response.update(_target_identity(alias, node)) return response except Exception as exc: - return {"ok": False, "error": str(exc) if isinstance(exc, FleetError) else "NODE_READ_FAILED"} + response = {"ok": False, "error": str(exc) if isinstance(exc, FleetError) else "NODE_READ_FAILED"} + if node is not None: + response.update(_target_identity(alias, node)) + return response def _exec_payload(script: str, authorized: bool, timeout_s: int, job_id: str, @@ -224,6 +241,7 @@ def _exec_payload(script: str, authorized: bool, timeout_s: int, job_id: str, def execute_node(alias: str, script: str, authorized: bool, timeout_s: int = 120, job_id: str = "", sha256: str = "", include_stdout: bool = False) -> dict[str, Any]: + node = None try: payload = _exec_payload(script, authorized, timeout_s, job_id, sha256, include_stdout) node = resolve_node(alias) @@ -241,20 +259,24 @@ def execute_node(alias: str, script: str, authorized: bool, timeout_s: int = 120 "NODE_EXEC_JOB_BINDING_INVALID") _require(response.get("mcp_script_sha256", response.get("command_sha256")) == payload["sha256"], "NODE_EXEC_HASH_BINDING_INVALID") - response.update(target="LOCAL" if node["transport"] == "local" else node["alias"], - node_id=node["node_id"], mcp_job_id=payload["job_id"], + response.update(_target_identity(alias, node)) + response.update(mcp_job_id=payload["job_id"], mcp_script_sha256=payload["sha256"]) if include_stdout is not True: response.pop("stdout", None) return response except Exception as exc: - return {"ok": False, "error": str(exc) if isinstance(exc, FleetError) else "NODE_EXEC_FAILED"} + response = {"ok": False, "error": str(exc) if isinstance(exc, FleetError) else "NODE_EXEC_FAILED"} + if node is not None: + response.update(_target_identity(alias, node)) + return response def execute_screen_node(alias: str, script: str, authorized: bool, timeout_s: int = 30, job_id: str = "", sha256: str = "", include_stdout: bool = False) -> dict[str, Any]: """Use the same confirmed-node authority with an explicit non-shell screen operation.""" from .real_screen.screen_transport import REQUEST_TYPE, validate_payload, ScreenTransportError + node = None try: _require(type(timeout_s) is int and 1 <= timeout_s <= 30, "INVALID_SCREEN_TIMEOUT") payload = _exec_payload(script, authorized, timeout_s, job_id, sha256, include_stdout) @@ -280,16 +302,20 @@ def execute_screen_node(alias: str, script: str, authorized: bool, timeout_s: in from .real_screen.screen_rpc import encode response.update(ok=False, exit_code="1", stdout_truncated=False, stdout=encode({"ok": False, "error": {"code": "SCREEN_RPC_UNSUPPORTED_ON_NODE"}}).decode("ascii") + "\n") - response.update(target="LOCAL" if node["transport"] == "local" else node["alias"], - node_id=node["node_id"], mcp_job_id=payload["job_id"], + response.update(_target_identity(alias, node)) + response.update(mcp_job_id=payload["job_id"], mcp_script_sha256=payload["sha256"]) return response except Exception as exc: - return {"ok": False, "error": str(exc) if isinstance(exc, (FleetError, ScreenTransportError)) else "SCREEN_RPC_FAILED"} + response = {"ok": False, "error": str(exc) if isinstance(exc, (FleetError, ScreenTransportError)) else "SCREEN_RPC_FAILED"} + if node is not None: + response.update(_target_identity(alias, node)) + return response def cua_node(alias: str, payload: dict[str, Any], authorized: bool, timeout_s: int = 60, job_id: str = "") -> dict[str, Any]: + node = None try: _require(authorized is True, "AUTHORIZED_TRUE_REQUIRED") _require(type(payload) is dict, "CUA_PAYLOAD_REQUIRED") @@ -316,10 +342,13 @@ def cua_node(alias: str, payload: dict[str, Any], authorized: bool, response = dict(result) if response.get("ok") is True: _require(response.get("job_id") == job, "NODE_CUA_JOB_BINDING_INVALID") - response.update(target="LOCAL" if node["transport"] == "local" else node["alias"], node_id=node["node_id"]) + response.update(_target_identity(alias, node)) return response except Exception as exc: - return {"ok": False, "error": str(exc) if isinstance(exc, FleetError) else "NODE_CUA_FAILED"} + response = {"ok": False, "error": str(exc) if isinstance(exc, FleetError) else "NODE_CUA_FAILED"} + if node is not None: + response.update(_target_identity(alias, node)) + return response def main() -> None: diff --git a/source/expanded/framebridge_expanded/guide_data.py b/source/expanded/framebridge_expanded/guide_data.py index 55eb0f4..0b7b65c 100644 --- a/source/expanded/framebridge_expanded/guide_data.py +++ b/source/expanded/framebridge_expanded/guide_data.py @@ -8,7 +8,7 @@ GUIDE = {'start': {'title': 'Start with FrameBridge', 'commands': ['fb help', 'fb status', 'fb --json status']}, {'heading': 'Install and connect', 'body': 'Install the package built for your exact Debian 13, Ubuntu 24.04 or Linux Mint 22.x amd64 profile. These are the three release profiles; other distributions and architectures are outside this release. Keep the distribution system Python: 3.13 on Debian 13, 3.12 on Ubuntu 24.04 and Mint 22.x. Use the matching signed APT suite: trixie, noble or mint22. Normal first connection does not require a separate setup, doctor or start sequence. Run connect in a normal interactive terminal; advanced setup is optional for central/node roles and public settings.', - 'commands': ["sudo apt install ./framebridge-expanded_" + __version__ + "_amd64.deb", 'fb connect']}, + 'commands': ['fb connect']}, {'heading': 'Updating and removal', 'body': 'Install an official update through the normal package manager when that update has been published. Normal removal stops package-owned managed processes and can retain the user profile and encrypted connection material; it is not a credential-forgetting operation. On systemd 255, package removal also revokes the administrative boot-credential grant. After reinstalling, run fb connect interactively to provision that grant again; retained files alone do not restore startup. Use the explicit credentials forget action first when that is your intended outcome. Do not assume purge erases user-profile data. An explicit downgrade also revokes administrative helper grants before the older package files replace the helper. Helper-backed profiles require a new interactive connect with a compatible package before managed startup can be restored.', 'commands': ['sudo dpkg --remove framebridge-original-expanded']}, @@ -50,6 +50,7 @@ GUIDE = {'start': {'title': 'Start with FrameBridge', 'fb status boot', 'fb status console', 'fb doctor', + 'fb health', 'fb setup', 'fb console', 'fb help']}, @@ -210,7 +211,11 @@ GUIDE = {'start': {'title': 'Start with FrameBridge', {'heading': 'Targets', 'body': 'LOCAL means the actual receiving machine. Use enrolled, ' 'confirmed aliases or IDs and inspect the selected target before ' - 'work. Do not guess SSH identities or use historical lab ' + 'work. Fleet results include requested_target, resolved_target, ' + 'node_id, hostname and transport from the confirmed descriptor. ' + 'The compatibility target field can remain LOCAL; resolved_target ' + 'names the actual local computer. Unknown targets never fall back ' + 'to LOCAL. Do not guess SSH identities or use historical lab ' 'hostnames as defaults. CLI tty --node can use the authenticated ' 'node transport. The interactive console command is local; run it ' 'at the destination or use an explicitly configured SSH ' @@ -327,8 +332,11 @@ GUIDE = {'start': {'title': 'Start with FrameBridge', 'fb status runtime', 'fb status boot']}, {'heading': 'Doctor', - 'body': 'doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Candidate eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. Debian 13/LMDE 7 use cp313, Ubuntu 24.04/Mint 22.x use cp312, and Ubuntu 26.04 uses cp314. A matching profile does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies.', + 'body': 'doctor diagnoses prerequisites and reports findings with suggested next steps. It is not an implicit repair, and it is not a substitute for checking actual live connection state. Inspect the diagnosis and relevant private application logs before considering configuration changes. Eligibility checks the exact OS release, amd64 architecture, package profile and CPython ABI before starting native components. The published 0.3.3 scope is Debian 13 with cp313 and Ubuntu 24.04/Mint 22.x with cp312. LMDE 7 and Ubuntu 26.04 builder experiments remain outside that validated scope. A matching profile or a successful development build does not establish a tested installation; never repair an ABI mismatch by replacing system Python or weakening package dependencies.', 'commands': ['fb doctor']}, + {'heading': 'Local health summary', + 'body': 'health combines this local profile\'s existing status and prerequisite observations into an allowlisted report. It identifies LOCAL as this computer and reports the profile, role, connection intent, local tools, boot policy and desktop availability. It never starts, repairs, connects, changes boot policy or creates an absent profile. It does not scan the fleet or probe terminal commands, screen capture or input. States are healthy, paused, degraded, unavailable and unconfigured. An intentional connection pause can be healthy; missing information cannot. JSON result.ok describes observation completeness; result.health.healthy describes health. Health exits 0 for a complete healthy or intentionally paused observation and 1 for degraded, unavailable or unconfigured state. The CLI version is not proof of the running version. Detailed troubleshooting remains local in status and doctor.', + 'commands': ['fb health', 'fb --json health']}, {'heading': 'Logs and progress', 'body': 'Normal connection presents concise progress and a final ' 'result, then returns to the prompt. Detailed diagnostics ' diff --git a/source/expanded/framebridge_expanded/health.py b/source/expanded/framebridge_expanded/health.py new file mode 100644 index 0000000..da09c90 --- /dev/null +++ b/source/expanded/framebridge_expanded/health.py @@ -0,0 +1,234 @@ +"""Read-only, allowlisted health observations for one local FrameBridge profile. + +This combines existing status and prerequisite checks. It does not execute a +terminal/CUA probe, contact another node, repair a profile or change boot intent. +Snapshot success, observed readiness and compatibility are separate facts. +""" +from __future__ import annotations + +from datetime import datetime, timezone +import re +import socket +import uuid + +from . import __version__, lifecycle, runtime +from .config import state_path + + +_KINDS = frozenset({"physical-x11", "virtual-x11", "text", "not_started", "unavailable"}) +_PHASES = frozenset({"starting", "checking", "access", "unverified", "ready", + "retrying", "error", "rejected", "stopped", "closed"}) +_SERVICES = frozenset({"active", "activating", "deactivating", "inactive", "failed", + "reloading", "maintenance", "refreshing", "not_configured"}) +_CAPABILITIES = ("fbexec", "fbterm", "cua_tty_module", "graphical_cua") + + +def _mapping(value): + return value if isinstance(value, dict) else {} + + +def _boolean(value): + return value if type(value) is bool else None + + +def _name(value): + return value if isinstance(value, str) and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]{0,252}", value) else None + + +def _node_id(value): + try: + return str(uuid.UUID(value)) if isinstance(value, str) else None + except (ValueError, AttributeError): + return None + + +def _count(value): + return len(value) if isinstance(value, list) else 0 + + +def _choice(value, options, fallback="unavailable"): + return value if isinstance(value, str) and value in options else fallback + + +def _runtime_state(value): + if value.get("ok") is False or value.get("status_unavailable") or type(value.get("running")) is not bool: + return "unavailable" + if value.get("ready") is True and value.get("running") is True: + return "ready" + return "running" if value["running"] else "stopped" + + +def _boot_state(value): + if value.get("configured") is False: + return "not_configured" + if value.get("configured") is not True or type(value.get("enabled")) is not bool: + return "unavailable" + return "enabled" if value["enabled"] else "disabled" + + +def build_report(status_snapshot=None, doctor_snapshot=None, *, observed_at=None, + host=None, status_available=True, doctor_available=True): + """Project snapshots onto a fixed public schema; never copy raw dictionaries. + + Errors deliberately omit exception text and diagnostic free text. Existing + local ``fb doctor`` remains the detailed troubleshooting interface; this + summary can be shown to an assistant without connection metadata or paths. + """ + status = _mapping(status_snapshot) + diagnosis = _mapping(doctor_snapshot) + local = _mapping(status.get("runtime")) + connection = _mapping(status.get("connection")) + boot = _mapping(status.get("boot")) + platform = _mapping(diagnosis.get("platform_compatibility")) + capabilities = _mapping(local.get("capabilities")) + prerequisite_capabilities = _mapping(diagnosis.get("capabilities")) + context = _mapping(local.get("display_context")) + status_available = bool(status_available and isinstance(status_snapshot, dict) and status.get("ok") is not False) + configured = _boolean(status.get("configured")) if status_available else None + role = status.get("role") or local.get("role") + role = _choice(role, {"standalone", "central", "node"}, None) + local_state = _runtime_state(local) if configured is not False else "not_configured" + phase = _choice(connection.get("state"), _PHASES) + intent = _choice(status.get("desired_connection"), {"connected", "disconnected", "not_configured", "not_applicable"}) + kind = _choice(context.get("kind"), _KINDS) + doctor_available = bool(doctor_available and isinstance(doctor_snapshot, dict) and type(diagnosis.get("ok")) is bool) if configured else False + diagnostics_ok = _boolean(diagnosis.get("ok")) if doctor_available else None + connection_available = role == "node" or ( + bool(connection) and connection.get("ok") is not False + and phase != "unavailable" and type(connection.get("verified")) is bool) + boot_available = _boot_state(boot) != "unavailable" + issues = [] + if not status_available: + issues.append("STATUS_UNAVAILABLE") + if configured and not doctor_available: + issues.append("DIAGNOSTICS_UNAVAILABLE") + if configured and local_state == "unavailable": + issues.append("RUNTIME_STATUS_UNAVAILABLE") + if configured and not connection_available: + issues.append("CONNECTION_STATUS_UNAVAILABLE") + if configured and not boot_available: + issues.append("BOOT_STATUS_UNAVAILABLE") + if diagnostics_ok is False: + issues.append("PREREQUISITES_NEED_ATTENTION") + if configured is False: + health_state, healthy = "unconfigured", False + elif (not status_available or configured is None or role is None or not doctor_available + or local_state == "unavailable" or not connection_available or not boot_available): + health_state, healthy = "unavailable", None + elif diagnostics_ok is not True or local_state != "ready": + health_state, healthy = "degraded", False + elif role == "node": + health_state, healthy = "healthy", True + elif intent == "disconnected": + if connection.get("verified") is False and connection.get("alive") is not True and phase in {"stopped", "closed"}: + health_state, healthy = "paused", True + else: + health_state, healthy = "degraded", False + issues.append("CONNECTION_INTENT_MISMATCH") + elif connection.get("verified") is True: + health_state, healthy = "healthy", True + else: + health_state, healthy = "degraded", False + issues.append("CONNECTION_NOT_VERIFIED") + if configured and local_state in {"running", "stopped"}: + issues.append("LOCAL_TOOLS_NOT_READY") + observation_ok = (status_available and configured is not None and local_state != "unavailable" + and (configured is False or (doctor_available and connection_available + and boot_available and role is not None))) + build_profile = platform.get("artifact_profile_id") or platform.get("profile_id") + missing = diagnosis.get("missing_commands") + missing = sorted({v for v in missing if isinstance(v, str) and re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.+-]{0,63}", v)}) if isinstance(missing, list) else [] + notes = ["This is a local profile observation, not a fleet scan.", + "Status and prerequisites are sampled sequentially; this is not an atomic snapshot.", + "No FBEXEC/FBTERM command, screen capture or input probe was performed."] + if role == "node": + notes.append("The central computer provides the ChatGPT connection; this report does not verify that central connection.") + if configured is False: + notes.append("This profile is not configured. No profile or connection was created.") + if kind == "text": + notes.append("Text mode does not require a graphical session.") + return { + "schema_version": 1, "ok": observation_ok, "read_only": True, + "observed_at": observed_at or datetime.now(timezone.utc).isoformat(), + "effective_target": {"selector": "LOCAL", "host": _name(host), + "profile_name": _name(status.get("name") or local.get("name")), + "role": role, "node_id": _node_id(local.get("node_id"))}, + "software": {"cli_version": __version__, "runtime_version": None, + "runtime_version_status": "not_reported"}, + "health": {"state": health_state, "healthy": healthy, "issues": issues}, + "runtime": {"state": local_state, "running": _boolean(local.get("running")) if configured else None, + "ready": _boolean(local.get("ready")) if configured else None, + "availability": {k: _boolean(capabilities.get(k)) for k in _CAPABILITIES}, + "operational_probe_performed": False}, + "connection": {"state": "managed_by_central" if role == "node" else phase, + "verified": None if role == "node" else _boolean(connection.get("verified")), + "desired": intent}, + "boot": {"policy": _boot_state(boot), + "service_state": _choice(boot.get("service_state"), _SERVICES)}, + "prerequisites": {"state": "not_run" if configured is False else ("passed" if diagnostics_ok is True else "needs_attention" if diagnostics_ok is False else "unavailable"), + "compatible": _boolean(platform.get("ok")) if doctor_available else None, + "profile_id": _name(build_profile), + "validation_status": _choice(platform.get("validation_status"), {"candidate", "release_build", "validated", "source-unvalidated"}, "not_reported"), + "missing_commands": missing, + "issue_count": _count(diagnosis.get("issues")), + "compatibility_issue_count": _count(platform.get("issues")), + "availability": {k: _boolean(prerequisite_capabilities.get(k)) for k in _CAPABILITIES}}, + "desktop": {"kind": kind, "graphical_available": _boolean(capabilities.get("graphical_cua")), + "capture_verified_by_this_report": False, "input_verified_by_this_report": False}, + "notes": notes, + } + + +def collect(state): + """Observe only the selected local profile without creating or repairing it.""" + state = state_path(state) + status_snapshot, diagnosis = None, None + status_available = doctor_available = True + try: + status_snapshot = lifecycle.status(state) + except Exception: + status_available = False + if _mapping(status_snapshot).get("configured") is True: + try: + diagnosis = runtime.doctor(state) + except Exception: + doctor_available = False + else: + doctor_available = False + try: + host = socket.gethostname() + except OSError: + host = None + return build_report(status_snapshot, diagnosis, host=host, + status_available=status_available, doctor_available=doctor_available) + + +def render(report): + """Render the same allowlisted report for a human terminal.""" + target = report["effective_target"] + software = report["software"] + state = report["health"]["state"] + lines = ["FrameBridge " + software["cli_version"] + " — health: " + state, + "Target: LOCAL = this computer (" + (target["host"] or "hostname unavailable") + ")", + "Profile: " + (target["profile_name"] or "not available") + " | role: " + (target["role"] or "not available")] + if target["node_id"]: + lines.append("Node ID: " + target["node_id"]) + lines.extend(["Observed: " + report["observed_at"], + "Local tools: " + report["runtime"]["state"], + "Connection: " + ("connected (verified)" if report["connection"]["verified"] is True else report["connection"]["state"]), + "Connection intent: " + report["connection"]["desired"], + "Automatic startup: " + report["boot"]["policy"], + "Current service: " + report["boot"]["service_state"], + "Prerequisites: " + report["prerequisites"]["state"]]) + if report["prerequisites"]["profile_id"]: + lines.append("Build profile: " + report["prerequisites"]["profile_id"]) + lines.append("Desktop: " + report["desktop"]["kind"] + " (capture/input not tested)") + for issue in report["health"]["issues"]: + lines.append("Finding: " + issue) + if report["prerequisites"]["missing_commands"]: + lines.append("Missing commands: " + ", ".join(report["prerequisites"]["missing_commands"])) + if state in {"degraded", "unavailable"}: + lines.append("Inspect details locally: fb status; fb doctor") + lines.append("Runtime version: not reported; the CLI version is not proof of the running version.") + lines.extend(report["notes"]) + return "\n".join(lines) diff --git a/source/packaging/archive_sources.py b/source/packaging/archive_sources.py index dec5aff..d90b5ee 100755 --- a/source/packaging/archive_sources.py +++ b/source/packaging/archive_sources.py @@ -6,11 +6,13 @@ import gzip import hashlib import io import json +import re from pathlib import Path import tarfile import sys from build_profiles import CANDIDATE_VERSION, SOURCE_VENDOR, target_profile, validate_vendor, vendor_versions +from release_metadata import PUBLIC_RELEASE_PROFILES BASE = Path(__file__).resolve().parents[1] ROOT = BASE.parent @@ -25,6 +27,45 @@ BLOG_POLICY_FILES = ("README.md", "LICENSING.md", "POST-TEMPLATE.md", "LICENSE-C ARCHIVE_README_NAME = "README-SOURCE-ARCHIVE.md" DEPENDENCY_SOURCE_ASSETS = [{'filename': 'FrameBridge-0.3.1-Community-Preview1-dependency-sources.tar.gz', 'bytes': 82606998, 'sha256': '64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a'}, {'filename': 'FrameBridge-0.3.1-tunnel-client-dependency-sources.tar.gz', 'bytes': 26941745, 'sha256': '6445d4f0e773aba833fe5c610fbae54102b92de2ce636438f769f21e890c2bd9'}] ARCHIVE_README = f"# FrameBridge {CANDIDATE_VERSION} compatibility candidate source\n\nThis source archive is a QA candidate, not a signed public release or evidence\nthat an OS/desktop lifecycle has been tested. Original signed 0.3.1 assets retain\ntheir separate immutable identity. Check TARGET-VENDOR-PROVENANCE.json for the\nnative ABI inputs actually included in this archive.\n\nThe offline builder requires Python 3, Debian dpkg/dpkg-deb and documented host\nbuild prerequisites. It writes source/build/ and source/release/;\nit never installs a package, fetches dependencies, changes system Python or starts\nFrameBridge services. Run from this archive's top-level directory:\n\n python3 source/packaging/build_expanded.py --target debian13-amd64-py313\n python3 source/packaging/build_expanded.py --target lmde7-amd64-py313\n\nIf the cp312 input is recorded as included:\n\n python3 source/packaging/build_expanded.py --target ubuntu24.04-amd64-py312 --vendor-dir source/target-vendors/cp312\n python3 source/packaging/build_expanded.py --target mint22-amd64-py312 --vendor-dir source/target-vendors/cp312\n\nIf the cp314 input is recorded as included:\n\n python3 source/packaging/build_expanded.py --target ubuntu26.04-amd64-py314 --vendor-dir source/target-vendors/cp314\n\nThe default archive includes only the reviewed original cp313 vendor tree.\nThe archive producer can include reviewed alternate ABI trees using:\n\n python3 source/packaging/archive_sources.py --vendor-cp312 /reviewed/vendor-cp312 --vendor-cp314 /reviewed/vendor-cp314\n\nThose arguments must identify complete reviewed trees with the same 29 pinned\ndistribution names/versions as the original. The producer validates WHEEL/RECORD,\nCPython ABI, amd64 ELF and glibc baseline before including them. Local preparation\nmarkers and executable entry-point scripts are omitted. All included files and\ntheir hashes appear in SOURCE-ARCHIVE-MANIFEST.json alongside the finished archive;\nthe embedded provenance records input ABI identity without workstation paths.\n--check-vendor on build_expanded.py validates inputs without building a package.\nAn absent alternate tree must be supplied separately with equivalent provenance;\nchanging Depends cannot convert the original cp313 extensions into cp312/cp314.\n\nPackage output names contain the candidate version and a separate profile\nfolder. release-profile.json inside the installed prefix declares the exact\ncandidate profile. Build success and profile eligibility do not establish a\nvalidated installation, graphical control, real TTY or reboot lifecycle.\n\nOriginal FrameBridge material is GNU GPL version 3 only. Read LICENSE,\nLICENSING.md, COPYRIGHT.md, LICENSE-STATUS.md and OFFICIAL-RELEASES.md for scope,\nattribution, third-party terms and the official-release trust model.\n\nThe project source asset is accompanied by these separate unchanged dependency\nsource assets; they are not embedded or renamed by this helper:\n\n- FrameBridge-0.3.1-Community-Preview1-dependency-sources.tar.gz\n 82,606,998 bytes\n SHA-256 64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a\n- FrameBridge-0.3.1-tunnel-client-dependency-sources.tar.gz\n 26,941,745 bytes\n SHA-256 6445d4f0e773aba833fe5c610fbae54102b92de2ce636438f769f21e890c2bd9\n\nThe Preview1 name preserves an immutable shared asset's identity. Retain the R2\nsource-notice supplements and both dependency indices under licensing/third-party.\nMatching package versions do not constitute an independent source rebuild of the\nretained tunnel executable; its exact own-source revision is not asserted.\n\nThe blog directory contains licensing policies and the post template. Draft\narticles, private runtime profiles, QA logs, build outputs and Git history are\noutside the source allowlist. Only source/evidence/BASELINE.json is included from\ntechnical evidence. Release signatures and publication status are separate\nrecords; this candidate archiver does not sign or publish anything.\n".encode("utf-8") +PUBLIC_ARCHIVE_README = f"""# FrameBridge {CANDIDATE_VERSION} corresponding source + +This archive supplies the project source and the reviewed cp313 and cp312 vendor +inputs for Debian 13, Ubuntu 24.04 and Linux Mint 22.x on amd64. Keep its matching +SOURCE-ARCHIVE-MANIFEST.json sidecar beside the archive. Signatures, publication +and actual OS lifecycle acceptance are recorded separately; assembly alone does +not certify them. Historical signed assets retain their immutable identities. + +The offline builder needs Python 3, dpkg/dpkg-deb and the documented host build +prerequisites. It never fetches dependencies, installs packages or starts services. +Extract the archive beside its matching sidecar and run from the extracted root: + + python3 source/packaging/build_expanded.py --target debian13-amd64-py313 --public-release --source-manifest ../SOURCE-ARCHIVE-MANIFEST.json + python3 source/packaging/build_expanded.py --target ubuntu24.04-amd64-py312 --vendor-dir source/target-vendors/cp312 --public-release --source-manifest ../SOURCE-ARCHIVE-MANIFEST.json + python3 source/packaging/build_expanded.py --target mint22-amd64-py312 --vendor-dir source/target-vendors/cp312 --public-release --source-manifest ../SOURCE-ARCHIVE-MANIFEST.json + +Public-release mode verifies the archive hash, every current project source file +and the selected reviewed vendor identity before assembling a package. It does +not assert an independent rebuild of third-party native wheels or tunnel-client. +--check-vendor validates inputs without staging a package. + +Original FrameBridge material is GNU GPL version 3 only. Third-party material +retains its applicable terms. Read LICENSE, LICENSING.md, COPYRIGHT.md and the +source-delivery records. Distribute these separate, unchanged dependency assets +with the release; their historical names do not identify the installer version: + +- FrameBridge-0.3.1-Community-Preview1-dependency-sources.tar.gz + Bytes: 82606998 + SHA-256: 64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a +- FrameBridge-0.3.1-tunnel-client-dependency-sources.tar.gz + Bytes: 26941745 + SHA-256: 6445d4f0e773aba833fe5c610fbae54102b92de2ce636438f769f21e890c2bd9 + +The exact own-source revision of the retained tunnel executable is not asserted. +Retain the R2 source-notice supplements, both dependency indices and original +notices. Private profiles, credentials, QA logs, build outputs, Git history and +unpublished blog drafts are excluded from the archive allowlist. +""".encode("utf-8") + GPL_SHA256 = "3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986" def sha(path): @@ -81,12 +122,18 @@ def source_files(): def main(argv=None): parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--public-release", action="store_true", help="Assemble corresponding source for all three official release profiles") parser.add_argument("--vendor-cp312", type=Path, help="Reviewed cp312 vendor input to include") parser.add_argument("--vendor-cp314", type=Path, help="Reviewed cp314 vendor input to include") args = parser.parse_args(argv) + if args.public_release and not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", CANDIDATE_VERSION): + parser.error("--public-release requires a stable project version") + if args.public_release and (args.vendor_cp312 is None or args.vendor_cp314 is not None): + parser.error("--public-release requires --vendor-cp312 and excludes experimental cp314 input") names = source_files() expected_versions = vendor_versions(BASE / SOURCE_VENDOR) - provenance = {"schema": 1, "version": CANDIDATE_VERSION, "validation_status": "candidate", + provenance = {"schema": 1, "version": CANDIDATE_VERSION, "validation_status": "release_source" if args.public_release else "candidate", + "release_profiles": list(PUBLIC_RELEASE_PROFILES) if args.public_release else [], "vendors": {"cp313": {"path": "source/" + SOURCE_VENDOR.as_posix(), **validate_vendor(BASE / SOURCE_VENDOR, target_profile("debian13-amd64-py313"), expected_versions)}}} for abi, directory, profile_id in (("cp312", args.vendor_cp312, "ubuntu24.04-amd64-py312"), @@ -108,11 +155,11 @@ def main(argv=None): raise RuntimeError("Archive input path collision: " + name) names[name] = path provenance["omitted_vendor_abis"] = sorted({"cp312", "cp314"} - set(provenance["vendors"])) - if provenance["omitted_vendor_abis"]: + if provenance["omitted_vendor_abis"] and not args.public_release: print("Candidate source excludes alternate vendor ABIs: " + ", ".join(provenance["omitted_vendor_abis"]), file=sys.stderr) - generated = {ARCHIVE_README_NAME: ARCHIVE_README, + generated = {ARCHIVE_README_NAME: PUBLIC_ARCHIVE_README if args.public_release else ARCHIVE_README, "TARGET-VENDOR-PROVENANCE.json": (json.dumps(provenance, indent=2, sort_keys=True) + "\n").encode()} - release = BASE / "release" / "candidate-source" + release = BASE / "release" / ("public-source" if args.public_release else "candidate-source") release.mkdir(parents=True, exist_ok=True) output = release / ARCHIVE_NAME with output.open("wb") as raw: @@ -135,7 +182,7 @@ def main(argv=None): info.mode = 0o755 if path.stat().st_mode & 0o111 else 0o644 with path.open("rb") as stream: archive.addfile(info, stream) - manifest = {"status": "COMPATIBILITY_CANDIDATE_BUILD", "version": CANDIDATE_VERSION, "vendor_inputs": provenance, "archive": output.name, + manifest = {"status": "RELEASE_SOURCE_ASSEMBLED" if args.public_release else "COMPATIBILITY_CANDIDATE_BUILD", "version": CANDIDATE_VERSION, "vendor_inputs": provenance, "archive": output.name, "bytes": output.stat().st_size, "sha256": sha(output), "files": [{"path": name, "sha256": hashlib.sha256(data).hexdigest(), "generated": True} for name, data in sorted(generated.items())] diff --git a/source/packaging/build_expanded.py b/source/packaging/build_expanded.py index 717a2ab..dac5f4c 100755 --- a/source/packaging/build_expanded.py +++ b/source/packaging/build_expanded.py @@ -14,10 +14,13 @@ import shlex import subprocess from build_profiles import CANDIDATE_VERSION, PROFILES, SOURCE_VENDOR, VENDOR_RELATIVE, target_profile, validate_vendor, vendor_versions +from release_metadata import release_source BASE = Path(__file__).resolve().parents[1] ROOT = BASE.parent VERSION = CANDIDATE_VERSION +PUBLIC_RELEASE = False +SOURCE_ARCHIVE = None # Oldest package retaining the privileged helper lifecycle. Candidate/release # version bumps must not move this downgrade revocation boundary. PRIVILEGED_HELPER_FLOOR = "0.3.2" @@ -35,6 +38,14 @@ def sha(path): return hashlib.sha256(path.read_bytes()).hexdigest() +def contains_private_path(data, private_root): + """Match an actual path component, not e.g. /root in root_model.py.""" + prefix = str(private_root).rstrip("/").encode() + if not prefix: + return False + return re.search(re.escape(prefix) + rb"(?=$|[/\s\"'<>`])", data) is not None + + # These are release inputs, not files inferred from installed runtime profiles. LEGAL_FILES = ("LICENSE", "LICENSING.md", "COPYRIGHT.md", "LICENSE-STATUS.md", "OFFICIAL-RELEASES.md") THIRD_PARTY_REQUIRED = ("THIRD-PARTY-NOTICES.md", "DEPENDENCY-SOURCES.json", "SOURCE-AVAILABILITY.md", "R2-SUPPLEMENTS.json", "NATIVE-DEPENDENCY-TERMS.json", "NATIVE-DEPENDENCY-TERMS.md", "TUNNEL-DEPENDENCY-SOURCES.json") @@ -83,7 +94,7 @@ def legal_preflight(): for path in inputs: data = path.read_bytes() for private_root in private_roots: - if private_root.encode() in data: + if contains_private_path(data, private_root): raise RuntimeError("Local path found in legal input: " + str(path.relative_to(ROOT))) return index @@ -101,7 +112,7 @@ def install_legal_material(docs): shutil.copy2(ROOT / "blog" / name, docs / "blog" / name) shutil.copy2(ROOT / "RELEASE-NOTES.md", docs / "RELEASE-NOTES.md") (docs / "copyright").write_text( - "FrameBridge Original Expanded — compatibility candidate " + VERSION + "\n\n" + "FrameBridge Original Expanded — " + ("release " if PUBLIC_RELEASE else "compatibility candidate ") + VERSION + "\n\n" "Original FrameBridge material: GNU GPL version 3 only (GPL-3.0-only).\n" "The complete license is included in LICENSE. COPYRIGHT.md and LICENSING.md\n" "identify attribution, scope and third-party exceptions.\n\n" @@ -115,7 +126,8 @@ def install_legal_material(docs): "[licensing/third-party](licensing/third-party/THIRD-PARTY-NOTICES.md).\n" "Original vendored notices are preserved with their components.\n") lines = ["# Source availability for FrameBridge " + VERSION, "", - "Candidate source must be retained with its build identity; no public archive is asserted.", "", + ("Matching corresponding source: " + SOURCE_ARCHIVE["filename"] + " (SHA-256 " + SOURCE_ARCHIVE["sha256"] + ")." + if PUBLIC_RELEASE else "Candidate source must be retained with its build identity; no public archive is asserted."), "", "The release source set also includes these separate assets:", ""] for item in DEPENDENCY_SOURCE_ASSETS: lines.extend(["- " + item["filename"], @@ -131,12 +143,13 @@ def install_legal_material(docs): "signature status are external release records, not builder claims.", ""]) (docs / "SOURCE-AVAILABILITY.md").write_text("\n".join(lines)) (docs / "COMMUNITY-RELEASE-STATUS.json").write_text(json.dumps({ - "schema_version": 1, "version": VERSION, "status": "COMPATIBILITY_CANDIDATE_BUILD", + "schema_version": 1, "version": VERSION, + "status": "PUBLIC_RELEASE_BUILD_ASSEMBLED" if PUBLIC_RELEASE else "COMPATIBILITY_CANDIDATE_BUILD", "certified_as_RC7": False, "public_readiness": "EXTERNAL_RELEASE_RECORD", "signature_status": "EXTERNAL_RELEASE_RECORD", "vm_lifecycle_validation": "NOT_ASSERTED_BY_BUILDER", - "source_archive": "CANDIDATE_SOURCE_REQUIRED_BEFORE_PUBLICATION", + "source_archive": SOURCE_ARCHIVE if PUBLIC_RELEASE else "CANDIDATE_SOURCE_REQUIRED_BEFORE_PUBLICATION", "dependency_source_archives": DEPENDENCY_SOURCE_ASSETS }, indent=2) + "\n") @@ -175,7 +188,7 @@ def maintainer_prerm(version): def maintainer_preinst(version=None): - """Snapshot active profiles without stopping the process carrying APT.""" + """Snapshot running profiles for upgrades and same-version reinstalls.""" version = version or VERSION if not re.fullmatch(r"[0-9][0-9A-Za-z.+:~\\-]*", version): raise ValueError("Invalid package upgrade version") @@ -183,7 +196,7 @@ def maintainer_preinst(version=None): module = module.rsplit("if __name__ == '__main__':", 1)[0] return ("#!/bin/sh\nset -eu\ncase \"$1\" in\n upgrade)\n" '/usr/bin/dpkg --validate-version "$2"\n' - 'if /usr/bin/dpkg --compare-versions "$2" lt ' + shlex.quote(version) + "; then\n" + 'if /usr/bin/dpkg --compare-versions "$2" le ' + shlex.quote(version) + "; then\n" "/usr/bin/python3 -I -S - <<'FRAMEBRIDGE_UPGRADE_SNAPSHOT'\n" + module + "\nraise SystemExit(main(['snapshot']))\n" + "FRAMEBRIDGE_UPGRADE_SNAPSHOT\nfi\n ;;\nesac\n") @@ -204,17 +217,25 @@ def package_relationships(profile): def main(argv=None): - global VERSION, PUBLIC_FILENAME, RELEASE, STAGE, PREFIX + global VERSION, PUBLIC_FILENAME, RELEASE, STAGE, PREFIX, PUBLIC_RELEASE, SOURCE_ARCHIVE parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--target", required=True, choices=sorted(PROFILES)) parser.add_argument("--version", default=CANDIDATE_VERSION) parser.add_argument("--vendor-dir", type=Path, help="Reviewed target-ABI Fleet Hub vendor tree; never installed globally") + parser.add_argument("--public-release", action="store_true", help="Bind an official release profile to its assembled corresponding-source archive") + parser.add_argument("--source-manifest", type=Path, help="Matching SOURCE-ARCHIVE-MANIFEST.json kept beside its source archive") parser.add_argument("--check-vendor", action="store_true", help="Validate inputs without staging or building a package") args = parser.parse_args(argv) if not re.fullmatch(r"[0-9][0-9A-Za-z.+:~\-]*", args.version) or args.version == "0.3.1": parser.error("A distinct valid Debian candidate version is required") subprocess.run(["dpkg", "--validate-version", args.version], check=True) VERSION = args.version + PUBLIC_RELEASE = args.public_release + SOURCE_ARCHIVE = None + if args.public_release and args.source_manifest is None: + parser.error("--public-release requires --source-manifest") + if args.source_manifest and not args.public_release: + parser.error("--source-manifest requires --public-release") version_assignments = [node for node in ast.parse((BASE / "expanded/framebridge_expanded/__init__.py").read_text()).body if isinstance(node, ast.Assign) and any(isinstance(item, ast.Name) and item.id == "__version__" for item in node.targets)] if len(version_assignments) != 1 or ast.literal_eval(version_assignments[0].value) != VERSION: @@ -227,6 +248,11 @@ def main(argv=None): parser.error("This target requires --vendor-dir with reviewed " + profile["python_abi"] + " wheels") vendor_evidence = validate_vendor(vendor, profile, vendor_versions(original_vendor)) profile["vendor"] = vendor_evidence + if args.public_release: + from archive_sources import source_files + SOURCE_ARCHIVE = release_source(args.source_manifest, VERSION, args.target, source_files(), vendor_evidence) + profile["validation_status"] = "release_build" + profile["source_archive"] = SOURCE_ARCHIVE PUBLIC_FILENAME = "FrameBridge-" + VERSION + "-" + args.target + ".deb" RELEASE = BASE / "release" / args.target STAGE = BASE / "build" / args.target / "package-root" @@ -352,7 +378,7 @@ def main(argv=None): env = dict(os.environ, SOURCE_DATE_EPOCH=str(EPOCH)) subprocess.run(["dpkg-deb", "--root-owner-group", "-Zxz", "-z6", "--build", str(STAGE), str(output)], check=True, env=env) shutil.copy2(output, RELEASE / PUBLIC_FILENAME) - print(json.dumps({"package": str(output), "bytes": output.stat().st_size, "sha256": sha(output), "payload_entries": len(manifest), "profile_id": args.target, "validation_status": "candidate", "public_filename": PUBLIC_FILENAME, "status": "COMPATIBILITY_CANDIDATE_BUILD"})) + print(json.dumps({"package": str(output), "bytes": output.stat().st_size, "sha256": sha(output), "payload_entries": len(manifest), "profile_id": args.target, "validation_status": "release_build" if PUBLIC_RELEASE else "candidate", "public_filename": PUBLIC_FILENAME, "status": "PUBLIC_RELEASE_BUILD_ASSEMBLED" if PUBLIC_RELEASE else "COMPATIBILITY_CANDIDATE_BUILD"})) if __name__ == "__main__": main() diff --git a/source/packaging/build_profiles.py b/source/packaging/build_profiles.py index 2124307..346eaca 100644 --- a/source/packaging/build_profiles.py +++ b/source/packaging/build_profiles.py @@ -11,7 +11,7 @@ from pathlib import Path import re -CANDIDATE_VERSION = "0.3.3" +CANDIDATE_VERSION = "0.3.4" VENDOR_RELATIVE = Path("original/geranas/FrameBridge-Fleet-Hub/vendor") SOURCE_VENDOR = Path("sources/original-geranas/FrameBridge-Fleet-Hub/vendor") GLIBC_BASELINE = (2, 34) diff --git a/source/packaging/generate_command_docs.py b/source/packaging/generate_command_docs.py index 83ca95e..9b5df38 100644 --- a/source/packaging/generate_command_docs.py +++ b/source/packaging/generate_command_docs.py @@ -26,7 +26,7 @@ def markdown(data, title): def roff(text): return text.replace('\\','\\e').replace('-','\\-') def man(data): - lines=['.TH FRAMEBRIDGE 1 "2026-10-28" "FrameBridge '+__version__+'" "User Commands"', + lines=['.TH FRAMEBRIDGE 1 "2026-10-29" "FrameBridge '+__version__+'" "User Commands"', '.SH NAME','framebridge, fb \\- use local Linux tools and enrolled nodes with ChatGPT', '.SH SYNOPSIS','.B framebridge', '[\\-\\-json] [\\-\\-state\\-dir DIRECTORY] COMMAND [ARGUMENTS]', diff --git a/source/packaging/release_metadata.py b/source/packaging/release_metadata.py new file mode 100644 index 0000000..0e47817 --- /dev/null +++ b/source/packaging/release_metadata.py @@ -0,0 +1,87 @@ +"""Bind release packages to their corresponding source; never certify runtime QA.""" +import hashlib +import json +from pathlib import Path, PurePosixPath +import re +import tarfile + + +PUBLIC_RELEASE_PROFILES = ( + "debian13-amd64-py313", "ubuntu24.04-amd64-py312", "mint22-amd64-py312", +) + + +def release_source(manifest_path, version, profile_id, current_files, vendor_evidence): + """Require the same reviewed source and ABI input used by this package. + + The manifest and archive are release inputs kept beside one another. Their + signatures and the OS acceptance record are verified outside the builder. + """ + if profile_id not in PUBLIC_RELEASE_PROFILES or not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", version): + raise RuntimeError("Public release requires a stable version and an official release profile") + manifest_path = Path(manifest_path) + data = json.loads(manifest_path.read_text()) + expected_name = "FrameBridge-" + version + "-source.tar.gz" + if (data.get("version"), data.get("status"), data.get("archive")) != (version, "RELEASE_SOURCE_ASSEMBLED", expected_name): + raise RuntimeError("Matching release source manifest is required") + archive = manifest_path.parent / expected_name + if archive.is_symlink() or not archive.is_file(): + raise RuntimeError("Matching release source archive is missing") + digest = hashlib.sha256(archive.read_bytes()).hexdigest() + if archive.stat().st_size != data.get("bytes") or digest != data.get("sha256"): + raise RuntimeError("Release source archive hash or size differs from its manifest") + vendors = data.get("vendor_inputs", {}).get("vendors", {}) + if set(vendors) != {"cp312", "cp313"}: + raise RuntimeError("Release source must contain the reviewed cp312 and cp313 inputs") + abi = "cp313" if profile_id == "debian13-amd64-py313" else "cp312" + if vendors[abi].get("vendor_sha256") != vendor_evidence.get("vendor_sha256"): + raise RuntimeError("Package vendor input differs from corresponding source") + rows = data.get("files", []) + if not isinstance(rows, list) or any(not isinstance(row, dict) for row in rows): + raise RuntimeError("Invalid release source file manifest") + recorded = {row.get("path"): row.get("sha256") for row in rows} + if len(recorded) != len(rows): + raise RuntimeError("Duplicate release source manifest path") + seen = set() + prefix = "FrameBridge-" + version + "/" + with tarfile.open(archive, "r:gz") as source: + for member in source: + if not member.isfile() or not member.name.startswith(prefix): + raise RuntimeError("Unexpected release source archive member") + relative = member.name[len(prefix):] + if not relative or PurePosixPath(relative).is_absolute() or ".." in PurePosixPath(relative).parts: + raise RuntimeError("Unsafe release source archive path") + if relative in seen or relative not in recorded: + raise RuntimeError("Duplicate or unrecorded release source archive member") + seen.add(relative) + with source.extractfile(member) as stream: + if hashlib.sha256(stream.read()).hexdigest() != recorded[relative]: + raise RuntimeError("Release source archive content differs from its manifest") + if seen != set(recorded): + raise RuntimeError("Release source manifest contains files absent from the archive") + # Bind the ABI claims to the archived bytes, including the ABI not selected + # by this particular package. A manifest field alone is not vendor evidence. + for vendor_abi, expected_prefix in ( + ("cp313", "source/sources/original-geranas/FrameBridge-Fleet-Hub/vendor"), + ("cp312", "source/target-vendors/cp312"), + ): + if vendors[vendor_abi].get("path") != expected_prefix: + raise RuntimeError("Unexpected corresponding-source vendor path") + vendor_digest = hashlib.sha256() + # validate_vendor sorts Path objects, whose component ordering differs + # from slash-delimited strings for package/ versus package-1.dist-info/. + for path, file_digest in sorted(recorded.items(), key=lambda row: PurePosixPath(row[0]).parts): + if not path.startswith(expected_prefix + "/"): + continue + relative = path[len(expected_prefix) + 1:] + parts = PurePosixPath(relative).parts + if "__pycache__" in parts or "bin" in parts or relative.endswith(".pyc") or parts[-1] == "FB-ABI-PREPARED.json": + continue + vendor_digest.update(relative.encode() + b"\0") + vendor_digest.update(bytes.fromhex(file_digest)) + if vendor_digest.hexdigest() != vendors[vendor_abi].get("vendor_sha256"): + raise RuntimeError("Archived vendor bytes differ from their recorded ABI identity") + for relative, path in current_files.items(): + if recorded.get(relative) != hashlib.sha256(path.read_bytes()).hexdigest(): + raise RuntimeError("Package source differs from corresponding archive: " + relative) + return {"filename": expected_name, "bytes": data["bytes"], "sha256": digest} diff --git a/source/portable/front_door_mcp.py b/source/portable/front_door_mcp.py index 29ca06f..6f2bf77 100644 --- a/source/portable/front_door_mcp.py +++ b/source/portable/front_door_mcp.py @@ -50,7 +50,7 @@ mcp = FastMCP( "Use the installed CLI and tools for normal work; use a separate source clone when the owner requests software development. " "The six Fleet inspection tools are read-only. Guide instructions do not grant authorization." ), - website_url="https://betancourt.one/framebridge/", + website_url="https://framebridge.betancourt.one/", host=HOST, port=PORT, streamable_http_path="/mcp", diff --git a/source/target-vendors/cp312/_cffi_backend.cpython-312-x86_64-linux-gnu.so b/source/target-vendors/cp312/_cffi_backend.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..c10f359530772fd84ff48dd87c2b99bb30319269 GIT binary patch literal 348856 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
  • 8_56f>wXW62?? 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�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, Samuel Colvin , Zac Hatfield-Dodds +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: Environment :: MacOS X +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Unix +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Typing :: Typed +Requires-Python: >=3.10 +Description-Content-Type: text/markdown + +# annotated-types + +[![CI](https://github.com/annotated-types/annotated-types/workflows/CI/badge.svg?event=push)](https://github.com/annotated-types/annotated-types/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) +[![pypi](https://img.shields.io/pypi/v/annotated-types.svg)](https://pypi.python.org/pypi/annotated-types) +[![versions](https://img.shields.io/pypi/pyversions/annotated-types.svg)](https://github.com/annotated-types/annotated-types) +[![license](https://img.shields.io/github/license/annotated-types/annotated-types.svg)](https://github.com/annotated-types/annotated-types/blob/main/LICENSE) + +[PEP-593](https://peps.python.org/pep-0593/) added `typing.Annotated` as a way of +adding context-specific metadata to existing types, and specifies that +`Annotated[T, x]` _should_ be treated as `T` by any tool or library without special +logic for `x`. + +This package provides metadata objects which can be used to represent common +constraints such as upper and lower bounds on scalar values and collection sizes, +a `Predicate` marker for runtime checks, and +descriptions of how we intend these metadata to be interpreted. In some cases, +we also note alternative representations which do not require this package. + +## Install + +```bash +pip install annotated-types +``` + +## Examples + +```python +from typing import Annotated +from annotated_types import Gt, Len, Predicate + +class MyClass: + age: Annotated[int, Gt(18)] # Valid: 19, 20, ... + # Invalid: 17, 18, "19", 19.0, ... + factors: list[Annotated[int, Predicate(is_prime)]] # Valid: 2, 3, 5, 7, 11, ... + # Invalid: 4, 8, -2, 5.0, "prime", ... + + my_list: Annotated[list[int], Len(0, 10)] # Valid: [], [10, 20, 30, 40, 50] + # Invalid: (1, 2), ["abc"], [0] * 20 +``` + +## Documentation + +_While `annotated-types` avoids runtime checks for performance, users should not +construct invalid combinations such as `MultipleOf("non-numeric")` or `Annotated[int, Len(3)]`. +Downstream implementors may choose to raise an error, emit a warning, silently ignore +a metadata item, etc., if the metadata objects described below are used with an +incompatible type - or for any other reason!_ + +### Gt, Ge, Lt, Le + +Express inclusive and/or exclusive bounds on orderable values - which may be numbers, +dates, times, strings, sets, etc. Note that the boundary value need not be of the +same type that was annotated, so long as they can be compared: `Annotated[int, Gt(1.5)]` +is fine, for example, and implies that the value is an integer x such that `x > 1.5`. + +We suggest that implementors may also interpret `functools.partial(operator.le, 1.5)` +as being equivalent to `Gt(1.5)`, for users who wish to avoid a runtime dependency on +the `annotated-types` package. + +To be explicit, these types have the following meanings: + +* `Gt(x)` - value must be "Greater Than" `x` - equivalent to exclusive minimum +* `Ge(x)` - value must be "Greater than or Equal" to `x` - equivalent to inclusive minimum +* `Lt(x)` - value must be "Less Than" `x` - equivalent to exclusive maximum +* `Le(x)` - value must be "Less than or Equal" to `x` - equivalent to inclusive maximum + +### Interval + +`Interval(gt, ge, lt, le)` allows you to specify an upper and lower bound with a single +metadata object. `None` attributes should be ignored, and non-`None` attributes +treated as per the single bounds above. + +### MultipleOf + +`MultipleOf(multiple_of=x)` might be interpreted in two ways: + +1. Python semantics, implying `value % multiple_of == 0`, or +2. [JSONschema semantics](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.2.1), + where `int(value / multiple_of) == value / multiple_of`. + +We encourage users to be aware of these two common interpretations and their +distinct behaviours, especially since very large or non-integer numbers make +it easy to cause silent data corruption due to floating-point imprecision. + +We encourage libraries to carefully document which interpretation they implement. + +### MinLen, MaxLen, Len + +`Len()` implies that `min_length <= len(value) <= max_length` - lower and upper bounds are inclusive. + +As well as `Len()` which can optionally include upper and lower bounds, we also +provide `MinLen(x)` and `MaxLen(y)` which are equivalent to `Len(min_length=x)` +and `Len(max_length=y)` respectively. + +`Len`, `MinLen`, and `MaxLen` may be used with any type which supports `len(value)`. + +Examples of usage: + +* `Annotated[list, MaxLen(10)]` (or `Annotated[list, Len(max_length=10)]`) - list must have a length of 10 or less +* `Annotated[str, MaxLen(10)]` - string must have a length of 10 or less +* `Annotated[list, MinLen(3)]` (or `Annotated[list, Len(min_length=3)]`) - list must have a length of 3 or more +* `Annotated[list, Len(4, 6)]` - list must have a length of 4, 5, or 6 +* `Annotated[list, Len(8, 8)]` - list must have a length of exactly 8 + +#### Changed in v0.4.0 + +* `min_inclusive` has been renamed to `min_length`, no change in meaning +* `max_exclusive` has been renamed to `max_length`, upper bound is now **inclusive** instead of **exclusive** +* The recommendation that slices are interpreted as `Len` has been removed due to ambiguity and different semantic + meaning of the upper bound in slices vs. `Len` + +See [issue #23](https://github.com/annotated-types/annotated-types/issues/23) for discussion. + +### Timezone + +`Timezone` can be used with a `datetime` or a `time` to express which timezones +are allowed. `Annotated[datetime, Timezone(None)]` must be a naive datetime. +`Timezone[...]` ([literal ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis)) +expresses that any timezone-aware datetime is allowed. You may also pass a specific +timezone string or [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) +object such as `Timezone(timezone.utc)` or `Timezone("Africa/Abidjan")` to express that you only +allow a specific timezone, though we note that this is often a symptom of fragile design. + +#### Changed in v0.x.x + +* `Timezone` accepts [`tzinfo`](https://docs.python.org/3/library/datetime.html#tzinfo-objects) objects instead of + `timezone`, extending compatibility to [`zoneinfo`](https://docs.python.org/3/library/zoneinfo.html) and third party libraries. + +### Unit + +`Unit(unit: str)` expresses that the annotated numeric value is the magnitude of +a quantity with the specified unit. For example, `Annotated[float, Unit("m/s")]` +would be a float representing a velocity in meters per second. + +Please note that `annotated_types` itself makes no attempt to parse or validate +the unit string in any way. That is left entirely to downstream libraries, +such as [`pint`](https://pint.readthedocs.io) or +[`astropy.units`](https://docs.astropy.org/en/stable/units/). + +An example of how a library might use this metadata: + +```python +from annotated_types import Unit +from typing import Annotated, TypeVar, Callable, Any, get_origin, get_args + +# given a type annotated with a unit: +Meters = Annotated[float, Unit("m")] + + +# you can cast the annotation to a specific unit type with any +# callable that accepts a string and returns the desired type +T = TypeVar("T") +def cast_unit(tp: Any, unit_cls: Callable[[str], T]) -> T | None: + if get_origin(tp) is Annotated: + for arg in get_args(tp): + if isinstance(arg, Unit): + return unit_cls(arg.unit) + return None + + +# using `pint` +import pint +pint_unit = cast_unit(Meters, pint.Unit) + + +# using `astropy.units` +import astropy.units as u +astropy_unit = cast_unit(Meters, u.Unit) +``` + +### Predicate + +`Predicate(func: Callable)` expresses that `func(value)` is truthy for valid values. +Users should prefer the statically inspectable metadata above, but if you need +the full power and flexibility of arbitrary runtime predicates... here it is. + +For some common constraints, we provide generic types: + +* `LowerCase = Annotated[T, Predicate(str.islower)]` +* `UpperCase = Annotated[T, Predicate(str.isupper)]` +* `IsDigit = Annotated[T, Predicate(str.isdigit)]` +* `IsFinite = Annotated[T, Predicate(math.isfinite)]` +* `IsNotFinite = Annotated[T, Predicate(Not(math.isfinite))]` +* `IsNan = Annotated[T, Predicate(math.isnan)]` +* `IsNotNan = Annotated[T, Predicate(Not(math.isnan))]` +* `IsInfinite = Annotated[T, Predicate(math.isinf)]` +* `IsNotInfinite = Annotated[T, Predicate(Not(math.isinf))]` + +so that you can write e.g. `x: IsFinite[float] = 2.0` instead of the longer +(but exactly equivalent) `x: Annotated[float, Predicate(math.isfinite)] = 2.0`. + +Some libraries might have special logic to handle known or understandable predicates, +for example by checking for `str.isdigit` and using its presence to both call custom +logic to enforce digit-only strings, and customise some generated external schema. +Users are therefore encouraged to avoid indirection like `lambda s: s.lower()`, in +favor of introspectable methods such as `str.lower` or `re.compile("pattern").search`. + +To enable basic negation of commonly used predicates like `math.isnan` without introducing introspection that makes it impossible for implementers to introspect the predicate we provide a `Not` wrapper that simply negates the predicate in an introspectable manner. Several of the predicates listed above are created in this manner. + +We do not specify what behaviour should be expected for predicates that raise +an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently +skip invalid constraints, or statically raise an error; or it might try calling it +and then propagate or discard the resulting +`TypeError: descriptor 'isdigit' for 'str' objects doesn't apply to a 'int' object` +exception. We encourage libraries to document the behaviour they choose. + +### Doc + +`doc()` can be used to add documentation information in `Annotated`, for function and method parameters, variables, class attributes, return types, and any place where `Annotated` can be used. + +It expects a value that can be statically analyzed, as the main use case is for static analysis, editors, documentation generators, and similar tools. + +It returns a `DocInfo` class with a single attribute `documentation` containing the value passed to `doc()`. + +This is the early adopter's alternative form of the [`typing-doc` proposal](https://github.com/tiangolo/fastapi/blob/typing-doc/typing_doc.md). + +### Integrating downstream types with `GroupedMetadata` + +Implementers may choose to provide a convenience wrapper that groups multiple pieces of metadata. +This can help reduce verbosity and cognitive overhead for users. +For example, an implementer like Pydantic might provide a `Field` or `Meta` type that accepts keyword arguments and transforms these into low-level metadata: + +```python +from dataclasses import dataclass +from typing import Iterator +from annotated_types import GroupedMetadata, Ge + +@dataclass +class Field(GroupedMetadata): + ge: int | None = None + description: str | None = None + + def __iter__(self) -> Iterator[object]: + # Iterating over a GroupedMetadata object should yield annotated-types + # constraint metadata objects which describe it as fully as possible, + # and may include other unknown objects too. + if self.ge is not None: + yield Ge(self.ge) + if self.description is not None: + yield Description(self.description) +``` + +Libraries consuming annotated-types constraints should check for `GroupedMetadata` and unpack it by iterating over the object and treating the results as if they had been "unpacked" in the `Annotated` type. The same logic should be applied to the [PEP 646 `Unpack` type](https://peps.python.org/pep-0646/), so that `Annotated[T, Field(...)]`, `Annotated[T, Unpack[Field(...)]]` and `Annotated[T, *Field(...)]` are all treated consistently. + +Libraries consuming annotated-types should also ignore any metadata they do not recongize that came from unpacking a `GroupedMetadata`, just like they ignore unrecognized metadata in `Annotated` itself. + +Our own `annotated_types.Interval` class is a `GroupedMetadata` which unpacks itself into `Gt`, `Lt`, etc., so this is not an abstract concern. Similarly, `annotated_types.Len` is a `GroupedMetadata` which unpacks itself into `MinLen` (optionally) and `MaxLen`. + +### Consuming metadata + +We intend to not be prescriptive as to _how_ the metadata and constraints are used, but as an example of how one might parse constraints from types annotations see our [implementation in `test_main.py`](https://github.com/annotated-types/annotated-types/blob/f59cf6d1b5255a0fe359b93896759a180bec30ae/tests/test_main.py#L94-L103). + +It is up to the implementer to determine how this metadata is used. +You could use the metadata for runtime type checking, for generating schemas or to generate example data, amongst other use cases. + +## Design & History + +This package was designed at the PyCon 2022 sprints by the maintainers of Pydantic +and Hypothesis, with the goal of making it as easy as possible for end-users to +provide more informative annotations for use by runtime libraries. + +It is deliberately minimal, and following PEP-593 allows considerable downstream +discretion in what (if anything!) they choose to support. Nonetheless, we expect +that staying simple and covering _only_ the most common use-cases will give users +and maintainers the best experience we can. If you'd like more constraints for your +types - follow our lead, by defining them and documenting them downstream! diff --git a/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/RECORD b/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/RECORD new file mode 100644 index 0000000..646f789 --- /dev/null +++ b/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/RECORD @@ -0,0 +1,7 @@ +annotated_types/__init__.py,sha256=pxBKTUObJ6n3T8C-I2ubobeDHmBEAmgCogWrwSmKm8g,13273 +annotated_types/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +annotated_types/test_cases.py,sha256=2GdHKstXuBzpf3iXKCjmvFZpyk2zP9Hm9kXGGDhGBo4,6310 +annotated_types-0.8.0.dist-info/METADATA,sha256=YUmFsnj2Abjvhj-CeDuZHMOtpLifWS63HHxIxfLvIpg,15009 +annotated_types-0.8.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87 +annotated_types-0.8.0.dist-info/licenses/LICENSE,sha256=_hBJiEsaDZNCkB6I4H8ykl0ksxIdmXK2poBfuYJLCV0,1083 +annotated_types-0.8.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/WHEEL b/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/WHEEL new file mode 100644 index 0000000..7401812 --- /dev/null +++ b/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.31.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..d99323a --- /dev/null +++ b/source/target-vendors/cp312/annotated_types-0.8.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 the contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/source/target-vendors/cp312/annotated_types/__init__.py b/source/target-vendors/cp312/annotated_types/__init__.py new file mode 100644 index 0000000..dcb35c5 --- /dev/null +++ b/source/target-vendors/cp312/annotated_types/__init__.py @@ -0,0 +1,416 @@ +import math +import types +from collections.abc import Callable, Iterator +from dataclasses import dataclass +from datetime import tzinfo +from types import EllipsisType +from typing import ( + TYPE_CHECKING, + Annotated, + Any, + Literal, + Protocol, + SupportsFloat, + SupportsIndex, + TypeVar, + Union, + runtime_checkable, +) + +__all__ = ( + 'BaseMetadata', + 'GroupedMetadata', + 'Gt', + 'Ge', + 'Lt', + 'Le', + 'Interval', + 'MultipleOf', + 'MinLen', + 'MaxLen', + 'Len', + 'Timezone', + 'Predicate', + 'LowerCase', + 'UpperCase', + 'IsDigits', + 'IsFinite', + 'IsNotFinite', + 'IsNan', + 'IsNotNan', + 'IsInfinite', + 'IsNotInfinite', + 'doc', + 'DocInfo', + '__version__', +) + +__version__ = '0.8.0' + + +T = TypeVar('T') + + +# arguments that start with __ are considered +# positional only +# see https://peps.python.org/pep-0484/#positional-only-arguments + + +class SupportsGt(Protocol): + def __gt__(self: T, __other: T) -> bool: + ... + + +class SupportsGe(Protocol): + def __ge__(self: T, __other: T) -> bool: + ... + + +class SupportsLt(Protocol): + def __lt__(self: T, __other: T) -> bool: + ... + + +class SupportsLe(Protocol): + def __le__(self: T, __other: T) -> bool: + ... + + +class SupportsMod(Protocol): + def __mod__(self: T, __other: T) -> T: + ... + + +class SupportsDiv(Protocol): + def __div__(self: T, __other: T) -> T: + ... + + +class BaseMetadata: + """Base class for all metadata. + + This exists mainly so that implementers + can do `isinstance(..., BaseMetadata)` while traversing field annotations. + """ + + __slots__ = () + + +@dataclass(frozen=True, slots=True) +class Gt(BaseMetadata): + """Gt(gt=x) implies that the value must be greater than x. + + It can be used with any type that supports the ``>`` operator, + including numbers, dates and times, strings, sets, and so on. + """ + + gt: SupportsGt + + +@dataclass(frozen=True, slots=True) +class Ge(BaseMetadata): + """Ge(ge=x) implies that the value must be greater than or equal to x. + + It can be used with any type that supports the ``>=`` operator, + including numbers, dates and times, strings, sets, and so on. + """ + + ge: SupportsGe + + +@dataclass(frozen=True, slots=True) +class Lt(BaseMetadata): + """Lt(lt=x) implies that the value must be less than x. + + It can be used with any type that supports the ``<`` operator, + including numbers, dates and times, strings, sets, and so on. + """ + + lt: SupportsLt + + +@dataclass(frozen=True, slots=True) +class Le(BaseMetadata): + """Le(le=x) implies that the value must be less than or equal to x. + + It can be used with any type that supports the ``<=`` operator, + including numbers, dates and times, strings, sets, and so on. + """ + + le: SupportsLe + + +@runtime_checkable +class GroupedMetadata(Protocol): + """A grouping of multiple objects, like typing.Unpack. + + `GroupedMetadata` on its own is not metadata and has no meaning. + All of the constraints and metadata should be fully expressable + in terms of the `BaseMetadata`'s returned by `GroupedMetadata.__iter__()`. + + Concrete implementations should override `GroupedMetadata.__iter__()` + to add their own metadata. + For example: + + >>> @dataclass + >>> class Field(GroupedMetadata): + >>> gt: float | None = None + >>> description: str | None = None + ... + >>> def __iter__(self) -> Iterable[object]: + >>> if self.gt is not None: + >>> yield Gt(self.gt) + >>> if self.description is not None: + >>> yield Description(self.gt) + + Also see the implementation of `Interval` below for an example. + + Parsers should recognize this and unpack it so that it can be used + both with and without unpacking: + + - `Annotated[int, Field(...)]` (parser must unpack Field) + - `Annotated[int, *Field(...)]` (PEP-646) + """ # noqa: trailing-whitespace + + @property + def __is_annotated_types_grouped_metadata__(self) -> Literal[True]: + return True + + def __iter__(self) -> Iterator[object]: + ... + + if not TYPE_CHECKING: + __slots__ = () # allow subclasses to use slots + + def __init_subclass__(cls, *args: Any, **kwargs: Any) -> None: + # Basic ABC like functionality without the complexity of an ABC + super().__init_subclass__(*args, **kwargs) + if cls.__iter__ is GroupedMetadata.__iter__: + raise TypeError("Can't subclass GroupedMetadata without implementing __iter__") + + def __iter__(self) -> Iterator[object]: # noqa: F811 + raise NotImplementedError # more helpful than "None has no attribute..." type errors + + +@dataclass(frozen=True, kw_only=True, slots=True) +class Interval(GroupedMetadata): + """Interval can express inclusive or exclusive bounds with a single object. + + It accepts keyword arguments ``gt``, ``ge``, ``lt``, and/or ``le``, which + are interpreted the same way as the single-bound constraints. + """ + + gt: SupportsGt | None = None + ge: SupportsGe | None = None + lt: SupportsLt | None = None + le: SupportsLe | None = None + + def __iter__(self) -> Iterator[BaseMetadata]: + """Unpack an Interval into zero or more single-bounds.""" + if self.gt is not None: + yield Gt(self.gt) + if self.ge is not None: + yield Ge(self.ge) + if self.lt is not None: + yield Lt(self.lt) + if self.le is not None: + yield Le(self.le) + + +@dataclass(frozen=True, slots=True) +class MultipleOf(BaseMetadata): + """MultipleOf(multiple_of=x) might be interpreted in two ways: + + 1. Python semantics, implying ``value % multiple_of == 0``, or + 2. JSONschema semantics, where ``int(value / multiple_of) == value / multiple_of`` + + We encourage users to be aware of these two common interpretations, + and libraries to carefully document which they implement. + """ + + multiple_of: SupportsDiv | SupportsMod + + +@dataclass(frozen=True, slots=True) +class MinLen(BaseMetadata): + """ + MinLen() implies minimum inclusive length, + e.g. ``len(value) >= min_length``. + """ + + min_length: Annotated[int, Ge(0)] + + +@dataclass(frozen=True, slots=True) +class MaxLen(BaseMetadata): + """ + MaxLen() implies maximum inclusive length, + e.g. ``len(value) <= max_length``. + """ + + max_length: Annotated[int, Ge(0)] + + +@dataclass(frozen=True, slots=True) +class Len(GroupedMetadata): + """ + Len() implies that ``min_length <= len(value) <= max_length``. + + Upper bound may be omitted or ``None`` to indicate no upper length bound. + """ + + min_length: Annotated[int, Ge(0)] = 0 + max_length: Annotated[int, Ge(0)] | None = None + + def __iter__(self) -> Iterator[BaseMetadata]: + """Unpack a Len into zero or more single-bounds.""" + if self.min_length > 0: + yield MinLen(self.min_length) + if self.max_length is not None: + yield MaxLen(self.max_length) + + +@dataclass(frozen=True, slots=True) +class Timezone(BaseMetadata): + """Timezone(tz=...) requires a datetime to be aware (or ``tz=None``, naive). + + ``Annotated[datetime, Timezone(None)]`` must be a naive datetime. + ``Timezone(...)`` (the ellipsis literal) expresses that the datetime must be + tz-aware but any timezone is allowed. + + You may also pass a specific timezone string or tzinfo object such as + ``Timezone(timezone.utc)`` or ``Timezone("Africa/Abidjan")`` to express that + you only allow a specific timezone, though we note that this is often + a symptom of poor design. + """ + + tz: str | tzinfo | EllipsisType | None + + +@dataclass(frozen=True, slots=True) +class Unit(BaseMetadata): + """Indicates that the value is a physical quantity with the specified unit. + + It is intended for usage with numeric types, where the value represents the + magnitude of the quantity. For example, ``distance: Annotated[float, Unit('m')]`` + or ``speed: Annotated[float, Unit('m/s')]``. + + Interpretation of the unit string is left to the discretion of the consumer. + It is suggested to follow conventions established by python libraries that work + with physical quantities, such as + + - ``pint`` : + - ``astropy.units``: + + For indicating a quantity with a certain dimensionality but without a specific unit + it is recommended to use square brackets, e.g. `Annotated[float, Unit('[time]')]`. + Note, however, ``annotated_types`` itself makes no use of the unit string. + """ + + unit: str + + +@dataclass(frozen=True, slots=True) +class Predicate(BaseMetadata): + """``Predicate(func: Callable)`` implies `func(value)` is truthy for valid values. + + Users should prefer statically inspectable metadata, but if you need the full + power and flexibility of arbitrary runtime predicates... here it is. + + We provide a few predefined predicates for common string constraints: + ``LowerCase = Predicate(str.islower)``, ``UpperCase = Predicate(str.isupper)``, and + ``IsDigits = Predicate(str.isdigit)``. Users are encouraged to use methods which + can be given special handling, and avoid indirection like ``lambda s: s.lower()``. + + Some libraries might have special logic to handle certain predicates, e.g. by + checking for `str.isdigit` and using its presence to both call custom logic to + enforce digit-only strings, and customise some generated external schema. + + We do not specify what behaviour should be expected for predicates that raise + an exception. For example `Annotated[int, Predicate(str.isdigit)]` might silently + skip invalid constraints, or statically raise an error; or it might try calling it + and then propagate or discard the resulting exception. + """ + + func: Callable[[Any], bool] + + def __repr__(self) -> str: + if getattr(self.func, "__name__", "") == "": + return f"{self.__class__.__name__}({self.func!r})" + if isinstance(self.func, (types.MethodType, types.BuiltinMethodType)) and ( + namespace := getattr(self.func.__self__, "__name__", None) + ): + return f"{self.__class__.__name__}({namespace}.{self.func.__name__})" + if isinstance(self.func, type(str.isascii)): # method descriptor + return f"{self.__class__.__name__}({self.func.__qualname__})" + return f"{self.__class__.__name__}({self.func.__name__})" + + +@dataclass +class Not: + func: Callable[[Any], bool] + + def __call__(self, __v: Any) -> bool: + return not self.func(__v) + + +_StrType = TypeVar("_StrType", bound=str) + +LowerCase = Annotated[_StrType, Predicate(str.islower)] +""" +Return True if the string is a lowercase string, False otherwise. + +A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string. +""" # noqa: E501 +UpperCase = Annotated[_StrType, Predicate(str.isupper)] +""" +Return True if the string is an uppercase string, False otherwise. + +A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string. +""" # noqa: E501 +IsDigit = Annotated[_StrType, Predicate(str.isdigit)] +IsDigits = IsDigit # type: ignore # plural for backwards compatibility, see #63 +""" +Return True if the string is a digit string, False otherwise. + +A string is a digit string if all characters in the string are digits and there is at least one character in the string. +""" # noqa: E501 +IsAscii = Annotated[_StrType, Predicate(str.isascii)] +""" +Return True if all characters in the string are ASCII, False otherwise. + +ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too. +""" + +_NumericType = TypeVar('_NumericType', bound=Union[SupportsFloat, SupportsIndex]) +IsFinite = Annotated[_NumericType, Predicate(math.isfinite)] +"""Return True if x is neither an infinity nor a NaN, and False otherwise.""" +IsNotFinite = Annotated[_NumericType, Predicate(Not(math.isfinite))] +"""Return True if x is one of infinity or NaN, and False otherwise""" +IsNan = Annotated[_NumericType, Predicate(math.isnan)] +"""Return True if x is a NaN (not a number), and False otherwise.""" +IsNotNan = Annotated[_NumericType, Predicate(Not(math.isnan))] +"""Return True if x is anything but NaN (not a number), and False otherwise.""" +IsInfinite = Annotated[_NumericType, Predicate(math.isinf)] +"""Return True if x is a positive or negative infinity, and False otherwise.""" +IsNotInfinite = Annotated[_NumericType, Predicate(Not(math.isinf))] +"""Return True if x is neither a positive or negative infinity, and False otherwise.""" + +try: + # PEP 727 – Documentation in Annotated Metadata + from typing_extensions import Doc # type: ignore[attr-defined] +except ImportError: + + @dataclass(frozen=True, slots=True) + class Doc: # type: ignore [no-redef] + """ " + The return value of doc(), mainly to be used by tools that want to extract the + Annotated documentation at runtime. + """ + + documentation: str + """The documentation string passed to doc().""" + + +DocInfo = Doc # backwards compatibility +doc = Doc diff --git a/source/target-vendors/cp312/annotated_types/py.typed b/source/target-vendors/cp312/annotated_types/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/annotated_types/test_cases.py b/source/target-vendors/cp312/annotated_types/test_cases.py new file mode 100644 index 0000000..fba3c25 --- /dev/null +++ b/source/target-vendors/cp312/annotated_types/test_cases.py @@ -0,0 +1,146 @@ +import math +from collections.abc import Iterable, Iterator +from datetime import date, datetime, timedelta, timezone +from decimal import Decimal +from typing import Annotated, Any, NamedTuple + +import annotated_types as at + + +class Case(NamedTuple): + """ + A test case for `annotated_types`. + """ + + annotation: Any + valid_cases: Iterable[Any] + invalid_cases: Iterable[Any] + + +def cases() -> Iterable[Case]: + # Gt, Ge, Lt, Le + yield Case(Annotated[int, at.Gt(4)], (5, 6, 1000), (4, 0, -1)) + yield Case(Annotated[float, at.Gt(0.5)], (0.6, 0.7, 0.8, 0.9), (0.5, 0.0, -0.1)) + yield Case( + Annotated[datetime, at.Gt(datetime(2000, 1, 1))], + [datetime(2000, 1, 2), datetime(2000, 1, 3)], + [datetime(2000, 1, 1), datetime(1999, 12, 31)], + ) + yield Case( + Annotated[datetime, at.Gt(date(2000, 1, 1))], + [date(2000, 1, 2), date(2000, 1, 3)], + [date(2000, 1, 1), date(1999, 12, 31)], + ) + yield Case( + Annotated[datetime, at.Gt(Decimal('1.123'))], + [Decimal('1.1231'), Decimal('123')], + [Decimal('1.123'), Decimal('0')], + ) + + yield Case(Annotated[int, at.Ge(4)], (4, 5, 6, 1000, 4), (0, -1)) + yield Case(Annotated[float, at.Ge(0.5)], (0.5, 0.6, 0.7, 0.8, 0.9), (0.4, 0.0, -0.1)) + yield Case( + Annotated[datetime, at.Ge(datetime(2000, 1, 1))], + [datetime(2000, 1, 2), datetime(2000, 1, 3)], + [datetime(1998, 1, 1), datetime(1999, 12, 31)], + ) + + yield Case(Annotated[int, at.Lt(4)], (0, -1), (4, 5, 6, 1000, 4)) + yield Case(Annotated[float, at.Lt(0.5)], (0.4, 0.0, -0.1), (0.5, 0.6, 0.7, 0.8, 0.9)) + yield Case( + Annotated[datetime, at.Lt(datetime(2000, 1, 1))], + [datetime(1999, 12, 31), datetime(1999, 12, 31)], + [datetime(2000, 1, 2), datetime(2000, 1, 3)], + ) + + yield Case(Annotated[int, at.Le(4)], (4, 0, -1), (5, 6, 1000)) + yield Case(Annotated[float, at.Le(0.5)], (0.5, 0.0, -0.1), (0.6, 0.7, 0.8, 0.9)) + yield Case( + Annotated[datetime, at.Le(datetime(2000, 1, 1))], + [datetime(2000, 1, 1), datetime(1999, 12, 31)], + [datetime(2000, 1, 2), datetime(2000, 1, 3)], + ) + + # Interval + yield Case(Annotated[int, at.Interval(gt=4)], (5, 6, 1000), (4, 0, -1)) + yield Case(Annotated[int, at.Interval(gt=4, lt=10)], (5, 6), (4, 10, 1000, 0, -1)) + yield Case(Annotated[float, at.Interval(ge=0.5, le=1)], (0.5, 0.9, 1), (0.49, 1.1)) + yield Case( + Annotated[datetime, at.Interval(gt=datetime(2000, 1, 1), le=datetime(2000, 1, 3))], + [datetime(2000, 1, 2), datetime(2000, 1, 3)], + [datetime(2000, 1, 1), datetime(2000, 1, 4)], + ) + + yield Case(Annotated[int, at.MultipleOf(multiple_of=3)], (0, 3, 9), (1, 2, 4)) + yield Case(Annotated[float, at.MultipleOf(multiple_of=0.5)], (0, 0.5, 1, 1.5), (0.4, 1.1)) + + # lengths + + yield Case(Annotated[str, at.MinLen(3)], ('123', '1234', 'x' * 10), ('', '1', '12')) + yield Case(Annotated[str, at.Len(3)], ('123', '1234', 'x' * 10), ('', '1', '12')) + yield Case(Annotated[list[int], at.MinLen(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2])) + yield Case(Annotated[list[int], at.Len(3)], ([1, 2, 3], [1, 2, 3, 4], [1] * 10), ([], [1], [1, 2])) + + yield Case(Annotated[str, at.MaxLen(4)], ('', '1234'), ('12345', 'x' * 10)) + yield Case(Annotated[str, at.Len(0, 4)], ('', '1234'), ('12345', 'x' * 10)) + yield Case(Annotated[list[str], at.MaxLen(4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10)) + yield Case(Annotated[list[str], at.Len(0, 4)], ([], ['a', 'bcdef'], ['a', 'b', 'c']), (['a'] * 5, ['b'] * 10)) + + yield Case(Annotated[str, at.Len(3, 5)], ('123', '12345'), ('', '1', '12', '123456', 'x' * 10)) + yield Case(Annotated[str, at.Len(3, 3)], ('123',), ('12', '1234')) + + yield Case(Annotated[dict[int, int], at.Len(2, 3)], [{1: 1, 2: 2}], [{}, {1: 1}, {1: 1, 2: 2, 3: 3, 4: 4}]) + yield Case(Annotated[set[int], at.Len(2, 3)], ({1, 2}, {1, 2, 3}), (set(), {1}, {1, 2, 3, 4})) + yield Case(Annotated[tuple[int, ...], at.Len(2, 3)], ((1, 2), (1, 2, 3)), ((), (1,), (1, 2, 3, 4))) + + # Timezone + + yield Case( + Annotated[datetime, at.Timezone(None)], [datetime(2000, 1, 1)], [datetime(2000, 1, 1, tzinfo=timezone.utc)] + ) + yield Case( + Annotated[datetime, at.Timezone(...)], [datetime(2000, 1, 1, tzinfo=timezone.utc)], [datetime(2000, 1, 1)] + ) + yield Case( + Annotated[datetime, at.Timezone(timezone.utc)], + [datetime(2000, 1, 1, tzinfo=timezone.utc)], + [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))], + ) + yield Case( + Annotated[datetime, at.Timezone('Europe/London')], + [datetime(2000, 1, 1, tzinfo=timezone(timedelta(0), name='Europe/London'))], + [datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=6)))], + ) + + # Quantity + + yield Case(Annotated[float, at.Unit(unit='m')], (5, 4.2), ('5m', '4.2m')) + + # predicate types + + yield Case(at.LowerCase[str], ['abc', 'foobar'], ['', 'A', 'Boom']) + yield Case(at.UpperCase[str], ['ABC', 'DEFO'], ['', 'a', 'abc', 'AbC']) + yield Case(at.IsDigit[str], ['123'], ['', 'ab', 'a1b2']) + yield Case(at.IsAscii[str], ['123', 'foo bar'], ['£100', '😊', 'whatever 👀']) + + yield Case(Annotated[int, at.Predicate(lambda x: x % 2 == 0)], [0, 2, 4], [1, 3, 5]) + + yield Case(at.IsFinite[float], [1.23], [math.nan, math.inf, -math.inf]) + yield Case(at.IsNotFinite[float], [math.nan, math.inf], [1.23]) + yield Case(at.IsNan[float], [math.nan], [1.23, math.inf]) + yield Case(at.IsNotNan[float], [1.23, math.inf], [math.nan]) + yield Case(at.IsInfinite[float], [math.inf], [math.nan, 1.23]) + yield Case(at.IsNotInfinite[float], [math.nan, 1.23], [math.inf]) + + # check stacked predicates + yield Case(at.IsInfinite[Annotated[float, at.Predicate(lambda x: x > 0)]], [math.inf], [-math.inf, 1.23, math.nan]) + + # doc + yield Case(Annotated[int, at.doc("A number")], [1, 2], []) + + # custom GroupedMetadata + class MyCustomGroupedMetadata(at.GroupedMetadata): + def __iter__(self) -> Iterator[at.Predicate]: + yield at.Predicate(lambda x: float(x).is_integer()) + + yield Case(Annotated[float, MyCustomGroupedMetadata()], [0, 2.0], [0.01, 1.5]) diff --git a/source/target-vendors/cp312/anyio-4.15.1.dist-info/METADATA b/source/target-vendors/cp312/anyio-4.15.1.dist-info/METADATA new file mode 100644 index 0000000..13734ec --- /dev/null +++ b/source/target-vendors/cp312/anyio-4.15.1.dist-info/METADATA @@ -0,0 +1,108 @@ +Metadata-Version: 2.4 +Name: anyio +Version: 4.15.1 +Summary: High-level concurrency and networking framework on top of asyncio or Trio +Author-email: Alex Grönholm +License-Expression: MIT +Project-URL: Documentation, https://anyio.readthedocs.io/en/latest/ +Project-URL: Changelog, https://anyio.readthedocs.io/en/stable/versionhistory.html +Project-URL: Source code, https://github.com/agronholm/anyio +Project-URL: Issue tracker, https://github.com/agronholm/anyio/issues +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Framework :: AnyIO +Classifier: Typing :: Typed +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta +Requires-Python: >=3.10 +Description-Content-Type: text/x-rst +License-File: LICENSE +Requires-Dist: exceptiongroup>=1.0.2; python_version < "3.11" +Requires-Dist: idna>=2.8 +Requires-Dist: typing_extensions>=4.16.0; python_version < "3.15" +Provides-Extra: trio +Requires-Dist: trio>=0.32.0; extra == "trio" +Dynamic: license-file + +.. image:: https://github.com/agronholm/anyio/actions/workflows/test.yml/badge.svg + :target: https://github.com/agronholm/anyio/actions/workflows/test.yml + :alt: Build Status +.. image:: https://coveralls.io/repos/github/agronholm/anyio/badge.svg?branch=master + :target: https://coveralls.io/github/agronholm/anyio?branch=master + :alt: Code Coverage +.. image:: https://readthedocs.org/projects/anyio/badge/?version=latest + :target: https://anyio.readthedocs.io/en/latest/?badge=latest + :alt: Documentation +.. image:: https://badges.gitter.im/gitterHQ/gitter.svg + :target: https://gitter.im/python-trio/AnyIO + :alt: Gitter chat +.. image:: https://tidelift.com/badges/package/pypi/anyio + :target: https://tidelift.com/subscription/pkg/pypi-anyio + :alt: Tidelift + +AnyIO is an asynchronous networking and concurrency library that works on top of either asyncio_ or +Trio_. It implements Trio-like `structured concurrency`_ (SC) on top of asyncio and works in harmony +with the native SC of Trio itself. + +Applications and libraries written against AnyIO's API will run unmodified on either asyncio_ or +Trio_. AnyIO can also be adopted into a library or application incrementally – bit by bit, no full +refactoring necessary. It will blend in with the native libraries of your chosen backend. + +To find out why you might want to use AnyIO's APIs instead of asyncio's, you can read about it +`here `_. + +Documentation +------------- + +View full documentation at: https://anyio.readthedocs.io/ + +Features +-------- + +AnyIO offers the following functionality: + +* Task groups (nurseries_ in trio terminology) +* High-level networking (TCP, UDP and UNIX sockets) + + * `Happy eyeballs`_ algorithm for TCP connections (more robust than that of asyncio on Python + 3.8) + * async/await style UDP sockets (unlike asyncio where you still have to use Transports and + Protocols) + +* A versatile API for byte streams and object streams +* Inter-task synchronization and communication (locks, conditions, events, semaphores, object + streams and futures) +* Worker threads +* Subprocesses +* Subinterpreter support for code parallelization (on Python 3.13 and later) +* Asynchronous file I/O (using worker threads) +* Signal handling +* Asynchronous versions of the functools_ and itertools_ modules + +AnyIO also comes with its own pytest_ plugin which also supports asynchronous fixtures. +It even works with the popular Hypothesis_ library. + +.. _asyncio: https://docs.python.org/3/library/asyncio.html +.. _Trio: https://github.com/python-trio/trio +.. _structured concurrency: https://en.wikipedia.org/wiki/Structured_concurrency +.. _nurseries: https://trio.readthedocs.io/en/stable/reference-core.html#nurseries-and-spawning +.. _Happy eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs +.. _pytest: https://docs.pytest.org/en/latest/ +.. _functools: https://docs.python.org/3/library/functools.html +.. _itertools: https://docs.python.org/3/library/itertools.html +.. _Hypothesis: https://hypothesis.works/ + +Security contact information +---------------------------- + +To report a security vulnerability, please use the `Tidelift security contact`_. +Tidelift will coordinate the fix and disclosure. + +.. _Tidelift security contact: https://tidelift.com/security diff --git a/source/target-vendors/cp312/anyio-4.15.1.dist-info/RECORD b/source/target-vendors/cp312/anyio-4.15.1.dist-info/RECORD new file mode 100644 index 0000000..97a70cf --- /dev/null +++ b/source/target-vendors/cp312/anyio-4.15.1.dist-info/RECORD @@ -0,0 +1,53 @@ +anyio/__init__.py,sha256=OfroYRjIUw_JFj0Zwh1JAaajMQg4VqtoAt0XoOHDRwE,7602 +anyio/_lazyimport.py,sha256=LCjnYanIfYE9G-Dv_EsqNLDuVRppNicWZjCTfS9-sJU,6082 +anyio/from_thread.py,sha256=iZZbfcNySi4wAcx1_cxAQE4J0YZC88qRMIYqQ6SF9sc,19415 +anyio/functools.py,sha256=T4JS8IXq-x1S0Lbo2owF8l9fza2KypO147QLeyz4cjs,11797 +anyio/itertools.py,sha256=TS7_UCa2Y3cggtaLlWHbjOyf6QhPfQUdPduNW-ddXTE,16255 +anyio/lowlevel.py,sha256=QyWkvfetbCH0mHkqv1yxGwOaiZ7fyxhpZkHWOXPV5JU,6280 +anyio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/pytest_plugin.py,sha256=oLXyOstvRZW3VVbqIODhZsPt4jSz2UGh44YeG2nJXx0,14516 +anyio/to_interpreter.py,sha256=ATnoT6kei9wDmQZtXTA3SsY4CK7XKr8Ta4_x5i6pbTw,7100 +anyio/to_process.py,sha256=p6n8j0nreJUl1DEkR_9PL6KRoKtNqFxORTn8qZBvn94,9850 +anyio/to_thread.py,sha256=8MPVrrQq8ttGvV21cSd68rMto5bhxJ0-i9CupXag5Gs,2750 +anyio/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_backends/_asyncio.py,sha256=Vqy7O1ymmEpxTiPzehSuBCVTziGALNV-BbsIRaKXsg4,107767 +anyio/_backends/_trio.py,sha256=Gs8XzX0IeBvje8IEZtJmpNylKCUAChKv7I_YZi3wlmg,45715 +anyio/_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/_core/_asyncio_selector_thread.py,sha256=2PdxFM3cs02Kp6BSppbvmRT7q7asreTW5FgBxEsflBo,5626 +anyio/_core/_concurrency_utils.py,sha256=kvRXMrnDqgQTBkZc-f279-lBnZM4YbSToXqhnAUCfSc,4522 +anyio/_core/_contextmanagers.py,sha256=YInBCabiEeS-UaP_Jdxa1CaFC71ETPW8HZTHIM8Rsc8,7215 +anyio/_core/_eventloop.py,sha256=ByZUeJD9alMfcyTseRo5IzTO0IltEul_Gyq9iqSjqDk,6658 +anyio/_core/_exceptions.py,sha256=B4ZhLkBQT4tI6vShv4-GJui492IJsoIDTw1FQJEkmAI,5618 +anyio/_core/_fileio.py,sha256=q--ft9h5Y_FRLzhAnoYrXf3tOuZ8ZyIN2A9mCfMbZRc,34163 +anyio/_core/_futures.py,sha256=YQq5uhnCnKQMQD62tOLfzEm7dUXY3GQorJdH6ghfgIQ,6177 +anyio/_core/_resources.py,sha256=Ld5duCe9NwgPfI7EIOh3CMIBYQ7rq6ZQEa7CFS0u9Ec,450 +anyio/_core/_signals.py,sha256=mjTBB2hTKNPRlU0IhnijeQedpWOGERDiMjSlJQsFrug,1016 +anyio/_core/_sockets.py,sha256=C8b-3w5H9n0Fo4g7X8WJvk0m6CGh6NVAAFtieBGHK3g,35289 +anyio/_core/_streams.py,sha256=FczFwIgDpnkK0bODWJXMpsUJYdvAD04kaUaGzJU8DK0,1806 +anyio/_core/_subprocesses.py,sha256=TMBuGNILz-47w5t9vayJ1GpCpDT6LxsMohJDFCewIRc,7938 +anyio/_core/_synchronization.py,sha256=ggsd74QPd846faA2HQeT07ONQ5HQ1S78gy8mvB3qCrw,21658 +anyio/_core/_tasks.py,sha256=J2dhM_Jq3Grsfg_enNWpRz2SxfM15uLt-pEfvoQq3uA,15391 +anyio/_core/_tempfile.py,sha256=IgoBCFaPhrFvsF9KHcCcrnCRn-UqMfw0WRdSDWgxAiI,19726 +anyio/_core/_testing.py,sha256=ZRucLh5kqhiFWAJMMbd8yZ6uIvz0rq3WwL72ldosxAU,2340 +anyio/_core/_typedattr.py,sha256=gt9Dzn-IL0QW14aHPDD8PAtq95FYKNNupHyf37xZGPQ,2607 +anyio/abc/__init__.py,sha256=XIVvCI2c6oyaOcqXe94k2rzU5_s7-ZNnlxGTk34H4T0,3050 +anyio/abc/_eventloop.py,sha256=0-UwgB351rkocCt8m3fjTmcNx2Fxn52nUoujG5DzMvU,11127 +anyio/abc/_resources.py,sha256=hrb0LXUgHSp3i8G6W8JJchdzKXgg1m0T-L7udXmv2y0,900 +anyio/abc/_sockets.py,sha256=jQWnPX7iDIDyvyvVkbuFhjezw4oI2WggzbW6Vl2-eqs,13162 +anyio/abc/_streams.py,sha256=IMeOPPutFXRbyeAutxV1HJe7FUQZYp2qKrJJpP1DCv0,7620 +anyio/abc/_subprocesses.py,sha256=CDqU1p0HuBS0pXUzBW_hbfhihTJRM67n__7qZmoPU84,2123 +anyio/abc/_tasks.py,sha256=HBPpT72aOy0bwMAxBCKmnXsR328wCYRjYm3iaVw2fQo,7070 +anyio/abc/_testing.py,sha256=A9Y8RAClIPn1A0aNHBN8YoaRy_MKOpbFGEbTHAXgB6U,2145 +anyio/streams/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +anyio/streams/buffered.py,sha256=u7hCD8SNrYHcutG6K5wEiy1F88-pizgjvEFM22Kq2Cw,6746 +anyio/streams/file.py,sha256=6jujI2m-QJITqqKFamrupX_DNsU7y2Fz3omLZxOLuY0,4524 +anyio/streams/memory.py,sha256=rpxNzDMag9PCOynBqN64KyuAfAPB41vFyRP-Npo-lE0,10793 +anyio/streams/stapled.py,sha256=UJ2Rgt0NUmM1VovRNOoZoic960lcbDjb3vhfZg3b_Z0,4845 +anyio/streams/text.py,sha256=BcVAGJw1VRvtIqnv-o0Rb0pwH7p8vwlvl21xHq522ag,5765 +anyio/streams/tls.py,sha256=fqLmxvULFO9rvxGyJ33VPrOIN7E3eiU1q90BkmKigQ8,15818 +anyio-4.15.1.dist-info/licenses/LICENSE,sha256=U2GsncWPLvX9LpsJxoKXwX8ElQkJu8gCO9uC6s8iwrA,1081 +anyio-4.15.1.dist-info/METADATA,sha256=BDrstXGvcYnopsUo9djjJUXxss36r3YdUebVtn6jyoE,4733 +anyio-4.15.1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91 +anyio-4.15.1.dist-info/entry_points.txt,sha256=_d6Yu6uiaZmNe0CydowirE9Cmg7zUL2g08tQpoS3Qvc,39 +anyio-4.15.1.dist-info/top_level.txt,sha256=QglSMiWX8_5dpoVAEIHdEYzvqFMdSYWmCj6tYw2ITkQ,6 +anyio-4.15.1.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/anyio-4.15.1.dist-info/WHEEL b/source/target-vendors/cp312/anyio-4.15.1.dist-info/WHEEL new file mode 100644 index 0000000..13013d7 --- /dev/null +++ b/source/target-vendors/cp312/anyio-4.15.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (84.0.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/anyio-4.15.1.dist-info/entry_points.txt b/source/target-vendors/cp312/anyio-4.15.1.dist-info/entry_points.txt new file mode 100644 index 0000000..44dd9bd --- /dev/null +++ b/source/target-vendors/cp312/anyio-4.15.1.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[pytest11] +anyio = anyio.pytest_plugin diff --git a/source/target-vendors/cp312/anyio-4.15.1.dist-info/licenses/LICENSE b/source/target-vendors/cp312/anyio-4.15.1.dist-info/licenses/LICENSE new file mode 100644 index 0000000..104eebf --- /dev/null +++ b/source/target-vendors/cp312/anyio-4.15.1.dist-info/licenses/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2018 Alex Grönholm + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/source/target-vendors/cp312/anyio-4.15.1.dist-info/top_level.txt b/source/target-vendors/cp312/anyio-4.15.1.dist-info/top_level.txt new file mode 100644 index 0000000..c77c069 --- /dev/null +++ b/source/target-vendors/cp312/anyio-4.15.1.dist-info/top_level.txt @@ -0,0 +1 @@ +anyio diff --git a/source/target-vendors/cp312/anyio/__init__.py b/source/target-vendors/cp312/anyio/__init__.py new file mode 100644 index 0000000..30a3a16 --- /dev/null +++ b/source/target-vendors/cp312/anyio/__init__.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from ._lazyimport import ( + fix_package_names, + install_lazy_importer, + set_deprecated_aliases, +) + +if TYPE_CHECKING or not install_lazy_importer(): + from ._core._concurrency_utils import amap as amap + from ._core._concurrency_utils import as_completed as as_completed + from ._core._concurrency_utils import gather as gather + from ._core._contextmanagers import ( + AsyncContextManagerMixin as AsyncContextManagerMixin, + ) + from ._core._contextmanagers import ContextManagerMixin as ContextManagerMixin + from ._core._eventloop import current_time as current_time + from ._core._eventloop import get_all_backends as get_all_backends + from ._core._eventloop import get_available_backends as get_available_backends + from ._core._eventloop import get_cancelled_exc_class as get_cancelled_exc_class + from ._core._eventloop import run as run + from ._core._eventloop import sleep as sleep + from ._core._eventloop import sleep_forever as sleep_forever + from ._core._eventloop import sleep_until as sleep_until + from ._core._exceptions import BrokenResourceError as BrokenResourceError + from ._core._exceptions import BrokenWorkerInterpreter as BrokenWorkerInterpreter + from ._core._exceptions import BrokenWorkerProcess as BrokenWorkerProcess + from ._core._exceptions import BusyResourceError as BusyResourceError + from ._core._exceptions import ClosedResourceError as ClosedResourceError + from ._core._exceptions import ConnectionFailed as ConnectionFailed + from ._core._exceptions import DelimiterNotFound as DelimiterNotFound + from ._core._exceptions import EndOfStream as EndOfStream + from ._core._exceptions import FutureAlreadyFinished as FutureAlreadyFinished + from ._core._exceptions import FutureCancelled as FutureCancelled + from ._core._exceptions import FutureFailed as FutureFailed + from ._core._exceptions import FutureNotFinished as FutureNotFinished + from ._core._exceptions import IncompleteRead as IncompleteRead + from ._core._exceptions import NoEventLoopError as NoEventLoopError + from ._core._exceptions import RunFinishedError as RunFinishedError + from ._core._exceptions import TaskCancelled as TaskCancelled + from ._core._exceptions import TaskFailed as TaskFailed + from ._core._exceptions import TaskNotFinished as TaskNotFinished + from ._core._exceptions import ( + TypedAttributeLookupError as TypedAttributeLookupError, + ) + from ._core._exceptions import WouldBlock as WouldBlock + from ._core._fileio import AsyncFile as AsyncFile + from ._core._fileio import Path as Path + from ._core._fileio import open_file as open_file + from ._core._fileio import wrap_file as wrap_file + from ._core._futures import Future as Future + from ._core._resources import aclose_forcefully as aclose_forcefully + from ._core._signals import open_signal_receiver as open_signal_receiver + from ._core._sockets import TCPConnectable as TCPConnectable + from ._core._sockets import UNIXConnectable as UNIXConnectable + from ._core._sockets import as_connectable as as_connectable + from ._core._sockets import connect_tcp as connect_tcp + from ._core._sockets import connect_unix as connect_unix + from ._core._sockets import ( + create_connected_udp_socket as create_connected_udp_socket, + ) + from ._core._sockets import ( + create_connected_unix_datagram_socket as create_connected_unix_datagram_socket, + ) + from ._core._sockets import create_tcp_listener as create_tcp_listener + from ._core._sockets import create_udp_socket as create_udp_socket + from ._core._sockets import ( + create_unix_datagram_socket as create_unix_datagram_socket, + ) + from ._core._sockets import create_unix_listener as create_unix_listener + from ._core._sockets import getaddrinfo as getaddrinfo + from ._core._sockets import getnameinfo as getnameinfo + from ._core._sockets import notify_closing as notify_closing + from ._core._sockets import wait_readable as wait_readable + from ._core._sockets import wait_socket_readable as wait_socket_readable + from ._core._sockets import wait_socket_writable as wait_socket_writable + from ._core._sockets import wait_writable as wait_writable + from ._core._streams import ( + create_memory_object_stream as create_memory_object_stream, + ) + from ._core._subprocesses import open_process as open_process + from ._core._subprocesses import run_process as run_process + from ._core._synchronization import CapacityLimiter as CapacityLimiter + from ._core._synchronization import ( + CapacityLimiterStatistics as CapacityLimiterStatistics, + ) + from ._core._synchronization import Condition as Condition + from ._core._synchronization import ConditionStatistics as ConditionStatistics + from ._core._synchronization import Event as Event + from ._core._synchronization import EventStatistics as EventStatistics + from ._core._synchronization import Lock as Lock + from ._core._synchronization import LockStatistics as LockStatistics + from ._core._synchronization import ResourceGuard as ResourceGuard + from ._core._synchronization import Semaphore as Semaphore + from ._core._synchronization import SemaphoreStatistics as SemaphoreStatistics + from ._core._tasks import TASK_STATUS_IGNORED as TASK_STATUS_IGNORED + from ._core._tasks import CancelScope as CancelScope + from ._core._tasks import TaskHandle as TaskHandle + from ._core._tasks import create_task_group as create_task_group + from ._core._tasks import current_effective_deadline as current_effective_deadline + from ._core._tasks import fail_after as fail_after + from ._core._tasks import fail_at as fail_at + from ._core._tasks import move_on_after as move_on_after + from ._core._tasks import move_on_at as move_on_at + from ._core._tempfile import NamedTemporaryFile as NamedTemporaryFile + from ._core._tempfile import SpooledTemporaryFile as SpooledTemporaryFile + from ._core._tempfile import TemporaryDirectory as TemporaryDirectory + from ._core._tempfile import TemporaryFile as TemporaryFile + from ._core._tempfile import gettempdir as gettempdir + from ._core._tempfile import gettempdirb as gettempdirb + from ._core._tempfile import mkdtemp as mkdtemp + from ._core._tempfile import mkstemp as mkstemp + from ._core._testing import TaskInfo as TaskInfo + from ._core._testing import get_current_task as get_current_task + from ._core._testing import get_running_tasks as get_running_tasks + from ._core._testing import wait_all_tasks_blocked as wait_all_tasks_blocked + from ._core._typedattr import TypedAttributeProvider as TypedAttributeProvider + from ._core._typedattr import TypedAttributeSet as TypedAttributeSet + from ._core._typedattr import typed_attribute as typed_attribute + + # ruff: isort: off + from . import ( + abc as abc, + ) + from . import ( + from_thread as from_thread, + ) + from . import ( + functools as functools, + ) + from . import ( + itertools as itertools, + ) + from . import ( + lowlevel as lowlevel, + ) + from . import ( + to_interpreter as to_interpreter, + ) + from . import ( + to_process as to_process, + ) + from . import ( + to_thread as to_thread, + ) + + fix_package_names() + set_deprecated_aliases( + { + "BrokenWorkerIntepreter": "anyio.BrokenWorkerInterpreter", + } + ) diff --git a/source/target-vendors/cp312/anyio/_backends/__init__.py b/source/target-vendors/cp312/anyio/_backends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/anyio/_backends/_asyncio.py b/source/target-vendors/cp312/anyio/_backends/_asyncio.py new file mode 100644 index 0000000..7eba257 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_backends/_asyncio.py @@ -0,0 +1,3201 @@ +from __future__ import annotations + +import array +import asyncio +import concurrent.futures +import math +import os +import socket +import sys +import threading +import weakref +from asyncio import ( + AbstractEventLoop, + CancelledError, + all_tasks, + create_task, + current_task, + get_running_loop, + sleep, +) +from asyncio.base_events import _run_until_complete_cb # type: ignore[attr-defined] +from collections import OrderedDict, deque +from collections.abc import ( + AsyncGenerator, + AsyncIterator, + Awaitable, + Callable, + Collection, + Coroutine, + Iterable, + Sequence, +) +from concurrent.futures import Future +from contextlib import AbstractContextManager, suppress +from contextvars import Context, copy_context +from dataclasses import dataclass, field +from functools import partial, wraps +from inspect import ( + CORO_RUNNING, + CORO_SUSPENDED, + getcoroutinestate, +) +from io import IOBase +from os import PathLike +from queue import Queue +from signal import Signals +from socket import AddressFamily, SocketKind +from threading import Thread +from types import CodeType, TracebackType +from typing import ( + IO, + TYPE_CHECKING, + Any, + Literal, + ParamSpec, + TypeVar, + cast, +) +from weakref import WeakKeyDictionary + +from .. import ( + CapacityLimiterStatistics, + EventStatistics, + LockStatistics, + TaskInfo, + abc, +) +from .._core._eventloop import ( + claim_worker_thread, + set_current_async_library, + threadlocals, +) +from .._core._exceptions import ( + BrokenResourceError, + BusyResourceError, + ClosedResourceError, + EndOfStream, + RunFinishedError, + WouldBlock, +) +from .._core._sockets import convert_ipv6_sockaddr +from .._core._streams import create_memory_object_stream +from .._core._synchronization import ( + CapacityLimiter as BaseCapacityLimiter, +) +from .._core._synchronization import Event as BaseEvent +from .._core._synchronization import Lock as BaseLock +from .._core._synchronization import ( + ResourceGuard, + SemaphoreStatistics, +) +from .._core._synchronization import Semaphore as BaseSemaphore +from .._core._tasks import CancelScope as BaseCancelScope +from .._core._tasks import TaskHandle +from ..abc import ( + AsyncBackend, + IPSockAddrType, + SocketListener, + UDPPacketType, + UNIXDatagramPacketType, +) +from ..abc._tasks import call_for_coroutine, get_callable_name, get_coro_name +from ..lowlevel import RunVar, _run_vars + +if TYPE_CHECKING: + from _typeshed import FileDescriptorLike + + from ..abc._eventloop import StrOrBytesPath + from ..streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +else: + FileDescriptorLike = object + +if sys.version_info >= (3, 11): + from asyncio import Runner + from typing import Self, TypeVarTuple, Unpack +else: + import contextvars + import enum + import signal + from asyncio import coroutines, events, exceptions, tasks + + from exceptiongroup import BaseExceptionGroup + from typing_extensions import Self, TypeVarTuple, Unpack + + class _State(enum.Enum): + CREATED = "created" + INITIALIZED = "initialized" + CLOSED = "closed" + + class Runner: + # Copied from CPython 3.11 + def __init__( + self, + *, + debug: bool | None = None, + loop_factory: Callable[[], AbstractEventLoop] | None = None, + ): + self._state = _State.CREATED + self._debug = debug + self._loop_factory = loop_factory + self._loop: AbstractEventLoop | None = None + self._context = None + self._interrupt_count = 0 + self._set_event_loop = False + + def __enter__(self) -> Self: + self._lazy_init() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def close(self) -> None: + """Shutdown and close event loop.""" + loop = self._loop + if self._state is not _State.INITIALIZED or loop is None: + return + try: + _cancel_all_tasks(loop) + loop.run_until_complete(loop.shutdown_asyncgens()) + if hasattr(loop, "shutdown_default_executor"): + loop.run_until_complete(loop.shutdown_default_executor()) + else: + loop.run_until_complete(_shutdown_default_executor(loop)) + finally: + if self._set_event_loop: + events.set_event_loop(None) + loop.close() + self._loop = None + self._state = _State.CLOSED + + def get_loop(self) -> AbstractEventLoop: + """Return embedded event loop.""" + self._lazy_init() + return self._loop + + def run(self, coro: Coroutine[T_Retval], *, context=None) -> T_Retval: + """Run a coroutine inside the embedded event loop.""" + if not coroutines.iscoroutine(coro): + raise ValueError(f"a coroutine was expected, got {coro!r}") + + if events._get_running_loop() is not None: + # fail fast with short traceback + raise RuntimeError( + "Runner.run() cannot be called from a running event loop" + ) + + self._lazy_init() + + if context is None: + context = self._context + task = context.run(self._loop.create_task, coro) + + if ( + threading.current_thread() is threading.main_thread() + and signal.getsignal(signal.SIGINT) is signal.default_int_handler + ): + sigint_handler = partial(self._on_sigint, main_task=task) + try: + signal.signal(signal.SIGINT, sigint_handler) + except ValueError: + # `signal.signal` may throw if `threading.main_thread` does + # not support signals (e.g. embedded interpreter with signals + # not registered - see gh-91880) + sigint_handler = None + else: + sigint_handler = None + + self._interrupt_count = 0 + try: + return self._loop.run_until_complete(task) + except exceptions.CancelledError: + if self._interrupt_count > 0: + uncancel = getattr(task, "uncancel", None) + if uncancel is not None and uncancel() == 0: + raise KeyboardInterrupt # noqa: B904 + raise # CancelledError + finally: + if ( + sigint_handler is not None + and signal.getsignal(signal.SIGINT) is sigint_handler + ): + signal.signal(signal.SIGINT, signal.default_int_handler) + + def _lazy_init(self) -> None: + if self._state is _State.CLOSED: + raise RuntimeError("Runner is closed") + if self._state is _State.INITIALIZED: + return + if self._loop_factory is None: + self._loop = events.new_event_loop() + if not self._set_event_loop: + # Call set_event_loop only once to avoid calling + # attach_loop multiple times on child watchers + events.set_event_loop(self._loop) + self._set_event_loop = True + else: + self._loop = self._loop_factory() + if self._debug is not None: + self._loop.set_debug(self._debug) + self._context = contextvars.copy_context() + self._state = _State.INITIALIZED + + def _on_sigint(self, signum, frame, main_task: asyncio.Task) -> None: + self._interrupt_count += 1 + if self._interrupt_count == 1 and not main_task.done(): + main_task.cancel() + # wakeup loop if it is blocked by select() with long timeout + self._loop.call_soon_threadsafe(lambda: None) + return + raise KeyboardInterrupt() + + def _cancel_all_tasks(loop: AbstractEventLoop) -> None: + to_cancel = tasks.all_tasks(loop) + if not to_cancel: + return + + for task in to_cancel: + task.cancel() + + loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True)) + + for task in to_cancel: + if task.cancelled(): + continue + if task.exception() is not None: + loop.call_exception_handler( + { + "message": "unhandled exception during asyncio.run() shutdown", + "exception": task.exception(), + "task": task, + } + ) + + async def _shutdown_default_executor(loop: AbstractEventLoop) -> None: + """Schedule the shutdown of the default executor.""" + + def _do_shutdown(future: asyncio.futures.Future) -> None: + try: + loop._default_executor.shutdown(wait=True) # type: ignore[attr-defined] + loop.call_soon_threadsafe(future.set_result, None) + except Exception as ex: + loop.call_soon_threadsafe(future.set_exception, ex) + + loop._executor_shutdown_called = True + if loop._default_executor is None: + return + future = loop.create_future() + thread = threading.Thread(target=_do_shutdown, args=(future,)) + thread.start() + try: + await future + finally: + thread.join() + + +T_Retval = TypeVar("T_Retval") +T_co = TypeVar("T_co", covariant=True) +T_contra = TypeVar("T_contra", contravariant=True) +PosArgsT = TypeVarTuple("PosArgsT") +P = ParamSpec("P") + +_root_task: RunVar[asyncio.Task[Any] | None] = RunVar("_root_task") + + +def find_root_task() -> asyncio.Task: + root_task = _root_task.get(None) + if root_task is not None and not root_task.done(): + return root_task + + # Look for a task that has been started via run_until_complete() + for task in all_tasks(): + if task._callbacks and not task.done(): + for cb, context in task._callbacks: + if ( + cb is _run_until_complete_cb + or getattr(cb, "__module__", None) == "uvloop.loop" + ): + _root_task.set(task) + + def _unset(t: asyncio.Task[Any]) -> None: + if vars := _run_vars.get(t.get_loop()): + vars.pop(_root_task, None) + + # Register a callback to break the task -> loop -> _run_var[loop][_root_task] -> task cycle + # Also run it in its own context to not create another reference. + # We can't use RunVar.reset() here since these are called synchronously + # and thus lowlevel.current_token() (which RunVar.reset() depends on) fails. + task.add_done_callback(_unset, context=context) + return task + + # Look up the topmost task in the AnyIO task tree, if possible + task = cast(asyncio.Task, current_task()) + state = _task_states.get(task) + if state: + cancel_scope = state.cancel_scope + while cancel_scope and cancel_scope._parent_scope is not None: + cancel_scope = cancel_scope._parent_scope + + if cancel_scope is not None: + return cast(asyncio.Task, cancel_scope._host_task) + + return task + + +def _task_started(task: asyncio.Task) -> bool: + """Return ``True`` if the task has been started and has not finished.""" + # The task coro should never be None here, as we never add finished tasks to the + # task list + coro = task.get_coro() + assert coro is not None + return getcoroutinestate(coro) in (CORO_RUNNING, CORO_SUSPENDED) + + +# +# Timeouts and cancellation +# + + +def is_anyio_cancellation(exc: CancelledError) -> bool: + # Sometimes third party frameworks catch a CancelledError and raise a new one, so as + # a workaround we have to look at the previous ones in __context__ too for a + # matching cancel message + while True: + if ( + exc.args + and isinstance(exc.args[0], str) + and exc.args[0].startswith("Cancelled via cancel scope ") + ): + return True + + if isinstance(exc.__context__, CancelledError): + exc = exc.__context__ + continue + + return False + + +class CancelScope(BaseCancelScope): + __slots__ = ( + "_active", + "_cancel_called", + "_cancel_handle", + "_cancel_reason", + "_cancelled_caught", + "_child_scopes", + "_deadline", + "_host_task", + "_parent_scope", + "_pending_uncancellations", + "_shield", + "_tasks", + "_timeout_handle", + ) + + def __new__(cls, *, deadline: float = math.inf, shield: bool = False) -> Self: + return object.__new__(cls) + + def __init__(self, deadline: float = math.inf, shield: bool = False): + self._deadline = deadline + self._shield = shield + self._parent_scope: CancelScope | None = None + self._child_scopes: set[CancelScope] = set() + self._cancel_called = False + self._cancel_reason: str | None = None + self._cancelled_caught = False + self._active = False + self._timeout_handle: asyncio.TimerHandle | None = None + self._cancel_handle: asyncio.Handle | None = None + self._tasks: set[asyncio.Task] = set() + self._host_task: asyncio.Task | None = None + if sys.version_info >= (3, 11): + self._pending_uncancellations: int | None = 0 + else: + self._pending_uncancellations = None + + def __enter__(self) -> Self: + if self._active: + raise RuntimeError( + "Each CancelScope may only be used for a single 'with' block" + ) + + self._host_task = host_task = cast(asyncio.Task, current_task()) + self._tasks.add(host_task) + try: + task_state = _task_states[host_task] + except KeyError: + task_state = TaskState(None, self) + _task_states[host_task] = task_state + else: + self._parent_scope = task_state.cancel_scope + task_state.cancel_scope = self + if self._parent_scope is not None: + # If using an eager task factory, the parent scope may not even contain + # the host task + self._parent_scope._child_scopes.add(self) + self._parent_scope._tasks.discard(host_task) + + self._timeout() + self._active = True + + # Start cancelling the host task if the scope was cancelled before entering + if self._cancel_called: + self._deliver_cancellation(self) + + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + del exc_tb + + if not self._active: + raise RuntimeError("This cancel scope is not active") + if current_task() is not self._host_task: + raise RuntimeError( + "Attempted to exit cancel scope in a different task than it was " + "entered in" + ) + + assert self._host_task is not None + host_task_state = _task_states.get(self._host_task) + if host_task_state is None or host_task_state.cancel_scope is not self: + raise RuntimeError( + "Attempted to exit a cancel scope that isn't the current tasks's " + "current cancel scope" + ) + + try: + self._active = False + if self._timeout_handle: + self._timeout_handle.cancel() + self._timeout_handle = None + + self._tasks.remove(self._host_task) + if self._parent_scope is not None: + self._parent_scope._child_scopes.remove(self) + self._parent_scope._tasks.add(self._host_task) + + host_task_state.cancel_scope = self._parent_scope + + # Restart the cancellation effort in the closest visible, cancelled parent + # scope if necessary + self._restart_cancellation_in_parent() + + # We only swallow the exception iff it was an AnyIO CancelledError, either + # directly as exc_val or inside an exception group and there are no cancelled + # parent cancel scopes visible to us here + if self._cancel_called and not self._parent_cancellation_is_visible_to_us: + # For each level-cancel() call made on the host task, call uncancel() + while self._pending_uncancellations: + self._host_task.uncancel() + self._pending_uncancellations -= 1 + + # Update cancelled_caught and check for exceptions we must not swallow + if isinstance(exc_val, BaseExceptionGroup): + cancelleds_caught, remaining = exc_val.split( + lambda exc: ( + isinstance(exc, CancelledError) + and is_anyio_cancellation(exc) + ) + ) + + if cancelleds_caught is None: + return False + + self._cancelled_caught = True + + if remaining is None: + return True + + context = remaining.__context__ + try: + # Preserve __cause__ and __suppress_context__ by avoiding `raise + # ... from ...` + raise remaining + finally: + # Preserve __context__ + remaining.__context__ = context + del context + else: + if isinstance(exc_val, CancelledError) and is_anyio_cancellation( + exc_val + ): + self._cancelled_caught = True + return True + else: + return False + else: + if self._pending_uncancellations: + assert self._parent_scope is not None + assert self._parent_scope._pending_uncancellations is not None + self._parent_scope._pending_uncancellations += ( + self._pending_uncancellations + ) + self._pending_uncancellations = 0 + + return False + finally: + self._host_task = None + del exc_val + + @property + def _effectively_cancelled(self) -> bool: + cancel_scope: CancelScope | None = self + while cancel_scope is not None: + if cancel_scope._cancel_called: + return True + + if cancel_scope.shield: + return False + + cancel_scope = cancel_scope._parent_scope + + return False + + @property + def _parent_cancellation_is_visible_to_us(self) -> bool: + return ( + self._parent_scope is not None + and not self.shield + and self._parent_scope._effectively_cancelled + ) + + def _timeout(self) -> None: + if self._deadline != math.inf: + loop = get_running_loop() + if loop.time() >= self._deadline: + self.cancel("deadline exceeded") + else: + self._timeout_handle = loop.call_at(self._deadline, self._timeout) + + def _deliver_cancellation(self, origin: CancelScope) -> bool: + """ + Deliver cancellation to directly contained tasks and nested cancel scopes. + + Schedule another run at the end if we still have tasks eligible for + cancellation. + + :param origin: the cancel scope that originated the cancellation + :return: ``True`` if the delivery needs to be retried on the next cycle + + """ + should_retry = False + current = current_task() + for task in self._tasks: + # Always skip tasks that are already done (see issue #1111) + if task.done(): + continue + + should_retry = True + if task._must_cancel: # type: ignore[attr-defined] + continue + + # The task is eligible for cancellation if it has started + if task is not current and (task is self._host_task or _task_started(task)): + waiter = task._fut_waiter # type: ignore[attr-defined] + if not isinstance(waiter, asyncio.Future) or not waiter.done(): + task.cancel(origin._cancel_reason) + if ( + task is origin._host_task + and origin._pending_uncancellations is not None + ): + origin._pending_uncancellations += 1 + + # Deliver cancellation to child scopes that aren't shielded or running their own + # cancellation callbacks + for scope in self._child_scopes: + if not scope._shield and not scope.cancel_called: + should_retry = scope._deliver_cancellation(origin) or should_retry + + # Schedule another callback if there are still tasks left + if origin is self: + if should_retry: + self._cancel_handle = get_running_loop().call_soon( + self._deliver_cancellation, origin + ) + else: + self._cancel_handle = None + + return should_retry + + def _restart_cancellation_in_parent(self) -> None: + """ + Restart the cancellation effort in the closest directly cancelled parent scope. + + """ + scope = self._parent_scope + while scope is not None: + if scope._cancel_called: + if scope._cancel_handle is None: + scope._deliver_cancellation(scope) + + break + + # No point in looking beyond any shielded scope + if scope._shield: + break + + scope = scope._parent_scope + + def _reparent(self, new_parent: CancelScope) -> None: + """ + Move this active scope from its current parent to ``new_parent``. + + Used by :meth:`TaskGroup.start` to move a task that has just called + ``task_status.started()`` into the target task group's cancel scope. + """ + if self._parent_scope is new_parent: + return + + if self._parent_scope is not None: + self._parent_scope._child_scopes.discard(self) + + self._parent_scope = new_parent + new_parent._child_scopes.add(self) + + # If the new parent (or an ancestor) is already cancelled, (re)start the + # delivery loop to ensure we're cancelled at next checkpoint like Trio. + self._restart_cancellation_in_parent() + + def cancel(self, reason: str | None = None) -> None: + if not self._cancel_called: + if self._timeout_handle: + self._timeout_handle.cancel() + self._timeout_handle = None + + self._cancel_called = True + self._cancel_reason = f"Cancelled via cancel scope {id(self):x}" + if task := current_task(): + self._cancel_reason += f" by {task}" + + if reason: + self._cancel_reason += f"; reason: {reason}" + + if self._host_task is not None: + self._deliver_cancellation(self) + + @property + def deadline(self) -> float: + return self._deadline + + @deadline.setter + def deadline(self, value: float) -> None: + self._deadline = float(value) + if self._timeout_handle is not None: + self._timeout_handle.cancel() + self._timeout_handle = None + + if self._active and not self._cancel_called: + self._timeout() + + @property + def cancel_called(self) -> bool: + return self._cancel_called + + @property + def cancelled_caught(self) -> bool: + return self._cancelled_caught + + @property + def shield(self) -> bool: + return self._shield + + @shield.setter + def shield(self, value: bool) -> None: + if self._shield != value: + self._shield = value + if not value: + self._restart_cancellation_in_parent() + + +# +# Task states +# + + +class TaskState: + """ + Encapsulates auxiliary task information that cannot be added to the Task instance + itself because there are no guarantees about its implementation. + """ + + __slots__ = "__weakref__", "cancel_scope", "parent_id" + + def __init__(self, parent_id: int | None, cancel_scope: CancelScope | None): + self.parent_id = parent_id + self.cancel_scope = cancel_scope + + +_task_states: WeakKeyDictionary[asyncio.Task, TaskState] = WeakKeyDictionary() + + +# +# Task groups +# + + +class _AsyncioTaskStatus(abc.TaskStatus[T_contra]): + def __init__( + self, + future: asyncio.Future, + parent_id: int, + target_scope: CancelScope, + spawn_scope: CancelScope, + ): + self._future = future + self._parent_id = parent_id + # The eventual parent scope for this spawn_scope + # (after task_status.started() has been called) + self._target_scope = target_scope + # The task's own cancel scope, also held by its TaskHandle + self._spawn_scope = spawn_scope + + def started(self, value: T_contra | None = None) -> None: + task = cast(asyncio.Task, current_task()) + _task_states[task].parent_id = self._parent_id + if self._future.done(): + if not self._future.cancelled(): + raise RuntimeError("called 'started' twice on the same task status") + else: + # Caller of start() was cancelled, nothing to reparent + return + + self._future.set_result(value) + self._spawn_scope._reparent(self._target_scope) + + +if sys.version_info >= (3, 12): + _eager_task_factory_code: CodeType | None = asyncio.eager_task_factory.__code__ +else: + _eager_task_factory_code = None + + +class TaskGroup(abc.TaskGroup): + def __init__(self) -> None: + self.cancel_scope: CancelScope = CancelScope() + self._entered = False + self._exceptions: list[BaseException] = [] + self._tasks: set[asyncio.Task] = set() + self._on_completed_fut: asyncio.Future[None] | None = None + + async def __aenter__(self) -> Self: + if self._entered: + raise RuntimeError("TaskGroup cannot be entered more than once") + + self._entered = True + + self.cancel_scope.__enter__() + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + try: + if exc_val is not None: + self.cancel_scope.cancel() + if not isinstance(exc_val, CancelledError): + self._exceptions.append(exc_val) + + loop = get_running_loop() + try: + if self._tasks: + with CancelScope() as wait_scope: + while self._tasks: + self._on_completed_fut = loop.create_future() + + try: + await self._on_completed_fut + except CancelledError as exc: + # Shield the scope against further cancellation attempts, + # as they're not productive (#695) + wait_scope.shield = True + self.cancel_scope.cancel() + + # Set exc_val from the cancellation exception if it was + # previously unset. However, we should not replace a native + # cancellation exception with one raise by a cancel scope. + if exc_val is None or ( + isinstance(exc_val, CancelledError) + and not is_anyio_cancellation(exc) + ): + exc_val = exc + + self._on_completed_fut = None + else: + # If there are no child tasks to wait on, run at least one checkpoint + # anyway + await AsyncIOBackend.cancel_shielded_checkpoint() + + if self._exceptions: + # The exception that got us here should already have been + # added to self._exceptions so it's ok to break exception + # chaining and avoid adding a "During handling of above..." + # for each nesting level. + raise BaseExceptionGroup( + "unhandled errors in a TaskGroup", self._exceptions + ) from None + elif exc_val: + raise exc_val + except BaseException as exc: + if self.cancel_scope.__exit__(type(exc), exc, exc.__traceback__): + return True + + raise + + return self.cancel_scope.__exit__(exc_type, exc_val, exc_tb) + finally: + del exc_val, exc_tb, self._exceptions + + def _spawn( + self, + coro: Coroutine[Any, Any, T_co], + name: object, + task_status: _AsyncioTaskStatus | None = None, + ) -> TaskHandle[T_co]: + task_status_future = task_status._future if task_status is not None else None + + def task_done(_task: asyncio.Task) -> None: + if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: + asyncio.future_discard_from_awaited_by( + _task, self.cancel_scope._host_task + ) + + task_state = _task_states[_task] + assert task_state.cancel_scope is not None + assert _task in task_state.cancel_scope._tasks + task_state.cancel_scope._tasks.remove(_task) + self._tasks.remove(task) + del _task_states[_task] + + if self._on_completed_fut is not None and not self._tasks: + try: + self._on_completed_fut.set_result(None) + except asyncio.InvalidStateError: + pass + + try: + exc = _task.exception() + except CancelledError as e: + while isinstance(e.__context__, CancelledError): + e = e.__context__ + + exc = e + + if exc is not None: + # The future can only be in the cancelled state if the host task was + # cancelled, so return immediately instead of adding one more + # CancelledError to the exceptions list + if task_status_future is not None and task_status_future.cancelled(): + return + + if task_status_future is None or task_status_future.done(): + if not isinstance(exc, CancelledError): + self._exceptions.append(exc) + + if not self.cancel_scope._effectively_cancelled: + self.cancel_scope.cancel() + else: + task_status_future.set_exception(exc) + elif task_status_future is not None and not task_status_future.done(): + task_status_future.set_exception( + RuntimeError("Child exited without calling task_status.started()") + ) + + if task_status_future is not None: + parent_id = id(current_task()) + caller_state = _task_states.get(cast(asyncio.Task, current_task())) + if caller_state is not None and caller_state.cancel_scope is not None: + initial_scope = caller_state.cancel_scope + else: + # The caller is an unmanaged task (no task state) + initial_scope = self.cancel_scope + else: + parent_id = id(self.cancel_scope._host_task) + initial_scope = self.cancel_scope + + spawn_scope = task_status._spawn_scope if task_status is not None else None + handle = TaskHandle(coro, name, cancel_scope=spawn_scope) + loop = asyncio.get_running_loop() + wrapper_coro = handle._run_coro() + try: + if ( + (factory := loop.get_task_factory()) + and getattr(factory, "__code__", None) is _eager_task_factory_code + and (closure := getattr(factory, "__closure__", None)) + ): + custom_task_constructor = closure[0].cell_contents + task = custom_task_constructor( + wrapper_coro, loop=loop, name=handle.name + ) + else: + task = loop.create_task(wrapper_coro, name=handle.name) + except BaseException: + with suppress(BaseException): + wrapper_coro.close() + + with suppress(BaseException): + coro.close() + + raise + + # Make the spawned task inherit the initial cancel scope + _task_states[task] = TaskState(parent_id=parent_id, cancel_scope=initial_scope) + initial_scope._tasks.add(task) + self._tasks.add(task) + if sys.version_info >= (3, 14) and self.cancel_scope._host_task is not None: + asyncio.future_add_to_awaited_by(task, self.cancel_scope._host_task) + + task.add_done_callback(task_done) + return handle + + def create_task( + self, + coro: Coroutine[Any, Any, T_co], + *, + name: object = None, + context: Context | None = None, + ) -> TaskHandle[T_co]: + if not isinstance(coro, Coroutine): + raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}") + + if not self._entered or not self.cancel_scope._active: + coro.close() + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + final_name = get_coro_name(coro, name) + + if context is not None: + return context.run(self._spawn, coro, name=final_name) + else: + return self._spawn(coro, name=final_name) + + async def start( + self, + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + *args: Unpack[PosArgsT], + name: object = None, + return_handle: Literal[False, True] = False, + ) -> Any: + if not self._entered or not self.cancel_scope._active: + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + # Until task_status.started() is called, a task spawned via start() belongs to + # the *caller's* cancel scope, not the target group's, so cancelling the group + # does not cancel a task that hasn't reported startup yet. The + # task_status.started() call moves the task's cancel scope to this task group's + # cancel scope. + # + # The caller may be an unmanaged task (no _task_states entry), in which case + # fall back to the group's own scope. + future: asyncio.Future = asyncio.Future() + final_name = get_callable_name(func, name) + task_status: _AsyncioTaskStatus[Any] = _AsyncioTaskStatus( + future, id(self.cancel_scope._host_task), self.cancel_scope, CancelScope() + ) + coro = call_for_coroutine(func, args, task_status=task_status) + handle = self._spawn(coro, final_name, task_status) + + # If the task raises an exception after sending a start value without a switch + # point between, the task group is cancelled and this method never proceeds to + # process the completed future. That's why we have to have a shielded cancel + # scope here. + try: + await future + except BaseException: + if handle.status is TaskHandle.Status.PENDING: + # Cancel the task and wait for it to exit before returning + handle.cancel() + with CancelScope(shield=True): + await handle.wait() + + raise + + if return_handle: + handle._start_value = future.result() + return handle + else: + return future.result() + + +# +# Threads +# + +_Retval_Queue_Type = tuple[T_Retval | None, BaseException | None] + + +class WorkerThread(Thread): + MAX_IDLE_TIME = 10 # seconds + + def __init__( + self, + root_task: asyncio.Task, + workers: set[WorkerThread], + idle_workers: deque[WorkerThread], + ): + kwargs: dict[str, Any] = {} + if sys.version_info >= (3, 14): + kwargs["context"] = Context() + + super().__init__(name="AnyIO worker thread", **kwargs) + self.root_task = root_task + self.workers = workers + self.idle_workers = idle_workers + self.loop = root_task._loop + self.queue: Queue[ + tuple[Context, Callable, tuple, asyncio.Future, CancelScope] | None + ] = Queue(2) + self.idle_since = AsyncIOBackend.current_time() + self.stopping = False + + def _report_result( + self, future: asyncio.Future, result: Any, exc: BaseException | None + ) -> None: + self.idle_since = AsyncIOBackend.current_time() + if not self.stopping: + self.idle_workers.append(self) + + if not future.cancelled(): + if exc is not None: + if isinstance(exc, StopIteration): + new_exc = RuntimeError("coroutine raised StopIteration") + new_exc.__cause__ = exc + exc = new_exc + + future.set_exception(exc) + else: + future.set_result(result) + + def run(self) -> None: + with claim_worker_thread(AsyncIOBackend, self.loop): + while True: + item = self.queue.get() + if item is None: + # Shutdown command received + return + + context, func, args, future, cancel_scope = item + if not future.cancelled(): + result = None + exception: BaseException | None = None + threadlocals.current_cancel_scope = cancel_scope + try: + result = context.run(func, *args) + except BaseException as exc: + exception = exc + finally: + del threadlocals.current_cancel_scope + + try: + self.loop.call_soon_threadsafe( + self._report_result, future, result, exception + ) + except RuntimeError: + if not self.loop.is_closed(): + raise + + del result, exception + + self.queue.task_done() + del item, context, func, args, future, cancel_scope + + def stop(self, f: asyncio.Task | None = None) -> None: + self.stopping = True + self.queue.put_nowait(None) + self.workers.discard(self) + try: + self.idle_workers.remove(self) + except ValueError: + pass + + +_threadpool_idle_workers: RunVar[deque[WorkerThread]] = RunVar( + "_threadpool_idle_workers" +) +_threadpool_workers: RunVar[set[WorkerThread]] = RunVar("_threadpool_workers") + + +# +# Subprocesses +# + + +@dataclass(eq=False) +class StreamReaderWrapper(abc.ByteReceiveStream): + _stream: asyncio.StreamReader + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + data = await self._stream.read(max_bytes) + if data: + return data + else: + raise EndOfStream + + async def aclose(self) -> None: + self._stream.set_exception(ClosedResourceError()) + await AsyncIOBackend.checkpoint() + + +@dataclass(eq=False) +class StreamWriterWrapper(abc.ByteSendStream): + _stream: asyncio.StreamWriter + _closed: bool = field(init=False, default=False) + + async def send(self, item: bytes) -> None: + await AsyncIOBackend.checkpoint_if_cancelled() + stream_paused = self._stream._protocol._paused # type: ignore[attr-defined] + try: + self._stream.write(item) + await self._stream.drain() + except (ConnectionResetError, BrokenPipeError, RuntimeError) as exc: + # If closed by us and/or the peer: + # * on stdlib, drain() raises ConnectionResetError or BrokenPipeError + # * on uvloop and Winloop, write() eventually starts raising RuntimeError + if self._closed: + raise ClosedResourceError from exc + elif self._stream.is_closing(): + raise BrokenResourceError from exc + + raise + + if not stream_paused: + await AsyncIOBackend.cancel_shielded_checkpoint() + + async def aclose(self) -> None: + self._closed = True + self._stream.close() + await AsyncIOBackend.checkpoint() + + +@dataclass(eq=False) +class Process(abc.Process): + _process: asyncio.subprocess.Process + _stdin: StreamWriterWrapper | None + _stdout: StreamReaderWrapper | None + _stderr: StreamReaderWrapper | None + _exited: asyncio.Event + _transport: asyncio.SubprocessTransport + + async def aclose(self) -> None: + with CancelScope(shield=True) as scope: + # We need to close the underlying pipe_transports as well to allow a + # process blocking on full buffers to receive SIGPIPE and exit. + if self._stdin: + await self._stdin.aclose() + if pipe := self._transport.get_pipe_transport(0): + pipe.close() + if self._stdout: + await self._stdout.aclose() + if pipe := self._transport.get_pipe_transport(1): + pipe.close() + if self._stderr: + await self._stderr.aclose() + if pipe := self._transport.get_pipe_transport(2): + pipe.close() + + scope.shield = False + try: + await self.wait() + except BaseException: + scope.shield = True + # Closing the transport on asyncio also handles sending kill + self._transport.close() + await self.wait() + raise + + async def wait(self) -> int: + await self._exited.wait() + assert self._process.returncode is not None + return self._process.returncode + + def terminate(self) -> None: + self._process.terminate() + + def kill(self) -> None: + self._process.kill() + + def send_signal(self, signal: int) -> None: + self._process.send_signal(signal) + + @property + def pid(self) -> int: + return self._process.pid + + @property + def returncode(self) -> int | None: + return self._process.returncode + + @property + def stdin(self) -> abc.ByteSendStream | None: + return self._stdin + + @property + def stdout(self) -> abc.ByteReceiveStream | None: + return self._stdout + + @property + def stderr(self) -> abc.ByteReceiveStream | None: + return self._stderr + + +def _forcibly_shutdown_process_pool_on_exit( + workers: set[Process], _task: object +) -> None: + """ + Forcibly shuts down worker processes belonging to this event loop.""" + child_watcher: asyncio.AbstractChildWatcher | None = None # type: ignore[name-defined] + if sys.version_info < (3, 12): + try: + child_watcher = asyncio.get_event_loop_policy().get_child_watcher() + except NotImplementedError: + pass + + # Close as much as possible (w/o async/await) to avoid warnings + for process in workers.copy(): + if process.returncode is not None: + continue + + process._stdin._stream._transport.close() # type: ignore[union-attr] + process._stdout._stream._transport.close() # type: ignore[union-attr] + process._stderr._stream._transport.close() # type: ignore[union-attr] + process.kill() + if child_watcher: + child_watcher.remove_child_handler(process.pid) + + +async def _shutdown_process_pool_on_exit(workers: set[abc.Process]) -> None: + """ + Shuts down worker processes belonging to this event loop. + + NOTE: this only works when the event loop was started using asyncio.run() or + anyio.run(). + + """ + process: abc.Process + try: + await sleep(math.inf) + except asyncio.CancelledError: + workers = workers.copy() + for process in workers: + if process.returncode is None: + process.kill() + + for process in workers: + await process.aclose() + + +# +# Sockets and networking +# + + +class StreamProtocol(asyncio.Protocol): + read_queue: deque[bytes] + read_event: asyncio.Event + write_event: asyncio.Event + exception: Exception | None = None + is_at_eof: bool = False + + def connection_made(self, transport: asyncio.BaseTransport) -> None: + self.read_queue = deque() + self.read_event = asyncio.Event() + self.write_event = asyncio.Event() + self.write_event.set() + cast(asyncio.Transport, transport).set_write_buffer_limits(0) + + def connection_lost(self, exc: Exception | None) -> None: + if exc: + self.exception = exc + + self.read_event.set() + self.write_event.set() + + def data_received(self, data: bytes) -> None: + # ProactorEventloop sometimes sends bytearray instead of bytes + self.read_queue.append(bytes(data)) + self.read_event.set() + + def eof_received(self) -> bool | None: + self.is_at_eof = True + self.read_event.set() + return True + + def pause_writing(self) -> None: + self.write_event = asyncio.Event() + + def resume_writing(self) -> None: + self.write_event.set() + + +class DatagramProtocol(asyncio.DatagramProtocol): + read_queue: deque[tuple[bytes, IPSockAddrType]] + read_event: asyncio.Event + write_event: asyncio.Event + closed_event: asyncio.Event + exception: Exception | None = None + + def connection_made(self, transport: asyncio.BaseTransport) -> None: + self.read_queue = deque(maxlen=100) # arbitrary value + self.read_event = asyncio.Event() + self.write_event = asyncio.Event() + self.closed_event = asyncio.Event() + self.write_event.set() + + def connection_lost(self, exc: Exception | None) -> None: + self.read_event.set() + self.write_event.set() + self.closed_event.set() + + def datagram_received(self, data: bytes, addr: IPSockAddrType) -> None: + addr = convert_ipv6_sockaddr(addr) + self.read_queue.append((data, addr)) + self.read_event.set() + + def error_received(self, exc: Exception) -> None: + self.exception = exc + + def pause_writing(self) -> None: + self.write_event.clear() + + def resume_writing(self) -> None: + self.write_event.set() + + +class SocketStream(abc.SocketStream): + def __init__(self, transport: asyncio.Transport, protocol: StreamProtocol): + self._transport = transport + self._protocol = protocol + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + self._closed = False + + @property + def _raw_socket(self) -> socket.socket: + return self._transport.get_extra_info("socket") + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + with self._receive_guard: + if ( + not self._protocol.read_event.is_set() + and not self._transport.is_closing() + and not self._protocol.is_at_eof + ): + self._transport.resume_reading() + await self._protocol.read_event.wait() + self._transport.pause_reading() + else: + await AsyncIOBackend.checkpoint() + + try: + chunk = self._protocol.read_queue.popleft() + except IndexError: + if self._closed: + raise ClosedResourceError from None + elif self._protocol.exception: + raise BrokenResourceError from self._protocol.exception + else: + raise EndOfStream from None + + if len(chunk) > max_bytes: + # Split the oversized chunk + chunk, leftover = chunk[:max_bytes], chunk[max_bytes:] + self._protocol.read_queue.appendleft(leftover) + + # If the read queue is empty, clear the flag so that the next call will + # block until data is available + if not self._protocol.read_queue: + self._protocol.read_event.clear() + + return chunk + + async def send(self, item: bytes) -> None: + with self._send_guard: + await AsyncIOBackend.checkpoint() + + if self._closed: + raise ClosedResourceError + elif self._protocol.exception is not None: + raise BrokenResourceError from self._protocol.exception + + try: + self._transport.write(item) + except RuntimeError as exc: + if self._transport.is_closing(): + raise BrokenResourceError from exc + else: + raise + + await self._protocol.write_event.wait() + + async def send_eof(self) -> None: + try: + self._transport.write_eof() + except OSError: + pass + + async def aclose(self) -> None: + self._closed = True + if not self._transport.is_closing(): + try: + self._transport.write_eof() + except OSError: + pass + + self._transport.close() + await sleep(0) + self._transport.abort() + + +class _RawSocketMixin: + _receive_future: asyncio.Future | None = None + _send_future: asyncio.Future | None = None + _closing = False + + def __init__(self, raw_socket: socket.socket): + self.__raw_socket = raw_socket + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + @property + def _raw_socket(self) -> socket.socket: + return self.__raw_socket + + def _wait_until_readable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: + def callback(f: object) -> None: + del self._receive_future + loop.remove_reader(self.__raw_socket) + + f = self._receive_future = asyncio.Future() + loop.add_reader(self.__raw_socket, f.set_result, None) + f.add_done_callback(callback) + return f + + def _wait_until_writable(self, loop: asyncio.AbstractEventLoop) -> asyncio.Future: + def callback(f: object) -> None: + del self._send_future + loop.remove_writer(self.__raw_socket) + + f = self._send_future = asyncio.Future() + loop.add_writer(self.__raw_socket, f.set_result, None) + f.add_done_callback(callback) + return f + + async def aclose(self) -> None: + if not self._closing: + self._closing = True + if self.__raw_socket.fileno() != -1: + self.__raw_socket.close() + + if self._receive_future and not self._receive_future.done(): + self._receive_future.set_result(None) + if self._send_future and not self._send_future.done(): + self._send_future.set_result(None) + + +class UNIXSocketStream(_RawSocketMixin, abc.UNIXSocketStream): + async def send_eof(self) -> None: + with self._send_guard: + self._raw_socket.shutdown(socket.SHUT_WR) + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + loop = get_running_loop() + await AsyncIOBackend.checkpoint() + with self._receive_guard: + while True: + try: + data = self._raw_socket.recv(max_bytes) + except BlockingIOError: + await self._wait_until_readable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + if not data: + raise EndOfStream + + return data + + async def send(self, item: bytes) -> None: + loop = get_running_loop() + await AsyncIOBackend.checkpoint() + with self._send_guard: + view = memoryview(item) + while view: + try: + bytes_sent = self._raw_socket.send(view) + except BlockingIOError: + await self._wait_until_writable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + view = view[bytes_sent:] + + async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: + if not isinstance(msglen, int) or msglen < 0: + raise ValueError("msglen must be a non-negative integer") + if not isinstance(maxfds, int) or maxfds < 1: + raise ValueError("maxfds must be a positive integer") + + loop = get_running_loop() + fds = array.array("i") + await AsyncIOBackend.checkpoint() + with self._receive_guard: + while True: + try: + message, ancdata, _flags, _addr = self._raw_socket.recvmsg( + msglen, socket.CMSG_LEN(maxfds * fds.itemsize) + ) + except BlockingIOError: + await self._wait_until_readable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + if not message and not ancdata: + raise EndOfStream + + break + + for cmsg_level, cmsg_type, cmsg_data in ancdata: + if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: + raise RuntimeError( + f"Received unexpected ancillary data; message = {message!r}, " + f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" + ) + + fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) + + return message, list(fds) + + async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: + if not message: + raise ValueError("message must not be empty") + if not fds: + raise ValueError("fds must not be empty") + + loop = get_running_loop() + filenos: list[int] = [] + for fd in fds: + if isinstance(fd, int): + filenos.append(fd) + elif isinstance(fd, IOBase): + filenos.append(fd.fileno()) + + fdarray = array.array("i", filenos) + await AsyncIOBackend.checkpoint() + with self._send_guard: + while True: + try: + # The ignore can be removed after mypy picks up + # https://github.com/python/typeshed/pull/5545 + self._raw_socket.sendmsg( + [message], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, fdarray)] + ) + break + except BlockingIOError: + await self._wait_until_writable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + + +class TCPSocketListener(abc.SocketListener): + _accept_scope: CancelScope | None = None + _closed = False + + def __init__(self, raw_socket: socket.socket): + self.__raw_socket = raw_socket + self._loop = cast(asyncio.BaseEventLoop, get_running_loop()) + self._accept_guard = ResourceGuard("accepting connections from") + + @property + def _raw_socket(self) -> socket.socket: + return self.__raw_socket + + async def accept(self) -> abc.SocketStream: + if self._closed: + raise ClosedResourceError + + with self._accept_guard: + await AsyncIOBackend.checkpoint() + with CancelScope() as self._accept_scope: + try: + client_sock, _addr = await self._loop.sock_accept(self._raw_socket) + except asyncio.CancelledError: + # Workaround for https://bugs.python.org/issue41317 + try: + self._loop.remove_reader(self._raw_socket) + except (ValueError, NotImplementedError): + pass + + if self._closed: + raise ClosedResourceError from None + + raise + finally: + self._accept_scope = None + + client_sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + transport, protocol = await self._loop.connect_accepted_socket( + StreamProtocol, client_sock + ) + return SocketStream(transport, protocol) + + async def aclose(self) -> None: + if self._closed: + return + + self._closed = True + if self._accept_scope: + # Workaround for https://bugs.python.org/issue41317 + try: + self._loop.remove_reader(self._raw_socket) + except (ValueError, NotImplementedError): + pass + + self._accept_scope.cancel() + await sleep(0) + + self._raw_socket.close() + + +class UNIXSocketListener(abc.SocketListener): + def __init__(self, raw_socket: socket.socket): + self.__raw_socket = raw_socket + self._loop = get_running_loop() + self._accept_guard = ResourceGuard("accepting connections from") + self._closed = False + + async def accept(self) -> abc.SocketStream: + await AsyncIOBackend.checkpoint() + with self._accept_guard: + while True: + try: + client_sock, _ = self.__raw_socket.accept() + client_sock.setblocking(False) + return UNIXSocketStream(client_sock) + except BlockingIOError: + f: asyncio.Future = asyncio.Future() + self._loop.add_reader(self.__raw_socket, f.set_result, None) + f.add_done_callback( + lambda _: self._loop.remove_reader(self.__raw_socket) + ) + await f + except OSError as exc: + if self._closed: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + + async def aclose(self) -> None: + self._closed = True + self.__raw_socket.close() + + @property + def _raw_socket(self) -> socket.socket: + return self.__raw_socket + + +class UDPSocket(abc.UDPSocket): + def __init__( + self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol + ): + self._transport = transport + self._protocol = protocol + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + self._closed = False + + @property + def _raw_socket(self) -> socket.socket: + return self._transport.get_extra_info("socket") + + async def aclose(self) -> None: + self._closed = True + if not self._transport.is_closing(): + self._transport.close() + + await self._protocol.closed_event.wait() + + async def receive(self) -> tuple[bytes, IPSockAddrType]: + with self._receive_guard: + await AsyncIOBackend.checkpoint() + + # If the buffer is empty, ask for more data + if not self._protocol.read_queue and not self._transport.is_closing(): + self._protocol.read_event.clear() + await self._protocol.read_event.wait() + + try: + return self._protocol.read_queue.popleft() + except IndexError: + if self._closed: + raise ClosedResourceError from None + else: + raise BrokenResourceError from None + + async def send(self, item: UDPPacketType) -> None: + with self._send_guard: + await AsyncIOBackend.checkpoint() + await self._protocol.write_event.wait() + if self._closed: + raise ClosedResourceError + elif self._transport.is_closing(): + raise BrokenResourceError + else: + self._transport.sendto(*item) + + +class ConnectedUDPSocket(abc.ConnectedUDPSocket): + def __init__( + self, transport: asyncio.DatagramTransport, protocol: DatagramProtocol + ): + self._transport = transport + self._protocol = protocol + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + self._closed = False + + @property + def _raw_socket(self) -> socket.socket: + return self._transport.get_extra_info("socket") + + async def aclose(self) -> None: + self._closed = True + if not self._transport.is_closing(): + self._transport.close() + + await self._protocol.closed_event.wait() + + async def receive(self) -> bytes: + with self._receive_guard: + await AsyncIOBackend.checkpoint() + + # If the buffer is empty, ask for more data + if not self._protocol.read_queue and not self._transport.is_closing(): + self._protocol.read_event.clear() + await self._protocol.read_event.wait() + + try: + packet = self._protocol.read_queue.popleft() + except IndexError: + if self._closed: + raise ClosedResourceError from None + else: + raise BrokenResourceError from None + + return packet[0] + + async def send(self, item: bytes) -> None: + with self._send_guard: + await AsyncIOBackend.checkpoint() + await self._protocol.write_event.wait() + if self._closed: + raise ClosedResourceError + elif self._transport.is_closing(): + raise BrokenResourceError + else: + self._transport.sendto(item) + + +class UNIXDatagramSocket(_RawSocketMixin, abc.UNIXDatagramSocket): + async def receive(self) -> UNIXDatagramPacketType: + loop = get_running_loop() + await AsyncIOBackend.checkpoint() + with self._receive_guard: + while True: + try: + data = self._raw_socket.recvfrom(65536) + except BlockingIOError: + await self._wait_until_readable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + return data + + async def send(self, item: UNIXDatagramPacketType) -> None: + loop = get_running_loop() + await AsyncIOBackend.checkpoint() + with self._send_guard: + while True: + try: + self._raw_socket.sendto(*item) + except BlockingIOError: + await self._wait_until_writable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + return + + +class ConnectedUNIXDatagramSocket(_RawSocketMixin, abc.ConnectedUNIXDatagramSocket): + async def receive(self) -> bytes: + loop = get_running_loop() + await AsyncIOBackend.checkpoint() + with self._receive_guard: + while True: + try: + data = self._raw_socket.recv(65536) + except BlockingIOError: + await self._wait_until_readable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + return data + + async def send(self, item: bytes) -> None: + loop = get_running_loop() + await AsyncIOBackend.checkpoint() + with self._send_guard: + while True: + try: + self._raw_socket.send(item) + except BlockingIOError: + await self._wait_until_writable(loop) + except OSError as exc: + if self._closing: + raise ClosedResourceError from None + else: + raise BrokenResourceError from exc + else: + return + + +_read_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("read_events") +_write_events: RunVar[dict[int, asyncio.Future[bool]]] = RunVar("write_events") + + +# +# Synchronization +# + + +class Event(BaseEvent): + __slots__ = ("_event",) + + def __new__(cls) -> Self: + return object.__new__(cls) + + def __init__(self) -> None: + self._event = asyncio.Event() + + def set(self) -> None: + self._event.set() + + def is_set(self) -> bool: + return self._event.is_set() + + async def wait(self) -> None: + if self.is_set(): + await AsyncIOBackend.checkpoint() + else: + await self._event.wait() + + def statistics(self) -> EventStatistics: + return EventStatistics(len(self._event._waiters)) + + +class Lock(BaseLock): + __slots__ = "_fast_acquire", "_owner_task", "_waiters" + + def __new__(cls, *, fast_acquire: bool = False) -> Self: + return object.__new__(cls) + + def __init__(self, *, fast_acquire: bool = False) -> None: + self._fast_acquire = fast_acquire + self._owner_task: asyncio.Task | None = None + self._waiters: deque[tuple[asyncio.Task, asyncio.Future]] = deque() + + async def acquire(self) -> None: + task = cast(asyncio.Task, current_task()) + if self._owner_task is None and not self._waiters: + await AsyncIOBackend.checkpoint_if_cancelled() + self._owner_task = task + + # Unless on the "fast path", yield control of the event loop so that other + # tasks can run too + if not self._fast_acquire: + try: + await AsyncIOBackend.cancel_shielded_checkpoint() + except CancelledError: + self.release() + raise + + return + + if self._owner_task == task: + raise RuntimeError("Attempted to acquire an already held Lock") + + fut: asyncio.Future[None] = asyncio.Future() + item = task, fut + self._waiters.append(item) + try: + await fut + except CancelledError: + if fut.cancelled(): + try: + self._waiters.remove(item) + except ValueError: + pass + else: + self.release() + + raise + + def acquire_nowait(self) -> None: + task = cast(asyncio.Task, current_task()) + if self._owner_task is None and not self._waiters: + self._owner_task = task + return + + if self._owner_task is task: + raise RuntimeError("Attempted to acquire an already held Lock") + + raise WouldBlock + + def locked(self) -> bool: + return self._owner_task is not None + + def release(self) -> None: + if self._owner_task != current_task(): + raise RuntimeError("The current task is not holding this lock") + + # A cancelled waiter that already received ownership removes itself from + # _waiters before calling release(); any cancelled waiter still queued here + # was cancelled before being woken, so drop it. + while self._waiters: + task, fut = self._waiters.popleft() + if fut.cancelled(): + continue + + self._owner_task = task + fut.set_result(None) + return + + self._owner_task = None + + def statistics(self) -> LockStatistics: + task_info = AsyncIOTaskInfo(self._owner_task) if self._owner_task else None + return LockStatistics(self.locked(), task_info, len(self._waiters)) + + +class Semaphore(BaseSemaphore): + __slots__ = "_fast_acquire", "_max_value", "_value", "_waiters" + + def __new__( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> Self: + return object.__new__(cls) + + def __init__( + self, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ): + super().__init__(initial_value, max_value=max_value) + self._value = initial_value + self._max_value = max_value + self._fast_acquire = fast_acquire + self._waiters: deque[asyncio.Future[None]] = deque() + + async def acquire(self) -> None: + if self._value > 0 and not self._waiters: + await AsyncIOBackend.checkpoint_if_cancelled() + self._value -= 1 + + # Unless on the "fast path", yield control of the event loop so that other + # tasks can run too + if not self._fast_acquire: + try: + await AsyncIOBackend.cancel_shielded_checkpoint() + except CancelledError: + self.release() + raise + + return + + fut: asyncio.Future[None] = asyncio.Future() + self._waiters.append(fut) + try: + await fut + except CancelledError: + if fut.cancelled(): + try: + self._waiters.remove(fut) + except ValueError: + pass + else: + self.release() + + raise + + def acquire_nowait(self) -> None: + if self._value == 0: + raise WouldBlock + + self._value -= 1 + + def release(self) -> None: + if self._max_value is not None and self._value == self._max_value: + raise ValueError("semaphore released too many times") + + while self._waiters: + fut = self._waiters.popleft() + if fut.cancelled(): + continue + + fut.set_result(None) + return + + self._value += 1 + + @property + def value(self) -> int: + return self._value + + @property + def max_value(self) -> int | None: + return self._max_value + + def statistics(self) -> SemaphoreStatistics: + return SemaphoreStatistics(len(self._waiters)) + + +class CapacityLimiter(BaseCapacityLimiter): + __slots__ = "_borrowers", "_total_tokens", "_wait_queue" + + def __new__(cls, total_tokens: float) -> Self: + return object.__new__(cls) + + def __init__(self, total_tokens: float): + self._total_tokens: float = 0 + self._borrowers: set[Any] = set() + self._wait_queue: OrderedDict[Any, asyncio.Event] = OrderedDict() + self.total_tokens = total_tokens + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.release() + + @property + def total_tokens(self) -> float: + return self._total_tokens + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + if not isinstance(value, int) and not math.isinf(value): + raise TypeError("total_tokens must be an int or math.inf") + + if value < 0: + raise ValueError("total_tokens must be >= 0") + + self._total_tokens = value + + # Notify waiting tasks that they have acquired the limiter while + # there is spare capacity. + while self._wait_queue and len(self._borrowers) < self._total_tokens: + borrower, event = self._wait_queue.popitem(last=False) + self._borrowers.add(borrower) + event.set() + + @property + def borrowed_tokens(self) -> int: + return len(self._borrowers) + + @property + def available_tokens(self) -> float: + return self._total_tokens - len(self._borrowers) + + def _notify_next_waiter(self) -> None: + """Hand a free token to the next task in line, if any.""" + if self._wait_queue and len(self._borrowers) < self._total_tokens: + borrower, event = self._wait_queue.popitem(last=False) + self._borrowers.add(borrower) + event.set() + + def acquire_nowait(self) -> None: + self.acquire_on_behalf_of_nowait(current_task()) + + def acquire_on_behalf_of_nowait(self, borrower: object) -> None: + if borrower in self._borrowers: + raise RuntimeError( + "this borrower is already holding one of this CapacityLimiter's tokens" + ) + + if self._wait_queue or len(self._borrowers) >= self._total_tokens: + raise WouldBlock + + self._borrowers.add(borrower) + + async def acquire(self) -> None: + return await self.acquire_on_behalf_of(current_task()) + + async def acquire_on_behalf_of(self, borrower: object) -> None: + await AsyncIOBackend.checkpoint_if_cancelled() + try: + self.acquire_on_behalf_of_nowait(borrower) + except WouldBlock: + event = asyncio.Event() + self._wait_queue[borrower] = event + try: + await event.wait() + except BaseException: + self._wait_queue.pop(borrower, None) + if event.is_set(): + self._borrowers.discard(borrower) + self._notify_next_waiter() + + raise + else: + try: + await AsyncIOBackend.cancel_shielded_checkpoint() + except BaseException: + self.release() + raise + + def release(self) -> None: + self.release_on_behalf_of(current_task()) + + def release_on_behalf_of(self, borrower: object) -> None: + try: + self._borrowers.remove(borrower) + except KeyError: + raise RuntimeError( + "this borrower isn't holding any of this CapacityLimiter's tokens" + ) from None + + self._notify_next_waiter() + + def statistics(self) -> CapacityLimiterStatistics: + return CapacityLimiterStatistics( + self.borrowed_tokens, + self.total_tokens, + tuple(self._borrowers), + len(self._wait_queue), + ) + + +_default_thread_limiter: RunVar[CapacityLimiter] = RunVar("_default_thread_limiter") + + +# +# Operating system signals +# + + +class _SignalReceiver: + def __init__(self, signals: tuple[Signals, ...]): + self._signals = signals + self._loop = get_running_loop() + self._signal_queue: deque[Signals] = deque() + self._future: asyncio.Future = asyncio.Future() + self._handled_signals: set[Signals] = set() + + def _deliver(self, signum: Signals) -> None: + self._signal_queue.append(signum) + if not self._future.done(): + self._future.set_result(None) + + def __enter__(self) -> Self: + for sig in set(self._signals): + self._loop.add_signal_handler(sig, self._deliver, sig) + self._handled_signals.add(sig) + + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + for sig in self._handled_signals: + self._loop.remove_signal_handler(sig) + + def __aiter__(self) -> _SignalReceiver: + return self + + async def __anext__(self) -> Signals: + await AsyncIOBackend.checkpoint() + if not self._signal_queue: + self._future = asyncio.Future() + await self._future + + return self._signal_queue.popleft() + + +# +# Testing and debugging +# + + +class AsyncIOTaskInfo(TaskInfo): + def __init__(self, task: asyncio.Task): + task_state = _task_states.get(task) + if task_state is None: + parent_id = None + else: + parent_id = task_state.parent_id + + coro = task.get_coro() + assert coro is not None, "created TaskInfo from a completed Task" + super().__init__(id(task), parent_id, task.get_name(), coro) + self._task = weakref.ref(task) + + def has_pending_cancellation(self) -> bool: + if not (task := self._task()): + # If the task isn't around anymore, it won't have a pending cancellation + return False + + if task._must_cancel or ( # type: ignore[attr-defined] + isinstance(task._fut_waiter, asyncio.Future) # type: ignore[attr-defined] + and task._fut_waiter.cancelled() # type: ignore[attr-defined] + ): + return True + + if task_state := _task_states.get(task): + if cancel_scope := task_state.cancel_scope: + return cancel_scope._effectively_cancelled + + return False + + +class TestRunner(abc.TestRunner): + _send_stream: MemoryObjectSendStream[tuple[Awaitable[Any], asyncio.Future[Any]]] + + def __init__( + self, + *, + debug: bool | None = None, + use_uvloop: bool = False, + loop_factory: Callable[[], AbstractEventLoop] | None = None, + ) -> None: + if use_uvloop and loop_factory is None: + if sys.platform != "win32": + import uvloop + + loop_factory = uvloop.new_event_loop + else: + import winloop + + loop_factory = winloop.new_event_loop + + self._runner = Runner(debug=debug, loop_factory=loop_factory) + self._exceptions: list[BaseException] = [] + self._runner_task: asyncio.Task | None = None + + def __enter__(self) -> Self: + self._runner.__enter__() + self.get_loop().set_exception_handler(self._exception_handler) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self._runner.__exit__(exc_type, exc_val, exc_tb) + + def get_loop(self) -> AbstractEventLoop: + return self._runner.get_loop() + + def is_running(self) -> bool: + try: + asyncio.get_running_loop() + return True + except RuntimeError: + return False + + def _exception_handler( + self, loop: asyncio.AbstractEventLoop, context: dict[str, Any] + ) -> None: + if isinstance(context.get("exception"), Exception): + self._exceptions.append(context["exception"]) + else: + loop.default_exception_handler(context) + + def _raise_async_exceptions(self) -> None: + # Re-raise any exceptions raised in asynchronous callbacks + if self._exceptions: + exceptions, self._exceptions = self._exceptions, [] + if len(exceptions) == 1: + raise exceptions[0] + elif exceptions: + raise BaseExceptionGroup( + "Multiple exceptions occurred in asynchronous callbacks", exceptions + ) + + async def _run_tests_and_fixtures( + self, + receive_stream: MemoryObjectReceiveStream[ + tuple[Awaitable[T_Retval], asyncio.Future[T_Retval]] + ], + ) -> None: + from _pytest.outcomes import OutcomeException + + with receive_stream, self._send_stream: + async for coro, future in receive_stream: + try: + retval = await coro + except CancelledError as exc: + if not future.cancelled(): + future.cancel(*exc.args) + + raise + except BaseException as exc: + if not future.cancelled(): + future.set_exception(exc) + + if not isinstance(exc, (Exception, OutcomeException)): + raise + else: + if not future.cancelled(): + future.set_result(retval) + + async def _call_in_runner_task( + self, + func: Callable[P, Awaitable[T_Retval]], + /, + *args: P.args, + **kwargs: P.kwargs, + ) -> T_Retval: + if not self._runner_task: + self._send_stream, receive_stream = create_memory_object_stream[ + tuple[Awaitable[Any], asyncio.Future] + ](1) + self._runner_task = self.get_loop().create_task( + self._run_tests_and_fixtures(receive_stream) + ) + + coro = func(*args, **kwargs) + future: asyncio.Future[T_Retval] = self.get_loop().create_future() + self._send_stream.send_nowait((coro, future)) + return await future + + def run_asyncgen_fixture( + self, + fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], + kwargs: dict[str, Any], + ) -> Iterable[T_Retval]: + asyncgen = fixture_func(**kwargs) + fixturevalue: T_Retval = self.get_loop().run_until_complete( + self._call_in_runner_task(asyncgen.asend, None) + ) + self._raise_async_exceptions() + + yield fixturevalue + + try: + self.get_loop().run_until_complete( + self._call_in_runner_task(asyncgen.asend, None) + ) + except StopAsyncIteration: + self._raise_async_exceptions() + else: + self.get_loop().run_until_complete(asyncgen.aclose()) + raise RuntimeError("Async generator fixture did not stop") + + def run_fixture( + self, + fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], + kwargs: dict[str, Any], + ) -> T_Retval: + retval = self.get_loop().run_until_complete( + self._call_in_runner_task(fixture_func, **kwargs) + ) + self._raise_async_exceptions() + return retval + + def run_test( + self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] + ) -> None: + from _pytest.outcomes import OutcomeException + + try: + self.get_loop().run_until_complete( + self._call_in_runner_task(test_func, **kwargs) + ) + except Exception as exc: + self._exceptions.append(exc) + except OutcomeException: + raise + except BaseException: + # A BaseException (e.g. KeyboardInterrupt, SystemExit) interrupted the event loop before + # the test completed. Cancel _runner_task so it does not resume when the event + # loop is re-entered during async generator fixture teardown. + if self._runner_task is not None and not self._runner_task.done(): + self._runner_task.cancel() + self._send_stream.close() + try: + self.get_loop().run_until_complete(self._runner_task) + except CancelledError: + pass + finally: + self._runner_task = None + raise + self._raise_async_exceptions() + + +class _ProcessStreamProtocol(asyncio.subprocess.SubprocessStreamProtocol): + """ + A subprocess protocol that allows us to be notified of ``process_exited`` + + asyncio's own ``Process.wait()`` only resolves once every pipe transport has + disconnected so to get same semantics as on trio and uvloop we need this. + """ + + def __init__(self) -> None: + # Match the standard factory for asyncio.create_process + super().__init__(limit=2**16, loop=asyncio.get_running_loop()) + self.exited = asyncio.Event() + + def process_exited(self) -> None: + super().process_exited() + self.exited.set() + + +class AsyncIOBackend(AsyncBackend): + @classmethod + def run( + cls, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + args: tuple[Unpack[PosArgsT]], + kwargs: dict[str, Any], + options: dict[str, Any], + ) -> T_Retval: + @wraps(func) + async def wrapper() -> T_Retval: + task = cast(asyncio.Task, current_task()) + task.set_name(get_callable_name(func)) + _task_states[task] = TaskState(None, None) + + try: + return await func(*args) + finally: + del _task_states[task] + + debug = options.get("debug", None) + loop_factory = options.get("loop_factory", None) + if loop_factory is None and options.get("use_uvloop", False): + if sys.platform != "win32": + import uvloop + + loop_factory = uvloop.new_event_loop + else: + import winloop + + loop_factory = winloop.new_event_loop + + with Runner(debug=debug, loop_factory=loop_factory) as runner: + return runner.run(wrapper()) + + @classmethod + def current_token(cls) -> object: + return get_running_loop() + + @classmethod + def current_time(cls) -> float: + return get_running_loop().time() + + @classmethod + def cancelled_exception_class(cls) -> type[BaseException]: + return CancelledError + + @classmethod + async def checkpoint(cls) -> None: + await sleep(0) + + @classmethod + async def checkpoint_if_cancelled(cls) -> None: + task = current_task() + if task is None: + return + + try: + cancel_scope = _task_states[task].cancel_scope + except KeyError: + return + + while cancel_scope: + if cancel_scope.cancel_called: + await sleep(0) + elif cancel_scope.shield: + break + else: + cancel_scope = cancel_scope._parent_scope + + @classmethod + async def cancel_shielded_checkpoint(cls) -> None: + with CancelScope(shield=True): + await sleep(0) + + @classmethod + async def sleep(cls, delay: float) -> None: + await sleep(delay) + + @classmethod + def create_cancel_scope( + cls, *, deadline: float = math.inf, shield: bool = False + ) -> CancelScope: + return CancelScope(deadline=deadline, shield=shield) + + @classmethod + def current_effective_deadline(cls) -> float: + if (task := current_task()) is None: + return math.inf + + try: + cancel_scope = _task_states[task].cancel_scope + except KeyError: + return math.inf + + deadline = math.inf + while cancel_scope: + deadline = min(deadline, cancel_scope.deadline) + if cancel_scope._cancel_called: + deadline = -math.inf + break + elif cancel_scope.shield: + break + else: + cancel_scope = cancel_scope._parent_scope + + return deadline + + @classmethod + def create_task_group(cls) -> abc.TaskGroup: + return TaskGroup() + + @classmethod + def create_event(cls) -> BaseEvent: + return Event() + + @classmethod + def create_lock(cls, *, fast_acquire: bool) -> BaseLock: + return Lock(fast_acquire=fast_acquire) + + @classmethod + def create_semaphore( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> BaseSemaphore: + return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) + + @classmethod + def create_capacity_limiter(cls, total_tokens: float) -> BaseCapacityLimiter: + return CapacityLimiter(total_tokens) + + @classmethod + async def run_sync_in_worker_thread( # type: ignore[return] + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + abandon_on_cancel: bool = False, + limiter: BaseCapacityLimiter | None = None, + ) -> T_Retval: + await cls.checkpoint() + + # If this is the first run in this event loop thread, set up the necessary + # variables + try: + idle_workers = _threadpool_idle_workers.get() + workers = _threadpool_workers.get() + except LookupError: + idle_workers = deque() + workers = set() + _threadpool_idle_workers.set(idle_workers) + _threadpool_workers.set(workers) + + async with limiter or cls.current_default_thread_limiter(): + with CancelScope(shield=not abandon_on_cancel) as scope: + future = asyncio.Future[T_Retval]() + root_task = find_root_task() + if not idle_workers: + worker = WorkerThread(root_task, workers, idle_workers) + worker.start() + workers.add(worker) + root_task.add_done_callback(worker.stop, context=Context()) + else: + worker = idle_workers.pop() + + # Prune any other workers that have been idle for MAX_IDLE_TIME + # seconds or longer + now = cls.current_time() + while idle_workers: + if ( + now - idle_workers[0].idle_since + < WorkerThread.MAX_IDLE_TIME + ): + break + + expired_worker = idle_workers.popleft() + expired_worker.root_task.remove_done_callback( + expired_worker.stop + ) + expired_worker.stop() + + context = copy_context() + context.run(set_current_async_library, None) + if abandon_on_cancel or scope._parent_scope is None: + worker_scope = scope + else: + worker_scope = scope._parent_scope + + worker.queue.put_nowait((context, func, args, future, worker_scope)) + return await future + + @classmethod + def check_cancelled(cls) -> None: + scope: CancelScope | None = threadlocals.current_cancel_scope + while scope is not None: + if scope.cancel_called: + raise CancelledError(f"Cancelled via cancel scope {id(scope):x}") + + if scope.shield: + return + + scope = scope._parent_scope + + @classmethod + def run_async_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_co: + async def task_wrapper() -> T_co: + __tracebackhide__ = True + if scope is not None: + task = cast(asyncio.Task, current_task()) + _task_states[task] = TaskState(None, scope) + scope._tasks.add(task) + try: + return await func(*args) + except CancelledError as exc: + raise concurrent.futures.CancelledError(str(exc)) from None + finally: + if scope is not None: + scope._tasks.discard(task) + + loop = cast( + "AbstractEventLoop", token or threadlocals.current_token.native_token + ) + if loop.is_closed(): + raise RunFinishedError + + context = copy_context() + context.run(set_current_async_library, "asyncio") + scope = getattr(threadlocals, "current_cancel_scope", None) + f: concurrent.futures.Future[T_co] = context.run( + asyncio.run_coroutine_threadsafe, task_wrapper(), loop=loop + ) + return f.result() + + @classmethod + def run_sync_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + @wraps(func) + def wrapper() -> None: + try: + set_current_async_library("asyncio") + f.set_result(func(*args)) + except BaseException as exc: + f.set_exception(exc) + if not isinstance(exc, Exception): + raise + + loop = cast( + "AbstractEventLoop", token or threadlocals.current_token.native_token + ) + if loop.is_closed(): + raise RunFinishedError + + f: concurrent.futures.Future[T_Retval] = Future() + loop.call_soon_threadsafe(wrapper) + return f.result() + + @classmethod + async def open_process( + cls, + command: StrOrBytesPath | Sequence[StrOrBytesPath], + *, + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + **kwargs: Any, + ) -> Process: + await cls.checkpoint() + if isinstance(command, PathLike): + command = os.fspath(command) + + # Use loop.subprocess_shell()/subprocess_exec() rather than their + # asyncio.create_subprocess_*() counterparts to get access to + # transport/protocol. + loop = asyncio.get_running_loop() + if isinstance(command, (str, bytes)): + transport, protocol = await loop.subprocess_shell( + _ProcessStreamProtocol, + command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + **kwargs, + ) + else: + transport, protocol = await loop.subprocess_exec( + _ProcessStreamProtocol, + *command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + **kwargs, + ) + + process = asyncio.subprocess.Process(transport, protocol, loop) + stdin_stream = StreamWriterWrapper(process.stdin) if process.stdin else None + stdout_stream = StreamReaderWrapper(process.stdout) if process.stdout else None + stderr_stream = StreamReaderWrapper(process.stderr) if process.stderr else None + return Process( + process, + stdin_stream, + stdout_stream, + stderr_stream, + protocol.exited, + transport, + ) + + @classmethod + def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: + create_task( + _shutdown_process_pool_on_exit(workers), + name="AnyIO process pool shutdown task", + ) + find_root_task().add_done_callback( + partial(_forcibly_shutdown_process_pool_on_exit, workers) # type:ignore[arg-type] + ) + + @classmethod + async def connect_tcp( + cls, host: str, port: int, local_address: IPSockAddrType | None = None + ) -> abc.SocketStream: + transport, protocol = cast( + tuple[asyncio.Transport, StreamProtocol], + await get_running_loop().create_connection( + StreamProtocol, host, port, local_addr=local_address + ), + ) + transport.pause_reading() + return SocketStream(transport, protocol) + + @classmethod + async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: + await cls.checkpoint() + loop = get_running_loop() + raw_socket = socket.socket(socket.AF_UNIX) + raw_socket.setblocking(False) + while True: + try: + raw_socket.connect(path) + except BlockingIOError: + f: asyncio.Future = asyncio.Future() + loop.add_writer(raw_socket, f.set_result, None) + f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) + await f + except BaseException: + raw_socket.close() + raise + else: + return UNIXSocketStream(raw_socket) + + @classmethod + def create_tcp_listener(cls, sock: socket.socket) -> SocketListener: + return TCPSocketListener(sock) + + @classmethod + def create_unix_listener(cls, sock: socket.socket) -> SocketListener: + return UNIXSocketListener(sock) + + @classmethod + async def create_udp_socket( + cls, + family: AddressFamily, + local_address: IPSockAddrType | None, + remote_address: IPSockAddrType | None, + reuse_port: bool, + ) -> UDPSocket | ConnectedUDPSocket: + transport, protocol = await get_running_loop().create_datagram_endpoint( + DatagramProtocol, + local_addr=local_address, + remote_addr=remote_address, + family=family, + reuse_port=reuse_port, + ) + if protocol.exception: + transport.close() + raise protocol.exception + + if not remote_address: + return UDPSocket(transport, protocol) + else: + return ConnectedUDPSocket(transport, protocol) + + @classmethod + async def create_unix_datagram_socket( # type: ignore[override] + cls, raw_socket: socket.socket, remote_path: str | bytes | None + ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: + await cls.checkpoint() + loop = get_running_loop() + + if remote_path: + while True: + try: + raw_socket.connect(remote_path) + except BlockingIOError: + f: asyncio.Future = asyncio.Future() + loop.add_writer(raw_socket, f.set_result, None) + f.add_done_callback(lambda _: loop.remove_writer(raw_socket)) + await f + except BaseException: + raw_socket.close() + raise + else: + return ConnectedUNIXDatagramSocket(raw_socket) + else: + return UNIXDatagramSocket(raw_socket) + + @classmethod + async def getaddrinfo( + cls, + host: bytes | str | None, + port: str | int | None, + *, + family: int | AddressFamily = 0, + type: int | SocketKind = 0, + proto: int = 0, + flags: int = 0, + ) -> Sequence[ + tuple[ + AddressFamily, + SocketKind, + int, + str, + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], + ] + ]: + return await get_running_loop().getaddrinfo( + host, port, family=family, type=type, proto=proto, flags=flags + ) + + @classmethod + async def getnameinfo( + cls, sockaddr: IPSockAddrType, flags: int = 0 + ) -> tuple[str, str]: + return await get_running_loop().getnameinfo(sockaddr, flags) + + @classmethod + async def wait_readable(cls, obj: FileDescriptorLike) -> None: + try: + read_events = _read_events.get() + except LookupError: + read_events = {} + _read_events.set(read_events) + + fd = obj if isinstance(obj, int) else obj.fileno() + if read_events.get(fd): + raise BusyResourceError("reading from") + + loop = get_running_loop() + fut: asyncio.Future[bool] = loop.create_future() + + def cb() -> None: + try: + del read_events[fd] + except KeyError: + pass + else: + remove_reader(fd) + + try: + fut.set_result(True) + except asyncio.InvalidStateError: + pass + + try: + loop.add_reader(fd, cb) + except NotImplementedError: + from anyio._core._asyncio_selector_thread import get_selector + + selector = get_selector() + selector.add_reader(fd, cb) + remove_reader = selector.remove_reader + else: + remove_reader = loop.remove_reader + + read_events[fd] = fut + try: + success = await fut + finally: + try: + del read_events[fd] + except KeyError: + pass + else: + remove_reader(fd) + + if not success: + raise ClosedResourceError + + @classmethod + async def wait_writable(cls, obj: FileDescriptorLike) -> None: + try: + write_events = _write_events.get() + except LookupError: + write_events = {} + _write_events.set(write_events) + + fd = obj if isinstance(obj, int) else obj.fileno() + if write_events.get(fd): + raise BusyResourceError("writing to") + + loop = get_running_loop() + fut: asyncio.Future[bool] = loop.create_future() + + def cb() -> None: + try: + del write_events[fd] + except KeyError: + pass + else: + remove_writer(fd) + + try: + fut.set_result(True) + except asyncio.InvalidStateError: + pass + + try: + loop.add_writer(fd, cb) + except NotImplementedError: + from anyio._core._asyncio_selector_thread import get_selector + + selector = get_selector() + selector.add_writer(fd, cb) + remove_writer = selector.remove_writer + else: + remove_writer = loop.remove_writer + + write_events[fd] = fut + try: + success = await fut + finally: + try: + del write_events[fd] + except KeyError: + pass + else: + remove_writer(fd) + + if not success: + raise ClosedResourceError + + @classmethod + def notify_closing(cls, obj: FileDescriptorLike) -> None: + fd = obj if isinstance(obj, int) else obj.fileno() + loop = get_running_loop() + + try: + write_events = _write_events.get() + except LookupError: + pass + else: + try: + fut = write_events.pop(fd) + except KeyError: + pass + else: + try: + fut.set_result(False) + except asyncio.InvalidStateError: + pass + + try: + loop.remove_writer(fd) + except NotImplementedError: + from anyio._core._asyncio_selector_thread import get_selector + + get_selector().remove_writer(fd) + + try: + read_events = _read_events.get() + except LookupError: + pass + else: + try: + fut = read_events.pop(fd) + except KeyError: + pass + else: + try: + fut.set_result(False) + except asyncio.InvalidStateError: + pass + + try: + loop.remove_reader(fd) + except NotImplementedError: + from anyio._core._asyncio_selector_thread import get_selector + + get_selector().remove_reader(fd) + + @classmethod + async def wrap_listener_socket(cls, sock: socket.socket) -> SocketListener: + if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: + return UNIXSocketListener(sock) + + return TCPSocketListener(sock) + + @classmethod + async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: + transport, protocol = await get_running_loop().create_connection( + StreamProtocol, sock=sock + ) + return SocketStream(transport, protocol) + + @classmethod + async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: + return UNIXSocketStream(sock) + + @classmethod + async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: + transport, protocol = await get_running_loop().create_datagram_endpoint( + DatagramProtocol, sock=sock + ) + return UDPSocket(transport, protocol) + + @classmethod + async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: + transport, protocol = await get_running_loop().create_datagram_endpoint( + DatagramProtocol, sock=sock + ) + return ConnectedUDPSocket(transport, protocol) + + @classmethod + async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: + return UNIXDatagramSocket(sock) + + @classmethod + async def wrap_connected_unix_datagram_socket( + cls, sock: socket.socket + ) -> ConnectedUNIXDatagramSocket: + return ConnectedUNIXDatagramSocket(sock) + + @classmethod + def current_default_thread_limiter(cls) -> CapacityLimiter: + try: + return _default_thread_limiter.get() + except LookupError: + limiter = CapacityLimiter(40) + _default_thread_limiter.set(limiter) + return limiter + + @classmethod + def open_signal_receiver( + cls, *signals: Signals + ) -> AbstractContextManager[AsyncIterator[Signals]]: + return _SignalReceiver(signals) + + @classmethod + def get_current_task(cls) -> TaskInfo: + return AsyncIOTaskInfo(current_task()) # type: ignore[arg-type] + + @classmethod + def get_running_tasks(cls) -> Sequence[TaskInfo]: + return [AsyncIOTaskInfo(task) for task in all_tasks() if not task.done()] + + @classmethod + async def wait_all_tasks_blocked(cls) -> None: + await cls.checkpoint() + this_task = current_task() + while True: + for task in all_tasks(): + if task is this_task: + continue + + waiter = task._fut_waiter # type: ignore[attr-defined] + if waiter is None or waiter.done(): + await sleep(0.1) + break + else: + return + + @classmethod + def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: + return TestRunner(**options) + + +backend_class = AsyncIOBackend diff --git a/source/target-vendors/cp312/anyio/_backends/_trio.py b/source/target-vendors/cp312/anyio/_backends/_trio.py new file mode 100644 index 0000000..2e67786 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_backends/_trio.py @@ -0,0 +1,1473 @@ +from __future__ import annotations + +import array +import math +import os +import socket +import sys +import types +import weakref +from collections.abc import ( + AsyncGenerator, + AsyncIterator, + Awaitable, + Callable, + Collection, + Coroutine, + Iterable, + Sequence, +) +from contextlib import AbstractContextManager +from contextvars import Context +from dataclasses import dataclass +from functools import partial, wraps +from io import IOBase +from os import PathLike +from signal import Signals +from socket import AddressFamily, SocketKind +from types import TracebackType +from typing import ( + IO, + TYPE_CHECKING, + Any, + Generic, + Literal, + NoReturn, + ParamSpec, + TypeVar, + cast, + overload, +) + +import trio.from_thread +import trio.lowlevel +from outcome import Error, Outcome, Value +from trio.lowlevel import ( + current_root_task, + current_task, + notify_closing, + wait_readable, + wait_writable, +) +from trio.socket import SocketType as TrioSocketType +from trio.to_thread import run_sync + +from .. import ( + CapacityLimiterStatistics, + EventStatistics, + LockStatistics, + RunFinishedError, + TaskInfo, + WouldBlock, + abc, +) +from .._core._eventloop import claim_worker_thread +from .._core._exceptions import ( + BrokenResourceError, + BusyResourceError, + ClosedResourceError, + EndOfStream, +) +from .._core._sockets import convert_ipv6_sockaddr +from .._core._streams import create_memory_object_stream +from .._core._synchronization import ( + CapacityLimiter as BaseCapacityLimiter, +) +from .._core._synchronization import Event as BaseEvent +from .._core._synchronization import Lock as BaseLock +from .._core._synchronization import ( + ResourceGuard, + SemaphoreStatistics, +) +from .._core._synchronization import Semaphore as BaseSemaphore +from .._core._tasks import CancelScope as BaseCancelScope +from .._core._tasks import TaskHandle +from ..abc import IPSockAddrType, UDPPacketType, UNIXDatagramPacketType +from ..abc._eventloop import AsyncBackend, StrOrBytesPath +from ..abc._tasks import T_contra, call_for_coroutine, get_callable_name, get_coro_name + +if TYPE_CHECKING: + from _typeshed import FileDescriptorLike + + from ..streams.memory import MemoryObjectSendStream + +if sys.version_info < (3, 15): + from typing_extensions import sentinel + +if sys.version_info >= (3, 11): + from typing import Self, TypeVarTuple, Unpack +else: + from exceptiongroup import BaseExceptionGroup + from typing_extensions import Self, TypeVarTuple, Unpack + +T = TypeVar("T") +T_Retval = TypeVar("T_Retval") +T_co = TypeVar("T_co", covariant=True) +T_SockAddr = TypeVar("T_SockAddr", str, IPSockAddrType) +PosArgsT = TypeVarTuple("PosArgsT") +P = ParamSpec("P") + + +def ensure_returns_coro( + func: Callable[P, Awaitable[T_Retval]], +) -> Callable[P, Coroutine[Any, Any, T_Retval]]: + @wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> Coroutine[Any, Any, T_Retval]: + awaitable = func(*args, **kwargs) + # Check the common case first. + if isinstance(awaitable, Coroutine): + return awaitable + elif not isinstance(awaitable, Awaitable): + # The user violated the type annotations. Still, we should pass this on to + # Trio so it can raise with an appropriate message. + return awaitable + else: + + @wraps(func) + async def inner_wrapper() -> T_Retval: + return await awaitable + + return inner_wrapper() + + return wrapper + + +# +# Event loop +# + +RunVar = trio.lowlevel.RunVar + + +# +# Timeouts and cancellation +# + + +class CancelScope(BaseCancelScope): + __slots__ = ("__original",) + + def __new__( + cls, original: trio.CancelScope | None = None, **kwargs: object + ) -> Self: + return object.__new__(cls) + + def __init__(self, original: trio.CancelScope | None = None, **kwargs: Any) -> None: + self.__original = original or trio.CancelScope(**kwargs) + + def __enter__(self) -> Self: + self.__original.__enter__() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + return self.__original.__exit__(exc_type, exc_val, exc_tb) + + def cancel(self, reason: str | None = None) -> None: + self.__original.cancel(reason) + + @property + def deadline(self) -> float: + return self.__original.deadline + + @deadline.setter + def deadline(self, value: float) -> None: + self.__original.deadline = value + + @property + def cancel_called(self) -> bool: + return self.__original.cancel_called + + @property + def cancelled_caught(self) -> bool: + return self.__original.cancelled_caught + + @property + def shield(self) -> bool: + return self.__original.shield + + @shield.setter + def shield(self, value: bool) -> None: + self.__original.shield = value + + +# +# Task groups +# + +empty_start_value = sentinel("empty_start_value") + + +class _TrioTaskStatus(abc.TaskStatus[T_contra], Generic[T_contra]): + early_start_value: T_contra | object = empty_start_value + real_task_status: trio.TaskStatus[T_contra | None] | None = None + + def started(self, value: T_contra | None = None) -> None: + if self.real_task_status is None: + if self.early_start_value is not empty_start_value: + raise RuntimeError("called 'started' twice on the same task status") + + self.early_start_value = value + else: + self.real_task_status.started(value) + + +class TaskGroup(abc.TaskGroup): + def __init__(self) -> None: + self._entered = False + self._active = False + self._nursery_manager = trio.open_nursery(strict_exception_groups=True) + self.cancel_scope = None # type: ignore[assignment] + + async def __aenter__(self) -> Self: + if self._entered: + raise RuntimeError("TaskGroup cannot be entered more than once") + + self._entered = True + self._active = True + self._nursery = await self._nursery_manager.__aenter__() + self.cancel_scope = CancelScope(self._nursery.cancel_scope) + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + try: + # trio.Nursery.__exit__ returns bool; .open_nursery has wrong type + return await self._nursery_manager.__aexit__(exc_type, exc_val, exc_tb) # type: ignore[return-value] + except BaseExceptionGroup as exc: + if not exc.split(trio.Cancelled)[1]: + raise trio.Cancelled._create() from exc + + raise + finally: + del exc_val, exc_tb + self._active = False + + def _check_active(self, coro: Coroutine | None = None) -> None: + if not self._active: + if coro is not None: + coro.close() + + raise RuntimeError( + "This task group is not active; no new tasks can be started." + ) + + def create_task( + self, + coro: Coroutine[Any, Any, T_co], + *, + name: object = None, + context: Context | None = None, + ) -> TaskHandle[T_co]: + if not isinstance(coro, Coroutine): + raise TypeError(f"expected a coroutine, got {coro.__class__.__qualname__}") + + self._check_active(coro) + final_name = get_coro_name(coro, name) + handle = TaskHandle(coro, final_name) + if context is not None: + context.run( + partial(self._nursery.start_soon, handle._run_coro, name=handle.name) + ) + else: + self._nursery.start_soon(handle._run_coro, name=handle.name) + + return handle + + async def start( + self, + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + *args: Unpack[PosArgsT], + name: object = None, + return_handle: Literal[False, True] = False, + ) -> Any: + handle: TaskHandle[T_co] + + async def run_coro_with_task_status( + *, task_status: trio.TaskStatus[Any] + ) -> None: + nonlocal handle + wrapper_task_status = _TrioTaskStatus() + coro = call_for_coroutine(func, args, task_status=wrapper_task_status) + if wrapper_task_status.early_start_value is not empty_start_value: + task_status.started(wrapper_task_status.early_start_value) + else: + wrapper_task_status.real_task_status = task_status + + handle = TaskHandle(coro, final_name) + await handle._run_coro() + + self._check_active() + final_name = get_callable_name(func, name) + start_value = await self._nursery.start( + run_coro_with_task_status, name=final_name + ) + if return_handle: + handle._start_value = start_value + return handle + else: + return start_value + + +# +# Subprocesses +# + + +@dataclass(eq=False) +class ReceiveStreamWrapper(abc.ByteReceiveStream): + _stream: trio.abc.ReceiveStream + + async def receive(self, max_bytes: int | None = None) -> bytes: + if max_bytes is not None and max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + try: + data = await self._stream.receive_some(max_bytes) + except trio.ClosedResourceError as exc: + raise ClosedResourceError from exc.__cause__ + except trio.BrokenResourceError as exc: + raise BrokenResourceError from exc.__cause__ + + if data: + return bytes(data) + else: + raise EndOfStream + + async def aclose(self) -> None: + await self._stream.aclose() + + +@dataclass(eq=False) +class SendStreamWrapper(abc.ByteSendStream): + _stream: trio.abc.SendStream + + async def send(self, item: bytes) -> None: + try: + await self._stream.send_all(item) + except trio.ClosedResourceError as exc: + raise ClosedResourceError from exc.__cause__ + except trio.BrokenResourceError as exc: + raise BrokenResourceError from exc.__cause__ + + async def aclose(self) -> None: + await self._stream.aclose() + + +@dataclass(eq=False) +class Process(abc.Process): + _process: trio.Process + _stdin: abc.ByteSendStream | None + _stdout: abc.ByteReceiveStream | None + _stderr: abc.ByteReceiveStream | None + + async def aclose(self) -> None: + with CancelScope(shield=True): + if self._stdin: + await self._stdin.aclose() + if self._stdout: + await self._stdout.aclose() + if self._stderr: + await self._stderr.aclose() + + try: + await self.wait() + except BaseException: + self.kill() + with CancelScope(shield=True): + await self.wait() + raise + + async def wait(self) -> int: + return await self._process.wait() + + def terminate(self) -> None: + self._process.terminate() + + def kill(self) -> None: + self._process.kill() + + def send_signal(self, signal: Signals) -> None: + self._process.send_signal(signal) + + @property + def pid(self) -> int: + return self._process.pid + + @property + def returncode(self) -> int | None: + return self._process.returncode + + @property + def stdin(self) -> abc.ByteSendStream | None: + return self._stdin + + @property + def stdout(self) -> abc.ByteReceiveStream | None: + return self._stdout + + @property + def stderr(self) -> abc.ByteReceiveStream | None: + return self._stderr + + +class _ProcessPoolShutdownInstrument(trio.abc.Instrument): + def after_run(self) -> None: + super().after_run() + + +current_default_worker_process_limiter: trio.lowlevel.RunVar = RunVar( + "current_default_worker_process_limiter" +) + + +async def _shutdown_process_pool(workers: set[abc.Process]) -> None: + try: + await trio.sleep(math.inf) + except trio.Cancelled: + for process in workers: + if process.returncode is None: + process.kill() + + with CancelScope(shield=True): + for process in workers: + await process.aclose() + + +# +# Sockets and networking +# + + +class _TrioSocketMixin(Generic[T_SockAddr]): + def __init__(self, trio_socket: TrioSocketType) -> None: + self._trio_socket = trio_socket + self._closed = False + + def _check_closed(self) -> None: + if self._closed: + raise ClosedResourceError + if self._trio_socket.fileno() < 0: + raise BrokenResourceError + + @property + def _raw_socket(self) -> socket.socket: + return self._trio_socket._sock # type: ignore[attr-defined] + + async def aclose(self) -> None: + if self._trio_socket.fileno() >= 0: + self._closed = True + self._trio_socket.close() + + def _convert_socket_error(self, exc: BaseException) -> NoReturn: + if isinstance(exc, trio.ClosedResourceError): + raise ClosedResourceError from exc + elif self._trio_socket.fileno() < 0 and self._closed: + raise ClosedResourceError from None + elif isinstance(exc, OSError): + raise BrokenResourceError from exc + else: + raise exc + + +class SocketStream(_TrioSocketMixin, abc.SocketStream): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + with self._receive_guard: + try: + data = await self._trio_socket.recv(max_bytes) + except BaseException as exc: + self._convert_socket_error(exc) + + if data: + return data + else: + raise EndOfStream + + async def send(self, item: bytes) -> None: + with self._send_guard: + view = memoryview(item) + while view: + try: + bytes_sent = await self._trio_socket.send(view) + except BaseException as exc: + self._convert_socket_error(exc) + + view = view[bytes_sent:] + + async def send_eof(self) -> None: + self._trio_socket.shutdown(socket.SHUT_WR) + + +class UNIXSocketStream(SocketStream, abc.UNIXSocketStream): + async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: + if not isinstance(msglen, int) or msglen < 0: + raise ValueError("msglen must be a non-negative integer") + if not isinstance(maxfds, int) or maxfds < 1: + raise ValueError("maxfds must be a positive integer") + + fds = array.array("i") + await trio.lowlevel.checkpoint() + with self._receive_guard: + while True: + try: + message, ancdata, _flags, _addr = await self._trio_socket.recvmsg( + msglen, socket.CMSG_LEN(maxfds * fds.itemsize) + ) + except BaseException as exc: + self._convert_socket_error(exc) + else: + if not message and not ancdata: + raise EndOfStream + + break + + for cmsg_level, cmsg_type, cmsg_data in ancdata: + if cmsg_level != socket.SOL_SOCKET or cmsg_type != socket.SCM_RIGHTS: + raise RuntimeError( + f"Received unexpected ancillary data; message = {message!r}, " + f"cmsg_level = {cmsg_level}, cmsg_type = {cmsg_type}" + ) + + fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)]) + + return message, list(fds) + + async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: + if not message: + raise ValueError("message must not be empty") + if not fds: + raise ValueError("fds must not be empty") + + filenos: list[int] = [] + for fd in fds: + if isinstance(fd, int): + filenos.append(fd) + elif isinstance(fd, IOBase): + filenos.append(fd.fileno()) + + fdarray = array.array("i", filenos) + await trio.lowlevel.checkpoint() + with self._send_guard: + while True: + try: + await self._trio_socket.sendmsg( + [message], + [ + ( + socket.SOL_SOCKET, + socket.SCM_RIGHTS, + fdarray, + ) + ], + ) + break + except BaseException as exc: + self._convert_socket_error(exc) + + +class TCPSocketListener(_TrioSocketMixin, abc.SocketListener): + def __init__(self, raw_socket: socket.socket): + super().__init__(trio.socket.from_stdlib_socket(raw_socket)) + self._accept_guard = ResourceGuard("accepting connections from") + + async def accept(self) -> SocketStream: + with self._accept_guard: + try: + trio_socket, _addr = await self._trio_socket.accept() + except BaseException as exc: + self._convert_socket_error(exc) + + trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + return SocketStream(trio_socket) + + +class UNIXSocketListener(_TrioSocketMixin, abc.SocketListener): + def __init__(self, raw_socket: socket.socket): + super().__init__(trio.socket.from_stdlib_socket(raw_socket)) + self._accept_guard = ResourceGuard("accepting connections from") + + async def accept(self) -> UNIXSocketStream: + with self._accept_guard: + try: + trio_socket, _addr = await self._trio_socket.accept() + except BaseException as exc: + self._convert_socket_error(exc) + + return UNIXSocketStream(trio_socket) + + +class UDPSocket(_TrioSocketMixin[IPSockAddrType], abc.UDPSocket): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self) -> tuple[bytes, IPSockAddrType]: + with self._receive_guard: + try: + data, addr = await self._trio_socket.recvfrom(65536) + return data, convert_ipv6_sockaddr(addr) + except BaseException as exc: + self._convert_socket_error(exc) + + async def send(self, item: UDPPacketType) -> None: + with self._send_guard: + try: + await self._trio_socket.sendto(*item) + except BaseException as exc: + self._convert_socket_error(exc) + + +class ConnectedUDPSocket(_TrioSocketMixin[IPSockAddrType], abc.ConnectedUDPSocket): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self) -> bytes: + with self._receive_guard: + try: + return await self._trio_socket.recv(65536) + except BaseException as exc: + self._convert_socket_error(exc) + + async def send(self, item: bytes) -> None: + with self._send_guard: + try: + await self._trio_socket.send(item) + except BaseException as exc: + self._convert_socket_error(exc) + + +class UNIXDatagramSocket(_TrioSocketMixin[str], abc.UNIXDatagramSocket): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self) -> UNIXDatagramPacketType: + with self._receive_guard: + try: + data, addr = await self._trio_socket.recvfrom(65536) + return data, addr + except BaseException as exc: + self._convert_socket_error(exc) + + async def send(self, item: UNIXDatagramPacketType) -> None: + with self._send_guard: + try: + await self._trio_socket.sendto(*item) + except BaseException as exc: + self._convert_socket_error(exc) + + +class ConnectedUNIXDatagramSocket( + _TrioSocketMixin[str], abc.ConnectedUNIXDatagramSocket +): + def __init__(self, trio_socket: TrioSocketType) -> None: + super().__init__(trio_socket) + self._receive_guard = ResourceGuard("reading from") + self._send_guard = ResourceGuard("writing to") + + async def receive(self) -> bytes: + with self._receive_guard: + try: + return await self._trio_socket.recv(65536) + except BaseException as exc: + self._convert_socket_error(exc) + + async def send(self, item: bytes) -> None: + with self._send_guard: + try: + await self._trio_socket.send(item) + except BaseException as exc: + self._convert_socket_error(exc) + + +# +# Synchronization +# + + +class Event(BaseEvent): + __slots__ = ("__original",) + + def __new__(cls) -> Self: + return object.__new__(cls) + + def __init__(self) -> None: + self.__original = trio.Event() + + def is_set(self) -> bool: + return self.__original.is_set() + + async def wait(self) -> None: + return await self.__original.wait() + + def statistics(self) -> EventStatistics: + orig_statistics = self.__original.statistics() + return EventStatistics(tasks_waiting=orig_statistics.tasks_waiting) + + def set(self) -> None: + self.__original.set() + + +class Lock(BaseLock): + __slots__ = "__original", "_fast_acquire" + + def __new__(cls, *, fast_acquire: bool = False) -> Self: + return object.__new__(cls) + + def __init__(self, *, fast_acquire: bool = False) -> None: + self._fast_acquire = fast_acquire + self.__original = trio.Lock() + + @staticmethod + def _convert_runtime_error_msg(exc: RuntimeError) -> None: + if exc.args == ("attempt to re-acquire an already held Lock",): + exc.args = ("Attempted to acquire an already held Lock",) + + async def acquire(self) -> None: + if not self._fast_acquire: + try: + await self.__original.acquire() + except RuntimeError as exc: + self._convert_runtime_error_msg(exc) + raise + + return + + # This is the "fast path" where we don't let other tasks run + await trio.lowlevel.checkpoint_if_cancelled() + try: + self.__original.acquire_nowait() + except trio.WouldBlock: + await self.__original._lot.park() + except RuntimeError as exc: + self._convert_runtime_error_msg(exc) + raise + + def acquire_nowait(self) -> None: + try: + self.__original.acquire_nowait() + except trio.WouldBlock: + raise WouldBlock from None + except RuntimeError as exc: + self._convert_runtime_error_msg(exc) + raise + + def locked(self) -> bool: + return self.__original.locked() + + def release(self) -> None: + self.__original.release() + + def statistics(self) -> LockStatistics: + orig_statistics = self.__original.statistics() + owner = TrioTaskInfo(orig_statistics.owner) if orig_statistics.owner else None + return LockStatistics( + orig_statistics.locked, owner, orig_statistics.tasks_waiting + ) + + +class Semaphore(BaseSemaphore): + __slots__ = ("__original",) + + def __new__( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> Self: + return object.__new__(cls) + + def __init__( + self, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> None: + super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) + self.__original = trio.Semaphore(initial_value, max_value=max_value) + + async def acquire(self) -> None: + if not self._fast_acquire: + await self.__original.acquire() + return + + # This is the "fast path" where we don't let other tasks run + await trio.lowlevel.checkpoint_if_cancelled() + try: + self.__original.acquire_nowait() + except trio.WouldBlock: + await self.__original._lot.park() + + def acquire_nowait(self) -> None: + try: + self.__original.acquire_nowait() + except trio.WouldBlock: + raise WouldBlock from None + + @property + def max_value(self) -> int | None: + return self.__original.max_value + + @property + def value(self) -> int: + return self.__original.value + + def release(self) -> None: + self.__original.release() + + def statistics(self) -> SemaphoreStatistics: + orig_statistics = self.__original.statistics() + return SemaphoreStatistics(orig_statistics.tasks_waiting) + + +class CapacityLimiter(BaseCapacityLimiter): + __slots__ = ("__original",) + + def __new__( + cls, + total_tokens: float | None = None, + *, + original: trio.CapacityLimiter | None = None, + ) -> Self: + return object.__new__(cls) + + def __init__( + self, + total_tokens: float | None = None, + *, + original: trio.CapacityLimiter | None = None, + ) -> None: + if original is not None: + self.__original = original + else: + assert total_tokens is not None + self.__original = trio.CapacityLimiter(total_tokens) + + async def __aenter__(self) -> None: + return await self.__original.__aenter__() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.__original.__aexit__(exc_type, exc_val, exc_tb) + + @property + def total_tokens(self) -> float: + return self.__original.total_tokens + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + self.__original.total_tokens = value + + @property + def borrowed_tokens(self) -> int: + return self.__original.borrowed_tokens + + @property + def available_tokens(self) -> float: + return self.__original.available_tokens + + def acquire_nowait(self) -> None: + try: + self.__original.acquire_nowait() + except trio.WouldBlock: + raise WouldBlock from None + + def acquire_on_behalf_of_nowait(self, borrower: object) -> None: + try: + self.__original.acquire_on_behalf_of_nowait(borrower) + except trio.WouldBlock: + raise WouldBlock from None + + async def acquire(self) -> None: + await self.__original.acquire() + + async def acquire_on_behalf_of(self, borrower: object) -> None: + await self.__original.acquire_on_behalf_of(borrower) + + def release(self) -> None: + return self.__original.release() + + def release_on_behalf_of(self, borrower: object) -> None: + return self.__original.release_on_behalf_of(borrower) + + def statistics(self) -> CapacityLimiterStatistics: + orig = self.__original.statistics() + return CapacityLimiterStatistics( + borrowed_tokens=orig.borrowed_tokens, + total_tokens=orig.total_tokens, + borrowers=tuple(orig.borrowers), + tasks_waiting=orig.tasks_waiting, + ) + + +_capacity_limiter_wrapper: trio.lowlevel.RunVar = RunVar("_capacity_limiter_wrapper") + + +# +# Signal handling +# + + +class _SignalReceiver: + _iterator: AsyncIterator[int] + + def __init__(self, signals: tuple[Signals, ...]): + self._signals = signals + + def __enter__(self) -> Self: + self._cm = trio.open_signal_receiver(*self._signals) + self._iterator = self._cm.__enter__() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool | None: + return self._cm.__exit__(exc_type, exc_val, exc_tb) + + def __aiter__(self) -> _SignalReceiver: + return self + + async def __anext__(self) -> Signals: + signum = await self._iterator.__anext__() + return Signals(signum) + + +# +# Testing and debugging +# + + +class TestRunner(abc.TestRunner): + def __init__(self, **options: Any) -> None: + from queue import Queue + + self._call_queue: Queue[Callable[[], object]] = Queue() + self._send_stream: ( + MemoryObjectSendStream[tuple[Awaitable[Any], list[Outcome]]] | None + ) = None + self._options = options + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: types.TracebackType | None, + ) -> None: + if self._send_stream: + self._send_stream.close() + while self._send_stream is not None: + self._call_queue.get()() + + def is_running(self) -> bool: + return trio.lowlevel.in_trio_task() + + async def _run_tests_and_fixtures(self) -> None: + self._send_stream, receive_stream = create_memory_object_stream[ + tuple[Awaitable[Any], list[Outcome]] + ](1) + with receive_stream: + async for awaitable, outcome_holder in receive_stream: + try: + retval = await awaitable + except BaseException as exc: + outcome_holder.append(Error(exc)) + else: + outcome_holder.append(Value(retval)) + + def _main_task_finished(self, outcome: object) -> None: + self._send_stream = None + + def _call_in_runner_task( + self, + func: Callable[P, Awaitable[T_Retval]], + /, + *args: P.args, + **kwargs: P.kwargs, + ) -> T_Retval: + if self._send_stream is None: + trio.lowlevel.start_guest_run( + self._run_tests_and_fixtures, + run_sync_soon_threadsafe=self._call_queue.put, + done_callback=self._main_task_finished, + **self._options, + ) + while self._send_stream is None: + self._call_queue.get()() + + outcome_holder: list[Outcome] = [] + self._send_stream.send_nowait((func(*args, **kwargs), outcome_holder)) + while not outcome_holder: + self._call_queue.get()() + + return outcome_holder[0].unwrap() + + def run_asyncgen_fixture( + self, + fixture_func: Callable[..., AsyncGenerator[T_Retval, Any]], + kwargs: dict[str, Any], + ) -> Iterable[T_Retval]: + asyncgen = fixture_func(**kwargs) + fixturevalue: T_Retval = self._call_in_runner_task(asyncgen.asend, None) + + yield fixturevalue + + try: + self._call_in_runner_task(asyncgen.asend, None) + except StopAsyncIteration: + pass + else: + self._call_in_runner_task(asyncgen.aclose) + raise RuntimeError("Async generator fixture did not stop") + + def run_fixture( + self, + fixture_func: Callable[..., Coroutine[Any, Any, T_Retval]], + kwargs: dict[str, Any], + ) -> T_Retval: + return self._call_in_runner_task(fixture_func, **kwargs) + + def run_test( + self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] + ) -> None: + self._call_in_runner_task(test_func, **kwargs) + + +class TrioTaskInfo(TaskInfo): + def __init__(self, task: trio.lowlevel.Task): + parent_id = None + if task.parent_nursery and task.parent_nursery.parent_task: + parent_id = id(task.parent_nursery.parent_task) + + super().__init__(id(task), parent_id, task.name, task.coro) + self._task = weakref.proxy(task) + + def has_pending_cancellation(self) -> bool: + try: + return self._task._cancel_status.effectively_cancelled + except ReferenceError: + # If the task is no longer around, it surely doesn't have a cancellation + # pending + return False + + +class TrioBackend(AsyncBackend): + @classmethod + def run( + cls, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + args: tuple[Unpack[PosArgsT]], + kwargs: dict[str, Any], + options: dict[str, Any], + ) -> T_Retval: + assert not kwargs, "unreachable, and not supported by Trio" + return trio.run(ensure_returns_coro(func), *args, **options) + + @classmethod + def current_token(cls) -> object: + return trio.lowlevel.current_trio_token() + + @classmethod + def current_time(cls) -> float: + return trio.current_time() + + @classmethod + def cancelled_exception_class(cls) -> type[BaseException]: + return trio.Cancelled + + @classmethod + async def checkpoint(cls) -> None: + await trio.lowlevel.checkpoint() + + @classmethod + async def checkpoint_if_cancelled(cls) -> None: + await trio.lowlevel.checkpoint_if_cancelled() + + @classmethod + async def cancel_shielded_checkpoint(cls) -> None: + await trio.lowlevel.cancel_shielded_checkpoint() + + @classmethod + async def sleep(cls, delay: float) -> None: + await trio.sleep(delay) + + @classmethod + def create_cancel_scope( + cls, *, deadline: float = math.inf, shield: bool = False + ) -> BaseCancelScope: + return CancelScope(deadline=deadline, shield=shield) + + @classmethod + def current_effective_deadline(cls) -> float: + return trio.current_effective_deadline() + + @classmethod + def create_task_group(cls) -> abc.TaskGroup: + return TaskGroup() + + @classmethod + def create_event(cls) -> BaseEvent: + return Event() + + @classmethod + def create_lock(cls, *, fast_acquire: bool) -> Lock: + return Lock(fast_acquire=fast_acquire) + + @classmethod + def create_semaphore( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> BaseSemaphore: + return Semaphore(initial_value, max_value=max_value, fast_acquire=fast_acquire) + + @classmethod + def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: + return CapacityLimiter(total_tokens) + + @classmethod + async def run_sync_in_worker_thread( + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + abandon_on_cancel: bool = False, + limiter: BaseCapacityLimiter | None = None, + ) -> T_Retval: + def wrapper() -> T_Retval: + with claim_worker_thread(TrioBackend, token): + return func(*args) + + token = TrioBackend.current_token() + return await run_sync( + wrapper, + abandon_on_cancel=abandon_on_cancel, + limiter=cast(trio.CapacityLimiter, limiter), + ) + + @classmethod + def check_cancelled(cls) -> None: + trio.from_thread.check_cancelled() + + @classmethod + def run_async_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_co: + trio_token = cast("trio.lowlevel.TrioToken | None", token) + try: + return trio.from_thread.run(func, *args, trio_token=trio_token) + except trio.RunFinishedError: + raise RunFinishedError from None + + @classmethod + def run_sync_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + trio_token = cast("trio.lowlevel.TrioToken | None", token) + try: + return trio.from_thread.run_sync(func, *args, trio_token=trio_token) + except trio.RunFinishedError: + raise RunFinishedError from None + + @classmethod + async def open_process( + cls, + command: StrOrBytesPath | Sequence[StrOrBytesPath], + *, + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + **kwargs: Any, + ) -> Process: + def convert_item(item: StrOrBytesPath) -> str: + str_or_bytes = os.fspath(item) + if isinstance(str_or_bytes, str): + return str_or_bytes + else: + return os.fsdecode(str_or_bytes) + + if isinstance(command, (str, bytes, PathLike)): + process = await trio.lowlevel.open_process( + convert_item(command), + stdin=stdin, + stdout=stdout, + stderr=stderr, + shell=True, + **kwargs, + ) + else: + process = await trio.lowlevel.open_process( + [convert_item(item) for item in command], + stdin=stdin, + stdout=stdout, + stderr=stderr, + shell=False, + **kwargs, + ) + + stdin_stream = SendStreamWrapper(process.stdin) if process.stdin else None + stdout_stream = ReceiveStreamWrapper(process.stdout) if process.stdout else None + stderr_stream = ReceiveStreamWrapper(process.stderr) if process.stderr else None + return Process(process, stdin_stream, stdout_stream, stderr_stream) + + @classmethod + def setup_process_pool_exit_at_shutdown(cls, workers: set[abc.Process]) -> None: + trio.lowlevel.spawn_system_task(_shutdown_process_pool, workers) + + @classmethod + async def connect_tcp( + cls, host: str, port: int, local_address: IPSockAddrType | None = None + ) -> SocketStream: + family = socket.AF_INET6 if ":" in host else socket.AF_INET + trio_socket = trio.socket.socket(family) + trio_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + if local_address: + await trio_socket.bind(local_address) + + try: + await trio_socket.connect((host, port)) + except BaseException: + trio_socket.close() + raise + + return SocketStream(trio_socket) + + @classmethod + async def connect_unix(cls, path: str | bytes) -> abc.UNIXSocketStream: + trio_socket = trio.socket.socket(socket.AF_UNIX) + try: + await trio_socket.connect(path) + except BaseException: + trio_socket.close() + raise + + return UNIXSocketStream(trio_socket) + + @classmethod + def create_tcp_listener(cls, sock: socket.socket) -> abc.SocketListener: + return TCPSocketListener(sock) + + @classmethod + def create_unix_listener(cls, sock: socket.socket) -> abc.SocketListener: + return UNIXSocketListener(sock) + + @classmethod + async def create_udp_socket( + cls, + family: socket.AddressFamily, + local_address: IPSockAddrType | None, + remote_address: IPSockAddrType | None, + reuse_port: bool, + ) -> UDPSocket | ConnectedUDPSocket: + trio_socket = trio.socket.socket(family=family, type=socket.SOCK_DGRAM) + + if reuse_port: + trio_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + + if local_address: + await trio_socket.bind(local_address) + + if remote_address: + await trio_socket.connect(remote_address) + return ConnectedUDPSocket(trio_socket) + else: + return UDPSocket(trio_socket) + + @classmethod + @overload + async def create_unix_datagram_socket( + cls, raw_socket: socket.socket, remote_path: None + ) -> abc.UNIXDatagramSocket: ... + + @classmethod + @overload + async def create_unix_datagram_socket( + cls, raw_socket: socket.socket, remote_path: str | bytes + ) -> abc.ConnectedUNIXDatagramSocket: ... + + @classmethod + async def create_unix_datagram_socket( + cls, raw_socket: socket.socket, remote_path: str | bytes | None + ) -> abc.UNIXDatagramSocket | abc.ConnectedUNIXDatagramSocket: + trio_socket = trio.socket.from_stdlib_socket(raw_socket) + + if remote_path: + await trio_socket.connect(remote_path) + return ConnectedUNIXDatagramSocket(trio_socket) + else: + return UNIXDatagramSocket(trio_socket) + + @classmethod + async def getaddrinfo( + cls, + host: bytes | str | None, + port: str | int | None, + *, + family: int | AddressFamily = 0, + type: int | SocketKind = 0, + proto: int = 0, + flags: int = 0, + ) -> Sequence[ + tuple[ + AddressFamily, + SocketKind, + int, + str, + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], + ] + ]: + return await trio.socket.getaddrinfo(host, port, family, type, proto, flags) + + @classmethod + async def getnameinfo( + cls, sockaddr: IPSockAddrType, flags: int = 0 + ) -> tuple[str, str]: + return await trio.socket.getnameinfo(sockaddr, flags) + + @classmethod + async def wait_readable(cls, obj: FileDescriptorLike) -> None: + try: + await wait_readable(obj) + except trio.ClosedResourceError as exc: + raise ClosedResourceError().with_traceback(exc.__traceback__) from None + except trio.BusyResourceError: + raise BusyResourceError("reading from") from None + + @classmethod + async def wait_writable(cls, obj: FileDescriptorLike) -> None: + try: + await wait_writable(obj) + except trio.ClosedResourceError as exc: + raise ClosedResourceError().with_traceback(exc.__traceback__) from None + except trio.BusyResourceError: + raise BusyResourceError("writing to") from None + + @classmethod + def notify_closing(cls, obj: FileDescriptorLike) -> None: + notify_closing(obj) + + @classmethod + async def wrap_listener_socket(cls, sock: socket.socket) -> abc.SocketListener: + if hasattr(socket, "AF_UNIX") and sock.family == socket.AF_UNIX: + return UNIXSocketListener(sock) + + return TCPSocketListener(sock) + + @classmethod + async def wrap_stream_socket(cls, sock: socket.socket) -> SocketStream: + trio_sock = trio.socket.from_stdlib_socket(sock) + return SocketStream(trio_sock) + + @classmethod + async def wrap_unix_stream_socket(cls, sock: socket.socket) -> UNIXSocketStream: + trio_sock = trio.socket.from_stdlib_socket(sock) + return UNIXSocketStream(trio_sock) + + @classmethod + async def wrap_udp_socket(cls, sock: socket.socket) -> UDPSocket: + trio_sock = trio.socket.from_stdlib_socket(sock) + return UDPSocket(trio_sock) + + @classmethod + async def wrap_connected_udp_socket(cls, sock: socket.socket) -> ConnectedUDPSocket: + trio_sock = trio.socket.from_stdlib_socket(sock) + return ConnectedUDPSocket(trio_sock) + + @classmethod + async def wrap_unix_datagram_socket(cls, sock: socket.socket) -> UNIXDatagramSocket: + trio_sock = trio.socket.from_stdlib_socket(sock) + return UNIXDatagramSocket(trio_sock) + + @classmethod + async def wrap_connected_unix_datagram_socket( + cls, sock: socket.socket + ) -> ConnectedUNIXDatagramSocket: + trio_sock = trio.socket.from_stdlib_socket(sock) + return ConnectedUNIXDatagramSocket(trio_sock) + + @classmethod + def current_default_thread_limiter(cls) -> CapacityLimiter: + try: + return _capacity_limiter_wrapper.get() + except LookupError: + limiter = CapacityLimiter( + original=trio.to_thread.current_default_thread_limiter() + ) + _capacity_limiter_wrapper.set(limiter) + return limiter + + @classmethod + def open_signal_receiver( + cls, *signals: Signals + ) -> AbstractContextManager[AsyncIterator[Signals]]: + return _SignalReceiver(signals) + + @classmethod + def get_current_task(cls) -> TaskInfo: + task = current_task() + return TrioTaskInfo(task) + + @classmethod + def get_running_tasks(cls) -> Sequence[TaskInfo]: + root_task = current_root_task() + assert root_task + task_infos = [TrioTaskInfo(root_task)] + nurseries = root_task.child_nurseries + while nurseries: + new_nurseries: list[trio.Nursery] = [] + for nursery in nurseries: + for task in nursery.child_tasks: + task_infos.append(TrioTaskInfo(task)) + new_nurseries.extend(task.child_nurseries) + + nurseries = new_nurseries + + return task_infos + + @classmethod + async def wait_all_tasks_blocked(cls) -> None: + from trio.testing import wait_all_tasks_blocked + + await wait_all_tasks_blocked() + + @classmethod + def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: + return TestRunner(**options) + + +backend_class = TrioBackend diff --git a/source/target-vendors/cp312/anyio/_core/__init__.py b/source/target-vendors/cp312/anyio/_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/anyio/_core/_asyncio_selector_thread.py b/source/target-vendors/cp312/anyio/_core/_asyncio_selector_thread.py new file mode 100644 index 0000000..9f35bae --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_asyncio_selector_thread.py @@ -0,0 +1,167 @@ +from __future__ import annotations + +import asyncio +import socket +import threading +from collections.abc import Callable +from selectors import EVENT_READ, EVENT_WRITE, DefaultSelector +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from _typeshed import FileDescriptorLike + +_selector_lock = threading.Lock() +_selector: Selector | None = None + + +class Selector: + def __init__(self) -> None: + self._thread = threading.Thread(target=self.run, name="AnyIO socket selector") + self._selector = DefaultSelector() + self._send, self._receive = socket.socketpair() + self._send.setblocking(False) + self._receive.setblocking(False) + # This somewhat reduces the amount of memory wasted queueing up data + # for wakeups. With these settings, maximum number of 1-byte sends + # before getting BlockingIOError: + # Linux 4.8: 6 + # macOS (darwin 15.5): 1 + # Windows 10: 525347 + # Windows you're weird. (And on Windows setting SNDBUF to 0 makes send + # blocking, even on non-blocking sockets, so don't do that.) + self._receive.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 1) + self._send.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 1) + # On Windows this is a TCP socket so this might matter. On other + # platforms this fails b/c AF_UNIX sockets aren't actually TCP. + try: + self._send.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + except OSError: + pass + + self._selector.register(self._receive, EVENT_READ) + self._closed = False + + def start(self) -> None: + self._thread.start() + threading._register_atexit(self._stop) # type: ignore[attr-defined] + + def _stop(self) -> None: + global _selector + self._closed = True + self._notify_self() + self._send.close() + self._thread.join() + self._selector.unregister(self._receive) + self._receive.close() + self._selector.close() + _selector = None + assert not self._selector.get_map(), ( + "selector still has registered file descriptors after shutdown" + ) + + def _notify_self(self) -> None: + try: + self._send.send(b"\x00") + except BlockingIOError: + pass + + def add_reader(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: + loop = asyncio.get_running_loop() + try: + key = self._selector.get_key(fd) + except KeyError: + self._selector.register(fd, EVENT_READ, {EVENT_READ: (loop, callback)}) + else: + if EVENT_READ in key.data: + raise ValueError( + "this file descriptor is already registered for reading" + ) + + key.data[EVENT_READ] = loop, callback + self._selector.modify(fd, key.events | EVENT_READ, key.data) + + self._notify_self() + + def add_writer(self, fd: FileDescriptorLike, callback: Callable[[], Any]) -> None: + loop = asyncio.get_running_loop() + try: + key = self._selector.get_key(fd) + except KeyError: + self._selector.register(fd, EVENT_WRITE, {EVENT_WRITE: (loop, callback)}) + else: + if EVENT_WRITE in key.data: + raise ValueError( + "this file descriptor is already registered for writing" + ) + + key.data[EVENT_WRITE] = loop, callback + self._selector.modify(fd, key.events | EVENT_WRITE, key.data) + + self._notify_self() + + def remove_reader(self, fd: FileDescriptorLike) -> bool: + try: + key = self._selector.get_key(fd) + except KeyError: + return False + + if new_events := key.events ^ EVENT_READ: + del key.data[EVENT_READ] + self._selector.modify(fd, new_events, key.data) + else: + self._selector.unregister(fd) + + return True + + def remove_writer(self, fd: FileDescriptorLike) -> bool: + try: + key = self._selector.get_key(fd) + except KeyError: + return False + + if new_events := key.events ^ EVENT_WRITE: + del key.data[EVENT_WRITE] + self._selector.modify(fd, new_events, key.data) + else: + self._selector.unregister(fd) + + return True + + def run(self) -> None: + while not self._closed: + for key, events in self._selector.select(): + if key.fileobj is self._receive: + try: + while self._receive.recv(4096): + pass + except BlockingIOError: + pass + + continue + + if events & EVENT_READ: + loop, callback = key.data[EVENT_READ] + self.remove_reader(key.fd) + try: + loop.call_soon_threadsafe(callback) + except RuntimeError: + pass # the loop was already closed + + if events & EVENT_WRITE: + loop, callback = key.data[EVENT_WRITE] + self.remove_writer(key.fd) + try: + loop.call_soon_threadsafe(callback) + except RuntimeError: + pass # the loop was already closed + + +def get_selector() -> Selector: + global _selector + + with _selector_lock: + if _selector is None: + _selector = Selector() + _selector.start() + + return _selector diff --git a/source/target-vendors/cp312/anyio/_core/_concurrency_utils.py b/source/target-vendors/cp312/anyio/_core/_concurrency_utils.py new file mode 100644 index 0000000..f66229a --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_concurrency_utils.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +from inspect import iscoroutine + +__all__ = ("amap", "as_completed", "gather") + +from collections.abc import AsyncGenerator, Awaitable, Callable, Coroutine, Iterable +from contextlib import asynccontextmanager +from typing import TYPE_CHECKING, Any, TypeVar, overload + +from ..abc._tasks import get_coro_name +from ._exceptions import BrokenResourceError +from ._streams import create_memory_object_stream +from ._tasks import TaskHandle, create_task_group + +if TYPE_CHECKING: + from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream + +R = TypeVar("R") +S = TypeVar("S") +T = TypeVar("T") +U = TypeVar("U") +V = TypeVar("V") +W = TypeVar("W") + + +@overload +async def gather( + coro1: Coroutine[Any, Any, R], coro2: Coroutine[Any, Any, S], / +) -> tuple[R, S]: ... + + +@overload +async def gather( + coro1: Coroutine[Any, Any, R], + coro2: Coroutine[Any, Any, S], + coro3: Coroutine[Any, Any, T], + /, +) -> tuple[R, S, T]: ... + + +@overload +async def gather( + coro1: Coroutine[Any, Any, R], + coro2: Coroutine[Any, Any, S], + coro3: Coroutine[Any, Any, T], + coro4: Coroutine[Any, Any, U], + /, +) -> tuple[R, S, T, U]: ... + + +@overload +async def gather( + coro1: Coroutine[Any, Any, R], + coro2: Coroutine[Any, Any, S], + coro3: Coroutine[Any, Any, T], + coro4: Coroutine[Any, Any, U], + coro5: Coroutine[Any, Any, V], + /, +) -> tuple[R, S, T, U, V]: ... + + +@overload +async def gather( + coro1: Coroutine[Any, Any, R], + coro2: Coroutine[Any, Any, S], + coro3: Coroutine[Any, Any, T], + coro4: Coroutine[Any, Any, U], + coro5: Coroutine[Any, Any, V], + coro6: Coroutine[Any, Any, W], + /, +) -> tuple[R, S, T, U, V, W]: ... + + +# handle arbitrary length if awaitables are all of the same type +@overload +async def gather(*coros: Coroutine[Any, Any, R]) -> tuple[R, ...]: ... + + +async def gather(*coros: Coroutine[Any, Any, Any]) -> tuple[Any, ...]: + """ + Run coroutines concurrently in a task group. The order of result values corresponds + to the order of coroutines passed. + + :param coros: coroutine objects to run as tasks + :return: task results for each argument in the same order as they were passed + + """ + handles: list[TaskHandle[Any]] = [] + async with create_task_group() as tg: + handles.extend(tg.create_task(coro) for coro in coros) + + return tuple(h.return_value for h in handles) + + +@asynccontextmanager +async def as_completed( + *awaitables: Awaitable[R], +) -> AsyncGenerator[MemoryObjectReceiveStream[TaskHandle[R]]]: + """ + Run awaitable objects concurrently in a task group, returning an iterator which can + be used to get finished task handles in the order they complete. + + :param awaitables: awaitable objects to run as tasks + :return: MemoryObjectReceiveStream for iterating over task handles as tasks complete. + + """ + if not awaitables: + raise ValueError("as_completed() takes at least one awaitable") + + send, recv = create_memory_object_stream[TaskHandle[R]](len(awaitables)) + task_handles: list[TaskHandle[R]] = [] + + async def runner( + awaitable: Awaitable[R], + index: int, + _send: MemoryObjectSendStream[TaskHandle[R]], + ) -> R: + async with _send: + try: + return await awaitable + finally: + try: + _send.send_nowait(task_handles[index]) + except BrokenResourceError: + pass + + async with recv, create_task_group() as tg: + async with send: + for i, awaitable in enumerate(awaitables): + name = get_coro_name(awaitable) if iscoroutine(awaitable) else None + task_handles.append( + tg.start_soon(runner, awaitable, i, send.clone(), name=name) + ) + try: + yield recv + finally: + tg.cancel_scope.cancel() + + +async def amap( + func: Callable[[T], Coroutine[Any, Any, R]], args: Iterable[T] +) -> list[R]: + """ + Run the given coroutine function concurrently for multiple argument values. + + :param func: a coroutine function that takes a single argument + :param args: a sequence of argument values to pass to ``func`` + :return: task results for each argument in the same order as they were passed + + """ + handles: list[TaskHandle[R]] = [] + async with create_task_group() as tg: + handles.extend(tg.start_soon(func, arg) for arg in args) + + return [h.return_value for h in handles] diff --git a/source/target-vendors/cp312/anyio/_core/_contextmanagers.py b/source/target-vendors/cp312/anyio/_core/_contextmanagers.py new file mode 100644 index 0000000..302f32b --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_contextmanagers.py @@ -0,0 +1,200 @@ +from __future__ import annotations + +from abc import abstractmethod +from contextlib import AbstractAsyncContextManager, AbstractContextManager +from inspect import isasyncgen, iscoroutine, isgenerator +from types import TracebackType +from typing import Protocol, TypeVar, cast, final + +_T_co = TypeVar("_T_co", covariant=True) +_ExitT_co = TypeVar("_ExitT_co", covariant=True, bound="bool | None") + + +class _SupportsCtxMgr(Protocol[_T_co, _ExitT_co]): + def __contextmanager__(self) -> AbstractContextManager[_T_co, _ExitT_co]: ... + + +class _SupportsAsyncCtxMgr(Protocol[_T_co, _ExitT_co]): + def __asynccontextmanager__( + self, + ) -> AbstractAsyncContextManager[_T_co, _ExitT_co]: ... + + +class ContextManagerMixin: + """ + Mixin class providing context manager functionality via a generator-based + implementation. + + This class allows you to implement a context manager via :meth:`__contextmanager__` + which should return a generator. The mechanics are meant to mirror those of + :func:`@contextmanager `. + + .. note:: Classes using this mix-in are not reentrant as context managers, meaning + that once you enter it, you can't re-enter before first exiting it. + + .. seealso:: :doc:`contextmanagers` + """ + + __cm: AbstractContextManager[object, bool | None] | None = None + + @final + def __enter__(self: _SupportsCtxMgr[_T_co, bool | None]) -> _T_co: + # Needed for mypy to assume self still has the __cm member + assert isinstance(self, ContextManagerMixin) + if self.__cm is not None: + raise RuntimeError( + f"this {self.__class__.__qualname__} has already been entered" + ) + + cm = self.__contextmanager__() + if not isinstance(cm, AbstractContextManager): + if isgenerator(cm): + raise TypeError( + "__contextmanager__() returned a generator object instead of " + "a context manager. Did you forget to add the @contextmanager " + "decorator?" + ) + + raise TypeError( + f"__contextmanager__() did not return a context manager object, " + f"but {cm.__class__!r}" + ) + + if cm is self: + raise TypeError( + f"{self.__class__.__qualname__}.__contextmanager__() returned " + f"self. Did you forget to add the @contextmanager decorator and a " + f"'yield' statement?" + ) + + value = cm.__enter__() + self.__cm = cm + return value + + @final + def __exit__( + self: _SupportsCtxMgr[object, _ExitT_co], + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> _ExitT_co: + # Needed for mypy to assume self still has the __cm member + assert isinstance(self, ContextManagerMixin) + if self.__cm is None: + raise RuntimeError( + f"this {self.__class__.__qualname__} has not been entered yet" + ) + + # Prevent circular references + cm = self.__cm + del self.__cm + + return cast(_ExitT_co, cm.__exit__(exc_type, exc_val, exc_tb)) + + @abstractmethod + def __contextmanager__(self) -> AbstractContextManager[object, bool | None]: + """ + Implement your context manager logic here. + + This method **must** be decorated with + :func:`@contextmanager `. + + .. note:: Remember that the ``yield`` will raise any exception raised in the + enclosed context block, so use a ``finally:`` block to clean up resources! + + :return: a context manager object + """ + + +class AsyncContextManagerMixin: + """ + Mixin class providing async context manager functionality via a generator-based + implementation. + + This class allows you to implement a context manager via + :meth:`__asynccontextmanager__`. The mechanics are meant to mirror those of + :func:`@asynccontextmanager `. + + .. note:: Classes using this mix-in are not reentrant as context managers, meaning + that once you enter it, you can't re-enter before first exiting it. + + .. seealso:: :doc:`contextmanagers` + """ + + __cm: AbstractAsyncContextManager[object, bool | None] | None = None + + @final + async def __aenter__(self: _SupportsAsyncCtxMgr[_T_co, bool | None]) -> _T_co: + # Needed for mypy to assume self still has the __cm member + assert isinstance(self, AsyncContextManagerMixin) + if self.__cm is not None: + raise RuntimeError( + f"this {self.__class__.__qualname__} has already been entered" + ) + + cm = self.__asynccontextmanager__() + if not isinstance(cm, AbstractAsyncContextManager): + if isasyncgen(cm): + raise TypeError( + "__asynccontextmanager__() returned an async generator instead of " + "an async context manager. Did you forget to add the " + "@asynccontextmanager decorator?" + ) + elif iscoroutine(cm): + cm.close() + raise TypeError( + "__asynccontextmanager__() returned a coroutine object instead of " + "an async context manager. Did you forget to add the " + "@asynccontextmanager decorator and a 'yield' statement?" + ) + + raise TypeError( + f"__asynccontextmanager__() did not return an async context manager, " + f"but {cm.__class__!r}" + ) + + if cm is self: + raise TypeError( + f"{self.__class__.__qualname__}.__asynccontextmanager__() returned " + f"self. Did you forget to add the @asynccontextmanager decorator and a " + f"'yield' statement?" + ) + + value = await cm.__aenter__() + self.__cm = cm + return value + + @final + async def __aexit__( + self: _SupportsAsyncCtxMgr[object, _ExitT_co], + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> _ExitT_co: + assert isinstance(self, AsyncContextManagerMixin) + if self.__cm is None: + raise RuntimeError( + f"this {self.__class__.__qualname__} has not been entered yet" + ) + + # Prevent circular references + cm = self.__cm + del self.__cm + + return cast(_ExitT_co, await cm.__aexit__(exc_type, exc_val, exc_tb)) + + @abstractmethod + def __asynccontextmanager__( + self, + ) -> AbstractAsyncContextManager[object, bool | None]: + """ + Implement your async context manager logic here. + + This method **must** be decorated with + :func:`@asynccontextmanager `. + + .. note:: Remember that the ``yield`` will raise any exception raised in the + enclosed context block, so use a ``finally:`` block to clean up resources! + + :return: an async context manager object + """ diff --git a/source/target-vendors/cp312/anyio/_core/_eventloop.py b/source/target-vendors/cp312/anyio/_core/_eventloop.py new file mode 100644 index 0000000..a3e2ab1 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_eventloop.py @@ -0,0 +1,240 @@ +from __future__ import annotations + +import math +import sys +import threading +from collections.abc import Awaitable, Callable, Generator +from contextlib import contextmanager +from contextvars import Token +from importlib import import_module +from typing import TYPE_CHECKING, Any, TypeVar + +from ._exceptions import NoEventLoopError + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +sniffio: Any +try: + import sniffio +except ModuleNotFoundError: + sniffio = None + +if TYPE_CHECKING: + from ..abc import AsyncBackend + +# This must be updated when new backends are introduced +BACKENDS = "asyncio", "trio" + +T_Retval = TypeVar("T_Retval") +PosArgsT = TypeVarTuple("PosArgsT") + +threadlocals = threading.local() +loaded_backends: dict[str, type[AsyncBackend]] = {} + + +def run( + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + *args: Unpack[PosArgsT], + backend: str = "asyncio", + backend_options: dict[str, Any] | None = None, +) -> T_Retval: + """ + Run the given coroutine function in an asynchronous event loop. + + The current thread must not be already running an event loop. + + :param func: a coroutine function + :param args: positional arguments to ``func`` + :param backend: name of the asynchronous event loop implementation – currently + either ``asyncio`` or ``trio`` + :param backend_options: keyword arguments to call the backend ``run()`` + implementation with (documented :ref:`here `) + :return: the return value of the coroutine function + :raises RuntimeError: if an asynchronous event loop is already running in this + thread + :raises LookupError: if the named backend is not found + + """ + if asynclib_name := current_async_library(): + raise RuntimeError(f"Already running {asynclib_name} in this thread") + + try: + async_backend = get_async_backend(backend) + except ImportError as exc: + if backend in BACKENDS: + raise LookupError( + f"Backend {backend!r} is not available. " + f"Install it with: pip install anyio[{backend}]" + ) from exc + + raise LookupError(f"No such backend: {backend}") from exc + + token = None + if asynclib_name is None: + # Since we're in control of the event loop, we can cache the name of the async + # library + token = set_current_async_library(backend) + + try: + backend_options = backend_options or {} + return async_backend.run(func, args, {}, backend_options) + finally: + reset_current_async_library(token) + + +async def sleep(delay: float) -> None: + """ + Pause the current task for the specified duration. + + :param delay: the duration, in seconds + + """ + return await get_async_backend().sleep(delay) + + +async def sleep_forever() -> None: + """ + Pause the current task until it's cancelled. + + This is a shortcut for ``sleep(math.inf)``. + + .. versionadded:: 3.1 + + """ + await sleep(math.inf) + + +async def sleep_until(deadline: float) -> None: + """ + Pause the current task until the given time. + + :param deadline: the absolute time to wake up at (according to the internal + monotonic clock of the event loop) + + .. versionadded:: 3.1 + + """ + now = current_time() + await sleep(max(deadline - now, 0)) + + +def current_time() -> float: + """ + Return the current value of the event loop's internal clock. + + :return: the clock value (seconds) + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().current_time() + + +def get_all_backends() -> tuple[str, ...]: + """Return a tuple of the names of all built-in backends.""" + return BACKENDS + + +def get_available_backends() -> tuple[str, ...]: + """ + Test for the availability of built-in backends. + + :return a tuple of the built-in backend names that were successfully imported + + .. versionadded:: 4.12 + + """ + available_backends: list[str] = [] + for backend_name in get_all_backends(): + try: + get_async_backend(backend_name) + except ImportError: + continue + + available_backends.append(backend_name) + + return tuple(available_backends) + + +def get_cancelled_exc_class() -> type[BaseException]: + """ + Return the current async library's cancellation exception class. + + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().cancelled_exception_class() + + +# +# Private API +# + + +@contextmanager +def claim_worker_thread( + backend_class: type[AsyncBackend], token: object +) -> Generator[Any, None, None]: + from ..lowlevel import EventLoopToken + + threadlocals.current_token = EventLoopToken(backend_class, token) + try: + yield + finally: + del threadlocals.current_token + + +def get_async_backend(asynclib_name: str | None = None) -> type[AsyncBackend]: + if asynclib_name is None: + asynclib_name = current_async_library() + if not asynclib_name: + raise NoEventLoopError( + f"Not currently running on any asynchronous event loop. " + f"Available async backends: {', '.join(get_all_backends())}" + ) + + # We use our own dict instead of sys.modules to get the already imported back-end + # class because the appropriate modules in sys.modules could potentially be only + # partially initialized + try: + return loaded_backends[asynclib_name] + except KeyError: + module = import_module(f"anyio._backends._{asynclib_name}") + loaded_backends[asynclib_name] = module.backend_class + return module.backend_class + + +def current_async_library() -> str | None: + if sniffio is None: + # If sniffio is not installed, we assume we're either running asyncio or nothing + import asyncio + + try: + asyncio.get_running_loop() + return "asyncio" + except RuntimeError: + pass + else: + try: + return sniffio.current_async_library() + except sniffio.AsyncLibraryNotFoundError: + pass + + return None + + +def set_current_async_library(asynclib_name: str | None) -> Token | None: + # no-op if sniffio is not installed + if sniffio is None: + return None + + return sniffio.current_async_library_cvar.set(asynclib_name) + + +def reset_current_async_library(token: Token | None) -> None: + if token is not None: + sniffio.current_async_library_cvar.reset(token) diff --git a/source/target-vendors/cp312/anyio/_core/_exceptions.py b/source/target-vendors/cp312/anyio/_core/_exceptions.py new file mode 100644 index 0000000..7d9165f --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_exceptions.py @@ -0,0 +1,205 @@ +from __future__ import annotations + +import sys +from collections.abc import Generator +from textwrap import dedent +from typing import Any + +if sys.version_info < (3, 11): + from exceptiongroup import BaseExceptionGroup + + +class BrokenResourceError(Exception): + """ + Raised when trying to use a resource that has been rendered unusable due to external + causes (e.g. a send stream whose peer has disconnected). + """ + + +class BrokenWorkerProcess(Exception): + """ + Raised by :meth:`~anyio.to_process.run_sync` if the worker process terminates abruptly or + otherwise misbehaves. + """ + + +class BrokenWorkerInterpreter(Exception): + """ + Raised by :meth:`~anyio.to_interpreter.run_sync` if an unexpected exception is + raised in the subinterpreter. + """ + + def __init__(self, excinfo: Any): + # This was adapted from concurrent.futures.interpreter.ExecutionFailed + msg = excinfo.formatted + if not msg: + if excinfo.type and excinfo.msg: + msg = f"{excinfo.type.__name__}: {excinfo.msg}" + else: + msg = excinfo.type.__name__ or excinfo.msg + + super().__init__(msg) + self.excinfo = excinfo + + def __str__(self) -> str: + try: + formatted = self.excinfo.errdisplay + except Exception: + return super().__str__() + else: + return dedent( + f""" + {super().__str__()} + + Uncaught in the interpreter: + + {formatted} + """.strip() + ) + + +class BusyResourceError(Exception): + """ + Raised when two tasks are trying to read from or write to the same resource + concurrently. + """ + + def __init__(self, action: str): + super().__init__(f"Another task is already {action} this resource") + + +class ClosedResourceError(Exception): + """Raised when trying to use a resource that has been closed.""" + + +class ConnectionFailed(OSError): + """ + Raised when a connection attempt fails. + + .. note:: This class inherits from :exc:`OSError` for backwards compatibility. + """ + + +def iterate_exceptions( + exception: BaseException, +) -> Generator[BaseException, None, None]: + if isinstance(exception, BaseExceptionGroup): + for exc in exception.exceptions: + yield from iterate_exceptions(exc) + else: + yield exception + + +class DelimiterNotFound(Exception): + """ + Raised during + :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the + maximum number of bytes has been read without the delimiter being found. + """ + + def __init__(self, max_bytes: int) -> None: + super().__init__( + f"The delimiter was not found among the first {max_bytes} bytes" + ) + + +class EndOfStream(Exception): + """ + Raised when trying to read from a stream that has been closed from the other end. + """ + + +class IncompleteRead(Exception): + """ + Raised during + :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_exactly` or + :meth:`~anyio.streams.buffered.BufferedByteReceiveStream.receive_until` if the + connection is closed before the requested amount of bytes has been read. + """ + + def __init__(self) -> None: + super().__init__( + "The stream was closed before the read operation could be completed" + ) + + +class TypedAttributeLookupError(LookupError): + """ + Raised by :meth:`~anyio.TypedAttributeProvider.extra` when the given typed attribute + is not found and no default value has been given. + """ + + +class WouldBlock(Exception): + """Raised by ``X_nowait`` functions if ``X()`` would block.""" + + +class NoEventLoopError(RuntimeError): + """ + Raised by several functions that require an event loop to be running in the current + thread when there is no running event loop. + + This is also raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` + if not calling from an AnyIO worker thread, and no ``token`` was passed. + """ + + +class RunFinishedError(RuntimeError): + """ + Raised by :func:`.from_thread.run` and :func:`.from_thread.run_sync` if the event + loop associated with the explicitly passed token has already finished. + """ + + def __init__(self) -> None: + super().__init__( + "The event loop associated with the given token has already finished" + ) + + +class TaskFailed(Exception): + """ + Raised when awaiting on, or attempting to access the return value of, a + :class:`.TaskHandle` that raised an exception. + """ + + +class TaskCancelled(TaskFailed): + """ + Raised when awaiting on, or attempting to access the return value of, a + :class:`.TaskHandle` that was cancelled. + """ + + +class TaskNotFinished(Exception): + """ + Raised when attempting to access the return value or exception of a + :class:`.TaskHandle` that is still pending completion. + """ + + +class FutureFailed(Exception): + """ + Raised when awaiting on, or attempting to access the return value of, a + :class:`.Future` that raised an exception. + """ + + +class FutureCancelled(FutureFailed): + """ + Raised when attempting to access the return value or exception of a + :class:`.Future` that was cancelled. + """ + + +class FutureNotFinished(Exception): + """ + Raised when attempting to access the return value or exception of a + :class:`.Future` that is still pending completion. + """ + + +class FutureAlreadyFinished(Exception): + """ + Raised when attempting set a result of or await a + :class:`.Future` that has already completed. + """ diff --git a/source/target-vendors/cp312/anyio/_core/_fileio.py b/source/target-vendors/cp312/anyio/_core/_fileio.py new file mode 100644 index 0000000..498eef4 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_fileio.py @@ -0,0 +1,1045 @@ +from __future__ import annotations + +import os +import pathlib +import sys +from collections.abc import ( + AsyncIterator, + Callable, + Iterable, + Iterator, + Sequence, +) +from dataclasses import dataclass +from functools import partial +from os import PathLike +from typing import ( + IO, + TYPE_CHECKING, + Any, + AnyStr, + ClassVar, + Final, + Generic, + TypeVar, + overload, +) + +from .. import to_thread +from ..abc import AsyncResource +from ._synchronization import CapacityLimiter + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + +if sys.version_info >= (3, 14): + from pathlib.types import PathInfo + +if TYPE_CHECKING: + from types import ModuleType + + from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer +else: + ReadableBuffer = OpenBinaryMode = OpenTextMode = WriteableBuffer = object + + +T = TypeVar("T", bound="Path") + + +class AsyncFile(AsyncResource, Generic[AnyStr]): + """ + An asynchronous file object. + + This class wraps a standard file object and provides async friendly versions of the + following blocking methods (where available on the original file object): + + * read + * read1 + * readline + * readlines + * readinto + * readinto1 + * write + * writelines + * truncate + * seek + * tell + * flush + + All other methods are directly passed through. + + This class supports the asynchronous context manager protocol which closes the + underlying file at the end of the context block. + + This class also supports asynchronous iteration:: + + async with await open_file(...) as f: + async for line in f: + print(line) + """ + + def __init__( + self, fp: IO[AnyStr], *, limiter: CapacityLimiter | None = None + ) -> None: + if limiter is not None and not isinstance(limiter, CapacityLimiter): + raise TypeError( + f"limiter must be a CapacityLimiter or None, not " + f"{limiter.__class__.__name__}" + ) + + self._fp: Any = fp + self._limiter = limiter + + def __getattr__(self, name: str) -> object: + return getattr(self._fp, name) + + @property + def limiter(self) -> CapacityLimiter | None: + """The capacity limiter used by this file object, if not the global limiter.""" + return self._limiter + + @property + def wrapped(self) -> IO[AnyStr]: + """The wrapped file object.""" + return self._fp + + async def __aiter__(self) -> AsyncIterator[AnyStr]: + while True: + line = await self.readline() + if line: + yield line + else: + break + + async def aclose(self) -> None: + return await to_thread.run_sync(self._fp.close, limiter=self._limiter) + + async def read(self, size: int = -1) -> AnyStr: + return await to_thread.run_sync(self._fp.read, size, limiter=self._limiter) + + async def read1(self: AsyncFile[bytes], size: int = -1) -> bytes: + return await to_thread.run_sync(self._fp.read1, size, limiter=self._limiter) + + async def readline(self) -> AnyStr: + return await to_thread.run_sync(self._fp.readline, limiter=self._limiter) + + async def readlines(self) -> list[AnyStr]: + return await to_thread.run_sync(self._fp.readlines, limiter=self._limiter) + + async def readinto(self: AsyncFile[bytes], b: WriteableBuffer) -> int: + return await to_thread.run_sync(self._fp.readinto, b, limiter=self._limiter) + + async def readinto1(self: AsyncFile[bytes], b: WriteableBuffer) -> int: + return await to_thread.run_sync(self._fp.readinto1, b, limiter=self._limiter) + + @overload + async def write(self: AsyncFile[bytes], b: ReadableBuffer) -> int: ... + + @overload + async def write(self: AsyncFile[str], b: str) -> int: ... + + async def write(self, b: ReadableBuffer | str) -> int: + return await to_thread.run_sync(self._fp.write, b, limiter=self._limiter) + + @overload + async def writelines( + self: AsyncFile[bytes], lines: Iterable[ReadableBuffer] + ) -> None: ... + + @overload + async def writelines(self: AsyncFile[str], lines: Iterable[str]) -> None: ... + + async def writelines(self, lines: Iterable[ReadableBuffer] | Iterable[str]) -> None: + return await to_thread.run_sync( + self._fp.writelines, lines, limiter=self._limiter + ) + + async def truncate(self, size: int | None = None) -> int: + return await to_thread.run_sync(self._fp.truncate, size, limiter=self._limiter) + + async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: + return await to_thread.run_sync( + self._fp.seek, offset, whence, limiter=self._limiter + ) + + async def tell(self) -> int: + return await to_thread.run_sync(self._fp.tell, limiter=self._limiter) + + async def flush(self) -> None: + return await to_thread.run_sync(self._fp.flush, limiter=self._limiter) + + +@overload +async def open_file( + file: str | PathLike[str] | int, + mode: OpenBinaryMode, + buffering: int = ..., + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., + closefd: bool = ..., + opener: Callable[[str, int], int] | None = ..., + *, + limiter: CapacityLimiter | None = ..., +) -> AsyncFile[bytes]: ... + + +@overload +async def open_file( + file: str | PathLike[str] | int, + mode: OpenTextMode = ..., + buffering: int = ..., + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., + closefd: bool = ..., + opener: Callable[[str, int], int] | None = ..., + *, + limiter: CapacityLimiter | None = ..., +) -> AsyncFile[str]: ... + + +async def open_file( + file: str | PathLike[str] | int, + mode: str = "r", + buffering: int = -1, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + closefd: bool = True, + opener: Callable[[str, int], int] | None = None, + *, + limiter: CapacityLimiter | None = None, +) -> AsyncFile[Any]: + """ + Open a file asynchronously. + + Except for ``limiter``, the arguments are exactly the same as for the builtin :func:`open`. + + :param limiter: an optional capacity limiter to use with the file + instead of the default one + :return: an asynchronous file object + + .. versionchanged:: 4.14.0 + Added the ``limiter`` keyword argument. + + """ + fp = await to_thread.run_sync( + open, + file, + mode, + buffering, + encoding, + errors, + newline, + closefd, + opener, + limiter=limiter, + ) + return AsyncFile(fp, limiter=limiter) + + +def wrap_file( + file: IO[AnyStr], *, limiter: CapacityLimiter | None = None +) -> AsyncFile[AnyStr]: + """ + Wrap an existing file as an asynchronous file. + + :param file: an existing file-like object + :param limiter: an optional capacity limiter to use with the file + instead of the default one + :return: an asynchronous file object + + .. versionchanged:: 4.14.0 + Added the ``limiter`` keyword argument. + + """ + return AsyncFile(file, limiter=limiter) + + +@dataclass(eq=False) +class _PathIterator(AsyncIterator[T]): + iterator: Iterator[PathLike[str]] + limiter: CapacityLimiter | None + # This was added to ensure that iterating over a subclass of Path yields instances + # of that subclass rather than the base Path class. + path_cls: type[T] + + async def __anext__(self) -> T: + nextval = await to_thread.run_sync( + next, self.iterator, None, abandon_on_cancel=True, limiter=self.limiter + ) + if nextval is None: + raise StopAsyncIteration from None + + return self.path_cls(nextval, limiter=self.limiter) + + +class Path: + """ + An asynchronous version of :class:`pathlib.Path`. + + This class cannot be substituted for :class:`pathlib.Path` or + :class:`pathlib.PurePath`, but it is compatible with the :class:`os.PathLike` + interface. + + It implements the Python 3.10 version of :class:`pathlib.Path` interface, except for + the deprecated :meth:`~pathlib.Path.link_to` method. + + Some methods may be unavailable or have limited functionality, based on the Python + version: + + * :meth:`~pathlib.Path.copy` (available on Python 3.14 or later) + * :meth:`~pathlib.Path.copy_into` (available on Python 3.14 or later) + * :meth:`~pathlib.Path.from_uri` (available on Python 3.13 or later) + * :meth:`~pathlib.PurePath.full_match` (available on Python 3.13 or later) + * :attr:`~pathlib.Path.info` (available on Python 3.14 or later) + * :meth:`~pathlib.Path.is_junction` (available on Python 3.12 or later) + * :meth:`~pathlib.PurePath.match` (the ``case_sensitive`` parameter is only + available on Python 3.13 or later) + * :meth:`~pathlib.Path.move` (available on Python 3.14 or later) + * :meth:`~pathlib.Path.move_into` (available on Python 3.14 or later) + * :meth:`~pathlib.PurePath.relative_to` (the ``walk_up`` parameter is only available + on Python 3.12 or later) + * :meth:`~pathlib.Path.walk` (available on Python 3.12 or later) + + Any methods that do disk I/O need to be awaited on. These methods are: + + * :meth:`~pathlib.Path.absolute` + * :meth:`~pathlib.Path.chmod` + * :meth:`~pathlib.Path.cwd` + * :meth:`~pathlib.Path.exists` + * :meth:`~pathlib.Path.expanduser` + * :meth:`~pathlib.Path.group` + * :meth:`~pathlib.Path.hardlink_to` + * :meth:`~pathlib.Path.home` + * :meth:`~pathlib.Path.is_block_device` + * :meth:`~pathlib.Path.is_char_device` + * :meth:`~pathlib.Path.is_dir` + * :meth:`~pathlib.Path.is_fifo` + * :meth:`~pathlib.Path.is_file` + * :meth:`~pathlib.Path.is_junction` + * :meth:`~pathlib.Path.is_mount` + * :meth:`~pathlib.Path.is_socket` + * :meth:`~pathlib.Path.is_symlink` + * :meth:`~pathlib.Path.lchmod` + * :meth:`~pathlib.Path.lstat` + * :meth:`~pathlib.Path.mkdir` + * :meth:`~pathlib.Path.open` + * :meth:`~pathlib.Path.owner` + * :meth:`~pathlib.Path.read_bytes` + * :meth:`~pathlib.Path.read_text` + * :meth:`~pathlib.Path.readlink` + * :meth:`~pathlib.Path.rename` + * :meth:`~pathlib.Path.replace` + * :meth:`~pathlib.Path.resolve` + * :meth:`~pathlib.Path.rmdir` + * :meth:`~pathlib.Path.samefile` + * :meth:`~pathlib.Path.stat` + * :meth:`~pathlib.Path.symlink_to` + * :meth:`~pathlib.Path.touch` + * :meth:`~pathlib.Path.unlink` + * :meth:`~pathlib.Path.walk` + * :meth:`~pathlib.Path.write_bytes` + * :meth:`~pathlib.Path.write_text` + + Additionally, the following methods return an async iterator yielding + :class:`~.Path` objects: + + * :meth:`~pathlib.Path.glob` + * :meth:`~pathlib.Path.iterdir` + * :meth:`~pathlib.Path.rglob` + + .. versionchanged:: 4.14.0 + Added the ``limiter`` keyword argument. + """ + + __slots__ = "__weakref__", "_limiter", "_path" + + __weakref__: Any + + def __init__( + self, *args: str | PathLike[str], limiter: CapacityLimiter | None = None + ) -> None: + if limiter is not None and not isinstance(limiter, CapacityLimiter): + raise TypeError( + f"limiter must be a CapacityLimiter or None, not " + f"{limiter.__class__.__name__}" + ) + + self._path: Final[pathlib.Path] = pathlib.Path(*args) + self._limiter = limiter + + def __fspath__(self) -> str: + return self._path.__fspath__() + + if sys.version_info >= (3, 15): + + def __vfspath__(self) -> str: + return self._path.__vfspath__() + + def __str__(self) -> str: + return self._path.__str__() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.as_posix()!r})" + + def __bytes__(self) -> bytes: + return self._path.__bytes__() + + def __hash__(self) -> int: + return self._path.__hash__() + + def __eq__(self, other: object) -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__eq__(target) + + def __lt__(self, other: pathlib.PurePath | Path) -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__lt__(target) + + def __le__(self, other: pathlib.PurePath | Path) -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__le__(target) + + def __gt__(self, other: pathlib.PurePath | Path) -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__gt__(target) + + def __ge__(self, other: pathlib.PurePath | Path) -> bool: + target = other._path if isinstance(other, Path) else other + return self._path.__ge__(target) + + def __truediv__(self, other: str | PathLike[str]) -> Self: + return type(self)(self._path / other, limiter=self._limiter) + + def __rtruediv__(self, other: str | PathLike[str]) -> Self: + return type(self)(other, limiter=self._limiter) / self + + @property + def limiter(self) -> CapacityLimiter | None: + """The capacity limiter used by this path, if not the global limiter.""" + return self._limiter + + @property + def parts(self) -> tuple[str, ...]: + return self._path.parts + + @property + def drive(self) -> str: + return self._path.drive + + @property + def root(self) -> str: + return self._path.root + + @property + def anchor(self) -> str: + return self._path.anchor + + @property + def parents(self) -> Sequence[Self]: + return tuple(type(self)(p, limiter=self._limiter) for p in self._path.parents) + + @property + def parent(self) -> Self: + return type(self)(self._path.parent, limiter=self._limiter) + + @property + def name(self) -> str: + return self._path.name + + @property + def suffix(self) -> str: + return self._path.suffix + + @property + def suffixes(self) -> list[str]: + return self._path.suffixes + + @property + def stem(self) -> str: + return self._path.stem + + async def absolute(self) -> Self: + path = await to_thread.run_sync(self._path.absolute, limiter=self._limiter) + return type(self)(path, limiter=self._limiter) + + def as_posix(self) -> str: + return self._path.as_posix() + + def as_uri(self) -> str: + return self._path.as_uri() + + if sys.version_info >= (3, 13): + parser: ClassVar[ModuleType] = pathlib.Path.parser + + @classmethod + def from_uri(cls, uri: str, *, limiter: CapacityLimiter | None = None) -> Self: + return cls(pathlib.Path.from_uri(uri), limiter=limiter) + + def full_match( + self, path_pattern: str, *, case_sensitive: bool | None = None + ) -> bool: + return self._path.full_match(path_pattern, case_sensitive=case_sensitive) + + def match( + self, path_pattern: str, *, case_sensitive: bool | None = None + ) -> bool: + return self._path.match(path_pattern, case_sensitive=case_sensitive) + else: + + def match(self, path_pattern: str) -> bool: + return self._path.match(path_pattern) + + if sys.version_info >= (3, 14): + + @property + def info(self) -> PathInfo: + return self._path.info + + async def copy( + self, + target: str | os.PathLike[str], + *, + follow_symlinks: bool = True, + preserve_metadata: bool = False, + ) -> Self: + func = partial( + self._path.copy, + follow_symlinks=follow_symlinks, + preserve_metadata=preserve_metadata, + ) + return type(self)( + await to_thread.run_sync( + func, pathlib.Path(target), limiter=self._limiter + ), + limiter=self._limiter, + ) + + async def copy_into( + self, + target_dir: str | os.PathLike[str], + *, + follow_symlinks: bool = True, + preserve_metadata: bool = False, + ) -> Self: + func = partial( + self._path.copy_into, + follow_symlinks=follow_symlinks, + preserve_metadata=preserve_metadata, + ) + return type(self)( + await to_thread.run_sync( + func, pathlib.Path(target_dir), limiter=self._limiter + ), + limiter=self._limiter, + ) + + async def move(self, target: str | os.PathLike[str]) -> Self: + # Upstream does not handle anyio.Path properly as a PathLike + target = pathlib.Path(target) + return type(self)( + await to_thread.run_sync( + self._path.move, target, limiter=self._limiter + ), + limiter=self._limiter, + ) + + async def move_into( + self, + target_dir: str | os.PathLike[str], + ) -> Self: + return type(self)( + await to_thread.run_sync( + self._path.move_into, target_dir, limiter=self._limiter + ), + limiter=self._limiter, + ) + + def is_relative_to(self, other: str | PathLike[str]) -> bool: + try: + self.relative_to(other) + return True + except ValueError: + return False + + async def chmod(self, mode: int, *, follow_symlinks: bool = True) -> None: + func = partial(os.chmod, follow_symlinks=follow_symlinks) + return await to_thread.run_sync(func, self._path, mode, limiter=self._limiter) + + @classmethod + async def cwd(cls, *, limiter: CapacityLimiter | None = None) -> Self: + path = await to_thread.run_sync(pathlib.Path.cwd, limiter=limiter) + return cls(path, limiter=limiter) + + if sys.version_info >= (3, 12): + + async def exists(self, *, follow_symlinks: bool = True) -> bool: + return await to_thread.run_sync( + partial(self._path.exists, follow_symlinks=follow_symlinks), + abandon_on_cancel=True, + limiter=self._limiter, + ) + + else: + + async def exists(self) -> bool: + return await to_thread.run_sync( + self._path.exists, abandon_on_cancel=True, limiter=self._limiter + ) + + async def expanduser(self) -> Self: + return type(self)( + await to_thread.run_sync( + self._path.expanduser, abandon_on_cancel=True, limiter=self._limiter + ), + limiter=self._limiter, + ) + + if sys.version_info < (3, 12): + # Python 3.11 and earlier + def glob(self, pattern: str) -> AsyncIterator[Self]: + gen = self._path.glob(pattern) + return _PathIterator(gen, self._limiter, type(self)) + elif (3, 12) <= sys.version_info < (3, 13): + # changed in Python 3.12: + # - The case_sensitive parameter was added. + def glob( + self, + pattern: str, + *, + case_sensitive: bool | None = None, + ) -> AsyncIterator[Self]: + gen = self._path.glob(pattern, case_sensitive=case_sensitive) + return _PathIterator(gen, self._limiter, type(self)) + elif sys.version_info >= (3, 13): + # Changed in Python 3.13: + # - The recurse_symlinks parameter was added. + # - The pattern parameter accepts a path-like object. + def glob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block + self, + pattern: str | PathLike[str], + *, + case_sensitive: bool | None = None, + recurse_symlinks: bool = False, + ) -> AsyncIterator[Self]: + gen = self._path.glob( + pattern, # type: ignore[arg-type] + case_sensitive=case_sensitive, + recurse_symlinks=recurse_symlinks, + ) + return _PathIterator(gen, self._limiter, type(self)) + + if sys.version_info >= (3, 13): + + async def group(self, *, follow_symlinks: bool = True) -> str: + return await to_thread.run_sync( + partial(self._path.group, follow_symlinks=follow_symlinks), + abandon_on_cancel=True, + limiter=self._limiter, + ) + + else: + + async def group(self) -> str: + return await to_thread.run_sync( + self._path.group, abandon_on_cancel=True, limiter=self._limiter + ) + + async def hardlink_to( + self, target: str | bytes | PathLike[str] | PathLike[bytes] + ) -> None: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(os.link, target, self, limiter=self._limiter) + + @classmethod + async def home(cls, *, limiter: CapacityLimiter | None = None) -> Self: + home_path = await to_thread.run_sync(pathlib.Path.home, limiter=limiter) + return cls(home_path, limiter=limiter) + + def is_absolute(self) -> bool: + return self._path.is_absolute() + + async def is_block_device(self) -> bool: + return await to_thread.run_sync( + self._path.is_block_device, abandon_on_cancel=True, limiter=self._limiter + ) + + async def is_char_device(self) -> bool: + return await to_thread.run_sync( + self._path.is_char_device, abandon_on_cancel=True, limiter=self._limiter + ) + + if sys.version_info >= (3, 13): + + async def is_dir(self, *, follow_symlinks: bool = True) -> bool: + return await to_thread.run_sync( + partial(self._path.is_dir, follow_symlinks=follow_symlinks), + abandon_on_cancel=True, + limiter=self._limiter, + ) + + else: + + async def is_dir(self) -> bool: + return await to_thread.run_sync( + self._path.is_dir, abandon_on_cancel=True, limiter=self._limiter + ) + + async def is_fifo(self) -> bool: + return await to_thread.run_sync( + self._path.is_fifo, abandon_on_cancel=True, limiter=self._limiter + ) + + if sys.version_info >= (3, 13): + + async def is_file(self, *, follow_symlinks: bool = True) -> bool: + return await to_thread.run_sync( + partial(self._path.is_file, follow_symlinks=follow_symlinks), + abandon_on_cancel=True, + limiter=self._limiter, + ) + + else: + + async def is_file(self) -> bool: + return await to_thread.run_sync( + self._path.is_file, abandon_on_cancel=True, limiter=self._limiter + ) + + if sys.version_info >= (3, 12): + + async def is_junction(self) -> bool: + return await to_thread.run_sync( + self._path.is_junction, limiter=self._limiter + ) + + async def is_mount(self) -> bool: + return await to_thread.run_sync( + os.path.ismount, self._path, abandon_on_cancel=True, limiter=self._limiter + ) + + if sys.version_info < (3, 15): + + def is_reserved(self) -> bool: + return self._path.is_reserved() + + async def is_socket(self) -> bool: + return await to_thread.run_sync( + self._path.is_socket, abandon_on_cancel=True, limiter=self._limiter + ) + + async def is_symlink(self) -> bool: + return await to_thread.run_sync( + self._path.is_symlink, abandon_on_cancel=True, limiter=self._limiter + ) + + async def iterdir(self) -> AsyncIterator[Self]: + gen = ( + self._path.iterdir() + if sys.version_info < (3, 13) + else await to_thread.run_sync( + self._path.iterdir, abandon_on_cancel=True, limiter=self._limiter + ) + ) + async for path in _PathIterator(gen, self._limiter, type(self)): + yield path + + def joinpath(self, *args: str | PathLike[str]) -> Self: + return type(self)(self._path.joinpath(*args), limiter=self._limiter) + + async def lchmod(self, mode: int) -> None: + await to_thread.run_sync(self._path.lchmod, mode, limiter=self._limiter) + + async def lstat(self) -> os.stat_result: + return await to_thread.run_sync( + self._path.lstat, abandon_on_cancel=True, limiter=self._limiter + ) + + async def mkdir( + self, mode: int = 0o777, parents: bool = False, exist_ok: bool = False + ) -> None: + await to_thread.run_sync( + self._path.mkdir, mode, parents, exist_ok, limiter=self._limiter + ) + + @overload + async def open( + self, + mode: OpenBinaryMode, + buffering: int = ..., + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., + ) -> AsyncFile[bytes]: ... + + @overload + async def open( + self, + mode: OpenTextMode = ..., + buffering: int = ..., + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., + ) -> AsyncFile[str]: ... + + async def open( + self, + mode: str = "r", + buffering: int = -1, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + ) -> AsyncFile[Any]: + fp = await to_thread.run_sync( + self._path.open, + mode, + buffering, + encoding, + errors, + newline, + limiter=self._limiter, + ) + return AsyncFile(fp, limiter=self._limiter) + + if sys.version_info >= (3, 13): + + async def owner(self, *, follow_symlinks: bool = True) -> str: + return await to_thread.run_sync( + partial(self._path.owner, follow_symlinks=follow_symlinks), + abandon_on_cancel=True, + limiter=self._limiter, + ) + + else: + + async def owner(self) -> str: + return await to_thread.run_sync( + self._path.owner, abandon_on_cancel=True, limiter=self._limiter + ) + + async def read_bytes(self) -> bytes: + return await to_thread.run_sync(self._path.read_bytes, limiter=self._limiter) + + if sys.version_info >= (3, 13): + + async def read_text( + self, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + ) -> str: + return await to_thread.run_sync( + self._path.read_text, + encoding, + errors, + newline, + limiter=self._limiter, + ) + + else: + + async def read_text( + self, encoding: str | None = None, errors: str | None = None + ) -> str: + return await to_thread.run_sync( + self._path.read_text, encoding, errors, limiter=self._limiter + ) + + if sys.version_info >= (3, 12): + + def relative_to( + self, *other: str | PathLike[str], walk_up: bool = False + ) -> Self: + # relative_to() should work with any PathLike but it doesn't + others = [pathlib.Path(other) for other in other] + return type(self)( + self._path.relative_to(*others, walk_up=walk_up), limiter=self._limiter + ) + + else: + + def relative_to(self, *other: str | PathLike[str]) -> Self: + return type(self)(self._path.relative_to(*other), limiter=self._limiter) + + async def readlink(self) -> Self: + target = await to_thread.run_sync( + os.readlink, self._path, limiter=self._limiter + ) + return type(self)(target, limiter=self._limiter) + + async def rename(self, target: str | pathlib.PurePath | Path) -> Self: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.rename, target, limiter=self._limiter) + return type(self)(target, limiter=self._limiter) + + async def replace(self, target: str | pathlib.PurePath | Path) -> Self: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync(self._path.replace, target, limiter=self._limiter) + return type(self)(target, limiter=self._limiter) + + async def resolve(self, strict: bool = False) -> Self: + func = partial(self._path.resolve, strict=strict) + return type(self)( + await to_thread.run_sync( + func, abandon_on_cancel=True, limiter=self._limiter + ), + limiter=self._limiter, + ) + + if sys.version_info < (3, 12): + # Pre Python 3.12 + def rglob(self, pattern: str) -> AsyncIterator[Self]: + gen = self._path.rglob(pattern) + return _PathIterator(gen, self._limiter, type(self)) + elif (3, 12) <= sys.version_info < (3, 13): + # Changed in Python 3.12: + # - The case_sensitive parameter was added. + def rglob( + self, pattern: str, *, case_sensitive: bool | None = None + ) -> AsyncIterator[Self]: + gen = self._path.rglob(pattern, case_sensitive=case_sensitive) + return _PathIterator(gen, self._limiter, type(self)) + elif sys.version_info >= (3, 13): + # Changed in Python 3.13: + # - The recurse_symlinks parameter was added. + # - The pattern parameter accepts a path-like object. + def rglob( # type: ignore[misc] # mypy doesn't allow for differing signatures in a conditional block + self, + pattern: str | PathLike[str], + *, + case_sensitive: bool | None = None, + recurse_symlinks: bool = False, + ) -> AsyncIterator[Self]: + gen = self._path.rglob( + pattern, # type: ignore[arg-type] + case_sensitive=case_sensitive, + recurse_symlinks=recurse_symlinks, + ) + return _PathIterator(gen, self._limiter, type(self)) + + async def rmdir(self) -> None: + await to_thread.run_sync(self._path.rmdir, limiter=self._limiter) + + async def samefile(self, other_path: str | PathLike[str]) -> bool: + if isinstance(other_path, Path): + other_path = other_path._path + + return await to_thread.run_sync( + self._path.samefile, + other_path, + abandon_on_cancel=True, + limiter=self._limiter, + ) + + async def stat(self, *, follow_symlinks: bool = True) -> os.stat_result: + func = partial(os.stat, follow_symlinks=follow_symlinks) + return await to_thread.run_sync( + func, self._path, abandon_on_cancel=True, limiter=self._limiter + ) + + async def symlink_to( + self, + target: str | bytes | PathLike[str] | PathLike[bytes], + target_is_directory: bool = False, + ) -> None: + if isinstance(target, Path): + target = target._path + + await to_thread.run_sync( + self._path.symlink_to, target, target_is_directory, limiter=self._limiter + ) + + async def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None: + await to_thread.run_sync( + self._path.touch, mode, exist_ok, limiter=self._limiter + ) + + async def unlink(self, missing_ok: bool = False) -> None: + try: + await to_thread.run_sync(self._path.unlink, limiter=self._limiter) + except FileNotFoundError: + if not missing_ok: + raise + + if sys.version_info >= (3, 12): + + async def walk( + self, + top_down: bool = True, + on_error: Callable[[OSError], object] | None = None, + follow_symlinks: bool = False, + ) -> AsyncIterator[tuple[Self, list[str], list[str]]]: + def get_next_value() -> tuple[pathlib.Path, list[str], list[str]] | None: + try: + return next(gen) + except StopIteration: + return None + + gen = self._path.walk(top_down, on_error, follow_symlinks) + while True: + value = await to_thread.run_sync(get_next_value, limiter=self._limiter) + if value is None: + return + + root, dirs, paths = value + yield type(self)(root, limiter=self._limiter), dirs, paths + + def with_name(self, name: str) -> Self: + return type(self)(self._path.with_name(name), limiter=self._limiter) + + if sys.version_info < (3, 13): + # Backport pathlib's Python>=3.13 behavior for empty stems on paths with non-empty suffixes. + # See: https://github.com/python/cpython/pull/114612 + def with_stem(self, stem: str) -> Self: + suffix = self._path.suffix + if not suffix: + return self.with_name(stem) + elif not stem: + # If the suffix is non-empty, we can't make the stem empty. + raise ValueError(f"{self!r} has a non-empty suffix") + else: + return self.with_name(stem + suffix) + else: + + def with_stem(self, stem: str) -> Self: + return type(self)(self._path.with_stem(stem), limiter=self._limiter) + + def with_suffix(self, suffix: str) -> Self: + return type(self)(self._path.with_suffix(suffix), limiter=self._limiter) + + def with_segments(self, *pathsegments: str | PathLike[str]) -> Self: + return type(self)(*pathsegments, limiter=self._limiter) + + async def write_bytes(self, data: ReadableBuffer) -> int: + return await to_thread.run_sync( + self._path.write_bytes, data, limiter=self._limiter + ) + + async def write_text( + self, + data: str, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + ) -> int: + return await to_thread.run_sync( + self._path.write_text, + data, + encoding, + errors, + newline, + limiter=self._limiter, + ) + + +PathLike.register(Path) diff --git a/source/target-vendors/cp312/anyio/_core/_futures.py b/source/target-vendors/cp312/anyio/_core/_futures.py new file mode 100644 index 0000000..7730c53 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_futures.py @@ -0,0 +1,191 @@ +from __future__ import annotations + +from collections.abc import Generator +from enum import Enum, auto +from typing import Any, Generic, TypeVar + +from ._exceptions import ( + FutureAlreadyFinished, + FutureCancelled, + FutureFailed, + FutureNotFinished, +) +from ._synchronization import Event + +T = TypeVar("T") + + +class Future(Generic[T]): + """ + An awaitable object that works similar to a :class:`asyncio.Future` but + with similar characteristics to a :class:`.TaskHandle`. + """ + + class Status(Enum): + """ + The status of a future handle. + + .. attribute:: PENDING + + The future has not finished yet. + .. attribute:: FINISHED + + The future has finished with a return value. + .. attribute:: CANCELLED + + The future was cancelled and has finished since. + .. attribute:: FAILED + + The future raised an exception. + """ + + PENDING = auto() + FINISHED = auto() + CANCELLED = auto() + FAILED = auto() + + __slots__ = ( + "_cancelled", + "_exception", + "_finished_event", + "_name", + "_return_value", + ) + _return_value: T + + def __init__(self, *, name: str | None = None) -> None: + self._finished_event = Event() + self._exception: BaseException | None = None + self._cancelled: bool = False + self._name = name + + def _check_pending(self) -> None: + """Shortcut for checking if a Future is pending + + :raises FutureAlreadyFinished: if future was already given a result or exception. + :raises FutureCancelled: if future has been cancelled previously. + """ + match self.status: + case Future.Status.PENDING: + return + case Future.Status.FINISHED: + raise FutureAlreadyFinished("future has already finished") + case Future.Status.FAILED: + raise FutureAlreadyFinished("future already failed") + case Future.Status.CANCELLED: + raise FutureCancelled("future was cancelled") + + async def wait(self) -> None: + """ + Waits for the future to finish. + + This method will attempt to wait for a result or exception + """ + await self._finished_event.wait() + + def cancel(self) -> None: + """Cancels a pending `.Future` object + + Does nothing if the Future was already finished. + """ + if self.status is Future.Status.PENDING: + self._cancelled = True + self._finished_event.set() + + @property + def exception(self) -> BaseException | None: + """ + The exception value of a `.Future` + + :raises FutureNotFinished: if future is still pending + :raises FutureCancelled: if future was cancelled + :returns: None if future succeeds with a result sent instead + otherwise this will be an exception + """ + + match self.status: + case Future.Status.PENDING: + raise FutureNotFinished("the future has not finished yet") + case Future.Status.FINISHED: + return None + case Future.Status.CANCELLED: + raise FutureCancelled("the future was cancelled") + case Future.Status.FAILED: + return self._exception + + @exception.setter + def exception(self, exception: BaseException) -> None: + """Send exception for a `.Future` object + + :raises FutureAlreadyFinished: if future was already given a result or exception. + :raises FutureCancelled: if future has been cancelled previously. + """ + self._check_pending() + self._exception = exception + self._finished_event.set() + + @property + def return_value(self) -> T: + """ + The return value of the future. + + :raises FutureNotFinished: if the future has not finished yet + :raises FutureCancelled: if the future was cancelled + :raises FutureFailed: if the future raised an exception + + """ + match self.status: + case Future.Status.PENDING: + raise FutureNotFinished("the future has not finished yet") + case Future.Status.FINISHED: + return self._return_value + case Future.Status.CANCELLED: + raise FutureCancelled("the future was cancelled") + case Future.Status.FAILED: + raise FutureFailed( + "the future raised an exception" + ) from self._exception + + @return_value.setter + def return_value(self, value: T) -> None: + """ + Send pending result for a `.Future` object + + :raises FutureAlreadyFinished: if future was already given a result or exception. + :raises FutureCancelled: if future has been cancelled previously. + """ + self._check_pending() + self._return_value = value + self._finished_event.set() + + @property + def status(self) -> Future.Status: + """ + The current status of a future. + + Every future starts in the :attr:`~Future.Status.PENDING` state. + If a future is cancelled while in this state, it will transition to the + :attr:`Future.Status.CANCELLED` state. When the task finishes, it will + transition to one of the three final states ( + :attr:`Future.Status.FINISHED`, :attr:`Future.Status.FAILED`, or + :attr:`Future.Status.CANCELLED`) depending on the exception the task + raised, if any. No other status transitions will happen. + """ + if not self._finished_event.is_set(): + return Future.Status.PENDING + elif self._cancelled: + return Future.Status.CANCELLED + elif self._exception is not None: + return Future.Status.FAILED + else: + return Future.Status.FINISHED + + def __await__(self) -> Generator[Any, Any, T]: + yield from self.wait().__await__() + return self.return_value + + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} {self.status.name.lower()} " + f"name={self._name!r}>" + ) diff --git a/source/target-vendors/cp312/anyio/_core/_resources.py b/source/target-vendors/cp312/anyio/_core/_resources.py new file mode 100644 index 0000000..6ca35d9 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_resources.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +from ..abc import AsyncResource # noqa: TC001 +from ._tasks import CancelScope + + +async def aclose_forcefully(resource: AsyncResource) -> None: + """ + Close an asynchronous resource in a cancelled scope. + + Doing this closes the resource without waiting on anything. + + :param resource: the resource to close + + """ + with CancelScope() as scope: + scope.cancel() + await resource.aclose() diff --git a/source/target-vendors/cp312/anyio/_core/_signals.py b/source/target-vendors/cp312/anyio/_core/_signals.py new file mode 100644 index 0000000..e24c79e --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_signals.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from collections.abc import AsyncIterator +from contextlib import AbstractContextManager +from signal import Signals + +from ._eventloop import get_async_backend + + +def open_signal_receiver( + *signals: Signals, +) -> AbstractContextManager[AsyncIterator[Signals]]: + """ + Start receiving operating system signals. + + :param signals: signals to receive (e.g. ``signal.SIGINT``) + :return: an asynchronous context manager for an asynchronous iterator which yields + signal numbers + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. warning:: Windows does not support signals natively so it is best to avoid + relying on this in cross-platform applications. + + .. warning:: On asyncio, this permanently replaces any previous signal handler for + the given signals, as set via :meth:`~asyncio.loop.add_signal_handler`. + + """ + return get_async_backend().open_signal_receiver(*signals) diff --git a/source/target-vendors/cp312/anyio/_core/_sockets.py b/source/target-vendors/cp312/anyio/_core/_sockets.py new file mode 100644 index 0000000..14ee6e4 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_sockets.py @@ -0,0 +1,1011 @@ +from __future__ import annotations + +import errno +import os +import socket +import ssl +import stat +import sys +from collections.abc import Awaitable +from dataclasses import dataclass +from ipaddress import IPv4Address, IPv6Address, ip_address +from os import PathLike, chmod +from socket import AddressFamily, SocketKind +from typing import TYPE_CHECKING, Any, Literal, cast, overload + +from .. import ConnectionFailed, to_thread +from ..abc import ( + ByteStreamConnectable, + ConnectedUDPSocket, + ConnectedUNIXDatagramSocket, + IPAddressType, + IPSockAddrType, + SocketListener, + SocketStream, + UDPSocket, + UNIXDatagramSocket, + UNIXSocketStream, +) +from ..streams.stapled import MultiListener +from ..streams.tls import TLSConnectable, TLSStream +from ._eventloop import get_async_backend +from ._resources import aclose_forcefully +from ._synchronization import Event +from ._tasks import create_task_group, move_on_after + +if TYPE_CHECKING: + from _typeshed import FileDescriptorLike +else: + FileDescriptorLike = object + +if sys.version_info < (3, 11): + from exceptiongroup import ExceptionGroup + +if sys.version_info >= (3, 12): + from typing import override +else: + from typing_extensions import override + +if sys.version_info < (3, 13): + from typing_extensions import deprecated +else: + from warnings import deprecated + +IPPROTO_IPV6 = getattr(socket, "IPPROTO_IPV6", 41) # https://bugs.python.org/issue29515 + +AnyIPAddressFamily = Literal[ + AddressFamily.AF_UNSPEC, AddressFamily.AF_INET, AddressFamily.AF_INET6 +] +IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6] + + +def idna2008_resolve(host: str) -> bytes: + try: + return host.encode("ascii") + except UnicodeEncodeError: + import idna + + return idna.encode(host, uts46=True) + + +# tls_hostname given +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | None = ..., + local_port: int | None = ..., + ssl_context: ssl.SSLContext | None = ..., + tls_standard_compatible: bool = ..., + tls_hostname: str, + happy_eyeballs_delay: float = ..., +) -> TLSStream: ... + + +# ssl_context given +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | None = ..., + local_port: int | None = ..., + ssl_context: ssl.SSLContext, + tls_standard_compatible: bool = ..., + tls_hostname: str | None = ..., + happy_eyeballs_delay: float = ..., +) -> TLSStream: ... + + +# tls=True +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | None = ..., + local_port: int | None = ..., + tls: Literal[True], + ssl_context: ssl.SSLContext | None = ..., + tls_standard_compatible: bool = ..., + tls_hostname: str | None = ..., + happy_eyeballs_delay: float = ..., +) -> TLSStream: ... + + +# tls=False +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | None = ..., + local_port: int | None = ..., + tls: Literal[False], + ssl_context: ssl.SSLContext | None = ..., + tls_standard_compatible: bool = ..., + tls_hostname: str | None = ..., + happy_eyeballs_delay: float = ..., +) -> SocketStream: ... + + +# No TLS arguments +@overload +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | None = ..., + local_port: int | None = ..., + happy_eyeballs_delay: float = ..., +) -> SocketStream: ... + + +async def connect_tcp( + remote_host: IPAddressType, + remote_port: int, + *, + local_host: IPAddressType | None = None, + local_port: int | None = None, + tls: bool = False, + ssl_context: ssl.SSLContext | None = None, + tls_standard_compatible: bool = True, + tls_hostname: str | None = None, + happy_eyeballs_delay: float = 0.25, +) -> SocketStream | TLSStream: + """ + Connect to a host using the TCP protocol. + + This function implements the stateless version of the Happy Eyeballs algorithm (RFC + 6555). If ``remote_host`` is a host name that resolves to multiple IP addresses, + each one is tried until one connection attempt succeeds. If the first attempt does + not connected within 250 milliseconds, a second attempt is started using the next + address in the list, and so on. On IPv6 enabled systems, an IPv6 address (if + available) is tried first. + + When the connection has been established, a TLS handshake will be done if either + ``ssl_context`` or ``tls_hostname`` is not ``None``, or if ``tls`` is ``True``. + + :param remote_host: the IP address or host name to connect to + :param remote_port: port on the target host to connect to + :param local_host: the interface address or name to bind the socket to before + connecting + :param local_port: the local port to bind to (requires ``local_host`` to also be + set) + :param tls: ``True`` to do a TLS handshake with the connected stream and return a + :class:`~anyio.streams.tls.TLSStream` instead + :param ssl_context: the SSL context object to use (if omitted, a default context is + created) + :param tls_standard_compatible: If ``True``, performs the TLS shutdown handshake + before closing the stream and requires that the server does this as well. + Otherwise, :exc:`~ssl.SSLEOFError` may be raised during reads from the stream. + Some protocols, such as HTTP, require this option to be ``False``. + See :meth:`~ssl.SSLContext.wrap_socket` for details. + :param tls_hostname: host name to check the server certificate against (defaults to + the value of ``remote_host``) + :param happy_eyeballs_delay: delay (in seconds) before starting the next connection + attempt + :return: a socket stream object if no TLS handshake was done, otherwise a TLS stream + :raises ConnectionFailed: if the connection fails + + """ + # Placed here due to https://github.com/python/mypy/issues/7057 + connected_stream: SocketStream | None = None + + async def try_connect(remote_host: str, event: Event) -> None: + nonlocal connected_stream + try: + stream = await asynclib.connect_tcp(remote_host, remote_port, local_address) + except OSError as exc: + oserrors.append(exc) + return + else: + if connected_stream is None: + connected_stream = stream + tg.cancel_scope.cancel() + else: + await stream.aclose() + finally: + event.set() + + asynclib = get_async_backend() + local_address: IPSockAddrType | None = None + family = socket.AF_UNSPEC + if local_host: + gai_res = await getaddrinfo(str(local_host), local_port) + family, *_, local_address = gai_res[0] + + target_host = str(remote_host) + try: + addr_obj = ip_address(remote_host) + except ValueError: + addr_obj = None + + if addr_obj is not None: + if isinstance(addr_obj, IPv6Address): + target_addrs = [(socket.AF_INET6, addr_obj.compressed)] + else: + target_addrs = [(socket.AF_INET, addr_obj.compressed)] + else: + # getaddrinfo() will raise an exception if name resolution fails + gai_res = await getaddrinfo( + target_host, remote_port, family=family, type=socket.SOCK_STREAM + ) + + # Organize the list so that the first address is an IPv6 address (if available) + # and the second one is an IPv4 addresses. The rest can be in whatever order. + v6_found = v4_found = False + target_addrs = [] + for af, *_, sa in gai_res: + if af == socket.AF_INET6 and not v6_found: + v6_found = True + target_addrs.insert(0, (af, sa[0])) + elif af == socket.AF_INET and not v4_found and v6_found: + v4_found = True + target_addrs.insert(1, (af, sa[0])) + else: + target_addrs.append((af, sa[0])) + + oserrors: list[OSError] = [] + try: + async with create_task_group() as tg: + for _af, addr in target_addrs: + event = Event() + tg.start_soon(try_connect, addr, event) + with move_on_after(happy_eyeballs_delay): + await event.wait() + + if connected_stream is None: + cause = ( + oserrors[0] + if len(oserrors) == 1 + else ExceptionGroup("multiple connection attempts failed", oserrors) + ) + raise OSError("All connection attempts failed") from cause + finally: + oserrors.clear() + + if tls or tls_hostname or ssl_context: + try: + return await TLSStream.wrap( + connected_stream, + server_side=False, + hostname=tls_hostname or str(remote_host), + ssl_context=ssl_context, + standard_compatible=tls_standard_compatible, + ) + except BaseException: + await aclose_forcefully(connected_stream) + raise + + return connected_stream + + +async def connect_unix(path: str | bytes | PathLike[Any]) -> UNIXSocketStream: + """ + Connect to the given UNIX socket. + + Not available on Windows. + + :param path: path to the socket + :return: a socket stream object + :raises ConnectionFailed: if the connection fails + + """ + path = os.fspath(path) + return await get_async_backend().connect_unix(path) + + +async def create_tcp_listener( + *, + local_host: IPAddressType | None = None, + local_port: int = 0, + family: AnyIPAddressFamily = socket.AddressFamily.AF_UNSPEC, + backlog: int = 65536, + reuse_port: bool = False, +) -> MultiListener[SocketStream]: + """ + Create a TCP socket listener. + + :param local_port: port number to listen on + :param local_host: IP address of the interface to listen on. If omitted, listen on + all IPv4 and IPv6 interfaces. To listen on all interfaces on a specific address + family, use ``0.0.0.0`` for IPv4 or ``::`` for IPv6. + :param family: address family (used if ``local_host`` was omitted) + :param backlog: maximum number of queued incoming connections (up to a maximum of + 2**16, or 65536) + :param reuse_port: ``True`` to allow multiple sockets to bind to the same + address/port (not supported on Windows) + :return: a multi-listener object containing one or more socket listeners + :raises OSError: if there's an error creating a socket, or binding to one or more + interfaces failed + + """ + asynclib = get_async_backend() + backlog = min(backlog, 65536) + local_host = str(local_host) if local_host is not None else None + + def setup_raw_socket( + fam: AddressFamily, + bind_addr: tuple[str, int] | tuple[str, int, int, int], + *, + v6only: bool = True, + ) -> socket.socket: + sock = socket.socket(fam) + try: + sock.setblocking(False) + + if fam == AddressFamily.AF_INET6: + sock.setsockopt(IPPROTO_IPV6, socket.IPV6_V6ONLY, v6only) + + # For Windows, enable exclusive address use. For others, enable address + # reuse. + if sys.platform == "win32": + sock.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) + else: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + + if reuse_port: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + + # Workaround for #554 + if fam == socket.AF_INET6 and "%" in bind_addr[0]: + addr, scope_id = bind_addr[0].split("%", 1) + bind_addr = (addr, bind_addr[1], 0, int(scope_id)) + + sock.bind(bind_addr) + sock.listen(backlog) + except BaseException: + sock.close() + raise + + return sock + + # We passing type=0 on non-Windows platforms as a workaround for a uvloop bug + # where we don't get the correct scope ID for IPv6 link-local addresses when passing + # type=socket.SOCK_STREAM to getaddrinfo(): + # https://github.com/MagicStack/uvloop/issues/539 + gai_res = await getaddrinfo( + local_host, + local_port, + family=family, + type=socket.SOCK_STREAM if sys.platform == "win32" else 0, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + + # The set comprehension is here to work around a glibc bug: + # https://sourceware.org/bugzilla/show_bug.cgi?id=14969 + sockaddrs = sorted({res for res in gai_res if res[1] == SocketKind.SOCK_STREAM}) + + # Special case for dual-stack binding on the "any" interface + if ( + local_host is None + and family == AddressFamily.AF_UNSPEC + and socket.has_dualstack_ipv6() + and any(fam == AddressFamily.AF_INET6 for fam, *_ in gai_res) + ): + raw_socket = setup_raw_socket( + AddressFamily.AF_INET6, ("::", local_port), v6only=False + ) + listener = asynclib.create_tcp_listener(raw_socket) + return MultiListener([listener]) + + errors: list[OSError] = [] + try: + for _ in range(len(sockaddrs)): + listeners: list[SocketListener] = [] + bound_ephemeral_port = local_port + try: + for fam, *_, sockaddr in sockaddrs: + sockaddr = sockaddr[0], bound_ephemeral_port, *sockaddr[2:] + raw_socket = setup_raw_socket(fam, sockaddr) + + # Store the assigned port if an ephemeral port was requested, so + # we'll bind to the same port on all interfaces + if local_port == 0 and len(gai_res) > 1: + bound_ephemeral_port = raw_socket.getsockname()[1] + + listeners.append(asynclib.create_tcp_listener(raw_socket)) + except BaseException as exc: + for listener in listeners: + await listener.aclose() + + # If an ephemeral port was requested but binding the assigned port + # failed for another interface, rotate the address list and try again + if ( + isinstance(exc, OSError) + and exc.errno == errno.EADDRINUSE + and local_port == 0 + and bound_ephemeral_port + ): + errors.append(exc) + sockaddrs.append(sockaddrs.pop(0)) + continue + + raise + + return MultiListener(listeners) + + raise OSError( + f"Could not create {len(sockaddrs)} listeners with a consistent port" + ) from ExceptionGroup("Several bind attempts failed", errors) + finally: + del errors # Prevent reference cycles + + +async def create_unix_listener( + path: str | bytes | PathLike[Any], + *, + mode: int | None = None, + backlog: int = 65536, +) -> SocketListener: + """ + Create a UNIX socket listener. + + Not available on Windows. + + :param path: path of the socket + :param mode: permissions to set on the socket + :param backlog: maximum number of queued incoming connections (up to a maximum of + 2**16, or 65536) + :return: a listener object + + .. versionchanged:: 3.0 + If a socket already exists on the file system in the given path, it will be + removed first. + + """ + backlog = min(backlog, 65536) + raw_socket = await setup_unix_local_socket(path, mode, socket.SOCK_STREAM) + try: + raw_socket.listen(backlog) + return get_async_backend().create_unix_listener(raw_socket) + except BaseException: + raw_socket.close() + raise + + +async def create_udp_socket( + family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, + *, + local_host: IPAddressType | None = None, + local_port: int = 0, + reuse_port: bool = False, +) -> UDPSocket: + """ + Create a UDP socket. + + If ``port`` has been given, the socket will be bound to this port on the local + machine, making this socket suitable for providing UDP based services. + + :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically + determined from ``local_host`` if omitted + :param local_host: IP address or host name of the local interface to bind to + :param local_port: local port to bind to + :param reuse_port: ``True`` to allow multiple sockets to bind to the same + address/port (not supported on Windows) + :return: a UDP socket + + """ + if family is AddressFamily.AF_UNSPEC and not local_host: + raise ValueError('Either "family" or "local_host" must be given') + + if local_host: + gai_res = await getaddrinfo( + str(local_host), + local_port, + family=family, + type=socket.SOCK_DGRAM, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + family = cast(AnyIPAddressFamily, gai_res[0][0]) + local_address = gai_res[0][-1] + elif family is AddressFamily.AF_INET6: + local_address = ("::", 0) + else: + local_address = ("0.0.0.0", 0) + + sock = await get_async_backend().create_udp_socket( + family, local_address, None, reuse_port + ) + return cast(UDPSocket, sock) + + +async def create_connected_udp_socket( + remote_host: IPAddressType, + remote_port: int, + *, + family: AnyIPAddressFamily = AddressFamily.AF_UNSPEC, + local_host: IPAddressType | None = None, + local_port: int = 0, + reuse_port: bool = False, +) -> ConnectedUDPSocket: + """ + Create a connected UDP socket. + + Connected UDP sockets can only communicate with the specified remote host/port, an + any packets sent from other sources are dropped. + + :param remote_host: remote host to set as the default target + :param remote_port: port on the remote host to set as the default target + :param family: address family (``AF_INET`` or ``AF_INET6``) – automatically + determined from ``local_host`` or ``remote_host`` if omitted + :param local_host: IP address or host name of the local interface to bind to + :param local_port: local port to bind to + :param reuse_port: ``True`` to allow multiple sockets to bind to the same + address/port (not supported on Windows) + :return: a connected UDP socket + + """ + local_address = None + if local_host: + gai_res = await getaddrinfo( + str(local_host), + local_port, + family=family, + type=socket.SOCK_DGRAM, + flags=socket.AI_PASSIVE | socket.AI_ADDRCONFIG, + ) + family = cast(AnyIPAddressFamily, gai_res[0][0]) + local_address = gai_res[0][-1] + + gai_res = await getaddrinfo( + str(remote_host), remote_port, family=family, type=socket.SOCK_DGRAM + ) + family = cast(AnyIPAddressFamily, gai_res[0][0]) + remote_address = gai_res[0][-1] + + sock = await get_async_backend().create_udp_socket( + family, local_address, remote_address, reuse_port + ) + return cast(ConnectedUDPSocket, sock) + + +async def create_unix_datagram_socket( + *, + local_path: None | str | bytes | PathLike[Any] = None, + local_mode: int | None = None, +) -> UNIXDatagramSocket: + """ + Create a UNIX datagram socket. + + Not available on Windows. + + If ``local_path`` has been given, the socket will be bound to this path, making this + socket suitable for receiving datagrams from other processes. Other processes can + send datagrams to this socket only if ``local_path`` is set. + + If a socket already exists on the file system in the ``local_path``, it will be + removed first. + + :param local_path: the path on which to bind to + :param local_mode: permissions to set on the local socket + :return: a UNIX datagram socket + + """ + raw_socket = await setup_unix_local_socket( + local_path, local_mode, socket.SOCK_DGRAM + ) + return await get_async_backend().create_unix_datagram_socket(raw_socket, None) + + +async def create_connected_unix_datagram_socket( + remote_path: str | bytes | PathLike[Any], + *, + local_path: None | str | bytes | PathLike[Any] = None, + local_mode: int | None = None, +) -> ConnectedUNIXDatagramSocket: + """ + Create a connected UNIX datagram socket. + + Connected datagram sockets can only communicate with the specified remote path. + + If ``local_path`` has been given, the socket will be bound to this path, making + this socket suitable for receiving datagrams from other processes. Other processes + can send datagrams to this socket only if ``local_path`` is set. + + If a socket already exists on the file system in the ``local_path``, it will be + removed first. + + :param remote_path: the path to set as the default target + :param local_path: the path on which to bind to + :param local_mode: permissions to set on the local socket + :return: a connected UNIX datagram socket + + """ + remote_path = os.fspath(remote_path) + raw_socket = await setup_unix_local_socket( + local_path, local_mode, socket.SOCK_DGRAM + ) + return await get_async_backend().create_unix_datagram_socket( + raw_socket, remote_path + ) + + +async def getaddrinfo( + host: bytes | str | None, + port: str | int | None, + *, + family: int | AddressFamily = 0, + type: int | SocketKind = 0, + proto: int = 0, + flags: int = 0, +) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int]]]: + """ + Look up a numeric IP address given a host name. + + Internationalized domain names are translated according to the (non-transitional) + IDNA 2008 standard. + + .. note:: 4-tuple IPv6 socket addresses are automatically converted to 2-tuples of + (host, port), unlike what :func:`socket.getaddrinfo` does. + + :param host: host name + :param port: port number + :param family: socket family (`'AF_INET``, ...) + :param type: socket type (``SOCK_STREAM``, ...) + :param proto: protocol number + :param flags: flags to pass to upstream ``getaddrinfo()`` + :return: list of tuples containing (family, type, proto, canonname, sockaddr) + + .. seealso:: :func:`socket.getaddrinfo` + + """ + # Handle unicode hostnames + encoded_host = idna2008_resolve(host) if isinstance(host, str) else host + gai_res = await get_async_backend().getaddrinfo( + encoded_host, port, family=family, type=type, proto=proto, flags=flags + ) + return [ + (family, type, proto, canonname, convert_ipv6_sockaddr(sockaddr)) + for family, type, proto, canonname, sockaddr in gai_res + # filter out IPv6 results when IPv6 is disabled + if not isinstance(sockaddr[0], int) + ] + + +def getnameinfo(sockaddr: IPSockAddrType, flags: int = 0) -> Awaitable[tuple[str, str]]: + """ + Look up the host name of an IP address. + + :param sockaddr: socket address (e.g. (ipaddress, port) for IPv4) + :param flags: flags to pass to upstream ``getnameinfo()`` + :return: a tuple of (host name, service name) + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. seealso:: :func:`socket.getnameinfo` + + """ + return get_async_backend().getnameinfo(sockaddr, flags) + + +@deprecated("This function is deprecated; use `wait_readable` instead") +def wait_socket_readable(sock: socket.socket) -> Awaitable[None]: + """ + .. deprecated:: 4.7.0 + Use :func:`wait_readable` instead. + + Wait until the given socket has data to be read. + + .. warning:: Only use this on raw sockets that have not been wrapped by any higher + level constructs like socket streams! + + :param sock: a socket object + :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the + socket to become readable + :raises ~anyio.BusyResourceError: if another task is already waiting for the socket + to become readable + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().wait_readable(sock.fileno()) + + +@deprecated("This function is deprecated; use `wait_writable` instead") +def wait_socket_writable(sock: socket.socket) -> Awaitable[None]: + """ + .. deprecated:: 4.7.0 + Use :func:`wait_writable` instead. + + Wait until the given socket can be written to. + + This does **NOT** work on Windows when using the asyncio backend with a proactor + event loop (default on py3.8+). + + .. warning:: Only use this on raw sockets that have not been wrapped by any higher + level constructs like socket streams! + + :param sock: a socket object + :raises ~anyio.ClosedResourceError: if the socket was closed while waiting for the + socket to become writable + :raises ~anyio.BusyResourceError: if another task is already waiting for the socket + to become writable + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().wait_writable(sock.fileno()) + + +def wait_readable(obj: FileDescriptorLike) -> Awaitable[None]: + """ + Wait until the given object has data to be read. + + On Unix systems, ``obj`` must either be an integer file descriptor, or else an + object with a ``.fileno()`` method which returns an integer file descriptor. Any + kind of file descriptor can be passed, though the exact semantics will depend on + your kernel. For example, this probably won't do anything useful for on-disk files. + + On Windows systems, ``obj`` must either be an integer ``SOCKET`` handle, or else an + object with a ``.fileno()`` method which returns an integer ``SOCKET`` handle. File + descriptors aren't supported, and neither are handles that refer to anything besides + a ``SOCKET``. + + On backends where this functionality is not natively provided (asyncio + ``ProactorEventLoop`` on Windows), it is provided using a separate selector thread + which is set to shut down when the interpreter shuts down. + + .. warning:: Don't use this on raw sockets that have been wrapped by any higher + level constructs like socket streams! + + :param obj: an object with a ``.fileno()`` method or an integer handle + :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the + object to become readable + :raises ~anyio.BusyResourceError: if another task is already waiting for the object + to become readable + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().wait_readable(obj) + + +def wait_writable(obj: FileDescriptorLike) -> Awaitable[None]: + """ + Wait until the given object can be written to. + + :param obj: an object with a ``.fileno()`` method or an integer handle + :raises ~anyio.ClosedResourceError: if the object was closed while waiting for the + object to become writable + :raises ~anyio.BusyResourceError: if another task is already waiting for the object + to become writable + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. seealso:: See the documentation of :func:`wait_readable` for the definition of + ``obj`` and notes on backend compatibility. + + .. warning:: Don't use this on raw sockets that have been wrapped by any higher + level constructs like socket streams! + + """ + return get_async_backend().wait_writable(obj) + + +def notify_closing(obj: FileDescriptorLike) -> None: + """ + Call this before closing a file descriptor (on Unix) or socket (on + Windows). This will cause any `wait_readable` or `wait_writable` + calls on the given object to immediately wake up and raise + `~anyio.ClosedResourceError`. + + This doesn't actually close the object – you still have to do that + yourself afterwards. Also, you want to be careful to make sure no + new tasks start waiting on the object in between when you call this + and when it's actually closed. So to close something properly, you + usually want to do these steps in order: + + 1. Explicitly mark the object as closed, so that any new attempts + to use it will abort before they start. + 2. Call `notify_closing` to wake up any already-existing users. + 3. Actually close the object. + + It's also possible to do them in a different order if that's more + convenient, *but only if* you make sure not to have any checkpoints in + between the steps. This way they all happen in a single atomic + step, so other tasks won't be able to tell what order they happened + in anyway. + + :param obj: an object with a ``.fileno()`` method or an integer handle + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + get_async_backend().notify_closing(obj) + + +# +# Private API +# + + +def convert_ipv6_sockaddr( + sockaddr: tuple[str, int, int, int] | tuple[str, int], +) -> tuple[str, int]: + """ + Convert a 4-tuple IPv6 socket address to a 2-tuple (address, port) format. + + If the scope ID is nonzero, it is added to the address, separated with ``%``. + Otherwise the flow id and scope id are simply cut off from the tuple. + Any other kinds of socket addresses are returned as-is. + + :param sockaddr: the result of :meth:`~socket.socket.getsockname` + :return: the converted socket address + + """ + # This is more complicated than it should be because of MyPy + if isinstance(sockaddr, tuple) and len(sockaddr) == 4: + host, port, _flowinfo, scope_id = sockaddr + if scope_id: + # PyPy (as of v7.3.11) leaves the interface name in the result, so + # we discard it and only get the scope ID from the end + # (https://foss.heptapod.net/pypy/pypy/-/issues/3938) + host = host.split("%")[0] + + # Add scope_id to the address + return f"{host}%{scope_id}", port + else: + return host, port + else: + return sockaddr + + +async def setup_unix_local_socket( + path: None | str | bytes | PathLike[Any], + mode: int | None, + socktype: int, +) -> socket.socket: + """ + Create a UNIX local socket object, deleting the socket at the given path if it + exists. + + Not available on Windows. + + :param path: path of the socket + :param mode: permissions to set on the socket + :param socktype: socket.SOCK_STREAM or socket.SOCK_DGRAM + + """ + path_str: str | None + if path is not None: + path_str = os.fsdecode(path) + + # Linux abstract namespace sockets aren't backed by a concrete file so skip stat call + if not path_str.startswith("\0"): + # Copied from pathlib... + try: + stat_result = os.stat(path) + except OSError as e: + if e.errno not in ( + errno.ENOENT, + errno.ENOTDIR, + errno.EBADF, + errno.ELOOP, + ): + raise + else: + if stat.S_ISSOCK(stat_result.st_mode): + os.unlink(path) + else: + path_str = None + + raw_socket = socket.socket(socket.AF_UNIX, socktype) + raw_socket.setblocking(False) + + if path_str is not None: + try: + await to_thread.run_sync(raw_socket.bind, path_str, abandon_on_cancel=True) + if mode is not None: + await to_thread.run_sync(chmod, path_str, mode, abandon_on_cancel=True) + except BaseException: + raw_socket.close() + raise + + return raw_socket + + +@dataclass +class TCPConnectable(ByteStreamConnectable): + """ + Connects to a TCP server at the given host and port. + + :param host: host name or IP address of the server + :param port: TCP port number of the server + """ + + host: str | IPv4Address | IPv6Address + port: int + + def __post_init__(self) -> None: + if self.port < 1 or self.port > 65535: + raise ValueError("TCP port number out of range") + + @override + async def connect(self) -> SocketStream: + try: + return await connect_tcp(self.host, self.port) + except OSError as exc: + raise ConnectionFailed( + f"error connecting to {self.host}:{self.port}: {exc}" + ) from exc + + +@dataclass +class UNIXConnectable(ByteStreamConnectable): + """ + Connects to a UNIX domain socket at the given path. + + :param path: the file system path of the socket + """ + + path: str | bytes | PathLike[str] | PathLike[bytes] + + @override + async def connect(self) -> UNIXSocketStream: + try: + return await connect_unix(self.path) + except OSError as exc: + raise ConnectionFailed(f"error connecting to {self.path!r}: {exc}") from exc + + +def as_connectable( + remote: ByteStreamConnectable + | tuple[str | IPv4Address | IPv6Address, int] + | str + | bytes + | PathLike[str], + /, + *, + tls: bool = False, + ssl_context: ssl.SSLContext | None = None, + tls_hostname: str | None = None, + tls_standard_compatible: bool = True, +) -> ByteStreamConnectable: + """ + Return a byte stream connectable from the given object. + + If a bytestream connectable is given, it is returned unchanged. + If a tuple of (host, port) is given, a TCP connectable is returned. + If a string or bytes path is given, a UNIX connectable is returned. + + If ``tls=True``, the connectable will be wrapped in a + :class:`~.streams.tls.TLSConnectable`. + + :param remote: a connectable, a tuple of (host, port) or a path to a UNIX socket + :param tls: if ``True``, wrap the plaintext connectable in a + :class:`~.streams.tls.TLSConnectable`, using the provided TLS settings) + :param ssl_context: if ``tls=True``, the SSLContext object to use (if not provided, + a secure default will be created) + :param tls_hostname: if ``tls=True``, host name of the server to use for checking + the server certificate (defaults to the host portion of the address for TCP + connectables) + :param tls_standard_compatible: if ``False`` and ``tls=True``, makes the TLS stream + skip the closing handshake when closing the connection, so it won't raise an + exception if the server does the same + + """ + connectable: TCPConnectable | UNIXConnectable | TLSConnectable + if isinstance(remote, ByteStreamConnectable): + return remote + elif isinstance(remote, tuple) and len(remote) == 2: + connectable = TCPConnectable(*remote) + elif isinstance(remote, (str, bytes, PathLike)): + connectable = UNIXConnectable(remote) + else: + raise TypeError(f"cannot convert {remote!r} to a connectable") + + if tls: + if not tls_hostname and isinstance(connectable, TCPConnectable): + tls_hostname = str(connectable.host) + + connectable = TLSConnectable( + connectable, + ssl_context=ssl_context, + hostname=tls_hostname, + standard_compatible=tls_standard_compatible, + ) + + return connectable diff --git a/source/target-vendors/cp312/anyio/_core/_streams.py b/source/target-vendors/cp312/anyio/_core/_streams.py new file mode 100644 index 0000000..2b9c7df --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_streams.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +import math +from typing import TypeVar +from warnings import warn + +from ..streams.memory import ( + MemoryObjectReceiveStream, + MemoryObjectSendStream, + _MemoryObjectStreamState, +) + +T_Item = TypeVar("T_Item") + + +class create_memory_object_stream( + tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]], +): + """ + Create a memory object stream. + + The stream's item type can be annotated like + :func:`create_memory_object_stream[T_Item]`. + + :param max_buffer_size: number of items held in the buffer until ``send()`` starts + blocking + :param item_type: old way of marking the streams with the right generic type for + static typing (does nothing on AnyIO 4) + + .. deprecated:: 4.0 + Use ``create_memory_object_stream[YourItemType](...)`` instead. + :return: a tuple of (send stream, receive stream) + + """ + + def __new__( # type: ignore[misc] + cls, max_buffer_size: float = 0, item_type: object = None + ) -> tuple[MemoryObjectSendStream[T_Item], MemoryObjectReceiveStream[T_Item]]: + if max_buffer_size != math.inf and not isinstance(max_buffer_size, int): + raise ValueError("max_buffer_size must be either an integer or math.inf") + if max_buffer_size < 0: + raise ValueError("max_buffer_size cannot be negative") + if item_type is not None: + warn( + "The item_type argument has been deprecated in AnyIO 4.0. " + "Use create_memory_object_stream[YourItemType](...) instead.", + DeprecationWarning, + stacklevel=2, + ) + + state = _MemoryObjectStreamState[T_Item](max_buffer_size) + return (MemoryObjectSendStream(state), MemoryObjectReceiveStream(state)) diff --git a/source/target-vendors/cp312/anyio/_core/_subprocesses.py b/source/target-vendors/cp312/anyio/_core/_subprocesses.py new file mode 100644 index 0000000..53184a2 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_subprocesses.py @@ -0,0 +1,196 @@ +from __future__ import annotations + +from collections.abc import AsyncIterable, Iterable, Mapping, Sequence +from io import BytesIO +from os import PathLike +from subprocess import PIPE, CalledProcessError, CompletedProcess +from typing import IO, Any, TypeAlias, cast + +from ..abc import Process # noqa: TC001 +from ._eventloop import get_async_backend +from ._tasks import create_task_group + +StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes] + + +async def run_process( + command: StrOrBytesPath | Sequence[StrOrBytesPath], + *, + input: bytes | None = None, + stdin: int | IO[Any] | None = None, + stdout: int | IO[Any] | None = PIPE, + stderr: int | IO[Any] | None = PIPE, + check: bool = True, + cwd: StrOrBytesPath | None = None, + env: Mapping[str, str] | None = None, + startupinfo: Any = None, + creationflags: int = 0, + start_new_session: bool = False, + pass_fds: Sequence[int] = (), + user: str | int | None = None, + group: str | int | None = None, + extra_groups: Iterable[str | int] | None = None, + umask: int = -1, +) -> CompletedProcess[bytes]: + """ + Run an external command in a subprocess and wait until it completes. + + .. seealso:: :func:`subprocess.run` + + :param command: either a string to pass to the shell, or an iterable of strings + containing the executable name or path and its arguments + :param input: bytes passed to the standard input of the subprocess + :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + a file-like object, or `None`; ``input`` overrides this + :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + a file-like object, or `None` + :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + :data:`subprocess.STDOUT`, a file-like object, or `None` + :param check: if ``True``, raise :exc:`~subprocess.CalledProcessError` if the + process terminates with a return code other than 0 + :param cwd: If not ``None``, change the working directory to this before running the + command + :param env: if not ``None``, this mapping replaces the inherited environment + variables from the parent process + :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used + to specify process startup parameters (Windows only) + :param creationflags: flags that can be used to control the creation of the + subprocess (see :class:`subprocess.Popen` for the specifics) + :param start_new_session: if ``true`` the setsid() system call will be made in the + child process prior to the execution of the subprocess. (POSIX only) + :param pass_fds: sequence of file descriptors to keep open between the parent and + child processes. (POSIX only) + :param user: effective user to run the process as (Python >= 3.9, POSIX only) + :param group: effective group to run the process as (Python >= 3.9, POSIX only) + :param extra_groups: supplementary groups to set in the subprocess (Python >= 3.9, + POSIX only) + :param umask: if not negative, this umask is applied in the child process before + running the given command (Python >= 3.9, POSIX only) + :return: an object representing the completed process + :raises ~subprocess.CalledProcessError: if ``check`` is ``True`` and the process + exits with a nonzero return code + + """ + + async def drain_stream(stream: AsyncIterable[bytes], index: int) -> None: + buffer = BytesIO() + async for chunk in stream: + buffer.write(chunk) + + stream_contents[index] = buffer.getvalue() + + if stdin is not None and input is not None: + raise ValueError("only one of stdin and input is allowed") + + async with await open_process( + command, + stdin=PIPE if input else stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + startupinfo=startupinfo, + creationflags=creationflags, + start_new_session=start_new_session, + pass_fds=pass_fds, + user=user, + group=group, + extra_groups=extra_groups, + umask=umask, + ) as process: + stream_contents: list[bytes | None] = [None, None] + async with create_task_group() as tg: + if process.stdout: + tg.start_soon(drain_stream, process.stdout, 0) + + if process.stderr: + tg.start_soon(drain_stream, process.stderr, 1) + + if process.stdin and input: + await process.stdin.send(input) + await process.stdin.aclose() + + await process.wait() + + output, errors = stream_contents + if check and process.returncode != 0: + raise CalledProcessError(cast(int, process.returncode), command, output, errors) + + return CompletedProcess(command, cast(int, process.returncode), output, errors) + + +async def open_process( + command: StrOrBytesPath | Sequence[StrOrBytesPath], + *, + stdin: int | IO[Any] | None = PIPE, + stdout: int | IO[Any] | None = PIPE, + stderr: int | IO[Any] | None = PIPE, + cwd: StrOrBytesPath | None = None, + env: Mapping[str, str] | None = None, + startupinfo: Any = None, + creationflags: int = 0, + start_new_session: bool = False, + pass_fds: Sequence[int] = (), + user: str | int | None = None, + group: str | int | None = None, + extra_groups: Iterable[str | int] | None = None, + umask: int = -1, +) -> Process: + """ + Start an external command in a subprocess. + + .. seealso:: :class:`subprocess.Popen` + + :param command: either a string to pass to the shell, or an iterable of strings + containing the executable name or path and its arguments + :param stdin: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, a + file-like object, or ``None`` + :param stdout: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + a file-like object, or ``None`` + :param stderr: one of :data:`subprocess.PIPE`, :data:`subprocess.DEVNULL`, + :data:`subprocess.STDOUT`, a file-like object, or ``None`` + :param cwd: If not ``None``, the working directory is changed before executing + :param env: If env is not ``None``, it must be a mapping that defines the + environment variables for the new process + :param creationflags: flags that can be used to control the creation of the + subprocess (see :class:`subprocess.Popen` for the specifics) + :param startupinfo: an instance of :class:`subprocess.STARTUPINFO` that can be used + to specify process startup parameters (Windows only) + :param start_new_session: if ``true`` the setsid() system call will be made in the + child process prior to the execution of the subprocess. (POSIX only) + :param pass_fds: sequence of file descriptors to keep open between the parent and + child processes. (POSIX only) + :param user: effective user to run the process as (POSIX only) + :param group: effective group to run the process as (POSIX only) + :param extra_groups: supplementary groups to set in the subprocess (POSIX only) + :param umask: if not negative, this umask is applied in the child process before + running the given command (POSIX only) + :return: an asynchronous process object + + """ + kwargs: dict[str, Any] = {} + if user is not None: + kwargs["user"] = user + + if group is not None: + kwargs["group"] = group + + if extra_groups is not None: + kwargs["extra_groups"] = extra_groups + + if umask >= 0: + kwargs["umask"] = umask + + return await get_async_backend().open_process( + command, + stdin=stdin, + stdout=stdout, + stderr=stderr, + cwd=cwd, + env=env, + startupinfo=startupinfo, + creationflags=creationflags, + start_new_session=start_new_session, + pass_fds=pass_fds, + **kwargs, + ) diff --git a/source/target-vendors/cp312/anyio/_core/_synchronization.py b/source/target-vendors/cp312/anyio/_core/_synchronization.py new file mode 100644 index 0000000..cb988c6 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_synchronization.py @@ -0,0 +1,778 @@ +from __future__ import annotations + +import math +import sys +from collections import deque +from collections.abc import Callable +from dataclasses import dataclass +from types import TracebackType +from typing import TypeVar + +from ..lowlevel import checkpoint_if_cancelled +from ._eventloop import get_async_backend +from ._exceptions import BusyResourceError, NoEventLoopError +from ._tasks import CancelScope +from ._testing import TaskInfo, get_current_task + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + +T = TypeVar("T") + + +@dataclass(frozen=True) +class EventStatistics: + """ + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Event.wait` + """ + + tasks_waiting: int + + +@dataclass(frozen=True) +class CapacityLimiterStatistics: + """ + :ivar int borrowed_tokens: number of tokens currently borrowed by tasks + :ivar float total_tokens: total number of available tokens + :ivar tuple borrowers: tasks or other objects currently holding tokens borrowed from + this limiter + :ivar int tasks_waiting: number of tasks waiting on + :meth:`~.CapacityLimiter.acquire` or + :meth:`~.CapacityLimiter.acquire_on_behalf_of` + """ + + borrowed_tokens: int + total_tokens: float + borrowers: tuple[object, ...] + tasks_waiting: int + + +@dataclass(frozen=True) +class LockStatistics: + """ + :ivar bool locked: flag indicating if this lock is locked or not + :ivar ~anyio.TaskInfo owner: task currently holding the lock (or ``None`` if the + lock is not held by any task) + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Lock.acquire` + """ + + locked: bool + owner: TaskInfo | None + tasks_waiting: int + + +@dataclass(frozen=True) +class ConditionStatistics: + """ + :ivar int tasks_waiting: number of tasks blocked on :meth:`~.Condition.wait` + :ivar ~anyio.LockStatistics lock_statistics: statistics of the underlying + :class:`~.Lock` + """ + + tasks_waiting: int + lock_statistics: LockStatistics + + +@dataclass(frozen=True) +class SemaphoreStatistics: + """ + :ivar int tasks_waiting: number of tasks waiting on :meth:`~.Semaphore.acquire` + + """ + + tasks_waiting: int + + +class Event: + __slots__ = ("__weakref__",) + + def __new__(cls) -> Event: + try: + return get_async_backend().create_event() + except NoEventLoopError: + return EventAdapter() + + def set(self) -> None: + """Set the flag, notifying all listeners.""" + raise NotImplementedError + + def is_set(self) -> bool: + """Return ``True`` if the flag is set, ``False`` if not.""" + raise NotImplementedError + + async def wait(self) -> None: + """ + Wait until the flag has been set. + + If the flag has already been set when this method is called, it returns + immediately. + + """ + raise NotImplementedError + + def statistics(self) -> EventStatistics: + """Return statistics about the current state of this event.""" + raise NotImplementedError + + +class EventAdapter(Event): + __slots__ = "_internal_event", "_is_set" + + def __new__(cls) -> Self: + return object.__new__(cls) + + def __init__(self) -> None: + self._internal_event: Event | None = None + self._is_set = False + + @property + def _event(self) -> Event: + if self._internal_event is None: + self._internal_event = get_async_backend().create_event() + if self._is_set: + self._internal_event.set() + + return self._internal_event + + def set(self) -> None: + if self._internal_event is None: + self._is_set = True + else: + self._event.set() + + def is_set(self) -> bool: + if self._internal_event is None: + return self._is_set + + return self._internal_event.is_set() + + async def wait(self) -> None: + await self._event.wait() + + def statistics(self) -> EventStatistics: + if self._internal_event is None: + return EventStatistics(tasks_waiting=0) + + return self._internal_event.statistics() + + +class Lock: + __slots__ = ("__weakref__",) + + def __new__(cls, *, fast_acquire: bool = False) -> Lock: + try: + return get_async_backend().create_lock(fast_acquire=fast_acquire) + except NoEventLoopError: + return LockAdapter(fast_acquire=fast_acquire) + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.release() + + async def acquire(self) -> None: + """Acquire the lock.""" + raise NotImplementedError + + def acquire_nowait(self) -> None: + """ + Acquire the lock, without blocking. + + :raises ~anyio.WouldBlock: if the operation would block + + """ + raise NotImplementedError + + def release(self) -> None: + """Release the lock.""" + raise NotImplementedError + + def locked(self) -> bool: + """Return True if the lock is currently held.""" + raise NotImplementedError + + def statistics(self) -> LockStatistics: + """ + Return statistics about the current state of this lock. + + .. versionadded:: 3.0 + """ + raise NotImplementedError + + +class LockAdapter(Lock): + __slots__ = "_fast_acquire", "_internal_lock" + + def __new__(cls, *, fast_acquire: bool = False) -> Self: + return object.__new__(cls) + + def __init__(self, *, fast_acquire: bool = False): + self._internal_lock: Lock | None = None + self._fast_acquire = fast_acquire + + @property + def _lock(self) -> Lock: + if self._internal_lock is None: + self._internal_lock = get_async_backend().create_lock( + fast_acquire=self._fast_acquire + ) + + return self._internal_lock + + async def __aenter__(self) -> None: + await self._lock.acquire() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + if self._internal_lock is not None: + self._internal_lock.release() + + async def acquire(self) -> None: + """Acquire the lock.""" + await self._lock.acquire() + + def acquire_nowait(self) -> None: + """ + Acquire the lock, without blocking. + + :raises ~anyio.WouldBlock: if the operation would block + + """ + self._lock.acquire_nowait() + + def release(self) -> None: + """Release the lock.""" + self._lock.release() + + def locked(self) -> bool: + """Return True if the lock is currently held.""" + return self._lock.locked() + + def statistics(self) -> LockStatistics: + """ + Return statistics about the current state of this lock. + + .. versionadded:: 3.0 + + """ + if self._internal_lock is None: + return LockStatistics(False, None, 0) + + return self._internal_lock.statistics() + + +class Condition: + __slots__ = "__weakref__", "_lock", "_owner_task", "_waiters" + + def __init__(self, lock: Lock | None = None): + self._owner_task: TaskInfo | None = None + self._lock = lock or Lock() + self._waiters: deque[Event] = deque() + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.release() + + def _check_acquired(self) -> None: + if self._owner_task != get_current_task(): + raise RuntimeError("The current task is not holding the underlying lock") + + async def acquire(self) -> None: + """Acquire the underlying lock.""" + await self._lock.acquire() + self._owner_task = get_current_task() + + def acquire_nowait(self) -> None: + """ + Acquire the underlying lock, without blocking. + + :raises ~anyio.WouldBlock: if the operation would block + + """ + self._lock.acquire_nowait() + self._owner_task = get_current_task() + + def release(self) -> None: + """Release the underlying lock.""" + self._lock.release() + + def locked(self) -> bool: + """Return True if the lock is set.""" + return self._lock.locked() + + def notify(self, n: int = 1) -> None: + """Notify exactly n listeners.""" + self._check_acquired() + for _ in range(n): + try: + event = self._waiters.popleft() + except IndexError: + break + + event.set() + + def notify_all(self) -> None: + """Notify all the listeners.""" + self._check_acquired() + for event in self._waiters: + event.set() + + self._waiters.clear() + + async def wait(self) -> None: + """Wait for a notification.""" + await checkpoint_if_cancelled() + self._check_acquired() + event = Event() + self._waiters.append(event) + self.release() + try: + await event.wait() + except BaseException: + if not event.is_set(): + self._waiters.remove(event) + elif self._waiters: + # This task was notified by could not act on it, so pass + # it on to the next task + self._waiters.popleft().set() + + raise + finally: + with CancelScope(shield=True): + await self.acquire() + + async def wait_for(self, predicate: Callable[[], T]) -> T: + """ + Wait until a predicate becomes true. + + :param predicate: a callable that returns a truthy value when the condition is + met + :return: the result of the predicate + + .. versionadded:: 4.11.0 + + """ + while not (result := predicate()): + await self.wait() + + return result + + def statistics(self) -> ConditionStatistics: + """ + Return statistics about the current state of this condition. + + .. versionadded:: 3.0 + """ + return ConditionStatistics(len(self._waiters), self._lock.statistics()) + + +class Semaphore: + __slots__ = "__weakref__", "_fast_acquire" + + def __new__( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> Semaphore: + try: + return get_async_backend().create_semaphore( + initial_value, max_value=max_value, fast_acquire=fast_acquire + ) + except NoEventLoopError: + return SemaphoreAdapter(initial_value, max_value=max_value) + + def __init__( + self, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ): + if not isinstance(initial_value, int): + raise TypeError("initial_value must be an integer") + if initial_value < 0: + raise ValueError("initial_value must be >= 0") + if max_value is not None: + if not isinstance(max_value, int): + raise TypeError("max_value must be an integer or None") + if max_value < initial_value: + raise ValueError( + "max_value must be equal to or higher than initial_value" + ) + + self._fast_acquire = fast_acquire + + async def __aenter__(self) -> Self: + await self.acquire() + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.release() + + async def acquire(self) -> None: + """Decrement the semaphore value, blocking if necessary.""" + raise NotImplementedError + + def acquire_nowait(self) -> None: + """ + Acquire the underlying lock, without blocking. + + :raises ~anyio.WouldBlock: if the operation would block + + """ + raise NotImplementedError + + def release(self) -> None: + """Increment the semaphore value.""" + raise NotImplementedError + + @property + def value(self) -> int: + """The current value of the semaphore.""" + raise NotImplementedError + + @property + def max_value(self) -> int | None: + """The maximum value of the semaphore.""" + raise NotImplementedError + + def statistics(self) -> SemaphoreStatistics: + """ + Return statistics about the current state of this semaphore. + + .. versionadded:: 3.0 + """ + raise NotImplementedError + + +class SemaphoreAdapter(Semaphore): + __slots__ = "_initial_value", "_internal_semaphore", "_max_value" + + def __new__( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> Self: + return object.__new__(cls) + + def __init__( + self, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> None: + super().__init__(initial_value, max_value=max_value, fast_acquire=fast_acquire) + self._internal_semaphore: Semaphore | None = None + self._initial_value = initial_value + self._max_value = max_value + + @property + def _semaphore(self) -> Semaphore: + if self._internal_semaphore is None: + self._internal_semaphore = get_async_backend().create_semaphore( + self._initial_value, max_value=self._max_value + ) + + return self._internal_semaphore + + async def acquire(self) -> None: + await self._semaphore.acquire() + + def acquire_nowait(self) -> None: + self._semaphore.acquire_nowait() + + def release(self) -> None: + self._semaphore.release() + + @property + def value(self) -> int: + if self._internal_semaphore is None: + return self._initial_value + + return self._semaphore.value + + @property + def max_value(self) -> int | None: + return self._max_value + + def statistics(self) -> SemaphoreStatistics: + if self._internal_semaphore is None: + return SemaphoreStatistics(tasks_waiting=0) + + return self._semaphore.statistics() + + +class CapacityLimiter: + __slots__ = ("__weakref__",) + + def __new__(cls, total_tokens: float) -> CapacityLimiter: + try: + return get_async_backend().create_capacity_limiter(total_tokens) + except NoEventLoopError: + return CapacityLimiterAdapter(total_tokens) + + async def __aenter__(self) -> None: + raise NotImplementedError + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + raise NotImplementedError + + @property + def total_tokens(self) -> float: + """ + The total number of tokens available for borrowing. + + This is a read-write property. If the total number of tokens is increased, the + proportionate number of tasks waiting on this limiter will be granted their + tokens. + + .. versionchanged:: 3.0 + The property is now writable. + .. versionchanged:: 4.12 + The value can now be set to 0. + + """ + raise NotImplementedError + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + raise NotImplementedError + + @property + def borrowed_tokens(self) -> int: + """The number of tokens that have currently been borrowed.""" + raise NotImplementedError + + @property + def available_tokens(self) -> float: + """The number of tokens currently available to be borrowed""" + raise NotImplementedError + + def acquire_nowait(self) -> None: + """ + Acquire a token for the current task without waiting for one to become + available. + + :raises ~anyio.WouldBlock: if there are no tokens available for borrowing + + """ + raise NotImplementedError + + def acquire_on_behalf_of_nowait(self, borrower: object) -> None: + """ + Acquire a token without waiting for one to become available. + + :param borrower: the entity borrowing a token + :raises ~anyio.WouldBlock: if there are no tokens available for borrowing + + """ + raise NotImplementedError + + async def acquire(self) -> None: + """ + Acquire a token for the current task, waiting if necessary for one to become + available. + + """ + raise NotImplementedError + + async def acquire_on_behalf_of(self, borrower: object) -> None: + """ + Acquire a token, waiting if necessary for one to become available. + + :param borrower: the entity borrowing a token + + """ + raise NotImplementedError + + def release(self) -> None: + """ + Release the token held by the current task. + + :raises RuntimeError: if the current task has not borrowed a token from this + limiter. + + """ + raise NotImplementedError + + def release_on_behalf_of(self, borrower: object) -> None: + """ + Release the token held by the given borrower. + + :raises RuntimeError: if the borrower has not borrowed a token from this + limiter. + + """ + raise NotImplementedError + + def statistics(self) -> CapacityLimiterStatistics: + """ + Return statistics about the current state of this limiter. + + .. versionadded:: 3.0 + + """ + raise NotImplementedError + + +class CapacityLimiterAdapter(CapacityLimiter): + __slots__ = "_internal_limiter", "_total_tokens" + + def __new__(cls, total_tokens: float) -> Self: + return object.__new__(cls) + + def __init__(self, total_tokens: float) -> None: + self._internal_limiter: CapacityLimiter | None = None + self.total_tokens = total_tokens + + @property + def _limiter(self) -> CapacityLimiter: + if self._internal_limiter is None: + self._internal_limiter = get_async_backend().create_capacity_limiter( + self._total_tokens + ) + + return self._internal_limiter + + async def __aenter__(self) -> None: + await self._limiter.__aenter__() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + return await self._limiter.__aexit__(exc_type, exc_val, exc_tb) + + @property + def total_tokens(self) -> float: + if self._internal_limiter is None: + return self._total_tokens + + return self._internal_limiter.total_tokens + + @total_tokens.setter + def total_tokens(self, value: float) -> None: + if not isinstance(value, int) and not math.isinf(value): + raise TypeError("total_tokens must be an int or math.inf") + elif value < 0: + raise ValueError("total_tokens must be >= 0") + + if self._internal_limiter is None: + self._total_tokens = value + return + + self._limiter.total_tokens = value + + @property + def borrowed_tokens(self) -> int: + if self._internal_limiter is None: + return 0 + + return self._internal_limiter.borrowed_tokens + + @property + def available_tokens(self) -> float: + if self._internal_limiter is None: + return self._total_tokens + + return self._internal_limiter.available_tokens + + def acquire_nowait(self) -> None: + self._limiter.acquire_nowait() + + def acquire_on_behalf_of_nowait(self, borrower: object) -> None: + self._limiter.acquire_on_behalf_of_nowait(borrower) + + async def acquire(self) -> None: + await self._limiter.acquire() + + async def acquire_on_behalf_of(self, borrower: object) -> None: + await self._limiter.acquire_on_behalf_of(borrower) + + def release(self) -> None: + self._limiter.release() + + def release_on_behalf_of(self, borrower: object) -> None: + self._limiter.release_on_behalf_of(borrower) + + def statistics(self) -> CapacityLimiterStatistics: + if self._internal_limiter is None: + return CapacityLimiterStatistics( + borrowed_tokens=0, + total_tokens=self.total_tokens, + borrowers=(), + tasks_waiting=0, + ) + + return self._internal_limiter.statistics() + + +class ResourceGuard: + """ + A context manager for ensuring that a resource is only used by a single task at a + time. + + Entering this context manager while the previous has not exited it yet will trigger + :exc:`BusyResourceError`. + + :param action: the action to guard against (visible in the :exc:`BusyResourceError` + when triggered, e.g. "Another task is already {action} this resource") + + .. versionadded:: 4.1 + """ + + __slots__ = "__weakref__", "_guarded", "action" + + def __init__(self, action: str = "using"): + self.action: str = action + self._guarded = False + + def __enter__(self) -> None: + if self._guarded: + raise BusyResourceError(self.action) + + self._guarded = True + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self._guarded = False diff --git a/source/target-vendors/cp312/anyio/_core/_tasks.py b/source/target-vendors/cp312/anyio/_core/_tasks.py new file mode 100644 index 0000000..044eda6 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_tasks.py @@ -0,0 +1,464 @@ +from __future__ import annotations + +import math +import sys +from collections.abc import ( + Coroutine, + Generator, +) +from contextlib import contextmanager +from enum import Enum, auto +from inspect import iscoroutine +from types import TracebackType +from typing import Any, Generic, final + +from ..abc import TaskGroup, TaskStatus +from ._eventloop import get_async_backend, get_cancelled_exc_class +from ._exceptions import TaskCancelled, TaskFailed, TaskNotFinished + +if sys.version_info >= (3, 13): + from typing import TypeVar +else: + from typing_extensions import TypeVar + +if sys.version_info >= (3, 11): + from typing import Never, Self, TypeVarTuple +else: + from typing_extensions import Never, Self, TypeVarTuple + +T = TypeVar("T") +T_co = TypeVar("T_co", covariant=True) +T_startval_co = TypeVar("T_startval_co", covariant=True, default=Never) +PosArgsT = TypeVarTuple("PosArgsT") + + +class _IgnoredTaskStatus(TaskStatus[object]): + def started(self, value: object = None) -> None: + pass + + +TASK_STATUS_IGNORED = _IgnoredTaskStatus() + + +class CancelScope: + """ + Wraps a unit of work that can be made separately cancellable. + + :param deadline: The time (clock value) when this scope is cancelled automatically + :param shield: ``True`` to shield the cancel scope from external cancellation + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + """ + + __slots__ = ("__weakref__",) + + def __new__( + cls, *, deadline: float = math.inf, shield: bool = False + ) -> CancelScope: + return get_async_backend().create_cancel_scope(shield=shield, deadline=deadline) + + def cancel(self, reason: str | None = None) -> None: + """ + Cancel this scope immediately. + + :param reason: a message describing the reason for the cancellation + + """ + raise NotImplementedError + + @property + def deadline(self) -> float: + """ + The time (clock value) when this scope is cancelled automatically. + + Will be ``float('inf')`` if no timeout has been set. + + """ + raise NotImplementedError + + @deadline.setter + def deadline(self, value: float) -> None: + raise NotImplementedError + + @property + def cancel_called(self) -> bool: + """``True`` if :meth:`cancel` has been called.""" + raise NotImplementedError + + @property + def cancelled_caught(self) -> bool: + """ + ``True`` if this scope suppressed a cancellation exception it itself raised. + + This is typically used to check if any work was interrupted, or to see if the + scope was cancelled due to its deadline being reached. The value will, however, + only be ``True`` if the cancellation was triggered by the scope itself (and not + an outer scope). + + """ + raise NotImplementedError + + @property + def shield(self) -> bool: + """ + ``True`` if this scope is shielded from external cancellation. + + While a scope is shielded, it will not receive cancellations from outside. + + """ + raise NotImplementedError + + @shield.setter + def shield(self, value: bool) -> None: + raise NotImplementedError + + def __enter__(self) -> Self: + raise NotImplementedError + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + raise NotImplementedError + + +@contextmanager +def fail_at( + deadline: float | None, shield: bool = False, reason: str | None = None +) -> Generator[CancelScope, None, None]: + """ + Create a context manager which raises a :class:`TimeoutError` if the code in the + enclosing context does not finish by the given deadline. + + :param deadline: the deadline before raising the exception, or + ``None`` to disable the timeout + :param shield: ``True`` to shield the cancel scope from external cancellation + :param reason: explanation for timeout to add to the message of a raised `TimeoutError` + :return: a context manager that yields a cancel scope + :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\] + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. versionadded:: 4.15.0 + + """ + current_time = get_async_backend().current_time + effective_deadline = math.inf if deadline is None else deadline + with get_async_backend().create_cancel_scope( + deadline=effective_deadline, shield=shield + ) as cancel_scope: + yield cancel_scope + + if cancel_scope.cancelled_caught and current_time() >= cancel_scope.deadline: + raise TimeoutError(reason) if reason else TimeoutError + + +@contextmanager +def fail_after( + delay: float | None, shield: bool = False, reason: str | None = None +) -> Generator[CancelScope, None, None]: + """ + Create a context manager which raises a :class:`TimeoutError` if the code in the + enclosing context block does not finish in time. + + :param delay: maximum allowed time (in seconds) before raising the exception, or + ``None`` to disable the timeout + :param shield: ``True`` to shield the cancel scope from external cancellation + :param reason: explanation for timeout to add to the message of a raised `TimeoutError` + :return: a context manager that yields a cancel scope + :rtype: :class:`~typing.ContextManager`\\[:class:`~anyio.CancelScope`\\] + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + current_time = get_async_backend().current_time + deadline = (current_time() + delay) if delay is not None else math.inf + with fail_at(deadline, shield=shield, reason=reason) as scope: + yield scope + + +def move_on_at(deadline: float | None, shield: bool = False) -> CancelScope: + """ + Create a cancel scope with a deadline that expires after the given delay. + + :param deadline: the deadline before exiting the context block, or + ``None`` to disable the timeout + :param shield: ``True`` to shield the cancel scope from external cancellation + :return: a cancel scope + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. versionadded:: 4.15.0 + + """ + return get_async_backend().create_cancel_scope( + deadline=deadline if deadline is not None else math.inf, shield=shield + ) + + +def move_on_after(delay: float | None, shield: bool = False) -> CancelScope: + """ + Create a cancel scope with a deadline that expires after the given delay. + + :param delay: maximum allowed time (in seconds) before exiting the context block, or + ``None`` to disable the timeout + :param shield: ``True`` to shield the cancel scope from external cancellation + :return: a cancel scope + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. note:: Unlike with :func:`fail_after`, the timer starts when this function is + called, not when the context manager is entered. This will be changed in v5.0. + + """ + deadline = ( + (get_async_backend().current_time() + delay) if delay is not None else math.inf + ) + return get_async_backend().create_cancel_scope(deadline=deadline, shield=shield) + + +def current_effective_deadline() -> float: + """ + Return the nearest deadline among all the cancel scopes effective for the current + task. + + :return: a clock value from the event loop's internal clock (or ``float('inf')`` if + there is no deadline in effect, or ``float('-inf')`` if the current scope has + been cancelled) + :rtype: float + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().current_effective_deadline() + + +def create_task_group() -> TaskGroup: + """ + Create a task group. + + :return: a task group + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().create_task_group() + + +@final +class TaskHandle(Generic[T_co, T_startval_co]): + """ + Returned from the task-spawning methods of :class:`TaskGroup`. Can be awaited on to + get the return value of the task (or the raised exception). If the task was + terminated by a :exc:`BaseException`, :exc:`TaskFailed` will be raised (or its + subclass :exc:`TaskCancelled` if the task was cancelled). + + .. versionadded:: 4.14.0 + """ + + class Status(Enum): + """ + The status of a task handle. + + .. attribute:: PENDING + + The task has not finished yet. + .. attribute:: FINISHED + + The task has finished with a return value. + .. attribute:: CANCELLING + + The task has been cancelled but has not finished yet. + .. attribute:: CANCELLED + + The task was cancelled and has finished since. + .. attribute:: FAILED + + The task raised an exception. + """ + + PENDING = auto() + FINISHED = auto() + CANCELLING = auto() + CANCELLED = auto() + FAILED = auto() + + __slots__ = ( + "__weakref__", + "_cancel_scope", + "_coro", + "_exception", + "_finished_event", + "_name", + "_return_value", + "_start_value", + ) + + _return_value: T_co + _start_value: T_startval_co + + def __init__( + self, + coro: Coroutine[Any, Any, T_co], + name: object, + cancel_scope: CancelScope | None = None, + ) -> None: + from ._synchronization import Event + + self._coro = coro + self._cancel_scope = cancel_scope if cancel_scope is not None else CancelScope() + self._finished_event = Event() + self._exception: BaseException | None = None + + if name is not None: + self._name = str(name) + elif iscoroutine(coro): + self._name = coro.__qualname__ + else: + self._name = str(coro) # coroutine-like object (e.g. asend() objects) + + async def _run_coro(self) -> None: + __tracebackhide__ = True + + with self._cancel_scope: + try: + retval = await self._coro + except BaseException as exc: + self._exception = exc + raise + else: + self._return_value = retval + finally: + self._finished_event.set() + del self # Break the reference cycle + + def cancel(self) -> None: + """ + Set the task to a cancelled state. + + This will interrupt any interruptible asynchronous operation, and will cause + any further awaits on this task to get immediately cancelled, unless done in + a shielded cancel scope. + + If the task has already finished, this method has no effect. + """ + if not self._finished_event.is_set(): + self._cancel_scope.cancel() + + @property + def coro(self) -> Coroutine[Any, Any, T_co]: + """ + The coroutine object that was passed to one of the task-spawning methods in + :class:`TaskGroup`. + """ + return self._coro + + @property + def status(self) -> TaskHandle.Status: + """ + The current status of the task. + + Every task starts in the :attr:`~TaskHandle.Status.PENDING` state. + If a task is cancelled while in this state, it will transition to the + :attr:`~TaskHandle.Status.CANCELLING` state. When the task finishes, it will + transition to one of the three final states ( + :attr:`~TaskHandle.Status.FINISHED`, :attr:`~TaskHandle.Status.FAILED`, or + :attr:`~TaskHandle.Status.CANCELLING`) depending on the exception the task + raised, if any. No other status transitions will happen. + """ + if not self._finished_event.is_set(): + if self._cancel_scope.cancel_called: + return TaskHandle.Status.CANCELLING + else: + return TaskHandle.Status.PENDING + elif self._exception is not None: + if isinstance(self._exception, get_cancelled_exc_class()): + return TaskHandle.Status.CANCELLED + else: + return TaskHandle.Status.FAILED + else: + return TaskHandle.Status.FINISHED + + @property + def name(self) -> str: + """The name of the task.""" + return self._name + + @property + def exception(self) -> BaseException | None: + """ + The exception raised by the task, or ``None`` if it finished without raising. + + :raises TaskNotFinished: if the task has not finished yet + :raises TaskCancelled: if the task was cancelled + + """ + match self.status: + case TaskHandle.Status.PENDING: + raise TaskNotFinished("the task has not finished yet") + case TaskHandle.Status.FINISHED: + return None + case TaskHandle.Status.CANCELLING: + raise TaskCancelled("the task was cancelled") + case TaskHandle.Status.CANCELLED: + raise TaskCancelled("the task was cancelled") from self._exception + case TaskHandle.Status.FAILED: + return self._exception + + @property + def return_value(self) -> T_co: + """ + The return value of the task. + + :raises TaskNotFinished: if the task has not finished yet + :raises TaskCancelled: if the task was cancelled + :raises TaskFailed: if the task raised an exception + + """ + match self.status: + case TaskHandle.Status.PENDING: + raise TaskNotFinished("the task has not finished yet") + case TaskHandle.Status.FINISHED: + return self._return_value + case TaskHandle.Status.CANCELLING: + raise TaskCancelled("the task was cancelled") + case TaskHandle.Status.CANCELLED: + raise TaskCancelled("the task was cancelled") from self._exception + case TaskHandle.Status.FAILED: + raise TaskFailed("the task raised an exception") from self._exception + + @property + def start_value(self) -> T_startval_co: + """ + The value passed to :meth:`task_status.started() <.abc.TaskStatus.started>`, + + :raises RuntimeError: if the task was not started with :meth:`TaskGroup.start() + <.abc.TaskGroup.start>` + """ + try: + return self._start_value + except AttributeError: + raise RuntimeError( + "the task was not started with TaskGroup.start()" + ) from None + + async def wait(self) -> None: + """ + Wait for the task to finish. + + This method will return as soon as the task has finished, no matter how it + happened. + """ + await self._finished_event.wait() + + def __await__(self) -> Generator[Any, Any, T_co]: + yield from self._finished_event.wait().__await__() + return self.return_value + + def __repr__(self) -> str: + return ( + f"<{self.__class__.__name__} {self.status.name.lower()} " + f"name={self._name!r} coro={self._coro!r}>" + ) diff --git a/source/target-vendors/cp312/anyio/_core/_tempfile.py b/source/target-vendors/cp312/anyio/_core/_tempfile.py new file mode 100644 index 0000000..9603086 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_tempfile.py @@ -0,0 +1,615 @@ +from __future__ import annotations + +import os +import sys +import tempfile +from collections.abc import Iterable +from io import BytesIO, TextIOWrapper +from types import TracebackType +from typing import ( + TYPE_CHECKING, + Any, + AnyStr, + Generic, + overload, +) + +from .. import to_thread +from .._core._fileio import AsyncFile +from ..lowlevel import checkpoint_if_cancelled +from ._tasks import CancelScope + +if TYPE_CHECKING: + from _typeshed import OpenBinaryMode, OpenTextMode, ReadableBuffer, WriteableBuffer + + +class TemporaryFile(Generic[AnyStr]): + """ + An asynchronous temporary file that is automatically created and cleaned up. + + This class provides an asynchronous context manager interface to a temporary file. + The file is created using Python's standard `tempfile.TemporaryFile` function in a + background thread, and is wrapped as an asynchronous file using `AsyncFile`. + + :param mode: The mode in which the file is opened. Defaults to "w+b". + :param buffering: The buffering policy (-1 means the default buffering). + :param encoding: The encoding used to decode or encode the file. Only applicable in + text mode. + :param newline: Controls how universal newlines mode works (only applicable in text + mode). + :param suffix: The suffix for the temporary file name. + :param prefix: The prefix for the temporary file name. + :param dir: The directory in which the temporary file is created. + :param errors: The error handling scheme used for encoding/decoding errors. + """ + + _async_file: AsyncFile[AnyStr] + + @overload + def __init__( + self: TemporaryFile[bytes], + mode: OpenBinaryMode = ..., + buffering: int = ..., + encoding: str | None = ..., + newline: str | None = ..., + suffix: str | None = ..., + prefix: str | None = ..., + dir: str | None = ..., + *, + errors: str | None = ..., + ): ... + @overload + def __init__( + self: TemporaryFile[str], + mode: OpenTextMode, + buffering: int = ..., + encoding: str | None = ..., + newline: str | None = ..., + suffix: str | None = ..., + prefix: str | None = ..., + dir: str | None = ..., + *, + errors: str | None = ..., + ): ... + + def __init__( + self, + mode: OpenTextMode | OpenBinaryMode = "w+b", + buffering: int = -1, + encoding: str | None = None, + newline: str | None = None, + suffix: str | None = None, + prefix: str | None = None, + dir: str | None = None, + *, + errors: str | None = None, + ) -> None: + self.mode = mode + self.buffering = buffering + self.encoding = encoding + self.newline = newline + self.suffix: str | None = suffix + self.prefix: str | None = prefix + self.dir: str | None = dir + self.errors = errors + + async def __aenter__(self) -> AsyncFile[AnyStr]: + fp = await to_thread.run_sync( + lambda: tempfile.TemporaryFile( + self.mode, + self.buffering, + self.encoding, + self.newline, + self.suffix, + self.prefix, + self.dir, + errors=self.errors, + ) + ) + self._async_file = AsyncFile(fp) + return self._async_file + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: + await self._async_file.aclose() + + +class NamedTemporaryFile(Generic[AnyStr]): + """ + An asynchronous named temporary file that is automatically created and cleaned up. + + This class provides an asynchronous context manager for a temporary file with a + visible name in the file system. It uses Python's standard + :func:`~tempfile.NamedTemporaryFile` function and wraps the file object with + :class:`AsyncFile` for asynchronous operations. + + :param mode: The mode in which the file is opened. Defaults to "w+b". + :param buffering: The buffering policy (-1 means the default buffering). + :param encoding: The encoding used to decode or encode the file. Only applicable in + text mode. + :param newline: Controls how universal newlines mode works (only applicable in text + mode). + :param suffix: The suffix for the temporary file name. + :param prefix: The prefix for the temporary file name. + :param dir: The directory in which the temporary file is created. + :param delete: Whether to delete the file when it is closed. + :param errors: The error handling scheme used for encoding/decoding errors. + :param delete_on_close: (Python 3.12+) Whether to delete the file on close. + """ + + _async_file: AsyncFile[AnyStr] + + @overload + def __init__( + self: NamedTemporaryFile[bytes], + mode: OpenBinaryMode = ..., + buffering: int = ..., + encoding: str | None = ..., + newline: str | None = ..., + suffix: str | None = ..., + prefix: str | None = ..., + dir: str | None = ..., + delete: bool = ..., + *, + errors: str | None = ..., + delete_on_close: bool = ..., + ): ... + @overload + def __init__( + self: NamedTemporaryFile[str], + mode: OpenTextMode, + buffering: int = ..., + encoding: str | None = ..., + newline: str | None = ..., + suffix: str | None = ..., + prefix: str | None = ..., + dir: str | None = ..., + delete: bool = ..., + *, + errors: str | None = ..., + delete_on_close: bool = ..., + ): ... + + def __init__( + self, + mode: OpenBinaryMode | OpenTextMode = "w+b", + buffering: int = -1, + encoding: str | None = None, + newline: str | None = None, + suffix: str | None = None, + prefix: str | None = None, + dir: str | None = None, + delete: bool = True, + *, + errors: str | None = None, + delete_on_close: bool = True, + ) -> None: + self._params: dict[str, Any] = { + "mode": mode, + "buffering": buffering, + "encoding": encoding, + "newline": newline, + "suffix": suffix, + "prefix": prefix, + "dir": dir, + "delete": delete, + "errors": errors, + } + if sys.version_info >= (3, 12): + self._params["delete_on_close"] = delete_on_close + + async def __aenter__(self) -> AsyncFile[AnyStr]: + fp = await to_thread.run_sync( + lambda: tempfile.NamedTemporaryFile(**self._params) + ) + self._async_file = AsyncFile(fp) + return self._async_file + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: + await self._async_file.aclose() + + +class SpooledTemporaryFile(AsyncFile[AnyStr]): + """ + An asynchronous spooled temporary file that starts in memory and is spooled to disk. + + This class provides an asynchronous interface to a spooled temporary file, much like + Python's standard :class:`~tempfile.SpooledTemporaryFile`. It supports asynchronous + write operations and provides a method to force a rollover to disk. + + :param max_size: Maximum size in bytes before the file is rolled over to disk. + :param mode: The mode in which the file is opened. Defaults to "w+b". + :param buffering: The buffering policy (-1 means the default buffering). + :param encoding: The encoding used to decode or encode the file (text mode only). + :param newline: Controls how universal newlines mode works (text mode only). + :param suffix: The suffix for the temporary file name. + :param prefix: The prefix for the temporary file name. + :param dir: The directory in which the temporary file is created. + :param errors: The error handling scheme used for encoding/decoding errors. + """ + + _rolled: bool = False + + @overload + def __init__( + self: SpooledTemporaryFile[bytes], + max_size: int = ..., + mode: OpenBinaryMode = ..., + buffering: int = ..., + encoding: str | None = ..., + newline: str | None = ..., + suffix: str | None = ..., + prefix: str | None = ..., + dir: str | None = ..., + *, + errors: str | None = ..., + ): ... + @overload + def __init__( + self: SpooledTemporaryFile[str], + max_size: int = ..., + mode: OpenTextMode = ..., + buffering: int = ..., + encoding: str | None = ..., + newline: str | None = ..., + suffix: str | None = ..., + prefix: str | None = ..., + dir: str | None = ..., + *, + errors: str | None = ..., + ): ... + + def __init__( + self, + max_size: int = 0, + mode: OpenBinaryMode | OpenTextMode = "w+b", + buffering: int = -1, + encoding: str | None = None, + newline: str | None = None, + suffix: str | None = None, + prefix: str | None = None, + dir: str | None = None, + *, + errors: str | None = None, + ) -> None: + self._tempfile_params: dict[str, Any] = { + "mode": mode, + "buffering": buffering, + "encoding": encoding, + "newline": newline, + "suffix": suffix, + "prefix": prefix, + "dir": dir, + "errors": errors, + } + self._max_size = max_size + if "b" in mode: + super().__init__(BytesIO()) # type: ignore[arg-type] + else: + super().__init__( + TextIOWrapper( # type: ignore[arg-type] + BytesIO(), + encoding=encoding, + errors=errors, + newline=newline, + write_through=True, + ) + ) + + async def aclose(self) -> None: + if not self._rolled: + self._fp.close() + return + + await super().aclose() + + async def _check(self) -> None: + if self._rolled or self._fp.tell() <= self._max_size: + return + + await self.rollover() + + async def rollover(self) -> None: + if self._rolled: + return + + self._rolled = True + buffer = self._fp + buffer.seek(0) + self._fp = await to_thread.run_sync( + lambda: tempfile.TemporaryFile(**self._tempfile_params) + ) + await self.write(buffer.read()) + buffer.close() + + @property + def closed(self) -> bool: + return self._fp.closed + + async def read(self, size: int = -1) -> AnyStr: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.read(size) + + return await super().read(size) # type: ignore[return-value] + + async def read1(self: SpooledTemporaryFile[bytes], size: int = -1) -> bytes: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.read1(size) + + return await super().read1(size) + + async def readline(self) -> AnyStr: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.readline() + + return await super().readline() # type: ignore[return-value] + + async def readlines(self) -> list[AnyStr]: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.readlines() + + return await super().readlines() # type: ignore[return-value] + + async def readinto(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.readinto(b) + + return await super().readinto(b) + + async def readinto1(self: SpooledTemporaryFile[bytes], b: WriteableBuffer) -> int: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.readinto1(b) + + return await super().readinto1(b) + + async def seek(self, offset: int, whence: int | None = os.SEEK_SET) -> int: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.seek(offset, whence) + + return await super().seek(offset, whence) + + async def tell(self) -> int: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.tell() + + return await super().tell() + + async def truncate(self, size: int | None = None) -> int: + if not self._rolled: + await checkpoint_if_cancelled() + return self._fp.truncate(size) + + return await super().truncate(size) + + @overload + async def write(self: SpooledTemporaryFile[bytes], b: ReadableBuffer) -> int: ... + @overload + async def write(self: SpooledTemporaryFile[str], b: str) -> int: ... + + async def write(self, b: ReadableBuffer | str) -> int: + """ + Asynchronously write data to the spooled temporary file. + + If the file has not yet been rolled over, the data is written synchronously, + and a rollover is triggered if the size exceeds the maximum size. + + :param s: The data to write. + :return: The number of bytes written. + :raises RuntimeError: If the underlying file is not initialized. + + """ + if not self._rolled: + await checkpoint_if_cancelled() + result = self._fp.write(b) + await self._check() + return result + + return await super().write(b) # type: ignore[misc] + + @overload + async def writelines( + self: SpooledTemporaryFile[bytes], lines: Iterable[ReadableBuffer] + ) -> None: ... + @overload + async def writelines( + self: SpooledTemporaryFile[str], lines: Iterable[str] + ) -> None: ... + + async def writelines(self, lines: Iterable[str] | Iterable[ReadableBuffer]) -> None: + """ + Asynchronously write a list of lines to the spooled temporary file. + + If the file has not yet been rolled over, the lines are written synchronously, + and a rollover is triggered if the size exceeds the maximum size. + + :param lines: An iterable of lines to write. + :raises RuntimeError: If the underlying file is not initialized. + + """ + if not self._rolled: + await checkpoint_if_cancelled() + result = self._fp.writelines(lines) + await self._check() + return result + + return await super().writelines(lines) # type: ignore[misc] + + +class TemporaryDirectory(Generic[AnyStr]): + """ + An asynchronous temporary directory that is created and cleaned up automatically. + + This class provides an asynchronous context manager for creating a temporary + directory. It wraps Python's standard :class:`~tempfile.TemporaryDirectory` to + perform directory creation and cleanup operations in a background thread. + + :param suffix: Suffix to be added to the temporary directory name. + :param prefix: Prefix to be added to the temporary directory name. + :param dir: The parent directory where the temporary directory is created. + :param ignore_cleanup_errors: Whether to ignore errors during cleanup + :param delete: Whether to delete the directory upon closing (Python 3.12+). + """ + + def __init__( + self, + suffix: AnyStr | None = None, + prefix: AnyStr | None = None, + dir: AnyStr | None = None, + *, + ignore_cleanup_errors: bool = False, + delete: bool = True, + ) -> None: + self.suffix: AnyStr | None = suffix + self.prefix: AnyStr | None = prefix + self.dir: AnyStr | None = dir + self.ignore_cleanup_errors = ignore_cleanup_errors + self.delete = delete + + self._tempdir: tempfile.TemporaryDirectory | None = None + + async def __aenter__(self) -> str: + params: dict[str, Any] = { + "suffix": self.suffix, + "prefix": self.prefix, + "dir": self.dir, + "ignore_cleanup_errors": self.ignore_cleanup_errors, + } + if sys.version_info >= (3, 12): + params["delete"] = self.delete + + self._tempdir = await to_thread.run_sync( + lambda: tempfile.TemporaryDirectory(**params) + ) + return await to_thread.run_sync(self._tempdir.__enter__) + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + ) -> None: + if self._tempdir is not None: + with CancelScope(shield=True): + await to_thread.run_sync( + self._tempdir.__exit__, exc_type, exc_value, traceback + ) + + async def cleanup(self) -> None: + if self._tempdir is not None: + await to_thread.run_sync(self._tempdir.cleanup) + + +@overload +async def mkstemp( + suffix: str | None = None, + prefix: str | None = None, + dir: str | None = None, + text: bool = False, +) -> tuple[int, str]: ... + + +@overload +async def mkstemp( + suffix: bytes | None = None, + prefix: bytes | None = None, + dir: bytes | None = None, + text: bool = False, +) -> tuple[int, bytes]: ... + + +async def mkstemp( + suffix: AnyStr | None = None, + prefix: AnyStr | None = None, + dir: AnyStr | None = None, + text: bool = False, +) -> tuple[int, str | bytes]: + """ + Asynchronously create a temporary file and return an OS-level handle and the file + name. + + This function wraps `tempfile.mkstemp` and executes it in a background thread. + + :param suffix: Suffix to be added to the file name. + :param prefix: Prefix to be added to the file name. + :param dir: Directory in which the temporary file is created. + :param text: Whether the file is opened in text mode. + :return: A tuple containing the file descriptor and the file name. + + """ + return await to_thread.run_sync(tempfile.mkstemp, suffix, prefix, dir, text) + + +@overload +async def mkdtemp( + suffix: str | None = None, + prefix: str | None = None, + dir: str | None = None, +) -> str: ... + + +@overload +async def mkdtemp( + suffix: bytes | None = None, + prefix: bytes | None = None, + dir: bytes | None = None, +) -> bytes: ... + + +async def mkdtemp( + suffix: AnyStr | None = None, + prefix: AnyStr | None = None, + dir: AnyStr | None = None, +) -> str | bytes: + """ + Asynchronously create a temporary directory and return its path. + + This function wraps `tempfile.mkdtemp` and executes it in a background thread. + + :param suffix: Suffix to be added to the directory name. + :param prefix: Prefix to be added to the directory name. + :param dir: Parent directory where the temporary directory is created. + :return: The path of the created temporary directory. + + """ + return await to_thread.run_sync(tempfile.mkdtemp, suffix, prefix, dir) + + +async def gettempdir() -> str: + """ + Asynchronously return the name of the directory used for temporary files. + + This function wraps `tempfile.gettempdir` and executes it in a background thread. + + :return: The path of the temporary directory as a string. + + """ + return await to_thread.run_sync(tempfile.gettempdir) + + +async def gettempdirb() -> bytes: + """ + Asynchronously return the name of the directory used for temporary files in bytes. + + This function wraps `tempfile.gettempdirb` and executes it in a background thread. + + :return: The path of the temporary directory as bytes. + + """ + return await to_thread.run_sync(tempfile.gettempdirb) diff --git a/source/target-vendors/cp312/anyio/_core/_testing.py b/source/target-vendors/cp312/anyio/_core/_testing.py new file mode 100644 index 0000000..fa2c391 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_testing.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Awaitable, Generator +from typing import Any, cast + +from ._eventloop import get_async_backend + + +class TaskInfo: + """ + Represents an asynchronous task. + + :ivar int id: the unique identifier of the task + :ivar parent_id: the identifier of the parent task, if any + :vartype parent_id: Optional[int] + :ivar str name: the description of the task (if any) + :ivar ~collections.abc.Coroutine coro: the coroutine object of the task + """ + + __slots__ = "_name", "coro", "id", "name", "parent_id" + + def __init__( + self, + id: int, + parent_id: int | None, + name: str | None, + coro: Generator[Any, Any, Any] | Awaitable[Any], + ): + func = get_current_task + self._name = f"{func.__module__}.{func.__qualname__}" + self.id: int = id + self.parent_id: int | None = parent_id + self.name: str | None = name + self.coro: Generator[Any, Any, Any] | Awaitable[Any] = coro + + def __eq__(self, other: object) -> bool: + if isinstance(other, TaskInfo): + return self.id == other.id + + return NotImplemented + + def __hash__(self) -> int: + return hash(self.id) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(id={self.id!r}, name={self.name!r})" + + def has_pending_cancellation(self) -> bool: + """ + Return ``True`` if the task has a cancellation pending, ``False`` otherwise. + + """ + return False + + +def get_current_task() -> TaskInfo: + """ + Return the current task. + + :return: a representation of the current task + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().get_current_task() + + +def get_running_tasks() -> list[TaskInfo]: + """ + Return a list of running tasks in the current event loop. + + :return: a list of task info objects + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return cast("list[TaskInfo]", get_async_backend().get_running_tasks()) + + +async def wait_all_tasks_blocked() -> None: + """Wait until all other tasks are waiting for something.""" + await get_async_backend().wait_all_tasks_blocked() diff --git a/source/target-vendors/cp312/anyio/_core/_typedattr.py b/source/target-vendors/cp312/anyio/_core/_typedattr.py new file mode 100644 index 0000000..59d3da9 --- /dev/null +++ b/source/target-vendors/cp312/anyio/_core/_typedattr.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import sys +from collections.abc import Callable, Mapping +from typing import Any, TypeVar, final, overload + +from ._exceptions import TypedAttributeLookupError + +if sys.version_info < (3, 15): + from typing_extensions import sentinel + +T_Attr = TypeVar("T_Attr") +T_Default = TypeVar("T_Default") +undefined = sentinel("undefined") + + +def typed_attribute() -> Any: + """Return a unique object, used to mark typed attributes.""" + return object() + + +class TypedAttributeSet: + """ + Superclass for typed attribute collections. + + Checks that every public attribute of every subclass has a type annotation. + """ + + def __init_subclass__(cls) -> None: + annotations: dict[str, Any] = getattr(cls, "__annotations__", {}) + for attrname in dir(cls): + if not attrname.startswith("_") and attrname not in annotations: + raise TypeError( + f"Attribute {attrname!r} is missing its type annotation" + ) + + super().__init_subclass__() + + +class TypedAttributeProvider: + """Base class for classes that wish to provide typed extra attributes.""" + + @property + def extra_attributes(self) -> Mapping[T_Attr, Callable[[], T_Attr]]: + """ + A mapping of the extra attributes to callables that return the corresponding + values. + + If the provider wraps another provider, the attributes from that wrapper should + also be included in the returned mapping (but the wrapper may override the + callables from the wrapped instance). + + """ + return {} + + @overload + def extra(self, attribute: T_Attr) -> T_Attr: ... + + @overload + def extra(self, attribute: T_Attr, default: T_Default) -> T_Attr | T_Default: ... + + @final + def extra(self, attribute: Any, default: object = undefined) -> object: + """ + extra(attribute, default=undefined) + + Return the value of the given typed extra attribute. + + :param attribute: the attribute (member of a :class:`~TypedAttributeSet`) to + look for + :param default: the value that should be returned if no value is found for the + attribute + :raises ~anyio.TypedAttributeLookupError: if the search failed and no default + value was given + + """ + try: + getter = self.extra_attributes[attribute] + except KeyError: + if default is undefined: + raise TypedAttributeLookupError("Attribute not found") from None + else: + return default + + return getter() diff --git a/source/target-vendors/cp312/anyio/_lazyimport.py b/source/target-vendors/cp312/anyio/_lazyimport.py new file mode 100644 index 0000000..dc0a4fa --- /dev/null +++ b/source/target-vendors/cp312/anyio/_lazyimport.py @@ -0,0 +1,176 @@ +from __future__ import annotations + +__all__ = ( + "fix_package_names", + "install_lazy_importer", + "set_deprecated_aliases", +) + +import ast +import inspect +import sys +import warnings +from importlib import import_module +from types import ModuleType +from typing import Any + + +def install_lazy_importer() -> bool: + module_globals = sys._getframe(1).f_globals + module_name = module_globals["__name__"] + module_prefix = module_name + "." + module = sys.modules[module_name] + lazy_map, deprecated_aliases, submodule_names = _build_lazy_map(module) + names = sorted(lazy_map) + + # Delete symbols that are not part of the API + del module_globals["TYPE_CHECKING"] + del module_globals["install_lazy_importer"] + + if not lazy_map and not deprecated_aliases: + return False + + def __getattr__(name: str) -> Any: + if new_name := deprecated_aliases.get(name): + emit_deprecation_warning(module_name, name, new_name) + target_mod, target_attr = new_name.rsplit(".", 1) + elif name in submodule_names: + target_mod, target_attr = "." + name, "" + else: + try: + target_mod, target_attr = lazy_map[name] + except KeyError: + raise AttributeError( + f"module {module_name!r} has no attribute {name!r}" + ) from None + + imported = import_module(target_mod, module_name) + value = getattr(imported, target_attr) if target_attr else imported + + # patch the module name to match + if ( + getattr(value, "__module__", "").startswith(module_prefix) + and name not in deprecated_aliases + ): + value.__module__ = module_name + + module_globals[name] = value + return value + + def __dir__() -> list[str]: + return names + + module_globals["__dir__"] = __dir__ + module_globals["__getattr__"] = __getattr__ + module_globals.pop("fix_package_names", None) + module_globals.pop("set_deprecated_aliases", None) + return True + + +def fix_package_names() -> None: + module_globals = sys._getframe(1).f_globals + module_prefix = module_globals["__name__"] + "." + del module_globals[fix_package_names.__name__] + for value in module_globals.values(): + if modname := getattr(value, "__module__", ""): + if modname.startswith(module_prefix): + parts = modname.split(".") + value.__module__ = ".".join( + part for part in parts if not part.startswith("_") + ) + + +def emit_deprecation_warning(module_name: str, name: str, target: str) -> None: + warnings.warn( + f"The {module_name}.{name} alias is deprecated, use {target} instead.", + DeprecationWarning, + stacklevel=3, + ) + + +def set_deprecated_aliases(aliases: dict[str, str]) -> None: + module_globals = sys._getframe(1).f_globals + module_name = module_globals["__name__"] + del module_globals[set_deprecated_aliases.__name__] + + def __getattr__(name: str) -> Any: + try: + target = aliases[name] + except KeyError: + raise AttributeError( + f"module {module_name!r} has no attribute {name!r}" + ) from None + + emit_deprecation_warning(module_name, name, target) + target_modname, attrname = target.rsplit(".", 1) + module = import_module(target_modname) + return getattr(module, attrname) + + sys.modules[module_name].__dict__["__getattr__"] = __getattr__ + + +def _build_lazy_map( + module: ModuleType, +) -> tuple[dict[str, tuple[str, str]], dict[str, str], list[str]]: + try: + source = inspect.getsource(module) + except OSError: + return {}, {}, [] + + tree = compile(source, module.__file__ or "", "exec", ast.PyCF_ONLY_AST) + assert isinstance(tree, ast.Module) + out: dict[str, tuple[str, str]] = {} + deprecated_aliases: dict[str, str] = {} + submodule_names: list[str] = [] + + for node in tree.body: + if not isinstance(node, ast.If) or not _is_type_checking_block(node.test): + continue + + for stmt in node.body: + match stmt: + case ast.ImportFrom(): + if stmt.module is None: + submodule_names.extend(alias.name for alias in stmt.names) + else: + base = "." * stmt.level + (stmt.module or "") + for alias in stmt.names: + if alias.name == "*": + raise RuntimeError("star imports not supported") + + exported = alias.asname or alias.name + out[exported] = (base, alias.name) + case ast.Expr() if isinstance(stmt.value, ast.Call): + call = stmt.value + if ( + isinstance(call.func, ast.Name) + and call.func.id == "set_deprecated_aliases" + ): + arg0 = call.args[0] + assert isinstance(arg0, ast.Dict) + for key, value in zip(arg0.keys, arg0.values, strict=True): + assert isinstance(key, ast.Constant) + assert isinstance(key.value, str) + assert isinstance(value, ast.Constant) + assert isinstance(value.value, str) + deprecated_aliases[key.value] = value.value + + return out, deprecated_aliases, submodule_names + + +def _is_type_checking_block(test: ast.AST) -> bool: + if not isinstance(test, ast.BoolOp): + return False + + subtest = test.values[0] + match subtest: + case ast.Name(): + return subtest.id == "TYPE_CHECKING" + case ast.Attribute(): + return ( + isinstance(subtest.value, ast.Name) + and subtest.value.id == "typing" + and subtest.attr == "TYPE_CHECKING" + ) + case _: + return False diff --git a/source/target-vendors/cp312/anyio/abc/__init__.py b/source/target-vendors/cp312/anyio/abc/__init__.py new file mode 100644 index 0000000..ba738f8 --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/__init__.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from .._lazyimport import ( + fix_package_names, + install_lazy_importer, + set_deprecated_aliases, +) + +if TYPE_CHECKING or not install_lazy_importer(): + from ._eventloop import AsyncBackend as AsyncBackend + from ._resources import AsyncResource as AsyncResource + from ._sockets import ConnectedUDPSocket as ConnectedUDPSocket + from ._sockets import ConnectedUNIXDatagramSocket as ConnectedUNIXDatagramSocket + from ._sockets import IPAddressType as IPAddressType + from ._sockets import IPSockAddrType as IPSockAddrType + from ._sockets import SocketAttribute as SocketAttribute + from ._sockets import SocketListener as SocketListener + from ._sockets import SocketStream as SocketStream + from ._sockets import UDPPacketType as UDPPacketType + from ._sockets import UDPSocket as UDPSocket + from ._sockets import UNIXDatagramPacketType as UNIXDatagramPacketType + from ._sockets import UNIXDatagramSocket as UNIXDatagramSocket + from ._sockets import UNIXSocketStream as UNIXSocketStream + from ._streams import AnyByteReceiveStream as AnyByteReceiveStream + from ._streams import AnyByteSendStream as AnyByteSendStream + from ._streams import AnyByteStream as AnyByteStream + from ._streams import AnyByteStreamConnectable as AnyByteStreamConnectable + from ._streams import ( + AnyUnreliableByteReceiveStream as AnyUnreliableByteReceiveStream, + ) + from ._streams import AnyUnreliableByteSendStream as AnyUnreliableByteSendStream + from ._streams import AnyUnreliableByteStream as AnyUnreliableByteStream + from ._streams import ByteReceiveStream as ByteReceiveStream + from ._streams import ByteSendStream as ByteSendStream + from ._streams import ByteStream as ByteStream + from ._streams import ByteStreamConnectable as ByteStreamConnectable + from ._streams import Listener as Listener + from ._streams import ObjectReceiveStream as ObjectReceiveStream + from ._streams import ObjectSendStream as ObjectSendStream + from ._streams import ObjectStream as ObjectStream + from ._streams import ObjectStreamConnectable as ObjectStreamConnectable + from ._streams import UnreliableObjectReceiveStream as UnreliableObjectReceiveStream + from ._streams import UnreliableObjectSendStream as UnreliableObjectSendStream + from ._streams import UnreliableObjectStream as UnreliableObjectStream + from ._subprocesses import Process as Process + from ._tasks import TaskGroup as TaskGroup + from ._tasks import TaskStatus as TaskStatus + from ._testing import TestRunner as TestRunner + + fix_package_names() + set_deprecated_aliases( + { + "CapacityLimiter": "anyio.CapacityLimiter", + "Condition": "anyio.Condition", + "Event": "anyio.Event", + "Lock": "anyio.Lock", + "Semaphore": "anyio.Semaphore", + "CancelScope": "anyio.CancelScope", + "BlockingPortal": "anyio.from_thread.BlockingPortal", + } + ) diff --git a/source/target-vendors/cp312/anyio/abc/_eventloop.py b/source/target-vendors/cp312/anyio/abc/_eventloop.py new file mode 100644 index 0000000..a3cbed2 --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_eventloop.py @@ -0,0 +1,428 @@ +from __future__ import annotations + +import math +import sys +from abc import ABCMeta, abstractmethod +from collections.abc import ( + AsyncIterator, + Awaitable, + Callable, + Coroutine, + Iterable, + Mapping, + Sequence, +) +from contextlib import AbstractContextManager +from os import PathLike +from signal import Signals +from socket import AddressFamily, SocketKind, socket +from typing import ( + IO, + TYPE_CHECKING, + Any, + TypeAlias, + TypeVar, + overload, +) + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +if TYPE_CHECKING: + from _typeshed import FileDescriptorLike + + from .._core._synchronization import CapacityLimiter, Event, Lock, Semaphore + from .._core._tasks import CancelScope + from .._core._testing import TaskInfo + from ._sockets import ( + ConnectedUDPSocket, + ConnectedUNIXDatagramSocket, + IPSockAddrType, + SocketListener, + SocketStream, + UDPSocket, + UNIXDatagramSocket, + UNIXSocketStream, + ) + from ._subprocesses import Process + from ._tasks import TaskGroup + from ._testing import TestRunner + +T_Retval = TypeVar("T_Retval") +T_co = TypeVar("T_co", covariant=True) +PosArgsT = TypeVarTuple("PosArgsT") +StrOrBytesPath: TypeAlias = str | bytes | PathLike[str] | PathLike[bytes] + + +class AsyncBackend(metaclass=ABCMeta): + @classmethod + @abstractmethod + def run( + cls, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + args: tuple[Unpack[PosArgsT]], + kwargs: dict[str, Any], + options: dict[str, Any], + ) -> T_Retval: + """ + Run the given coroutine function in an asynchronous event loop. + + The current thread must not be already running an event loop. + + :param func: a coroutine function + :param args: positional arguments to ``func`` + :param kwargs: positional arguments to ``func`` + :param options: keyword arguments to call the backend ``run()`` implementation + with + :return: the return value of the coroutine function + """ + + @classmethod + @abstractmethod + def current_token(cls) -> object: + """ + Return an object that allows other threads to run code inside the event loop. + + :return: a token object, specific to the event loop running in the current + thread + """ + + @classmethod + @abstractmethod + def current_time(cls) -> float: + """ + Return the current value of the event loop's internal clock. + + :return: the clock value (seconds) + """ + + @classmethod + @abstractmethod + def cancelled_exception_class(cls) -> type[BaseException]: + """Return the exception class that is raised in a task if it's cancelled.""" + + @classmethod + @abstractmethod + async def checkpoint(cls) -> None: + """ + Check if the task has been cancelled, and allow rescheduling of other tasks. + + This is effectively the same as running :meth:`checkpoint_if_cancelled` and then + :meth:`cancel_shielded_checkpoint`. + """ + + @classmethod + async def checkpoint_if_cancelled(cls) -> None: + """ + Check if the current task group has been cancelled. + + This will check if the task has been cancelled, but will not allow other tasks + to be scheduled if not. + + """ + if cls.current_effective_deadline() == -math.inf: + await cls.checkpoint() + + @classmethod + async def cancel_shielded_checkpoint(cls) -> None: + """ + Allow the rescheduling of other tasks. + + This will give other tasks the opportunity to run, but without checking if the + current task group has been cancelled, unlike with :meth:`checkpoint`. + + """ + with cls.create_cancel_scope(shield=True): + await cls.sleep(0) + + @classmethod + @abstractmethod + async def sleep(cls, delay: float) -> None: + """ + Pause the current task for the specified duration. + + :param delay: the duration, in seconds + """ + + @classmethod + @abstractmethod + def create_cancel_scope( + cls, *, deadline: float = math.inf, shield: bool = False + ) -> CancelScope: + pass + + @classmethod + @abstractmethod + def current_effective_deadline(cls) -> float: + """ + Return the nearest deadline among all the cancel scopes effective for the + current task. + + :return: + - a clock value from the event loop's internal clock + - ``inf`` if there is no deadline in effect + - ``-inf`` if the current scope has been cancelled + :rtype: float + """ + + @classmethod + @abstractmethod + def create_task_group(cls) -> TaskGroup: + pass + + @classmethod + @abstractmethod + def create_event(cls) -> Event: + pass + + @classmethod + @abstractmethod + def create_lock(cls, *, fast_acquire: bool) -> Lock: + pass + + @classmethod + @abstractmethod + def create_semaphore( + cls, + initial_value: int, + *, + max_value: int | None = None, + fast_acquire: bool = False, + ) -> Semaphore: + pass + + @classmethod + @abstractmethod + def create_capacity_limiter(cls, total_tokens: float) -> CapacityLimiter: + pass + + @classmethod + @abstractmethod + async def run_sync_in_worker_thread( + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + abandon_on_cancel: bool = False, + limiter: CapacityLimiter | None = None, + ) -> T_Retval: + pass + + @classmethod + @abstractmethod + def check_cancelled(cls) -> None: + pass + + @classmethod + @abstractmethod + def run_async_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_co: + pass + + @classmethod + @abstractmethod + def run_sync_from_thread( + cls, + func: Callable[[Unpack[PosArgsT]], T_Retval], + args: tuple[Unpack[PosArgsT]], + token: object, + ) -> T_Retval: + pass + + @classmethod + @abstractmethod + async def open_process( + cls, + command: StrOrBytesPath | Sequence[StrOrBytesPath], + *, + stdin: int | IO[Any] | None, + stdout: int | IO[Any] | None, + stderr: int | IO[Any] | None, + cwd: StrOrBytesPath | None = None, + env: Mapping[str, str] | None = None, + startupinfo: Any = None, + creationflags: int = 0, + start_new_session: bool = False, + pass_fds: Sequence[int] = (), + user: str | int | None = None, + group: str | int | None = None, + extra_groups: Iterable[str | int] | None = None, + umask: int = -1, + **kwargs: Any, + ) -> Process: + pass + + @classmethod + @abstractmethod + def setup_process_pool_exit_at_shutdown(cls, workers: set[Process]) -> None: + pass + + @classmethod + @abstractmethod + async def connect_tcp( + cls, host: str, port: int, local_address: IPSockAddrType | None = None + ) -> SocketStream: + pass + + @classmethod + @abstractmethod + async def connect_unix(cls, path: str | bytes) -> UNIXSocketStream: + pass + + @classmethod + @abstractmethod + def create_tcp_listener(cls, sock: socket) -> SocketListener: + pass + + @classmethod + @abstractmethod + def create_unix_listener(cls, sock: socket) -> SocketListener: + pass + + @classmethod + @abstractmethod + async def create_udp_socket( + cls, + family: AddressFamily, + local_address: IPSockAddrType | None, + remote_address: IPSockAddrType | None, + reuse_port: bool, + ) -> UDPSocket | ConnectedUDPSocket: + pass + + @classmethod + @overload + async def create_unix_datagram_socket( + cls, raw_socket: socket, remote_path: None + ) -> UNIXDatagramSocket: ... + + @classmethod + @overload + async def create_unix_datagram_socket( + cls, raw_socket: socket, remote_path: str | bytes + ) -> ConnectedUNIXDatagramSocket: ... + + @classmethod + @abstractmethod + async def create_unix_datagram_socket( + cls, raw_socket: socket, remote_path: str | bytes | None + ) -> UNIXDatagramSocket | ConnectedUNIXDatagramSocket: + pass + + @classmethod + @abstractmethod + async def getaddrinfo( + cls, + host: bytes | str | None, + port: str | int | None, + *, + family: int | AddressFamily = 0, + type: int | SocketKind = 0, + proto: int = 0, + flags: int = 0, + ) -> Sequence[ + tuple[ + AddressFamily, + SocketKind, + int, + str, + tuple[str, int] | tuple[str, int, int, int] | tuple[int, bytes], + ] + ]: + pass + + @classmethod + @abstractmethod + async def getnameinfo( + cls, sockaddr: IPSockAddrType, flags: int = 0 + ) -> tuple[str, str]: + pass + + @classmethod + @abstractmethod + async def wait_readable(cls, obj: FileDescriptorLike) -> None: + pass + + @classmethod + @abstractmethod + async def wait_writable(cls, obj: FileDescriptorLike) -> None: + pass + + @classmethod + @abstractmethod + def notify_closing(cls, obj: FileDescriptorLike) -> None: + pass + + @classmethod + @abstractmethod + async def wrap_listener_socket(cls, sock: socket) -> SocketListener: + pass + + @classmethod + @abstractmethod + async def wrap_stream_socket(cls, sock: socket) -> SocketStream: + pass + + @classmethod + @abstractmethod + async def wrap_unix_stream_socket(cls, sock: socket) -> UNIXSocketStream: + pass + + @classmethod + @abstractmethod + async def wrap_udp_socket(cls, sock: socket) -> UDPSocket: + pass + + @classmethod + @abstractmethod + async def wrap_connected_udp_socket(cls, sock: socket) -> ConnectedUDPSocket: + pass + + @classmethod + @abstractmethod + async def wrap_unix_datagram_socket(cls, sock: socket) -> UNIXDatagramSocket: + pass + + @classmethod + @abstractmethod + async def wrap_connected_unix_datagram_socket( + cls, sock: socket + ) -> ConnectedUNIXDatagramSocket: + pass + + @classmethod + @abstractmethod + def current_default_thread_limiter(cls) -> CapacityLimiter: + pass + + @classmethod + @abstractmethod + def open_signal_receiver( + cls, *signals: Signals + ) -> AbstractContextManager[AsyncIterator[Signals]]: + pass + + @classmethod + @abstractmethod + def get_current_task(cls) -> TaskInfo: + pass + + @classmethod + @abstractmethod + def get_running_tasks(cls) -> Sequence[TaskInfo]: + pass + + @classmethod + @abstractmethod + async def wait_all_tasks_blocked(cls) -> None: + pass + + @classmethod + @abstractmethod + def create_test_runner(cls, options: dict[str, Any]) -> TestRunner: + pass diff --git a/source/target-vendors/cp312/anyio/abc/_resources.py b/source/target-vendors/cp312/anyio/abc/_resources.py new file mode 100644 index 0000000..9373f71 --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_resources.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import sys +from abc import ABCMeta, abstractmethod +from types import TracebackType +from typing import TypeVar + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + +T = TypeVar("T") + + +class AsyncResource(metaclass=ABCMeta): + """ + Abstract base class for all closeable asynchronous resources. + + Works as an asynchronous context manager which returns the instance itself on enter, + and calls :meth:`aclose` on exit. + """ + + __slots__ = () + + async def __aenter__(self) -> Self: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + await self.aclose() + + @abstractmethod + async def aclose(self) -> None: + """Close the resource.""" diff --git a/source/target-vendors/cp312/anyio/abc/_sockets.py b/source/target-vendors/cp312/anyio/abc/_sockets.py new file mode 100644 index 0000000..d6a1139 --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_sockets.py @@ -0,0 +1,401 @@ +from __future__ import annotations + +import errno +import socket +from abc import abstractmethod +from collections.abc import Callable, Collection, Mapping +from contextlib import AsyncExitStack +from io import IOBase +from ipaddress import IPv4Address, IPv6Address +from socket import AddressFamily +from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar + +from .._core._eventloop import get_async_backend +from .._core._typedattr import ( + TypedAttributeProvider, + TypedAttributeSet, + typed_attribute, +) +from ._streams import ByteStream, Listener, UnreliableObjectStream + +if TYPE_CHECKING: + from ._tasks import TaskGroup + +IPAddressType: TypeAlias = str | IPv4Address | IPv6Address +IPSockAddrType: TypeAlias = tuple[str, int] +SockAddrType: TypeAlias = IPSockAddrType | str +UDPPacketType: TypeAlias = tuple[bytes, IPSockAddrType] +UNIXDatagramPacketType: TypeAlias = tuple[bytes, str] +T_Retval = TypeVar("T_Retval") + + +def _validate_socket( + sock_or_fd: socket.socket | int, + sock_type: socket.SocketKind, + addr_family: socket.AddressFamily = socket.AF_UNSPEC, + *, + require_connected: bool = False, + require_bound: bool = False, +) -> socket.socket: + if isinstance(sock_or_fd, int): + try: + sock = socket.socket(fileno=sock_or_fd) + except OSError as exc: + if exc.errno == errno.ENOTSOCK: + raise ValueError( + "the file descriptor does not refer to a socket" + ) from exc + elif require_connected: + raise ValueError("the socket must be connected") from exc + elif require_bound: + raise ValueError("the socket must be bound to a local address") from exc + else: + raise + elif isinstance(sock_or_fd, socket.socket): + sock = sock_or_fd + else: + raise TypeError( + f"expected an int or socket, got {type(sock_or_fd).__qualname__} instead" + ) + + try: + if require_connected: + try: + sock.getpeername() + except OSError as exc: + raise ValueError("the socket must be connected") from exc + + if require_bound: + try: + if sock.family in (socket.AF_INET, socket.AF_INET6): + bound_addr = sock.getsockname()[1] + else: + bound_addr = sock.getsockname() + except OSError: + bound_addr = None + + if not bound_addr: + raise ValueError("the socket must be bound to a local address") + + if addr_family != socket.AF_UNSPEC and sock.family != addr_family: + raise ValueError( + f"address family mismatch: expected {addr_family.name}, got " + f"{sock.family.name}" + ) + + if sock.type != sock_type: + raise ValueError( + f"socket type mismatch: expected {sock_type.name}, got {sock.type.name}" + ) + except BaseException: + # Avoid ResourceWarning from the locally constructed socket object + if isinstance(sock_or_fd, int): + sock.detach() + + raise + + sock.setblocking(False) + return sock + + +class SocketAttribute(TypedAttributeSet): + """ + .. attribute:: family + :type: socket.AddressFamily + + the address family of the underlying socket + + .. attribute:: local_address + :type: tuple[str, int] | str + + the local address the underlying socket is connected to + + .. attribute:: local_port + :type: int + + for IP based sockets, the local port the underlying socket is bound to + + .. attribute:: raw_socket + :type: socket.socket + + the underlying stdlib socket object + + .. attribute:: remote_address + :type: tuple[str, int] | str + + the remote address the underlying socket is connected to + + .. attribute:: remote_port + :type: int + + for IP based sockets, the remote port the underlying socket is connected to + """ + + family: AddressFamily = typed_attribute() + local_address: SockAddrType = typed_attribute() + local_port: int = typed_attribute() + raw_socket: socket.socket = typed_attribute() + remote_address: SockAddrType = typed_attribute() + remote_port: int = typed_attribute() + + +class _SocketProvider(TypedAttributeProvider): + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + from .._core._sockets import convert_ipv6_sockaddr as convert + + attributes: dict[Any, Callable[[], Any]] = { + SocketAttribute.family: lambda: self._raw_socket.family, + SocketAttribute.local_address: lambda: convert( + self._raw_socket.getsockname() + ), + SocketAttribute.raw_socket: lambda: self._raw_socket, + } + try: + peername: tuple[str, int] | None = convert(self._raw_socket.getpeername()) + except OSError: + peername = None + + # Provide the remote address for connected sockets + if peername is not None: + attributes[SocketAttribute.remote_address] = lambda: peername + + # Provide local and remote ports for IP based sockets + if self._raw_socket.family in (AddressFamily.AF_INET, AddressFamily.AF_INET6): + attributes[SocketAttribute.local_port] = lambda: ( + self._raw_socket.getsockname()[1] + ) + if peername is not None: + remote_port = peername[1] + attributes[SocketAttribute.remote_port] = lambda: remote_port + + return attributes + + @property + @abstractmethod + def _raw_socket(self) -> socket.socket: + pass + + +class SocketStream(ByteStream, _SocketProvider): + """ + Transports bytes over a socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @classmethod + async def from_socket(cls, sock_or_fd: socket.socket | int) -> SocketStream: + """ + Wrap an existing socket object or file descriptor as a socket stream. + + The newly created socket wrapper takes ownership of the socket being passed in. + The existing socket must already be connected. + + :param sock_or_fd: a socket object or file descriptor + :return: a socket stream + + """ + sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_connected=True) + return await get_async_backend().wrap_stream_socket(sock) + + +class UNIXSocketStream(SocketStream): + @classmethod + async def from_socket(cls, sock_or_fd: socket.socket | int) -> UNIXSocketStream: + """ + Wrap an existing socket object or file descriptor as a UNIX socket stream. + + The newly created socket wrapper takes ownership of the socket being passed in. + The existing socket must already be connected. + + :param sock_or_fd: a socket object or file descriptor + :return: a UNIX socket stream + + """ + sock = _validate_socket( + sock_or_fd, socket.SOCK_STREAM, socket.AF_UNIX, require_connected=True + ) + return await get_async_backend().wrap_unix_stream_socket(sock) + + @abstractmethod + async def send_fds(self, message: bytes, fds: Collection[int | IOBase]) -> None: + """ + Send file descriptors along with a message to the peer. + + :param message: a non-empty bytestring + :param fds: a collection of files (either numeric file descriptors or open file + or socket objects) + """ + + @abstractmethod + async def receive_fds(self, msglen: int, maxfds: int) -> tuple[bytes, list[int]]: + """ + Receive file descriptors along with a message from the peer. + + :param msglen: length of the message to expect from the peer + :param maxfds: maximum number of file descriptors to expect from the peer + :return: a tuple of (message, file descriptors) + """ + + +class SocketListener(Listener[SocketStream], _SocketProvider): + """ + Listens to incoming socket connections. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @classmethod + async def from_socket( + cls, + sock_or_fd: socket.socket | int, + ) -> SocketListener: + """ + Wrap an existing socket object or file descriptor as a socket listener. + + The newly created listener takes ownership of the socket being passed in. + + :param sock_or_fd: a socket object or file descriptor + :return: a socket listener + + """ + sock = _validate_socket(sock_or_fd, socket.SOCK_STREAM, require_bound=True) + return await get_async_backend().wrap_listener_socket(sock) + + @abstractmethod + async def accept(self) -> SocketStream: + """Accept an incoming connection.""" + + async def serve( + self, + handler: Callable[[SocketStream], Any], + task_group: TaskGroup | None = None, + ) -> None: + from .. import create_task_group + + async with AsyncExitStack() as stack: + if task_group is None: + task_group = await stack.enter_async_context(create_task_group()) + + while True: + stream = await self.accept() + task_group.start_soon(handler, stream) + + +class UDPSocket(UnreliableObjectStream[UDPPacketType], _SocketProvider): + """ + Represents an unconnected UDP socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @classmethod + async def from_socket(cls, sock_or_fd: socket.socket | int) -> UDPSocket: + """ + Wrap an existing socket object or file descriptor as a UDP socket. + + The newly created socket wrapper takes ownership of the socket being passed in. + The existing socket must be bound to a local address. + + :param sock_or_fd: a socket object or file descriptor + :return: a UDP socket + + """ + sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, require_bound=True) + return await get_async_backend().wrap_udp_socket(sock) + + async def sendto(self, data: bytes, host: str, port: int) -> None: + """ + Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, (host, port))). + + """ + return await self.send((data, (host, port))) + + +class ConnectedUDPSocket(UnreliableObjectStream[bytes], _SocketProvider): + """ + Represents an connected UDP socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @classmethod + async def from_socket(cls, sock_or_fd: socket.socket | int) -> ConnectedUDPSocket: + """ + Wrap an existing socket object or file descriptor as a connected UDP socket. + + The newly created socket wrapper takes ownership of the socket being passed in. + The existing socket must already be connected. + + :param sock_or_fd: a socket object or file descriptor + :return: a connected UDP socket + + """ + sock = _validate_socket( + sock_or_fd, + socket.SOCK_DGRAM, + require_connected=True, + ) + return await get_async_backend().wrap_connected_udp_socket(sock) + + +class UNIXDatagramSocket( + UnreliableObjectStream[UNIXDatagramPacketType], _SocketProvider +): + """ + Represents an unconnected Unix datagram socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @classmethod + async def from_socket( + cls, + sock_or_fd: socket.socket | int, + ) -> UNIXDatagramSocket: + """ + Wrap an existing socket object or file descriptor as a UNIX datagram + socket. + + The newly created socket wrapper takes ownership of the socket being passed in. + + :param sock_or_fd: a socket object or file descriptor + :return: a UNIX datagram socket + + """ + sock = _validate_socket(sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX) + return await get_async_backend().wrap_unix_datagram_socket(sock) + + async def sendto(self, data: bytes, path: str) -> None: + """Alias for :meth:`~.UnreliableObjectSendStream.send` ((data, path)).""" + return await self.send((data, path)) + + +class ConnectedUNIXDatagramSocket(UnreliableObjectStream[bytes], _SocketProvider): + """ + Represents a connected Unix datagram socket. + + Supports all relevant extra attributes from :class:`~SocketAttribute`. + """ + + @classmethod + async def from_socket( + cls, + sock_or_fd: socket.socket | int, + ) -> ConnectedUNIXDatagramSocket: + """ + Wrap an existing socket object or file descriptor as a connected UNIX datagram + socket. + + The newly created socket wrapper takes ownership of the socket being passed in. + The existing socket must already be connected. + + :param sock_or_fd: a socket object or file descriptor + :return: a connected UNIX datagram socket + + """ + sock = _validate_socket( + sock_or_fd, socket.SOCK_DGRAM, socket.AF_UNIX, require_connected=True + ) + return await get_async_backend().wrap_connected_unix_datagram_socket(sock) diff --git a/source/target-vendors/cp312/anyio/abc/_streams.py b/source/target-vendors/cp312/anyio/abc/_streams.py new file mode 100644 index 0000000..daf335d --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_streams.py @@ -0,0 +1,237 @@ +from __future__ import annotations + +from abc import ABCMeta, abstractmethod +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Generic, TypeAlias, TypeVar + +from .._core._exceptions import EndOfStream +from .._core._typedattr import TypedAttributeProvider +from ._resources import AsyncResource + +if TYPE_CHECKING: + from ._tasks import TaskGroup + +T_Item = TypeVar("T_Item") +T_co = TypeVar("T_co", covariant=True) +T_contra = TypeVar("T_contra", contravariant=True) + + +class UnreliableObjectReceiveStream( + AsyncResource, TypedAttributeProvider, Generic[T_co] +): + """ + An interface for receiving objects. + + This interface makes no guarantees that the received messages arrive in the order in + which they were sent, or that no messages are missed. + + Asynchronously iterating over objects of this type will yield objects matching the + given type parameter. + """ + + def __aiter__(self) -> UnreliableObjectReceiveStream[T_co]: + return self + + async def __anext__(self) -> T_co: + try: + return await self.receive() + except EndOfStream: + raise StopAsyncIteration from None + + @abstractmethod + async def receive(self) -> T_co: + """ + Receive the next item. + + :raises ~anyio.ClosedResourceError: if the receive stream has been explicitly + closed + :raises ~anyio.EndOfStream: if this stream has been closed from the other end + :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable + due to external causes + """ + + +class UnreliableObjectSendStream( + AsyncResource, TypedAttributeProvider, Generic[T_contra] +): + """ + An interface for sending objects. + + This interface makes no guarantees that the messages sent will reach the + recipient(s) in the same order in which they were sent, or at all. + """ + + @abstractmethod + async def send(self, item: T_contra) -> None: + """ + Send an item to the peer(s). + + :param item: the item to send + :raises ~anyio.ClosedResourceError: if the send stream has been explicitly + closed + :raises ~anyio.BrokenResourceError: if this stream has been rendered unusable + due to external causes + """ + + +class UnreliableObjectStream( + UnreliableObjectReceiveStream[T_Item], UnreliableObjectSendStream[T_Item] +): + """ + A bidirectional message stream which does not guarantee the order or reliability of + message delivery. + """ + + +class ObjectReceiveStream(UnreliableObjectReceiveStream[T_co]): + """ + A receive message stream which guarantees that messages are received in the same + order in which they were sent, and that no messages are missed. + """ + + +class ObjectSendStream(UnreliableObjectSendStream[T_contra]): + """ + A send message stream which guarantees that messages are delivered in the same order + in which they were sent, without missing any messages in the middle. + """ + + +class ObjectStream( + ObjectReceiveStream[T_Item], + ObjectSendStream[T_Item], + UnreliableObjectStream[T_Item], +): + """ + A bidirectional message stream which guarantees the order and reliability of message + delivery. + """ + + @abstractmethod + async def send_eof(self) -> None: + """ + Send an end-of-file indication to the peer. + + You should not try to send any further data to this stream after calling this + method. This method is idempotent (does nothing on successive calls). + """ + + +class ByteReceiveStream(AsyncResource, TypedAttributeProvider): + """ + An interface for receiving bytes from a single peer. + + Iterating this byte stream will yield a byte string of arbitrary length, but no more + than 65536 bytes. + """ + + def __aiter__(self) -> ByteReceiveStream: + return self + + async def __anext__(self) -> bytes: + try: + return await self.receive() + except EndOfStream: + raise StopAsyncIteration from None + + @abstractmethod + async def receive(self, max_bytes: int = 65536) -> bytes: + """ + Receive at most ``max_bytes`` bytes from the peer. + + .. note:: Implementers of this interface should not return an empty + :class:`bytes` object, and users should ignore them. + + :param max_bytes: maximum number of bytes to receive (must be a positive + integer) + :return: the received bytes + :raises ValueError: if ``max_bytes`` is less than 1 + :raises ~anyio.EndOfStream: if this stream has been closed from the other end + """ + + +class ByteSendStream(AsyncResource, TypedAttributeProvider): + """An interface for sending bytes to a single peer.""" + + @abstractmethod + async def send(self, item: bytes) -> None: + """ + Send the given bytes to the peer. + + :param item: the bytes to send + """ + + +class ByteStream(ByteReceiveStream, ByteSendStream): + """A bidirectional byte stream.""" + + @abstractmethod + async def send_eof(self) -> None: + """ + Send an end-of-file indication to the peer. + + You should not try to send any further data to this stream after calling this + method. This method is idempotent (does nothing on successive calls). + """ + + +#: Type alias for all unreliable bytes-oriented receive streams. +AnyUnreliableByteReceiveStream: TypeAlias = ( + UnreliableObjectReceiveStream[bytes] | ByteReceiveStream +) +#: Type alias for all unreliable bytes-oriented send streams. +AnyUnreliableByteSendStream: TypeAlias = ( + UnreliableObjectSendStream[bytes] | ByteSendStream +) +#: Type alias for all unreliable bytes-oriented streams. +AnyUnreliableByteStream: TypeAlias = UnreliableObjectStream[bytes] | ByteStream +#: Type alias for all bytes-oriented receive streams. +AnyByteReceiveStream: TypeAlias = ObjectReceiveStream[bytes] | ByteReceiveStream +#: Type alias for all bytes-oriented send streams. +AnyByteSendStream: TypeAlias = ObjectSendStream[bytes] | ByteSendStream +#: Type alias for all bytes-oriented streams. +AnyByteStream: TypeAlias = ObjectStream[bytes] | ByteStream + + +class Listener(AsyncResource, TypedAttributeProvider, Generic[T_co]): + """An interface for objects that let you accept incoming connections.""" + + @abstractmethod + async def serve( + self, handler: Callable[[T_co], Any], task_group: TaskGroup | None = None + ) -> None: + """ + Accept incoming connections as they come in and start tasks to handle them. + + :param handler: a callable that will be used to handle each accepted connection + :param task_group: the task group that will be used to start tasks for handling + each accepted connection (if omitted, an ad-hoc task group will be created) + """ + + +class ObjectStreamConnectable(Generic[T_co], metaclass=ABCMeta): + @abstractmethod + async def connect(self) -> ObjectStream[T_co]: + """ + Connect to the remote endpoint. + + :return: an object stream connected to the remote end + :raises ConnectionFailed: if the connection fails + """ + + +class ByteStreamConnectable(metaclass=ABCMeta): + @abstractmethod + async def connect(self) -> ByteStream: + """ + Connect to the remote endpoint. + + :return: a bytestream connected to the remote end + :raises ConnectionFailed: if the connection fails + """ + + +#: Type alias for all connectables returning bytestreams or bytes-oriented object streams +AnyByteStreamConnectable: TypeAlias = ( + ObjectStreamConnectable[bytes] | ByteStreamConnectable +) diff --git a/source/target-vendors/cp312/anyio/abc/_subprocesses.py b/source/target-vendors/cp312/anyio/abc/_subprocesses.py new file mode 100644 index 0000000..555f15f --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_subprocesses.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from abc import abstractmethod +from signal import Signals +from typing import TYPE_CHECKING + +from ._resources import AsyncResource + +if TYPE_CHECKING: + from ._streams import ByteReceiveStream, ByteSendStream + + +class Process(AsyncResource): + """An asynchronous version of :class:`subprocess.Popen`.""" + + @abstractmethod + async def wait(self) -> int: + """ + Wait until the process exits. + + :return: the exit code of the process + """ + + @abstractmethod + def terminate(self) -> None: + """ + Terminates the process, gracefully if possible. + + On Windows, this calls ``TerminateProcess()``. + On POSIX systems, this sends ``SIGTERM`` to the process. + + .. seealso:: :meth:`subprocess.Popen.terminate` + """ + + @abstractmethod + def kill(self) -> None: + """ + Kills the process. + + On Windows, this calls ``TerminateProcess()``. + On POSIX systems, this sends ``SIGKILL`` to the process. + + .. seealso:: :meth:`subprocess.Popen.kill` + """ + + @abstractmethod + def send_signal(self, signal: Signals) -> None: + """ + Send a signal to the subprocess. + + .. seealso:: :meth:`subprocess.Popen.send_signal` + + :param signal: the signal number (e.g. :data:`signal.SIGHUP`) + """ + + @property + @abstractmethod + def pid(self) -> int: + """The process ID of the process.""" + + @property + @abstractmethod + def returncode(self) -> int | None: + """ + The return code of the process. If the process has not yet terminated, this will + be ``None``. + """ + + @property + @abstractmethod + def stdin(self) -> ByteSendStream | None: + """The stream for the standard input of the process.""" + + @property + @abstractmethod + def stdout(self) -> ByteReceiveStream | None: + """The stream for the standard output of the process.""" + + @property + @abstractmethod + def stderr(self) -> ByteReceiveStream | None: + """The stream for the standard error output of the process.""" diff --git a/source/target-vendors/cp312/anyio/abc/_tasks.py b/source/target-vendors/cp312/anyio/abc/_tasks.py new file mode 100644 index 0000000..0a019e2 --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_tasks.py @@ -0,0 +1,223 @@ +from __future__ import annotations + +import sys +from abc import ABCMeta, abstractmethod +from collections.abc import Callable, Coroutine +from contextvars import Context +from types import TracebackType +from typing import TYPE_CHECKING, Any, Literal, Protocol, final, overload + +if sys.version_info >= (3, 13): + from typing import TypeVar +else: + from typing_extensions import TypeVar + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +if TYPE_CHECKING: + from .._core._tasks import CancelScope, TaskHandle + +T_co = TypeVar("T_co", covariant=True) +T_contra = TypeVar("T_contra", contravariant=True, default=None) +PosArgsT = TypeVarTuple("PosArgsT") + + +def get_coro_name(coro: Coroutine[Any, Any, object], override: object = None) -> str: + if override is not None: + return str(override) + + try: + cr_frame = coro.cr_frame # type: ignore[attr-defined] + module = cr_frame.f_globals["__name__"] + except (AttributeError, KeyError): + module = None + + qualname = getattr(coro, "__qualname__", None) + return ".".join([x for x in (module, qualname) if x]) + + +def get_callable_name(func: Callable, override: object = None) -> str: + if override is not None: + return str(override) + + module = getattr(func, "__module__", None) + qualname = getattr(func, "__qualname__", None) + return ".".join([x for x in (module, qualname) if x]) + + +def call_for_coroutine( + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + args: tuple[Unpack[PosArgsT]], + **kwargs: Any, +) -> Coroutine[Any, Any, T_co]: + """ + Call the given function with the given positional and keyword arguments. + + :return: the resulting coroutine + :raises TypeError: if the return value was not a coroutine object + + """ + coro = func(*args, **kwargs) + if not isinstance(coro, Coroutine): + prefix = f"{func.__module__}." if hasattr(func, "__module__") else "" + raise TypeError( + f"Expected {prefix}{func.__qualname__}() to return a coroutine, but " + f"the return value ({coro!r}) is not a coroutine object" + ) + + return coro + + +class TaskStatus(Protocol[T_contra]): + @overload + def started(self: TaskStatus[None]) -> None: ... + + @overload + def started(self, value: T_contra) -> None: ... + + def started(self, value: T_contra | None = None) -> None: + """ + Signal that the task has started. + + :param value: object passed back to the starter of the task + """ + + +class TaskGroup(metaclass=ABCMeta): + """ + Groups several asynchronous tasks together. + + :ivar cancel_scope: the cancel scope inherited by all child tasks + :vartype cancel_scope: CancelScope + + .. note:: On asyncio, support for eager task factories is considered to be + **experimental**. In particular, they don't follow the usual semantics of new + tasks being scheduled on the next iteration of the event loop, and may thus + cause unexpected behavior in code that wasn't written with such semantics in + mind. + """ + + cancel_scope: CancelScope + + def cancel(self, reason: str | None = None) -> None: + """ + Cancel this task group's cancel scope immediately. + + This is a shortcut for calling ``.cancel_scope.cancel()`` on the task group. + + :param reason: a message describing the reason for the cancellation + + .. versionadded:: 4.14.0 + + """ + self.cancel_scope.cancel(reason) + + @abstractmethod + def create_task( + self, + coro: Coroutine[Any, Any, T_co], + *, + name: object = None, + context: Context | None = None, + ) -> TaskHandle[T_co]: + """ + Create a new task from a coroutine object and schedule it to run. + + :param coro: a coroutine object + :param name: optional name to give the task + :param context: optional context to run the task in + :return: a task handle + + .. versionadded:: 4.14.0 + """ + + @final + def start_soon( + self, + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + *args: Unpack[PosArgsT], + name: object = None, + ) -> TaskHandle[T_co]: + """ + Start a new task in this task group. + + :param func: a coroutine function + :param args: positional arguments to call the function with + :param name: name of the task, for the purposes of introspection and debugging + :return: a task handle + + .. versionadded:: 3.0 + .. versionchanged:: 4.14.0 + This method now returns a task handle. + + """ + final_name = get_callable_name(func, name) + return self.create_task(call_for_coroutine(func, args), name=final_name) + + @overload + async def start( + self, + func: Callable[..., Coroutine[Any, Any, T_co]], + *args: object, + name: object = None, + return_handle: Literal[False] = ..., + ) -> Any: ... + + @overload + async def start( + self, + func: Callable[..., Coroutine[Any, Any, T_co]], + *args: object, + name: object = None, + return_handle: Literal[True], + ) -> TaskHandle[T_co, Any]: ... + + @abstractmethod + async def start( + self, + func: Callable[..., Coroutine[Any, Any, T_co]], + *args: object, + name: object = None, + return_handle: Literal[False, True] = False, + ) -> Any: + """ + Start a new task and wait until it signals for readiness. + + The target callable must accept a keyword argument ``task_status`` (of type + :class:`TaskStatus`). Awaiting on this method will return whatever was passed to + ``task_status.started()`` (``None`` by default). + + .. note:: The :class:`TaskStatus` class is generic, and the type argument should + indicate the type of the value that will be passed to + ``task_status.started()``. + + :param func: a coroutine function that accepts the ``task_status`` keyword + argument + :param args: positional arguments to call the function with + :param name: an optional name for the task, for introspection and debugging + :param return_handle: if ``True``, return a :class:`TaskHandle` which also + contains the start value in ``start_value`` + :return: the value passed to ``task_status.started()`` + :raises RuntimeError: if the task finishes without calling + ``task_status.started()`` + + .. seealso:: :ref:`start_initialize` + + .. versionadded:: 3.0 + """ + + @abstractmethod + async def __aenter__(self) -> TaskGroup: + """Enter the task group context and allow starting new tasks.""" + + @abstractmethod + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + """Exit the task group context waiting for all tasks to finish.""" diff --git a/source/target-vendors/cp312/anyio/abc/_testing.py b/source/target-vendors/cp312/anyio/abc/_testing.py new file mode 100644 index 0000000..b18d835 --- /dev/null +++ b/source/target-vendors/cp312/anyio/abc/_testing.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import sys +import types +from abc import ABCMeta, abstractmethod +from collections.abc import AsyncGenerator, Callable, Coroutine, Iterable +from typing import Any, TypeVar + +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + +_T = TypeVar("_T") + + +class TestRunner(metaclass=ABCMeta): + """ + Encapsulates a running event loop. Every call made through this object will use the + same event loop. + """ + + def __enter__(self) -> Self: + return self + + @abstractmethod + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: types.TracebackType | None, + ) -> bool | None: ... + + @abstractmethod + def run_asyncgen_fixture( + self, + fixture_func: Callable[..., AsyncGenerator[_T, Any]], + kwargs: dict[str, Any], + ) -> Iterable[_T]: + """ + Run an async generator fixture. + + :param fixture_func: the fixture function + :param kwargs: keyword arguments to call the fixture function with + :return: an iterator yielding the value yielded from the async generator + """ + + @abstractmethod + def run_fixture( + self, + fixture_func: Callable[..., Coroutine[Any, Any, _T]], + kwargs: dict[str, Any], + ) -> _T: + """ + Run an async fixture. + + :param fixture_func: the fixture function + :param kwargs: keyword arguments to call the fixture function with + :return: the return value of the fixture function + """ + + @abstractmethod + def run_test( + self, test_func: Callable[..., Coroutine[Any, Any, Any]], kwargs: dict[str, Any] + ) -> None: + """ + Run an async test function. + + :param test_func: the test function + :param kwargs: keyword arguments to call the test function with + """ + + @abstractmethod + def is_running(self) -> bool: + """ + Check if the test runner is running. + + :return: ``True`` if the coroutine is currently being run, ``False`` otherwise. + """ diff --git a/source/target-vendors/cp312/anyio/from_thread.py b/source/target-vendors/cp312/anyio/from_thread.py new file mode 100644 index 0000000..f163d81 --- /dev/null +++ b/source/target-vendors/cp312/anyio/from_thread.py @@ -0,0 +1,588 @@ +from __future__ import annotations + +__all__ = ( + "BlockingPortal", + "BlockingPortalProvider", + "check_cancelled", + "run", + "run_sync", + "start_blocking_portal", +) + +import sys +from collections.abc import Awaitable, Callable, Coroutine, Generator +from concurrent.futures import Future +from contextlib import ( + AbstractAsyncContextManager, + AbstractContextManager, + contextmanager, +) +from contextvars import Context +from dataclasses import dataclass, field +from functools import partial +from inspect import isawaitable +from threading import Lock, Thread, current_thread, get_ident +from types import TracebackType +from typing import ( + Any, + Generic, + TypeVar, + cast, + overload, +) + +from ._core._eventloop import ( + get_cancelled_exc_class, + threadlocals, +) +from ._core._eventloop import run as run_eventloop +from ._core._exceptions import NoEventLoopError +from ._core._synchronization import Event +from ._core._tasks import CancelScope, create_task_group +from .abc._tasks import TaskStatus +from .lowlevel import EventLoopToken, current_token + +if sys.version_info >= (3, 11): + from typing import Self, TypeVarTuple, Unpack +else: + from typing_extensions import Self, TypeVarTuple, Unpack + +T_Retval = TypeVar("T_Retval") +T_co = TypeVar("T_co", covariant=True) +PosArgsT = TypeVarTuple("PosArgsT") + + +def _token_or_error(token: EventLoopToken | None) -> EventLoopToken: + if token is not None: + return token + + try: + return threadlocals.current_token + except AttributeError: + raise NoEventLoopError( + "Not running inside an AnyIO worker thread, and no event loop token was " + "provided" + ) from None + + +def run( + func: Callable[[Unpack[PosArgsT]], Coroutine[Any, Any, T_co]], + *args: Unpack[PosArgsT], + token: EventLoopToken | None = None, +) -> T_co: + """ + Call a coroutine function from a worker thread. + + :param func: a coroutine function + :param args: positional arguments for the callable + :param token: an event loop token to use to get back to the event loop thread + (required if calling this function from outside an AnyIO worker thread) + :return: the return value of the coroutine function + :raises MissingTokenError: if no token was provided and called from outside an + AnyIO worker thread + :raises RunFinishedError: if the event loop tied to ``token`` is no longer running + + .. versionchanged:: 4.11.0 + Added the ``token`` parameter. + + """ + explicit_token = token is not None + token = _token_or_error(token) + return token.backend_class.run_async_from_thread( + func, args, token=token.native_token if explicit_token else None + ) + + +def run_sync( + func: Callable[[Unpack[PosArgsT]], T_Retval], + *args: Unpack[PosArgsT], + token: EventLoopToken | None = None, +) -> T_Retval: + """ + Call a function in the event loop thread from a worker thread. + + :param func: a callable + :param args: positional arguments for the callable + :param token: an event loop token to use to get back to the event loop thread + (required if calling this function from outside an AnyIO worker thread) + :return: the return value of the callable + :raises MissingTokenError: if no token was provided and called from outside an + AnyIO worker thread + :raises RunFinishedError: if the event loop tied to ``token`` is no longer running + + .. versionchanged:: 4.11.0 + Added the ``token`` parameter. + + """ + explicit_token = token is not None + token = _token_or_error(token) + return token.backend_class.run_sync_from_thread( + func, args, token=token.native_token if explicit_token else None + ) + + +class _BlockingAsyncContextManager(AbstractContextManager, Generic[T_co]): + _enter_future: Future[T_co] + _exit_future: Future[bool | None] + _exit_event: Event + _exit_exc_info: tuple[ + type[BaseException] | None, BaseException | None, TracebackType | None + ] = (None, None, None) + + def __init__( + self, async_cm: AbstractAsyncContextManager[T_co], portal: BlockingPortal + ): + self._async_cm = async_cm + self._portal = portal + + async def run_async_cm(self) -> bool | None: + try: + self._exit_event = Event() + value = await self._async_cm.__aenter__() + except BaseException as exc: + self._enter_future.set_exception(exc) + raise + else: + self._enter_future.set_result(value) + + try: + # Wait for the sync context manager to exit. + # This next statement can raise `get_cancelled_exc_class()` if + # something went wrong in a task group in this async context + # manager. + await self._exit_event.wait() + finally: + # In case of cancellation, it could be that we end up here before + # `_BlockingAsyncContextManager.__exit__` is called, and an + # `_exit_exc_info` has been set. + result = await self._async_cm.__aexit__(*self._exit_exc_info) + + return result + + def __enter__(self) -> T_co: + self._enter_future = Future() + self._exit_future = self._portal.start_task_soon(self.run_async_cm) + return self._enter_future.result() + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: TracebackType | None, + /, + ) -> bool | None: + self._exit_exc_info = exc_type, exc_value, traceback + self._portal.call(self._exit_event.set) + return self._exit_future.result() + + +class _BlockingPortalTaskStatus(TaskStatus): + def __init__(self, future: Future): + self._future = future + + def started(self, value: object = None) -> None: + self._future.set_result(value) + + +class BlockingPortal: + """ + An object that lets external threads run code in an asynchronous event loop. + + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + """ + + def __init__(self) -> None: + self._token = current_token() + self._event_loop_thread_id: int | None = get_ident() + self._stop_event = Event() + self._task_group = create_task_group() + + async def __aenter__(self) -> Self: + await self._task_group.__aenter__() + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool: + await self.stop() + return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) + + def _check_running(self) -> None: + if self._event_loop_thread_id is None: + raise RuntimeError("This portal is not running") + if self._event_loop_thread_id == get_ident(): + raise RuntimeError( + "This method cannot be called from the event loop thread" + ) + + async def sleep_until_stopped(self) -> None: + """Sleep until :meth:`stop` is called.""" + await self._stop_event.wait() + + async def stop(self, cancel_remaining: bool = False) -> None: + """ + Signal the portal to shut down. + + This marks the portal as no longer accepting new calls and exits from + :meth:`sleep_until_stopped`. + + :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False`` + to let them finish before returning + + """ + self._event_loop_thread_id = None + self._stop_event.set() + if cancel_remaining: + self._task_group.cancel_scope.cancel("the blocking portal is shutting down") + + async def _call_func( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], + args: tuple[Unpack[PosArgsT]], + kwargs: dict[str, Any], + future: Future[T_Retval], + ) -> None: + event_loop_thread_id = self._event_loop_thread_id + + def callback(f: Future[T_Retval]) -> None: + if f.cancelled(): + if event_loop_thread_id == get_ident(): + scope.cancel("the future was cancelled") + elif event_loop_thread_id is not None: + run_sync( + scope.cancel, "the future was cancelled", token=self._token + ) + + try: + retval_or_awaitable = func(*args, **kwargs) + if isawaitable(retval_or_awaitable): + with CancelScope() as scope: + future.add_done_callback(callback) + retval = await retval_or_awaitable + else: + retval = retval_or_awaitable + except get_cancelled_exc_class(): + future.cancel() + future.set_running_or_notify_cancel() + except BaseException as exc: + if not future.cancelled(): + future.set_exception(exc) + + # Let base exceptions fall through + if not isinstance(exc, Exception): + raise + else: + if not future.cancelled(): + future.set_result(retval) + finally: + scope = None # type: ignore[assignment] + + def _spawn_task_from_thread( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], + args: tuple[Unpack[PosArgsT]], + kwargs: dict[str, Any], + name: object, + future: Future[T_Retval], + ) -> None: + """ + Spawn a new task using the given callable. + + :param func: a callable + :param args: positional arguments to be passed to the callable + :param kwargs: keyword arguments to be passed to the callable + :param name: name of the task (will be coerced to a string if not ``None``) + :param future: a future that will resolve to the return value of the callable, + or the exception raised during its execution + + """ + run_sync( + partial(self._task_group.start_soon, name=name), + self._call_func, + func, + args, + kwargs, + future, + token=self._token, + ) + + @overload + def call( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + *args: Unpack[PosArgsT], + ) -> T_Retval: ... + + @overload + def call( + self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] + ) -> T_Retval: ... + + def call( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], + *args: Unpack[PosArgsT], + ) -> T_Retval: + """ + Call the given function in the event loop thread. + + If the callable returns a coroutine object, it is awaited on. + + :param func: any callable + :raises RuntimeError: if the portal is not running or if this method is called + from within the event loop thread + + """ + return cast(T_Retval, self.start_task_soon(func, *args).result()) + + @overload + def start_task_soon( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]], + *args: Unpack[PosArgsT], + name: object = None, + ) -> Future[T_Retval]: ... + + @overload + def start_task_soon( + self, + func: Callable[[Unpack[PosArgsT]], T_Retval], + *args: Unpack[PosArgsT], + name: object = None, + ) -> Future[T_Retval]: ... + + def start_task_soon( + self, + func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval], + *args: Unpack[PosArgsT], + name: object = None, + ) -> Future[T_Retval]: + """ + Start a task in the portal's task group. + + The task will be run inside a cancel scope which can be cancelled by cancelling + the returned future. + + :param func: the target function + :param args: positional arguments passed to ``func`` + :param name: name of the task (will be coerced to a string if not ``None``) + :return: a future that resolves with the return value of the callable if the + task completes successfully, or with the exception raised in the task + :raises RuntimeError: if the portal is not running or if this method is called + from within the event loop thread + :rtype: concurrent.futures.Future[T_Retval] + + .. versionadded:: 3.0 + + """ + self._check_running() + f: Future[T_Retval] = Future() + self._spawn_task_from_thread(func, args, {}, name, f) + return f + + def start_task( + self, + func: Callable[..., Awaitable[T_Retval]], + *args: object, + name: object = None, + ) -> tuple[Future[T_Retval], Any]: + """ + Start a task in the portal's task group and wait until it signals for readiness. + + This method works the same way as :meth:`.abc.TaskGroup.start`. + + :param func: the target function + :param args: positional arguments passed to ``func`` + :param name: name of the task (will be coerced to a string if not ``None``) + :return: a tuple of (future, task_status_value) where the ``task_status_value`` + is the value passed to ``task_status.started()`` from within the target + function + :rtype: tuple[concurrent.futures.Future[T_Retval], Any] + + .. versionadded:: 3.0 + + """ + + def task_done(future: Future[T_Retval]) -> None: + if not task_status_future.done(): + if future.cancelled(): + task_status_future.cancel() + elif future.exception(): + task_status_future.set_exception(future.exception()) + else: + exc = RuntimeError( + "Task exited without calling task_status.started()" + ) + task_status_future.set_exception(exc) + + self._check_running() + task_status_future: Future = Future() + task_status = _BlockingPortalTaskStatus(task_status_future) + f: Future = Future() + f.add_done_callback(task_done) + self._spawn_task_from_thread(func, args, {"task_status": task_status}, name, f) + return f, task_status_future.result() + + def wrap_async_context_manager( + self, cm: AbstractAsyncContextManager[T_co] + ) -> AbstractContextManager[T_co]: + """ + Wrap an async context manager as a synchronous context manager via this portal. + + Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping + in the middle until the synchronous context manager exits. + + :param cm: an asynchronous context manager + :return: a synchronous context manager + + .. versionadded:: 2.1 + + """ + return _BlockingAsyncContextManager(cm, self) + + +@dataclass +class BlockingPortalProvider: + """ + A manager for a blocking portal. Used as a context manager. The first thread to + enter this context manager causes a blocking portal to be started with the specific + parameters, and the last thread to exit causes the portal to be shut down. Thus, + there will be exactly one blocking portal running in this context as long as at + least one thread has entered this context manager. + + The parameters are the same as for :func:`~anyio.run`. + + :param backend: name of the backend + :param backend_options: backend options + + .. versionadded:: 4.4 + """ + + backend: str = "asyncio" + backend_options: dict[str, Any] | None = None + _lock: Lock = field(init=False, default_factory=Lock) + _leases: int = field(init=False, default=0) + _portal: BlockingPortal = field(init=False) + _portal_cm: AbstractContextManager[BlockingPortal] | None = field( + init=False, default=None + ) + + def __enter__(self) -> BlockingPortal: + with self._lock: + if self._portal_cm is None: + self._portal_cm = start_blocking_portal( + self.backend, self.backend_options + ) + self._portal = self._portal_cm.__enter__() + + self._leases += 1 + return self._portal + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + portal_cm: AbstractContextManager[BlockingPortal] | None = None + with self._lock: + assert self._portal_cm + assert self._leases > 0 + self._leases -= 1 + if not self._leases: + portal_cm = self._portal_cm + self._portal_cm = None + del self._portal + + if portal_cm: + portal_cm.__exit__(None, None, None) + + +@contextmanager +def start_blocking_portal( + backend: str = "asyncio", + backend_options: dict[str, Any] | None = None, + *, + name: str | None = None, +) -> Generator[BlockingPortal, Any, None]: + """ + Start a new event loop in a new thread and run a blocking portal in its main task. + + The parameters are the same as for :func:`~anyio.run`. + + :param backend: name of the backend + :param backend_options: backend options + :param name: name of the thread + :return: a context manager that yields a blocking portal + + .. versionchanged:: 3.0 + Usage as a context manager is now required. + + """ + + async def run_portal() -> None: + async with BlockingPortal() as portal_: + if name is None: + current_thread().name = f"{backend}-portal-{id(portal_):x}" + + future.set_result(portal_) + await portal_.sleep_until_stopped() + + def run_blocking_portal() -> None: + if future.set_running_or_notify_cancel(): + try: + run_eventloop( + run_portal, backend=backend, backend_options=backend_options + ) + except BaseException as exc: + if not future.done(): + future.set_exception(exc) + + future: Future[BlockingPortal] = Future() + kwargs: dict[str, Any] = {} + if sys.version_info >= (3, 14): + kwargs["context"] = Context() + + thread = Thread(target=run_blocking_portal, daemon=True, name=name, **kwargs) + thread.start() + try: + cancel_remaining_tasks = False + portal = future.result() + try: + yield portal + except BaseException: + cancel_remaining_tasks = True + raise + finally: + try: + portal.call(portal.stop, cancel_remaining_tasks) + except RuntimeError: + pass + finally: + thread.join() + + +def check_cancelled() -> None: + """ + Check if the cancel scope of the host task's running the current worker thread has + been cancelled. + + If the host task's current cancel scope has indeed been cancelled, the + backend-specific cancellation exception will be raised. + + :raises RuntimeError: if the current thread was not spawned by + :func:`.to_thread.run_sync` + + """ + try: + token: EventLoopToken = threadlocals.current_token + except AttributeError: + raise NoEventLoopError( + "This function can only be called inside an AnyIO worker thread" + ) from None + + token.backend_class.check_cancelled() diff --git a/source/target-vendors/cp312/anyio/functools.py b/source/target-vendors/cp312/anyio/functools.py new file mode 100644 index 0000000..b0bdfb4 --- /dev/null +++ b/source/target-vendors/cp312/anyio/functools.py @@ -0,0 +1,400 @@ +from __future__ import annotations + +__all__ = ( + "AsyncCacheInfo", + "AsyncCacheParameters", + "AsyncLRUCacheWrapper", + "cache", + "lru_cache", + "reduce", +) + +import functools +from collections import OrderedDict +from collections.abc import ( + AsyncIterable, + Awaitable, + Callable, + Coroutine, + Hashable, + Iterable, +) +from functools import update_wrapper +from inspect import iscoroutinefunction +from typing import ( + Any, + Generic, + NamedTuple, + ParamSpec, + TypedDict, + TypeVar, + cast, + final, + overload, +) +from weakref import WeakKeyDictionary + +from ._core._eventloop import current_time +from ._core._synchronization import Lock +from .lowlevel import RunVar, checkpoint + +T = TypeVar("T") +S = TypeVar("S") +P = ParamSpec("P") +lru_cache_items: RunVar[ + WeakKeyDictionary[ + AsyncLRUCacheWrapper[Any, Any], + OrderedDict[ + Hashable, + tuple[_InitialMissingType, Lock, float | None] + | tuple[Any, None, float | None], + ], + ] +] = RunVar("lru_cache_items") + + +class _InitialMissingType: + pass + + +initial_missing: _InitialMissingType = _InitialMissingType() + + +class AsyncCacheInfo(NamedTuple): + hits: int + misses: int + maxsize: int | None + currsize: int + ttl: int | None + + +class AsyncCacheParameters(TypedDict): + maxsize: int | None + typed: bool + always_checkpoint: bool + ttl: int | None + + +class _LRUMethodWrapper(Generic[T]): + def __init__(self, wrapper: AsyncLRUCacheWrapper[..., T], instance: object): + self.__wrapper = wrapper + self.__instance = instance + + def cache_info(self) -> AsyncCacheInfo: + return self.__wrapper.cache_info() + + def cache_parameters(self) -> AsyncCacheParameters: + return self.__wrapper.cache_parameters() + + def cache_clear(self) -> None: + self.__wrapper.cache_clear() + + async def __call__(self, *args: Any, **kwargs: Any) -> T: + if self.__instance is None: + return await self.__wrapper(*args, **kwargs) + + return await self.__wrapper(self.__instance, *args, **kwargs) + + +@final +class AsyncLRUCacheWrapper(Generic[P, T]): + def __init__( + self, + func: Callable[P, Awaitable[T]], + maxsize: int | None, + typed: bool, + always_checkpoint: bool, + ttl: int | None, + ): + self.__wrapped__ = func + self._hits: int = 0 + self._misses: int = 0 + self._maxsize = max(maxsize, 0) if maxsize is not None else None + self._currsize: int = 0 + self._typed = typed + self._always_checkpoint = always_checkpoint + self._ttl = ttl + update_wrapper(self, func) + + def cache_info(self) -> AsyncCacheInfo: + return AsyncCacheInfo( + self._hits, self._misses, self._maxsize, self._currsize, self._ttl + ) + + def cache_parameters(self) -> AsyncCacheParameters: + return { + "maxsize": self._maxsize, + "typed": self._typed, + "always_checkpoint": self._always_checkpoint, + "ttl": self._ttl, + } + + def cache_clear(self) -> None: + if cache := lru_cache_items.get(None): + cache.pop(self, None) + self._hits = self._misses = self._currsize = 0 + + async def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T: + # Easy case first: if maxsize == 0, no caching is done + if self._maxsize == 0: + value = await self.__wrapped__(*args, **kwargs) + self._misses += 1 + return value + + # The key is constructed as a flat tuple to avoid memory overhead + key: tuple[Any, ...] = args + if kwargs: + # initial_missing is used as a separator + key += (initial_missing,) + sum(kwargs.items(), ()) + + if self._typed: + key += tuple(type(arg) for arg in args) + if kwargs: + key += (initial_missing,) + tuple(type(val) for val in kwargs.values()) + + try: + cache = lru_cache_items.get() + except LookupError: + cache = WeakKeyDictionary() + lru_cache_items.set(cache) + + try: + cache_entry = cache[self] + except KeyError: + cache_entry = cache[self] = OrderedDict() + + cached_value: T | _InitialMissingType + try: + cached_value, lock, expires_at = cache_entry[key] + except KeyError: + # We're the first task to call this function + cached_value, lock, expires_at = ( + initial_missing, + Lock(fast_acquire=not self._always_checkpoint), + None, + ) + cache_entry[key] = cached_value, lock, expires_at + + if lock is None: + if expires_at is not None and current_time() >= expires_at: + self._currsize -= 1 + cached_value, lock, expires_at = ( + initial_missing, + Lock(fast_acquire=not self._always_checkpoint), + None, + ) + cache_entry[key] = cached_value, lock, expires_at + else: + # The value was already cached + self._hits += 1 + cache_entry.move_to_end(key) + if self._always_checkpoint: + await checkpoint() + + return cast(T, cached_value) + + async with lock: + # Check if another task filled the cache while we acquired the lock + if (cached_value := cache_entry[key][0]) is initial_missing: + self._misses += 1 + if self._maxsize is not None and self._currsize >= self._maxsize: + cache_entry.popitem(last=False) + else: + self._currsize += 1 + + value = await self.__wrapped__(*args, **kwargs) + expires_at = ( + current_time() + self._ttl if self._ttl is not None else None + ) + cache_entry[key] = value, None, expires_at + else: + # Another task filled the cache while we were waiting for the lock + self._hits += 1 + cache_entry.move_to_end(key) + value = cast(T, cached_value) + + return value + + def __get__( + self, instance: object, owner: type | None = None + ) -> _LRUMethodWrapper[T]: + wrapper = _LRUMethodWrapper(self, instance) + update_wrapper(wrapper, self.__wrapped__) + return wrapper + + +class _LRUCacheWrapper: + def __init__( + self, maxsize: int | None, typed: bool, always_checkpoint: bool, ttl: int | None + ): + self._maxsize = maxsize + self._typed = typed + self._always_checkpoint = always_checkpoint + self._ttl = ttl + + @overload + def __call__( # type: ignore[overload-overlap] + self, func: Callable[P, Coroutine[Any, Any, T]], / + ) -> AsyncLRUCacheWrapper[P, T]: ... + + @overload + def __call__( + self, func: Callable[..., T], / + ) -> functools._lru_cache_wrapper[T]: ... + + def __call__( + self, f: Callable[P, Coroutine[Any, Any, T]] | Callable[..., T], / + ) -> AsyncLRUCacheWrapper[P, T] | functools._lru_cache_wrapper[T]: + if iscoroutinefunction(f): + return AsyncLRUCacheWrapper( + f, self._maxsize, self._typed, self._always_checkpoint, self._ttl + ) + + return functools.lru_cache(maxsize=self._maxsize, typed=self._typed)(f) # type: ignore[arg-type] + + +@overload +def cache( # type: ignore[overload-overlap] + func: Callable[P, Coroutine[Any, Any, T]], / +) -> AsyncLRUCacheWrapper[P, T]: ... + + +@overload +def cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... + + +def cache(func: Callable[..., Any] | Callable[P, Coroutine[Any, Any, Any]], /) -> Any: + """ + A convenient shortcut for :func:`lru_cache` with ``maxsize=None``. + + This is the asynchronous equivalent to :func:`functools.cache`. + + """ + return lru_cache(maxsize=None)(func) + + +@overload +def lru_cache( + *, + maxsize: int | None = ..., + typed: bool = ..., + always_checkpoint: bool = ..., + ttl: int | None = ..., +) -> _LRUCacheWrapper: ... + + +@overload +def lru_cache( # type: ignore[overload-overlap] + func: Callable[P, Coroutine[Any, Any, T]], / +) -> AsyncLRUCacheWrapper[P, T]: ... + + +@overload +def lru_cache(func: Callable[..., T], /) -> functools._lru_cache_wrapper[T]: ... + + +def lru_cache( + func: Callable[..., Coroutine[Any, Any, Any]] | Callable[..., Any] | None = None, + /, + *, + maxsize: int | None = 128, + typed: bool = False, + always_checkpoint: bool = False, + ttl: int | None = None, +) -> Any: + """ + An asynchronous version of :func:`functools.lru_cache`. + + If a synchronous function is passed, the standard library + :func:`functools.lru_cache` is applied instead. + + :param always_checkpoint: if ``True``, every call to the cached function will be + guaranteed to yield control to the event loop at least once + :param ttl: time in seconds after which to invalidate cache entries + + .. note:: Caches and locks are managed on a per-event loop basis. + + """ + if func is None: + return _LRUCacheWrapper(maxsize, typed, always_checkpoint, ttl) + + if not callable(func): + raise TypeError("the first argument must be callable") + + return _LRUCacheWrapper(maxsize, typed, always_checkpoint, ttl)(func) + + +@overload +async def reduce( + function: Callable[[T, S], Awaitable[T]], + iterable: Iterable[S] | AsyncIterable[S], + /, + initial: T, +) -> T: ... + + +@overload +async def reduce( + function: Callable[[T, T], Awaitable[T]], + iterable: Iterable[T] | AsyncIterable[T], + /, +) -> T: ... + + +async def reduce( # type: ignore[misc] + function: Callable[[T, T], Awaitable[T]] | Callable[[T, S], Awaitable[T]], + iterable: Iterable[T] | Iterable[S] | AsyncIterable[T] | AsyncIterable[S], + /, + initial: T | _InitialMissingType = initial_missing, +) -> T: + """ + Asynchronous version of :func:`functools.reduce`. + + :param function: a coroutine function that takes two arguments: the accumulated + value and the next element from the iterable + :param iterable: an iterable or async iterable + :param initial: the initial value (if missing, the first element of the iterable is + used as the initial value) + + """ + element: Any + function_called = False + if isinstance(iterable, AsyncIterable): + async_it = iterable.__aiter__() + if initial is initial_missing: + try: + value = cast(T, await async_it.__anext__()) + except StopAsyncIteration: + raise TypeError( + "reduce() of empty sequence with no initial value" + ) from None + else: + value = cast(T, initial) + + async for element in async_it: + value = await function(value, element) + function_called = True + elif isinstance(iterable, Iterable): + it = iter(iterable) + if initial is initial_missing: + try: + value = cast(T, next(it)) + except StopIteration: + raise TypeError( + "reduce() of empty sequence with no initial value" + ) from None + else: + value = cast(T, initial) + + for element in it: + value = await function(value, element) + function_called = True + else: + raise TypeError("reduce() argument 2 must be an iterable or async iterable") + + # Make sure there is at least one checkpoint, even if an empty iterable and an + # initial value were given + if not function_called: + await checkpoint() + + return value diff --git a/source/target-vendors/cp312/anyio/itertools.py b/source/target-vendors/cp312/anyio/itertools.py new file mode 100644 index 0000000..2a10cfd --- /dev/null +++ b/source/target-vendors/cp312/anyio/itertools.py @@ -0,0 +1,629 @@ +from __future__ import annotations + +__all__ = ( + "Chain", + "accumulate", + "batched", + "combinations", + "combinations_with_replacement", + "compress", + "count", + "cycle", + "dropwhile", + "filterfalse", + "groupby", + "islice", + "pairwise", + "permutations", + "product", + "repeat", + "starmap", + "takewhile", + "tee", + "zip_longest", +) + +import itertools +import operator +import sys +from collections.abc import ( + AsyncGenerator, + AsyncIterable, + AsyncIterator, + Awaitable, + Callable, + Iterable, + Iterator, +) +from dataclasses import dataclass, field +from typing import Any, Generic, TypeVar, cast, overload + +from ._core._synchronization import Lock +from ._core._tasks import CancelScope +from .lowlevel import cancel_shielded_checkpoint, checkpoint, checkpoint_if_cancelled + +if sys.version_info < (3, 15): + from typing_extensions import sentinel + +T = TypeVar("T") +R = TypeVar("R") +_tee_end = sentinel("_tee_end") + + +@dataclass(eq=False) +class _IterableAsyncIterator(AsyncIterator[T]): + iterator: Iterator[T] + + async def __anext__(self) -> T: + await checkpoint_if_cancelled() + try: + result = next(self.iterator) + except StopIteration: + await cancel_shielded_checkpoint() + raise StopAsyncIteration from None + + await cancel_shielded_checkpoint() + return result + + +def _iterate(iterable: Iterable[T] | AsyncIterable[T]) -> AsyncIterator[T]: + if isinstance(iterable, AsyncIterator): + return iterable + + if isinstance(iterable, AsyncIterable): + return iterable.__aiter__() + + return _IterableAsyncIterator(iter(iterable)) + + +@dataclass(eq=False) +class _TeeLink(Generic[T]): + value: object | None = None + next: _TeeLink[T] | None = None + filled: bool = False + + +@dataclass(eq=False) +class _TeeState(Generic[T]): + iterator: AsyncIterator[T] + lock: Lock = field(default_factory=Lock) + + async def fill(self, link: _TeeLink[T]) -> bool: + if link.filled: + return False + + async with self.lock: + if link.filled: + return True + + link.value = await anext(self.iterator, _tee_end) + if link.value is not _tee_end: + link.next = _TeeLink() + + link.filled = True + return True + + +class _TeeAsyncIterator(AsyncIterator[T]): + _state: _TeeState[T] + _link: _TeeLink[T] + _element_yielded: bool + + def __init__( + self, iterable: Iterable[T] | AsyncIterable[T] | _TeeAsyncIterator[T] + ) -> None: + if isinstance(iterable, _TeeAsyncIterator): + self._state = iterable._state + self._link = iterable._link + else: + self._state = _TeeState(_iterate(iterable)) + self._link = _TeeLink() + + self._element_yielded = False + + async def __anext__(self) -> T: + had_yieldpoint = await self._state.fill(self._link) + if self._link.value is _tee_end: + if not self._element_yielded: + await checkpoint() + + raise StopAsyncIteration + + if not had_yieldpoint: + await checkpoint_if_cancelled() + + self._element_yielded = True + value = cast(T, self._link.value) + next_link = self._link.next + assert next_link is not None + self._link = next_link + if not had_yieldpoint: + await cancel_shielded_checkpoint() + + return value + + +async def _operator_add(x: T, y: T) -> T: + return operator.add(x, y) + + +async def accumulate( + iterable: Iterable[T] | AsyncIterable[T], + function: Callable[[T, T], Awaitable[T]] = _operator_add, + *, + initial: T | None = None, +) -> AsyncGenerator[T, None]: + iterator = _iterate(iterable) + if initial is None: + try: + total = await anext(iterator) + except StopAsyncIteration: + await checkpoint() + return + else: + await checkpoint_if_cancelled() + total = initial + await cancel_shielded_checkpoint() + + yield total + + async for element in iterator: + total = await function(total, element) + yield total + + +async def batched( + iterable: Iterable[T] | AsyncIterable[T], n: int, *, strict: bool = False +) -> AsyncGenerator[tuple[T, ...], None]: + if n < 1: + raise ValueError("n must be at least one") + + iterator = _iterate(iterable) + + while True: + batch: list[T] = [] + for _ in range(n): + try: + batch.append(await anext(iterator)) + except StopAsyncIteration: + if not batch: + await checkpoint() + return + if strict: + raise ValueError("batched(): incomplete batch") from None + + yield tuple(batch) + return + + yield tuple(batch) + + +class Chain: + def __call__( + self, *iterables: Iterable[T] | AsyncIterable[T] + ) -> AsyncGenerator[T, None]: + return self.from_iterable(iterables) + + async def from_iterable( + self, + iterables: ( + Iterable[Iterable[T] | AsyncIterable[T]] + | AsyncIterable[Iterable[T] | AsyncIterable[T]] + ), + ) -> AsyncGenerator[T, None]: + element_yielded = False + outer_iter = _iterate(iterables) + + try: + async for iterable in outer_iter: + async for element in _iterate(iterable): + element_yielded = True + yield element + finally: + aclose = getattr(outer_iter, "aclose", None) + if aclose is not None: + with CancelScope(shield=True): + await aclose() + + if not element_yielded: + await checkpoint() + + +chain: Chain = Chain() + + +async def combinations( + iterable: Iterable[T] | AsyncIterable[T], r: int +) -> AsyncGenerator[tuple[T, ...], None]: + pool: list[T] = [element async for element in _iterate(iterable)] + async for combination in _iterate(itertools.combinations(pool, r)): + yield combination + + +async def combinations_with_replacement( + iterable: Iterable[T] | AsyncIterable[T], r: int +) -> AsyncGenerator[tuple[T, ...], None]: + pool: list[T] = [element async for element in _iterate(iterable)] + async for combination in _iterate(itertools.combinations_with_replacement(pool, r)): + yield combination + + +async def compress( + data: Iterable[T] | AsyncIterable[T], + selectors: Iterable[object] | AsyncIterable[object], +) -> AsyncGenerator[T, None]: + data_iterator = _iterate(data) + selector_iterator = _iterate(selectors) + element_yielded = False + + while True: + try: + datum = await anext(data_iterator) + selector = await anext(selector_iterator) + except StopAsyncIteration: + if not element_yielded: + await checkpoint() + + return + + if selector: + element_yielded = True + yield datum + + +async def count(start: int = 0, step: int = 1) -> AsyncGenerator[int, None]: + n = start + while True: + await checkpoint_if_cancelled() + value = n + n += step + await cancel_shielded_checkpoint() + yield value + + +async def cycle( + iterable: Iterable[T] | AsyncIterable[T], +) -> AsyncGenerator[T, None]: + saved: list[T] = [] + async for element in _iterate(iterable): + saved.append(element) + yield element + + if not saved: + await checkpoint() + return + + while True: + for element in saved: + await checkpoint() + yield element + + +async def dropwhile( + predicate: Callable[[T], Awaitable[object]], + iterable: Iterable[T] | AsyncIterable[T], +) -> AsyncGenerator[T, None]: + element_yielded = False + dropping = True + + async for element in _iterate(iterable): + if dropping and await predicate(element): + continue + + dropping = False + element_yielded = True + yield element + + if not element_yielded: + await checkpoint() + + +async def filterfalse( + predicate: Callable[[T], Awaitable[object]], + iterable: Iterable[T] | AsyncIterable[T], +) -> AsyncGenerator[T, None]: + element_yielded = False + + async for element in _iterate(iterable): + if not await predicate(element): + element_yielded = True + yield element + + if not element_yielded: + await checkpoint() + + +@overload +def groupby( + iterable: Iterable[T] | AsyncIterable[T], +) -> AsyncGenerator[tuple[T, list[T]], None]: ... + + +@overload +def groupby( + iterable: Iterable[T] | AsyncIterable[T], + key: Callable[[T], Awaitable[R]], +) -> AsyncGenerator[tuple[R, list[T]], None]: ... + + +async def groupby( + iterable: Iterable[T] | AsyncIterable[T], + key: Callable[[T], Awaitable[object]] | None = None, +) -> AsyncGenerator[tuple[object, list[T]], None]: + iterator = _iterate(iterable) + try: + element = await anext(iterator) + except StopAsyncIteration: + await checkpoint() + return + + group_key = element if key is None else await key(element) + values = [element] + + async for element in iterator: + next_key = element if key is None else await key(element) + if next_key != group_key: + completed_group = group_key, values + group_key = next_key + values = [element] + yield completed_group + else: + values.append(element) + + yield group_key, values + + +@overload +def islice( + iterable: Iterable[T] | AsyncIterable[T], + stop: int | None, + /, +) -> AsyncGenerator[T, None]: ... + + +@overload +def islice( + iterable: Iterable[T] | AsyncIterable[T], + start: int | None, + stop: int | None, + step: int | None = 1, + /, +) -> AsyncGenerator[T, None]: ... + + +async def islice( + iterable: Iterable[T] | AsyncIterable[T], + *args: int | None, +) -> AsyncGenerator[T, None]: + if not args: + raise TypeError("islice expected at least 2 arguments, got 1") + if len(args) > 3: + raise TypeError(f"islice expected at most 4 arguments, got {len(args) + 1}") + + slice_args = slice(*args) + + start_message = ( + "Indices for islice() must be None or an integer: 0 <= x <= sys.maxsize." + ) + stop_message = ( + "Stop argument for islice() must be None or an integer: 0 <= x <= sys.maxsize." + ) + step_message = "Step for islice() must be a positive integer or None." + + def normalize_index(value: object, message: str) -> int: + try: + index = operator.index(cast(Any, value)) + except TypeError: + raise ValueError(message) from None + + if index < 0 or index > sys.maxsize: + raise ValueError(message) + + return index + + start = ( + 0 + if slice_args.start is None + else normalize_index(slice_args.start, start_message) + ) + stop = ( + None + if slice_args.stop is None + else normalize_index(slice_args.stop, stop_message) + ) + step = ( + 1 if slice_args.step is None else normalize_index(slice_args.step, step_message) + ) + + if step <= 0: + raise ValueError(step_message) + + if stop == 0 or start == stop: + await checkpoint() + return + + iterator = _iterate(iterable) + index = 0 + element_yielded = False + + while stop is None or index < stop: + try: + element = await anext(iterator) + except StopAsyncIteration: + if not element_yielded: + await checkpoint() + + return + + if index >= start and (index - start) % step == 0: + index += 1 + element_yielded = True + yield element + else: + index += 1 + + if not element_yielded: + await checkpoint() + + +async def pairwise( + iterable: Iterable[T] | AsyncIterable[T], +) -> AsyncGenerator[tuple[T, T], None]: + iterator = _iterate(iterable) + try: + previous = await anext(iterator) + except StopAsyncIteration: + await checkpoint() + return + + element_yielded = False + async for element in iterator: + element_yielded = True + pair = (previous, element) + previous = element + yield pair + + if not element_yielded: + await checkpoint() + + +async def permutations( + iterable: Iterable[T] | AsyncIterable[T], r: int | None = None +) -> AsyncGenerator[tuple[T, ...], None]: + pool: list[T] = [element async for element in _iterate(iterable)] + n = len(pool) + if r is None: + r = n + elif not isinstance(r, int): + raise TypeError("Expected int as r") + elif r < 0: + raise ValueError("r must be non-negative") + + async for permutation in _iterate(itertools.permutations(pool, r)): + yield permutation + + +async def product( + *iterables: Iterable[T] | AsyncIterable[T], repeat: int = 1 +) -> AsyncGenerator[tuple[T, ...], None]: + repeat = operator.index(repeat) + if repeat < 0: + raise ValueError("repeat argument cannot be negative") + + pools: list[tuple[T, ...]] = [] + for iterable in iterables: + pool: list[T] = [element async for element in _iterate(iterable)] + pools.append(tuple(pool)) + + async for value in _iterate(itertools.product(*pools, repeat=repeat)): + yield value + + +async def repeat(element: T, times: int | None = None) -> AsyncGenerator[T, None]: + if times is None: + while True: + await checkpoint() + yield element + + remaining = operator.index(cast(Any, times)) + if remaining <= 0: + await checkpoint() + return + + while remaining > 0: + await checkpoint_if_cancelled() + remaining -= 1 + await cancel_shielded_checkpoint() + yield element + + +async def starmap( + function: Callable[..., Awaitable[R]], + iterable: ( + Iterable[Iterable[object] | AsyncIterable[object]] + | AsyncIterable[Iterable[object] | AsyncIterable[object]] + ), +) -> AsyncGenerator[R, None]: + result_yielded = False + + async for args_iterable in _iterate(iterable): + args = [element async for element in _iterate(args_iterable)] + result_yielded = True + yield await function(*args) + + if not result_yielded: + await checkpoint() + + +def tee( + iterable: Iterable[T] | AsyncIterable[T], n: int = 2 +) -> tuple[AsyncIterator[T], ...]: + n = operator.index(cast(Any, n)) + if n < 0: + raise ValueError("n must be >= 0") + if n == 0: + return () + + iterator = _TeeAsyncIterator(iterable) + iterators: list[AsyncIterator[T]] = [iterator] + iterators.extend(_TeeAsyncIterator(iterator) for _ in range(n - 1)) + return tuple(iterators) + + +async def takewhile( + predicate: Callable[[T], Awaitable[object]], + iterable: Iterable[T] | AsyncIterable[T], +) -> AsyncGenerator[T, None]: + element_yielded = False + + async for element in _iterate(iterable): + if not await predicate(element): + if not element_yielded: + await checkpoint() + + return + + element_yielded = True + yield element + + if not element_yielded: + await checkpoint() + + +async def zip_longest( + *iterables: Iterable[object] | AsyncIterable[object], + fillvalue: object = None, +) -> AsyncGenerator[tuple[object, ...], None]: + iterators = [_iterate(iterable) for iterable in iterables] + num_active = len(iterators) + if not num_active: + await checkpoint() + return + + active = [True] * num_active + tuple_yielded = False + + while True: + values: list[object] = [] + for index, iterator in enumerate(iterators): + if not active[index]: + values.append(fillvalue) + continue + + try: + value = await anext(iterator) + except StopAsyncIteration: + active[index] = False + num_active -= 1 + if not num_active: + if not tuple_yielded: + await checkpoint() + + return + + value = fillvalue + + values.append(value) + + tuple_yielded = True + yield tuple(values) diff --git a/source/target-vendors/cp312/anyio/lowlevel.py b/source/target-vendors/cp312/anyio/lowlevel.py new file mode 100644 index 0000000..361b2eb --- /dev/null +++ b/source/target-vendors/cp312/anyio/lowlevel.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +__all__ = ( + "EventLoopToken", + "RunVar", + "RunvarToken", + "cancel_shielded_checkpoint", + "checkpoint", + "checkpoint_if_cancelled", + "current_token", +) + +import enum +from dataclasses import dataclass +from types import TracebackType +from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar, final, overload +from weakref import WeakKeyDictionary + +from ._core._eventloop import get_async_backend + +if TYPE_CHECKING: + from .abc import AsyncBackend + +T = TypeVar("T") +D = TypeVar("D") + + +async def checkpoint() -> None: + """ + Check for cancellation and allow the scheduler to switch to another task. + + Equivalent to (but more efficient than):: + + await checkpoint_if_cancelled() + await cancel_shielded_checkpoint() + + .. versionadded:: 3.0 + + """ + await get_async_backend().checkpoint() + + +async def checkpoint_if_cancelled() -> None: + """ + Enter a checkpoint if the enclosing cancel scope has been cancelled. + + This does not allow the scheduler to switch to a different task. + + .. versionadded:: 3.0 + + """ + await get_async_backend().checkpoint_if_cancelled() + + +async def cancel_shielded_checkpoint() -> None: + """ + Allow the scheduler to switch to another task but without checking for cancellation. + + Equivalent to (but potentially more efficient than):: + + with CancelScope(shield=True): + await checkpoint() + + .. versionadded:: 3.0 + + """ + await get_async_backend().cancel_shielded_checkpoint() + + +@final +@dataclass(frozen=True, repr=False) +class EventLoopToken: + """ + An opaque object that holds a reference to an event loop. + + .. versionadded:: 4.11.0 + """ + + backend_class: type[AsyncBackend] + native_token: object + + +def current_token() -> EventLoopToken: + """ + Return a token object that can be used to call code in the current event loop from + another thread. + + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + .. versionadded:: 4.11.0 + + """ + backend_class = get_async_backend() + raw_token = backend_class.current_token() + return EventLoopToken(backend_class, raw_token) + + +_run_vars: WeakKeyDictionary[object, dict[RunVar[Any], Any]] = WeakKeyDictionary() + + +class _NoValueSet(enum.Enum): + NO_VALUE_SET = enum.auto() + + +class RunvarToken(Generic[T]): + """ + A token that can be used to restore a :class:`RunVar` to its previous value. + + Returned by :meth:`RunVar.set`. Can be used as a context manager to automatically + reset the variable on exit, or passed directly to :meth:`RunVar.reset`. + """ + + __slots__ = "_redeemed", "_value", "_var" + + def __init__(self, var: RunVar[T], value: T | Literal[_NoValueSet.NO_VALUE_SET]): + self._var = var + self._value: T | Literal[_NoValueSet.NO_VALUE_SET] = value + self._redeemed = False + + def __enter__(self) -> RunvarToken[T]: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self._var.reset(self) + + +class RunVar(Generic[T]): + """ + Like a :class:`~contextvars.ContextVar`, except scoped to the running event loop. + + Can be used as a context manager, Just like :class:`~contextvars.ContextVar`, that + will reset the variable to its previous value when the context block is exited. + """ + + __slots__ = "_default", "_name" + + NO_VALUE_SET: Literal[_NoValueSet.NO_VALUE_SET] = _NoValueSet.NO_VALUE_SET + + def __init__( + self, name: str, default: T | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET + ): + self._name = name + self._default = default + + @property + def _current_vars(self) -> dict[RunVar[T], T]: + native_token = current_token().native_token + try: + return _run_vars[native_token] + except KeyError: + run_vars = _run_vars[native_token] = {} + return run_vars + + @overload + def get(self, default: D) -> T | D: ... + + @overload + def get(self) -> T: ... + + def get( + self, default: D | Literal[_NoValueSet.NO_VALUE_SET] = NO_VALUE_SET + ) -> T | D: + """ + Return the current value of this run variable. + + :param default: a fallback value to return if no value has been set + :return: the current value, the provided default, or the variable's own default + :raises LookupError: if no value is set and no default is available + + """ + try: + return self._current_vars[self] + except KeyError: + if default is not RunVar.NO_VALUE_SET: + return default + elif self._default is not RunVar.NO_VALUE_SET: + return self._default + + raise LookupError( + f'Run variable "{self._name}" has no value and no default set' + ) + + def set(self, value: T) -> RunvarToken[T]: + """ + Set the value of this run variable for the current event loop. + + :param value: the new value + :return: a token that can be used to restore the previous value + + """ + current_vars = self._current_vars + token = RunvarToken(self, current_vars.get(self, RunVar.NO_VALUE_SET)) + current_vars[self] = value + return token + + def reset(self, token: RunvarToken[T]) -> None: + """ + Restore this run variable to the value it held before the matching :meth:`set`. + + :param token: the token returned by :meth:`set` + :raises ValueError: if the token belongs to a different :class:`RunVar` or the token + has already been used + + """ + if token._var is not self: + raise ValueError("This token does not belong to this RunVar") + + if token._redeemed: + raise ValueError("This token has already been used") + + if token._value is _NoValueSet.NO_VALUE_SET: + try: + del self._current_vars[self] + except KeyError: + pass + else: + self._current_vars[self] = token._value + + token._redeemed = True + + def __repr__(self) -> str: + return f"" diff --git a/source/target-vendors/cp312/anyio/py.typed b/source/target-vendors/cp312/anyio/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/anyio/pytest_plugin.py b/source/target-vendors/cp312/anyio/pytest_plugin.py new file mode 100644 index 0000000..d6238cd --- /dev/null +++ b/source/target-vendors/cp312/anyio/pytest_plugin.py @@ -0,0 +1,404 @@ +from __future__ import annotations + +import dataclasses +import socket +import sys +from collections.abc import Callable, Generator, Iterator +from contextlib import ExitStack, contextmanager +from inspect import isasyncgenfunction, iscoroutinefunction, ismethod +from typing import TYPE_CHECKING, Any, cast + +import pytest +from _pytest.fixtures import FuncFixtureInfo, SubRequest +from _pytest.outcomes import Exit +from _pytest.scope import Scope + +from . import get_available_backends +from ._core._eventloop import ( + current_async_library, + get_async_backend, + reset_current_async_library, + set_current_async_library, +) +from ._core._exceptions import iterate_exceptions + +if TYPE_CHECKING: + from .abc import TestRunner + +if sys.version_info < (3, 11): + from exceptiongroup import ExceptionGroup + +if TYPE_CHECKING: + # pytest >= 9.2 keeps CallSpec2 as a TYPE_CHECKING-only alias of CallSpec + from _pytest.python import CallSpec2 as CallSpec +else: + try: + # c.f. https://github.com/pytest-dev/pytest/pull/14742 + # pytest >= 9.2 + from _pytest.python import CallSpec + except ImportError: + from _pytest.python import CallSpec2 as CallSpec + +_current_runner: TestRunner | None = None +_runner_stack: ExitStack | None = None +_runner_leases = 0 + + +def extract_backend_and_options(backend: object) -> tuple[str, dict[str, Any]]: + if isinstance(backend, str): + return backend, {} + elif isinstance(backend, tuple) and len(backend) == 2: + if isinstance(backend[0], str) and isinstance(backend[1], dict): + return cast(tuple[str, dict[str, Any]], backend) + + raise TypeError("anyio_backend must be either a string or tuple of (string, dict)") + + +@contextmanager +def get_runner( + backend_name: str, backend_options: dict[str, Any] +) -> Iterator[TestRunner]: + global _current_runner, _runner_leases, _runner_stack + if _current_runner is None: + asynclib = get_async_backend(backend_name) + _runner_stack = ExitStack() + if current_async_library() is None: + # Since we're in control of the event loop, we can cache the name of the + # async library + token = set_current_async_library(backend_name) + _runner_stack.callback(reset_current_async_library, token) + + backend_options = backend_options or {} + _current_runner = _runner_stack.enter_context( + asynclib.create_test_runner(backend_options) + ) + + _runner_leases += 1 + try: + yield _current_runner + finally: + _runner_leases -= 1 + if not _runner_leases: + assert _runner_stack is not None + _runner_stack.close() + _runner_stack = _current_runner = None + + +def pytest_addoption(parser: pytest.Parser) -> None: + group = parser.getgroup("anyio") + parser.addini( + "anyio_mode", + default="strict", + help='AnyIO plugin mode (either "strict" or "auto")', + ) + group.addoption( + "--anyio-mode", + default=None, + dest="anyio_mode", + help=""" + 'auto' - All async test functions will be handled by AnyIO pytest plugin + 'strict' - Disabling autoprocessing(useful when anyio tests + need to coexist with other async test plugins) + """, + ) + + +def _is_auto_mode(config: pytest.Config, mode: str) -> bool: + return ( + config.getoption(mode, default=None) == "auto" or config.getini(mode) == "auto" + ) + + +def pytest_configure(config: pytest.Config) -> None: + config.addinivalue_line( + "markers", + "anyio: mark the (coroutine function) test to be run asynchronously via anyio.", + ) + if ( + _is_auto_mode(config, "anyio_mode") + and config.pluginmanager.has_plugin("asyncio") + and _is_auto_mode(config, "asyncio_mode") + ): + config.issue_config_time_warning( + pytest.PytestConfigWarning( + "AnyIO auto mode has been enabled together with pytest-asyncio auto " + "mode. This may cause unexpected behavior." + ), + 1, + ) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_fixture_setup(fixturedef: Any, request: Any) -> Generator[Any]: + def wrapper(anyio_backend: Any, request: SubRequest, **kwargs: Any) -> Any: + # Rebind any fixture methods to the request instance + if ( + request.instance + and ismethod(func) + and type(func.__self__) is type(request.instance) + ): + local_func = func.__func__.__get__(request.instance) + else: + local_func = func + + backend_name, backend_options = extract_backend_and_options(anyio_backend) + if has_backend_arg: + kwargs["anyio_backend"] = anyio_backend + + if has_request_arg: + kwargs["request"] = request + + with get_runner(backend_name, backend_options) as runner: + # re-entrant call into the test runner detected. this happens when an async fixture + # is dynamically requested via request.getfixturevalue() from inside a running async + # test or fixture. on asyncio this raises RuntimeError: This event loop is already + # running, on trio the runner deadlocks - the host loop blocks waiting for the + # coroutine to return, but the coroutine is waiting for the host loop. raising here + # prevents the hang and gives a consistent error across backends. + if runner.is_running(): + raise RuntimeError( + "Cannot schedule a coroutine in the test runner while another is already running; " + "likely caused by request.getfixturevalue() on an async fixture." + ) + + if isasyncgenfunction(local_func): + yield from runner.run_asyncgen_fixture(local_func, kwargs) + else: + yield runner.run_fixture(local_func, kwargs) + + # Only apply this to coroutine functions and async generator functions in requests + # that involve the anyio_backend fixture + func = fixturedef.func + if isasyncgenfunction(func) or iscoroutinefunction(func): + if "anyio_backend" in request.fixturenames: + fixturedef.func = wrapper + original_argname = fixturedef.argnames + + if not (has_backend_arg := "anyio_backend" in fixturedef.argnames): + fixturedef.argnames += ("anyio_backend",) + + if not (has_request_arg := "request" in fixturedef.argnames): + fixturedef.argnames += ("request",) + + try: + return (yield) + finally: + fixturedef.func = func + fixturedef.argnames = original_argname + + return (yield) + + +@pytest.hookimpl(tryfirst=True) +def pytest_pycollect_makeitem( + collector: pytest.Module | pytest.Class, name: str, obj: object +) -> None: + if collector.istestfunction(obj, name): + inner_func = obj.hypothesis.inner_test if hasattr(obj, "hypothesis") else obj + if iscoroutinefunction(inner_func): + anyio_auto_mode = _is_auto_mode(collector.config, "anyio_mode") + marker = collector.get_closest_marker("anyio") + own_markers = getattr(obj, "pytestmark", ()) + if ( + anyio_auto_mode + or marker + or any(marker.name == "anyio" for marker in own_markers) + ): + pytest.mark.usefixtures("anyio_backend")(obj) + + +def pytest_collection_finish(session: pytest.Session) -> None: + for i, item in reversed(list(enumerate(session.items))): + if ( + isinstance(item, pytest.Function) + and iscoroutinefunction(item.function) + and item.get_closest_marker("anyio") is not None + and "anyio_backend" not in item.fixturenames + ): + new_items = [] + try: + cs_fields = {f.name for f in dataclasses.fields(CallSpec)} + except TypeError: + cs_fields = set() + + for param_index, backend in enumerate(get_available_backends()): + if "_arg2scope" in cs_fields: # pytest >= 8 + callspec = CallSpec( + params={"anyio_backend": backend}, + indices={"anyio_backend": param_index}, + _arg2scope={"anyio_backend": Scope.Module}, + _idlist=[backend], + marks=[], + ) + else: # pytest 7.x + callspec = CallSpec( # type: ignore[call-arg] + funcargs={}, + params={"anyio_backend": backend}, + indices={"anyio_backend": param_index}, + arg2scope={"anyio_backend": Scope.Module}, + idlist=[backend], + marks=[], + ) + + fi = item._fixtureinfo + new_names_closure = list(fi.names_closure) + if "anyio_backend" not in new_names_closure: + new_names_closure.append("anyio_backend") + + new_fixtureinfo = FuncFixtureInfo( + argnames=fi.argnames, + initialnames=fi.initialnames, + names_closure=new_names_closure, + name2fixturedefs=fi.name2fixturedefs, + ) + new_item = pytest.Function.from_parent( + item.parent, + name=f"{item.originalname}[{backend}]", + callspec=callspec, + callobj=item.obj, + fixtureinfo=new_fixtureinfo, + keywords=item.keywords, + originalname=item.originalname, + ) + new_items.append(new_item) + + session.items[i : i + 1] = new_items + + +@pytest.hookimpl(tryfirst=True) +def pytest_pyfunc_call(pyfuncitem: Any) -> bool | None: + def run_with_hypothesis(**kwargs: Any) -> None: + with get_runner(backend_name, backend_options) as runner: + runner.run_test(original_func, kwargs) + + backend = pyfuncitem.funcargs.get("anyio_backend") + if backend: + backend_name, backend_options = extract_backend_and_options(backend) + + if hasattr(pyfuncitem.obj, "hypothesis"): + # Wrap the inner test function unless it's already wrapped + original_func = pyfuncitem.obj.hypothesis.inner_test + if original_func.__qualname__ != run_with_hypothesis.__qualname__: + if iscoroutinefunction(original_func): + pyfuncitem.obj.hypothesis.inner_test = run_with_hypothesis + + return None + + if iscoroutinefunction(pyfuncitem.obj): + funcargs = pyfuncitem.funcargs + testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} + with get_runner(backend_name, backend_options) as runner: + try: + runner.run_test(pyfuncitem.obj, testargs) + except ExceptionGroup as excgrp: + for exc in iterate_exceptions(excgrp): + if isinstance(exc, (Exit, KeyboardInterrupt, SystemExit)): + raise exc from excgrp + + raise + + return True + + return None + + +@pytest.fixture(scope="module", params=get_available_backends()) +def anyio_backend(request: Any) -> Any: + return request.param + + +@pytest.fixture +def anyio_backend_name(anyio_backend: Any) -> str: + if isinstance(anyio_backend, str): + return anyio_backend + else: + return anyio_backend[0] + + +@pytest.fixture +def anyio_backend_options(anyio_backend: Any) -> dict[str, Any]: + if isinstance(anyio_backend, str): + return {} + else: + return anyio_backend[1] + + +class FreePortFactory: + """ + Manages port generation based on specified socket kind, ensuring no duplicate + ports are generated. + + This class provides functionality for generating available free ports on the + system. It is initialized with a specific socket kind and can generate ports + for given address families while avoiding reuse of previously generated ports. + + Users should not instantiate this class directly, but use the + ``free_tcp_port_factory`` and ``free_udp_port_factory`` fixtures instead. For simple + uses cases, ``free_tcp_port`` and ``free_udp_port`` can be used instead. + """ + + def __init__(self, kind: socket.SocketKind) -> None: + self._kind = kind + self._generated = set[int]() + + @property + def kind(self) -> socket.SocketKind: + """ + The type of socket connection (e.g., :data:`~socket.SOCK_STREAM` or + :data:`~socket.SOCK_DGRAM`) used to bind for checking port availability + + """ + return self._kind + + def __call__(self, family: socket.AddressFamily | None = None) -> int: + """ + Return an unbound port for the given address family. + + :param family: if omitted, both IPv4 and IPv6 addresses will be tried + :return: a port number + + """ + if family is not None: + families = [family] + else: + families = [socket.AF_INET] + if socket.has_ipv6: + families.append(socket.AF_INET6) + + while True: + port = 0 + with ExitStack() as stack: + for fam in families: + sock = stack.enter_context(socket.socket(fam, self._kind)) + addr = "::1" if fam == socket.AF_INET6 else "127.0.0.1" + try: + sock.bind((addr, port)) + except OSError: + break + + if not port: + port = sock.getsockname()[1] + else: + if port not in self._generated: + self._generated.add(port) + return port + + +@pytest.fixture(scope="session") +def free_tcp_port_factory() -> FreePortFactory: + return FreePortFactory(socket.SOCK_STREAM) + + +@pytest.fixture(scope="session") +def free_udp_port_factory() -> FreePortFactory: + return FreePortFactory(socket.SOCK_DGRAM) + + +@pytest.fixture +def free_tcp_port(free_tcp_port_factory: Callable[[], int]) -> int: + return free_tcp_port_factory() + + +@pytest.fixture +def free_udp_port(free_udp_port_factory: Callable[[], int]) -> int: + return free_udp_port_factory() diff --git a/source/target-vendors/cp312/anyio/streams/__init__.py b/source/target-vendors/cp312/anyio/streams/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/anyio/streams/buffered.py b/source/target-vendors/cp312/anyio/streams/buffered.py new file mode 100644 index 0000000..a3b07f7 --- /dev/null +++ b/source/target-vendors/cp312/anyio/streams/buffered.py @@ -0,0 +1,201 @@ +from __future__ import annotations + +__all__ = ( + "BufferedByteReceiveStream", + "BufferedByteStream", + "BufferedConnectable", +) + +import sys +from collections.abc import Callable, Iterable, Mapping +from dataclasses import dataclass, field +from typing import Any, SupportsIndex + +from .. import ClosedResourceError, DelimiterNotFound, EndOfStream, IncompleteRead +from ..abc import ( + AnyByteReceiveStream, + AnyByteStream, + AnyByteStreamConnectable, + ByteReceiveStream, + ByteStream, + ByteStreamConnectable, +) + +if sys.version_info >= (3, 12): + from typing import override +else: + from typing_extensions import override + + +@dataclass(eq=False) +class BufferedByteReceiveStream(ByteReceiveStream): + """ + Wraps any bytes-based receive stream and uses a buffer to provide sophisticated + receiving capabilities in the form of a byte stream. + """ + + receive_stream: AnyByteReceiveStream + _buffer: bytearray = field(init=False, default_factory=bytearray) + _closed: bool = field(init=False, default=False) + + async def aclose(self) -> None: + await self.receive_stream.aclose() + self._closed = True + + @property + def buffer(self) -> bytes: + """The bytes currently in the buffer.""" + return bytes(self._buffer) + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return self.receive_stream.extra_attributes + + def feed_data(self, data: Iterable[SupportsIndex], /) -> None: + """ + Append data directly into the buffer. + + Any data in the buffer will be consumed by receive operations before receiving + anything from the wrapped stream. + + :param data: the data to append to the buffer (can be bytes or anything else + that supports ``__index__()``) + + """ + self._buffer.extend(data) + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + if self._closed: + raise ClosedResourceError + + if self._buffer: + chunk = bytes(self._buffer[:max_bytes]) + del self._buffer[:max_bytes] + return chunk + elif isinstance(self.receive_stream, ByteReceiveStream): + return await self.receive_stream.receive(max_bytes) + else: + # With a bytes-oriented object stream, we need to handle any surplus bytes + # we get from the receive() call + chunk = await self.receive_stream.receive() + if len(chunk) > max_bytes: + # Save the surplus bytes in the buffer + self._buffer.extend(chunk[max_bytes:]) + return chunk[:max_bytes] + else: + return chunk + + async def receive_exactly(self, nbytes: int) -> bytes: + """ + Read exactly the given amount of bytes from the stream. + + :param nbytes: the number of bytes to read + :return: the bytes read + :raises ~anyio.IncompleteRead: if the stream was closed before the requested + amount of bytes could be read from the stream + + """ + while True: + remaining = nbytes - len(self._buffer) + if remaining <= 0: + retval = self._buffer[:nbytes] + del self._buffer[:nbytes] + return bytes(retval) + + try: + if isinstance(self.receive_stream, ByteReceiveStream): + chunk = await self.receive_stream.receive(remaining) + else: + chunk = await self.receive_stream.receive() + except EndOfStream as exc: + raise IncompleteRead from exc + + self._buffer.extend(chunk) + + async def receive_until(self, delimiter: bytes, max_bytes: int) -> bytes: + """ + Read from the stream until the delimiter is found or max_bytes have been read. + + :param delimiter: the marker to look for in the stream + :param max_bytes: maximum number of bytes that will be read before raising + :exc:`~anyio.DelimiterNotFound` + :return: the bytes read (not including the delimiter) + :raises ~anyio.IncompleteRead: if the stream was closed before the delimiter + was found + :raises ~anyio.DelimiterNotFound: if the delimiter is not found within the + bytes read up to the maximum allowed + + """ + delimiter_size = len(delimiter) + offset = 0 + while True: + # Check if the delimiter can be found in the current buffer + index = self._buffer.find(delimiter, offset) + if index >= 0: + found = self._buffer[:index] + del self._buffer[: index + len(delimiter) :] + return bytes(found) + + # Check if the buffer is already at or over the limit + if len(self._buffer) >= max_bytes: + raise DelimiterNotFound(max_bytes) + + # Read more data into the buffer from the socket + try: + data = await self.receive_stream.receive() + except EndOfStream as exc: + raise IncompleteRead from exc + + # Move the offset forward and add the new data to the buffer + offset = max(len(self._buffer) - delimiter_size + 1, 0) + self._buffer.extend(data) + + +class BufferedByteStream(BufferedByteReceiveStream, ByteStream): + """ + A full-duplex variant of :class:`BufferedByteReceiveStream`. All writes are passed + through to the wrapped stream as-is. + """ + + def __init__(self, stream: AnyByteStream): + """ + :param stream: the stream to be wrapped + + """ + super().__init__(stream) + self._stream = stream + + @override + async def send_eof(self) -> None: + await self._stream.send_eof() + + @override + async def send(self, item: bytes) -> None: + await self._stream.send(item) + + +class BufferedConnectable(ByteStreamConnectable): + """ + Wraps a byte stream connectable to produce :class:`BufferedByteStream` connections. + + Use this when you want the streams returned by :meth:`connect` to have the buffered + receive API (e.g. :meth:`~BufferedByteReceiveStream.receive_exactly` and + :meth:`~BufferedByteReceiveStream.receive_until`). + + :param connectable: the byte stream connectable to wrap + """ + + def __init__(self, connectable: AnyByteStreamConnectable): + """ + :param connectable: the connectable to wrap + + """ + self.connectable = connectable + + @override + async def connect(self) -> BufferedByteStream: + stream = await self.connectable.connect() + return BufferedByteStream(stream) diff --git a/source/target-vendors/cp312/anyio/streams/file.py b/source/target-vendors/cp312/anyio/streams/file.py new file mode 100644 index 0000000..b9d7ca4 --- /dev/null +++ b/source/target-vendors/cp312/anyio/streams/file.py @@ -0,0 +1,157 @@ +from __future__ import annotations + +__all__ = ( + "FileReadStream", + "FileStreamAttribute", + "FileWriteStream", +) + +from collections.abc import Callable, Mapping +from io import SEEK_SET, UnsupportedOperation +from os import PathLike +from pathlib import Path +from typing import IO, Any + +from .. import ( + BrokenResourceError, + ClosedResourceError, + EndOfStream, + TypedAttributeSet, + to_thread, + typed_attribute, +) +from ..abc import ByteReceiveStream, ByteSendStream + + +class FileStreamAttribute(TypedAttributeSet): + #: the open file descriptor + file: IO[bytes] = typed_attribute() + #: the path of the file on the file system, if available (file must be a real file) + path: Path = typed_attribute() + #: the file number, if available (file must be a real file or a TTY) + fileno: int = typed_attribute() + + +class _BaseFileStream: + def __init__(self, file: IO[bytes]): + self._file = file + + async def aclose(self) -> None: + await to_thread.run_sync(self._file.close) + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + attributes: dict[Any, Callable[[], Any]] = { + FileStreamAttribute.file: lambda: self._file, + } + + if hasattr(self._file, "name"): + attributes[FileStreamAttribute.path] = lambda: Path(self._file.name) + + try: + self._file.fileno() + except UnsupportedOperation: + pass + else: + attributes[FileStreamAttribute.fileno] = lambda: self._file.fileno() + + return attributes + + +class FileReadStream(_BaseFileStream, ByteReceiveStream): + """ + A byte stream that reads from a file in the file system. + + :param file: a file that has been opened for reading in binary mode + + .. versionadded:: 3.0 + """ + + @classmethod + async def from_path(cls, path: str | PathLike[str]) -> FileReadStream: + """ + Create a file read stream by opening the given file. + + :param path: path of the file to read from + + """ + file = await to_thread.run_sync(Path(path).open, "rb") + return cls(file) + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + try: + data = await to_thread.run_sync(self._file.read, max_bytes) + except ValueError: + raise ClosedResourceError from None + except OSError as exc: + raise BrokenResourceError from exc + + if data: + return data + else: + raise EndOfStream + + async def seek(self, position: int, whence: int = SEEK_SET) -> int: + """ + Seek the file to the given position. + + .. seealso:: :meth:`io.IOBase.seek` + + .. note:: Not all file descriptors are seekable. + + :param position: position to seek the file to + :param whence: controls how ``position`` is interpreted + :return: the new absolute position + :raises OSError: if the file is not seekable + + """ + return await to_thread.run_sync(self._file.seek, position, whence) + + async def tell(self) -> int: + """ + Return the current stream position. + + .. note:: Not all file descriptors are seekable. + + :return: the current absolute position + :raises OSError: if the file is not seekable + + """ + return await to_thread.run_sync(self._file.tell) + + +class FileWriteStream(_BaseFileStream, ByteSendStream): + """ + A byte stream that writes to a file in the file system. + + :param file: a file that has been opened for writing in binary mode + + .. versionadded:: 3.0 + """ + + @classmethod + async def from_path( + cls, path: str | PathLike[str], append: bool = False + ) -> FileWriteStream: + """ + Create a file write stream by opening the given file for writing. + + :param path: path of the file to write to + :param append: if ``True``, open the file for appending; if ``False``, any + existing file at the given path will be truncated + + """ + mode = "ab" if append else "wb" + file = await to_thread.run_sync(Path(path).open, mode) + return cls(file) + + async def send(self, item: bytes) -> None: + try: + await to_thread.run_sync(self._file.write, item) + except ValueError: + raise ClosedResourceError from None + except OSError as exc: + raise BrokenResourceError from exc diff --git a/source/target-vendors/cp312/anyio/streams/memory.py b/source/target-vendors/cp312/anyio/streams/memory.py new file mode 100644 index 0000000..329a75e --- /dev/null +++ b/source/target-vendors/cp312/anyio/streams/memory.py @@ -0,0 +1,326 @@ +from __future__ import annotations + +__all__ = ( + "MemoryObjectReceiveStream", + "MemoryObjectSendStream", + "MemoryObjectStreamStatistics", +) + +import warnings +from collections import OrderedDict, deque +from dataclasses import dataclass, field +from types import TracebackType +from typing import Generic, NamedTuple, TypeVar + +from .._core._exceptions import ( + BrokenResourceError, + ClosedResourceError, + EndOfStream, + WouldBlock, +) +from .._core._synchronization import Event +from .._core._testing import TaskInfo, get_current_task +from ..abc import ObjectReceiveStream, ObjectSendStream +from ..lowlevel import checkpoint + +T_Item = TypeVar("T_Item") +T_co = TypeVar("T_co", covariant=True) +T_contra = TypeVar("T_contra", contravariant=True) + + +class MemoryObjectStreamStatistics(NamedTuple): + current_buffer_used: int #: number of items stored in the buffer + #: maximum number of items that can be stored on this stream (or :data:`math.inf`) + max_buffer_size: float + open_send_streams: int #: number of unclosed clones of the send stream + open_receive_streams: int #: number of unclosed clones of the receive stream + #: number of tasks blocked on :meth:`MemoryObjectSendStream.send` + tasks_waiting_send: int + #: number of tasks blocked on :meth:`MemoryObjectReceiveStream.receive` + tasks_waiting_receive: int + + +@dataclass(eq=False) +class _MemoryObjectItemReceiver(Generic[T_Item]): + task_info: TaskInfo = field(init=False, default_factory=get_current_task) + item: T_Item = field(init=False) + + def __repr__(self) -> str: + # When item is not defined, we get following error with default __repr__: + # AttributeError: 'MemoryObjectItemReceiver' object has no attribute 'item' + item = getattr(self, "item", None) + return f"{self.__class__.__name__}(task_info={self.task_info}, item={item!r})" + + +@dataclass(eq=False) +class _MemoryObjectStreamState(Generic[T_Item]): + max_buffer_size: float = field() + buffer: deque[T_Item] = field(init=False, default_factory=deque) + open_send_channels: int = field(init=False, default=0) + open_receive_channels: int = field(init=False, default=0) + waiting_receivers: OrderedDict[Event, _MemoryObjectItemReceiver[T_Item]] = field( + init=False, default_factory=OrderedDict + ) + waiting_senders: OrderedDict[Event, T_Item] = field( + init=False, default_factory=OrderedDict + ) + + def statistics(self) -> MemoryObjectStreamStatistics: + return MemoryObjectStreamStatistics( + len(self.buffer), + self.max_buffer_size, + self.open_send_channels, + self.open_receive_channels, + len(self.waiting_senders), + len(self.waiting_receivers), + ) + + +@dataclass(eq=False) +class MemoryObjectReceiveStream(ObjectReceiveStream[T_co], Generic[T_co]): + _state: _MemoryObjectStreamState[T_co] + _closed: bool = field(init=False, default=False) + + def __post_init__(self) -> None: + self._state.open_receive_channels += 1 + + def receive_nowait(self) -> T_co: + """ + Receive the next item if it can be done without waiting. + + :return: the received item + :raises ~anyio.ClosedResourceError: if this send stream has been closed + :raises ~anyio.EndOfStream: if the buffer is empty and this stream has been + closed from the sending end + :raises ~anyio.WouldBlock: if there are no items in the buffer and no tasks + waiting to send + + """ + if self._closed: + raise ClosedResourceError + + if self._state.waiting_senders: + # Get the item from the next sender + send_event, item = self._state.waiting_senders.popitem(last=False) + self._state.buffer.append(item) + send_event.set() + + if self._state.buffer: + return self._state.buffer.popleft() + elif not self._state.open_send_channels: + raise EndOfStream + + raise WouldBlock + + async def receive(self) -> T_co: + await checkpoint() + try: + return self.receive_nowait() + except WouldBlock: + # Add ourselves in the queue + receive_event = Event() + receiver = _MemoryObjectItemReceiver[T_co]() + self._state.waiting_receivers[receive_event] = receiver + + try: + await receive_event.wait() + finally: + self._state.waiting_receivers.pop(receive_event, None) + + try: + return receiver.item + except AttributeError: + raise EndOfStream from None + + def clone(self) -> MemoryObjectReceiveStream[T_co]: + """ + Create a clone of this receive stream. + + Each clone can be closed separately. Only when all clones have been closed will + the receiving end of the memory stream be considered closed by the sending ends. + + :return: the cloned stream + + """ + if self._closed: + raise ClosedResourceError + + return MemoryObjectReceiveStream(_state=self._state) + + def close(self) -> None: + """ + Close the stream. + + This works the exact same way as :meth:`aclose`, but is provided as a special + case for the benefit of synchronous callbacks. + + """ + if not self._closed: + self._closed = True + self._state.open_receive_channels -= 1 + if self._state.open_receive_channels == 0: + send_events = list(self._state.waiting_senders.keys()) + for event in send_events: + event.set() + + async def aclose(self) -> None: + self.close() + + def statistics(self) -> MemoryObjectStreamStatistics: + """ + Return statistics about the current state of this stream. + + .. versionadded:: 3.0 + """ + return self._state.statistics() + + def __enter__(self) -> MemoryObjectReceiveStream[T_co]: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def __del__(self) -> None: + if not self._closed: + warnings.warn( + f"Unclosed <{self.__class__.__name__} at {id(self):x}>", + ResourceWarning, + stacklevel=1, + source=self, + ) + + +@dataclass(eq=False) +class MemoryObjectSendStream(ObjectSendStream[T_contra], Generic[T_contra]): + _state: _MemoryObjectStreamState[T_contra] + _closed: bool = field(init=False, default=False) + + def __post_init__(self) -> None: + self._state.open_send_channels += 1 + + def send_nowait(self, item: T_contra) -> None: + """ + Send an item immediately if it can be done without waiting. + + :param item: the item to send + :raises ~anyio.ClosedResourceError: if this send stream has been closed + :raises ~anyio.BrokenResourceError: if the stream has been closed from the + receiving end + :raises ~anyio.WouldBlock: if the buffer is full and there are no tasks waiting + to receive + + """ + if self._closed: + raise ClosedResourceError + if not self._state.open_receive_channels: + raise BrokenResourceError + + while self._state.waiting_receivers: + receive_event, receiver = self._state.waiting_receivers.popitem(last=False) + if not receiver.task_info.has_pending_cancellation(): + receiver.item = item + receive_event.set() + return + + if len(self._state.buffer) < self._state.max_buffer_size: + self._state.buffer.append(item) + else: + raise WouldBlock + + async def send(self, item: T_contra) -> None: + """ + Send an item to the stream. + + If the buffer is full, this method blocks until there is again room in the + buffer or the item can be sent directly to a receiver. + + :param item: the item to send + :raises ~anyio.ClosedResourceError: if this send stream has been closed + :raises ~anyio.BrokenResourceError: if the stream has been closed from the + receiving end + + """ + await checkpoint() + try: + self.send_nowait(item) + except WouldBlock: + # Wait until there's someone on the receiving end + send_event = Event() + self._state.waiting_senders[send_event] = item + try: + await send_event.wait() + except BaseException: + self._state.waiting_senders.pop(send_event, None) + raise + + if send_event in self._state.waiting_senders: + del self._state.waiting_senders[send_event] + raise BrokenResourceError from None + + def clone(self) -> MemoryObjectSendStream[T_contra]: + """ + Create a clone of this send stream. + + Each clone can be closed separately. Only when all clones have been closed will + the sending end of the memory stream be considered closed by the receiving ends. + + :return: the cloned stream + + """ + if self._closed: + raise ClosedResourceError + + return MemoryObjectSendStream(_state=self._state) + + def close(self) -> None: + """ + Close the stream. + + This works the exact same way as :meth:`aclose`, but is provided as a special + case for the benefit of synchronous callbacks. + + """ + if not self._closed: + self._closed = True + self._state.open_send_channels -= 1 + if self._state.open_send_channels == 0: + receive_events = list(self._state.waiting_receivers.keys()) + self._state.waiting_receivers.clear() + for event in receive_events: + event.set() + + async def aclose(self) -> None: + self.close() + + def statistics(self) -> MemoryObjectStreamStatistics: + """ + Return statistics about the current state of this stream. + + .. versionadded:: 3.0 + """ + return self._state.statistics() + + def __enter__(self) -> MemoryObjectSendStream[T_contra]: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + self.close() + + def __del__(self) -> None: + if not self._closed: + warnings.warn( + f"Unclosed <{self.__class__.__name__} at {id(self):x}>", + ResourceWarning, + stacklevel=1, + source=self, + ) diff --git a/source/target-vendors/cp312/anyio/streams/stapled.py b/source/target-vendors/cp312/anyio/streams/stapled.py new file mode 100644 index 0000000..9a75345 --- /dev/null +++ b/source/target-vendors/cp312/anyio/streams/stapled.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +__all__ = ( + "MultiListener", + "StapledByteStream", + "StapledObjectStream", +) + +from collections.abc import Callable, Mapping, Sequence +from dataclasses import dataclass +from typing import Any, Generic, TypeVar + +from ..abc import ( + ByteReceiveStream, + ByteSendStream, + ByteStream, + Listener, + ObjectReceiveStream, + ObjectSendStream, + ObjectStream, + TaskGroup, +) + +T_Item = TypeVar("T_Item") +T_Stream = TypeVar("T_Stream") + + +@dataclass(eq=False) +class StapledByteStream(ByteStream): + """ + Combines two byte streams into a single, bidirectional byte stream. + + Extra attributes will be provided from both streams, with the receive stream + providing the values in case of a conflict. + + :param ByteSendStream send_stream: the sending byte stream + :param ByteReceiveStream receive_stream: the receiving byte stream + """ + + send_stream: ByteSendStream + receive_stream: ByteReceiveStream + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + return await self.receive_stream.receive(max_bytes) + + async def send(self, item: bytes) -> None: + await self.send_stream.send(item) + + async def send_eof(self) -> None: + await self.send_stream.aclose() + + async def aclose(self) -> None: + await self.send_stream.aclose() + await self.receive_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self.send_stream.extra_attributes, + **self.receive_stream.extra_attributes, + } + + +@dataclass(eq=False) +class StapledObjectStream(ObjectStream[T_Item], Generic[T_Item]): + """ + Combines two object streams into a single, bidirectional object stream. + + Extra attributes will be provided from both streams, with the receive stream + providing the values in case of a conflict. + + :param ObjectSendStream send_stream: the sending object stream + :param ObjectReceiveStream receive_stream: the receiving object stream + """ + + send_stream: ObjectSendStream[T_Item] + receive_stream: ObjectReceiveStream[T_Item] + + async def receive(self) -> T_Item: + return await self.receive_stream.receive() + + async def send(self, item: T_Item) -> None: + await self.send_stream.send(item) + + def send_nowait(self, item: T_Item) -> None: + try: + send_nowait = self.send_stream.send_nowait # type: ignore[attr-defined] + except AttributeError as exc: + raise NotImplementedError( + f"'send_nowait' method not implemented in {type(self.send_stream)}" + ) from exc + + send_nowait(item) + + async def send_eof(self) -> None: + await self.send_stream.aclose() + + async def aclose(self) -> None: + await self.send_stream.aclose() + await self.receive_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self.send_stream.extra_attributes, + **self.receive_stream.extra_attributes, + } + + +@dataclass(eq=False) +class MultiListener(Listener[T_Stream], Generic[T_Stream]): + """ + Combines multiple listeners into one, serving connections from all of them at once. + + Any MultiListeners in the given collection of listeners will have their listeners + moved into this one. + + Extra attributes are provided from each listener, with each successive listener + overriding any conflicting attributes from the previous one. + + :param listeners: listeners to serve + :type listeners: Sequence[Listener[T_Stream]] + """ + + listeners: Sequence[Listener[T_Stream]] + + def __post_init__(self) -> None: + listeners: list[Listener[T_Stream]] = [] + for listener in self.listeners: + if isinstance(listener, MultiListener): + listeners.extend(listener.listeners) + del listener.listeners[:] # type: ignore[attr-defined] + else: + listeners.append(listener) + + self.listeners = listeners + + async def serve( + self, handler: Callable[[T_Stream], Any], task_group: TaskGroup | None = None + ) -> None: + from .. import create_task_group + + async with create_task_group() as tg: + for listener in self.listeners: + tg.start_soon(listener.serve, handler, task_group) + + async def aclose(self) -> None: + for listener in self.listeners: + await listener.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + attributes: dict = {} + for listener in self.listeners: + attributes.update(listener.extra_attributes) + + return attributes diff --git a/source/target-vendors/cp312/anyio/streams/text.py b/source/target-vendors/cp312/anyio/streams/text.py new file mode 100644 index 0000000..296cd25 --- /dev/null +++ b/source/target-vendors/cp312/anyio/streams/text.py @@ -0,0 +1,176 @@ +from __future__ import annotations + +__all__ = ( + "TextConnectable", + "TextReceiveStream", + "TextSendStream", + "TextStream", +) + +import codecs +import sys +from collections.abc import Callable, Mapping +from dataclasses import InitVar, dataclass, field +from typing import Any + +from ..abc import ( + AnyByteReceiveStream, + AnyByteSendStream, + AnyByteStream, + AnyByteStreamConnectable, + ObjectReceiveStream, + ObjectSendStream, + ObjectStream, + ObjectStreamConnectable, +) + +if sys.version_info >= (3, 12): + from typing import override +else: + from typing_extensions import override + + +@dataclass(eq=False) +class TextReceiveStream(ObjectReceiveStream[str]): + """ + Stream wrapper that decodes bytes to strings using the given encoding. + + Decoding is done using :class:`~codecs.IncrementalDecoder` which returns any + completely received unicode characters as soon as they come in. + + :param transport_stream: any bytes-based receive stream + :param encoding: character encoding to use for decoding bytes to strings (defaults + to ``utf-8``) + :param errors: handling scheme for decoding errors (defaults to ``strict``; see the + `codecs module documentation`_ for a comprehensive list of options) + + .. _codecs module documentation: + https://docs.python.org/3/library/codecs.html#codec-objects + """ + + transport_stream: AnyByteReceiveStream + encoding: InitVar[str] = "utf-8" + errors: InitVar[str] = "strict" + _decoder: codecs.IncrementalDecoder = field(init=False) + + def __post_init__(self, encoding: str, errors: str) -> None: + decoder_class = codecs.getincrementaldecoder(encoding) + self._decoder = decoder_class(errors=errors) + + async def receive(self) -> str: + while True: + chunk = await self.transport_stream.receive() + decoded = self._decoder.decode(chunk) + if decoded: + return decoded + + async def aclose(self) -> None: + await self.transport_stream.aclose() + self._decoder.reset() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return self.transport_stream.extra_attributes + + +@dataclass(eq=False) +class TextSendStream(ObjectSendStream[str]): + """ + Sends strings to the wrapped stream as bytes using the given encoding. + + :param AnyByteSendStream transport_stream: any bytes-based send stream + :param str encoding: character encoding to use for encoding strings to bytes + (defaults to ``utf-8``) + :param str errors: handling scheme for encoding errors (defaults to ``strict``; see + the `codecs module documentation`_ for a comprehensive list of options) + + .. _codecs module documentation: + https://docs.python.org/3/library/codecs.html#codec-objects + """ + + transport_stream: AnyByteSendStream + encoding: InitVar[str] = "utf-8" + errors: str = "strict" + _encoder: Callable[..., tuple[bytes, int]] = field(init=False) + + def __post_init__(self, encoding: str) -> None: + self._encoder = codecs.getencoder(encoding) + + async def send(self, item: str) -> None: + encoded = self._encoder(item, self.errors)[0] + await self.transport_stream.send(encoded) + + async def aclose(self) -> None: + await self.transport_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return self.transport_stream.extra_attributes + + +@dataclass(eq=False) +class TextStream(ObjectStream[str]): + """ + A bidirectional stream that decodes bytes to strings on receive and encodes strings + to bytes on send. + + Extra attributes will be provided from both streams, with the receive stream + providing the values in case of a conflict. + + :param AnyByteStream transport_stream: any bytes-based stream + :param str encoding: character encoding to use for encoding/decoding strings to/from + bytes (defaults to ``utf-8``) + :param str errors: handling scheme for encoding errors (defaults to ``strict``; see + the `codecs module documentation`_ for a comprehensive list of options) + + .. _codecs module documentation: + https://docs.python.org/3/library/codecs.html#codec-objects + """ + + transport_stream: AnyByteStream + encoding: InitVar[str] = "utf-8" + errors: InitVar[str] = "strict" + _receive_stream: TextReceiveStream = field(init=False) + _send_stream: TextSendStream = field(init=False) + + def __post_init__(self, encoding: str, errors: str) -> None: + self._receive_stream = TextReceiveStream( + self.transport_stream, encoding=encoding, errors=errors + ) + self._send_stream = TextSendStream( + self.transport_stream, encoding=encoding, errors=errors + ) + + async def receive(self) -> str: + return await self._receive_stream.receive() + + async def send(self, item: str) -> None: + await self._send_stream.send(item) + + async def send_eof(self) -> None: + await self.transport_stream.send_eof() + + async def aclose(self) -> None: + await self._send_stream.aclose() + await self._receive_stream.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self._send_stream.extra_attributes, + **self._receive_stream.extra_attributes, + } + + +class TextConnectable(ObjectStreamConnectable[str]): + def __init__(self, connectable: AnyByteStreamConnectable): + """ + :param connectable: the bytestream endpoint to wrap + + """ + self.connectable = connectable + + @override + async def connect(self) -> TextStream: + stream = await self.connectable.connect() + return TextStream(stream) diff --git a/source/target-vendors/cp312/anyio/streams/tls.py b/source/target-vendors/cp312/anyio/streams/tls.py new file mode 100644 index 0000000..b9ddf1d --- /dev/null +++ b/source/target-vendors/cp312/anyio/streams/tls.py @@ -0,0 +1,436 @@ +from __future__ import annotations + +__all__ = ( + "TLSAttribute", + "TLSConnectable", + "TLSListener", + "TLSStream", +) + +import logging +import re +import ssl +import sys +from collections.abc import Callable, Mapping +from dataclasses import dataclass +from functools import wraps +from ssl import SSLContext +from typing import Any, TypeAlias, TypeVar + +from .. import ( + BrokenResourceError, + EndOfStream, + aclose_forcefully, + get_cancelled_exc_class, + to_thread, +) +from .._core._typedattr import TypedAttributeSet, typed_attribute +from ..abc import ( + AnyByteStream, + AnyByteStreamConnectable, + ByteStream, + ByteStreamConnectable, + Listener, + TaskGroup, +) + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +if sys.version_info >= (3, 12): + from typing import override +else: + from typing_extensions import override + +T_Retval = TypeVar("T_Retval") +PosArgsT = TypeVarTuple("PosArgsT") +_PCTRTT: TypeAlias = tuple[tuple[str, str], ...] +_PCTRTTT: TypeAlias = tuple[_PCTRTT, ...] + + +class TLSAttribute(TypedAttributeSet): + """Contains Transport Layer Security related attributes.""" + + #: the selected ALPN protocol + alpn_protocol: str | None = typed_attribute() + #: the channel binding for type ``tls-unique`` + channel_binding_tls_unique: bytes = typed_attribute() + #: the selected cipher + cipher: tuple[str, str, int] = typed_attribute() + #: the peer certificate in dictionary form (see :meth:`ssl.SSLSocket.getpeercert` + # for more information) + peer_certificate: None | (dict[str, str | _PCTRTTT | _PCTRTT]) = typed_attribute() + #: the peer certificate in binary form + peer_certificate_binary: bytes | None = typed_attribute() + #: ``True`` if this is the server side of the connection + server_side: bool = typed_attribute() + #: ciphers shared by the client during the TLS handshake (``None`` if this is the + #: client side) + shared_ciphers: list[tuple[str, str, int]] | None = typed_attribute() + #: the :class:`~ssl.SSLObject` used for encryption + ssl_object: ssl.SSLObject = typed_attribute() + #: ``True`` if this stream does (and expects) a closing TLS handshake when the + #: stream is being closed + standard_compatible: bool = typed_attribute() + #: the TLS protocol version (e.g. ``TLSv1.2``) + tls_version: str = typed_attribute() + + +@dataclass(eq=False) +class TLSStream(ByteStream): + """ + A stream wrapper that encrypts all sent data and decrypts received data. + + This class has no public initializer; use :meth:`wrap` instead. + All extra attributes from :class:`~TLSAttribute` are supported. + + :var AnyByteStream transport_stream: the wrapped stream + + """ + + transport_stream: AnyByteStream + standard_compatible: bool + _ssl_object: ssl.SSLObject + _read_bio: ssl.MemoryBIO + _write_bio: ssl.MemoryBIO + + @classmethod + async def wrap( + cls, + transport_stream: AnyByteStream, + *, + server_side: bool | None = None, + hostname: str | None = None, + ssl_context: ssl.SSLContext | None = None, + standard_compatible: bool = True, + ) -> TLSStream: + """ + Wrap an existing stream with Transport Layer Security. + + This performs a TLS handshake with the peer. + + :param transport_stream: a bytes-transporting stream to wrap + :param server_side: ``True`` if this is the server side of the connection, + ``False`` if this is the client side (if omitted, will be set to ``False`` + if ``hostname`` has been provided, ``False`` otherwise). Used only to create + a default context when an explicit context has not been provided. + :param hostname: host name of the peer (if host name checking is desired) + :param ssl_context: the SSLContext object to use (if not provided, a secure + default will be created) + :param standard_compatible: if ``False``, skip the closing handshake when + closing the connection, and don't raise an exception if the peer does the + same + :raises ~ssl.SSLError: if the TLS handshake fails + + """ + if server_side is None: + server_side = not hostname + + if not ssl_context: + purpose = ( + ssl.Purpose.CLIENT_AUTH if server_side else ssl.Purpose.SERVER_AUTH + ) + ssl_context = ssl.create_default_context(purpose) + + # Re-enable detection of unexpected EOFs if it was disabled by Python + if hasattr(ssl, "OP_IGNORE_UNEXPECTED_EOF"): + ssl_context.options &= ~ssl.OP_IGNORE_UNEXPECTED_EOF + + bio_in = ssl.MemoryBIO() + bio_out = ssl.MemoryBIO() + + # Resolve international host names using IDNA 2008. + # Otherwise wrap_bio() would resolve them with IDNA 2003. + if hostname is not None: + from .._core._sockets import idna2008_resolve + + server_hostname: bytes | None = idna2008_resolve(hostname) + else: + server_hostname = None + + # External SSLContext implementations may do blocking I/O in wrap_bio(), + # but the standard library implementation won't + if type(ssl_context) is ssl.SSLContext: + ssl_object = ssl_context.wrap_bio( + bio_in, + bio_out, + server_side=server_side, + server_hostname=server_hostname, + ) + else: + ssl_object = await to_thread.run_sync( + ssl_context.wrap_bio, + bio_in, + bio_out, + server_side, + server_hostname, + None, + ) + + wrapper = cls( + transport_stream=transport_stream, + standard_compatible=standard_compatible, + _ssl_object=ssl_object, + _read_bio=bio_in, + _write_bio=bio_out, + ) + await wrapper._call_sslobject_method(ssl_object.do_handshake) + return wrapper + + async def _call_sslobject_method( + self, func: Callable[[Unpack[PosArgsT]], T_Retval], *args: Unpack[PosArgsT] + ) -> T_Retval: + while True: + try: + result = func(*args) + except ssl.SSLWantReadError: + try: + # Flush any pending writes first + if self._write_bio.pending: + await self.transport_stream.send(self._write_bio.read()) + + data = await self.transport_stream.receive() + except EndOfStream: + self._read_bio.write_eof() + except OSError as exc: + self._read_bio.write_eof() + self._write_bio.write_eof() + raise BrokenResourceError from exc + else: + self._read_bio.write(data) + except ssl.SSLWantWriteError: + await self.transport_stream.send(self._write_bio.read()) + except ssl.SSLSyscallError as exc: + self._read_bio.write_eof() + self._write_bio.write_eof() + raise BrokenResourceError from exc + except ssl.SSLError as exc: + self._read_bio.write_eof() + self._write_bio.write_eof() + if isinstance(exc, ssl.SSLEOFError) or ( + exc.strerror and "UNEXPECTED_EOF_WHILE_READING" in exc.strerror + ): + if self.standard_compatible: + raise BrokenResourceError from exc + else: + raise EndOfStream from None + + raise + else: + # Flush any pending writes first + if self._write_bio.pending: + await self.transport_stream.send(self._write_bio.read()) + + return result + + async def unwrap(self) -> tuple[AnyByteStream, bytes]: + """ + Does the TLS closing handshake. + + :return: a tuple of (wrapped byte stream, bytes left in the read buffer) + + """ + await self._call_sslobject_method(self._ssl_object.unwrap) + self._read_bio.write_eof() + self._write_bio.write_eof() + return self.transport_stream, self._read_bio.read() + + async def aclose(self) -> None: + if self.standard_compatible: + try: + await self.unwrap() + except BaseException: + await aclose_forcefully(self.transport_stream) + raise + + await self.transport_stream.aclose() + + async def receive(self, max_bytes: int = 65536) -> bytes: + if max_bytes < 1: + raise ValueError("max_bytes must be a positive integer") + + data = await self._call_sslobject_method(self._ssl_object.read, max_bytes) + if not data: + raise EndOfStream + + return data + + async def send(self, item: bytes) -> None: + await self._call_sslobject_method(self._ssl_object.write, item) + + async def send_eof(self) -> None: + tls_version = self.extra(TLSAttribute.tls_version) + match = re.match(r"TLSv(\d+)(?:\.(\d+))?", tls_version) + if match: + major, minor = int(match.group(1)), int(match.group(2) or 0) + if (major, minor) < (1, 3): + raise NotImplementedError( + f"send_eof() requires at least TLSv1.3; current " + f"session uses {tls_version}" + ) + + raise NotImplementedError( + "send_eof() has not yet been implemented for TLS streams" + ) + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + **self.transport_stream.extra_attributes, + TLSAttribute.alpn_protocol: self._ssl_object.selected_alpn_protocol, + TLSAttribute.channel_binding_tls_unique: ( + self._ssl_object.get_channel_binding + ), + TLSAttribute.cipher: self._ssl_object.cipher, + TLSAttribute.peer_certificate: lambda: self._ssl_object.getpeercert(False), + TLSAttribute.peer_certificate_binary: lambda: self._ssl_object.getpeercert( + True + ), + TLSAttribute.server_side: lambda: self._ssl_object.server_side, + TLSAttribute.shared_ciphers: lambda: ( + self._ssl_object.shared_ciphers() + if self._ssl_object.server_side + else None + ), + TLSAttribute.standard_compatible: lambda: self.standard_compatible, + TLSAttribute.ssl_object: lambda: self._ssl_object, + TLSAttribute.tls_version: self._ssl_object.version, + } + + +@dataclass(eq=False) +class TLSListener(Listener[TLSStream]): + """ + A convenience listener that wraps another listener and auto-negotiates a TLS session + on every accepted connection. + + If the TLS handshake times out or raises an exception, + :meth:`handle_handshake_error` is called to do whatever post-mortem processing is + deemed necessary. + + Supports only the :attr:`~TLSAttribute.standard_compatible` extra attribute. + + :param Listener listener: the listener to wrap + :param ssl_context: the SSL context object + :param standard_compatible: a flag passed through to :meth:`TLSStream.wrap` + :param handshake_timeout: time limit for the TLS handshake + (passed to :func:`~anyio.fail_after`) + """ + + listener: Listener[Any] + ssl_context: ssl.SSLContext + standard_compatible: bool = True + handshake_timeout: float = 30 + + @staticmethod + async def handle_handshake_error(exc: BaseException, stream: AnyByteStream) -> None: + """ + Handle an exception raised during the TLS handshake. + + This method does 3 things: + + #. Forcefully closes the original stream + #. Logs the exception (unless it was a cancellation exception) using the + ``anyio.streams.tls`` logger + #. Reraises the exception if it was a base exception or a cancellation exception + + :param exc: the exception + :param stream: the original stream + + """ + await aclose_forcefully(stream) + + # Log all except cancellation exceptions + if not isinstance(exc, get_cancelled_exc_class()): + # CPython (as of 3.11.5) returns incorrect `sys.exc_info()` here when using + # any asyncio implementation, so we explicitly pass the exception to log + # (https://github.com/python/cpython/issues/108668). Trio does not have this + # issue because it works around the CPython bug. + logging.getLogger(__name__).exception( + "Error during TLS handshake", exc_info=exc + ) + + # Only reraise base exceptions and cancellation exceptions + if not isinstance(exc, Exception) or isinstance(exc, get_cancelled_exc_class()): + raise # noqa: PLE0704 + + async def serve( + self, + handler: Callable[[TLSStream], Any], + task_group: TaskGroup | None = None, + ) -> None: + @wraps(handler) + async def handler_wrapper(stream: AnyByteStream) -> None: + from .. import fail_after + + try: + with fail_after(self.handshake_timeout): + wrapped_stream = await TLSStream.wrap( + stream, + ssl_context=self.ssl_context, + standard_compatible=self.standard_compatible, + ) + except BaseException as exc: + await self.handle_handshake_error(exc, stream) + else: + await handler(wrapped_stream) + + await self.listener.serve(handler_wrapper, task_group) + + async def aclose(self) -> None: + await self.listener.aclose() + + @property + def extra_attributes(self) -> Mapping[Any, Callable[[], Any]]: + return { + TLSAttribute.standard_compatible: lambda: self.standard_compatible, + } + + +class TLSConnectable(ByteStreamConnectable): + """ + Wraps another connectable and does TLS negotiation after a successful connection. + + :param connectable: the connectable to wrap + :param hostname: host name of the server (if host name checking is desired) + :param ssl_context: the SSLContext object to use (if not provided, a secure default + will be created) + :param standard_compatible: if ``False``, skip the closing handshake when closing + the connection, and don't raise an exception if the server does the same + """ + + def __init__( + self, + connectable: AnyByteStreamConnectable, + *, + hostname: str | None = None, + ssl_context: ssl.SSLContext | None = None, + standard_compatible: bool = True, + ) -> None: + self.connectable = connectable + self.ssl_context: SSLContext = ssl_context or ssl.create_default_context( + ssl.Purpose.SERVER_AUTH + ) + if not isinstance(self.ssl_context, ssl.SSLContext): + raise TypeError( + "ssl_context must be an instance of ssl.SSLContext, not " + f"{type(self.ssl_context).__name__}" + ) + self.hostname = hostname + self.standard_compatible = standard_compatible + + @override + async def connect(self) -> TLSStream: + stream = await self.connectable.connect() + try: + return await TLSStream.wrap( + stream, + hostname=self.hostname, + ssl_context=self.ssl_context, + standard_compatible=self.standard_compatible, + ) + except BaseException: + await aclose_forcefully(stream) + raise diff --git a/source/target-vendors/cp312/anyio/to_interpreter.py b/source/target-vendors/cp312/anyio/to_interpreter.py new file mode 100644 index 0000000..54ef4a8 --- /dev/null +++ b/source/target-vendors/cp312/anyio/to_interpreter.py @@ -0,0 +1,246 @@ +from __future__ import annotations + +__all__ = ( + "current_default_interpreter_limiter", + "run_sync", +) + +import atexit +import os +import sys +from collections import deque +from collections.abc import Callable +from typing import Any, Final, TypeVar + +from . import current_time, to_thread +from ._core._exceptions import BrokenWorkerInterpreter +from ._core._synchronization import CapacityLimiter +from .lowlevel import RunVar + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +if sys.version_info >= (3, 14): + from concurrent.interpreters import ExecutionFailed, create + + def _interp_call( + func: Callable[..., Any], args: tuple[Any, ...] + ) -> tuple[Any, bool]: + try: + retval = func(*args) + except BaseException as exc: + return exc, True + else: + return retval, False + + class _Worker: + last_used: float = 0 + + def __init__(self) -> None: + self._interpreter = create() + + def destroy(self) -> None: + self._interpreter.close() + + def call( + self, + func: Callable[..., T_Retval], + args: tuple[Any, ...], + ) -> T_Retval: + try: + res, is_exception = self._interpreter.call(_interp_call, func, args) + except ExecutionFailed as exc: + raise BrokenWorkerInterpreter(exc.excinfo) from exc + + if is_exception: + raise res + + return res +elif sys.version_info >= (3, 13): + import _interpqueues + import _interpreters + + UNBOUND: Final = 2 # I have no clue how this works, but it was used in the stdlib + FMT_UNPICKLED: Final = 0 + FMT_PICKLED: Final = 1 + QUEUE_PICKLE_ARGS: Final = (FMT_PICKLED, UNBOUND) + QUEUE_UNPICKLE_ARGS: Final = (FMT_UNPICKLED, UNBOUND) + + _run_func = compile( + """ +import _interpqueues +from _interpreters import NotShareableError +from pickle import loads, dumps, HIGHEST_PROTOCOL + +QUEUE_PICKLE_ARGS = (1, 2) +QUEUE_UNPICKLE_ARGS = (0, 2) + +item = _interpqueues.get(queue_id)[0] +try: + func, args = loads(item) + retval = func(*args) +except BaseException as exc: + is_exception = True + retval = exc +else: + is_exception = False + +try: + _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_UNPICKLE_ARGS) +except NotShareableError: + retval = dumps(retval, HIGHEST_PROTOCOL) + _interpqueues.put(queue_id, (retval, is_exception), *QUEUE_PICKLE_ARGS) + """, + "", + "exec", + ) + + class _Worker: + last_used: float = 0 + + def __init__(self) -> None: + self._interpreter_id = _interpreters.create() + self._queue_id = _interpqueues.create(1, *QUEUE_UNPICKLE_ARGS) + _interpreters.set___main___attrs( + self._interpreter_id, {"queue_id": self._queue_id} + ) + + def destroy(self) -> None: + _interpqueues.destroy(self._queue_id) + _interpreters.destroy(self._interpreter_id) + + def call( + self, + func: Callable[..., T_Retval], + args: tuple[Any, ...], + ) -> T_Retval: + import pickle + + item = pickle.dumps((func, args), pickle.HIGHEST_PROTOCOL) + _interpqueues.put(self._queue_id, item, *QUEUE_PICKLE_ARGS) + exc_info = _interpreters.exec(self._interpreter_id, _run_func) + if exc_info: + raise BrokenWorkerInterpreter(exc_info) + + res = _interpqueues.get(self._queue_id) + (res, is_exception), fmt = res[:2] + if fmt == FMT_PICKLED: + res = pickle.loads(res) + + if is_exception: + raise res + + return res +else: + + class _Worker: + last_used: float = 0 + + def __init__(self) -> None: + raise RuntimeError("subinterpreters require at least Python 3.13") + + def call( + self, + func: Callable[..., T_Retval], + args: tuple[Any, ...], + ) -> T_Retval: + raise NotImplementedError + + def destroy(self) -> None: + pass + + +DEFAULT_CPU_COUNT: Final = 8 # this is just an arbitrarily selected value +MAX_WORKER_IDLE_TIME = ( + 30 # seconds a subinterpreter can be idle before becoming eligible for pruning +) + +T_Retval = TypeVar("T_Retval") +PosArgsT = TypeVarTuple("PosArgsT") + +_idle_workers = RunVar[deque[_Worker]]("_available_workers") +_default_interpreter_limiter = RunVar[CapacityLimiter]("_default_interpreter_limiter") + + +def _stop_workers(workers: deque[_Worker]) -> None: + for worker in workers: + worker.destroy() + + workers.clear() + + +async def run_sync( + func: Callable[[Unpack[PosArgsT]], T_Retval], + *args: Unpack[PosArgsT], + limiter: CapacityLimiter | None = None, +) -> T_Retval: + """ + Call the given function with the given arguments in a subinterpreter. + + .. warning:: On Python 3.13, the :mod:`concurrent.interpreters` module was not yet + available, so the code path for that Python version relies on an undocumented, + private API. As such, it is recommended to not rely on this function for anything + mission-critical on Python 3.13. + + :param func: a callable + :param args: the positional arguments for the callable + :param limiter: capacity limiter to use to limit the total number of subinterpreters + running (if omitted, the default limiter is used) + :return: the result of the call + :raises BrokenWorkerInterpreter: if there's an internal error in a subinterpreter + + """ + if limiter is None: + limiter = current_default_interpreter_limiter() + + try: + idle_workers = _idle_workers.get() + except LookupError: + idle_workers = deque() + _idle_workers.set(idle_workers) + atexit.register(_stop_workers, idle_workers) + + async with limiter: + try: + worker = idle_workers.pop() + except IndexError: + worker = _Worker() + + try: + return await to_thread.run_sync( + worker.call, + func, + args, + limiter=limiter, + ) + finally: + # Prune workers that have been idle for too long + now = current_time() + while idle_workers: + if now - idle_workers[0].last_used <= MAX_WORKER_IDLE_TIME: + break + + await to_thread.run_sync(idle_workers.popleft().destroy, limiter=limiter) + + worker.last_used = current_time() + idle_workers.append(worker) + + +def current_default_interpreter_limiter() -> CapacityLimiter: + """ + Return the capacity limiter used by default to limit the number of concurrently + running subinterpreters. + + Defaults to the number of CPU cores. + + :return: a capacity limiter object + + """ + try: + return _default_interpreter_limiter.get() + except LookupError: + limiter = CapacityLimiter(os.cpu_count() or DEFAULT_CPU_COUNT) + _default_interpreter_limiter.set(limiter) + return limiter diff --git a/source/target-vendors/cp312/anyio/to_process.py b/source/target-vendors/cp312/anyio/to_process.py new file mode 100644 index 0000000..584128e --- /dev/null +++ b/source/target-vendors/cp312/anyio/to_process.py @@ -0,0 +1,269 @@ +from __future__ import annotations + +__all__ = ( + "current_default_process_limiter", + "process_worker", + "run_sync", +) + +import os +import pickle +import runpy +import subprocess +import sys +from collections import deque +from collections.abc import Callable +from types import ModuleType +from typing import TypeVar, cast + +from ._core._eventloop import current_time, get_async_backend, get_cancelled_exc_class +from ._core._exceptions import BrokenWorkerProcess +from ._core._subprocesses import open_process +from ._core._synchronization import CapacityLimiter +from ._core._tasks import CancelScope, fail_after +from .abc import ByteReceiveStream, ByteSendStream, Process +from .lowlevel import RunVar, checkpoint_if_cancelled +from .streams.buffered import BufferedByteReceiveStream + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +WORKER_MAX_IDLE_TIME = 300 # 5 minutes + +T_Retval = TypeVar("T_Retval") +PosArgsT = TypeVarTuple("PosArgsT") + +_process_pool_workers: RunVar[set[Process]] = RunVar("_process_pool_workers") +_process_pool_idle_workers: RunVar[deque[tuple[Process, float]]] = RunVar( + "_process_pool_idle_workers" +) +_default_process_limiter: RunVar[CapacityLimiter] = RunVar("_default_process_limiter") + + +async def run_sync( # type: ignore[return] + func: Callable[[Unpack[PosArgsT]], T_Retval], + *args: Unpack[PosArgsT], + cancellable: bool = False, + limiter: CapacityLimiter | None = None, +) -> T_Retval: + """ + Call the given function with the given arguments in a worker process. + + If the ``cancellable`` option is enabled and the task waiting for its completion is + cancelled, the worker process running it will be abruptly terminated using SIGKILL + (or ``terminateProcess()`` on Windows). + + :param func: a callable + :param args: positional arguments for the callable + :param cancellable: ``True`` to allow cancellation of the operation while it's + running + :param limiter: capacity limiter to use to limit the total amount of processes + running (if omitted, the default limiter is used) + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + :return: an awaitable that yields the return value of the function. + + """ + + async def send_raw_command(pickled_cmd: bytes) -> object: + try: + await stdin.send(pickled_cmd) + response = await buffered.receive_until(b"\n", 50) + status, length = response.split(b" ") + if status not in (b"RETURN", b"EXCEPTION"): + raise RuntimeError( + f"Worker process returned unexpected response: {response!r}" + ) + + pickled_response = await buffered.receive_exactly(int(length)) + except BaseException as exc: + workers.discard(process) + try: + process.kill() + with CancelScope(shield=True): + await process.aclose() + except ProcessLookupError: + pass + + if isinstance(exc, get_cancelled_exc_class()): + raise + else: + raise BrokenWorkerProcess from exc + + retval = pickle.loads(pickled_response) + if status == b"EXCEPTION": + assert isinstance(retval, BaseException) + raise retval + else: + return retval + + # First pickle the request before trying to reserve a worker process + await checkpoint_if_cancelled() + request = pickle.dumps(("run", func, args), protocol=pickle.HIGHEST_PROTOCOL) + + # If this is the first run in this event loop thread, set up the necessary variables + try: + workers = _process_pool_workers.get() + idle_workers = _process_pool_idle_workers.get() + except LookupError: + workers = set() + idle_workers = deque() + _process_pool_workers.set(workers) + _process_pool_idle_workers.set(idle_workers) + get_async_backend().setup_process_pool_exit_at_shutdown(workers) + + async with limiter or current_default_process_limiter(): + # Pop processes from the pool (starting from the most recently used) until we + # find one that hasn't exited yet + process: Process + while idle_workers: + process, _idle_since = idle_workers.pop() + if process.returncode is None: + stdin = cast(ByteSendStream, process.stdin) + buffered = BufferedByteReceiveStream( + cast(ByteReceiveStream, process.stdout) + ) + + # Prune any other workers that have been idle for WORKER_MAX_IDLE_TIME + # seconds or longer + now = current_time() + killed_processes: list[Process] = [] + while idle_workers: + if now - idle_workers[0][1] < WORKER_MAX_IDLE_TIME: + break + + process_to_kill, _idle_since = idle_workers.popleft() + process_to_kill.kill() + workers.remove(process_to_kill) + killed_processes.append(process_to_kill) + + with CancelScope(shield=True): + for killed_process in killed_processes: + await killed_process.aclose() + + break + + workers.remove(process) + else: + command = [sys.executable, "-u", "-m", __name__] + process = await open_process( + command, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) + try: + stdin = cast(ByteSendStream, process.stdin) + buffered = BufferedByteReceiveStream( + cast(ByteReceiveStream, process.stdout) + ) + with fail_after(20): + message = await buffered.receive(6) + + if message != b"READY\n": + raise BrokenWorkerProcess( + f"Worker process returned unexpected response: {message!r}" + ) + + main_module_path = getattr(sys.modules["__main__"], "__file__", None) + pickled = pickle.dumps( + ("init", sys.path, main_module_path), + protocol=pickle.HIGHEST_PROTOCOL, + ) + await send_raw_command(pickled) + except (BrokenWorkerProcess, get_cancelled_exc_class()): + raise + except BaseException as exc: + process.kill() + raise BrokenWorkerProcess( + "Error during worker process initialization" + ) from exc + + workers.add(process) + + with CancelScope(shield=not cancellable): + try: + return cast(T_Retval, await send_raw_command(request)) + finally: + if process in workers: + idle_workers.append((process, current_time())) + + +def current_default_process_limiter() -> CapacityLimiter: + """ + Return the capacity limiter that is used by default to limit the number of worker + processes. + + :return: a capacity limiter object + + """ + try: + return _default_process_limiter.get() + except LookupError: + limiter = CapacityLimiter(os.cpu_count() or 2) + _default_process_limiter.set(limiter) + return limiter + + +def process_worker() -> None: + # Redirect standard streams to os.devnull so that user code won't interfere with the + # parent-worker communication + stdin = sys.stdin + stdout = sys.stdout + sys.stdin = open(os.devnull) + sys.stdout = open(os.devnull, "w") + sys.stderr = open(os.devnull, "w") + + stdout.buffer.write(b"READY\n") + while True: + retval = exception = None + try: + command, *args = pickle.load(stdin.buffer) + except EOFError: + return + except BaseException as exc: + exception = exc + else: + if command == "run": + func, args = args + try: + retval = func(*args) + except BaseException as exc: + exception = exc + elif command == "init": + main_module_path: str | None + sys.path, main_module_path = args + del sys.modules["__main__"] + if main_module_path and os.path.isfile(main_module_path): + # Load the parent's main module but as __mp_main__ instead of + # __main__ (like multiprocessing does) to avoid infinite recursion + try: + main = ModuleType("__mp_main__") + main_content = runpy.run_path( + main_module_path, run_name="__mp_main__" + ) + main.__dict__.update(main_content) + sys.modules["__main__"] = sys.modules["__mp_main__"] = main + except BaseException as exc: + exception = exc + try: + if exception is not None: + status = b"EXCEPTION" + pickled = pickle.dumps(exception, pickle.HIGHEST_PROTOCOL) + else: + status = b"RETURN" + pickled = pickle.dumps(retval, pickle.HIGHEST_PROTOCOL) + except BaseException as exc: + exception = exc + status = b"EXCEPTION" + pickled = pickle.dumps(exc, pickle.HIGHEST_PROTOCOL) + + stdout.buffer.write(b"%s %d\n" % (status, len(pickled))) + stdout.buffer.write(pickled) + + # Respect SIGTERM + if isinstance(exception, SystemExit): + raise exception + + +if __name__ == "__main__": + process_worker() diff --git a/source/target-vendors/cp312/anyio/to_thread.py b/source/target-vendors/cp312/anyio/to_thread.py new file mode 100644 index 0000000..5cdb725 --- /dev/null +++ b/source/target-vendors/cp312/anyio/to_thread.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +__all__ = ( + "current_default_thread_limiter", + "run_sync", +) + +import sys +from collections.abc import Callable +from typing import TYPE_CHECKING, TypeVar +from warnings import warn + +from ._core._eventloop import get_async_backend + +if TYPE_CHECKING: + from ._core._synchronization import CapacityLimiter + +if sys.version_info >= (3, 11): + from typing import TypeVarTuple, Unpack +else: + from typing_extensions import TypeVarTuple, Unpack + +T_Retval = TypeVar("T_Retval") +PosArgsT = TypeVarTuple("PosArgsT") + + +async def run_sync( + func: Callable[[Unpack[PosArgsT]], T_Retval], + *args: Unpack[PosArgsT], + abandon_on_cancel: bool = False, + cancellable: bool | None = None, + limiter: CapacityLimiter | None = None, +) -> T_Retval: + """ + Call the given function with the given arguments in a worker thread. + + If the ``abandon_on_cancel`` option is enabled and the task waiting for its + completion is cancelled, the thread will still run its course but its + return value (or any raised exception) will be ignored. + + :param func: a callable + :param args: positional arguments for the callable + :param abandon_on_cancel: ``True`` to abandon the thread (leaving it to run + unchecked on own) if the host task is cancelled, ``False`` to ignore + cancellations in the host task until the operation has completed in the worker + thread + :param cancellable: deprecated alias of ``abandon_on_cancel``; will override + ``abandon_on_cancel`` if both parameters are passed + :param limiter: capacity limiter to use to limit the total amount of threads running + (if omitted, the default limiter is used) + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + :return: an awaitable that yields the return value of the function. + + """ + if cancellable is not None: + abandon_on_cancel = cancellable + warn( + "The `cancellable=` keyword argument to `anyio.to_thread.run_sync` is " + "deprecated since AnyIO 4.1.0; use `abandon_on_cancel=` instead", + DeprecationWarning, + stacklevel=2, + ) + + return await get_async_backend().run_sync_in_worker_thread( + func, args, abandon_on_cancel=abandon_on_cancel, limiter=limiter + ) + + +def current_default_thread_limiter() -> CapacityLimiter: + """ + Return the capacity limiter that is used by default to limit the number of + concurrent threads. + + :return: a capacity limiter object + :raises NoEventLoopError: if no supported asynchronous event loop is running in the + current thread + + """ + return get_async_backend().current_default_thread_limiter() diff --git a/source/target-vendors/cp312/attr/__init__.py b/source/target-vendors/cp312/attr/__init__.py new file mode 100644 index 0000000..5c6e065 --- /dev/null +++ b/source/target-vendors/cp312/attr/__init__.py @@ -0,0 +1,104 @@ +# SPDX-License-Identifier: MIT + +""" +Classes Without Boilerplate +""" + +from functools import partial +from typing import Callable, Literal, Protocol + +from . import converters, exceptions, filters, setters, validators +from ._cmp import cmp_using +from ._config import get_run_validators, set_run_validators +from ._funcs import asdict, assoc, astuple, has, resolve_types +from ._make import ( + NOTHING, + Attribute, + Converter, + Factory, + _Nothing, + attrib, + attrs, + evolve, + fields, + fields_dict, + make_class, + validate, +) +from ._next_gen import define, field, frozen, mutable +from ._version_info import VersionInfo + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + + +class AttrsInstance(Protocol): + pass + + +NothingType = Literal[_Nothing.NOTHING] + +__all__ = [ + "NOTHING", + "Attribute", + "AttrsInstance", + "Converter", + "Factory", + "NothingType", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "field", + "fields", + "fields_dict", + "filters", + "frozen", + "get_run_validators", + "has", + "ib", + "make_class", + "mutable", + "resolve_types", + "s", + "set_run_validators", + "setters", + "validate", + "validators", +] + + +def _make_getattr(mod_name: str) -> Callable: + """ + Create a metadata proxy for packaging information that uses *mod_name* in + its warnings and errors. + """ + + def __getattr__(name: str) -> str: + if name not in ("__version__", "__version_info__"): + msg = f"module {mod_name} has no attribute {name}" + raise AttributeError(msg) + + from importlib.metadata import metadata + + meta = metadata("attrs") + + if name == "__version_info__": + return VersionInfo._from_version_string(meta["version"]) + + return meta["version"] + + return __getattr__ + + +__getattr__ = _make_getattr(__name__) diff --git a/source/target-vendors/cp312/attr/__init__.pyi b/source/target-vendors/cp312/attr/__init__.pyi new file mode 100644 index 0000000..758decf --- /dev/null +++ b/source/target-vendors/cp312/attr/__init__.pyi @@ -0,0 +1,389 @@ +import enum +import sys + +from typing import ( + Any, + Callable, + Generic, + Literal, + Mapping, + Protocol, + Sequence, + TypeVar, + overload, +) + +# `import X as X` is required to make these public +from . import converters as converters +from . import exceptions as exceptions +from . import filters as filters +from . import setters as setters +from . import validators as validators +from ._cmp import cmp_using as cmp_using +from ._typing_compat import AttrsInstance_ +from ._version_info import VersionInfo +from attrs import ( + define as define, + field as field, + mutable as mutable, + frozen as frozen, + _EqOrderType, + _ValidatorType, + _ConverterType, + _ReprArgType, + _OnSetAttrType, + _OnSetAttrArgType, + _FieldTransformer, + _ValidatorArgType, +) + +if sys.version_info >= (3, 10): + from typing import TypeGuard, TypeAlias +else: + from typing_extensions import TypeGuard, TypeAlias + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + +__version__: str +__version_info__: VersionInfo +__title__: str +__description__: str +__url__: str +__uri__: str +__author__: str +__email__: str +__license__: str +__copyright__: str + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_FilterType = Callable[["Attribute[_T]", _T], bool] + +# We subclass this here to keep the protocol's qualified name clean. +class AttrsInstance(AttrsInstance_, Protocol): + pass + +_A = TypeVar("_A", bound=type[AttrsInstance]) + +class _Nothing(enum.Enum): + NOTHING = enum.auto() + +NOTHING = _Nothing.NOTHING +NothingType: TypeAlias = Literal[_Nothing.NOTHING] + +# NOTE: Factory lies about its return type to make this possible: +# `x: List[int] # = Factory(list)` +# Work around mypy issue #4554 in the common case by using an overload. + +@overload +def Factory(factory: Callable[[], _T]) -> _T: ... +@overload +def Factory( + factory: Callable[[Any], _T], + takes_self: Literal[True], +) -> _T: ... +@overload +def Factory( + factory: Callable[[], _T], + takes_self: Literal[False], +) -> _T: ... + +In = TypeVar("In") +Out = TypeVar("Out") + +class Converter(Generic[In, Out]): + @overload + def __init__(self, converter: Callable[[In], Out]) -> None: ... + @overload + def __init__( + self, + converter: Callable[[In, AttrsInstance, Attribute], Out], + *, + takes_self: Literal[True], + takes_field: Literal[True], + ) -> None: ... + @overload + def __init__( + self, + converter: Callable[[In, Attribute], Out], + *, + takes_field: Literal[True], + ) -> None: ... + @overload + def __init__( + self, + converter: Callable[[In, AttrsInstance], Out], + *, + takes_self: Literal[True], + ) -> None: ... + +class Attribute(Generic[_T]): + name: str + default: _T | None + validator: _ValidatorType[_T] | None + repr: _ReprArgType + cmp: _EqOrderType + eq: _EqOrderType + order: _EqOrderType + hash: bool | None + init: bool + converter: Converter | None + metadata: dict[Any, Any] + type: type[_T] | None + kw_only: bool + on_setattr: _OnSetAttrType + alias: str | None + + def evolve(self, **changes: Any) -> "Attribute[Any]": ... + +# NOTE: We had several choices for the annotation to use for type arg: +# 1) Type[_T] +# - Pros: Handles simple cases correctly +# - Cons: Might produce less informative errors in the case of conflicting +# TypeVars e.g. `attr.ib(default='bad', type=int)` +# 2) Callable[..., _T] +# - Pros: Better error messages than #1 for conflicting TypeVars +# - Cons: Terrible error messages for validator checks. +# e.g. attr.ib(type=int, validator=validate_str) +# -> error: Cannot infer function type argument +# 3) type (and do all of the work in the mypy plugin) +# - Pros: Simple here, and we could customize the plugin with our own errors. +# - Cons: Would need to write mypy plugin code to handle all the cases. +# We chose option #1. + +# `attr` lies about its return type to make the following possible: +# attr() -> Any +# attr(8) -> int +# attr(validator=) -> Whatever the callable expects. +# This makes this type of assignments possible: +# x: int = attr(8) +# +# This form catches explicit None or no default but with no other arguments +# returns Any. +@overload +def attrib( + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def attrib( + default: None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: type[_T] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def attrib( + default: _T, + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: type[_T] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def attrib( + default: _T | None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + type: object = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., +) -> Any: ... +@overload +@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) +def attrs( + maybe_cls: _C, + these: dict[str, Any] | None = ..., + repr_ns: str | None = ..., + repr: bool = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., + unsafe_hash: bool | None = ..., +) -> _C: ... +@overload +@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) +def attrs( + maybe_cls: None = ..., + these: dict[str, Any] | None = ..., + repr_ns: str | None = ..., + repr: bool = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., + unsafe_hash: bool | None = ..., +) -> Callable[[_C], _C]: ... +def fields(cls: type[AttrsInstance] | AttrsInstance) -> Any: ... +def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ... +def validate(inst: AttrsInstance) -> None: ... +def resolve_types( + cls: _A, + globalns: dict[str, Any] | None = ..., + localns: dict[str, Any] | None = ..., + attribs: list[Attribute[Any]] | None = ..., + include_extras: bool = ..., +) -> _A: ... + +# TODO: add support for returning a proper attrs class from the mypy plugin +# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', +# [attr.ib()])` is valid +def make_class( + name: str, + attrs: list[str] | tuple[str, ...] | dict[str, Any], + bases: tuple[type, ...] = ..., + class_body: dict[str, Any] | None = ..., + repr_ns: str | None = ..., + repr: bool = ..., + cmp: _EqOrderType | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + collect_by_mro: bool = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., +) -> type: ... + +# _funcs -- + +# TODO: add support for returning TypedDict from the mypy plugin +# FIXME: asdict/astuple do not honor their factory args. Waiting on one of +# these: +# https://github.com/python/mypy/issues/4236 +# https://github.com/python/typing/issues/253 +# XXX: remember to fix attrs.asdict/astuple too! +def asdict( + inst: AttrsInstance, + recurse: bool = ..., + filter: _FilterType[Any] | None = ..., + dict_factory: type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ..., + tuple_keys: bool | None = ..., +) -> dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: AttrsInstance, + recurse: bool = ..., + filter: _FilterType[Any] | None = ..., + tuple_factory: type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> tuple[Any, ...]: ... +def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ... +def assoc(inst: _T, **changes: Any) -> _T: ... +def evolve(inst: _T, **changes: Any) -> _T: ... + +# _config -- + +def set_run_validators(run: bool) -> None: ... +def get_run_validators() -> bool: ... + +# aliases -- + +s = attributes = attrs +ib = attr = attrib +dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/source/target-vendors/cp312/attr/_cmp.py b/source/target-vendors/cp312/attr/_cmp.py new file mode 100644 index 0000000..09bab49 --- /dev/null +++ b/source/target-vendors/cp312/attr/_cmp.py @@ -0,0 +1,160 @@ +# SPDX-License-Identifier: MIT + + +import functools +import types + +from ._make import __ne__ + + +_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} + + +def cmp_using( + eq=None, + lt=None, + le=None, + gt=None, + ge=None, + require_same_type=True, + class_name="Comparable", +): + """ + Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, + and ``cmp`` arguments to customize field comparison. + + The resulting class will have a full set of ordering methods if at least + one of ``{lt, le, gt, ge}`` and ``eq`` are provided. + + Args: + eq (typing.Callable | None): + Callable used to evaluate equality of two objects. + + lt (typing.Callable | None): + Callable used to evaluate whether one object is less than another + object. + + le (typing.Callable | None): + Callable used to evaluate whether one object is less than or equal + to another object. + + gt (typing.Callable | None): + Callable used to evaluate whether one object is greater than + another object. + + ge (typing.Callable | None): + Callable used to evaluate whether one object is greater than or + equal to another object. + + require_same_type (bool): + When `True`, equality and ordering methods will return + `NotImplemented` if objects are not of the same type. + + class_name (str | None): Name of class. Defaults to "Comparable". + + See `comparison` for more details. + + .. versionadded:: 21.1.0 + """ + + body = { + "__slots__": ["value"], + "__init__": _make_init(), + "_requirements": [], + "_is_comparable_to": _is_comparable_to, + } + + # Add operations. + num_order_functions = 0 + has_eq_function = False + + if eq is not None: + has_eq_function = True + body["__eq__"] = _make_operator("eq", eq) + body["__ne__"] = __ne__ + + if lt is not None: + num_order_functions += 1 + body["__lt__"] = _make_operator("lt", lt) + + if le is not None: + num_order_functions += 1 + body["__le__"] = _make_operator("le", le) + + if gt is not None: + num_order_functions += 1 + body["__gt__"] = _make_operator("gt", gt) + + if ge is not None: + num_order_functions += 1 + body["__ge__"] = _make_operator("ge", ge) + + type_ = types.new_class( + class_name, (object,), {}, lambda ns: ns.update(body) + ) + + # Add same type requirement. + if require_same_type: + type_._requirements.append(_check_same_type) + + # Add total ordering if at least one operation was defined. + if 0 < num_order_functions < 4: + if not has_eq_function: + # functools.total_ordering requires __eq__ to be defined, + # so raise early error here to keep a nice stack. + msg = "eq must be define is order to complete ordering from lt, le, gt, ge." + raise ValueError(msg) + type_ = functools.total_ordering(type_) + + return type_ + + +def _make_init(): + """ + Create __init__ method. + """ + + def __init__(self, value): + """ + Initialize object with *value*. + """ + self.value = value + + return __init__ + + +def _make_operator(name, func): + """ + Create operator method. + """ + + def method(self, other): + if not self._is_comparable_to(other): + return NotImplemented + + result = func(self.value, other.value) + if result is NotImplemented: + return NotImplemented + + return result + + method.__name__ = f"__{name}__" + method.__doc__ = ( + f"Return a {_operation_names[name]} b. Computed by attrs." + ) + + return method + + +def _is_comparable_to(self, other): + """ + Check whether `other` is comparable to `self`. + """ + return all(func(self, other) for func in self._requirements) + + +def _check_same_type(self, other): + """ + Return True if *self* and *other* are of the same type, False otherwise. + """ + return other.value.__class__ is self.value.__class__ diff --git a/source/target-vendors/cp312/attr/_cmp.pyi b/source/target-vendors/cp312/attr/_cmp.pyi new file mode 100644 index 0000000..cc7893b --- /dev/null +++ b/source/target-vendors/cp312/attr/_cmp.pyi @@ -0,0 +1,13 @@ +from typing import Any, Callable + +_CompareWithType = Callable[[Any, Any], bool] + +def cmp_using( + eq: _CompareWithType | None = ..., + lt: _CompareWithType | None = ..., + le: _CompareWithType | None = ..., + gt: _CompareWithType | None = ..., + ge: _CompareWithType | None = ..., + require_same_type: bool = ..., + class_name: str = ..., +) -> type: ... diff --git a/source/target-vendors/cp312/attr/_compat.py b/source/target-vendors/cp312/attr/_compat.py new file mode 100644 index 0000000..bc68ed9 --- /dev/null +++ b/source/target-vendors/cp312/attr/_compat.py @@ -0,0 +1,99 @@ +# SPDX-License-Identifier: MIT + +import inspect +import platform +import sys +import threading + +from collections.abc import Mapping, Sequence # noqa: F401 +from typing import _GenericAlias + + +PYPY = platform.python_implementation() == "PyPy" +PY_3_10_PLUS = sys.version_info[:2] >= (3, 10) +PY_3_11_PLUS = sys.version_info[:2] >= (3, 11) +PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) +PY_3_13_PLUS = sys.version_info[:2] >= (3, 13) +PY_3_14_PLUS = sys.version_info[:2] >= (3, 14) + + +if PY_3_14_PLUS: + import annotationlib + + # We request forward-ref annotations to not break in the presence of + # forward references. + + def _get_annotations(cls): + return annotationlib.get_annotations( + cls, format=annotationlib.Format.FORWARDREF + ) + +else: + + def _get_annotations(cls): + """ + Get annotations for *cls*. + """ + return cls.__dict__.get("__annotations__", {}) + + +class _AnnotationExtractor: + """ + Extract type annotations from a callable, returning None whenever there + is none. + """ + + __slots__ = ["sig"] + + def __init__(self, callable): + try: + self.sig = inspect.signature(callable) + except (ValueError, TypeError): # inspect failed + self.sig = None + + def get_first_param_type(self): + """ + Return the type annotation of the first argument if it's not empty. + """ + if not self.sig: + return None + + params = list(self.sig.parameters.values()) + if params and params[0].annotation is not inspect.Parameter.empty: + return params[0].annotation + + return None + + def get_return_type(self): + """ + Return the return type if it's not empty. + """ + if ( + self.sig + and self.sig.return_annotation is not inspect.Signature.empty + ): + return self.sig.return_annotation + + return None + + +# Thread-local global to track attrs instances which are already being repr'd. +# This is needed because there is no other (thread-safe) way to pass info +# about the instances that are already being repr'd through the call stack +# in order to ensure we don't perform infinite recursion. +# +# For instance, if an instance contains a dict which contains that instance, +# we need to know that we're already repr'ing the outside instance from within +# the dict's repr() call. +# +# This lives here rather than in _make.py so that the functions in _make.py +# don't have a direct reference to the thread-local in their globals dict. +# If they have such a reference, it breaks cloudpickle. +repr_context = threading.local() + + +def get_generic_base(cl): + """If this is a generic class (A[str]), return the generic base for it.""" + if cl.__class__ is _GenericAlias: + return cl.__origin__ + return None diff --git a/source/target-vendors/cp312/attr/_config.py b/source/target-vendors/cp312/attr/_config.py new file mode 100644 index 0000000..4b25772 --- /dev/null +++ b/source/target-vendors/cp312/attr/_config.py @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MIT + +__all__ = ["get_run_validators", "set_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` + instead. + """ + if not isinstance(run, bool): + msg = "'run' must be bool." + raise TypeError(msg) + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` + instead. + """ + return _run_validators diff --git a/source/target-vendors/cp312/attr/_funcs.py b/source/target-vendors/cp312/attr/_funcs.py new file mode 100644 index 0000000..1adb500 --- /dev/null +++ b/source/target-vendors/cp312/attr/_funcs.py @@ -0,0 +1,497 @@ +# SPDX-License-Identifier: MIT + + +import copy + +from ._compat import get_generic_base +from ._make import _OBJ_SETATTR, NOTHING, fields +from .exceptions import AttrsAttributeNotFoundError + + +_ATOMIC_TYPES = frozenset( + { + type(None), + bool, + int, + float, + str, + complex, + bytes, + type(...), + type, + range, + property, + } +) + + +def asdict( + inst, + recurse=True, + filter=None, + dict_factory=dict, + retain_collection_types=False, + value_serializer=None, +): + """ + Return the *attrs* attribute values of *inst* as a dict. + + Optionally recurse into other *attrs*-decorated classes. + + Args: + inst: Instance of an *attrs*-decorated class. + + recurse (bool): Recurse into classes that are also *attrs*-decorated. + + filter (~typing.Callable): + A callable whose return code determines whether an attribute or + element is included (`True`) or dropped (`False`). Is called with + the `attrs.Attribute` as the first argument and the value as the + second argument. + + dict_factory (~typing.Callable): + A callable to produce dictionaries from. For example, to produce + ordered dictionaries instead of normal Python dictionaries, pass in + ``collections.OrderedDict``. + + retain_collection_types (bool): + Do not convert to `list` when encountering an attribute whose type + is `tuple` or `set`. Only meaningful if *recurse* is `True`. + + value_serializer (typing.Callable | None): + A hook that is called for every attribute or dict key/value. It + receives the current instance, field and value and must return the + (updated) value. The hook is run *after* the optional *filter* has + been applied. + + Returns: + Return type of *dict_factory*. + + Raises: + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* + .. versionadded:: 20.3.0 *value_serializer* + .. versionadded:: 21.3.0 + If a dict has a collection for a key, it is serialized as a tuple. + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + + if value_serializer is not None: + v = value_serializer(inst, a, v) + + if recurse is True: + value_type = type(v) + if value_type in _ATOMIC_TYPES: + rv[a.name] = v + elif has(value_type): + rv[a.name] = asdict( + v, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif issubclass(value_type, (tuple, list, set, frozenset)): + cf = value_type if retain_collection_types is True else list + items = [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in v + ] + try: + rv[a.name] = cf(items) + except TypeError: + if not issubclass(cf, tuple): + raise + # Workaround for TypeError: cf.__new__() missing 1 required + # positional argument (which appears, for a namedturle) + rv[a.name] = cf(*items) + elif issubclass(value_type, dict): + df = dict_factory + rv[a.name] = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in v.items() + ) + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + +def _asdict_anything( + val, + is_key, + filter, + dict_factory, + retain_collection_types, + value_serializer, +): + """ + ``asdict`` only works on attrs instances, this works on anything. + """ + val_type = type(val) + if val_type in _ATOMIC_TYPES: + rv = val + if value_serializer is not None: + rv = value_serializer(None, None, rv) + elif getattr(val_type, "__attrs_attrs__", None) is not None: + # Attrs class. + rv = asdict( + val, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif issubclass(val_type, (tuple, list, set, frozenset)): + if retain_collection_types is True: + cf = val.__class__ + elif is_key: + cf = tuple + else: + cf = list + + rv = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in val + ] + ) + elif issubclass(val_type, dict): + df = dict_factory + rv = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in val.items() + ) + else: + rv = val + if value_serializer is not None: + rv = value_serializer(None, None, rv) + + return rv + + +def astuple( + inst, + recurse=True, + filter=None, + tuple_factory=tuple, + retain_collection_types=False, +): + """ + Return the *attrs* attribute values of *inst* as a tuple. + + Optionally recurse into other *attrs*-decorated classes. + + Args: + inst: Instance of an *attrs*-decorated class. + + recurse (bool): + Recurse into classes that are also *attrs*-decorated. + + filter (~typing.Callable): + A callable whose return code determines whether an attribute or + element is included (`True`) or dropped (`False`). Is called with + the `attrs.Attribute` as the first argument and the value as the + second argument. + + tuple_factory (~typing.Callable): + A callable to produce tuples from. For example, to produce lists + instead of tuples. + + retain_collection_types (bool): + Do not convert to `list` or `dict` when encountering an attribute + which type is `tuple`, `dict` or `set`. Only meaningful if + *recurse* is `True`. + + Returns: + Return type of *tuple_factory* + + Raises: + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + value_type = type(v) + if recurse is True: + if value_type in _ATOMIC_TYPES: + rv.append(v) + elif has(value_type): + rv.append( + astuple( + v, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + ) + elif issubclass(value_type, (tuple, list, set, frozenset)): + cf = v.__class__ if retain is True else list + items = [ + ( + astuple( + j, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(j.__class__) + else j + ) + for j in v + ] + try: + rv.append(cf(items)) + except TypeError: + if not issubclass(cf, tuple): + raise + # Workaround for TypeError: cf.__new__() missing 1 required + # positional argument (which appears, for a namedturle) + rv.append(cf(*items)) + elif issubclass(value_type, dict): + df = value_type if retain is True else dict + rv.append( + df( + ( + ( + astuple( + kk, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(kk.__class__) + else kk + ), + ( + astuple( + vv, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(vv.__class__) + else vv + ), + ) + for kk, vv in v.items() + ) + ) + else: + rv.append(v) + else: + rv.append(v) + + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with *attrs* attributes. + + Args: + cls (type): Class to introspect. + + Raises: + TypeError: If *cls* is not a class. + + Returns: + bool: + """ + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is not None: + return True + + # No attrs, maybe it's a specialized generic (A[str])? + generic_base = get_generic_base(cls) + if generic_base is not None: + generic_attrs = getattr(generic_base, "__attrs_attrs__", None) + if generic_attrs is not None: + # Stick it on here for speed next time. + cls.__attrs_attrs__ = generic_attrs + return generic_attrs is not None + return False + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + This is different from `evolve` that applies the changes to the arguments + that create the new instance. + + `evolve`'s behavior is preferable, but there are `edge cases`_ where it + doesn't work. Therefore `assoc` is deprecated, but will not be removed. + + .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 + + Args: + inst: Instance of a class with *attrs* attributes. + + changes: Keyword changes in the new copy. + + Returns: + A copy of inst with *changes* incorporated. + + Raises: + attrs.exceptions.AttrsAttributeNotFoundError: + If *attr_name* couldn't be found on *cls*. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. deprecated:: 17.1.0 + Use `attrs.evolve` instead if you can. This function will not be + removed du to the slightly different approach compared to + `attrs.evolve`, though. + """ + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in changes.items(): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + msg = f"{k} is not an attrs attribute on {new.__class__}." + raise AttrsAttributeNotFoundError(msg) + _OBJ_SETATTR(new, k, v) + return new + + +def resolve_types( + cls, globalns=None, localns=None, attribs=None, include_extras=True +): + """ + Resolve any strings and forward annotations in type annotations. + + This is only required if you need concrete types in :class:`Attribute`'s + *type* field. In other words, you don't need to resolve your types if you + only use them for static type checking. + + With no arguments, names will be looked up in the module in which the class + was created. If this is not what you want, for example, if the name only + exists inside a method, you may pass *globalns* or *localns* to specify + other dictionaries in which to look up these names. See the docs of + `typing.get_type_hints` for more details. + + Args: + cls (type): Class to resolve. + + globalns (dict | None): Dictionary containing global variables. + + localns (dict | None): Dictionary containing local variables. + + attribs (list | None): + List of attribs for the given class. This is necessary when calling + from inside a ``field_transformer`` since *cls* is not an *attrs* + class yet. + + include_extras (bool): + Resolve more accurately, if possible. Pass ``include_extras`` to + ``typing.get_hints``, if supported by the typing module. On + supported Python versions (3.9+), this resolves the types more + accurately. + + Raises: + TypeError: If *cls* is not a class. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class and you didn't pass any attribs. + + NameError: If types cannot be resolved because of missing variables. + + Returns: + *cls* so you can use this function also as a class decorator. Please + note that you have to apply it **after** `attrs.define`. That means the + decorator has to come in the line **before** `attrs.define`. + + .. versionadded:: 20.1.0 + .. versionadded:: 21.1.0 *attribs* + .. versionadded:: 23.1.0 *include_extras* + """ + # Since calling get_type_hints is expensive we cache whether we've + # done it already. + if getattr(cls, "__attrs_types_resolved__", None) != cls: + import typing + + kwargs = { + "globalns": globalns, + "localns": localns, + "include_extras": include_extras, + } + + hints = typing.get_type_hints(cls, **kwargs) + for field in fields(cls) if attribs is None else attribs: + if field.name in hints: + # Since fields have been frozen we must work around it. + _OBJ_SETATTR(field, "type", hints[field.name]) + # We store the class we resolved so that subclasses know they haven't + # been resolved. + cls.__attrs_types_resolved__ = cls + + # Return the class so you can use it as a decorator too. + return cls diff --git a/source/target-vendors/cp312/attr/_make.py b/source/target-vendors/cp312/attr/_make.py new file mode 100644 index 0000000..4b32d6a --- /dev/null +++ b/source/target-vendors/cp312/attr/_make.py @@ -0,0 +1,3406 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +import abc +import contextlib +import copy +import enum +import inspect +import itertools +import linecache +import sys +import types +import unicodedata +import weakref + +from collections.abc import Callable, Mapping +from functools import cached_property +from typing import Any, NamedTuple, TypeVar + +# We need to import _compat itself in addition to the _compat members to avoid +# having the thread-local in the globals here. +from . import _compat, _config, setters +from ._compat import ( + PY_3_10_PLUS, + PY_3_11_PLUS, + PY_3_13_PLUS, + _AnnotationExtractor, + _get_annotations, + get_generic_base, +) +from .exceptions import ( + DefaultAlreadySetError, + FrozenInstanceError, + NotAnAttrsClassError, + UnannotatedAttributeError, +) + + +# This is used at least twice, so cache it here. +_OBJ_SETATTR = object.__setattr__ +_INIT_FACTORY_PAT = "__attr_factory_%s" +_CLASSVAR_PREFIXES = ( + "typing.ClassVar", + "t.ClassVar", + "ClassVar", + "typing_extensions.ClassVar", +) +# we don't use a double-underscore prefix because that triggers +# name mangling when trying to create a slot for the field +# (when slots=True) +_HASH_CACHE_FIELD = "_attrs_cached_hash" + +_EMPTY_METADATA_SINGLETON = types.MappingProxyType({}) + +# Unique object for unequivocal getattr() defaults. +_SENTINEL = object() + +_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate) + + +class _Nothing(enum.Enum): + """ + Sentinel to indicate the lack of a value when `None` is ambiguous. + + If extending attrs, you can use ``typing.Literal[NOTHING]`` to show + that a value may be ``NOTHING``. + + .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. + .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. + """ + + NOTHING = enum.auto() + + def __repr__(self): + return "NOTHING" + + def __bool__(self): + return False + + +NOTHING = _Nothing.NOTHING +""" +Sentinel to indicate the lack of a value when `None` is ambiguous. + +When using in 3rd party code, use `attrs.NothingType` for type annotations. +""" + + +class _CacheHashWrapper(int): + """ + An integer subclass that pickles / copies as None + + This is used for non-slots classes with ``cache_hash=True``, to avoid + serializing a potentially (even likely) invalid hash value. Since `None` + is the default value for uncalculated hashes, whenever this is copied, + the copy's value for the hash should automatically reset. + + See GH #613 for more details. + """ + + def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 + return _none_constructor, _args + + +def attrib( + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=None, + eq=None, + order=None, + on_setattr=None, + alias=None, +): + """ + Create a new field / attribute on a class. + + Identical to `attrs.field`, except it's not keyword-only. + + Consider using `attrs.field` in new code (``attr.ib`` will *never* go away, + though). + + .. warning:: + + Does **nothing** unless the class is also decorated with + `attr.s` (or similar)! + + + .. versionadded:: 15.2.0 *convert* + .. versionadded:: 16.3.0 *metadata* + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 + *hash* is `None` and therefore mirrors *eq* by default. + .. versionadded:: 17.3.0 *type* + .. deprecated:: 17.4.0 *convert* + .. versionadded:: 17.4.0 + *converter* as a replacement for the deprecated *convert* to achieve + consistency with other noun-based arguments. + .. versionadded:: 18.1.0 + ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. + .. versionadded:: 18.2.0 *kw_only* + .. versionchanged:: 19.2.0 *convert* keyword argument removed. + .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 22.2.0 *alias* + .. versionchanged:: 25.4.0 + *kw_only* can now be None, and its default is also changed from False to + None. + """ + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq, order, True + ) + + if hash is not None and hash is not True and hash is not False: + msg = "Invalid value for hash. Must be True, False, or None." + raise TypeError(msg) + + if factory is not None: + if default is not NOTHING: + msg = ( + "The `default` and `factory` arguments are mutually exclusive." + ) + raise ValueError(msg) + if not callable(factory): + msg = "The `factory` argument must be a callable." + raise ValueError(msg) + default = Factory(factory) + + if metadata is None: + metadata = {} + + # Apply syntactic sugar by auto-wrapping. + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + if validator and isinstance(validator, (list, tuple)): + validator = and_(*validator) + + if converter and isinstance(converter, (list, tuple)): + converter = pipe(*converter) + + return _CountingAttr( + default=default, + validator=validator, + repr=repr, + cmp=None, + hash=hash, + init=init, + converter=converter, + metadata=metadata, + type=type, + kw_only=kw_only, + eq=eq, + eq_key=eq_key, + order=order, + order_key=order_key, + on_setattr=on_setattr, + alias=alias, + ) + + +def _compile_and_eval( + script: str, + globs: dict[str, Any] | None, + locs: Mapping[str, object] | None = None, + filename: str = "", +) -> None: + """ + Evaluate the script with the given global (globs) and local (locs) + variables. + """ + bytecode = compile(script, filename, "exec") + eval(bytecode, globs, locs) + + +def _linecache_and_compile( + script: str, + filename: str, + globs: dict[str, Any] | None, + locals: Mapping[str, object] | None = None, +) -> dict[str, Any]: + """ + Cache the script with _linecache_, compile it and return the _locals_. + """ + + locs = {} if locals is None else locals + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + count = 1 + base_filename = filename + while True: + linecache_tuple = ( + len(script), + None, + script.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(filename, linecache_tuple) + if old_val == linecache_tuple: + break + + filename = f"{base_filename[:-1]}-{count}>" + count += 1 + + _compile_and_eval(script, globs, locs, filename) + + return locs + + +def _make_attr_tuple_class(cls_name: str, attr_names: list[str]) -> type: + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = f"{cls_name}Attributes" + body = {} + for i, attr_name in enumerate(attr_names): + + def getter(self, i=i): + return self[i] + + body[attr_name] = property(getter) + return type(attr_class_name, (tuple,), body) + + +# Tuple class for extracted attributes from a class definition. +# `base_attrs` is a subset of `attrs`. +class _Attributes(NamedTuple): + attrs: type + base_attrs: list[Attribute] + base_attrs_map: dict[str, type] + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The string comparison hack is used to avoid evaluating all string + annotations which would put attrs-based classes at a performance + disadvantage compared to plain old classes. + """ + annot = str(annot) + + # Annotation can be quoted. + if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): + annot = annot[1:-1] + + return annot.startswith(_CLASSVAR_PREFIXES) + + +def _has_own_attribute(cls, attrib_name): + """ + Check whether *cls* defines *attrib_name* (and doesn't just inherit it). + """ + return attrib_name in cls.__dict__ + + +def _collect_base_attrs( + cls, taken_attr_names +) -> tuple[list[Attribute], dict[str, type]]: + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in reversed(cls.__mro__[1:-1]): + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.inherited or a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) # noqa: PLW2901 + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + # For each name, only keep the freshest definition i.e. the furthest at the + # back. base_attr_map is fine because it gets overwritten with every new + # instance. + filtered = [] + seen = set() + for a in reversed(base_attrs): + if a.name in seen: + continue + filtered.insert(0, a) + seen.add(a.name) + + return filtered, base_attr_map + + +def _collect_base_attrs_broken(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + + N.B. *taken_attr_names* will be mutated. + + Adhere to the old incorrect behavior. + + Notably it collects from the front and considers inherited attributes which + leads to the buggy behavior reported in #428. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in cls.__mro__[1:-1]: + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) # noqa: PLW2901 + taken_attr_names.add(a.name) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + return base_attrs, base_attr_map + + +def _transform_attrs( + cls, + these, + auto_attribs, + kw_only, + collect_by_mro, + field_transformer, +) -> _Attributes: + """ + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + + If *collect_by_mro* is True, collect them in the correct MRO order, + otherwise use the old -- incorrect -- order. See #428. + + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: + ca_list = list(these.items()) + elif auto_attribs is True: + ca_names = { + name + for name, attr in cd.items() + if attr.__class__ is _CountingAttr + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + + if a.__class__ is not _CountingAttr: + a = attrib(a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if unannotated: + raise UnannotatedAttributeError( + "The following `attr.ib`s lack a type annotation: " + + ", ".join( + sorted(unannotated, key=lambda n: cd.get(n).counter) + ) + + "." + ) + else: + ca_list = sorted( + ( + (name, attr) + for name, attr in cd.items() + if attr.__class__ is _CountingAttr + ), + key=lambda e: e[1].counter, + ) + + fca = Attribute.from_counting_attr + no = ClassProps.KeywordOnly.NO + own_attrs = [ + fca( + attr_name, + ca, + kw_only is not no, + anns.get(attr_name), + ) + for attr_name, ca in ca_list + ] + + if collect_by_mro: + base_attrs, base_attr_map = _collect_base_attrs( + cls, {a.name for a in own_attrs} + ) + else: + base_attrs, base_attr_map = _collect_base_attrs_broken( + cls, {a.name for a in own_attrs} + ) + + if kw_only is ClassProps.KeywordOnly.FORCE: + own_attrs = [a.evolve(kw_only=True) for a in own_attrs] + base_attrs = [a.evolve(kw_only=True) for a in base_attrs] + + attrs = base_attrs + own_attrs + + # Resolve default field alias before executing field_transformer, so that + # the transformer receives fully populated Attribute objects with usable + # alias values. + for a in attrs: + if not a.alias: + # Evolve is very slow, so we hold our nose and do it dirty. + _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) + _OBJ_SETATTR.__get__(a)("alias_is_default", True) + + if field_transformer is not None: + attrs = tuple(field_transformer(cls, attrs)) + + # Check attr order after executing the field_transformer. + # Mandatory vs non-mandatory attr order only matters when they are part of + # the __init__ signature and when they aren't kw_only (which are moved to + # the end and can be mandatory or non-mandatory in any order, as they will + # be specified as keyword args anyway). Check the order of those attrs: + had_default = False + for a in (a for a in attrs if a.init is not False and a.kw_only is False): + if had_default is True and a.default is NOTHING: + msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" + raise ValueError(msg) + + if had_default is False and a.default is not NOTHING: + had_default = True + + # Resolve default field alias for any new attributes that the + # field_transformer may have added without setting an alias. + for a in attrs: + if not a.alias: + _OBJ_SETATTR.__get__(a)("alias", _default_init_alias_for(a.name)) + _OBJ_SETATTR.__get__(a)("alias_is_default", True) + + # Create AttrsClass *after* applying the field_transformer since it may + # add or remove attributes! + attr_names = [a.name for a in attrs] + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + return _Attributes(AttrsClass(attrs), base_attrs, base_attr_map) + + +def _make_cached_property_getattr(cached_properties, original_getattr, cls): + lines = [ + # Wrapped to get `__class__` into closure cell for super() + # (It will be replaced with the newly constructed class after construction). + "def wrapper(_cls):", + " __class__ = _cls", + " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", + " func = cached_properties.get(item)", + " if func is not None:", + " result = func(self)", + " _setter = _cached_setattr_get(self)", + " _setter(item, result)", + " return result", + ] + if original_getattr is not None: + lines.append( + " return original_getattr(self, item)", + ) + else: + lines.extend( + [ + " try:", + " return super().__getattribute__(item)", + " except AttributeError:", + " if not hasattr(super(), '__getattr__'):", + " raise", + " return super().__getattr__(item)", + " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", + " raise AttributeError(original_error)", + ] + ) + + lines.extend( + [ + " return __getattr__", + "__getattr__ = wrapper(_cls)", + ] + ) + + unique_filename = _generate_unique_filename(cls, "getattr") + + glob = { + "cached_properties": cached_properties, + "_cached_setattr_get": _OBJ_SETATTR.__get__, + "original_getattr": original_getattr, + } + + return _linecache_and_compile( + "\n".join(lines), unique_filename, glob, locals={"_cls": cls} + )["__getattr__"] + + +def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + if isinstance(self, BaseException) and name in ( + "__cause__", + "__context__", + "__traceback__", + "__suppress_context__", + "__notes__", + ): + BaseException.__setattr__(self, name, value) + return + + raise FrozenInstanceError + + +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + if isinstance(self, BaseException) and name == "__notes__": + BaseException.__delattr__(self, name) + return + + raise FrozenInstanceError + + +def evolve(*args, **changes): + """ + Create a new instance, based on the first positional argument with + *changes* applied. + + .. tip:: + + On Python 3.13 and later, you can also use `copy.replace` instead. + + Args: + + inst: + Instance of a class with *attrs* attributes. *inst* must be passed + as a positional argument. + + changes: + Keyword changes in the new copy. + + Returns: + A copy of inst with *changes* incorporated. + + Raises: + TypeError: + If *attr_name* couldn't be found in the class ``__init__``. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + .. versionadded:: 17.1.0 + .. deprecated:: 23.1.0 + It is now deprecated to pass the instance using the keyword argument + *inst*. It will raise a warning until at least April 2024, after which + it will become an error. Always pass the instance as a positional + argument. + .. versionchanged:: 24.1.0 + *inst* can't be passed as a keyword argument anymore. + """ + try: + (inst,) = args + except ValueError: + msg = ( + f"evolve() takes 1 positional argument, but {len(args)} were given" + ) + raise TypeError(msg) from None + + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = a.alias + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + + return cls(**changes) + + +class _ClassBuilder: + """ + Iteratively build *one* class. + """ + + __slots__ = ( + "_add_method_dunders", + "_attr_names", + "_attrs", + "_base_attr_map", + "_base_names", + "_cache_hash", + "_cls", + "_cls_dict", + "_delete_attribs", + "_frozen", + "_has_custom_setattr", + "_has_post_init", + "_has_pre_init", + "_is_exc", + "_on_setattr", + "_pre_init_has_args", + "_repr_added", + "_script_snippets", + "_slots", + "_weakref_slot", + "_wrote_own_setattr", + ) + + def __init__( + self, + cls: type, + these, + auto_attribs: bool, + props: ClassProps, + has_custom_setattr: bool, + ): + attrs, base_attrs, base_map = _transform_attrs( + cls, + these, + auto_attribs, + props.kw_only, + props.collected_fields_by_mro, + props.field_transformer, + ) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if props.is_slotted else {} + self._attrs = attrs + self._base_names = {a.name for a in base_attrs} + self._base_attr_map = base_map + self._attr_names = tuple(a.name for a in attrs) + self._slots = props.is_slotted + self._frozen = props.is_frozen + self._weakref_slot = props.has_weakref_slot + self._cache_hash = ( + props.hashability is ClassProps.Hashability.HASHABLE_CACHED + ) + self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) + self._pre_init_has_args = False + if self._has_pre_init: + # Check if the pre init method has more arguments than just `self` + # We want to pass arguments if pre init expects arguments + pre_init_func = cls.__attrs_pre_init__ + pre_init_signature = inspect.signature(pre_init_func) + self._pre_init_has_args = len(pre_init_signature.parameters) > 1 + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + self._delete_attribs = not bool(these) + self._is_exc = props.is_exception + self._on_setattr = props.on_setattr_hook + + self._has_custom_setattr = has_custom_setattr + self._wrote_own_setattr = False + + self._cls_dict["__attrs_attrs__"] = self._attrs + self._cls_dict["__attrs_props__"] = props + + if props.is_frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + + self._wrote_own_setattr = True + elif self._on_setattr in ( + _DEFAULT_ON_SETATTR, + setters.validate, + setters.convert, + ): + has_validator = has_converter = False + for a in attrs: + if a.validator is not None: + has_validator = True + if a.converter is not None: + has_converter = True + + if has_validator and has_converter: + break + if ( + ( + self._on_setattr == _DEFAULT_ON_SETATTR + and not (has_validator or has_converter) + ) + or (self._on_setattr == setters.validate and not has_validator) + or (self._on_setattr == setters.convert and not has_converter) + ): + # If class-level on_setattr is set to convert + validate, but + # there's no field to convert or validate, pretend like there's + # no on_setattr. + self._on_setattr = None + + if props.added_pickling: + ( + self._cls_dict["__getstate__"], + self._cls_dict["__setstate__"], + ) = self._make_getstate_setstate() + + # tuples of script, globs, hook + self._script_snippets: list[ + tuple[str, dict, Callable[[dict, dict], Any]] + ] = [] + self._repr_added = False + + # We want to only do this check once; in 99.9% of cases these + # exist. + if not hasattr(self._cls, "__module__") or not hasattr( + self._cls, "__qualname__" + ): + self._add_method_dunders = self._add_method_dunders_safe + else: + self._add_method_dunders = self._add_method_dunders_unsafe + + def __repr__(self): + return f"<_ClassBuilder(cls={self._cls.__name__})>" + + def _eval_snippets(self) -> None: + """ + Evaluate any registered snippets in one go. + """ + script = "\n".join([snippet[0] for snippet in self._script_snippets]) + globs = {} + for _, snippet_globs, _ in self._script_snippets: + globs.update(snippet_globs) + + locs = _linecache_and_compile( + script, + _generate_unique_filename(self._cls, "methods"), + globs, + ) + + for _, _, hook in self._script_snippets: + hook(self._cls_dict, locs) + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used after calling this method. + """ + self._eval_snippets() + if self._slots is True: + cls = self._create_slots_class() + self._cls.__attrs_base_of_slotted__ = weakref.ref(cls) + else: + cls = self._patch_original_class() + if PY_3_10_PLUS: + cls = abc.update_abstractmethods(cls) + + # The method gets only called if it's not inherited from a base class. + # _has_own_attribute does NOT work properly for classmethods. + if ( + getattr(cls, "__attrs_init_subclass__", None) + and "__attrs_init_subclass__" not in cls.__dict__ + ): + cls.__attrs_init_subclass__() + + return cls + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls + base_names = self._base_names + + # Clean class of attribute definitions (`attr.ib()`s). + if self._delete_attribs: + for name in self._attr_names: + if ( + name not in base_names + and getattr(cls, name, _SENTINEL) is not _SENTINEL + ): + # An AttributeError can happen if a base class defines a + # class variable and we want to set an attribute with the + # same name by using only a type annotation. + with contextlib.suppress(AttributeError): + delattr(cls, name) + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + + # If we've inherited an attrs __setattr__ and don't write our own, + # reset it to object's. + if not self._wrote_own_setattr and getattr( + cls, "__attrs_own_setattr__", False + ): + cls.__attrs_own_setattr__ = False + + if not self._has_custom_setattr: + cls.__setattr__ = _OBJ_SETATTR + + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + cd = { + k: v + for k, v in self._cls_dict.items() + if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") + } + + # 3.14.0rc2+ + if hasattr(sys, "_clear_type_descriptors"): + sys._clear_type_descriptors(self._cls) + + # If our class doesn't have its own implementation of __setattr__ + # (either from the user or by us), check the bases, if one of them has + # an attrs-made __setattr__, that needs to be reset. We don't walk the + # MRO because we only care about our immediate base classes. + # XXX: This can be confused by subclassing a slotted attrs class with + # XXX: a non-attrs class and subclass the resulting class with an attrs + # XXX: class. See `test_slotted_confused` for details. For now that's + # XXX: OK with us. + if not self._wrote_own_setattr: + cd["__attrs_own_setattr__"] = False + + if not self._has_custom_setattr: + for base_cls in self._cls.__bases__: + if base_cls.__dict__.get("__attrs_own_setattr__", False): + cd["__setattr__"] = _OBJ_SETATTR + break + + # Traverse the MRO to collect existing slots + # and check for an existing __weakref__. + existing_slots = {} + weakref_inherited = False + for base_cls in self._cls.__mro__[1:-1]: + if base_cls.__dict__.get("__weakref__", None) is not None: + weakref_inherited = True + existing_slots.update( + { + name: getattr(base_cls, name) + for name in getattr(base_cls, "__slots__", []) + } + ) + + base_names = set(self._base_names) + + names = self._attr_names + if ( + self._weakref_slot + and "__weakref__" not in getattr(self._cls, "__slots__", ()) + and "__weakref__" not in names + and not weakref_inherited + ): + names += ("__weakref__",) + + cached_properties = { + name: cached_prop.func + for name, cached_prop in cd.items() + if isinstance(cached_prop, cached_property) + } + + # Collect methods with a `__class__` reference that are shadowed in the new class. + # To know to update them. + additional_closure_functions_to_update = [] + if cached_properties: + class_annotations = _get_annotations(self._cls) + for name, func in cached_properties.items(): + # Add cached properties to names for slotting. + names += (name,) + # Clear out function from class to avoid clashing. + del cd[name] + additional_closure_functions_to_update.append(func) + annotation = inspect.signature(func).return_annotation + if annotation is not inspect.Parameter.empty: + class_annotations[name] = annotation + + original_getattr = cd.get("__getattr__") + if original_getattr is not None: + additional_closure_functions_to_update.append(original_getattr) + + cd["__getattr__"] = _make_cached_property_getattr( + cached_properties, original_getattr, self._cls + ) + + # We only add the names of attributes that aren't inherited. + # Setting __slots__ to inherited attributes wastes memory. + slot_names = [name for name in names if name not in base_names] + + # There are slots for attributes from current class + # that are defined in parent classes. + # As their descriptors may be overridden by a child class, + # we collect them here and update the class dict + reused_slots = { + slot: slot_descriptor + for slot, slot_descriptor in existing_slots.items() + if slot in slot_names + } + slot_names = [name for name in slot_names if name not in reused_slots] + cd.update(reused_slots) + if self._cache_hash: + slot_names.append(_HASH_CACHE_FIELD) + + cd["__slots__"] = tuple(slot_names) + + cd["__qualname__"] = self._cls.__qualname__ + + # Create new class based on old class and our methods. + cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) + + # The following is a fix for + # . + # If a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in itertools.chain( + cls.__dict__.values(), additional_closure_functions_to_update + ): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) + elif isinstance(item, property): + # Workaround for property `super()` shortcut (PY3-only). + # There is no universal way for other descriptors. + closure_cells = getattr(item.fget, "__closure__", None) + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: + try: + match = cell.cell_contents is self._cls + except ValueError: # noqa: PERF203 + # ValueError: Cell is empty + pass + else: + if match: + cell.cell_contents = cls + return cls + + def add_repr(self, ns): + script, globs = _make_repr_script(self._attrs, ns) + + def _attach_repr(cls_dict, globs): + cls_dict["__repr__"] = self._add_method_dunders(globs["__repr__"]) + + self._script_snippets.append((script, globs, _attach_repr)) + self._repr_added = True + return self + + def add_str(self): + if not self._repr_added: + msg = "__str__ can only be generated if a __repr__ exists." + raise ValueError(msg) + + def __str__(self): + return self.__repr__() + + self._cls_dict["__str__"] = self._add_method_dunders(__str__) + return self + + def _make_getstate_setstate(self): + """ + Create custom __setstate__ and __getstate__ methods. + """ + # __weakref__ is not writable. + state_attr_names = tuple( + an for an in self._attr_names if an != "__weakref__" + ) + + def slots_getstate(self): + """ + Automatically created by attrs. + """ + return {name: getattr(self, name) for name in state_attr_names} + + hash_caching_enabled = self._cache_hash + + def slots_setstate(self, state): + """ + Automatically created by attrs. + """ + __bound_setattr = _OBJ_SETATTR.__get__(self) + if isinstance(state, tuple): + # Backward compatibility with attrs instances pickled with + # attrs versions before v22.2.0 which stored tuples. + for name, value in zip(state_attr_names, state): + __bound_setattr(name, value) + else: + for name in state_attr_names: + if name in state: + __bound_setattr(name, state[name]) + + # The hash code cache is not included when the object is + # serialized, but it still needs to be initialized to None to + # indicate that the first call to __hash__ should be a cache + # miss. + if hash_caching_enabled: + __bound_setattr(_HASH_CACHE_FIELD, None) + + return slots_getstate, slots_setstate + + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + script, globs = _make_hash_script( + self._cls, + self._attrs, + frozen=self._frozen, + cache_hash=self._cache_hash, + ) + + def attach_hash(cls_dict: dict, locs: dict) -> None: + cls_dict["__hash__"] = self._add_method_dunders(locs["__hash__"]) + + self._script_snippets.append((script, globs, attach_hash)) + + return self + + def add_init(self): + script, globs, annotations = _make_init_script( + self._cls, + self._attrs, + self._has_pre_init, + self._pre_init_has_args, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=False, + ) + + def _attach_init(cls_dict, globs): + init = globs["__init__"] + init.__annotations__ = annotations + cls_dict["__init__"] = self._add_method_dunders(init) + + self._script_snippets.append((script, globs, _attach_init)) + + return self + + def add_replace(self): + self._cls_dict["__replace__"] = self._add_method_dunders(evolve) + return self + + def add_match_args(self): + self._cls_dict["__match_args__"] = tuple( + field.name + for field in self._attrs + if field.init and not field.kw_only + ) + + def add_attrs_init(self): + script, globs, annotations = _make_init_script( + self._cls, + self._attrs, + self._has_pre_init, + self._pre_init_has_args, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=True, + ) + + def _attach_attrs_init(cls_dict, globs): + init = globs["__attrs_init__"] + init.__annotations__ = annotations + cls_dict["__attrs_init__"] = self._add_method_dunders(init) + + self._script_snippets.append((script, globs, _attach_attrs_init)) + + return self + + def add_eq(self): + cd = self._cls_dict + + script, globs = _make_eq_script(self._attrs) + + def _attach_eq(cls_dict, globs): + cls_dict["__eq__"] = self._add_method_dunders(globs["__eq__"]) + + self._script_snippets.append((script, globs, _attach_eq)) + + cd["__ne__"] = __ne__ + + return self + + def add_order(self): + cd = self._cls_dict + + cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( + self._add_method_dunders(meth) + for meth in _make_order(self._cls, self._attrs) + ) + + return self + + def add_setattr(self): + sa_attrs = {} + for a in self._attrs: + on_setattr = a.on_setattr or self._on_setattr + if on_setattr and on_setattr is not setters.NO_OP: + sa_attrs[a.name] = a, on_setattr + + if not sa_attrs: + return self + + if self._has_custom_setattr: + # We need to write a __setattr__ but there already is one! + msg = "Can't combine custom __setattr__ with on_setattr hooks." + raise ValueError(msg) + + # docstring comes from _add_method_dunders + def __setattr__(self, name, val): + try: + a, hook = sa_attrs[name] + except KeyError: + nval = val + else: + nval = hook(self, a, val) + + _OBJ_SETATTR(self, name, nval) + + self._cls_dict["__attrs_own_setattr__"] = True + self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) + self._wrote_own_setattr = True + + return self + + def _add_method_dunders_unsafe(self, method: Callable) -> Callable: + """ + Add __module__ and __qualname__ to a *method*. + """ + method.__module__ = self._cls.__module__ + + method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" + + method.__doc__ = ( + f"Method generated by attrs for class {self._cls.__qualname__}." + ) + + return method + + def _add_method_dunders_safe(self, method: Callable) -> Callable: + """ + Add __module__ and __qualname__ to a *method* if possible. + """ + with contextlib.suppress(AttributeError): + method.__module__ = self._cls.__module__ + + with contextlib.suppress(AttributeError): + method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" + + with contextlib.suppress(AttributeError): + method.__doc__ = f"Method generated by attrs for class {self._cls.__qualname__}." + + return method + + +def _determine_attrs_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + msg = "Don't mix `cmp` with `eq' and `order`." + raise ValueError(msg) + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + return cmp, cmp + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq = default_eq + + if order is None: + order = eq + + if eq is False and order is True: + msg = "`order` can only be True if `eq` is True too." + raise ValueError(msg) + + return eq, order + + +def _determine_attrib_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + msg = "Don't mix `cmp` with `eq' and `order`." + raise ValueError(msg) + + def decide_callable_or_boolean(value): + """ + Decide whether a key function is used. + """ + if callable(value): + value, key = True, value + else: + key = None + return value, key + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + cmp, cmp_key = decide_callable_or_boolean(cmp) + return cmp, cmp_key, cmp, cmp_key + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq, eq_key = default_eq, None + else: + eq, eq_key = decide_callable_or_boolean(eq) + + if order is None: + order, order_key = eq, eq_key + else: + order, order_key = decide_callable_or_boolean(order) + + if eq is False and order is True: + msg = "`order` can only be True if `eq` is True too." + raise ValueError(msg) + + return eq, eq_key, order, order_key + + +def _determine_whether_to_implement( + cls, flag, auto_detect, dunders, default=True +): + """ + Check whether we should implement a set of methods for *cls*. + + *flag* is the argument passed into @attr.s like 'init', *auto_detect* the + same as passed into @attr.s and *dunders* is a tuple of attribute names + whose presence signal that the user has implemented it themselves. + + Return *default* if no reason for either for or against is found. + """ + if flag is True or flag is False: + return flag + + if flag is None and auto_detect is False: + return default + + # Logically, flag is None and auto_detect is True here. + for dunder in dunders: + if _has_own_attribute(cls, dunder): + return False + + return default + + +def attrs( + maybe_cls=None, + these=None, + repr_ns=None, + repr=None, + cmp=None, + hash=None, + init=None, + slots=False, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=False, + kw_only=False, + cache_hash=False, + auto_exc=False, + eq=None, + order=None, + auto_detect=False, + collect_by_mro=False, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, + unsafe_hash=None, + force_kw_only=True, +): + r""" + A class decorator that adds :term:`dunder methods` according to the + specified attributes using `attr.ib` or the *these* argument. + + Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will + *never* go away, though). + + Args: + repr_ns (str): + When using nested classes, there was no way in Python 2 to + automatically detect that. This argument allows to set a custom + name for a more meaningful ``repr`` output. This argument is + pointless in Python 3 and is therefore deprecated. + + .. caution:: + Refer to `attrs.define` for the rest of the parameters, but note that they + can have different defaults. + + Notably, leaving *on_setattr* as `None` will **not** add any hooks. + + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str* + .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. + .. versionchanged:: 17.1.0 + *hash* supports `None` as value which is also the default now. + .. versionadded:: 17.3.0 *auto_attribs* + .. versionchanged:: 18.1.0 + If *these* is passed, no attributes are deleted from the class body. + .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. + .. versionadded:: 18.2.0 *weakref_slot* + .. deprecated:: 18.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a + `DeprecationWarning` if the classes compared are subclasses of + each other. ``__eq`` and ``__ne__`` never tried to compared subclasses + to each other. + .. versionchanged:: 19.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider + subclasses comparable anymore. + .. versionadded:: 18.2.0 *kw_only* + .. versionadded:: 18.2.0 *cache_hash* + .. versionadded:: 19.1.0 *auto_exc* + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *auto_detect* + .. versionadded:: 20.1.0 *collect_by_mro* + .. versionadded:: 20.1.0 *getstate_setstate* + .. versionadded:: 20.1.0 *on_setattr* + .. versionadded:: 20.3.0 *field_transformer* + .. versionchanged:: 21.1.0 + ``init=False`` injects ``__attrs_init__`` + .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 21.3.0 *match_args* + .. versionadded:: 22.2.0 + *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). + .. deprecated:: 24.1.0 *repr_ns* + .. versionchanged:: 24.1.0 + Instances are not compared as tuples of attributes anymore, but using a + big ``and`` condition. This is faster and has more correct behavior for + uncomparable values like `math.nan`. + .. versionadded:: 24.1.0 + If a class has an *inherited* classmethod called + ``__attrs_init_subclass__``, it is executed after the class is created. + .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. + .. versionchanged:: 25.4.0 + *kw_only* now only applies to attributes defined in the current class, + and respects attribute-level ``kw_only=False`` settings. + .. versionadded:: 25.4.0 *force_kw_only* + """ + if repr_ns is not None: + import warnings + + warnings.warn( + DeprecationWarning( + "The `repr_ns` argument is deprecated and will be removed in or after August 2025." + ), + stacklevel=2, + ) + + eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) + + # unsafe_hash takes precedence due to PEP 681. + if unsafe_hash is not None: + hash = unsafe_hash + + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + def wrap(cls): + nonlocal hash + is_frozen = frozen or _has_frozen_base_class(cls) + is_exc = auto_exc is True and issubclass(cls, BaseException) + has_own_setattr = auto_detect and _has_own_attribute( + cls, "__setattr__" + ) + + if has_own_setattr and is_frozen: + msg = "Can't freeze a class with a custom __setattr__." + raise ValueError(msg) + + eq = not is_exc and _determine_whether_to_implement( + cls, eq_, auto_detect, ("__eq__", "__ne__") + ) + + Hashability = ClassProps.Hashability + + if is_exc: + hashability = Hashability.LEAVE_ALONE + elif hash is True: + hashability = ( + Hashability.HASHABLE_CACHED + if cache_hash + else Hashability.HASHABLE + ) + elif hash is False: + hashability = Hashability.LEAVE_ALONE + elif hash is None: + if auto_detect is True and _has_own_attribute(cls, "__hash__"): + hashability = Hashability.LEAVE_ALONE + elif eq is True and is_frozen is True: + hashability = ( + Hashability.HASHABLE_CACHED + if cache_hash + else Hashability.HASHABLE + ) + elif eq is False: + hashability = Hashability.LEAVE_ALONE + else: + hashability = Hashability.UNHASHABLE + else: + msg = "Invalid value for hash. Must be True, False, or None." + raise TypeError(msg) + + KeywordOnly = ClassProps.KeywordOnly + if kw_only: + kwo = KeywordOnly.FORCE if force_kw_only else KeywordOnly.YES + else: + kwo = KeywordOnly.NO + + props = ClassProps( + is_exception=is_exc, + is_frozen=is_frozen, + is_slotted=slots, + collected_fields_by_mro=collect_by_mro, + added_init=_determine_whether_to_implement( + cls, init, auto_detect, ("__init__",) + ), + added_repr=_determine_whether_to_implement( + cls, repr, auto_detect, ("__repr__",) + ), + added_eq=eq, + added_ordering=not is_exc + and _determine_whether_to_implement( + cls, + order_, + auto_detect, + ("__lt__", "__le__", "__gt__", "__ge__"), + ), + hashability=hashability, + added_match_args=match_args, + kw_only=kwo, + has_weakref_slot=weakref_slot, + added_str=str, + added_pickling=_determine_whether_to_implement( + cls, + getstate_setstate, + auto_detect, + ("__getstate__", "__setstate__"), + default=slots, + ), + on_setattr_hook=on_setattr, + field_transformer=field_transformer, + ) + + if not props.is_hashable and cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." + raise TypeError(msg) + + builder = _ClassBuilder( + cls, + these, + auto_attribs=auto_attribs, + props=props, + has_custom_setattr=has_own_setattr, + ) + + if props.added_repr: + builder.add_repr(repr_ns) + + if props.added_str: + builder.add_str() + + if props.added_eq: + builder.add_eq() + if props.added_ordering: + builder.add_order() + + if not frozen: + builder.add_setattr() + + if props.is_hashable: + builder.add_hash() + elif props.hashability is Hashability.UNHASHABLE: + builder.make_unhashable() + + if props.added_init: + builder.add_init() + else: + builder.add_attrs_init() + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, init must be True." + raise TypeError(msg) + + if PY_3_13_PLUS and not _has_own_attribute(cls, "__replace__"): + builder.add_replace() + + if ( + PY_3_10_PLUS + and match_args + and not _has_own_attribute(cls, "__match_args__") + ): + builder.add_match_args() + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but `None` if used as `@attrs()`. + if maybe_cls is None: + return wrap + + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ is _frozen_setattrs + + +def _generate_unique_filename(cls: type, func_name: str) -> str: + """ + Create a "filename" suitable for a function being generated. + """ + return ( + f"" + ) + + +def _make_hash_script( + cls: type, attrs: list[Attribute], frozen: bool, cache_hash: bool +) -> tuple[str, dict]: + attrs = tuple( + a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) + ) + + tab = " " + + type_hash = hash(_generate_unique_filename(cls, "hash")) + # If eq is custom generated, we need to include the functions in globs + globs = {} + + hash_def = "def __hash__(self" + hash_func = "hash((" + closing_braces = "))" + if not cache_hash: + hash_def += "):" + else: + hash_def += ", *" + + hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" + hash_func = "_cache_wrapper(" + hash_func + closing_braces += ")" + + method_lines = [hash_def] + + def append_hash_computation_lines(prefix, indent): + """ + Generate the code for actually computing the hash code. + Below this will either be returned directly or used to compute + a value which is then cached, depending on the value of cache_hash + """ + + method_lines.extend( + [ + indent + prefix + hash_func, + indent + f" {type_hash},", + ] + ) + + for a in attrs: + if a.eq_key: + cmp_name = f"_{a.name}_key" + globs[cmp_name] = a.eq_key + method_lines.append( + indent + f" {cmp_name}(self.{a.name})," + ) + else: + method_lines.append(indent + f" self.{a.name},") + + method_lines.append(indent + " " + closing_braces) + + if cache_hash: + method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:") + if frozen: + append_hash_computation_lines( + f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2 + ) + method_lines.append(tab * 2 + ")") # close __setattr__ + else: + append_hash_computation_lines( + f"self.{_HASH_CACHE_FIELD} = ", tab * 2 + ) + method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}") + else: + append_hash_computation_lines("return ", tab) + + script = "\n".join(method_lines) + return script, globs + + +def _add_hash(cls: type, attrs: list[Attribute]): + """ + Add a hash method to *cls*. + """ + script, globs = _make_hash_script( + cls, attrs, frozen=False, cache_hash=False + ) + _compile_and_eval( + script, globs, filename=_generate_unique_filename(cls, "__hash__") + ) + cls.__hash__ = globs["__hash__"] + return cls + + +def __ne__(self, other): + """ + Check equality and either forward a NotImplemented or + return the result negated. + """ + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + + return not result + + +def _make_eq_script(attrs: list) -> tuple[str, dict]: + """ + Create __eq__ method for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.eq] + + lines = [ + "def __eq__(self, other):", + " if other.__class__ is not self.__class__:", + " return NotImplemented", + ] + + globs = {} + if attrs: + lines.append(" return (") + for a in attrs: + if a.eq_key: + cmp_name = f"_{a.name}_key" + # Add the key function to the global namespace + # of the evaluated function. + globs[cmp_name] = a.eq_key + lines.append( + f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})" + ) + else: + lines.append(f" self.{a.name} == other.{a.name}") + if a is not attrs[-1]: + lines[-1] = f"{lines[-1]} and" + lines.append(" )") + else: + lines.append(" return True") + + script = "\n".join(lines) + + return script, globs + + +def _make_order(cls, attrs): + """ + Create ordering methods for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.order] + + def attrs_to_tuple(obj): + """ + Save us some typing. + """ + return tuple( + key(value) if key else value + for value, key in ( + (getattr(obj, a.name), a.order_key) for a in attrs + ) + ) + + def __lt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) < attrs_to_tuple(other) + + return NotImplemented + + def __le__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) <= attrs_to_tuple(other) + + return NotImplemented + + def __gt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) > attrs_to_tuple(other) + + return NotImplemented + + def __ge__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) >= attrs_to_tuple(other) + + return NotImplemented + + return __lt__, __le__, __gt__, __ge__ + + +def _add_eq(cls, attrs=None): + """ + Add equality methods to *cls* with *attrs*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + script, globs = _make_eq_script(attrs) + _compile_and_eval( + script, globs, filename=_generate_unique_filename(cls, "__eq__") + ) + cls.__eq__ = globs["__eq__"] + cls.__ne__ = __ne__ + + return cls + + +def _make_repr_script(attrs, ns) -> tuple[str, dict]: + """ + Create the source and globs for a __repr__ and return it. + """ + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, (repr if a.repr is True else a.repr), a.init) + for a in attrs + if a.repr is not False + ) + globs = { + name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr + } + globs["_compat"] = _compat + globs["AttributeError"] = AttributeError + globs["NOTHING"] = NOTHING + attribute_fragments = [] + for name, r, i in attr_names_with_reprs: + accessor = ( + "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' + ) + fragment = ( + "%s={%s!r}" % (name, accessor) + if r == repr + else "%s={%s_repr(%s)}" % (name, name, accessor) + ) + attribute_fragments.append(fragment) + repr_fragment = ", ".join(attribute_fragments) + + if ns is None: + cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' + else: + cls_name_fragment = ns + ".{self.__class__.__name__}" + + lines = [ + "def __repr__(self):", + " try:", + " already_repring = _compat.repr_context.already_repring", + " except AttributeError:", + " already_repring = {id(self),}", + " _compat.repr_context.already_repring = already_repring", + " else:", + " if id(self) in already_repring:", + " return '...'", + " else:", + " already_repring.add(id(self))", + " try:", + f" return f'{cls_name_fragment}({repr_fragment})'", + " finally:", + " already_repring.remove(id(self))", + ] + + return "\n".join(lines), globs + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + script, globs = _make_repr_script(attrs, ns) + _compile_and_eval( + script, globs, filename=_generate_unique_filename(cls, "__repr__") + ) + cls.__repr__ = globs["__repr__"] + return cls + + +def fields(cls): + """ + Return the tuple of *attrs* attributes for a class or instance. + + The tuple also allows accessing the fields by their names (see below for + examples). + + Args: + cls (type): Class or instance to introspect. + + Raises: + TypeError: If *cls* is neither a class nor an *attrs* instance. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + Returns: + tuple (with name accessors) of `attrs.Attribute` + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + .. versionchanged:: 23.1.0 Add support for generic classes. + .. versionchanged:: 26.1.0 Add support for instances. + """ + generic_base = get_generic_base(cls) + + if generic_base is None and not isinstance(cls, type): + type_ = type(cls) + if getattr(type_, "__attrs_attrs__", None) is None: + msg = "Passed object must be a class or attrs instance." + raise TypeError(msg) + + return fields(type_) + + attrs = getattr(cls, "__attrs_attrs__", None) + + if attrs is None: + if generic_base is not None: + attrs = getattr(generic_base, "__attrs_attrs__", None) + if attrs is not None: + # Even though this is global state, stick it on here to speed + # it up. We rely on `cls` being cached for this to be + # efficient. + cls.__attrs_attrs__ = attrs + return attrs + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) + + return attrs + + +def fields_dict(cls): + """ + Return an ordered dictionary of *attrs* attributes for a class, whose keys + are the attribute names. + + Args: + cls (type): Class to introspect. + + Raises: + TypeError: If *cls* is not a class. + + attrs.exceptions.NotAnAttrsClassError: + If *cls* is not an *attrs* class. + + Returns: + dict[str, attrs.Attribute]: Dict of attribute name to definition + + .. versionadded:: 18.1.0 + """ + if not isinstance(cls, type): + msg = "Passed object must be a class." + raise TypeError(msg) + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) + return {a.name: a for a in attrs} + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + Args: + inst: Instance of a class with *attrs* attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _is_slot_attr(a_name, base_attr_map): + """ + Check if the attribute name comes from a slot class. + """ + cls = base_attr_map.get(a_name) + return cls and "__slots__" in cls.__dict__ + + +def _make_init_script( + cls, + attrs, + pre_init, + pre_init_has_args, + post_init, + frozen, + slots, + cache_hash, + base_attr_map, + is_exc, + cls_on_setattr, + attrs_init, +) -> tuple[str, dict, dict]: + has_cls_on_setattr = ( + cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP + ) + + if frozen and has_cls_on_setattr: + msg = "Frozen classes can't use on_setattr." + raise ValueError(msg) + + needs_cached_setattr = cache_hash or frozen + filtered_attrs = [] + attr_dict = {} + for a in attrs: + if not a.init and a.default is NOTHING: + continue + + filtered_attrs.append(a) + attr_dict[a.name] = a + + if a.on_setattr is not None: + if frozen is True and a.on_setattr is not setters.NO_OP: + msg = "Frozen classes can't use on_setattr." + raise ValueError(msg) + + needs_cached_setattr = True + elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: + needs_cached_setattr = True + + script, globs, annotations = _attrs_to_init_script( + filtered_attrs, + frozen, + slots, + pre_init, + pre_init_has_args, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + "__attrs_init__" if attrs_init else "__init__", + ) + if cls.__module__ in sys.modules: + # This makes typing.get_type_hints(CLS.__init__) resolve string types. + globs.update(sys.modules[cls.__module__].__dict__) + + globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) + + if needs_cached_setattr: + # Save the lookup overhead in __init__ if we need to circumvent + # setattr hooks. + globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__ + + return script, globs, annotations + + +def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str: + """ + Use the cached object.setattr to set *attr_name* to *value_var*. + """ + return f"_setattr('{attr_name}', {value_var})" + + +def _setattr_with_converter( + attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter +) -> str: + """ + Use the cached object.setattr to set *attr_name* to *value_var*, but run + its converter first. + """ + return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})" + + +def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str: + """ + Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise + relegate to _setattr. + """ + if has_on_setattr: + return _setattr(attr_name, value, True) + + return f"self.{attr_name} = {value}" + + +def _assign_with_converter( + attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter +) -> str: + """ + Unless *attr_name* has an on_setattr hook, use normal assignment after + conversion. Otherwise relegate to _setattr_with_converter. + """ + if has_on_setattr: + return _setattr_with_converter(attr_name, value_var, True, converter) + + return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}" + + +def _determine_setters( + frozen: bool, slots: bool, base_attr_map: dict[str, type] +): + """ + Determine the correct setter functions based on whether a class is frozen + and/or slotted. + """ + if frozen is True: + if slots is True: + return (), _setattr, _setattr_with_converter + + # Dict frozen classes assign directly to __dict__. + # But only if the attribute doesn't come from an ancestor slot + # class. + # Note _inst_dict will be used again below if cache_hash is True + + def fmt_setter( + attr_name: str, value_var: str, has_on_setattr: bool + ) -> str: + if _is_slot_attr(attr_name, base_attr_map): + return _setattr(attr_name, value_var, has_on_setattr) + + return f"_inst_dict['{attr_name}'] = {value_var}" + + def fmt_setter_with_converter( + attr_name: str, + value_var: str, + has_on_setattr: bool, + converter: Converter, + ) -> str: + if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): + return _setattr_with_converter( + attr_name, value_var, has_on_setattr, converter + ) + + return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}" + + return ( + ("_inst_dict = self.__dict__",), + fmt_setter, + fmt_setter_with_converter, + ) + + # Not frozen -- we can just assign directly. + return (), _assign, _assign_with_converter + + +def _attrs_to_init_script( + attrs: list[Attribute], + is_frozen: bool, + is_slotted: bool, + call_pre_init: bool, + pre_init_has_args: bool, + call_post_init: bool, + does_cache_hash: bool, + base_attr_map: dict[str, type], + is_exc: bool, + needs_cached_setattr: bool, + has_cls_on_setattr: bool, + method_name: str, +) -> tuple[str, dict, dict]: + """ + Return a script of an initializer for *attrs*, a dict of globals, and + annotations for the initializer. + + The globals are required by the generated script. + """ + lines = ["self.__attrs_pre_init__()"] if call_pre_init else [] + + if needs_cached_setattr: + lines.append( + # Circumvent the __setattr__ descriptor to save one lookup per + # assignment. Note _setattr will be used again below if + # does_cache_hash is True. + "_setattr = _cached_setattr_get(self)" + ) + + extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters( + is_frozen, is_slotted, base_attr_map + ) + lines.extend(extra_lines) + + args = [] # Parameters in the definition of __init__ + pre_init_args = [] # Parameters in the call to __attrs_pre_init__ + kw_only_args = [] # Used for both 'args' and 'pre_init_args' above + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} + annotations = {"return": None} + + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + + attr_name = a.name + has_on_setattr = a.on_setattr is not None or ( + a.on_setattr is not setters.NO_OP and has_cls_on_setattr + ) + # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not + # explicitly provided + arg_name = a.alias + + has_factory = isinstance(a.default, Factory) + maybe_self = "self" if has_factory and a.default.takes_self else "" + + if a.converter is not None and not isinstance(a.converter, Converter): + converter = Converter(a.converter) + else: + converter = a.converter + + if a.init is False: + if has_factory: + init_factory_name = _INIT_FACTORY_PAT % (a.name,) + if converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + init_factory_name + f"({maybe_self})", + has_on_setattr, + converter, + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append( + fmt_setter( + attr_name, + init_factory_name + f"({maybe_self})", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + elif converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + f"attr_dict['{attr_name}'].default", + has_on_setattr, + converter, + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append( + fmt_setter( + attr_name, + f"attr_dict['{attr_name}'].default", + has_on_setattr, + ) + ) + elif a.default is not NOTHING and not has_factory: + arg = f"{arg_name}=attr_dict['{attr_name}'].default" + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + pre_init_args.append(arg_name) + + if converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr, converter + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + elif has_factory: + arg = f"{arg_name}=NOTHING" + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + pre_init_args.append(arg_name) + lines.append(f"if {arg_name} is not NOTHING:") + + init_factory_name = _INIT_FACTORY_PAT % (a.name,) + if converter is not None: + lines.append( + " " + + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr, converter + ) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter_with_converter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + converter, + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append( + " " + fmt_setter(attr_name, arg_name, has_on_setattr) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.kw_only: + kw_only_args.append(arg_name) + else: + args.append(arg_name) + pre_init_args.append(arg_name) + + if converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr, converter + ) + ) + names_for_globals[converter._get_global_name(a.name)] = ( + converter.converter + ) + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + if a.init is True: + if a.type is not None and converter is None: + annotations[arg_name] = a.type + elif converter is not None and converter._first_param_type: + # Use the type from the converter if present. + annotations[arg_name] = converter._first_param_type + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: + val_name = "__attr_validator_" + a.name + attr_name = "__attr_" + a.name + lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + + if call_post_init: + lines.append("self.__attrs_post_init__()") + + # Because this is set only after __attrs_post_init__ is called, a crash + # will result if post-init tries to access the hash code. This seemed + # preferable to setting this beforehand, in which case alteration to field + # values during post-init combined with post-init accessing the hash code + # would result in silent bugs. + if does_cache_hash: + if is_frozen: + if is_slotted: + init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)" + else: + init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None" + else: + init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None" + lines.append(init_hash_cache) + + # For exceptions we rely on BaseException.__init__ for proper + # initialization. + if is_exc: + vals = ",".join(f"self.{a.name}" for a in attrs if a.init) + + lines.append(f"BaseException.__init__(self, {vals})") + + args = ", ".join(args) + pre_init_args = ", ".join(pre_init_args) + if kw_only_args: + # leading comma & kw_only args + args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}" + pre_init_kw_only_args = ", ".join( + [ + f"{kw_arg_name}={kw_arg_name}" + # We need to remove the defaults from the kw_only_args. + for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args) + ] + ) + pre_init_args += ", " if pre_init_args else "" + pre_init_args += pre_init_kw_only_args + + if call_pre_init and pre_init_has_args: + # If pre init method has arguments, pass the values given to __init__. + lines[0] = f"self.__attrs_pre_init__({pre_init_args})" + + # Python <3.12 doesn't allow backslashes in f-strings. + NL = "\n " + return ( + f"""def {method_name}(self, {args}): + {NL.join(lines) if lines else "pass"} +""", + names_for_globals, + annotations, + ) + + +def _default_init_alias_for(name: str) -> str: + """ + The default __init__ parameter name for a field. + + This performs private-name adjustment via leading-unscore stripping, + and is the default value of Attribute.alias if not provided. + """ + + return name.lstrip("_") + + +class Attribute: + """ + *Read-only* representation of an attribute. + + .. warning:: + + You should never instantiate this class yourself. + + The class has *all* arguments of `attr.ib` (except for ``factory`` which is + only syntactic sugar for ``default=Factory(...)`` plus the following: + + - ``name`` (`str`): The name of the attribute. + - ``alias`` (`str`): The __init__ parameter name of the attribute, after + any explicit overrides and default private-attribute-name handling. + - ``alias_is_default`` (`bool`): Whether the ``alias`` was automatically + generated (``True``) or explicitly provided by the user (``False``). + - ``inherited`` (`bool`): Whether or not that attribute has been inherited + from a base class. + - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The + callables that are used for comparing and ordering objects by this + attribute, respectively. These are set by passing a callable to + `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also + :ref:`comparison customization `. + + Instances of this class are frequently used for introspection purposes + like: + + - `fields` returns a tuple of them. + - Validators get them passed as the first argument. + - The :ref:`field transformer ` hook receives a list of + them. + - The ``alias`` property exposes the __init__ parameter name of the field, + with any overrides and default private-attribute handling applied. + + + .. versionadded:: 20.1.0 *inherited* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.2.0 *inherited* is not taken into account for + equality checks and hashing anymore. + .. versionadded:: 21.1.0 *eq_key* and *order_key* + .. versionadded:: 22.2.0 *alias* + .. versionadded:: 26.1.0 *alias_is_default* + + For the full version history of the fields, see `attr.ib`. + """ + + # These slots must NOT be reordered because we use them later for + # instantiation. + __slots__ = ( # noqa: RUF023 + "name", + "default", + "validator", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "type", + "converter", + "kw_only", + "inherited", + "on_setattr", + "alias", + "alias_is_default", + ) + + def __init__( + self, + name, + default, + validator, + repr, + cmp, # XXX: unused, remove along with other cmp code. + hash, + init, + inherited, + metadata=None, + type=None, + converter=None, + kw_only=False, + eq=None, + eq_key=None, + order=None, + order_key=None, + on_setattr=None, + alias=None, + alias_is_default=None, + ): + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq_key or eq, order_key or order, True + ) + + # Cache this descriptor here to speed things up later. + bound_setattr = _OBJ_SETATTR.__get__(self) + + # Despite the big red warning, people *do* instantiate `Attribute` + # themselves. + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) + bound_setattr("eq", eq) + bound_setattr("eq_key", eq_key) + bound_setattr("order", order) + bound_setattr("order_key", order_key) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("converter", converter) + bound_setattr( + "metadata", + ( + types.MappingProxyType(dict(metadata)) # Shallow copy + if metadata + else _EMPTY_METADATA_SINGLETON + ), + ) + bound_setattr("type", type) + bound_setattr("kw_only", kw_only) + bound_setattr("inherited", inherited) + bound_setattr("on_setattr", on_setattr) + bound_setattr("alias", alias) + bound_setattr( + "alias_is_default", + alias is None if alias_is_default is None else alias_is_default, + ) + + def __setattr__(self, name, value): + raise FrozenInstanceError + + @classmethod + def from_counting_attr( + cls, name: str, ca: _CountingAttr, kw_only: bool, type=None + ): + # The 'kw_only' argument is the class-level setting, and is used if the + # attribute itself does not explicitly set 'kw_only'. + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + msg = f"Type annotation and type argument cannot both be present for '{name}'." + raise ValueError(msg) + return cls( + name, + ca._default, + ca._validator, + ca.repr, + None, + ca.hash, + ca.init, + False, + ca.metadata, + type, + ca.converter, + kw_only if ca.kw_only is None else ca.kw_only, + ca.eq, + ca.eq_key, + ca.order, + ca.order_key, + ca.on_setattr, + ca.alias, + ca.alias is None, + ) + + # Don't use attrs.evolve since fields(Attribute) doesn't work + def evolve(self, **changes): + """ + Copy *self* and apply *changes*. + + This works similarly to `attrs.evolve` but that function does not work + with :class:`attrs.Attribute`. + + It is mainly meant to be used for `transform-fields`. + + .. versionadded:: 20.3.0 + """ + new = copy.copy(self) + + new._setattrs(changes.items()) + + if "alias" in changes and "alias_is_default" not in changes: + # Explicit alias provided -- no longer the default. + _OBJ_SETATTR.__get__(new)("alias_is_default", False) + elif ( + "name" in changes + and "alias" not in changes + # Don't auto-generate alias if the user picked picked the old one. + and self.alias_is_default + ): + # Name changed, alias was auto-generated -- update it. + _OBJ_SETATTR.__get__(new)( + "alias", _default_init_alias_for(new.name) + ) + + return new + + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple( + getattr(self, name) if name != "metadata" else dict(self.metadata) + for name in self.__slots__ + ) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + if len(state) < len(self.__slots__): + # Pre-26.1.0 pickle without alias_is_default -- infer it + # heuristically. + state_dict = dict(zip(self.__slots__, state)) + alias_is_default = state_dict.get( + "alias" + ) is None or state_dict.get("alias") == _default_init_alias_for( + state_dict["name"] + ) + state = (*state, alias_is_default) + + self._setattrs(zip(self.__slots__, state)) + + def _setattrs(self, name_values_pairs): + bound_setattr = _OBJ_SETATTR.__get__(self) + for name, value in name_values_pairs: + if name != "metadata": + bound_setattr(name, value) + else: + bound_setattr( + name, + ( + types.MappingProxyType(dict(value)) + if value + else _EMPTY_METADATA_SINGLETON + ), + ) + + +_a = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=(name != "alias_is_default"), + cmp=None, + eq=True, + order=False, + hash=(name != "metadata"), + init=True, + inherited=False, + alias=_default_init_alias_for(name), + ) + for name in Attribute.__slots__ +] + +Attribute = _add_hash( + _add_eq( + _add_repr(Attribute, attrs=_a), + attrs=[a for a in _a if a.name != "inherited"], + ), + attrs=[a for a in _a if a.hash and a.name != "inherited"], +) + + +class _CountingAttr: + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ + + __slots__ = ( + "_default", + "_validator", + "alias", + "converter", + "counter", + "eq", + "eq_key", + "hash", + "init", + "kw_only", + "metadata", + "on_setattr", + "order", + "order_key", + "repr", + "type", + ) + __attrs_attrs__ = ( + *tuple( + Attribute( + name=name, + alias=_default_init_alias_for(name), + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=True, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ) + for name in ( + "counter", + "_default", + "repr", + "eq", + "order", + "hash", + "init", + "on_setattr", + "alias", + ) + ), + Attribute( + name="metadata", + alias="metadata", + default=None, + validator=None, + repr=True, + cmp=None, + hash=False, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ), + ) + cls_counter = 0 + + def __init__( + self, + default, + validator, + repr, + cmp, + hash, + init, + converter, + metadata, + type, + kw_only, + eq, + eq_key, + order, + order_key, + on_setattr, + alias, + ): + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default + self._validator = validator + self.converter = converter + self.repr = repr + self.eq = eq + self.eq_key = eq_key + self.order = order + self.order_key = order_key + self.hash = hash + self.init = init + self.metadata = metadata + self.type = type + self.kw_only = kw_only + self.on_setattr = on_setattr + self.alias = alias + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + Raises: + DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError + + self._default = Factory(meth, takes_self=True) + + return meth + + +_CountingAttr = _add_eq(_add_repr(_CountingAttr)) + + +class ClassProps: + """ + Effective class properties as derived from parameters to `attr.s()` or + `define()` decorators. + + This is the same data structure that *attrs* uses internally to decide how + to construct the final class. + + Warning: + + This feature is currently **experimental** and is not covered by our + strict backwards-compatibility guarantees. + + + Attributes: + is_exception (bool): + Whether the class is treated as an exception class. + + is_slotted (bool): + Whether the class is `slotted `. + + has_weakref_slot (bool): + Whether the class has a slot for weak references. + + is_frozen (bool): + Whether the class is frozen. + + kw_only (KeywordOnly): + Whether / how the class enforces keyword-only arguments on the + ``__init__`` method. + + collected_fields_by_mro (bool): + Whether the class fields were collected by method resolution order. + That is, correctly but unlike `dataclasses`. + + added_init (bool): + Whether the class has an *attrs*-generated ``__init__`` method. + + added_repr (bool): + Whether the class has an *attrs*-generated ``__repr__`` method. + + added_eq (bool): + Whether the class has *attrs*-generated equality methods. + + added_ordering (bool): + Whether the class has *attrs*-generated ordering methods. + + hashability (Hashability): How `hashable ` the class is. + + added_match_args (bool): + Whether the class supports positional `match ` over its + fields. + + added_str (bool): + Whether the class has an *attrs*-generated ``__str__`` method. + + added_pickling (bool): + Whether the class has *attrs*-generated ``__getstate__`` and + ``__setstate__`` methods for `pickle`. + + on_setattr_hook (Callable[[Any, Attribute[Any], Any], Any] | None): + The class's ``__setattr__`` hook. + + field_transformer (Callable[[Attribute[Any]], Attribute[Any]] | None): + The class's `field transformers `. + + .. versionadded:: 25.4.0 + """ + + class Hashability(enum.Enum): + """ + The hashability of a class. + + .. versionadded:: 25.4.0 + """ + + HASHABLE = "hashable" + """Write a ``__hash__``.""" + HASHABLE_CACHED = "hashable_cache" + """Write a ``__hash__`` and cache the hash.""" + UNHASHABLE = "unhashable" + """Set ``__hash__`` to ``None``.""" + LEAVE_ALONE = "leave_alone" + """Don't touch ``__hash__``.""" + + class KeywordOnly(enum.Enum): + """ + How attributes should be treated regarding keyword-only parameters. + + .. versionadded:: 25.4.0 + """ + + NO = "no" + """Attributes are not keyword-only.""" + YES = "yes" + """Attributes in current class without kw_only=False are keyword-only.""" + FORCE = "force" + """All attributes are keyword-only.""" + + __slots__ = ( # noqa: RUF023 -- order matters for __init__ + "is_exception", + "is_slotted", + "has_weakref_slot", + "is_frozen", + "kw_only", + "collected_fields_by_mro", + "added_init", + "added_repr", + "added_eq", + "added_ordering", + "hashability", + "added_match_args", + "added_str", + "added_pickling", + "on_setattr_hook", + "field_transformer", + ) + + def __init__( + self, + is_exception, + is_slotted, + has_weakref_slot, + is_frozen, + kw_only, + collected_fields_by_mro, + added_init, + added_repr, + added_eq, + added_ordering, + hashability, + added_match_args, + added_str, + added_pickling, + on_setattr_hook, + field_transformer, + ): + self.is_exception = is_exception + self.is_slotted = is_slotted + self.has_weakref_slot = has_weakref_slot + self.is_frozen = is_frozen + self.kw_only = kw_only + self.collected_fields_by_mro = collected_fields_by_mro + self.added_init = added_init + self.added_repr = added_repr + self.added_eq = added_eq + self.added_ordering = added_ordering + self.hashability = hashability + self.added_match_args = added_match_args + self.added_str = added_str + self.added_pickling = added_pickling + self.on_setattr_hook = on_setattr_hook + self.field_transformer = field_transformer + + @property + def is_hashable(self): + return ( + self.hashability is ClassProps.Hashability.HASHABLE + or self.hashability is ClassProps.Hashability.HASHABLE_CACHED + ) + + +_cas = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + alias=_default_init_alias_for(name), + ) + for name in ClassProps.__slots__ +] + +ClassProps = _add_eq(_add_repr(ClassProps, attrs=_cas), attrs=_cas) + + +class Factory: + """ + Stores a factory callable. + + If passed as the default value to `attrs.field`, the factory is used to + generate a new value. + + Args: + factory (typing.Callable): + A callable that takes either none or exactly one mandatory + positional argument depending on *takes_self*. + + takes_self (bool): + Pass the partially initialized instance that is being initialized + as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ + + __slots__ = ("factory", "takes_self") + + def __init__(self, factory, takes_self=False): + self.factory = factory + self.takes_self = takes_self + + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple(getattr(self, name) for name in self.__slots__) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + for name, value in zip(self.__slots__, state): + setattr(self, name, value) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in Factory.__slots__ +] + +Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) + + +class Converter: + """ + Stores a converter callable. + + Allows for the wrapped converter to take additional arguments. The + arguments are passed in the order they are documented. + + Args: + converter (Callable): A callable that converts the passed value. + + takes_self (bool): + Pass the partially initialized instance that is being initialized + as a positional argument. (default: `False`) + + takes_field (bool): + Pass the field definition (an :class:`Attribute`) into the + converter as a positional argument. (default: `False`) + + .. versionadded:: 24.1.0 + """ + + __slots__ = ( + "__call__", + "_first_param_type", + "_global_name", + "converter", + "takes_field", + "takes_self", + ) + + def __init__(self, converter, *, takes_self=False, takes_field=False): + self.converter = converter + self.takes_self = takes_self + self.takes_field = takes_field + + ex = _AnnotationExtractor(converter) + self._first_param_type = ex.get_first_param_type() + + if not (self.takes_self or self.takes_field): + self.__call__ = lambda value, _, __: self.converter(value) + elif self.takes_self and not self.takes_field: + self.__call__ = lambda value, instance, __: self.converter( + value, instance + ) + elif not self.takes_self and self.takes_field: + self.__call__ = lambda value, __, field: self.converter( + value, field + ) + else: + self.__call__ = self.converter + + rt = ex.get_return_type() + if rt is not None: + self.__call__.__annotations__["return"] = rt + + @staticmethod + def _get_global_name(attr_name: str) -> str: + """ + Return the name that a converter for an attribute name *attr_name* + would have. + """ + return f"__attr_converter_{attr_name}" + + def _fmt_converter_call(self, attr_name: str, value_var: str) -> str: + """ + Return a string that calls the converter for an attribute name + *attr_name* and the value in variable named *value_var* according to + `self.takes_self` and `self.takes_field`. + """ + if not (self.takes_self or self.takes_field): + return f"{self._get_global_name(attr_name)}({value_var})" + + if self.takes_self and self.takes_field: + return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])" + + if self.takes_self: + return f"{self._get_global_name(attr_name)}({value_var}, self)" + + return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])" + + def __getstate__(self): + """ + Return a dict containing only converter and takes_self -- the rest gets + computed when loading. + """ + return { + "converter": self.converter, + "takes_self": self.takes_self, + "takes_field": self.takes_field, + } + + def __setstate__(self, state): + """ + Load instance from state. + """ + self.__init__(**state) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in ("converter", "takes_self", "takes_field") +] + +Converter = _add_hash( + _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f +) + + +def make_class( + name, attrs, bases=(object,), class_body=None, **attributes_arguments +): + r""" + A quick way to create a new class called *name* with *attrs*. + + .. note:: + + ``make_class()`` is a thin wrapper around `attr.s`, not `attrs.define` + which means that it doesn't come with some of the improved defaults. + + For example, if you want the same ``on_setattr`` behavior as in + `attrs.define`, you have to pass the hooks yourself: ``make_class(..., + on_setattr=setters.pipe(setters.convert, setters.validate)`` + + .. warning:: + + It is *your* duty to ensure that the class name and the attribute names + are valid identifiers. ``make_class()`` will *not* validate them for + you. + + Args: + name (str): The name for the new class. + + attrs (list | dict): + A list of names or a dictionary of mappings of names to `attr.ib`\ + s / `attrs.field`\ s. + + The order is deduced from the order of the names or attributes + inside *attrs*. Otherwise the order of the definition of the + attributes is used. + + bases (tuple[type, ...]): Classes that the new class will subclass. + + class_body (dict): + An optional dictionary of class attributes for the new class. + + attributes_arguments: Passed unmodified to `attr.s`. + + Returns: + type: A new class with *attrs*. + + .. versionadded:: 17.1.0 *bases* + .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. + .. versionchanged:: 23.2.0 *class_body* + .. versionchanged:: 25.2.0 Class names can now be unicode. + """ + # Class identifiers are converted into the normal form NFKC while parsing + name = unicodedata.normalize("NFKC", name) + + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = {a: attrib() for a in attrs} + else: + msg = "attrs argument must be a dict or a list." + raise TypeError(msg) + + pre_init = cls_dict.pop("__attrs_pre_init__", None) + post_init = cls_dict.pop("__attrs_post_init__", None) + user_init = cls_dict.pop("__init__", None) + + body = {} + if class_body is not None: + body.update(class_body) + if pre_init is not None: + body["__attrs_pre_init__"] = pre_init + if post_init is not None: + body["__attrs_post_init__"] = post_init + if user_init is not None: + body["__init__"] = user_init + + type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) + + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + with contextlib.suppress(AttributeError, ValueError): + type_.__module__ = sys._getframe(1).f_globals.get( + "__name__", "__main__" + ) + + # We do it here for proper warnings with meaningful stacklevel. + cmp = attributes_arguments.pop("cmp", None) + ( + attributes_arguments["eq"], + attributes_arguments["order"], + ) = _determine_attrs_eq_order( + cmp, + attributes_arguments.get("eq"), + attributes_arguments.get("order"), + True, + ) + + cls = _attrs(these=cls_dict, **attributes_arguments)(type_) + # Only add type annotations now or "_attrs()" will complain: + cls.__annotations__ = { + k: v.type for k, v in cls_dict.items() if v.type is not None + } + return cls + + +# These are required by within this module so we define them here and merely +# import into .validators / .converters. + + +@attrs(slots=True, unsafe_hash=True) +class _AndValidator: + """ + Compose many validators to a single one. + """ + + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + + Args: + validators (~collections.abc.Iterable[typing.Callable]): + Arbitrary number of validators. + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( + validator._validators + if isinstance(validator, _AndValidator) + else [validator] + ) + + return _AndValidator(tuple(vals)) + + +def pipe(*converters): + """ + A converter that composes multiple converters into one. + + When called on a value, it runs all wrapped converters, returning the + *last* value. + + Type annotations will be inferred from the wrapped converters', if they + have any. + + converters (~collections.abc.Iterable[typing.Callable]): + Arbitrary number of converters. + + .. versionadded:: 20.1.0 + """ + + return_instance = any(isinstance(c, Converter) for c in converters) + + if return_instance: + + def pipe_converter(val, inst, field): + for c in converters: + val = ( + c(val, inst, field) if isinstance(c, Converter) else c(val) + ) + + return val + + else: + + def pipe_converter(val): + for c in converters: + val = c(val) + + return val + + if not converters: + # If the converter list is empty, pipe_converter is the identity. + A = TypeVar("A") + pipe_converter.__annotations__.update({"val": A, "return": A}) + else: + # Get parameter type from first converter. + t = _AnnotationExtractor(converters[0]).get_first_param_type() + if t: + pipe_converter.__annotations__["val"] = t + + last = converters[-1] + if not PY_3_11_PLUS and isinstance(last, Converter): + last = last.__call__ + + # Get return type from last converter. + rt = _AnnotationExtractor(last).get_return_type() + if rt: + pipe_converter.__annotations__["return"] = rt + + if return_instance: + return Converter(pipe_converter, takes_self=True, takes_field=True) + return pipe_converter diff --git a/source/target-vendors/cp312/attr/_next_gen.py b/source/target-vendors/cp312/attr/_next_gen.py new file mode 100644 index 0000000..4ccd0da --- /dev/null +++ b/source/target-vendors/cp312/attr/_next_gen.py @@ -0,0 +1,674 @@ +# SPDX-License-Identifier: MIT + +""" +These are keyword-only APIs that call `attr.s` and `attr.ib` with different +default values. +""" + +from functools import partial + +from . import setters +from ._funcs import asdict as _asdict +from ._funcs import astuple as _astuple +from ._make import ( + _DEFAULT_ON_SETATTR, + NOTHING, + _frozen_setattrs, + attrib, + attrs, +) +from .exceptions import NotAnAttrsClassError, UnannotatedAttributeError + + +def define( + maybe_cls=None, + *, + these=None, + repr=None, + unsafe_hash=None, + hash=None, + init=None, + slots=True, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=None, + kw_only=False, + cache_hash=False, + auto_exc=True, + eq=None, + order=False, + auto_detect=True, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, + force_kw_only=False, +): + r""" + A class decorator that adds :term:`dunder methods` according to + :term:`fields ` specified using :doc:`type annotations `, + `field()` calls, or the *these* argument. + + Since *attrs* patches or replaces an existing class, you cannot use + `object.__init_subclass__` with *attrs* classes, because it runs too early. + As a replacement, you can define ``__attrs_init_subclass__`` on your class. + It will be called by *attrs* classes that subclass it after they're + created. See also :ref:`init-subclass`. + + Args: + slots (bool): + Create a :term:`slotted class ` that's more + memory-efficient. Slotted classes are generally superior to the + default dict classes, but have some gotchas you should know about, + so we encourage you to read the :term:`glossary entry `. + + auto_detect (bool): + Instead of setting the *init*, *repr*, *eq*, and *hash* arguments + explicitly, assume they are set to True **unless any** of the + involved methods for one of the arguments is implemented in the + *current* class (meaning, it is *not* inherited from some base + class). + + So, for example by implementing ``__eq__`` on a class yourself, + *attrs* will deduce ``eq=False`` and will create *neither* + ``__eq__`` *nor* ``__ne__`` (but Python classes come with a + sensible ``__ne__`` by default, so it *should* be enough to only + implement ``__eq__`` in most cases). + + Passing :data:`True` or :data:`False` to *init*, *repr*, *eq*, or *hash* + overrides whatever *auto_detect* would determine. + + auto_exc (bool): + If the class subclasses `BaseException` (which implicitly includes + any subclass of any exception), the following happens to behave + like a well-behaved Python exception class: + + - the values for *eq*, *order*, and *hash* are ignored and the + instances compare and hash by the instance's ids [#]_ , + - all attributes that are either passed into ``__init__`` or have a + default value are additionally available as a tuple in the + ``args`` attribute, + - the value of *str* is ignored leaving ``__str__`` to base + classes. + + .. [#] + Note that *attrs* will *not* remove existing implementations of + ``__hash__`` or the equality methods. It just won't add own + ones. + + on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): + A callable that is run whenever the user attempts to set an + attribute (either by assignment like ``i.x = 42`` or by using + `setattr` like ``setattr(i, "x", 42)``). It receives the same + arguments as validators: the instance, the attribute that is being + modified, and the new value. + + If no exception is raised, the attribute is set to the return value + of the callable. + + If a list of callables is passed, they're automatically wrapped in + an `attrs.setters.pipe`. + + If left None, the default behavior is to run converters and + validators whenever an attribute is set. + + init (bool): + Create a ``__init__`` method that initializes the *attrs* + attributes. Leading underscores are stripped for the argument name, + unless an alias is set on the attribute. + + .. seealso:: + `init` shows advanced ways to customize the generated + ``__init__`` method, including executing code before and after. + + repr(bool): + Create a ``__repr__`` method with a human readable representation + of *attrs* attributes. + + str (bool): + Create a ``__str__`` method that is identical to ``__repr__``. This + is usually not necessary except for `Exception`\ s. + + eq (bool | None): + If True or None (default), add ``__eq__`` and ``__ne__`` methods + that check two instances for equality. + + .. seealso:: + `comparison` describes how to customize the comparison behavior + going as far comparing NumPy arrays. + + order (bool | None): + If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` + methods that behave like *eq* above and allow instances to be + ordered. + + They compare the instances as if they were tuples of their *attrs* + attributes if and only if the types of both classes are + *identical*. + + If `None` mirror value of *eq*. + + .. seealso:: `comparison` + + unsafe_hash (bool | None): + If None (default), the ``__hash__`` method is generated according + how *eq* and *frozen* are set. + + 1. If *both* are True, *attrs* will generate a ``__hash__`` for + you. + 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set + to None, marking it unhashable (which it is). + 3. If *eq* is False, ``__hash__`` will be left untouched meaning + the ``__hash__`` method of the base class will be used. If the + base class is `object`, this means it will fall back to id-based + hashing. + + Although not recommended, you can decide for yourself and force + *attrs* to create one (for example, if the class is immutable even + though you didn't freeze it programmatically) by passing True or + not. Both of these cases are rather special and should be used + carefully. + + .. seealso:: + + - Our documentation on `hashing`, + - Python's documentation on `object.__hash__`, + - and the `GitHub issue that led to the default \ behavior + `_ for more + details. + + hash (bool | None): + Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence. + + cache_hash (bool): + Ensure that the object's hash code is computed only once and stored + on the object. If this is set to True, hashing must be either + explicitly or implicitly enabled for this class. If the hash code + is cached, avoid any reassignments of fields involved in hash code + computation or mutations of the objects those fields point to after + object creation. If such changes occur, the behavior of the + object's hash code is undefined. + + frozen (bool): + Make instances immutable after initialization. If someone attempts + to modify a frozen instance, `attrs.exceptions.FrozenInstanceError` + is raised. + + .. note:: + + 1. This is achieved by installing a custom ``__setattr__`` + method on your class, so you can't implement your own. + + 2. True immutability is impossible in Python. + + 3. This *does* have a minor a runtime performance `impact + ` when initializing new instances. In other + words: ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You + can circumvent that limitation by using + ``object.__setattr__(self, "attribute_name", value)``. + + 5. Subclasses of a frozen class are frozen too. + + kw_only (bool): + Make attributes keyword-only in the generated ``__init__`` (if + *init* is False, this parameter is ignored). Attributes that + explicitly set ``kw_only=False`` are not affected; base class + attributes are also not affected. + + Also see *force_kw_only*. + + weakref_slot (bool): + Make instances weak-referenceable. This has no effect unless + *slots* is True. + + field_transformer (~typing.Callable | None): + A function that is called with the original class object and all + fields right before *attrs* finalizes the class. You can use this, + for example, to automatically add converters or validators to + fields based on their types. + + .. seealso:: `transform-fields` + + match_args (bool): + If True (default), set ``__match_args__`` on the class to support + :pep:`634` (*Structural Pattern Matching*). It is a tuple of all + non-keyword-only ``__init__`` parameter names on Python 3.10 and + later. Ignored on older Python versions. + + collect_by_mro (bool): + If True, *attrs* collects attributes from base classes correctly + according to the `method resolution order + `_. If False, *attrs* + will mimic the (wrong) behavior of `dataclasses` and :pep:`681`. + + See also `issue #428 + `_. + + force_kw_only (bool): + A back-compat flag for restoring pre-25.4.0 behavior. If True and + ``kw_only=True``, all attributes are made keyword-only, including + base class attributes, and those set to ``kw_only=False`` at the + attribute level. Defaults to False. + + See also `issue #980 + `_. + + getstate_setstate (bool | None): + .. note:: + + This is usually only interesting for slotted classes and you + should probably just set *auto_detect* to True. + + If True, ``__getstate__`` and ``__setstate__`` are generated and + attached to the class. This is necessary for slotted classes to be + pickleable. If left None, it's True by default for slotted classes + and False for dict classes. + + If *auto_detect* is True, and *getstate_setstate* is left None, and + **either** ``__getstate__`` or ``__setstate__`` is detected + directly on the class (meaning: not inherited), it is set to False + (this is usually what you want). + + auto_attribs (bool | None): + If True, look at type annotations to determine which attributes to + use, like `dataclasses`. If False, it will only look for explicit + :func:`field` class attributes, like classic *attrs*. + + If left None, it will guess: + + 1. If any attributes are annotated and no unannotated + `attrs.field`\ s are found, it assumes *auto_attribs=True*. + 2. Otherwise it assumes *auto_attribs=False* and tries to collect + `attrs.field`\ s. + + If *attrs* decides to look at type annotations, **all** fields + **must** be annotated. If *attrs* encounters a field that is set to + a :func:`field` / `attr.ib` but lacks a type annotation, an + `attrs.exceptions.UnannotatedAttributeError` is raised. Use + ``field_name: typing.Any = field(...)`` if you don't want to set a + type. + + .. warning:: + + For features that use the attribute name to create decorators + (for example, :ref:`validators `), you still *must* + assign :func:`field` / `attr.ib` to them. Otherwise Python will + either not find the name or try to use the default value to + call, for example, ``validator`` on it. + + Attributes annotated as `typing.ClassVar`, and attributes that are + neither annotated nor set to an `field()` are **ignored**. + + these (dict[str, object]): + A dictionary of name to the (private) return value of `field()` + mappings. This is useful to avoid the definition of your attributes + within the class body because you can't (for example, if you want + to add ``__repr__`` methods to Django models) or don't want to. + + If *these* is not `None`, *attrs* will *not* search the class body + for attributes and will *not* remove any attributes from it. + + The order is deduced from the order of the attributes inside + *these*. + + Arguably, this is a rather obscure feature. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. + .. versionadded:: 22.2.0 + *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). + .. versionchanged:: 24.1.0 + Instances are not compared as tuples of attributes anymore, but using a + big ``and`` condition. This is faster and has more correct behavior for + uncomparable values like `math.nan`. + .. versionadded:: 24.1.0 + If a class has an *inherited* classmethod called + ``__attrs_init_subclass__``, it is executed after the class is created. + .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*. + .. versionadded:: 24.3.0 + Unless already present, a ``__replace__`` method is automatically + created for `copy.replace` (Python 3.13+ only). + .. versionchanged:: 25.4.0 + *kw_only* now only applies to attributes defined in the current class, + and respects attribute-level ``kw_only=False`` settings. + .. versionadded:: 25.4.0 + Added *force_kw_only* to go back to the previous *kw_only* behavior. + + .. note:: + + The main differences to the classic `attr.s` are: + + - Automatically detect whether or not *auto_attribs* should be `True` + (c.f. *auto_attribs* parameter). + - Converters and validators run when attributes are set by default -- + if *frozen* is `False`. + - *slots=True* + + Usually, this has only upsides and few visible effects in everyday + programming. But it *can* lead to some surprising behaviors, so + please make sure to read :term:`slotted classes`. + + - *auto_exc=True* + - *auto_detect=True* + - *order=False* + - *force_kw_only=False* + - Some options that were only relevant on Python 2 or were kept around + for backwards-compatibility have been removed. + + """ + + def do_it(cls, auto_attribs): + return attrs( + maybe_cls=cls, + these=these, + repr=repr, + hash=hash, + unsafe_hash=unsafe_hash, + init=init, + slots=slots, + frozen=frozen, + weakref_slot=weakref_slot, + str=str, + auto_attribs=auto_attribs, + kw_only=kw_only, + cache_hash=cache_hash, + auto_exc=auto_exc, + eq=eq, + order=order, + auto_detect=auto_detect, + collect_by_mro=True, + getstate_setstate=getstate_setstate, + on_setattr=on_setattr, + field_transformer=field_transformer, + match_args=match_args, + force_kw_only=force_kw_only, + ) + + def wrap(cls): + """ + Making this a wrapper ensures this code runs during class creation. + + We also ensure that frozen-ness of classes is inherited. + """ + nonlocal frozen, on_setattr + + had_on_setattr = on_setattr not in (None, setters.NO_OP) + + # By default, mutable classes convert & validate on setattr. + if frozen is False and on_setattr is None: + on_setattr = _DEFAULT_ON_SETATTR + + # However, if we subclass a frozen class, we inherit the immutability + # and disable on_setattr. + for base_cls in cls.__bases__: + if base_cls.__setattr__ is _frozen_setattrs: + if had_on_setattr: + msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." + raise ValueError(msg) + + on_setattr = setters.NO_OP + break + + if auto_attribs is not None: + return do_it(cls, auto_attribs) + + try: + return do_it(cls, True) + except UnannotatedAttributeError: + return do_it(cls, False) + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but `None` if used as `@attrs()`. + if maybe_cls is None: + return wrap + + return wrap(maybe_cls) + + +mutable = define +frozen = partial(define, frozen=True, on_setattr=None) + + +def field( + *, + default=NOTHING, + validator=None, + repr=True, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=None, + eq=None, + order=None, + on_setattr=None, + alias=None, +): + """ + Create a new :term:`field` / :term:`attribute` on a class. + + .. warning:: + + Does **nothing** unless the class is also decorated with + `attrs.define` (or similar)! + + Args: + default: + A value that is used if an *attrs*-generated ``__init__`` is used + and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + + If the value is an instance of `attrs.Factory`, its callable will + be used to construct a new value (useful for mutable data types + like lists or dicts). + + If a default is not set (or set manually to `attrs.NOTHING`), a + value *must* be supplied when instantiating; otherwise a + `TypeError` will be raised. + + .. seealso:: `defaults` + + factory (~typing.Callable): + Syntactic sugar for ``default=attr.Factory(factory)``. + + validator (~typing.Callable | list[~typing.Callable]): + Callable that is called by *attrs*-generated ``__init__`` methods + after the instance has been initialized. They receive the + initialized instance, the :func:`~attrs.Attribute`, and the passed + value. + + The return value is *not* inspected so the validator has to throw + an exception itself. + + If a `list` is passed, its items are treated as validators and must + all pass. + + Validators can be globally disabled and re-enabled using + `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. + + The validator can also be set using decorator notation as shown + below. + + .. seealso:: :ref:`validators` + + repr (bool | ~typing.Callable): + Include this attribute in the generated ``__repr__`` method. If + True, include the attribute; if False, omit it. By default, the + built-in ``repr()`` function is used. To override how the attribute + value is formatted, pass a ``callable`` that takes a single value + and returns a string. Note that the resulting string is used as-is, + which means it will be used directly *instead* of calling + ``repr()`` (the default). + + eq (bool | ~typing.Callable): + If True (default), include this attribute in the generated + ``__eq__`` and ``__ne__`` methods that check two instances for + equality. To override how the attribute value is compared, pass a + callable that takes a single value and returns the value to be + compared. + + .. seealso:: `comparison` + + order (bool | ~typing.Callable): + If True (default), include this attributes in the generated + ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To + override how the attribute value is ordered, pass a callable that + takes a single value and returns the value to be ordered. + + .. seealso:: `comparison` + + hash (bool | None): + Include this attribute in the generated ``__hash__`` method. If + None (default), mirror *eq*'s value. This is the correct behavior + according the Python spec. Setting this value to anything else + than None is *discouraged*. + + .. seealso:: `hashing` + + init (bool): + Include this attribute in the generated ``__init__`` method. + + It is possible to set this to False and set a default value. In + that case this attributed is unconditionally initialized with the + specified default value or factory. + + .. seealso:: `init` + + converter (typing.Callable | Converter): + A callable that is called by *attrs*-generated ``__init__`` methods + to convert attribute's value to the desired format. + + If a vanilla callable is passed, it is given the passed-in value as + the only positional argument. It is possible to receive additional + arguments by wrapping the callable in a `Converter`. + + Either way, the returned value will be used as the new value of the + attribute. The value is converted before being passed to the + validator, if any. + + .. seealso:: :ref:`converters` + + metadata (dict | None): + An arbitrary mapping, to be used by third-party code. + + .. seealso:: `extending-metadata`. + + type (type): + The type of the attribute. Nowadays, the preferred method to + specify the type is using a variable annotation (see :pep:`526`). + This argument is provided for backwards-compatibility and for usage + with `make_class`. Regardless of the approach used, the type will + be stored on ``Attribute.type``. + + Please note that *attrs* doesn't do anything with this metadata by + itself. You can use it as part of your own code or for `static type + checking `. + + kw_only (bool | None): + Make this attribute keyword-only in the generated ``__init__`` (if + *init* is False, this parameter is ignored). If None (default), + mirror the setting from `attrs.define`. + + on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]): + Allows to overwrite the *on_setattr* setting from `attr.s`. If left + None, the *on_setattr* value from `attr.s` is used. Set to + `attrs.setters.NO_OP` to run **no** `setattr` hooks for this + attribute -- regardless of the setting in `define()`. + + alias (str | None): + Override this attribute's parameter name in the generated + ``__init__`` method. If left None, default to ``name`` stripped + of leading underscores. See `private-attributes`. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionadded:: 22.2.0 *alias* + .. versionadded:: 23.1.0 + The *type* parameter has been re-added; mostly for `attrs.make_class`. + Please note that type checkers ignore this metadata. + .. versionchanged:: 25.4.0 + *kw_only* can now be None, and its default is also changed from False to + None. + + .. seealso:: + + `attr.ib` + """ + return attrib( + default=default, + validator=validator, + repr=repr, + hash=hash, + init=init, + metadata=metadata, + type=type, + converter=converter, + factory=factory, + kw_only=kw_only, + eq=eq, + order=order, + on_setattr=on_setattr, + alias=alias, + ) + + +def asdict(inst, *, recurse=True, filter=None, value_serializer=None): + """ + Same as `attr.asdict`, except that collections types are always retained + and dict is always used as *dict_factory*. + + .. versionadded:: 21.3.0 + """ + return _asdict( + inst=inst, + recurse=recurse, + filter=filter, + value_serializer=value_serializer, + retain_collection_types=True, + ) + + +def astuple(inst, *, recurse=True, filter=None): + """ + Same as `attr.astuple`, except that collections types are always retained + and `tuple` is always used as the *tuple_factory*. + + .. versionadded:: 21.3.0 + """ + return _astuple( + inst=inst, recurse=recurse, filter=filter, retain_collection_types=True + ) + + +def inspect(cls): + """ + Inspect the class and return its effective build parameters. + + Warning: + This feature is currently **experimental** and is not covered by our + strict backwards-compatibility guarantees. + + Args: + cls: The *attrs*-decorated class to inspect. + + Returns: + The effective build parameters of the class. + + Raises: + NotAnAttrsClassError: If the class is not an *attrs*-decorated class. + + .. versionadded:: 25.4.0 + """ + try: + return cls.__dict__["__attrs_props__"] + except KeyError: + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) from None diff --git a/source/target-vendors/cp312/attr/_typing_compat.pyi b/source/target-vendors/cp312/attr/_typing_compat.pyi new file mode 100644 index 0000000..ca7b71e --- /dev/null +++ b/source/target-vendors/cp312/attr/_typing_compat.pyi @@ -0,0 +1,15 @@ +from typing import Any, ClassVar, Protocol + +# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. +MYPY = False + +if MYPY: + # A protocol to be able to statically accept an attrs class. + class AttrsInstance_(Protocol): + __attrs_attrs__: ClassVar[Any] + +else: + # For type checkers without plug-in support use an empty protocol that + # will (hopefully) be combined into a union. + class AttrsInstance_(Protocol): + pass diff --git a/source/target-vendors/cp312/attr/_version_info.py b/source/target-vendors/cp312/attr/_version_info.py new file mode 100644 index 0000000..27f1888 --- /dev/null +++ b/source/target-vendors/cp312/attr/_version_info.py @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: MIT + + +from functools import total_ordering + +from ._funcs import astuple +from ._make import attrib, attrs + + +@total_ordering +@attrs(eq=False, order=False, slots=True, frozen=True) +class VersionInfo: + """ + A version object that can be compared to tuple of length 1--4: + + >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) + True + >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) + True + >>> vi = attr.VersionInfo(19, 2, 0, "final") + >>> vi < (19, 1, 1) + False + >>> vi < (19,) + False + >>> vi == (19, 2,) + True + >>> vi == (19, 2, 1) + False + + .. versionadded:: 19.2 + """ + + year = attrib(type=int) + minor = attrib(type=int) + micro = attrib(type=int) + releaselevel = attrib(type=str) + + @classmethod + def _from_version_string(cls, s): + """ + Parse *s* and return a _VersionInfo. + """ + v = s.split(".") + if len(v) == 3: + v.append("final") + + return cls( + year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] + ) + + def _ensure_tuple(self, other): + """ + Ensure *other* is a tuple of a valid length. + + Returns a possibly transformed *other* and ourselves as a tuple of + the same length as *other*. + """ + + if self.__class__ is other.__class__: + other = astuple(other) + + if not isinstance(other, tuple): + raise NotImplementedError + + if not (1 <= len(other) <= 4): + raise NotImplementedError + + return astuple(self)[: len(other)], other + + def __eq__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + return us == them + + def __lt__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't + # have to do anything special with releaselevel for now. + return us < them + + def __hash__(self): + return hash((self.year, self.minor, self.micro, self.releaselevel)) diff --git a/source/target-vendors/cp312/attr/_version_info.pyi b/source/target-vendors/cp312/attr/_version_info.pyi new file mode 100644 index 0000000..45ced08 --- /dev/null +++ b/source/target-vendors/cp312/attr/_version_info.pyi @@ -0,0 +1,9 @@ +class VersionInfo: + @property + def year(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def micro(self) -> int: ... + @property + def releaselevel(self) -> str: ... diff --git a/source/target-vendors/cp312/attr/converters.py b/source/target-vendors/cp312/attr/converters.py new file mode 100644 index 0000000..0a79dee --- /dev/null +++ b/source/target-vendors/cp312/attr/converters.py @@ -0,0 +1,162 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful converters. +""" + +import typing + +from ._compat import _AnnotationExtractor +from ._make import NOTHING, Converter, Factory, pipe + + +__all__ = [ + "default_if_none", + "optional", + "pipe", + "to_bool", +] + + +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to `None`. + + Type annotations will be inferred from the wrapped converter's, if it has + any. + + Args: + converter (typing.Callable): + the converter that is used for non-`None` values. + + .. versionadded:: 17.1.0 + """ + + if isinstance(converter, Converter): + + def optional_converter(val, inst, field): + if val is None: + return None + return converter(val, inst, field) + + else: + + def optional_converter(val): + if val is None: + return None + return converter(val) + + xtr = _AnnotationExtractor(converter) + + t = xtr.get_first_param_type() + if t: + optional_converter.__annotations__["val"] = typing.Optional[t] + + rt = xtr.get_return_type() + if rt: + optional_converter.__annotations__["return"] = typing.Optional[rt] + + if isinstance(converter, Converter): + return Converter(optional_converter, takes_self=True, takes_field=True) + + return optional_converter + + +def default_if_none(default=NOTHING, factory=None): + """ + A converter that allows to replace `None` values by *default* or the result + of *factory*. + + Args: + default: + Value to be used if `None` is passed. Passing an instance of + `attrs.Factory` is supported, however the ``takes_self`` option is + *not*. + + factory (typing.Callable): + A callable that takes no parameters whose result is used if `None` + is passed. + + Raises: + TypeError: If **neither** *default* or *factory* is passed. + + TypeError: If **both** *default* and *factory* are passed. + + ValueError: + If an instance of `attrs.Factory` is passed with + ``takes_self=True``. + + .. versionadded:: 18.2.0 + """ + if default is NOTHING and factory is None: + msg = "Must pass either `default` or `factory`." + raise TypeError(msg) + + if default is not NOTHING and factory is not None: + msg = "Must pass either `default` or `factory` but not both." + raise TypeError(msg) + + if factory is not None: + default = Factory(factory) + + if isinstance(default, Factory): + if default.takes_self: + msg = "`takes_self` is not supported by default_if_none." + raise ValueError(msg) + + def default_if_none_converter(val): + if val is not None: + return val + + return default.factory() + + else: + + def default_if_none_converter(val): + if val is not None: + return val + + return default + + return default_if_none_converter + + +def to_bool(val): + """ + Convert "boolean" strings (for example, from environment variables) to real + booleans. + + Values mapping to `True`: + + - ``True`` + - ``"true"`` / ``"t"`` + - ``"yes"`` / ``"y"`` + - ``"on"`` + - ``"1"`` + - ``1`` + + Values mapping to `False`: + + - ``False`` + - ``"false"`` / ``"f"`` + - ``"no"`` / ``"n"`` + - ``"off"`` + - ``"0"`` + - ``0`` + + Raises: + ValueError: For any other value. + + .. versionadded:: 21.3.0 + """ + if isinstance(val, str): + val = val.lower() + + if val in (True, "true", "t", "yes", "y", "on", "1", 1): + return True + if val in (False, "false", "f", "no", "n", "off", "0", 0): + return False + + msg = f"Cannot convert value to bool: {val!r}" + raise ValueError(msg) diff --git a/source/target-vendors/cp312/attr/converters.pyi b/source/target-vendors/cp312/attr/converters.pyi new file mode 100644 index 0000000..12bd0c4 --- /dev/null +++ b/source/target-vendors/cp312/attr/converters.pyi @@ -0,0 +1,19 @@ +from typing import Callable, Any, overload + +from attrs import _ConverterType, _CallableConverterType + +@overload +def pipe(*validators: _CallableConverterType) -> _CallableConverterType: ... +@overload +def pipe(*validators: _ConverterType) -> _ConverterType: ... +@overload +def optional(converter: _CallableConverterType) -> _CallableConverterType: ... +@overload +def optional(converter: _ConverterType) -> _ConverterType: ... +@overload +def default_if_none(default: Any) -> _CallableConverterType: ... +@overload +def default_if_none( + *, factory: Callable[[], Any] +) -> _CallableConverterType: ... +def to_bool(val: str | int | bool) -> bool: ... diff --git a/source/target-vendors/cp312/attr/exceptions.py b/source/target-vendors/cp312/attr/exceptions.py new file mode 100644 index 0000000..a207df4 --- /dev/null +++ b/source/target-vendors/cp312/attr/exceptions.py @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + + +class FrozenError(AttributeError): + """ + A frozen/immutable instance or attribute have been attempted to be + modified. + + It mirrors the behavior of ``namedtuples`` by using the same error message + and subclassing `AttributeError`. + + .. versionadded:: 20.1.0 + """ + + def __init__(self): + msg = "can't set attribute" + super().__init__(msg) + self.msg = msg + + +class FrozenInstanceError(FrozenError): + """ + A frozen instance has been attempted to be modified. + + .. versionadded:: 16.1.0 + """ + + +class FrozenAttributeError(FrozenError): + """ + A frozen attribute has been attempted to be modified. + + .. versionadded:: 20.1.0 + """ + + +class AttrsAttributeNotFoundError(ValueError): + """ + An *attrs* function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-*attrs* class has been passed into an *attrs* function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set when defining the field and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has a field without a type annotation. + + .. versionadded:: 17.3.0 + """ + + +class PythonTooOldError(RuntimeError): + """ + It was attempted to use an *attrs* feature that requires a newer Python + version. + + .. versionadded:: 18.2.0 + """ + + +class NotCallableError(TypeError): + """ + A field requiring a callable has been set with a value that is not + callable. + + .. versionadded:: 19.2.0 + """ + + def __init__(self, msg, value): + super(TypeError, self).__init__(msg, value) + self.msg = msg + self.value = value + + def __str__(self): + return str(self.msg) diff --git a/source/target-vendors/cp312/attr/exceptions.pyi b/source/target-vendors/cp312/attr/exceptions.pyi new file mode 100644 index 0000000..f268011 --- /dev/null +++ b/source/target-vendors/cp312/attr/exceptions.pyi @@ -0,0 +1,17 @@ +from typing import Any + +class FrozenError(AttributeError): + msg: str = ... + +class FrozenInstanceError(FrozenError): ... +class FrozenAttributeError(FrozenError): ... +class AttrsAttributeNotFoundError(ValueError): ... +class NotAnAttrsClassError(ValueError): ... +class DefaultAlreadySetError(RuntimeError): ... +class UnannotatedAttributeError(RuntimeError): ... +class PythonTooOldError(RuntimeError): ... + +class NotCallableError(TypeError): + msg: str = ... + value: Any = ... + def __init__(self, msg: str, value: Any) -> None: ... diff --git a/source/target-vendors/cp312/attr/filters.py b/source/target-vendors/cp312/attr/filters.py new file mode 100644 index 0000000..689b170 --- /dev/null +++ b/source/target-vendors/cp312/attr/filters.py @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful filters for `attrs.asdict` and `attrs.astuple`. +""" + +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isinstance(cls, type)), + frozenset(cls for cls in what if isinstance(cls, str)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Create a filter that only allows *what*. + + Args: + what (list[type, str, attrs.Attribute]): + What to include. Can be a type, a name, or an attribute. + + Returns: + Callable: + A callable that can be passed to `attrs.asdict`'s and + `attrs.astuple`'s *filter* argument. + + .. versionchanged:: 23.1.0 Accept strings with field names. + """ + cls, names, attrs = _split_what(what) + + def include_(attribute, value): + return ( + value.__class__ in cls + or attribute.name in names + or attribute in attrs + ) + + return include_ + + +def exclude(*what): + """ + Create a filter that does **not** allow *what*. + + Args: + what (list[type, str, attrs.Attribute]): + What to exclude. Can be a type, a name, or an attribute. + + Returns: + Callable: + A callable that can be passed to `attrs.asdict`'s and + `attrs.astuple`'s *filter* argument. + + .. versionchanged:: 23.3.0 Accept field name string as input argument + """ + cls, names, attrs = _split_what(what) + + def exclude_(attribute, value): + return not ( + value.__class__ in cls + or attribute.name in names + or attribute in attrs + ) + + return exclude_ diff --git a/source/target-vendors/cp312/attr/filters.pyi b/source/target-vendors/cp312/attr/filters.pyi new file mode 100644 index 0000000..974abdc --- /dev/null +++ b/source/target-vendors/cp312/attr/filters.pyi @@ -0,0 +1,6 @@ +from typing import Any + +from . import Attribute, _FilterType + +def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... +def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ... diff --git a/source/target-vendors/cp312/attr/py.typed b/source/target-vendors/cp312/attr/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/attr/setters.py b/source/target-vendors/cp312/attr/setters.py new file mode 100644 index 0000000..78b0839 --- /dev/null +++ b/source/target-vendors/cp312/attr/setters.py @@ -0,0 +1,79 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly used hooks for on_setattr. +""" + +from . import _config +from .exceptions import FrozenAttributeError + + +def pipe(*setters): + """ + Run all *setters* and return the return value of the last one. + + .. versionadded:: 20.1.0 + """ + + def wrapped_pipe(instance, attrib, new_value): + rv = new_value + + for setter in setters: + rv = setter(instance, attrib, rv) + + return rv + + return wrapped_pipe + + +def frozen(_, __, ___): + """ + Prevent an attribute to be modified. + + .. versionadded:: 20.1.0 + """ + raise FrozenAttributeError + + +def validate(instance, attrib, new_value): + """ + Run *attrib*'s validator on *new_value* if it has one. + + .. versionadded:: 20.1.0 + """ + if _config._run_validators is False: + return new_value + + v = attrib.validator + if not v: + return new_value + + v(instance, attrib, new_value) + + return new_value + + +def convert(instance, attrib, new_value): + """ + Run *attrib*'s converter -- if it has one -- on *new_value* and return the + result. + + .. versionadded:: 20.1.0 + """ + c = attrib.converter + if c: + # This can be removed once we drop 3.8 and use attrs.Converter instead. + from ._make import Converter + + if not isinstance(c, Converter): + return c(new_value) + + return c(new_value, instance, attrib) + + return new_value + + +# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. +# Sphinx's autodata stopped working, so the docstring is inlined in the API +# docs. +NO_OP = object() diff --git a/source/target-vendors/cp312/attr/setters.pyi b/source/target-vendors/cp312/attr/setters.pyi new file mode 100644 index 0000000..73abf36 --- /dev/null +++ b/source/target-vendors/cp312/attr/setters.pyi @@ -0,0 +1,20 @@ +from typing import Any, NewType, NoReturn, TypeVar + +from . import Attribute +from attrs import _OnSetAttrType + +_T = TypeVar("_T") + +def frozen( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> NoReturn: ... +def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... +def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... + +# convert is allowed to return Any, because they can be chained using pipe. +def convert( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> Any: ... + +_NoOpType = NewType("_NoOpType", object) +NO_OP: _NoOpType diff --git a/source/target-vendors/cp312/attr/validators.py b/source/target-vendors/cp312/attr/validators.py new file mode 100644 index 0000000..0b1a294 --- /dev/null +++ b/source/target-vendors/cp312/attr/validators.py @@ -0,0 +1,750 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful validators. +""" + +import operator +import re + +from contextlib import contextmanager +from re import Pattern + +from ._config import get_run_validators, set_run_validators +from ._make import _AndValidator, and_, attrib, attrs +from .converters import default_if_none +from .exceptions import NotCallableError + + +__all__ = [ + "and_", + "deep_iterable", + "deep_mapping", + "disabled", + "ge", + "get_disabled", + "gt", + "in_", + "instance_of", + "is_callable", + "le", + "lt", + "matches_re", + "max_len", + "min_len", + "not_", + "optional", + "or_", + "set_disabled", +] + + +def set_disabled(disabled): + """ + Globally disable or enable running validators. + + By default, they are run. + + Args: + disabled (bool): If `True`, disable running all validators. + + .. warning:: + + This function is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(not disabled) + + +def get_disabled(): + """ + Return a bool indicating whether validators are currently disabled or not. + + Returns: + bool:`True` if validators are currently disabled. + + .. versionadded:: 21.3.0 + """ + return not get_run_validators() + + +@contextmanager +def disabled(): + """ + Context manager that disables running validators within its context. + + .. warning:: + + This context manager is not thread-safe! + + .. versionadded:: 21.3.0 + .. versionchanged:: 26.1.0 The contextmanager is nestable. + """ + prev = get_run_validators() + set_run_validators(False) + try: + yield + finally: + set_run_validators(prev) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _InstanceOfValidator: + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})." + raise TypeError( + msg, + attr, + self.type, + value, + ) + + def __repr__(self): + return f"" + + +def instance_of(type): + """ + A validator that raises a `TypeError` if the initializer is called with a + wrong type for this particular attribute (checks are performed using + `isinstance` therefore it's also valid to pass a tuple of types). + + Args: + type (type | tuple[type]): The type to check for. + + Raises: + TypeError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the expected type, and the value it got. + """ + return _InstanceOfValidator(type) + + +@attrs(repr=False, frozen=True, slots=True) +class _MatchesReValidator: + pattern = attrib() + match_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.match_func(value): + msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)" + raise ValueError( + msg, + attr, + self.pattern, + value, + ) + + def __repr__(self): + return f"" + + +def matches_re(regex, flags=0, func=None): + r""" + A validator that raises `ValueError` if the initializer is called with a + string that doesn't match *regex*. + + Args: + regex (str, re.Pattern): + A regex string or precompiled pattern to match against + + flags (int): + Flags that will be passed to the underlying re function (default 0) + + func (typing.Callable): + Which underlying `re` function to call. Valid options are + `re.fullmatch`, `re.search`, and `re.match`; the default `None` + means `re.fullmatch`. For performance reasons, the pattern is + always precompiled using `re.compile`. + + .. versionadded:: 19.2.0 + .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. + """ + valid_funcs = (re.fullmatch, None, re.search, re.match) + if func not in valid_funcs: + msg = "'func' must be one of {}.".format( + ", ".join( + sorted((e and e.__name__) or "None" for e in set(valid_funcs)) + ) + ) + raise ValueError(msg) + + if isinstance(regex, Pattern): + if flags: + msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" + raise TypeError(msg) + pattern = regex + else: + pattern = re.compile(regex, flags) + + if func is re.match: + match_func = pattern.match + elif func is re.search: + match_func = pattern.search + else: + match_func = pattern.fullmatch + + return _MatchesReValidator(pattern, match_func) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _OptionalValidator: + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): + return f"" + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to `None` in addition to satisfying the requirements of + the sub-validator. + + Args: + validator + (typing.Callable | tuple[typing.Callable] | list[typing.Callable]): + A validator (or validators) that is used for non-`None` values. + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. + """ + if isinstance(validator, (list, tuple)): + return _OptionalValidator(_AndValidator(validator)) + + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _InValidator: + options = attrib() + _original_options = attrib(hash=False) + + def __call__(self, inst, attr, value): + try: + in_options = value in self.options + except TypeError: # e.g. `1 in "abc"` + in_options = False + + if not in_options: + msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})" + raise ValueError( + msg, + attr, + self._original_options, + value, + ) + + def __repr__(self): + return f"" + + +def in_(options): + """ + A validator that raises a `ValueError` if the initializer is called with a + value that does not belong in the *options* provided. + + The check is performed using ``value in options``, so *options* has to + support that operation. + + To keep the validator hashable, dicts, lists, and sets are transparently + transformed into a `tuple`. + + Args: + options: Allowed options. + + Raises: + ValueError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the expected options, and the value it got. + + .. versionadded:: 17.1.0 + .. versionchanged:: 22.1.0 + The ValueError was incomplete until now and only contained the human + readable error message. Now it contains all the information that has + been promised since 17.1.0. + .. versionchanged:: 24.1.0 + *options* that are a list, dict, or a set are now transformed into a + tuple to keep the validator hashable. + """ + repr_options = options + if isinstance(options, (list, dict, set)): + options = tuple(options) + + return _InValidator(options, repr_options) + + +@attrs(repr=False, slots=False, unsafe_hash=True) +class _IsCallableValidator: + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not callable(value): + message = ( + "'{name}' must be callable " + "(got {value!r} that is a {actual!r})." + ) + raise NotCallableError( + msg=message.format( + name=attr.name, value=value, actual=value.__class__ + ), + value=value, + ) + + def __repr__(self): + return "" + + +def is_callable(): + """ + A validator that raises a `attrs.exceptions.NotCallableError` if the + initializer is called with a value for this particular attribute that is + not callable. + + .. versionadded:: 19.1.0 + + Raises: + attrs.exceptions.NotCallableError: + With a human readable error message containing the attribute + (`attrs.Attribute`) name, and the value it got. + """ + return _IsCallableValidator() + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _DeepIterable: + member_validator = attrib(validator=is_callable()) + iterable_validator = attrib( + default=None, validator=optional(is_callable()) + ) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.iterable_validator is not None: + self.iterable_validator(inst, attr, value) + + for member in value: + self.member_validator(inst, attr, member) + + def __repr__(self): + iterable_identifier = ( + "" + if self.iterable_validator is None + else f" {self.iterable_validator!r}" + ) + return ( + f"" + ) + + +def deep_iterable(member_validator, iterable_validator=None): + """ + A validator that performs deep validation of an iterable. + + Args: + member_validator: Validator(s) to apply to iterable members. + + iterable_validator: + Validator(s) to apply to iterable itself (optional). + + Raises + TypeError: if any sub-validators fail + + .. versionadded:: 19.1.0 + + .. versionchanged:: 25.4.0 + *member_validator* and *iterable_validator* can now be a list or tuple + of validators. + """ + if isinstance(member_validator, (list, tuple)): + member_validator = and_(*member_validator) + if isinstance(iterable_validator, (list, tuple)): + iterable_validator = and_(*iterable_validator) + return _DeepIterable(member_validator, iterable_validator) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _DeepMapping: + key_validator = attrib(validator=optional(is_callable())) + value_validator = attrib(validator=optional(is_callable())) + mapping_validator = attrib(validator=optional(is_callable())) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.mapping_validator is not None: + self.mapping_validator(inst, attr, value) + + for key in value: + if self.key_validator is not None: + self.key_validator(inst, attr, key) + if self.value_validator is not None: + self.value_validator(inst, attr, value[key]) + + def __repr__(self): + return f"" + + +def deep_mapping( + key_validator=None, value_validator=None, mapping_validator=None +): + """ + A validator that performs deep validation of a dictionary. + + All validators are optional, but at least one of *key_validator* or + *value_validator* must be provided. + + Args: + key_validator: Validator(s) to apply to dictionary keys. + + value_validator: Validator(s) to apply to dictionary values. + + mapping_validator: + Validator(s) to apply to top-level mapping attribute. + + .. versionadded:: 19.1.0 + + .. versionchanged:: 25.4.0 + *key_validator* and *value_validator* are now optional, but at least one + of them must be provided. + + .. versionchanged:: 25.4.0 + *key_validator*, *value_validator*, and *mapping_validator* can now be a + list or tuple of validators. + + Raises: + TypeError: If any sub-validator fails on validation. + + ValueError: + If neither *key_validator* nor *value_validator* is provided on + instantiation. + """ + if key_validator is None and value_validator is None: + msg = ( + "At least one of key_validator or value_validator must be provided" + ) + raise ValueError(msg) + + if isinstance(key_validator, (list, tuple)): + key_validator = and_(*key_validator) + if isinstance(value_validator, (list, tuple)): + value_validator = and_(*value_validator) + if isinstance(mapping_validator, (list, tuple)): + mapping_validator = and_(*mapping_validator) + + return _DeepMapping(key_validator, value_validator, mapping_validator) + + +@attrs(repr=False, frozen=True, slots=True) +class _NumberValidator: + bound = attrib() + compare_op = attrib() + compare_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.compare_func(value, self.bound): + msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def lt(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number larger or equal to *val*. + + The validator uses `operator.lt` to compare the values. + + Args: + val: Exclusive upper bound for values. + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<", operator.lt) + + +def le(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number greater than *val*. + + The validator uses `operator.le` to compare the values. + + Args: + val: Inclusive upper bound for values. + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<=", operator.le) + + +def ge(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number smaller than *val*. + + The validator uses `operator.ge` to compare the values. + + Args: + val: Inclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">=", operator.ge) + + +def gt(val): + """ + A validator that raises `ValueError` if the initializer is called with a + number smaller or equal to *val*. + + The validator uses `operator.gt` to compare the values. + + Args: + val: Exclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">", operator.gt) + + +@attrs(repr=False, frozen=True, slots=True) +class _MaxLengthValidator: + max_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) > self.max_length: + msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def max_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is longer than *length*. + + Args: + length (int): Maximum length of the string or iterable + + .. versionadded:: 21.3.0 + """ + return _MaxLengthValidator(length) + + +@attrs(repr=False, frozen=True, slots=True) +class _MinLengthValidator: + min_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) < self.min_length: + msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def min_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is shorter than *length*. + + Args: + length (int): Minimum length of the string or iterable + + .. versionadded:: 22.1.0 + """ + return _MinLengthValidator(length) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _SubclassOfValidator: + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not issubclass(value, self.type): + msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." + raise TypeError( + msg, + attr, + self.type, + value, + ) + + def __repr__(self): + return f"" + + +def _subclass_of(type): + """ + A validator that raises a `TypeError` if the initializer is called with a + wrong type for this particular attribute (checks are performed using + `issubclass` therefore it's also valid to pass a tuple of types). + + Args: + type (type | tuple[type, ...]): The type(s) to check for. + + Raises: + TypeError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the expected type, and the value it got. + """ + return _SubclassOfValidator(type) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _NotValidator: + validator = attrib() + msg = attrib( + converter=default_if_none( + "not_ validator child '{validator!r}' " + "did not raise a captured error" + ) + ) + exc_types = attrib( + validator=deep_iterable( + member_validator=_subclass_of(Exception), + iterable_validator=instance_of(tuple), + ), + ) + + def __call__(self, inst, attr, value): + try: + self.validator(inst, attr, value) + except self.exc_types: + pass # suppress error to invert validity + else: + raise ValueError( + self.msg.format( + validator=self.validator, + exc_types=self.exc_types, + ), + attr, + self.validator, + value, + self.exc_types, + ) + + def __repr__(self): + return f"" + + +def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): + """ + A validator that wraps and logically 'inverts' the validator passed to it. + It will raise a `ValueError` if the provided validator *doesn't* raise a + `ValueError` or `TypeError` (by default), and will suppress the exception + if the provided validator *does*. + + Intended to be used with existing validators to compose logic without + needing to create inverted variants, for example, ``not_(in_(...))``. + + Args: + validator: A validator to be logically inverted. + + msg (str): + Message to raise if validator fails. Formatted with keys + ``exc_types`` and ``validator``. + + exc_types (tuple[type, ...]): + Exception type(s) to capture. Other types raised by child + validators will not be intercepted and pass through. + + Raises: + ValueError: + With a human readable error message, the attribute (of type + `attrs.Attribute`), the validator that failed to raise an + exception, the value it got, and the expected exception types. + + .. versionadded:: 22.2.0 + """ + try: + exc_types = tuple(exc_types) + except TypeError: + exc_types = (exc_types,) + return _NotValidator(validator, msg, exc_types) + + +@attrs(repr=False, slots=True, unsafe_hash=True) +class _OrValidator: + validators = attrib() + + def __call__(self, inst, attr, value): + for v in self.validators: + try: + v(inst, attr, value) + except Exception: # noqa: BLE001, PERF203, S112 + continue + else: + return + + msg = f"None of {self.validators!r} satisfied for value {value!r}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def or_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators until one of them is + satisfied. + + Args: + validators (~collections.abc.Iterable[typing.Callable]): + Arbitrary number of validators. + + Raises: + ValueError: + If no validator is satisfied. Raised with a human-readable error + message listing all the wrapped validators and the value that + failed all of them. + + .. versionadded:: 24.1.0 + """ + vals = [] + for v in validators: + vals.extend(v.validators if isinstance(v, _OrValidator) else [v]) + + return _OrValidator(tuple(vals)) diff --git a/source/target-vendors/cp312/attr/validators.pyi b/source/target-vendors/cp312/attr/validators.pyi new file mode 100644 index 0000000..18fb112 --- /dev/null +++ b/source/target-vendors/cp312/attr/validators.pyi @@ -0,0 +1,140 @@ +from types import UnionType +from typing import ( + Any, + AnyStr, + Callable, + Container, + ContextManager, + Iterable, + Mapping, + Match, + Pattern, + TypeVar, + overload, +) + +from attrs import _ValidatorType +from attrs import _ValidatorArgType + +_T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") +_T4 = TypeVar("_T4") +_T5 = TypeVar("_T5") +_T6 = TypeVar("_T6") +_I = TypeVar("_I", bound=Iterable) +_K = TypeVar("_K") +_V = TypeVar("_V") +_M = TypeVar("_M", bound=Mapping) + +def set_disabled(run: bool) -> None: ... +def get_disabled() -> bool: ... +def disabled() -> ContextManager[None]: ... + +# To be more precise on instance_of use some overloads. +# If there are more than 3 items in the tuple then we fall back to Any +@overload +def instance_of(type: type[_T]) -> _ValidatorType[_T]: ... +@overload +def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ... +@overload +def instance_of( + type: tuple[type[_T1], type[_T2]], +) -> _ValidatorType[_T1 | _T2]: ... +@overload +def instance_of( + type: tuple[type[_T1], type[_T2], type[_T3]], +) -> _ValidatorType[_T1 | _T2 | _T3]: ... +@overload +def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ... +@overload +def instance_of(type: UnionType) -> _ValidatorType[Any]: ... +def optional( + validator: ( + _ValidatorType[_T] + | list[_ValidatorType[_T]] + | tuple[_ValidatorType[_T], ...] + ), +) -> _ValidatorType[_T | None]: ... +def in_(options: Container[_T]) -> _ValidatorType[_T]: ... +def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... +def matches_re( + regex: Pattern[AnyStr] | AnyStr, + flags: int = ..., + func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ..., +) -> _ValidatorType[AnyStr]: ... +def deep_iterable( + member_validator: _ValidatorArgType[_T], + iterable_validator: _ValidatorArgType[_I] | None = ..., +) -> _ValidatorType[_I]: ... +@overload +def deep_mapping( + key_validator: _ValidatorArgType[_K], + value_validator: _ValidatorArgType[_V] | None = ..., + mapping_validator: _ValidatorArgType[_M] | None = ..., +) -> _ValidatorType[_M]: ... +@overload +def deep_mapping( + key_validator: _ValidatorArgType[_K] | None = ..., + value_validator: _ValidatorArgType[_V] = ..., + mapping_validator: _ValidatorArgType[_M] | None = ..., +) -> _ValidatorType[_M]: ... +def is_callable() -> _ValidatorType[_T]: ... +def lt(val: _T) -> _ValidatorType[_T]: ... +def le(val: _T) -> _ValidatorType[_T]: ... +def ge(val: _T) -> _ValidatorType[_T]: ... +def gt(val: _T) -> _ValidatorType[_T]: ... +def max_len(length: int) -> _ValidatorType[_T]: ... +def min_len(length: int) -> _ValidatorType[_T]: ... +def not_( + validator: _ValidatorType[_T], + *, + msg: str | None = None, + exc_types: type[Exception] | Iterable[type[Exception]] = ..., +) -> _ValidatorType[_T]: ... +@overload +def or_( + __v1: _ValidatorType[_T1], + __v2: _ValidatorType[_T2], +) -> _ValidatorType[_T1 | _T2]: ... +@overload +def or_( + __v1: _ValidatorType[_T1], + __v2: _ValidatorType[_T2], + __v3: _ValidatorType[_T3], +) -> _ValidatorType[_T1 | _T2 | _T3]: ... +@overload +def or_( + __v1: _ValidatorType[_T1], + __v2: _ValidatorType[_T2], + __v3: _ValidatorType[_T3], + __v4: _ValidatorType[_T4], +) -> _ValidatorType[_T1 | _T2 | _T3 | _T4]: ... +@overload +def or_( + __v1: _ValidatorType[_T1], + __v2: _ValidatorType[_T2], + __v3: _ValidatorType[_T3], + __v4: _ValidatorType[_T4], + __v5: _ValidatorType[_T5], +) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5]: ... +@overload +def or_( + __v1: _ValidatorType[_T1], + __v2: _ValidatorType[_T2], + __v3: _ValidatorType[_T3], + __v4: _ValidatorType[_T4], + __v5: _ValidatorType[_T5], + __v6: _ValidatorType[_T6], +) -> _ValidatorType[_T1 | _T2 | _T3 | _T4 | _T5 | _T6]: ... +@overload +def or_( + __v1: _ValidatorType[Any], + __v2: _ValidatorType[Any], + __v3: _ValidatorType[Any], + __v4: _ValidatorType[Any], + __v5: _ValidatorType[Any], + __v6: _ValidatorType[Any], + *validators: _ValidatorType[Any], +) -> _ValidatorType[Any]: ... diff --git a/source/target-vendors/cp312/attrs-26.1.0.dist-info/METADATA b/source/target-vendors/cp312/attrs-26.1.0.dist-info/METADATA new file mode 100644 index 0000000..5cf16a0 --- /dev/null +++ b/source/target-vendors/cp312/attrs-26.1.0.dist-info/METADATA @@ -0,0 +1,199 @@ +Metadata-Version: 2.4 +Name: attrs +Version: 26.1.0 +Summary: Classes Without Boilerplate +Project-URL: Documentation, https://www.attrs.org/ +Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html +Project-URL: GitHub, https://github.com/python-attrs/attrs +Project-URL: Funding, https://github.com/sponsors/hynek +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi +Author-email: Hynek Schlawack +License-Expression: MIT +License-File: LICENSE +Keywords: attribute,boilerplate,class +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Typing :: Typed +Requires-Python: >=3.9 +Description-Content-Type: text/markdown + +

    + + attrs + +

    + + +*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)). +Trusted by NASA for [Mars missions since 2020](https://github.com/readme/featured/nasa-ingenuity-helicopter)! + +Its main goal is to help you to write **concise** and **correct** software without slowing down your code. + + +## Sponsors + +*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek). +Especially those generously supporting us at the *The Organization* tier and higher: + + + +

    + + + + + + + + + + + +

    + + + +

    + Please consider joining them to help make attrs’s maintenance more sustainable! +

    + + + +## Example + +*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: + + + +```pycon +>>> from attrs import asdict, define, make_class, Factory + +>>> @define +... class SomeClass: +... a_number: int = 42 +... list_of_numbers: list[int] = Factory(list) +... +... def hard_math(self, another_number): +... return self.a_number + sum(self.list_of_numbers) * another_number + + +>>> sc = SomeClass(1, [1, 2, 3]) +>>> sc +SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + +>>> sc.hard_math(3) +19 +>>> sc == SomeClass(1, [1, 2, 3]) +True +>>> sc != SomeClass(2, [3, 2, 1]) +True + +>>> asdict(sc) +{'a_number': 1, 'list_of_numbers': [1, 2, 3]} + +>>> SomeClass() +SomeClass(a_number=42, list_of_numbers=[]) + +>>> C = make_class("C", ["a", "b"]) +>>> C("foo", "bar") +C(a='foo', b='bar') +``` + +After *declaring* your attributes, *attrs* gives you: + +- a concise and explicit overview of the class's attributes, +- a nice human-readable `__repr__`, +- equality-checking methods, +- an initializer, +- and much more, + +*without* writing dull boilerplate code again and again and *without* runtime performance penalties. + +--- + +This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. +The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. + +Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation! + + +### Hate Type Annotations!? + +No problem! +Types are entirely **optional** with *attrs*. +Simply assign `attrs.field()` to the attributes instead of annotating them with types: + +```python +from attrs import define, field + +@define +class SomeClass: + a_number = field(default=42) + list_of_numbers = field(factory=list) +``` + + +## Data Classes + +On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). +In practice it does a lot more and is more flexible. +For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger. + +For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice. + + +## Project Information + +- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) +- [**Documentation**](https://www.attrs.org/) +- [**PyPI**](https://pypi.org/project/attrs/) +- [**Source Code**](https://github.com/python-attrs/attrs) +- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) +- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) +- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs) + + +### *attrs* for Enterprise + +Available as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek). + +The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. + +## Release Information + +### Backwards-incompatible Changes + +- Field aliases are now resolved *before* calling `field_transformer`, so transformers receive fully populated `Attribute` objects with usable `alias` values instead of `None`. + The new `Attribute.alias_is_default` flag indicates whether the alias was auto-generated (`True`) or explicitly set by the user (`False`). + [#1509](https://github.com/python-attrs/attrs/issues/1509) + + +### Changes + +- Fix type annotations for `attrs.validators.optional()`, so it no longer rejects tuples with more than one validator. + [#1496](https://github.com/python-attrs/attrs/issues/1496) +- The `attrs.validators.disabled()` contextmanager can now be nested. + [#1513](https://github.com/python-attrs/attrs/issues/1513) +- Frozen classes can set `on_setattr=attrs.setters.NO_OP` in addition to `None`. + [#1515](https://github.com/python-attrs/attrs/issues/1515) +- It's now possible to pass *attrs* **instances** in addition to *attrs* **classes** to `attrs.fields()`. + [#1529](https://github.com/python-attrs/attrs/issues/1529) + + + +--- + +[Full changelog →](https://www.attrs.org/en/stable/changelog.html) diff --git a/source/target-vendors/cp312/attrs-26.1.0.dist-info/RECORD b/source/target-vendors/cp312/attrs-26.1.0.dist-info/RECORD new file mode 100644 index 0000000..d048dcf --- /dev/null +++ b/source/target-vendors/cp312/attrs-26.1.0.dist-info/RECORD @@ -0,0 +1,35 @@ +attr/__init__.py,sha256=fOYIvt1eGSqQre4uCS3sJWKZ0mwAuC8UD6qba5OS9_U,2057 +attr/__init__.pyi,sha256=pVGImAUVovq2_TYl_r_HIYnGlyOaoCuEhxo-EvsnnSc,11325 +attr/_cmp.py,sha256=3Nn1TjxllUYiX_nJoVnEkXoDk0hM1DYKj5DE7GZe4i0,4117 +attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368 +attr/_compat.py,sha256=x0g7iEUOnBVJC72zyFCgb1eKqyxS-7f2LGnNyZ_r95s,2829 +attr/_config.py,sha256=dGq3xR6fgZEF6UBt_L0T-eUHIB4i43kRmH0P28sJVw8,843 +attr/_funcs.py,sha256=Ix5IETTfz5F01F-12MF_CSFomIn2h8b67EVVz2gCtBE,16479 +attr/_make.py,sha256=H7OH2eWS5CnBzLUjNFE1WymfPrmF1r8fv2RPdt9MuYA,106129 +attr/_next_gen.py,sha256=BQtCUlzwg2gWHTYXBQvrEYBnzBUrDvO57u0Py6UCPhc,26274 +attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 +attr/_version_info.py,sha256=w4R-FYC3NK_kMkGUWJlYP4cVAlH9HRaC-um3fcjYkHM,2222 +attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 +attr/converters.py,sha256=GlDeOzPeTFgeBBLbj9G57Ez5lAk68uhSALRYJ_exe84,3861 +attr/converters.pyi,sha256=orU2bff-VjQa2kMDyvnMQV73oJT2WRyQuw4ZR1ym1bE,643 +attr/exceptions.py,sha256=b4vMbnoQ3VpwWZhqrYi_ssXVCK8o2c4HQSS09cSUM9o,1990 +attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 +attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795 +attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208 +attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attr/setters.py,sha256=5-dcT63GQK35ONEzSgfXCkbB7pPkaR-qv15mm4PVSzQ,1617 +attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584 +attr/validators.py,sha256=m3QRzZTANr4f2C4eVdUoFg11NgXWak8Wat4qQTGhvcs,21553 +attr/validators.pyi,sha256=gM1ZmHaBckyYWI2EirpRNzqm3B19cw5Iq6B4Kno9YCM,4087 +attrs/__init__.py,sha256=RxaAZNwYiEh-fcvHLZNpQ_DWKni73M_jxEPEftiq1Zc,1183 +attrs/__init__.pyi,sha256=2gV79g9UxJppGSM48hAZJ6h_MHb70dZoJL31ZNJeZYI,9416 +attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 +attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 +attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 +attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 +attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 +attrs-26.1.0.dist-info/METADATA,sha256=TNQOaQ8jvzfLytNO_WdY4GLfHfB8hoM_fjzpW_H6OMw,8754 +attrs-26.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87 +attrs-26.1.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 +attrs-26.1.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/attrs-26.1.0.dist-info/WHEEL b/source/target-vendors/cp312/attrs-26.1.0.dist-info/WHEEL new file mode 100644 index 0000000..b1b94fd --- /dev/null +++ b/source/target-vendors/cp312/attrs-26.1.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.29.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/attrs-26.1.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/attrs-26.1.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..2bd6453 --- /dev/null +++ b/source/target-vendors/cp312/attrs-26.1.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hynek Schlawack and the attrs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/source/target-vendors/cp312/attrs/__init__.py b/source/target-vendors/cp312/attrs/__init__.py new file mode 100644 index 0000000..dc1ce4b --- /dev/null +++ b/source/target-vendors/cp312/attrs/__init__.py @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: MIT + +from attr import ( + NOTHING, + Attribute, + AttrsInstance, + Converter, + Factory, + NothingType, + _make_getattr, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) +from attr._make import ClassProps +from attr._next_gen import asdict, astuple, inspect + +from . import converters, exceptions, filters, setters, validators + + +__all__ = [ + "NOTHING", + "Attribute", + "AttrsInstance", + "ClassProps", + "Converter", + "Factory", + "NothingType", + "__author__", + "__copyright__", + "__description__", + "__doc__", + "__email__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "asdict", + "assoc", + "astuple", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "field", + "fields", + "fields_dict", + "filters", + "frozen", + "has", + "inspect", + "make_class", + "mutable", + "resolve_types", + "setters", + "validate", + "validators", +] + +__getattr__ = _make_getattr(__name__) diff --git a/source/target-vendors/cp312/attrs/__init__.pyi b/source/target-vendors/cp312/attrs/__init__.pyi new file mode 100644 index 0000000..6364bac --- /dev/null +++ b/source/target-vendors/cp312/attrs/__init__.pyi @@ -0,0 +1,314 @@ +import sys + +from typing import ( + Any, + Callable, + Mapping, + Sequence, + overload, + TypeVar, +) + +# Because we need to type our own stuff, we have to make everything from +# attr explicitly public too. +from attr import __author__ as __author__ +from attr import __copyright__ as __copyright__ +from attr import __description__ as __description__ +from attr import __email__ as __email__ +from attr import __license__ as __license__ +from attr import __title__ as __title__ +from attr import __url__ as __url__ +from attr import __version__ as __version__ +from attr import __version_info__ as __version_info__ +from attr import assoc as assoc +from attr import Attribute as Attribute +from attr import AttrsInstance as AttrsInstance +from attr import cmp_using as cmp_using +from attr import converters as converters +from attr import Converter as Converter +from attr import evolve as evolve +from attr import exceptions as exceptions +from attr import Factory as Factory +from attr import fields as fields +from attr import fields_dict as fields_dict +from attr import filters as filters +from attr import has as has +from attr import make_class as make_class +from attr import NOTHING as NOTHING +from attr import resolve_types as resolve_types +from attr import setters as setters +from attr import validate as validate +from attr import validators as validators +from attr import attrib, asdict as asdict, astuple as astuple +from attr import NothingType as NothingType + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_EqOrderType = bool | Callable[[Any], Any] +_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] +_CallableConverterType = Callable[[Any], Any] +_ConverterType = _CallableConverterType | Converter[Any, Any] +_ReprType = Callable[[Any], str] +_ReprArgType = bool | _ReprType +_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] +_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType +_FieldTransformer = Callable[ + [type, list["Attribute[Any]"]], list["Attribute[Any]"] +] +# FIXME: in reality, if multiple validators are passed they must be in a list +# or tuple, but those are invariant and so would prevent subtypes of +# _ValidatorType from working when passed in a list or tuple. +_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]] + +@overload +def field( + *, + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool | None = ..., + eq: bool | None = ..., + order: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def field( + *, + default: None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType, ...] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def field( + *, + default: _T, + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType, ...] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def field( + *, + default: _T | None = ..., + validator: _ValidatorArgType[_T] | None = ..., + repr: _ReprArgType = ..., + hash: bool | None = ..., + init: bool = ..., + metadata: Mapping[Any, Any] | None = ..., + converter: _ConverterType + | list[_ConverterType] + | tuple[_ConverterType, ...] + | None = ..., + factory: Callable[[], _T] | None = ..., + kw_only: bool | None = ..., + eq: _EqOrderType | None = ..., + order: _EqOrderType | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + alias: str | None = ..., + type: type | None = ..., +) -> Any: ... +@overload +@dataclass_transform(field_specifiers=(attrib, field)) +def define( + maybe_cls: _C, + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@dataclass_transform(field_specifiers=(attrib, field)) +def define( + maybe_cls: None = ..., + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... + +mutable = define + +@overload +@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) +def frozen( + maybe_cls: _C, + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) +def frozen( + maybe_cls: None = ..., + *, + these: dict[str, Any] | None = ..., + repr: bool = ..., + unsafe_hash: bool | None = ..., + hash: bool | None = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: bool | None = ..., + order: bool | None = ..., + auto_detect: bool = ..., + getstate_setstate: bool | None = ..., + on_setattr: _OnSetAttrArgType | None = ..., + field_transformer: _FieldTransformer | None = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... + +class ClassProps: + # XXX: somehow when defining/using enums Mypy starts looking at our own + # (untyped) code and causes tons of errors. + Hashability: Any + KeywordOnly: Any + + is_exception: bool + is_slotted: bool + has_weakref_slot: bool + is_frozen: bool + # kw_only: ClassProps.KeywordOnly + kw_only: Any + collected_fields_by_mro: bool + added_init: bool + added_repr: bool + added_eq: bool + added_ordering: bool + # hashability: ClassProps.Hashability + hashability: Any + added_match_args: bool + added_str: bool + added_pickling: bool + on_setattr_hook: _OnSetAttrType | None + field_transformer: Callable[[Attribute[Any]], Attribute[Any]] | None + + def __init__( + self, + is_exception: bool, + is_slotted: bool, + has_weakref_slot: bool, + is_frozen: bool, + # kw_only: ClassProps.KeywordOnly + kw_only: Any, + collected_fields_by_mro: bool, + added_init: bool, + added_repr: bool, + added_eq: bool, + added_ordering: bool, + # hashability: ClassProps.Hashability + hashability: Any, + added_match_args: bool, + added_str: bool, + added_pickling: bool, + on_setattr_hook: _OnSetAttrType, + field_transformer: Callable[[Attribute[Any]], Attribute[Any]], + ) -> None: ... + @property + def is_hashable(self) -> bool: ... + +def inspect(cls: type) -> ClassProps: ... diff --git a/source/target-vendors/cp312/attrs/converters.py b/source/target-vendors/cp312/attrs/converters.py new file mode 100644 index 0000000..7821f6c --- /dev/null +++ b/source/target-vendors/cp312/attrs/converters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.converters import * # noqa: F403 diff --git a/source/target-vendors/cp312/attrs/exceptions.py b/source/target-vendors/cp312/attrs/exceptions.py new file mode 100644 index 0000000..3323f9d --- /dev/null +++ b/source/target-vendors/cp312/attrs/exceptions.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.exceptions import * # noqa: F403 diff --git a/source/target-vendors/cp312/attrs/filters.py b/source/target-vendors/cp312/attrs/filters.py new file mode 100644 index 0000000..3080f48 --- /dev/null +++ b/source/target-vendors/cp312/attrs/filters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.filters import * # noqa: F403 diff --git a/source/target-vendors/cp312/attrs/py.typed b/source/target-vendors/cp312/attrs/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/attrs/setters.py b/source/target-vendors/cp312/attrs/setters.py new file mode 100644 index 0000000..f3d73bb --- /dev/null +++ b/source/target-vendors/cp312/attrs/setters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.setters import * # noqa: F403 diff --git a/source/target-vendors/cp312/attrs/validators.py b/source/target-vendors/cp312/attrs/validators.py new file mode 100644 index 0000000..037e124 --- /dev/null +++ b/source/target-vendors/cp312/attrs/validators.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.validators import * # noqa: F403 diff --git a/source/target-vendors/cp312/certifi-2026.7.22.dist-info/METADATA b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/METADATA new file mode 100644 index 0000000..eb460c2 --- /dev/null +++ b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/METADATA @@ -0,0 +1,78 @@ +Metadata-Version: 2.4 +Name: certifi +Version: 2026.7.22 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://github.com/certifi/python-certifi +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Source, https://github.com/certifi/python-certifi +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Requires-Python: >=3.7 +License-File: LICENSE +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: license +Dynamic: license-file +Dynamic: project-url +Dynamic: requires-python +Dynamic: summary + +Certifi: Python SSL Certificates +================================ + +Certifi provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +.. _`Requests`: https://requests.readthedocs.io/en/latest/ + +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/source/target-vendors/cp312/certifi-2026.7.22.dist-info/RECORD b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/RECORD new file mode 100644 index 0000000..f378e12 --- /dev/null +++ b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/RECORD @@ -0,0 +1,12 @@ +certifi/__init__.py,sha256=elLl9CBfmz0SoxiYzqp-P2g30ZzCMHALyuGp2R0UhsE,94 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/cacert.pem,sha256=nMKndLUZjc_xTZvh5mCR9TiXXYZ84Cmpa84VpV39cw8,240216 +certifi/core.py,sha256=XFXycndG5pf37ayeF8N32HUuDafsyhkVMbO4BAPWHa0,3394 +certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +certifi/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +certifi/tests/test_certify.py,sha256=fBedHt839-kSsTNmNzX7RsYzjV0OX4kV0Rw7wofSJ7g,467 +certifi-2026.7.22.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 +certifi-2026.7.22.dist-info/METADATA,sha256=71rxY4-7I2dqw8V3ffz8LNnDSP5Bcu1bo9J3ZVskgJA,2474 +certifi-2026.7.22.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91 +certifi-2026.7.22.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi-2026.7.22.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/certifi-2026.7.22.dist-info/WHEEL b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/WHEEL new file mode 100644 index 0000000..1d472b6 --- /dev/null +++ b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (83.0.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/certifi-2026.7.22.dist-info/licenses/LICENSE b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/licenses/LICENSE new file mode 100644 index 0000000..62b076c --- /dev/null +++ b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/licenses/LICENSE @@ -0,0 +1,20 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/source/target-vendors/cp312/certifi-2026.7.22.dist-info/top_level.txt b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/top_level.txt new file mode 100644 index 0000000..963eac5 --- /dev/null +++ b/source/target-vendors/cp312/certifi-2026.7.22.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/source/target-vendors/cp312/certifi/__init__.py b/source/target-vendors/cp312/certifi/__init__.py new file mode 100644 index 0000000..66dae9e --- /dev/null +++ b/source/target-vendors/cp312/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2026.07.22" diff --git a/source/target-vendors/cp312/certifi/__main__.py b/source/target-vendors/cp312/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/source/target-vendors/cp312/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/source/target-vendors/cp312/certifi/cacert.pem b/source/target-vendors/cp312/certifi/cacert.pem new file mode 100644 index 0000000..9a40f43 --- /dev/null +++ b/source/target-vendors/cp312/certifi/cacert.pem @@ -0,0 +1,3959 @@ + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Label: "AC RAIZ FNMT-RCM" +# Serial: 485876308206448804701554682760554759 +# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d +# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 +# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 1 O=Amazon +# Subject: CN=Amazon Root CA 1 O=Amazon +# Label: "Amazon Root CA 1" +# Serial: 143266978916655856878034712317230054538369994 +# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 +# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 +# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 2 O=Amazon +# Subject: CN=Amazon Root CA 2 O=Amazon +# Label: "Amazon Root CA 2" +# Serial: 143266982885963551818349160658925006970653239 +# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 +# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a +# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 3 O=Amazon +# Subject: CN=Amazon Root CA 3 O=Amazon +# Label: "Amazon Root CA 3" +# Serial: 143266986699090766294700635381230934788665930 +# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 +# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e +# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 4 O=Amazon +# Subject: CN=Amazon Root CA 4 O=Amazon +# Label: "Amazon Root CA 4" +# Serial: 143266989758080763974105200630763877849284878 +# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd +# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be +# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" +# Serial: 1 +# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 +# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca +# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Label: "GDCA TrustAUTH R5 ROOT" +# Serial: 9009899650740120186 +# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 +# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 +# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Label: "SSL.com Root Certification Authority RSA" +# Serial: 8875640296558310041 +# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 +# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb +# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com Root Certification Authority ECC" +# Serial: 8495723813297216424 +# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e +# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a +# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority RSA R2" +# Serial: 6248227494352943350 +# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 +# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a +# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority ECC" +# Serial: 3182246526754555285 +# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 +# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d +# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GC CA" +# Serial: 44084345621038548146064804565436152554 +# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 +# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 +# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +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 +mpv0 +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft ECC Root Certificate Authority 2017" +# Serial: 136839042543790627607696632466672567020 +# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 +# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 +# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft RSA Root Certificate Authority 2017" +# Serial: 40975477897264996090493496164228220339 +# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 +# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 +# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Label: "e-Szigno Root CA 2017" +# Serial: 411379200276854331539784714 +# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 +# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 +# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- + +# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Label: "certSIGN Root CA G2" +# Serial: 313609486401300475190 +# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 +# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 +# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Label: "NAVER Global Root Certification Authority" +# Serial: 9013692873798656336226253319739695165984492813 +# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b +# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 +# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- + +# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" +# Serial: 131542671362353147877283741781055151509 +# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb +# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a +# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Label: "GlobalSign Root R46" +# Serial: 1552617688466950547958867513931858518042577 +# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef +# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 +# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Label: "GlobalSign Root E46" +# Serial: 1552617690338932563915843282459653771421763 +# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f +# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 +# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Label: "ANF Secure Server Root CA" +# Serial: 996390341000653745 +# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 +# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 +# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum EC-384 CA" +# Serial: 160250656287871593594747141429395092468 +# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 +# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed +# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Root CA" +# Serial: 40870380103424195783807378461123655149 +# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 +# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 +# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 +MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu +MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV +BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw +MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg +U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ +n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q +p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq +NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF +8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 +HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa +mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi +7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF +ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P +qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ +v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 +Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD +ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 +WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo +zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR +5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ +GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf +5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq +0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D +P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM +qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP +0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf +E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- + +# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique +# Label: "TunTrust Root CA" +# Serial: 108534058042236574382096126452369648152337120275 +# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4 +# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb +# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS RSA Root CA 2021" +# Serial: 76817823531813593706434026085292783742 +# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91 +# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d +# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE----- + +# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA +# Label: "HARICA TLS ECC Root CA 2021" +# Serial: 137515985548005187474074462014555733966 +# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 +# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 +# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 +-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 1977337328857672817 +# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3 +# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe +# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE----- + +# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. +# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd. +# Label: "vTrus ECC Root CA" +# Serial: 630369271402956006249506845124680065938238527194 +# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85 +# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1 +# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3 +-----BEGIN CERTIFICATE----- +MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw +RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY +BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz +MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u +LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0 +v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd +e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw +V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA +AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG +GJTO +-----END CERTIFICATE----- + +# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd. +# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd. +# Label: "vTrus Root CA" +# Serial: 387574501246983434957692974888460947164905180485 +# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc +# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7 +# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87 +-----BEGIN CERTIFICATE----- +MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL +BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x +FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx +MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s +THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc +IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU +AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+ +GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9 +8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH +flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt +J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim +0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN +pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ +UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW +OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB +AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet +8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd +nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j +bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM +Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv +TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS +S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr +I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9 +b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB +UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P +Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven +sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s= +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X2 O=Internet Security Research Group +# Subject: CN=ISRG Root X2 O=Internet Security Research Group +# Label: "ISRG Root X2" +# Serial: 87493402998870891108772069816698636114 +# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5 +# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af +# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70 +-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE----- + +# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. +# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd. +# Label: "HiPKI Root CA - G1" +# Serial: 60966262342023497858655262305426234976 +# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3 +# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60 +# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc +-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa +Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 +YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw +qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv +Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 +lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz +Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ +KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK +FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj +HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr +y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ +/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM +a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 +fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG +SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc +SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza +ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc +XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg +iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho +L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF +Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr +kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ +vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU +YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 159662223612894884239637590694 +# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc +# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28 +# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2 +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 159662320309726417404178440727 +# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40 +# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a +# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 159662495401136852707857743206 +# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73 +# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46 +# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48 +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 159662532700760215368942768210 +# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8 +# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47 +# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + +# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj +# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj +# Label: "Telia Root CA v2" +# Serial: 7288924052977061235122729490515358 +# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48 +# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd +# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH +# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH +# Label: "D-TRUST BR Root CA 1 2020" +# Serial: 165870826978392376648679885835942448534 +# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed +# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67 +# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44 +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 +NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS +zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 +QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ +VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW +wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV +dWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH +# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH +# Label: "D-TRUST EV Root CA 1 2020" +# Serial: 126288379621884218666039612629459926992 +# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e +# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07 +# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db +-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 +NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC +/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD +wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 +OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA +y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb +gfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. +# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc. +# Label: "DigiCert TLS ECC P384 Root G5" +# Serial: 13129116028163249804115411775095713523 +# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed +# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee +# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05 +-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. +# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc. +# Label: "DigiCert TLS RSA4096 Root G5" +# Serial: 11930366277458970227240571539258396554 +# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1 +# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35 +# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75 +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE----- + +# Issuer: CN=Certainly Root R1 O=Certainly +# Subject: CN=Certainly Root R1 O=Certainly +# Label: "Certainly Root R1" +# Serial: 188833316161142517227353805653483829216 +# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12 +# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af +# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE----- + +# Issuer: CN=Certainly Root E1 O=Certainly +# Subject: CN=Certainly Root E1 O=Certainly +# Label: "Certainly Root E1" +# Serial: 8168531406727139161245376702891150584 +# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9 +# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b +# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2 +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- + +# Issuer: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. +# Subject: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD. +# Label: "Security Communication ECC RootCA1" +# Serial: 15446673492073852651 +# MD5 Fingerprint: 7e:43:b0:92:68:ec:05:43:4c:98:ab:5d:35:2e:7e:86 +# SHA1 Fingerprint: b8:0e:26:a9:bf:d2:b2:3b:c0:ef:46:c9:ba:c7:bb:f6:1d:0d:41:41 +# SHA256 Fingerprint: e7:4f:bd:a5:5b:d5:64:c4:73:a3:6b:44:1a:a7:99:c8:a6:8e:07:74:40:e8:28:8b:9f:a1:e5:0e:4b:ba:ca:11 +-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT +AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD +VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx +NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT +HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 +IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl +dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK +ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu +9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O +be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= +-----END CERTIFICATE----- + +# Issuer: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY +# Subject: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY +# Label: "BJCA Global Root CA1" +# Serial: 113562791157148395269083148143378328608 +# MD5 Fingerprint: 42:32:99:76:43:33:36:24:35:07:82:9b:28:f9:d0:90 +# SHA1 Fingerprint: d5:ec:8d:7b:4c:ba:79:f4:e7:e8:cb:9d:6b:ae:77:83:10:03:21:6a +# SHA256 Fingerprint: f3:89:6f:88:fe:7c:0a:88:27:66:a7:fa:6a:d2:74:9f:b5:7a:7f:3e:98:fb:76:9c:1f:a7:b0:9c:2c:44:d5:ae +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU +MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI +T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz +MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF +SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh +bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z +xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ +spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5 +58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR +at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll +5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq +nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK +V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/ +pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO +z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn +jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+ +WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF +7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4 +YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli +awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u ++2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88 +X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN +SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo +P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI ++pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz +znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9 +eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2 +YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy +r/6zcCwupvI= +-----END CERTIFICATE----- + +# Issuer: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY +# Subject: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY +# Label: "BJCA Global Root CA2" +# Serial: 58605626836079930195615843123109055211 +# MD5 Fingerprint: 5e:0a:f6:47:5f:a6:14:e8:11:01:95:3f:4d:01:eb:3c +# SHA1 Fingerprint: f4:27:86:eb:6e:b8:6d:88:31:67:02:fb:ba:66:a4:53:00:aa:7a:a6 +# SHA256 Fingerprint: 57:4d:f6:93:1e:27:80:39:66:7b:72:0a:fd:c1:60:0f:c2:7e:b6:6d:d3:09:29:79:fb:73:85:64:87:21:28:82 +-----BEGIN CERTIFICATE----- +MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw +CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ +VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy +MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ +TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS +b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B +IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+ ++kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK +sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA +94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B +43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w== +-----END CERTIFICATE----- + +# Issuer: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited +# Subject: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited +# Label: "Sectigo Public Server Authentication Root E46" +# Serial: 88989738453351742415770396670917916916 +# MD5 Fingerprint: 28:23:f8:b2:98:5c:37:16:3b:3e:46:13:4e:b0:b3:01 +# SHA1 Fingerprint: ec:8a:39:6c:40:f0:2e:bc:42:75:d4:9f:ab:1c:1a:5b:67:be:d2:9a +# SHA256 Fingerprint: c9:0f:26:f0:fb:1b:40:18:b2:22:27:51:9b:5c:a2:b5:3e:2c:a5:b3:be:5c:f1:8e:fe:1b:ef:47:38:0c:53:83 +-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN +MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG +A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC +WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ +6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B +Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa +qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q +4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== +-----END CERTIFICATE----- + +# Issuer: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited +# Subject: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited +# Label: "Sectigo Public Server Authentication Root R46" +# Serial: 156256931880233212765902055439220583700 +# MD5 Fingerprint: 32:10:09:52:00:d5:7e:6c:43:df:15:c0:b1:16:93:e5 +# SHA1 Fingerprint: ad:98:f9:f3:e4:7d:75:3b:65:d4:82:b3:a4:52:17:bb:6e:f5:e4:38 +# SHA256 Fingerprint: 7b:b6:47:a6:2a:ee:ac:88:bf:25:7a:a5:22:d0:1f:fe:a3:95:e0:ab:45:c7:3f:93:f6:56:54:ec:38:f2:5a:06 +-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa +ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz +SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf +iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X +ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 +IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS +VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE +SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu ++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt +8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L +HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt +zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P +AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ +YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 +gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA +Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB +JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX +DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui +TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 +dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 +LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp +0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY +QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation +# Subject: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation +# Label: "SSL.com TLS RSA Root CA 2022" +# Serial: 148535279242832292258835760425842727825 +# MD5 Fingerprint: d8:4e:c6:59:30:d8:fe:a0:d6:7a:5a:2c:2c:69:78:da +# SHA1 Fingerprint: ec:2c:83:40:72:af:26:95:10:ff:0e:f2:03:ee:31:70:f6:78:9d:ca +# SHA256 Fingerprint: 8f:af:7d:2e:2c:b4:70:9b:b8:e0:b3:36:66:bf:75:a5:dd:45:b5:de:48:0f:8e:a8:d4:bf:e6:be:bc:17:f2:ed +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation +# Subject: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation +# Label: "SSL.com TLS ECC Root CA 2022" +# Serial: 26605119622390491762507526719404364228 +# MD5 Fingerprint: 99:d7:5c:f1:51:36:cc:e9:ce:d9:19:2e:77:71:56:c5 +# SHA1 Fingerprint: 9f:5f:d9:1a:54:6d:f5:0c:71:f0:ee:7a:bd:17:49:98:84:73:e2:39 +# SHA256 Fingerprint: c3:2f:fd:9f:46:f9:36:d1:6c:36:73:99:09:59:43:4b:9a:d6:0a:af:bb:9e:7c:f3:36:54:f1:44:cc:1b:a1:43 +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos +# Subject: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos +# Label: "Atos TrustedRoot Root CA ECC TLS 2021" +# Serial: 81873346711060652204712539181482831616 +# MD5 Fingerprint: 16:9f:ad:f1:70:ad:79:d6:ed:29:b4:d1:c5:79:70:a8 +# SHA1 Fingerprint: 9e:bc:75:10:42:b3:02:f3:81:f4:f7:30:62:d4:8f:c3:a7:51:b2:dd +# SHA256 Fingerprint: b2:fa:e5:3e:14:cc:d7:ab:92:12:06:47:01:ae:27:9c:1d:89:88:fa:cb:77:5f:a8:a0:08:91:4e:66:39:88:a8 +-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w +LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w +CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 +MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF +Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X +tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 +AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 +KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD +aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu +CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo +9H1/IISpQuQo +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos +# Subject: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos +# Label: "Atos TrustedRoot Root CA RSA TLS 2021" +# Serial: 111436099570196163832749341232207667876 +# MD5 Fingerprint: d4:d3:46:b8:9a:c0:9c:76:5d:9e:3a:c3:b9:99:31:d2 +# SHA1 Fingerprint: 18:52:3b:0d:06:37:e4:d6:3a:df:23:e4:98:fb:5b:16:fb:86:74:48 +# SHA256 Fingerprint: 81:a9:08:8e:a5:9f:b3:64:c5:48:a6:f8:55:59:09:9b:6f:04:05:ef:bf:18:e5:32:4e:c9:f4:57:ba:00:11:2f +-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM +MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx +MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 +MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD +QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z +4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv +Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ +kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs +GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln +nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh +3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD +0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy +geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 +ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB +c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI +pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs +o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ +qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw +xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM +rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 +AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR +0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY +o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 +dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE +oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE----- + +# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. +# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc. +# Label: "TrustAsia Global Root CA G3" +# Serial: 576386314500428537169965010905813481816650257167 +# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04 +# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7 +# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08 +-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM +BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe +Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw +IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU +cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS +T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK +AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 +nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep +qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA +yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs +hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX +zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv +kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT +f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA +uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih +MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 +wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 +XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 +JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j +ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV +VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx +xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on +AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d +7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj +gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV ++Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo +FGWsJwt0ivKH +-----END CERTIFICATE----- + +# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. +# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc. +# Label: "TrustAsia Global Root CA G4" +# Serial: 451799571007117016466790293371524403291602933463 +# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb +# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a +# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c +-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw +WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y +MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD +VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz +dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx +s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw +LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD +pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE +AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR +UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj +/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE----- + +# Issuer: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH +# Subject: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH +# Label: "Telekom Security TLS ECC Root 2020" +# Serial: 72082518505882327255703894282316633856 +# MD5 Fingerprint: c1:ab:fe:6a:10:2c:03:8d:bc:1c:22:32:c0:85:a7:fd +# SHA1 Fingerprint: c0:f8:96:c5:a9:3b:01:06:21:07:da:18:42:48:bc:e9:9d:88:d5:ec +# SHA256 Fingerprint: 57:8a:f4:de:d0:85:3f:4e:59:98:db:4a:ea:f9:cb:ea:8d:94:5f:60:b6:20:a3:8d:1a:3c:13:b2:bc:7b:a8:e1 +-----BEGIN CERTIFICATE----- +MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw +CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH +bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw +MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx +JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE +AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O +tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP +f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA +MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di +z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn +27iQ7t0l +-----END CERTIFICATE----- + +# Issuer: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH +# Subject: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH +# Label: "Telekom Security TLS RSA Root 2023" +# Serial: 44676229530606711399881795178081572759 +# MD5 Fingerprint: bf:5b:eb:54:40:cd:48:71:c4:20:8d:7d:de:0a:42:f2 +# SHA1 Fingerprint: 54:d3:ac:b3:bd:57:56:f6:85:9d:ce:e5:c3:21:e2:d4:ad:83:d0:93 +# SHA256 Fingerprint: ef:c6:5c:ad:bb:59:ad:b6:ef:e8:4d:a2:23:11:b3:56:24:b7:1b:3b:1e:a0:da:8b:66:55:17:4e:c8:97:86:46 +-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj +MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0 +eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy +MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC +REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG +A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9 +cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV +cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA +U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6 +Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug +BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy +8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J +co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg +8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8 +rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12 +mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg ++y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX +gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2 +p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ +pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm +9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw +M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd +GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+ +CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t +xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+ +w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK +L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj +X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q +ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm +dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA CYBER Root CA" +# Serial: 85076849864375384482682434040119489222 +# MD5 Fingerprint: 0b:33:a0:97:52:95:d4:a9:fd:bb:db:6e:a3:55:5b:51 +# SHA1 Fingerprint: f6:b1:1c:1a:83:38:e9:7b:db:b3:a8:c8:33:24:e0:2d:9c:7f:26:66 +# SHA256 Fingerprint: 3f:63:bb:28:14:be:17:4e:c8:b6:43:9c:f0:8d:6d:56:f0:b7:c4:05:88:3a:56:48:a3:34:42:4d:6b:3e:c5:58 +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ +MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 +IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 +WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO +LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P +40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF +avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/ +34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i +JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu +j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf +Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP +2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA +S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA +oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC +kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW +5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd +BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t +tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn +68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn +TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t +RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx +f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI +Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz +8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4 +NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX +xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 +t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. +# Subject: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd. +# Label: "SecureSign Root CA14" +# Serial: 575790784512929437950770173562378038616896959179 +# MD5 Fingerprint: 71:0d:72:fa:92:19:65:5e:89:04:ac:16:33:f0:bc:d5 +# SHA1 Fingerprint: dd:50:c0:f7:79:b3:64:2e:74:a2:b8:9d:9f:d3:40:dd:bb:f0:f2:4f +# SHA256 Fingerprint: 4b:00:9c:10:34:49:4f:9a:b5:6b:ba:3b:a1:d6:27:31:fc:4d:20:d8:95:5a:dc:ec:10:a9:25:60:72:61:e3:38 +-----BEGIN CERTIFICATE----- +MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM +BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u +LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw +NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD +eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS +b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/ +FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg +vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy +6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo +/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J +kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ +0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib +y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac +18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs +0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB +SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL +ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk +86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E +rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib +ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT +zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS +DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4 +2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo +FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy +K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6 +dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl +Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB +365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c +JRNItX+S +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. +# Subject: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd. +# Label: "SecureSign Root CA15" +# Serial: 126083514594751269499665114766174399806381178503 +# MD5 Fingerprint: 13:30:fc:c4:62:a6:a9:de:b5:c1:68:af:b5:d2:31:47 +# SHA1 Fingerprint: cb:ba:83:c8:c1:5a:5d:f1:f9:73:6f:ca:d7:ef:28:13:06:4a:07:7d +# SHA256 Fingerprint: e7:78:f0:f0:95:fe:84:37:29:cd:1a:00:82:17:9e:53:14:a9:c2:91:44:28:05:e1:fb:1d:8f:b6:b8:88:6c:3a +-----BEGIN CERTIFICATE----- +MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw +UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM +dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy +NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl +cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290 +IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4 +wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR +ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT +9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp +4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6 +bkU6iYAZezKYVWOr62Nuk22rGwlgMU4= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH +# Subject: CN=D-TRUST BR Root CA 2 2023 O=D-Trust GmbH +# Label: "D-TRUST BR Root CA 2 2023" +# Serial: 153168538924886464690566649552453098598 +# MD5 Fingerprint: e1:09:ed:d3:60:d4:56:1b:47:1f:b7:0c:5f:1b:5f:85 +# SHA1 Fingerprint: 2d:b0:70:ee:71:94:af:69:68:17:db:79:ce:58:9f:a0:6b:96:f7:87 +# SHA256 Fingerprint: 05:52:e6:f8:3f:df:65:e8:fa:96:70:e6:66:df:28:a4:e2:13:40:b5:10:cb:e5:25:66:f9:7c:4f:b9:4b:2b:d1 +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQczswBEhb2U14LnNLyaHcZjANBgkqhkiG9w0BAQ0FADBI +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE +LVRSVVNUIEJSIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA4NTYzMVoXDTM4MDUw +OTA4NTYzMFowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi +MCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAK7/CVmRgApKaOYkP7in5Mg6CjoWzckjYaCTcfKr +i3OPoGdlYNJUa2NRb0kz4HIHE304zQaSBylSa053bATTlfrdTIzZXcFhfUvnKLNE +gXtRr90zsWh81k5M/itoucpmacTsXld/9w3HnDY25QdgrMBM6ghs7wZ8T1soegj8 +k12b9py0i4a6Ibn08OhZWiihNIQaJZG2tY/vsvmA+vk9PBFy2OMvhnbFeSzBqZCT +Rphny4NqoFAjpzv2gTng7fC5v2Xx2Mt6++9zA84A9H3X4F07ZrjcjrqDy4d2A/wl +2ecjbwb9Z/Pg/4S8R7+1FhhGaRTMBffb00msa8yr5LULQyReS2tNZ9/WtT5PeB+U +cSTq3nD88ZP+npNa5JRal1QMNXtfbO4AHyTsA7oC9Xb0n9Sa7YUsOCIvx9gvdhFP +/Wxc6PWOJ4d/GUohR5AdeY0cW/jPSoXk7bNbjb7EZChdQcRurDhaTyN0dKkSw/bS +uREVMweR2Ds3OmMwBtHFIjYoYiMQ4EbMl6zWK11kJNXuHA7e+whadSr2Y23OC0K+ +0bpwHJwh5Q8xaRfX/Aq03u2AnMuStIv13lmiWAmlY0cL4UEyNEHZmrHZqLAbWt4N +DfTisl01gLmB1IRpkQLLddCNxbU9CZEJjxShFHR5PtbJFR2kWVki3PaKRT08EtY+ +XTIvAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUZ5Dw1t61 +GNVGKX5cq/ieCLxklRAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfYnJfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQA097N3U9swFrktpSHxQCF16+tI +FoE9c+CeJyrrd6kTpGoKWloUMz1oH4Guaf2Mn2VsNELZLdB/eBaxOqwjMa1ef67n +riv6uvw8l5VAk1/DLQOj7aRvU9f6QA4w9QAgLABMjDu0ox+2v5Eyq6+SmNMW5tTR +VFxDWy6u71cqqLRvpO8NVhTaIasgdp4D/Ca4nj8+AybmTNudX0KEPUUDAxxZiMrc +LmEkWqTqJwtzEr5SswrPMhfiHocaFpVIbVrg0M8JkiZmkdijYQ6qgYF/6FKC0ULn +4B0Y+qSFNueG4A3rvNTJ1jxD8V1Jbn6Bm2m1iWKPiFLY1/4nwSPFyysCu7Ff/vtD +hQNGvl3GyiEm/9cCnnRK3PgTFbGBVzbLZVzRHTF36SXDw7IyN9XxmAnkbWOACKsG +koHU6XCPpz+y7YaMgmo1yEJagtFSGkUPFaUA8JR7ZSdXOUPPfH/mvTWze/EZTN46 +ls/pdu4D58JDUjxqgejBWoC9EV2Ta/vH5mQ/u2kc6d0li690yVRAysuTEwrt+2aS +Ecr1wPrYg1UDfNPFIkZ1cGt5SAYqgpq/5usWDiJFAbzdNpQ0qTUmiteXue4Icr80 +knCDgKs4qllo3UCkGJCy89UDyibK79XH4I9TjvAA46jtn/mtd+ArY0+ew+43u3gJ +hJ65bvspmZDogNOfJA== +-----END CERTIFICATE----- + +# Issuer: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. +# Subject: CN=TrustAsia TLS ECC Root CA O=TrustAsia Technologies, Inc. +# Label: "TrustAsia TLS ECC Root CA" +# Serial: 310892014698942880364840003424242768478804666567 +# MD5 Fingerprint: 09:48:04:77:d2:fc:65:93:71:66:b1:11:95:4f:06:8c +# SHA1 Fingerprint: b5:ec:39:f3:a1:66:37:ae:c3:05:94:57:e2:be:11:be:b7:a1:7f:36 +# SHA256 Fingerprint: c0:07:6b:9e:f0:53:1f:b1:a6:56:d6:7c:4e:be:97:cd:5d:ba:a4:1e:f4:45:98:ac:c2:48:98:78:c9:2d:87:11 +-----BEGIN CERTIFICATE----- +MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMw +WDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQw +NTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBYMQswCQYDVQQGEwJDTjElMCMGA1UE +ChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1c3RB +c2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/pVs/ +AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDp +guMqWzJ8S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAw +DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01 +L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15KeAIxAKORh/IRM4PDwYqR +OkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== +-----END CERTIFICATE----- + +# Issuer: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. +# Subject: CN=TrustAsia TLS RSA Root CA O=TrustAsia Technologies, Inc. +# Label: "TrustAsia TLS RSA Root CA" +# Serial: 160405846464868906657516898462547310235378010780 +# MD5 Fingerprint: 3b:9e:c3:86:0f:34:3c:6b:c5:46:c4:8e:1d:e7:19:12 +# SHA1 Fingerprint: a5:46:50:c5:62:ea:95:9a:1a:a7:04:6f:17:58:c7:29:53:3d:03:fa +# SHA256 Fingerprint: 06:c0:8d:7d:af:d8:76:97:1e:b1:12:4f:e6:7f:84:7e:c0:c7:a1:58:d3:ea:53:cb:e9:40:e2:ea:97:91:f4:c3 +-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEM +BQAwWDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcN +MjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2WjBYMQswCQYDVQQGEwJDTjElMCMG +A1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1 +c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+ +NmDQDIPNlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJ +Q1DNDX3eRA5gEk9bNb2/mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561 +HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fkzv93uMltrOXVmPGZLmzjyUT5tUMnCE32 +ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYozza/+lcK7Fs/6TAWe8Tb +xNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyrz2I8sMeX +i9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQ +UNoyIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+j +TnhMmCWr8n4uIF6CFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DT +bE3txci3OE9kxJRMT6DNrqXGJyV1J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8 +S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnTq1mt1tve1CuBAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZylomkadFK/hT +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 +Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4 +iqME3mmL5Dw8veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt +7DlK9RME7I10nYEKqG/odv6LTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp +2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHxtlotJnMnlvm5P1vQiJ3koP26TpUJ +g3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp27RIGAAtvKLEiUUj +pQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87qqA8M +pugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongP +XvPKnbwbPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIwe +SsCI3zWQzj8C9GRh3sfIB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0 +ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNzFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy +323imttUQ/hHWKNddBWcwauwxzQ= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH +# Subject: CN=D-TRUST EV Root CA 2 2023 O=D-Trust GmbH +# Label: "D-TRUST EV Root CA 2 2023" +# Serial: 139766439402180512324132425437959641711 +# MD5 Fingerprint: 96:b4:78:09:f0:09:cb:77:eb:bb:1b:4d:6f:36:bc:b6 +# SHA1 Fingerprint: a5:5b:d8:47:6c:8f:19:f7:4c:f4:6d:6b:b6:c2:79:82:22:df:54:8b +# SHA256 Fingerprint: 8e:82:21:b2:e7:d4:00:78:36:a1:67:2f:0d:cc:29:9c:33:bc:07:d3:16:f1:32:fa:1a:20:6d:58:71:50:f1:ce +-----BEGIN CERTIFICATE----- +MIIFqTCCA5GgAwIBAgIQaSYJfoBLTKCnjHhiU19abzANBgkqhkiG9w0BAQ0FADBI +MQswCQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlE +LVRSVVNUIEVWIFJvb3QgQ0EgMiAyMDIzMB4XDTIzMDUwOTA5MTAzM1oXDTM4MDUw +OTA5MTAzMlowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEi +MCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDIgMjAyMzCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBANiOo4mAC7JXUtypU0w3uX9jFxPvp1sjW2l1sJkK +F8GLxNuo4MwxusLyzV3pt/gdr2rElYfXR8mV2IIEUD2BCP/kPbOx1sWy/YgJ25yE +7CUXFId/MHibaljJtnMoPDT3mfd/06b4HEV8rSyMlD/YZxBTfiLNTiVR8CUkNRFe +EMbsh2aJgWi6zCudR3Mfvc2RpHJqnKIbGKBv7FD0fUDCqDDPvXPIEysQEx6Lmqg6 +lHPTGGkKSv/BAQP/eX+1SH977ugpbzZMlWGG2Pmic4ruri+W7mjNPU0oQvlFKzIb +RlUWaqZLKfm7lVa/Rh3sHZMdwGWyH6FDrlaeoLGPaxK3YG14C8qKXO0elg6DpkiV +jTujIcSuWMYAsoS0I6SWhjW42J7YrDRJmGOVxcttSEfi8i4YHtAxq9107PncjLgc +jmgjutDzUNzPZY9zOjLHfP7KgiJPvo5iR2blzYfi6NUPGJ/lBHJLRjwQ8kTCZFZx +TnXonMkmdMV9WdEKWw9t/p51HBjGGjp82A0EzM23RWV6sY+4roRIPrN6TagD4uJ+ +ARZZaBhDM7DS3LAaQzXupdqpRlyuhoFBAUp0JuyfBr/CBTdkdXgpaP3F9ev+R/nk +hbDhezGdpn9yo7nELC7MmVcOIQxFAZRl62UJxmMiCzNJkkg8/M3OsD6Onov4/knF +NXJHAgMBAAGjgY4wgYswDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUqvyREBuH +kV8Wub9PS5FeAByxMoAwDgYDVR0PAQH/BAQDAgEGMEkGA1UdHwRCMEAwPqA8oDqG +OGh0dHA6Ly9jcmwuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3RfZXZfcm9vdF9jYV8y +XzIwMjMuY3JsMA0GCSqGSIb3DQEBDQUAA4ICAQCTy6UfmRHsmg1fLBWTxj++EI14 +QvBukEdHjqOSMo1wj/Zbjb6JzkcBahsgIIlbyIIQbODnmaprxiqgYzWRaoUlrRc4 +pZt+UPJ26oUFKidBK7GB0aL2QHWpDsvxVUjY7NHss+jOFKE17MJeNRqrphYBBo7q +3C+jisosketSjl8MmxfPy3MHGcRqwnNU73xDUmPBEcrCRbH0O1P1aa4846XerOhU +t7KR/aypH/KH5BfGSah82ApB9PI+53c0BFLd6IHyTS9URZ0V4U/M5d40VxDJI3IX +cI1QcB9WbMy5/zpaT2N6w25lBx2Eof+pDGOJbbJAiDnXH3dotfyc1dZnaVuodNv8 +ifYbMvekJKZ2t0dT741Jj6m2g1qllpBFYfXeA08mD6iL8AOWsKwV0HFaanuU5nCT +2vFp4LJiTZ6P/4mdm13NRemUAiKN4DV/6PEEeXFsVIP4M7kFMhtYVRFP0OUnR3Hs +7dpn1mKmS00PaaLJvOwiS5THaJQXfuKOKD62xur1NGyfN4gHONuGcfrNlUhDbqNP +gofXNJhuS5N5YHVpD/Aa1VP6IQzCP+k/HxiMkl14p3ZnGbuy6n/pcAlWVqOwDAst +Nl7F6cTVg8uGF5csbBNvh1qvSaYd2804BC5f4ko1Di1L+KIkBI3Y4WNeApI02phh +XBxvWHZks/wCuPWdCg== +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG +# Subject: CN=SwissSign RSA TLS Root CA 2022 - 1 O=SwissSign AG +# Label: "SwissSign RSA TLS Root CA 2022 - 1" +# Serial: 388078645722908516278762308316089881486363258315 +# MD5 Fingerprint: 16:2e:e4:19:76:81:85:ba:8e:91:58:f1:15:ef:72:39 +# SHA1 Fingerprint: 81:34:0a:be:4c:cd:ce:cc:e7:7d:cc:8a:d4:57:e2:45:a0:77:5d:ce +# SHA256 Fingerprint: 19:31:44:f4:31:e0:fd:db:74:07:17:d4:de:92:6a:57:11:33:88:4b:43:60:d3:0e:27:29:13:cb:e6:60:ce:41 +-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UE +AxMiU3dpc3NTaWduIFJTQSBUTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgx +MTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxT +d2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0EgVExTIFJvb3QgQ0Eg +MjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmjiC8NX +vDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7 +LCTLf5ImgKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX +5XH8irCRIFucdFJtrhUnWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyE +EPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlfGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt +/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36qOTw7D59Ke4LKa2/KIj4x +0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLOEGrOyvi5 +KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM +0ZPlEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shd +OxtYk8EXlFXIC+OCeYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrta +clXvyFu1cvh43zcgTFeRc5JzrBh3Q4IgaezprClG5QtO+DdziZaKHG29777YtvTK +wP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQABo2MwYTAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow4UD2p8P98Q+4 +DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL +BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO3 +10aewCoSPY6WlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgz +Hqp41eZUBDqyggmNzhYzWUUo8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQ +iJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zpy1FVCypM9fJkT6lc/2cyjlUtMoIc +gC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3CjlvrzG4ngRhZi0Rjn9UM +ZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6MOuhF +LhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJp +zv1/THfQwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/Td +Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 +rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO +gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ +-----END CERTIFICATE----- + +# Issuer: CN=OISTE Server Root ECC G1 O=OISTE Foundation +# Subject: CN=OISTE Server Root ECC G1 O=OISTE Foundation +# Label: "OISTE Server Root ECC G1" +# Serial: 47819833811561661340092227008453318557 +# MD5 Fingerprint: 42:a7:d2:35:ae:02:92:db:19:76:08:de:2f:05:b4:d4 +# SHA1 Fingerprint: 3b:f6:8b:09:ae:2a:92:7b:ba:e3:8d:3f:11:95:d9:e6:44:0c:45:e2 +# SHA256 Fingerprint: ee:c9:97:c0:c3:0f:21:6f:7e:3b:8b:30:7d:2b:ae:42:41:2d:75:3f:c8:21:9d:af:d1:52:0b:25:72:85:0f:49 +-----BEGIN CERTIFICATE----- +MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQsw +CQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwY +T0lTVEUgU2VydmVyIFJvb3QgRUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUy +NDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRp +b24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBHMTB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOujvqQy +cvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N +2xml4z+cKrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3 +TYhlz/w9itWj8UnATgwQb0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9C +tJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCpKjAd0MKfkFFR +QD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxgZzFDJe0CMQCSia7pXGKD +YmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE Server Root RSA G1 O=OISTE Foundation +# Subject: CN=OISTE Server Root RSA G1 O=OISTE Foundation +# Label: "OISTE Server Root RSA G1" +# Serial: 113845518112613905024960613408179309848 +# MD5 Fingerprint: 23:a7:9e:d4:70:b8:b9:14:57:41:8a:7e:44:59:e2:68 +# SHA1 Fingerprint: f7:00:34:25:94:88:68:31:e4:34:87:3f:70:fe:86:b3:86:9f:f0:6e +# SHA256 Fingerprint: 9a:e3:62:32:a5:18:9f:fd:db:35:3d:fd:26:52:0c:01:53:95:d2:27:77:da:c5:9d:b5:7b:98:c0:89:a6:51:e6 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBL +MQswCQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UE +AwwYT0lTVEUgU2VydmVyIFJvb3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4 +MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5k +YXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJTQSBHMTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxVYOPM +vLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7b +rEi56rAUjtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzk +ik/HEzxux9UTl7Ko2yRpg1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4z +O8vbUZeUapU8zhhabkvG/AePLhq5SvdkNCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8R +tOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY+m0o/DjH40ytas7ZTpOS +jswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+lKXHiHUh +sd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+Ho +mnqT8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu ++zrkL8Fl47l6QGzwBrd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYR +i3drVByjtdgQ8K4p92cIiBdcuJd5z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnT +kCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU +8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC77EUOSh+1sbM2 +zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33 +I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG +5D1rd9QhEOP28yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8 +qyiWXmFcuCIzGEgWUOrKL+mlSdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dP +AGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l8PjaV8GUgeV6Vg27Rn9vkf195hfk +gSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+FKrDgHGdPY3ofRRs +YWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNqqYY1 +9tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome +/msVuduCmsuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3 +J8tRd/iWkx7P8nd9H0aTolkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2 +wq1yVAb+axj5d9spLFKebXd7Yv0PTY6YMjAwcRLWJTXjn/hvnLXrahut6hDTlhZy +BiElxky8j3C7DOReIoMt0r7+hVu05L0= +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno TLS Root CA 2023 O=Microsec Ltd. +# Subject: CN=e-Szigno TLS Root CA 2023 O=Microsec Ltd. +# Label: "e-Szigno TLS Root CA 2023" +# Serial: 71934828665710877219916191754 +# MD5 Fingerprint: 6a:e9:99:74:a5:da:5e:f1:d9:2e:f2:c8:d1:86:8b:71 +# SHA1 Fingerprint: 6f:9a:d5:d5:df:e8:2c:eb:be:37:07:ee:4f:4f:52:58:29:41:d1:fe +# SHA256 Fingerprint: b4:91:41:50:2d:00:66:3d:74:0f:2e:7e:c3:40:c5:28:00:96:26:66:12:1a:36:d0:9c:f7:dd:2b:90:38:4f:b4 +-----BEGIN CERTIFICATE----- +MIICzzCCAjGgAwIBAgINAOhvGHvWOWuYSkmYCjAKBggqhkjOPQQDBDB1MQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xFzAVBgNVBGEMDlZBVEhVLTIzNTg0NDk3MSIwIAYDVQQDDBllLVN6aWdubyBU +TFMgUm9vdCBDQSAyMDIzMB4XDTIzMDcxNzE0MDAwMFoXDTM4MDcxNzE0MDAwMFow +dTELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRYwFAYDVQQKDA1NaWNy +b3NlYyBMdGQuMRcwFQYDVQRhDA5WQVRIVS0yMzU4NDQ5NzEiMCAGA1UEAwwZZS1T +emlnbm8gVExTIFJvb3QgQ0EgMjAyMzCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAE +AGgP36J8PKp0iGEKjcJMpQEiFNT3YHdCnAo4YKGMZz6zY+n6kbCLS+Y53wLCMAFS +AL/fjO1ZrTJlqwlZULUZwmgcAOAFX9pQJhzDrAQixTpN7+lXWDajwRlTEArRzT/v +SzUaQ49CE0y5LBqcvjC2xN7cS53kpDzLLtmt3999Cd8ukv+ho2MwYTAPBgNVHRMB +Af8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUWYQCYlpGePVd3I8K +ECgj3NXW+0UwHwYDVR0jBBgwFoAUWYQCYlpGePVd3I8KECgj3NXW+0UwCgYIKoZI +zj0EAwQDgYsAMIGHAkIBLdqu9S54tma4n7Zwf2Z0z+yOfP7AAXmazlIC58PRDHpt +y7Ve7hekm9sEdu4pKeiv+62sUvTXK9Z3hBC9xdIoaDQCQTV2WnXzkoYI9bIeCvZl +C9p2x1L/Cx6AcCIwwzPbGO2E14vs7dOoY4G1VnxHx1YwlGhza9IuqbnZLBwpvQy6 +uWWL +-----END CERTIFICATE----- + +# Issuer: CN=SECOM TLS RSA Root CA 2024 O=SECOM Trust Systems Co., Ltd. +# Subject: CN=SECOM TLS RSA Root CA 2024 O=SECOM Trust Systems Co., Ltd. +# Label: "SECOM TLS RSA Root CA 2024" +# Serial: 17188327524208271538 +# MD5 Fingerprint: d0:a4:db:32:eb:44:98:d2:62:0b:3e:bc:4d:7c:5c:e9 +# SHA1 Fingerprint: fb:97:96:7c:ef:8d:98:63:06:c0:3b:b6:11:f8:e0:13:97:a2:98:d3 +# SHA256 Fingerprint: 14:35:f2:25:c5:d2:52:d7:a2:19:48:cc:3c:e6:2a:ec:fa:88:00:1e:3d:d7:2d:1c:c3:55:51:00:eb:37:2f:93 +-----BEGIN CERTIFICATE----- +MIIFmjCCA4KgAwIBAgIJAO6JNNDLgOCyMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNV +BAYTAkpQMSYwJAYDVQQKEx1TRUNPTSBUcnVzdCBTeXN0ZW1zIENvLiwgTHRkLjEj +MCEGA1UEAxMaU0VDT00gVExTIFJTQSBSb290IENBIDIwMjQwHhcNMjQwMTMxMDUx +MTU1WhcNNDkwMTE0MDUxMTU1WjBaMQswCQYDVQQGEwJKUDEmMCQGA1UEChMdU0VD +T00gVHJ1c3QgU3lzdGVtcyBDby4sIEx0ZC4xIzAhBgNVBAMTGlNFQ09NIFRMUyBS +U0EgUm9vdCBDQSAyMDI0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA +4TjizUwzxbInq8Tx11gaFYNk5fO+34y7TyM4neh0UgL5JIZbJNLTz2x//L/B71+5 +m6X6nGIr7d4lFJBGtjO677hXOz93zkcWaUTm3VbOAjBlt4YWxlcccBHXuZ7o3Q+4 +R+ormrBdHeJ1CTUEG8ttQbKIl3G7OZYbnH8/pP8cjPub/0kDVNuMzp7xsVRROOis +Qt53fMoJLlYgoebbuMphOqMCtjkJ7R6efEMfLp8UAVi9ZaLRn76ET/CJkk925ndu +uufC4BatS4mnXFmxN0vUXb0ij9B8O/D8gixQEsVSD4GK8FWRPh3bVd/6bzdkHGJj +y21XI0yejVomZUbRrOfNuz0boPGV1pt18fFC39IHQEth3OFqb5NDO3L+A9bNqTgA +yUgRmIn4ucgDc/Ri/Km3V51ueZjy1/yk0qwJVadAVVrCt56iNeXOyEvzJADGgDQ8 +E1Pdaqct8Cynz/47ReQM62vFYO08wcQkrjmX/tesiko1V1yyaf6EfPzUFzmaGy9x +vkCwdbm15EdTolOjE0H2Vb5/APDOyCFEokiYGmXTLdAUl0wKZ4IyjkHGzy0jhpaX +EXE/GJcEvI6VzEchjaBL03EJ0h9pG4OqeIOycKvAo3A+TbetyfsrgYyHzU0a7/qU +jGat1AAq1nVljMpKqpinPTsf/d9H39FTUeJL7TpzzjUCAwEAAaNjMGEwHQYDVR0O +BBYEFCzrchKOWHdkNRVWNQFXB6l9DTbmMB8GA1UdIwQYMBaAFCzrchKOWHdkNRVW +NQFXB6l9DTbmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG +SIb3DQEBDAUAA4ICAQAVwsvluSafaez5tFPR/hRTBzRxEyMMQF3XJXCVi3yegZyK +oec7hmE6jx2ZM8KgM1kn2yJRwFXHX8zUW9nBLEDWc4wuE8LrlZqhGZM9pJQXGmGz +ResDJV6JgRBna+j4sA1M7yIdlvL0sAfFXFCTRaWTD4E1V99RLrFzWfTcC+e180hD +uNMpqOEo46+lMeW/Wvh7ifOQs+kiK0O2gHxQDNxslSavnCs4V7l8HRDJ2La10o70 +Bo7VLzf1W8MBvv0VTnxB+NjT5qTAbhGFh9Gvp4BaJpmdUf0C5CEP6dbQlfgxWfzY +r69yVT6dPQB+GFEaY03IMY+AcBCs+om1fNxrQXt9zoofMBNFbLhvpNH/JsXWdGUz +fNbO12uswTa5wah8LB18FTQN2/zPHYmvBEoLuyUgZ09VNLJo5YA0kXItVYkLjMe2 +SixzK4scUHv81IK99I91DWx7FwMVKw2xgFp+ZLYB2dnpQQrqwlW64glHUcK2N9BD +snjLSxeZ+UPECh9RxH4WAcKiZW+cqaKMmhP2WBfR4IcR7NOL32ml11ds87hhV1CZ +WWFCJAcCidYZz6CZa8exzHojP9SB5RH0/v1KdHAisqhSjtJl/UIAHIQ48elOn8wr +TdFap4Yb5aHglmMeNx+fAIhDluWVfxTO7H4dTPU+SFVRMLAh+wwKZfqb94nMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=SECOM TLS ECC Root CA 2024 O=SECOM Trust Systems Co., Ltd. +# Subject: CN=SECOM TLS ECC Root CA 2024 O=SECOM Trust Systems Co., Ltd. +# Label: "SECOM TLS ECC Root CA 2024" +# Serial: 9329818985461676612 +# MD5 Fingerprint: 99:d3:9d:e4:d2:b1:2d:f0:2a:04:67:85:f3:df:46:d6 +# SHA1 Fingerprint: 7a:1f:22:2d:72:b2:c3:19:87:44:db:61:69:e8:a6:4b:d7:0d:44:0e +# SHA256 Fingerprint: 6a:b2:ab:75:f5:1c:b4:f4:f0:15:62:03:fb:f6:f6:46:23:2f:51:4b:e0:59:f6:28:33:30:8b:82:b4:d7:2d:b1 +-----BEGIN CERTIFICATE----- +MIICTDCCAdGgAwIBAgIJAIF6LO+PI3pEMAoGCCqGSM49BAMDMFoxCzAJBgNVBAYT +AkpQMSYwJAYDVQQKEx1TRUNPTSBUcnVzdCBTeXN0ZW1zIENvLiwgTHRkLjEjMCEG +A1UEAxMaU0VDT00gVExTIEVDQyBSb290IENBIDIwMjQwHhcNMjQwMTMxMDU1MjM0 +WhcNNDkwMTE0MDU1MjM0WjBaMQswCQYDVQQGEwJKUDEmMCQGA1UEChMdU0VDT00g +VHJ1c3QgU3lzdGVtcyBDby4sIEx0ZC4xIzAhBgNVBAMTGlNFQ09NIFRMUyBFQ0Mg +Um9vdCBDQSAyMDI0MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE7NzFMtu9dzQXSNC1 +2fabk0+GlC5finB3R7XaZonRUd20aFiWObtuNBCLUZSfk6QXAE55BjEXsXQ/NG8y +UqicXjsu9ksDK3JZBgCwLOVh6+nwJXTvso/dEj/GUYH5mBdoo2MwYTAdBgNVHQ4E +FgQUO3YReyl04k4GTFaCQNAhL3qzydUwHwYDVR0jBBgwFoAUO3YReyl04k4GTFaC +QNAhL3qzydUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZI +zj0EAwMDaQAwZgIxAN3ib8fi1pMYtAPjMilB5e5/H+t5CL0xPL+cZ5oTTZuSCjpA +n1v7F/VAr8bFxQXAowIxAKsBVO1ACFp7skwzPvdv1EUY5a897WGLT4lb+bjxFAWy +l8wDcZJdwGZ/pAHxt1AJ1g== +-----END CERTIFICATE----- + +# Issuer: CN=Telia EC TLS Root CA v3 O=Telia Company AB +# Subject: CN=Telia EC TLS Root CA v3 O=Telia Company AB +# Label: "Telia EC TLS Root CA v3" +# Serial: 8028200332079443110287896228123317 +# MD5 Fingerprint: b6:fa:6a:5c:42:fb:c5:67:72:c0:e0:2f:72:fb:5a:44 +# SHA1 Fingerprint: b4:d6:07:c2:a5:95:bc:5b:f4:67:4d:c9:dc:6f:6f:0a:00:7a:a5:35 +# SHA256 Fingerprint: 09:8e:08:a9:1d:bb:f7:74:78:b9:6c:ce:b8:9b:14:13:a5:da:37:b7:c8:62:60:6a:95:5d:eb:07:17:9f:43:26 +-----BEGIN CERTIFICATE----- +MIICMjCCAbegAwIBAgIPAYvSIlRjTQSLbOVHH9K1MAoGCCqGSM49BAMDMEoxCzAJ +BgNVBAYTAlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFCMSAwHgYDVQQDDBdU +ZWxpYSBFQyBUTFMgUm9vdCBDQSB2MzAeFw0yMzExMTUwODU1MjZaFw00ODA1MjMx +MTAwMDBaMEoxCzAJBgNVBAYTAlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFC +MSAwHgYDVQQDDBdUZWxpYSBFQyBUTFMgUm9vdCBDQSB2MzB2MBAGByqGSM49AgEG +BSuBBAAiA2IABMHIlhVDLbmFKUpW0iK4dpryT6emYOeS31JPwWnWPmkWRrAkTbPX +40sQfHI9mpR7Rbktu3ngg6W+BBSXSechtMCnBmWXj/EaVlmV5cY1jD2HoTfhBQ3A +acpCNMLJK4NpZaNjMGEwHwYDVR0jBBgwFoAU1GToQ4g6cy/QGnGCNgtehd7H3kMw +HQYDVR0OBBYEFNRk6EOIOnMv0BpxgjYLXoXex95DMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2kAMGYCMQCXAUdS/9bbJ8A1JYaG +f/bWt/s7Ta0ot5Ulno8OjSNYRWQIlS4tVWldvTAVA7heOFgCMQCvKr8+Z2Rn+OBr +5UHzlgBObpad1LuwNTRcdNgUJxIWadcki+UBLEi1/AURKV5md2M= +-----END CERTIFICATE----- + +# Issuer: CN=Telia RSA TLS Root CA v3 O=Telia Company AB +# Subject: CN=Telia RSA TLS Root CA v3 O=Telia Company AB +# Label: "Telia RSA TLS Root CA v3" +# Serial: 8028214673410753541795188766939845 +# MD5 Fingerprint: f4:8b:9c:f3:f8:63:cf:dc:25:8f:b4:bb:a2:e9:9d:e2 +# SHA1 Fingerprint: b5:2e:88:4e:40:c1:11:fb:50:c7:e2:4f:ac:18:2b:bd:68:15:d2:34 +# SHA256 Fingerprint: d1:3d:b1:29:4c:45:eb:c6:fc:86:c6:bb:f6:9f:a2:9b:df:e6:92:df:f7:c7:13:c2:43:c7:a9:56:c6:a2:28:4c +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgIPAYvSUKtCVSxHWr2h3BrFMA0GCSqGSIb3DQEBDAUAMEsx +CzAJBgNVBAYTAlNFMRkwFwYDVQQKDBBUZWxpYSBDb21wYW55IEFCMSEwHwYDVQQD +DBhUZWxpYSBSU0EgVExTIFJvb3QgQ0EgdjMwHhcNMjMxMTE1MDk0NzQyWhcNNDgw +NTIzMTEwMDAwWjBLMQswCQYDVQQGEwJTRTEZMBcGA1UECgwQVGVsaWEgQ29tcGFu +eSBBQjEhMB8GA1UEAwwYVGVsaWEgUlNBIFRMUyBSb290IENBIHYzMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsV89KG19hCf4S1Fvk8D3TyDERhmcvx8F +7Kmb4WATx3ije1id3KHxRE0TKmcNCbAQ57bvHFEYa4hR2l20VjVadExqOW+2ld99 +MbEiO+jRVOz+BbxLxJnmGwCqI+BfuTjjVReDxsxjQvjgBsClaO/sm5i70nlZcWGR +tIkvWDK3NNkT5RtwXc/O8NTFVpbUqT6cRjIj3olAblR+lRf4Ffy5o+Q9fabjYn9Z +9S4itruElcEFf9Ljk7fwdTycT/rvJW9w/B3G2a3r0f/zXNOVruIBcqE6pkSospAC +U2bG42fYKrbM/GWnp7u+p9Frz4jaNwpb4YHuEeS8BratNcP8X62jXIvvKHxlsMDJ +Cnb4U8JzFOLsU6mohVY58BdZrvi0Gk9UOuqmgoG6dskHoksjZTlK61D/InzmEoA1 +yAYJFDVysjRxDUOu9cAwANbqmq77WIFL6BpnZgVqPtMfG6wN8BrTKdapvilVsYR5 +9BFgIsAVBMxrGh+W+QcvmJafUpASvlArKvVG2FI4i6PiLjSBT0+6F6EQLrYqefOQ +F/fBNEXb+njUQ0SUVrAqtH4Y+OjCI/a4/JJQppxeemZcQ0SUShgiI5AM5xHO5iya +UrTjYH4zxUz9j+1FEbDH/xpstr1gXBykspup+hRTaJcbA+UbpJqtWZndAPddJmt6 +YJQ+dU3pDu8CAwEAAaNjMGEwHwYDVR0jBBgwFoAUsMep0t2yKFZzBJSMFFxIbzdS +kqgwHQYDVR0OBBYEFLDHqdLdsihWcwSUjBRcSG83UpKoMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQBdYzFsNGDRk7bR +/AgRKq+5637YuOW+w6uhpoS0VnKMUpyHCwku86hEvqivakPtfmlm4bFwt++sb/8O +XsWBqtfbXMaBNDTZl8XRMJuLWOW2JrbKkRzgG0eBUcvsadG1rrhbmZqYvFXaAZO7 +o4TdOZzxhBB5GOAWWXB3IeraNP4J63zyo9n8Gqw3sJBG44em5hoYjBffP+npibys +lnslRi4L6xHsCYj/Pab+OlqbMCB6v+sTCLeEIukRVzoR9aQ45pEK7Z1QBnSsbAKQ +tss0JKD9d/mX143H1xePjPhTXlv5JCkhrcj+SShz0P9+EHoWe6m9lyUEOIVn0rp+ +yVJWNbmyDv3VkwFxHC1ApSQsgSimjGQ4wtr6cSmordYxkV+Ro8lOIIhRksXPyDk2 +7gW6IjUXCkZKpxFjkL3jiBSc8SkxnwCWtXg8xwNwdFVNBGLCCuJnsneYXjJNqzRq +UcoGwzsvF3Qi/ZnHUNvISdevlgIAXL4Wvrxaqvoa01wB+GCfs57RTGE4TvAGhKNK +us8K3hRT1BSpigzMIRzSxtAOrqPN6j//QSmW9f8Jcncri4j2ihSpVrFU0NdNkMhZ +eAKidTFPsxCVFuW4Aniz7jqiw5sWtjbQrlW035izIEU4sYwQoC1Nx0Svy+mMTRai +50LqFQ+A1/Hq6xHHDNx7CI83d23Erw== +-----END CERTIFICATE----- diff --git a/source/target-vendors/cp312/certifi/core.py b/source/target-vendors/cp312/certifi/core.py new file mode 100644 index 0000000..1c9661c --- /dev/null +++ b/source/target-vendors/cp312/certifi/core.py @@ -0,0 +1,83 @@ +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import sys +import atexit + +def exit_cacert_ctx() -> None: + _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr] + + +if sys.version_info >= (3, 11): + + from importlib.resources import as_file, files + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem")) + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") + +else: + + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where() -> str: + # This is slightly terrible, but we want to delay extracting the + # file in cases where we're inside of a zipimport situation until + # someone actually calls where(), but we don't want to re-extract + # the file on every call of where(), so we'll do it once then store + # it in a global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you + # to manage the cleanup of this file, so it doesn't actually + # return a path, it returns a context manager that will give + # you the path when you enter it and will do any cleanup when + # you leave it. In the common case of not needing a temporary + # file, it will just return the file system location and the + # __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + atexit.register(exit_cacert_ctx) + + return _CACERT_PATH + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/source/target-vendors/cp312/certifi/py.typed b/source/target-vendors/cp312/certifi/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/certifi/tests/__init__.py b/source/target-vendors/cp312/certifi/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/certifi/tests/test_certify.py b/source/target-vendors/cp312/certifi/tests/test_certify.py new file mode 100644 index 0000000..54670ea --- /dev/null +++ b/source/target-vendors/cp312/certifi/tests/test_certify.py @@ -0,0 +1,18 @@ +import os +import unittest + +import certifi + + +class TestCertifi(unittest.TestCase): + def test_cabundle_exists(self) -> None: + assert os.path.exists(certifi.where()) + + def test_read_contents(self) -> None: + content = certifi.contents() + assert "-----BEGIN CERTIFICATE-----" in content + + def test_py_typed_exists(self) -> None: + assert os.path.exists( + os.path.join(os.path.dirname(certifi.__file__), 'py.typed') + ) diff --git a/source/target-vendors/cp312/cffi-2.1.1.dist-info/METADATA b/source/target-vendors/cp312/cffi-2.1.1.dist-info/METADATA new file mode 100644 index 0000000..7c07654 --- /dev/null +++ b/source/target-vendors/cp312/cffi-2.1.1.dist-info/METADATA @@ -0,0 +1,67 @@ +Metadata-Version: 2.4 +Name: cffi +Version: 2.1.1 +Summary: Foreign Function Interface for Python calling C code. +Author: Armin Rigo, Maciej Fijalkowski +Maintainer: Matt Davis, Matt Clay +License-Expression: MIT-0 +Project-URL: Documentation, https://cffi.readthedocs.io/ +Project-URL: Changelog, https://cffi.readthedocs.io/en/latest/whatsnew.html +Project-URL: Download, https://github.com/python-cffi/cffi/releases +Project-URL: Contact, https://groups.google.com/forum/#!forum/python-cffi +Project-URL: Source Code, https://github.com/python-cffi/cffi +Project-URL: Issue Tracker, https://github.com/python-cffi/cffi/issues +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta +Classifier: Programming Language :: Python :: Implementation :: CPython +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-File: LICENSE +Requires-Dist: pycparser; implementation_name != "PyPy" +Dynamic: license-file + +[![GitHub Actions Status](https://github.com/python-cffi/cffi/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/python-cffi/cffi/actions/workflows/ci.yaml?query=branch%3Amain++) +[![PyPI version](https://img.shields.io/pypi/v/cffi.svg)](https://pypi.org/project/cffi) +[![Read the Docs](https://img.shields.io/badge/docs-latest-blue.svg)][Documentation] + + +CFFI +==== + +Foreign Function Interface for Python calling C code. + +Please see the [Documentation] or uncompiled in the `doc/` subdirectory. + +Download +-------- + +[Download page](https://github.com/python-cffi/cffi/releases) + +Source Code +----------- + +Source code is publicly available on +[GitHub](https://github.com/python-cffi/cffi). + +Contact +------- + +[Mailing list](https://groups.google.com/forum/#!forum/python-cffi) + +Testing/development tips +------------------------ + +After `git clone` or `wget && tar`, we will get a directory called `cffi` or `cffi-x.x.x`. We call it `repo-directory`. To run tests under CPython, run the following in the `repo-directory`: + + pip install pytest + pip install -e . # editable install of CFFI for local development + pytest src/c/ testing/ + +[Documentation]: http://cffi.readthedocs.org/ diff --git a/source/target-vendors/cp312/cffi-2.1.1.dist-info/RECORD b/source/target-vendors/cp312/cffi-2.1.1.dist-info/RECORD new file mode 100644 index 0000000..9476fc0 --- /dev/null +++ b/source/target-vendors/cp312/cffi-2.1.1.dist-info/RECORD @@ -0,0 +1,31 @@ +_cffi_backend.cpython-312-x86_64-linux-gnu.so,sha256=m8HQgHIlWl7C2xD8dd8d2ecwl6dc2RUM_odevWcS8Xw,348856 +cffi/__init__.py,sha256=xHstsoxfGX4kLU3Ur5W367DaZXY_x2lyyv0G-T6ULNo,511 +cffi/_cffi_errors.h,sha256=Wzg-0Bu1_K2GEK0pSU5b6Q2GAAudcaF87HNG8LoFmWw,3583 +cffi/_cffi_gen_src.py,sha256=yUR53pFSbsa3ssF7_VOqXTaKeL5AJTHM_dyZ9IGY9sw,7044 +cffi/_cffi_include.h,sha256=zY6KFoo_bpa02PagQs1hzeW9O56snioloyxqvRKAot8,15234 +cffi/_embedding.h,sha256=PhAdAMcKClATVZ-lBcZeDEc12F6FqVdaHtaJ2Pkg6E8,17554 +cffi/_imp_emulation.py,sha256=RxREG8zAbI2RPGBww90u_5fi8sWdahpdipOoPzkp7C0,2960 +cffi/_shimmed_dist_utils.py,sha256=Bjj2wm8yZbvFvWEx5AEfmqaqZyZFhYfoyLLQHkXZuao,2230 +cffi/api.py,sha256=cWX1ZlscmOyTkvthiBpUWLcSRBtqlpn-moBu4esBmzI,42013 +cffi/backend_ctypes.py,sha256=T7CSc14P5vyloi5hyox68qhBWX079owHXaGDbY_U7bo,42283 +cffi/cffi_opcode.py,sha256=5-1cU6ppHGzsstF_eoglD_8tCDk76_Zhkzj3fW4Sic0,5723 +cffi/commontypes.py,sha256=7N6zPtCFlvxXMWhHV08psUjdYIK2XgsN3yo5dgua_v4,2805 +cffi/cparser.py,sha256=WY-ox4UGSuVSYTtgm02FmGgbmcuaaBK3moFlkdFSmsU,44754 +cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877 +cffi/ffiplatform.py,sha256=avxFjdikYGJoEtmJO7ewVmwG_VEVl6EZ_WaNhZYCqv4,3584 +cffi/gen_src.py,sha256=TU_ZVDwoLnHPlal8_mPmpxqyWJ7U752jTc3UsTmE1QI,132 +cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747 +cffi/model.py,sha256=cA-bEAibcHUbtbqfgMq0CLQjFPAjV0JSRzMyKViNgF4,21752 +cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976 +cffi/pkgconfig.py,sha256=uyt117TQeea3djagM1W5go8RpnySGTgoCzN8QHyZdlc,4365 +cffi/recompiler.py,sha256=TJVF07mFzYGTV6szp2zPrJd2dJKHN-eB_SuiJiGl9Kw,65140 +cffi/setuptools_ext.py,sha256=pZrnTqVCkGMqu8NxIxkdbItl65gehMP1LoraUdT7-4U,9566 +cffi/vengine_cpy.py,sha256=rRouYQ6BllAIXNjZGTPUW54rB952qi3gcm16SWXWKLc,43030 +cffi/vengine_gen.py,sha256=Z_KqaF6r54n5i4hjQThZdb-1DBTEimnU4y4E_KxSCDg,26931 +cffi/verifier.py,sha256=xIzV8iDMhZ1-qhX3RRX4DWo2k07WpcJxdhhAFXAjrmY,11154 +cffi-2.1.1.dist-info/METADATA,sha256=VYuvuQk6jnkBddns_5aIOCmB10SHfa2G_Wdw2w9NyRg,2527 +cffi-2.1.1.dist-info/WHEEL,sha256=UErIDMlRkMma6hd1UFY9eTm4_KaxQxwBwNQ150r7vQ4,151 +cffi-2.1.1.dist-info/entry_points.txt,sha256=prYQgBH44nBQ_lJpu6iMgFG0FGl4gNOwtvvjoDoLABw,132 +cffi-2.1.1.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 +cffi-2.1.1.dist-info/RECORD,, +cffi-2.1.1.dist-info/licenses/LICENSE,sha256=W6JN3FcGf5JJrdZEw6_EGl1tw34jQz73Wdld83Cwr2M,1123 diff --git a/source/target-vendors/cp312/cffi-2.1.1.dist-info/WHEEL b/source/target-vendors/cp312/cffi-2.1.1.dist-info/WHEEL new file mode 100644 index 0000000..50a7ad2 --- /dev/null +++ b/source/target-vendors/cp312/cffi-2.1.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (83.0.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 + diff --git a/source/target-vendors/cp312/cffi-2.1.1.dist-info/entry_points.txt b/source/target-vendors/cp312/cffi-2.1.1.dist-info/entry_points.txt new file mode 100644 index 0000000..46bb21b --- /dev/null +++ b/source/target-vendors/cp312/cffi-2.1.1.dist-info/entry_points.txt @@ -0,0 +1,5 @@ +[console_scripts] +cffi-gen-src = cffi._cffi_gen_src:run + +[distutils.setup_keywords] +cffi_modules = cffi.setuptools_ext:cffi_modules diff --git a/source/target-vendors/cp312/cffi-2.1.1.dist-info/licenses/LICENSE b/source/target-vendors/cp312/cffi-2.1.1.dist-info/licenses/LICENSE new file mode 100644 index 0000000..0a1dbfb --- /dev/null +++ b/source/target-vendors/cp312/cffi-2.1.1.dist-info/licenses/LICENSE @@ -0,0 +1,23 @@ + +Except when otherwise stated (look for LICENSE files in directories or +information at the beginning of each file) all software and +documentation is licensed as follows: + + MIT No Attribution + + 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. + + 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/source/target-vendors/cp312/cffi-2.1.1.dist-info/top_level.txt b/source/target-vendors/cp312/cffi-2.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..f645779 --- /dev/null +++ b/source/target-vendors/cp312/cffi-2.1.1.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_cffi_backend +cffi diff --git a/source/target-vendors/cp312/cffi/__init__.py b/source/target-vendors/cp312/cffi/__init__.py new file mode 100644 index 0000000..93dcdb3 --- /dev/null +++ b/source/target-vendors/cp312/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__ = "2.1.1" +__version_info__ = (2, 1, 1) + +# 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/source/target-vendors/cp312/cffi/_cffi_errors.h b/source/target-vendors/cp312/cffi/_cffi_errors.h new file mode 100644 index 0000000..0931379 --- /dev/null +++ b/source/target-vendors/cp312/cffi/_cffi_errors.h @@ -0,0 +1,135 @@ +#ifndef CFFI_MESSAGEBOX +# ifdef _MSC_VER +# define CFFI_MESSAGEBOX 1 +# else +# define CFFI_MESSAGEBOX 0 +# endif +#endif + + +#if CFFI_MESSAGEBOX +/* Windows only: logic to take the Python-CFFI embedding logic + initialization errors and display them in a background thread + with MessageBox. The idea is that if the whole program closes + as a result of this problem, then likely it is already a console + program and you can read the stderr output in the console too. + If it is not a console program, then it will likely show its own + dialog to complain, or generally not abruptly close, and for this + case the background thread should stay alive. +*/ +static void *volatile _cffi_bootstrap_text; + +static PyObject *_cffi_start_error_capture(void) +{ + PyObject *result = NULL; + PyObject *x, *m, *bi; + + if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, + (void *)1, NULL) != NULL) + return (PyObject *)1; + + m = PyImport_AddModule("_cffi_error_capture"); + if (m == NULL) + goto error; + + result = PyModule_GetDict(m); + if (result == NULL) + goto error; + + bi = PyImport_ImportModule("builtins"); + 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" + " def flush(self):\n" + " pass\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 */ + MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, + L"Python-CFFI error", + MB_OK | MB_ICONERROR); + _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. */ + text = PyUnicode_AsWideCharString(s, NULL); + + _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/source/target-vendors/cp312/cffi/_cffi_gen_src.py b/source/target-vendors/cp312/cffi/_cffi_gen_src.py new file mode 100644 index 0000000..3d4fb7e --- /dev/null +++ b/source/target-vendors/cp312/cffi/_cffi_gen_src.py @@ -0,0 +1,216 @@ +# Integrated from the cffi-buildtool project by Rose Davidson +# (https://github.com/inklesspen/cffi-buildtool), under the following +# license: +# +# MIT License +# +# Copyright (c) 2024, Rose Davidson +# +# 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 (including the +# next paragraph) 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. +"""Implementation of the ``cffi-gen-src`` command-line tool. + +This module is private; the command line is the only supported +interface. Two subcommands: + +``exec-python`` + Execute a Python script that constructs a :class:`cffi.FFI` + (the same kind of script that the CFFI docs' "Main mode of usage" + describes) and emit the generated C source. + +``read-sources`` + Create the :class:`cffi.FFI` from a separate ``cdef`` file and C + source prelude, then emit the generated C source. +""" + +import argparse +import io +import os +import sys + +from .api import FFI + + +def _execfile(pysrc, filename, globs): + compiled = compile(source=pysrc, filename=filename, mode='exec') + exec(compiled, globs, globs) + + +def find_ffi_in_python_script(pysrc, filename, ffivar): + """Execute ``pysrc`` and return the :class:`FFI` object it defines. + + The script is executed with ``__name__`` set to ``"cffi.gen_src"``, + so a trailing ``if __name__ == "__main__": ffibuilder.compile()`` + block in the script is skipped. + + ``ffivar`` is the name bound by the script to the :class:`FFI` + object, or to a callable that returns one. + + Raises :class:`NameError` if the name is not bound by the script, + or :class:`TypeError` if the name does not resolve to an + :class:`FFI` instance. + """ + filename = os.path.abspath(filename) + globs = {'__name__': 'cffi.gen_src', '__file__': filename} + old_path = sys.path[:] + sys.path.insert(0, os.path.dirname(filename)) + try: + _execfile(pysrc, filename, globs) + if ffivar not in globs: + raise NameError( + "Expected to find the FFI object with the name %r, " + "but it was not found." % (ffivar,) + ) + ffi = globs[ffivar] + if not isinstance(ffi, FFI) and callable(ffi): + # Maybe it's a callable that returns a FFI + ffi = ffi() + if not isinstance(ffi, FFI): + raise TypeError( + "Found an object with the name %r but it was not an " + "instance of cffi.api.FFI" % (ffivar,) + ) + return ffi + finally: + sys.path[:] = old_path + + +def make_ffi_from_sources(modulename, cdef, csrc): + """Create an :class:`FFI` from ``cdef`` text and a C source prelude.""" + ffibuilder = FFI() + ffibuilder.cdef(cdef) + ffibuilder.set_source(modulename, csrc) + return ffibuilder + + +def generate_c_source(ffi): + """Return the C source that :meth:`FFI.emit_c_code` would write.""" + output = io.StringIO() + ffi.emit_c_code(output) + return output.getvalue() + + +def write_c_source(output, generated): + if output == '-': + sys.stdout.write(generated) + return + with open(output, 'w', encoding='utf-8') as f: + f.write(generated) + + +def same_input_file(file1, file2): + if file1 is file2: + return True + try: + return os.path.samefile(file1.name, file2.name) + except OSError: + return False + + +def exec_python(*, output, pyfile, ffi_var): + with pyfile: + ffi = find_ffi_in_python_script(pyfile.read(), pyfile.name, ffi_var) + generated = generate_c_source(ffi) + write_c_source(output, generated) + + +def read_sources(*, output, module_name, cdef_input, csrc_input): + with csrc_input, cdef_input: + csrc = csrc_input.read() + cdef = cdef_input.read() + ffi = make_ffi_from_sources(module_name, cdef, csrc) + generated = generate_c_source(ffi) + write_c_source(output, generated) + + +def _prog(): + # The same parser serves both documented invocations; make --help + # and usage messages show the one that was actually used. + argv0 = os.path.basename(sys.argv[0]) if sys.argv else '' + if argv0.startswith('cffi-gen-src'): + return 'cffi-gen-src' + return 'python -m cffi.gen_src' + + +parser = argparse.ArgumentParser( + prog=_prog(), + description='Generate CFFI C source for extension modules.', +) +subparsers = parser.add_subparsers(dest='mode') + +exec_python_parser = subparsers.add_parser( + 'exec-python', + help='Execute a Python script that defines an FFI object', +) +exec_python_parser.add_argument( + '--ffi-var', + default='ffibuilder', + help="Name of the FFI object in the Python script; defaults to 'ffibuilder'.", +) +exec_python_parser.add_argument( + 'pyfile', + type=argparse.FileType('r', encoding='utf-8'), + help='Path to the Python script', +) +exec_python_parser.add_argument( + 'output', + help='Output path for the C source', +) + +read_sources_parser = subparsers.add_parser( + 'read-sources', + help='Read cdef and C source prelude files that define an FFI object', +) +read_sources_parser.add_argument( + 'module_name', + help='Full name of the generated module, including packages', +) +read_sources_parser.add_argument( + 'cdef', + type=argparse.FileType('r', encoding='utf-8'), + help='File containing C definitions', +) +read_sources_parser.add_argument( + 'csrc', + type=argparse.FileType('r', encoding='utf-8'), + help='File containing C source prelude', +) +read_sources_parser.add_argument( + 'output', + help='Output path for the C source', +) + + +def run(args=None): + args = parser.parse_args(args=args) + if args.mode == 'exec-python': + exec_python(output=args.output, pyfile=args.pyfile, ffi_var=args.ffi_var) + elif args.mode == 'read-sources': + if same_input_file(args.cdef, args.csrc): + parser.error('cdef and csrc are the same file and should not be') + read_sources( + output=args.output, + module_name=args.module_name, + cdef_input=args.cdef, + csrc_input=args.csrc, + ) + else: + parser.error('a subcommand is required: exec-python or read-sources') + parser.exit(0) diff --git a/source/target-vendors/cp312/cffi/_cffi_include.h b/source/target-vendors/cp312/cffi/_cffi_include.h new file mode 100644 index 0000000..c8c6d34 --- /dev/null +++ b/source/target-vendors/cp312/cffi/_cffi_include.h @@ -0,0 +1,397 @@ +#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) +# if !defined(Py_GIL_DISABLED) +# define Py_LIMITED_API +# else +# define Py_LIMITED_API 0x030f0000 +# endif +# 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) +# if !defined(Py_GIL_DISABLED) +# define Py_LIMITED_API +# else +# define Py_LIMITED_API 0x030f0000 +# endif +# endif +# endif +#endif + +#include +#ifdef __cplusplus +extern "C" { +#endif +#include +#include +#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 +# define _cffi_float_complex_t _Fcomplex /* include for it */ +# define _cffi_double_complex_t _Dcomplex /* include for it */ +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +# define _cffi_float_complex_t float _Complex +# define _cffi_double_complex_t double _Complex +#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 + + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyLong_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) ? \ + PyLong_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyLong_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/source/target-vendors/cp312/cffi/_embedding.h b/source/target-vendors/cp312/cffi/_embedding.h new file mode 100644 index 0000000..ba6e79b --- /dev/null +++ b/source/target-vendors/cp312/cffi/_embedding.h @@ -0,0 +1,512 @@ + +/***** 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. If _cffi_start_python() fails, then this is set + to NULL; otherwise, it should never be NULL. + + 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( + 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: 2.1.1" + "\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; +} + +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. + + In Python >= 3.12, this stopped working because that particular + tp_version_tag gets modified during interpreter startup. It's + arguably a bad idea before 3.12 too, but again we can't change + that because someone might use a mixture of cffi embedded + modules, and no-one reported a bug so far. In Python >= 3.12 + we go instead for PyCapsuleType.tp_as_buffer, which is supposed + to always be NULL. We write to it temporarily a pointer to + a struct full of NULLs, which is semantically the same. + */ + +#ifdef WITH_THREAD +# if PY_VERSION_HEX < 0x030C0000 + int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; + int old_value, locked_value = -42; + assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); +# else + static struct ebp_s { PyBufferProcs buf; int mark; } empty_buffer_procs; + empty_buffer_procs.mark = -42; + PyBufferProcs *volatile *lock = (PyBufferProcs *volatile *) + &PyCapsule_Type.tp_as_buffer; + PyBufferProcs *old_value, *locked_value = &empty_buffer_procs.buf; +# endif + + while (1) { /* spin loop */ + old_value = *lock; + if (old_value == 0) { + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { +# if PY_VERSION_HEX < 0x030C0000 + assert(old_value == locked_value); +# else + /* The pointer should point to a possibly different + empty_buffer_procs from another C extension module */ + assert(((struct ebp_s *)old_value)->mark == -42); +# endif + /* 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 + + /* call Py_InitializeEx() */ + if (!Py_IsInitialized()) { + _cffi_py_initialize(); + 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 { + } + +#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/source/target-vendors/cp312/cffi/_imp_emulation.py b/source/target-vendors/cp312/cffi/_imp_emulation.py new file mode 100644 index 0000000..136abdd --- /dev/null +++ b/source/target-vendors/cp312/cffi/_imp_emulation.py @@ -0,0 +1,83 @@ + +try: + # this works on Python < 3.12 + from imp import * + +except ImportError: + # this is a limited emulation for Python >= 3.12. + # Note that this is used only for tests or for the old ffi.verify(). + # This is copied from the source code of Python 3.11. + + from _imp import (acquire_lock, release_lock, + is_builtin, is_frozen) + + from importlib._bootstrap import _load + + from importlib import machinery + import os + import sys + import tokenize + + SEARCH_ERROR = 0 + PY_SOURCE = 1 + PY_COMPILED = 2 + C_EXTENSION = 3 + PY_RESOURCE = 4 + PKG_DIRECTORY = 5 + C_BUILTIN = 6 + PY_FROZEN = 7 + PY_CODERESOURCE = 8 + IMP_HOOK = 9 + + def get_suffixes(): + extensions = [(s, 'rb', C_EXTENSION) + for s in machinery.EXTENSION_SUFFIXES] + source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] + bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES] + return extensions + source + bytecode + + def find_module(name, path=None): + if not isinstance(name, str): + raise TypeError("'name' must be a str, not {}".format(type(name))) + elif not isinstance(path, (type(None), list)): + # Backwards-compatibility + raise RuntimeError("'path' must be None or a list, " + "not {}".format(type(path))) + + if path is None: + if is_builtin(name): + return None, None, ('', '', C_BUILTIN) + elif is_frozen(name): + return None, None, ('', '', PY_FROZEN) + else: + path = sys.path + + for entry in path: + package_directory = os.path.join(entry, name) + for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]: + package_file_name = '__init__' + suffix + file_path = os.path.join(package_directory, package_file_name) + if os.path.isfile(file_path): + return None, package_directory, ('', '', PKG_DIRECTORY) + for suffix, mode, type_ in get_suffixes(): + file_name = name + suffix + file_path = os.path.join(entry, file_name) + if os.path.isfile(file_path): + break + else: + continue + break # Break out of outer loop when breaking out of inner loop. + else: + raise ImportError(name, name=name) + + encoding = None + if 'b' not in mode: + with open(file_path, 'rb') as file: + encoding = tokenize.detect_encoding(file.readline)[0] + file = open(file_path, mode, encoding=encoding) + return file, file_path, (suffix, mode, type_) + + def load_dynamic(name, path, file=None): + loader = machinery.ExtensionFileLoader(name, path) + spec = machinery.ModuleSpec(name=name, loader=loader, origin=path) + return _load(spec) diff --git a/source/target-vendors/cp312/cffi/_shimmed_dist_utils.py b/source/target-vendors/cp312/cffi/_shimmed_dist_utils.py new file mode 100644 index 0000000..c3d2312 --- /dev/null +++ b/source/target-vendors/cp312/cffi/_shimmed_dist_utils.py @@ -0,0 +1,45 @@ +""" +Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful +error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken. + +This is a compromise to avoid a hard-dep on setuptools for Python >= 3.12, since many users don't need runtime compilation support from CFFI. +""" +import sys + +try: + # import setuptools first; this is the most robust way to ensure its embedded distutils is available + # (the .pth shim should usually work, but this is even more robust) + import setuptools +except Exception as ex: + if sys.version_info >= (3, 12): + # Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal + raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex + + # silently ignore on older Pythons (support fallback to stdlib distutils where available) +else: + del setuptools + +try: + # bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils + from distutils import log, sysconfig + from distutils.ccompiler import CCompiler + from distutils.command.build_ext import build_ext + from distutils.core import Distribution, Extension + from distutils.dir_util import mkpath + from distutils.errors import DistutilsSetupError, CompileError, LinkError + from distutils.log import set_threshold, set_verbosity + + if sys.platform == 'win32': + try: + # FUTURE: msvc9compiler module was removed in setuptools 74; consider removing, as it's only used by an ancient patch in `recompiler` + from distutils.msvc9compiler import MSVCCompiler + except ImportError: + MSVCCompiler = None +except Exception as ex: + if sys.version_info >= (3, 12): + raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex + + # anything older, just let the underlying distutils import error fly + raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex + +del sys diff --git a/source/target-vendors/cp312/cffi/api.py b/source/target-vendors/cp312/cffi/api.py new file mode 100644 index 0000000..ec8ee7d --- /dev/null +++ b/source/target-vendors/cp312/cffi/api.py @@ -0,0 +1,960 @@ +import sys, types +from .lock import allocate_lock +from .error import CDefError +from . import model + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +_unspecified = object() + + + +class FFI: + 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 replace_with[0] not 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 cffi._shimmed_dist_utils 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 cffi._shimmed_dist_utils 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, + uses_ffiplatform=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, + uses_ffiplatform=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: + 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/source/target-vendors/cp312/cffi/backend_ctypes.py b/source/target-vendors/cp312/cffi/backend_ctypes.py new file mode 100644 index 0000000..12cd162 --- /dev/null +++ b/source/target-vendors/cp312/cffi/backend_ctypes.py @@ -0,0 +1,1120 @@ +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: + __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: + + 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__,)) + 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 in {'int', '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 in {'int', 'byte', '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 in {'charp', '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()._arg_to_ctypes(*value) + + if kind in {'charp', '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()._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 in {'char', '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()._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()._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: + + 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/source/target-vendors/cp312/cffi/cffi_opcode.py b/source/target-vendors/cp312/cffi/cffi_opcode.py new file mode 100644 index 0000000..c964ba1 --- /dev/null +++ b/source/target-vendors/cp312/cffi/cffi_opcode.py @@ -0,0 +1,187 @@ +from .error import VerificationError + +class CffiOp: + 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, + '_cffi_float_complex_t': PRIM_FLOATCOMPLEX, + '_cffi_double_complex_t': 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/source/target-vendors/cp312/cffi/commontypes.py b/source/target-vendors/cp312/cffi/commontypes.py new file mode 100644 index 0000000..d4dae35 --- /dev/null +++ b/source/target-vendors/cp312/cffi/commontypes.py @@ -0,0 +1,82 @@ +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 +COMMON_TYPES['float _Complex'] = '_cffi_float_complex_t' +COMMON_TYPES['double _Complex'] = '_cffi_double_complex_t' + +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/source/target-vendors/cp312/cffi/cparser.py b/source/target-vendors/cp312/cffi/cparser.py new file mode 100644 index 0000000..1896b7e --- /dev/null +++ b/source/target-vendors/cp312/cffi/cparser.py @@ -0,0 +1,1014 @@ +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 in between, 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: + + 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) + csourcelines.append('') # see test_missing_newline_bug + 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': + # skip pragma, only in pycparser 2.15 + import warnings + warnings.warn( + "#pragma in cdef() are entirely ignored. " + "They should be removed for now, otherwise your " + "code might behave differently in a future version " + "of CFFI if #pragma support gets added. Note that " + "'#pragma pack' needs to be replaced with the " + "'packed' keyword argument to cdef().") + 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) + elif 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/source/target-vendors/cp312/cffi/error.py b/source/target-vendors/cp312/cffi/error.py new file mode 100644 index 0000000..0a27247 --- /dev/null +++ b/source/target-vendors/cp312/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/source/target-vendors/cp312/cffi/ffiplatform.py b/source/target-vendors/cp312/cffi/ffiplatform.py new file mode 100644 index 0000000..adca28f --- /dev/null +++ b/source/target-vendors/cp312/cffi/ffiplatform.py @@ -0,0 +1,113 @@ +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): + from cffi._shimmed_dist_utils 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.""" + + 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 cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity + + 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 = set_threshold(0) or 0 + try: + set_verbosity(compiler_verbose) + dist.run_command('build_ext') + cmd_obj = dist.get_command_obj('build_ext') + [soname] = cmd_obj.get_outputs() + finally: + set_threshold(old_level) + except (CompileError, 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() diff --git a/source/target-vendors/cp312/cffi/gen_src.py b/source/target-vendors/cp312/cffi/gen_src.py new file mode 100644 index 0000000..8eb57b1 --- /dev/null +++ b/source/target-vendors/cp312/cffi/gen_src.py @@ -0,0 +1,5 @@ +"""Entry point so ``python -m cffi.gen_src`` works.""" + +if __name__ == '__main__': + from cffi._cffi_gen_src import run + run() diff --git a/source/target-vendors/cp312/cffi/lock.py b/source/target-vendors/cp312/cffi/lock.py new file mode 100644 index 0000000..db91b71 --- /dev/null +++ b/source/target-vendors/cp312/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/source/target-vendors/cp312/cffi/model.py b/source/target-vendors/cp312/cffi/model.py new file mode 100644 index 0000000..8bade1d --- /dev/null +++ b/source/target-vendors/cp312/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: + 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 replace_with[0] not 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', + '_cffi_float_complex_t': 'j', + '_cffi_double_complex_t': '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 = " *&" + if totype.is_array_type: + extra = "(%s)" % (extra.lstrip(),) + extra = qualify(quals, extra) + 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 + yield from type.enumfields() + 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/source/target-vendors/cp312/cffi/parse_c_type.h b/source/target-vendors/cp312/cffi/parse_c_type.h new file mode 100644 index 0000000..84e4ef8 --- /dev/null +++ b/source/target-vendors/cp312/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/source/target-vendors/cp312/cffi/pkgconfig.py b/source/target-vendors/cp312/cffi/pkgconfig.py new file mode 100644 index 0000000..e1034ad --- /dev/null +++ b/source/target-vendors/cp312/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 OSError 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/source/target-vendors/cp312/cffi/recompiler.py b/source/target-vendors/cp312/cffi/recompiler.py new file mode 100644 index 0000000..5e71aed --- /dev/null +++ b/source/target-vendors/cp312/cffi/recompiler.py @@ -0,0 +1,1586 @@ +import io, os, sys, sysconfig +from . import ffiplatform, model +from .error import VerificationError +from .cffi_opcode import * + +VERSION_BASE = 0x2601 +VERSION_EMBEDDED = 0x2701 +VERSION_CHAR16CHAR32 = 0x2801 + +FREE_THREADED_BUILD = sysconfig.get_config_var("Py_GIL_DISABLED") +USE_LIMITED_API = ((sys.platform != 'win32' or sys.version_info < (3, 0) or + sys.version_info >= (3, 5)) and + # free-threaded build doesn't support the stable ABI until Python 3.15 + (not FREE_THREADED_BUILD or sys.version_info >= (3, 15))) + +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): + lines = [' { "%s", %d, _cffi_prim_int(%s, %s),' % (self.name, self.type_index, + self.size, self.signed,)] + pending = 0 + while len(self.allenums) > pending + 110: + j = self.allenums.find(',', pending + 100) + if j < 0: + break + j += 1 + lines.append(' "%s"' % (self.allenums[pending:j],)) + pending = j + lines.append(' "%s" },' % (self.allenums[pending:],)) + return '\n'.join(lines) + + 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 _enum_fields(self, tp): + # When producing C, expand all anonymous struct/union fields. + # That's necessary to have C code checking the offsets of the + # individual fields contained in them. When producing Python, + # don't do it and instead write it like it is, with the + # corresponding fields having an empty name. Empty names are + # recognized at runtime when we import the generated Python + # file. + expand_anonymous_struct_union = not self.target_is_python + return tp.enumfields(expand_anonymous_struct_union) + + 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 self._enum_fields(tp): + 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): + with open(os.path.join(os.path.dirname(__file__), filename), 'r') as g: + return g.readlines() + + 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('#else') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%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 > 0 or self.ffi._embedding is not None: + 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 flags & 1: + 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(' return NULL;') + 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(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) + prnt('# endif') + prnt('#else') + 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('#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, 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 self._enum_fields(tp): + 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: + enumfields = list(self._enum_fields(tp)) + 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 = '(size_t)(((char *)&((%s)4096)->%s) - (char *)4096)' % ( + 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 + 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().write(s) + +def _is_file_like(maybefile): + # compare to xml.etree.ElementTree._get_writer + return hasattr(maybefile, 'write') + +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() + if _is_file_like(target_file): + recompiler.write_source_to_f(target_file, preamble) + return True + 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 OSError + if verbose: + print("(already up-to-date)") + return False # already up-to-date + except OSError: + 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! + # FUTURE: this module was removed in setuptools 74; this is likely dead code and should be removed, + # since the toolchain it supports (VS2005-2008) is also long dead. + from cffi._shimmed_dist_utils import MSVCCompiler + if MSVCCompiler is not None: + _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 cffi._shimmed_dist_utils 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 cffi._shimmed_dist_utils 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, + uses_ffiplatform=True, **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: + if call_c_compiler and _is_file_like(c_file): + raise TypeError("Writing to file-like objects is not supported " + "with call_c_compiler=True") + 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 = '*' + # + if uses_ffiplatform: + ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) + else: + ext = None + 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/source/target-vendors/cp312/cffi/setuptools_ext.py b/source/target-vendors/cp312/cffi/setuptools_ext.py new file mode 100644 index 0000000..946afb4 --- /dev/null +++ b/source/target-vendors/cp312/cffi/setuptools_ext.py @@ -0,0 +1,231 @@ +import os +import sys +import sysconfig + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +def error(msg): + from cffi._shimmed_dist_utils 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._shimmed_dist_utils import log + 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 + + if sysconfig.get_config_var("Py_GIL_DISABLED"): + if sys.version_info < (3, 15): + if kwds.get('py_limited_api'): + log.info("Ignoring py_limited_api=True for free-threaded build.") + kwds['py_limited_api'] = False + else: + kwds.setdefault("define_macros", []).append(("Py_TARGET_ABI3T", "0x030f0000")) + + if kwds.get('py_limited_api') is False: + # avoid setting Py_LIMITED_API if py_limited_api=False + # which _cffi_include.h does unless _CFFI_NO_LIMITED_API is defined + kwds.setdefault("define_macros", []).append(("_CFFI_NO_LIMITED_API", None)) + return kwds + +def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext + from cffi._shimmed_dist_utils import Extension, log, mkpath + 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 setuptools.command.build_py import build_py + from setuptools.command.build_ext import build_ext + from cffi._shimmed_dist_utils import log, mkpath + 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/source/target-vendors/cp312/cffi/vengine_cpy.py b/source/target-vendors/cp312/cffi/vengine_cpy.py new file mode 100644 index 0000000..4d2ea43 --- /dev/null +++ b/source/target-vendors/cp312/cffi/vengine_cpy.py @@ -0,0 +1,1058 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys +from . import model +from .error import VerificationError +from . import _imp_emulation as imp + + +class VCPythonEngine: + _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('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('#if Py_GIL_DISABLED') + prnt(' PyUnstable_Module_SetGIL(lib, Py_MOD_GIL_NOT_USED);') + prnt('#endif') + prnt(' return lib;') + prnt('}') + prnt() + + 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: + _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 + elif tp.is_complex_type(): + raise VerificationError( + "not implemented in verify(): complex types") + 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 +# define _cffi_float_complex_t _Fcomplex /* include for it */ +# define _cffi_double_complex_t _Dcomplex /* include for it */ +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +# define _cffi_float_complex_t float _Complex +# define _cffi_double_complex_t double _Complex +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyLong_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) ? \ + PyLong_FromLong((long)(x)) : \ + PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ + ((long long)(x) >= (long long)LONG_MIN) ? \ + PyLong_FromLong((long)(x)) : \ + PyLong_FromLongLong((long long)(x))) + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyLong_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyLong_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/source/target-vendors/cp312/cffi/vengine_gen.py b/source/target-vendors/cp312/cffi/vengine_gen.py new file mode 100644 index 0000000..0209c79 --- /dev/null +++ b/source/target-vendors/cp312/cffi/vengine_gen.py @@ -0,0 +1,679 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os +import types + +from . import model +from .error import VerificationError + + +class VGenericEngine: + _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 +# define _cffi_float_complex_t _Fcomplex /* include for it */ +# define _cffi_double_complex_t _Dcomplex /* include for it */ +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +# define _cffi_float_complex_t float _Complex +# define _cffi_double_complex_t double _Complex +#endif +''' diff --git a/source/target-vendors/cp312/cffi/verifier.py b/source/target-vendors/cp312/cffi/verifier.py new file mode 100644 index 0000000..96baadb --- /dev/null +++ b/source/target-vendors/cp312/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().write(s) + + +class Verifier: + + 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(['%d.%d' % sys.version_info[:2], + __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): + 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 = 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/source/target-vendors/cp312/click-8.5.0.dist-info/METADATA b/source/target-vendors/cp312/click-8.5.0.dist-info/METADATA new file mode 100644 index 0000000..7b78530 --- /dev/null +++ b/source/target-vendors/cp312/click-8.5.0.dist-info/METADATA @@ -0,0 +1,83 @@ +Metadata-Version: 2.4 +Name: click +Version: 8.5.0 +Summary: Composable command line interface toolkit +Maintainer-email: Pallets +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +License-File: LICENSE.txt +Project-URL: Changes, https://click.palletsprojects.com/page/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/click/ + +
    + +# Click + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +## A Simple Example + +```python +import click + +@click.command() +@click.option("--count", default=1, help="Number of greetings.") +@click.option("--name", prompt="Your name", help="The person to greet.") +def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + +if __name__ == '__main__': + hello() +``` + +``` +$ python hello.py --count=3 +Your name: Click +Hello, Click! +Hello, Click! +Hello, Click! +``` + + +## Donate + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/source/target-vendors/cp312/click-8.5.0.dist-info/RECORD b/source/target-vendors/cp312/click-8.5.0.dist-info/RECORD new file mode 100644 index 0000000..b50c362 --- /dev/null +++ b/source/target-vendors/cp312/click-8.5.0.dist-info/RECORD @@ -0,0 +1,22 @@ +click/__init__.py,sha256=Wr_FTTfUfMeIt-egXpUUeH-MWgt9tCnQ8k10isiZZMo,5145 +click/_compat.py,sha256=jbHaKWXPPl3GbGxTgzy8YT6hzSRAudDraqg2DrRtSRM,17939 +click/_termui_impl.py,sha256=iLl9m3pblHsQoW2KsmmDe8hMflXCi6cupfL7M5ESM2o,32805 +click/_textwrap.py,sha256=7Z0N7Vmn-66TNSTUwp6OXJbcUXRmYET9h9c2ucD8oQQ,6270 +click/_utils.py,sha256=eCZCtwJtsYD5QYkkNWJ8MY_8ABIjy8MczgMMyVY32rQ,996 +click/_winconsole.py,sha256=KSxfNbMlYRa6GOJuCLgsg2Pb3dVkgJNPqLJPae-Pa10,8543 +click/core.py,sha256=TGWmE8HEB9zpB6ThI7Es7F_g9iCIqLn4b6vUtgxLbXg,147845 +click/decorators.py,sha256=FgaTV2FWkfzfyceUu1FfYAnrNarW96dsAXvc4G2ujVU,21680 +click/exceptions.py,sha256=HvSY34G4auj_bYRR8-T8CU8Jwq_1-OcsRU4ezfozeEk,11862 +click/formatting.py,sha256=8SW2KGkvjfz9Q1NbeojMHuZBN0cfnQJDs4mqDP6oXms,10444 +click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 +click/parser.py,sha256=oJ-fU_3mvxugIuNtHaCATZ56lgEmHRggjJiSqEgYrjA,19052 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=GFIvdd3_5lXpQ5eNGVMlXER4QoZ9P9Z_vcFUPT332gk,26172 +click/termui.py,sha256=jsgCK45FKPhz7EExlKXRYU6W2lC2xKcfYmCzJnYqfpw,35370 +click/testing.py,sha256=dvTmSbxTAA1mfIwN7_FZGXD6A0sPCFogcWWDmyMBAZo,27584 +click/types.py,sha256=HpiJBKen9oq61jDH-5wDikNF-i5nAcl2puUfEL37Ut0,46842 +click/utils.py,sha256=9D1XQ9wHJA5hL-76CmnSsWl7aQAUn4-An_zZfstILb8,21483 +click-8.5.0.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.5.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +click-8.5.0.dist-info/METADATA,sha256=6HvOC9GU3nDfuOcI4KawSDAJ8lYRgE6vh7_rY-bCBQE,2567 +click-8.5.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/click-8.5.0.dist-info/WHEEL b/source/target-vendors/cp312/click-8.5.0.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/source/target-vendors/cp312/click-8.5.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/click-8.5.0.dist-info/licenses/LICENSE.txt b/source/target-vendors/cp312/click-8.5.0.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/source/target-vendors/cp312/click-8.5.0.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/click/__init__.py b/source/target-vendors/cp312/click/__init__.py new file mode 100644 index 0000000..a34ab02 --- /dev/null +++ b/source/target-vendors/cp312/click/__init__.py @@ -0,0 +1,144 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" + +from __future__ import annotations + +from .core import Argument as Argument +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import Option as Option +from .core import Parameter as Parameter +from .core import ParameterSource as ParameterSource +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import custom_version_option as custom_version_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchCommand as NoSuchCommand +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import get_pager_file as get_pager_file +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import open_file as open_file + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + from .core import _BaseCommand + + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + from .core import _MultiCommand + + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + if name == "OptionParser": + from .parser import _OptionParser + + warnings.warn( + "'OptionParser' is deprecated and will be removed in Click 9.0. The" + " old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return _OptionParser + + if name == "__version__": + import importlib.metadata + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Click 9.1. Use feature detection or" + " 'importlib.metadata.version(\"click\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("click") + + if name == "get_binary_stream": + from .utils import _get_binary_stream + + warnings.warn( + "'get_binary_stream' is deprecated and will be removed in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return _get_binary_stream + + if name == "get_text_stream": + from .utils import _get_text_stream + + warnings.warn( + "'get_text_stream' is deprecated and will be removed in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return _get_text_stream + + raise AttributeError(name) diff --git a/source/target-vendors/cp312/click/_compat.py b/source/target-vendors/cp312/click/_compat.py new file mode 100644 index 0000000..8507a50 --- /dev/null +++ b/source/target-vendors/cp312/click/_compat.py @@ -0,0 +1,590 @@ +from __future__ import annotations + +import codecs +import collections.abc as cabc +import io +import os +import re +import sys +import typing as t +from types import TracebackType +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +WIN = sys.platform.startswith("win") +# One CSI escape sequence per the ECMA-48 grammar: parameter bytes (0x30-0x3F), +# intermediate bytes (0x20-0x2F), then a final byte (0x40-0x7E). Broader than the +# SGR codes Click emits, so foreign sequences (colon-delimited true-color, mouse +# reporting) are stripped too. +_ansi_re = re.compile(r"\033\[[0-?]*[ -/]*[@-~]") + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO[t.Any]) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write(b"") + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: str | None, errors: str | None +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO[t.Any], + encoding: str | None, + errors: str | None, + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: str | os.PathLike[str] | int, + mode: str, + encoding: str | None, + errors: str | None, +) -> t.IO[t.Any]: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, +) -> tuple[t.IO[t.Any], bool]: + binary = "b" in mode + filename = os.fspath(filename) + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: int | None = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO[t.Any], af), True + + +class _AtomicFile: + def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> _AtomicFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + elif hasattr(stream, "color"): + # ._termui_impl._PagerWriter handles stripping ansi itself, + # so we don't need to strip it here + return False + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# Double check is needed so mypy does not analyze this on Linux. +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None + ) -> t.TextIO | None: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO[t.Any]) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO | None], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.TextIO | None]: + cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO | None: + stream = src_func() + + if stream is None: + return None + + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/source/target-vendors/cp312/click/_termui_impl.py b/source/target-vendors/cp312/click/_termui_impl.py new file mode 100644 index 0000000..70aabf8 --- /dev/null +++ b/source/target-vendors/cp312/click/_termui_impl.py @@ -0,0 +1,972 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" + +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import math +import os +import shlex +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +from pathlib import Path +from types import TracebackType + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: cabc.Iterable[V] | None, + length: int | None = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + label: str | None = None, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.hidden = hidden + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label: str = label or "" + + if file is None: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + file = StringIO() + + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width: int = width + self.autowidth: bool = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast("cabc.Iterable[V]", range(length)) + self.iter: cabc.Iterable[V] = iter(iterable) + self.length = length + self.pos: int = 0 + self.avg: list[float] = [] + self.last_eta: float + self.start: float + self.start = self.last_eta = time.time() + self.eta_known: bool = False + self.finished: bool = False + self.max_width: int | None = None + self.entered: bool = False + self.current_item: V | None = None + self._is_atty = isatty(self.file) + self._last_line: str | None = None + + def __enter__(self) -> ProgressBar[V]: + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.render_finish() + + def __iter__(self) -> cabc.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + # Steps stay pending until they add up to update_min_steps, so a length + # that is not a multiple of it keeps a sub-threshold remainder that + # never reaches pos. Apply it so the bar settles on its true position. + if self._completed_intervals: + self.make_step(self._completed_intervals) + self._completed_intervals = 0 + self.render_progress() + + if self.hidden or not self._is_atty: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return "{d}{day_label} {h:02}:{m:02}:{s:02}".format( + d=t, + day_label=_("d"), + h=hours, + m=minutes, + s=seconds, + ) + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + if self.hidden: + return + + if not self._is_atty: + # Only output the label once if the output is not a TTY. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + import shutil + + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width and self.max_width is not None: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: V | None = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> cabc.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if not self._is_atty: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +class _PagerWriter: + """Wrap a pager's output stream to strip ANSI styling when colors are + disabled. + + The wrapped stream is owned by the pager strategy that produced it, so this + wrapper never closes it: ``_pipepager`` closes its pipe to signal EOF to the + pager process, ``_tempfilepager`` closes and removes its temporary file, and + ``_nullpager`` leaves an external stream such as ``sys.stdout`` untouched. + + The ``color`` attribute lets :func:`click.echo` detect that ANSI stripping + is handled here, so it doesn't strip a second time (see + :func:`._compat.should_strip_ansi`). + """ + + def __init__(self, stream: t.TextIO, color: bool) -> None: + self._stream = stream + self.color = color + + def write(self, text: str) -> int: + if not self.color: + text = strip_ansi(text) + + return self._stream.write(text) + + def writelines(self, lines: cabc.Iterable[str]) -> None: + for line in lines: + self.write(line) + + def flush(self) -> None: + self._stream.flush() + + def close(self) -> None: + # The pager strategy owns the stream's lifecycle. Flush pending output, + # but never close the underlying stream from here. + self._stream.flush() + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + +def _resolve_pager_command(cmd_parts: list[str]) -> tuple[Path, list[str]] | None: + """Resolve a pager ``argv`` to an absolute command path and its parameters. + + The command is looked up with :func:`shutil.which`, which the + :mod:`subprocess` docs recommend on every platform for an unqualified name: + https://docs.python.org/3/library/subprocess.html#popen-constructor + + Returns ``None`` when there is no command to run or it is not on the path, + leaving the caller to pick a fallback. + """ + if not cmd_parts: + return None + + import shutil + + cmd_filepath = shutil.which(cmd_parts[0]) + + if not cmd_filepath: + return None + + # Normalize to an absolute path without resolving symlinks: multi-call + # binaries such as busybox derive their identity from the link they are + # invoked through, so resolving less -> busybox makes them misbehave. + # See https://github.com/pallets/click/issues/2943 and + # https://github.com/pallets/click/pull/2944 + return Path(cmd_filepath).absolute(), cmd_parts[1:] + + +def _pager_contextmanager( + color: bool | None = None, +) -> t.ContextManager[tuple[t.TextIO, bool | None]]: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if stdout is None: + stdout = StringIO() + + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, color) + + # Split using POSIX mode (the default) so that quote characters are + # stripped from tokens and quoted Windows paths are preserved. + # Non-POSIX mode retains quotes in tokens, and wrapping tokens + # with shlex.quote re-introduces quoting issues on Windows. + pager_cmd_parts = shlex.split(os.environ.get("PAGER", "")) + + if pager_cmd_parts: + # Piping to `more` on Windows adds spurious \r\n, so it gets the temp + # file strategy whatever the user asked for. + use_tempfile = WIN + else: + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, color) + + use_tempfile = WIN or sys.platform.startswith("os2") + pager_cmd_parts = ["more"] if use_tempfile else ["less"] + + resolved = _resolve_pager_command(pager_cmd_parts) + + if resolved is None: + # Page through stdout, which _nullpager leaves open for its owner. + return _nullpager(stdout, color) + + cmd_path, cmd_params = resolved + + if use_tempfile: + return _tempfilepager(cmd_path, cmd_params, color) + + return _pipepager(cmd_path, cmd_params, color) + + +@contextlib.contextmanager +def get_pager_file(color: bool | None = None) -> t.Generator[t.TextIO, None, None]: + """Context manager. + + Yields a writable file-like object which can be used as an output pager. + + .. versionadded:: 8.4.0 + + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + with _pager_contextmanager(color=color) as (stream, color): + # Every pager strategy yields a text stream, so the only thing left to + # do is strip ANSI styling when colors are disabled. A strategy yields + # None when it has no opinion on colors, which settles as off here. The + # wrapper does not close the stream: each strategy owns its stream's + # lifecycle. + writer = _PagerWriter(stream, color=bool(color)) + try: + yield t.cast(t.TextIO, writer) + finally: + writer.flush() + + +def _less_uses_raw_mode(less_env: str, cmd_params: list[str]) -> bool: + """Detect a raw-control-characters request in a ``less`` invocation. + + Parses the tokens of the ``LESS`` environment variable and the command + line: only short-option clusters (``-R``, ``-rX``, ``-XrY``) and the + ``--raw-control-chars`` long option request raw mode. Filenames and + long-option values may carry the letter ``r`` without being such a + request. + """ + try: + env_tokens = shlex.split(less_env) + except ValueError: + # Unbalanced quotes make ``LESS`` unparsable: fall back to whitespace + # splitting rather than failing the pager over it. + env_tokens = less_env.split() + tokens = env_tokens + cmd_params + + for token in tokens: + if token.startswith("--"): + if token.casefold() == "--raw-control-chars": + return True + elif token.startswith("-") and len(token) > 1: + if "r" in token[1:].casefold(): + return True + + return False + + +@contextlib.contextmanager +def _pipepager( + cmd_path: Path, cmd_params: list[str], color: bool | None = None +) -> t.Iterator[tuple[t.TextIO, bool | None]]: + """Page through text by feeding it to another program. + + Invokes the pager via :class:`subprocess.Popen` with an ``argv`` list. + + Invoking a pager through this might support colors: if piping to + ``less`` and the user hasn't decided on colors, ``LESS=-R`` is set + automatically. + """ + import subprocess + + # Make a local copy of the environment to not affect the global one. + env = dict(os.environ) + + # If we're piping to less and the user hasn't decided on colors, we enable + # them: either the invocation already requests raw control characters, or + # ``LESS=-R`` is injected. Match on the stem so a resolved ``less.exe`` is + # recognized like bare ``less``, case-insensitively on Windows since its + # filesystems are. POSIX keeps an exact match. + cmd_name = cmd_path.stem + if WIN: + # ``_pager_contextmanager`` currently routes every Windows invocation + # to ``_tempfilepager``, so this branch is not reachable on Windows + # today: it keeps the detection correct should that routing ever + # change. + cmd_name = cmd_name.casefold() + + if color is None and cmd_name == "less": + less_env = os.environ.get("LESS", "") + if _less_uses_raw_mode(less_env, cmd_params): + color = True + elif not less_env and not cmd_params: + env["LESS"] = "-R" + color = True + + c = subprocess.Popen( + [str(cmd_path)] + cmd_params, + shell=False, + stdin=subprocess.PIPE, + env=env, + errors="replace", + text=True, + ) + # With ``text=True``, ``c.stdin`` is already a text stream that encodes + # writes for the pager process (honoring ``errors="replace"``). + stdin = t.cast(t.TextIO, c.stdin) + try: + yield stdin, color + except BrokenPipeError: + # In case the pager exited unexpectedly, ignore the broken pipe error. + pass + except Exception as e: + # In case there is an exception we want to close the pager immediately + # and let the caller handle it. + # Otherwise the pager will keep running, and the user may not notice + # the error message, or worse yet it may leave the terminal in a broken state. + c.terminate() + raise e + finally: + # We must close stdin and wait for the pager to exit before we continue + try: + stdin.close() + # Close implies flush, so it might throw a BrokenPipeError if the pager + # process exited already. + except BrokenPipeError: + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +@contextlib.contextmanager +def _tempfilepager( + cmd_path: Path, cmd_params: list[str], color: bool | None = None +) -> t.Iterator[tuple[t.TextIO, bool | None]]: + """Page through text by invoking a program on a temporary file. + + Used as the primary pager strategy on Windows (where piping to + ``more`` adds spurious ``\\r\\n``), and as a fallback on other + platforms. The command is invoked with any parameters from ``PAGER`` + followed by the temporary file name. + """ + import subprocess + import tempfile + + encoding = get_best_encoding(sys.stdout) + # On Windows, NamedTemporaryFile cannot be opened by another process + # while Python still has it open, so we use delete=False and clean up manually + # rather than using a contextmanager here. + f = tempfile.NamedTemporaryFile( + mode="w", encoding=encoding, errors="replace", delete=False + ) + try: + yield t.cast(t.TextIO, f), color + f.flush() + f.close() + subprocess.call([str(cmd_path), *cmd_params, f.name]) + finally: + # An error raised while paging skips the close() above, and Windows + # refuses to unlink a file the process still holds open. Closing here + # keeps that PermissionError from replacing the original exception. + # close() is idempotent, so this is a no-op on the success path. + f.close() + os.unlink(f.name) + + +@contextlib.contextmanager +def _nullpager( + stream: t.TextIO, color: bool | None = None +) -> t.Iterator[tuple[t.TextIO, bool | None]]: + """Simply print unformatted text. This is the ultimate fallback. + + The stream comes from elsewhere (typically ``sys.stdout``), so its lifecycle + is left untouched: :class:`_PagerWriter` never closes what it wraps, and it + is the only thing :func:`get_pager_file` hands to the caller. + """ + yield stream, color + + +class Editor: + def __init__( + self, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + + from shutil import which + + for editor in "sensible-editor", "vim", "nano": + if which(editor) is not None: + return editor + return "vi" + + def edit_files(self, filenames: cabc.Iterable[str | os.PathLike[str]]) -> None: + """Open files in the user's editor.""" + import shlex + import subprocess + + editor = self.get_editor() + environ: dict[str, str] | None = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + try: + # Split in POSIX mode (the default) for the same reasons as + # in pager(): strips quotes from tokens and preserves quoted + # Windows paths. + c = subprocess.Popen( + args=shlex.split(editor) + list(filenames), + env=environ, + ) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + @t.overload + def edit(self, text: bytes | bytearray) -> bytes | None: ... + + # We cannot know whether or not the type expected is str or bytes when None + # is passed, so str is returned as that was what was done before. + @t.overload + def edit(self, text: str | None) -> str | None: ... + + def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: + import tempfile + + if text is None: + data: bytes | bytearray = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_files((name,)) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = ["explorer", "/select,", url] + try: + return subprocess.call(args) + except OSError: + return 127 + else: + try: + os.startfile(url) # type: ignore[attr-defined] + except OSError: + return 127 + return 0 + elif CYGWIN: + if locate: + url = _unquote_file(url) + args = ["cygstart", os.path.dirname(url)] + else: + args = ["cygstart"] + if wait: + args.append("-w") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> None: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + +if sys.platform == "win32": + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + + if echo: + func = t.cast(t.Callable[[], str], msvcrt.getwche) + else: + func = t.cast(t.Callable[[], str], msvcrt.getwch) + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import termios + import tty + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + f: t.TextIO | None + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/source/target-vendors/cp312/click/_textwrap.py b/source/target-vendors/cp312/click/_textwrap.py new file mode 100644 index 0000000..82840f2 --- /dev/null +++ b/source/target-vendors/cp312/click/_textwrap.py @@ -0,0 +1,188 @@ +from __future__ import annotations + +import collections.abc as cabc +import textwrap +from contextlib import contextmanager + +from ._compat import _ansi_re +from ._compat import term_len + + +def _truncate_visible(text: str, n: int) -> str: + """Return the longest prefix of ``text`` containing at most ``n`` visible + characters. + + ANSI escape sequences inside the prefix are kept intact and do not count + toward the visible width. A cut is never placed inside an escape sequence. + """ + if n <= 0: + return "" + + visible = 0 + i = 0 + cut = 0 + end = len(text) + while i < end: + m = _ansi_re.match(text, i) + if m is not None: + i = m.end() + continue + visible += 1 + i += 1 + cut = i + if visible >= n: + break + return text[:cut] + + +class TextWrapper(textwrap.TextWrapper): + """``textwrap.TextWrapper`` variant that measures widths by visible + character count. + + ANSI escape sequences embedded in chunks, indents, or the placeholder are + excluded from the width budget. Without this, styled help text (a styled + ``Usage:`` prefix, a colorized option name, ...) would be wrapped earlier + than its visible length warrants and tokens would split mid-word. + """ + + def _handle_long_word( + self, + reversed_chunks: list[str], + cur_line: list[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = _truncate_visible(last, space_left) + res = last[len(cut) :] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + def _wrap_chunks(self, chunks: list[str]) -> list[str]: + """Wrap chunks counting widths in visible characters. + + Mirrors the algorithm of :meth:`textwrap.TextWrapper._wrap_chunks` + with every width measurement routed through + :func:`click._compat.term_len` instead of :func:`len`, so ANSI escape + bytes in chunks, indents, or the placeholder do not inflate the count. + + .. seealso:: + :class:`textwrap.TextWrapper` in the Python standard library documentation: + https://docs.python.org/3/library/textwrap.html#textwrap.TextWrapper + + Reference implementation in CPython: + https://github.com/python/cpython/blob/main/Lib/textwrap.py + """ + lines: list[str] = [] + if self.width <= 0: + raise ValueError(f"invalid width {self.width!r} (must be > 0)") + if self.max_lines is not None: + if self.max_lines > 1: + indent = self.subsequent_indent + else: + indent = self.initial_indent + if term_len(indent) + term_len(self.placeholder.lstrip()) > self.width: + raise ValueError("placeholder too large for max width") + + chunks.reverse() + + while chunks: + cur_line: list[str] = [] + cur_len = 0 + + if lines: + indent = self.subsequent_indent + else: + indent = self.initial_indent + + width = self.width - term_len(indent) + + if self.drop_whitespace and chunks[-1].strip() == "" and lines: + del chunks[-1] + + while chunks: + n = term_len(chunks[-1]) + + if cur_len + n <= width: + cur_line.append(chunks.pop()) + cur_len += n + + else: + break + + if chunks and term_len(chunks[-1]) > width: + self._handle_long_word(chunks, cur_line, cur_len, width) + cur_len = sum(map(term_len, cur_line)) + + if self.drop_whitespace and cur_line and cur_line[-1].strip() == "": + cur_len -= term_len(cur_line[-1]) + del cur_line[-1] + + if cur_line: + if ( + self.max_lines is None + or len(lines) + 1 < self.max_lines + or ( + not chunks + or self.drop_whitespace + and len(chunks) == 1 + and not chunks[0].strip() + ) + and cur_len <= width + ): + lines.append(indent + "".join(cur_line)) + else: + while cur_line: + if ( + cur_line[-1].strip() + and cur_len + term_len(self.placeholder) <= width + ): + cur_line.append(self.placeholder) + lines.append(indent + "".join(cur_line)) + break + cur_len -= term_len(cur_line[-1]) + del cur_line[-1] + else: + if lines: + prev_line = lines[-1].rstrip() + if ( + term_len(prev_line) + term_len(self.placeholder) + <= self.width + ): + lines[-1] = prev_line + self.placeholder + break + lines.append(indent + self.placeholder.lstrip()) + break + + return lines + + @contextmanager + def extra_indent(self, indent: str) -> cabc.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/source/target-vendors/cp312/click/_utils.py b/source/target-vendors/cp312/click/_utils.py new file mode 100644 index 0000000..05ee2e9 --- /dev/null +++ b/source/target-vendors/cp312/click/_utils.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import enum +import typing as t + + +class Sentinel(enum.Enum): + """Enum used to define sentinel values. + + .. seealso:: + + `PEP 661 - Sentinel Values `_. + """ + + UNSET = object() + FLAG_NEEDS_VALUE = object() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}.{self.name}" + + +UNSET: t.Literal[Sentinel.UNSET] = Sentinel.UNSET +"""Sentinel used to indicate that a value is not set.""" + +FLAG_NEEDS_VALUE: t.Literal[Sentinel.FLAG_NEEDS_VALUE] = Sentinel.FLAG_NEEDS_VALUE +"""Sentinel used to indicate an option was passed as a flag without a +value but is not a flag option. + +``Option.consume_value`` uses this to prompt or use the ``flag_value``. +""" + +T_UNSET: t.TypeAlias = t.Literal[Sentinel.UNSET] +"""Type hint for the :data:`UNSET` sentinel value.""" + +T_FLAG_NEEDS_VALUE: t.TypeAlias = t.Literal[Sentinel.FLAG_NEEDS_VALUE] +"""Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" diff --git a/source/target-vendors/cp312/click/_winconsole.py b/source/target-vendors/cp312/click/_winconsole.py new file mode 100644 index 0000000..d25178d --- /dev/null +++ b/source/target-vendors/cp312/click/_winconsole.py @@ -0,0 +1,297 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +from __future__ import annotations + +import collections.abc as cabc +import io +import sys +import time +import typing as t +from ctypes import Array +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR +from gettext import gettext as _ + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +if t.TYPE_CHECKING: + try: + # Using `typing_extensions.Buffer` instead of `collections.abc` + # on Windows for some reason does not have `Sized` implemented. + from collections.abc import Buffer # type: ignore + except ImportError: + from typing_extensions import Buffer + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ # noqa: RUF012 + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: + buf = Py_buffer() + flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + out: Array[c_char] = buffer_type.from_address(buf.buf) + return out + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle: int | None) -> None: + self.handle = handle + + def isatty(self) -> t.Literal[True]: + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self) -> t.Literal[True]: + return True + + def readinto(self, b: Buffer) -> int: + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(_("Windows error: {error}").format(error=GetLastError())) + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self) -> t.Literal[True]: + return True + + @staticmethod + def _get_error_message(errno: int) -> str: + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return _("Windows error: {error}").format(error=errno) + + def write(self, b: Buffer) -> int: + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self) -> str: + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None +) -> t.TextIO | None: + if ( + get_buffer is None + or encoding not in {"utf-16-le", None} + or errors not in {"strict", None} + or not _is_console(f) + ): + return None + + func = _stream_factories.get(f.fileno()) + if func is None: + return None + + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/source/target-vendors/cp312/click/core.py b/source/target-vendors/cp312/click/core.py new file mode 100644 index 0000000..de129ec --- /dev/null +++ b/source/target-vendors/cp312/click/core.py @@ -0,0 +1,3799 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import errno +import inspect +import os +import sys +import typing as t +from abc import ABC +from abc import abstractmethod +from collections import abc +from collections import Counter +from contextlib import AbstractContextManager +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from ._utils import FLAG_NEEDS_VALUE +from ._utils import UNSET +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import NoArgsIsHelpError +from .exceptions import NoSuchCommand +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _OptionParser +from .parser import _split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import _make_default_short_help +from .utils import _PacifyFlushWrapper +from .utils import echo +from .utils import make_str + +if t.TYPE_CHECKING: + from typing_extensions import Self + + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound="t.Callable[..., t.Any]") +V = t.TypeVar("V") + +# Reserved storage name of the automatic help option. No user parameter is +# expected to claim it. +_HELP_OPTION_STORAGE_NAME = "_click_default_help" + + +def _complete_visible_commands( + ctx: Context, incomplete: str +) -> cabc.Iterator[tuple[str, Command]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(Group, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_nested_chain( + base_command: Group, cmd_name: str, cmd: Command, register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, Group): + return + + if register: + message = ( + f"It is not possible to add the group {cmd_name!r} to another" + f" group {base_command.name!r} that is in chain mode." + ) + else: + message = ( + f"Found the group {cmd_name!r} as subcommand to another group " + f" {base_command.name!r} that is in chain mode. This is not supported." + ) + + raise RuntimeError(message) + + +def _format_deprecated_label(deprecated: bool | str) -> str: + """Return the parenthesized deprecation label shown in help text.""" + label = _("deprecated").upper() + if isinstance(deprecated, str): + return f"({label}: {deprecated})" + return f"({label})" + + +def _format_deprecated_suffix(deprecated: bool | str) -> str: + """Return the trailing reason for a ``DeprecationWarning`` message, + prefixed with a space, or an empty string when no reason was given. + """ + if isinstance(deprecated, str): + return f" {deprecated}" + return "" + + +def batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size), strict=False)) + + +@contextmanager +def augment_usage_errors( + ctx: Context, param: Parameter | None = None +) -> cabc.Generator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: cabc.Sequence[Parameter], + declaration_order: cabc.Sequence[Parameter], +) -> list[Parameter]: + """Returns all declared parameters in the order they should be processed. + + The declared parameters are re-shuffled depending on the order in which + they were invoked, as well as the eagerness of each parameters. + + The invocation order takes precedence over the declaration order. I.e. the + order in which the user provided them to the CLI is respected. + + This behavior and its effect on callback evaluation is detailed at: + https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order + """ + + def sort_key(item: Parameter) -> tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.IntEnum): + """This is an :class:`~enum.IntEnum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + Members are ordered from most explicit to least explicit source. + This allows comparison to check if a value was explicitly provided: + + .. code-block:: python + + source = ctx.get_parameter_source("port") + if source < click.ParameterSource.DEFAULT_MAP: + ... # value was explicitly set + + .. versionchanged:: 8.3.3 + Use :class:`~enum.IntEnum` and reorder members from most to + least explicit. Supports comparison operators. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below that it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.2 + The ``protected_args`` attribute is deprecated and will be removed in + Click 9.0. ``args`` will contain remaining unparsed tokens. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: type[HelpFormatter] = HelpFormatter + + parent: Context | None + command: Command + info_name: str | None + params: dict[str, t.Any] + args: list[str] + _protected_args: list[str] + _opt_prefixes: set[str] + obj: t.Any + _meta: dict[str, t.Any] + default_map: cabc.MutableMapping[str, t.Any] | None + invoked_subcommand: str | None + terminal_width: int | None + max_content_width: int | None + allow_extra_args: bool + allow_interspersed_args: bool + ignore_unknown_options: bool + help_option_names: list[str] + token_normalize_func: t.Callable[[str], str] | None + resilient_parsing: bool + auto_envvar_prefix: str | None + color: bool | None + show_default: bool | None + _close_callbacks: list[t.Callable[[], t.Any]] + _depth: int + _parameter_source: dict[str, ParameterSource] + _param_default_explicit: dict[str, bool] + _exit_stack: ExitStack + + def __init__( + self, + command: Command, + parent: Context | None = None, + info_name: str | None = None, + obj: t.Any | None = None, + auto_envvar_prefix: str | None = None, + default_map: cabc.MutableMapping[str, t.Any] | None = None, + terminal_width: int | None = None, + max_content_width: int | None = None, + resilient_parsing: bool = False, + allow_extra_args: bool | None = None, + allow_interspersed_args: bool | None = None, + ignore_unknown_options: bool | None = None, + help_option_names: list[str] | None = None, + token_normalize_func: t.Callable[[str], str] | None = None, + color: bool | None = None, + show_default: bool | None = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params = {} + #: the leftover arguments. + self.args = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self._protected_args = [] + #: the collected prefixes of the command's options. + self._opt_prefixes = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj = obj + self._meta = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default = show_default + + self._close_callbacks = [] + self._depth = 0 + self._parameter_source = {} + # Tracks whether the option that currently owns each parameter slot in + # :attr:`params` had its ``default`` set explicitly by the user. Used + # to tie-break feature-switch groups where multiple options share a + # parameter name and both fall back to their default value. + # Refs: https://github.com/pallets/click/issues/3403 + self._param_default_explicit = {} + self._exit_stack = ExitStack() + + @property + def protected_args(self) -> list[str]: + import warnings + + warnings.warn( + "'protected_args' is deprecated and will be removed in Click 9.0." + " 'args' will contain remaining unparsed tokens.", + DeprecationWarning, + stacklevel=2, + ) + return self._protected_args + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> Self: + self._depth += 1 + push_context(self) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> bool | None: + self._depth -= 1 + exit_result: bool | None = None + if self._depth == 0: + exit_result = self._close_with_exception_info(exc_type, exc_value, tb) + pop_context() + + return exit_result + + @contextmanager + def scope(self, cleanup: bool = True) -> cabc.Generator[Context]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: AbstractContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._close_with_exception_info(None, None, None) + + def _close_with_exception_info( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> bool | None: + """Unwind the exit stack by calling its :meth:`__exit__` providing the exception + information to allow for exception handling by the various resources registered + using :meth;`with_resource` + + :return: Whatever ``exit_stack.__exit__()`` returns. + """ + exit_result = self._exit_stack.__exit__(exc_type, exc_value, tb) + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + return exit_result + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> Context: + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: type[V]) -> V | None: + """Finds the closest object of a given type.""" + node: Context | None = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + def _default_map_has(self, name: str | None) -> bool: + """Check if :attr:`default_map` contains a real value for ``name``. + + Returns ``False`` when the key is absent, the map is ``None``, + ``name`` is ``None``, or the stored value is the internal + :data:`UNSET` sentinel. + """ + return ( + name is not None + and self.default_map is not None + and name in self.default_map + and self.default_map[name] is not UNSET + ) + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[False] = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def lookup_default(self, name: str, call: bool = True) -> t.Any | None: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if not self._default_map_has(name): + return None + + # Assert to make the type checker happy. + assert self.default_map is not None + value = self.default_map[name] + + if call and callable(value): + return value() + + return value + + def fail(self, message: str) -> t.NoReturn: + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> t.NoReturn: + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> t.NoReturn: + """Exits the application with a given exit code. + + .. versionchanged:: 8.2 + Callbacks and context managers registered with :meth:`call_on_close` + and :meth:`with_resource` are closed before exiting. + """ + self.close() + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: Command) -> Context: + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + @t.overload + def invoke( + self, callback: t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> V: ... + + @t.overload + def invoke(self, callback: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: ... + + def invoke( + self, callback: Command | t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> t.Any | V: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + + .. versionchanged:: 3.2 + A new context is created, and missing arguments use default values. + """ + if isinstance(callback, Command): + other_cmd = callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + callback = t.cast("t.Callable[..., V]", other_cmd.callback) + + ctx = self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + default_value = param.get_default(ctx) + # We explicitly hide the :attr:`UNSET` value to the user, as we + # choose to make it an implementation detail. And because ``invoke`` + # has been designed as part of Click public API, we return ``None`` + # instead. Refs: + # https://github.com/pallets/click/issues/3066 + # https://github.com/pallets/click/issues/3065 + # https://github.com/pallets/click/pull/3068 + if default_value is UNSET: + default_value = None + kwargs[param.name] = param.type_cast_value(ctx, default_value) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = self + + with augment_usage_errors(self), ctx: + return callback(*args, **kwargs) + + def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(cmd, Command): + raise TypeError("Callback is not a command.") + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> ParameterSource | None: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class Command: + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the command is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. + + .. versionchanged:: 8.2 + This is the base class for all commands, not ``BaseCommand``. + ``deprecated`` can be set to a string as well to customize the + deprecation message. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: type[Context] = Context + + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + name: str | None + context_settings: cabc.MutableMapping[str, t.Any] + callback: t.Callable[..., t.Any] | None + params: list[Parameter] + help: str | None + epilog: str | None + options_metavar: str | None + short_help: str | None + add_help_option: bool + _help_option: Option | None + no_args_is_help: bool + hidden: bool + deprecated: bool | str + + def __init__( + self, + name: str | None, + context_settings: cabc.MutableMapping[str, t.Any] | None = None, + callback: t.Callable[..., t.Any] | None = None, + params: list[Parameter] | None = None, + help: str | None = None, + epilog: str | None = None, + short_help: str | None = None, + options_metavar: str | None = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool | str = False, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings = context_settings + + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self._help_option = None + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + return { + "name": self.name, + "params": [param.to_info_dict() for param in self.get_params(ctx)], + "help": self.help, + "epilog": self.epilog, + "short_help": self.short_help, + "hidden": self.hidden, + "deprecated": self.deprecated, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> list[Parameter]: + params = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + params = [*params, help_option] + + if __debug__: + import warnings + + opts = [opt for param in params for opt in param.opts] + opts_counter = Counter(opts) + duplicate_opts = (opt for opt, count in opts_counter.items() if count > 1) + + for duplicate_opt in duplicate_opts: + warnings.warn( + ( + f"The parameter {duplicate_opt} is used more than once. " + "Remove its duplicate as parameters should be unique." + ), + stacklevel=3, + ) + + # Options may deliberately share a storage name to compete for + # the same value (feature switches), but an argument sharing a + # name silently overwrites the other parameter's value. + names_counter = Counter(param.name for param in params) + duplicate_names = ( + name for name, count in names_counter.items() if count > 1 + ) + + for duplicate_name in duplicate_names: + sharers = [param for param in params if param.name == duplicate_name] + + if help_option in sharers: + warnings.warn( + ( + f"The name {duplicate_name!r} is reserved for the " + "automatic help option. Give the parameter a " + "different name." + ), + stacklevel=3, + ) + elif any(isinstance(param, Argument) for param in sharers): + warnings.warn( + ( + f"The name {duplicate_name!r} is used by an argument " + "and another parameter. They will overwrite each " + "other's value during parsing. Give each parameter " + "a unique name." + ), + stacklevel=3, + ) + + return params + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> list[str]: + """Returns the names for the help option. + + Drops duplicates and names already reserved by another parameter. Order of + :attr:`Context.help_option_names` is preserved, so the result is stable. + + .. versionchanged:: 8.5.0 + Names keep their declaration order. + """ + all_names = dict.fromkeys(ctx.help_option_names) + for param in self.params: + for name in (*param.opts, *param.secondary_opts): + all_names.pop(name, None) + return list(all_names) + + def get_help_option(self, ctx: Context) -> Option | None: + """Returns the help option object. + + Skipped if :attr:`add_help_option` is ``False``. + + .. versionchanged:: 8.5.0 + The help option stores its value under the reserved name + ``_click_default_help``, so a parameter named ``help`` no + longer breaks parsing. + + .. versionchanged:: 8.1.8 + The help option is now cached to avoid creating it multiple times. + """ + help_option_names = self.get_help_option_names(ctx) + + if not help_option_names or not self.add_help_option: + return None + + # Cache the help option object in private _help_option attribute to + # avoid creating it multiple times. Not doing this will break the + # callback ordering by iter_params_for_processing(), which relies on + # object comparison. + if self._help_option is None: + # Avoid circular import. + from .decorators import help_option + + # The help option never exposes its value, so it uses a reserved + # storage name, keeping it clear of user parameters (like an + # argument named "help") that would otherwise clobber its value. + help_option(*help_option_names, _HELP_OPTION_STORAGE_NAME)(self) + self._help_option = self.params.pop() # type: ignore[assignment] + + return self._help_option + + def make_parser(self, ctx: Context) -> _OptionParser: + """Creates the underlying option parser for this command.""" + parser = _OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = _make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + text = f"{_(text)} {_format_deprecated_label(self.deprecated)}" + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_arguments` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_arguments(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + if self.help is not None: + # truncate the help text to the first form feed + text = inspect.cleandoc(self.help).partition("\f")[0] + else: + text = "" + + if self.deprecated: + label = _format_deprecated_label(self.deprecated) + text = f"{_(text)} {label}" if text else label + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None and not isinstance(param, Argument): + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_arguments(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the arguments that have a help record into the formatter.""" + args = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None and isinstance(param, Argument): + args.append(rv) + + if args: + with formatter.section(_("Positional arguments")): + formatter.write_dl(args) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: Context | None = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + _, args = param.handle_parse_result(ctx, opts, args) + + # We now have all parameters' values into `ctx.params`, but the data may contain + # the `UNSET` sentinel. + # Convert `UNSET` to `None` to ensure that the user doesn't see `UNSET`. + # + # Waiting until after the initial parse to convert allows us to treat `UNSET` + # more like a missing value when multiple params use the same name. + # Refs: + # https://github.com/pallets/click/issues/3071 + # https://github.com/pallets/click/pull/3079 + for name, value in ctx.params.items(): + if value is UNSET: + ctx.params[name] = None + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + message = _( + "DeprecationWarning: The command {name!r} is deprecated.{extra_message}" + ).format( + name=self.name, + extra_message=_format_deprecated_suffix(self.deprecated), + ) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: list[CompletionItem] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, Group) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx._protected_args + ) + + return results + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: t.Literal[True] = True, + **extra: t.Any, + ) -> t.NoReturn: ... + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: ... + + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt) as e: + echo(file=sys.stderr) + raise Abort() from e + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, _PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, _PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str | None = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + + .. versionchanged:: 8.2.0 + Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). + """ + if complete_var is None: + complete_name = prog_name.replace("-", "_").replace(".", "_") + complete_var = f"_{complete_name}_COMPLETE".upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: type) -> bool: + return issubclass(subclass, cls.__bases__[0]) + + def __instancecheck__(cls, instance: t.Any) -> bool: + return isinstance(instance, cls.__bases__[0]) + + +class _BaseCommand(Command, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Command`` instead. + """ + + +class Group(Command): + """A group is a command that nests other commands (or more groups). + + :param name: The name of the group command. + :param commands: Map names to :class:`Command` objects. Can be a list, which + will use :attr:`Command.name` as the keys. + :param invoke_without_command: Invoke the group's callback even if a + subcommand is not given. + :param no_args_is_help: If no arguments are given, show the group's help and + exit. Defaults to the opposite of ``invoke_without_command``. + :param subcommand_metavar: How to represent the subcommand argument in help. + The default will represent whether ``chain`` is set or not. + :param chain: Allow passing more than one subcommand argument. After parsing + a command's arguments, if any arguments remain another command will be + matched, and so on. + :param result_callback: A function to call after the group's and + subcommand's callbacks. The value returned by the subcommand is passed. + If ``chain`` is enabled, the value will be a list of values returned by + all the commands. If ``invoke_without_command`` is enabled, the value + will be the value returned by the group's callback, or an empty list if + ``chain`` is enabled. + :param kwargs: Other arguments passed to :class:`Command`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + + .. versionchanged:: 8.2 + Merged with and replaces the ``MultiCommand`` base class. + """ + + allow_extra_args = True + allow_interspersed_args = False + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: type[Command] | None = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: type[Group | type] | None = None + # Literal[type] isn't valid, so use Type[type] + + commands: cabc.MutableMapping[str, Command] + invoke_without_command: bool + subcommand_metavar: str + chain: bool + _result_callback: t.Callable[..., t.Any] | None + + def __init__( + self, + name: str | None = None, + commands: cabc.MutableMapping[str, Command] + | cabc.Sequence[Command] + | None = None, + invoke_without_command: bool = False, + no_args_is_help: bool | None = None, + subcommand_metavar: str | None = None, + chain: bool = False, + result_callback: t.Callable[..., t.Any] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands = commands + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + # When the group can run without a subcommand, the leading command + # token is optional, so wrap it in brackets to reflect that. + if chain: + if invoke_without_command: + subcommand_metavar = "[COMMAND1] [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + elif invoke_without_command: + subcommand_metavar = "[COMMAND] [ARGS]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "A group in chain mode cannot have optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def add_command(self, cmd: Command, name: str | None = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_nested_chain(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'command(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> Group: ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'group(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> Group: + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + inner = old_callback(value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv # type: ignore[return-value] + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + """Given a context and a command name, this returns a :class:`Command` + object if it exists or returns ``None``. + """ + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> list[str]: + """Returns a list of subcommand names in the order they should appear.""" + return sorted(self.commands) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx._protected_args = rest + ctx.args = [] + elif rest: + ctx._protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx._protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx._protected_args, *ctx.args] + ctx.args = [] + ctx._protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: list[str] + ) -> tuple[str | None, Command | None, list[str]]: + cmd_name = make_str(args[0]) + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if _split_opt(cmd_name)[0]: + self.parse_args(ctx, args) + raise NoSuchCommand(cmd_name, possibilities=self.commands, ctx=ctx) + return cmd_name if cmd else None, cmd, args[1:] + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class _MultiCommand(Group, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Group`` instead. + """ + + +class CommandCollection(Group): + """A :class:`Group` that looks up subcommands on other groups. If a command + is not found on this group, each registered source is checked in order. + Parameters on a source are not added to this group, and a source's callback + is not invoked when invoking its commands. In other words, this "flattens" + commands in many groups into this one group. + + :param name: The name of the group command. + :param sources: A list of :class:`Group` objects to look up commands from. + :param kwargs: Other arguments passed to :class:`Group`. + + .. versionchanged:: 8.2 + This is a subclass of ``Group``. Commands are looked up first on this + group, then each of its sources. + """ + + sources: list[Group] + + def __init__( + self, + name: str | None = None, + sources: list[Group] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + #: The list of registered groups. + self.sources = sources or [] + + def add_source(self, group: Group) -> None: + """Add a group as a source of commands.""" + self.sources.append(group) + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + rv = super().get_command(ctx, cmd_name) + + if rv is not None: + return rv + + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_nested_chain(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> list[str]: + rv: set[str] = set(super().list_commands(ctx)) + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: cabc.Iterable[V]) -> cabc.Iterator[V]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter(ABC): + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The latter is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: environment variable(s) that are used to provide a default value for + this parameter. This can be a string or a sequence of strings. If a sequence is + given, only the first non-empty environment variable is used for the parameter. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the argument is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. A deprecated parameter + cannot be required, a ValueError will be raised otherwise. + + .. versionchanged:: 8.2.0 + Introduction of ``deprecated``. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + name: str + opts: list[str] + secondary_opts: list[str] + # `Parameter.type` is annotated in `__init__` to avoid confusing mypy + required: bool + callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None + nargs: int + multiple: bool + expose_value: bool + default: t.Any | t.Callable[[], t.Any] | None + _default_explicit: bool + is_eager: bool + metavar: str | None + envvar: str | cabc.Sequence[str] | None + _custom_shell_complete: ( + t.Callable[[Context, Parameter, str], list[CompletionItem] | list[str]] | None + ) + deprecated: bool | str + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + type: types.ParamType[t.Any] | t.Any | None = None, + required: bool = False, + # XXX The default historically embed two concepts: + # - the declaration of a Parameter object carrying the default (handy to + # arbitrage the default value of coupled Parameters sharing the same + # self.name, like flag options), + # - and the actual value of the default. + # It is confusing and is the source of many issues discussed in: + # https://github.com/pallets/click/pull/3030 + # In the future, we might think of splitting it in two, not unlike + # Option.is_flag and Option.flag_value: we could have something like + # Parameter.is_default and Parameter.default_value. + default: t.Any | t.Callable[[], t.Any] | None = UNSET, + callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None = None, + nargs: int | None = None, + multiple: bool = False, + metavar: str | None = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: str | cabc.Sequence[str] | None = None, + shell_complete: t.Callable[ + [Context, Parameter, str], list[CompletionItem] | list[str] + ] + | None = None, + deprecated: bool | str = False, + ) -> None: + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type: types.ParamType[t.Any] = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default = default + # Whether the user passed ``default`` explicitly to the constructor. + # Captured before any auto-derived default (like ``False`` for boolean + # flags in :class:`Option`) replaces the :data:`UNSET` sentinel, so it + # remains ``False`` when the default was inferred rather than chosen. + # Refs: https://github.com/pallets/click/issues/3403 + self._default_explicit = default is not UNSET + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + self.deprecated = deprecated + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + if required and deprecated: + raise ValueError( + f"The {self.param_type_name} '{self.human_readable_name}' " + "is deprecated and still required. A deprecated " + f"{self.param_type_name} cannot be required." + ) + + @staticmethod + def _hide_unset(value: t.Any) -> t.Any: + """Present the internal :data:`UNSET` sentinel as ``None`` at a boundary that + exposes a parameter's value (introspection, prompts), keeping the sentinel an + implementation detail. + """ + return None if value is UNSET else value + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionchanged:: 8.3.0 + Returns ``None`` for the :attr:`default` if it was not set. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + "default": self._hide_unset(self.default), + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + @abstractmethod + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str, list[str], list[str]]: ... + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(param=self, ctx=ctx) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) + + if value is None and not ctx._default_map_has(self.name): + value = self.default + + if call and callable(value): + value = value() + + return value + + @abstractmethod + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: ... + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, t.Any] + ) -> tuple[t.Any, ParameterSource]: + """Returns the parameter value produced by the parser. + + If the parser did not produce a value from user input, the value is either + sourced from the environment variable, the default map, or the parameter's + default value. In that order of precedence. + + If no value is found, an internal sentinel value is returned. + + :meta private: + """ + # Collect from the parse the value passed by the user to the CLI. + value = opts.get(self.name, UNSET) + # If the value is set, it means it was sourced from the command line by the + # parser, otherwise it left unset by default. + source = ( + ParameterSource.COMMANDLINE + if value is not UNSET + else ParameterSource.DEFAULT + ) + + if value is UNSET: + envvar_value = self.value_from_envvar(ctx) + if envvar_value is not None: + value = envvar_value + source = ParameterSource.ENVIRONMENT + + if value is UNSET: + default_map_value = ctx.lookup_default(self.name) + if default_map_value is not None or ctx._default_map_has(self.name): + value = default_map_value + source = ParameterSource.DEFAULT_MAP + + # A string from default_map must be split for multi-value + # parameters, matching value_from_envvar behavior. + if isinstance(value, str) and self.nargs != 1: + value = self.type.split_envvar_value(value) + + if value is UNSET: + default_value = self.get_default(ctx) + if default_value is not UNSET: + value = default_value + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the parameter's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + if self.multiple or self.nargs == -1: + return () + else: + return value + + def check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + try: + return _check_iter(value) + except TypeError: + # This should only happen when passing in args manually, + # the parser should construct an iterable when parsing + # the command line. + raise BadParameter( + _("Value must be an iterable."), ctx=ctx, param=self + ) from None + + # Define the conversion function based on nargs and type. + + if self.nargs == 1 or self.type.is_composite: + + def convert(value: t.Any) -> t.Any: + return self.type(value, param=self, ctx=ctx) + + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + """A value is considered missing if: + + - it is :attr:`UNSET`, + - or if it is an empty sequence while the parameter is suppose to have + non-single value (i.e. :attr:`nargs` is not ``1`` or :attr:`multiple` is + set). + + :meta private: + """ + if value is UNSET: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + """Process the value of this parameter: + + 1. Type cast the value using :meth:`type_cast_value`. + 2. Check if the value is missing (see: :meth:`value_is_missing`), and raise + :exc:`MissingParameter` if it is required. + 3. If a :attr:`callback` is set, call it to have the value replaced by the + result of the callback. If the value was not set, the callback receive + ``None``. This keep the legacy behavior as it was before the introduction of + the :attr:`UNSET` sentinel. + + :meta private: + """ + # shelter `type_cast_value` from ever seeing an `UNSET` value by handling the + # cases in which `UNSET` gets special treatment explicitly at this layer + # + # Refs: + # https://github.com/pallets/click/issues/3069 + if value is UNSET: + if self.multiple or self.nargs == -1: + value = () + else: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + # Legacy case: UNSET is not exposed directly to the callback, but converted + # to None. + if value is UNSET: + value = None + + # Search for parameters with UNSET values in the context. + unset_keys = {k: None for k, v in ctx.params.items() if v is UNSET} + # No UNSET values, call the callback as usual. + if not unset_keys: + value = self.callback(ctx, self, value) + + # Legacy case: provide a temporarily manipulated context to the callback + # to hide UNSET values as None. + # + # Refs: + # https://github.com/pallets/click/issues/3136 + # https://github.com/pallets/click/pull/3137 + else: + # Add another layer to the context stack to clearly hint that the + # context is temporarily modified. + with ctx: + # Update the context parameters to replace UNSET with None. + ctx.params.update(unset_keys) + # Feed these fake context parameters to the callback. + value = self.callback(ctx, self, value) + # Restore the UNSET values in the context parameters. + ctx.params.update( + { + k: UNSET + for k in unset_keys + # Only restore keys that are present and still None, in case + # the callback modified other parameters. + if k in ctx.params and ctx.params[k] is None + } + ) + + return value + + def resolve_envvar_value(self, ctx: Context) -> str | None: + """Returns the value found in the environment variable(s) attached to this + parameter. + + Environment variables values are `always returned as strings + `_. + + This method returns ``None`` if: + + - the :attr:`envvar` property is not set on the :class:`Parameter`, + - the environment variable is not found in the environment, + - the variable is found in the environment but its value is empty (i.e. the + environment variable is present but has an empty string). + + If :attr:`envvar` is setup with multiple environment variables, + then only the first non-empty value is returned. + + .. caution:: + + The raw value extracted from the environment is not normalized and is + returned as-is. Any normalization or reconciliation is performed later by + the :class:`Parameter`'s :attr:`type`. + + :meta private: + """ + if not self.envvar: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + # Return the first non-empty value of the list of environment variables. + if rv: + return rv + # Else, absence of value is interpreted as an environment variable that + # is not set, so proceed to the next one. + + return None + + def value_from_envvar(self, ctx: Context) -> str | cabc.Sequence[str] | None: + """Process the raw environment variable string for this parameter. + + Returns the string as-is or splits it into a sequence of strings if the + parameter is expecting multiple values (i.e. its :attr:`nargs` property is set + to a value other than ``1``). + + :meta private: + """ + rv = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + return self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: cabc.Mapping[str, t.Any], args: list[str] + ) -> tuple[t.Any, list[str]]: + """Process the value produced by the parser from user input. + + Always process the value through the Parameter's :attr:`type`, wherever it + comes from. + + If the parameter is deprecated, this method warn the user about it. But only if + the value has been explicitly set by the user (and as such, is not coming from + a default). + + :meta private: + """ + # Capture the slot's existing state before we mutate + # ``_parameter_source`` so the write decision below can compare our + # incoming source against the source of the option that already wrote + # the slot (if any). + existing_value = ctx.params.get(self.name, UNSET) + existing_source = ctx.get_parameter_source(self.name) + existing_default_explicit = ctx._param_default_explicit.get(self.name, False) + + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + + # Record the source before processing so eager callbacks and type + # conversion can inspect it. Restored after arbitration if this + # option loses a feature-switch group. + ctx.set_parameter_source(self.name, source) + + # Display a deprecation warning if necessary. + if ( + self.deprecated + and value is not UNSET + and source < ParameterSource.DEFAULT_MAP + ): + message = _( + "DeprecationWarning: The {param_type} {name!r} is deprecated." + "{extra_message}" + ).format( + param_type=self.param_type_name, + name=self.human_readable_name, + extra_message=_format_deprecated_suffix(self.deprecated), + ) + echo(style(message, fg="red"), err=True) + + # Process the value through the parameter's type. + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + # In resilient parsing mode, we do not want to fail the command if the + # value is incompatible with the parameter type, so we reset the value + # to UNSET, which will be interpreted as a missing value. + value = UNSET + + # Arbitrate the slot when several parameters target the same variable + # name (feature-switch groups). See: https://github.com/pallets/click/issues/3403 + slot_empty = existing_value is UNSET + more_explicit = existing_source is not None and source < existing_source + same_source = existing_source is not None and source == existing_source + auto_would_downgrade_explicit = ( + same_source + and source == ParameterSource.DEFAULT + and existing_default_explicit + and not self._default_explicit + ) + is_winner = ( + slot_empty + or more_explicit + or (same_source and not auto_would_downgrade_explicit) + ) + + if is_winner: + if self.expose_value: + ctx.params[self.name] = value + ctx._param_default_explicit[self.name] = self._default_explicit + elif existing_source is not None: + # Lost arbitration; restore the winning option's source. + ctx.set_parameter_source(self.name, existing_source) + # else: ctx.params[self.name] was populated by code that bypassed + # handle_parse_result (from another option's callback for example). Keep + # the provisional source recorded before process_value so downstream + # lookups don't return ``None``. + + return value, args + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + return None + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [] + + def get_error_hint(self, ctx: Context | None) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + + .. versionchanged:: 8.4.0 + ``ctx`` can be ``None``. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType[t.Any].shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast("list[CompletionItem]", results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page and error messages. + Normally, environment variables are not shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. A deprecated option cannot be + prompted. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + :param attrs: Other command arguments described in :class:`Parameter`. + + .. versionchanged:: 8.4.0 + Non-basic ``flag_value`` types (not ``str``, ``int``, ``float``, or + ``bool``) are passed through unchanged instead of being stringified. + Previously, ``type=click.UNPROCESSED`` was required to preserve them. + + .. versionchanged:: 8.2 + ``envvar`` used with ``flag_value`` will always use the ``flag_value``, + previously it would use the value of the environment variable. + + .. versionchanged:: 8.1 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given, for basic Python + types (``str``, ``int``, ``float``, ``bool``). + """ + + param_type_name = "option" + + prompt: str | None + confirmation_prompt: bool | str + prompt_required: bool + hide_input: bool + hidden: bool + + _flag_needs_value: bool + is_flag: bool + flag_value: t.Any + type: types.ParamType[t.Any] + default: t.Any | t.Callable[[], t.Any] | None + + count: bool + allow_from_autoenv: bool + help: str | None + show_default: bool | str | None + show_choices: bool + show_envvar: bool + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + show_default: bool | str | None = None, + prompt: bool | str = False, + confirmation_prompt: bool | str = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: bool | None = None, + flag_value: t.Any = UNSET, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: types.ParamType[t.Any] | t.Any | None = None, + help: str | None = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + deprecated: bool | str = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + super().__init__( + param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs + ) + + # Phase 1: prompt-related attributes. ``_infer_flag_kind`` reads ``self.prompt`` + # and ``self.prompt_required`` so this must run first. + if prompt is True: + if not self.name: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + if deprecated: + label = _format_deprecated_label(deprecated) + help = f"{help} {label}" if help else label + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # Phase 2: flag-kind inference. + self.is_flag, self._flag_needs_value = self._infer_flag_kind( + is_flag, flag_value + ) + + # Phase 3: type inference. Override the type set by :meth:`Parameter.__init__` + # when this option is a flag or a count. + self.type = self._pick_type(type, flag_value, count, self.is_flag) + + # Phase 4: store the raw ``flag_value`` and ``count`` settings. + # ``self.flag_value`` and ``self.default`` deliberately keep the :data:`UNSET` + # sentinel when the user didn't pass them. Auto-derived values are resolved + # lazily in :meth:`_resolve_lazy_default` and :attr:`flag_activation_value`. + # Keeping the raw values means ``is UNSET`` reliably answers "did the user pass + # this?": #3403 needs it for arbitration, and any future feature needing the + # same distinction can reuse it without reintroducing parallel "was it + # explicit?" tracking. + self.flag_value = flag_value + self.count = count + if count and self.default is UNSET: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + # Phase 5: validate. Raises on illegal kwarg combinations. + self._validate(prompt, deprecated) + + @property + def is_bool_flag(self) -> bool: + """``True`` when this option is a flag with a boolean type. + + Derived from :attr:`is_flag` and :attr:`type`; computed on access so it cannot + drift if a subclass replaces :attr:`type` after construction. + """ + return self.is_flag and isinstance(self.type, types.BoolParamType) + + @property + def flag_activation_value(self) -> t.Any: + """Value the function receives when this flag is activated on the command line. + + Resolves a missing :attr:`flag_value` to ``True`` for actual flag options and + ``None`` otherwise. Used by the parser bridge (:meth:`add_to_parser`) and the + runtime (:meth:`consume_value`) so :attr:`flag_value` can keep the :data:`UNSET` + sentinel for "did the user pass one?" introspection. + """ + if self.flag_value is UNSET: + return True if self.is_flag else None + return self.flag_value + + def _infer_flag_kind( + self, is_flag: bool | None, flag_value: t.Any + ) -> tuple[bool, bool]: + """Resolve ``is_flag`` and the parser hint ``_flag_needs_value``. + + Returns ``(is_flag, flag_needs_value)``, where ``_flag_needs_value`` tells the + parser this option is a flag that cannot be used standalone and needs a value. + The parser uses it to decide whether to treat the next CLI token as the flag's + value or as a new option. If ``prompt`` is enabled with + ``prompt_required=False``, it opens the door for an interactive value, hence the + initial condition. Ref: https://github.com/pallets/click/issues/3084 + """ + needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + # Implicitly a flag because flag_value was set. + if flag_value is not UNSET: + return True, needs_value + # Not a flag, but when used as a flag it shows a prompt. + if needs_value: + return False, needs_value + # Implicitly a flag because secondary options names were given. + if self.secondary_opts: + return True, needs_value + return False, needs_value + + if is_flag is False and not needs_value: + # Explicit ``is_flag=False`` with a flag-like value/default still makes the + # option flag-shaped to the parser. + needs_value = flag_value is not UNSET or self.default is UNSET + + return bool(is_flag), needs_value + + def _pick_type( + self, + type_arg: t.Any, + flag_value: t.Any, + count: bool, + is_flag: bool, + ) -> types.ParamType[t.Any]: + """Pick the final :class:`ParamType` for this option. + + :meth:`Parameter.__init__` already stored ``self.type`` from the explicit + ``type`` argument or from ``default``. This method either returns that as-is, or + overrides it for flag and count options (which are inferred from ``flag_value`` + rather than ``default``). + """ + if type_arg is not None: + return self.type + + if count: + return types.IntRange(min=0) + + if not is_flag: + return self.type + + # A flag without a flag_value is a boolean flag. + if flag_value is UNSET or isinstance(flag_value, bool): + return types.BoolParamType() + + guessed: types.ParamType[t.Any] = types.convert_type(None, flag_value) + if ( + isinstance(guessed, types.StringParamType) + and not isinstance(flag_value, str) + and flag_value is not None + ): + # The flag_value type couldn't be auto-detected (not str, int, float, or + # bool). Since flag_value is a programmer-provided Python object, not CLI + # input, pass it through unchanged instead of stringifying it. + return types.UNPROCESSED + return guessed + + def _resolve_lazy_default(self, value: t.Any) -> t.Any: + """Apply lazy auto-derivations to a default-style value. + + Shared between :meth:`get_default` (the runtime path) and :meth:`to_info_dict` + (the introspection path) so the two views cannot drift apart. Callables are + *not* invoked here: that is :meth:`get_default`'s responsibility. Rules: + + * ``UNSET`` resolves to ``False`` for a non-required boolean flag, and to ``()`` + for a non-required, non-prompted multi flag. + * ``True`` resolves to :attr:`flag_value` for a non-boolean flag (the "activate + this flag by default" shorthand). Boolean flags keep ``True`` as a literal. + """ + if value is UNSET and self.is_flag: + if self.multiple and not self.required and not self.prompt: + return () + if self.is_bool_flag and not self.required: + return False + if value is True and self.is_flag and not self.is_bool_flag: + # Use ``flag_activation_value`` so an unset ``flag_value`` resolves to + # ``True`` (the bool-flag activation value) rather than leaking the + # :data:`UNSET` sentinel. + return self.flag_activation_value + return value + + def _validate(self, prompt: bool | str, deprecated: bool | str) -> None: + """Raise :class:`TypeError` / :class:`ValueError` on illegal kwarg combinations. + + Called once, after every other attribute has been assigned, so each check can + read the final state. + """ + if not __debug__: + return + if deprecated and prompt: + raise ValueError("`deprecated` options cannot use `prompt`.") + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError("'prompt' with 'hide_input' is not valid for boolean flag.") + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + def to_info_dict(self) -> dict[str, t.Any]: + """ + .. versionchanged:: 8.5.0 + ``default`` and ``flag_value`` reflect the auto-derived values (``False`` + for unset boolean-flag defaults, ``True`` for unset boolean-flag activation + values, etc.) when no explicit value was passed, matching what the function + would receive at call time. + + .. versionchanged:: 8.3.0 + Returns ``None`` for the :attr:`flag_value` if it was not set. + """ + info_dict = super().to_info_dict() + info_dict.update( + default=self._hide_unset(self._resolve_lazy_default(self.default)), + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_activation_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + """Return the default value for this option. + + Several auto-derived defaults are resolved lazily here rather than eagerly in + :meth:`__init__`. This keeps :attr:`default` raw at construction time, so + ``self.default is UNSET`` reliably answers "did the user pass a default?" for + feature-switch-group arbitration and for anything else that needs to distinguish + "absent" from a chosen value. The resolution rules live in + :meth:`_resolve_lazy_default`. + + .. versionchanged:: 8.5.0 + ``UNSET`` defaults for boolean and multi flags are now resolved here instead + of being coerced in :meth:`__init__`. Reading :attr:`default` directly + returns the user-supplied value (or ``UNSET`` if none was passed) rather + than the auto-derived one. + + .. versionchanged:: 8.3.3 + ``default=True`` is no longer substituted with ``flag_value`` for boolean + flags, fixing negative boolean flags like + ``flag_value=False, default=True``. + """ + raw = super().get_default(ctx, call=False) + value = self._resolve_lazy_default(raw) + # Only invoke the value as a callable when the lazy resolver passed it through + # unchanged. If the resolver substituted ``True`` -> :attr:`flag_value`, the + # result is the programmer-supplied ``flag_value`` (often a class or enum), + # which must NOT be instantiated here. See + # https://github.com/pallets/click/issues/3121. + if value is raw and call and callable(value): + value = value() + return value + + def get_error_hint(self, ctx: Context | None) -> str: + result = super().get_error_hint(ctx) + if self.show_envvar and self.envvar is not None: + result += f" (env var: '{self.envvar}')" + return result + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str, list[str], list[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(_("Name '{name}' defined twice").format(name=name)) + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(_split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + _( + "Boolean option {decl!r} cannot use the" + " same flag for true/false." + ).format(decl=decl) + ) + else: + possible_names.append(_split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return "", opts, secondary_opts + raise TypeError( + _( + "Could not determine name for option with declarations {decls!r}" + ).format(decls=decls) + ) + + if not opts and not secondary_opts: + raise TypeError( + _( + "No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + " you mean to pass '--{name}'?" + ).format(name=name) + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + # ``flag_activation_value`` resolves UNSET to the right parser-store + # constant (``True`` for bool flags) so the raw :attr:`flag_value` + # can keep the sentinel. + const=self.flag_activation_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: cabc.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar(ctx=ctx)}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + + extra = self.get_help_extra(ctx) + extra_items = [] + if "envvars" in extra: + extra_items.append( + _("env var: {var}").format(var=", ".join(extra["envvars"])) + ) + if "default" in extra: + extra_items.append(_("default: {default}").format(default=extra["default"])) + if "range" in extra: + extra_items.append(extra["range"]) + if "required" in extra: + extra_items.append(_(extra["required"])) + + if extra_items: + extra_str = "; ".join(extra_items) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: + extra: types.OptionHelpExtra = {} + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + if isinstance(envvar, str): + extra["envvars"] = (envvar,) + else: + extra["envvars"] = tuple(str(d) for d in envvar) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or ( + show_default and (default_value not in (None, UNSET)) + ): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif isinstance(default_value, enum.Enum): + default_string = default_value.name + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = _split_opt( + (self.opts if default_value else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + elif isinstance(default_value, str) and default_value == "": + default_string = '""' + else: + default_string = str(default_value) + + if default_string: + extra["default"] = default_string + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra["range"] = range_str + + if self.required: + extra["required"] = "required" + + return extra + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to lock in the value before + # attempting any user interaction. + default = self.get_default(ctx) + + # A boolean flag can use a simplified [y/n] confirmation prompt. + if self.is_bool_flag: + # If we have no boolean default, we force the user to explicitly provide + # one. + if default in (UNSET, None): + default = None + # Nothing prevent you to declare an option that is simultaneously: + # 1) auto-detected as a boolean flag, + # 2) allowed to prompt, and + # 3) still declare a non-boolean default. + # This forced casting into a boolean is necessary to align any non-boolean + # default to the prompt, which is going to be a [y/n]-style confirmation + # because the option is still a boolean flag. That way, instead of [y/n], + # we get [Y/n] or [y/N] depending on the truthy value of the default. + # Refs: https://github.com/pallets/click/pull/3030#discussion_r2289180249 + else: + default = bool(default) + return confirm(self.prompt, default) + + # If show_default is given, provide this to `prompt` as well, + # otherwise we use `prompt`'s default behavior + prompt_kwargs: t.Any = {} + if self.show_default is not None: + prompt_kwargs["show_default"] = self.show_default + + return prompt( + self.prompt, + # Use ``None`` to inform the prompt() function to reiterate until a valid + # value is provided by the user if we have no default. + default=self._hide_unset(default), + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + **prompt_kwargs, + ) + + def resolve_envvar_value(self, ctx: Context) -> str | None: + """:class:`Option` resolves its environment variable the same way as + :func:`Parameter.resolve_envvar_value`, but it also supports + :attr:`Context.auto_envvar_prefix`. If we could not find an environment from + the :attr:`envvar` property, we fallback on :attr:`Context.auto_envvar_prefix` + to build dynamiccaly the environment variable name using the + :python:`{ctx.auto_envvar_prefix}_{self.name.upper()}` template. + + :meta private: + """ + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if self.allow_from_autoenv and ctx.auto_envvar_prefix is not None and self.name: + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any: + """For :class:`Option`, this method processes the raw environment variable + string the same way as :func:`Parameter.value_from_envvar` does. + + But in the case of non-boolean flags, the value is analyzed to determine if the + flag is activated or not, and returns a boolean of its activation, or the + :attr:`flag_value` if the latter is set. + + This method also takes care of repeated options (i.e. options with + :attr:`multiple` set to ``True``). + + :meta private: + """ + rv = self.resolve_envvar_value(ctx) + + # Absent environment variable or an empty string is interpreted as unset. + if rv is None: + return None + + # Non-boolean flags are more liberal in what they accept. But a flag being a + # flag, its envvar value still needs to be analyzed to determine if the flag is + # activated or not. + if self.is_flag and not self.is_bool_flag: + # An exact match against ``flag_value`` (a non-bool flag always has one + # explicitly set) returns it directly. Otherwise the value is analyzed as a + # boolean: a truthy reading activates the flag and the function receives + # ``flag_value``; a falsy reading produces ``False``; an unrecognized + # reading falls through as ``None``. Folding the substitution here means + # :meth:`consume_value` no longer has to repeat it in a source-checked + # branch. + if rv == self.flag_value: + return self.flag_value + parsed = types.BoolParamType.str_to_bool(rv) + if parsed is None: + return None + return self.flag_value if parsed else False + + # Split the envvar value if it is allowed to be repeated. + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0: + multi_rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + multi_rv = batch(multi_rv, self.nargs) # type: ignore[assignment] + + return multi_rv + + return rv + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, Parameter] + ) -> tuple[t.Any, ParameterSource]: + """For :class:`Option`, the value can be collected from an interactive prompt + if the option is a flag that needs a value (and the :attr:`prompt` property is + set). + + Additionally, this method handles flag option that are activated without a + value, in which case the :attr:`flag_value` is returned. + + :meta private: + """ + value, source = super().consume_value(ctx, opts) + + # The parser emits a sentinel when a flag is allowed to be used without a value. + # Resolve it to a prompt or to the activation value depending on the option's + # configuration. + if value is FLAG_NEEDS_VALUE: + # If the option allows for a prompt, start an interaction with the user. + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + # Else the flag takes its activation value (resolves UNSET). + else: + value = self.flag_activation_value + source = ParameterSource.COMMANDLINE + + # Re-interpret a multiple option that the parser sent through as a list still + # containing the FLAG_NEEDS_VALUE sentinel, replacing each occurrence with the + # activation value. + elif ( + self.multiple + and value is not UNSET + and isinstance(value, cabc.Iterable) + and source < ParameterSource.DEFAULT_MAP + and any(v is FLAG_NEEDS_VALUE for v in value) + ): + value = [ + self.flag_activation_value if v is FLAG_NEEDS_VALUE else v + for v in value + ] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt for one to the user + # if prompting is enabled. + elif ( + (value is UNSET or source >= ParameterSource.DEFAULT_MAP) + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + # process_value has to be overridden on Options in order to capture + # `value == UNSET` cases before `type_cast_value()` gets called. + # + # Refs: + # https://github.com/pallets/click/issues/3069 + if self.is_flag and not self.required and self.is_bool_flag and value is UNSET: + value = False + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + # in the normal case, rely on Parameter.process_value + return super().process_value(ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the constructor of :class:`Parameter`. + + :param help: the help string. + + .. versionchanged:: 8.5.0 + Added the ``help`` parameter. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: cabc.Sequence[str], + required: bool | None = None, + help: str | None = None, + **attrs: t.Any, + ) -> None: + # Auto-detect the requirement status of the argument if not explicitly set. + if required is None: + # The argument gets automatically required if it has no explicit default + # value set and is setup to match at least one value. + if attrs.get("default", UNSET) is UNSET: + required = attrs.get("nargs", 1) > 0 + # If the argument has a default value, it is not required. + else: + required = False + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + deprecated = attrs.get("deprecated", False) + + if help: + help = inspect.cleandoc(help) + + if deprecated: + label = _format_deprecated_label(deprecated) + help = f"{help} {label}" if help else label + + self.help = help + + super().__init__(param_decls, required=required, **attrs) + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(help=self.help) + return info_dict + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(param=self, ctx=ctx) + if not var: + var = self.name.upper() + # Types like ``Choice`` and ``DateTime`` already surround their metavar + # with square brackets to enumerate the allowed values. Reuse those + # outer brackets as the optional-argument indicator instead of wrapping + # the metavar in a second pair, which would produce ``[[a|b|c]]``. + already_bracketed = var.startswith("[") and var.endswith("]") + if self.deprecated: + var += "!" + if not self.required and not already_bracketed: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str, list[str], list[str]]: + if not decls: + if not expose_value: + return "", [], [] + raise TypeError("Argument is marked as exposed, but does not have a name.") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + _( + "Arguments take exactly one parameter declaration, got" + " {length}: {decls}." + ).format(length=len(decls), decls=decls) + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [self.make_metavar(ctx)] + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + if self.help is None: + return None + + return self.make_metavar(ctx), self.help + + def get_error_hint(self, ctx: Context | None) -> str: + if ctx is not None: + return f"'{self.make_metavar(ctx)}'" + return f"'{self.human_readable_name}'" + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + raise AttributeError(name) diff --git a/source/target-vendors/cp312/click/decorators.py b/source/target-vendors/cp312/click/decorators.py new file mode 100644 index 0000000..cc42e5d --- /dev/null +++ b/source/target-vendors/cp312/click/decorators.py @@ -0,0 +1,627 @@ +from __future__ import annotations + +import inspect +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") +T = t.TypeVar("T") +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound="_AnyCallable | Command") + + +def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + + +def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def make_pass_decorator( + object_type: type[T], ensure: bool = False +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + + obj: T | None + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: str | None = None +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +# variant: no call, directly as decorator for a function. +@t.overload +def command(name: _AnyCallable) -> Command: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) +@t.overload +def command( + name: str | None, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) +@t.overload +def command( + name: None = None, + *, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: ... + + +def command( + name: str | _AnyCallable | None = None, + cls: type[CmdType] | None = None, + **attrs: t.Any, +) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function, converted to + lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes + ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, + ``init_data_command`` becomes ``init-data``. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: The name of the command. Defaults to modifying the function's + name as described above. + :param cls: The command class to create. Defaults to :class:`Command`. + + .. versionchanged:: 8.2 + The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are + removed when generating the name. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Callable[[_AnyCallable], t.Any] | None = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = t.cast("type[CmdType]", Command) + + def decorator(f: _AnyCallable) -> CmdType: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + if t.TYPE_CHECKING: + assert cls is not None + assert not callable(name) + + if name is not None: + cmd_name = name + else: + cmd_name = f.__name__.lower().replace("_", "-") + cmd_left, sep, suffix = cmd_name.rpartition("-") + + if sep and suffix in {"command", "cmd", "group", "grp"}: + cmd_name = cmd_left + + cmd = cls(name=cmd_name, callback=f, params=params, **attrs) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +GrpType = t.TypeVar("GrpType", bound=Group) + + +# variant: no call, directly as decorator for a function. +@t.overload +def group(name: _AnyCallable) -> Group: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) +@t.overload +def group( + name: str | None, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) +@t.overload +def group( + name: None = None, + *, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: ... + + +def group( + name: str | _AnyCallable | None = None, + cls: type[GrpType] | None = None, + **attrs: t.Any, +) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if cls is None: + cls = t.cast("type[GrpType]", Group) + + if callable(name): + return command(cls=cls, **attrs)(name) + + return command(name, cls, **attrs) + + +def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument( + *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default argument class, refer to :class:`Argument` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Argument + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def option( + *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default option class, refer to :class:`Option` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Option + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", _("Do you want to continue?")) + kwargs.setdefault("help", _("Confirm the action without prompting.")) + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: str | None = None, + *param_decls: str, + package_name: str | None = None, + prog_name: str | None = None, + message: str | None = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. If the detected (or given) name does + not match an installed distribution, Click resolves it as an import + (top-level module) name via + :func:`importlib.metadata.packages_distributions`, so e.g. ``PIL`` + resolves to the ``Pillow`` distribution. + + .. note:: + The parameters and message variables accepted by this option are + frozen: no new slots will be added, to keep the common case simple + and predictable. If you need values it does not expose, such as a + file path, the Python version, or git metadata, use + :func:`custom_version_option` to render the output yourself. + + Rationale: `discussion #3527 + `_. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + + .. versionchanged:: 8.4.2 + When ``package_name`` does not match an installed distribution, + Click now resolves it as an import (top-level module). + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + nonlocal package_name + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + import importlib.metadata + + try: + version = importlib.metadata.version(package_name) + except importlib.metadata.PackageNotFoundError: + # The given name didn't match an installed distribution. + # Try resolving it as an import (top-level module) name, + # e.g. ``PIL`` is provided by the ``Pillow`` distribution. + distributions = importlib.metadata.packages_distributions().get( + package_name, [] + ) + if len(distributions) == 1: + package_name = distributions[0] + version = importlib.metadata.version(package_name) + elif len(distributions) > 1: + raise RuntimeError( + f"{package_name!r} maps to multiple installed" + f" distributions ({', '.join(distributions)})." + " Pass 'package_name' to disambiguate." + ) from None + else: + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + message % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def custom_version_option( + callback: t.Callable[[Context], str], + *param_decls: str, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option whose output is produced by ``callback``. + + This is the customizable companion to :func:`version_option`. Where + :func:`version_option` is intentionally limited to a fixed message and + a small set of values, this option calls ``callback`` to build the + whole string to print. Use it when you need values that + :func:`version_option` does not expose, such as a file path, the + Python version, or git metadata. + + :param callback: Called with the current :class:`Context` when the + option is invoked. Its return value is printed, then the program + exits. + :param param_decls: One or more option names. Defaults to the single + value ``--version``. + :param kwargs: Extra arguments are passed to :func:`option`. + + .. versionadded:: 8.5.0 + """ + + def show_version(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + echo(callback(ctx), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = show_version + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Pre-configured ``--help`` option which immediately prints the help page + and exits the program. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def show_help(ctx: Context, param: Parameter, value: bool) -> None: + """Callback that print the help page on ```` and exits.""" + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs.setdefault("callback", show_help) + + return option(*param_decls, **kwargs) diff --git a/source/target-vendors/cp312/click/exceptions.py b/source/target-vendors/cp312/click/exceptions.py new file mode 100644 index 0000000..6272c38 --- /dev/null +++ b/source/target-vendors/cp312/click/exceptions.py @@ -0,0 +1,378 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .globals import resolve_color_default +from .utils import echo +from .utils import format_filename + +if t.TYPE_CHECKING: + from .core import Command + from .core import Context + from .core import Parameter + + +def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +def _format_possibilities(possibilities: list[str]) -> str: + possibility_str = ", ".join(repr(p) for p in sorted(possibilities)) + return ngettext( + "Did you mean {possibility}?", + "(Did you mean one of: {possibilities}?)", + len(possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code: t.ClassVar[int] = 1 + + show_color: t.Final[bool | None] + message: t.Final[str] + + def __init__(self, message: str) -> None: + super().__init__(message) + # The context will be removed by the time we print the message, so cache + # the color settings here to be used later on (in `show`) + self.show_color = resolve_color_default() + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=self.show_color, + ) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code: t.ClassVar[int] = 2 + + ctx: Context | None + cmd: t.Final[Command | None] + + def __init__(self, message: str, ctx: Context | None = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd = self.ctx.command if self.ctx else None + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + help_names = self.ctx.command.get_help_option_names(self.ctx) + # Pick the longest name (like ``--help`` over ``-h``) for + # readability in error messages. + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, + option=max(help_names, key=len), + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + param: Parameter | None + param_hint: cabc.Sequence[str] | str | None + + def __init__( + self, + message: str, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: cabc.Sequence[str] | str | None = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + param_type: t.Final[str | None] + + def __init__( + self, + message: str | None = None, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: cabc.Sequence[str] | str | None = None, + param_type: str | None = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: cabc.Sequence[str] | str | None = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message( + param=self.param, ctx=self.ctx + ) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if Click attempted to handle an option that does not exist. + + .. versionadded:: 4.0 + """ + + option_name: t.Final[str] + possibilities: t.Final[list[str] | None] + + def __init__( + self, + option_name: str, + message: str | None = None, + possibilities: cabc.Iterable[str] | None = None, + ctx: Context | None = None, + ) -> None: + if message is None: + message = _("No such option {name!r}.").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + + if possibilities: + from difflib import get_close_matches + + possibilities_ = get_close_matches(option_name, possibilities) + else: + possibilities_ = None + self.possibilities = possibilities_ + + def format_message(self) -> str: + if not self.possibilities: + return self.message + return f"{self.message} {_format_possibilities(self.possibilities)}" + + +class NoSuchCommand(UsageError): + """Raised if Click attempted to handle a command that does not exist. + + .. versionadded:: 8.4.0 + """ + + command_name: t.Final[str] + possibilities: t.Final[list[str] | None] + + def __init__( + self, + command_name: str, + message: str | None = None, + possibilities: cabc.Iterable[str] | None = None, + ctx: Context | None = None, + ) -> None: + if message is None: + message = _("No such command {name!r}.").format(name=command_name) + + super().__init__(message, ctx) + self.command_name = command_name + + if possibilities: + from difflib import get_close_matches + + possibilities_ = get_close_matches(command_name, possibilities) + else: + possibilities_ = None + self.possibilities = possibilities_ + + def format_message(self) -> str: + if not self.possibilities: + return self.message + return f"{self.message} {_format_possibilities(self.possibilities)}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + option_name: t.Final[str] + + def __init__( + self, option_name: str, message: str, ctx: Context | None = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class NoArgsIsHelpError(UsageError): + ctx: Context + + def __init__(self, ctx: Context) -> None: + super().__init__(ctx.get_help(), ctx=ctx) + + def show(self, file: t.IO[t.Any] | None = None) -> None: + echo(self.format_message(), file=file, err=True, color=self.ctx.color) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + ui_filename: t.Final[str] + filename: t.Final[str] + + def __init__(self, filename: str, hint: str | None = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename = format_filename(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + exit_code: t.Final[int] + + def __init__(self, code: int = 0) -> None: + self.exit_code = code diff --git a/source/target-vendors/cp312/click/formatting.py b/source/target-vendors/cp312/click/formatting.py new file mode 100644 index 0000000..c4aa2de --- /dev/null +++ b/source/target-vendors/cp312/click/formatting.py @@ -0,0 +1,320 @@ +from __future__ import annotations + +import collections.abc as cabc +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import _split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: int | None = None + + +def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: + widths: dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: cabc.Iterable[tuple[str, str]], col_count: int +) -> cabc.Iterator[tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + + .. versionchanged:: 8.4.0 + Width is measured in visible characters. ANSI escape sequences in + ``text``, ``initial_indent``, or ``subsequent_indent`` no longer + count toward the width budget, so styled input wraps based on what + the user sees instead of raw byte length. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: list[tuple[int, bool, str]] = [] + buf: list[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + indent_increment: int + width: int + current_indent: int + buffer: list[str] + + def __init__( + self, + indent_increment: int = 2, + width: int | None = None, + max_width: int | None = None, + ) -> None: + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + import shutil + + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = "{usage} ".format(usage=_("Usage:")) + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if not args: + # Without args, the prefix's trailing space and the wrap_text + # call that would normally place args on the line are both + # unnecessary. Emit just the prefix line. + self.write(usage_prefix.rstrip(" ")) + self.write("\n") + return + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: cabc.Iterable[tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> cabc.Generator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> cabc.Generator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: cabc.Iterable[str]) -> tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = _split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/source/target-vendors/cp312/click/globals.py b/source/target-vendors/cp312/click/globals.py new file mode 100644 index 0000000..a2f9172 --- /dev/null +++ b/source/target-vendors/cp312/click/globals.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import typing as t +from threading import local + +if t.TYPE_CHECKING: + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: t.Literal[False] = False) -> Context: ... + + +@t.overload +def get_current_context(silent: bool = ...) -> Context | None: ... + + +def get_current_context(silent: bool = False) -> Context | None: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: Context) -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: bool | None = None) -> bool | None: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/source/target-vendors/cp312/click/parser.py b/source/target-vendors/cp312/click/parser.py new file mode 100644 index 0000000..4fcbf7c --- /dev/null +++ b/source/target-vendors/cp312/click/parser.py @@ -0,0 +1,533 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" + +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from ._utils import FLAG_NEEDS_VALUE +from ._utils import UNSET +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + from ._utils import T_FLAG_NEEDS_VALUE + from ._utils import T_UNSET + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + + +def _unpack_args( + args: cabc.Sequence[str], nargs_spec: cabc.Sequence[int] +) -> tuple[cabc.Sequence[str | cabc.Sequence[str | T_UNSET] | T_UNSET], list[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with ``UNSET``. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: list[str | tuple[str | T_UNSET, ...] | T_UNSET] = [] + spos: int | None = None + + def _fetch(c: deque[str]) -> str | T_UNSET: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return UNSET + + while nargs_spec: + if spos is None: + nargs = nargs_spec.popleft() + else: + nargs = nargs_spec.pop() + + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x: list[str | T_UNSET] = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(UNSET) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def _split_opt(opt: str) -> tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def _normalize_opt(opt: str, ctx: Context | None) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = _split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +class _Option: + def __init__( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes: set[str] = set() + + for opt in opts: + prefix, value = _split_opt(opt) + if not prefix: + raise ValueError( + _("Invalid start character for option ({option})").format( + option=opt + ) + ) + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: t.Any, state: _ParsingState) -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class _Argument: + def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: str | cabc.Sequence[str | T_UNSET] | T_UNSET, + state: _ParsingState, + ) -> None: + if self.nargs > 1: + assert isinstance(value, cabc.Sequence) + holes = sum(x is UNSET for x in value) + if holes == len(value): + value = UNSET + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + # We failed to collect any argument value so we consider the argument as unset. + if value == (): + value = UNSET + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class _ParsingState: + def __init__(self, rargs: list[str]) -> None: + self.opts: dict[str, t.Any] = {} + self.largs: list[str] = [] + self.rargs = rargs + self.order: list[CoreParameter] = [] + + +class _OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + + .. deprecated:: 8.2 + Will be removed in Click 9.0. + """ + + def __init__(self, ctx: Context | None = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args: bool = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options: bool = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: dict[str, _Option] = {} + self._long_opt: dict[str, _Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: list[_Argument] = [] + + def add_option( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [_normalize_opt(opt, self.ctx) for opt in opts] + option = _Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, obj: CoreArgument, dest: str | None, nargs: int = 1) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(_Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: list[str] + ) -> tuple[dict[str, t.Any], list[str], list[CoreParameter]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = _ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: _ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: _ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: str | None, state: _ParsingState + ) -> None: + if opt not in self._long_opt: + raise NoSuchOption(opt, possibilities=self._long_opt, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = UNSET + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: _ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = _normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = UNSET + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we recombine the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new large. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: _Option, state: _ParsingState + ) -> str | cabc.Sequence[str] | T_UNSET | T_FLAG_NEEDS_VALUE: + nargs = option.nargs + + value: str | cabc.Sequence[str] | T_UNSET | T_FLAG_NEEDS_VALUE + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = FLAG_NEEDS_VALUE + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = FLAG_NEEDS_VALUE + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: _ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = _normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) + + +def __getattr__(name: str) -> object: + import warnings + + if name in { + "OptionParser", + "Argument", + "Option", + "split_opt", + "normalize_opt", + "ParsingState", + }: + warnings.warn( + f"'parser.{name}' is deprecated and will be removed in Click 9.0." + " The old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return globals()[f"_{name}"] + + if name == "split_arg_string": + from .shell_completion import split_arg_string + + warnings.warn( + "Importing 'parser.split_arg_string' is deprecated, it will only be" + " available in 'shell_completion' in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return split_arg_string + + raise AttributeError(name) diff --git a/source/target-vendors/cp312/click/py.typed b/source/target-vendors/cp312/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/click/shell_completion.py b/source/target-vendors/cp312/click/shell_completion.py new file mode 100644 index 0000000..8a2668b --- /dev/null +++ b/source/target-vendors/cp312/click/shell_completion.py @@ -0,0 +1,801 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .utils import echo + + +def shell_complete( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> t.Literal[0, 1]: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + # Write bytes, otherwise Windows text stdout translates LF to CRLF and breaks. + if instruction == "source": + echo(comp.source().encode(), nl=False) + return 0 + + if instruction == "complete": + echo(comp.complete().encode()) + return 0 + + return 1 + + +if t.TYPE_CHECKING: + from typing_extensions import TypeVar + + # `Any` is used as default for backwards compatibility (instead of e.g. `str`) + _ValueT_co = TypeVar("_ValueT_co", covariant=True, default=t.Any) +else: + _ValueT_co = t.TypeVar("_ValueT_co", covariant=True) + + +class CompletionItem(t.Generic[_ValueT_co]): + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: _ValueT_co, + type: str = "plain", + help: str | None = None, + **kwargs: t.Any, + ) -> None: + self.value: _ValueT_co = value + self.type: str = type + self.help: str | None = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +# See ZshComplete.format_completion below, and issue #2703, before +# changing this script. +# +# (TL;DR: _describe is picky about the format, but this Zsh script snippet +# is already widely deployed. So freeze this script, and use clever-ish +# handling of colons in ZshComplet.format_completion.) +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +if [[ $zsh_eval_context[-1] == loadautofunc ]]; then + # autoload from fpath, call function directly + %(complete_func)s "$@" +else + # eval/source/. command, register function for later + compdef %(complete_func)s %(prog_name)s +fi +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + +# Compatible with Windows PowerShell 5.1+ and PowerShell (pwsh) 7+. +# Uses Register-ArgumentCompleter -Native, which receives the command AST +# as parsed by PowerShell. The command text is forwarded verbatim through +# COMP_WORDS so the Python side can reuse the same shlex-based splitting +# used by the bash/zsh completers. +_SOURCE_POWERSHELL = """\ +Register-ArgumentCompleter -Native -CommandName %(prog_name)s -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $prev_complete = $env:%(complete_var)s + $prev_words = $env:COMP_WORDS + $prev_cword = $env:COMP_CWORD + + $env:%(complete_var)s = 'powershell_complete' + $env:COMP_WORDS = $commandAst.ToString() + if ($wordToComplete) { + $env:COMP_CWORD = $commandAst.CommandElements.Count - 1 + } else { + $env:COMP_CWORD = $commandAst.CommandElements.Count + } + + try { + $response = & %(prog_name)s 2>$null + } finally { + $env:%(complete_var)s = $prev_complete + $env:COMP_WORDS = $prev_words + $env:COMP_CWORD = $prev_cword + } + + if (-not $response) { return } + + $prefix = "$wordToComplete*" + $lines = $response -split "`n" + for ($i = 0; $i + 2 -lt $lines.Count; $i += 3) { + $type = $lines[$i] + $value = $lines[$i + 1] + $descr = $lines[$i + 2] + if (-not $type) { continue } + + if ($type -eq 'plain') { + $tip = if ($descr -and $descr -ne '_') { $descr } else { $value } + [System.Management.Automation.CompletionResult]::new( + $value, $value, 'ParameterValue', $tip) + } elseif ($type -eq 'dir') { + Get-ChildItem -Directory -Path $prefix -ErrorAction SilentlyContinue | + ForEach-Object { + [System.Management.Automation.CompletionResult]::new( + $_.FullName, $_.Name, 'ProviderContainer', $_.FullName) + } + } elseif ($type -eq 'file') { + Get-ChildItem -Path $prefix -ErrorAction SilentlyContinue | + ForEach-Object { + $kind = 'ProviderItem' + if ($_.PSIsContainer) { $kind = 'ProviderContainer' } + [System.Management.Automation.CompletionResult]::new( + $_.FullName, $_.Name, $kind, $_.FullName) + } + } + } +} +""" + + +class _SourceVarsDict(t.TypedDict): + complete_func: str + complete_var: str + prog_name: str + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + cli: Command + ctx_args: cabc.MutableMapping[str, t.Any] + prog_name: str + complete_var: str + + def __init__( + self, + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> _SourceVarsDict: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> tuple[list[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions( + self, args: list[str], incomplete: str + ) -> list[CompletionItem[str]]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem[str]) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name: t.ClassVar[str] = "bash" + source_template: t.ClassVar[str] = _SOURCE_BASH + + @staticmethod + def _check_version() -> None: + import shutil + import subprocess + + bash_exe = shutil.which("bash") + + if bash_exe is None: + match = None + else: + output = subprocess.run( + [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], + stdout=subprocess.PIPE, + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + echo( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ), + err=True, + ) + else: + echo( + _("Couldn't detect Bash version, shell completion is not supported."), + err=True, + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem[t.Any]) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name: t.ClassVar[str] = "zsh" + source_template: t.ClassVar[str] = _SOURCE_ZSH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem[str]) -> str: + help_ = item.help or "_" + # The zsh completion script uses `_describe` on items with help + # texts (which splits the item help from the item value at the + # first unescaped colon) and `compadd` on items without help + # text (which uses the item value as-is and does not support + # colon escaping). So escape colons in the item value if and + # only if the item help is not the sentinel "_" value, as used + # by the completion script. + # + # (The zsh completion script is potentially widely deployed, and + # thus harder to fix than this method.) + # + # See issue #1812 and issue #2703 for further context. + value = item.value.replace(":", r"\:") if help_ != "_" else item.value + return f"{item.type}\n{value}\n{help_}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name: t.ClassVar[str] = "fish" + source_template: t.ClassVar[str] = _SOURCE_FISH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + if incomplete: + incomplete = split_arg_string(incomplete)[0] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem[str]) -> str: + """ + .. versionchanged:: 8.4.2 + Escape newlines and replace tabs with spaces in the help text to + fix completion errors with multi-line help strings. + """ + # According to https://fishshell.com/docs/current/cmds/complete.html + # Command substitutions found in ARGUMENTS should return a newline- + # separated list of arguments, and each argument may optionally have a tab + # character followed by the argument description. + if item.help: + help_ = item.help.replace("\n", "\\n").replace("\t", " ") + return f"{item.type},{item.value}\t{help_}" + + return f"{item.type},{item.value}" + + +class PowerShellComplete(ShellComplete): + """Shell completion for PowerShell (Windows PowerShell 5.1+ and pwsh 7+). + + .. versionadded:: 8.5.0 + """ + + name: t.ClassVar[str] = "powershell" + source_template: t.ClassVar[str] = _SOURCE_POWERSHELL + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem[str]) -> str: + # PowerShell parses the response by splitting on newlines and + # consuming three lines per completion (type, value, help). + # Multi-line help text would break that framing, so collapse + # newlines and carriage returns to spaces. The literal "_" + # sentinel matches what ZshComplete uses for "no help text". + if item.help: + help_ = item.help.replace("\r", " ").replace("\n", " ") + else: + help_ = "_" + return f"{item.type}\n{item.value}\n{help_}" + + +_available_shells: t.Final[dict[str, type[ShellComplete]]] = { + "bash": BashComplete, + "fish": FishComplete, + "powershell": PowerShellComplete, + "zsh": ZshComplete, +} + +_ShellCompleteT = t.TypeVar("_ShellCompleteT", bound="ShellComplete") + + +def add_completion_class( + cls: type[_ShellCompleteT], name: str | None = None +) -> type[_ShellCompleteT]: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + return cls + + +@t.overload +def get_completion_class(shell: t.Literal["bash"]) -> type[BashComplete]: ... +@t.overload +def get_completion_class(shell: t.Literal["fish"]) -> type[FishComplete]: ... +@t.overload +def get_completion_class(shell: t.Literal["zsh"]) -> type[ZshComplete]: ... +@t.overload +def get_completion_class(shell: str) -> type[ShellComplete] | None: ... +def get_completion_class(shell: str) -> type[ShellComplete] | None: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def split_arg_string(string: str) -> list[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + + .. versionchanged:: 8.2 + Moved to ``shell_completion`` from ``parser``. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out: list[str] = [] + + try: + out.extend(lex) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + value = ctx.params.get(param.name) + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + break + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + args: list[str], +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx: + args = ctx._protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, Group): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, args, parent=ctx, resilient_parsing=True + ) as sub_ctx: + ctx = sub_ctx + args = ctx._protected_args + ctx.args + else: + sub_ctx = ctx + + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) as sub_sub_ctx: + sub_ctx = sub_sub_ctx + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx._protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: list[str], incomplete: str +) -> tuple[Command | Parameter, str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/source/target-vendors/cp312/click/termui.py b/source/target-vendors/cp312/click/termui.py new file mode 100644 index 0000000..e1315f2 --- /dev/null +++ b/source/target-vendors/cp312/click/termui.py @@ -0,0 +1,1014 @@ +from __future__ import annotations + +import collections.abc as cabc +import inspect +import io +import itertools +import os +import re +import sys +import typing as t +from contextlib import AbstractContextManager +from contextlib import redirect_stdout +from gettext import gettext as _ + +from . import _compat +from ._compat import isatty +from ._compat import strip_ansi +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import _LazyFile +from .utils import echo + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +_HIDDEN_INPUT_MASK = "'***'" + + +def _mask_hidden_input(message: str, value: str) -> str: + """Replace occurrences of ``value`` in ``message`` with a fixed mask. + + Both ``repr(value)`` (the form built-in :class:`ParamType` errors use + via ``{value!r}``) and the raw value are masked. The raw-value pass + uses word-boundary lookarounds so a substring like ``"1"`` does not + match inside ``"10"``, and ``"ent"`` does not match inside + ``"Authentication"``. The empty string is skipped to avoid matching + at every boundary. + """ + message = message.replace(repr(value), _HIDDEN_INPUT_MASK) + if value: + message = re.sub( + rf"(? str: + import getpass + + return getpass.getpass(prompt) + + +def _readline_prompt(func: t.Callable[[str], str], text: str, err: bool) -> str: + """Call a prompt function, passing the full prompt so readline can + handle line editing and cursor positioning correctly. + + The prompt is handed to *func* (such as :func:`input`) rather than + written through :func:`echo`, so it has to strip ANSI color and style + codes itself when the destination stream does not support them. Without + this the prompt would keep codes that :func:`echo` removes from the + rest of the output. + """ + stream = sys.stderr if err else sys.stdout + + # Look up ``should_strip_ansi`` on the module so that ``CliRunner``, + # which patches it there during test isolation, is honored. + if _compat.should_strip_ansi(stream, resolve_color_default()): + text = strip_ansi(text) + + if err: + with redirect_stdout(sys.stderr): + return func(text) + return func(text) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool | str = False, + default: object | None = None, + show_choices: bool = True, + type: object | None = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + default_preview = "" + if show_default: + if isinstance(show_default, str): + default_preview = f" [({show_default})]" + elif default is not None: + default_preview = f" [{_format_default(default)}]" + return f"{prompt}{default_preview}{suffix}" + + +def _format_default(default: V) -> V | str: + if isinstance(default, (io.IOBase, _LazyFile)): + name = getattr(default, "name", None) + + if name is not None: + return str(name) + + return default + + +@t.overload +def prompt( + text: str, + default: str | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: None = None, + value_proc: None = None, + prompt_suffix: str = ": ", + show_default: bool | str = True, + err: bool = False, + show_choices: bool = True, +) -> str: ... + + +@t.overload +def prompt( + text: str, + default: V | str | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: ParamType[V, str] | type[V] | None = None, + value_proc: t.Callable[[str], V] | None = None, + prompt_suffix: str = ": ", + show_default: bool | str = True, + err: bool = False, + show_choices: bool = True, +) -> V: ... + + +def prompt( + text: str, + default: V | str | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: ParamType[V, str] | type[V] | None = None, + value_proc: t.Callable[[str], V] | None = None, + prompt_suffix: str = ": ", + show_default: bool | str = True, + err: bool = False, + show_choices: bool = True, +) -> V: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + If this value is a string, it shows that string + in parentheses instead of the actual value. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionchanged:: 8.5.0 + Generically typed: the return type is narrowed by ``type``, + ``value_proc``, or ``default`` instead of being ``Any``. Runtime + behavior is unchanged. + + .. versionchanged:: 8.3.3 + ``show_default`` can be a string to show a custom value instead + of the actual default, matching the help text behavior. + + .. versionchanged:: 8.3.1 + A space is no longer appended to the prompt. + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + return _readline_prompt(f, text, err) + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + # Defaults of any type are accepted and round trip through + # value_proc like typed input, so the annotation is only + # accurate for typed input. + value = t.cast("str", default) + break + try: + result = value_proc(value) + except UsageError as e: + message = _mask_hidden_input(e.message, value) if hide_input else e.message + echo(_("Error: {message}").format(message=message), err=err) + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: bool | None = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.3.1 + A space is no longer appended to the prompt. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + value = _readline_prompt(visible_prompt_func, prompt, err).lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def get_pager_file( + color: bool | None = None, +) -> t.ContextManager[t.TextIO]: + """Context manager. + + Yields a writable file-like object which can be used as an output pager. + + .. versionadded:: 8.4.0 + + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + from ._termui_impl import get_pager_file + + color = resolve_color_default(color) + + return get_pager_file(color=color) + + +def echo_via_pager( + text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, + color: bool | None = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + with get_pager_file(color=color) as pager: + for text in itertools.chain(text_generator, "\n"): + pager.write(text) + # Flush after each write so a slow generator streams to the pager + # incrementally rather than staying invisible until the pipe buffer + # fills (~8 KB). + pager.flush() + + +@t.overload +def progressbar( + *, + length: int, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[int]: ... + + +@t.overload +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: ... + + +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param hidden: hide the progressbar. Defaults to ``False``. When no tty is + detected, it will only print the progressbar label. Setting this to + ``False`` also disables that. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionadded:: 8.2 + The ``hidden`` argument. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + The ``update_min_steps`` parameter. + + .. versionadded:: 4.0 + The ``color`` parameter and ``update`` method. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + hidden=hidden, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + + # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor + echo("\033[2J\033[1;1H", nl=False) + + +def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: + """Interprets a color value and returns the corresponding ANSI code.""" + if isinstance(color, str) and color in _ansi_colors: + return str(_ansi_colors[color] + offset) + + # bool is an int subclass: without the exclusion, True and False would + # silently render as the palette indices 1 and 0. + elif isinstance(color, int) and not isinstance(color, bool): + if 0 <= color <= 255: + return f"{38 + offset};5;{color:d}" + + elif ( + isinstance(color, (tuple, list)) + and len(color) == 3 + and all( + isinstance(c, int) and not isinstance(c, bool) and 0 <= c <= 255 + for c in color + ) + ): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + raise ValueError(_("Unknown color {colour!r}").format(colour=color)) + + +def style( + text: t.Any, + fg: int | tuple[int, int, int] | str | None = None, + bg: int | tuple[int, int, int] | str | None = None, + bold: bool | None = None, + dim: bool | None = None, + underline: bool | None = None, + overline: bool | None = None, + italic: bool | None = None, + blink: bool | None = None, + reverse: bool | None = None, + strikethrough: bool | None = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.5.0 + All invalid color values raise :exc:`ValueError`. 256-color index + ``0`` is no longer ignored. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg is not None: + bits.append(f"\033[{_interpret_color(fg)}m") + + if bg is not None: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Any | None = None, + file: t.IO[t.AnyStr] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +@t.overload +def edit( + text: bytes | bytearray, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = False, + extension: str = ".txt", +) -> bytes | None: ... + + +@t.overload +def edit( + text: str, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", +) -> str | None: ... + + +@t.overload +def edit( + text: None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str + | os.PathLike[str] + | cabc.Iterable[str | os.PathLike[str]] + | None = None, +) -> None: ... + + +def edit( + text: str | bytes | bytearray | None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str + | os.PathLike[str] + | cabc.Iterable[str | os.PathLike[str]] + | None = None, +) -> str | bytes | bytearray | None: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. It accepts a path + or any iterable of paths. If the editor supports + editing multiple files at once, a sequence of files may + be passed as well. Invoke `click.file` once per file + instead if multiple files cannot be managed at once or + editing the files serially is desired. + + .. versionchanged:: 8.2.0 + ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` + if the ``editor`` supports editing multiple files at once. + + .. versionchanged:: 8.5.0 + ``filename`` accepts ``os.PathLike`` values in addition to strings. + + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + if isinstance(filename, (str, os.PathLike)): + filename = (filename,) + + ed.edit_files(filenames=filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Callable[[bool], str] | None = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> AbstractContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: str | None = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/source/target-vendors/cp312/click/testing.py b/source/target-vendors/cp312/click/testing.py new file mode 100644 index 0000000..cc123d4 --- /dev/null +++ b/source/target-vendors/cp312/click/testing.py @@ -0,0 +1,798 @@ +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import io +import os +import pdb +import shlex +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import _compat +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from _typeshed import ReadableBuffer + + from .core import Command + +if sys.platform == "win32": + CaptureMode: t.TypeAlias = t.Literal["sys"] # pyright: ignore[reportRedeclaration] +else: + CaptureMode: t.TypeAlias = t.Literal["sys", "fd"] # pyright: ignore[reportRedeclaration] +ExceptionInfo: t.TypeAlias = tuple[type[BaseException], BaseException, TracebackType] + + +class EchoingStdin: + _input: t.BinaryIO + _output: t.BinaryIO + _paused: bool + + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> list[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> cabc.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: EchoingStdin | None) -> cabc.Generator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class _FDCapture: + """Redirect a file descriptor to a temporary file for capture. + + Saves the current target of *targetfd* via :func:`os.dup`, then + redirects it to a temporary file via :func:`os.dup2`. On + :meth:`stop`, restores the original ``fd`` and returns the captured + bytes. Inspired by Pytest's ``FDCapture``. + + .. versionadded:: 8.4.0 + """ + + _targetfd: int + saved_fd: int + _tmpfile: t.BinaryIO | None + + def __init__(self, targetfd: int) -> None: + self._targetfd = targetfd + self.saved_fd = -1 + self._tmpfile = None + + def start(self) -> None: + self.saved_fd = os.dup(self._targetfd) + self._tmpfile = tempfile.TemporaryFile(buffering=0) + os.dup2(self._tmpfile.fileno(), self._targetfd) + + def stop(self) -> bytes: + assert self._tmpfile is not None, "_FDCapture.start() was not called" + os.dup2(self.saved_fd, self._targetfd) + os.close(self.saved_fd) + self.saved_fd = -1 + self._tmpfile.seek(0) + data = self._tmpfile.read() + self._tmpfile.close() + self._tmpfile = None + return data + + +class BytesIOCopy(io.BytesIO): + """Patch ``io.BytesIO`` to let the written stream be copied to another. + + .. versionadded:: 8.2 + """ + + copy_to: io.BytesIO + + def __init__(self, copy_to: io.BytesIO) -> None: + super().__init__() + self.copy_to = copy_to + + def flush(self) -> None: + super().flush() + self.copy_to.flush() + + def write(self, b: ReadableBuffer) -> int: + self.copy_to.write(b) + return super().write(b) + + +class StreamMixer: + """Mixes `` and `` streams. + + The result is available in the ``output`` attribute. + + .. versionadded:: 8.2 + """ + + output: io.BytesIO + stdout: BytesIOCopy + stderr: BytesIOCopy + + def __init__(self) -> None: + self.output = io.BytesIO() + self.stdout = BytesIOCopy(copy_to=self.output) + self.stderr = BytesIOCopy(copy_to=self.output) + + +class _NamedTextIOWrapper(io.TextIOWrapper): + """A :class:`~io.TextIOWrapper` with custom ``name`` and ``mode`` + that does not close its underlying buffer. + + When ``CliRunner`` runs in ``fd`` mode, ``_original_fd`` is patched to + point at the saved (pre-redirection) ``fd``, so C-level consumers that call + :meth:`fileno` (like ``faulthandler`` or ``subprocess``) keep working. In + the default ``sys`` mode ``_original_fd`` stays at ``-1`` and + :meth:`fileno` raises :exc:`io.UnsupportedOperation`, matching the + pre-``8.3.3`` behavior. + """ + + _name: str + _mode: str + _original_fd: int + + def __init__( + self, + buffer: t.BinaryIO, + name: str, + mode: str, + **kwargs: t.Any, + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + self._original_fd = -1 + + def close(self) -> None: + """The buffer this object contains belongs to some other object, + so prevent the default ``__del__`` implementation from closing + that buffer. + + .. versionadded:: 8.3.2 + """ + + def fileno(self) -> int: + """Return the file descriptor of the saved original stream when + ``CliRunner`` runs in ``fd`` mode. Otherwise delegate to + :class:`~io.TextIOWrapper`, which raises + :exc:`io.UnsupportedOperation` for a ``BytesIO``-backed buffer. + """ + if self._original_fd >= 0: + return self._original_fd + return super().fileno() + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: str | bytes | t.IO[t.Any] | None, charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(input) + + +class Result: + """Holds the captured result of an invoked CLI script. + + :param runner: The runner that created the result + :param stdout_bytes: The standard output as bytes. + :param stderr_bytes: The standard error as bytes. + :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the + user would see it in its terminal. + :param return_value: The value returned from the invoked command. + :param exit_code: The exit code as integer. + :param exception: The exception that happened if one did. + :param exc_info: Exception information (exception type, exception instance, + traceback type). + + .. versionchanged:: 8.2 + ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and + ``mix_stderr`` has been removed. + + .. versionadded:: 8.0 + Added ``return_value``. + """ + + runner: CliRunner + stdout_bytes: bytes + stderr_bytes: bytes + output_bytes: bytes + return_value: t.Any + exit_code: int + exception: BaseException | None + exc_info: ExceptionInfo | None + + def __init__( + self, + runner: CliRunner, + stdout_bytes: bytes, + stderr_bytes: bytes, + output_bytes: bytes, + return_value: t.Any, + exit_code: int, + exception: BaseException | None, + exc_info: ExceptionInfo | None = None, + ) -> None: + self.runner = runner + self.stdout_bytes = stdout_bytes + self.stderr_bytes = stderr_bytes + self.output_bytes = output_bytes + self.return_value = return_value + self.exit_code = exit_code + self.exception = exception + self.exc_info = exc_info + + @property + def output(self) -> str: + """The terminal output as unicode string, as the user would see it. + + .. versionchanged:: 8.2 + No longer a proxy for ``self.stdout``. Now has its own independent stream + that is mixing `` and ``, in the order they were written. + """ + return self.output_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string. + + .. versionchanged:: 8.2 + No longer raise an exception, always returns the `` string. + """ + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from `` writes + to ``. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param catch_exceptions: Whether to catch any exceptions other than + ``SystemExit`` when running :meth:`~CliRunner.invoke`. + :param capture: Selects the output capture strategy. ``sys`` (default) + captures Python-level writes only and leaves + :meth:`sys.stdout.fileno` raising :exc:`io.UnsupportedOperation`, so + user code that calls :func:`os.dup2` on ``sys.stdout.fileno()`` cannot + clobber the host runner's stdout. ``fd`` redirects file descriptors + ``1`` and ``2`` via :func:`os.dup2` to a temporary file, also catching + output from stale stream references, C extensions, and subprocesses. + ``fd`` is not supported on Windows. + + .. versionchanged:: 8.4.0 + Added the ``capture`` parameter. The default ``sys`` mode no longer + exposes the original fd through :meth:`fileno`, reverting the change + introduced in ``8.3.3`` that broke Pytest's ``fd``-level capture + teardown. Use ``capture="fd"`` to restore that behavior with proper + isolation. :issue:`3384` + + .. versionchanged:: 8.2 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 8.2 + ``mix_stderr`` parameter has been removed. + """ + + charset: str + env: cabc.Mapping[str, str | None] + echo_stdin: bool + catch_exceptions: bool + capture: CaptureMode + + def __init__( + self, + charset: str = "utf-8", + env: cabc.Mapping[str, str | None] | None = None, + echo_stdin: bool = False, + catch_exceptions: bool = True, + capture: CaptureMode = "sys", + ) -> None: + if capture not in {"sys", "fd"}: + raise ValueError( + f"capture={capture!r} is not valid. Choose from 'sys' or 'fd'." + ) + if capture == "fd" and sys.platform == "win32": + raise ValueError( + f"capture={capture!r} is not supported on Windows. Use 'sys'." + ) + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + self.catch_exceptions = catch_exceptions + self.capture = capture + + def get_default_prog_name(self, cli: Command) -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: cabc.Mapping[str, str | None] | None = None + ) -> cabc.Mapping[str, str | None]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + color: bool = False, + ) -> cabc.Generator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up `` with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into `sys.stdin`. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + An additional output stream is returned, which is a mix of + `` and `` streams. + + .. versionchanged:: 8.2 + Always returns the `` stream. + + .. versionchanged:: 8.0 + `` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + stream_mixer = StreamMixer() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + stream_mixer.stdout, + encoding=self.charset, + name="", + mode="w", + ) + + sys.stderr = _NamedTextIOWrapper( + stream_mixer.stderr, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: str | None = None) -> str: + sys.stdout.write(prompt or "") + try: + val = next(text_input).rstrip("\r\n") + except StopIteration as e: + raise EOFError() from e + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: str | None = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + try: + return next(text_input).rstrip("\r\n") + except StopIteration as e: + raise EOFError() from e + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + old__compat_should_strip_ansi = _compat.should_strip_ansi + old_pdb_init = pdb.Pdb.__init__ + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + _compat.should_strip_ansi = should_strip_ansi + + def _patched_pdb_init( + self: pdb.Pdb, + completekey: str = "tab", + stdin: t.IO[str] | None = None, + stdout: t.IO[str] | None = None, + **kwargs: t.Any, + ) -> None: + """Default ``pdb.Pdb`` to real terminal streams during + ``CliRunner`` isolation. + + Without this patch, ``pdb.Pdb.__init__`` inherits from + ``cmd.Cmd`` which falls back to ``sys.stdin``/``sys.stdout`` + when no explicit streams are provided. During isolation + those are ``BytesIO``-backed wrappers, so the debugger + reads from an empty buffer and writes to captured output, + making interactive debugging impossible. + + By defaulting to ``sys.__stdin__``/``sys.__stdout__`` (the + original terminal streams Python preserves regardless of + redirection), debuggers can interact with the user while + ``click.echo`` output is still captured normally. + + This covers ``pdb.set_trace()``, ``breakpoint()``, + ``pdb.post_mortem()``, and debuggers that subclass + ``pdb.Pdb`` (ipdb, pdbpp). Explicit ``stdin``/``stdout`` + arguments are honored and not overridden. Debuggers that + do not subclass ``pdb.Pdb`` (pudb, debugpy) are not + covered. + """ + if stdin is None: + stdin = sys.__stdin__ + if stdout is None: + stdout = sys.__stdout__ + old_pdb_init( + self, completekey=completekey, stdin=stdin, stdout=stdout, **kwargs + ) + + pdb.Pdb.__init__ = _patched_pdb_init # type: ignore[assignment] + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + _compat.should_strip_ansi = old__compat_should_strip_ansi + formatting.FORCED_WIDTH = old_forced_width + pdb.Pdb.__init__ = old_pdb_init # type: ignore[method-assign] + + def invoke( + self, + cli: Command, + args: str | cabc.Sequence[str] | None = None, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + catch_exceptions: bool | None = None, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. If :data:`None`, the value + from :class:`CliRunner` is used. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + The result object has the ``output_bytes`` attribute with + the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would + see it in its terminal. + + .. versionchanged:: 8.2 + The result object always returns the ``stderr_bytes`` stream. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + if catch_exceptions is None: + catch_exceptions = self.catch_exceptions + + # Set up fd capture before isolation replaces sys.stdout and sys.stderr. + cap_out: _FDCapture | None = None + cap_err: _FDCapture | None = None + + if self.capture == "fd": + cap_out = _FDCapture(1) + cap_err = _FDCapture(2) + try: + cap_out.start() + cap_err.start() + except OSError: + cap_out = cap_err = None + + with self.isolation(input=input, env=env, color=color) as outstreams: + # Point the captured streams' fileno() at the saved (original) + # fd so that C-level consumers like faulthandler keep working + # while fd 1/2 are redirected to the capture tmpfile. + if cap_out is not None and cap_err is not None: + sys.stdout._original_fd = cap_out.saved_fd # type: ignore[union-attr] + sys.stderr._original_fd = cap_err.saved_fd # type: ignore[union-attr] + + return_value = None + exception: BaseException | None = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast("int | t.Any | None", e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + sys.stderr.flush() + + # Stop fd capture and merge the captured bytes into + # the stdout/stderr BytesIO streams. BytesIOCopy mirrors + # those writes into outstreams[2] automatically. + if cap_out is not None and cap_err is not None: + fd_out = cap_out.stop() + fd_err = cap_err.stop() + if fd_out: + outstreams[0].write(fd_out) + if fd_err: + outstreams[1].write(fd_err) + + stdout = outstreams[0].getvalue() + stderr = outstreams[1].getvalue() + output = outstreams[2].getvalue() + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + output_bytes=output, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: str | os.PathLike[str] | None = None + ) -> cabc.Generator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + .. warning:: + This helper predates Python 3 and modern pytest, and is not + thread-safe: it relies on :func:`os.chdir`, which mutates + process-global state, and :meth:`invoke` swaps the + process-global standard streams too. Parallelize tests with + processes (``pytest-xdist``), not threads. Locking the + runner (:pr:`3511`, :pr:`3520`, :pr:`3530`) and a + ``set_filesystem()`` API (:issue:`3123`) were declined: + neither removes the global-state mutation. See :issue:`3700` + and :issue:`3501`. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. deprecated:: 8.5.0 + Will be removed in Click 9.0. Use + :class:`tempfile.TemporaryDirectory` or pytest's + ``tmp_path`` fixture with absolute paths instead. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + import warnings + + warnings.warn( + "'isolated_filesystem' is deprecated and will be removed in Click" + " 9.0. Use 'tempfile.TemporaryDirectory' or pytest's 'tmp_path'" + " fixture with absolute paths instead.", + DeprecationWarning, + stacklevel=3, + ) + + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) + os.chdir(dt) + + try: + yield dt + finally: + os.chdir(cwd) + + if temp_dir is None: + import shutil + + try: + shutil.rmtree(dt) + except OSError: + pass diff --git a/source/target-vendors/cp312/click/types.py b/source/target-vendors/cp312/click/types.py new file mode 100644 index 0000000..0eb8462 --- /dev/null +++ b/source/target-vendors/cp312/click/types.py @@ -0,0 +1,1422 @@ +from __future__ import annotations + +import abc +import collections.abc as cabc +import enum +import os +import stat +import sys +import typing as t +import uuid +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import _LazyFile +from .utils import _safecall +from .utils import format_filename + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + +_ValueT = t.TypeVar("_ValueT") +_ValueT_contra = t.TypeVar("_ValueT_contra", contravariant=True) +_ValueT_co = t.TypeVar("_ValueT_co", covariant=True) + +# The input type parameter of ParamType defaults to Any. TypeVar defaults +# (PEP 696) landed in typing on Python 3.13, so type checkers get the +# default from typing_extensions, which is never imported at runtime. On +# older Pythons the runtime TypeVar carries no default; +# ParamType.__class_getitem__ fills in the omitted parameter instead. +if t.TYPE_CHECKING: + _InputT_contra = te.TypeVar("_InputT_contra", contravariant=True, default=t.Any) +elif sys.version_info >= (3, 13): + _InputT_contra = t.TypeVar("_InputT_contra", contravariant=True, default=t.Any) +else: + _InputT_contra = t.TypeVar("_InputT_contra", contravariant=True) + +_FloatValueT = t.TypeVar("_FloatValueT", bound=float) +_FloatValueT_co = t.TypeVar("_FloatValueT_co", bound=float, covariant=True) + + +class ParamTypeInfoDict(t.TypedDict): + param_type: str + name: str + + +class ParamType(t.Generic[_ValueT_co, _InputT_contra], abc.ABC): + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + + .. versionchanged:: 8.4.0 + Now a generic abstract base class. Parameterize with the + converted value type (``ParamType[int]`` for an integer-returning + type) so that :meth:`convert` and downstream consumers carry the + narrowed return type. + + .. versionchanged:: 8.5.0 + Accepts a second optional type parameter for the input value type + that :meth:`convert` accepts (``ParamType[int, str]`` for a type + converting strings to integers), defaulting to ``Any``. + """ + + is_composite: t.ClassVar[bool] = False + arity: int = 1 # read-only + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[str | None] = None + + if sys.version_info < (3, 13): + # ``_InputT_contra`` carries its ``Any`` default only for type + # checkers: ``TypeVar(default=...)`` (PEP 696) is unavailable at + # runtime before Python 3.13. Fill in the omitted input type + # parameter by hand so ``ParamType[int]`` keeps working. + def __class_getitem__(cls, params: t.Any) -> t.Any: + if cls is ParamType: + if not isinstance(params, tuple): + params = (params,) + if len(params) == 1: + params = (*params, t.Any) + # Checkers cannot see Generic.__class_getitem__ through super(). + return super().__class_getitem__(params) # type: ignore[misc] + + def to_info_dict(self) -> ParamTypeInfoDict: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + @t.overload + def __call__( + self, + value: None, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> None: ... + + @t.overload + def __call__( + self, + value: _InputT_contra, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> _ValueT_co: ... + + def __call__( + self, + value: _InputT_contra | None, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> _ValueT_co | None: + if value is not None: + return self.convert(value, param, ctx) + return None + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: _InputT_contra, param: Parameter | None, ctx: Context | None + ) -> _ValueT_co: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + # The default returns the value as-is so subclasses that only customize + # metadata are not forced to redeclare ``convert``. + return t.cast("_ValueT_co", value) + + def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.NoReturn: + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType[_ValueT_co]): + is_composite: t.ClassVar[bool] = True + + @property + @abc.abstractmethod + def arity(self) -> int: ... # type: ignore[override] + + +if t.TYPE_CHECKING: + # on Python 3.10 this will raise a TypeError + + class FuncParamTypeInfoDict( + ParamTypeInfoDict, + t.Generic[_ValueT_contra, _ValueT_co], + ): + func: t.Callable[[_ValueT_contra], _ValueT_co] +else: + + class FuncParamTypeInfoDict(ParamTypeInfoDict): + func: t.Callable[[t.Any], t.Any] + + +class FuncParamType(ParamType[_ValueT_co], t.Generic[_ValueT_contra, _ValueT_co]): + name: str + func: t.Callable[[_ValueT_contra], _ValueT_co] + + def __init__(self, func: t.Callable[[_ValueT_contra], _ValueT_co]) -> None: + self.name = func.__name__ + self.func = func + + def to_info_dict(self) -> FuncParamTypeInfoDict[_ValueT_contra, _ValueT_co]: + return {"func": self.func, **super().to_info_dict()} + + def convert( + self, value: _ValueT_contra, param: Parameter | None, ctx: Context | None + ) -> _ValueT_co: + try: + return self.func(value) + except ValueError as exc: + message = str(exc) + + if not message: + try: + message = str(value) + except UnicodeError: + message = t.cast("bytes", value).decode("utf-8", "replace") + + self.fail(message, param, ctx) + + +class UnprocessedParamType(ParamType[t.Any]): + name = "text" + + def convert( + self, value: _ValueT, param: Parameter | None, ctx: Context | None + ) -> _ValueT: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType[str]): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> str: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + return value.decode(enc) + except UnicodeError: + fs_enc = sys.getfilesystemencoding() + if fs_enc != enc: + try: + return value.decode(fs_enc) + except UnicodeError: + return value.decode("utf-8", "replace") + else: + return value.decode("utf-8", "replace") + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +if t.TYPE_CHECKING: + # on Python 3.10 this will raise a TypeError + + class ChoiceInfoDict(ParamTypeInfoDict, t.Generic[_ValueT_co]): + choices: tuple[_ValueT_co, ...] + case_sensitive: bool +else: + + class ChoiceInfoDict(ParamTypeInfoDict): + choices: tuple[t.Any, ...] + case_sensitive: bool + + +class Choice(ParamType[_ValueT_co], t.Generic[_ValueT_co]): + """The choice type allows a value to be checked against a fixed set + of supported values. + + You may pass any iterable value which will be converted to a tuple + and thus will only be iterated once. + + The resulting value will always be one of the originally passed choices. + See :meth:`normalize_choice` for more info on the mapping of strings + to choices. See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + + .. versionchanged:: 8.4.0 + Now generic in the choice value type. Parameterize with the type of + the choice values (``Choice[HashType]`` for an enum, ``Choice[str]`` + for plain strings) to enable type-checked consumers. + + .. versionchanged:: 8.2.0 + Non-``str`` ``choices`` are now supported. It can additionally be any + iterable. Before you were not recommended to pass anything but a list or + tuple. + + .. versionadded:: 8.2.0 + Choice normalization can be overridden via :meth:`normalize_choice`. + """ + + name: str = "choice" + + choices: tuple[_ValueT_co, ...] + case_sensitive: bool + + def __init__( + self, choices: cabc.Iterable[_ValueT_co], case_sensitive: bool = True + ) -> None: + self.choices = tuple(choices) + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> ChoiceInfoDict[_ValueT_co]: + return { + "choices": self.choices, + "case_sensitive": self.case_sensitive, + **super().to_info_dict(), + } + + def _normalized_mapping( + self, ctx: Context | None = None + ) -> cabc.Mapping[_ValueT_co, str]: + """ + Returns mapping where keys are the original choices and the values are + the normalized values that are accepted via the command line. + + This is a simple wrapper around :meth:`normalize_choice`, use that + instead which is supported. + """ + return { + choice: self.normalize_choice( + choice=choice, + ctx=ctx, + ) + for choice in self.choices + } + + def normalize_choice(self, choice: object, ctx: Context | None) -> str: + """ + Normalize a choice value, used to map a passed string to a choice. + Each choice must have a unique normalized value. + + By default uses :meth:`Context.token_normalize_func` and if not case + sensitive, convert it to a casefolded value. + + .. versionadded:: 8.2.0 + """ + normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(normed_value) + + if not self.case_sensitive: + normed_value = normed_value.casefold() + + return normed_value + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + if param.param_type_name == "option" and not param.show_choices: # type: ignore[attr-defined] + choice_metavars = [ + convert_type(type(choice)).name.upper() for choice in self.choices + ] + choices_str = "|".join([*dict.fromkeys(choice_metavars)]) + else: + choices_str = "|".join( + [str(i) for i in self._normalized_mapping(ctx=ctx).values()] + ) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: + """ + Message shown when no choice is passed. + + .. versionchanged:: 8.2.0 Added ``ctx`` argument. + """ + return _("Choose from:\n\t{choices}").format( + choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) + ) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> _ValueT_co: + """ + For a given value from the parser, normalize it and find its + matching normalized value in the list of choices. Then return the + matched "original" choice. + """ + normed_value = self.normalize_choice(choice=value, ctx=ctx) + normalized_mapping = self._normalized_mapping(ctx=ctx) + + try: + return next( + original + for original, normalized in normalized_mapping.items() + if normalized == normed_value + ) + except StopIteration: + self.fail( + self.get_invalid_choice_message(value=value, ctx=ctx), + param=param, + ctx=ctx, + ) + + def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: + """Get the error message when the given choice is invalid. + + :param value: The invalid value. + + .. versionadded:: 8.2 + """ + choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) + return ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str) + + def __repr__(self) -> str: + return _("Choice({choices})").format(choices=list(self.choices)) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = [self.normalize_choice(choice, ctx) for choice in self.choices] + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTimeInfoDict(ParamTypeInfoDict): + formats: cabc.Sequence[str] + + +class DateTime(ParamType[datetime]): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + formats: cabc.Sequence[str] + + def __init__(self, formats: cabc.Sequence[str] | None = None): + self.formats = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> DateTimeInfoDict: + return {"formats": self.formats, **super().to_info_dict()} + + def get_metavar(self, param: Parameter, ctx: Context) -> str: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> datetime: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase( + ParamType[_ValueT_co], t.Generic[_ValueT_contra, _ValueT_co] +): + _number_class: t.Callable[[_ValueT_contra], _ValueT_co] + + def convert( + self, value: _ValueT_contra, param: Parameter | None, ctx: Context | None + ) -> _ValueT_co: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +if t.TYPE_CHECKING: + # on Python 3.10 this will raise a TypeError + + class NumberRangeInfoDict(ParamTypeInfoDict, t.Generic[_FloatValueT_co]): + min: _FloatValueT_co | None + max: _FloatValueT_co | None + min_open: bool + max_open: bool + clamp: bool +else: + + class NumberRangeInfoDict(ParamTypeInfoDict): + min: t.Any | None + max: t.Any | None + min_open: bool + max_open: bool + clamp: bool + + +class _NumberRangeBase( + _NumberParamTypeBase[_ValueT_contra, _FloatValueT_co], + t.Generic[_ValueT_contra, _FloatValueT_co], +): + min: _FloatValueT_co | None + max: _FloatValueT_co | None + min_open: bool + max_open: bool + clamp: bool + + def __init__( + self, + min: _FloatValueT_co | None = None, + max: _FloatValueT_co | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> NumberRangeInfoDict[_FloatValueT_co]: + return { + "min": self.min, + "max": self.max, + "min_open": self.min_open, + "max_open": self.max_open, + "clamp": self.clamp, + **super().to_info_dict(), + } + + def convert( + self, value: _ValueT_contra, param: Parameter | None, ctx: Context | None + ) -> _FloatValueT_co: + import operator + + rv = super().convert(value, param, ctx) + min = self.min + max = self.max + lt_min: bool = min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, min) + gt_max: bool = max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, max) + + if self.clamp: + if min is not None and lt_min: + return self._clamp(min, 1, self.min_open) + + if max is not None and gt_max: + return self._clamp(max, -1, self.max_open) + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + @abc.abstractmethod + def _clamp( + # Covariant type variables cannot be used in input positions, so we use a + # separate method-scoped type variable instead. + self: _NumberRangeBase[t.Any, _FloatValueT], + bound: _FloatValueT, + dir: t.Literal[1, -1], + open: bool, + ) -> _FloatValueT: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + ... + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase[t.SupportsInt | t.SupportsIndex, int]): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase[int, int], IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp(self, bound: int, dir: t.Literal[1, -1], open: bool) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase[t.SupportsFloat | t.SupportsIndex, float]): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase[float, float], FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + if not open: + return bound + + # Could use math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType[bool]): + name = "boolean" + + bool_states: dict[str, bool] = { + "1": True, + "0": False, + "yes": True, + "no": False, + "true": True, + "false": False, + "on": True, + "off": False, + "t": True, + "f": False, + "y": True, + "n": False, + # Absence of value is considered False. + "": False, + } + """A mapping of string values to boolean states. + + Mapping is inspired by :py:attr:`configparser.ConfigParser.BOOLEAN_STATES` + and extends it. + + .. caution:: + String values are lower-cased, as the ``str_to_bool`` comparison function + below is case-insensitive. + + .. warning:: + The mapping is not exhaustive, and does not cover all possible boolean strings + representations. It will remains as it is to avoid endless bikeshedding. + + Future work my be considered to make this mapping user-configurable from public + API. + """ + + @staticmethod + def str_to_bool(value: str | bool) -> bool | None: + """Convert a string to a boolean value. + + If the value is already a boolean, it is returned as-is. If the value is a + string, it is stripped of whitespaces and lower-cased, then checked against + the known boolean states pre-defined in the `BoolParamType.bool_states` mapping + above. + + Returns `None` if the value does not match any known boolean state. + """ + if isinstance(value, bool): + return value + return BoolParamType.bool_states.get(value.strip().lower()) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> bool: + normalized = self.str_to_bool(value) + if normalized is None: + self.fail( + _( + "{value!r} is not a valid boolean. Recognized values: {states}" + ).format(value=value, states=", ".join(sorted(self.bool_states))), + param, + ctx, + ) + return normalized + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType[uuid.UUID]): + name = "uuid" + + def convert( + self, value: uuid.UUID | str, param: Parameter | None, ctx: Context | None + ) -> uuid.UUID: + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class FileInfoDict(ParamTypeInfoDict): + mode: str + encoding: str | None + + +class File(ParamType[t.IO[t.Any]]): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Files can also be opened atomically in which case all writes go into a + separate file in the same folder and upon completion the file will + be moved over to the original location. This is useful if a file + regularly read by other users is modified. + + See :ref:`file-args` for more information. + + .. versionchanged:: 2.0 + Added the ``atomic`` parameter. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + mode: str + encoding: str | None + errors: str | None + lazy: bool | None + atomic: bool + + def __init__( + self, + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool | None = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> FileInfoDict: + return { + "mode": self.mode, + "encoding": self.encoding, + **super().to_info_dict(), + } + + def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: + if self.lazy is not None: + return self.lazy + if os.fspath(value) == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, + value: str | os.PathLike[str] | t.IO[t.Any], + param: Parameter | None, + ctx: Context | None, + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + try: + lazy = self.resolve_lazy_flag(value) + + if lazy: + lf = _LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + if ctx is not None: + ctx.call_on_close(lf.close_intelligently) + + return t.cast("t.IO[t.Any]", lf) + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(_safecall(f.close)) + else: + ctx.call_on_close(_safecall(f.flush)) + + return f + except OSError as e: + self.fail( + f"'{format_filename(value)}': {e.strerror}", + param, + ctx, + ) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +def _is_file_like(value: t.Any) -> te.TypeIs[t.IO[t.Any]]: + return hasattr(value, "read") or hasattr(value, "write") + + +class PathInfoDict(ParamTypeInfoDict): + exists: bool + file_okay: bool + dir_okay: bool + writable: bool + readable: bool + allow_dash: bool + + +class Path(ParamType[str | bytes | os.PathLike[str]]): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``path_type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + exists: bool + file_okay: bool + dir_okay: bool + readable: bool + writable: bool + executable: bool + resolve_path: bool + allow_dash: bool + name: str + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: type | None = None, + executable: bool = False, + ) -> None: + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type: type | None = path_type + + if self.file_okay and not self.dir_okay: + self.name = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> PathInfoDict: + return { + "exists": self.exists, + "file_okay": self.file_okay, + "dir_okay": self.dir_okay, + "writable": self.writable, + "readable": self.readable, + "allow_dash": self.allow_dash, + **super().to_info_dict(), + } + + def coerce_path_result( + self, value: str | os.PathLike[str] + ) -> str | bytes | os.PathLike[str]: + if self.type is not None and not isinstance(value, self.type): + if self.type is str: + return os.fsdecode(value) + elif self.type is bytes: + return os.fsencode(value) + else: + return t.cast("os.PathLike[str]", self.type(value)) + + return value + + def convert( + self, + value: str | os.PathLike[str], + param: Parameter | None, + ctx: Context | None, + ) -> str | bytes | os.PathLike[str]: + rv = value + + dash = b"-" if isinstance(rv, bytes) else "-" + is_dash = self.file_okay and self.allow_dash and rv == dash + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} {filename!r} is a directory.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class TupleInfoDict(ParamTypeInfoDict): + types: cabc.Sequence[ParamTypeInfoDict] + + +class Tuple(CompositeParamType[tuple[t.Any, ...]]): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType[t.Any]]) -> None: + self.types: cabc.Sequence[ParamType[t.Any]] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> TupleInfoDict: + return { + "types": [ty.to_info_dict() for ty in self.types], + **super().to_info_dict(), + } + + @property + def name(self) -> str: # type: ignore[override] + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore[override] + return len(self.types) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> tuple[t.Any, ...]: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple( + ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) + ) + + +def _guess_type( + ty: type[t.Any] | ParamType[t.Any] | None, + default: t.Any | None, +) -> type[t.Any] | tuple[type[t.Any], ...] | ParamType[t.Any] | None: + """Infer a type from *ty* or *default*. + + Returns *ty* unchanged when it is not ``None``. Otherwise inspects + *default* to produce a ``type``, a ``tuple`` of types (for tuple + defaults), or ``None``. + """ + if ty is not None: + return ty + + if default is None: + return None + + if not isinstance(default, (tuple, list)): + return type(default) + + # If the default is empty, return None so convert_type falls + # through to STRING. + if not default: + return None + + item = default[0] + + # A sequence of iterables needs to detect the inner types. + # Can't call convert_type recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + return tuple(map(type, item)) + + return type(item) + + +@t.overload +def convert_type(ty: None, default: None = None) -> StringParamType: ... +@t.overload +def convert_type( + ty: type | ParamType[t.Any], default: t.Any | None = None +) -> ParamType[t.Any]: ... +@t.overload +def convert_type( + ty: t.Any | None, default: t.Any | None = None +) -> ParamType[t.Any]: ... +def convert_type( + ty: t.Any | None = None, default: t.Any | None = None +) -> ParamType[t.Any]: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed = _guess_type(ty, default) + is_guessed = guessed is not ty + + if isinstance(guessed, tuple): + return Tuple(guessed) + + if isinstance(guessed, ParamType): + return guessed + + if guessed is str or guessed is None: + return STRING + + if guessed is int: + return INT + + if guessed is float: + return FLOAT + + if guessed is bool: + return BOOL + + if is_guessed: + return STRING + + if __debug__: + try: + if issubclass(guessed, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({guessed})." + ) + except TypeError: + # guessed is an instance (correct), so issubclass fails. + pass + + return FuncParamType(guessed) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED: t.Final[UnprocessedParamType] = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING: t.Final[StringParamType] = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT: t.Final[IntParamType] = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT: t.Final[FloatParamType] = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL: t.Final[BoolParamType] = BoolParamType() + +#: A UUID parameter. +UUID: t.Final[UUIDParameterType] = UUIDParameterType() + + +class OptionHelpExtra(t.TypedDict, total=False): + envvars: tuple[str, ...] + default: str + range: str + required: str diff --git a/source/target-vendors/cp312/click/utils.py b/source/target-vendors/cp312/click/utils.py new file mode 100644 index 0000000..b529eb0 --- /dev/null +++ b/source/target-vendors/cp312/click/utils.py @@ -0,0 +1,688 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import sys +import typing as t +from functools import update_wrapper +from gettext import gettext as _ +from types import ModuleType +from types import TracebackType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import binary_streams +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def _safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: + """Wraps a function so that it swallows exceptions. + + :meta private: + """ + + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: + try: + return func(*args, **kwargs) + except Exception: + pass + return None + + return update_wrapper(wrapper, func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(sys.getfilesystemencoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def _make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string. + + :meta private: + """ + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class _LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + + :meta private: + """ + + name: str + mode: str + encoding: str | None + errors: str | None + atomic: bool + _f: t.IO[t.Any] | None + should_close: bool + + def __init__( + self, + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, + ) -> None: + self.name = os.fspath(filename) + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + + if self.name == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO[t.Any]: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> _LazyFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close_intelligently() + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class _KeepOpenFile: + """Proxy a file object but keep it open across a ``with`` block. + + Wraps a borrowed file (such as ``sys.stdin`` or ``sys.stdout``) so that + leaving a ``with`` block does not close it, as used by :func:`open_file` + for the ``-`` filename. The caller stays responsible for the file: an + explicit :meth:`close` still passes through to the wrapped object. + + Dunder methods are proxied explicitly: implicit special-method lookups + bypass :meth:`__getattr__`, because Python resolves them on the type rather + than the instance. + + :meta private: + """ + + _file: t.IO[t.Any] + + def __init__(self, file: t.IO[t.Any]) -> None: + self._file = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> _KeepOpenFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: object = None, + file: t.IO[t.Any] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 8.5.0 + Colorama is no longer used for color on Windows. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + return + + match message: + case str() | bytes() | bytearray(): + out = message + case None: + out = "" + case _: + out = str(message) + + if nl: + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + elif should_strip_ansi(file, resolve_color_default(color)): + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def _get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: + """Returns a system stream for byte processing. + + .. deprecated:: 8.5.0 + Will be removed in Click 9.0. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + + :meta private: + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(_("Unknown standard stream '{name}'").format(name=name)) + return opener() + + +def _get_text_stream( + name: t.Literal["stdin", "stdout", "stderr"], + encoding: str | None = None, + errors: str | None = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. + + .. deprecated:: 8.5.0 + Will be removed in Click 9.0. + + This usually returns a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + :meta private: + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(_("Unknown standard stream '{name}'").format(name=name)) + return opener(encoding, errors) + + +def open_file( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO[t.Any]: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name or Path of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast( + "t.IO[t.Any]", _LazyFile(filename, mode, encoding, errors, atomic=atomic) + ) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast("t.IO[t.Any]", _KeepOpenFile(f)) + + return f + + +def format_filename( + filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], + shorten: bool = False, +) -> str: + """Format a filename as a string for display. Ensures the filename can be + displayed by replacing any invalid bytes or surrogate escapes in the name + with the replacement character ``�``. + + Invalid bytes or surrogate escapes will raise an error when written to a + stream with ``errors="strict"``. This will typically happen with ``stdout`` + when the locale is something like ``en_GB.UTF-8``. + + Many scenarios *are* safe to write surrogates though, due to PEP 538 and + PEP 540, including: + + - Writing to ``stderr``, which uses ``errors="backslashreplace"``. + - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens + stdout and stderr with ``errors="surrogateescape"``. + - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. + - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. + Python opens stdout and stderr with ``errors="surrogateescape"``. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + else: + filename = os.fspath(filename) + + if isinstance(filename, bytes): + filename = filename.decode(sys.getfilesystemencoding(), "replace") + else: + filename = filename.encode("utf-8", "surrogateescape").decode( + "utf-8", "replace" + ) + + return filename + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no effect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class _PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + + :meta private: + """ + + wrapped: t.IO[t.Any] + + def __init__(self, wrapped: t.IO[t.Any]) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: str | None = None, _main: ModuleType | None = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + # It is set to "" inside a Shiv or PEX zipapp. + if getattr(_main, "__package__", None) in {None, ""} or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: cabc.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> list[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out + + +def __getattr__(name: str) -> object: + import warnings + + if name in { + "LazyFile", + "KeepOpenFile", + "make_default_short_help", + "PacifyFlushWrapper", + "safecall", + "get_text_stream", + "get_binary_stream", + }: + warnings.warn( + f"'click.utils.{name}' is deprecated and will be removed in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return globals()[f"_{name}"] + + raise AttributeError(name) diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/METADATA b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/METADATA new file mode 100644 index 0000000..530b398 --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/METADATA @@ -0,0 +1,110 @@ +Metadata-Version: 2.4 +Name: cryptography +Version: 50.0.1 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: POSIX +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable +Classifier: Topic :: Security :: Cryptography +Requires-Dist: cffi>=2.0.0 ; platform_python_implementation != 'PyPy' +Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11' +Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh' +Provides-Extra: ssh +License-File: LICENSE +License-File: LICENSE.APACHE +License-File: LICENSE.BSD +Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. +Author-email: The Python Cryptographic Authority and individual contributors +License-Expression: Apache-2.0 OR BSD-3-Clause +Requires-Python: >=3.9, !=3.9.0, !=3.9.1 +Description-Content-Type: text/x-rst; charset=UTF-8 +Project-URL: changelog, https://cryptography.io/en/latest/changelog/ +Project-URL: documentation, https://cryptography.io/ +Project-URL: homepage, https://github.com/pyca/cryptography +Project-URL: issues, https://github.com/pyca/cryptography/issues +Project-URL: source, https://github.com/pyca/cryptography/ + +pyca/cryptography +================= + +.. image:: https://img.shields.io/pypi/v/cryptography.svg + :target: https://pypi.org/project/cryptography/ + :alt: Latest Version + +.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest + :target: https://cryptography.io + :alt: Latest Docs + +.. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg + :target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain + +``cryptography`` is a package which provides cryptographic recipes and +primitives to Python developers. Our goal is for it to be your "cryptographic +standard library". It supports Python 3.9+ and PyPy3 7.3.11+. + +``cryptography`` includes both high level recipes and low level interfaces to +common cryptographic algorithms such as symmetric ciphers, message digests, and +key derivation functions. For example, to encrypt something with +``cryptography``'s high level symmetric encryption recipe: + +.. code-block:: pycon + + >>> from cryptography.fernet import Fernet + >>> # Put this somewhere safe! + >>> key = Fernet.generate_key() + >>> f = Fernet(key) + >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") + >>> token + b'...' + >>> f.decrypt(token) + b'A really secret message. Not for prying eyes.' + +You can find more information in the `documentation`_. + +You can install ``cryptography`` with: + +.. code-block:: console + + $ pip install cryptography + +For full details see `the installation documentation`_. + +Discussion +~~~~~~~~~~ + +If you run into bugs, you can file them in our `issue tracker`_. + +We maintain a `cryptography-dev`_ mailing list for development discussion. + +You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get +involved. + +Security +~~~~~~~~ + +Need to report a security issue? Please consult our `security reporting`_ +documentation. + + +.. _`documentation`: https://cryptography.io/ +.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ +.. _`issue tracker`: https://github.com/pyca/cryptography/issues +.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _`security reporting`: https://cryptography.io/en/latest/security/ + diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/RECORD b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/RECORD new file mode 100644 index 0000000..5a9bb03 --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/RECORD @@ -0,0 +1,120 @@ +cryptography/__about__.py,sha256=SUJRVMWtZoUu-WdZLfY7p_s2xm5YQjNLFj80YrUP9F0,445 +cryptography/__init__.py,sha256=mthuUrTd4FROCpUYrTIqhjz6s6T9djAZrV7nZ1oMm2o,364 +cryptography/cobblestone.py,sha256=T_-F08-AUf3ljaypZeklNTV1hWObH57oo45mVSzk9wc,693 +cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087 +cryptography/fernet.py,sha256=2sLCPOmejhOVbudcS3QsM1PIuHbxCeRcRtWkncQ3mCo,7687 +cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +cryptography/utils.py,sha256=Ia7S0QZzS0ezwpIHQfY8G1e-o4GjrHijEXXjwAr1iuI,4635 +cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455 +cryptography/hazmat/_oid.py,sha256=Ohe2nUE6XjKx1UF6TAsGUy2v8GUJ-Vi9DS4yxSukt5U,18150 +cryptography/hazmat/asn1/__init__.py,sha256=YqYToHGFjLOKigRC00HGj6hrjEwbu1SPpAiu6-u-fao,812 +cryptography/hazmat/asn1/asn1.py,sha256=9mcfrmdvK7KtjhRYofMzAjW0u7nvqbfsvPfbhNQK1BQ,19152 +cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361 +cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305 +cryptography/hazmat/backends/openssl/backend.py,sha256=0NczFbiwGxfq9qi28oHYr08r_r7VQg4AXHjb0oFPwqA,10475 +cryptography/hazmat/bindings/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 +cryptography/hazmat/bindings/_rust.abi3.so,sha256=PWQjZkv_6Sb9kdGRPRxd3aXDHuf_HK4G_ItxxHyVAaE,14389392 +cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=uUnnvOq_uameYnBNpmsv3SRAVO0WQGpjI58aR1lL4Kw,2285 +cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=T_5TpYO8bghIPjAQ3BtAABqw-CcYskHp92wm5PNY6dc,228 +cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354 +cryptography/hazmat/bindings/_rust/cobblestone.pyi,sha256=9lUf1W1hTrszEJ4YpScJNIPSD9BOM7o-C82-mtSDG9o,1325 +cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=MBmOZzLTdmPJ6-1K6Aq3PTuHJ1MGgRfIu0hIgag7ocE,3866 +cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640 +cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020 +cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605 +cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601 +cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757 +cryptography/hazmat/bindings/_rust/x509.pyi,sha256=LVT4htBNse5gijQh4GhVNYEbAO0E1ANgE28tWqw3g4I,10211 +cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=O6GOyvDxt6ylicB2aFGuu5RcGZy9UjKnYqGR8rqzvdw,1578 +cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=7d--xdc0vuzRe4S2uuQaGm-9GGKv4NcSLQcLyWcaD6s,4582 +cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315 +cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564 +cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564 +cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299 +cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691 +cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532 +cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514 +cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=bFe3T13UeyRInUJMD-R5ArGTGLqWDiWo2Lv2KGzUbf4,1076 +cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702 +cryptography/hazmat/bindings/_rust/openssl/hpke.pyi,sha256=p_hGLn6YH-EarJF1V5bUsUtjipviEApcR5O0sUHJLtc,2914 +cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=HiiLdEB9nqMsTvMwiFppQpfPz6fHUz9_gpjEB_XAOXA,6619 +cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912 +cryptography/hazmat/bindings/_rust/openssl/keywrap.pyi,sha256=mGCJEoQ4lxi4CROTBEuUzb9U4ky8n52L3iDvCOXNBRI,733 +cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi,sha256=H84XDW0TQ3LHhdGJD5uPaDT5ijEiK6MZytXYc8rBNf4,1421 +cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi,sha256=byoeus4-lIOlWlEiRQdCc00qCkXpOB5peBY6yo9ik8s,835 +cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585 +cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364 +cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523 +cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505 +cryptography/hazmat/bindings/openssl/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 +cryptography/hazmat/bindings/openssl/_conditional.py,sha256=vfzi-xHdStAcJQjLqqOlSos94L8D_tqFtBe7Ovw-KtY,5611 +cryptography/hazmat/bindings/openssl/binding.py,sha256=FsuLxbTnrqW60-dAWtakgufeq7TnqaQai1Pc7Dowrjo,3706 +cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 +cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 +cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=WSPjM2sXfrLDXrtN5R7N6rA1XF7b93I1e_lvD4yx2oA,3752 +cryptography/hazmat/decrepit/ciphers/modes.py,sha256=Oq_PEwCke5OLczOfr_vzAOJ6wPx-rlsvHAXPBuh5b9o,1649 +cryptography/hazmat/primitives/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 +cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532 +cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522 +cryptography/hazmat/primitives/_modes.py,sha256=_EiAOD8Jb6WpFXluwkcUT3ECz_TH8xjGvbQlGkNm59Q,3075 +cryptography/hazmat/primitives/_serialization.py,sha256=hi0xJblBAZ8pmZx2lWa-lruphxvvvG3g9DNK0G8Odfs,4440 +cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338 +cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422 +cryptography/hazmat/primitives/hashes.py,sha256=Srtwgc3_pFvZfIhRj9e1p4Wdi-F_PpleGHlqJARgtOg,7916 +cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423 +cryptography/hazmat/primitives/hpke.py,sha256=RsHissC5l-dTPn1p2JbcrIrAnDBrLqM5ugBFSGpmKu4,865 +cryptography/hazmat/primitives/keywrap.py,sha256=t9t8KZuzZ4Us30ASUhI27MZPPPKy4EERRDkAK-lM7TQ,735 +cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865 +cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355 +cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 +cryptography/hazmat/primitives/asymmetric/dh.py,sha256=Rnt2fLaDpQEjQSX8fNtlmTXOJHjlt_DKQZ1Vlfhdja4,5793 +cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=kQzTViqAI9PiELNOBco_n6MfP3N9ehIPkSduOpupt0M,4482 +cryptography/hazmat/primitives/asymmetric/ec.py,sha256=LklVCLLxbbQzqiE6HRaYTRauLMphYUw3tE6c8oBIxYQ,10183 +cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=mbffLvs-3PgCDeg1rQXVXh7GLntlVL4ATjkIEc4pt5M,2998 +cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=n0dK6y-VLxuw-zvrDxuPT4598hymgX-1Ry_jq9aUQhE,4002 +cryptography/hazmat/primitives/asymmetric/mldsa.py,sha256=LHMaaU0m66EsSrSodWf4e2kdmdDRTEGRC1y-fCKxGK0,13803 +cryptography/hazmat/primitives/asymmetric/mlkem.py,sha256=wvVkeFT-4of-VcUAER2-zI_5hXT6rwTJPMCQ8gF9GTA,7901 +cryptography/hazmat/primitives/asymmetric/padding.py,sha256=jbgajvGHYwkPjMDljHu5lxMBlDfmCxWUe2AF2S6KE10,3678 +cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=lIE7lGe449W5URLTKCpvFGerITouKoZV9GwuTzScsSo,8492 +cryptography/hazmat/primitives/asymmetric/types.py,sha256=SjJhTrnFRLlTPdYrBD1poMi6cjYG-fh0fSIaQn3QUiw,2588 +cryptography/hazmat/primitives/asymmetric/utils.py,sha256=Qs8Re9GFPjW_tNp_73IeJEjPCf0slOIsWOxo6qymT6k,821 +cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=lQcgUk-Piubj8ynFNWQeYme3tYZMgHQqkRKkIDOHLzo,3888 +cryptography/hazmat/primitives/asymmetric/x448.py,sha256=b37ig7k7poG6SJDry42j-ElCj5q4eQ0X5CFmN0Sn8z8,3913 +cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680 +cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634 +cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=IGfCycYJOh1TvoI34rfw8KfJ_xmt1p_DpBht2Fghceo,3496 +cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253 +cryptography/hazmat/primitives/ciphers/modes.py,sha256=H7AZSgJiSTBCi0grL97NxakS950JyFKYLsra8tjHPxQ,6003 +cryptography/hazmat/primitives/kdf/__init__.py,sha256=v3yiYBGU272EojNXbwfYZdbbfI9cVOCCG3nXhTDda3k,1037 +cryptography/hazmat/primitives/kdf/argon2.py,sha256=ZJx-enUlAA4o7b46C1wlzG_XAQQW0wIkFgUKkrM_wA8,632 +cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=BFnOKS72txKF0yQvASr0Na7uhzvLHpUCckK5iNAC_aQ,591 +cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543 +cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=C3w99vjFqhqzAxzFOH4zzvVoHkb5AC6Lz6AEQGV7d_g,737 +cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=Xchkk99s-Mk6b6KSCouqdk8FVyiNVOSFIenmnW3tLgQ,468 +cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590 +cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=QKjhRehuTsAstL384bKfvjuv1yfdamAHVhsBRWen2Vw,456 +cryptography/hazmat/primitives/serialization/__init__.py,sha256=fXcu49ugL9rxhpRl_wZjnMqE9DCkhCMcsRxfj_qTveg,2217 +cryptography/hazmat/primitives/serialization/base.py,sha256=SABrvo0S86QcoBlj7DpjeLWy2lzQMryiioJ6DrEYQVA,651 +cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104 +cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=mFM7OFuZ8cCxUGUoo4Cof6BnCHc_Ibx1AQjjfxnPlxo,13998 +cryptography/hazmat/primitives/serialization/ssh.py,sha256=FisXe_nUKdPGfqENVhKpmoazmaI8qH8Ge-VGbc0dykw,53592 +cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258 +cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256 +cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652 +cryptography/x509/__init__.py,sha256=0KVNTmRtdYNX_i_ewsTNzbTm2e1qyfoOhc4emog5hL4,8253 +cryptography/x509/base.py,sha256=UIMKkwmsx10BR3_gnBRBCBTwQp1-O8wkfVm7azH-_mE,28311 +cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797 +cryptography/x509/extensions.py,sha256=-iXcwWnIL1zl5Ml3BVJFkEo_71ncXe84ehvqzW1sK4M,77975 +cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836 +cryptography/x509/name.py,sha256=oI2w6VdY8zgw7qpNhlxEx512W0AhWDXQrDYf5EsM2PY,15566 +cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699 +cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931 +cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958 +cryptography-50.0.1.dist-info/METADATA,sha256=jptVcNpGhoSO5ca7g__8IkvN35eTE2cx3QUM4MBf_-I,4343 +cryptography-50.0.1.dist-info/WHEEL,sha256=ObQlzmyJjoP4uM3utl2uaQ06ufI4LKnDhg53v200B3o,109 +cryptography-50.0.1.dist-info/RECORD,, +cryptography-50.0.1.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197 +cryptography-50.0.1.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 +cryptography-50.0.1.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 +cryptography-50.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json,sha256=m9rCnuTZv9tCQeBPD9vRLlti_jFwa9OovtKMjK_LVaA,45685 +cryptography-50.0.1.dist-info/sboms/sbom.json,sha256=S9XP7BDLleOELcWlLWOrYuGy3RtuaXtFh5A-yN5T9yA,1206 diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/WHEEL b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/WHEEL new file mode 100644 index 0000000..08b80b3 --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: maturin (1.14.1) +Root-Is-Purelib: false +Tag: cp311-abi3-manylinux_2_34_x86_64 + diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE new file mode 100644 index 0000000..b11f379 --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE @@ -0,0 +1,3 @@ +This software is made available under the terms of *either* of the licenses +found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made +under the terms of *both* these licenses. diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.APACHE b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.APACHE new file mode 100644 index 0000000..62589ed --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://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 + + 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. diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.BSD b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.BSD new file mode 100644 index 0000000..ec1a29d --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/licenses/LICENSE.BSD @@ -0,0 +1,27 @@ +Copyright (c) Individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of PyCA Cryptography nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json new file mode 100644 index 0000000..e7df0f2 --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/cryptography-rust.cyclonedx.json @@ -0,0 +1,1365 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "version": 1, + "serialNumber": "urn:uuid:8937a838-8d73-4fdd-9a20-bac2da7b0240", + "metadata": { + "timestamp": "2026-08-25T19:33:44.118311124Z", + "tools": [ + { + "vendor": "CycloneDX", + "name": "cargo-cyclonedx", + "version": "0.5.9" + } + ], + "authors": [ + { + "name": "The cryptography developers", + "email": "cryptography-dev@python.org" + } + ], + "component": { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust#cryptography-rust@0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-rust", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-rust@0.50.1?download_url=file://.", + "components": [ + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust#cryptography-rust@0.50.1 bin-target-0", + "name": "cryptography_rust", + "version": "0.50.1", + "purl": "pkg:cargo/cryptography-rust@0.50.1?download_url=file://.#src/lib.rs" + } + ] + }, + "properties": [ + { + "name": "cdx:rustc:sbom:target:all_targets", + "value": "true" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-cffi#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-cffi", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-cffi@0.50.1?download_url=file://cryptography-cffi" + }, + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-crypto#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-crypto", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-crypto@0.50.1?download_url=file://cryptography-crypto" + }, + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-keepalive#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-keepalive", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-keepalive@0.50.1?download_url=file://cryptography-keepalive" + }, + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-key-parsing#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-key-parsing", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-key-parsing@0.50.1?download_url=file://cryptography-key-parsing" + }, + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-openssl#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-openssl", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-openssl@0.50.1?download_url=file://cryptography-openssl" + }, + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-x509", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-x509@0.50.1?download_url=file://cryptography-x509" + }, + { + "type": "library", + "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509-verification#0.50.1", + "author": "The cryptography developers ", + "name": "cryptography-x509-verification", + "version": "0.50.1", + "scope": "required", + "licenses": [ + { + "expression": "Apache-2.0 OR BSD-3-Clause" + } + ], + "purl": "pkg:cargo/cryptography-x509-verification@0.50.1?download_url=file://cryptography-x509-verification" + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", + "author": "Alex Gaynor ", + "name": "asn1", + "version": "0.24.1", + "description": "ASN.1 (DER) parser and writer for Rust.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "c9795210620c0cb3f9a7ce4f882808c38e1ef7b347c90591dceae0886e031fb1" + } + ], + "licenses": [ + { + "expression": "BSD-3-Clause" + } + ], + "purl": "pkg:cargo/asn1@0.24.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/alex/rust-asn1" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1", + "author": "Alex Gaynor ", + "name": "asn1_derive", + "version": "0.24.1", + "description": "#[derive] support for asn1", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "909e307f1cc32bb8bccbd98f446e6d1bf03fa30f7b53a4337da7181ad30fa11a" + } + ], + "licenses": [ + { + "expression": "BSD-3-Clause" + } + ], + "purl": "pkg:cargo/asn1_derive@0.24.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/alex/rust-asn1" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0", + "author": "Marshall Pierce ", + "name": "base64", + "version": "0.23.0", + "description": "encodes and decodes base64 as bytes or utf8", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/base64@0.23.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/base64" + }, + { + "type": "vcs", + "url": "https://github.com/marshallpierce/rust-base64" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.13.1", + "author": "The Rust Project Developers", + "name": "bitflags", + "version": "2.13.1", + "description": "A macro to generate structures which behave like bitflags. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/bitflags@2.13.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/bitflags" + }, + { + "type": "website", + "url": "https://github.com/bitflags/bitflags" + }, + { + "type": "vcs", + "url": "https://github.com/bitflags/bitflags" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0", + "author": "Alex Crichton ", + "name": "cc", + "version": "1.4.0", + "description": "A build-time dependency for Cargo build scripts to assist in invoking the native C compiler to compile native C code into a static archive to be linked into Rust code. ", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/cc@1.4.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/cc" + }, + { + "type": "website", + "url": "https://github.com/rust-lang/cc-rs" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/cc-rs" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", + "author": "Alex Crichton ", + "name": "cfg-if", + "version": "1.0.4", + "description": "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/cfg-if@1.0.4", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/rust-lang/cfg-if" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", + "name": "find-msvc-tools", + "version": "0.1.9", + "description": "Find windows-specific tools, read MSVC versions from the registry and from COM interfaces", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/find-msvc-tools@0.1.9", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/find-msvc-tools" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/cc-rs" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1", + "author": "Steven Fackler ", + "name": "foreign-types-shared", + "version": "0.1.1", + "description": "An internal crate used by foreign-types", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/foreign-types-shared@0.1.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/sfackler/foreign-types" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", + "author": "Steven Fackler ", + "name": "foreign-types", + "version": "0.3.2", + "description": "A framework for Rust wrappers over C APIs", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/foreign-types@0.3.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/sfackler/foreign-types" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "name": "heck", + "version": "0.5.0", + "description": "heck is a case conversion library.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/heck@0.5.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/withoutboats/heck" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18", + "author": "David Tolnay ", + "name": "itoa", + "version": "1.0.18", + "description": "Fast integer primitive to string conversion", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/itoa@1.0.18", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/itoa" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/itoa" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189", + "name": "libc", + "version": "0.2.189", + "description": "Raw FFI bindings to platform libraries like libc.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/libc@0.2.189", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/rust-lang/libc" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4", + "author": "Aleksey Kladov ", + "name": "once_cell", + "version": "1.21.4", + "description": "Single assignment cells and lazy values.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/once_cell@1.21.4", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/once_cell" + }, + { + "type": "vcs", + "url": "https://github.com/matklad/once_cell" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1", + "name": "openssl-macros", + "version": "0.1.1", + "description": "Internal macros used by the openssl crate.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/openssl-macros@0.1.1" + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117", + "author": "Alex Crichton , Steven Fackler ", + "name": "openssl-sys", + "version": "0.9.117", + "description": "FFI bindings to OpenSSL", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/openssl-sys@0.9.117", + "externalReferences": [ + { + "type": "other", + "url": "openssl" + }, + { + "type": "vcs", + "url": "https://github.com/rust-openssl/rust-openssl" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81", + "author": "Steven Fackler ", + "name": "openssl", + "version": "0.10.81", + "description": "OpenSSL bindings", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" + } + ], + "licenses": [ + { + "expression": "Apache-2.0" + } + ], + "purl": "pkg:cargo/openssl@0.10.81", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/rust-openssl/rust-openssl" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0", + "author": "Jonathan Creekmore ", + "name": "pem", + "version": "4.0.0", + "description": "Parse and encode PEM-encoded data.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/pem@4.0.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/pem/" + }, + { + "type": "website", + "url": "https://github.com/jcreekmore/pem-rs.git" + }, + { + "type": "vcs", + "url": "https://github.com/jcreekmore/pem-rs.git" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33", + "author": "Alex Crichton ", + "name": "pkg-config", + "version": "0.3.33", + "description": "A library to run the pkg-config system tool at build time in order to be used in Cargo build scripts. ", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pkg-config@0.3.33", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/pkg-config" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/pkg-config-rs" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.14.0", + "name": "portable-atomic", + "version": "1.14.0", + "description": "Portable atomic types including support for 128-bit atomics, atomic float, etc. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/portable-atomic@1.14.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/taiki-e/portable-atomic" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "author": "David Tolnay , Alex Crichton ", + "name": "proc-macro2", + "version": "1.0.107", + "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/proc-macro2@1.0.107", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/proc-macro2" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/proc-macro2" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-build-config", + "version": "0.29.0", + "description": "Build configuration for the PyO3 ecosystem", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-build-config@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-ffi", + "version": "0.29.0", + "description": "Python-API bindings for the PyO3 ecosystem", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-ffi@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "other", + "url": "python" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-macros-backend", + "version": "0.29.0", + "description": "Code generation for PyO3 package", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-macros-backend@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-macros", + "version": "0.29.0", + "description": "Proc macros for PyO3 package", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-macros@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3", + "version": "0.29.0", + "description": "Bindings to Python interpreter", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3@0.29.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/crate/pyo3/" + }, + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "other", + "url": "pyo3-python" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "author": "David Tolnay ", + "name": "quote", + "version": "1.0.47", + "description": "Quasi-quoting macro quote!(...)", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/quote@1.0.47", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/quote/" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/quote" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.3.0", + "author": "Lukas Bergdoll ", + "name": "self_cell", + "version": "1.3.0", + "description": "Safe-to-use proc-macro-free self-referential structs in stable Rust.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR GPL-2.0-only" + } + ], + "purl": "pkg:cargo/self_cell@1.3.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/self_cell" + }, + { + "type": "vcs", + "url": "https://github.com/Voultapher/self_cell" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@2.0.1", + "author": "comex , Fenhl , Adrian Taylor , Alex Touchet , Daniel Parks , Garrett Berg ", + "name": "shlex", + "version": "2.0.1", + "description": "Split a string into shell words, like Python's shlex.", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/shlex@2.0.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/comex/rust-shlex" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119", + "author": "David Tolnay ", + "name": "syn", + "version": "2.0.119", + "description": "Parser for Rust source code", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/syn@2.0.119", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/syn" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/syn" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5", + "author": "Dan Gohman ", + "name": "target-lexicon", + "version": "0.13.5", + "description": "LLVM target triple types", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 WITH LLVM-exception" + } + ], + "purl": "pkg:cargo/target-lexicon@0.13.5", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/target-lexicon/" + }, + { + "type": "vcs", + "url": "https://github.com/bytecodealliance/target-lexicon" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24", + "author": "David Tolnay ", + "name": "unicode-ident", + "version": "1.0.24", + "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + } + ], + "licenses": [ + { + "expression": "(MIT OR Apache-2.0) AND Unicode-3.0" + } + ], + "purl": "pkg:cargo/unicode-ident@1.0.24", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/unicode-ident" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/unicode-ident" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15", + "author": "Jim McGrath ", + "name": "vcpkg", + "version": "0.2.15", + "description": "A library to find native dependencies in a vcpkg tree at build time in order to be used in Cargo build scripts. ", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/vcpkg@0.2.15", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/vcpkg" + }, + { + "type": "vcs", + "url": "https://github.com/mcgoo/vcpkg-rs" + } + ] + } + ], + "dependencies": [ + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust#cryptography-rust@0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", + "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0", + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-cffi#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-crypto#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-keepalive#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-key-parsing#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-openssl#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509-verification#0.50.1", + "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1", + "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81", + "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117", + "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.3.0" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-cffi#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0", + "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117", + "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-crypto#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-keepalive#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-key-parsing#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-crypto#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-openssl#0.50.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509#0.50.1", + "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81", + "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117", + "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-openssl#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", + "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", + "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1", + "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81", + "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1" + ] + }, + { + "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509-verification#0.50.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", + "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpHjnbGg/cryptography-50.0.1/src/rust/cryptography-x509#0.50.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1", + "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.13.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9", + "registry+https://github.com/rust-lang/crates.io-index#shlex@2.0.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0", + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189", + "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33", + "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.13.1", + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4", + "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2", + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189", + "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1", + "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.14.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189", + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4", + "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.14.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.3.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@2.0.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47", + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15" + } + ] +} \ No newline at end of file diff --git a/source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/sbom.json b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/sbom.json new file mode 100644 index 0000000..b35f4b1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography-50.0.1.dist-info/sboms/sbom.json @@ -0,0 +1,43 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "version": 1, + "serialNumber": "urn:uuid:8993a62f-53da-4d3f-b423-fc6d6d57604c", + "metadata": { + "timestamp": "2026-08-25T18:07:43Z" + }, + "components": [ + { + "type": "library", + "name": "openssl", + "version": "4.0.2", + "purl": "pkg:generic/openssl@4.0.2?download_url=https://github.com/openssl/openssl/releases/download/openssl-4.0.2/openssl-4.0.2.tar.gz", + "hashes": [ + { + "alg": "SHA-256", + "content": "736b467530f916737b7031310ccb21d8218c6229e61e8e160cd1d3458cd543a8" + } + ], + "externalReferences": [ + { + "type": "distribution", + "url": "https://github.com/openssl/openssl/releases/download/openssl-4.0.2/openssl-4.0.2.tar.gz" + } + ], + "properties": [ + { + "name": "build:operating-system", + "value": "linux" + }, + { + "name": "build:architecture", + "value": "x86_64" + }, + { + "name": "build:flags", + "value": "no-zlib no-shared no-module no-comp no-apps no-docs no-sm2-precomp no-atexit enable-ec_nistp_64_gcc_128" + } + ] + } + ] +} diff --git a/source/target-vendors/cp312/cryptography/__about__.py b/source/target-vendors/cp312/cryptography/__about__.py new file mode 100644 index 0000000..d6fc1ae --- /dev/null +++ b/source/target-vendors/cp312/cryptography/__about__.py @@ -0,0 +1,17 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +__all__ = [ + "__author__", + "__copyright__", + "__version__", +] + +__version__ = "50.0.1" + + +__author__ = "The Python Cryptographic Authority and individual contributors" +__copyright__ = f"Copyright 2013-2026 {__author__}" diff --git a/source/target-vendors/cp312/cryptography/__init__.py b/source/target-vendors/cp312/cryptography/__init__.py new file mode 100644 index 0000000..d374f75 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/__init__.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.__about__ import __author__, __copyright__, __version__ + +__all__ = [ + "__author__", + "__copyright__", + "__version__", +] diff --git a/source/target-vendors/cp312/cryptography/cobblestone.py b/source/target-vendors/cp312/cryptography/cobblestone.py new file mode 100644 index 0000000..09f67af --- /dev/null +++ b/source/target-vendors/cp312/cryptography/cobblestone.py @@ -0,0 +1,21 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import ( + cobblestone as _cobblestone, +) + +Cobblestone128Decryptor = _cobblestone.Cobblestone128Decryptor +Cobblestone128Encryptor = _cobblestone.Cobblestone128Encryptor +Cobblestone256Decryptor = _cobblestone.Cobblestone256Decryptor +Cobblestone256Encryptor = _cobblestone.Cobblestone256Encryptor + +__all__ = [ + "Cobblestone128Decryptor", + "Cobblestone128Encryptor", + "Cobblestone256Decryptor", + "Cobblestone256Encryptor", +] diff --git a/source/target-vendors/cp312/cryptography/exceptions.py b/source/target-vendors/cp312/cryptography/exceptions.py new file mode 100644 index 0000000..fe125ea --- /dev/null +++ b/source/target-vendors/cp312/cryptography/exceptions.py @@ -0,0 +1,52 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import typing + +from cryptography.hazmat.bindings._rust import exceptions as rust_exceptions + +if typing.TYPE_CHECKING: + from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +_Reasons = rust_exceptions._Reasons + + +class UnsupportedAlgorithm(Exception): + def __init__(self, message: str, reason: _Reasons | None = None) -> None: + super().__init__(message) + self._reason = reason + + +class AlreadyFinalized(Exception): + pass + + +class AlreadyUpdated(Exception): + pass + + +class NotYetFinalized(Exception): + pass + + +class InvalidTag(Exception): + pass + + +class InvalidSignature(Exception): + pass + + +class InternalError(Exception): + def __init__( + self, msg: str, err_code: list[rust_openssl.OpenSSLError] + ) -> None: + super().__init__(msg) + self.err_code = err_code + + +class InvalidKey(Exception): + pass diff --git a/source/target-vendors/cp312/cryptography/fernet.py b/source/target-vendors/cp312/cryptography/fernet.py new file mode 100644 index 0000000..582e594 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/fernet.py @@ -0,0 +1,240 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import base64 +import binascii +import os +import time +import typing +from collections.abc import Iterable + +from cryptography import utils +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import hashes, padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.hmac import HMAC + + +class InvalidToken(Exception): + pass + + +_MAX_CLOCK_SKEW = 60 + +# Hoisted to module level so each operation doesn't reconstruct them. +_PKCS7_128 = padding.PKCS7(128) +_SHA256 = hashes.SHA256() + + +class Fernet: + def __init__( + self, + key: bytes | str, + backend: typing.Any = None, + ) -> None: + try: + key = base64.urlsafe_b64decode(key) + except binascii.Error as exc: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) from exc + if len(key) != 32: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) + + self._signing_key = key[:16] + self._encryption_key = key[16:] + self._aes = algorithms.AES(self._encryption_key) + + @classmethod + def generate_key(cls) -> bytes: + return base64.urlsafe_b64encode(os.urandom(32)) + + def encrypt(self, data: bytes) -> bytes: + return self.encrypt_at_time(data, int(time.time())) + + def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: + iv = os.urandom(16) + return self._encrypt_from_parts(data, current_time, iv) + + def _encrypt_from_parts( + self, data: bytes, current_time: int, iv: bytes + ) -> bytes: + utils._check_bytes("data", data) + + padder = _PKCS7_128.padder() + padded_data = padder.update(data) + padder.finalize() + encryptor = Cipher(self._aes, modes.CBC(iv)).encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + basic_parts = ( + b"\x80" + + current_time.to_bytes(length=8, byteorder="big") + + iv + + ciphertext + ) + + h = HMAC(self._signing_key, _SHA256) + h.update(basic_parts) + hmac = h.finalize() + return base64.urlsafe_b64encode(basic_parts + hmac) + + def decrypt(self, token: bytes | str, ttl: int | None = None) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(token) + if ttl is None: + time_info = None + else: + time_info = (ttl, int(time.time())) + return self._decrypt_data(data, timestamp, time_info) + + def decrypt_at_time( + self, token: bytes | str, ttl: int, current_time: int + ) -> bytes: + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, (ttl, current_time)) + + def extract_timestamp(self, token: bytes | str) -> int: + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + @staticmethod + def _get_unverified_token_data(token: bytes | str) -> tuple[int, bytes]: + if not isinstance(token, (str, bytes)): + raise TypeError("token must be bytes or str") + + try: + data = base64.urlsafe_b64decode(token) + except (TypeError, binascii.Error): + raise InvalidToken + + if not data or data[0] != 0x80: + raise InvalidToken + + if len(data) < 9: + raise InvalidToken + + timestamp = int.from_bytes(data[1:9], byteorder="big") + return timestamp, data + + def _verify_signature(self, data: bytes) -> None: + h = HMAC(self._signing_key, _SHA256) + h.update(memoryview(data)[:-32]) + try: + h.verify(data[-32:]) + except InvalidSignature: + raise InvalidToken + + def _decrypt_data( + self, + data: bytes, + timestamp: int, + time_info: tuple[int, int] | None, + ) -> bytes: + if time_info is not None: + ttl, current_time = time_info + if timestamp + ttl < current_time: + raise InvalidToken + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + self._verify_signature(data) + + mv = memoryview(data) + iv = data[9:25] + ciphertext = mv[25:-32] + decryptor = Cipher(self._aes, modes.CBC(iv)).decryptor() + plaintext_padded = decryptor.update(ciphertext) + try: + plaintext_padded += decryptor.finalize() + except ValueError: + raise InvalidToken + unpadder = _PKCS7_128.unpadder() + + unpadded = unpadder.update(plaintext_padded) + try: + unpadded += unpadder.finalize() + except ValueError: + raise InvalidToken + return unpadded + + +class MultiFernet: + def __init__(self, fernets: Iterable[Fernet]): + fernets = list(fernets) + if not fernets: + raise ValueError( + "MultiFernet requires at least one Fernet instance" + ) + self._fernets = fernets + + def encrypt(self, msg: bytes) -> bytes: + return self.encrypt_at_time(msg, int(time.time())) + + def encrypt_at_time(self, msg: bytes, current_time: int) -> bytes: + return self._fernets[0].encrypt_at_time(msg, current_time) + + def rotate(self, msg: bytes | str) -> bytes: + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + + def decrypt(self, msg: bytes | str, ttl: int | None = None) -> bytes: + if ttl is None: + time_info = None + else: + time_info = (ttl, int(time.time())) + # Parse the token once rather than once per key. + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + return f._decrypt_data(data, timestamp, time_info) + except InvalidToken: + pass + raise InvalidToken + + def decrypt_at_time( + self, msg: bytes | str, ttl: int, current_time: int + ) -> bytes: + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + # Parse the token once rather than once per key. + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + return f._decrypt_data(data, timestamp, (ttl, current_time)) + except InvalidToken: + pass + raise InvalidToken + + def extract_timestamp(self, msg: bytes | str) -> int: + # Parse the token once rather than once per key. + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + f._verify_signature(data) + return timestamp + except InvalidToken: + pass + raise InvalidToken diff --git a/source/target-vendors/cp312/cryptography/hazmat/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/__init__.py new file mode 100644 index 0000000..b9f1187 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/__init__.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +""" +Hazardous Materials + +This is a "Hazardous Materials" module. You should ONLY use it if you're +100% absolutely sure that you know what you're doing because this module +is full of land mines, dragons, and dinosaurs with laser guns. +""" diff --git a/source/target-vendors/cp312/cryptography/hazmat/_oid.py b/source/target-vendors/cp312/cryptography/hazmat/_oid.py new file mode 100644 index 0000000..244a1b3 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/_oid.py @@ -0,0 +1,373 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import ( + ObjectIdentifier as ObjectIdentifier, +) +from cryptography.hazmat.primitives import hashes + + +class ExtensionOID: + SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") + SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") + KEY_USAGE = ObjectIdentifier("2.5.29.15") + PRIVATE_KEY_USAGE_PERIOD = ObjectIdentifier("2.5.29.16") + SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") + ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") + BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") + NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") + CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") + CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") + POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33") + AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35") + POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36") + EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37") + FRESHEST_CRL = ObjectIdentifier("2.5.29.46") + INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54") + ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28") + AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1") + SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11") + OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5") + TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24") + CRL_NUMBER = ObjectIdentifier("2.5.29.20") + DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27") + PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier( + "1.3.6.1.4.1.11129.2.4.2" + ) + PRECERT_POISON = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3") + SIGNED_CERTIFICATE_TIMESTAMPS = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.5") + MS_CERTIFICATE_TEMPLATE = ObjectIdentifier("1.3.6.1.4.1.311.21.7") + ADMISSIONS = ObjectIdentifier("1.3.36.8.3.3") + + +class OCSPExtensionOID: + NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2") + ACCEPTABLE_RESPONSES = ObjectIdentifier("1.3.6.1.5.5.7.48.1.4") + + +class CRLEntryExtensionOID: + CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") + CRL_REASON = ObjectIdentifier("2.5.29.21") + INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") + + +class NameOID: + COMMON_NAME = ObjectIdentifier("2.5.4.3") + COUNTRY_NAME = ObjectIdentifier("2.5.4.6") + LOCALITY_NAME = ObjectIdentifier("2.5.4.7") + STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8") + STREET_ADDRESS = ObjectIdentifier("2.5.4.9") + ORGANIZATION_IDENTIFIER = ObjectIdentifier("2.5.4.97") + ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10") + ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11") + SERIAL_NUMBER = ObjectIdentifier("2.5.4.5") + SURNAME = ObjectIdentifier("2.5.4.4") + GIVEN_NAME = ObjectIdentifier("2.5.4.42") + TITLE = ObjectIdentifier("2.5.4.12") + INITIALS = ObjectIdentifier("2.5.4.43") + GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44") + X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45") + DN_QUALIFIER = ObjectIdentifier("2.5.4.46") + PSEUDONYM = ObjectIdentifier("2.5.4.65") + USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1") + DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25") + EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1") + JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3") + JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1") + JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier( + "1.3.6.1.4.1.311.60.2.1.2" + ) + BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15") + POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16") + POSTAL_CODE = ObjectIdentifier("2.5.4.17") + INN = ObjectIdentifier("1.2.643.3.131.1.1") + OGRN = ObjectIdentifier("1.2.643.100.1") + SNILS = ObjectIdentifier("1.2.643.100.3") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + UNSIGNED = ObjectIdentifier("1.3.6.1.5.5.7.25.1") + + +class SignatureAlgorithmOID: + RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4") + RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5") + # This is an alternate OID for RSA with SHA1 that is occasionally seen + _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29") + RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14") + RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11") + RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12") + RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13") + RSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.13") + RSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.14") + RSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.15") + RSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.16") + RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") + ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1") + ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1") + ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2") + ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3") + ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4") + ECDSA_WITH_SHA3_224 = ObjectIdentifier("2.16.840.1.101.3.4.3.9") + ECDSA_WITH_SHA3_256 = ObjectIdentifier("2.16.840.1.101.3.4.3.10") + ECDSA_WITH_SHA3_384 = ObjectIdentifier("2.16.840.1.101.3.4.3.11") + ECDSA_WITH_SHA3_512 = ObjectIdentifier("2.16.840.1.101.3.4.3.12") + DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3") + DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1") + DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2") + DSA_WITH_SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.3.3") + DSA_WITH_SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.3.4") + ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") + ML_DSA_44 = ObjectIdentifier("2.16.840.1.101.3.4.3.17") + ML_DSA_65 = ObjectIdentifier("2.16.840.1.101.3.4.3.18") + ML_DSA_87 = ObjectIdentifier("2.16.840.1.101.3.4.3.19") + GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3") + GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2") + GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3") + UNSIGNED = ObjectIdentifier("1.3.6.1.5.5.7.6.36") + + +_SIG_OIDS_TO_HASH: dict[ObjectIdentifier, hashes.HashAlgorithm | None] = { + SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(), + SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.RSA_WITH_SHA3_224: hashes.SHA3_224(), + SignatureAlgorithmOID.RSA_WITH_SHA3_256: hashes.SHA3_256(), + SignatureAlgorithmOID.RSA_WITH_SHA3_384: hashes.SHA3_384(), + SignatureAlgorithmOID.RSA_WITH_SHA3_512: hashes.SHA3_512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_224: hashes.SHA3_224(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_256: hashes.SHA3_256(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_384: hashes.SHA3_384(), + SignatureAlgorithmOID.ECDSA_WITH_SHA3_512: hashes.SHA3_512(), + SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(), + SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(), + SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(), + SignatureAlgorithmOID.ED25519: None, + SignatureAlgorithmOID.ED448: None, + SignatureAlgorithmOID.ML_DSA_44: None, + SignatureAlgorithmOID.ML_DSA_65: None, + SignatureAlgorithmOID.ML_DSA_87: None, + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None, + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None, + SignatureAlgorithmOID.UNSIGNED: None, +} + + +class HashAlgorithmOID: + SHA1 = ObjectIdentifier("1.3.14.3.2.26") + SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.2.4") + SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.2.1") + SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.2.2") + SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.2.3") + SHA3_224 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.224") + SHA3_256 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.256") + SHA3_384 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.384") + SHA3_512 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.512") + SHA3_224_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.7") + SHA3_256_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.8") + SHA3_384_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.9") + SHA3_512_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.10") + + +class PublicKeyAlgorithmOID: + DSA = ObjectIdentifier("1.2.840.10040.4.1") + EC_PUBLIC_KEY = ObjectIdentifier("1.2.840.10045.2.1") + RSAES_PKCS1_v1_5 = ObjectIdentifier("1.2.840.113549.1.1.1") + RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10") + X25519 = ObjectIdentifier("1.3.101.110") + X448 = ObjectIdentifier("1.3.101.111") + ED25519 = ObjectIdentifier("1.3.101.112") + ED448 = ObjectIdentifier("1.3.101.113") + ML_DSA_44 = ObjectIdentifier("2.16.840.1.101.3.4.3.17") + ML_DSA_65 = ObjectIdentifier("2.16.840.1.101.3.4.3.18") + ML_DSA_87 = ObjectIdentifier("2.16.840.1.101.3.4.3.19") + ML_KEM_768 = ObjectIdentifier("2.16.840.1.101.3.4.4.2") + ML_KEM_1024 = ObjectIdentifier("2.16.840.1.101.3.4.4.3") + + +class ExtendedKeyUsageOID: + SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1") + CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2") + CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3") + EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4") + TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8") + OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") + ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0") + SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") + KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") + IPSEC_IKE = ObjectIdentifier("1.3.6.1.5.5.7.3.17") + BUNDLE_SECURITY = ObjectIdentifier("1.3.6.1.5.5.7.3.35") + CERTIFICATE_TRANSPARENCY = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.4") + + +class OtherNameFormOID: + PERMANENT_IDENTIFIER = ObjectIdentifier("1.3.6.1.5.5.7.8.3") + HW_MODULE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.4") + DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") + NAI_REALM = ObjectIdentifier("1.3.6.1.5.5.7.8.8") + SMTP_UTF8_MAILBOX = ObjectIdentifier("1.3.6.1.5.5.7.8.9") + ACP_NODE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.10") + BUNDLE_EID = ObjectIdentifier("1.3.6.1.5.5.7.8.11") + + +class AuthorityInformationAccessOID: + CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") + OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") + + +class SubjectInformationAccessOID: + CA_REPOSITORY = ObjectIdentifier("1.3.6.1.5.5.7.48.5") + + +class CertificatePoliciesOID: + CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") + CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") + ANY_POLICY = ObjectIdentifier("2.5.29.32.0") + + +class AttributeOID: + CHALLENGE_PASSWORD = ObjectIdentifier("1.2.840.113549.1.9.7") + UNSTRUCTURED_NAME = ObjectIdentifier("1.2.840.113549.1.9.2") + + +_OID_NAMES = { + NameOID.COMMON_NAME: "commonName", + NameOID.COUNTRY_NAME: "countryName", + NameOID.LOCALITY_NAME: "localityName", + NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName", + NameOID.STREET_ADDRESS: "streetAddress", + NameOID.ORGANIZATION_NAME: "organizationName", + NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName", + NameOID.SERIAL_NUMBER: "serialNumber", + NameOID.SURNAME: "surname", + NameOID.GIVEN_NAME: "givenName", + NameOID.TITLE: "title", + NameOID.GENERATION_QUALIFIER: "generationQualifier", + NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier", + NameOID.DN_QUALIFIER: "dnQualifier", + NameOID.PSEUDONYM: "pseudonym", + NameOID.USER_ID: "userID", + NameOID.DOMAIN_COMPONENT: "domainComponent", + NameOID.EMAIL_ADDRESS: "emailAddress", + NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName", + NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName", + NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: ( + "jurisdictionStateOrProvinceName" + ), + NameOID.BUSINESS_CATEGORY: "businessCategory", + NameOID.POSTAL_ADDRESS: "postalAddress", + NameOID.POSTAL_CODE: "postalCode", + NameOID.INN: "INN", + NameOID.OGRN: "OGRN", + NameOID.SNILS: "SNILS", + NameOID.UNSTRUCTURED_NAME: "unstructuredName", + SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", + SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", + SignatureAlgorithmOID.RSASSA_PSS: "rsassaPss", + SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", + SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", + SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", + SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384", + SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512", + SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1", + SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224", + SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256", + SignatureAlgorithmOID.ED25519: "ed25519", + SignatureAlgorithmOID.ED448: "ed448", + SignatureAlgorithmOID.ML_DSA_44: "ML-DSA-44", + SignatureAlgorithmOID.ML_DSA_65: "ML-DSA-65", + SignatureAlgorithmOID.ML_DSA_87: "ML-DSA-87", + SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: ( + "GOST R 34.11-94 with GOST R 34.10-2001" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)" + ), + SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( + "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" + ), + HashAlgorithmOID.SHA1: "sha1", + HashAlgorithmOID.SHA224: "sha224", + HashAlgorithmOID.SHA256: "sha256", + HashAlgorithmOID.SHA384: "sha384", + HashAlgorithmOID.SHA512: "sha512", + HashAlgorithmOID.SHA3_224: "sha3_224", + HashAlgorithmOID.SHA3_256: "sha3_256", + HashAlgorithmOID.SHA3_384: "sha3_384", + HashAlgorithmOID.SHA3_512: "sha3_512", + HashAlgorithmOID.SHA3_224_NIST: "sha3_224", + HashAlgorithmOID.SHA3_256_NIST: "sha3_256", + HashAlgorithmOID.SHA3_384_NIST: "sha3_384", + HashAlgorithmOID.SHA3_512_NIST: "sha3_512", + PublicKeyAlgorithmOID.DSA: "dsaEncryption", + PublicKeyAlgorithmOID.EC_PUBLIC_KEY: "id-ecPublicKey", + PublicKeyAlgorithmOID.RSAES_PKCS1_v1_5: "rsaEncryption", + PublicKeyAlgorithmOID.X25519: "X25519", + PublicKeyAlgorithmOID.X448: "X448", + ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", + ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth", + ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning", + ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection", + ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping", + ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning", + ExtendedKeyUsageOID.SMARTCARD_LOGON: "msSmartcardLogin", + ExtendedKeyUsageOID.KERBEROS_PKINIT_KDC: "pkInitKDC", + ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", + ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", + ExtensionOID.KEY_USAGE: "keyUsage", + ExtensionOID.PRIVATE_KEY_USAGE_PERIOD: "privateKeyUsagePeriod", + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", + ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", + ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + "signedCertificateTimestampList" + ), + ExtensionOID.PRECERT_POISON: "ctPoison", + ExtensionOID.MS_CERTIFICATE_TEMPLATE: "msCertificateTemplate", + ExtensionOID.ADMISSIONS: "Admissions", + CRLEntryExtensionOID.CRL_REASON: "cRLReason", + CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate", + CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer", + ExtensionOID.NAME_CONSTRAINTS: "nameConstraints", + ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints", + ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies", + ExtensionOID.POLICY_MAPPINGS: "policyMappings", + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier", + ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints", + ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage", + ExtensionOID.FRESHEST_CRL: "freshestCRL", + ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy", + ExtensionOID.ISSUING_DISTRIBUTION_POINT: "issuingDistributionPoint", + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess", + ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess", + ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck", + ExtensionOID.CRL_NUMBER: "cRLNumber", + ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator", + ExtensionOID.TLS_FEATURE: "TLSFeature", + AuthorityInformationAccessOID.OCSP: "OCSP", + AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers", + SubjectInformationAccessOID.CA_REPOSITORY: "caRepository", + CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps", + CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice", + OCSPExtensionOID.NONCE: "OCSPNonce", + AttributeOID.CHALLENGE_PASSWORD: "challengePassword", +} diff --git a/source/target-vendors/cp312/cryptography/hazmat/asn1/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/asn1/__init__.py new file mode 100644 index 0000000..d19e2a6 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/asn1/__init__.py @@ -0,0 +1,47 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.asn1.asn1 import ( + TLV, + BitString, + Default, + Explicit, + GeneralizedTime, + IA5String, + Implicit, + Null, + PrintableString, + SetOf, + Size, + UTCTime, + Variant, + decode_der, + encode_der, + sequence, + set, + value_set, +) + +__all__ = [ + "TLV", + "BitString", + "Default", + "Explicit", + "GeneralizedTime", + "IA5String", + "Implicit", + "Null", + "PrintableString", + "SetOf", + "Size", + "UTCTime", + "Variant", + "decode_der", + "encode_der", + "sequence", + "set", + "value_set", +] diff --git a/source/target-vendors/cp312/cryptography/hazmat/asn1/asn1.py b/source/target-vendors/cp312/cryptography/hazmat/asn1/asn1.py new file mode 100644 index 0000000..62d3811 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/asn1/asn1.py @@ -0,0 +1,533 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import builtins +import dataclasses +import enum +import sys +import types +import typing + +if sys.version_info < (3, 11): + import typing_extensions + + LiteralString = typing_extensions.LiteralString +else: + LiteralString = typing.LiteralString + +from cryptography.hazmat.bindings._rust import declarative_asn1 +from cryptography.hazmat.bindings._rust import x509 as rust_x509 + +if sys.version_info < (3, 10): + NoneType = type(None) +else: + NoneType = types.NoneType # type: ignore[nonetype-type] + +T = typing.TypeVar("T", covariant=True) +U = typing.TypeVar("U") +Tag = typing.TypeVar("Tag", bound=LiteralString) + + +@dataclasses.dataclass(frozen=True) +class Variant(typing.Generic[U, Tag]): + """ + A tagged variant for CHOICE fields with the same underlying type. + + Use this when you have multiple CHOICE alternatives with the same type + and need to distinguish between them: + + foo: ( + Annotated[Variant[int, typing.Literal["IntA"]], Implicit(0)] + | Annotated[Variant[int, typing.Literal["IntB"]], Implicit(1)] + ) + + Usage: + example = Example(foo=Variant(5, "IntA")) + decoded.foo.value # The int value + decoded.foo.tag # "IntA" or "IntB" + """ + + value: U + tag: str + + +decode_der = declarative_asn1.decode_der +encode_der = declarative_asn1.encode_der + + +_X509_TYPES = ( + rust_x509.Certificate, + rust_x509.CertificateSigningRequest, + rust_x509.CertificateRevocationList, +) + + +def _check_x509_field_annotations( + field_type: typing.Any, + annotation: declarative_asn1.Annotation, + field_name: str, +) -> None: + if field_type in _X509_TYPES and isinstance(annotation.encoding, Implicit): + raise TypeError( + f"field '{field_name}' has an IMPLICIT annotation, but " + "IMPLICIT annotations are not supported for X.509 types." + ) + + +def _is_union(field_type: type) -> bool: + # NOTE: types.UnionType for `T | U`, typing.Union for `Union[T, U]`. + # TODO: Drop the `hasattr()` once the minimum supported Python version + # is >= 3.10. + union_types = ( + (types.UnionType, typing.Union) + if hasattr(types, "UnionType") + else (typing.Union,) + ) + return typing.get_origin(field_type) in union_types + + +def _resolve_type_aliases(field_type: typing.Any) -> typing.Any: + # Recursively resolve PEP 695 (`type X = ...`) type aliases (Python + # 3.12+) to their underlying value, so that the rest of the + # normalization logic never encounters an alias. Aliases can refer + # to other aliases and can appear at any level of nesting (e.g. + # inside `Annotated[...]`, unions, or `list[...]`). + if sys.version_info < (3, 12): + return field_type + + while isinstance(field_type, typing.TypeAliasType): + field_type = field_type.__value__ + + args = typing.get_args(field_type) + resolved_args = tuple(_resolve_type_aliases(arg) for arg in args) + if resolved_args == args: + # No aliases anywhere inside: return the type unchanged. + return field_type + + if _is_union(field_type): + # `X | Y` unions can't be rebuilt through their origin like + # other generics below: `typing.get_origin` returns + # `types.UnionType` for them, which is only subscriptable on + # Python 3.14+. Rebuilding through `typing.Union` also + # flattens any nested union introduced by an alias of a union + # (e.g. `Time | int` where `type Time = UTCTime | + # GeneralizedTime`), just like `typing.Union` would have done + # if the alias had been written inline. + return typing.Union[resolved_args] + + # An alias appeared inside a generic (e.g. `Annotated[Time, ...]`, + # `list[MyInt]`, or `SetOf[MyInt]`): re-parameterize the generic + # with the resolved arguments. Subscripting with a tuple is + # equivalent to subscripting with multiple arguments. + return typing.get_origin(field_type)[resolved_args] + + +def _extract_annotation( + metadata: tuple, field_name: str +) -> declarative_asn1.Annotation: + default = None + encoding = None + size = None + for raw_annotation in metadata: + if isinstance(raw_annotation, Default): + if default is not None: + raise TypeError( + f"multiple DEFAULT annotations found in field " + f"'{field_name}'" + ) + default = raw_annotation.value + elif isinstance(raw_annotation, declarative_asn1.Encoding): + if encoding is not None: + raise TypeError( + f"multiple IMPLICIT/EXPLICIT annotations found in field " + f"'{field_name}'" + ) + encoding = raw_annotation + elif isinstance(raw_annotation, declarative_asn1.Size): + if size is not None: + raise TypeError( + f"multiple SIZE annotations found in field '{field_name}'" + ) + size = raw_annotation + else: + raise TypeError(f"unsupported annotation: {raw_annotation}") + + return declarative_asn1.Annotation( + default=default, encoding=encoding, size=size + ) + + +def _normalize_field_type( + field_type: typing.Any, field_name: str +) -> declarative_asn1.AnnotatedType: + field_type = _resolve_type_aliases(field_type) + + # Strip the `Annotated[...]` off, and populate the annotation + # from it if it exists. + if typing.get_origin(field_type) is typing.Annotated: + annotation = _extract_annotation(field_type.__metadata__, field_name) + field_type, *_ = typing.get_args(field_type) + else: + annotation = declarative_asn1.Annotation() + + if annotation.size is not None and ( + typing.get_origin(field_type) not in (builtins.list, SetOf) + and field_type + not in ( + builtins.bytes, + builtins.str, + BitString, + IA5String, + PrintableString, + ) + ): + raise TypeError( + f"field '{field_name}' has a SIZE annotation, but SIZE " + "annotations are only supported for fields of types: " + "[SEQUENCE OF, SET OF, BIT STRING, OCTET STRING, UTF8String, " + "PrintableString, IA5String]" + ) + + if field_type is TLV: + if isinstance(annotation.encoding, Implicit): + raise TypeError( + f"field '{field_name}' has an IMPLICIT annotation, but " + "IMPLICIT annotations are not supported for TLV types." + ) + elif annotation.default is not None: + raise TypeError( + f"field '{field_name}' has a DEFAULT annotation, but " + "DEFAULT annotations are not supported for TLV types." + ) + + _check_x509_field_annotations(field_type, annotation, field_name) + + if hasattr(field_type, "__asn1_root__"): + root_type = field_type.__asn1_root__ + if not isinstance( + root_type, + ( + declarative_asn1.Type.Sequence, + declarative_asn1.Type.Set, + declarative_asn1.Type.ValueSet, + ), + ): + raise TypeError(f"unsupported root type: {root_type}") + return declarative_asn1.AnnotatedType( + typing.cast(declarative_asn1.Type, root_type), annotation + ) + elif _is_union(field_type): + union_args = typing.get_args(field_type) + if len(union_args) == 2 and NoneType in union_args: + # A Union between a type and None is an OPTIONAL + optional_type = ( + union_args[0] if union_args[1] is type(None) else union_args[1] + ) + if optional_type is TLV: + raise TypeError( + "optional TLV types (`TLV | None`) are not " + "currently supported" + ) + # For optional types, the annotation is associated with the + # union, so we check it against the inner type here. + _check_x509_field_annotations( + optional_type, annotation, field_name + ) + annotated_type = _normalize_field_type(optional_type, field_name) + + if not annotated_type.annotation.is_empty(): + raise TypeError( + "optional (`X | None`) types cannot have `X` " + "annotated: annotations must apply to the union " + "(i.e: `Annotated[X | None, annotation]`)" + ) + + if annotation.default is not None: + raise TypeError( + "optional (`X | None`) types should not have a DEFAULT " + "annotation" + ) + + rust_field_type = declarative_asn1.Type.Option(annotated_type) + + else: + # Otherwise, the Union is a CHOICE + if isinstance(annotation.encoding, Implicit): + # CHOICEs cannot be IMPLICIT. See X.680 section 31.2.9. + raise TypeError( + "CHOICE (`X | Y | ...`) types should not have an IMPLICIT " + "annotation" + ) + variants = [ + _type_to_variant(arg, field_name) + for arg in union_args + if arg is not type(None) + ] + + # Union types should either be all Variants + # (`Variant[..] | Variant[..] | etc`) or all non Variants + are_union_types_tagged = variants[0].tag_name is not None + if any( + (v.tag_name is not None) != are_union_types_tagged + for v in variants + ): + raise TypeError( + "When using `asn1.Variant` in a union, all the other " + "types in the union must also be `asn1.Variant`" + ) + + if are_union_types_tagged: + tags = {v.tag_name for v in variants} + if len(variants) != len(tags): + raise TypeError( + "When using `asn1.Variant` in a union, the tags used " + "must be unique" + ) + + rust_choice_type = declarative_asn1.Type.Choice(variants) + # If None is part of the union types, this is an OPTIONAL CHOICE + rust_field_type = ( + declarative_asn1.Type.Option( + declarative_asn1.AnnotatedType( + rust_choice_type, declarative_asn1.Annotation() + ) + ) + if NoneType in union_args + else rust_choice_type + ) + + elif typing.get_origin(field_type) is builtins.list: + inner_type = _normalize_field_type( + typing.get_args(field_type)[0], field_name + ) + rust_field_type = declarative_asn1.Type.SequenceOf(inner_type) + elif typing.get_origin(field_type) is SetOf: + inner_type = _normalize_field_type( + typing.get_args(field_type)[0], field_name + ) + rust_field_type = declarative_asn1.Type.SetOf(inner_type) + else: + rust_field_type = declarative_asn1.non_root_python_to_rust(field_type) + + return declarative_asn1.AnnotatedType(rust_field_type, annotation) + + +# Convert a type to a Variant. Used with types inside Union +# annotations (T1, T2, etc in `Union[T1, T2, ...]`). +def _type_to_variant( + t: typing.Any, field_name: str +) -> declarative_asn1.Variant: + is_annotated = typing.get_origin(t) is typing.Annotated + inner_type = typing.get_args(t)[0] if is_annotated else t + + # Check if this is a Variant[T, Tag] type + if typing.get_origin(inner_type) is Variant: + value_type, tag_literal = typing.get_args(inner_type) + if typing.get_origin(tag_literal) is not typing.Literal: + raise TypeError( + "When using `asn1.Variant` in a type annotation, the second " + "type parameter must be a `typing.Literal` type. E.g: " + '`Variant[int, typing.Literal["MyInt"]]`.' + ) + tag_name = typing.get_args(tag_literal)[0] + + if hasattr(value_type, "__asn1_root__"): + rust_type = value_type.__asn1_root__ + else: + rust_type = declarative_asn1.non_root_python_to_rust(value_type) + + if is_annotated: + ann_type = declarative_asn1.AnnotatedType( + rust_type, + _extract_annotation(t.__metadata__, field_name), + ) + else: + ann_type = declarative_asn1.AnnotatedType( + rust_type, + declarative_asn1.Annotation(), + ) + + return declarative_asn1.Variant(Variant, ann_type, tag_name) + else: + # Plain type (not a tagged Variant) + return declarative_asn1.Variant( + inner_type, + _normalize_field_type(t, field_name), + None, + ) + + +def _annotate_fields( + raw_fields: dict[str, type], +) -> dict[str, declarative_asn1.AnnotatedType]: + fields = {} + for field_name, field_type in raw_fields.items(): + # Recursively normalize the field type into something that the + # Rust code can understand. + annotated_field_type = _normalize_field_type(field_type, field_name) + fields[field_name] = annotated_field_type + + return fields + + +def _register_asn1_sequence(cls: type[U]) -> None: + raw_fields = typing.get_type_hints(cls, include_extras=True) + root = declarative_asn1.Type.Sequence(cls, _annotate_fields(raw_fields)) + + setattr(cls, "__asn1_root__", root) + + +def _register_asn1_set(cls: type[U]) -> None: + raw_fields = typing.get_type_hints(cls, include_extras=True) + root = declarative_asn1.Type.Set(cls, _annotate_fields(raw_fields)) + + setattr(cls, "__asn1_root__", root) + + +# Due to https://github.com/python/mypy/issues/19731, we can't define an alias +# for `dataclass_transform` that conditionally points to `typing` or +# `typing_extensions` depending on the Python version. We work around it by +# making the whole decorated class conditional on the Python version. +if sys.version_info < (3, 11): + + @typing_extensions.dataclass_transform(kw_only_default=True) + def sequence(cls: type[U]) -> type[U]: + # We use `dataclasses.dataclass` to add an __init__ method + # to the class with keyword-only parameters. + if sys.version_info >= (3, 10): + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + # `match_args` was added in Python 3.10 and defaults + # to True + match_args=False, + # `kw_only` was added in Python 3.10 and defaults to + # False + kw_only=True, + )(cls) + else: + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + )(cls) + _register_asn1_sequence(dataclass_cls) + return dataclass_cls + + @typing_extensions.dataclass_transform(kw_only_default=True) + def set(cls: type[U]) -> type[U]: + # We use `dataclasses.dataclass` to add an __init__ method + # to the class with keyword-only parameters. + if sys.version_info >= (3, 10): + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + # `match_args` was added in Python 3.10 and defaults + # to True + match_args=False, + # `kw_only` was added in Python 3.10 and defaults to + # False + kw_only=True, + )(cls) + else: + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + )(cls) + _register_asn1_set(dataclass_cls) + return dataclass_cls + +else: + + @typing.dataclass_transform(kw_only_default=True) + def sequence(cls: type[U]) -> type[U]: + # Only add an __init__ method, with keyword-only + # parameters. + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + match_args=False, + kw_only=True, + )(cls) + _register_asn1_sequence(dataclass_cls) + return dataclass_cls + + @typing.dataclass_transform(kw_only_default=True) + def set(cls: type[U]) -> type[U]: + # Only add an __init__ method, with keyword-only + # parameters. + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + match_args=False, + kw_only=True, + )(cls) + _register_asn1_set(dataclass_cls) + return dataclass_cls + + +def value_set( + value_type: type, +) -> typing.Callable[[type[U]], type[U]]: + """ + A class decorator that registers an `enum.Enum` subclass as an + ASN.1 value set of the given underlying type. All the member + values must be instances of `value_type`. Members are encoded as + their value; decoding fails if the decoded value does not match + any member. + """ + rust_type = declarative_asn1.non_root_python_to_rust(value_type) + + def decorator(cls: type[U]) -> type[U]: + if not issubclass(cls, enum.Enum): + raise TypeError( + "value sets can only be defined from enum.Enum subclasses" + ) + members = list(cls) + if not members: + raise TypeError( + f"value set '{cls.__name__}' must have at least one member" + ) + for member in members: + if not isinstance(member.value, value_type): + raise TypeError( + f"member '{member.name}' of value set '{cls.__name__}' " + f"must have a value of type " + f"'{value_type.__name__}', got: " + f"'{type(member.value).__name__}'" + ) + inner = declarative_asn1.AnnotatedType( + rust_type, declarative_asn1.Annotation() + ) + # Map from member value to member, used for O(1) lookups when + # decoding. This requires the member values to be hashable. + value_map = {member.value: member for member in members} + root = declarative_asn1.Type.ValueSet(cls, inner, value_map) + + setattr(cls, "__asn1_root__", root) + return cls + + return decorator + + +# TODO: replace with `Default[U]` once the min Python version is >= 3.12 +@dataclasses.dataclass(frozen=True) +class Default(typing.Generic[U]): + value: U + + +SetOf = declarative_asn1.SetOf + +Explicit = declarative_asn1.Encoding.Explicit +Implicit = declarative_asn1.Encoding.Implicit +Size = declarative_asn1.Size + +PrintableString = declarative_asn1.PrintableString +IA5String = declarative_asn1.IA5String +UTCTime = declarative_asn1.UTCTime +GeneralizedTime = declarative_asn1.GeneralizedTime +BitString = declarative_asn1.BitString +TLV = declarative_asn1.Tlv +Null = declarative_asn1.Null diff --git a/source/target-vendors/cp312/cryptography/hazmat/backends/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/backends/__init__.py new file mode 100644 index 0000000..b4400aa --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/backends/__init__.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from typing import Any + + +def default_backend() -> Any: + from cryptography.hazmat.backends.openssl.backend import backend + + return backend diff --git a/source/target-vendors/cp312/cryptography/hazmat/backends/openssl/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/backends/openssl/__init__.py new file mode 100644 index 0000000..51b0447 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/backends/openssl/__init__.py @@ -0,0 +1,9 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.backends.openssl.backend import backend + +__all__ = ["backend"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/backends/openssl/backend.py b/source/target-vendors/cp312/cryptography/hazmat/backends/openssl/backend.py new file mode 100644 index 0000000..0d02c4f --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/backends/openssl/backend.py @@ -0,0 +1,309 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.bindings.openssl import binding +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils +from cryptography.hazmat.primitives.asymmetric.padding import ( + MGF1, + OAEP, + PSS, + PKCS1v15, +) +from cryptography.hazmat.primitives.ciphers import ( + CipherAlgorithm, +) +from cryptography.hazmat.primitives.ciphers.algorithms import ( + AES, +) +from cryptography.hazmat.primitives.ciphers.modes import ( + CBC, + Mode, +) + + +class Backend: + """ + OpenSSL API binding interfaces. + """ + + name = "openssl" + + # TripleDES encryption is disallowed/deprecated throughout 2023 in + # FIPS 140-3. To keep it simple we denylist any use of TripleDES (TDEA). + _fips_ciphers = (AES,) + # Sometimes SHA1 is still permissible. That logic is contained + # within the various *_supported methods. + _fips_hashes = ( + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, + hashes.SHAKE128, + hashes.SHAKE256, + ) + _fips_ecdh_curves = ( + ec.SECP224R1, + ec.SECP256R1, + ec.SECP384R1, + ec.SECP521R1, + ) + _fips_rsa_min_key_size = 2048 + _fips_rsa_min_public_exponent = 65537 + _fips_dsa_min_modulus = 1 << 2048 + _fips_dh_min_key_size = 2048 + _fips_dh_min_modulus = 1 << _fips_dh_min_key_size + + def __init__(self) -> None: + self._binding = binding.Binding() + self._ffi = self._binding.ffi + self._lib = self._binding.lib + self._fips_enabled = rust_openssl.is_fips_enabled() + + def __repr__(self) -> str: + return ( + f"" + ) + + def openssl_assert(self, ok: bool) -> None: + return binding._openssl_assert(ok) + + def _enable_fips(self) -> None: + # This function enables FIPS mode for OpenSSL 3.0.0 on installs that + # have the FIPS provider installed properly. + rust_openssl.enable_fips(rust_openssl._providers) + assert rust_openssl.is_fips_enabled() + self._fips_enabled = rust_openssl.is_fips_enabled() + + def openssl_version_text(self) -> str: + """ + Friendly string name of the loaded OpenSSL library. This is not + necessarily the same version as it was compiled against. + + Example: OpenSSL 3.2.1 30 Jan 2024 + """ + return rust_openssl.openssl_version_text() + + def openssl_version_number(self) -> int: + return rust_openssl.openssl_version() + + def hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): + return False + + return rust_openssl.hashes.hash_supported(algorithm) + + def signature_hash_supported( + self, algorithm: hashes.HashAlgorithm + ) -> bool: + # Dedicated check for hashing algorithm use in message digest for + # signatures, e.g. RSA PKCS#1 v1.5 SHA1 (sha1WithRSAEncryption). + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return False + return self.hash_supported(algorithm) + + def scrypt_supported(self) -> bool: + if self._fips_enabled: + return False + else: + return hasattr(rust_openssl.kdf.Scrypt, "derive") + + def argon2_supported(self) -> bool: + if self._fips_enabled: + return False + else: + return hasattr(rust_openssl.kdf.Argon2id, "derive") + + def hmac_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + # FIPS mode still allows SHA1 for HMAC + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return True + if rust_openssl.CRYPTOGRAPHY_IS_AWSLC: + return isinstance( + algorithm, + ( + hashes.MD5, + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, + ), + ) + return self.hash_supported(algorithm) + + def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: + if self._fips_enabled: + # FIPS mode requires AES. TripleDES is disallowed/deprecated in + # FIPS 140-3. + if not isinstance(cipher, self._fips_ciphers): + return False + + return rust_openssl.ciphers.cipher_supported(cipher, mode) + + def _consume_errors(self) -> list[rust_openssl.OpenSSLError]: + return rust_openssl.capture_error_stack() + + def _oaep_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if self._fips_enabled and isinstance(algorithm, hashes.SHA1): + return False + + return isinstance( + algorithm, + ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ) + + def rsa_padding_supported(self, padding: AsymmetricPadding) -> bool: + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + # FIPS 186-4 only allows salt length == digest length for PSS + # It is technically acceptable to set an explicit salt length + # equal to the digest length and this will incorrectly fail, but + # since we don't do that in the tests and this method is + # private, we'll ignore that until we need to do otherwise. + if ( + self._fips_enabled + and padding._salt_length != PSS.DIGEST_LENGTH + ): + return False + return self.hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return self._oaep_hash_supported( + padding._mgf._algorithm + ) and self._oaep_hash_supported(padding._algorithm) + else: + return False + + def rsa_encryption_supported(self, padding: AsymmetricPadding) -> bool: + if self._fips_enabled and isinstance(padding, PKCS1v15): + return False + else: + return self.rsa_padding_supported(padding) + + def dsa_supported(self) -> bool: + return ( + not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not self._fips_enabled + ) + + def dsa_hash_supported(self, algorithm: hashes.HashAlgorithm) -> bool: + if not self.dsa_supported(): + return False + return self.signature_hash_supported(algorithm) + + def cmac_algorithm_supported(self, algorithm) -> bool: + return self.cipher_supported( + algorithm, CBC(b"\x00" * algorithm.block_size) + ) + + def elliptic_curve_supported(self, curve: ec.EllipticCurve) -> bool: + if self._fips_enabled and not isinstance( + curve, self._fips_ecdh_curves + ): + return False + + return rust_openssl.ec.curve_supported(curve) + + def elliptic_curve_signature_algorithm_supported( + self, + signature_algorithm: ec.EllipticCurveSignatureAlgorithm, + curve: ec.EllipticCurve, + ) -> bool: + # We only support ECDSA right now. + if not isinstance(signature_algorithm, ec.ECDSA): + return False + + return self.elliptic_curve_supported(curve) and ( + isinstance(signature_algorithm.algorithm, asym_utils.Prehashed) + or self.hash_supported(signature_algorithm.algorithm) + ) + + def elliptic_curve_exchange_algorithm_supported( + self, algorithm: ec.ECDH, curve: ec.EllipticCurve + ) -> bool: + return self.elliptic_curve_supported(curve) and isinstance( + algorithm, ec.ECDH + ) + + def dh_supported(self) -> bool: + return not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + + def dh_x942_serialization_supported(self) -> bool: + return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 + + def x25519_supported(self) -> bool: + return not self._fips_enabled + + def x448_supported(self) -> bool: + if self._fips_enabled: + return False + return ( + not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL + and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC + ) + + def mlkem_supported(self) -> bool: + return ( + rust_openssl.CRYPTOGRAPHY_IS_AWSLC + or rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + or rust_openssl.CRYPTOGRAPHY_OPENSSL_350_OR_GREATER + ) + + def mldsa_supported(self) -> bool: + return ( + rust_openssl.CRYPTOGRAPHY_IS_AWSLC + or rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + or rust_openssl.CRYPTOGRAPHY_OPENSSL_350_OR_GREATER + ) + + def ed25519_supported(self) -> bool: + return True + + def ed448_supported(self) -> bool: + return ( + not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL + and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC + ) + + def ecdsa_deterministic_supported(self) -> bool: + return ( + rust_openssl.CRYPTOGRAPHY_OPENSSL_320_OR_GREATER + and not self._fips_enabled + ) + + def poly1305_supported(self) -> bool: + if rust_openssl.CRYPTOGRAPHY_IS_AWSLC: + return True + return not self._fips_enabled + + +backend = Backend() diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/bindings/__init__.py new file mode 100644 index 0000000..41d7318 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust.abi3.so b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust.abi3.so new file mode 100644 index 0000000000000000000000000000000000000000..fddbd2a130f8e539225ed62be610ecc293396029 GIT binary patch literal 14389392 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

    dfG!JcmC^d6>gA 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.gS*W^m=_ zaP5OIhie~%0Bsl;o1iwf@}R5!IdAw8{em3 z4A(vg30&*X1g`uPu6+=uaP5PT!L|O(;L6Y8jqg)1hie~%0NR$2X zuk~jDSAGcBJ_tj&_Cbi?dd@O}YkiC1+6Q3_*FFddT=^5Y>Yu{355g3#eGoFZ@@H_} z-^l5{Pr)3neGm$`@)z*Nua8Q&_CZ*}wGToC*K?&6TBt2aOJPzYX26l zeGoQq?Ss(4)jnIe?(g+*?Srs`YafK*9{b~8`2)D_?}c#fgD`|^AA|_5_hd$JwSNrP zJ_uvD_CZMCdaq*wSAGiDJ_u8|_Cd(thwmZ4m7l}455gR-eGm$`+GhdR_$lGq2Vn`< zJ_r?D?X!X_zlLicgaf$tL1^G=pEX?hEnNE`Y~b1lp@VB5fh}Fnzu?*jVF%Yf2*C;a z<6rp$c;?SBL%8-q7{av=LIhX-2)^+A7_NN~#&GR}kij*7XYldF?*HU)?SoLjwT>;| z$|>R62cd%NdEW}IoEolu5E{6iTdm>BY2n%jp@ZxB#TKrd9;B#ruACmOeGq~_!T9n0Ob2k~gmCSH5W#i4 z7{Qej!?h1W0@rb20#{B7*FFdtT= zT|9v+CxvStgbc3h-x*vvIb8c76mVVVF5t>3;o1kGg6n#A1y@cD*FFdhT-U8@xN=&! z_Ce_2x<1{)mD9tu4?^&#`{PIF2?Kcemv){I!nF@V1Xs=oKGyp@@Zb^tJr}sn6DDxg zCxvStgbc2n8C>EYT3Avke={2ZSDz*V0Ru6+<9xN=5t)hC8)AA|(1oC$pG`!l9+?SqiPb-po! z_xd}faP5Ooz?HLrk8W@CtAuMGgbJ>l6}Bsdll}3daX5ghJ|SHDAVhHGjNqzI4A(vg30$9R0-yMMn<-rTAY^dm%;0lh z4|BNoK`7wLS-@u+KXC1XP{Eb6g0DQMhHD>$2CkeneCPM&TDbN>=-|rP!nfKd0aP&4 zeGnqJaz=3VR}9xa2nk#{6S(>-g=-.d9RT>X{9t5fZKtbpshWdT=zm2mBYP{Eb6 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�gl5!No{SCLcGErK_bQIRZpDw}T zPI2CIOgS;nyXV_flWz~a@|Xfi;L6II%a#cbg`ftgPPWwRXQzq z@f7|=BS6P@^9-b2x7Z*`s4%y@yw;u$2B0c zs4{ZR`XbzCT(BF03g)uCPXQ2-MIngtTW24*~w+*O(fBRzi}o$ zvJoi{E0U{$atE0UQF{+J5=>xdIJnVaf(s8_Nc+&Jkij4b9h+)Z(CEhj`+aae!Dc1Q zfj=aclrSPDq_Z{L5Y;2OQ#y%Ys!o&{zJC2n#vct~bO0n)l|uZC_K{^Qvt*=!(lvNS za^XwBHow@l8K{sgA&aIr7%?1kwYFZb0pm=J4^KD@lj#3Qd3l*olMX$E6mSAGezcxo zSpdyJHCpRF>QPa+YkT&_^!7^EeYCw|wB7zJP?UvW&AUm_Iof*Q`u1b-WA^{*1J{S{ zeKr`ftYT;L1^Qz8x*RvwgIZ33_4w)o7-~;MIt~E?$VX_LphkX}ae;ShlxYyuX#l|% z@}4Pg+{1zE-D7fDn%0HXdcb7^A3$NQN@6hau4BTo^~ldy4+%o?;@SME@$pzw4g)r2 zSnH@U;uUDg&PvV39Z`_2hn>M|@tH<(F*nCK1m+RFGP(%$ft)e}Fa`k^bG1>0ovQ)Xk0Te8?)=Kp8cd(IpEOJLD;{Je_8%WLH`*wp<#=i4 zp?jn0K)V8V%lqEUWCjN0y#G#*%+J<8jfC0VQN_;{nxq4InH<~H7lJKc##oK zjv5gteF}es2JB_{@#+QNBVPeo4D6$~nxdQf;9F^t9w_zN&5JB4PK`uF&7(#_8;=pw z#!E$v9OK=YO!u8HJQfK8nnw5{^&Kt4R8XJoGcdL`UUfubq1REaI5&nNwM0O6vD9sr zCNaQ0@(q?&T1bxM)N z>~+vXia&Gl5Rbem%&b=dGOi%7?tYdqvPcFcJ;UG@%u3q;ReP?mRLti%3MT8!49zQ) zCNYb20qvbH!JUMwJ-c)#h^baXH&|w6;2R!eHuPQMm_y zs3fdi@nCMSRC=VaRB~4FC7DbQmCnxO&Xu5l8@(G-mel&0aHiWgcYYc&C0PLry|Lnq zEFT5)7MI44VXor?!)oAAGu8$VypCxx1mgM6AjuQ}gg-uFc#9hKwYi4FnBryy3|W%( zDzFXo2dJGkx*5&!qiRy-(dcXEH@bvgm5_qVY4%XuNh7+wNZu|NF&+L2JVFRDbv8TL zC#Q$U#_l%*Md&E)&pAf7xMVmr77<{e_D2N#5!jucS|dQlnA^tMMod|nynIr{69!4+ zc5KS<*0J2F#IYqfp4_MZXwM*b)Nk#$3H2M02t7hbrg9k{3wkTMx)O>=KXLhg-= zQXHL|pDRHBfLSNF9RgVN5MpO#lUY-SZsWld{|(<>hF0WoPOy4M#3q1{FDjO>Xjojo z(Cqu1QW$Au7Fu_fzn%<6e4$0mpq&N}97ha5Z_FRjWAxI|?l?YRi`ytFb#QLTs6>DJ zM1OJ7WoAocD2TwrHCqTO$2}#YvZgs}D5Xq71+~btz`pXK6;HzsAO0VQrrfme2aKB4^D8-ZxnQ+;VXh9 zjHA)xRl-#_{C=a@&=8Zc5kqMWvvW;{OwP~G6o`V`my1hhPthoD04IDtt}3p>qt?K2 zfTTj){#sU|%b}Ext#q;Bi311;8EsHF_C^bnz%^rzgRTolgtlh!5A#bi^XE(p1V9rL zn;Uh8ThXd09@a`3EAJKn|Iv?TFxG}g5Oc-9NhLEtED99xnR7NvyI_5Ztl+UCKp&CPnG_EWi z4;vHxks3KZIN=;*1`u!8?Kfh1h?98ma2Wtk?uc-GP688}(R2iTyGk8L2>73Oi!@#zWefHIi}Xw3@YRz%Z9N@kVvqRj7UdGs3w z-z+AUOBmSbS>;a{hR9nHEuAby1rd3_{h@g0CKVmbLF6RB@tBa-a4c3D zz2V{vcChi-7tTHW2%Xgn%h>$KFd|}f%3}2p*&U5k5&~S>_Y*K|NFAze$^0fF+s|+( z$zX7UDByi2#I$Aqs^3HjA3rsA{QfM_izOiW1&N0u0~E)lo$qto`kCz(*nq1#$6Zs6 zJ&)Ssii%7KS9c{mI??5g#~Yg@vDGfyFu+(D%eLApaNErSi+~QSm`YT}OUueYRE|V0 z#2}P`VUf1>rlMREgw#c4H-1q(7HyR6({Yf<)%7wN742-f(jvj>3$WYsS=tHie| zFp6zZmCM=OQc-R%F}CDd_KJ-twkjQ?>~bcS5G5EY>#c{zBNw^VM3V|P=tIFMxg~_< ztZ%FFd?TJr)_{fL`IX3XPtyl191ok+rN9tI6O=OhF%?X!(2q)R|cV&tVzG6>#8xbKECqRSU4a zWM3KWBEL`sz#e`k3~(Nd8P*GQ^bLNC%0}h-RneQVF%*kMFn1M$-Aj}gQ-nAm-N?Qr zF(kUNrUo~fmy5iVTRc}-lA)+zi_9)XR{D0Cmuo#C)!>!qUM{8!#)2Ce4ibu*RGSPM zJ;K!NwB>XcBQgG!hLQM89IvX(WhF!dy$M*D{@`MAMu>`8W?DYQIk_CY0I6onnXQes zUXfAbg1iWga_!>ARWfI7N?9L1!*C}+yj@n#C6GXgE&(tPGlb@IX>)n;akR` zbg?eyPVhc9FRiB=vF@D0|FUV%cr+sx$K#QQaihP~3wF9y^TvmVNBAeKOdx4u+d7-; z%OsROo`7QzT^J!~rCZ(M!Gjz5zdIdjz-x4MRH7DqN$8&Fdh{9q4(N3V4D_Nh9$`D| zxkCci6ve?Z6v!R`IeXz4M;l@+V^$mYh zWK4hE5~QrcXGXxq8^bQGfKisAOm{0#43sJ%cb7i@;$aSzf-ujWS|CB;`8)QWz*)52 z<&J@%$akgZ`AQdkISCPwymn%6amQc7Ln;BqbImnU9}?G)%|4Zma5d2tkTpiB$6#$T zsrrN?gon=I_4@np+GJO#^o0?r>EfQ==NX-!>PXFlaH%!MA!q)~5Qe@f)a;Iou3wL? ziQSgCT4;s=29mG{jD2-1BtXJ0A=o#vhb`*kU_WFh(^FV4`c#~W{<95Ww0(M=YVuD?TEk(4&31}kca=5l8_Al6wzLz}qbt4P zkQ6s^$$V${3PSUqf<2u_O~G*IA0~-t{?a3+da!PRKrLOuX#kIpYUr4Z@JN5BWkTpH zUfjm&@aWRP4Re(>zIXglANwB`Ep<%P$Bb@|M6D zLy?DUKnBAlk!@(QL4+HdUr`r){d+N>RTJeRWbsLEH$OM?2-PE0m?F9?(`^i=U=!C@ zwP~!BjgTW50*GwN5%Mo`%;!Shk}%JD4Tjp6u`S?_3K9r2A`jYT%_Rbh~E z;uz0Miy&TD807W^I$&@d1v(lo1V1)4{RK`KR$|2E^(v|VJ;)Kut#x92%z=$EfftI! z`%u677;r~Td*{b?n3UC8gc_z2*ShXs0R)ikJBARfOj##w&0X92TGQ2$b9IU z6K4}%<2JLb>EjVs1blmb{iI2zvR{;2Diz3t^Uw@N1bb z91gp=0pYBMs84y(0u!&$QcM@KU>)08YEVWf!xD>!V&;UbR;`nH9GW=b#nla_5gaKWv4Tl!oPI)-e-?6+s2bHO+ga&*Z&QhBfgh3j(#YxdU8)$q%Q7%Ff`Qs!V2n4~3ji2M8t#*uGYAnW!#kilJ%P{X@VsKnN zR^hgRUJ3r1l2>H)9!O;4&Gz7mMIWi@Ko511=2+BMa~&;R0~t`OQ*bhD^!}vM31^9y z3v?3@60KiaG=_d;`NFg3i%28~%DM@IC6*=9gkR1lfok%l2f;DFslVn!x#fyEOco3* z6LHrNw8#3Gy8%+;JY(~^+hk{HA#hchG85BF7qd$OqD0#TC&M7@=E%C#`=HA;^C9!P z4iA_O6%^yaE&he11VaR70yQ>8)g)=)2P5aB91c!;=yoivjf5gic1Ux1QZ~XiV=XSzh;E=foL=-7eF*Cg2BVP z!Vw73%Zd77s)wW<@Be~NY-k#OEH=y2*Iy{KmuHjl7RaFu|(2?qLu;Q zRIVAWEd*JE%*;t6tNxeVZ*u|XDLN;VMt_CK_l-Xw9vmFkH<3rG`gRjHJ2E_Wyfb`c zbfWr=kq{_JEXQ)fHsE_DCyKX&)!dfYwl9RR5*ty~4#$rqE#jhZ(;(JWMc_9ECk^B`hF%Xw zaNX@+Zg`I_T5L&1u0#6WUJ{J1ChZt()>M{#^F&iqz22g;=IB4splC_|=2m4BcNGJW z?UvIZT6+kVOZ6#=mGx09diGft`yeD(kA!WX?R-+tNKer$WgYa;tblPbKeiShaM{U} zESONa0yr6?(K%wVY=EM1KjjN1hL1;Z^2^scjjEzh-YE2G0gO9tV}7j9O6wad%2tt3 zHC=n8b0$7|gn9ur$Zq^K;}aYsT0uMtZgR6CU}^n?;AFjB%c?9H5K6>&?f~#ub{RS6 z>l?~9ats8q$Xv#au`E2r7;7~On1e;a(wbXWlk(*VCqJsMO6V?&DDWlYXFaa2>cPo( zJXGGww7q?hX?t^)t<3cR3#2}`J_P<+Vpn$)8OyVQM`CELgKYx3L;+h5v_*NVz!6=) zJFpc)X;U)+ys%Py+7gZ>{2WWb_Mu-I`b;-ilmH23JeU_Yt!a>x<9XGp^0J*yUg zzZA8Lh(iQl&CKGE4exL;JoLWT`$YkNMe@SktwBx=9^XL=o zsDUhd6N{H53N4`@J0LwUs5je7Vbz8emAzcCJT2)a>a!enP^G zbq_YI#|Ci`!g;;4eJ41r_G@&v-IoG`I1mcFK&El|^7`Otag0U?15xlX7G`ow3e?y= zjPXNF9SD$=`qW)jOt+M$26LgL%67JCDJ@_t%*{_L54}BP5?nW=nkaf%c?^`xUf7G`tP_&w7kTrH7dZhO>Oev&$Nd?;*dosYVr zZV5(j=AP^EJ%MB%N*@pM;qST5f^Yv+dg0#T67U7=>e8eA96njY*rUO|?xXVgtx9B< z0q!9*9ghbejt}(#iiN_IwxM@MFnEN4!OTKqnQ?vUG_V+3fG&{$E-_px^_*Br9S>;X zrX+|&Tv$)Fqhg>wi>am;yHWBF$jq@|Ar*a)WR$F?j|b#)obUMcy)v;;t78-&QE1EWgR>=~V?*RMrd ze#JzYf}FjorUI*al}tMhGQ+-bXtuFEE#rTx0IQb{JRdkC&IyzqbjCWfbm0U3v!2Tq<}S`MWGSsp@H36*hqQmjpi-&{2|$AN7YJ$n+R?LzmaQx* zlKBeTj?_2AYp{xT!qj5of|Pm|u{~mnAe||y%WWy)O(9S`*(D3ZnZ-PetimkD*CRrA z9&~V7g*WW4)k1Syip3t=Oa|fD#8{iSzdljy)PFi1K8;UIh;!yTASCry8Y{i#hm8)% z&4r$bF^_t-ibFLdC+!We539Ytfmzhyt=6w$3>Bsn_F#`g01emk#7A+(`kH`O;*n@U zbz@X7O$lUb4Ee;p;;Mb8wIp!J=O%q$9eo2WO+!+5l1nEnO+FMwn*9~Xt4`8Vt}f(J zoSI%d6VHw0!ZC@f#LLwITCc9u&>_Jm7QUA9xWw~hr3?_9WYWl6 z3z?EV!k5lAJ(lvP0$|sE)D#9*GA9DAk|RD8#1AzO?s?y>Lya+*;NoRbDFFp ziJGy|QDdOUD!?!?L)voqPo`3WxKf3^qY;-@MX6#p{Z2Eji z0m}_CE$;lZ&}AwQYmS|cN8nx=Bd&_2N&f<2_S1?TPL~?9*p>j+z=0I(Pj{*nu*KtR z)43(c`b#<2$I!4`a=g-H%5`fQ)4JlshIQ&V5k=Kd_oAqUxsp?c$o z64|eTY6;zPFU1iE>-G+ol#q_2)|bscw=`80oMJ=9oGDCeUaRw`9#V>Oz`DAvbr~Xc za8?I;Ib_#RFUwgc<9&H~AqCR;WQjpxUu(VSa-*HC>yfl<;Xc%nGHtrp3q< ztKr)(R;hAma>}G#f9%5PN|TyCazJm1`@Jds8|o}ch6mZMoO(r5U->}Feju9p9M&_`{z=iiWS!}l(rh1~-N0}> zK_@0K;esVNv+V@ zn`@#Y0RDBZA>w#BTR_80C1685vhW;WKE_guHer--v$Y!G0T~jG#1c6j%qzfccKNAR zW>&AeBCSJz_Ztx?R%r%1i_vCFE5%~SH9_M<5a%2Z^T+0O7zS)K41;3Kf%RD%lrA#9 zpdT%!24khh0Ni%S&K8RGz>&u{juFGVrVpXayTgrVixlIUB=uk9>8*uKEq7m~DX4EM zpDQhP+QZPb$(`r70iJ7HfD+A6y*Zc|3Lg@}f?(&$p`JQUVZpJ96URyW8a^?MQAyZK zMdZ^+wrsQxgw7f2sFa-%rOoWGZko1ppeDgGlN=WfLxrfh6(aEV zxGhK!FV_|5SeBKm;-_8~bk@g5_!ZnjQ?huEa2z66PhokBenZxO_SYH=Y+y@8&v4epXU*8=cHT*2TzE6Z< z7vR1(x&?FUD|tOPK8!}y`xszK51RI)bOTsr3aUD$nV$Fy)ogXR>;)`kYD`_GuqI;tSH>ioOap4KOP9_ZC1_ zkTiRHYhZCmnoVs~Lt6vu#uJ6t_AjR8j=c#HQumgzaU%&*9@;o7ce?8sp>f=Jsd!|T zp>5U02Ff4gk!f14!_gx}k+BsQD4!Q-l0Z%8r_Y^_o_EZETNZ6v6nr};QrOwt#hIm& z@hMA_(YZXX$Rslbv0v3x;FUW1X7fhTvYDwm%46tnCd0vrxy_cA6Dfd&YI? zVZ5H(6+AgsDHQi`K~8A@5>_WiNgxJQ7_+KfTF^6Tlj}<2f>32HOcI27ObY>I=Gj1P z^O)IG{7Zr7$ul@WMvtsClTh22-~^bed9Uba*(>5kS_P_LH}>#Y_;}KCf?}u6vn)U~ z9*x}}Nt9T6n)gfsIw;^;fer`7$vq)IH>qeK^5%u?L%U;``3<-TDi@~|l^#~9Cp6sL zIVJM&qL$&7AlAIj^2Rmq*#vGPOv02^sIG#J%ZOGKH*gmml38b7F!%%orP-yyJ8}u+ zeXg7<&1C*-U-ni&Y(q#`&U;FQgyqIPJqj?8k}PPmh2n~25zvG_o5r5ZA@X`9_O(Zv zb>{p=!vI|8&rymJz9c4&y0-_`_QD=^i8M6r-;iZkn7_zsw?=Xt07tD5>ti>P8n2A^ z@fySASZ|FGGsR4+^)2FNudU+@A<-3?IdWhfJ-|N7?7|yYc`1AZBIW_rw!M~05rE)< z4uZa*Ub75hF*>zKU?(nzrKUAc0LeKBbC}_D(;VP%Ui4i2rWh}kS&QLEJ3!c3)D1{r zSkWE>WQEK^r@3LxAeNq}o(P%1;ziC*jYEqZ&mwzz6;e~sEnajPG{WrgDz|0>vqlz+ zF_l$`)D^W%3z4RRytui(P7FsE(9%X_Z2pT@1kcJauvJj3x^>ZdRmW+IG03GrnvH3L ze>q2oCG#tjHC9g3aoWVRXFjlwmdkw?{Zh1*s577Qq{$R~HMn?+I|V!z1OYVGQyUG8 zi9=T;(0mBxrfW4ZU36@8$qBCNok%i`Vg8uK)i0Ny4QpF32Xq9A!P2|nyi za+7*FpK~1GyGu*O-t`R6!&qfOI7JuwvwHPn4WN~I;m}!?7{%!pKwDf~u*k2Xqb87* zeydXi$ciWHGk9%nvoDl$JHcS?)G9z-nCK`@v@R)nQWrq@0>Oa3#RW6a6IfIDYhR_% zXlY@VVrp(l!1$)nYHoS}B27Uxk=NiZyCtXeiV>+<3!kZ!S%{%o-B2w>n_IfLSg@H_ zyJGG$quUFWYH~RSa&}?NPL;>uZ3jK*GNWv1r_OSDRSMGa!^oe8x&id$7WxRA(Eu*K z1JlYcl%Zk{%viscpAi9F{bG|fn(T(92Py9hSi02%Q6o-kFr&2UNBW&57i~=p;UcKD zUZu0n7I_#XeyVYtaY4X$8y0lF6d4$6dx_eO`Tfwb~*>K=9?0gn2S zHU=aNE^fTUF+O|uoK;q@&!OZ<i4d z)#g;wniJm#NQM_fA6}!Tx}%Bvx7^Fi^)Iytfh!#9{B;=xfRhgE3}MA}(-d0L0*x+? zqf?cGI5h*;!hm6nUSqnAh}39>FI8c{RsZ+aG;waIe;q2gst~V(AAM<32Q{jqy`hYL znIn-U{6`^l=O(eX25aEU&ymW_qL7t6fEYyMb~}&9zFTD0Uv}9l7P#zg1l@{DppxtV9QnL*{t=O6_u`Ra=3zhHrzBBmv$nFj6CMwYs;0V41Hd%vbG3FM7dl&%2Ke$;)dU&sn(ZfoB~wpc2*|D z%}#8g-jbzag_weQH}Uw1IJdDHkB?HmT%gYel*&H4-L@g##!8k(*1<6ZuoO>EsJMNw zB|`>LCZ*_7_kxOCQ1bE=9+(2~7=w^Ee}R>yRIYI8ylo3SK{pY5YxW=)$5d+0ZqEYt z>B{v6GO3*$5%RF@AbV)fR%A^gi{8o}A)UB?dHS$4qwRXAG=CvQqCzsKJ-s{s%SVo| zk`fk~#f_ZspcIiL?7tBQ*Vb7N%feM7qzdrz4NSUe;%^X^DvY>{V>_lpztl-2UXjDF zaJWZgy>&Yyj)l@3Ead5KyEXaPP=~Kb1EBnmAmQy=U-2YnSAMp&Sy3(gk$U;@O@o3; z&JWN%19vjYoVo66yMs^+mPQn2A-Imw=$5M&R0o_VsO$??IW(%I5+Q|DaDuFLA%YIB z6E4@=D7EXh4;ic4ExyN?E~+p1%nT@}?CO9qczcmemJp3%Nh`1mTIe zuvV_s6I+AKeb6kdtXH)r=K{s4yrj+NY=$utZ?+OsU~sZ#Dl|?jp;#0WsEimXByS#} zc0=lNM@z-(uEktPMHXsfX1H>fWsuMk?L+n4bdCDaEvOyAGEg}A?$dJ=BUQb?JcW*l zm{BN48WLMTi4XvcwRP(KcoT+lv8p!Jw-`O^pwAT-<`=2mJ{c_-<#!1TLp_42MWTg4 za`AJOXYst~SpxIov9V|Snt^lE5Uh*28ISAviR=iNoyXdJ*qd=ZyZrB~u8(7u*|Ws}+QQxh`uxS zeXBGvdjEJx+{IZscLt^aPDputl%+^~6)M)n9=$f!dpH*o;tB>qPc2TK%c`)9&pif1 z^Q>wIqowA$TWdm=Vb~-e$oy>C-0YCA<_gIu1+AqmT5!D|EECZ0{HOrRc@rYNsPo2! zmtpN7T?r0&J4xsOcQB#>G*u(r8Q;Pjw{oXat0~5*Y~&Q%>9H__X{!V^ycGhCqz3aU zRAw{1IfOhOh{ENLl+g1&|R%@x; z!8(K~oagNsXh-gMdr-W>XFv_)+*u*=X*1Q#9~S@M*q@W6Y#uk z`G){{zyhMEkySYv$R$QH_mYbz7^MctSlKASTR8)ZJyd0X2A7z3#q@y1=-ms+rr3#+ zJ&vKMMBWS2093BrD{Mo|ajP)v7E(81c>^gij}7gLqO}LsoPpcq5L4b6SEeX@4+wLF z#Q=nP2BV>69vjo9%45p+l{-D#S@qk6+hoB4@)G;2ZOYY#Oyukob`bN!GPkE@&qlTG zMwT#|61i1(&rj$HeIu*a*513Z?w+E^MlBtDY^gA?Ar;eGoH)+X@u!bx1?nZaI?Ud{ zIHWk8j_RsFo<@86#f|fROihPgxR&B+S_?k6$f`V2>@oz3MF}A;#;ejAHTfQj`Grz+ zS(HccRT&y*uhyLvM@(!<=X@Ws7I=uu%Ynd{3)yZq6t;2%jX^oMQ7ftA3&=f*9IlU# z4RC7g7Rkj07Prl6aGi;d9}}`;vG`I-7c2JjynS?zh&)O(T?ZQH+}19amyJs*Z!!%* zcr}1lH{zef;~FzRC@0xO)FBDl$)q=~@k-Mbf-~qK5Yj_DfcOivTcF(jN!kB!2)YAsCa8BQTMZkK!xWx|ZLoIbYPcsVvUe zUnXfU;kN=ImRw)Sm?q*V0Zma|56prf1+8cxH`QNm3XV1H_^$K+qu*Q3ks>fov}#N`P6z@_@YTd6)^DW-dQxE8 zRIPb4qW^qk(9=i)^5-vtIq36SWQ)0Uo*pQ6rnvZ!K!7t=-fuRy7-dHZX?dj60c|v2 zMREFNw#UNyUzFZfsjfwfd`_h#pdcf!#AKSeyFZ{dlMJindMp-d>`u2#4thGgzqdd+LwGAiugAIe26`S0UqCyi_6-Y{kBuH5J_YYB1VINE zA(tZYXjj&H38Ra=?H(1_ub19W((}vxST&loke=VTrMw=SAX;H5M zln-mByLrWZcJQADkM_UOg_5BrX!`%m^tnTkU}dvdKwwN&u;_ zy4G47pZQC6Z3Bl-S;3%u2nVWObg8{X0uIXNu&t>xNCtY~`e8vq-e3#Mi@T+DY?=sY z;|T+RbQ3O*V;>A4d9s0kdD5D0eLhyC_2<1G6)r0EW8r`R{-qmkK<-kU%FPJxoYO$9 zcB*ixgU3h@F&7tZNBv6l)YRvRZ@OO2^&Ycr;Ibwcbw`4=>&=F)XlPRkWr^t4YpWSf z;h9|2R$UhmEV12&@d4}fwh=$%#PnfzJ>uH27%0!5rlhhy@*E0_G>oXbnS~ zakz!3o7xWvO_~`W#64M3z1Lx^Q0(0icBkQJS^|Tt6lb`z&L}F5W|?PWq)C>p(wc1K z6?LyNA@=%)Dqw}H3PIRKrTmH?w%)zCcdWf$<3FPPuKXauguz;a={VE}y+{oX@8F9A zhn6E-gamE3D2+2xj|#uv;97ol8fKn{vKc1FSat~{GaXz0{c|mxnlP$3ZfoYW=M{n= zjE#;TA6R2Pf+b|A=^$b%1QAQLwBFq?^iXJ`Q{4{Wlo!nU16s+1!^T{lEITq3KLoo# zwHjP1-$c|J5;JEk*IEbmuuMW7x*g=9+3Eb^d~yCPWGE#pPfw*K2m2D39k^kq06RhM zvsG6BDs>T`tL<4uEGXv+5vuwA<=A2Ru1ew#%fz9kgqcn!4cXzHE|1x-Y8W8W{#~R# zlj}J%ooBfg%I8hzVPKObdQ)sNl@U@)8U&6qjbX~jG!mR3slZx`0%m2V^Q7e*8{`&r zrM3$zQ-jqnqAChg5d%V9u6lVW4x{_)VwOIulp`Tp{59xGmGIE9R2J&ifT{ugH)+X2 zkn$bFrGTUyq$CKg#|9&P4$I;>EW<#uWn{S#y`3!1UAn4Lcdg4Z!oJCsqVr1)DL1wd z>KR1xjI(}CMG9#12&JV^vra2OFp?F&vV|XlNyuzpLDn`_O5Bp`SL-Vk@F3`F%bVi6 z9laO0Dd=g{VeTpImAcA>$j@rBIyL{ovf5CaeQE}UUFI=)4Ba`BuKIx9a#^Sb@{pRV zB1)AmOK+2gd(*|YkN2TKAak66v{pzu+#allv{?GcDE&ZW@UyH;pAXT>y?~LIbuyTy z`1nm953BD|9WJxJy3TZUK7(OLV<#p~hWo8?qY?ebgZlH7okL8y$sBMHL$7e1r6nq5 zPOJxPO)O9xQ3VyXM3114e(xsOr?dfUz`+(Wc+{ZOxe3vB&jaF3N#c6KNx+J%06@4L z&!F;MM&U}!!nu4Ok1%<=*q0;(X49g;1`QcmELeTcZ9I$Q8DeR4VR7eesB=f_gopEGTiR*Er6EUQ(KX3ezrfr#Zh4&&R6mxt9T7 zB3;&0Ef$c(dlY<42`2;4{7qfws!D5LmaU5v2YKU(UfkR9yV%}?hn#A2Z;zSjZl#un zL|NQo$CvA~UEJY*(0akikTqkAY`0DsVoDD(y1*KYRkXVsI#$hYAg2}s$E|B8Ka0hD z3)fWT4c3qceBkJu&Yrkmz=KPi1%6ns}zMBm{pJE5^_dJIH_~zjA{m!CLV*MK4&LcOZ9Fv)otan6e`AJY-5IvL~H7KZ(y# zoh8RLeIznf!{=+jfcYf~FHuf3<*HDguBPV;TFZrCM9AuG@hdi~v+V`bt`_oCq%EbP zCPl?baLExr%B5vtnyi2&K9YDnP%Q3LB#2%NCk1F+)i}$lRrjk{ojBWlFbxTi=uk@Fub?k8-1l`e}hAQEvr0{}F+Bhtt96OirjK`zI z>MBeHPv4QdHLrsMg?-GToq{ek^)RX_!iFRi7kNt&PIzmQ(m>-zl5C6aB2KRjZdM~O z4C+XgpoCMZ7IwLoDm6y}25KM>&up^~2E1Ef$em)Q5eSbWDKZzPrnU0JJmx|Vl=0b~ zDc)mrop~$wBs6Z?_)<5lIWS$t5HJXcoAVe0h!49Y;+V4{M^gI1NK#ge7?Sf|2ll8| zpRSP31-GiR;#u>uy{sm6VX6-REKw18b}Le3YZZnZQaH+bPlZRQkxeC&(gOJ{^HWiw zTEq16%aho})5>!0a_LtqIp?-1wPZ>eq)}C?JOq6w(}bsz?c>#IGCGW?11PVuZ>a0xnHjS+`7;A6H=8Bf_`EDijGIwPC^zwoK-5MJydaHfuk| zetNJ%74BGT&8hDI=4ig9+7Qhcpq*e%p%T4HjzSv^YPL);W@;sIYlQ+sfkK(@w;)sgJXm}PWCKb$8S#+n z0ThXrEo@GbT?s&VQ)lKf)qUaXUvUHppF+gK3b5^w2aRrUL$^AqN>edM3)idB#8xr3IlZm&LKv_ zq`4*yXc0o`M^?&@jXdM(+9vdC)-TM~vXCb*qq6IuN+eb3QVvYOm_}lf>|XB-laI*? zuC}5j7Nnww5Z2kRfq)5v*J4=^Qd=C#6bb7(M5(myIs0bh$g~j?RJlE*|ESuAWgdoJ zmt6O#Kv?X;X+`=V9McCJ(G!-9=OG9;cI7AZ67_l@RYaJI&eg&jR#ey5lH0NsNQg$* z`jhaz9PT~2QLAJ9hT?PhnGVx%%C&P8s+PYE?+xmV7{v z;gP#0PnKrp=NHoE)5g(0h$b`=IDj+frZ6-v^l*}X8E?-N2x3HYtgOOUAg4Hlv&q6A z9X{nGnS4wJv;-O0gb{YYCxnb_`Fdl0Qy4v6g>-er!Fl!IIwu!i73;Vndw~L zPLZ0pb>K1uf$3dX;0I666N00_r#Es8D6zdRROVMTpdOY}edvhb??_D-gI$&j9PB`) z?0DcepR-yUdYiGwdtxg_SXhEMBcSHIvI!sJzoPzsxJY85F;*NcsE}Knc|>Rx3>{U* zDC8F@wdPkRBC;Sf#nwI-|6hzCz~pr*rfUfT;^pR*V~v+8SG6>?>J}L)0V+~jsn=H5 zpgbGr*d-H&(1l;DfDSavUsw|Zot!{p4i(7j1GWO;o0*;kLUW6hA_SsmIKap+BHgQg zIbdWO2?)a##c$K%Y=Dgbq`36_;v;@i*-$XI@R=gW{BexEuR#Oz1?F z*sSu0uY-qz+mT`#9!Cl49X2%Fb+kE1fL1Q*r4p(liAdiREXF1Q;74=&MnIvrwZ$wu zTn)f9{Qqcs_wBZ_bp?#UNIvhKvMp4F-jS-6wduGu+4?r2MjIIlj`Y6_`|L4`=w{Afl=k5x0=!i1?v zN(;rlCEf`frLkmeTfN*A$EKIl!$f)|(CmN*j7bhITmp$cB@m@SqktvA5yGADUKQ1t zqnUuIys*}wsqB*(vSU%US04~-TgJp+d52r5(pNJu$`wy*V3YeAwlvxUQO<*44XsX~ z7SXA3kE-3xQ!t&CbnT2R57ELc4Kg=!;1ErXbW~K>7LoQP){=SP>IX#ZfJcLqOVW}) zKZfJcOvMWz5+*^>n?0Vm7xP5&?dR#&FH(&p&PwW|l6eESepE+zf~E`*Z9Ac(2KGeF zhLv_s-s7A>MzG4o3017nlF;Y3J)MZauH4ztxp~xOCF(Yve9)>?=9{uK8eWF7FEvXx zWird0iM?*FH@+~>0GF$_lf3P+ul#4eU%^QLJcYR1@^Pf;MwCoJaH5q-!m`wDRWD?? z`X$UPftfPn3dro0mO@8Bg-x8u&x?cTY3qH%ws7?wC#Rv87TTP zJTBJP+N@+?NZ4u$fN{Hb$ftdzSVK~A3=)XeOm|cFz^t=rfEG!@2Rl^Oz%sZm?vE9! z_0plD>d09;`Y)Jlqn}zWSTob&yFo|BUk}!xBHsMkgn%QJw(=-M&aw={E)7BgKsySw z4yRVOg89j`(9tMLD%TgmlAAmFgyjfp%udk#aNe; zsY|z`77LU22;q2rHW_{pH2UCVSpXFrq7SQ-Oqtr5!XJj-D8f$txv1i5doZ{Jg1pF( zo9I?LF;82-a$OBDj~b~XI~~5xVl|evt@40o?JkRSh6ZJ!P1eqMT>7Ln9ME&O=`a|= zb>ry(7SCm$j^0Pa-LyGz+1Wq%>}I( z-r1##CMnVz zOB=+N+&x_#l#n~>SGAK$w}Stw-J&`)M1k zzvg&pbvAO71zwmp7U!9k(NX27KruoZ3?HW0&e0O?osBrPCwuFnSPBc?UXkP)j;)PAr`oSK0e_#Zlw7}lP3mY9O=)+a10-ZdvK{|pRA82Z46QQU z&Oa7fN(?F5j`F{%Hc@cc?are-@#&!=)_-JZT#-*nL&tYa@eoG~aAyi;1}rt6FrjaL z0`AsyUcHLOrxZ+{U0&$|e(c@Suy0;~mx{9Ik&*dP2USMd&`BmsDqqTI9F9N&f`}f9 zU36#eMjFjf=qo%E-Qqp;wmUZato>nc0rCPP?T$l#YNBCsz8&WZSSKG^f7lVt@4QZz z^|v|xuCzx=+!mhGFU&L5i%IFTc)WF9R07jdxErVYuO2w?v`v>o84+j7=9aOeUY;uI zoqzp8zpC zzaB3O_kSK`lIPb(v;2uF1MkA)PVLxUF$%Np4CQp*0lZ5V591%jpLm7(SXJo>Ypd<% z;G9*iB_uC?qE)EQe9~uuZfx^PLQ$d;?3QZ$lEWHTq0{QCwN9rYM^*S;?eKo`JH8-V zn>Ub-^br1rpeZZ5?c@4$4IgMY#H*ytGihz>uLu;@4sUzYnzxZ_hvq<_puJ!f9tfek zqg}(02`!e?I>mmwowZ{1wL-oq>;sbVb`3T_UcRSmV~-w5ZZ55wiRNEqkZxgax#DDf zOR8PqH~atYcQ|&+3m8dFjA+TDdT0;d8jTJjowzI z7vNP7B!A2QSFI)NQKM($)hFb`UApoVpEslxQQ z=70`n=xFqU5FHIplK}~#6sF9FbFL}4`G6BoDJ0hc)ievZ__ImLdOhrwVtaxKQ+hj^ z(7T3cwJ_#e2>P0&p8{93PI*3)D}eBe0ua=4yet>${$e+4-6lFV2Nmx#B}d}I8ZYle z5!bx^m(ejCsF1Xhx~EPCODLtkUn;3j;ooI>(wScsIG=$%LytvlDXyhiJ!NsudsTG5H*ZxBd zbd~t8Txn=28RlYDGzL(~Km;ITDm{k8+WJ_7g=$o-VR8Q;zd}`&f+l#}g{qX!;Jclm z$)lmGL0wej9p1uv0|u|{B*GmJ3!7!wUnDK6j~8;Yj#%jxsv3lw_Tg>oqAQi$KXf&8m-x_WL(DfZp+Cy{V zY}%Oyxk=DK4YUJ|ApBuIA-UA56}f@`srBmQh>Y`a@##YGJ;sQUs5%RAuQW^$Xp-4$ z4j;S$ebWjRaEejbtTad^S}R>wq!(fp=Z6Tf z-Ri;Gg_N^o6gt>0s=2tJ!F?kn4^uTWk4d^<&ePNN+Da;F+YV5Qp(t$PqeAuBEp0u8 z0PM7bby)ol9-K8{Rbe!pX|2eRwRr}%!`HusZ>b@w;2Gw29S$@mP+|Qa#MeuZmGnGk z5W7-*Hfn;V5Ts5%q48k|N7HTSEE;wzqO5wFyt&eWuxCeoOL-WehyP;TRRwrv_L{!Y z1qgU@K{A8#Yh*Y1O`M@t;c2@{5@0yJxHNe2R;^~EKR7==t#3TW6fZszw@%O`E!;UG zb720>Shkr zMFD5R@0j*g&y}LPx(ZDLul-1{OG2ck4*I3EX~PngI!;La!_`Pk%$AByiinW{-qW7c z-eTt(j{hb2Pj_A`4Lu%t6&o(CKb#tZ>P;f_joeWQOeDlrpW9s;-bVhj{#|1AX%HpO zHk~$3PNxkmeT*iiM+8FiHI)$eHbnHdB?IB~i0}=1o#xB-YV%bGihcFu{05+U z0x-IIl@B5n_Anbuti(A`e4&(~Ep_gLXxm5XFw2>;)MV{W`_toOFJrN0ep{)kyF|nQ zOAT&qUIbGup#2#m?_1<&C~w0h6d5#}0SO&FaeT)n0fwEIL>y+E!(GcN61(l;wXUe$ zYjOYC^sQ3|)O_7d^8*}M+E=OkQ~!q}j|qzM^OXWxv)Kq7Uc9OX?x6X%*j!D7s9jaI zz11u_^VTt%zmyN+AI3VOw6x*FTk+~U(Y>)>ELV(ADg1oIi$JDy-x zNKm@c6#Qbc@kGEqzdwRutNhQ9)qRr+D* zAB%rb%|S@qOIvKE^n6WeN@D@u(gNb29#)B3L%MP9a{r{;JO2!hm;%VKY5q^~*RO6- z&2HH5$E!^xm;77_GMD)~&j(zx%F$11P#YqLGGJm0FDMq}_q|?99{*qhpt}*HS|Yk0p29{^O25 zI6a{rQLo{n(naKIg|Hp^>5V9MJ*5%s5am8~p^VYk+yJ!Pyi_I)Mqxm*b`)V0j9R_7 zhC!=%%l|59HB~}NKh8l}!#1CNL5X8(#Zau^-tbP0FW(;`#c(R(1u3vV{$x{13ShC) z*+z)iY#k+dp*B}lo9aKCOPVf8r7eNtDatnwK7inwy}eZsI$LroWHc3EnkA9Oo7OklbUodb#Gc_^3J9cu&kJG) zdD+vUC{Py8^>TfSvQvTsyV}*>SG%zE?SuEp{i=!nyl=EIm@WO>f~Cf)U;8F9gA}W7 zZ8qN_k*2=gf}h3*2O5;#PiUy>{77YdWNDCM^Zyz8H(U(C2?2fQ7^+JH+M>Au-lrVV z8bq65RK8Jkmo(At-mJhv-w4sQV2BmTN>TF%ePa|&LYG@-;$`Ro(`1A$wJHW-(1RNy zzxuE^=J3U_*pur!B@+Uh30wkuCRKMcqKNQ7C4l7kNZ!#bdon1Mqe0KSiLBvZ%sV{( z&EoY-c_g)-044sFg(QZ;GAGRk$DFuogy(@HRY0$V&+kt^cW8$PKvo+NCBNGh{wj#I zN3Gl`KE*8LIym@_ZP=#Nz`<5nR{q)DJpbF9NRNzZMOg>E3wN5`*S*~~+G<-JWxl~p zAiP``E9AM`+b!olg1l~Zo2wh`cw_E=OX+MlJqbK@51pV&9Q4qzk*%C3-a0z_t9yTi zn9XW?$ylX`sht57IGc=zRqSlp2Hz(H(R5 zR(ProE_}s20>VXao!ApM7e7>>V5}Am9h1LNMlpaG(Oq9g^o9IcKd$=B5+|o3*xFV^ zS*+@W6QK_+Is~{UVNx%#6`56utq5kp%%ywTmF4e=qt1Iz7fFfB8`BFxP^Ew5>MlLb7AWX(kwL4Bd%*R6hYl0(z=SLkF?j7rqIeytQPYF%( z{=-rh8#mW4ZuW%!v@MWJNZS~wqk1`9JDahjVPL#DPH0vEgHSplnL@h#xH^@tTkJq{ zi;$p4SBNYf>YFm`zMJv+wV#$mN``K4o(P`<$^bLvx7vx<-AF$5&8hi;%yybS_EwWc zzEr9Jdr>NFSYiPnMGtxC6h+KJm<}E$(!%U_nc-o;pb~|YnnBkL6pVo-KU!sWc#74) z>D^iC{tmMr^CkrP9TC^EjD-nMl%&(%StT0 zp3+!3zCm1N$!l?o83R;7Eeinkh11cxA||R+G_SFkr&8#Ev~*gdz;Q*uIv3zaI>K=E znmh-X_Yre@XoxCnhtU;_n)^f^H;5XEHMl!^ufn+95$bK31UMjRk}GVy_&%nsFh%QZ zaB(TFye?~9GnH40Ne#-dUE}>Bra$eR5>X8he%lzMY+LIP0fa#jCr%5`P3VL`U<``G zfdVG=L5nJtyVSSxfewt;$9AzeK7u-tu%^Z0YH?|?8Ql=5W_4++-P})Y!=^dMSC1k; zKA>XCq`JYPiFw|jlS;I0`_=ANLIk}}g6eKNN9V?4%f?R4bD4r(b;}&M4MYkMvYmBY zd=c11%VGdx^xL`Hv7KyvrzV`h-jhZA)WzlEHN*FjIbQOxrFL#(B>*qug$D4wT;J)G z8>0`Slfd}eZ)Wh3u9SSs78AreORRUc%jXLV3%+x;om&Xb-?J}1K?tV)j6{yyA2bp$ z%ap%3HL)$$Ybd)wyTK2(v9AMkvWOX&q}FBY>lwlnW{B{?EpA|W{$5*BH@>itu(!7U zN+)t7O@5Cz#<_q+n5JZ5BU9tczh_6ZJUAg;)uC=%6BELyE5pe?EU$KZtB9E z1J-O}=Aj#pUH4<=?2hkPJ*_)Kti=g1Jhyx(3+j^L8v=s>i~MrL&ts)D4wY5v)n49Y zsxOb`FOO2=833fMG4Qe$@Bjwq=z)}$fSOx`@AdLZNvaNCH&{x3L(z#Qa zET%6mJZ*)Eq^+uisw$N`40l4aQ2 z2ZP?tk^#$0RxVNJSJEH!>$w|C{Gt#ZCvdp(a!h)u%AfLGa(m7L)Bb##JHp2G&b-)& z?141jD=s0hqof&m%;x0%_-x7FN%KJ1hX}(0#^HOL5G$ETzA}p>3@0BblyvM{p zk|2hN!cl9Bx%rq-R!o)_0wvEIz2f8KU-d!TQ>Mifr*%iR(1QA1|~wz7}1*bZ57p zxfOeeaMS*p1IU3ndvC?5VyjX1>unPfkC8)H)x|w3+F)z&{N4Zh;~AwD>gW4Tq8`PQ%4|Y=1zZ<8A)5d5%}$Ni6i4>=>*!VuaUIVzz#bhp1M`SUrwo37Xv56~ z+N)I``+TW2;^UtP@sUl{=ux6=Q@^Tewq_27YZ~k-w@Tdi_n&ZZ_L1rD*{i zynk?iD1o?+Qy#nOQx4JQlIb2uqQ}RW0mJJwNoM*t@MxR|TYX`$oO6f5<);Lj%8~9) zd#ybadPXWetz-!U0Sh!l3grRNDK&G@ZH9!Q7jM&H;pNNqR;t|=w0{XMb>6==OJMHz z!-BHz-LLOx;*gQX!9WU!AgF@eETWdY*RW>@ki@=_Ps(+LD*txCbH!D_FbAYBKiLY7 zFap|8Pgl!f&kJ*s;O4yWcvV@?QS-!j%7ZGuA5F#$PcD^|;N3z&rw5i`;Oeq2L2u1o zUii7*PPPZ0U$hSU{BLOiLM=|I9b`iF0{^cL$_6NK41e+__l7G_tOB3Pn{q;akxItH zPxbn50v3K)ZQ{XvPyXV(cO^2YW-blgrln!m@_0%mY;}Ikm;=PadQX?I4^1wMT6@Hd zcxc_PwsG7?Cqr%*P8ZQl;FZ!Kl!30Dk(<~*FnBzw(?!!PllxY&L9fOK@*+9$as%-q zQ3Ta}B6ooh7V3*G2X|#>`daF`7q0G~T)~aV9M6>Gj@sQ;XdH`00OiyomXJQp#M3*! z_;h!RSk*EXY}uh@hO=HS{?z%QWZMqV_CinbQ^CR%g)H+bQ*%5n!>v474{Q@XGoi(j-p&2* zG@)gm1=jIXx88ualiMsz3jNPOJ_%8A%y6@WkAilptl2ESULfZ-hEvF%Tz-RdD;LjSCenukB9X=3FI zwBjS_psKL8e*y!?cq@R9&@6$D+SgOMKlHnRz@G3C&7`BAYX5lMH0e433uykyM~zUm^Uj4ds$73fMeT(=I+o_Zkn~FZz^#!LT}L zGy8Ge5LJ~2f4*w}4l>dRN~Sx~y`Q`pU3Yj1)y}ojHPm2_rdq<~EQsK0h#C!ci*KR( zO{MtE6x=AhUYauDi35@7^c1TbR5dQ`i|5F35=oN>=}2UASIHP9IXQGDLb~e2(P)J9 z?9ue&djQAr#mSLz38`gvRv<9pv}g;UIm1{mN6Lh*rue9x-Wx+s)Noa^`kKA%9hPr1 z6a71#zsI3GwHIrE`(4&X6bN`#hieT$_1SUnJEvFbmp$M{4MwzURG%Zd^E z4@CFpaE8gf$3@|BNp$;6LA^{$ar7PZKV36c2iFq4gM;!rUcQP+XpBEz1!n!l;b{SB z=CkjP#vcQMY>`?Cp3E#hKAfX`P%bYM5Ej{BR0H`>60IEfscacxD_!gt3|NP71 z*+L;*Fs~op-QH;TIyX>$~FJ5C8MSqvB`Ee!W%nm}WO&PAGZgDpLXR&o*>CZeuhZ_(TmJ3Jg@AP*a+%B0CrNNr{idKUzM3J zLuuBHTzV_a#lu~~#-$Ff`KvVK)}bkh0F|I(coVO?-JN+#uE;~%>jTeMfF!R~k{PVp zI8bD)RxO`&n^D@!b$8sSF@IxzjHKAC`Df~;yqdqZv{IA4*m+ZkI_86yoJd zGOTyW=lyU^@7~2gFLw~Y;?t~-o~K?(8XLre^{>m(O&`eJf+{DhQ0Wr>+lQ$aekAK> zh4aM)&u|$7DOB{20I$TT9J~=b3^&G7?xUXBgnBaO6Ikkjs9fjlsElJW zf&sC`_0&)`Sbs2m^@GHSoBh&cENkCpEbR6LTBgp%OTd?dXK|}DVA;$!e++V_XP;hU z*;#$ot@ct9-mNb>g8IfAu%(a+@5oHEf4L|#!{mxKvbAq`g6EXbnYw}Kb^40P_PC&I zb$zQ%C&LLb=qVJG4l??xl<&d|qNs=cHrrkNLt=2RD-t)(Bxuc6Ahg!IxVl)9j)`_w z8-@-|X!-l?l7Tim&9$|3D84mM#xXE7?er572CL4p#;Hh~!|K>>7u4#X%<{LUwuXVi zt+rp%OTwYIq&KKzI12IuSR0dIrlkvda7^LQg>{_dB2gpR-dX|>5WOy7wE(gN{v^^}z-lEf*9r{z{#6WiO@sE3iJCYo=>ZhdzR!b50MBD4@ zKM9J{Qro75x_~|FQ@7e$wjj(as+Xa>8j0AD87ft%5jnu2A6%_ic8#SUnwP4rw@3!I z-@w^?!!Ns6zahpJOR57I-MBpP0HxXN9%QSzgOii;?X6~qDuZ54=Za*I)iEem?8n>Q zTnc2&y^?#;q>J$$%-#GoE*Rht4i0|#spsB%Q!qBNb+*ZJSUpqiGguA&6C=Y54FuNl z_`=l5aNWy=`NhU=x0}B0t!`{{uQX0sUt5ojhM4^-dYODlcucaOLb&$NdhZ9bpck8* zFlZ~c3wO(p^m6BYD$Bhh6?(w0zuIl?fc(tSH4xueRp8AoPwwleF*j0QRck7qli{TV z0>{Np!?fs^F3$EBpD%tuYUTvVnK-tZ+rJQAVa3Z7F3Vkk+jLP#P+OO>W4R9_2S$lg zh&ThoJzZA2!NKU5LsDN#8FK0gB6oxaf1&^~p@mS|1}rCjsFr;AgBIS?;u;WB@D)3p z_Y9o^fV#5EJU!#&WjUH@n+>qR$X8&JdA-Edb}&;B@dUUq8=^4+i?$&r1n%PG@clVPnOR>lPI z10uDS1ZBZ3mBxGM?hfvpE!H( zVoQrz3+D~kfm>5E)2e*B0jdP6@Nnc$O zWPwVaOX&4Rbd}(+?ruZ9wgvo1QeCmM0NgImSn8!_s+=k zF0R%}+n1Ko^BR$!kn^EB+X9;}{7!v52+}1%0i|4R31kcgh0sd~#}V(=?6XC|uC2tb0Q2C&}xzqhxk};1#GRIpH*#{Iyv?9ZwPPA2Mzus$(mMW5y~3>eTWOgAvtxWpcJfLK+}#t`rybcB z<(8Cc^XhF|?@L9vsgA%?UgnO(yfw#zIixU5Q&paXJX)RYk1c9V@_fjl5}2?$DCWEQ z%ksfE^f@fn^O0tW+%5in@;?AzwH68u`UT5e$4XiZm3eXViwy1bn?HXfPy5Bq&uNZeMR6}~{$2XBr#b5FTB$6iz8x$f zDaetIIk{e3UU)+L=6!1HnGRe7;xH zxh>Y{^CMH{jLg9y|Ia+aa&pm-3H6V_G!Vv8i=cFG?o|guS5$36aoLc`lRIWV!@C$*?dD| zfsX#Ox!&1qcBvhdBV#~Sgo@tzQ{`>>8|OVciS5U;tQ59FWu>>Ix3|Cs>g{#lXYEe} zGO3u3lZbQ$F5@D4EF*#>dP0W;^oYb_po~DK`UasvP0*Vfnxp*`>I%@&u6KN;bFIBb zdl+Zut99xXRWs1TO_Ok61!R$nCAvtJs5)jkeUq>FoW9ak=$QPPKjR<6o$>-$_W^aJ z*7oMkMtc)2x9yiSOWd!D|B5#6KijWo>TFv`Cd}1Q0J`Z?Wql0j=gsoD*QDtsU^D*Soj)U*moJ3KPXI zKE>P2Za@Iz-;r2g8VMmwsA(_u^vCnZjw>~b@-b!qV`r|Nl+#+t=-P<=Won&hJ<7#JbC1$kyl%{H1V3KKX;>1@9G9R2S$z zw;PQw`O=Z@K$LPGs1U}W_9gC}3Gk?BQhH$3r`G09^&zfXL@6gZanX$A=}6HYJSw45 zkFD1$kDeQK34y|O>v~3K>J+c6acgqug^d4lx#X1L*5ft@fl3jEprmRG34^19Yi(2Y zh{)HrY*6}&_4JNH!mS93>OJQnz$!4vSv`&?ghYo~xLVTxqYvidU<9)75?=5Qh_=&x zVjuOFsd~xZ9iO1#N8DzZPL$mOgOQ7zfvK312HzxCDzcA(d?gN2tctehDS;9Tbf8iq zOtAsDQ`_VUR?kma2-~F52kPWyN>_se06%D?ilAUT1UeW_IPea{faHI&3p*Mdv~+%) zF%_?~RiSCRdVgclz2oUjy+cL%>T+^IoM&jVvl`Aj6 zb5OsSd~{}sCc3Ujm(FwKL0iEow#opq+dswD5)~jsqvF_@PCiliAvbPKI1)A*18IYr zx1G{JL?Bt(z_`Iua1Y(b--zwhr#=zV#Y)z$Y7RGyEcQh-`Ee4ToZ2kLm;V5iF+{Bt zq!y@1i+fBI7z;+#isE$I!m9-X5xV2Z8T>25SkJAUK}OSf)cx~T?WFk!YC78=yft;` z`o>wkwdw@yudg)b_9HMCT>dQ=Vl&{WYsIRFEObVLGCpu*z!8;D4o2Gtt49)iYSK{h zZL5=&Zc7sh1U(cLWAkV*8BfOtlu&kdyaw|%?MTaYp?RPpn$}*2M``m1xIbir*RTS| zMPP9Wp!=>;@7q~lLk6(JtRb9O6*^|9UH=>yuf|iuCbslmR7jg#2C@B;OX5tgm#d4P zYyrh%f_Ukx$~IL^JLuDcWIR0*{2EIbv)x!bJ788;^pN83chru3+TOO)>MC6x2iDc7 z&1}9JZD>(bt7=?0a2WS!J8N{c;n~!pOCG@tZB6+Qw%Ps}7Ie`+xnS~%EN5ckfbyqw zPKordsrQE2wem>-g(BVsWQc?#M}@$s8L|`g@Uewb_*%^^xKgUQT{T|Z3>sMBcl4gs z?C-cN#MTHB;N;kdazLr|8rvEgA-)Xl0c_fy92)Y8mxH{XSTuEFjWK)<8uBJ}%fh;X zS>LW$cd{)`8A;|CkFwquty;ih^(x7z;rgj1Q<7{gfBp!Ojol_0ae2-pFcnTq9;ZbzJ#ui1P=)-Sh;usq%r>c3pvs|9y`9lzC*+{ zo6d6aenN=Lf-x>Lhnvebc|B=maKL8_Q_(+V&AX&iv4`YoiSc_)zL<9|%{+X5>*aX1 zQo&UPn1{>9H0Q00b?B{mBQo43hX-G7aDU<1$<-Wx4T}WUc}`&E{=l|8V42p03KIyY z{E@99E0pN4jsp#)3%Uw!pJx?$URo1|_{?hMQL2|msl-9EvujKEpeaP#;ltHt2MWFM zAt~-5l5FBLcH|*u+>gJ*ih}L&7GGUEGFUj!*{lCw-9GhuQ-IL(>Ovz^u!8UPp9^JC11e2 zR4ya4D^wQvk%vy@f?fxZrhuU1$Kk1V?;MbB?34T5islQ9*%p$W=L((=Hyk-g}hUKTh1O#@&CF4zci zh?18G!~KAyb>lTlE-6mSi7NfgP4N$9FqF@{e7W}ep$-C-5Z8z?qbdS-FQNj#KwxE9 zdfx13$Sk5B?%-0?G`5MjN8?`5e6}LNMpTc>HL=2n%J(B|bLR4#Z1D`*YUt|!{r~-J zFXTc~0B3Kz6x_HnfAjf6v?;lvhCYTU&Ant1>;HZ{7Z2KKr0AX=g$+embfAZ4!FyC++UZw?ho0Q|kJ&fbo7JzeX04#YYXSeI~o zi_Kzj-IsbA-sE`HA{bXP$TP@jrZ{|h!+vS^F7Hiq|FX)k@d=Ux83*n4$7VMOl12vi zn-OFQr;J{R-p$|Le&t%7-TcP2Oj0&WI<{VKueaI|NW10#RqpZsb8~awJiOOs-YJb? zt^+U>bNs{`_lf#u>(g5~meMFCRL72mkyIXYaB)Ri(UvW`La~Atg1s>cdi8tg@~{bp z*td=~duwD~dgl~=R3y-|8Xs@Qf+4gbH>rPt9-74l{SkHXb_KAx{o`7n<4(KlOm^_; zAV0Er0rAo&Pe9IC#;KF|DJ}y|xiA)xwFgxCL&>F*@yCiiv$_qIB4XNkDiD!4_Cy==M#~ zrouN9#S00rbO%iHHD=$U0Nz$A zqVzKsg){V=G~F=k;h;jO38o%zrJgT%bjOH!tV(P$_3Va3476u#W9ihiw#~0vTy-;* z)y@{w(n?A+_M_nm&ElEJpqz!OMYXY-wX8f*=_k#Q2fZ?`xZ|dLU87j$yk57l}Gq&$81rCPv#t4zHBAs-A#AWj08zEU6Lh ztdgr=6z{NJ02``;MEwg_1o7?8aMBHUdD%c?NFJE`Q6YAjH-B9P1>FDWW z>_%-gWJq+l2sXlukR_tig<1aML4phuM~9SuMQscWzpT{Wy>Ql$0DD9=D`1tb_-o+i z`cr^IterdtBFUs?ni?V}ImWmuqnKDgAu%qEaaFD3frhr%@#R70IkE=Y8z7rluIZTr z@mZ&YM*wpJWQJ?yvIaUu74>ovMAtRv^U0=e?KH$b#I#_dt+dO~8f&*Jy9;KNAx+{z zp7WtX7;T3OXk;@40C$X-YcRLCVY-3>x1wKc@}KwSawG_q%F3<~2|eRF@6VZI0S0o0 z^|SA|qJRyJvgcR?&3OC!M=&L$3$Um^4WsupRu@28@KgR}8^oZ2)>~t}yVvL%p$WT$ zQN{;?n3pj;t-wMQYv>#3Q$TXBl!$w_`1p&)v*$4U09a4R>0fm%t=~VX)i_4#&8^;1 zXKici(l~;=%_cjmAxU&O#*Okh#31NwpeMve9rwzN-@wm4Upy$@W_l+^8Xm z-o^MF&uOf+YJpgxT3hu2CJ}nsH{)R4V2;ll`|rhqq&G{VKL#eLXPY`FbqotGgT~0R zb5!W%rz3D`{80#EGrH(n#CRVvTqiy{eGE=H(HlpGV zBsM(@NR4Ng%CZq&PSg!&rr(IqPva?yqgaJsM}y`W^_Y0)!bSNmixFBza&L0f_^@15 zC&5yOF5!&Spqv+YjzUvZ+N1#w+9RT~6HhCTC;sNzn`-$ESq?7^2K${YHO4Lpit#1G z8qjkJM#x7kty{IqOQILBC-d#B`*WVgcN<`vWp;Z?EoK4Qe#?I#B1_GuO2BQV|E6(JRRF*FYl5wGL zyk42&P&_QHO{Rl+KvL|G^aaV1rF{hkfm_sIK>0vNQ!oEj*kUiD+}P;eOeB%g*E(gY z6GmS_B?!EWXreNU(WMJj<^<$YLnDas$0Hg@+YszKt|7RlcZ3&Y6?=aySdyrq>Rs$P zkDk>{%;Vu$LK54IE+MfIHrm7g40R?mlNAILS{U%>pMU^{Rj^LCc!p|$_#PNS3tPIR z8vpQblfR7zLpeXZOi#24SsGojP(4W9HL7mEg)f*jM}(Hh3`6n1zs#tyPIt@s*C8=W z(JaRam+*=%K~wuIH2?4aLxP4Y!$IR!b#@Q0C>!@jc=#23J4Zt=!LsEPJgBT-m35taQcSC0h3lM~P zrZB*(bXKf>kRi5uPVKCPA!X?kl+6(W-3DQ;VaxG~2oI|*^blZyHYMWi4S+K`-KSgD za86Upcp?AAlI1BKS;1^Kt+E3(egh^Gd2^qdxEj;B(lG3~^ot%S*+e6!e;IS`6;Fvq zBisgQ-Z~pN5sH2FvT2p;pe+?y2mER0M2fAKx|x{cJ_s^%XLK>sDY~ovsIyI?ah5R> zgs-nzb?)jBV~dAy**nDrvrUGMf}r=TYT*wT#b*ww^@&ME-z+qDAd~frQYs+cVZ3K6 z|Gqp^4cD#8?kMZh4tHL*8t_QwCcU2Q2PVUVA#W1L7u1)!tz4X*_mI!jCPOKns zb=j#siQ$0mSJ}?|K5#mI2-V|IeveOT-*fBGez0>V&Y;W(_CV)?&g;rk5 zMOsC8Z*|WL%!lJ1jQGIuGz5q>AhAu^DkWz6oZb+-EnBxqwI+O&Xq;vIE#)ZiMx)h= zz}xAu=|n0?Wh-OxS4ga|I=V$HZ~h|e(U*nwh+(xSg6p+51x+sYP;dDJ-ei}a?E_A! zFNu#n;mG!$*;fjnYNS?0PC9NNk5wf$UId#JDCLk#XfEr0>aC*hI=edt)XF2NeU<4V z3O#l7bj1X0cfhs$`T=`B6x8~F!#phditPHueYRYMx7Q0t9 zKV1c2*fi(LiPdPmHV85mOLL2h%MBH-D9_aU@U-~#-g>L}-QQ!RIFymdm8=6+)o5vC zq%Z$+WBV&*^1BG}IC5XdLLCx~s^#!S0|v$1l0q32|3_JrFG^&03K9s(U$uRPOGm`r z?2>8!-v^P+${N5X{!U#_<|*6_}4IOdZ4oV6kJVwj6F z7uK;{EP^kKQj_~$;N+<#v^wH?eOz*yzV+G6?xjwsh1BPhY_Z&gQX^?F6cK7Y_2=nu zt^SMz_N*$m?!SL;DeCJw3O5?hiX#~$n*3%xZBo`}MvK$6#5K4_&$Z%~6jIhZ1^ttc z6V{BA2LC8Ae`_23z2Zt7g-m-YexUpfX21mZf+j4nuR)a6*5eUGkP}gE zO+w7mxYo$p^1>l+!ZD9>EuI{NOmo-|C;@6MWQ?{N-HS%Iw6a~QoKgvinviL-q+>|FDFPYdH{ z@>K#|VPVStVk(+zWmm3xCl!1fKC(L=BMo?Vdj4Sv0l`y%&2Jy@=BY(@K1{J}J z8gB14L#YxDwiva-Y=ByMqo8YmD`FbF7mDSAscP0)Vv`=HWqRznGR+%QP0wPMI&}sy zwJd5wk`^ch>JP2KavhM(y;p0z$r?nvD;18$^T&<;DuRTJkU+}35%yn_k7}N~0vd}L zOQ69))psct#6;Ez_;ezyE?1cC3<#_17YNHZ@jqzzZ?33t5hg1{mc<9b?k5427w4yMBW4Nck}X7m(cM`vm8w{nZ$!{$D9bmzwmNS_Qou(iqYs)9 zV5div=yE|7J9KY%J$+JLcLrobvcnGc2YI3lW`5f|=%gRf{yS2XKG`q?!in+kzZaN^5K(Y*RLcH*9 zB#Pn3vF?!PIff?7f!Jv?jXCHaA&I)6RF&UWD6&}McqfyBk%9I>pRyx(F?plNT=Pch z!lQP$PIjl(@R&Zw<%1;Y%MzRaZws@zYDMo{fVPUQnXpnjBz#Rk&Nbi>!_s*XcI4bl z3wzXZ;l>z8>$>a^c%ZAEcqu7yc3`tME6M;s1-t`p=FCn#ZzsUDGlMoi9` znoZ$qIeb}eL_N2k=KjlNYqrDr6#pQL*l|$p$YBUv=T_h}MJbkQK zWX1n11{YJ8yy+qWIZ{lYu47j45O9w9hjuq;k7TxR&ROfHv$!Vy*-XpiXw{6Zt5==J zRw$D7t+=6e@N;;)Qd~kO?N?os!$v6%ka;z&As)Wp9+lR=;l)otLOVFUn8zp9 z=~?;J(S`e$d%SP%@rr?QjEraoH~)cAfxwQ(|Pz}m!@yDwYMmXhwx)Sd=g}*ye3ethSiamye@;g0)04<9+TYal$_qysnsj7n6A&GVhi( z`a(k&U!PmiyDfjU725l3uDBM`vm(|%DTGJy1a8S{SGaS9K$vb7q3<{%edG~94)q)Vb2eP*7Rq-mMw+dfGFY z`2@>tZ3~$L4RkR^#1wbiTkTidFc+iGabD9P=7oBy!7#n$*`6nMHFnCIpDQhAeB+yY zRZMmBGc#&GLGk+S4oZs1d%Ol{dT1&p98A!p(H2<(auK_}G_bA0?=n1>QhZu2@VWWN zj-{WoRH+8O_bgEt(WED}DNfSGb?=aA!(#b318jKb{&%n_JA1T^UgaR*Y|=Occ~h9D zmDM#4quWHinq27Hkb)6|;*8B~K{KIMuBK3Qgtf6mY7~zHn9lSZQ67cY8uo}Dd3>e( zU={jycRMYL`|wef(k(%3BqvNrkeHB4SFX6~T>|442`YOZ9xDZ%S`)LAmwWTbqx{ta zz7y87W0HxgmFIPLrwOM91uT$S^KS4Kun!C<*Dw*eYzVpdlnXEpJE)RX$cj5{x-vcXwgP&8E0Tw#Tr-3JN< zd&HgC&(6`+m|lF(l;;cXH)N`;Er3xt@S~OFe)d=j*b9%JDB%qU%zD^IElmah2?0%i zuYv^AsX*vN+Q#y8njO{d89<1y3B{6$2TMwQNc0!Ij7ao6{K?k2MuoG(( zBU6y?mO%Tx;*ik+eNN78yHypp=zzv*Yp|kt`_2}NiV-S7L3zo}E+`Y6rB^QB-tdKd z573dFm5g~Ph+nuuXg~lc&Q(kGBs?+Rqcpr)s!bNe8N7KA7nh$relDs2;|Xums_TW< zctZmvn5-$ZyvcZtSRXSdMt&+Mqt|~u{EI( zu4&4p2DdR})c12e_`lk%7!UEejr}I4k;@PioDO7M;QWcV3H>=DP8h&OWdNO~Z97%% z{UJS2ByTpvPG(t3^MMjBI5_okq-uGqd_5+Y1A0}6C*35+)NA9PE=#hNmA@aeUW4rn zgX*PoK}tT0@hQ%xUUM5`Z7}=+BCJ;diPWNjG_H}p{~t5zKp3Jpul6dy(5Mm#b=Z02iJ+ z771qAM3syOV89h&|mGiG#US`<<^5+SSCcHmzQv*aa8Mv%CXtIrXExAQWjf=o^ zgmfrM({845<_(f;q}F?tcif7}Ii4$)+ONxEj(RWReJ9VS^LwCt!ThOoeWRZxJ zFIS(5(1;!UwBDa3BBkpx@Te36t$cGXE~lJ?Fg7^SqBUABNz5X<;K3L3GwoMuGZTQWr={= zss_;ITIOOdqgTSkJxQ#~B?lIbfmwnL8u4>N9P>)#t9|k2@U^u0T>k~8Y79=#mll=~ zE?P?SNP})%%d$qc6x8R46y@{MeC+OQirr=e*E;lKXX+6U1rOr^aj8HxCGlUa`U9l7S{TeRWXr2)z&|GFz@}rg^H3!5IhoysF3{A1cH(Dv7 z>dB{uiDuk6^fHq(bT*IdGk(UI$bM7`PD-p`wLBR$HTI4Aa;c!QFC%BHjS^Yscad7IO1io_+;iJPn#X;Q0%tY2vxrqOerD%PIo)N!e+PmRuww$ zzK%98D2mcd685LndKvd!0HzMRJLU-~`^{BZ1S=PBrQB++b3-SmwQaMVVJvB-15kjj z_RB%-B>vcB-KD87;}#3D(t|XZicF0-l%nz=%I#8`T2sI}W0)j?_9s>4CzY$0H2HVXYj{@|1UH&zBd z_xDF9S&0&mQ!1jf%&kY|Ke7R1eQZ2XIS(^vR5XnwyH)hb65!7lX^zV*4sc~_|p))iZ^adWS0707^q+V&AIAUK42_o&8%1!%X6(O&cx zOo=*YU5T;8(UREqPrZtpUb~FWAPrNeG*B8NvjyD)Med(yx-+O!xO_ghK<;t?(|TWT zxb@RE)NKa6%kW$NDzonrdM77Ws*v*1?*Q^{e5e+Z1K!>J+=gg`SI;GAc)sn*cL13o{k-8aoyo$`V#JICE7Msm?z4bNf)rBl? zQzpzyoC9F0?})oqfa~4(Zh>`aEF3^6A6#6W=ls$`+%<17?4}vdmXQ$tM;mW56AlSL z4O*}!B-u>-9^kNRR|K#~CO3$ia2@B)zu;@)&o<1f6Tmwv-4sk? zl-J1dl54^=%0W*K@!(>fdb|$@wX)vf;XI8*_yrRuVN_^NZH_Ju$H1P~r+SPTC@(SEpW?IA@V(6NHmtlL|53*aoVB0F^EN|W`!pBZL6?vKuUr^7=3Hf$jl zr{TP}w16wI2z<6+#mfnqSmrgDE_(z_BQlES2(LlKa#)b8D9M*~ z6e;SBHD})wpqR6f_Nc#i0KSAJpl&lfKS@xZ0dDzS#<847c`_a!qs-!k42mcN!(nq*lCN3!K0=+?#CO>Z=`|Xt@iEf|HM}^Gf5};c+Tr<+Zi0 zEVfW718|+ux7y>Nj97}Pqv00IO-mOSmF$9HI!=)EHBe(li7eTvA-vqtrg&&0{mM`{ zn0erMErNGJ2mKR!?}Y4~Gk+iit`BDrJyL&!fz!rE96XRwy`i(Bk9BCTv$JLbk@1Gs zzcPx)(V+JJW}-jfb3^kWQn!tEcQfZ{SVO!wG>EJ)($U4K<9k(Um4DveqR#5q#8(0;RQBe1dr+6$Izbuz8Drl)B(iSP}Ihrk|yTcM5>d`F`@U%UahI;{cbx z{DLB{S6l71at#zIorP+rc~v~Ip5QbDS$MTcfljytTD9i|SU?n@mTXWwNZm;U>s5qC z*m_)&a0lgR5Iv4{PxKkp!x@g6=s6q|k;im~BqPb<&GFNE84z+EQ}o70ZmW$lDEYs! zw+kB$xdLsh`Le#@mJH-nI*@XNRpcPaf?VPQJ5{&h~Z0dTI~ zsF0|P+U3B^luHuLNDdQ_W&+Sy^fwJaOLu5&N62)|^n34qp_S{?a^$Ucw?iXAQ3c`)%HdNC$`(Ue{xzxveEt*R;pZc;^Y z2W>3$8fn`CE3dnIXWj7^#rj&isU>kG{XyD#bFH<+F`vw-cQFS@G z^QsYzMaxR~vbOa>AlP2l!YU#CJF)VBC zKh!IxX67qTZUZMa_;cS}VNK_LaIbF)R(FK$9+kaCzZe3)2j7@d<~NVZZ>V3t2x+^6 zqX{80YooLrWXEMAVyJ9?HqcE*rRT7>Av)U*_(zZKS(yisJEZU0@B6skOy;mQKxPU9 zu9Y1JCdZ0A1cNj=%hhAX?zRqLCA}w@2pF!U?jjIb+DxRQ{a3{6)Ksh=J1i}Ao`zTei{8tb(gBg zRBPeTGUH$sPfSNvR~ZU5Td&)_)omEnx3J45zR}qXdg%mm~pu~V& zYsS2c%$D%3C>a&p#d0BMwMJR{1RYBafVH2s0CRdMM_c=Hd$lwfLi%B0?zzECW$X1kHKnu> z+1>bBOv~c8b$b?+uJVB@OCSEe_?7iv`!d@2&K8zVXg1GV23kdMh1Vl*7&|Wblm8Vh zXHux&ID^bJ;zD`ydB=I27-*H^2)Gk3qiFfxFzeCBeJfV~HI-TRiSED%yzdoz9Ywbp z_Ri*&t>oawRH?zLA#gu3*cqfu#qA@Cmxo#0wILQZpCp3?J;dxJJ*CaK%zP z6l1RXA#W^YZ&1;RYxE7XHj(oNCu0ht?gr0T?SHqYHg@ll*Ov+p3>!mR@TgYcx^KB& zb0ztqzdU4rl>nAIs%;GYl+c0fEAF-=+KFCbM=t4LUjOO!&yTdPRS@^6ReF!B$1+J< zsrBv#;1iX$zeYP}XJfs!o=a|>;-)~A-=f?>Ihz%yS~X5ZH(Tp$rxZlB5e@9>17R}Z zO@CjuoJ!Tjr^`gPgYzd#i$OnQ%MT%Di(<3b{WP%sXA)T~UU}0hj53tN1i)bBSJI7J zaq5%aU~*ok-dV+}hY;iiJ%O5A2zyN=nQyTUv_y{@fJz5cgc)>Ze?479=Senzmme|3 z45C@tGhwzM?aU?f&jk)Y4@w@0W*QxRqqJ93CwutBEUY|4nx%TXb4RE8jgY52$#ozR zH^H`8?Y#VPw(KbfMDKj6rhv?Ej@v~UnTVFDJB21^WCQ|i-r73% zqJH^DDv&j5fhi6}U~3~&l@}+XL6GM%D3gbm1sgVtdfMkxiaVw#Eu6su=00;9uOw~I z6@`yRy#e%W*oKo!>LY}C!bdKTf{$z)Oh^KU1ysTef$o!M&P!Pd)u)Ln|B$CVvgVA2 z!-aS|1U;;z(Me>*CX}-DuR$LeK#t~CzK~XF4GFY8!i#5*+~wHwa`DB^YFlD~R_iL9 zgh?bgOxSOODPdG4)?SgYY-TIc%jg|$0Xl_bStdrIFoP3V0qI$n8-KM`&|??M)b!$s zLC8dA@1noTI?BSQ)Aq}bAdZCDReuwbKxHy+Q+x?3w+t9%tgQT#!LV^Mgr;RMiT(== zr+-peEmWx{Bp2$Vw@vxQ$x?JWX3Dga_f3a#3Zg&A>>rFkixr!9e#bvj5m-DB*xis@6r~`ux-hpUEW~3G+-B=4I53$bIE#~ z5wHlMF?R_DV9lv6oq?fyLvc^9zl!U+eUP|X9j%lqGRtj2wWy0_%W@RVvH~1hhT_sZ zO8K-I_Pc`BnIL_`+y=6z0?2SXYUmh9oIz!>Xwr0GS{U1nRg?>3uGCtd@CA`5WwFj) zdtMxKOeF|Urwu^FhT(}4eH36t^^9}W3h~f@xrk`>*ZLYogwO`OEpZ0A%2|+1M;MHF z=w8u!S3zqI`szSd^gu}v*KD}Wr5+S|Ei8FmL!WqpAjaY@u_RoM5dZlAwLa0(!s^Ik zV%Z6&)nckR|8VTDw5j?RGH)Dhz8cnWu*M^P2g-bu$>%{WDpVuy&C; zNI`AT{uSw~<+YW?a*3h|7@`xNft8g;y{fN>x2}S!ah_B%EUG9lqZV^Q|9=ud$T{D?xncr0sHjn4tL7|vXot~dJL0(r38EX%Zb`pbbWtLX9Ti5f0 z_=j%s*0_9Yx-OMkak`Z0vE5nc9k`eF-NAxT$u(e9`1CcR*EMR|uzyV@`K_C|yiijb z_}H2O@kq1FY}4Y_^dw$#AyhMvQS!pN2DL?F=^Y3`>VJEG`g=U4@^!bnGru^ufY!7{ zilRAK!|H5#tx&ezs_JB`>eElQ5l~m#YOgB7edG|;>PmQ+_Ir$!ZoT^ z1J7qE0Th;sE`i^rFi63dn5lYfE10Os%8Hc@US1qLdvNn_A0n}H^Y`UP=T79QEPt-V>-+vdSbfycRBR6Mz~&(1+V|O|RJRMPk_;-<$=L1i(Z&>1qy(QIg}Tw)*|Ri^?t>cD5=Tx!QY|NwU4d!Nl78i zB7qlTA=&qVymT3$YMZAnP6qRz1ufh!O-0 zymapfW4w2o4E$*X_#1s zdia6pJR5{d(^kWN9~gA#=ij@KoHZQWL>3oJ$a7`vEKb|Mq&A6|Cy-5>fcJREh+~f? zcKDx!wSYc&jw69OQX}p01Fbtf9a)m z&gxd}_E7CWsv23_Dd0M3bXCZX?We;C_w}z)d#foEHmgVz8*OuHg>2Er1oR4ySDw+mTfVR)ZRwAW7K(o zR=3MzhJR~{Ouk;Go+MTT@w&aSlRA>vd9%14<(pQkb@wcmzo1e~cXBa|HlMTA`|&91 zZQd+y>OBANJ-zkH-2AdcZZ7ZxRvz=3>FLT_k*d(j&u@PA`A>l8-o6$oz?pI54M-Y; zG{{s8W7WhG@NxK+|IUE8cOtv98x;fvjC)%lP#~>R;lxL#9BAZ5=nVQv+MY08ZL|Fd zs5K_`tVmMeZ^#H1xoo+hXt|&khGx$Ol~|Q4?|1Zk_F$kG3|7k7j?ZV~9uUAHv(h67 z=4QPFIqHRxVmTSp_PV_doi<^y+1{IDpK5!VLkM>vU98>htu3gT#UUn% zSWJnB?H#O49mN%b2SZ@UD4RpA)_APEORnfE!MEwb|WrTD-i= zxTQhCGE~$vbB6vu5v&JM?EqP#L;AVQQ~}?~q7*HvFucC_tvvMK-z!$Pw>JuMk_8>@ zpk8#X3cGl_-dTsM3BGE%LWT~I;e)LPpaeC>qc=|Hf_|mM#h1!E8xR~QAED(e&PU={ zX+KF`;txxwYA;KBV(T@$&xD$DEfkQ*{lol}k@1SeBs2+kM>jYcPtX zt;XY;rs49^0-A%tOBL--ts_jLCA`wCNV@k z9)Md!1W%c%RlD?4ZDv|>?W`@k&6ea_H@+^$BQUJme&+-Zhw*Z8NH+;&B5Y3EQH4lD zWfchBlSE%JvPtXFYLYu#&@KBd6z7^U>QjJWPhqv+rib{ z==Qv!!AA{hag-PVL2{bqSEK#XX?mq#NFGzL!Xxz#co z+mky<6itVZaXIid)hFPGWTdr8SO2J)z%xT}TO__@p) z{M){ik&`ZjakRwgv_F8agL{a{R9b`aj|Z>!$_S_Yu(SSF*N-8oN z%zH#{zPB)x6ah;AB;+(iwYe?$3p`)hm0QqtZ7gdIM@nD}Ru19X6wJdffx;S<){HZX z`dqE1a8+sT8Qz18=-0`Xi$=AKNqWd?RiX5ZmyTnUX~0kQu*nuVW%raQund$X;XY9~vylK9izhS*eRix`L3q_} zG`^%~^|XjUSK&AO95VmJ%5E#o(JB@n*SKyLCoZmt_i#-9w_g9jdSl(U14`gB!rBeT zBVRShRSuYGtTaR?gx$h!_F>0E?ln6qBVSzLqlj0`4n)Ushvu%)ZxCC;aVgHY|LrBL zh$%vj-(EfR`%UZ!33bn<|8X<9*$kz)SPzh6@&ts2!nE_?CtF_!sYz3b(2G{5CV<&7 zpkDB2lk6aUxC=QL{C8W?r-0U8=WFV2-U$$H;@#7{xy*EAX+fS3cDQ%4aJ@$kE0MU9hZOj=TXWtG9+phQ#C!|B(fewUa;%mq&cu zbZ`up>4n?k%fXML_ltFsl2*9X)gfa#*@U-*qbQM-M4fp-Tu3qHqf>Yj(|iU>_Ng41 zeYt0~8WG-0`9uk=CJ97a@DIgpdPS{5>4|$-6W$A%G`}bF zH-Gtv_lvvY<-b?_rwCaXkyIW64e#bvsNK0Ua!+`l3J!2Vf)*+Vl+&__6ZJn(yi9Gq z=8S}AaFH*~NxDZj?jhRPgYo&b8ga{6f`X`X28d;CSOgMMh-8Pn8y#hE3?5$n6TlOU zTcWl8-K>`*fq-n2z}gMFlSg}k{tNK~CgXjvMR*lFMFn6OWx8{K=*>tk%0GR?bC^!y z`rlP<{XYS$R`}`T$Fur^`P6!`dxPnuc(O2uN|ggyP6cGv@uSH(D0qD{M#6|`m8ncGUZo?(I{+={<6m6Fx=t93Ll|I9wz6#vblC#z>e7}yv* zq-Jr_@uEwVJQ>wUgZSKe_$QdYD$eWC#WuR?*lWUD2jv$3R!_TESj+0X2Xd$Cw^Lf5 zbpyHuIa^f1R?V&iiksb-&fUAWadeE!WF)ip)zQTxP;%g<>WF-B3_E@ggJaZASA<+X z`_s!D&W@)5TxKrL6BC~J3X<)7z+{~bKe(1rg-w+w1j`!`q6HtVs4;Y|m+*B$ICgwa98^Ko|6!bWeo~RgI>v%MlhI z;9jXP8-cEqpk42HkDcO$Co5JrcOnmwz&m_Cc}Q|1LGZ%msAGLgJcQURLe9MY!=@GK z*{Ee++5LK_ZI!`>mdJq`Hl!g4fXlkvFm`)N=-{o#v7%hr1qf%oh(zflZ_9!z3Pc6L zyA71j6l+1TjWWMQYiCamHex~Z z&0<2g=2Mypw%co_zGm*9zX3*iWYSJ~Pu|Jm@kCslmk z?>DN1va#w6=~4?L5Q1R;Hl8o*7ouMtkNOmnS|f?ZvuE0>UcbnYU>fA8uz}_mqFN?M z&B~-_&^r4DnEq%W1Oc$h&;my(q@Txt7*lE!NML__RSeg=yCD&opf3bgjm2(2ScQ5~ z{r#R+)XBQxMObD+w0jxz?PhzYf_Bs}3gLy>s899kttLcIJkld3yw!A9=oc+WW(t&b zyBJvVF8vIle~X~$R1Obw7q)y_Pa9fLg?qgx>!fbe+-66W_$H#qjh!iuzak0j8#pvi zLAinqUa65vOqJz^sFXumGJE@KeU&Sd8~wrg@o57N+8{PsPZlU3(@yZ)-mEUoHcKYP zrej!eOzbO#4^_j9s^c*xxK2Wa>>MZ*P#tFon2O8)1c~CMj^a9oU-Cbe>w$+P(S*7x6Y5>+y1VSAWgHp2 z&s`S7)AL0;G@i%%$)!$+Kblc0b77%#;;wKHR>FegYqfKxeyj@%ue?t)=zGP8J|SS1inbVIp6&fhy)Ig*Y;L@1Z<;QtVD1FcIbx+P#=Q4VJ^0P10o)zI44D+UOdIbJ zC!Lt*Z^B8h`;jwM)EwAZl(T2z(W|bs&L(xoFYT5uCAFHq;}^miegC*h7I^U43kn>V z=T^1+)3juUdT96Avy8Inm2g37kz3L;!To#2GoJAX44nI9)*~IA$dRF?6#(oSQ{+g7kyA zc_^FF^dQ5nKoH(3*$Ih`#X`b_+3Nhst#11j>y{8vfqG(i>Tk(6>bJq(9FQNQMKzCH zU~BPNE4kz6hu0_|N?30DrL_YtKJ#YA#b+GG1scTy)ob57y|~OYOxG^)bFI=hd25Zh z=?yuiZZmLO{S08A<(auSom`wV0lo2^F3`SB8tk@WIu5N1*LS`i*cYL=m?~X+pBloYWA1Rdi*WiE?KCp;r`CMvPjh@AID6x1JaBlq zKYxf{IX^eR*&5HgV$|f?uERQ3%?&^#c~s-`FEsyfyX$n_v>TI1*hrULIMj$twiRZQBIDfX*0mn+5Ah2LKNDy04lmv-IA+e);5Te|Xz(52$ zz6gk{4G_mptPS&f&N=`8`&N^)yPDZ`zNBZ0RrS_;fB%PIO&Q_6u3peko-t~G9$}L;fxA-g5z0i zn1t&%{xWw7HUwP&K}{?_5gm?tYxA}dITNU-3n=@C)@Uj`*f3@xzO!R=%UMV;R(ko)`s(J|xNv1u zjmGJT@+f1$`7ykj z>vd7W!&Fi^;b#$?Qy9P)6Y4dFH|($i?x$Q0XfW2-R3}9frRBE7d7Cwg=Mre8pX~N< zpIi_`&kOrEew3pcW=7wnM$;3P#$}-2c@bI{?)c*36PbC>(bVZjqTX22i& zDK}o@->^pk!A$VQtzBkbO%A0&x`cv|L0kaR^w_L+0y<3h5hHL-&OEz!Mx7!dK&@6> z#?o(9s1Qi2w|5$fjRmD>bIqB1!3JT(-Q81+-EMaGxQE@zlQlM^E@_h|FCEfYC>2Bw z87i2pwcKw$ZY?@*GM0+`)BtlrOcT4>v0Sg?0zjK4a9g0{_WJ!yjXPMawUm2dvx0fi zx2)-1O8*kT@ivYH@~pT@ZBVD}hj)-esIuzr9Al%V^gr4gpIpy(-GtN~D@!RO|GD#W& zv2`CZCM}^?`$aa6(M9PfQQ1ZsGi;#!j>`ZjP&`J_Y-ow^lLKr+(zGwyr@n;v=CwLo zl&aiyocoT_O)@oe>BKGxb(=BJyTvtH-gToZj_wvx6?WCMQswWpx?*1HbQKmsDo1(k z6^C`bzhl9X_)*;|^#~RW=4uCxR91&!04#oUxO?`8wt0YQsfl^kl@Mg-o0b?ovUvb}s>#UdqKorL zc`xTCQ*ULu$->{$h-%m569jmi1UEfxlnDo2G&yp04Bl5{x?vMyK@mQ`hm^Kq0 z!?unK9xfcG4x%f1=_tAfSQR;;v}C(u0R(t`Bq`jB90jGMY*|_Dk`sjCktTuhVmVi5 zAq-g25T90cVNPphzTYl>x-r4YWfdO9C@Y%=u4Hi!E|yK(%;B8=Hfh&n-^^1PXMN)> zA-7!faA%t`w>G@pYPJ_!N;bl_L+u|f;)N5S>+<5V^nfLxaw%w?1|k#dpoiY$6g+uC ziBKxQ=SBDeOjnDxx=(t_fC~3bNdQ}adru0=ZI>ZNe9MvAf|~Dh1tqqNeE_kCH2-jZ zkt236J#NUcB~S2tFkfUW(TN7Si@~PNi4VkJbNuD#;0k}jERh*2cZ7flv{-e4nvCb$EbAws^ioxGjIMHkV%}iX8dP!rt zuv{R;UR*8fljY^2OQwC*S@sHG=+V>Z9r$`cl;xVwQhqNlpvSd~h0;AqVcQW2( zhQ=Eds2S7mdL>5vV%oxJh zlT_vVJ+%bLIm$liZ}Rs)V<|G&s_=+4%1V=+lrFKjJ(xDxwcHS%ERc zM85?mT>M-8R)?rB^2DW+#~uTi)APGyv($*(NEHc{S| z0~t?M&1;NzTIKE63(BmWwvUE^bG}X6bToEz)i5?u!7pVeh4i>;mxo69`i)?$%2qeu|=Dj|rr>iv?L~Y`i%EnHdo#l8jTEL5~ z&w$3cl{EF)^BmQ03@v<|QaT`ERB9<+p+<0S(lSwf9E#z{<;6+2RvKTLGr> zzU6!xB+I~WX9Id)BvjefBw&9Rv8?mch4Ss4`*w$V*6YoCi(gqF|BAYGmcZVsBgEp( zw%0e-o@enI)@gt-En1Ml^H<~2h8@9_2OPl@^*9UdZ$hs@5 zpj5U#R|X5v9ap8EP3Mx@LIa&$Xz88gYuOG{TE2>xj4jZm0Z1*cnZ4t`Ipi!+R$DcI zX6Q2^6+mSb{{=xf|KL5|VfYV@sj7nuUq-mva8e=8*y-x~uT-ig9!aolzA#m7fPMSv zOK*P{aO1OC`A66zBN5+8SJ8W%IsL>dR)n!h4>ih%V_u2w$__6TkEE3fI7YFXUen6a&9uIuQbrhG#5j<+ev2hs6CbHz)wU z!9Oiv$o2NpX2Cw?R_c%)`IrKV2nm^-E8`pa>mD(II#zrECd?b1ja4LBJgnxavY7PK zR@Dcaa)lC_a1b)1CNR^Gs`qV+=9-i~n+n5ww=au^^>0~Q#TI*wH8eq!n*Mr!eh z#Mc+_`T96uz4GQw7=4DVMvi$PnQ$pp)jJbZ9a_bsV9zz2c+!SxE9qcpws4wh(K}wd zFhU>;PR|0g9CF|iy4b+qiqqwuhvq5mj@>4$4*_tDhvx54x6s0p$5z1*3Dh_}G)ObM z(tySW^IDK=WA}!sGSqfRj}(H6GD$rZK3Rg9B%&ldnxV``gHdtiMVwWkZA4Eg)%(IS zL9?|?b}|^rQ<4|Nv{6f9C#79bx%Mmw-}sh=c{*){6Tf7XThd}k-RZ-F5fLZxtw2~0 z7~f&SB~r)*&_-j(dOEwIj-u3XNFOY2mV7(8F+0s29E_%~U+X9pJ<`&NZCJLUPy)K1 z3E^8`p>rkTIPH3XoRsWP02~FCS>j-zM-;;h&>{C9>_ejRP=&@W!lHDpqw>ww+pDWiWm2V0B(_ZwS-lSt?Y)d?09p3`iI7k7ifBh z8)Rm^T~O@GlcdqeDM>GTR9XF*Ks(ywB6e_0iS5|Pkbe=}3jx`#l7fDQcX6K#z8mvD zA359I%KUD? za&n^z9|E}-I$@3VuF->8<=Um9TpB!#rz@lQoBao@HTNkgJ>7D zETm7r1j4vK+FV=F#Zml?kS7{#5Y!M<=H}m)Lx%PW2hi~w<_#SHhDrH??*^R z1;E#k=2N7$%nQ+9O`ioVJ{mOAI!pc2TBoW3j}nuqWvwqPyk8w~#1*xxg-`O1}?&@M|!#aSA`O5`UA_N&|KC;Tzj4XBkO z^6dDdt&!|C#X}UIqJ`La6GN0DORh!o{G3q(L4_##V9gER_HjQd20?vYplVPWTWcBe z`!4vi7_**=eQO@jI8lwC=5~RS%KOqZATS10oKns)55}0yam6}2RY4;AAPXvc=uB>! zY!$Rr9w{@e5lW0-Yz4|o4XdW*!r%oW1jXVQxkLjpYhWxclh7-jVctOVvgVTuJ($V{ ztjf$!u}rw8!THu~U^E5AIh?MN67|Wy;&fx7+kpIJGgNH+UJGiRn zWW+R&AC4Gao+SLMjtD*bc&K0z)}luP0BI%JdVoH%lhPoPD&wYDIEd(=r5ym=>wX(q z8Em3Bo(M2>-85XFhe_pBl5=mqrD?h;otNNBca|}ziPX2xd@q^=jMpL)wi1d>5e*lL z?eFtsO$GK1DtTn~vSG8FIoGjlFfE_+#7bB=L&7;W>ap(Qi6_$`m$3Qj7SfJR2#I@EkL{{_vU{jnP(-EH7-rpR%>~&DNZF=_Y{;yMCVBS${UtA} z#12i4HI??hEW`2UX@4Y2%vqF{f=k8z9(MKhS4Frd=S3zhW3rLWlITWlgh=${T7LeR zLhJZ)4J+5KjwJ>-x(i~$JmhBRg|S-U$sAQtI?t3sFWpRJRXvZYN{~W8k!YJJejZJ7 z&SsRufMI08C=Y$MG|2G$ppmO3Cy0|6IE~01Wcn-yDQ&bW>P`V1m2M{QJt4@&XH#B1 zNG++V(tISPNEyLTKQwpl=}UngPnvwJq%5{kt6|P$ju4$|V&+vt2bAoFL;il@+{`Jq zqbu*>yRtXNm`T#sMyJ}_3n9&igGYuWd}a--&$M^ihWc5aEc{?gpC6;=P8FXefSgN( z;7?-^VGBzX_i2hy9RRy#61{ZL#KZ2p zfP@oU;Nsli(S+BYQdgc}wst$0&beUZk2I$p$Y><}`Sz%VnT=RY%)Qv}hT94TCV^R$D)!x+j zeungVQbD*X10}sw!*&Tg5R>IJ#uZnq>rynBRRPTf`{$vDnqnuyiec3PrJ=)U;}*8gSSrA1@l55Xk%eQaFi~70C;LR zah)eTPaR2Hio65yXVqZeT!G?i8VsF<)!X*t`a)}A@jmjDV@j>~Cmj`h<%x@gG$vRP z{NX8wXzd>BjCrKGd-gr5UVZS9f#%k@f{@0P4bRppjM)DpX?CiY=F`aasdEjGis7zO zS)P8Vy!iCPmn=Z{f%&s%L0nBs=%y%sNyK2MzkSMsu;Km#AL>O^U5mwQ_wvOQ@MTmH z5DZvcFRPWrRXrqZdI(yJ@kcIzP$*#q>;rm$S32(qV-`Bhdbaab1Q^g~iZdBp(RDfw6Z01qi;2BvZ4d!&eoSKIm+}ql5#2gFesT za-InKNf0w8o$A+QdaaRk@e&{>vTth#KnZSvmlu`H$UJI72$vE~m+JB9^M_b&#d3YiHn}#NVYX7Z$6AlW~|gw&8A?7*pW4k7jMv9(6>yz=r%{QoUYNe);PK zRuT+e(ime~m6Z~%=wp_QX;pi_F#~Q))7bCRvfc~Py;ehRA!c%tX`d=I-{EYn>@02& zqL%2Y3@M`mbnFA6H31ul8J0Vb3FSdmU@Kc>YNpt(c(PE51=@~bz6qFBt53HLe!vzI z7_#EHh#D$N`kRN0HBC7fsS*O>wLpcy5k09nhn`B45?}eDva;AZz}W<&8oMBnJ_k~b z?TygJiCjy$xmA+AU6DQjN4A0oN9d_R--2k!Y2@T|@z@M=vO9EXb<{@pyeG8tot0ABZp~5L>4nPv*P8d>B z%CpW-mtjKWUFR;V6pzq2HE-N~ov3cHufpBLgR8X*A-#dPm`=i#DNC6b{wiKo-JCBK}#fbo0eHLB{UYiteeFZJVBu&dD!O6x@10}UXzV%T{ zv^>0JI$nj5uDLN(z?@RDtubLWE(o)h>L*~h04C8g1sfaTwK#x>tNX&~g1Z?|Y#;UT z7D$$2agCPRXx(4dsQ`pFcpw=F)qED?KJIdV`^q?76*A^@wL~+X#0}Wb9URd0*(=j7 z=IJ#_+MLL?2FAVqfGV_o$3yJQvO>}best}rNICW40`$Q>x?0ch;-+Fjx?|e&!EA{1NG8Q1wg#*&wpSaQP3%wb zQC(2!ItWy^x=}BF#iVGfkMlseF`NMav|t>_JFw;wU6cEW?ggR?u8o*u15IKM4-Ql> zldxDf^Xzk1gT6EIh-t*_ki4$J^YNB!zK z85bStW+d9AybcEorB6B5W0jXugCCFry5{pjshlb&ifdrwf=fMggSyLFpHGvHjcJqi zFNr@Y7Nx0&!3~(L)JYrCsqy1Uisi+0b-X)yyqlOOY?P*Uo~mw`;22xPpa+tM{j@3% zq1o)rQ`nLWKVr_d0`sn1!?YI+Pqg>K-hiD3Uk;rBLj+nV@yQmKHOcsr%Fcc$z>QN zrJcWIj}w@B3jAtMl}7@*yeDCylv>Ly19EIR5loN|nT8Js&XTO5WZ>xZ*PSBLahxnk zee-F|%2=j3eFHX2LnVow$M0-&Q^$31S;gB9cQhl`_HB_d>Xg@zHWB#HT*q!ZEc(c6 z4Tg^jkfTCjD zt_D9w-{off5uU0hEo!DGfGo?;L`~hnq%-7mQZ2cYa7oB~b z_+aXP0V3F)`B+P7Tq?a38A8?EoA3t%E2shc&KTHbO`1;C@2y!D-_vs@rXVxBeELJk zbEZ1!wglS9&prLnWl~&!{<}c_d5(YtyV5N?-Da=KSbQ#L3Bmv@)e*5Qm2ZRDeuNS8 z{u!njl5|yq5l#@JjacQDEBHtYbRy!hr2DSV>Aw3^PyGWkqY*d6ggM$fRTa2n66>~3 zzYDkMMev`1IGxuRP?eqFv85-1^8Ne}V~pNU;)r6>+68md_dE$Ixjs0S1wO)r_fX;0zMy*~P_uM>Q@+;U$~p(UUzm2yp?% z3zJ8QCwGP&NtFJ~lF=}Lynz4e`VSSprZVmoC?{brmP_y@4i=NUrC4=c-Bkj>_c zA9&{>nTepERtQ^DwH5MV3I;PESLn{_%FLocF1H~%s%TiJ-D=-2jMqo$SxqdmR*mxa z95Ta?R;5Q6kLZBT5=@*xfjMcJtVo%sf%C9SgDXa}9f~$!8wk-L0gHaCF*T}(`;05k z7(c+7e*35LTLCk~Vl#vX9u}_TAq~v}duYpz!v~9$%pUePbAqH`MF@YmJ=2|8-2XmV znDvBg4D5|vsYhBe?U<0IRp3d!6^2LwYt`lY=s)=I>~|~!#yT3N8}5{_+cNIDLZ)>k zOWlmty+swHf(Ll}HhCtHA1QCsSt-`vT-s!$#Yj1P$Ei;ggA6D~{#+lkh`JjLE;ciG z5p-`CG&0#9AW)Bp7>GTILK(0vO!8FGL)i-+!cMy?)B+Tc?<};yddX`KZ!?^6teQEa ztvT&hb*s#j0mrxi1Oz_Ro6G;eT`TV_Zxju(hWe+tbfL2eq7=lvI4Fi4=Jpd zlvJ6;NXb7_L&w(uoM5AcR%T|ZhP~ho#!ETSu{$Feb{+*Dgh$igUQ1z4h_|&b-3_ET-Y?wd;JW1W{=zPzv!bWVttuD433}DmPBR zi^O>$QYm_YVj%6${NReBy}EW2G5nKa`ntLF&^tM4{7Q9GIpbDuCgH5^0YZ5dq5#qD z@iFXzYzaogruoM?FyQ!PqKVD@Z*7=yR&HD5vDu8t4RvTlCS`(vn3`zmW>;AlsmxUY z!m5I;*9&53%?ZLR5qCGN^(sFt7}U{Ls^!BzbAlS4nYm&t*5*F5!u+!6H}(25v48b= zOI0p(qDH^WNA^ns4Rng15&y!JPMNc%dNtHlV8wLVHXwmCVqh@`J2DKgh{FVsbbJ7s zL82PBuZGT~P8ias+OFK*it|V`$+lR`<*lHL^5|s0St5Zbn@3dgPG@k0v!q)aSYjo; z83>aj&%&duPPITz5%NGk$m6G-Z9FM3q<%ZRdN*SVPxVWLEzttRxBz4CFLRyfq$OrvsF_u6944Ug=Zs_b7$V-A zT40dThUzaXxsS0aB{S2z#EctT02oDfY<(4>YNk%2{9dP-Pfddf_4Ylrz3QsWsJ4Pw z7jPau|JRTp047blEWB=Llc)3w`+|DOw28;KdM!wnux%7q<>tW}Vk(*0 z5;)jirV0xzwv!vzW@+JonXNMFxPzAn_6ty_*%k#VcRM*qS6Q zU1&Hh%s`GWt_BptY01Qq+5z>kpmAAV>Z{H+v+)!Ch0*rzu6n-LSILtI!#KeT{KErr z;4@+!T(Q#HHrJMuZfSWBjTnY8U{-J-zaUpC;)2m}TZzJR<E2aNgH*~ldw z--eX}s|49!OPX|4UkXoSLybl`qqX|g7!0QE1&gPP7!3!LygE-zASH4bW!p0=RO!fZ zACFF$c(*3~jY}p$RxzgD1lepjzd&}Onwbz_?yuknq+%)k8Vq&#{`*rH_9o7oIkRl=CnY>#vppV|^ z6W@TgkHMEt$UVtfS+8Pvb3PgqgUDuP0;HwSc@h`zVb9*s=kV0T`-YTPnonbkn7S%at> z^Xs?n6tU*=X3=WT6jhKjrRmzcM7KGI7>htjvNvYu@6j11P1Bbos#1@h0Mm1cFfmj; ziO`(vPy@Hn*R^`KQg161CMP;&*(0JyzO%#Rc5!ettO|fz7G~;_=BA`C(!cz6xD`*s zaEuR%n8AvkJRAw35p=*cYjh54%0(L=7Zu~E@Gz3|s{}iV1WlDLTn_GGory(GkgxS! z!1P9wS-=nFN&>t()%Sbh86c7kJK60aw};aKM${j0!Un;lo?IzWcBnd2{9t-Mx#_d}0OewkGjBfq_+@2^UwXZGI#FJ9&)m1Osc0eLGD2FTkj0@5 za+fr^GaJJDvTRj#hvNGzkszn;KK)eW?iz6z;rvV$tCFWJK5Gf>7jww9Vm7^yr&V#v zuD|-8G$tEBiCSIkOi{vTn%9hjJoW=a%Taj|`v2SggX8^)1^#)P3L}!aXPP9z#4~pk zhQ!{NsMtBB(g>?!4C9*jPBp-jmNqeM)6S&{t6E|eu1ZiI1%iaQsz^xOHysHUCzHDh zk|1W!-8kr-JG1h|r0p9|0rj@}5se=WY^=f}V`nN<3!*6d1!EhMHdLJhYWQ8WsZ=S& zH#z5XB#+e2$rn;BU6~M8X2l*97dTNVrUt^6?V|GH+w}Lhi5b^gmEYmFHAGL;mcLyz z(cU|l+3j7_RDL=5uq34?7m!=BCjkX0fD~IAs-pFX^}0O+*e>f{0S?vCHovJ2VF1kZ zis{Qi#I-Ygy<7Tp>GVfWcBU_6qT}40&lhuZJ{?YI)WQ%qMiM}{gLXa@r;)`+N;Eemyz{~`Q~tTFXaWXNGs;v~ zEcPkRA$E1vR29!8XN0zH-)lnIPxQk1#r0GJI1#5Px4vH}E*1nZJ9|im6pNw=-V(J2 zY8Y-+B%Y|_t%cjr5dG&3(gWH{--Yl2wF|n9X;s_0j$yn#DUU%D;s@s8ou&Lyjz~k^ zq+=ZhyDNJDIOMx?Jn?TZzC}pS`l7T2OBeXw9bxN0`9keB>2d_eFl*=K6z>k*EvCwQT%uygrHnW0%sA4IQ;UvEcz1LG&@_=@2 zG|`RExGckm&^PE36*!BJY?L-}GdP8W@fy>MYMqy{R7#uFuvmoojQ{I|UQL^l&8l-3l zdU!fpaZ)h+9QIB2IWc>sy#@6Uc;gA!g<%}jDBbDq@9v#t;MwkCeYcI-X+G$~-cU3F z_$B1o)G!D46V-dTsp>9qr-~e3$5NrL#N*<^-kv07@rxZeO6O)OzTlLOX=mUhP!~)m zm*9OejWH`2R@{+V#D>0wXDGb zX*Xk)fV@7CkkD`rahFkE*-%mu;)91rKopp6bQ0XZy(n!fH#(Sd8CDYp$r$NE037=+ zSSpk{MiXjKfCr+GNsH~Rw1Yh(77x<0hx;p$Hg0xgSIp!DkQyM0`erO?Za;2yhdu3Q zdGsI_t}Si?OdA#K)CX3`0PHYyk`*Vb*zkcxhlS)| zSb+G+Y`Fs3IwtX%BOMz1b*uA&gr5puK57_pCqPH|C^e&X_-+fsCTL7r>A^Jf$Ro!ui87cjUwEphUcOU?Bf0wyd<uPjZi5PMdztTBI}vtlZa+g)h_bdwmKbnTqQ5f?JX@B>^{8QExJ z`l&@zpebvqLG6Jd12*5{hLC!akY=SduZibg=1$%DuOW@{?%dnd3L1g4!b3jk=VD4z`KsUpQRayZxw{7HCKRts&GIzyQ$upg#5YRS*swS5et3ZvEZ_x$B zqDq$rkrt-Q1Fork%pJfd=3{Jb)BR4OA{p4Zp}FPA()6D{%oZ&OvqVQaa{?X@x5|u@ zKl{fl;b0DF0;_jDSKMA-)Fo^%AhJ_FQD?{@SWF#Zs!6SJZ_g8YnJt3DV|QgoOf$_i z4j(h`A2ARb5nGxQPV)1d?fQA??vTO6W9NjOg{YmV;t<}8WH&T7bB}PhVbAYCQxMD{ zmf;9eKfdPR5rG&&2uvT`LQ8X=9J}-r7%h+4yNfe=8EnI2<2?5FOb^lDtKXmnZQ9HW0x}0SSQkX{>6Dxc9youCAYVP1+ zMywZC5bL5|nDNbI+0oLqcLfO}bAY^EOeGT+RCjUXL#3okX|k1%$gh>LB82z-;*S+o zF<{N%JIbD~fX$d@6FJR#Ybr#8H+Hx!89?ejS7gD{8YJiDiSB-p;W_!Qw1CkVM{w;_ z<5{tJw5_IU><6qW^^dXD0$1={lT1VNC+-MMLrqW2jf~KkSLz^5DtEp1z2T%Wj6`)D zPrq_vnp?E#25L~Tz)S!(FRw91P`YHE8~EDOmtHRxBL@JuF;-cCFhY!S+xVAjM!WDC zVs!E3a!JN#9RMQU8S#U(&fs$Sm?y^nlxx$!kNJ1^@jlCatW6Ij4##xJR6JWtmj&4} z$;R3u!d*6op7Cq15vpRAmY`6w~Wr!?JJ)nVbP8fi3 zM^1{Xiy(5;jf6LmauXq$uH9`xkrnpBJ%N32dU%Y*43G<$iS-Kq^k<9Dv|OW zAQ$PiO~Ad3el5Jpsv^gJMby8I;0y-?c4{Lrac_a7#?EHjv8AB%tt~(zuU&>6$-X<4 z?=JEU#${YyY%e!AT6Zh9>2n?0`fyYldMv=?>4oxv$T|l=+S$M1#;VGE$wYc=u({Cz zzxzm(C>EVbbpbG{j6i`MP4=dP@|W?JfMEc0gw>3rGP1}7@#uycElnC_8Q*a%r};c! zV>^0&u>qCC!6OC1rm6IDySaIf((`v0m`^NfJDL2oNrzA-9vaCI%R-4+4B|p3MVq>E za<2HKO63VDFUYT%y>j*1tJiOIx3;n2nzvf)y!g2bQ&&zd6VK+K(dC~j;v?UGUM3+T z!wgwW`hdtsyUf)jLBcLI_JrJ)+h8J^-**pMP0uW2T0qf2*bediH(G5$Nq39ZTg4hk z5*L9bK-~qo*myTG@rB(moXQs=;kbLY91NOBiHs;hqRf8KuE<-}t=9vyiY=B>s)ve+ zU|w;5r%Nh`h6l1x-Ctc?S=>PL8r1a7&OFRjAp#HxxaoyNsXW9{k3AmP&3>!lNC6`Sj_9=5nO6x@w|q611Bi zNJhADV9Se|hh-E{6Oy0o>lX6xB%yDvD;K|=yfYuGsHg1z708I(8TePT^9GRmiajesz#8OjewW7Cuaxh1_a1Fg&w$ zp=B`C8G$XiVg`ILknZ=TStyDtAHD83%^`$NFycv>;5<ab@Q~E!DiS+}wr>M5=~2VT1^mKm~@)gcd94Lf6dYGyVhz*by}WUis|C zFypXNh1=Lk*Dq+Cqo^2E+&6V~Ri4SQL&KzO1W1q<5U{%iwOK}94YzS8UlXX%(Kh6< zQ)hi<3%^RFZQi2-D@{tzSw|h`THBH#fntneuE20&MaL2n*(07=s&$uIGgDd8ZQkBy zBqDUF)YQasq-D~stnJI0(J7n%#d{<^upg_Zl@Yrzn&RG!VR^w{-R^404eU>+qTQxE zibP3^W)a*lHI#f=juX4e`lvGqx%F)dU@dMG%z>qB;GB?n88mKtqLhG{I@&_T)Eg^2 zZi@T#79ID{MHGkIGnTkJ1}DM*M&YRes)$4ab#6pG)CwYX3V(ElFpum+eOo9GM9l3j zp287_Zs`VA$d5j1+UY&i1Y~l1f|Wei6Kqm&RDWm`h6)`6rm7sKKoxlipl)jf^SE@n zXH{P&z6f(#?~e=|jOkmzLU*rmIDCM}(z}K;5Uvr1CCp5zxEg6J2RKXexxR$vzLeXl z2@sOTa8Grh6K;4LwE3Z2%OJNV)+Q?(Yq~&xa6$M0NXAl1hi+|*Nei}H8%%rjVwEa) zxjS${ZrIWG3^i7aPb?)$^Q3Wl#eL;b3rS}7WUnP8Gs8`=Fz-_7Te6abqX)(dahfM! z-8h^l0mS;%X<)5?M+K2J;QiL_fP;X_?j;$3?189nE;w<%(n6dnq<2_~+F2$7ZA)=T zfsySRI7toYD-8w8Wa5IsE(Xq*5KDuo8J=5Mjhe?Ely{WVZup%T+Vo&c_Z77fD7*iF zz>NhLD#(v>y)iX4<;sO;v5cKDpwHR^w@Hd5%9u9da$^CB!@EoKxAjd8ASOq*VMmj^ z2ftp~RY87ppzpyUor3Wz%ZlT?v`O9N^it1Y= zH!Ox4uBZ|xrP&dh^uQ^Mx&VE(Uk$-=ri??An)E?IgkjE3y*iVk^QEGJ<>sPg%7Sb? z^c-31o)A7258=c`0T=V1QIo-*>#TfE;!6#Vt_g+^jdtjrLo>Z z6stSsD!`&2L*@bV=YzhW`yOPt1J!R?yVq`*C<`s`{@O|oH=YE1sg}o;412o*2f^ny zhkKDr>{5IVN&6yMGaJI;ogm8D(2O-gS$=hqz40oWjyg#&F6xD4RxlGxrBDo0pApiz z42H@@u~1|d^h1{at(A@Dn>srnR#B3mLOGggYg%U78tyQn|7k`HqO4(Q=5RJ^70^5P zXJA1r=ao%++d#NHaT5b#3}o&<#F_HU0p@1bs(mWqUDOZ3#dHq zcW@Q}^H1r*U}c)taM6!ecQOiDOfjl5z>IcwEoA+Ce)L@B2AA#T3dzz!phAbU&J+X9 z1FBMhD^6^z=u6;Kb;UrHnOlR>)WJKY{Lwr8EzC16#hi15-}=EMEIdo}2VZlsTiI%1 zm0o=Mnaj`>z1p9xb@S`3}aQRMnx!hl7d@jCdQOcz*cI#spN}> zusTn1e66>sUwG6utTBMkI*y%SS0grl7kQ2J^>NihgzE2tpH{@eIP&}L2`P3E<&!LR zRXr;PB1BU^7x<|IpqgG0l$XajWFQB-d-{ozI{tM4)T|j}6B^>^ zK%}|f0wAS^$7o~ijA(%rit11&Tt8WEMh3K*z*u-bC#blPVWGBPKtvcJIy9qqu7l(F zrA=aFu&zhNl?=-kj(~fTjY`o-XRtXxzix0URTw(twax6IP!Xpplr?Zu%QwCXA?c1S zk>)r@79Kd=naM?9>{LC1;MZtIQN#`312E+pNN=<-md8H&R%ZHT4gRv^u?a6fEk2nc zoTnePkEk4cV9wr)v;-7VeXgQ74^U0z>BoU99`#4%(;p@8VicvEGJrb*URSYmRUHV~G7@3W*@y#d+d-VNBeC;#&MH2O4l~!|6Hu$hDEl zYwR)!1L{)U^}Kvt82bT{vur79VDwltay(tT_$pMg z;~{-RX2#*p4&#EjPnOjaCDnNF-e%Gi#3jr zmiEFro6i?ft|}1NTgz+l$p^NDFKq-CA5!HS%Pay9PRUaE6l(TfN3AtSxj#p;T_Vdqfpl z>&v$*wjhb&*Jru$+egzkW@#7tgklq)URY)3#)}tEPt{VzXJ@9^Tq&fP>*oM(kjgo= zwxO+f4X;I!p_)}pD%xSUKM<@Gx`tE@uVs{9l>p#C#t^{3!;UfOsfMg|aJ|-8en{kD zfb)rnh``XNkOY>3eONlx%rG#VsVCxw6FTL@^5Uys1@QW&V>4u?`q zH&KN;lAl?Yh}G#{`&dSXJMn?zBNN8(Tq=%l*#?fxDn`3~2sMt1knX%z(CqV(GJnjG zWy+M`#R#YxaG!{y1!<=gjzGweU`QVbptyD05K;!?#`+@iG4pEw22cnQ^>MP|YtDee z7J85>2fixua2UWLA}09H6Xlur8_HhG3!u(f!(w*v0>k{0_;tJ+r&4RDWz0ZUOGJ3^ z5^xPai48h99NgPIc(iT=ZY?Bp6O@tJU$s_R7#8m`+C3!m-tlwB#BA!@NQqp~?H2WL zZ46r@H`j5RI4d};^8&nxcmT7bRo*93u&9SuPmQ)RzJ-`ws zU65So$DohzW2#g>v}RPKSvh=iT+9AejhC1h^*72&!)Av9fIT`izwxSdPzh>CglKH_Q%hpP{?D=iC)VGA6UYWjf zb&G7-{ee}!Mv<82eikMzm(EBcw$$HELv;7(xPb;{s)WOd*C1|t&=k+6GplVWOIG;< zcD`@i!|%jyDie|>$W+J{-Mg`cn@i88FcpNdDnq|CoK<@juAFMQTz_?}mdkz7h)x}d zv{)g5$y!WP!xd&b!!)G9`iK*LyDZI!jyj4uddM&@&ZK{p*QlpJbCO8VDdDvkkhyVU zGGs=j6=&YS1;KUQMh5HwzGn=jj({)#(Y*~S=P5&PI%TvNtF~fsVZY$mNSZqBN-Wi#xi^#9NxUpOCmk^<{MfR}HSn1IqCMP-+kMLGR}aXH24w#^n%K zy<{LEW^;|#s9A5BY(7S25$u%5g>eW#xQkpUye3GD@v{Su>#J~C+K9Aw95S3QstPIS z(|V;NtO{C&Vs$hMBK;iv!rq&9c<7b6SPCibkGRe+ZNkbWuFg?;>;z=DoVgq9BW9#g zzg1xti`jLv8QBevR0-=dz~YS=q8L}MT(2dyquC?%Ka??w;HNPnYu42x67k_w2@|rtso_V% zWyN|=(L92Hc+CbYb`S@reKm5fZm}5mhtPW!=8ef2+lN#F_zYH!Hk!C+x{n;;&$rjG z0q;kVdf^-`Oc3zQ4+?gW(i6Vx%U))L`8U-$nLX!F2=hGN<|BT2PN2+wnJ81el!^CW zSNjb5!s8KzR!(&Tv%{q$EgoOWjPmFQ2_MX2I^X1MD_{I&*`E7?ycvM-$W6s@!nGN= zWn%=)4(@_r#Ic3`w1TY{1USYi(<=afGXOWRrWbQI!xb^KLgTcqVvVFF3s%XGRy;3n zst;l4Pwwvl6Ki#hu#Q=cf;5YdwS{6@{S`Be6Yy#fXPkP+X3VF0o z`RmS8qTG3XjhH~k6Ob?35Y`{Yu@N<^=GjUd0X@;&^jy3+6)CqHgX8`@KlMGcru}AC z+k7kLs)L*XsHCT^21NM6VDC!lRE;GbGwksv7N|-PA(miJjtV6M+AuD$9s8gk6M%2Q zKxH}SRq_`ChnDoLeWo%iYzjHCs4jDaZw9E3`WlhEupHrpF-tu1t{przfe#8GXo zL!J{V>r1UTx9%RX#?D(@(Ea8;NOrX!$sE16N#{8vAw#v z4oqX4>f}81;iT+pEXytc1tN{QZew80G}qYn*$jFf9V6~l$2)&ik)I>u!anz#;gx!< z#w|5SQlgi_BLNr_7nRXf$-eq3zd~QNYN7}@3sv)X>u!_(XQmoCf~h^(FFa*pHI`Vc z?eTagdD+kd6cgPYJmgaP%#kihPpv?gv*-#3Wq@z4+b(q4q>Yvrg+A0=(r;^bdW_Wu6C^-O2=Fw)?ykL^6pvat+JVOb;e#0j4xpR0vn4IoZ zd8O%;bG+uj*b>$)m765FUEiF4^)?V88#G>I_IjVI#Psl z(m{51s8wK85@?~s-k%7@vI-(;B8vy?SYh%a9tSKZCzRtRJJ}SqVuMObjR7bnx9bsG zjZHU^eSI&P$wbdQ?3vFDG}NmVsK(Am0HT7t9ijBvoh}4!Qt@()ZT=$kYPbq1%)s$Xx(BRL6;^k?+_eO_+w;U(6+rWNGbj` zcTMw0Mkdn%YeR?&PLi(?H%Os^V=9?|_iGqQ(kpP8rEiDfEcDe_NEto#X2NZ;Gj%l6 z(oS@#fD@QS6*E+~4wx8)SVJK5W69%rf+qc0_!J>~eK4QU{*IvvZ%&2A?G*e>wd=&G4LH!C7tzI)F~M~O0BID}Ox9pDG6XjPoS55b z?^rk64*|=-vl2F!@2&Cwc8BXfiqqzbw$<(R7^U5Z$|tjzAjXRPvdx! zw5&{8$vavpcM&*6+|;`mpW^LB`R&;x0-0)Q*Y>r5+{5l(t#}5)r>fp^g0o#4{)KI# z*w$7F1nP0EwJo98cup|;ysa}eq{1t}NEzQ0rj%7d%}PEvA{AH}j>_%pH6AA_sdm)R z_|F8RAG+J!#*nOD?!uMl??MwtzI^k>#5G)@x&&uqVflUyKfJ#?f=NmzC;H{{#q+z8 zQDPKDgF#9w2IzjG0`KyIL`80~B9ae+B<+D!xn$h)-GTT$G zG0~<5=9QX#CL^=FA+1mWah+Su_9CL&?KS_ZPl{d^nqgfgG9{7{>MU#d;N`mFjqMGh zxno5&7OZ9i!vT|Xj7UjIbnxgpqmtRZ#D|~%)hM1!gY_C6X&2~@PR~pZre{p{gWaS- z+=7{!<|<++H~~0{*(Liu`G43tfTOI$Amefq)htXa)MTQ5k@IQa!9P`i*dE}_90=^_ z(VhN5Gda~}o|$(G+0>@L2wUZ|O1pb;$(Wcq7&>iUsvh&wbH1OIhru?{^gM^{MdZSK|8>nXtkg^-smPjv27|mLX=FVxJRedV zT7@xf&}*(GQ;q53wyO2fgpe1_$bE&jZmz9(DeC&&;nH0@uY>)@4Y-YywQ-jw`0x;F z?F17d`7No*rJJP$7}mY;W)vV(Gdeb;=71nEsxcLjo`k}b9wWHe@!E{s6yS++zC1dc z4)gHnXfUaNAkfKT(X)#p)tCg*(M$7Up|wVH7P?oH0CO)DujJGPzt=Amr^0k}c=$($ z6j*f7wuaN%D6kXR?_h;sY9aIf^thpB zT%an?#LckC>aI|_edyH&u~p3RlG*Q%BB$!ORgss2K-#`4i`OK1!*%+gm~Rl=cD)+1 zf;9;Sl|O5uTvF>2vp$i27%92~>Pd-;!l)zw1araa(_%+EIur=d2WMTKRZ7!fIhyP- zs|h{$;QJ4Fc3c^aUZm`59l?phFfuh@ja^%9Ryz}8=vio-S;4orE)M(C7T9}mVOPn98X(V}+oBYko$WuiK$ zGrH)R_77qW+Bo%C)Xzf(a&D#abAsRjSK47id07+X2FW)J7iqtv)B(z;-?y}Ts~UPH zzCE+@V+K!86e@`0#L7IaxqxmwRHG~kR+K~0Kiq-2D|&z}#;dZ$pejC}YdseNsh~P7 z!@;do59M9HS^ic=GqIqsP7>$-I-Ce?9j(;SoWfEkx zqxc>=mbj+R!uKrwTE=|Jhzs~p5U7EVB5e6>^8TxvvWSyeY)T8|MfZz&gXxMdZ!We#Aju{+ z7!eqd9HBy~?nT?21r2M)Tfh(Q04>hKoJ93-Wxd#3VoqWls_NJXc?5Z95@0H2|BXBA ztD9?%?=k*GYPzg=&dHdMWU8r9&HTc>=36Kgu8pUf<4*G^1eplbVed?ZiMd!1tk+;_ zbKxrdJ{spFMurjpzDi~(+2}I3>PR5rTqa+S_F1eeaKCD=2qBIkf*>$*fH9qb4FFu+ zIL>o1>E~u=cS#Si5wpPE@Yn#E>V*>M2@@!3-CU5`=S-&bq;>IDO^ML~WzjnKs}f@b zn}<)7yQCXzoX`DuW5_WpY(dCPi4DTNw^-!4;?8<=?e1bL!W3hK%8t~+!UQwnMoRWX zx_Ba4?m|}Ii^QIsN#!g_U^`AFHctumL|9DAu_ENCSgGaCMB04A1RO1Ge-2Y{53rU~ z7P*1*Hj^i3u=6~2CiRapAUGDTk8ySvm)G$AEf6mw(pVqP{aiEx2tEp2KlnU&YGSW? zFr4taiYs_e$6rb{7u2R4mVpTM$i|!U{%nPydaONVkVm`-U40T7inWG9ww%iVve-~4 z#r6@@PwG%tRA1=7z|q{r-LNWi2ovIuV+Gj|Rsy~1MUd~y^%9L;a{-mc5-y%Yv-&tk z^A=urbSd8}+cL69*;L$4wWvy9=bW9pfqM8R9UI7SZ26kv))C z;qzG(wXzXZ%##BnL1EedMh4}XtDD25p>v*)%7{e)K@xKaSH#jF2_363z->Cg=B|95 znviC#RR|*_Av2QqHSd%d6$c|#F69`}ifWTzVB7%&2GXb!12pm@#eCxzU_@OgZw5;a zM5MID8W1eP@^pfXz$TxbAb<|UdQ>d3anMx<9N?s@Zp-S{os`?<9ixaJxn%o=2Rh*L zG7Rha+Nt}ddqm4|Ts+R7Hm;%Auv&&v`Fftn@8(ajU4@J?2wh*6nuk06RaU>TL>*41 zOJ<)Z+y;hOH)QJIJ8m@`uc5TJIMm*rg75ThvCZ+gV4CL>;M^i(zy5gQX4dlgYj-13 z@eFQTpeM8BBGB_E@ZtMMNK?2o!XxQWVy}{g)z7 zeGS}=9OkVZM~ZVmmLzLLcBUThdLBQqR?cw3*aOWufe#fFC zZbc^U5@Zgk81#$KD8RCqZXWcmOx@Z&GL=(x`~(j}4c%yOEXoJY%R)&KWW*5^*kJsI z6afi!YxqlpheNJU%f<+h7 zXaFgL654$PgF87gCy4}i;(+?r8FrMZvF-J zxUHpH*5zoQaw`Ew+XBp1+owc6b&WbQlaPpN0e3IYY72(*lSE+UE0_9!b_q^I;YhJ3 z!L4rFedIQ(wpV&kz$)aPIW=9Ascw)xLemG{J8CDSHA5vfxq`wsb1G*&vS0`?qX(ez zc%5!1J=)JI?7g+sj#^*w!&+-`;k|HaNYsqv;L=W`rCiTA3%`=WO; z1R%6IJu~vNGDVC0%(21P!)CzKR&`BE04%Pfkm=SX0F&uTnem%WeN_g6dS+2o5;vYr zp}RJbWda29YWULrTLzCtUU$Fez{ZC1gH-h?xU5_N=aI@l*#)rxlTtOStZr3?c_H~K zz%){XA0E$}Z#l9lk%f~}`y3ym4WtVhZ0}mb!2Cm6HDkR=u9Rjuf+`D>fcz*<>&_Ue*rW?opIRyL=S~+E&D+)2UZQR(cHE~ltvGEg+ zkEpPQWXt$s5Ua6n&jPhv z?%Cx6YDK`!#v%dEx%8#t6*(Q1cf_jGikFO@z=Bs$aQ z$Dmz?1d`enWEPeyuHzF^6f^&pdr~lCD>I$hk}u&3K(JM5^`PWVPUdHG{AfSfusP)) zAl1!^(irA}u4BXSl-TES%4d4|(wzP;zF%bf_g54B1A~iOjGKx1i?)`DV;JYt0GLnj z02>BJUK~uIK_wO`M-?M2iQdXE!oqupf$*mi1(%BI7k4N66Dnb&U!XEPz~Eppj-Xf| zmoCRx53j`8cV>-qiGLCxs&D0vN7xS?@{M zGM_1@NiK~Sf~Zc_dXIf|tTU1|fxRMe!B1CLBsAE#B*mpP;LFj*BEj8J2%@~0W^ah> zUSJTGwjz2@KX%zDl1d8~hWRoSVs#3QCiK=CBT{BzWPyu%Af%Rya0X?H^?-49uAc=z zwV{EZbxDx0^CjM}Mc0q639Q+?r1bRB+D^*yn* z07u(0$FRB@y6Cf6Jr%|A)fQf#_H`PHoBnWFoP?J8BXW*8!$3- zbx%;U;T-Ok+dB_#s?7U2(x2Dwy`}k*N-HHkJwU413Z8G)YMMOg#v8X6SC9d{yKeYu zi{YVIY*Rpn6P;HKk@;SzhB^vgO@1>X^~~Vv8HNjuipP704?00mBitk}2GCHPCHqG~ z3(e&LMXuhy-MP20($T>&a9mW=FhusZ3)VWMD2`&mMnyLqz-pROBOyF>hUy2x8d%eG zE=UqOR{(k5OS#>PUs;$pUCl6%3^4?COclHF?~Q(k-lCI$l>X#BP~ zF-JEa?96Brf|{V@y@m!`!Dg0OUyvPY0F*l``smwMpkW37(X>e1u3xkOzHkg;v89+l zVwjiBTS0eM$DljX!Sz!Ot#fFvw!k*%DD6#zOxD)uZBX9v7AK$1LRjHIKyT-P4tRl( zJhuqw*Ax{QN4@+E@;T7hFifzim0l;eceaqWWNwFnX<>;S@4+g}Y(b~GjQ0#y>I1`Z4x)~q$oGlUTM!>q=L0`FrhH_Qx#L9pbMw`*b^gxoolldlTw6wHv zBhsWLqrOfa&$VFo)zl(<%g!4~uOrQ{$E3Moi$rt7R!BUyoFmR*1tUm#6KKflGs;d^Yk10Q7 zsel@WszJ|K=4L}Zw_du3bzl-FNzBHFj9-CZZyi&x=19gPr*CsRI3j75UiU{R#|Ue* zf3Qm%uK&WB8sA;`uTkd(KQeK%5A&jA4<~y?Kc!T48W9bS;nE-N3I3IhDM9Eoj7iXt zWuT`lUnbH9Ldyo}fgx>^+j7-}KWnm=(*}sO>Cu8BiE&eTpkZnNKp^zg#`bW3he%%w zO9JX8K)53#D0|XkWSdxOpT&@#XY(WdS@W%eG zmeJ8qO_3bizW+{_5J7j)-J(p0F=AL1-sj;F2*$=kw0Y}T<31zAHW`)J_z3AJtZ7U? z)A`gS&3r9Mm7_Fl$54|Pl~ANJcal|w>+ro&0cBI_TLHN*+pTdXp_rLyc1qp!i1JI2 zDY+}g>vZ;WUB2^q!Y6Y&0PO+(Vq_}m?r(^{tT@>98wM>3YrV}3i37re8=wU8#>QIF zmV<}CaYDN)SFJJ}iZu_F(70D4iXIK)iztsukXL(II5|>|y=QE2zO@U-lXbDrxM2n% z>dLz|=3Ld~DU5S4BEz>pP9TcC1M&m8=F?{_9;0*-Ztp|g~uBE%*(qR0A zD6V*?c?Gr!NLM4{1|+BZYEljV~*1b*iXF8<{c7Ov4nnBFp_~ zh)69$wTXxN-oLcX)v0e3X(Y1I5+YhBkjfg&1X3|ZZ@slaGFJ^a5Y=4S%h#?j7RWTH zpuxbJ6!sQ16QxT-d(xyUe8510&>J1J508i2{oBwkilf-p<`c{nC6Ja(-xeuS^$Hu_ zX=M+F$UiYnz@e!IQO2b_AuBKub;lx0-e*7MuWJtI*7A(=AWIPS!iXW9uF25vkuYQQ_AlZ`|0@?3!>MRCv=Y_<2Qh`XVCEWuag!Zauu zo87AdtuSnWC>h_gym_;9Jdbl?0H*gAVx{Y}7QOlwXdqM6+}K+&Gdp+n2LC5`j>&Y$ z$VZpnz_Q?u5sEN7;Y`S}JEAqfL>1ob?tt82wX50`ug6806=TT5e}PIXV~Y7@z}Vb_ z&tVgD`Uz{#nvl_aTkFD8?%l3pp-f2vH`$nBz2D=pqpC=tyt}6`y1ArA$!TuBS+xzF z)#V*Di*KIxNl`wNJ5Rx_8#6o4Ep|jNaWXXq2@q6*{qnt~g=NVLAs^LhHBm~!E0g=A ztOgSXy+SS088m;<1f8Ck_1e7G5ZY(zbi=8#V=BGEF&K}Gfh#kmqUY<2_tBR!NnWd2 zKej|%h!RPBrdU->w)`jx-t9V-K(_W)vCS++IVggFkwRq2_(YkBI~@;qxo>kZNnw-BtfAyS+;OQ_mvvc zLGN$`y|ImtN)*tMr}s^EOj-ZA1ikSu6Z)jgc+G`g+YJjT2QUL7!_)1swssXn|2m!zIboZoCgn~Z;JIr9d$0NmV#gVh_FE?2;wY4tem&LuPL$q+pXE6@(XT*?O`&Fr0X_&XyIRyQXi- zFwkBN>yj*hee=Y z^P^+v{@^~V$Tii|=yPpwAl+d-IUc@^?y2jh@0RWTGu9^VB&ye1r^9PYLxkl$Kjge;!Ab{j@sdNLZ#; zV_P7r>wXR%A+~endFm=_Ubu>7jXBzwp-v38=pKx&n-{L|hE3)5$Y*Z6o*XGdb@_*3 z!vNgCP;K#%mUGJN)R?XqfJo_+jz6~XiDJ0dlr*2%SaByHV&OQONm>zDQIsPE8++dD zLd?9M8QU2W1(*-)E79d8JPS|WG&Ax6#NRSXa{X-C^k@hk#>Vq^?I~pt+A(UdDec%< z%_SoiZ9uAu*~ts=DoD`6kHp60+TU7fRbaF!_UBSkkKv7u3d(-VwIlEFy5Q-V0kzAo z%`)n}P@(i{jn4{{0H0MJLAnpdJq6TeDC2bHOipE9D$vWM;1?Ry(L;WX>racr`rrrS z9lB1!2B9!%4cILad~H5#z|>L!VYRbvDLKoTF+yaL+sr+|uIC54OEIdL`>kVWQWPC0fp|hDQ0h0&8o`O(EZr|Kna6QJ z2eG(og%s0aaQemzNm&*Vr;sSgZns#9f4JZI{J3;d5?%iiCSVkK)HH}}9q#lAPnB8$ ze3vDeK=;Ir;PkmPoo=>9gDA>Y=Ka%yT~trDmmE~H=!FY}1fO*UsL9HG(6X@%#oksoq(qr4P_%RfuPp?!9b_B*!W$L={eOcsbi>rSvpw5IDvz6ffUY zFsX+p!FU4}W@Dmay@I_TQYg3Xr4sAh9=%HZpST`kLB zvhb+oStd9G$ z9h7MnDH!Mxvm5{r>_QJ(>Yp~5%FsH*ISWFK)j|)D8Pxy~=7Uj{s3sQaSMDv|s>r2) zXq-DXc8jQw^lYqjVfC36mLl%+)n*t7Wlqiw4yMxgU6u;RB}d zC(S3cSH|U0fAPTq1jdX#w!Qldq;|T&TsojYL?B$554t8>oqAC+JrekRM*6e`F2iA% z`C*E_8SAxxvs;S{AlMKhkowlXsw!QHaYDn=`6et!m#D!-9VEtNhUr6w=^N7sfNOq2 z*8w&bMohV0&f=d>HMp&?vhG%xb}c)eQ69g7{>?$0kBT*@-H>`Nkepj*fVXyP<$zHaAh*?ZVECrpfzO2^2w4lM(6%WWV!nv@GOwGWej6<@zd;M9M zmM`MCvU78#t(v{G9p6|;cX?`nL@e4>Y8tSc45ZqdIdon;(Uzf@*+@~F2*1rs6W~}7vogU zk}-I1r(skdEcuHXqA!8V=eU+I-~y|K*#wyQwT0!ijki!rR}YD9cvsQ3;|b6J?js}m z>Tq4it)t@%=M0UkiAB(yr>3uDM^p7CXi1a_wp+Q1hz&#Z5K^`IE9%;COgZ8TGjTg< z@Vs6~mBeDwE(TtGS4oGx5^BbM6R7(NBU8ql$)$OyymQDI7#kWLNochRs)ITAS_(t@ zgoZ2gx=nz(VP+~?#HKh=4i|4Y9${cYGel)jLg)fIl3Mdp|_uw?s)o-fN4Xg|1ICt%qGo!k;xkM7;##g5R;F?;OClu?xTB!J@;pa^At{&hl zQ$f$DuvWUSxl)TQN~Sd)YI!*5a@V*v0VEcAF}+BSKdR0kerk*HA>B|JkTyIUFZB%C zyakbzc@MU|oTToFQjHAz9sPM#=x z*rqbYXm!-p*3|HRS)LWDI+~1Rf1;w6+x|g!IWaNG|FZ1q-P?UbjYp^ZTgdIaOIeiN z{k>g7IILXN!A5U0n!W8EBW4HjOrS$E!#%OD zG}_u%`9blO=I->i#rw~r)9?e0R7gN)t;%WG-!1~}Uq@RR| zW?>Vxc*&DUX;q3-O=^^`Ffc1P^pN=3S76e7`W)iUA1drm<6#pm%)6kphHmZ;ria9> zh1!aHr+f#-qSubO`hCPoBsIOnb9RvR!43qN-XweaL0&dO6fgaD`*6R%`&bpgPmZMZ zs(C{X~kT(oN?LCu$p(?L3NAi`fyvBay^@^BNULZ zWx$U^B2TeYSjb_b`N)N@8r!Kk;Nlymz*ID9)*3v1pf;TdiGlg&4M-VzQEMiu%l|V| zNlft%)B2v%GWV9KW3T6p$Ie$B6*U$RPso^i>}~*u!e;*6i4^ zXfk7iM?O}=Ry`YM6=nFnhXidxKS<)vO)KiQ+xsId(;p_zZG}+f#PwE>kEDLAzL1)L zul0>z|Ni)+Sz2U)e)Oo%O-V6_-=yPx##a8FXV0Gfep4Uyo#>I#5~zFT6D-RXPOZ;)r+*}<1&GP9XH zHSbPGBUs1uI5fj+UB7Pa>FLkv-{R{9qk;dm1RTuGZQ1vz$5{ufNVZ!vwq~EG&w<9`)OXQz5U)`d{RwUHK6Fl(qktrd=1$gK-M|ntkr$V2`1x zx4gGxaV*BJS?L1VJKg3I+t2XQUplQH_piki@1NkM>zZfW6pu*9(*5eicY7|%uIEqZ zt9S0-fA&)R{c`-ZxGL3M25+)J<9}Ng#X}CLb9|S_826|9iBEI9m{W9tAJ*>pOU5!* z{9X^U%&&9i$|lSW72V)^mKL}!DRG04jg}(0R@kr^PUYb!qzgJYi`hi=DHVO_N#u`vwqc!;bv6|@Qluc%f5sAaCVdJnbBZ^ z49dyvhk%MO)T=A{;*;s0UdGL!OF$H2#OvXvp~;3y$?pC!>ZHC!jUkZG&Wkf&_`>XU zUtx4>pp-L zQ1%X$8s-&OIYRkb`GD78A{wWulA4_{nwz6NqXm+j9~&c68&2;UE9!sqRypSR$yxrZ zY`DsdWr84Y4TtvPgYpYsC{M}@<>1o9)T=kY@r|@|-p_v5Pc}Hc$3L4H)lWti09}o+ zw{GRtvLVGqj`I2bf$ZXP&C1_`OZWPB z{viMTo@S}D-;0+%^xe- z_7nFf-=3F0{e6CSswMee>Gr++>9~9P-S1~`*wnMsBSS*38gHwU+fcv)`X@U%R~%Iv@(bO%iP0da3x(OCS00M?doMkA33f z=RWzVb7#LZPrdZ5UT2?g1%q{@f;aji)9AN)o#gT4^>WHa)7Q$!6R9tGjL=e|Y+R;O zSI&?5RC%bLfTDa-YJ{6E8;mnHnA;TEJ_4&adtd(l@AX#W_F8?(KkobUyZ6dMFH*0H zKh5j2SgQ5cKY3CXpL@3~e&Dn${y4Ayg73e?_y332U*!9*eZ4IHCa>S*_22ON4PL*; z>;L5S*LnTepB#UEjqiF*{;9I~m;RZu_!OW2!arLU6MWv~{lET;W$`Ee-LiP&-zkfK zo7WHVD*ipT;r07`{%ilhUw@zXcmHAa{V)H}=L^052CrZIVgIb}Kll^=`dQxp)%dJs zKl3?%J>dO6jn7*4yI=l%@u$~6k9ObZi_dO+zL?Z#lVqZ&j6_X}D; z%g09X*62qi^2Tn~nDy}v&=nC^%!Hhz#O8oC3VWYY&p|?6j7p=4?$&m)W7q{V@`QCF z1+}TZCh%=!Y4rBf_?qM2O7YYZm}@~}WBl0xVVE6lPh1+`V4^gdX`0KGf5rKF%qMD- z_IndeF0E&I-1Y0jr%f1vnJM+PeE7H9aCWu#g9|24G7ntS_^8IXF5k5C%4Vfmk22VO zIncA$6xIh!_2INW-~$b-Js5u)+Tip1NWbKRWvcaitg9(!d}a3gUT2v0-tiU2x6_{F zLw}0{b@Y4QDvpxp-7_~Lua}NmO@evN^wapdb|%m7Hs6ZzwX5rWk4?nS{FWE|9^2_O z?25fBD0h{h0!Uj;CUK7Gp6?iD%9QJZN~r#wJ10TOvzoca7N15v+m z7f&4}EqNt|!94dg&OB!;btWe^ulT}-b7H+}Y`y%z$D3r{VW9N+d$oSO89SM};-|bdJv((3i`sl}!)Uzu zB~bZWaLChEcDqS-Kj`^rZ;^)x{MjThwhyK)Iu>$;{fU!P+hFWxztst`wtJT6>Jr2bqDOfdsj{rUZZG8vAkaGHfy zwcC6~rbQg>iiddy%ZVS%kp^z#f~M>u=A^HTmr}Kh4cSC^x->PHS`h z{=!+a=oWnvyh5;l1!picHIlNHSCI``yKFKKl!IzWMC*{}v(vl>cGib^z#e@q4N6_k{19eNX3=-f#TDvuAgCy}@gT*O1rp(ksPBmR~9U58mhR zy;6K`&tFTt|6B1{%kCWbYsCA18K1T6Z~m26ij7}qAH2@<`u%@Uz5XjcC)ShoCfQ88 zl9Cp?Qi6HuS2~aJUs5lvWhquON^N1)9V*o4%(fb)qxzJlADoxk_KH|*W*{fodRp>t zVinu=+pNRPaK>4hp1%GqcIQJ!@|dP!Y19t=?F@v4h~Vad#YSiRf@4GU z55>yLH(?Qbcx(mRW^75?wOw)SrZt{1I=23E`J~49i^{Or0f--qj4_H5x0ZlLK=5{6#U0O&!urRy{GvjeNW^6_r(c*iShM5uQ$K= z&1YM@AMpAUywdzo#(Iiz>hFjBt@xpM?|<{zvw!$^o;^F^{TF%t8@%+>=i~P@zohlk z`J|ZfPsVy*W4nKW*T2r|w_p3_v%kdqZ}Ix`FP|^;`m4M;pZ3rC{>{(&>nDEneDQ0% z()Yjh7VueS6}hhf6x2jAFIBu>Nn;Fb23-v5=qbiVk}UpZg==l|jP;y3@J^TqvNJ74_#e{#O~Q@?(`__P1<`Qqs5 z`QjJ(ZG!i|_p9fNzsv8F{MO?0E3E%E+x~sldzs%ie&c-c3AX*8|H}E|f8hJ$zr`{C z_W9xmczu!AZ}I(Cc>mvcy}|3p|IYd1AF=FZ-v0yM|5slB6U+Y`@0WQ0=Xw7H-v5Bt zL)Q5v-v1h}%Y6Pe_~iOqYa6Rpuiz~bFBevnZiyP%y@fl?)?0gsL~fr({*GsA5WpFX z!V4sD{hc%SEGC`^9RUS&raIFd_!1}fBWjAUF#KOza5iDv7H%GGi`Eivw&?$5?@hog z$*%g&=xza$umlEV7OBN+N!4A|UHNja%1Wu#ewF#MDpk3WOLez|{gn0cWmT$j>wKBj zl>#$j)yHQuU|=v~j|Y7)3G)jBSL#*s_o@J-`3COWb%b z-pkCAu*d$K-BA%Q;>Nu2EKiSMRjI*ZD!Tjp41By}iWu-g`3lkjAx6w^J6MZs+od~XwTpas_xW++lLT(p>9 zEf#2iulC=g8I38Xv5e6l&v=9KWR z*H)+0FDDhP#PuebBQXP^A&ug`uompP$?H%hhj#)&heUSQ2}xY-p#i%-Ox>f`1Qo@GH2R}f3t>&p+_CkwIw^Uj4X^)#RYX)Tb-G3UuAgwysVDzv^zokR=Y37 z;pyt^sxK-eQe9+AX|Hr|ce1iNcXNNlOs zzLfo6dcWI#mHn0P&wu~;PoB%P{TAEi-*w0O{hl9xJo}cv@p$$L_BYx82>Zpq|9JMo zKYTp`U2yi2dK^-1oD8jQw9?yT$R3{)5M}b6nqN|6T0A ziE~%}@5i&B;CP1P&*b=nY#$;0udr2qin2)i^PKw?w*QATe~Prf&HfiT{|@EHHp%wW z)agHw<_Wgj-23NA_b!hABo0N750Kx>IL^3!iS3AMKgqd2$@c$p{1)~Nw$CQb z8u$JI(tH#9FK7Q@@~e=?F#A8r?@zG*0q*&7(*8R4{Ka3)w{Pe8P5(PM z{^sM^MfTsw_SqaCv3(V3?y+6{E%GMq=d*t!+pm-6A-0dR9drKGZ2y?Le3b3oY=fkE z9rwS6d%uu03mm_N^RuLT8OJ}t^&jE)pWye8vV9)MALiU4+c$8$zA#&c z>+H{y-vs%68QTwW{1&zb$A6S`1El$F?x`Eg4k=8a*hQ%|@C^?LSb`HQwkwqgxu6HF z3#C^`(_(1_Sa1<$T`b)^9R^wQvP5w!wFN})+eeJ5or%&ksikyBnQM=R^;$Z{p8EI^ zW*UqCV7Q!<-e<9t&8H1; z#s^%I(u7FYlpZHmCmea%7G&(diHq z7C04$+xJjn?BMIuBv};f*JL!5fmAfhV$owY{vg&?r$yxfq%5L!!J8qkqg(gFo7tDT zWr$Y>`xNaw$)vn-2CwE&%P$N~=H&dhsI}G}4HA!2w_Td>5!A+8&8hg&te5k-byfsZ$so{`;|2K; z%!je4)3>2VO%m+Xt?qZ$SsKL94{;PQIpxSu1;5;iRh8W3$Oa*(o?mg$0zqMwrcFzb zQp>%fS@X-Nbb$|KV^Iaxk{#H((5z{L`Dz@U;$zi<(=V&2EJkw;W>*dLe)tBko4q%h zzL?P6qW0gJ3}ROR&no`_)+^8AS4420FJL1C{>cZkwMT=5EA1|)K7J(F-`GTu^sl@G zO*Q6kQ_qpk2?cxTWI{r&Ku2_)4Z)?f6HGUVHZ=p?2mj;YYwgiDp1O`D2_JEaT3d2s zA0(T#wsVLd#%6nC8~`9VNFE^IK&xX9FWsg=P%5Aks%`eL~$huI*8Wr1EBk z=<%WwTXD1S!b`=z31LDXp2|P3qF@86ci0P2u#&}w!n5q)TsTx+HmVr!+rD+-IEU199CD-hge)Q(!kdYj3 z9lVsnEAEq0<#&t(<%KI@Qbc(o%+=^WX>YfTr?7$j`0jdIf`b7K`9^4v-0S6Z7vqvR zLPgUI+_=F%H%E~rZX%<9$e5kNb?jp7244dIj*| z_a#$5`>A2)h`1UcSS=nfU4@ZPN z4R3ZU%gS&ZKbm$LWW6}_*x+c+-Wa1a@KRx8;^71eR7uQbtr9k-WCs~!r1nFOTC7jm zFFrY$bpqw@wag<_yo?pOweM9Sv+3(gmgoNM@Y-GZSc%`p@67e*+~pVEl@Be>2BAG8 z3zXSuGej|uWmY+7n$T{$+Y)0Yb@UEXCIn=`D6P%<4jb94aE?aYtx=%Q7lAtv-R|nN zf3V3wvD32hr$XFYBh;+ExM$D4ersnPzlczJau${B=6w!DgP0Yogez2jk#iFZbJ50J z@@|Wv0V5oT4(^+akLs14OSf7bwQesF(**@}xUk$DnYz{ViSA81Ki5}}=hqMJ;(n

    RrQ-%y7I;{9Jbo!2lPVsQR>z){R>z^l#QgSjdwp!oc9+I& zH*wjKEX|@-TH<;W{0AB4KMI*y!{yh^bT|E3xN}qvqPV)$Zqpcr_DFsZp(xgs+w&jX zJbh=n;Ejxa(55p$xEyi)?K*C!!gD6aJX-o|{8I9ZGLl~uQftw}Cg@f=xT5~W0eyx8 z?9=M_m*U8Gyjv}mHoq}m+uh(I7pRi20H??Y@%M6btZ;VpM(cR>U<=Mq$t^D8t##`~ z;J`s#T;#r<1b{!)^5g&7@(Xr+fmaZC24Phl_-TR17I*+*@ep`nA$_?2SO5JJnYPdR z*b`ZcE&Tq>k3W%VyUg|t{#d_9KjF3p`w#eIo$Fz0Ts#dZ3D$!R*;bnwhjJRMUn zB~%#3Y@rIri?MM~Q-%BKm@{)GuyS0S1l;Sy*H}iqQPeFZwb#;w#YS=_IV`SQk_#&Z zZSe{`q!f<#TQK@%Ad! zJexd8=FcQV;gq*r;0U`?!VM{V*cTLXPb|`9ogSR8B;JKoC9b%>mE0DR`ct{vbq6tI z2u-)a69s_dI_3`f53aZo+Bx>v@cupE<&BcoTx7{jjvXi)#7ME#bnL1^z49Nv63+IW ze=+dqUmT+Fue^!4Q~b_ZbBy&d*W%fjznzA|)nO^oaXKbf)@{?W6{VBzTL5_tPU_D6Q-RI~2MI-~$l$ID68)I=U>1DUA zolkLT{G=2UmrqJTDf`wuL0UOHT5y(?*N4(NQeGKP-D>42DYck#Wc*5+(u?ul$;fb$ zS1{kUxlH#E*OiEOu~Bjy*`1?!EiiVQZWz~syn%;?qX(s`nrz5qU&nEA?|zc4dqC$T z$1la4t1^G#E`AUT^a-f7`K4HAR*vpvCM{O=RLKoNYF2L{=s|w^(s=3VLWqPsHJPNf z%`cEm`2{jcFU+yV#v!ct4A@Q?1^>0-rL)%e{*Ro`&boaY_nc;X{fAuMC#5}Y`Lloh zeD=+3o%y}-$IfS!zi~eMfge7feVFYBIWEidyQz2Be)K2KXRrRz^VuHzpXPkn-ov@K z|BTzdp8czTHvj$2KTr8=A7Y#N1$V69KlzW{_8-{)%0J0}{|}!ypJ{tP+e81+9qae^ z{jS@7f&KgcQ~vwq-*zGU(Z6sZ`-&gDkUjS2E@V%9_l4|>zV|}*gC9EG_R0@j$majj zh3wb=YMy@RuUyDJ|GO?^gYVDJ^~&$^_w-NmoA0}jef-zl_Ksh@kbRWxv%m7mGjCtW zJ*U~e-sgQ%+SAtIr^xTyO3HrWtDekmbAE*Vm$EJUay#>VjPqgpa*p56c8&B;vk%+v zaQqRrU;LUUv#(_PA-3Q6>L;^_uYEH67Pi05@4v}@k^Ns_|EIY27LMP`@$(#iE61;5 z|2ypech0@`>z>TMfc=-T{Vv-&zjwKIi>>-z@}~Sp*nbw=&vX4Foc}fUE%NvT*ZvOM zFR^X1y_PgD=l+LC^J%1+ zc%|ynv1pejDSjs&3S}+Rey7EKZ=-9+`L7d49<-ck8j~b(;oFsWO3u`f_3=A%GaHjO zRr}M3XZ<8r@UnyU`(+RPqvMBP_F($KiX4fC?V4+R9Ltq!b@&5*IQLqrdHv~&|9Kl*r|C_ zeJctCqn_r}NmEu7lDM|7erhxxNd>F%NgR$sgR(9+57nGHcKg_g z#1%ivJ&roGdy9@4?k$C!PEjI&3F*d+vTNT-henB7#uY>84JNWr#Lm&2R%JzyEt3{A z9Cbyll$Zh)OAZ~0RUgJ#kUk~pHh!lG(<#uObEK4q9}2>qGwxqLwclPl*s2igr8EC2aZ*}r7J#(tgc4QxAX3#8HS*Rko^za`CUxHsLNB+YH|(fuD~`#!c= z(k`>TjO`t4mw)D|?2mKbJ+?o_w#W9(Z2vRc*RZ{hZT#1s%6^*d``P{q+jp@2GTTSk z{ubLO*#5?EKb3v?zk4dn*bn~O?(N{?Ph}Io^Hla*|KX|ZUwy25`!`b;v%fuaF?)Ia zV)i%LzH0hn_Qq=$vqQE$&eyMB%zlb zg>8rJcliASa~HEYwieqc+uvgQ_iSIm_Pxs&vu|6wm_5z5&-Q(*7qfrIe(~nT?5o*- zCHv20zsr7wYaeHu;`lY}mpK2ED;Kj5u)oE*pJV$OjxV$S%WRK6dog>G->+x;*BpNz zX@89U-(&k$u75A*-^czj^7BBOeTZ})u+)G`#Iiz zj_2WcjO&|hKg_lJoO>PHIOjjc{jcEo1&)7}^naK%ui)H=+5a;6y^(WY%Kq2*{TUp8 zI_Z9v?ay$}zkUbx`%-`$sehSQFAQMDnSfZpkmI*!=a&Y1~i-piK_uIb^V=R zcm1K(BQJZn=$-b|Rd_{P;n7CMLN*ULal35BFNJI#a5lDVkPL@x9y#@M6cSoCs1M<> zur|T&&cO#pWHoK>ztgv*)GyYS;thH0L&z|8nt4`qm}FwMl*BLvi>%vutn+b!3F*s) za4beta6@I#uv9dd3`H z5$^Atk58FTyg&FqJ>`8NS-d~!Q^SQ*?q7lNn(T22G>}Bmp4}9M%f1T@a&VH=@838f z?j`X0q7l4oStyTX#tJidmt^6FqR0z7!*Vwcc$BOaWbP@Uw|{z3)d=cRSOPFA%Tu9- z$MxIQ4pDKUxrGBzrqE4&T_>qeq5fS(WHOb*<|V_CGuCo`Y36?f4C;RV7u5!PL*bRf zgD$hoXd^AtVQD!GHFZ%TP0e8$&LW{b>mf-{=Q@U(RMGy-f7dY^l>%wQf7dZfCH>!?j@jueJ2abK z&6D^aOkgjvb1MvF z28Rwi(*2#enP%n68;2|RhO6kn9al&bb_syg)NM-$#2lV|>N10cQ91vjd=SyXww`HM znESjF{|l}lf}&Yu#(tTbcAKV53edwk#H>Y$Zq|g3YPm-Xm@z?)wf$lyZx^#af^_FI z)x6$q^Mz;@dj=!1a@C1k&tIrw9$^+m&Xs=V-{WUI=zH|I?;*4;5Aqjq+e3l>cE(KN z{SUgP^3VT@2VG2s`<-+AGuA%KUJ>qp&=qR9Kkx+4Sc6wwoDvyh_i#WSASNx)@u2zr zR8TT4>@Z;o=6X(7fu9C<-aZyb%C5YX2r0h9oA5h_eL?olSLHofg>;A{Z3(E{f_a_g zsqZ=!$IFLDj(!=M%$!0IZ}M@#7o(5YEgt*bpigHL2NruTYGvxHWv)WT zkXDA2p+zKFr853IbWSy}h21^cDGW{B1JkMTd}u3+Jp7(Nk=gp=ayk+-%0(rUthprr zz&BUBf=$&$0t3RY;~Av{laf-G^_%Ng>&w;3taB>9c_c-`Mc1%0S-OQD18Z%DD4D>S zTas$UX$A3NiL`~dlz%-l1`ifCUIL5^$P3{8fZZru^8;gWo(Tslq33%|POFjhhPH{| zO_&Xv{&M#v6KZ!|y21Dz-VhIfr21k7st!KZn{3Wkx(=YlU##qGTcp`B!nOFrOXC)~ z#s3mjD%V0)Bg;82f!Xsm)2O+&mf|5dFRCU+2YGtg7O`}kU%x+RMiy3@3)|vOR6pep z5LH`p?mB8twJ}ZWa*gBWI1rV6MQ3`{i#DUl@Vcalbh?7a{aususQby|wto|vVC`LW zmsft@$!|dQf>p5MJs-CZcMheOXIf2S?gj{?b=MK&AXtK5-kSV*YO*!2@8Z zGRvhNTBD`4tN6gh3;Od;rVxLgMqiWVLA`p^un;s@^R&Z|AX1A=T z-veg|w$RhqE%|buSpuQFh$WIq03Du`lrTvWa8X2i)wHQYYgO|>Au6W4ir=o-m=Lez ziE}~#7G&$2tw#Iq)_y~3EOK^wDN`fondEo)Q8+gUGB=2XE(^hZY-my-VvnQSxza2Q zg~?d3VKJJ_vM3(`XP8UY2o!3AtW#9WaYE>aR1(82|7p4pwdEaRC4JMrX*0UbCo=o+ zn4}mK*NIfThwj?PUASn6NR$tTZ4lB03%^jsg#zFiyHCPr$%3q7O05=NrY5tVFEqZ) zyc>qlZx@r9%eSz;2?grNN8F@S$eR+ESTG!HA5Rt%p=dzt1+JDUf15~3hXl{STLw}& z3nt1mU>}{#&Nd`G6$O%#LwDkc8ApluTP!7HgnBSJ+37;ktxP)Szxxvxv)_B|K=vJM zVXxy~{NjP^%hg)~Xd^6&x91)k*kkzRj&NzVKiDPp( zZ5&XymHfX9_0h$rR+bqW35m*-?0t5$ZEdEmvfUb>Qh4#mlXT1n?VT~j+O8qc5UNfV zZyGMfFDKrz^EAaVzK|#vRV7Xoi8G!rM(ks$O2Q2McIHb6kO*XnmL{l6a7)~7r4UgGU&9DB}=@0Y#b;+)$?BJwn{r>Q#(>F!XQC&tkf>aIG=B0HblHHdT)) z))rRQmX;QmQ6e=gbhQsTTTL%a%`RQ9FPGl4RGXew&Skd|KD+e11BnelVxu;9ZE<;a z_4<5i!us6Y?9%G&l#8fPnq;NEJX@QaeS2+nc5$IJg`6CeUZ_7u1eAqq^%E*FJv%cq zTW?&aGV`_aA~2~cz75PW5|fS%jZVkKt5@5Zcw;;5GQcWJmW84brb~%L5SDLt;m_0BiXrihkI?{`50it;rY<^_JVSOfEd2U7L^Os_<|&l zOCf1hel@0pBc+%uSt5CDqufL2WQ zt;3n{E|XH?GQCi_JL~TTV^n#aIPn99wyPi-`2hA=y0EOX-qo&2y*FVPnf1Ufkne^|i4Q1!K_qW;p1?k`O(V^^z*nZ|W zhO%#EUvqBga0ooP9uD(JzR6XP$0nnh2JbBvdF|xVZb$szc!|i!{W9gUm#4Pn0w^YJ zJNL_pKjvBpEzFme`(_~baNhcVk;Hq-dmPT}m6#DASrD+8^lhMZt{x7zK=GWlOJ@=% zScS!)hC`@+t98(sB*}qKw(Vv$6`)lbw@pq$qrsC^L&2_XVbUi}zIt)_d`Y;+)i`ER zdbP709(@)$ANYA1>98Sd>SGZ-SuR0+!?BIcVC_ak-fkr7eH%6;I6G_}%3D+KRF-)g z@x31;+b1NA^^p51X?#wb9@5jnNq1}{506_gMBlkd0a3ra2&*CVl3oCTY&G=&o6JNU zEw?riu;XXVLP6`2>ksX&%LIuh8mx2Fqp5Hz_dTidocmZpgWWnjXtm6jQXvJB2j_-1 zCMkJ+G{2|0mt1r+Q@i9!cUyENQjI4kX9$d-qaK%aX}Ps+G~3lZaebU~NST*yR8C{H z&1*QN&;Kn?;$4j1MUzMjeBsEyK1C55O#JbHPS$gu@TsTx+>v{9&5_Hhz^QUzj9f(0 zqu_Pkgrz}AmU^xa?SNKo5^3E`ZEbGVJ2I3IFm&YH?|ZnR>#?4z%2k~C&7$$vLjd<~ z&+&j%6M1&9$c$oZYuGzmw{dv@hDPkH$%R!eU^hyBmx^?=o)tHk=u^g z|3iPQbM0fdeFyu0?~iqE@_XFYV*f#ZtaIKCOpdZ8!~;gE8w0az?c*I7$p>5b-fE>xb4xRN@2X^+L`PBKl!Pn3~q^zp&vKOMcEpC(76&cTNii$_PqizY=TP z{yMhSZoc}e2WRrCSn#&$3Q~*O%2@*&UaR>Sy5;S-0OWtXE~}qfo4ThnN&e`_0LHx1 zGik!Zh6JVwJ}v1K*^x)|g-{wI?Xfdu?YPQ8PH@rU^8ne!EJY(LS0Aa(;Temleg%R`XyF zH6p9`!*^?`gPHp_fr(uOVs2`HAVczktr%tu~!pc488ndvCQwh;)d{W?mbDtsd3q(Y0A`2(qxC zBU0aUwvX6v=AR>S`DzW1MfsTMpGZqIDO98&OSR1!fVArJ*KF!v$Hc}HwcmKcYb|4j0XOB z_BJ-E`7fwuqt>h6QrWHU#zZ<@-GA~0cfx&yjD<(rNA2py&I`jap>o^U*)N{(y$%=$ zSB3dFExOmWq#~i9@a=Zx^A?TER+p_8cJ^cT`RPIx)6+>s^V9w*`FitnWx4u7V|ms{ zkue-=xK;vMQ_)YrI0`#r_XIv_~K`dtd4 z&udf>aStT6v)@3$+n_%LzpTOq;W!SKDOqBB{Z?zcF<*PG!FSoX`uu8r#ePNO9e1w7 zpXz#rbrjeQZKX`)5UZPA`Z0RLkf7|CXQR zbgyN5y_ds1;-5S01JCt8BGa3G*Gn(`9{ZP(_LXd(%@)!HKC2INob}rO^Cw0#ZJ%>~ zGPs@oduFAnCv|IFrC_VsthviEI`WmC7uviWzp{l8-W zz5Kq!`H3GM%YKM$mFom_-EfZo_&b@F6Vxg?Uy;8 zV*e9t7oHf;F7f+GwvTcALDK#`_CLq=KCXX&^WV>YfV_U3Yv087U2IjhUnR|lx%QJ> z`v;_ZnBTuiUH=o;{xaw9pC8X&;P?-7{ebQ7aP4b2cb=`r`G?uRhV74W{87@+k>)kz z@sHX6I{6K9?hgCkNMis5tu*=i32s2|v`k@-ta(;?vzj*!A zydP)Ez^9`*lFR*AH>tl3uh8rTcOcw5#D@e^8h;+Mt5^b;o2?HQ>NfEIjxRCZG1?I4o5Q&s=e*- zU-_Q*I&!z1JHn}CJ(e1%pq^%?j&)a!*;tLm^ks%7BKioo!&B;+M+6R#y?802MBSCk!b*QKVJZ)oi1X_j;%z@7Rv7w>b#s;g?_F#Q_ zc4__K@K_T368^np#qG2&B`SUENT=a)Deul#LVrXow zXNlp7A0`tK#YYz^AoEzQbr;*mq?$VK#ES_b9Z?I)jK&?}3Rtv|2C)W++sjPinxP54 z$tf0oo>K$Fcc17XiJ+7?Zh{hwZq>=f)I)uz(NfQz3zvuqf1XDn?#qS}q5@^fsE%h- z2SSW>WAz|W1F3EJAIAS>`G|a%h2guI5_SM==o%e5k@1>Xi9otK6 zuVy!XeLQ;wThs4#tnGhg`>8*6DSP|ZUdq1V8!u%)`1Nl8OMl$$b?&6?)BnfrG=pF5 z&VB8BFJ-U(?n~L%zyDJ9u_CND~y1mYww0-0+cBk3@UU%+0f8bJrA(v5u5%WN_=&HbM_NcQKRt zgGE;8aIJBQ8t@$*@>QG4XUSx*C`qLLENKAbLV?8D3aSBd00Db|5|AU`8G^

    )yb|O7xl(L(9^basxK^0ndYk6-i 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�g1OFbIeZx`dlft+ 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	sR|MyXL$U?tMB1
    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⪚;(jT2w#oxz9#&s)j-3hjjV1TD
    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 k?gGbSVOHCse?{9Nb_WXbuZ+k5`>|!o{@rr8 z*XB$oJ<5(j+eb2_Fx5(wOL<+TZy$7B;IR9Fiuh4*KTtUlxk-OHN3k;D8rp2++RItp zblyfPN9u@LRa~;{S=YBv+vko(o>D}j>~{O))5uijCu#fzG}87YrGoJie4W&-HUy_k z5T9E3Zgatr3Q=lsbEZdNraH6-5if~87XT4+#5GV6iLwg&WZ7kFgMbyJW0y8jVyP?L3?&h|t!**DqQp5dvZX~~h^^GwrnrW#aD+li8gHEZj@l#!muUj0k`-0?1Zjz#5-5kkvbJTnR36A90 z@kC_aPCZ6)+z!*PgLl|Og7OO4vJ_DKEtcflN%``q?vWymraLLPHr0jUwr@*yseVAf znVTWc2x6Yx_ZGzc0%quH4@dgCBPY8;W~rTAg9j`YO4y4e&KkblH4H%wKVZ4t|8*DzC5GK4j>*G* z?GF1?x}#2mkb4Hr`y08n&2+2jYX~1``Qg9PIwPmKNDzeDo)_l{06|>oywZuk=ekbvpR{gorhRQc3h()lW#8Q$QXFcI#TluI#Rt> zM<%(BY~nid#?$Igwj-DHFYL%k>d50F_r!n-O4vwzT3Sc~5#*AQz-yp9IBj$>ne3cV z`AnOp5DM$%a`kp0)d6AIXEkkc&CR^3W|O$;-9_!=MXAS^4rttAP2D_TlS`*u5sk4kzH5sm*CR1UO$+)Aq^0arT-_y)9Y67W_jQXaIO zmC1;e8F$|2Jtz&&X_lz*j8|n-k)2WT=M?-Di)Alwe#OVDaB@w(WEviPz&nOQ0Kfb} zw#8r;{gO!MvP_QmN`f5bvg~qftQ_XDOpd359HI7p-*@8-!DP?QU?SuA;8f?*iivC$ zZOCHSY2U!**ojE7j#|*XtXW&+;YjXQ(b>PZo@^sFQ)<$X)T7mG=;7E9BusP}Pk(J9%(%i^SiGSP$ttRsSQ9j^DsR`Ui9=8_a;7 zl8>`0F4O>4M6;ubdQ_C&*{KS@Su11hLD`Ib$(VmSwe7~>bn4@;p65@eYTNrE^0^b5 z65OcZCdR+|gr;4hY9hL3O0`L6?8+vUYo=C98ndog`;4Zo^lJ_UY&~Lot z%!Q6YWPj)YDmhv$;*0w^0v6RGstk#;9qf~3l=NTWhSp#<}xDk zX6D~AvdoFo_~a%8Eg)(OFrz?3!tfe;sDRDM(|o{=y3FtaJL=M50q^HavBiXqPj8^- z#;2Xc2&ZrEp#IwA@qFgufEUlEC*;@Jfv+d|txh3aN_#%yB{hU@NsXkwK;y@nojoE7 zq=saEBnCeCBF>|+zh=VkuD;kH-CK~#4)ZDzsj}~rBQbdCe9guCWy0G5JXfjP9B@1g zY*P0e&>GllZl{!W)E38CmVWSi{))#+yOgN?BS3OCS`H;~eT-A!ve}nz!I`L&O04ZE zLEFEj>Y(lA;uuN%o_THW(skQ=7qmT=C-~6KbO>VYcAM31%2cAkGavPR-Zih?(}Q+( zT~E;GKYZC`pC7F#=yTh7)SE|>uK+n?u$0fbXi_7brO8eoaC)K-7)=%di?SI_mRlf4 zlT|(}k`z_c5>EYwKQ>Cqr_EIqZu8T_-s-&6r9$pl3lhl|(~wqCZ|V^0;|??^<(_%i zEt5g@th)&?XrvgR59kXbf2KO3i?{a&lG#;Js=N>vCHvAgy-jVx%YmC=yuc#TGdrl#2!cMywb&eE6q zjB?1|;lovy?xdPcb|RguR7;g2ycly63#C9DjsL)myFsV9d{ecg=xuL^R*^Uj|c>44E_?6uThf_&Z5?z{@QiO(^$ldS=faPio|n#-kt z3M^AVnNpevi)sTZcHEGo;xVM#yK%OWfd~O3CA#OWi-lf`qP@whgYJgf+bU@-QF00i z!D8>hPoWn;QwH<^x8nN%Dl^J@n%F@24p2_bth&u+rYS8t5H;+VcE>xe@tSbdOH~zW zYwxx$G85rcsguo6(K=M8?}E}aMF+yTlcrK*{OJ)Eg%ABBs~haa$^LcHRaer;I8$RN zUbb(xFMj_opsW04g`f#!lGrC-CQTzOQ!-B#dHkj1oR~kxdmY&27}qM=kMVG73AHz& zw=>4uDIw0G6BLZ+K5=8L4B69en@Lc_{O-A=$gT_+CT%MbrGzN!q^>FJI8Rxj_FlAx zY@)$K6z3Z}**7=?O2{^NGaO??WtU#*N;5#~{8&WgtxC*ck(co?W0ftmN=X^W*Y*(g zXuPPe%Fgj_L<3nF=G0BhLK0;r!!)Hbul@&Rn8}3A>5LZ$?|{s}(pV@M#M#M{%G_}? zNu%7>gysbag-)T3c}DtWRz_*k5!1AiiJ`&pz>flDQ^kX62WpCPB;jh@?hPZ+_)!7# zCa=3TpJPL9FHkOv%)-g9kW>F1TKt+!YMbFshNS*b>X6t8GDVFa4nb~VS`Z3Z^En#~ z%egf1&Z1ShBP9|ge^Z2W=Y<1SCVxIgd#@0W*Nm<)LOFGvG-Bdl9Y!iGGIq0*d^S;? z`(aj)%&cCIAkk>aG~tHP=@K@2>P#>}1*(DxwFyWo> zMdkS{J5Y%>Z#i%DQ2W&F)%WnuBuIuPPP79wh6yvu#9m6il5nSI0yaJmWH#{n$hTPI z9H}ERrnni}(Q9mk!Zjah*jT=LntO|;{7M!v!o5)Mt!n~WL%aD;$V`c((~yxuL>1Pn zgJ%izkWq4@vR;4(=p{C~l(RwQv~PYRcHozBjx7@%j4}i| z_iWC+MPsR^WaEVy9Ej$Z+XE!dI@PulWb!{V;{C>z*hoh_VyeMljtJBD+LAbHGRMT#Urmpgw1-d{G$>&Rx22WN1vsO8t7wO$S?U zCQ9&hUq>oJmvGo=tIFgjBO!}C5jC1-zKuj5jc1T- z=ZqzQR$GGXa)TFQZc2>^AaRgTRViT`g1h=$N@$ z51mL}M1JL;(2}ufJNtS4LkeZWFRr+_$WKO(>NY}3@5u?^bJu9Fb6`P((ZU8db`AdN zN^7t<+hB0ySlUK#0 za}sij&4e#~dtKAof61I?Og#B5Z=U)*b-eWG!r?r5uLA5ov8-S?8wT5O-aN^$d%=YD z4QDAL&JSm$Zb(cFXz16)a8?vHcu`@4d%Ff#OtuF1$Try3aQ+gZ;~V@-r8RgH4cc%9 zn;N#4bs_muCz2y~DmqBdg#QS3Qu|wRr_0!tHY<~l|E25kH_@l@w;2%Hw((ai$rkfpUBADGcM-LldDbxea)b3ETx5Z)Tc|mc~Pk2|1xCoC! z;&951`ExuIRanm8$aGb0Fru+f>`CBMR64{Ve50VC_JgsLj_VZel>X)+YQ) z*qvBe-|X`58IsgoAhU5<^*6eo&UZtL>+sPPv_|18@rMA#X*Fv!uFNENumkJNVfQ4Nqa@5a%9QNY$Kya)?jXj?No^9YkLK66=rcuc@6N17sA_X;y8{UdId<=9 zA*W9$)-n9*^9v}fg0o9a_DJI$@03z&DVid z@~LY4yog&{vOH)x1IhB_u5MJT*fe*Kjoa$vrQo2IB+Cn%tSwn|QEk_f<-f(5jX;!R z!>vGaYT4g}Lnl&E1KXErxse?n`(;C7zYJ&gONw#6ewe2fYSE`bNL}b#6P?K`WH zoO1mq7E9}sj9*FJKYq5RpY&cwZkfG=*ykHN?`IL4`{pNSL(cUQf%37mjK8 z#yQ1ALG-pe@bRl!KfW0Vu0Zo5TN+#BNL=5yUXxTspUZ3 z#Cab@~PDjVG*zms1J+20n=TFXQpk@zZ`yg&WO*caT{nkZ?%Up zuuKV7EI#wqZbHf~C~{2eXgFAaB%_z<-8JW2opbwl1!WTw$J#E&3=J2Y3t!5eOf!XI zc=({xzOK_EuOdLv0INeH3;{2v96jzMWY_77U=z|M9^D{7zdpU$ryJ%;*HD;Kk56yq zYXl=a80Gm40@2278b4gO{Vt9+-qfsYM5?}lF;O+LjVN>Syo+@GMfTLgk*wI`xzi5Y zkcH8##FWVS#f==t7Y&4?mWwE8wwQnCGDGQ&N}l#%ZM= zHj#Jm4YeIjazEZze=m7A8BzzT^m=Ldfn(+NvL+3;^`p73Gl(L9>>xTa_r9?mKIIz> zq8LD9Xao-+Hg{V~P_#8tb6vI7zpgFm2(z;&JQE)LJmU?XjNe<#yH7uP4^atZQ|OT< zTKi)ue=_0jibpdXLwxe|8i(a30!8jPw0MX=Ckr+vMvM2$b0gTBf&Sh^hxZIvscN8mD!6gP23+9(t0P>>YcaSBM5 zh0sr=l^OXgcS6Elm6 zFi9DRnNA`CF(d9MQm@0GE*Acr@QKplI;Txji(MpSUmQs(i(Yx8Ddi2-RZfR2uV2u; zx?3Z+_@Yh1F=Pg>w^O6Ts}wgWmw|@a@0CCimeL(+pTrdysVj94Mxh{|Vld?d`3S-q z)0ro@F%4=7U9~l+OAlV7c;gzyd;8*J*D9U@;YJ!C{MAVePa2z3BA+ybAfZbLDpjZ5 za@O^C7G=Bcul2I+j~`|-^qd98N8hKvcM;?S$MosvnXCiElBc+k+@%h zYE#p==G*{0L!te?^r7Pw>Zed*@Ir1DbQaY1k9640Z4#$$l#Nu@&>tvoRmO+5SLl0$ z%r|cEF4@8nE9?~A)Ke-P@BQl24l7ln6k8{oJ!Or>d2Yep#AuK&@VJnc=ZbaMFV^qD zbQG*HQxED=o5bLG28WwOlMjE`qbRlHWhDg2cos-f=W+{BF6z&Unr}A0!4tVNPo62l zT=G(iYdwZDIz-tFOsNB92gGRt{fynHn^p2PvZ}IL`j)pZ-Vf``2gz-o_ySOaePy>> zo!V7)yR}QOUQm(b<6RVqT9Lus^TAvG0lm9UH~1t5-<6-RfCOD}vxnI)248l^d3xzJ zG59Ke;J?GbrFSLx53b$Hgo_pIMX>Wu1wWumX|D7b-0v<0|4z_dCsUQW`VsXVy(V|` zJ=9)27fRfiKb8{kQ+|#PilzP%lt<2X?kP*ep0{TmHA>DQ}yE< z)$jetla5bN_apIvyzi{j5X%2Pe8kt*)n||?y#=B4b{54F;%G%R6EYbiQVbtJltRwD zH$WNo3u@R|AubiM>^Ay0y82bX!Z9BfcYO8)x%>Fs&XV$$qRuR6?>R-`w`g^`MmrRB z%$obT%A#s-QR+^4?C$+81%h;uKhlq;7B1`$1T!7F?UA0E!eTw|4j}#>1sM7kJdX;)pcj?dV z`lACXYN5n^1;m>ATz`S13xGVec|%pWTJif)E?Bt>tU#d-wUyGm)acW;1(wgr#(7Rk zzqIGqdH+kr;m4!#PzTY(HIwUAwMLT@KT z#whRxfpocmqjRfhCHcKANd{7BqWMbcAAPYZSSI;<0;vIH_azO1 z#O&7c#>crS;>#RNPW^)q?C;^~xAeZE|Hu@+Q>rMYl-*$N{34P{bY_(|l8 zL6$y)an35A-Qv}!yw(Z5f0;)2bkFP8qaT&u(7n&)_K?jg!H#-6l0jHq&mj)B_d zW`nFAPCu177^h6P5LciI|3S+ANocdz=*@<62~ilsT5gfOoOMu5Z0X$2(vkJC4eJ*U z+aS_(@KC-bL;GIPkLNl|qp@Kdg&rJQPWrHlXyVe%1rV3!{4En6O-0d(^EYp7f48M4 zRW}sBt;8z3P5V$1L$k(m3*&h9I<`6i1#}iRmVGiUmtcAvgu!&5`q(kpOAp10YnIX> z)x*(A4`jiPnyp`UlyjVZ)k#I3OfM9`p6V8z3N$M)-KUIEK*U4Jq*lJFDxz%V^^~IDmJ5qCvQab#4QY@1(1T3e8q^SjTA`kDEe-b0Us5zW z@v(|Xc2M!r)A33rUPNMjXjV(LAJ+XxWQR4>_J8#3zc{pCHE2s7rDOOU;vZFq`tsm> zjUhsHTl+DB>xUL{fd_p+U_l=Z>@-Aln^di|@mgK3s#_~^^pXs}w>2uKs5_0AFK9j! z9z|<1T8+_{wa%i$+*;?-ZIB0<@L@!+MOfUBL((B6rT>l%I$b71v^8+$+70v|n?%dK zzBnQ!amLltqsXw~@sQM$1h)h@^(K+$6lF+1=CDdY{#}=`e zIiPeom!tWoZjqVST3hIDA6Rwgmqr$nTltsL300Bhjz^(b!Q8~gTk?qg_1aKNb(74A z!{yl2UQEG8(s|U2`fj1VX#8mN&}+iacQ#caD0fwRiP6==G3GV#lwBFbp0jB4>!>RJ z{J2)D^Ez9`YQTXiy4jU9c{tS|wVA`-}^9LEL!%@9)gL z@7~0=l|#PA@|L4XU?2CbLMO_7edDftW_)H?;7Bg((m!?7-YkCV`7Xv+MA%1*U#CQ%=E3hiPEz7R8#wVVvb$kl0x8pEDjKLN$GC$I1SguCFaC#&z zTkD*k)s^ufg&Iz7EWU#He|oUJd3BqG4CK;}ZW|N}WGF%p7VYBHO})4IBbw=tXu3UJ z_@YMqbG?g&;9Q}0f>3+3ww5alipD~H+D1cYP&Mopd6xEXwh?nuzcngZr5Yr-{KN$n z*vwY}B_G47;!CGf3y+L3A??(AK+W_0Fvb#VxqvVGKs(;hzT4w5khqhTxcrM`5K;EzXCqEOfHUpXL|n(h*eST{I&Hawi-Nfw7^+KS@SMP%ejw2tYWX^B&f8lKb%d zKK=E`E8fn1kS0&26PVAg_et#Ntp-|#9=j=vnsW~~@HGIU>nZr0w>zLIcY)V}1sVt= zx`!WdMlWX+8mlWN_eMYWy~+?LaV#Zce=7n;@qqYe6C&@mnZ-)9!N}hHH7tRFYkPfZ4mI^P3;stj!O7|Lit<@~KHZ`?$q{nQf%5UK^I1SWG7} z5U4Y-AG6T}AJ@==is3)bGl?(fgGTHNb|?g&QQaV5drdhly&tfL10>cmwy>91laLW+ zjtL(SUIU#&2^|wFTlT((%DPo48GZR-HtXh}i4Hg)5C0NF(fw!&o{0Zd7PIJy)S31L zi&EcirN^B^U3pKuynU*d01uI-BgL;+bHaf3`dp2#m4wVLLWiVPseFuS#X_o)lnG-6 z8U`DeVOq=qQK3e>eWDIk)Phe;zV;6CFH<_>LAS@-lRf^8iZn8>yc@pZBXcVC5_giu zKEY4B>Bhh3=s%>*F?}NAM8P0@?X8^Um|%JqRv?b#_6I5RwbxFFoT0^Jh_ht{xc-(P za9c{2{8CroBsIC8Kj0>JY#5$h=|6G0?1u0?c3;S}k@XLm)}85-=tI0`BzhSg2AI~J zEs~Kdk&S;}&uP+@VYz9%PqUh-kc4dJpn~1zh=NGov22{$JgW*=pyry-GJrcy44URU zIqK10_mRfILK&>FEE)Y11&NbMyK8|ie>lL-M?FK>DWdnpD|!nn|8#*8_qps}VDK6! zM7#EWni@em9iW?x?gHMisJYIDtFzU5BmQW|jy}s{e&_IJ2j4*;eiW2>hxYQ@^akq} z9P;0XiND@VwUlh7A7S~bRclH|$Ic~e<)VB(%yl$Z(@D7Ds?tepifpXa94)OP*BxKz z$8ETZz302DuH;WPhD$=CuF4(p9s8KbD{0t z_I`ZgCJ^8O6mzy~J!>Y!jG!kiOkFKf#km4H@Zc4KsFd>a$r<^v_imw>MXTJm`ff{+p5*26#~2!0=x>5a*=dLBJqwX^;sK>PZ~xm zrKwGTNY-Jj@{ZTwblY)bl>?^wWz6tTIVg6s;|}*O+urcDemt?!7cDEEH{^Jk;;%b;?5z zT>4GRL!~x~b;v_wF6b-|l`E&E_jdLO%R^P|>y(G0RCe;v-{xh?L)*h;I?F?cQztAB zT|7lSx~{wj{{9`yLyzC>w#;1)NpIm-gyf-{DEH-|hr~tQ*3wMww<`~oZ@hh=`>aPE zIviM1TWQk)0QsHELsS3kIGR1-XwR3Wkr|eUCQ;9qhZ6h@%R{e`ww-MPOWw&t&wuf1 zS{^Ebsce`$bl;4WJoNUT+~f`q!_$pCRLA<4JanNi56$5{BhgJOS!d8B0i=3-xpD{@37mq9uUvyux=olL;0_?@=-}Rau zY24dqTu4XPP>?u^w3Ch|%?og~^z#s|xG^Ow@eH*FJ}#CSi*J^gFJ|Xxcja8#IGA); zEZP+Gr^KSY)ysQ&BU3E;C2xkrq5*69zKq)R3iS)I=*fd57F|KLZuCRh9XjcUWn`fd zozfzHI90Z`M%&GNjVZcQDd%5pKHmXZ~9j&W*BwXeu{Q=fuqG+%3GCFn;5=$-db-N0=$ zJChG_quY7`uAOR9FbfPLa|)$-nL=62j}Y|Ey&(DR316plq@K840BHV_(MRqCMon3y z>2c=5O&fpxxJrNC5DL_pgaqyXCN*TaA5KC5+?22Ygl+18<)%6*@N=z&H2C={WbW0n zX}}r>O*`zH-uC<-v0~rTL#ooV{G0%*>OVxR3a_HV3NPjj6BzEGv|`$jLh{;$Y`1cL zNv^cQJSM&XgZHlS%ECd+|3JZ7!@G*KskP^|PL@I{yGm)KG6XWGsz@+1fegXyHh*BP zREou&3uE~7Ns^}AsP!h+=Q;wC$Z4m#a*)SGW034bi}G1YK58{axWIT;>}6$j+CXlj zkCZHR{G-X}1cno4!6%S57W@S@MKCSB?_2XK3mdC%S?(V6aX(W^M`tWdq1Bh>&smde zS?yNtTYuU}fNfu*W0`QL;C7dtZPxK4=Q#BL;lMQdue=17W#}JHX=19ez23#%t9JkU z2S6eklf}^1E?$u$?}0<@ju|jk-av$Fquh>w&IAo)f(9``yD~uqTA&u?E116Gy4AZD z%W5-><#Rf1Xj#}yleWnu-2mDkbthgMIyCp9Tglg&UYllUsVEt(xWjFk_Jj^^Iv|9I z$?)F9`x?KiyaScp;1#3tsWkFF6MT(ai>-dISPOw`be#BxF`h>OcP380|O)1RF z(>udce*o>o%UKg_ z6rX+UHj3YuYNI%XN?%2P{)FY%(nWtJH&cIBHD7-oOb<|0O3S?gVgvy96zV_2=qr+m5{T=dNERexSB%9Jvn|71viPUUW-+?4)2?-tg4NPpfO z+=lh%&sE+W){3ox3+q_p3t#j}L4 zv}CfW?V?SPVq?=56&!~p7|&NSTB>3=SuVUj4?E=!@iAM;Ub$5)K4x<#^}6~Y4wIpu zPlq|112l&d0~NZK(D^`*>0qY``9QC9!$?Noy;J!Legf6hDVT7!T2uB=T33`eEZ780JiLe%<< z#|FDe6^AvdiM=ulXOjeps#p^~()W7;bpX96!|ze>1wGa89cyvBSr<=fSAT5B{=uLX zN2Oue%xV8t0{@nc925+l9XQ>Z1e`Y9u8zyJsGs2!Jy$Y=e>OsXhpRwEsvjki(N}5S z3_36TKGhG3lZo>ty64N1Sfy@@^sB~~79>tVT!{G2^I_BV3)(>Q7vg&;lt~jIvtv~R zvtx}cVYTv&v?&{bZ>c>wL&Q^(K!cvNw@OcQbUOO*j#y1hf$!`59b2$@9wUvrgAWv$ zT^T}xi`w|zZySfLO_=v7%vnXtdA`Hbk%K>NuK{N;ZIMQ8@^WSgT0t$ubi&enUN9l~ zuHOY%YJ3Ugnrk)E6rn4O%OhK z-NX}6GG7tu4f_b7Nx|5(#9HxDq^FGm ziW40%-Q8j5Ee}#>`f^dEjgPDVJ+u|5k~wt%Ovpg z1=y-TK*VH3^wlucQJI={(>>yEdH*v+K*HMSisvfv9(JD?rEJNxTA`6Q6b>op>n&x2&J_-gZsr}D1f!fW!NVq-xHe&{#nMx=RyANt+E52Rkc z|41d{hnLt7cJ!t81gB-N=-Sj=aEa*RgRRT)gueAGkO8A-mL|y}|(vPy4w$ksA^Y z_?aPpJR^!&xBM|*#a~DMQ1F$A$z%_scVF;W{d%V0v2}psdK*tC!9z_PSAIhIiN_Op z^|4kp=ht8KjxBYOSN?a~C2sU%P1#)SO*?!vFRuchq}Q;|mS$Ljl|4L*wc5zV?F(rW z9``WyI+`q$%Ge_2hg_2p6uzXMY9u=5`a8{e)JFHH$*$i+>l>FH>m(dRHBQdXvAE-K zOW_tq9q-t~oa?e{u*L;B?cs+RWCI1FJ%I@F%jXVrZN>#M{1wX=SSG_C&8gn+T3r(0XBizjYS>jW^lI5|4 z^m8HkVfwj{{x+O`_NVqYL_Z$_h|O)sul_6gnMXUF=;tP~jDA{!K9_k7OQy8Y7J*`pkRckbZeh%wM)6d9Xh<-}+cFWL9-Z1+4$GIu`DWo7xKPzTB z`q^*yfPO;!4PJqK!+QG?7WV=(^Oabf+9!()QPrInyg$sMfvLA^J{7-CQ zTV8D7(%8bq1+nZWV%dvh3m5i@4SbgTXl&slytyhiaBb|8_mk?6*Lh1X`)}$s-sVlc z#@qgzyrq}_>-y=o1rJv(Scgx?2GY}uv1x19#+J0fNRqM0AzXNaXD1zvJ8eJ^GoZldRaQ8*igBnb8&f1TitD}AoqJ};pVP6T%zg~-)y;Ht*eVWr8?`nhH z1!cQriC%*qb&#*lF{{`}jX#&dtrp(O7E^Y||D4-#r$T{RnY(4bDwvn^bGU%V*>>edQHlZTg zJOl$VhO3b2p<@y>k%Vq(q!#9$>D{ikLIB?M+OiV(hu+7HlX-WW3XmE*x zL4HVN=!EaR0Ydm*AXuAoe!Dt^?_ZHHeBbuV_2Bzdy_Uka9clE&JeGm-do!T=hEYCI z1QtU1GxE-XW}*C!7t<(T`L4K7G=H$6{HVvfL-|P9nU8X~*nf?3fB&2Ib~Q|9+9w;I z6DyBD9l7_6yjXmtgr8ZvuzAUCBhHW;Y5c3r`>WT$iJME7Tz<_|`&lGf-62nn%uBEGGn6IjR36F29_Nd!|zub8;kohS)@XWmWEg967G?UmZ z$a$BXHME!5ikz@}cTcK8x1H$q!gn(0b?pZsdi{ii(d(M4*F&#M^jex;(PXo{-~aXd zqt~6A)Aah;b7^|r|81k!iKRxbH!tpvUT?VW8>QDVwijN6Wcw2u&g9s~Jt}>}-z!^s z5BxXqG!I$`r5&W7Cl9$Kmi-KR=`Xr_(dR)HZ)m4EqzyP5rf3qz1-CBgcP5x%W{46c z!*{AzpI}aP)O`eM<9lMmp%Vg`qIF=C(q$v!m{k?c7h!#U1h8wCqT zht4B68C`r8URIYIY1~>WgE*}KndrT=g%d9cti^(ZicvS!3RnlcrJt~wl4bwWFYiTD zO+tK}Yywi_|EP#R&$$D?bFL2~(D8M`@4c#@LMQ4I{spr3lz5TqI$sJ&k+233V^C_e zc?E$S8>PZ7++ON5wQ#7?w5Xp#1Sdh}S;DJ& z384AAS_vF$Qo9SnUzh{k+wa%x=q?=1h|6)se z7V0Nl=jhWMyDZYJSt|GDR2i=<@_8l9#?Gsbm9t(ShOebA zS~+;=!80z%s@vSGXS18N=daP^ih4%DA5p3=DnS3E1ogT=1XSd`%{eEoALg?aF1q1U z8ibDeLq>a{CvA^ZhQ>qit*8r^K1)uAo65wPVlw7(lA*4!hF~5GrN*J5xP?4g37_C9 z@Y9mvRbK3;Tm7`TZXocvqy=&n&M~?t-cpPD?lTS zzf;q$KY$N9jj`PI9`_+o-GT!>lKk*5)7ttmEqPVZz62x7rk)L3udcFJe|wpR_K?kL zGU~w)loG`zqh}iwV^PCd9Y%1h4%b|Y(L|cA!Gn-k=3EoSP{vj2PY1G&Q)8^ynVO3D zTHGKEFBvUVs|Xg#W^58vV=Y1hLWT0Y2MO(W*v=fX^2%bcf_A+^!koYwvPjmQYPNXJ znp7klk#30>*p^&m?%$`YtKQH24M7&Ak(TUb;^_DsR7N1PTVK3g{udzPrM-93^;YPM zc_ca6^@g^qcKzmG;%vImEVfeF#^T*~*_J?sIO@m^j;Z@vlaZ!_sp@u>K~0J-m0vNK z#!utIzRlDz_A{8IPpGPDT6*|V{W3R6PbmdD#rU(_g^l`2ymBK2LaY;?y*Fk#*|`|m znay*sWOFv9O6{AR!4p%d0e+E;W0Q^(+5w@`^Z}v2ek##bcBzDCKkYvMHtX^LVDSUY za6Vl#J(YqQN*IHSQxDG*o0`RGyld~1Ow zf!QhMsecF&zxat0A_^4CtnzXTn)F_CqC`P<{U8g9EwZ54QroE|OjHNLgu=qz$<{!e zc%cU^H_x%wV$Bz#eGLcSc316t9fi~aVx+x6#-5<#S(0hqJASri# zw&2cQRA)QKk5iCU$5A(b*Fkp@H9!M-Y8p0Ir7}!9kUShk_CpFqa<;^ZMG(O$R(HB6 zaXf{rl&R{{4&okZ!08|^h9FKj{_f`}^5SQ#!>n>$4-O@~a0#fHwiciCvwELSZDr1- ziuO*?vO-AOc#4`Ch#$OzS9Rb%sd&o*8W^;Z>age(bIJd%L6^*9DC#oN+g`8*_glbV zVW^pdn4fi!12NL=03uOB{186l_^UA-fh>8#o*-)#X-P0`dV)uA>=cnSn)%$HU#Z=% z#HGoc6Bb{xHid9Q)13{PXl7UH^X()i5M-AfNgwIB!gf4eSuu@L|8&f7UN_lW-=?Uj>{Xb`YD5U(=8;m`hXg8**Bi#5!CFm4($7;Vj@R!nr2qUk^~=?etta zWadwdA{o7wZo)Ra8S1vF%?1-`6n}+I?|stoWO(rpc`Gxf+4^xO6oZ&%QEBQ#yAVB} z42Nax=oLS90nL|O?C|u@-f28txeN|$Yv&wF6VDmzhGv4;TW1~+UkOWja<30l{rgm3 zbX%g-!}fOc2!>RdqDz9-Aok-aH}=b7?8WH(t3dvfjP@|RBZ_E)s0lRBszCEZj2>2C z^rzD(8K#rOiLx6sM_;qHLtz-JE=qTHgSNL8?t29x)@d^O3)N>zzj}|Nw!t(mYP)80 zxTuUZ`x*jvAUp9i2ngFWkD(_Qn5^!T(eqSkr3EH~vuveqFbqE0aR3I84)h345WeS~ z_cy{32V(!Y5J)X68GVr7!EWLmO$8{~8_iRDWUe<{zt|Su-b{v*JE`mx&G32OtC+^_ zttO2wxF}>e@l}nG?WEDgw1>i~!3%?15Y>eB&Fk|x;I*8K`NZCM2_BSwBhs`~jln=>>d9hcw>DRP#<5=1u=K%O zR&q5FaO2_D*hrAu(%u}s89st4dMJ|&WUT|1$wDYr)!vVvk!i%2j+&j`=E&4-4~|mZ zZXjY6U(*`ow;B5Uwdi}TGzY1rgvqN57B+hfEKFNWGdZ_CrG;eCCx^m`;psE%lQ?{&pJ+WnlX2`hlYg1SURn}J*Y<#iUXW0)?36$LP zB!h}~!N#3rJ8aw|>S)QiSs7t$3}Gpzu@PxB_nJkPW{z#V)yo`Pq)~U8+FXgR#SGz) zh76YD0syxMKxOR7{7FxdDQH-RDJb!=ixqn9Z@@-7#kAuMxsh0*;bH>Vfx`v6s^9?n z^}Xe=-1+D8B5OQ1H}ICb^ZfFtwrbqijao)PbmDC-BW%k;KQmgIWo=t*o0bCm7iO89 z>y&FzZF}0Fa$1zp%rO|2piNFsn3P#)kddmhxQ`@7MZ?OvS%4u+v(ddfMrP4DEhfvb zB$=KORY+cdSra3d&4%Sj?yAFGZmq-?3<0ccEy)HA4FbPbncHjP3MA(4!s$Hp$4^idD7aJ+L-b_A zvN79;YFnQ#`nkK2+m(N}GDq%sqI9oZfC<|MH$BFQ^-NwR8^Se1%rKbe8wSJf0A%@C zAj=0=I0cftBBq3{+(QSh4$Oi@V8S;Gwg4c9mqsCb6<84ER6z{25GnqyxBOC8_`RTH z2x9HdK+BfiM*;8gYYS%sEr#x!1T@(uVi#z`(AFqQDpsP+Pq6K$tvUz;{=qVnyh#{; zB~hyq2}CJlA!$iNN?)b6NEeWv&dDZ{`k2UVJoS-Rfu!t~I2Xc3qItuI<3AL~g5F(Sxa zD>`pW;Dt;jUgR6I-d!|VfNQ0dG4vGI(V(Pi*`Oes`J_8`Fq)rUCz^LeW0Url_t9r2 zka2GVyanotH2oH4pHP@QtJ^r~K9raMmnOcI=Qt*?|3<-b&-4dKhH?U1%4N#JuK^PJ zFZmUBISSo@?-WIi@1K=_E#K(@^dtKrqkLFvV=jZ+_ zIXrS-;UO^n*A~5+jNI2VHUaLwajd!IW<$Nk947$sMx`{7kl9yrfF4SRPetx~cH!%} zmpqaM5YuCM!>3Q~Q#O6#mJ^ng^&NTW;6 zh*uSK@}X+7Qe=1hqhceq#yPgtENfXXXZ!sH-A5Bu8Atc&MTwS1o|Z;|mInTtadI6r z7H&jy@&s&Y&ua^Hv_f~^?ZY!sB55hr!Tht+9V}ZA?%)SHZquH}Tj1BcM_ZIrV_TmO{$U6HNt_%8R__y_4Tc{iHG=f`rCeERQF8;6E*nHMS z?>NDPH*mO%uB(Ky+DK}ztMYCwf#_XEcKwi)VFB558FeIkdiI>$w!SJ^ zT57>U(1|t!r3e1q`{VW7QD?S)tMMG?BWiXZCJZ2mH2#5>xOmnipjc$MXY2pSS_z0E z1I$wSI>uQbkrK9u!9hllHcbG8kSC+#TqSrKtD~?+@IdO-l5=WJlC=|3A`d)wO*9^9 zj3_}Dlhcsb6;1~1)z_uL*0GkQphNaLp@-eCjR&v4z+cIC?MktMuF(@x6bn?^kVv|f zv{++C6t@`YSQTC8)X@}W)<{G8uA{abZ?nqk-70&qDE=DzjBkE3;G<_RbUjlQ)N z4;W+7rg@b;@qp>s{mf~!!jqSLggDfEewkc`UAkic*N$~Wxi8k{qB59^#b;>6uqWAs zXf68@|rZ=Hio8u0z+T*h_$#KN>XgCY^-`g4%;>= zNp#5HGpUOrRX168oR*nNL}kiKiyXHZl*a5#4vk<5H zs#C71o^C_QobrIjjej6C<(pEGdu$m=2&rjCCljKf(|1#X?lwz9bvzSQW-PI*^=yWB zBxGJNMEjEk7A|V~Dui9t1yGaQe5xPwrZox^<(O_fPk8+b;BaQmL zfH)}jwJLHGPbuA;Q}@H5Z3%=}^G_$k+TJMC_Cc=g`Xkf=?Y?@d-)`Lrew&|@(=n9> zKNt`+XwpJU$y;PtgMXq*0PH&=6)tJ#O#86h#XXW8b$-i@LCcY*@nY27Nv|;V2B7a0 zwu3b%a~Q~I82XJ^}V%L_c-4D7QRz9oD=3=1dU|09-;a|pd`~=SJ@~#}uch$Kd94Z8WFY%H zJ+HMT?(u+`?B@R#vNxS?$o?$Hkp0|e-64AmIH!;7Z|A($EB9s4_ix)m`2H0M!}ppK z*Msj<^;!zw_e*T{KJa%m|A^dodS2_s>NLvl_J0fI*WYU>pWf3@Uh`>pD8J$46w1E| z{{0=E2OanaNp$~@g~Wfw^Pum{%b@oK4~OXeeiBCSxyP@E-Y?T@X?o8Qz4y2>gT;KO z^nMqg*a}$8qyBHv`>l5yz0b@xdawPsJ9@vP<{PE=^`1{$iA}%D`NV^clM}UM_i-{g zAa?#->GVBQ34P!M|1`Pb*rvIp!{-wx+{ysI^7+I+@9U7)<$U6=3<%t+Ykn+fGESu5 zGiNPbZP59|vuP&td}6h7I-gH$CKLNoCwXt^pEKxnz=I)r?N7q!wHo-oT)uuFgI;@y zUdPP%{^&J%WSU<4%FBeTEqeWUuFY@pxM>*f!9TETQTF3q);Jr0EH& zb@2jK9xYy_a1`eNBKlZfApCyvkmLWj%B(61kVv^6f)hK=1yRvF8oie;2CnwbsLnSK za0ub(QU8LYV%q1N=aNaghQ_?a?Q4@|oZ@&1?AcKy`8$ZWvC(icDH*+043v?$X6*I8 zL1Vm$55>NtD#w?+get1#Igpqr0?lq`NXF*RC(mNOmn5UJl*z|?;!Er^$Hc#r!S|bN zrqQu=VrsHL6f$*!sfLgE;S}Y-$EbKB8QlSp3`F8J^$wm4t7#F_f3)mjxnmkIHCYSe60xUdRHnAdLjSoVS) zt;mlk!7kv)#*a%NZR7+H?ycDtks>ciuC+49HBGC|HD#cc+!5Dmc3+t=#~Awbf zEy-eaFsRL?DY?U1?K#7Di!pA}i31d7p!rNj-xy=p%0PdOPpRscQa+y?V(6I>d5{5d z5yVOeRRt-s%<>zvD~bbDVf}K0Hb)aRlx|l|f;Q}pq8Tn62U=dL{Ql0(S$0nkIp%gJ z%22OX`LCAo6ouAS9w0nYLI(`=F?;;& zEJxktC~{Dope=ZSX;bF_V?Yo=;((mxe0j{AT$l1yx7yQ%vdCB6rnCmb+7X$_KVw1Q ze!AUH%gd(nRirf&tWXi(PB%N^BOJmG=r~&;2eP|674BS=@so2?SDc97g&lQjI2j#y zBqTXjwyT!jhwdq!=dP=iv8Z++H|md4-1|8qrp**u<_KftQ5b;xvJQ{X!hF>3LGIWl z2u?X(xl{zpf6&Seu>8lH*P4C&m&;`zKZaU99}gaiFNUXoP{EO==Ama;;~$qN|AA4` z{Uy$s%!>F4xfM&a(K0QoTnt@T{;u_+AVx0#5-_FSoujve+td+j-#oQ2CW@?rxt3bdh&_a6+$<~xuKRN?fc;%H^DX}WW}P5qJ=Q|wKjARy1U*Kt*L32!Nk zW0GR}$I}nLs)T~acuf;o>K*la7X+*vSq6;``u8lGbSvA3xhQQ|wwA%diA-4~^G`~YIwg^tlSAfwdZWOUwW zW%^g5ISIceL{85CtAJR!(tQ}=D0UAD^Ch{#!8`4390w&I6+2ib3)bAzdU)gd=Ar*A zQbf_$mK?Uwv^Nj3o1luk?f&edq&RK>r?sf3wID1NB?TDnh@n?}muk*)WYg?ExoP!F zY0$-90lhZ30@K2>z(qyN(Rm77FDQ?Dr)8g(?QOSvzKzIUsUKzGj;fig ztF{m#u@9xwaRe7HJVVc&M2nij7d6#T4z^;I@|pQIul2-&Ze%v zv*CpUbY|cn9qb;h&%2(G_%w*`V<6jAx^;5eOTH_{_*?q^lVw^ZY33I5299*htxAlF z!)M4qtld~v-57Bp0)5Cpq>1%(2aUiHq*7PN_j-S;T}4T)cQKA&0!)k)Z()^*Au%Pk zt90-=Y4(J_h+yJN!fTu>W)b0z9_eD8(V>G_XMrp3qbor=@dfwJ4|qp>Vah+lChUB8bV`Y9E+fO(A-^Xl$< zDnZ=xe3a%&){a^czKTRs#llyS;-AiP`*5i?1~wCR0#MEQ+@^a_ZesCqd}2Ekuf->r zXaC5UPx3iQ6SfZ^O^EADst|4z0M*V@OkZhwqJ z{*uot{>L-q zeM;&Lsc6?i%F^;d-pYV(%w?_X!&f10F3HU-w1 zu5K8jH^d6j(`nl(8#MODP5Q1-M*Z!m4RR<`kgD=@0V10GgJ z7as5o%QVdc>V|v;!s)dB30YyH+L#4oeBub<%ISF3e*zRrx>mI2Nm$WJ7rAJ@Y>A`= z^nl&CD=t)NjbDlLrJOR(qP5hDPDV!#x8)q8abZ0fodQiLrCCcx_o7(m^EC}w^;@Vw z6UKc{Dj-#DsT@)!d3-*MY=*LwZ10$vYm@G}9D!h8Qvw{VGn58fbu2>khC#9vA>I4j zlg$|xD)qB~syf3}C8ecCGgzRq^!+k@F@>n&Dpf3Uv8pxrui5mYn3ZnhW;BFo{m5 zcjk}TOp|D&=~y$Nq)5#hi%UaxJ>wBfju95PsNro9ng}dSiB}n*d&7}pRx;0qg!Bh3#Ihgx-xDxWK& zMnftRyJ}M%^_P9VOI?FR2q6a~!RLv!>Tt zpzjyS==SOgT1FsC`l>odqHXohEz@+Omn5U_XgQ@8C8MVTTjKPOl{IwFtEn3xaJN%9{Mou1=B~r_rD_Ho zKuF>-DehlIi`IOihr-cXhVJgSA+GJcKAtvetiPe}{=zkG1&>qUUVGC;S6e5~f%lG` zOwv!*mD&&kyq6wKQ9p__jF)F{Ha$OmD0NpA!kHfJ*g`ej^o(Y`rl%*1DrsKXR|Sq& zt~`i$iS)BeQyjy5URkMcbS(}l7!RFKO2{)F+V>h~nfmNWS*9MQsH;6`GI-$1No-RS zBK{ZO#5qG6$Va{a)$@NX^Z?E2v*kIdvZKRR8^hX+B6pghv&gi`(- zUGzbDV)fbc!5qs}LMydYPfkcR z-bovk)Di@?q_^aCdN{L}{v3|-pLdK-Pn?KFdzLM5$s<*~&Sr)R;(j<=wWt_jqU4Mj zPU2B#59qcZ?#D5pv?!5RFz$?om$Sbxsu8ACmgyH8<(X*uHa?EMrp9Q)+HNSs+yUb? zrKWibOgCpmPhX)qmtOy=L`&~K+ry#U;@iBL6Gf27X+Q!`72dPzMv9fT^2dr1;d3J~x-p@1%rV#DI;@3g#(Y`Wt zEaj#QJxe<&qQJDq*VPR^0j3TGr?V^SUOs`=N{*zhO{`Bh1n%oqgD!!>G9A>cpOzxn z8PJ^;Y{{Ro;3#&|a;xZCpz}EC-gPlrpFJLC4 z+X7BlCFw)jRFZ!g)V&wWBjHq%T^J84$tFx!->r0eh(4&upT|;P)oh?f=ErVP+Rn^r z`TNUB10atn82FCVk^_VzM3{mAr4k_uIO$5<*9pVHtdAnLpG#>}=nNw|89j+ngu@Ds zC2eqz0PYHWOf5OvUZQWy9-39Lolh#v({8eL#ln?6Mz#zJY)n{0 zjz7>aPO$@_kAE3L!Je(GwgWCeNDL0!xOL)gv_LX%70%H1=JJ%p*Pti)S|w6~v^rF| zHqzIZVg#mk8V$&sIz#3?s7pI?HEY_|eJr)^#n=3GZ`^H!GbmNW&&aKaZ;UOU0By0^ zkmQ!eABJX`rYAOPpK@>q>!JSe|7LyrsQw{LOH2Jl+x`suJBW{o%QlzFq?H(hc{{x0 zF9Mex4BslRq)wtWB@^U<5bkB7Mr1SY2N20rb|slTc&TF$GuO4@#SRJq-toCTh- zrByaxgg@z`{A4uAN>B?;ZS^~Fzc}|AL(Z}0o`v$6scoQyuL zC8WK-F8AP&mW(jr<~+_MlH z(vv)8~i@Mqgq7<@HMCndoFWt|O%=e9g;d2e&>)x@WoaZE$ zuqXc}xO|x%i)3~*f2RY>?-}qMSQlxHyNj46EleDh@}s!>jM+vp)iV{6c;$y-?GHWb zLT$Xgf0%bRdwNdwHV7Z_*B9&w+{x&HkbpVt46l&S_CDs$2a};E>ama7G2(otLs6V=cpSftjlW_<)aH9+ADSugFIFWEmmo z^dmLH7grlk0tmgzPcm+RsBatvO<{ zEZXbyAFaApH8=_X{^#GW z|L8%#Gx?8BJU#3`x}6fqOq16g`SVr%N25cXt!xPUkA|$jv-S9oUK$A2Sl)ZIg_d{b zc~%d!SIFSS=OklG?RM5k(@SO!F~#|9y}^FZRh$@d zB*)bCmO-+#d|uB)#Eg1Y@5yw%@vdGhKFidKy1te15A2mu@fCXOF%%q=vHUroUD##} zEuL;-lHV21jt>M}sV#n9=33=My%Z#Ef~7VZVutuVNWVoxTp!0Ch0#J?6pV^{qjYn^ zp|ElrhK*o5gGl2Ex1H#th8-QQ@P7ZvHuAZS*G1KzBWsGM^BOM%cU5l&L&Bv7tiny& zjtbY3*$qj1Deovztwg(@z@hHD{f*X0XzP)5GhH=E=lN;r4N4dI>D&CY)Ud>O=15q@ zm7-AtL4mBmWt4d<*JQ%p!i(zwoS767${ct7E&#t?+JgbEd7CHlbMuB|<31ti?f$P*&n zw3o>mJ-HlH+IEpIZ9K^+ByEh9tmc-P*U%?5ZqcEv5B)T`8aL5-$>{Za|L+Vvh6tMP zjhdo+caVH%?S(2ZuScxe-8h5%Plj=uhinaDzb6BBqxaC#<}nmiZewDT(OXDq@gcE6 z!(Oq<9JjNK4(niL<$`T-3jf}BaSJ3ojPy8lq<^aLZ1*9Er z-clqEF$6fS#<4l^jxh*yHe(p1jX{t$hCx~kLOPuoh9v7&%{p3ik@xULzHF^5ldb2f zF8#LIbCwy)Ot!972EuEDJ!hF~N0yw!?AmuL1#Bzj^{c3b>US8zL7&5m_;ZYtuPfrc z^jUyQ7HKa^$=3vQ#AlnTsg;BZz>NH4PhnBwUA)n}Az}wLyrrrWc}i4y%ti$Lc|9U2 z;`75~8o%%hS#&$nShpN6#qp6Mze~2KX{crp-kujjfzADP*u&A222`GWKA=N>q9N*U zbH8#!2-N47x4Eh&?$@&%Azy7g7I>MLU}r|!Pc6@ud9J%T!=$W0b-4bE2=e^BaKy-A z08W_M5HzUHM7<#5bPK8Hc{Yrr`mc8wQ*5N&593bOkqu*>Z>eTUCGJPTX84~Lt+(l& zzoh9gTCiH3N9u>MEFlZN$uC?5x-B~ECP`?<}x^CT7!EJI4k0Z=`QcB zL4HR>vCPJ0R@P(lj*{#^VOWxy`r-=>XS=L_U?U8zU2xWMW~z%ub%9af!`&@J$5zl| z{O;&sRRXSdPdKZLL13>)XBlUE32;(xiN?4mCCD;b+XO~vn9Ma6ne^u0a~5Ld63hD# zBE`(?&Gz$zXzx_xvPthsGEDI=Q^VG`$-6epQ}lk!!*G`S7z)Yjpyv0Q3?c_?Ko-k z9Mk0GS5a315Rt}rkj29BKxTKpdN*MP6wBv|YGa%qf4c-iZ0`t!bRoMzK|18e+22)I zCAfgER8QbD2I!+g@F@*^qc#M-ru%?aZr3&;1VPgwCLNz{2xGr!pjhA9)?I+s0ESxYn-TJK2O=B=aVBDqBAtowiOipB1zpVr85Z=AtHTgS@}i+e zyZ1zu$CSf+RrZ|ig0vtFb&-sI&MFh`U^rMc)09Pw9#_%v{j1>M!h>4sEyyOx=rZ0B zv9;1Os)xHMQKu`)BG>-ad3J_Rufr0;REp+JW*0RIR1j4+NsKzLvZa<-=AnPyRc1qO zsESo2pQ<~8&nC3<86Iyj+a^KHx#qFMHbefJ7?#Vv70vr~Ej#xyzR~%`dH3s;c~o5* zyw-6G4pe{yoVxsqg>T4C{)WY3#$bV%VfLkajjM+5%EL~E7kpH<`jxVVr+Snx071kc zCG{N$=37(a)w7+XCVwIcKD3^!JFN^Wb}O~D0yJWY0vfDh;IsrYuG8XbEfKO>$0&3| z4!nacYbi-e+Ig@_DItV__0!64@2>joeB;m7oK`#wh>hVb`+%8z%S zr~YpilaNxtVj6H(u$bH(HG9y#ctb(wfM?uvS*!%fVyhUOmQ=ev863~Vwu%};sdq$l z4eLW2!^^vf04956qsuG5Vg?Gtw zI*rm0Pu~E0;sLs{R=~OV?mbp~O?zTFJu^R<_QdB4I?dIzMKv1`-)-M<>(62d?Kasy zoOT{8&%5+ZgY#=gb>}cQ(h9NTYEK;2m}AM1S?)tSTeCJ^9g$!RKQ)fT^S=bnN7bWZItQ%vT1yR^%2)PG(C#|;S-f!k~ zl6bx(o;!PouNlw1ruJ*bbH68==`No8=R1D&cNXFGcL?-$x>N{HUKC1LcQyX|`DedYOKdMD0g#i$Ho|4#20I+A#g zfVph(<212fewGpYgAW<8*V@%@otev>JEVyH+qqxpcz_7;mj#nU_`aWn;d|yb>%sSB zdM(Xg5Noo$b1E}X{+-^pvK;?u4@HENU7F{s5)B+;6jt+;AY;QqmTPHjfD) ztmEf38afwdl;tW2O;#2=cWN;X96T-3!ie#sn5QAE6oKRKZ!5wB+cgDMQfWE!mzRyg zf4>2dOh)tVN5=g&FPyTLt~Tg?o2z*{^M0Gj%ISQ+%^hT-2Zrwd$Y*q4cK^qJPGPw2 z{*Nst@H2J)N8j#V^mWV(d*NeHZs?Qn7_h*QYyhpo6#t~nIW52B?lqtZJ-2~u*$!3J zyYnArJ5*kF{XrI8Ii24!9?rDqwPt3J@lfW4u<_8sih|RF+-1r96B0+GvPJ0hPSBaG z3rb_1yXydFJyaj*kib-6TLanIk;V&K*)2urP;$w#5l{hBQ$=3dqWA+wu2AL9CPf>S5UXM8 z+>{I=HTLw+RfTMd;n~utg%&T5MUeQHVixdw7KKsH0nUHtxwXsz&M(Ef^&DV50B0%9 z8+`2=9#|JaN=;9l*u0Gl;+9H0Xq~vFx{DcqkrFMvv+dz1RSM2F-hG4R+X6<}7ezdT z&@}MKsv9eF-&OpQ1xh3_5r~odpw$h)01NSiCY!UgtKG))#9)w#}G7TsU8(e=t_rtDS?& zjgr_^n~MV8O#BA$1F}y>S8u@x94={kE~K!29zcL~jRLIcvC^Wf;l~2d4<5n2TP7De zlOShp2&!s1+G|uM+~Yw@L4}KtIOJq>8^Gaelf)08V$R!<3ddXDMB28C)fSi1yT~*j z+b+640;&P~?y2AiXfavzFrSAbmCBZWXRSEPnP1;Y+)loTq?O{%>so0oYdMl@sVCd3 zCVpM3S^|bv_0a+|Sk=z7c{n36#)b2v5+tRMXJgx(>o4V2d%~!B8m1cfkvN|NDYE|N zt7o5`t97M`y^uSv;)`uCi(z;NSecC@jlFr3QC&g?2jm)g#Ag&L`Wmv#Q$slGwXDAW zVzTc=x6y%fdv>BpZ ze7R!=il2Rh4B=rZHNAst)`DuEyX`~54ZodcWjSx)NuwGuXz<5>37KF+ND*EQ4e)8l zQ{W})UW`R?2F1Lo>2I~l0Z;K=^kOWkWTPimyp1#w1z&!K&=`W@iF1U8AI=dPUbs9* z=nxh(dVyis@a^>tlzGYH!}j`xpu$X{MfM}ZUN1=@6m1ZLk7`hAT_YA7Apjs4_KsI< z%4Jh<{-plc!P;59ZSfi6Me#9EQ8!HQ5%=Rbh>jA(7kk@{m%G}}(y>~OcFlIZ(3|0v zw+iG$(tv}vIoCrM!Hc3q0cH-TLV=m_;vELNVCIhX-Vl99pUSwG_?g8JbK+}bnlg&g zLYIe*_#0#by#*fKh;d?*wh1s)_@nSP{WKde@J=?i)$MNK>1~^fEhS@c;QWlUs;6#( zAXtyDJAsgl2t2n$EV9&%rsbWG?-j zNLDx!|3K!*KYNEiLy(;74y)aCoR-8qV@}=<131NY%O~a$Nu4kwAmnYW8#kcCIF^=- z-asE6LvV)JI%`pCfTbwASSeP*qa6c%Z^>Nn>Mb3IgJiE{w1Hx)DmhKRgY|e96;kW* zcS>L%z5F`4O)9A;k#+<8B^B>Va!vV5K7I0Q`b+xIWfy|V+Yt(8vxk}mPrW9(wJ z&hgiylpDlf$COCLUvC5r#J=J9>sOCeo9H=qL(gJwzr9dizbyW`JO57kI}WeDf9H39 z`$qjcC!Z#-O*ja!X&wHZZ6~Pa`usa%Hiq-J9G#Cw!?MN4o_S|a$iH*{^S*!Qv78O? z?@XgzQI`c<-&y_b`gcbAoyq0${?M?0X9y+hak;qoq;+1_)5X8@8pGGf)Y+6VVgJrE zl&q(-_4s#w)|0kb%nx53c6P9yGxSq&Uk;DPQt{STI8G6cw;sa+l(>o?a2#yf&fHul zokVlOxk@csxG|zXBBsvP!0$<0y!DmF-L2lZbiMJeo_2HFrHJ*WK4-!eY&}}9pzb&? zq*Ta)WOV1?WrM*wi3Xkc(nell6W+8KN8{{I3T*bVTuUuhN&t)EaVsm{TD@?_YuTvy zCw!Ma=)oG_(wCS0Vce*F$&ug+Z}5|uvC41IE$9h?tb4?DI!UoJ;Db9JbhjqW4c$bbzhX};FZV@M*sinJuyDm_WJ`so_0M+}Uf*f(l<+WFo1 zXjt&k`5KA6Q#8XuH0{tIe@3GeIc-5F1GOA@%|G?0R7fPVNe$7E5bh0lB9j;-v2-Se zI0xImb9zWdPtQW)cnjGlGxmGx8ykbsFxzju6`-Xo&9~CHGZ)*mt@sI!RGMquoTX(~GAUWlKXgINE7n|*!UTHy=53QZTytpt( zi=RcFa$&V^0k^GeKU?9oCIjxm;LT)k?MuefUu6xV^7m zb{2+|oTaZzuo#<)m2ag7#mc{D@wmz8bYMZPAf|OUepz>Zi0=vOg5{SR`K;wy{a{VC z*=)IRCJ{`&2*&h@IQAD6Y6>L=iz|BfY~#)-`XR0Z+&DN8mgb&r&HLQbEqEf^61^>| zb%df?%lX-nuLGk2a<>@iqE0XRVhRhJdxiRqIlf zHYPik+Nm^K)NrNQS>Oux3TEv~vK=2Lxa=Z+BHDTbn!&tZM-5SQvR~AfA~i3xcrP9f zQBZ&F<(;-~vtK8p1AxXZ-ZFMxq%omrZFJnDrhvpa=pKELO!oW0|EqR$y^Am*p;YKw zvf79^`D2D40@D5OvL08;NmEXnj^xzouv}w^y2!>qbvjKRO=$(`e@_061vgQy^!EG{ zU2xEpJKl7}mUu<(hqR0z_!<50_A|H!!)g@Ga~bvf3n=cG!2%_l3kOukVJ!}sNmD?j z0E!Vj^(c3HzUzY&=qpt|L@gy(|A}eP=mTG14CL3V-Xq8xlFA$O ze9)fVhGwvqy%^+em8!SH3w~bxfg7@d-Ng@;@xehrg1hfhkhmfXZe?Y7yS~`h0bjq{ zhBVx92WFIxTRQ0zV5lPgR4o32-I)A&OcuZc*T9|VkR9n&?>Bh6^zrwiA(%bmRA;~H z51ZesoUr4brsSzh_{o`n_kn46G+)14O;oZJ`xnKlWabb0_fPu)(oBbDnafC{MMFX|_knh^5Ks zQ6EpqaKVluZ8r5ks}s8mWbF|4a_$0&Ejct-ciSkC`W)M0{XpuUu4XIBi|nl7VxarB z;;GeTfwrCe*uwT6v6ew?sc>py!{7J_$pLKj;G~41oBM(oCZpgI6J9jfP%@zQoVibH z>jM+zl$6OIs>!fhU~)T7G3mMN9=jyH2o!Vq7w4sd8Imk(T50`uHV59GYx=mkOO@0e z-f8YCGzm6$wzZ%2sl**N?4_UR2PAtcIkvOz#wa)oCdoLY3JiP)=_nR|$y+{E+ceU_ zfS`$%pov0qIu<#5U>>h0qkAwdkMk#i3(WhzdMU})4O>m z`@lpaI^BJ)d(H3<3B+BXHg1IQ5yr2(|4{tgX=Y% zsazVVv_)NB*lJI|UXlMEeufeBsDaA=DYMeM_Pn-G*K6zYe%-^ZGnNPIwB-+V?s8{w z%!oi1pX)41X*}5)Ss(r!y$gR%7^qczn6Qv|k5-e>=ikp{Ku?l31~i9t$z->bi~E>U zZ+Bj>u55+tvaAvQ`W{h05o9_-tNRaJV8%}t_Xu0ti7Qpsd@*=T()jJ9^6Ga*G(R6+ zXXnCl)hC!Ha9kIdQ13r1k)4b(-sY#xg3-=sUa^U&hd7O&;;suW_Y#|TmwV}a=ZFHK z#HLdzEI%VStq-joq87Cz4$zNF7K!LXi`@=<8haHNDM+g^oN55{*tAa~k;X;t*CvrB zVIcOvIj5XlJMe&g&W`Py7rD2Vn`%}MjBWB_q|yABR=UqVgSwRdD)sI@CHr+Lji*ZY zE$#a5`Ki*9eFk=U_a~`RT0T7!s``lwo?!n==w8m)13x+Yq@SKqd*+$3=Hl4E7h``p zb5fOn85rAlaGsrNlHe^_7rcVT%5fYq6-Z@sCdUFwv>nvQ>cF9<@rAX2DWG9*#ryKQvZqdD zhpow5T$aD_22f`4cK^v-BVzO_RoC=i#xvQwrxs@m6q_reDhnu9 zY{yZo@gARI$uqKrVj0~^?*IW<4uI0L8yLO{7%muC>FuDxLJGrM&t31Cg5Tn99!o}_ zd3Q=yVv1Z?Eko}v7i*noT-CdxFW#s&+*D|yk}Gyh-;?+*-zVXLR0t@;wtLp7{{8jaDen^$wcdC%>Zi9Np&)b>2@aDts^!WpcZGl?JPIwMH zmq^aW<3YS_(x;Je8|u_4WFS03D40yd?`yd4oibaqV)_Lllp$Y0lgYRJI!^;=I zTu#nU+(IYpAv@h0>>(2V`3iNE42xBq3aIwcXbB`-O%h*$oIsw=lREO0K&MNl-hyk{ z(Eszc>wF^9Uz1(GUkpQLtNMw%Z$cxKI$x*Ge%c<8`9Wm?*uhR`AEvgU-l!HYStN{z zGuf5(EhRs_M>E&^5PR6z`FOFnXTFP*ETH#%HmLpNbA{5XX|PNz5Um=cko0Sg>W|^G z1|th}kG}sU=Z@>4iDw4OTolcF?yRf@m2{en_J)Ee*qWSV^f6}I{E5tSPe3ymKkHED za&P1mnKF4gYFA3?f_;V62KxD3WDffg*HOQ4}pgn?>u?ecd=H>CD z(F{hLV!$@b2vY1k&ElmjxVzn|^{Yztq$-T4(XYw+1>RGN!p|G%KqdJqK^54THJBS~ zdf69`_7>#9N39*kO@1&?ZR_cw-9jtaZ4gjb{f>U=3h$P8oDiBWtm~(hp3gExe;9%K zFaZg4wA+E!2)Ru!*Ee;{2-^2P#Fmx9hJgLywL>alZ+_?rYjTPdj3UzOUG(6BB~5MYL5t!STJzGpjiA=D@(e`^ zWOx<^mO{~QLnw-m=@}mxA{WTpSSh9?_gx|g->rpeemGL$hocmJqzEO_XIca88l8}z zH=VoJM&@<|U!gDc7do>nCSXFWU6ZDnPH~!ZU=JhnJNg-&72 zH8{K5O{hpMbbl=kw$kNZ$GI5@%=G8+UI>M4^b?@)YKp9v2h}+X4yYD;SHS9p!aS`x z8CZe54{L6#GzyW7(aadVp|Fe}#mcGTN11-q@WW78%MVcKtJyvl9eYb*(KwC6V&V(B zGeGc1y#;aD#TpB+UpCn+rWA$kbA0t??ZW+B5HrqMkY=X@7-&F6H$>Q zOitZ`p|hEB*$X{Zw49;C#)qziLeY`gqyMV&#*xNcfzy0pd#t&>%b8>H?ac936lQfk zbWEN*bUaUoj_;yw`q1%B8WnKE3kSndh`_Pm`|}&!j~U?HF~1w3@t1%S{U5l(A=slx z+t`v6!|dQpJ z!auu0BRQ|W6#0wY>NjL&NFW*OX$>G%#9s)ckd?$AS6-Qu)u4M6&lmA`*07|NE#{>N z+S|SMoKYwdLz8r!J;xR9FKumiX=~d^TkB;L$EUN{mGiVKv(E6`Xb#z$`>;jtf(6|4 zG*sqcWgQdItFyD}&Phg#7-E=M3P>BVY=l$_v5Xy*B9?vV{7a_J&05jJ8MDUzCj^A% zWK_#VxHz!cuLTo_@QDOrf?L%&xoSW~noiYD;jH?9zf)n3Jqw2<>n6cgvSBMd(`*II zp|3GYV=Ef2v6V7@7+Vp4F}6~}57-Jpvizt`^OqD)$s^zA%!vwP8s_2`l-}s?0fzly zB$5>zrVyJy(Hd@6SipEPC5CP*SpbR4mqkyu9U}1&$Od=JtN((uoNiu-#ZPxH*da26 z`gUGKFvT!tADCQIp$|-+F0M%IunJ+PRu`)klD=}h=ZP(k5P1XryaUKf@t6$$BEGFpW?}Zs$MeL`~)E!enjrI!acHT{2P>I`4E1CxtcG^xUtt$-gr>Y%ns4sN1YSs&2a&=p0 zSeg=8_8-ZbvVEoW>6;{u9L+p@eCT%D*OqS#syu%+}|B)l2pWg4$5+ zH7|3xz*t!HgYtUM{_leF_RW~02oTC_jT&oyh|5?Lb}K5nToH_Rduoeyl*U?IOpiQT zQ&zxz{ScqJ6LnUlR;xTl-Sj8#hN@*=%2I#4bjm>gUNvRdy=r;<(7kGAUBw7lYz17= zUgjSr;8;P&iHZZ1oT#9jYCVMt@8b_S0LR2k22SpuI5SYRx|~z$k9}Xq66^-}8crEF zMc6+CFlnJ3gK-zX7pYbedOhqNXLNU0AZwQ7{$+lgA+@|?oE`d@U0 zSTW-CV995!_caDr@UgfyQB<0;9??z6ns=T4QkggRCL=Dc{Ib1~Kbj2|eU(H65R3mNcPp-qkkk$;$vbjP|4+2hbGmR=eW|fD=83YR^b#I9S3ZiLW znM`v32OyR=z&;vIqXzV$WJ9eWnBZ`>Ot;T>o(vMXY%ow`a`?At0oVONW4vfK<% z&8W~<)AgEBBk7rXgS4np)FsZTbQ$S{F3K@4kwGfr*U-HqZn5AjAKc)(cKUj}W{7=EMkn#6)(g>GmAWg>nWm%<8?8x0F3_xq=GjkE zbf5SgP#eI+m9usvqp%yOA%hm~99*~yn8DY%iURS3P|Np&x9n=$Z5$Agj&p(9-~dw0 zs=)@suK%fl{7=28(@ z>U70)eyQV`dU8?fiJM}Orbnfr_lK<5?^Su;Z;zE4@!o&YG5ahFviv@7_OxBMQtS%I zh?fGDCUQJWmR3|jtl7~*GWy~_RqG)$C?})yRY5xDdCR5{*9m|$kjK1gMOt8|!a0kj zNS8{7w!qGIP$1`%tws30u%Itz*$PB2fdabR<5{3Os4~VUabVeMByFpcbeUhS)hRrR z8fB3!@;=(b-*1#<`%Rnb((h7x&ayLkoGo&vEA6PH3J^zYdHVZ8W)P>|Rv{D$hwg5J z5WfwnFOFiE*IqC60eu<7B4Ug*oo`lkn}|nkX(1sVY3vYT?yr@qOe?-rG z@7(v?2KXg6G*;PgT==Pm=Z2MeLu1so5^ZLQQhvJgAd*230vP{8LI&J!LD~ppZaM{+ z5Bwt~q4MS|8wRv-+=~Fs)^x{swi(~1beNxaJ$b%_>f)y^d3!G42H!Q!lz=XmZqMl5 zH8I|1H`pdsm0iED)NMwqYLNg7wz^17IDM;fq$1=8Lb>V^eVFI zHaFA3M=uEXpNgnNgc4!?oG`gZ$)uBeh_G>fjI`Wys7A<3qISLXvm&1km0@()9sNUx zii_hAWwE|jQ`T{`vuH9~-Q@jGtX{X1qDHb!Ud(u|#;WxCMkY-mWrI<1x2 zm7FzQ#hn6uIJ;QlPT9JtSySS!3iAb?H<`0kd><|lc!oTbm!OW*^Ur@n|8kleE0Mvc zYDd@^EJ3?L;;Mg1QMWKq{OzEZ`~05Ao{-O5{x?0Bl9s4F(bUygJeFq~V;^UBg0GtC zVtC;YVD1UKsf>@@s*6>~nHJvsqo^)rYl>MU;e>^Yb0@^l$;KAsGMvUH2>5O?otuS+ zBlv}~tPwVYQf&??zWer^qvlsmN>Q#O;0$?7Jh~ERW0pOgbRp-XY<(5+e^kUjw9^lK zzm5!f(>y)d65542((QiQ?H2^F`f1NEU+SmVSURWItiX-bgRp>D%Z_VrAftIOb~WIw zY~It@$62CDnYHWeZN%3`|9B|tb>81auv0lX3@ztV!Fy?|?JQ&}CL3)BIbga1u2ad3 zZ?6C(4$>hj^H;{$dn*fTDLjk9Jf3wt`?}Q#&(T^*Q>LTjl)OuMnO`pcEgn_nr|0|W z8q)ORZY*VyI4(vvdChffHg#Majk7l3%Xn6@SOMt?;i3QG(p*-HpDTD%C>9Dx?TYQ?<_dbS|LLx7+DGu*z{ zztQk1G7(;7aINO)e7TLLe=!2Na~lgw-S9^sQn|Plm4uwS?{xt(+3ycaft^9a)c}%s zGLcQ(eViF7-1maVm=6>J_qEN*bi>wv66hEYWjKL6zT9T2fwE-uk2IPR4%|iGSWLz# zu7T~4$-#V2MfO|Rgg)F^M(teM)0N-~&l~O&XPtzT*SQze`}O79LfTFi!3r2-8@--c zPuG*Ks1+v+go;_Z;C)i1MFJ8cNO&*FY( zk;Y{PR$XB%y+8B=AC=%25tb26z{NTEnJHNlCd9mJj)!ASE6s{rvD8{(i^``6xXW0F zzeP~6jcIchcH$~h6C$;byerQB6ra3$Vs6ibeSEN`jR{Sk>f8dB z8=nCGVdqJmWQCKBje^x&&0jWCo8ifBAsFEo7~%Wmb3$%nJ4r2wSM1F z+oc~Cn~!uTz~42I8=nT+9~tb7r$(tg5j1cT*|_Rlj7=##sH1N(8lznPBk)t;Jy$4E zmo>E|x$5XAF+ zOyY3*oFU4!sIC`m)^heGqp}&KZDH^%fWc-xfTo+}9dL&Z1S4gF%Yy9sy?w#n*^ya( zDW$m^Z}%BaDL&Umu|!($$1;ZH*7u4v4_yU=;9h-35aj+)eWPMTU!VwiA{iY|DHqxl z5CF*p7-8ACpClji6DL;#PsdA78ZVkl^ZqX0GW2LJIMmpQMj~`{vA4zh8>`tw-;hn= zcX|)O?foAMgBkl<5sGghq`6~E(sXLHiqQYHko8YC1|f=F{|qj;7BxIZQf3BK^(uaW z1n2Vn3#vu&vWK+W)4$^%eyH`iE@|!x?RfM$lXvt_5|cp!#;UwGf1E=O%uEwi&34Wa zYF-fEm`J12a_904VAJNOG;W6NKM;GFZA!3oG%aGCK5yq4Kpkm(gvP=bq}bYQ`*uMNOF!fa$9M4u7R-q^;6i2QWp|JB7nHGwG*S>B$1AwFn#yh^P*2 z1gxBivi#*S$J-?pIfX=!zM|%0KwQVA*Sfnvqb{>2TfRMKxr=JnVPLvc7=dc@^f|!+ ziUW_vn%iB__`1c^k1?Dfsb+{e0~6Jo@1 zuy>jl2O-OVhP51OeL`vAsjg?*(|yV=1}o9JuWWJiC)T3+(zrHjS}XIksweA?t7Kt| z*tNiwmEMVOFyN5z_0r=1!`_z%HdST+x3oZ!j%lbq4r3iPx}B$=;tt4d!)dI1h>{ z^OlRb%8vtWyeE%5GC}uKHWWDw^!QTX66kD){0_5Ig&uSLR>qZFDc5wOl#$x5KhT_h zve>A-8;3y+i#^xPp3{mZJ%<@t+0|gNNVKb+L6*PMv`<tywJtEJZ+23SnF?r@h7h3?gk`8}Zo*miU!a;iAWvAp>LtXQ8 zvUla#^E)Tc-j>c8@@&%qe~LW&sP+%bvnOok^ecH*$YJa=dA46?vo|U*+dLWI9*}1* z9k2s=b}v509&X-O!>;E$MaZ2{M|I2jQWx%Dr z$BAhqOH3o^JT2zXXks2Puv`s?MRe+rjPOiO17Hrt2#)wT-?NYtftUdRLn*eu<+u&3 zhGo*uD}%6vjM`^16Eb9CftQ8~xbc?Bfo6$$f*Y{eu$RA{=y~@T-o>Q*4-}E30d4=2 z#w**~yO$2jI1!$ z>Jj!&lvDc)#In$sE{dpUxDz)N67ZF#3KBN_wMx-#v8*5oJ?lI2QH8HI`fHVjew`}# ziVL0lNavK19+roZJbE#jyQ|81BaW}8`$m80`2Mq+q6PC5w=Trko6hOl) zq9$!#HsCVdlQ7?wH8_A)`zrNCb$1ZmALgK|@f(R$tP%81nL1!3hSGx3AVnELkTOF| z+w!Rjh4Fyx1>(ab8g-c@{WECC2JTGSv4M8Fq9%3_>mXwXszf>+wNFH^tX`{E;$3KG zKa4@ljcq?mA?>uofx?WV&<1H|BI^NrB<&2igc^Bi|sXhLU7inc%AVWFfYu>U4d(s{)OB@N-UW~!2Xq$FU)c~malS#T5yX3-QD|j5sBlPj*t3S97PQ&Ehrjob8`ci51rw^|gD}NEmA*y!3>TaJG?9 zXv93JC^Qm=ykz7svZq3 zHlBhNd%WhtQ;K6w!zc!On6A0neX;CW?YNA2y0=D9Ohi42Zm*O z@|Jl5=R%xmp464-aE3dz)?K%-vperCy{^`#*VSct@@k7xS0J&go?2Iww-D)ej~`|7 zmbvR{vvfad!TqZq_Eejn!Lj75aQSOp-iG$xhDN<$Vfko1kltPQE`;Ip%uGG6&J#Ej z4J}9QHWXtAJb~UtsjJy?QQpVyxfgnt=ua8>OFlD=@iw-o`~S{&_Aql5t>2{A~|@!HjWm95k1^=20bsmzLvs>JXD@ z?G{hXo_t@*6^F4qC~EKa=a9;if}3Q^FnYuVC~r0;zg%zLPE3MYN=3OF$d^7l-KZ#_ zLVThJ1hZgG26+ijg4w8*`|l|g7bLI#Vonb{f|RfnOj-tJGeZj-7P01dnB`J57FihU zGZdJOy1%~zY-uL6JVc}Wm@7U12C-P{{-ua34-Rpj2~dmv?fnjGh+oZtKJ^j?>TOJ| zocLxt8ULE7{Q;&0PSOK7^XC6q&v{EPSaI!HAjb0caH%^0z}184C+h`ux;6}~qOpTZ zv<#0nq)`uy0Ev9#5)E2iL`d&}?~8tm3TuB;t=#}r38n;3ouknhBC)vrYm5#c=-QD; z>yJnz)U*8PZARIo&=W?-@B+C)zC1aOMIpr7W;HfkEYBt1XH z9mPKO)PY7>$c#kzMFDs^kGFY#_1^!%{wy4rAB&{ah+ z4X#N)%;>K+ug()ZcCo02*o?@G0IeEC+4-~V}DG;cZ1XW=W{ zW9sn%_K#;wHq?YZ;Zf%S<9ic03Qo5@YTpkG5O?*;EyhiW@>$|Y5>dux#vM4PDN$|+ zm7JbHlMDo;QhD~}&Lg!{@ zMbP<8-E816YXe290YPWBEDc=B25?hvGw9rM0~f{`s59wB&AyC48o))|s)06a;3~ca zJ0JN-GCKEpTG08|hl$SXpES|g>R%I+H|_;CU{H#n0z~Y2qy$PHxM3g+805}TOleW> z&=iu4;;qS@%3%p8PGN4!osXZDgXEAq(mbTab4ZCxo!@sXb>3xfnwL5?QjbOINQ6tl zen_2jlBLdJMorC0odK$<=B3WE^U#GBqz*%d@3Pc6TBMG$2g%Tymp8l;?2pKshM^{U z9|^RIF;lC&DMu5+t$jeL@MXIwZ>Gi?SZt!Vn)$fA39w~~gTvXtO?cZCad1eifiZ~< z#Kl1aKd^y?PoRNSc-xf*UN1C3l-5!MBCFZJ#caT)2()^3GJ)PXM+kHzKH&Vr<0gSN zkvGr>ljw8#Q_1vs3sd$eeSSEkMfyA)jUmv3g+6Ua*%S2Hh$&Cd3U{AApHWpcPoLT6 z{CCo)bFhhgt<&e1kL?D1u1ADvWl(CJKD}&USLt&~tbx|)^Ds8BtMu6`)IAENgAAKnG}EFfhk$j@&;-g}ll`#M{s&sWh{B7K%2WlzxOIH_lk z$j@G?s^;ml=B)ot`kXz`B%jvlvk(}y%kpzjtbx|)^NWXegFZhSV2+@5`kc-Nc9lMF ziZ#$WeICjN4EZ_qzGV6w@u1LWH++cNw?EJleOiTQ02fNZu<-;bJApojF=da+&%64! zNS{Zeu|)b@0bJM<^to2**(3BBR8=)kpP@7UJLxl}pNZYA)8`|=s9mPd2TnB`Xq`TX zuz_8bp95nJv`(L&-@hC5`DuYUg4XGC8XGX^^HKO(B-&G6{Fl&Y1wKUW7tU&iKBs** ziHjkg3{ke-ERghodtlO?a>IcAuoa@+R*eh;I`YwXKGFx!hXsx;e01`$dJP_F^_|3R zX6L82e?2rH9nVoUwqOpAH zf!@Y;n(tRM?rrR;`7Xjkcsxpa8!OcH1_SOzl2%=UG+FGQ3{Wt7IZr))2FEhtGkHv8 z-y{y&@Y!ONo`lnQle!@XtP|Jk*mf3YDs*}pI>2{s5OWX=9?y62cEbA|#(Spm{XXNp z#CU(ucrV5~gIzEN20d4wXF7Xy)`(c#{<`5H6o2^K_uMR@Z!=q&&B`;H zoyh|Mjqpf#<;URkLTfc?zO#tCP2m*&9rh?}puAK1sWNp91L8tpBd%DmZ>JkSQHdw2 zM6G%n;bvlEe@m<8y`Sdn7(Ae!`QetBh1#w#oA?qO3Qh3fQKnWs7!&SVkjXJ!2hU87 zSZ9%Oi71JK@I=W?d8?xK$*4e3()F^0@+VeC?N>``;{4FHh$v|w3(x%kQGhHwFfqbJ z7D36AjY{=!5s6fh@q_oWC6ET)>#Ib?D%Hbh zll1&Jbwo6vr*M zMNTxzEHuj`Ot0_rq%vldJd;Z=?@T~Jy?p`QqKhV3g|7gZxDU1g{)WO$ ze5y}LqSC<2vgV0XB68f!df7lV9>Qm^>0sYS$Ni6@%zIHe$(45~Tyc|;=rs~a!^d7| z5cUL>s8xHV3QQE`_@vw8JSdrljn3JP&T&&QTu0CVM>2^c#T1%4KgXp9P}WMSB{L07 zaj9E36m~2WvT7bX4C(Rv4p8=_yHuq*{o0DdH?jx8z879+a4R2b2TZi;7a;9i3wmH8 z!aYgT=p`d;MZ?pH9x>7tF!v@Z5X^_*!L^7xOY?y z8;tD})Ztoi0CV4OP!^aDogM)-rxj{(=@Yeo#OWq!#Q-)pRVeB*%yaeP>y?S{?&sb%|2g&;$_O&JBCOM<)gTM;^4gbVv zp^@OGyg#-hr^2TqqWI$xQ4nKIg-HoLiV5UIPtxWYLR#RF*@!}$;qLH(yF+~pen9au5E2EE@3{7C=SG}< z<@VjVf)9qyh<=H#hy!cXA)y!FLh*~trGyv!ptFtaqCz6OsE)|acVxdLvItN}tGAZOJ6TM!KHOr#2itRd$hhMXd#wj&JjLL+JkL-L_f%emp*#E=+5 zoW}kDQHcPYwBPx@9G4x2jA!5oxbAF$?ww=L667zYw^xMIR|071Jg~I zE*wjg*Rb@Oy_bi4j9ea^l0xYkwJ#>pOZRW(SMmQ&kx9Y!X$Y80w1xACoc1+6cP>$$ zJKu+UQxGIM2}q10xNmHvb96o(le1BuYd%{y{dax}9d|U=>*`Z##YB3*{M;LTEnSIw(JdE$hP zrvL%>G~bidgus*YPpdgLUz~FAP1>XAK+UhjYUZ+?S)HDoMs50~z<#0-$Kx(oTyZ@% zurI6rD({}qeSSb7WV0{^=fl`8(1Jv47q zjE$+J3<8zCA!14IurL%(4h>4W5l{gjJjhp!eBpLfbay1aRyQVzuL0;u_;sWXZ^kXG z#kmk9San1k2`aAN5dz3TGz$WZyA_RYKwo#g(F-h%YSsH;(723F9Z@4UGsC3ii;RX{ z@n!&eK63G|%0h@t5_S*@h^9tQuj)-?A!QX^3;_@4%|lQgx_x#^MV4Espxev4$FxQ# zY7xC_b2XYlSqbcNS1qf_aQSfEE(BhM&Bza-8MVJ_*D=T+wco}RD*s5i5-AZJB^Yo$ABNzeh7YIW;mxVcd@(Xd7?LXcda3!Z_r+=+ z$WI81HQ;I%X^#i?M@A8~=kO!emIH1_H8{E&9Pj`inCn@oID;7wOk}|3DQss00IGEi zzd<&}z>t{tB><5S=wf+TAFA9R^2dl8xf19L50TKtNMi^JnDEBX{;){Gy)q>`mhuv& zh(~syvuCAL*kh=WNp#7I+F$pY2!{u z{za}36&0h491EsZ-Ba=~%6dX@6b=8Zgo<6ZOG-~dMutJbmji~C3WSJS?LrN4PT6KAd9HTwu? zRJ_{c)Fd3Dp^|+kNTI&Zh<_i+g*Cquaf$D^~@yS8T*@)L!C4 zpYE-$^=Lyk7J+})94$Hmd+*%><6s$Hi~K*h>wd`AqstK}Ans_Y= z|I9aR;`kg@c#8#gN7$w3_zsf;S3iXq?kxUd&7Q`W`{bpYBm5K|r~+ma$M#a&vy8S! zv+Y?%+dUmc{tqK3;1C^8Lr%cyYn*C=nh)J?6)gjtF3S743W}JZ26mO6_hh?SG(TiB zm_RP|eXMW@F#OXQ=y?UQGNv=Aod82ht&uVg$Fd19AVd|D@JRrLD@SYaUSqs4dyc$z?9WIR=30&Cxu{LixP7t}lI^Ln4MjrA`7Jkvyk?&-i6HrBC zkQ?8(<2Vq9fPYyn!d<5M7j24VW<5ciHb-ER{TNY;!^87gnT%;vYrN$1g<}~SINv=q zaF$0+w!f!C>#FC+VW8ux0dvrLSz#bH(%Yw@aH0QRAAWQ{cs&Jo_7t+U0r%lbHQX0aG&N37VgjxPZ1$K>eKrM$?vI%90yw=5_$n+K1JSB~mer$$MK2;Ykxde!icK=4sq;@@(X<7#@8PHM zZ*TX(6rTt4)M`N=4dR*G+BY=kQU-LGVh-xfX&`YMD%e_U)AwYQrD<`W!n-9*0hP%jV3 zODDWgLNI2G9z@rThS<-&*i=juuDV%f|7*@FKN2BK5NvX z8aZuBWtk`f<#$uX*JK20^^beSE723l$;FJB#b(X&JhMQR?~rZ@!GhDY#kzM;O2y&m zB=%F8C(!SWVsucBiKEU8oQ;hhQLY-`%Od)vSTo^XMSO*P3O$o%shi_h@rVPxdG#wI z2Y1xH;q>`**3h*fJR;hsA{+ltsyGn;kE!gZGSzD_gYsqkU6OWo)dJz_L+CZ+*9mU;?~byRdYJ`R3{o7~bhUO~J+%;-SZJxl?Om_VgPw-Ocj>olUrCsE_mD^jN$@|`LWU`RAy46;E z?+)~L#E{Gt{V?(g4>j^rZ{yB3r#V|OrW-xt#lPMV=fQEL9HFCK(mpZi0puZ4ZjP2I zr0k?naVpDVbxs5g;MtrU{Hpo!PPM^MT|=_=Z!<^ZVU-@E%12No*#=P^h8?W=kH!~0 zFgeTZ9hfrZV%%@8-eFycR=6Z_q%j96_=4GmNF0SFV;V==mQ}3K1LeXA_s0=q8&Zt? z%gQ)Z-r_9{t;1{NuBd$_fB$9VsmBZY6Y0cGq3+P7V(g!s8~PSYf1f+h&WZ`O&0xY4*EEX> zYEn6$F5)L9Qui(`1;4|jdi$kRT;U0n15+mprVhZhgv8VfP*lJgDlYu~cxfGqj8j zTCrL}S0J7E^w;0YzyeP~6H)td_%9P8^d)D$2LYKw1CTe)X#~ALzWN4OrLN6j74+q^ ze%@?g`#j`>vU}b|Sg|Q)9CjiP0GyQV zF=mue|r9cW4UXNrDO=e03jPZ-0J+6=1Ut^k8NsD#m3CS&Low`+VJ`y5t zDhRT0=$l_LH9e#D$MJ#5)@s22kjlZ>u|6^1A;Q2A{$5whC{WZ5VV|!#yGh z3jxwXAz0r*U7D}tVA|Uvhg$fDZf06!W;zL(=)qCO72Tvr7f3#PA%m+(BsF^syf&c#$Q1ZaskaPmg>(R_kCZMtI+YY9vSs~P3g zgHYsfjZ#tdCz|g;d~k^yL{ZLXZtwOCmoU>Jm`C!K<2~K=CVMcS6)?n!c4u8MJ;b~3~!`DDXm62LMfpPLn$rH0t~RM8-Y+tTXcU%*K1t46y^L<=wFLCN{ErdI7&lo zX9W89K`a=wx5X1U0F8J8SD~$UQCVjdQE7!IFUDXp7$NaW-M`#u9JMUB8p>&g#0J=m#F zlfX(JslZBW%MWv>E;$VWmHJp<9qFD>pUixFK-fC-gIuq2lH)U92vaIUXMNx7oF5vS zbM58vGct@h*H?e#?(jXF35_^eU4fq?(=*~-`7l21z>eR6VS}!PcC=^^`&4}iOiJN{ zp~kYiaeV^w0QiUY*nEdE-;vJo`hj1r*JSWHzYO(%>hgZoSXA(X<{c--DdND$K3I|v z2@tibpF0)nkE=2S15)1wBC4QMK!T+R5d|c8pGcr9B+!8Yz@4JJkBWllWE2&At9gG1 z`WnhmarW-nxt?JmEuwCuq~3BxRG|zkvs`S&zR#*9sS#)Tpm+ z@N@{dgTo=rw`?!(;*Mg4i{LSzh3`ZGu-8m?9ynjQ;j4et0;9d%$1 zh29kh1I=0ZhVX~MP(5640L`$Svh3J4@a*I!WQsPpPMa6f{l_{y!HbH);vw5`JmFD% zQUR2Ta(;Dte~-(y56QfKH)I>c+V9P>I1y{Vrz^3R9v5p3MIDx!432>S(@n9)4}j>e zXqRHGr~|fHDb==TTzjn2GRq--JNK9e-;hhwpFniFXoJ?<$)i`z%QyJVQobRApCR9B zA>WpPVZ`MdgdTVeLj|rtI^-M5G%Mc>A^$_6f1}8^#WDGIY?6Gt6!PsI;Yt!Q5b|w< zl5h1f`PLAVZ}m#PEw;!vEbsl0Z(l>cZCCQ`SSvdJv_tv!lgPJYfy?QpP;sv|AzoOp zu^cjZG2~nNu?BMR8^H{0BXAeYwE$Q5cXI$0Ugv~pzExo7u2+tUQ-Qt#!VT*wbJ>$smMNx;fR%GaAA_IaQu81Q8dfAA%5oFMAu0$t@5aF3{amIc3 zsjK6?d<5vNBKzcQ)(ddIIsf56e@l103K>gL|AFf@!lp|JE!CV0{peg=r;$Me$Js zINR8scJs%eQ;awrj1I1s=oj~U#%a|Z(7EuH_-EyBiPLsC`~SaU+WMK(c0Q&pFB%@l zp2;P0*s_sHDS}=#nD;PvKHLVs}4$J#5GP{Q=fpcWOP!!x1NsMb=g-|Dhb4!@W?Jf}}Rq;pGzX zv|BvlDN$I>@-m5d+R2P~x}m7UvUvB1+j_y)@(iq6!hHb~rLWb3YbpK(rD-^LN*%aJ zVyM$)M$l2=UsRpJzfgw!tIp8RheJQ7ywG#D>hu_GKvPT0;U&<~0|N^s6DqfffQ{LI zJ%K(0i}HT~*N+E^loLuu3ES>l|1s1NN zg|^NUrX9VXw`cs=ZiRvLfpK1j=&`m)wg6G2F_uD%dO8qO-YL$!2rNPoVPg;0Qp)nkG4JnUQfl6We5O|Fr!Nm;uLBr?&!j20N0(`sHY-K>QXFLaEuN4 z>z3H{y!Uu|h~SWM3*ZrG*1NU6c30he_TW|3qoHUMoxqLn;fthQ>c&`xQDCKcQaSZ# z7m;KsuxhCvLw~~j0`?0b_9(L;utZof5GorQj&>KKT`tJh>i#rvi{A*^Ph$A_lQ#V+ zn3}@1_=ic)EaH+ZK}4dtBD5;_gV{!lob82z2(cD{6HrOuT4ZgJOF&Q%D3B@%VtW=M z_!0m!1af7#)8ls_*yyke@D9~txv~NqE9IQG+?Xk2`KS&4n3Zfz2haYh8IHP6t(CVn z%TenUt*sSWvvSmW(Av9%zI*kTMIC;l=(@Ix8ya7j=LLr5t%{6PB-dbthe2{lDg#Ik zIB%#7R3+jngO%hq03IgOT?u7NR0atx%;iweZn~_7Fym#?7@g-0h*1EljPaInkgLnATT;2^(8MYw2@M!@@w>X&<7A!Zz3x8>7 zy~{;Q=+=a{3J41emX-IyN}X)5TbvEnQ>=i%FN@$bfqIg;>;k4~uKwSqZfvZIwZXq| zF1JA~ScU2Qu$k%nNloXrW~UROrzs#eHkr$+AyFxSh*8YhL>UqQV@1=z0VWAT@OKR7@JNWPq%mQ8 z$Z|r?Y#I^XGd0UPQ?u;WNude&ze1By7zE8ThUElkvQDANq8OSOVW)v6i-0C82$DFO zj8bS~XqG^e^iEbZ`N>3+S_4g#2<`+lNsK}*Qq52%>wqSmIvHp}UJa0e=&4MmpQ?Ln zVNN5_Z>lIr(8`DsACc0v=?{Vkn+6uwrvC%!VcaWARUsS7+5ZQ=#7f_@z<;6z;PdoS zn88*7eBS3qQSt|ZyBljd;71)OEFbEQHvQahDRF6bwH_2qPiQZj+Ii; z#Uxb+@tYG=9j$kYC(sl6&Bwd0-ynYdUe#~*Z>ryrnnXW2B^*h4wj$|lZrtDv5%Kk+$rjCt6!xFlivL8%+k%g%@k^S9zTA6xG z_OD8i{XLt=ev!A7{jd-$qU`S(m;DPVWU0yNsUJbxr4m6n#o5^M!&Ptn`aNJkR z2yMZ#8#fHEK;|}@F9UMJjSFjnk2tE3;t66W#A2VM*DG_%jvepOtHlei&MW0h6<=`i z`R(#M(=l6qXDN61oY4qbkTa6E=kne>l*uyp=S(jK_(_M(&rD5`?HKG-vV*xH9Vy(? zyQU`HVNmRP=FBzH%aYPFkxq~JEFOEv_W1iato3g_5MN`S&EMe-M~-lqDD)Ey#4$Kj z%N6p|>Ip(CjAcI@yS4BG!L~@-U(et!Y^LnU-hpTAn~JaZ_e}R=rMOl(s&JPT8?T?O z!}1MVt7HF%`|R1sR4kWzMylN%*8Q6it_>1` z1194Fxu`uz_yq^tFE3T<<$8H3$4lb=Id1SECFuTbxDm2TYM`x-z{m{SK!ZQ#=)7lf z)er_-d9(-j%;Ciy7#OvG;lbWFoN2H~pdBbp9f?#Vbs;*^_b?X2?sKt@V-lJk^fcpYRG zuY<%DAc@yOI?*3>!C!bB4E{V+kcEoSk+!Fff+r!`0rj^1ItWWIo^csk-!^jyD*FL9 zAAq0E<8R^NOZ1NS=-FIy3q;g@b1{M+u*-;LA?^$qg6b~&#iuf%#~2MGIX7W&;X&w* z@~=pQcS@k`+Q$>%z3yoXyg$H;z`J~SEAW1Z#ggE?ee%A8_gm-1;eG9lIK2PgM3x{mi`v@3cVMap-{szwdj>0`Hl45qPJa-U_@gVX-85-*&^kgZKF*ad@{2 z#NmC|qXO@fyaMkTzUJWlSkYdCcY2_0BOSw|BJjRbZw20MSS$(NhroKh zulUKg=fvTCw?7W=7akUPFPbLs?&)m~-Y0{3?j?TGHqf>PJ+Q!g-5d+NKfsH?`|x3{ z!22N^a*X=ua-*9#u-bdEN;XU{vf%k|if%ntXnuGTe5c6Jwcbh=lO!UA4?}EoI z@a}^bf%l6;TY+~Q7E6Nnz-#v%y!RU!hxfdj915?R$g}5)z_5s$a04M%Ec2en{e6X*N;~xm|wa2nlTeDo_Ng|zGmvL zlwVeH{Uu{AtKe&vc5bcK6|s%@FQ00GE@}ZbItgAD2r|z44y(15> z;)tYi5$IQWafgq^ot zpZ2qCfuJ}_v9R1W$NdxJzt01CrbI zrL|CNqBwR9HCs;7DCl5&y1sZ++#B9FZ^21{ZF8Gd!=v~cMC~i^E`E@6 zkp|uD@wQ?IdA z?vFwJ9i_uZnkhdZWfD_(*^5{S-r$I$_NR~t{f~a*+Po>YsQs+dFuDX_6VU2Aa6Q=h zy!$ZRKpzAf>O6&ym-e5gry`QxN>_6Q4V_-rue_9R4qEkYX{+7xE7wK-ZT@Ab=i573 zPde&>`v`hE4^?5fSWn19Y(kVW&nk@3Gll@@1Piq_p>-c&ia`h1Jw=EKF0`uYz9sd% z>m-+(YI6s!wS}_Q*bvM~(l0k-thqj>>4SH?JBjx_<4{>ahn-8h~@2Q1lhU<;uB z0XiZ*dV7#WiNKBS1E{}eap95M^gegoHIEZ;Lo(*0UjSoTc!TKweP^Pca2=izmZC>W zMF)&&8j>RI@la*9@g~|Jn#%$y{5VUpD{xDf`)o^@58c8g+kKZ{W?pSe;BW=JC2Ajz zk3?!7*#pD|bd*YgtyfB=3D|niyV%;)Q9YJ?{m$U}&(6}p0q=9ZgZ8EU5G;lfW~26W ze28Em%CmXNK%x@-@!vJQs&|Y(3-3t8pKGNrz@HCMk%gdlh(BA_w2VJN)Dy#>hSf3r z>4kJF{`5k_JC8pfq4XZYpP4dHj5sjh58=;9)RTliE+h&5IL$VuqKzHkPZskT_;WL6 zCINps;-eLR-j=$6KS#?$0{)!)b{v1U4JZD5h)lqrzj3~U_6G`L_*0J$as0Wtzrvq2 zZ<+XGoOk#|j${mYL%wfzMPWHzul`5ve?g+#e_@7uDRvc!@EetlM>tr5{f)LXur3|U zgfyHV+FsBVv{2!2G8TuSn@Go#a7&Jh`3|mx-@0w(`U$u zFeNxGU&}_3rgLYms~E(DA`!sz*?u=rJmjY{riGKIqjd(hD5k-08H$mKE5n~H)Cy!0f#u5dW0KIC<yR)TB=4CAY1#)K!#*Bo@xxGw;lD-)mq3Z^^A!NB6CodQ7&K;Dj5T30edXGXg) zECLf!EBh0Cv>(v`O3_0r(0uuwr9j>Mb+6(3AtZ3I@wMF&)I97)nrHIJF#~5gUO}MF0gd zY9>~p0YbElGLU-WB+fol&8|i5W5I>Zfos(t;aj|mKIx)Zs?2^OPE$dmYV;D`MKz-5 z9*v{HwliR3ar@i3m!6i<3l(BCnon>RcmVPl2ND?YUOuR|M}ohccQMY}y=&YtAGoPO z4^)Phw5R>FB133{WE;2%M=PVa)HhI>()42`e3Z8Te%)M_`8V>eFv~?AWS|7jDTg;3 zzj{DL&zEV#gMGeK25C$> zMEaIf%-lbMk0B-~@hMFdLxoTb3&`ol1OXp?Vok>*=60@%Ga79B{Yg|3l{FqYNYT^< z*@Uj(n!0kGUYPC~ZE$8Io5nGmhHZ z1CFXgAb2MUzF4!3hLII9J8nl&MyIKg-x&&*fxe}958nYdDXa4O13;{G6pj$B$TnD} znybkt1EsL2ScFJ#@L&Y>alS+8OQ?--3eU&EeX@)f>S?pDKz2h_l^-Q9yx*0^`GyVU zt$gDN&JC){6q9V|plx6pcuTE3hGWax8O1Gf7?3{?O+&i^KF9t??e%>vB35bqr516N zcz$b{5SzLWWv&E1AeI4W8>PoaG+I7;zr&%czSqQiK0^Z5UYQmewY3XA*V`}zTWX~s zP9}$t&FRVK^yn?zYaN!06hJ`I8UQ^TErkw7SXfdOUl`|wh%P$$I3O@Q%&!Cwnk$WS zZkQ{SeRm5*cySAg+<;@OkBGb??qvcY5C$hrt9}oKT~$#mfa=*upzYFwl%+$fUWAf* z@VGaa5V#5RT;B&o85jzHe}mHia>Ghj@GJ?|`YlRxU4TG;Ly--KS}LyLFS+~;_lFVOf8B*#38$u=e*Y82?r0yy|4rH|qZ zX~y|ddYIlH(rOR38a&4aSJ!ukYV(#7PC{^?dmA%>s0f5BQ?5)69ozXpnLa6b%SjB_ z^R(o4RzbI@z6SY7*d$aq)h^?!8q8D3D|4<@cLK0f|C8n&WZ8fcB+C`@ix^q*3r@k` zZ1dMhN7N3{}U1Y$DF*yLgO8A9p}C%%GDfG*h$0@C?X)LEmTEMT{xb^*8V4p~yk5^t_ze7B>t zWO^H!OpIq_;a_}8X`77<6v%7&i(UOV`z04QSuYv65*p;?64I4=5j|`q^d~uig_nDP zDy&#q_Djp)P~ZT^T?w^3L%#eJwO@xX%}zW3`5OU=3F~A`SWjcZj>T{ITSg1DwsC}| z4JV9quTquv_|e7zJ7{CD)H%a(meIx~MjI2^#?2CawC^w7X@>0lj{IOgWcMy~_ULwi z+IUB%fx-v!+&1X3*orEEnP`}@5TB`p8Ajxkktr&Sp_yL^v+zJ!wJs3+j@swtVpU|9 zXzs8kEsENYKmvtF@UW8PuFu^lT9}R$oW!d1w{c~Xb;3UqJiVN6lD8Q84 zIfm*E?okY_-wCZB-)P7RVu=x|n@)^LcTjnT9}-ao49JxBvv~e4(1bxi*-{TRWlrp z8P9E3Tu%Nq;ACCEVqKv*EPNuqRi=!dC9X(PHm#FS_fqQ@F5S5ak6vQSL07Nv>e^QA!?JB+PK ziEb7q2z$YVPiZ{3m$0%~^~YzCBKl+GNNS2Fh^7d&HT3CgN;$miRSB^m!Xxik;;bMZ z%oT^@t$Bn<#TTqlE776#p^>P-&`W_>SjvBK49ej{KYXz8h@H?kI~<*$Z$7zkH}%ar z^Z)`OQQsUXiH1qAC4G}jEE8m9=)|NfQ8c-b!+IKDFrR%_a;_mV%amT+M)k8SwX%S0 zX;LiiD3;Opat>{?)UvvTWprE2F98jXk3~;t(QV2~hs6&3EJUOH4{8zhkl7&J7Kn}* zy8c$BPNql&GgYW`T7{2C0u@k^iZ33mv@F9O0A=fa)=-^x#~1e>EoOzd$DGF@=1Wn~2{a74qy-lV=y3JlkpVZ0IqDRFCXO zb?tUEk;G~Vf5Z6Amf;449zAO`HVNQA>k_MIpM@{2fZZqed{D-d?NBKjC%?0BvlZm; z7|~_s8hSSxb6FZ2J;f^HPiVcdLdWqGG6SjRouR=%eqlI`qSi3{zMHM6qu0v`)bWmr z*MsOb)4p3vEQ=f8^w6{;mGP~ZOtyqLPzsrfsK_H|D8qgb62PYPbb}cgfhY9Pq{&=2 z^Hm8PwQlAd$nq!4oD~~qMc7QlA)MeE5DTP`)eMD2Cy2Wpx}R4oCxXq@HM>h@#IQyf zWz#aNj#5KDdY*O2h#!Knl0GojK-sCicIf(a z9gBgAz>z(a=x>FFj!M|boi9iyjZ(t~xt1!uU{5$cT}dMz_pC&c(RfSAndl^ zkAsl_5}&&1axW>zerl;~vW!ZNiZe zqoVe-BPlKVeutkh52Qxzci_<~?frNcX)pe4!Oo>O5C*%tjrjJV3W`m(5ht<(4A`~u z2tFhj*0;ZiKr#LOA@A>Lm0i%w3z3&@gIyvA;4NRhRdUbBBeif}L260ZiHmPST4n0_ zD53TXdADXdnFUovwTB7GqVzeD6|VE_+uP9V}d{8I<=Y;!x>g;YDu||P4H!hW278EP4KHn?_Vea#`qK zb6dB+UmweT4RY_E{r&2m_c>EqD6*^e_hD&DJ&oDl z2QoqI?}fcU!io0xJHULB?eB|wA}wZr*HFk}e_sYk^C#Hf??WGU+W!9ZuifMJ_x32c zv-bC6I8wEl(CPnr`}+?EfhqhU`}=>0KP}kbZ%6H|+TVvCOc|nfoVYYEzglT*v#FHq zRr`AfX<6CdpE=9ANZ*W(lOH$TaNAY;`=h8ycp}zOwG*ss^E-FY#?IK^%cHEhvqyen z_V*79{}lWC$vu+n?~i5@4c3Q#eavcq|C^Dz9;sGgg69N%w2^ZiHzB|teN%7904ySR z)gFBr<}}$J{TE3y?a^<8zC|NTvPbtrUt{*@XPK#0d-QV$vPf(8=;_EsBS=;gd-OPb z*`Yo9M`W;Sli#qaM0@m?xOdgCM`rD6+5Y(KX$7+8%wE+}l>@Xu%$R;T3z= z9{t%8+M_cFs|0)WAxLS~9$oaPQkL3261PV`XeZ8^_UJqD#%Y(p+VO1&Y*73aUt;#? z`iGP3(IZ$6l=KunSZHP^?9n;)m=*&+th;2G~`5^z#@#N5;n9x!fxA9>AAY8f(QKJz#%D z9l_ZN)R81lLQ0-s58_%IHZ`$Ijf#6fx&l&gPySXQKv*V2O*`R*u!R3CqT6U7dg_YJcAr)2&ycW>K+lPZXS*@IU6&WO#ny zVkmV%8Xk;0&j7&LsEy8o{EfL@!~ko!WhmG_E$(u(pwsF{C6(rTK-wox9SYcizTax5 z6sM)Q1pCSqq8YT%=G8{}H8%^MfV!BRdAJwxi#Bz579y?YfFBlg^G@1Nd4U7lF2&dV|?w z=(7oeVB22C>l}IQ+vRF@!#;JGnD*~~Oqup=^kiZI*Zj`-AGQA*bZcPq4-yy+*d5O1 zJzK#655Gy#`7VG6L22mmI9Gu8@JMqb2@YJoE=o8OQE;C!-YDdj%re9$(k?O5UNF;O ztv-XLSYW8}@h*H6shF@IgWaSqIA3?~_=NLy?lQ}!Od(!mQ)UEe+To_m{wxNv#-@x( z)}aZ56Sigk)br@4(>UShmTs`^g~l_tWzM=v=5EnYnY+&)QFCXWM^_WK31n<+%j|{o z=-KE2H^Gea|F2B2zt$zn-zoG8|VLVK6*ZSV1c*)Y74x5coBG)cWedTXR%lkyl)${@8EsqL2-CbF`fzU ziQ@#`Ukny_w|S^Jcy|Yz*-QA1^Zz<}V1ajs@fLWe<3-?|wqGmoUUgMdcpoxw-@$up zW*pvKdZ=f@yUpbS?{b&G`|q=xgZE>d_Y}PU?DM+gS3>?lzW@L8x>SXB{k(3^aab%h zIj{R{J4*Gw_q3;&#-{WpzBf6qn~l#_Z8Zz;qD~s;bvK_6T-)W1_Dgu<8{}e>jrI=G z8)y&Xq&Ep0?RU-Ox_zh4>wb>XiRX2fF(vuD?lvSsBWa?KAU;mUm<0au#N`(L@d#do ze=KU-3jdhMVoCh^vx0rcKVIeX-OxwgGoHym7G5I!z?KhB!f9RC>GVbAdo^L+G) zsI#e`g5`Ylw9)8_Iv;&MAI>NQpM`jl`TQlVmHFJC z#ggW8%08UWD-Vdz=cYnZqH_D$U(KiYRGH6f|B*PKon&EfH%M(S$zRY<=;8!;zcR)G z@40vpczfHl0`KW8mIUuE`TLH3wswuf`{p5Wct2Ds^m9Ogz`Gq!^0U`Qd?^L*Bf)I; z61=f~nuH!$^quoAwZMBMUIg9;q_zU@!&oc{-uIup@8Er_Ee`MQgX8c%@gjlu!>0(m z@4lxwc+Ufi*fa2M;;)tz4`cL2&B@m@qSsTto|0n7*Sq=NM7}OVs#U($;@v7=?-{{S z@2VqP8@bJ{8TtBzbOQ17xZ-f9WIm`t{7_@Ut!!HbfA+ggG5L>5becbB|<2k))>#o>K( z|2VuKI#0>J6P5h?dvo}GB$&aTfwx6Jd=Pv8hJLt&kEVWj$5yb>W?W@OLrmDe&QImZ znzuc$v(nMj?f;!t=Q5;{kTaYh5rTp%UMB#SomzQ> zrDP>a-XvjpGQuxQFO{V|(#!O%(}Sl)(dzHlb(F(0QTu{M03*=$^|#P3dL~~AjsH2m z1UviXhvR|4^r+BT4!R(WcI3h(C_AOX#bJy?kDat+=hMRt$LdDH(5`hoI~V_ovhZ)H zjonLg`!9g=|7cj35nc;*_d1((2l_?rv(UaLa5%?WrU&N=aB(m!YM%_0kV626AqSc) zOO*<=YCmRzP3~Z4YnJ0kG{X}X-Q{(qv^_V9g2S!#2y} zI43$VM8Ry4-M-MLBRH*;H52uky|gRmdKGCClmEwgXGv3Wl(cv)lV7f&Wd?N5MX zyZrV2u?zVCtAJmfR{au2z&H~d@#~(py$U~?m$b)I`Fs;Plmo`9U+hs?=)(!yNT)ba z{uk-Z(~?*3H{MZJiR~C{`4=b%RpORAkt4A71ydyz`j`cwpM5E;H%AB z#N68JOS~HgJwGhFt~Q(&bX5s%)}$Y8nMquCrU!d2rW;k{7b1Z zlVxjC8hYecG<22mo*jBLV#Bn_!9P>3p3}Ts4X+0naOaxhAv{V3I)TJW z9a?i4Vgw3n#x`!$?%0C%&X#MwXBtSQlmbrxq@vr3uq}=&Ys@q!_#h=Gh`bijHK(Wx9Ma#(Ta=Mb(~m^`w?Vw7rTrk8JAD#BA=M`6xKJ0;x!dwNYn)r z*F$f=vp<@XK9`}D@GM-W&Jn@tpin>bL_EhC!a_{hlPPaEw-M6W{{MTj_kZ>-g3kv`59ubGeoEt-=p@cG0$2@h|uuIm=gTP zpc8m||CI1OD$!FAspv91(EmF~&`_I6ol_#;6a0qY)O`0N8#q&%5#a&b;aC3%kl%vj zsQp$vM*5)Yh==uq(-g|6)Q}>1NECTHIF|2(NLywO<^Q2L$ByeUQMwcS~4B5@<&65+(ckBpon1}wfb-J3?96rkY5Bg z4}-~rjVa!NshaN&aySMI&;zI86t)~?JPoHfaR?MT-ZQRGabWO>^HF;wTkGv(F(J~7 z(`w*v6J4T$GhX#;i2=VKUC|FnHqOx3gOHP21p^i^DGL!~LRDA6bsz8-K9sLCga%}w zb6z%t#?Z60SkkrwM{$}lYX1uO9Nx$`j0YSDs|eli!huR0Ve6U-)_}01qg@y9H0uQjs$}nc z6kr+byykl%Hx>X2sedHuKs_Ju7}BHm=lI$Kuh+wQ6ovBh5w>p_x`}g~_@o>jyGiuE z$e}!fPv{Ua5!Z{%%A5(rXZ?;y)W;#Nt^BA$fuSCL0AKj(2E$(?VZ9Whpn&~e1x4aI ziM~;##1aJ6s=_b-h*WL)8|*tl#-nsAI;SvesNi`ym9_#|jHqyH@yO%s)Fl}eP9zz_Z8jwtj(-PIc*?6ZP z6u%SnJl9UZ-7D{K{^2_$i%l+7pmd@djB+rpY~5lpYdXS;)2#;ak=BXvJk7Op`fXED{efP=(qBIOq($I_LE7 zAy8g{cS5&8exVk~?<_|ON+*wBCNt6924D-R_dONM21Y{w6cBu+OmFy=P zy&y4wbXFf~b@%Lrk1+?h7AeK&U{nJ}Ajp>AnT~wN)u}QB|REScMxxTp+JS%w8NbBO?P#>ik1g{KA}5h_ zRDSqP#y<+!I~rhCtzdQ0Cb5;9(25RL#qY23=sN5?%mG0w{lMD6h9Q`trBXN?BdW?q z96wpZCPbIIT9sr)5S4ko9%hz#X523I4w*-8!A%+xBYhab0iS7uWR{iRGWQcM{ zg+(J3Wrk)xB}_UC8B!}xJG#rc6WB zw<`HOOZ5xpF6k`DTSkCl=c5`U$b-ah?v3P-A0-lVQa7XYbwoLB8o@4_xUJcAm7#^DXM81Eb;>*pX>GG9v|_BmGZGphMqerGyjdUXc17zMXFwR#D12|a(iU}l666<0s?4NXY_LDH_ zqqS@#LOI|!SiGJv=3CL6G2iGQ`$YcW ziWhQC0$p$oR3&x6VH?^;7JEb-L!R84;rTTq3aDcHhn%XtTzw% zL$W~1U!`^<@KGs6Fb69lc=HA&a5!LyVEsS{985PpBJkcnK39T{A6w>w7J>7NSQDUy z&s8{p)gBg73uIbfMJ2%PL(pIZS8IXgtEmg!_*ccu$6P~Zek8t|D>wDaqdLTkxEd}n z0-R@~M#B4cP@Mzj zG7Vv~giGO3+981nsDQGwk;rw20wr4n^OjQ`&hU6F^VlbxDYyeu@JHdFP80(;tnfcR z8U7Mq1$qZWx#azWQ?NE~A56h7J@(2JB&L zuvyvE=&+7t3^&C46FtZyOFVd4-u@{inHfn`g(#FE^BL%p?7tXSvJAkx z7-l+S04j3ggxuIk)x*&y57|_*o)RN+;`#pr9@aHx|M|1yCzjw|nNQGZ%yn7lJy?8j z+#>o>S&BL`<<=%F8LN%2qr3&UCM?sk?K$NiBj$MC^2iWQt0<>sp_x*W_<{xCf!$SX zA9WP0@+_iB7FkrTAWuFauH!5Zn1ryauDFraKRk=a_Wh?#ty>!KDncu24*@QM zPs}1{Bn%FWt`-SgoUPz57H7q57>hH?Zb7qL^`O*_@Oms)tf8siM8(S5)Y(|B*h0Tt zLC|v&+!K@tdvF{@*rgvQh_Icd-#-77K)-Dt*c-i+<1C75Qt!Q2sReI|^d4b@{va!$jhJ9q&o{K3AKza{8_qTe&HRSf!_x?)H4`@~hv&~G;>X~^GmJN@_3@4+3K(C;|FWv|fh zAXJ32CP8T5PT#iZXaR_zx3j{Gozeyi`<8}$3YmR+LXVhrU^pa3I^&4jLjhb#U|Rjlpk1AWN=vu_Y>Uej`Q&Ngk??C{<8U%3mEyTRWrN$1V%``2`-XK;>wL|k(4b59V6ssj%it`a-9({t`I#;|j3uV!lGTVdZ;80164XjVH zmc>d*Y&#`PnT;Y?E5VtRD=3)Rabp(O8n+`IhElaj8<^>sfp>Turs0t;p#E--2$r^c zzNx~%ENQFIKiZMT7q(XD@9A*+af@A=3OYR*3%YXb9SzU&z|5#+8-Xmk4#%e0aGme7 zQ3~ISvDO<>iq+q^xRH2BSz*ncRrn4&4~CrP_fEr$Kj6cExLI=I3?t+sci?0_*r~go zv%>A~;`X1G;V!73SgOy5(J30mOn44$#3Z(>#O*ih6N^TV@Kfv>;eeM8F}8Gu=iFo#k4dqfWJ$k{iW)Ut6k`9=a!EE@=GJf-o-(vnQ9fAYLG+0a? zzr@Qfri3M4d2qmfONntGyq$<~f^TPoqv1lysQqM0BJm8q8zuGE%pT$1k;C!nP2Pe7 z?|WP_LVEBo!2`nDxPw!iQTtXfN|vp>u=#9Di&DRtc!t~iLzUS2-!`+K&|G#;YU9Mi zR2xzI9A@<|6k}ebO3N2QlJthjvxVf3#98@}8If7W(+pI`_jtS4~X zdH6x#9_8=JOF^*Pj$0%?l+L@{-X%`6M;M*AzSf<(w0tdE>L4w>_!cS=eS=d4|4N+a zQvG`k?{bL_k4b05I(fk&wR52U7l%&oc94QoFa1pvNNK|vr{{GYn1MOW^A_dRp2vdm z@nGYD^Qi}hWxUu%)+jFm(L8}c((j%+@3qAh*!9d5Z#?|eVU%XvLx7dmU``Mi>?>28 z_>~8lYNliozxa?PpRQV40;iZrp4PjH?}&6%LIIcQ_W$5Ugr_t7j@&c+<8w2_trk|; zBL8=~chQ`RVHA6S?DkL&deFa3CH%AyhDZ5C!Oz-OIhQ%$`uRM-7kOL+Cax;fd@~6U z3ZC#I^2D79wCEH|FZT{6@n5N!QTY!xVeVkSB*z}Y&AE-{U4oKI1hcQq1z%AQy|I>y zc-DOBth;VQIvu#P;k(8mt+<|J5OEH#Ko|N}z_IEaVX?aa_fnolA(J*N~{=fOghTAjvA{TrmVkro@^OLKw;^D1DKTvwX ztn5NRp{03$x0j!UV;I7WJi#%JQg^UVZ#byn7)z+v$To;Fmwt%utyRXwIW%dW1-if5{Ybk=wO3dji6b`;pvB+i^_QhwWhrTYJEaz zOQ@BB)fBbfCr>7|D%BB01=%UvirldP9Zn*(mhq_+{_AbH1(2b6Um^Jbnc_Pn*(SYe zzTZgJ&68?RD}8dmWami~s$UUrkljNhT1FDR|6(E0GJ`}XaSSbx=n#WMLB>M#2_!mU z5wVRV+H(gaTDmZfle6y?+`PTN*~<^4Q(CEzIj?8< z;D$CS;iH8Nxy#REBrBK0C-*=k?GF7_)Wye|*x&Q{1@!mAnN8>~gBXc5O)hrpJ%K6E z1|+T__6Oe<{sp?+O5DOqB%2b?(4-)1P*7x`j$hc;@JTQ>!C%{ylOj1O3y0=?ANfD* zeG7OMMbdTx2?PWtC`W@Ah!P}tfuJBkMG`JDM^7LMNE8%YS76l@RuYY(5KN++JsxGf zth(z3S6N+k1$R}@RY>ISs-URg6}$lF7=);+fGG37Z*|X{IhhQXp!eBOx_E3Ba zIUar=M}ST<`>i*Pp>W)GtK&PSF>t*ZInOf?qdo7(7G5k`UY-gkC!*VmMxX-<(WH)M z_}`+tG7^UpYCg?92;a7t+@*$}Kn!wy0=MwWydEQln9ouJrytb7Yz3}aq%9}Is>k8p z=8g{wU#7tG&aQIY6x~e*;%{Pihnl6F6HV*Fff!CRgBu)(+h_{_>nNk}D=%Uc-r*jF zArBaYu?1$i$XDH=T+!5YdztXtSNxbTf)JR2r_R+o=as+h8jmZtVobqpQS^l)=Vi{v z!2GsR#Y=b1$b}i9E5C#(KKUJt<{=5#M7rkFje#o2%)qFg$!2r7!pMP$4J7JoL~P7{ zuU&hEnYzZfxq|TUPetJ^p=b_{M{b0Fw~=SGrnV@2nZ_a*xxgb(nLM5~af}F5W@_mG z>IHo3vmwpL7lnTehPQ*L0U%2I-=GJ&je{KUs1L_zHz`=T>^`G<6ohDgv${0wl7R=j zG}k2riVya`c0Oc``|6(M-Z`;_E%l7#*PfQ0kCshksUs04ftIXU9AdbJvw9z z+QnAU>?AdfgW(@8l2&D;mM&(iaEywr!tSum?5D#rSn1Mi_hrx^GO53CrTRql6Xs|} z)f?DBK$@ZGn9#Khrf$WR(`RG+5ih3hD9s<_T@b8SO z70}Z7G`ycM+bR1flnrKnA8owD=3kC>y6aNV=yX>w+=;{o`+aOwUyGU~ zY7u=IBPW*1V9e^yiJqiu(o%sz!%r$uQ#@8-*95-ahR!ys>e;cjd<4TiRE1xawUWxR zQJES3I8J6BaI+4xD>JHopIl3#Sv4@kQqv3nLbLvXrvt9$=?iQn@8)VqqKa0aU8)$t zDt4m^7?ZTRX0X1MOY>c33a78e|AT8@oN~hb$xuhIu6hYPi1t4jAS-ahi^;*OWP34l z>q_armJ9`Kq=aM+MVjF%*|}pfm5n}Sk$JYfmQY(%Z}5peCL4N!G~QR`jDH1+n-Zgq z!*GPd=r|P2#S=3ph#&5ij;<+L8`%;0VsHi>~&>Mi2q2IQ+Fb`e+P%BY$Pt^>_GTXNT3wbl(@b4y zZ5*8cZP}%udOkkvhuyVhBU#f()Wm#^WoI+2VVY;Cqd8?bW2|-}(#b*ibT^cpCoDY1xL3^Ht}A(8PI8;o9cds2nBM7y{10Pe+JTr2IyOxE@TQ z5O0*fdLKJFw}#JPoUCB^2yy#!u_1W`!uMnHxD|X3KWUE(#M?LL$p>}-2O%CkuGobi z$YCn-Bh+-~N*RQyMqcWAAv_!9`2l@`#3PSJCazVrWiPY2kqHtqK|&@-@D(*k3KV8= z&Tt69Jd|H{nuwZ&QfTR>AZvPcO<6WY1E~;3=1eNXnGEc8H6v%{2+XMZ6D+87I(yUA z=@nl$>)kA4B|H8z+q+BhpK!-9zR>+2W9xMPlk?ghs{T>-Fay}LHEHU|WNc4YiUbZ1 z(OwZZwiR#a1ZOgui@6(*4oA6*9ES=sO=zxWEDj*7k!lLEslglN_gF+&;c=935<8yp z0(jho0%w;Q*tnY+L=n0}QPgaHR=L|MH11xZZdm_Zzd<4f{E`#SJSzv68ACFOfdXzM z4oZg~RG97Q>h`DtM}RTsN4S^7;B)X>>8&D4f5zGqD?#crFe8&aR~)+rhuG<+8F#-* z2lbxX?6<05HY)K^)vD4%gIE4Xox6rJW(A&~4<8e;KjWSn?EW+EuFa@5s%N8TgZ80d zD3TSp9cc0E@mdNd?iYevc2#n56M$D&(xAYy!A@ayr+P^^#Y;jNsB}(;qk01Uo}4mSxp-l}}}3c3Eo?8?c}Z_d;XN5c{$J6vz`gE}4>Q zl%x{E?%Lg|boE46i60G2)6=Sn3~Lc>Wb>g(C|` zS%FIza9*)=yu%c(&!E06kRcOG#xXD^u;g$Xgkt)XsM0H>NVN2E5-DGweAE*o&lTk(QW=q}G$-^23JMqq~+D1ii4)!_kaeppUY z`Gvm2vuUlwBn^#V=!G8sp6A#NIFBe31bvF&qa~5g3&ge&F<@+h4y8}&D`kYUIg7}zSthc)6!tBX;eRjAKZg2rX>7;IswYM z9slXaJVsAIp{klyF$c|hmQvbwArFwoC*vi=Is~x}e*nqeh?j{@gm?M)zvx}Q_>7V{ zUaEok7XFpJ;d1O+ZP^ynOjm3Y2QJzycy8r`QT>e}7?29QpuaVXe}OQEf3d;hKKvbw zZ57<=F*w{Ihrb_?-`H*ukKz|a{l8mnF#J*7;S-GQHL@3=*W27+vZ2>1yjeAvdK7{W z*JeV{n7(9!F{Nf3f4$0ofH9?39&6&_7e@O(`vkc+?eA(To+0AM09Pjnmp}C9|F21q3%pvkd26HpOy(*N5pSVC|vN~iW zM>6K%t<7)jDcO!B>s+J+<>WKXTmhSmttEN@Q%A8e6!Q&< zVA_pIKq;rYE}_dC@gp-_CDagWj$kQ*W~pwE=p87xDQc>O5=dP4W@2~RJx-gHKHx=K ztC2Zb`U>goPdW1((O=nbR8G-m9D4#37y%LLgakyOuyhuF!XD8Pd#Su06=H zh_F5ejW=*{uqs0*W+RFw&Lr$-k+?i&VtfU;r6d`cC(~{Xwgne54sIO+@fPJ#0$g`C zWVaS~x8WZ3zo8?zT>u}+k39Q_Y5y3{A3(v)Vl?A7=G=&bi!_E12|4(qob8ubuL!|) zPoT_b|2CEkb6-Cy%5mHaQ&L1PV7#$^1t>0ez_nkhghJ)gkDpMgTR)hh&^5p*{WwN! zezJaiDFi}NML(L`7%u%d9YwkIV~#vGrXS4zus8kaN_Z4!Pf=$qb3_}S^W|?S;V6JO z8{ddWoWO*HYYT%3&wRdXc#epZA(<3$a@1Uu2}OV>R3>uArA*I1$39%~_&$`W0AD35 z6DNs2%9IVzK`T?!YiznQDWRmFF-Q3IvLw&op<3ZH&$i=z2&%9Wf2mBQl84o)Iiavt zF1(ij1m4H+9(tzYO+1yG!VjQogA7jQB}7pSqpt?Am))WNOkHU9sokINrqH_iUbe?uRyctrHk+9CS*#RH;` zfq8CyTmcmKV3?$j4CA@SLteY+*2ndf>xTYfTNx3O$HSM2=;-6OG)D9&UHaIjfj)AN zF;>((JFAVGx00y6_>1ooF8*TWuc3@E0@$o!yNg)~V^uWA<1Vtjt`TnS-`Q20fVWqT zszKwDM>yJipAl{jKnFd-)u523)!1~6+LyaXn&=!R+(k9=HR>+T5#;@L7w`NNJ7Vm^ z)R}{I7fEMA2+W5>Lq7hGXvnMgi-vsrlv_jQ0wqa9664hq6g8K>$g$k5AC1nZzIs$k zzwdl%t&QQ*k6&UwwdA_S=2L30!hGta2R#bH2D=pGA5XGhmI80D3PO)1SzI&m#z#R? z06J&|X?l&noPv<1WCbA?eCAW+!U4>ues?cB;*1A=4h12d2?go)XHk%szZL~~Z~N zgOfW6B&Y}xthit-v@u+&!C4w|oI9b0%TTWwIaLoGX7~_hYQRnfJ)_$w&y9JIqxUhR8!R(Am>esx24fptNCZj_ zvp^i!i)|4IOX0_O{+NUxvf5mNABeNSOOcb6>>YI0SOgXiB(`!P;#OAR%0H4VT6wV4 zFAfz#Hxfz!yEthlMRYqDw^XXGLkV~v)9Kh4kaM=lK~cSmBBGIoZN${3?Aqh zri2p^F^@lq!v6cj&<2qjC%j2|_A|VR$v>BQRE(38VR)x`3~v@B;xD)nh2hN-z9E~4 zGhV`*QyA$lcL!W5zyStaX5+6b;384p+aw4pvCU0)u#+jMW(?8!O1|{!H(bE9xLE!&v#CH;Ux)Uh=`nVQlyZzIT zSXW~Hh7}vc`-^BC**^NG+=L6+uMwiK*eV#O+87*!HAchv+tpxZ_FuXHa3Qt{pcIL&pCCC5`G@bMi@LmWE-@O7iWmq&S%G88IWz~m z4H`f5Ocmm|taTX5RD(A%E@Oj%`^@uvyq7_F7Jfiiyl0-{5kP*4+Ncbyj`H8|*z;b; zV|FIg0Aq+K1X%z%&!sNNxmC8FZ?Jwv7C;wj^cx;scsbLLZIlu$G4I5kN-jGK?Xh)J;=6yJ@r?fnQQ)ZPLl+yv z<&+L)(XRO7lk(iyXf%+cjms%*s1H2}cf8Z#7<&`m=_Q0E0*sJeC%}k7XrBSbq+oyA z@LlK!p3NRrUMAYccoXI!Di0(IlV)p$gpuz&Qn|5LRZ6N_asA^0DtYN@xd zoBsX#|Awl~4U4LszEM=IGp?1xXjhDYPeRq2fe?GNbFZhBL+IV{$+sHl8+W(5^iBJJ zV&{|nzeQT#wEt&gxcomEN?qgKRlfT68Hw7`94q(HH&__3u`G38YO48(s5GFvJ4Uxu#19;~xq7vOc z7L{m&dY}^h5!y+p#CD))l}L;~4deCu&1_M#6TYJEU7;u?;+3`am8>=mudm&hB@hiTOweP|G{Pel;Q3LHlEK_7fQImQE$ zqm=ZFeWH{p03CFcvgtMMElPQC8=y!NwV>G907WkFO(Pqi$OWnf=PgtXj$E!FLBkDD zH8a=|zpqldkp*N?l05r|Y5y3{A5fpYY=9!23EjB1Qgq{x4@5WWr;BbJ`vp8ZNMX4B>)KFs_sp?C*s{1!aHliA2N}5d>d02vVwz zL=DkMHvx$=q+s}+VE3iQtucA_Xb86We#_!sq>)$ow02<=gw(^si)Q5ysW|(~bGUz} zH}*mcoCUtBzXjTjs+;j|RZaPHAZ1*eS@&BU98)KrE6z$OpOjck?7kM~V6lL(!3?jp z0;k?g{oqzcS+Hmi4)z5y14r=mkR0RrY_}vR!+sc ztEo8mx{l`?>}OS5x9~}MWGpugKbBL0dU%F~vgaIqz#$fqLA7TX(Y!PSD;@v_ezuey ziN9pE)Jn=cLltR!V9k7J$!&=p)Q(|fr4yzE!)w5oqVR6O+i(*rG8$~D>jEC#eD*C_{NUVRY+|c1brpg+7CA={-N~%Ki&U#N& z@VC=M1s{qgZ_pi9aXo}X?x9{648I)=zZEZlfI}}`=a*-0-H8g#@VEL1&PG=6K9U$! zXAff~Yj6%Eyi^}_u0ur848I$Er9JRznQ-Rnudp@hUc=a!dk=@&Ak9`8j}bB#*Lz$q zi=2x9k$rgiB00P~2L-82LycY3J0j`4HhnfQeOK(GqvbqjHnv@iCm|x;Sb__M&oG#u zIuy>y5lXJ2f!G#%{f~#k%q#`LLJrmen}JpyI_`|marzxMmM}2wT%J4grwa0+l6C?2 zFK34Obup@XHD^_Wc+xjp64P9U?ImfFDI$X;pel^v45Uy^B%%~MbWjT8iyz|!u0iZm z3A<=iF~XLVe}e&*_520}AnLE{ccCK`oP*GT&mBqC_YHv26zsCX*s3;oKwG;M@VsRCQM|UqRzMXy>Y|^w+;oTU$w6ORM8WFwrt7?1^nUSu?0Wfzy6sOA{VS9~NmL;7BHzOl>9{e~h19Bd`_cE#x zZtZjw!d)KOh2!tG)F71#&WG>e7e>{KAb{sKKi!Em3b?BmqE@zgc=V*4q;veNvrqxhqo@kQzLitHd=*T z&3mO?1v_6I%W)}P7s`j+&HDu!Bh|EKHSghRc(gZKvd76tfI~=)R)dy&9ZR#TF{(s` z5_*m7C~V1pjOrWYRy4Ha@taV^Rd_m}Djvzw%qs2fYC)p-c0AWcMwu)=1y6b{p1tLa z$QLg`9*Zw=8vOiH+T7=IDgfoUlC2JekGWA?q@w|~0xhN`IYY_zw{k1Sjc;)tb{k%50+MfG7@+**0ZX;3fzM(qP%P_*y*DOuYjwBxas-Mfy^HYnxx0o{J*& zwiO8-C86Tjn3c-X{ehZpTeE-g0oDvVGnOZ~3)X&zu0<*%^lf}9HGj5E$yNYJ$vLFN zuJvqL%4>)}}T-y)bmuHahqJBRb)up!m=ye0s0=dJjb77*8GRetA6!Vc4 z6@BW6i>XXhu;13QR-$!pUr)#QeHKBy!5dY;2lLv$6VG z$86~MLb0Sj?F(~4-^!@IkF0d1Kkb?WkgaA^c%A%&2Sv1%wCxbVk8X58T^ zQQ+eaW2OVe(Y`P2d^`QVEj=R`J+lY$HR>iA)so6=q3yq#(Q?@R_izt3IuE9{B$&E% z>WcW0C?5K^*hYiOSbQp} z6C7V04n?Dsf7@@jw5KP=bI_usVF9JV+n!8m&kD3>Iofj$%1&-io#d1F29ifZmO}Eu zZjLk+DA1@>^L6b4A4WUZ&;}#<6ZSsf;8X0ezbl99C55J($}hw=Dl;rIc%$k}+Q!Gk zHnI}rI!f?Y(eo=!&lDgz){~QdDM9Sv@-&w@PSB98X*f-)6_fmN7iE%{LEGb<+$A!2 zwO{u5Ozqz>ZCZG>6*!^HonJz+#F-U9JYk`JhClIC;*(=YD!Ik3ME6oX zdxkcYawv(0Ca@Bn_b0cMv%PQQQ_#L3hrGt` zlwTvZ`u?`Gc!Pc?4<`Z73LK6HSMba0@7br>7em>wIEnmWuy-dFn6;Z)gi<$gE|pz( zw0r&#oVm0Hoq=Hzd6Gm!x5Q?>-%%_6bkQK&dlVyf6vWe$E$l*Z_lEKN1I-q8Wm`x7 z+TnXgDvH8AjLrqp@Rr8N=>{pwP6uPlaU0u;0;~!O4@1VLa%JjA7jS)kfd(ssgkf`8x^nhbFmp$?QMH^_<{G?D&KJg# z-HF0{pbvx>czl^5?uBOVa2I1aBQxa9spOY$1WEIWv|1puWPmDo3*dvcI z7%Rr$yrvj~OIkUd(cWVWD$qS*4rsY0kdw!F1HsG<#5LSFI2)|pPwNYX>s9cJfKUk3Z|u~Ahm_F;Q$ z_mdsfysu0Q0r&dbX<;vuw6NpF5F{mpb%H=XKI5mcQRz-EWG5SffYG0#@Ptg1N_SxR z7s?%YgvE$EfJpWtJS5zKv6!AXoHD9D=6F6cX*}1p9ItDEe~`^skE@#4=c*b8lf^&S z9IHM;*@Gy{JFc)XWoOIQfF`F>hy)f$tOuX`GV` zPx!~L3Wk49N>s4}o$4A}r3wlENbzeYLLr=jvJ@c0z_WWRRTOL+;Wivx#-nf(R_`%DX z>aX0DsD?X*lMNH6Np_aw(^17i%wJAS)bsn~dJ>ZhXa4f$ubS$wEd5DyO-H92&iI`9 z%ayEx{)&H|pFGGn~|z%YyZh;LK%&ipz4d z*oW;g^HF6V%C7OaEaSyxxmXOr0lF-I`O%T9W0DQQ@eTZyC*E!7ue=Ev_!<0_J60+6 z|AqaPTwRUJUwOCP{}2Akh98_R+_%4S^SGw?D>o*p*t@^d1;rnvzml1#Yw!Nbf=in2 zuROKOHVk$wv=M*h0$su0{gv^fymsNLi^VRS3=r~#j&)s@`gO=lve=Xr^dIu zg#9WOmx?iH`#!#v?BdADtMG?DmaM<91$pqV?ECn-gJREpe9PrNzUz08Ctb!g>SxLB zK3u(*s2`bCv66y4=w@WNI9aQVs!wIa7?%O}syRHLAgEaa+iPC{vI0h#vn`kX;!^4_ zejmu_9U@b{_knZ9MGrZ&An$m~N1w2%KeN`{>Sylvye?;V>JNFH`<{}Y5X=6qfR zLOAApZabf)?m4m!p7Zpo6FhI^x(!$G+zQMABUmE0N;ux9`??JsJ;#m;b=?NWXQy!9 zw*h8`Xek;EqvO5}U4Ac=FM7Q#c5#LpcjUeeZk2G#oq6{Kx6A zUrU?a%U})T=f_;wRR8lZyBaWc2kfR%wfC^uKTBwgnjA)d>|3W*zF{-xx{aZzt7+G5 z^tY?=37fT+Y5fi>@Wp6U@#9{n$6pWg4mUqtAj8cffN<~XsOwXb?1RUCzNPJF=*svc z*v@-li*4Jv8^0mn{}p@L?VG*ZOY0(EdwHPuCnfR2&t9%^>}3=+H?)`6;~nfJk@mx0 zJ_T9%Iql`{dPh(X%wC=VLVjL*Sq?@Vti3!52Exx?X6f=>_VQ$$-b9t^exm;!_VS$V zPKWK=UVb&AsrK^oZMquR%XKgw`?8mnsOcc=WvN}AQMGS-c?4V4r0a>=+STmKUOspJ zKJ8^~&}%Q>I8W^5?EqPU^5O>elJ+4(l5;!$R5wKNDzF_PUHMaGw6_iXsY~$=_F>Nc z*@wu;pVvNoxYZH21G5jULCDW*AI5_b2WuZXU<~uK4=K8Qmwjk!$*$A?P4?l0I;X?- zZ6Dqk-cd@Q;!Vs z+K0aviG8>lAS+N3YQ#RMTw#uVz`Q+r61LeKGX@4pS%#$bDnJSW!K@g2ueakaGEUSY z1Jq>8sJ;nCqrrsh3RoqN1EKb(k8H|>>!p|@Zyh`nE=7wR2wIz*!qEE+540hTJ}vi{?s!&e8VafU9|9lh;1Dt8nI9rL1D__F-nB*FHppVjqS9WCij~ zU;A(*)tt$W5UYx&Eun;Gn~@WFe-6&H%8|Njx?w%o496P8tE}Z_Z7jo_xyzbC&8WTZ ztHn?S)OJ3sk;g8KlD$h$0ONoc0{`-bBWIJSg!Z~pQMgCpVmFw+4udW_I`sp*Zrku&w|m?SEsu77x2-n!;eSJ#m|;QGFdMl1%__4uzEd22TfE&C<`DY8ouF z+1n9eMeN|iL{>8iPX}Dh#dbAG%WR1%Zm_FJV-;87iOX!*0)X}7q@y6%THO9Duf82~ zw&>d@{i$y&2Pf$p?hhpcnG*VHbw}3Ccowbep>vvSqq>5_iS&A9HwZ{1ZG8gzYn<7V z-> z*CDl6SDo66^trcB^O!r2?`J1YgY&?EBpAi1Rdp_!_bnwdUHC^&Qe z881{|Z@_r~!$=iQkY^_jk2BtnBzcJg;srcijwE^ZVQ^emkIyDy26mN`CQlf_Gnq5x zTp}h2!lv(Y`WA&#*l-dX*+Qxy-=fQOd2}}AEx-`4NZS=QhAVMNUy-gv;*tmD*^`!G zsd2Mhe6g3rCERnxgS|WmWd$~4WJ)B?I#0~Ib2G-lCaxQW(?OmqYS8LzIsC%J33fNVLjEhie8=O>@T0P=ft z=l~0wo(qV)OXLE&;tY{|>klINUz{eAe=-7%i9A^=fZ|C0fsHRYg#gaxb-Y8U$pH0 z+eOQ!pDJ3m0^z!ZmR$-IN6W;2m65KpWS99Bh1v%aCe3m z6jiS(?O7-%1&X?_4E9?S46iLR2CffQ?oPX=)8NSADydSq)~sBW8tV7{HAmI;z>TZ% z`Cx@)tioJhgQf!)VI;2+(hc4PB!ZE)@9MXf#< z7;WO=^>4GbCey5~%?|ZiS(N%dUbaU>p-A2bLScNHXy5^c!KnCg_je{D)F_5<`tlX7$O<-W8Lkr<( zxEA~z+;7!2nRU6nYI?nGKTkdKoM@XCgN+3pGBhX2qE>H{lY{%MoO)O=wPv94LT|-P zbM0oc)i)-&CtUN&54IzLg8E>1S139<-HZ-T;{?RMzxu&JoK1|ytR~v$q}zC7b^j~y z3inqZCQm1yDF}Ujiiq6q!XJHqHRnkB{_1pnfAt~i{_00KNHx5_+MbUfSpei%E_s=b z9C9mJ_)_8r!+KL&reVT`+%?}=fwS>kcP$6s0!~Z{tiVT7$DY0YH(Rm~l*-_6H6$38*6 ziaDL+wLR?7si@rP(f%i+0-^6lek(otJ@QFd0hV8PBl8p>&?tHQTLTrbj5MQqvovZ4 zd-SK%`59)a?9+_L*r#w>)m#;wI#N$lQQ(KHfI%ttt7-Qu?mJQa$_|!(&9eJ-q3Tt+ z`J{4bal%Lny|4Fjx)!@!t_2yg*nrE_|3Qf2J0N2PvP}4XA0cG5aB!eNmJ4J$Am|C* zBMi7q%|<|Jrt}8#Qvis@X5owY<+?W_eZJ1)N86Ej4P7JuLdZVCOZLl2i*>)C(^d*1 zfQvQIuz`5@lzz8+(d5MF^7`utP_mbrm9!b4TT>R_U68^Bd{we8I z(*6{%`&%>oQ{@1JKY6$#C~;WwsN$vqMCd=ouY{fyp2nVPkV@_X2?#Th5#r9Lnf+=_ zV<^UzovjLA&LDq`K^vK!Mr6gEMT?n?X20pg3>m*xQlK&!p)ci1sCQv!7@R$=CE#$N zIa|k!Md!rm(2CXGRA48iNOf`qAvt`!x3|u&7~kU(wB#WIT;DHy(TB4X3#$vH%f!Y3_*-6lv~e zSQ*khlr(#qdx2_hVWZ9cS6}sM8+UU*;}?nMj)n0zD{sn1hS{S)K`2_5Eh68IJ>u~{T$v) ziWM%L=9!TzGtDzj)QO4KQs0nYWiW#ASZrg6)x^}fK>FnpEr#=;^OPl7N~}hY3v+}0 zmU5*k&!}343gX{WlU~NJlxA!ws>-E2$636x}2{{2^2{gm6#;P8(>FOy<6w17Pj~-&v zM6UMLv_iXxs%N1NkO_NA&(kZ{KeV??)0(vyJ8Qmbb31%WVw3#45cDPWgTG! zu$IrUQv`KwPsO6%kVWKWgb836j#>=u*NKw40p<(}lPD$)6D5sR?n-WKYpK$~vSYpd z6x;9@yOVy;REJbrl}q#%kR|YpPxs;i>B-b}s3>gK*lFU(=NzuNsoB^5Yd@3as;MdQLCzEqUG5 z%N=>y`GZSd63Od~YA#oz-BzGI*c=~&CmA2ePW;X$uJi;DcNw0}jiwFQFaJogfBrU6$Btbt2A~cn z^XD_vBr+hAbOg`k_+b08zj6w_Rici&lIut$G5zEBx{jy2qmEg4ia&b570p@d zFzf`siUv~g*qA}As5hPttTAUM>R3+ccaJBMQ4vS#(`|-r$VDAH4!Dl>OPqH6%CC-* zHp8Z|j*R$Yj!HjL%zPgrU)$m9?qA<|tIp`=#-D2F#B~!CL~4>rT_D?h*%y}$BJcm-z4YlZvh^-%arYpr-^+d|>bm>l$X$ERbQtGB7s1{|F| zYb^=<2kI~mK{8jV|3=i0uVb&zpNyK-yGin{PT*rT{As}56U0ROu;ly%I-@AO91TT^ z=J4)%h1w6|)EC}bKQP(yy*cSX<4PSl?nE#y#tp8XmjCNKcgv0HhcKufKzbAYY@NTwxyzp0u5#o_c`G8(?BiaxRR9-RB)t|tyN-wD%A@}(!m;ErFztA^Gvz|nL{BkxZnZTZTNdzvu z)J+m7Fa4*=Y)Z1~Oi+XxkVOGHz5pga}MVKntw7zddWr?47VG<7G6 zW$f)nh(5Z+v;w!&j)?Ld4lzW~gt51od?|v2*xPML`oY*6BIUeo2eG%|syi8;9mfiw zNjUO~`yuVv8!ir1u{WrNioHQc8i}bQ^yWlVM}agwj#yT}!Z_qm(AuVe>x4oraHmtsX^dg|a=H`1y-biJ}_Op#Pry9IVJ{m;{HNWr$Y z{9q&vs}(z&m5xxHaLgHRMc7;f1CTIhy^}Oz@8&H2Ac=xmGR4e(bTnEGGdsk1;Vey5 z{02qT&ID1{HXzEVQp%oWZAjS1#Yu!+e*lDu+lOflmoQ5@joWDZVw6x zp`AsMYY~HeOz!dE?Tib76$(F>Q-i-uUs%xJnb zRv9j3X!~Sc2RfpG?xVzT-F$(|aPb3WS*^hR&`NE%o}dk)oE(TjY|Re*gS_{RL8U@ z#I!0|dRV{Q{wCoyP zVA*f*gN2oi*9Dc0)`gS}!w(ivHU#Uayb`Ir>>9o-?T*LNoPKYW zb*kKzTGkcq&qDjN$_z9b5zHBxu?sKjm{QkKlA*)Ry##caI2~eEF3*TmQMuy=g7T(Mg1$Hbl z7g#Xzc`$}nsjSsu^=^<_rqfGw9G^HeA@wJgj3kB&fBp!Jb{+X?7VvT7I!ePh#C1JZ z$STmABZWY{#CHiczGDGemnQLByR?xgO@DH%e6k_-$lS>g#LED1F+jCH-)TR@lrt}^ zV`2BGG;$aknO}r;m|)~uyg3`J;RwpDotR(1)Ku3@Ka^x+@tD-sV6d_3aIR12O=E!o zW@E(7#emp5JfZ^!#*@tOh&JJK@lA7LVh(YGRLzzly{T%M0$eJ94Y5xjBmIvazBl^2 z9w7b8pyPX`e=t>XzvzESl(rH2AJN);tkC~?Ac_8@@z;ciNl##$vH};%cOnkB?E`%w z9V6TAA`l;>>-aO|f?6<${tUVw;i_W%F_9l1p*-wcu z7TA?o#+RU8Gcqa5tp2L>oKU13I~F#j^DC@iW@B?fzk&&G-LkM*ina@Si za8$#A#IB?40ptwCtv(-@y#ob-&U`Ba1*;q%xLc#xl&DBy7`BpRikTo zQCCmhC(YSGTm!~Db8rssT!A0DVo;VcJ%h5*G?<`4x$+!MpP0kpcTnDnK?SrC5j~c_a>n4B=)eswHjz1#o2CIP_}r{IFjKf8v(RkVYcfoFlfBVcZvyEoLD~>o z^e}s~qP^XlN%ybe{vX@S?*aQrTQ0jYuPA~8CDUcz&orEgQI9sBUgWN#@J94MY%6T# zF|t*qsQUZs`}X=u97)WyE)Rd>-&DNz0kf9a5_X4Cy99q%RU(pg^9e7`B*2c5V70YGlIY!eEhER)v z0Ztb9d^E?M>`?ery6Id8GsCz^r1sP7aE;k&CG-e_JpvYOY90&7wE{5~Alqr&3AfpK z7@^TN_9?F-`T7cakZpGzE1TuM$%aybbD4`yMDwh`DQKxorP21%u3{N%uFW$bOowWv z%#6)}-&u!!9-^bDf0ER{Ar^a(z4|1Ob$pZi?J%d#6PM)_!4fubz8Pt5Mlh^KVDKPO z5wtKeBHIddz+e(yg6_*fUP%VD0xrg9V z*)&1zweuVgm!yI7z%Db|275$SVvh)hh+VA;?G?jaTxUVRSuNVDd)62Nz4~cH+Rw~M zEiKc6Ef)=9Qh@REct!GroG?fN<4USCXw{U*UaiVsr#eOp5+pmtXc%&M`%f0o$te9&qfaa z9nI!bfw)8LyKL&}+?JLB%bKY>Il{{7<~3wiI4y^asSe>`elxhDxsFa;yu@c=reQD2 z8q?e-ZE~N`@k>yUd{5r5L;x|Q1WEEpJRL{{gPjV7`c*K{t{_Hv@6D$M;%G0I#TymJ zcx=Pp>{fgx6JYJ**fFlQ#f>$+5#Su(k}W_;i4=P+WNw%_3H@ zO&n9RdabeokFXb_{m%!$3WVAyl}pyQ5SPZ^#3}?V9ea=~MgPcD(jP`3L(a|rDtU37 zH?=wvEQbgiE{-$g5$l45Br4HB6r&cMuw9CIa+MG)H>xke!~ACPWAVpX&F(}g@vLS` zfp24ZiUrE$aol0DCs}^t$BuOoc9&8udpSD1vL@ENO+^FUs`#`V(YH8qmhPl6!Oohj zx*m*=WI6kPNlemxkFND-b-xGiYdfIzXh-KZVj~f)5q3{Wv+XIKqjN^}WSUs|MOEm( z_@#J)5I45o+fYknwReV70S_a&OkQHK_YPZ#yRd?pcsdX*>7*+tz1UTFVwG2?vz6u?DxPXtcJrc2i1Nn}ynV-%nOUwfKE&QHwJG!2M>eoRLTk zNQwQdGq=tG)3A00-3UcaGsEj-bLL&pDlDXqrzeMW_N74N?&9q7b>adjr%E*}ST4G>760;SU;n?^KQ&@ER^5#}ui{;HzXJMA2^71%VvJoRG zVG>rCJlKhuoQ~Z~@Ru`F%UVugY@}`;IhPg0El@ZnubO}bY;Fja8B-_lCVnEGoCt=B zcM1rbSkG{N1Bmo$Y8lSUAYI9TN>Cm2W)v*!WBb>d{`2)6*wALs47-^ zw+gY1;KZ*BSUdry$^dY}1T!`fK(jJGWjd}^-Y~}Mx;_2+6r2Q*-@EbKq3-q9&G1e} zpDOZGjB4I6W+FF9*To4Or$0lHzI3UKs)s}s#$f?tMka@^-)bN0W_(oF>c8P%ozl?1 za=O>*`ePc0&KY2-zA@bDx(dUK^XNLdAzT=tS@#aUBkNAOOS7)EV%KvlPZ;+qe(}7A zV)bJh|HnI%@v9vCI|bk2pTs*8TVuIpb2z83T$+h#e_1^;K2TPJI;vQc5SQN)aWQftd|r7rN4Q&Cylu)cmw^DUP_TERR87(}Zc+W@Jn*=O1WEI*V9?@n7Pc2oH|Hu0u=XF9g2)#EO)Kc_kj} z?!o+ze;?F1&*1@DTGvKYby{}ppW=Z`%ZpusfxE7=75J0Fup??dwe|qpT;CF%uel3`P?q56L16`T?IT_yh3WTHO)vZLRK#-@#w9r_xo zRFsJE(<*n52B;s}s5YMHxnwkb)J0r1W2^+r4OyL_q*mZve1}(UIO?tCVBN+F?7}-| z3k3t@IOLIziV4n^-3c3j!5tsj-0_je9UlcouH4%Gfb3;3y5F5sf%3Uo1Up8sNrB&v zw*r5}hrOVR?ci?I&Bi^_tV&IeQE>&HoVWynJF^73Ayyn^6A#6c7AE{DHsSY1``@$p zu#{LPx~OD{6tV^I z{a*Mo!q;ecxfh=PD&X@qyu=IN#P4Toc)k}dWC!`FM^ zmlK|;;S0U+A%xe%R7m^1@UDcf(eQFFT*{xX;U!-9Ch30-&-cQY5k5u3v%K)RBL5n` z^9OJH3D48;^^L%#{TjZ|3m5v4c~`aH3-8ME*JyaT7oJY|d<`%0!tePP;IlP6-wQ7z ze2Ru=dEs-Zzr`B9bCDc-V486^k2gldf`I|ug9if>3=W0E8%N2yxa?y^5<)K zi5Gs)OZa}ahUa_XWrR=B@GLKUuIRsp@7(EW|6FOmhOhU+tEK%KzR(L-_8*&xrTt#` zyDzf+8eZ;&r;Gj5@DeY4(<^MhhUYf|=l4@IJj)ATChgboojW}3uV(pq8ou5Oznt() z4PWSmkCOi1q1*3;-y{96;pJZV5RrckFY&_PC49Dq=X>GG{%d%a7e0#mTdd(bzxTBN zUBdG;e7zUG>}9rJ!xwtta|y4uBqv7RVc(vGn4KMM+mk~Z&!}GoHQA+@y zqTyLy_&tOdYxvIZyzM7EPs7)H;g>H3JX6CLdf{^kum4WB-wW?b_!RgPp+8T<*L&fCW%xc*!xwttb7_C-|D)UQ zg?A-?*JyaT7cS+`*YFZAe3SIQhUa_XUB&)sc$OEQPI$3~@BG%&{yyYSo`$dY!k5v0 zWor0BFZ^<8|F^pRUidxI{~BKIg%2Tr=WBS07hX;HYz@!%!Z(q=DH@*Th0o>p#Tvfz z8&CVC{5%a`?}fk1{>#+xg%H)0F94pY;S0U+xrEo(>-Kx$ z)r7Cn@NzHwa>D0pc!?K&&$EEf*6@5Uyo~TE8lL5ak0QKS!*_1?wx94k4PWntUrzra zQ^OZ};X??o->%#5g?A-5vmhUa_X%jlm>(eNxUd@kX|8oqOz zr~S(R(eU+NxblBAe4!UUgyq+7)9v@dyAr-e!^^$!bi(Irc!?LjiT=fG4bS(&#Xp&% z;aOg|_$S30zVjl(-nTtXB7SdjX%y0f0)9*LzjQ6#_#Ee-$~)y@-SNCTQQ&Z zZiB~!_IB3vbkq2&{qPql{NWmZM@-AVAO7vh<*(5All|~7QTW?+f8DF`2l(OlQ22I# zP1N{?AO0SANG^TvtMNB%@!`*#3g6bpmKuMaAO1rM-`4kaTeST9;a{!rEv;XVYy9DU z_-7@Tf1Sqf?1$e@;Xka)AFA=UZ}w^LC-9)apUE2k2#vqk5C0j3Z`+eCo3;G=;ZIli zwmn&(@yGe$4^#Lye{R+IJ^k=IDg4!%{?QuW+T_#TZSa`TUfZ5@)A+0X@E0lk;oAP} z*res(5C3+BzxuCA-&bh-$$t2kDEx;t{=FK1fFFJjg}+$ahlv{B@WbB&4~g=x@%w80 z4PW^1=S_t_PUE-K`1AbmA5!=|HU7FUwEX+wU#;-1zbXDauJMQa;h&XU{&gC^vmbst zg+F|*Du1ZP-~PEzdq05(1^#r__(y2`#eVqDDEtAM{w<$t`S-)0uJCRCEYSGl{P2e< ze49VFYW$vl_?;BK-Cv_MzV(?;d$+-nLVJ5YrufrMDjVT%fBD~bcH`o+s_3Wf1DrwFoi!r+rwKmeosIA zP72@9_@gzxwZW&o+u%r1{xv<_H2!Ko{6z|XwQc`5X!-ZUzg^*58h?expX`T!iNc?u z$FF-e{s2Gx9twY+#-FJ14L|%naE#F24I00%#^3OX4}acN_>TXh@#p#BKcw*Q(Ei)H zPqh5|;a{!r?eYC_jX&HE|15=X+pFs|erG@YcDnpWwf)!l+duYc?!ngT(tH$r?hu=xz8@j!tHNN$cPkXn)kwSYN z|3~Am_QPMK@a^{Q_(;pYAO7tMzq2j>8h^4M{v`^3_+M0i-K+5j_~G}^{p&u|^6!U#wZgak?Z-9#a6kOB z6uzP5^E!>+*$=;+!XKdVhid%oANaKQ6F5@f&mFqGM`--Te)!KQe7pQDA87ga!=JA3 zZTc5z{BeHx!xX;lZ{Mo%d-~ybQuww#9If%K_kG&C4UQDrYum$a8h^DP{vw5Mm%rnE zE&qP_w<~F=xYH>~&J z&zlP0=1)tFKhF>UA%$=E@4EF`{{8T;R`@ftK0dDThx_55rSOMq{OdG+XFvRQ3cs_) zAFA=Uuk&f|Cvc>|pY7US9ij0T`{6&M@NN3Htkd%Ehd*86FV^%d(D>v0@P{e<0S~JF zy;bA)^uzC@@C}VWTH{;q`LuT%94X5G1FHOP8h^DP{vw4xPvh@+Ps_g_{_P5X^}VY6 z6&ioCAO0l@|6z@Puf`wXhu=ftPuBPoHNN48zXy&H+B-nw_tp3t-u2U;O3pD;XKm1_|e}f+1Z`Jrc{qQ>} z{COIGw8ppA`m}c&94WMShQ{xv@mKrdFH-pS_`YMUmVZC|+ZBFiUH%GK}Z~3(M6F5?o2aSJ( z#$W7*|BS*Ppy}W8mX?1%{OJnc(D(~9{y0DUVG93YP0y_wzo#F5Cxt)mPQ}mB8sA#u z)81`xq|n}Zy8Lb$f3+X}B89&}(^#mflnZiJU46Sz`-3c4Gu7H z{SNqfz|Th>%KgKSPA|Z@eA478Tgr=0FT}p~M&bIrSqQmsa1_0)CGyw3k5+J>exN{p z;K+;4*dwRvdHBplbK?7K`}_Ot?^6!wdmIi^^{tC}<#e3(!{IlZ(_8T^ z&)eW!N1qJ4z{&eAFwq`|AFJdm@FQ>EpR4?U_ECuGNP6%sbP{(19cChpofWtT9vaw* zd1IpPcd`B6lT~-={(OJf&m> zuJe|U98UXDzG($cO)CFgcwBD!^Q8PEyycsI<;!^yeR7L8;@~0xBo@JePi8_m3#UG< zfC;tc0TN{J7?w>OoFsYG!heMo(=$^_({KV42`iA#3D;E^f2=k8tug*sQ&n4v96(mQ z2COxaxe5(rQj%!;k%xDb(u(;OXMb=dsEK^0Aeq0%Ges$K9fWcw@o@?tQFth)+|EvF zM*G}Y@}Wv!!V{+8$pCz81%C5JdCKA}RJSMt|5$-b@yxSJNQ;8gDrVS}tZzudn6kWi zbIFTC#cz=OCOjw?G!FY1N3~puZzMkonM7riBnyjJkrkMWIwbi95C3QLq#SZ$Ai0Om zxz*!!wrWG{mW%9!YLI7~&++4Tu^Bntj9im}d_UP!A)b5SK-INSf60!Yrw8uq&{z+A zBed>k5BzXJau2+MkFCI#e<%0A20S;h2VVbhKYO4HYTio^JpG#LfwT+l^R_d$R-o%B zwlnx1!<;xlw_Bj2HS({Ce7@VkV94e3YbTs}^6#C{4N%OT|V zj#4Z}1{j>PvH}<3OPqs8d)z{PBijcdN7+b#W(zqk_dzWi_9^ERK4`$@L}T1iz8IA_ zJVx#lE#=u-%FR`Z$8$zcPN8&@8*CZ)OTCY@Lo%__)6596Pp5&!=Vd3c_EEbcB{zCSGPJu;caJJ1j-a4i0Hv$!Lh*JKtqe}BJNJQkJgg~gjz zC>Hm>z&0e#ej&~8XnILEbyVJD!cAlDth^s~Wqn%fn%BG+QKP2^5vKS8c( zu|>Km*KH`*enLGa)64M%D@on{aQxNtlQ~|EFRj2lw9d`($JttN{2Y%^?^B}hUYE>n zyBThAu1E2E;q~>)6|dhKDd&3~{x(0}&0kz&@{90ycRMeCM@#ST4}X7kUNV2X;!7(q z94&J5cPLxfH2(H}Z{Pf#jpFyh-;T=^e}6Y3nZG-7-27$I>0d&A|J>Hg-yK5H{_wY1 zaWa3G;Y%y9eQ7d(x8S*n{C(%0ee*XDmF|VVFD_C1ZGS%ao9u5y(;w=hn4C`|QGnaK zgvsZN2fNM;zlk(b;(1iTv7zU|zhXHK(D!Qx-w!s#_L-7Az^pc^3z9v+YsfShk^S-j zZy2WfAzOQZ{qeCCn246U<$N4D0XYvHxCaSpOehr0KUY05iN4_w=Y}RH2&tS-Zy_MQ2bu_+iH>G@1-H|*Oi}a=2j-lL!NxO zRg$UYkxM4}a!w4Aj5r3Jn9M49GBR(=VFoYeT_|AQg*@8Z@f5*arYb|y3}j@wDyIbb z^N^4spGlbVV!e)I>C4e@qbeXZtyAg27lI(>;?7j>BW<_vVu5J-di<$gRd$mkCY_OC z_S;d~4tY{uDQEugs!7b@#d}wfc?owR?4}MNk>hwIekwt7qOVb4Fgg@dduE~tkL9d> zyJUmHO)atKSK#&>AR?D%ij=bfx4P_n8J&eYTr9cB#abI50N<74RyN8aK@(Gu+)B!e zrccwqvkDh7y}A_M=RICV5DgsBS~9Ws7{!Zy;qM}!D5%qf-N5>gJZF5OSw?kN)D-W* z>M)znvjV>bDUx(+d5RVPgylz$>8Px`6?lR`Cb~d^EZj!}{l$y;ErO-50m0-9lfA+M zCik3V;A)j}BlGSY4kEH1`yF10din8ZsMYY8I>Ju9c=@ z_@)3lNl$Q{ii`JkdnowqOXTI(zcE$qa~UpB0LvfC5SIUI1Z)IYQzCp$heYS(Drfb|+kl#uO}%3YP6C7~(z1&566N$&9QJ zJFc!*B0rD0q6I1el@oxl9l_5oAVytci+|B)__qi*B!EWFgFTy>Q#J; z%Q%=r4D(WSlUB=GypOakW;$T>KmH(FcQq4JCuEqaX}zdavp-V|>I9V{6_?QDAkUwz zocFRGt(+$F03w{g*rG-?0QxXvQ*@rlcTmAX-{jfsA6+%r(gP7x2#p zKJ3(axUKCoqpCG}uktKhG5Gx+YSOhC!SI@*?i&k?J69lgrpfCdd9PJgWe%8c+Flp2@&f^chuzi{yZ9o+vFoFa5*Z}_Te*WT?6|dRsRk3 z7c596`BjCq716d`|H-PE%?@%5?#KTnUn7Bz73jW@Oi#<932BSh5Qg_qjfD0uCyXWp z$BD#zj>U`kKZPf@2|;*j|18LFGU9jQOLWn%b1r0;U1UaImWI7_JKkG?8A8dKIfG~Q z9XxAdDsomeGo#PBF)k)XcsuT=UI3*V8cF{mOYF_{;OATT8HymdgAn}R0oJBZ-BA7* zUU=-ynK@SA5R?c7MWc@eiX;2fAKicgY^YrVAfE)t7{G%X=wj^JQiA*RYA$2!}3{<{;U+A$@&4}!IfK)kq}p) zr4NT~ur2urAR=#@8ZQft%oav>aENzr-46(~LS>H5Vnmu$A;q80|>HRmv91!gmTETUstGJ^EV|ho9<~Y^FbTcye->! zp(l|K(Gl3?|13`_sQ4+bG!SQ2SvTk@fS?MuX#$F0WZ;U|TD?ZwgYt`ml@<&bZ<~XF zyew~(a<9Rs%zX=YB+%)-4`d*RjmL`@??E9d-=-D#gR+$w$N<m(S8i>qZphs6bm&4VvJV)gDt|a#0yKu7gc{@RHcKUqUhBK zLZAE>K0;>>C+cDsJLJhMSN{5zCi=rRe(@60kC)+Qw}R zFObR40##kcfHaGb70Pw*LP7ik6fZ=b>Lu!Kz%)^9NmPdk34cM;S331zXnTpYJ@2ON z3CXZd?;%*bg}KcwNdYMohM&by!-0V*CXZ_fuWRj=ri+1#t0o~3g>AG%zt|F=QlPGf zy=0&Tc7|?YZPLH^k`M3E7EcxD;zxHwI~T?XVYiRirrAwme)sRrek%S;((TE~xQY1?th7ijU zxKra?th&fn0+v&EJ&Vr7FYp8x6Tmk(_7KIfY{smRt(Fmq*x0+;UF$u&iA0vPeTyeJCN>miaGCnzC1)jFQ<0qxl)Ys_r zJPi8TxbcNEPGpPE!2cE>@c`_ncf#c=J)C^o``Zj&%23)ZyEf4|gOd9jrXKZ86^?SL| z3P-w|0|)y8TA|q4D6Nh=FJ{=~FUKd1?|c{m`)&mu5_bvt5+9Twd)ZK;@TV($GyERz z*+bdraC@@>*XdpRIVyIwyzY3j`fcN$nyOX2v8phmrZiBs3Nxqbw@W+Ex8C0P{hF%5 zhg+p6fSQd3NOwGmKj{;VUS) zQS}3Ugp5~SEyQ%Dur>y+56u`7H7kZhi>-mtHt(|dV0dkCZQbBmp**-`X*ql~c-GN5 zL#p03s%S)jzh_`H?F|Bg;kU!J!L?rwo;5NjwUC$hO^%v7@m9ZUR#>qswRB9>tWUga zj(5#Uho;5cAE)7E^U_laqXj=i+bq*X>q622ODjFRq80_e6W=VdR^WLIWfx*j^?m8_Y}BlgdDi@9coFUY`69CCWOhQde+%JNwtDzfAcx^W4gK;j zZMA@tpxD6eOtJjyHDaDR)BtVNuoTY=+HmcP6@@oj#Vel0$u zO@M5|7{W6FlhZHLFS8_^pkEg2m$`hIr(OoOzp5-T3<+kJvEutP@cp0+n9BUrvJ<#u z4&#_=WCr1HoR@86UI-Ieg8z#VO~G!D_9w0_?0cl&>>(snaA z=fJ|C<~L||<|D(F`HiJV1{%C?jNkFZ+(_n~m}5`w@4}zHj?NV#kd5)=&{*{ZpYt?o zufW1%Na1?S3l*g?dcxXaw95FlA(ne2G(3!gd5tNew}4gv;3c3e?4n~vmvQ5hSs*Yd z3;4jAEHclR5Yws+$e9;jiZn0@4Y>U?BvBd)JNwqN6<#I$$A2cuRl*l{1(}s*CfH}b zAi#sYKS5IPFR`&Wsc%L=`VD@D7La~zPz|KFnOu*K6Qt`jNDDK#2CkCJt=r1GrCCVv zlwOozzyE4Z)s#U!3FM^!QZjTwDD=Hj=K|+Hi`8|81hxgvL;wW>r!msS*<8rs&#L5v zP%`Fe6x78Mkb~2D8k!F~e|?dHn(I@8QTgN|Q85d6lBsqu`dX^OcyywI(LQZm!Sd=v zF0YE3<8OoF^A@EcHPmd8i$AtSDfr2u+{bJ8;D9_|m&VemSJ5cx5Q@ie_&*`EoI0QO zK-+|{*ztZv95ld#M86lpFguAA9@+=(Gm4Xl51Oe7iTL^k#kul#`xX3l+`sOigBwJj z10oRXtrE7-A?oRFgYNoc#c*p4$Gx@TeV9 z;sN`|sM;z}^?Wh{5GluT-L_b{m5AdbliEr?1UGVkcJF)nhKIRDU)k5LxHNs%x>m`Khhp)*i>W{CUC`)`z zKb!cq-RhvlPJHgy7dU~C0-}KjL8_y2)-sFR6l(6 zuc$x1jzd}E>#9z~*GW%D;p@Tuz!wJ>?-(Pc_V{X64PR%DJ_3AEc7Y%JbIeToawAkf ze4Vnq{`lIuOyTRyj>OmYC!_H7+&5$K_5RIAfUn~ezJ4PN zCcXj))em3GmewC%_n<8C^?nE9YsMUfFa6%nc8AuesM)Wj2G^}uQt@r>(n${NCEUke zXyXvoBoZQw?Kn-cRlB|8oxLYe3Tg(P`on@MyteRmARW8MC#B~4vaUdDXdByR>^D}D zd+-@*(0L=Y38+}ut8r-CW>v2wOyJZ-m+YoC;OzbebkWPu9^N-479$yMQyG4J-OSKW z(44gkF=6MKLJ?~J2G5^P-M$%>lr>s78=nFf1;J)ji$O2*M>L4MA#dU z%1Yq5C-`9=j*@+8+6wgQ5PDZ&edC5;hIdkBwTRz&Xn=ON@(L^|Ja{-rD!K|4@nvhH zB=+YPbD0`;Zbk~0FD#C2AhFs({bwz)>OXc=pj~qJ1v@G*hQRP3b-(yH)?h!OfSCJU zLbGmfmsFY;%jPg(0{e?@@>WZe#pzsa#BFY_c4Zj^zZSGOk}VDib;{M9)KBcfTrY;4 zu=5l_7D&elfS@JkCl=pDWl$-+R0bzf8KeOtl$+~YDy`;v;h_PhfO#Lg>l;xr*LTJj zj}h(RobVU+1*0{ke1Wa7#NzI(5G$hSji?xVi!u;(0tlBS6!C1@3{)FxvAcI_)5M}( z2$!)L68S1=h$}tQhO`;r(dK}+d#+g(Wom%`(?AyVizO!G1yJ4+8*-y2u{K)@Fn@ToXSfPHip^=JJ>I`lhld=iX}CsD2q;`k?c1Q_lfK*t)em2%yi&&*q*Y*da@O8mX;7hF+#ywOQ ze2soN7GL|XI|6*kDHiCz95WMNDG1dMU%$Ooe|)`#vZSy5rxIUFABe(Nai&!@Z&PVVB%{LLiNMf%s1+fuK_4ad_8e8@ip{*g)g;U zn7W;Iyr`|S0vPc6X=K1{7Tah!qH_kO4;6f*=p8ewy%hG?{2J`BK|0lN=L_{hMGV|< zE4RJ4cEBHaNI=WJN9TY$6LXw)v(7;u6_sNJb086$y1SvL1x_6a|3O$2T`-mc9xPRI zv9qT4hOCYtmdz`9sT@m{bwU%~W0n1r-B&A?T-1*}Gi-4{NxXfg8aEe^vG-R~NyL8C zNx+{p9n~hR(aMm?jVWM;?kF+)QTMY0g<)qKOV!V!YA(DAmnfBPIn&s$I#$j-pIiKD z8){V>5Hhx*CbtlkG8fT72UcPdx`LqwT$hQzPT<~YYNuv03gI3Lq#7#c;nrKteu-Xh zeSxyl#Ch^@$n{pm{s!pg;nrKf&Zudors>SbM=& z-}TlltipH34XEH~uD4D?wbu1kD+AJj(opT!TR$?tUT~)Zr`KD_ACg$-u&6()jCAOC{`{=D-kQz?k~h{{{iPbL68qqTLh#`f>w4=P z9XkcF2I1@9!_j~0k1_Obv~-?)9FqR${aGve_tr@NXu=@I`q>-0qVBrUKMEL49!>g3 zwTk|y)tmlV1?V3Y998;9wNdnMKsrzwsssHqzd`>X)+l?!$4HE#f7J`n|9$LEH2s$u z^uJE%pG86cq(i^+;L{QMXM#chQVr=JA431mDEim2QxIE6`tPwhhW?F~&XbQr(tpXG zTG9W#HPSztFo?09^pCphM*k>aG!&ZSAM;JRZBA zzPSGptf%Snf%Wtl>9pa`Gm_Y<_14IP`wygGi~p z{o#wpV)1oi-VxyIc!jSEIc8XQYX2vM>W8lu^XiYU&z@HJIgvUtjO`u6=eAGh-8hj{(A#DKUHbS_14-dx)Js zGYY+CDb(Oo-`!)iY;sXC= zq)X>`ih-74=f^09C`C={<|sz_y(t;xZ6sM_GWPS}s)&;f8TX)JUgMcidT_G4C!n(&u zvCst(KtY}BJx>`0i3R1vD;-OS_26BPboxM6$nOm83#kMa!7BilJczd(RC{i}@{-g? zLO0&2055R+lnc57x=ioXD>EW?>y;T1JNCUC!E0%;!QTT&fhvY0$>~uQVRr$ZRW?~A8tw+WsDz&+0=9J)c zkhYcn2IpLnbGee(y8wl9Gck`_;C_jR6nz+{Ea(~$xT3EipU3iAPZ!UE~)@6=nK} zUaw3Z;}hyk?gcY=nWE6-UbutglBC5BWOjQS9jmaME8aQciBXNfXR%rkc!~VNKFu>V zATSfIcfW{+tFgePjt~+)B}d4NWvO(D2NlD$x-50A`gZYKUwCD#hhkHgp5KVS+xMx!@gY3}i;hjy4!#y{HW+{U7;U3QfEWo_6hkJ%YtqVKz zZnqrn>4kENAc3I@^d_+EGS2buNPvn4`z`80iOyO8+I<{#*vstbo~GY4YK$_If??^T z&ZFCVS=4t~y4yQDH63}a2dgkdE=J+hHU*l!Ls_bv9t0I7iF1*5GlIhrm5OZcaZCim zZ+cY?Uy?p-3`=QmcF68%g8!E~@Mkbi^Ej@PE6Jjk$%zcGG08kL+y zzb#U;?YRxjLn!u{jnRLZbl*X$97LJKQ}@#e1r%0@M%=9m~F2`ZUp=raEZl zo{0vCW zz~~AUR5JAUL32N<@>Z=m35=$R?W8w!rhqL3L^_b7B*Z$Ib)yBfuru z!USqgcObX*zOK^knY^~f`-#W

    hL$9vG@8-lB{)gf8>K6>|b#=hc~Jn!DH^EoI? zxZ-CfNr*BTVqWfgz$G7x5k=6$?zSs(yj7mWO`gP0^1T0eI(%op=UR;9?VeoR(SysN z8@oGvXCT+zB3>GY|7*em~$pFL9eE{7GKo!CYQL zgwnX!z!R>*(QdT77xmchVY?pO(&JA20rDG{jR4}ERCwSRhuH=9Tw)?Cub7N$S&^E! zYTV@9ZU-hb@_4U>H)x+EPgNg*I@F(7b;18q53Ng%m!E0vB{nXDJjtzdUTDo(bTWl$ z8mfe(NbZBnuvcfA6CEz00xW50ef&M3fUFrDiTgQj{^o83Fg$RWl%t2YAy(!fbx{Qd zP%hWm8u;ecePP`7?yzFZUivXeC%6@VQ0>P)R-1_mxPPtYhl#+ixP$&h*{a<^KUxQB zwzz|4+(tDRYWwU$eniZ37ow2I`xpC*h1XYsvQ4zjLAjtXC=i+530d-xj`2VR15tr; z1Lf^mrVr?Mh=v+51P-9zW4PShIIo5Gr@FI@i;oThz2STc$Ilc-2v~jT+tf@<6hK9g+VgnegdWR z=#212RSHJ*Z4b(SbQtE)rU^y8u`p;mYtEJs;^%%CV*>mD z>AXXUV}Uw=+^lI*JtpOCw-SsfD`4s<$h{e0g=57z`eBy#XH6!#`<;8HnO49uCTJ_5 zTdF~~F2V=p}H$!9D0h~lNV16CV(_%!aA@}QiBmDJL5 zq%54UR!Ko$0Gh204=zw4!S~l(k>H!N+1noya_1nNtb>Sn@&$H4-|dl9i90w+<*qh8OJZddSUqbUu4Cwv<4dq>v>{_Z?Tpy6+A zf&ZZo1pY>q0{@M8imy8S3&B}2@b^GQ4gWJptr7l#Sm7rYokaXkZUujADl0LE-7xNp z*2=h7-G^~kR~R(IxN{J-{q_tHhW0~lfbPatVGg%(--g_j6L$UrO6OU_ZoF^GpVhAt zwLlzUNS5A0q+!04``;>sBTQ*(u`Zz0x;8xi`6mjfX*%p&K8oL)0``3tN>ecC^Zw)j z9L2^4~h>^7_0esW}n34D3Ju@Yz(Pn^Z7uc3)s8>YdS%!&L4n7o>)zqpnXn_*eD>K;`1?7%l@;Tdo={VHN|gkgT7>H)l3js}<(SaP(_y_6%MIY+8?CC$a{d7?AODHY_uF*bQ_F{})I2Uv~%VE3}TDsT0mmBu zr);W#3bh0CYhdA68yc63bqe&wI=F5nv33{hK=-jqKX%hpP<D zGigPHDh(-#YcPfp;lP2~Hi(0RX{d`9KkOdRjI6-Ox@0LCt9i@uxOdNQoBs^y85@kt z&O&bZ&tDG<%mlC;uS(AKxx_3pb{LS)1v}33tpYf>QqErX1#sY9Bk6kz5O)yE#IZnZ zo^Of^nZr&m^&!bR6;-QypTo{ch{YW=s$S+0Lx5F2S;RYPfNjAEOsMlvoXb;& zasCsz;NVe;HkE@1YQV8V$V2ACq+iMGFt)vfUl`j!^uY#+tU(BA4q+w!)HXpu*tr-n zq24@T9dV0W;jM#Ol81yA2f5|J#V0p>5M2C4HmBVsdDXY$pUhdZ&>d^`62(#+vV8sdFf8Idb`9 zR;R_n9nM1Gjz{iP+~LsNF$PEp4Xp_m>jnOr_5rg#TO?IKF;=QR?3}Tw4$NG#c5OG3S7vlp{OyG&o7^#D-+EvHhi#VkNDt~9a!IuI8P+KmMonU`PTS3lU+(y81 zUN5kU𝔛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%0D1feUJ(90N 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

    kZlDd1kv1gyyj$^8ri#!QDqie9 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�h@f|fO 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

    4`%zY*qXwc6iP1vOoclLYYV`@Mr~TI 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

    n_ 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 z zuAq-vg97mnebie%(?=~r5Wur0nm(#gz`T^s(luTDsB}%+T*fMbbBi-&W@lSPQh{7l ztFel(A9)#ZbvsuCjoE1x83=yqcCIZIpsF{`LDI1e#oamUcVmDT?glu48;*E6%(2Dt>3NOU7wmlkD0QX$M5;9rC79%Wj8A8Jx^zq5l!?6Q6 z(`gO?|C`!Eq;qQGF+mL>QY}raAjNk6(MU$*IOG+cgSDsSE$Scd&g8rPSo=(CYBgl5x`uGqiD7{&I4NZ*E){&!UV^d!LP&Q0!u`q= z1xAVcOZfbwAH+>TBLWlsB}hDkGEEB7sK11Cyi#BA$v<|EE&FQ?0)5i?n|vm8)l^{w zsQwZdVx65#NX?lXBZ4P(71Se|>B7LEDk1@cX35iRk=i+bt;4)!fg_Y@IhB-L1 zZFYb0boo?fx5J)Vfh`DZ9AMf$S`Y6?MVXe32Td)wxsGzmG6(Y_f2FDAOZ;*|r&3y* zg%bNi&G=|_Wsdc^GEaiyA4Q$tjDJ>06+~V9vzpgFu#=3YkS>h*WF4ZQy6HSzL3Pt9 zO#+eCO=qTlRX3gO6jV2z-;wQztZq6tDyVKc-&9cDbgoiR-E>OJM_P5$$)-kB>ZbEn z1=UR_JuvaBxaq98nyG`R zqVqt$8W){C_-b5qX7W{Cbh0&I{~;PO^_TI_ImB;{H!*}$aOwmebNV{nxTBzd&eukA zqMi3T9-PHC_0PF49ExF>yC40E=`@%AId>%tVRB*m^1%t1=FYgy%vUNg(WGD2-jEgJ zpR?0NG832WCzzue|D687xTgL&Ib7a)mKiRSShQ@Tjce*)2b7-hoGDP8sz^Y7S3~|D zO1|wq^yd+A>ek}j`dAKs!>gZC_Yj0#&WfK8e4}waG|6enKPSoh%M{My=L!$ClMtR# zhryfz?t?r`$e+7VHp8gq5ak+pC+hhQBXD$`W*!dq)b5UDmGE*Tqpqp~68@nzZtHKx zHl`NSs>hkJ4Y^^@zsdf++p&P2ne%0kW4RoQ5yTHshrNloOGJ4RBNP8KI{9uRk1it8i9D| zbfMze!K;VPyUG53K^MX%#}vuWqzkgTR`|A=9y+f-&D8rk1cAZ)0^)i~9$$ysV-Zm{ zh`4fKEOzCv%gsUO+q^ps3}`s%2hnLyV<5-(N-%A@*VqXbk?oLO^uyJtF3u~~FereU zV6JX;1q6*dHSUtLZgQfnpbD_q3S69I!&ZRBW!3vloocAvBXReNo3fLW)~UU5$w>tV zo5B1Z*t_y>_)_ZHU|PFjrro(}M&UCG@y$@ye8vm%V8yTzTJ3K!Mkaea(HoH?lUWkV zR>FuvVP-BP3Or>*fu|W!XoM6-;NbJ?^Eon&Mm?Y6g}tp0U(muIMcstg;zzm&$&1`W zZ_kntmd+1wEH8ZD&gcbMR3~O}JhQkEKW&4(H?VVA=oJyao(~@jR?-qTktGZcjA>8o zMrFI^#=LE(#M`~CjuM?^#tO?qI|~cAMaIV1X!eo#8P|3nQA{8{F(^Av*?%rx!lfkL zu7lPSA8aQ+2rm@$G9cIENJYV1-byT&*>%Nd&f+ilaU#%j7Ef`L>fcnxS$rpdAPckj ze9C&8NY$-C8y+FU#~N?dZxNhu3P&uVygl1Frj2lxc{tj%ct)gZi=C0Z^}yE1*HfZ?jrhfNp-a8>E^;R#oj zg>Y4QB3xCT23M6O81xlm&?g)AnsHHi4X|S5*^G-yng7^o!sZ10T{5Viv}6{z`7Yz@ z%z|vbH=1yvGx`e}wJ*YULSby1 z;M5aSajVUc6kacLRl0S;)x2JYP9ZUOJX3ZTQTL$>9^vN1gme;stG+3?T4sv4qaP%6XgaXBOQP8c1-b6RhGI}th15oP!jWEQ5+8o=>VwCablA4(xz z){*k^nN@H6D42873KHeXbFE*_mZfny74fZ>>U}-lCm-@2_G$dFtH@`9E95S zn{Zris`bdeT@gC<}t9~edK8JjR{}<3l&n5}>mHDVV+E;R*QkvOM zVj3;`(0cG0<(cHPvhaqVGp9j!4)S93`#NH9s*JW?^7xyZlGFSE;t42Z#uzjR$CqD+4IFvCO63(F{0w!)THeVNQSkp3F8rW1q!P zz>Rz&iz+NVs3(1@F}c(sl*BY5l*BO>HMy8#U{NR&7&8%x2aUvd;8(po zp|RwN!r)m1>iBv=tAXXj4m~J zV|OaC`HqxTNNJy!!z(}65g9+n&dVVHPAW(6lAIA(4iWU-fIf1U?H`k)an#MX-6VVR zgCW*8Ym;cGS&JBC$Ogs-gQg-H;d;VgP=h?-LsFh|jY@7spxEtvgZTCpIrXXHLHS-h zsL~`0)Vq&BF7v|>-zQHM&>UM}u?r>frZUbZi_tq1CAuG?McE7*S?Pc%q{lHz(8qyhZ+9VHPH=>um>)0>FTOos`0x4^tfst zQ7{YOp03(@1@{8j-Bo+Nf;|B4?W(;-!F>QC>uCyR1MKChouJ@;0QYs(o~)o3;Qp@K z5egmvu(zwWzk)dc4|LV$D0mRSKGUg2k=N7=TYz|fO)RkXBEr`*dO=TD0no$0j}D+6&wU`psV%<1&06}?5eF+ z&@Na{;pz#v04W8p{$M}!0b_W-v{8!I(Knjy8THa=>|5`QD&*Kw`b;@F)vLQ{ z6IG0f=C=V7#VPY9J{28XFT<_s$2x(}bG<}c^%HDP_d@lu-=Z+bW9M~+&laoObQdTy zd2_B_8q?Ud6S7S7VzeIYR3Yu9)}+FpqTxx%W)_N;+0j+o8%A%u?v9>iFZ0?J)y4= zz;o{zRXa{Wy`*Zif@%;Q zqM#Z?4_8nPqS*?nK{QiAHHfxTPz|Er;m{<@s|L}H3aUZ$O$F5;x=KMch(4*H8bs$S zs0Ptn71Vo+{;r^2QZ-#cy`*Zgf_h2S848Ml6x&(=qN3lvl(I!-}VqN5d5B|1bwRicM0s7f?jK~QlnA*+GG2J=77Ahm0r9@TxhMEf7&%s-*FfQ!GcX~ zqaz;73M+6Ixb9iiS}$CJJ1-7DfebD@+qCxeDCp3aY@p ztDp+piwdg1Em2Sf?qLO0;OIdnw<3V3-gewti_m~f+}ze6jXuxCqNar+wj^{;Jig~f#Z~YK8I15 zLsanzn6nJRv+(3Lwl#Rt49%%I=DF+nje?VCj4@s7(HPsq+BVZ$g~;4f&$&7gxmK+? zo^}|TzKw;>^_DS~GX~KSZ8pC0fJYz5N?ej*ltH-FWoweQJs6qArz)@{N$+bcN}LSQ zBpdFiVy6OqEpr0zRD+6{7oZCCdHPia`g8?Vpt%aev?|a%UqDa=`cMT`p!ZQw1=^*c z3N($8OsfJdtOck7{Sg@kPz72HbO2SLSLjz2=qD6Zfxb^c73f=yf z*x;lu@F|Co=Zz*^@Js@N>=_T~Tm;xvyAiFz&?mGkkUMg)KO*YMJdJim-oF|rVK0=% zHbKU0jjr08BiQ@!G=69@ECpWv!4~#wH?u%TUI4sypjn_JCCN|`9?Irv1Fn9XP!)J{gnZ@1R)onM%7jq0p#%(e#(>ObYS2kq?qm{BfF9%Fq9 zJhm8wJAcb_#DkX=vAp1W&jazs%SfX9F~=?Wq$(I)yRm#!QDC0YHqbiMHdJgZ6C7N` za)sT51+b=XOHw#fF>kT6j<}I;p~*MuX&6N|=%gc*x0RCc;(5(=y<32TY-m6ZR8sY1 zH|;G7JEege8A@Ga(ysaFmFRaAVX9_ZglXQ9#E_F^d2#u*P!s)gSTT!5+NNwrwL@q~ZE z;}W-WJONm?a=cH?jcQ_antItjbZOJ+iv%o6IQpR-Sx(xZ4_}enRiz&b9s2&ZNxWT^ zgqcMXbGaMN4MHV_i>0ef%ihm4Z&%H=3<%}97!b;^_T|H_Uo>}Xp9<47$%(j-F98%j zi8>DDWoxoKQo>Ueu0kZPY*Yc}%0?ZY(wWYZ2q=)OE_Eox0yR&zwE?b0erX^$M~oM? z{uIy%6}K1Ahk3i0ZQEvE!f4bJ8ArI0Pry}pZhu8aR`ZGyv)~TC@LTx#?@&jM`|r{V zX^)QNy3cx9|Nkf6v4Ui)Q~7>9!eZPp8#>Y{2lj3dH-Y$Wkkc7GNuJ7g@rS0TTaTPg zjoKcZg{Yg$0)?G=Szs0UkvTNmzADeO^sdd{6o@T>vwHDh3vQ7eNvd&+EH{Q4SBBge z^Wl*cMx1e}mKD8ggxgqch)W-aDe)?t3|Af40G1D-<8lhu(srWM6Go^kjmJxJ@o{dJ z{*_XrD84Obtur#yM(K8-Y{pUV*5PJn%!zNd&@SN{nF!t8EL11|(7(Cdrn{?R4TsX^^fTQZ*U*4yz&j{u$n&o%>E(_D zT3Z=#OA6E2TT=Q1e@q?JJjp&!^9Gu2A1FOh&z{tJ>Bw6zbv+ja*E0=XlqB3241{Fe zjTl(3nukYVrgtF33CcHL+N&v%vr$wbmb1Nz;==%bt%k4T6YbcC^rCMp2|(=!AM$>o zkv3_hMnodA6h4t?t-@}FHz=H~@FqON3#hV@s8j>16zNojZHlT0BOW!MO_4tc8*cb~ z#n7N+*cciWwlSmYyn`Jd$YA%);@X8+L->y%k5oO!pO<5# zRT1PR?@|h$MdDxx$BsVQXX$#H`iN_l;AaWD-^D3+Pe`5y*m#N znML49;i}>j!*Ss`;8_Yc;>iidTEYmY@G+h=8jj^<5Klc5P=$*~jf{lh?OJ)xHolK? z=9-g|NW6*2GGRFpWV6jlU~GQN2F$*tSe|AsU|H9jZEOrAUu0^d8i#Nh!h2?G}PfG9NdiV6U>;8tiuPrhyI+l4s2sG9V}*>*0V2S57$r=Dth;nA=n|+p8KVm zumAmtcz66nJdv(pHuEqYEkruuvSW@8B_*{9-7SPyXh>`bAxHM?v6vj$OB##4JXl91 zFUiYiR!>l9@4R|S!*(%Y;a8bQBYqr1G}$D^nrwPt&(wG`&Wm`@Gt!}EVe3l1;&|@A zZ2}_ugAh0!f{!BOm8cKsiHu;8;m*iqo>5O%p%S}Fcjb#t^CP_?dquJs1$A8y@~knX zW@}jo#1e$qTDES`P7Pe|Ms(KV))&myGPyV_VSgD#wlMIsY%MFnHY&JoU5y}$qMY-` zS>34T2p`KAu_kaHOkYhCDNK%FR{pz|rQ|isUdkfkg^n0FHwW0Jz7( z7pWW__`x59y{f5K!8B0E-QZ_DZ;yE&lw?p|A05pxFV1w+t6()lfway>%5s#j9Azv= zWzx||Y`rfEYOUM`JfksvaBeXDYD{c{DYj8!gDFcBJMSU;O!0GkHhxY)VNi&|fNm_M z>^L`;QqP`%EW*W{6+n#H%A%fm3|hsJdSJOJ1zLkOX$^{r0JFDsC$eVZJ|?k<+R6bC zPK0^vFf^=3H7wN*!^Z175GE7C+4^zgYSSnZ+CvV-H1HGJ1FI;ZJ;3V}S&nk?8TIsF zLkM=PS`cCMN+7<>4G4Mx?@qNcUuT7lPp#qu6@6C)w^_C;Ma?08U#>@Cp^&BX)f z4m(3e(m6w~2TUo-LM&U26HXTxJDUk?VIR@#BK#Jqocws_EBq?;3yg zufJT{z*G-1_F6k>WUkF55C-p@ot)k|m-IL7$g|3BMpBn(t}y5-3iPFyz|Jct3c*Dncnk<0l^QtdcOaNq)vuVC z=>IOCji9CWLwyj}3-6&FimhYsV^J0~EBPE)WlbN=eQZX{&iI8=Sbj*rf_3ivjbMYl zN0N5Y>lNVx;Mmju03b*7DI9ER%?L+*o)L~M%WdJfNeG5;T!~LA9AyjxdLkiV9D+Sv z2O#R{4|dbfdOd=$KG6QsVg67DAB+qu7zzK7Amaqm8JH;*$xpcmhlL=Pa1dG&opk-$ zSf`kfNdqw=Q%7bmfF$N`in+iWD<P)ckp9&nOx?=%#$0Lclqh9QGKaOs#*-t$34{r8sI?iTKjgtF9xQC3y`1F6jy=UhBS?#^kajmuYio^dG zw0Ad%u-p6Gm)PF#1Iyy=J$K0;*4|exZmzv=VK0Sab*0VE7|S@-Dudoav%!7Z82NMF zBlj!$m@?SjU%hA@ng({K%SJVK)dn^c*gq_MFTyOZjBEB=7}%=@zw8tjW6oweM@F*t z{*tFuYP@#*`EYeA30p|A(D7qOv7A+6T;UGuWMJL*9;$q*jxchM=U{u z`#&~QS*!a;-2btcSpi~Z_J#)_&O5A;mFu}{k}L(~tb8RpI`CoCa}1iJmiM19sk0EMgHXMY z_IkjwMt%kJ3S|s@hqR~rSNqZrMy$l;@$7`ae7&4zRP@-()rC?O0a%$O^98%G$e5ZKPRfDmhw(Kr)r@6fypht+V(Hr9JyD9ch^< zGh)m~DDdKosZW}7%E$z_)$>Z4G9NNc-Z9FQ!KfQq$mEr)JlOy^y3N5;jF`FlH9Nc* zxTykI&r)6jX7&t5FfkJ`G1Exmd^<6v$#ZodC|aD_VvfWyQ*^<@ zqVa2X1S96(kW9G1c3A=$-;xvC)`G+4428e@j}b^gE45EQ>e};>Lt#^~*Pf?~>BcAX zPs}he`Q)ne_*_g>aVD6{!uF~&Rk&lE2|qLMq^di`SCJF;Rk4=*h($#K-HrW89@8R= z5eQQ)zroQpd0c|m7^BJ*5QbL*Aj7NhjG3H;QP3yh185@R2)CnMxMoaZ-yUd2Z^tdP zM{jq4*^=xPd=g_4-5hfI>kkbcej`LS(mDeMi(& z1)UT*5ox09*vSrHykh~jGbon*HHM-aKOJb6aM?0p&jQ5}Pdr2_FzN{*SXXwB199Oq zrGyS2b>&Z>6m-`%j+Z}4&F+GTbUSw%KgDZOOwGQg_GwgW6XUe0VM&qQjBz@;Kr$5? zsjN#Pdw_X^Fzs}BZsS#; z5k?QC4F#y@pILt<=23X%)(n`%;Cv5v@X{a)t1J_7V~N_Ah(6aJ80w1*DX6;$`_#sRb3_M= z`@6=)NP}1BKVX2F|A;-D4KIXGj9wJT$2E|t!vdRNdLl!p8^Fmkmit$u!$tth{K!7k z=Rh7xn>>j<1FQ{bSJstefT#QO(o4SlEE^ygR~Y!PU=j6w)Uz8nhz>J9rMx#k`H<+W zPOnFwHeadlq&@EmYQh(?$)Hfa@Ezz;3xi!i+yK_!fX5Qr2X}n7#1dSs;}4ATF;#n{ zik+w5vHJF-7K3SjpPo?P(*Tboma z?PPtIpcaE^M_-Xp-}?hJ^?lm@vHCs*uWeJ`R}5^s`d*uD>O1F=CiVS4__X8o{Rr=} zGVOcjIq~+r#?<%LRZ`zao$Rdd4${640|%4p+l6RPo3B}HFs$$Xpr+;eKJDS(Qs4U{ z)lSxT8EO&w{K16!9tzOZ_j&uq>U$Di+orx}4rsgj-ms6U@BII1Qr}DPX~*lk7nTyV zzUP+4>)U#O4DdYgp49h&&p7M5v()zxa4@O9r*=U5HeYktU|8QHK~2l`ecnUArM{0u zs#txWTmX$;{RO6xX0Z-kY{J@g4)t^n?lWSQq9aQO_44B88$+@ff{}!E@Vp-}`&`97 zExQP*@H4@i9?6QGUqCll6gb54M=^NA)qNNjSx-uum0UBzXk@ZCM=tgA55)3w#miiB zpY-UaXat)i#QGr%&7eU>%DihPp9JLCl;mcE5;#QUVCUB!riM>>(5_*bad5!%Es^zP4e*lm;zIBQ0}ph`FhO*Hy#fQR66fTBbd5!V@OT;SE?4?CK+lKo zLaE>%iBt!chpz>Mr$n$U92kvEiF$I($3%LgFO_E&hNi%C$&c2vh*%i-D)M=Y_>JYv$enSXf~5elaS*d;yx`Eu*_)Aor%kTJ@MsKyP{yJ1Kpy_kZ12~|)w&Vq z;<cXlVA_UCr6 zHHIdylO~B5%Ge~1XPkUmg;V2>%KWeRbn||~r^lHI>uy)jmZ)G_BR|=7 zC-FiVGn>$KL>tnybzhNyvPe^BER%>oBhWNXX<`ufUyEFg6rwV+o6vUi(6-~( z35K?hzf*p_vnOBLvnk2Ga6B7Wm!Z5hj6(UgKFxC>4jLcKi`jC^*Kclo;bqzEc;=Z) z&tTQfW+jF4g0ajlLuN(632l;@Pcy4TCd@R)WOjTkvo39z*~(rflc}0nuE{Jjmf2nX z+OA~BX=YrmXUS;T0vq4>)~>T7+Ay_NEIf+>pD_P9Cf|c&`QF;M?Kt|My-gug3@0~lvJ2M_ znXva2NBo;WLK|qV(~ucA9}*qaWxXlcqp?h%&2?mIwN0k0;N_2*5*;(0Z!(=6%k(&B zrW@KO(<3!gqGP7%hP?;IGJW%KM@iSUO{Vp5_r;PD9W!;COh5YCuG3Oyrfb_K(+tg& z=$Pp&W*Y2yawan6RBo}GFW3|-#9-)!XVi0@4618n{f#91H1!<$n!;IEfaXFO^DK~! z`y3gL4jriAYu)tzmU5D{0R&{Idg!3}o4+6Wv4kKzLqF)|J zLUghqx@u<-rGPMNK{BE)f@pASi0YGzc0n?t;^ z6Fb9p7tEr|ZIQ;2}nN=ZgkB8V=A z;h@>p-v}l*+Z{c5ZxWASQ9{x3TSBy^8AMXFDanXdVM#6O`H@rf<~m55qWa|O@12b3 zNM5@wS>r~$cacOIxZQ}J%T7g zlfm|Q)I?{eCL=mc5IxosBAX&7BB5x}-AO!h3!;l#Le!|$-$d13l#FOKoEbrmT0&$~ z|{h=WUy#gwuH#$ z(fnk|9+iyfUO_ahB}6twPDDacyJSSC3!<(qA)N_4nh@90ghz?9fbhRKVZVi#M)&$W9cP16>C_&_E4N<+L)&$W_ z$%wwh5>V9hvZnU7U>QdARC{dS2M06&^VeNzrnW5mgDIz|J6&qOG5sRJ8tr$ln?wXZ1_b zZcaw@6MDqa z?F=F*+Fz3qy?_-zoPXFEL{hXq$%tkMqUUyRfk#_fYHJ&AODbBvAezw{B4-CFJh~+r z(bt_=G+%3onlStLWJLD~qG(GqNV{mx>KBUAk`bLDh?cg7$l2Be(c)W^c(ex)VNpE% zFjvDD%Pnb7Aqdx*4)5C-^{hxiEnrvVTJ$E-@*Z{+YmYr}e-0BFSy^Vwe)NXOkb3oex9U1 zw6*kX0ZiW|IsF7l|HE#r&`-f<`WJ6b5)ZGWU(!! zq9!`w=ww8^+&=0V*czfHI^mm}l8RO+h_+?4z#6+~O?1NiWJHv{sOPDc5al>{L>`wV zr*A|A_)lmpy|;Cp>4t<7Rh;@P_I7}hvBZRZ%r#%5fj6t#7Bz#i ziYVtNqIA_f1QgKk`(oFP*Y;cx??JfTIXAAoxgiItyb+lA1$$GBt1c!eWe>4IzhGmu zI>JFT9Kg^s$58)ui~-n<$`SR?T~VU`vk^k|KOX_al`F8hFf;18|HmmQ4XFtBN$}vS zw@gW~{=OS_{shtYAS~*sK@?IVeHDZFX`OsJPd*vfV8qQ(e%&BnN9k7y#aD*%t0i9# z)vpqYuMFkaP4d;HUnLY@8H#OVQP1YhQ?T?uPgmG*GUXEl@Ko9?Nw4dRz++nQYWa#I z8K^nvBZZ0udQhPff$mVKRG@z-R3^|2g{BHLO`%GGCKBR0&^Wvl1wJNmi?l3N5@V>w zuM;Rw;)C!*BtD9?zq~}Fp1tG+JH|5k;@E;z^Q=^!y=WStQ=CfV0iP4)Q?Y+etQLP8 zzuS3vxrcBynoK0SFgU`v$tVn7mFy-X4-|0$&s|X05v?hmzA_2|BT@?j$9FJS7xEAi z4l?BOAOrUkj^MdQhi4h=HXPw2=QfcO;9Ls$OwPIGiG4D7GM%64O7L?^8Gg>JBWRK|qQQ-Oj*W_pBGo1v8lh0ih_jEWB~d7pH&G~!K*8vB2wnmHizOsqyE8DlevT^GxTeiMZt>`OTv%az^>uX6o!XopE z{jd0j-I)?Y83evc-6cqUOwbF1XTTNIK!5cyDdp+b`CoSid*Dxs!|y;Rb39EXBXeZB zEAs>#j{-J-U?lw=>H}~MAU*cF5OwRryxqaYW>9C#fg#M zOhq5k>^D>G?qELeIp}3~|o3ul5*@~i`qZ#*T?)YI# zvFpTH7myG{Me4;r#fSpm_@sMHwJK;lV6ITBkJJ#blXoJ6ljP*HFiI`hrt zmtyNaI`Y*xE7<$jFHitaqW`Sb@SpWExAb4Vp)h!9vga(^d~mfm&gxni?4RT}3*Rm^ zZnK`^-u?xMYJ1IkBXZyNyj)!ZI{eiua`g1yaybyO-ufE-KKJ22c{#ax86qY5e*w!! z2UZpaUMUQ`RT%gl$1%`uF~~-L&}DS+5@`KHry~_B3ogH|PLIAh8o#WqS>#CIE9=EC z*^L@^Pdo_Dk-fkAmuNZe_%`RPaV*mPG=rm_CrM`DVEEHc=V^(xktyOdF9+n&cOp)Q zx~{tdG|Ac3f8i^SMFa-19dbah{r`w{i_^|}A7jeku51F&>JV)xrAp|$B=XT?o?mlz9Rrt(t-&BtK zN;&Q;_J{bxp$PUt|GbT4aQ+d>^K3I$pyT}M7_U3(DIx24s+3YEhr3C8v6Y{OK52D( ziXT0Z`BztS;KRRgFC4_+*jkQ_49vR@g)Bci>KTIPv-=^!Qj`^pJc@6IxiciMzo zU&EE?OGJ%Zi#}t5(TFqSK#Rs>Y(c(=&=rgq8hqm%`VRO7C5yP7a{X__5xI`|ZF$Z{5F8Ac z<4?ubW$>FHIWp?$gJ8-tIwCZJsI?4E^(oI!;TaS1hcs{=o?7z-l5V}VZv}l?ac`On}9|CQsW_MVaGzNoVzZ zES3-JqR20pRy5R{&P2BWNl(iIXijI6uNrd=UR?_(!>zYAF~ zp>)S5<8#bc^+PIr8qQcjrikZ)r1SRQBXNM6vC@7%Abvh`T>+R8@)YhP=QD4*!ko|a z$$5M1P(f|o2_9k{!Y5-A#n#cDXtW{qwB;s3_!+cxr#wZvC&CvT zmI!wqln6gqmRMex@-IzWuobxY)XUMMC}kdsV`BDSuJ0zbSj#g)Aae5lx5}gEZ(j z@%Ql(-r>+012E&bLkFB+Z80iv1gMUB(hs>hfY}qZ&G1R2 zcRfDa^p3@Qfy> zSdRREMgE^i{%0Z2qF}xZRo_MY=Ido&QW-q9>M%G;U5QyrPUsV30H-g z?_G$&9NgH5yJGl_lNjr*as-pd!r#D8MZu$r0+@KhdE38myBTLQ?GTfr!P5~_9Np}J zLZN^EfLW}w*)3t8AuRGaGDe4PZG#MQ%)2|%!LJ)W*>%}`e%rn``Q3n+%S5V!U zUa-u9O>boS@Q}Z1c&IpfY^ckd_>76%>xHjJhSe42qF?UdWzev?9^TQ{D^{(Z(FF#N=2TXq>tT@Q?Kmj4yaO`rG%T=8j0D5cqn@^$ zv+e^}sJbz^(S~*i2n`9o5(;NFB#tk)muAG^A`kOb}gI& zJ@=VE@Rl`sAWpDzR!a+Kx~qo7!v6Ih1v>Bk_oeN_ua>-UY6wF(riIr_tbBwz9n9qd zmL4p6D`#@7Ar9tn(hF_?;Q&m%zF{zl4I-#fah{NiCxlWwC8fOR^uDqQ?`7a}l|sU&rQ={7ZNs}*QKMylaZK>Q6ARR7w(ya#^aVUhPD`HsHGU9md~ z^(|71$1n-`3L)zlg8enoxErphr!#Uh?F)lVu_6S13Z`Y8Ylf3cNpLW2pJR-ZzKVlz z-Bx!1;(~hJyHo)kF}O>|>OlZUfjO-r4k|c|p*|ZzSALj!ix0o2upcnRdb~5eqLq6~ zuwkY+wPGPhpfm{xD>woz)IT@JEML7e*8WZ6gc>O=RgO) zZv`Oy-mRKG!?ebC`t$hx%3X1O2eab*zVvM2_quf9cfj2ozYm7; z{QdYn8WcGA{c^s8-_HXOerLVa3cqh*vN*rnk>B5?{dxR8>&`g8_uezk?@pz{@3Kz9 z@9wVV`2Eb=zbC)nKP!RXQ~EpjeI5Ye_xv|n;dg%~i}Ra<0;{^ipU3a7=f?T{peN4n zTh0`IZ%Gq=KakNJzehoN{(ka(At<1HKLZwFeDZRhgWt~s5Ps*s-U`2OVX_#%`#x`V zYoEaErxN<_HXfW@kTf{C=Jq(Vhj0jju^|U12c03z4t5Y`59-n!vp+yfR%UyD*+Q*Pw zM|}+dAoZ06gxj6Jc4D%4ec^-y#y>y*dG&SHP4W8Ld$)Lfbvjk*tL)cKAUC6X$L8wm z87PC_uYJ6KN&>&HJIulF0080l{C~H??^Bs9&hIqxyZWa;kKbS480Ytc?0B_(+;Xz; zd&|$l?*}?G$L~?Ev?;%1>w)vZl*O$a%a%AJ%?aVi1-wulXxEKRLA$dAn( zxQa1xA4ujnYzofg=HE>2fTaUT>;(gLW!!86T|vrWZ9}j5JqQs>BWq+SFDtcTFb8a~ z$1o|DY<(`bpc|X-$~-9tYqwc&3!W~9BG|6NAIi8XZvpUxm*E}Df!*O;9L&5MK@lu3 z<<;AHtVbTSM2Xcad_Pl?6xhX!0^h<?}9YJ+IQ_ozedA;poa-`)b+H7<}r0>@Q0UCYla12VW zm4aE|{3tATV;_qdmXPxBep0=|P`%ZaVD=c?M3BR6TA5M{gNYs9VWX=esG-3Jro0;E zMc5!T!bv{;#=a#Hdmv&>W4VWzVf>y;Ta?Wo`SB27WAo zp~-mhjuR8~^OQag{d^t((a-5fx!wM-Ka(NLVq?!Gm#mY1{PXnlKdy`G=gu6ZsD3`R z*oOcp-!vKWeb5^v%?oKZw)S=!yE!FLo1V4?$B@X8%6((6i2&t9*7wYYJN2l|9 z$NcBROHo`i|M`lqvH4G9a|!MFkM7Tottk}+C!xDY8+R8(1uML8SPgZJYl}`oKwdRJ_U;z6J)ppc&aFVC{>&5cVq>cw5XIo#iyuzY9YgFU)}_Y_i3D!{Jc4S2z> zVQva5a6P%e`w?D-yB5y$er8^3yr0S^gnVLNW_vf97n~x*3r0UE7tX4mpK^XmG47Mc zWQ6+@q%3GCD3>pRXj49ngK{_yLa7oqBZqTfzQgcsf|Lrv^zWrAv9y)7RybVn^HHhh$Y;;X^xeGBqJ~7+nJ`F=;Y|YQa7X3_Y)z3_kYLDz{ zpD&A*xOzn~43=j9(2Os#Ayty?B^a}RX5~$%kWEXk;`Iv$7lrhEK;YA-sc&Rs(XPTm zZg;c#@3vb!8_W+1107@8%veFxGL7YyNa{~Nx3vWqae9j)HsFDI5n5wYZEMEI)n7nE zA=M@BN!3d?AbM)WvHlsWs9Hd4-`A{DeVtN3X-fHEPC9V0eM-VHh0JEAl98V1?@mAs zh&U{K8nd!A&RB6TgU%Ptl)%p^f$DBP$S~j5bZ}{xu(Q1m#hP;Af^q2X@_dNwo7?* zv?mrH?WrCQ?307kwbY(we8HVg+N6SiW1X{Ssb>9EZ$a=GQ~?Gl*nr6UJia&Rjn^9-x${&43l+cyE&aB931Faj{@)QFT3@Dm_9 z0wn}21deN=FhHA>a1V`S!FmJNL)I5foF!wAl$IV02{ZBW-M1=FbAcSkTEG6U47u2`|Wg3lsI0ntr z4w*x9InWG0fsc{{evZ$=&nY?hITItkaop2I8yL=@6?0hYV?W^ItRfp@>vYT~`JMx% z@ZvSE$h=nubJ=JopaADH7bF^=HUp;d=`WOM7+rbhjU7vC#-~*iIhS!7pP;^?*lb7k znLf~IUh0p`)x0G3SG63u)pFGMIO$$*WgQz+FOL3)B3l^P%w`OeTRNBndGFvwCE81aV7pYdW@Lz$ARxNM~oBzUZSq}^kw*yrlTp4ZIQw}P%7 z&+2tdRmqlmAQI!Ym7BI38pJ#k0;#5EqvTSu*WjI!9BUC2Z3-ZXf!n5y{$PR3sDD^UT1`@2(!ec`P!(eX>a4tdY4yz#3uk zP$OZvpG|BALy-V`Yt!wUn8lRL!6W1vjTcX0KJ-Z1kaJ8$- z^?vvseA&dis;>JMZ$%hD76tlwqaGKD%0`gdnmgG<-OFeJs2h+`7(5=M)J&|3R9xT> zo`_Lp0fxrKPy)D$jlCl5=GI_vjnfu08LT*%`U1+^Sm&Ls%we5>ibaaF>-)U)&jFkf zb#BM4-qx<-Fqq!`Od0oPg+BR%S-wBOn&Z8!##IxhCH8cn`qw-Jdm=$ z^QW5%qq|k?$w7VNjGv;B3!ShdT$ zkqh*-Ay)fK$Kg9pEJXe)rsMv#B*L=|;jWrg<`l}fkOnzpuOjgX`Sh$wDU9~KRn$~s_=s~4}SpKmv4||jF6nIVRrnwRUfIi%xPccikA&CQSg zrFsao44o0+{5L3Yis(^*jot^TsMqRo2{oN~wY*y^d)k(CxX1woxLSVYP;<3>F0Ph; z^$fXMUUYBXLugepDuH1P5mB{bD^uf`xs&{Yd{@_#j4Z^oIa%pAgwKjAu^yR7iO0Rw zx-i8je)KdBB6^dEz(e9LXcFd!bVq^-!mrE; zW}x!{4&!9-BJ)z?okE-lxDZba4<_?rD7I&YrE1ta8nVEdA*Hkgrma-A55KE+ccFS` z`?k3asqSxz)W*R-7gt3a3xH>74vC?5X@9SVp;HrHVF1kz$ zz-X+p8M&V=QlAo-}FP8g(theCJqxzTB3S5VcgA1UE`gl)&aIv|K>4Hrqy0&@c z13K%u0xwu9_oujO2N4|%ycji|k<{7I-ZYx)y*5A1I_SQ z1QZ5gkMa=z=wLtGpKT^1&^h~Wc9_JeA`{fkv*=8~bC`~EdGVYK=CfGirDVUD#HUgp z!DR_fU8ABYi1=I_xwJ4i63RyULRal$K#cuOD1lSiJkJtwNOLJGB9zgsWIM{HI7!(| zg|aC*#weRoDAft4QQ2%1R;{_;C>z94D||6Wh~_x^&}`IUE?k8)qio2?n6g>!dU9$h z8mWIGetZ+~GTybY_#C`XvYVuBYrmhvWi&})l3~~gGGm8$B_w-{ z&d%&Z(x9FdxszEc%G`HQu#mZXczJbvDARfew{cLc zgB!f*l(@`|`DZg79A$1OY{{dxBXiAma4(+;>RRgHo<~-ugWH1*=g;ZjhLH&E;Mk+F zFO?o`B40q$1U%WHjhE+a?>X|U@lL|iZa;RHb}lNvxi0N4RI*X@rk9Bib+#)A7qrly z&6DAK(?u{OW6@nU}~T)*ascvT5dacQ`AlJ8Z%m?G7g=bz0vbYiaMK7=zw;k2tiM z&gp`Cl;ZR8LdEcOu5?Z;yYzVPEJu&GOVne&n@($p#=Q=4%{bZqP0%MyZzfMA?&^W< z{BW|A<*McBQ`jkh!r6jvBuchm3K&}Oh7+4@!S+l9gHy~v4jVx0RnKEik_NlVm`K~x z_gD(D=GZPBPs~Y-eUum5rV_5!fLn=lODi~ zImz{PBg#EImp`194R`Ygi582mQpTTkJ8lO@J6VMI7|S-`k&26^F=#B~034ku+@al$ z5wEx;Jg#0ed0A@t`Tpo~|A28A@7E4yzl8y-IAsJ+{IFaA4TyuY6Oa|_b|9M`T7-d5A$Bs zGy5)_dUsuf==h~I6jKym__d@avlL~6)!-XBG2vSBpx#8(~mizPA6HzL4vVK z%HkDtN4AizlPlDk8!#tX*+?w4D9@SV29t-MHwiq~nRuR(_*uTIE`FQ#Q(|vdh3rrv851a%$#qu_B!RF9bpwZ- z61W>+k-*o;@KDCsq67(C)xm2UBex@kkB&}~LVMxdRofM4!?cY1LvVhHr?vQGBa;Lu z2~-;V$T_`A#G@#bkx6)MM*FLgSvM73B_dM>OH?My6wV@yi9c(XGMO*Wx#BmQ6aNy% zgG~D6X}SQ)bPix97G%fB4S&P;FuL;az}t%YP&mgRP@aL2Wu%>A;bTM@TkX+SVrFo zBb(^E`S|XXwt8ZvzPnxcp7CX2g0!i=+m6|LTQ5Bd+My3}BActHfZKZvEKM5o21Y2rlQ+G!E)OMR2@E5Pk2y0VRqcIdWv)|LNb`{9D6-xtY9rB>#EscBYMi!?NL=B z&)+_d^_1^|(d_S>_6sz-M4jWRO#@E&Et``l2{!{4NhqV53T1peGC>k#`iAUIEyTG2 zAV~2&*&Y{d4DTBq-gmRF4wfJkFnt(`-x)*9vxmWwJb`@(j$2&8!vW>6CP7_PAtluY zM-YCj)UyE>VX2<{#G@V$IwUVf4s=LfD$m(6NpR)Nl@>}ZF^}%sVc=g zhQWVln$Me%)5o^Lsu=cBF{FoCXL%@VqXXaj;N;F#`z+>(vl(x_b<=)2@w3MljX<5));Ypmi0Dp@|1gtN z<9BBCP{vO~6WV#}8vo?s$r_)1Ii72FHL9cL5{jvenoDD~jQgCC*4R47vDvgq{}NmF zp_rJl2)ivz7-dMl!8sZ}f<-fHvc=XJXkL*+qnEw>I}u@qE#_U&)?& zO~QTLD5O&`J%B|p8--UH=M?OuU@ks3NiZXOVti3**XPP^os_Ag+Kj1@&JG?bhpV}X z)yd6`;D~cZApNuK*JMXwuWSeFvMGGkTRXXKXngFV*FMJzY?tiksT-ZfaUc>W^Wfcz-3f&;Eb z1jvDwQ)khB43Bs+<}eEDL4*|sR+C|{#87kt&*7e8v{v{{fB7Gj=lDewkWU_zj1PUt zRP<-O7y`XWG3H?y1C2q`3!DVqJ}L+HT1?2G4g;gi))K?KY$Jd%@gz^EAmO2m8{Rvy z1St0uK4iTKBMfWn)3noJbOHNbX^N|cTQaFK>&Z~`+a)9hMhmmH%np%VHP3_kc^(uy z{;sUrK-VgCY9ox6347MfgB@OF|FlTip`nOJ4pWcg9%MN*6 zpUy;ptWU24GTDJ^toKW9NwD5K_r`Nv241)M`t+Tkz}ft6X7SiB^wRO);DqMay7|6$ z@0j_%ci&^;>(e)dnlazwEJw_IKfZ+}qh`(bu90jqEv!%P$};@f>(jL;uWi0Z?@|nP zi;b+DH`AEU0hk!`&)^G0b{w8G=8u)HjdG&S7fu%{l4qdjWdxG zx^(v5T%Wc+Xp{Bni-A^J+PWa{C#+9@b-pz8)$))Yo9ol=C);X$`lttXaQ)!@zpD~> z4==5+Pj^I-64$2>dC06!FGhN3mK|E3F0(T|R}!tap3I7Co|81}UW9ReC;tByQ9hc? z@7ExzvsE`TDO>g1GP23YI69$Kw{FioccAH1x2TBEaVB3g*;)hka%;w^^6CT#VmPZq9RYTFVR=`keJR;>^;DXJ(10aNCr#V zM#*)ySk!0`+XPrvrsav%I$$Y+0WTd-Kb~%ZjX?$Wx@=|wHn2D(wv;gJt-_w1nT9Pn zvkg07ZxuGczA}dKK4aG&=LF}p~18MHBYAuM)ed@oj5?8$&j6>emF@M$vO2+TBt z8)mSvaK~Ray!oDh1%9zuqpY{?#P|{`lBpH@Qam;w1zH4bJN6O|MKn9=xvB~nV1hJ- zJ_gZHpdS2~TZCfd`0BtBymSE{$b$m#0;>j?x$o&oPxvqY|}S zMQTx-Qd-oeloGWmr9*8>sZbi>3asbC4b-Y|0ktfp2Ul2Hmbwx6{CbMPXMOTothY0! zOsa;MDf0}>pg}$9$pv*iPy!>mC<$w`RVlM;sgKePbF0t|bE{n&w$ze7VP7r1Ey2Ek zl~Agel<;`n3n4NSJ|k%t-dM7pW-W73s8x+~?~%SZ&wsUq??~-6Ud5<5|CFK165}JI zFU6p<7A(;NP>K5ta*>5oVdgMPj?4d!6tHhp9F{OT(sB8AT)@9_xEYtnTvUX)CzVB` zVZ}oI4oXv4{WBULcQ{jQjk>Qf%d!v!&N3(p`S{KTQ%M+R zl{$H1fMwnWGugY95gl%O~;uuK9Go4`~8)wpJ$(jU?&HZO|q-xkGHhU801`B^xhXD+_L z%ck?q?nz+ZZ~2g1HzvT~|GgZ1ETqAK9KOmQMv%)xLdn=4F6C0&eO>DRX37Ew$hkY6EJI$7d zvWUhATxylvfu?d;)MHJTKs1%@Q$I)It+zJqGEvu~DM?M|t63u?lMmQ-bN>)L*?_DI=d?aq?SA=APFB|<0ny90o1b3%qb94*GuzfD ztH)i&XzQ(eIyok*E76J=7(!swa{{7pvWh?0M__%{onGe1*u<#kVMK6B+I_@H4P4Dy z4rP3o(^S$p)^66L+ldEJ%3_CV7on0;B8OL3X1A;8>JL_;rA~#PypJhKfmIPV)`c!b zcA_~xsN{=dk-yqp>f>yBkHrha@+A9raPDEt!+Bv~be8Nzz*4d=P06|^mJBCME2OHe zkFPQ3VAFZ(75Ah58ZAFf&%o}fXJ9?%3~Xl8Gq7}781h1?I^L=FoKc^r9PEUq0O%Y0*RBY|WpueEJ>o z*PgT3+UI7oeEM+t|6}e<;NvXHKc2J=4M*9nuo#ib7J?*DH04hr1p*tImJOsBX@PJ@ zC^gCzX#xcl0!<+6Hd?eQLcs`CtD=^}QYvB!r7b8@?g|R=!d;f50zwh!{=dIx=H2Y3 z30J-HX?Nb4ciuUkdG5I^@!h6RPql3Le@EmLO!<4~J>QaJX>-H#4js{cQa17wdGk^8 z5q&F`rc0kd&1iW6OC#mmd%V+T($lwPGwFTk0iTIqwnh_X*+?TQGb}7w^0!iVO5V?` z=#q6r-6fIVS7#+TxL;O}s1ttY@xj{hiROYzWjj7ib&0X#)Al1zVFpP1RgculXzf>> zk-uMcpI2%_=WeB+qqzGye5@3;Q&7~JVjLr+1=VqV#;#|Zz0S?NwhUe?)gq8E&(KV> zX=X`>&1%(Y$!p1We#bV8112pUt=R|mx5_0v=11H46B%?;L1XRmFdt_lw?THy2b31E ztxbr_XP1$2g?oFw_<}m0{tIS@2_pYf;7<`b+lI2YnVvo2=wN#d&n}wy6uZ4Lm*jAuK~_TI-ek$2w{ke}jB&n_-w<^;aKjuL07$B{k?-&* zJ3R)ZxQes$2ZFoWBQ=&CY_29P_Q#S(ib}q^m$R z7I_9NC^of7C^uawcZ^W(LOx68RLnm2&bu}U>|d>Ge>`T+HRAsjcF2<-4)eS zHAwT*y8#o=G0?m2e$jzDf=QdZ8Q%kFp%iHOb!1?!BjmhX`ka4KZas19hm>#igT}}q zR-ZT=M8M4C88D8{^=3T_rt*8Uek<$E*1OrRl8H~Hwc(ByReVZxI;PkHFwC~Ir=GjU zZQF^N2_NdZgH>1qNH-L+85f$HUOH$K!erW=w(G^=8C5ir%1Rn0i;WtbO4hUSTF=<3 zlfF38c*YAqG@fyOspA>d;u+C^XLLXgMhQ9x45t^LO(&!08K38EX19E;W%;?Jgk4G* z)n_B$Cx!V%I7=-373&wC7B)g0a*ogpNjZrJ>A_uZ%_6h|GIsI@WU#D*P5axCA;SqC z=J*gYrtU}a(S)w~IKSONd4hV}=Jcxf^a4IJ^3jshO~*(xA3 zrEb{Qj(BNhZ@tKWu6YjlL<=&cw`nK%5{1K@^>X1TAsLgwa%qZMt?WQ6Ldm#!p{Av0 ziPmo_@1P{@BvTqZkHO?^!y^ zPXayfyc4fd5#k@s=sQMNv$WWhV(jxBg2MQcb++jX^)V#ZLWz1Mm&Zg_8#2UqXxJqA zFC@(*z?y92CL7Cp4|hU zGC|BpP0U8Vt8buT%Q+9XZRfpI6z`euJ*UMohXsF_bL%LTPQijOooh|~_%1g}W$Ig0 z9G`PBp)bK&_^3!s5i@qdbj-I-v#xEtW}XRAj#GWKU;&kggE+Jqu*nUbyiFc#KGQ0U zQofU;+}Y8crmgy>P5MQzR^7P6308n=0H^dUsEy{ZuUDQR6qstA{f^-B&T!n4y=pQT zvA{y-JWo%ClXzgg`gx=IR;1qp%JPnwUx{=Xd{H3?jmapn0;r<;-q11tRdqh7kbe$T z0#20b6z^BH$W8mAV!qn|M2pw?7WWa_^h-9g=k&x|`n1u18Y2{jwl+-O5b6@tadOw* zUaY=>rcoh6fYmo9H)W@GX4^)ydwLDvlj|C1G~}pl8Xcqv@*+nyMwMz!w>1KPoQ*6l!(QdbE4|dhMdf`8)fv!VXtvJB120U!k4OFc4aC)2B(#w46L&h~3yXyU zEuDRYq+|IJi`4{KJM~B-KID-{;&*vEf)$*N)P4?>oQX(cN#1oki{}NaL}$VjP@<=c zMb86q{n8Mlq7y-`%nsY%(rlp8>~20<@o{k_-3tUpVx zfHC{f*{_LLxUiWcATF`OU$4zR!AI^l8yQPted3hT`Zc;ZhGE&@R)AUw1^iv~VwMJn zZqk_Q)Lmzkz-@3hiV??c9>xi@QZT0>@sG?@%ZER?A@STDF~}$z8KL%ryVa%%x)oV{ zs+Y9*<|jCv`Pp+!tAlYc_aOvwa~%S~T0YZ2R;SKbfnoxtDn%T?@Su{r<9Y5^S|wVU zB0>N~qH)&Z7g>MgH^owT4_D1QQ4t(?C1~W0{^m_zI@=9ebpzK5&speBUUIr`+XR_D zOiS4%65yU#N|RVhiwHiNyLdVM8C!yA%W%8EhRtg^LbZSbH@qsT?8bZE^UVWtI82vO zZgWSit^A0S!)21g;ndE1n;d4n=H9}2Scjzb7s9s@j$-%PGF~#rTzla4v+YL%O;$PcVJ zY_DNY?pH3{tVr#3-$px%2)~@R=jeJ89T&qoyo+E9ZSE{NVM;2tS~&;pdQ|>u-iDTa z-na->CqOiPDGV&?dyd6mSoWaMwOjRqt_JvMZ6fvg;?EbS_Bv!+>ydrZH4E|Ja%S6_ z8pNc;KJ=xZnL!VWQLeRJ^9yI*F3gwG2|_hvG8+qP3|JU;kPdE>K!t_fK{-V_Ti59^ zgO2plkl0u;Uq{U-K2)}?uMC+z>1T`bPj7pJwyNZJ(A+vrDbQw|CV>dX-D2S)+ZvcY z(U_zIs8x17MXG12Y}QWPa3YRmN5##5_sZ(ZKcOj_Lu8H}CCluT^gktd{Xs5!o$l!5 zqQ4JlulfGd^`a7ah8=T@r)p1g%&pO;mW2wP7+YE6bCYDG*rHPM{NNiNI&6td* z*8f~mMN!5j7DyEhfJv2TFeG6OiSd*SD;SUo4+>!tYw~H_Y3Z|1)1iSn1SdC7qvi&# z%|U#@eX}p$h%bD3LqUJt{lLJLzBYhbI_VMEryf}<{)FN}T=;RdLR-{ujQ~T=^-4)F zy=Q=OG8r>?nhfHjWDp-q7u`NZjrbC>X~dTka>OEVaO_!>AolE!)SRPc0=t;uIq9j% zKX#nbpAB}NTGhde9J6c`i)t3LY|Y^QIEtcSS%aHWz((H>gU@Vs^EA+s???hMZ$7sd zappLf{JO}LW^u1pT58-DXwk7rb0Uu0mWqQlr*7KAxUG)%5$zz8FbLHZqSE$;F?KYC zZ7vZmOTwA<&Cdu?R-qcyzP^fjI@(8T{QrE&xPGb4PpWa`blBCNZG5xy5+=Z^`ELI6y8dsFBHhR;oOX@P{0xULbnf?H3VW~ z!}QR!oGVX7bNW3^7BdyqwKg2I#|hNawyn{}uXvwfVbEWU*tGQc53}ezlvdn+#?avO zt9NM3QqO@*)ub^}HK%v|CDi#h9%i%pXe_1Ao*hqp?geb+dHAQkvWhoW@r$R>uwSVF z#%ybi*+(>Hl^V0j(zyG8iqw7~b_g?|-$L|PLMmz7FB>_6;`7}ghY>fkY!l^jDg(a+ zu~LN%iRLgTF7`2P%+@nsywqbAEA`kySG+jgf#P|4iTmv=|I;>7wzrlbf-RMd{V*8F zbCV9M93e!wS~cRbDU|@Ze+fJiPm~g|-P}?2rN?PiNKPWgeamY;TV#JDDvx%?u@m}7G1+6C@ z^xCl#|1INU-!Lx9E2i!)wwh6;`UEBN$5cKK{TPQppEZ|U(KS1fL}H13d5ek{OSmD{EPY36DJJ8uYN>-JiiL@ zSjeyTY5v#otItro_|+Y$&G^+JYS1d8$z4$rDubw`R zwtIeci#^ z(_!Ja`+ff%_st`crq-Jj@0rxFjT4i0UVTgIv5%OT zGP|P8A?9(qw{1V_s`6ekGJxjF&rts{l}Xyp;F}9 zP?avSTdZW1Nvo7bUS{D!TcEDJ@zuoBtLd6)niMit%I$b5w-cq@*2=ft&wDAg>nxn_ zm0hRVNc*%2(23GM$4mPhi=G*#mBAF~Ot*~VwCf$;mcEy5JI1q3r~jpyHll{7t^{od(I+oEb4c9L9EG{=-K^vn)x7M2&@M);+575y!&u40w7O1X<#WI)-g z@^O_R>#1QOb$2B$B;Pnfe$gY&R4rSdFP z2L^cpNoRm2y*^qg04dV_EpK!SDZPzF&D~Jve+j4G)>n_k($0zRY4;{ogK7yvzfYEJ`F&b zsiXU6X_DQh>t?yxqo@>l8F<2&u#AyDMF@j|j}ce0qaVV8lRtxPjBg?{I z-YM9WG34zS>YlovDm{Roi^v_WY;iPg*mT48(C5*^Qu|5eRohVGmEGQ*V)R?>-f-}m@>MmMQ! zgsc*cukL%#Mpk^vxlcE90l{%M7)1Rv7+AZ`;%=HOonWG$2|Bk?%63WFQ(!i!vD4|&r9m#r!V0rRF$P#673eHyIS zfu`S{u2HsB`u0)!mSMo}$w2V7TETjGuvE#Qm!Bk(*(n=2HTcpa{D-~1dFfNqH*0x2 zpl>4YwSumB`1z9YBb})C^Ci!XHBtZm=SzyI7hn|5mn>{hVjf`Tt!jP`^CeO5a^wJ+ z95+vEctCbrUlC3n=GyszXGuyJb-50qFHMt-T)Npb$*T-_Zkhxc<~@ve{CH@Kz3UT{ zXr4V`#4AUl@-R8#=cNYEk!X6P)}|{`$L|ae(I+i@@~)F3y8}>bv3y%cUH|W$9C?uz zsWQ!1d~II-ud>76rZS8q0K+{x=e~PoLrjj0qyk9EKs)9L z(b_Yqlh@}@7C&w@R)br;@Rv!KV=SP+=`hfEzKVxi%oFAE1|NiGkKEyZb^5>t( z?{YAI8uR?1=aRB)nDu&43MwDVUR$>}d4x}3QAgI*(zQE5ml*sO4~#Am#tBR35V3FA9>S6XE+)aHe2i6+5sI_m+ zlnNR{72LGfQ&P+j@L0WOO5D_uH6t;FbcvmBS5M6yOQl*z<}S#chWP-k$X`f#GWFxd z>Z#fBEsf_g>j2x|=q@V)+L(1f2KsC6epjd7asJaIFpdHKn4)R!HW2Q)no99iBzRgm zmblT%PiUcVfmN@Ut#P);as`4`G#mLCI-%rfpY?8a>ZeqR8Kh{ojlOcIB9ANFhwzU5 zDOZYftTuUtKr?USR-r3&)Oq@Tv@0pjGDW2Jt|OG{DlRUo7<%%zR}yJdM1*3qn2MBA zSk8DBQplj{P!3+Idc_y`xRiCpdx^^oiW8TfxRkhBXFF9(1Bwg_F4L3CREnnEu9@Q8 z*e^d6xUs*bwu?1hz$+mmXtN8Dfq!s=l1iVh1x1D3zH&Y3cbuap-MBI|FF~wcH!gMl zm?X4|X)WF0cqhvs-F&tXo;LRJmc{n_pr0x#aDlWxpY4#gLi^_ew z?jNIV`4~J$ZPhBvVp=aOMmD%>7?BM{t4F$nnTOppcJQlb6s6Ck(bBn9Baim17U@~5 z<}`@eNb#VW-#E0lm80K_-);ZP?ol`ean_$zu1(tbtD| zNO@Oy-}JIEjjAi+(HNaxgC>Rtnbl zi8(mECt0%l)8{a5p{~b3XPkr4_`I6e{{VS~I>P`Ax_z0LbnF#h)~yCB<15qLk+#Pw zQn`L^sVu)tog3JI{)E@@%`FJvCC+7ZQL_E)V6YVUFeC_)UFpo zonN5=BEuzwY(#OcM(y?PbqV-4c;M?hABY#PY#9H?c;bQh>wk!^{Nu>@%D;||S3XeR zv)?DVe0DBqCODkkvoYJ**M59$&(!Sfy78&n#J$3KSN^%aeEa~e{PQ2CNv@9eYi5Ub zty3%7o}3+e;@4gGg}Od0$}ZjzpVt@W?8tEX|0HITC12Pz*r+oN#Niyp782@?r#%Sg$ogX#vR!dK^TPW-w0l57Dy&Wp|a$l2W$=CH*u_Rx_Hi zk>hzog-y6$pC{F}Wi?x6t^6)5@1Rs378zS$bXcy!FDqC0Wf2R%Ha%}Y?>)m2nDamh^|wsa-zj4tLa2tR|3gp^O+t^lBOxK&VA( zB8C?yB9jVZ!d;pNpgE=KlyY+}=2N0K(^K@r6SdS-Dz#_Kf$1|C%#srcRCSXbY@LnF zK-Kf~@V6&L4_zDVSYKKn^pSU>0>r@j=_pMy@;< z@E-_7GxWnPJbv{cKQtL0r1czhzn{jV!%z6MJzbjACC;q%>Qb{;mwx0kjUdy&`c%B2 zZ_ayh#B#>EC^Tg?y{$(Z4Rv)W9xj=_T4PXGKHA{v_EaTH4p*ujnfV*CL1~95Az8BP zE{+1*zL=P7|=)l zdYwGtu;qpR1oYGNjYomMPo^1+eC=8Wus~jPj~3CrZN4Zb7fKkq%FgmIq1;l;0MNQg z`~F=7bf+za(j#HjT*hS@^6hlueDwjmlELoW(Te74> zuMJK9st)#)T%d#`W8+#ZJzO=g4iD;)8+jv*$#th*Es~O}mWVH@d(z>w!$~%Yx+iU2 zt0NtU61&0#YhmWB2^P-6(zG4%Nrlbog0}JO265v3QXIaw!k61ZROQaKkn${CHWA8sW0RGZNVRgwn?V>VEy^7SSU09euC378aX>Hz+8my0bH0)8g z1$U*TZm&U=;Zhr^dew4Rk#f>eT$G-!#YFd)U@b>`yzx4YoY5#oZYZ8b*xJj{+;H2m1pc!ET`#F z*pRL2Q#Z&Ttm>OeM7xH?5%VOiN@UCYGwNo{0N{=8aLL}k1iqW&O}UZ{Z{|6?`KS^K z@kZK9HnOwW@*uovoB1!onK%Th2B#0VU8S9NQn7l`58ngpd+v0tAH+GYP_nhY$+iAV zN+@i-!}^n|#W^`1jlKj}-!^Rv(Ou%UIWs3fTdk3}X)g)G+dNq^wsdNMiwbLmB|@~# zPOgGGFVK6IO>|gTSKd0nprx3!m?VE_U-%dMx}Fly8Yw9oxr?L#gxSbaWne4Z&T3c{ z08DK)byK$UsZiIm|IB97ZGc#j-zoB05AQhTSm|^47=R!A3kPr`mH{?1Ny!HApR+I< zHZws9g#dTxk`X;ahXnxt^cDi#_)G22i>>?VVvRW*Cyvy=X{=Ne$Iem*G;Y7yV7Frv z;R;wd5j>d8wu-iM`Re=mUlkAW6}h&IBN~dN>zIPY+gSyWi_*J`)%MhU8RwChj8Hmt z%(4H>rnlZGBa%kGROK5P>U>d{5H5K@nK!52)k?PE_;bXDBSh#a~mr@5O za8|uOVCY^~<$B#3wqEZ!T(4*Ew|TGIwp3rzv4YL%FGy88sAdA-3Uz*u_GTm1pET0> z?s6*Ke5|ffvW->aj@Ig{lrYp-E&V^ea9Umt(p{4O!f@e>_5#IH3wF?@_6~!@+f1Eg ze^}=l@Jv}ndku+y;=lg{3WQWLc5PflE3=XLq=1nzatP96hHmp#xi+8c+WhwI!?gJ= z<3NRN{ue-6n(64R3Oinw`qqbr>G+ohcf5pdat)}IoRRS!v+A8r=T9#>gZJ^I&1GG* z4=}n`Vm4WGEXnw{ND*9I z>rl56hU(C0>ySH6cAzgaGzeSR7uMM{r`ru-@i=B9f7n}HaqL}Uw*9+X<-~ZXtIIPX zEf5d{8fRnY6UNfxZ6~}Znxu&4#PBe-J9Rs$31{tb1?%I$Np#(+fx^KZsHkcXwS`g=}V|Yf6B9z=OE8=pU!}O<~G{3 zIi8-NWE<9}oUHh?5{4SqDmcUdo?>XzzJcMr`Cl-+V227dY+YKcc|i3k{ZYguc)Q>h z>JRYtpihCfX9{l_erY3mBh*bz{GHZ)I2B$ciJX+7sO_^#?zIXAEMjS5(z!Y;MAuR{ zv_+gpN;ZYrQ!~yt$%OTiqiE7MeUpqG3$wD34Il(W9m%JuAsyX*(8c1*7K6xbAJQ*0lI%Y5B1*}6ToadlARmsLWj&W+h zu}VmWhX$ZZmJKi%koYn7(q{vDWZ3|?KJJ0J1%511E$a-VM`}rH4wOBO;FO1CPuw-S zjK&p=x*9Fs+R)={&YZ4nwla%CiiENn4nPV5lvgEoW;EPEh`R}T41KqT9NTH5 z`bK8?8uW4AM}OS|48{c|Vz;Vt4f~a0m{8%i4qcPI1h(1 zB-3jXSFRO6oN4gQoTGP#;!1s#;A1WTrngp=7kxsT7rJ{v5dHQd4dQ+(dmo-mQGRUq@W6x>_aCs(v5u_3>WDaJrm? zYt?Ls3#s0;yBn+&fRNwD>R@~~2tbsjI#gDXuWPMB>Z;dVR6AwnE!Jt(z6RW|%*(O974lF9EUrl9D<+y%7;L*3cdX(>`6^g42m9@af zHMok4Bs`A28a124us|{`O0%<(r%7GvydHHNTT=#;D?`AwjYIm~%{%3kq(JWJQ4&Ot z@Eq~9)aZTPqUA;qHTC(4a%Lkxt)%oaoDQL|!y>eg0&D?y8wDQHn+XkPCj>aEiu6`k z+7!I4cKk9M>68YnE{ljpm&b}&28zIe%BQ+3quPpc4lP;Otd`l46I0x{-cpPn zAZm#MDfrjQhQ!0E+I`-YCtm?<98ca3I0%>D15f@m9~JQAT$j_I#bt*4{MiyQKQBM8 zsY8BV@{(Rm+P^rD9o}5Cy^XqXP+}?1YjO(%B!t*PY3IEre^RTG(>Nh)T9uAiVHCxY zK&&!CA$QaPy-LsvV4C{lVO!a3hG+$6eT;RT$A@lrG$T;y;8yW~(-heT)K%m>MRvAG zXZhvILA=7ph1XtLllsEosUd0UTJlfG+obGD6z5l~Y)^@Wo#h>bf{Fx<5fQzVZ5~5=>S3$r$yuJdFdKRg1a) z1;fLfvj>A(ochB4jtbSy)L#zbxUz|w6R9d{+g`LJ$()V6x(hZ0Hf2%U7{O0nPnGT` ziVb+d!{oTN7%5*yz6q$Z&%G(!bHtcBt9nz`2wN$lt<(vmC?Wz(O(&AR+dlBlkUZ|& zG)@qyIi4UJIg@GvIyHA|=314a?2^1ysaq=DsLH+pbb3K!dOYYFmCv&_jd_%~#=OeH zg>Ig3XzR;drtu_@Nxx{Np_-_uzI;Cr)YnLdv|dguF3v=+-ly*T`zRt{K8XXZ((G2i zXmQh%7R zRUVN5R*-anPOcZ^x0H>!LXA{R-oN}2`WkYE$`$#2op>l+x|A*jBZ*il7_mwiDmWmP z5+lTS(?noWUjWti$^{C^7xww0go03`;-INUL1?;8A^8LZl~=@jKNd&RK8&v$6(nA= z-8FwR1FR+rYyjW?bgQ^Kp%f{Wf}Kns-{GRVlzhbsuV=CXqTy+Couf;;(p%5j=Y6Kis6H1WPP=PN( zHNj~`J^HS~LhrL+_C8Krq$pw!`k2F&@w*FO=R4htS#rl%S-9zrb(*WTx~X#Mc7Ce- zZ63G2pReBFK{Ms7tt*Xh{ZM@Cm73a#3SMIN!Vk{1dkM%_mKm5ih{S>Yhc0fKM}>e7 zZ)7nn>&*v`!llZ&oOUpPl%4wIb#Jq#ajkR3=ojlg^!-Js1kEWr+_kcj!$N!f?sufHy=MyK)OvK@c8YBmFIrN>9x>1_H03 zzA+gn>>wH82m_y#xLUYmy>jLEB(=EFrYla&QeFRUQaGMbtBhn1V6b*zXpaV<&H=;f@`R>fmJ9`o@k9~UFldsE#ioa!b=Pgw8KaiW%wQ27{~ zu!ZjQE;U+uo4z-;4~r23+6qbw7kLY2v0v%Pe3CC`frX3wiQJ3*t(~Z-`VO(ur}vcC z?BnZvyw%71iA#OzAg+cz9lKjW4z{*|SRkJWF@P6iHkH01c^ zSdEhkX5HfF?gO*Bo@yKG*DStdYZiCkURj(PoVsEkF3P!G6MYrd)_?=vRrwAa@Q-7R z0~XrHkCHfG3$J!rCKR>B>{xJT1m9YmI)j3JN)`OgEMk(68c3Eo93&q=GRAaSQQJq^ zvG4_7g&b zk?njXF;@uy5hbQh-j!Rh^g;T!kLRf^IY8D-C;()7DYHDLXVkp;&46^a-WSsOqEp;T zz7?dtGLh6OoP93)cDWZ%>ct3LNF11#*;_v!;b-#!J$k#m0sZ;j1?|Y}WvA`Elwk|& zDldZeB7aUN&uq;L7gJwM{H@%R(-TJOgW+W0GuwI@*j}3XBpJO%C5lYF!kA^okeG?+ zXOhYhx-r_RJ%JKl<}1N9lFh1IL{XVJK9fi&^`~+-fCl$t_R;{Ft$m(ys<_PV%1$C? z^T{Np-Ns|9#!BeTFJT8tnD|0w2VX^4qnV|R+}%jC8UI2&-i`uqE!LfilhfaI?SzHO zu^UaF4nbPg@!37{u#1^Q9~;pFE`%CXVq{ z0I_B;F!j9(b4QV>u*9FZy6C~Jb~2v%qvnp^l-(?67dg`-gO=N>hzeSt**CB5^rNmg zC+sPdyHsw|cfZ!pYJM^ww~iak(^~^`z4l4Wz&x&`?+zrzvXOg~q&Iwyw5Yu-!-dlheg9C($D$RR zLQyju8@ZQs#f*(aZYQRNpXNH0;7*PCs1|;q8%m2#pVmrc%8hQ*E2rRaXT)UM+9JP``fBqm23;_dy@EhC@1pL)^dzovv z4jDs9RD10-3uaW^GXV7c@u!Uir+l5sHle)333v?78xZc%92mk4IC*60#-y&qjE=b2xUu|-G4g^;jSt5m z*w~~C!Be<@YPmJSh&0S&K9MfEQ$&iSahEi--v@;fD{kM%_5w!vrHAe;JUn5I!8vT& z3tGkxC&Dch9Dq6dmYA;3Mz%K2hRR4m&721DZF^6jtsZ|n$1G)1P1vfE9y*1aL+BtP z(Fivfb3YIFl#eRhz zzCIETy3K<4ynEyI*$3K=jwip=A5XTYR*$Bn*V;-=d9BSpPWr}pSC+fdlkG*DzieL{ zpSS7l3zqAfTgkgF_%8E3ox5FDzw$35kL=m+FDt|a<4HS9pp2?9F@Jd585}?mI%n2qg@|{CjO3>80HRw77i5b7%{W~6bwuQR4`ZSXXJqqYBEv?QXXHOBW2G1nL}rW zMhQa&cE7T1?!@YJ3VYM-Qx~dXPx76e+v<9@qcmnV`JJ@D#7GWn3-!joG2;ws>7u;KrS?nJH_zQlVt7lw9_w^s|GR(`*`kyTVOg01c6YVrVLh#OfUCEgoZ2~~$AE0h4Sd=RkHFLj~< zMT#_HU`0O=7q&>i2wOG~#xdqMDnvZ>S~%(2{qSrt%h^xV-w&1oE{0FaVrV2xldq!B zLhc+;$eN%=>XNTR8it{n5YNy|_?CW#O+fjy`YQ@HTFs1MQ?8+0>U2|c1Xh13?@5+i`!#p&1aPe~_HdAyU8PViWV_&JV8osUoju~ihefmnUdwD2ImA;(Ld8sq0U zoi_C;=AFhKPHRfGds?)05bhu9aamWAj!D z0p&;%!l{-0gwlT3D+Cc;$b3-qTW1$#&g4eeuTr7A5%zl|O;46{RF})AIV2&Q{&4?o zr8#`$fHYvnU2imA4C9|tUw+{YG)4|K+nO@aXZ4b$Tx$t}+EoJo2Ve8?Gv8o4XdW;> zXz@km&kzRSmD(meQindGkhr+C;*~zW*2gFN_2~w8I^8inPZ2;P1kfJ{mNXBwLk6NdK8GBmF3}+)`}41AWFsHnAFZTk%+D77 z7Md6OL-=YyaFgdU5E2`)!r%T2kSEO}ufNH&SC|WmR;Bk<{eD~hHUA_PiThl4a4tIM zU--1gNpm9D!+`}COP+8roNtZHd>;CwLHQECiMaS4r(KOX?kBkk zk$u(NEXyJgDrZD`uG@qO@0E zcWHH`2_tj<1#9G{c=AwIe`4*=w?gjWpsl0A$&!y#n+^{;h(0COuIwKL4PAc1x!}@% zBjU+X9G|n1ley$z68ISdkX0h(#XW_uC<#uj>sq253;<$3FsRL(&zU~RP(!Usk7|_~ zY_ba3Bm`k3+JNaa7B3KfgkF0sSlAw1E$G%AbZLy;O1CxEfD92^&C2 z+MzNum}842S`+IT%B5s>_I-Wgw{qaLkU*6s%jLMCF-<(TVFdVwO=`YOV;fmnVNB}0 zDk&z?ta>o0YnPYuG50x9wE>j_LqlCH%%T~bMW|89Z>Uw8QDtX&2l*9=DI(w&3_$vN zn}Dl%^!qv#Ytw5&uizx3)F;FEr*_Xqp83bwAkdmjNN+S6KP90d@rpg)V9%UKHBT5- zU|)zEXopF4ed1MHbBdifk19G2p%LT0z!N3Zho)}QOIYAODmVLBEnKHK|5cewV`gw5 zd(@?kq+!oYrwF0GeaZT?fm|_{Rzj{nkc-tqFX39`C|asu_`n;7M&}YFbZI9*&lRztR!0o6FsRVSDt+bP36Vp?R zW@EwTvt$FBu)eLl0|-&4_Jnlv_$xMOF$}vp1{3N$4tm2e2(WfklA#*9b2$5mAsS*{ zsx;o~yM&-V8YL>`;-ghWoui0*nx*1Sd(QJl_nvv^tcG z2Hj_&zX%rU@3pu?Sj`q1SE%sm%r=UsG~3vxaOgAZX?iv?O3g4b6f)*p5Ir^hHwx#s zdDXF0=lSFO4!+3DH>u9|t6tXk&!l#|%%r*qF`n9!qjr^;?Fhtr&c2ptHzGqbm!V%S zBnMVI=79;Gpe*>59H^F3he4_B{!_aUTs7?TxLuHw} z^V&P_`6ygp6gcQy$0%)#Cr8^Ut0k$CtJv2`dyx&z607r8MdcK;K9JU+G(htFr7~K6 z`uD(S8L(G`-}Q;#$Ye?23xAw*6o5P&Md~Ks?ByU8>in5y)R~&P%9`EPWxO#wd`;MQ znj{kt#dOLcUgmT)EtZX(LB)WQ<-HdRl$Z?gOxX=B@>1Y4-U2w9ZjPc`V*Kr zNRzLBSIG2B>X&5)pts>M^IgLu@ZgK~-7~4*Tw-`+2VRnVhEM)E$u=f~;q|Ca2Nojz znc@b3^){db2%%0LaIaCw0V~5BfW;iKfHevEWxzt~2rdN9eAWZ2n#vupF8$!ZLfzR+ zyYoj78>^i6lG>xQb_W6Mv|a&hK5g&-`yDwm*U4id5p$${_j>BuFPZYvAhaQQKcC!5 zvH&(9Z`fY-V0{93{X-y29>T?+T-dqKk>I;n{yp`{FL4%fJF=ucajzHX%fubPrMfuh z2qMFi<8Cs30p`K~gqO$$W0VYj+!mYSZ%N@rXH8G#MPL> zQ|)!?@R`&xfJ~EUu8^tgq5)(YZ)pyhBL4juyf=O_Kp#Wn6X$@tPH2)(8^5xVs|+Lo zE`41bYBOBwGQRaLxU}4%;n1A=7ny%EE^R{v!{O4i*9x>@I_h!hWHJxn(u2?G(`Qn< zURZ!j%YAaGOEz3uOj>|TSNr#=xgPjA{xnl+K_A4Jfcc1$8RNP^zTT#S@p zEUETJdj&~mBXz-BDSFP%>iV{*Iynu^>!En%%Fq>O!l;%@t7EF8Z|cN{r%t?YDpMWQ z^90v(YK5Y-H)eg9_mDtjZ?n17yiFigO6#@J%&ydHAd-;m@jk80KPif{3rk0#yId)2GUH8{Jc%K|qPM1d} z=3Pc4k?iCb(bY%bW&O#}|Nilw?RJV+uB%V56al$9dDVGsb(7x?E$oZmLC&Hq1JW@5 zjrgw=89^jI`Hj%Rm7QzbJ`7q7Dlh%JQj8s42u!{;Q_6f;<-@qbHB*|M3V-pe)$=-( zlAbMRYfnwvt-|EH(t*BJK<^b;1@(!?P32-sk(pvbE%1vdcAXd+xWJ9rXJLg3^`_^) zUlY8K2k%2&KcI4bgH4yJuj~t5aW(zZwA;O*;~u_4SUB-D7M}E_we!H-{msHT@PZ{+ zB*}Xuxh8xv4=M4hiE9F82_X}{8n-$^txeI^#pQ%L(V^@jCFZ zRFOx0WZTT8|IOO#6ED#R0}{$)rARjdkDJLH~GH3YKnLfTbojHRAay2~493WZf%XnX=h& z*{0R?lUIi>{|rMFze6s2VQc)ZFy(4I8aVfE{Mz{B4WX`m^a8lXWV6QOI?#E4OL7+$ zv(ebCQ0SSZEH`Q%PlL(d#UKb==vg`J{p_4D3l7V-$n6Y6V5o9<6fyc+8IC;+SHh-y%+pNzWXOqOL@ z{yZ7@WwSZX_YP4jEI2#yHK-!}7H(o~%ie`N;*ZVh0~QHnA^h$jb3>2w0N|D%DHhyE zn;M`2kp^i~%9N-HmzU*n7lmlmgD8WyoYW3A_43xZ^E#y_XVgzkp4cFkxdUSuPJh$B z8K&~vj3y~+t05|%_KuYwyLshPlc&_zCeIN#c2EPt^@+za9~o9e#S_k5uUWb%orp7q zBaglg3fDxM9Lm*%4dja}4lfsc;ynw?zi97|;7}4){`z+UQ)uiF&%@{0?5d2s?68-} zHhX#4c6HtG9iBn2FtoHo;)rPCuyL6qHJu=Y(4U^wfZ$n`2hXZZe`HY=jy>OG?P0D& zCDT4*wQg=>g_vG8GV{;q9LwBf4h(msMo|cN!2$8te;4l=6~jTes?omYp@}!NzF}2! z@Xf)@MfdS~Q(w0)#3Qp1| zl8w>P^JF-_h56v%I_S$rq? zz3blwbJq5TeEB^(c%LV~Zx(FnaZY~UOlM4fJK_DXm=@wYOmcw$bqw|Ug8g7idI!NC+O>mmf*>}N@8AB*U@Q!E z{e!H9^8MlQoU*yqnxWyvK-3@<@J2yf-P1cvll8-sjtUC*E8AJGC??-n*3%@xH)bIu$82 z)`|Beq=8+ViFY+de-iI%K=7=}gJ)HyKeDKbK)kCxhQ=OebKeNTDgBR|SlLW( zj54XNQIS-S6ULLb*=SHoqe*ow(HFNDWR&>4SbbE967^>dBkFgW$Q>*w#9q`(vgnZJ zK+^wQ&+lsc=1ck)Bjt4%MA#uP~oCN1ImK`$?1d+gaog7x|<`CKAa>{J=5fZS<(vGAjj` zJk*FsQw{V>EV4?@88q!t+*8;fhN;O%0iFw-m;=tmWT9bmKlc%XDP zlKq2|Of1!$h0!H&nSR8CyS@M0!27e@`%u^SRi^+x-TODbK_yyId~e{~kcO1!-oTE- zJtoSKhA;9l&@hK7WRcq4>(iGgB)y*y;4UYSesm|H^vym(eZE#9+P73?sY1U~NY~80 z@p~T$+#CO;+NUR;m!6EmTUXB1CN8+s1NX)ZaM-yw)PJW8%`j!C-^Ha2d0aI&M;TfX zX!7pP4GnjJ4#e8^cp}|UoNjRL4Pp$Oxi`K8?!=b|?u~}={e%1f61?WtkdfLrb>d&N zDECk;kSnDY`8DFU9v2UV&cprdfwrSY??$v=#Km=Z2Xxy=efBpZw#K6N$LnAJJu8+& zonpUAs}cd~`F*js57A`ZnjJ25BRo9uwe&Y^rH0>as+M?}Q~a2dIl>okeB=cO(3HTG zG?^xwvYEFqw^^%NWJ)TpOvx^aF+Da3r~B7?A`N=y<1gArX{7Uk}WI*T&>xNZXI zsd;meOu&5v)}ESWHpNrqB4aJG1Cg9`7&IT)B8(ftpKJUKe{Se^p5Mvd8_e%`|N46W zUQ-SBKGc=72d5`Cnm_jzI%hj59KVw__;9{GXnrgBop<9hN{-(llKE1D-wRkYdXC>A znn@p)-z{|f4%r$en~qr!DvIyrSX}`V9Iyxf%MEEryj|eo#r_Xipgg=>QilB}kT@1N z$5^01L3~(yP%!YG-d}V82M}o(Pp@#HfEluePKt05B{USj(NMW@ki++-Lc7q`vMRGK zI+4S7U8w7BMUg}<8En?FrTD}b?4Zuy%2K)VTWO;p}_rYkQG}xA8MKG}#6w=Cgmx z#N(3)4y(59qkezWEWf|WF=Wmv?hEII zUPr{t)U`_8%nR+{_inAg*W}7Hcl4lEID2)tRycdLpcS%LrzX$G7vAE zs;Cypu~scEohu8qn}L>vsz%8|mG*`;Y7S_1PVdyVoQ1laL=k46y>xEHz(N(PgT(VK z)TxqJO{AkZu#D3^xN3vvUOn)KZK}cp+f*&VHdUE9Ld_TDzx$0tcMXj61jD!sYMiFf zxhhUF|6~m z3r0DIaibBo6C6r3(=tY)ml~vv<^S>91tzDKoKN6=ATDrF{!vj8G@ew#*2<&>Nv@xY|@D7-4j(&DKUA$9S`NkwPS*wHYH+#^`WHsPg8F z&{AcjQ&D|wCaf2f=`YI&&GBkoyr~KB0r&Icdf!ts^BYn(uKzVd(o=KkLPc(NksBSX5h^SJgms0vj0a-+xGO4s! zKqi%GCP40L;>sp2Eu0bemR50-Lb}DGf`#Qjv3 zXoi_aXO))@m_~te`XI9JgAJM_qOir5r}Mm!XPACi^folsbb3S?RjzpISsuaEj+Jk3uPZ?MTs~ zRks63@?ek%7jvqO-QH=*ksk)qLjKFMM?_~ZeD_$1cI3uGL`CrK%C ztHD@^VuUGSihD`Ca!%b~Udi1EVkv_L@x4)`)N;qxkS9DFThq>g&DfepM2C2ZgUjK8 zhKY=9`bAt8A_n8QwkcW+!*Pp;ojc>C`C@CQ+++I1-z+kbNKU0Fn9p7U9tZx5+sy9Q z8L6Tw&&FJ0HZl!1DUlxtj(_6kZs?gM&BJA}y&V-nE-9MmAOFO(G?zDg*$M^2E7yds z=%rdV<~ap}1(Ga`d~xE#11t|Jkrz8w$nl!_O28jbG8#$ADH-m59f^+xv_BuNF;$1c z?39f8UPQ3OL~PP28H_~cB9Y^Np<h;mdP-9`gbO)BVu3d_yH-sJ z7OTzo_~C}qe7YZFv(muYt_J6~$k#qXUB97J;gpOZElKNFsD*0}`xl~LTe#-@>-C_B z5L|PU8+qlnnPemP-a8lpLtQ%iHF*D%f%hhAg?cZm3S0rI6QLTfd?|G0@vvkW+iK4d zJ)`z-sQgD9UZ3B*`pGYaE}t@#@4|c~GAZikZ7Oa%aC+Bk!Sr>g^Rpy}mTjel+2SNM zS$;yDvql zhvUt7nnB+jlTvASnVwjk`K)+&Sq_BafCE_rl*rTy_8jd{=~p+3QqtP0Z`RrDQ0v+{ zou31SWX4YHv&<|rrz9Tlvs!KL(v&B2{cET8fbL`_GMZAe6suP0LmCRFJNYxb&>WDy zIo&Cmr#snrU^rh*qq-ey9Y%LL7}ZHUNyy8RIu729`&D&Li$Zg%;uYMXVO4c7#PVxA zNpm*!1F_H3fSV@|%_Wc~7blX?{BP0>JaDhu=`^t&GQy&qD?Je?R_7kHtH-X)@qeQryleZB}-y~t~ z&x(MJT&K+MOGo2q44aj=PSB`k-$->rjcg>8tW-ZV#7n7xsQN-|IWcuzT~Y2BA#eLg zmW^dSLc^3gx@eJ*mdMQ$aM(@xy}_ge4oh*E8! zo($#hSo$jo1=Fqrf5%Z?aWQ|$)dTM}e{byj2KwObFE_n133dhW^UN<>0C`{f@0Jtu zYY1IroxRJ~Mfyl#IJ*h9-1_45;r~Xx)7=aTLI;0GeIm=GviuBa#IxMqX%@!kvk*Z+ z45Rr!V1AuEg!y&doP6`^6KYMq`Sk-tYR>#p4+?>rZ++!65bM>y#qc^Pu(__Msqc%P zGneG+fe!9k)adlUJ{t!nv4%Ig1{_br8eM+Xfc%yj4vRP)G{A$Izvx5sm{SpRKB+1H7AQuUGb-dUR@`G7tWjn} zqQF=i;I4Qe0@mssS@to7F6FEAx1Hg3<0WE^-}|}o$xmFW$Xp@?_S$m6HSudH68M(g zdN8Sb&7|W;UdgxGH{0o^{S%8ko1aq}?_uK1GA;V0GEFGgS^=eK#!1Sc*1>dG*lBD( z-ox@H6%{8j&NP%{LA*zfnB+c(-pb5{TYsvO=jv7B=~Rq7Ivqhuu=HPi)yXl*9d&p{ z$rlN_?rZ;IJXwXKqBK7F^|tLf?}mbuTeo4>_Z&y3@PW8~rFOfqSQA&M^R*qDvZ1aD zYBA&6XKGPA@h8sPz~1e%ZJ2KBEWcXr!HSS8ElZY!^h}i5oPJGvwtG!m30WJ!bJRaa zYnP9q*;f9fi@CypLqG1!ZbdNWks}`B<`f*S?2EtMHcGObq-z?oLzr4U(5q0_$Ehj( zNma+F3u>$bxJ81>8Eo-nEKGKB99D=;C}+nn?KeqvQhBv&c-NPKhYD`h2#6?#kU{-Q zX4H%uRJ!F#waZ4Pmr*63PGq^mez=OarIYNtrfgS+dbh=_eoq*)OwlSr!~uHMe_ z4y(wooeox-@jgsNxm9Sy#U2!2>ho6-R}a&=OYQx%prGe;iHU71N2k0bOAh4ld~l{K ztx|hRb|-3ZOu~TJ-u>oMQ4r!2KMq^SIVYEd{~37D8#@!|?Vkx@xzNXsSQeJ(QTGu1 znKv}oRvAe74JVEml{l^{n6Ge*fLr!|)Xx5ezI#FXE7*4V>v zmHNRNdswrcZJ@>;hSDD_h`79iqUyT$jVDehWp$tUOpejx3sAd`q+Mdg&AcmWtJN5V zS2F@@Vlo*OMtxZA!$yT`VlCpyJLE)jBGt+gN@n9=O~d~ z^HoLdJ!(XCdZlLKb!G$Iob^-j$7fQv9c){T@f$EOZloAEo-@n@;T@S!KJdUnSogS> zg+rQ+>|~`;>=<9{$rPKX?G9Q`q#m2XYy6$%rf&5qlhrZa#FNDh$tduX`fOA!{)HE! zZBG5XRUAhoC77Qm$0q#s4!H~_ee)-07il?2{(2A`ENr#^Q|j*PjK2bi+785O*Qcn$ zR3!FM+k~Q>PGkLg-1Aeh7U?h*MeVnXpSf1Gvha0v7$#Xe+k-sbGqb#`cDeipsf(X^ zRkyYHYNT|Pa%&!M@@R5oVpO@Y_WuTpN{?5s#Ew&!F4E?CjOv5-EMh(_Am*5exdLJ?BM-!U-w)3& zS|H+d^gDvX1C6j^qTlveqTRTs-Dn~0#&m+Oa9Ma=)cy-&d+}tBaKCbzBV1}^NkQ%M zZAG|uKjjJ6$`5s3j8{((bt zAaR-=LGxQC<EY-x(zp+vsuc2DCZ+lxs zRIegjJ@bSN=%vKv!jscZMqwYJws5T_YydIWD-NQm_e$@#bbkyk=?-a}gVuIvmy%Hn z`Hs}Q9hD4(Z0ronJ`%*Ad`Yi4ZY1zIO_sXkZ zLLLe)cGg4qCfAMdZQed{9@9`IvwK#)TaXy4yvh407YCDLbD1pTOwt)m9BUL0jlCF` z)f^6?JhLn`_H-uHM!H$!ehTqdJb)|cE_Qr~R@N9FF0<*ad&rdU#n@P|vL@7}Q&QtS zZt+rTu_Ca8B|z6Y}Bz+;(Cbc!iXwe7!eCqoJ5~D zKWPtEQIy`^np^YC*>a~;F2>VbAfI)MqOI<^&Cp7&l&dw4464v98#z|)7&}6y2!}>| z{7UZBD9y%KP&V!?QYJstUXrfSH+Nw1yQ4dF#)Y2gRW@F{lG|WMU$E_pKl4RAbmRT! z?dA&Hq^1>fyTZnj3x0XWWcPMuXr4f34Y1HPEE{P@%V>c31tQ%lf3<~omiJn?*r8q0 z&CLl79W%gLtLdaZGUeuTdAZI$^7DaUXg_h`heNtM0B@M z4p*o{ZYzf~J0mFtbvIOQ!8)_HBic{fd{|%metupztjZheT1_1qNY&Bc&y||Ajaw>K zYbz&o`4g)_)-ijo8Nc*Lp)P&VOKVtr=U5RBZe;)uenKD1+C%~y1N+IUeKYHTNigsr zmyJ6Ewo$LiRzw?=txwrB@L>|@zwTfFCSlSRl}D5bWY~#tdg7nc6Km25`XCOd?+tjk zWXOA`eczDyquju~ysJwtwz4#`Rh-YJDpXuu==Mccp2U~KCe}94h#bC%3?%bRw3S!1(anrVXc<4<3yow%1C0U&G+`mEiG_wV}@QVN%BI8gJA;7Afa%Ff&plMdx0zK#$?G(e`*Sk6Ve#JX8s2OS&{wJRYs6!x${L(LfV5-Lxl zzKE-tu{v1PXj^$WJ@I%0M};Mx)9Mj*Pm^T$!lmL%8Je2-vj|t6R^vlmf2Xwcb^j@v zbeQx`Gzp|y#eLi2iM!!{ju~k4oQPlR_xowK_#nAD4WD_Q%cHoy@`?JDPq@UZFt0Q& zb={8k#TfHZRFvn)bEb%TVRU^@Zk88Xiqd3P*gw^AR=h|d){#5`I>mosMsJ> zzGcSdsJxpB3K)z-!K-kGOT^qcSy`$*Fd7B_6tjn_XJ_UPK3{dQO13{U)81T7Zd)#5Wjh;tx7!)|pu60Se3lZ0& zL$}wJUo@L;SL7%H4{2#h=o@`rX-PS04nY3^CTiqqeyOG`dDX(S5)gd79J+YwM!`$pMAk>_;YhK&MM7M{x^T z*=ERS>)GnMukE6RvlGcH2pST5H|SIV-h+Ts!a9zSeSlH6Lo=m4hheuVt|{?4HbAT1 z(cM$d79=WWC#IZJ=N9Ove@yG8K&-VMAt)?_dlA-kpQLm3(W?DE0lX)ipT?RiR)_Um zQreK*W4o*IF6}Vjf7Sl8IQ!3b9&-O#ZT8U&N13@ZF0?ysr})bLk@24WVz&Rx{8cNy zg+p9pAm$S_<|CV0jG5L5m(?_(ubL|KwWe=2U|pX=1Dy>Tj8ZqSjbyPyjnchzvKkP! zk<)<4Z4gI&V&|D3%mqdY=yAjut_=i+Iz>Ean&4_mvC*yyb$(Tk@5|m0?rC_+LS1{S zGnymZ%^p}fD1kA(2R||={{Q5gfVV8qzs*enf^VqvesXarr|t23j=KYLd;GWuAoDvz zi~uK85eO2^0X{JW1UVg~ITJsfN7x*;7%Eb@FjttPuLK3#;Q_`96vEiS2&L}?9lqmm z%U^U*1Z9WanSsh(+C5L$D-1-M&l3v!>Gw>fK&pW$YWrBOm4%qW3D>>fz*@1zoHA?* zTt9BhpoqSuq4*)`PgM<->!jREX%)q4z|8DjwiO90WWWqQh;UIDw3A!JeLTAq{!Q$&L8m(tN9G_Vl@YQSM@3O_oe)b zE=yGs?F%aeHeq$Qj0pRC-CZ(F>NJ;Tb}Yc}RqS7Vux%IJKyJwWf^I0v!|um2Pua>; z2j8|xJ?lfcq3`_M4Sivob!2FOD(mdDjx(O^Qv;%El|Y~&?D`D+AyX;#){24AS8EGC zu{I{^N@X)SZqud9!5|wuYG5~f53VA*uX~>0`n`S-CJ0*8fzatJ-;W4#r%}&ZfaPRR zXZij-n;4SWP)$T7h~=16kCOnnv}49W3mGK%bpX%W#L9I2n=}UyhONrm%F76~zCm~+ zEw#$x6s(YfJ19tJI>vo^qfc)o-8R%VlOW5r#WJuS&N8sxf(*0>iA(}0*GYhelcXKQ zE_1PNV(F#){O6k_H=)`jvq6ngT&+@E&BAl|F2_GgbCUtyODLgW>XGQ1xXhyE_TDM% zvd#obrLVJe=VUZ_Ay}HSm*S1N7dP@C#v@`di(JqY(x^_d#^8?F@w{co)LI5Wo#2yQ zNQ6jr&y_nEQlIEgz9uzIe|lc)9__i`Ka;Gg10R&sT6|EdC&yH5!>lZMm79%JU*$IF zYLuaskrx~m_j+g%DfS^Yl=zMQBqO6Tu7rL8#SFerPY$)jab!SNZfl@H=3jvu4|@d??7um?6L|HS?Q*)F>8}*j__n1!GZns6J7=zSTX|bj{*6fm-)ClG? zOc3Ob_CR-(cGNR4pRu20Ei4$8IploCF2VbEn$Ng~Mr^@+MlWzIoX=Q5$~(?ybdbR~ zS1-d2xEB-9wf8Zfv89#%%jPrGkibKu(`Gjafni00fzpNlL(XRi1|fVfLgja!&k%X3 zSh1^CeT7sKn^Ah7g@I4a%~OceuP0qXr(a>^e4Ce$i>i_D#Yvkibki;}i{mO6VN|7b z%B`^XwlhxEsgcqc_3S8jO0%Agy3KZSO=G(cp7DWVVpg0l9;m2#O*1xIc^nPFo+2Ip zC4-3aQUCqa$Wk)A>(ofCO3ypZY4Fs@4FV3T(GtRxCWs`a6>*B(V)?#Faj@+yfURKH zM^4Sct+O!jQ$lRIZHK82x&13~`-=rMI|G$_BHxdNkq)8PNm8gP{pndlr$0TbY5L<) zU=O6mpqY!Ov~mb8(2Vl`z9uFX2m(Dd(~c3lT96!A0$(scG1nO5oAq~EQ#1qd%dj2= z(1hl#0yH;n`Cr*E{*U#)wCp2b4wKXW&))mM$6eI<|EVpSN^!T+Xhf9d%T|*^ z&LAi$Qg1_3_$+KR*rN4XFejC(QXonSRS-g(K-O(Ar^TyY&kJ`wty;B8g#ta>IP&*Gea1c3cDCyy?UpmN2AZTCIdyv^5?D z*$M!qcUd~;lPVwSYP-^Vi5rs>*@{hVwhUNKErYY4h{^SnE;}V=04>_yNfhRDkG_KG zs5*V!EQBN8V(F_LSa2JGB_@?Jgj{87Ct_Yw(KTric;ZSuK3|J!Cob^x-GF~DC>0;} z@w|^qBT~Kn#05uO-;0}3zM89gtsF30Ow||%`3+w3SJ-!w#*hWey^T7uFe6J-hGXuT z!LWSTku<1y*P@7lq#hOsFh+r3cUh`i+f@%<-aUkZOYjJ;UZr1i8%uhVFE}aao|0zv zvo%2pkjnutG{_>E*;=E-x;I!>x`0qx;5??)rUfdYL`+g276jd}wIFv&LVc>Xa0obO zfXBn87MmV#fcv?IkiAvet*hbzwfn> zwR$x_(hYeZ7pUr%ewt+ES?GpG_2(6*yp4p$`8)okFDOZ0=*xr+u*;!=c3;rpe!wgI zdxMygT8Qg=gTNnzNka@^J~x0FOaY7&Kr2$NMRpo}qNEtN;rLPjLBZnWJ_DE7~?)}A#ocN z-W!1Q{;&b+2h$I~8djka0o(?ixEuVAu?L^gvvO-gaW5gC5>`9FD z8B|?Eqhif@ATsRMK!zQwu#LGlyE$8$gm9TH4VEI*ty6E%X~0HP)I|8}0;RMlrBx_M zq}5(qgdz4lROjP8KAzG5p^o~H5>_zJ-yzfy}6x(ZI$R10*l~;N=M&#c} z`CNwQh)Opj6rL5yqgqPr>!;`T$g{+}ek5ZbPbuM6u6Hu<;$YtN_eqTW)9R4?N5%USN;)ChffJ8 z*jXgo1Ep-(7+kg^#Z1NdDLu&c2esQ{mrbq2@OQ(0r05KZX-T_lE3eMnPMUsd#12BP z;3{;f1m0CrA?i1>I%G}qKKHA9<$$~&K!l_YUc~;ZmVIOttVe}enl{|%;BCtO>d4zj(01*I3!mT%JLCz|P9~Y)FBW?K;_AZR#ae-3@w$;e zOSIx+w-&VWh9z1%zLh4T>2@Tw)Y8y5fL-R=)yZx(eCkcaa_?nx^*KMNndh zrs}J6ObDnq)N6vm%qlEyYkkadPLSSb43yCgF+9dDs*(-^Y>Sdh$h!7)l7< zYJ;lpp}1^Bf@$h~LEoc*w8=n9PkpxV2o&>YYJMjBYppd8s5!LcVGA|Fc!v1@J(%)Z#TRVWHk9B|H$`c0)|A7I8}5X!9LPWksCt zUc9x0qSlG({X{qn%<>%{R%)Fh8cF9c!DOJ>a7x3NQU)7c@he5}n%LsT?lB?MDg(G- z>L1g64@MAbyP>8V>>(Bj@0*rnk@_|*Qagp22d7Ds{9{|r{;}4ye@*mumrE6D!TTYS z?s!U1+e7yO?cP~BH+Kq$_PS#&nsRTF^VfhiVwH_wx^JKo?0>dt>aC607n^js=9FYX zr}L>5uOOO-6bHc-ar@R$xGfMoDFoSj!{L)9UdQ@qJmfp1!DpeSGCh?$<7vWwXR?Et z>|N>XpJWZzhy`#|k)8NT=$O|}JcE??$V(29vn@!A0UJ4kuV@X6w2OPG*65&VE&rv2 z&5Sk}AjM*V>)v=epdSwD@f zc-u69E#3%MnrH-v4od8Ho*`6+K3t>SUIO*XP6|?3Pn9|~`2MyJv5#a@JDbA7^MNJZ zTX`)RJxun7k^5K;PzrMFC`nAadF}JK(Xgzpl>!x7v20uL+^-`bQHr4Ee(leXrz1qo zQ2ixs;S|9hmAZq4AL-;Ruv)9i;L9T63mjRpRjsK5xLD`65Ti2tE+AI0({mVS>$&bJ z+y!~(t{wTa*ot4{LAh)9%~kuOih;lxJpQXiv_&#Z#7RV4LSyBrSG~P-g`u;W5k+U- z8Quu3$-IQPaRHu@n`r7l!gCvs%Xt)CEO+Y9eH4kLQ7SKOV4-m3H$Pe4GEgtZI^M1& zSx}+H-mLXI!SR13u35_(fyVnDeL;bam2{Y$8PSxX@Cs$^8-xlF{ap72A-!G3B`l zh&Y`Z7Gzo1MzdFmiL0QgMIHV zI9YY8a1yl8u!0Oaf^+2v=(yUi-unqkhm$%u<^ee6W=Z8aGH-) z(_+v9^=?sesqozkjj(&v6Wi$t@ogrlf&$LZh8}g&AC;Ogp9-=_i>c9A*dRN$zrl~Z zxxoqyic^nCSOAXmJBW${be*U;h;3u60Kp#Me1@Gg`f!bOdZafvCakp^!jI$sKmD9I-%eO|hRM z#0Ys{tYbgW*Dg6gt9Of~c0`|eNt|!=E1}_QnJ8eZ@!JU~C_U?rU99sfpPynlxGYud zL?Q9ushox+VOS~DgC}Y=a^;J-n>uC_>y)p9u(4UNa>mqakK_!fP03z?0KgK^f0Bj4 z=wCw7k*G#-3Gbw37|WpV`t^;+h*;<6tU&i6SFoU*o%0j3y4UkUG^kQ*l!@*(1f_@_ z6d~_nv68}-a0X$$W0ECVFM0y?mU>w)VrdZt&^Vak3?>ogvg*W|(=Sz*4ZV~e*?Q5~ zB_4<-LU#o-k?f-Eg!`maB^2S59uZ25xTVT`_NEtN9p3|BPEE68<@_|q(~)|rPR%)l zo|c(zfQZz&VGBEw&k?$r*Q(?*JU2}33l-(x5^b8gT}8AjH%nYygp5Hz0EP`(mpi-* zhz}5N$o{KI+_t+ zrDxfRxfN z6JkBRjh4GZdLgb#_^q$I*Ol2=0*XfPuqQ_g>+C}grfPiODSWPjO|eJq`Q zp>P*z-N#Q_`4B#m(`1h-YNB7Nkv%HZL=T|`uZfC)D!pc5ny54jItYe2#yqJg(jDDM zZzeA& zHt3!ZIZm7InQlFUUOg*;ExJbOJubZty|dowqRuNvhXLumkz)2dy3y&RVi6+4?3|)% zsw7b_S(XRcZ?{uosHpNrNFHQYT0KM;xTxB%@8T}n>!S%5U9V_1r-4+aW|z8|XyG+9 zdA#Yu?Qe??(qUwe4wBi3{B*$(_$3aKP(3n8A?6l_Ag=Ksd)@eum6))h&&vau5UC}E zj9E;O{ViiDB8=h>hcOi1Z5}YQ8{Z?N-}z@F?z(6HqeVX9BEPf9aYSSR4EgcC9v0BkZtk&U``eV?i5Bu~K<(NzoqD%aXtR(h@t!3MI zg|9%Y&G7WVWF8OI;uxNo;z-U7+hu*I>a2m4*Cv9`D+>KzHuqN!{TF`{z z;XYa@6N%Y5*kYV5wnpkxmSAsT+8|}WUHwzzNIHhcOBZo128)<;{@CSJ$*&MY2Ch|R z7Az9tkaZ#&ghZPd9x~I8;+2}(PA!rIT^4#pi?2=5Vu)Il&It5S8q;O0lWxx8j~(;1 z*;&uBC}~?M?)sgoo1Fhf*p<6nF^0We;q*Cv#b0|s0k4G=Huj!uTMJa1+TLm*{+J4< z&tnCci|wLbEkgg2R|}@*;)Y*H0em%|Uu~x<%?`0?mpS|{`>a&5>cPjA3miuQ)7?3@ zVM?}cQy10gV6l`?wO6p$I@u-+%aMH?-2fRuHSzaIG>=aI7MUE(V*E*W$EU_I2V^@AU2 z^}yB-oU4gkOYF(5AD}QmTy!ix=`%hHQ;}Or!LKz?L}u25wq{_fq*^mr_Gt-ZMgU}MpO60(Ds|jq5CjKjb zWteF-k7DvF#zukcQq#0hAU%vM2|D#KO4YT`8Q32$6z*&d5b>Mn9)z*|$I?dmeU-S2E*br>~ZUqzx+%P@p#$iW}FL2Mi zzKb_-`2h?}&5JkSppdS|!39zD5l-`1>lcJW8Sh(6e(QmF1N7nqU(oFr4ZEFTRF+Pa zSy(a=roHl*-jsc$9Md+cp$wg>7N(_$3)7l?y68-pCXJk-TB6sW4yd}y?sxQ<*5N;#$(gdwI0Jb~-LbLImutyR^m zwo4|3X{vp1Fs{}G3|kaqnP&p1Z)J;PD3V+#x&Zs3#M5kJ*HXn#=tZ+NgTAr zLf>Mr%X+|Ln&1|uSvP`ddM8X%ncVCVi`&g<1A-E#gZN4DSp0*DSp4su%Z(rL77N3D zCTnd6K`efJN~mm32aY;=RJPw$?%JBYB2JiGaD4-l$s5?34B?{lBE}PdLmt^_pkWB54AUh3-kK8paYM6RT zT9j=W8!TxIu};@hW(?q>jbF;5U&AMZEAHnz#}Z^lH@PY#)s#dTf~?~UGEr}*AC;b0 zNW4z(iCa2x?eHnQMHcDY(aDp#r@bvxJ5UbgN%~^5sWEELp@SywD^#DfkaU)Ncpe&j z>X$0l^pK*gzr@ME$R$$s#QbcLkC|;UjX1l=4+U;!#smL{& zSQ{T_2A&wH`p3m*S77Z^%Bz-rM!GLKqyW3u`HwlR7%rxHnNi4A@<#KlE9F@n<~huI z1?x#ucEIj<`y<1yF?ENYW5VVz4jbj$3d@z()w#(4@rLzxEOPey%?t%KPrl&2fj8Mp zgW;0{-t|Vuk5iKT!COcaKURK8{?kx*jUQV9k!IKX3T|Jh#yOWLnU1?CRt8gJcEr~Z z*QBslVJ);osNvk`(>MF{1R?TgyS-kOyh9;!E)N_?CmHyOiBFhefv5_LE5zAhkdRzY zC|4%=W*!Ufkrl{Ieo?_mRGBA?li4V|P1-#)tV`ZMM(6I`4DSQ_0?`~8UN`esQ+jlM zdHEs6@4!$eipfJ>A!-Wo;40c%O z=wdI9S?RDnPx`=mh7Z(Jsjjexbd6j_w`jRLG4+9ZDaCmd7o3|ao<+fZUtost{>?L@ zcrQz{FiG9bH(>r5jBe`1Z4x7%a5dDj$v4Xqzrd{SvUM&II=AzkAJw6^%1s95t3x4l zWtaZkL6kEgaFMws)167Sat)_x%)@-gvs0M|h~P8BePOWqrrasq7sh;CuemVHDR#W( z4%Rexuv%khAWOXJOa{@G;wncUh^Evlbf2RgbLWuhKCc|)w7w*#2&pkQjXo5HQR|yk zfisnK{1UH6WwzqIwxObtTDT#(lG#zu>ZdChHwwGL$f#4h<^h4zR;*C7AT_${!o0UO z<|eG=bG)_u43w6$uqK>`p}fW4wpe%saMkGvG?#anP9W<)s!NUCrKshEs8TRoW&nzH z%DgF&UjfisY^@}eU&X_1nGCv~t--%Dfn5P<@ zUxf;*SoSj(L&xVe#$h_Yrd4w-6O7g1=z;x`Hxa2Xf~qvW4@zPqLbSVm+}(0V4Vk`R z^gQ{P4~=5_(WP34|C;4d7(90AR@>Sw#23R~N^{B>zRHy#3mN_|Pjw96dJW7^=shDZ zT~EB(lqFWmQWj?#q!5O-(eiC_`YeoYiBIn(gmRWEO7cZMd02x%yi0MY{RPD#&^5$m zE?KJ(3^+=WulR^v7P9RBg)66U^($%Ck)_KA+?_{5^TbC4P{^ni7a$>nR@@)}@RWzd zAOMmKaWSPj;q_6vw$F%BOk7!I>a7$|f$|Yy%HTc<*?Qq#^bppX3b$(;TKDXhw@L;1 znEJJQ_F)z|)kS_|ks2ap{=hpZ*`I&cYh&nb`QUJ~UTLOG`ru>t8}=&gRm)CNuPoqk zQmpeFqET(- zbRY1sm}9sJDH=61$tOia`Gt3XgQt?=ofS}Q3A(1Q;A2!E7}Xjn7;1`+)>}@9==EYf zhxdd_z$n5)kYhoF5Cq+5(beXSt@*iFuLLW}#C8fE1}aZf1C>ySI@wQ1E>l2OC$Dzj z-08mANK8bpZq)EEv2cS^IHX{7T#ABGIJi<~%ZDTG+h%mt(S&JyrWhRlhif$>RbN4y zbf#BloYm{Vb_8PDE;(QwY}$w4p2?U=H!2QHFOiX|6BnqDs>7We3tAu_AAl#W#o*53hsjlp#}oB_zY;>ZRrhjrChF zED#Kv$>ww=Em5?Ryj;TJB8iW7-Wk;^WE3js9*u&Kf>E#~4@4r5HWOh}occe{+o9#J zVAWdTQQdZat0Jo1PIhH&P9Cn3qmrxl5K1l~%$ON?mj-nPle2oQtEWsSqBETLpk@;b zoPs3FWh+8=x!$Qfy}O9#9XwM-2Lb0UxIW<%r%}p6WSv8=h#&1QQEz?YdP{!F7hIT% z_$Y_uc-{U{ay*FA!;W@7%3neAHy>rShKWnU`ybGTvY{+>yQ#rahEey5LmPC{ipJbY zI0A?MC9jvmi&}^+#jYaPC^zQ*{w=u=Cai~P`2NZ>OdfrFkjFSvHg4aJUyLVPVaYhf~SW!TO|N?Gsc7ssv?`XSJ@ejI`v$6_MeurV-av5Pgge2Rj@||wKv5s zySSXIFp!R=z-jI(NZua#qyW;eisk1m++-3q6uat5bwFt-JKxRH82Xkem#R@Cpv`2? z9r(fkvsg238kooArm;|pCzIgG>Z-!e`75li0iD@TAZHs$_gv#+DF367T7 zawun+aNN#usOK1?5{FvsIg|~R=4H&#XpY!Zog2APgEsVfae<%16z;Nl+PzKO8Sc2% z@o+0=0nFrHE55F_hTKYxYs`JnaVsWja4W8Tbt_EzY!tUDHrjEk4$~pz^KJ@43v&Wo z&==T&WZ^2+$&0}b6~m-TnyBd_Y>Q2GUENM9FI5)kCdOBO0kgw)#&8aezU1V<=2)Xp z+}zoB(2B?$LtL|$($d}2-f0(ul{2vPtXpC$R`W?Y?=q4%-W8H3M@>_TV*^?4D|vqK zAx?BNB}6uS#{)W!VdApqC@;(4MZ(qril)`VGGfBH@o0@)URQ|o=yiny3)7`=GgSS2 zYFZ4en>}b~F>pZWBq&-j%jOF@fXmx2VSaKDK?(#=kLGoCgU#QuX@U~a z`oy2pH^zZaFiE}A49+xeLe2166xO;~g5s?{E^L6t(8Niw#VOmnjYz2DKA?{P=yfX9 zAIUv>FJg3`!A+T2&wF9yZUa_-Q%=eN=G>qrDYhATWiLXrG#}q%s8ov*1Jn@Bdr~Q{ zoJcLN4%srp4s>Xi)#H$(8gFM=#jZMX9wj^&;E@U*1ceuyH!Xal!SwmBH zX7w8D@-c3vVArdQK{MHjloG3Llo=Z%ctzVed#6wR3&r5pVY;q*Qj3*BEfp<<67;Hq z9hzg*w(N^qT}f$G%xw!lBMu{+hg;FfEV0Z(=wH}uK9*k4A3=#yRxwkatF?IiHgH_h zQbes=Ike_Wkg2QJ5YpAX1d`zE2&I6mClo6ZTaJqTJaHLs`xHWWXs)Z1TYY4IcLT*= zpyH>5FtEt)Fp7r&Tw=fqMz0j8c#@ z&q}^?rmFK%k17J{7%2jILS+i)DjmLSR#~r@DsX;O6$mNmUtVwp)K*9Cr_>Bc_`%PV`>9U9Ed1=wXVWH#jj?6UM8 zZx>*fb=nTEvCF2g%Qk8bhOe?dG&Bu6Nc33jAR|XadtCiXPLX4@W8~jMQ3<@Io3g)w z7W$3GI@WqytV$Lk=)euyqT;d_vc1?@G0`Z@0&7IBqjsTel}?!}J7{+HhD-S?>ahbm zpp_uYj7z5|j6*JFj5Y1Uovt8}5>X!{+v_mS9_ud^Ma*C}52Q8xtL8M~<|NUmwbuU{?RG1mAfv&C=9DqCVU&#UY!qj+OpJf^hDU_h;B|iAY1IMxmKK-lEnKDEQVV|gLR!mX8E#CJVx5Z*F9Xk5Z(i2o5tuw%x`?|C_)k;i|XvcR- zH8nhOZ#nb~0*Uk14u#sO)Z9F%Z6VaQ2&b6&OpSqABRF*N?m!8^4}lVk&ou&yf7c9&+91cu)Os6K10F4;Z8A8mtT8!O_8!tCuM^iNs!L{Qg zgqU;6)eH3yY0YNPSTE$_n5xBhjTlr5PS_v(&5?9cM!|2xRk#`$D@mk zaz$0ja^7M0zy(DQ{CHFi8g=;%%cUJJRTXQxib&1W6lr9^NY&QaP8rhZm@5))9m)I)boO181ntna^t0-tEq^joY+o zy#S}#YN}V-Z#dQwLXAq*te`Q(er4t#9~|(mKS-TfwN;Er#ITvLM$Lf;^r4908 zR#K#oRgSOh{ZuBbR{iRQB?_&zM3(zVv)*+1NQ)wCd;~J_J?A^S-oLQU4t&Hqdx4MC z6{hf{*^0nW+ckzBoEvBDLEEc;ziZpyI;!nDR;8@%szjBkQeW8zsVr3A)Q&-wfs-SS zrrri)9*;yS`N(`3#geK8HY9_q5i=)!`P*-lH0h%n$t=^#7YlqW^*V63K`Ak9q;2 zwErkBxy8yK>ZJHSCz(BLY#55PWdJEq8f~r-J-7` z9g&OZA#Wj$TNbijst|iaGx?+ric2dl2BPm%7J3FPRnYQz{o9`mNbv&7h^R=vbBuMV zHHP1$JBsJjKfn-Jvg@m1VUbo9!ah)0^oT%`8GwAC-l+3)dwE&fX|(I1f#xH7m}-f5 zpO)`5igk9YvEq${gHx3m=B$XDS!~i?9a08J3HvbIH>Xw4kkKSc=jCc1)hs&-r|0eE zQMpNG6VmAN)TW=FH5&TqdDuNl(-Ue))6*Pl8qa8YH3Zs^q$9UPtZ1w9GnVXyan-py z{Gwa7ygkLP7VMs#d~q=x<(#8Kj#6fi?1J7=B+^@KzN2OE8x0m)5Z4p$$0B7Twj}*=*LCrMa9w=a1@g=uG831Y?xn$gtIDGmCD{lAN@=@BfXpcFLj<wwK#rR zNAEbM2=~$umX#_e($QN=d5RrXG?|2ET9w2V~l|Ge}6$62@R|qBH^u0vI>7^hN726{w zcA}50pZO?GTwa?Amn%=M+?J$3fcI#(72jxYuNWU*6hb6;06bd*g5Ji2Si=o-z?5q< zzfErT!FL)%)iq$DTTRpYnIJ4#Ba7zE>9X>MtCXBW#>pI$FE|5rU1wu$l>`EH54iF% zXL?L1vF2?m8ZBK_NlUMt>NQm*7|}W|GvUyQF)iQ#%#>!<>IiK!(RrEi4<%yp)9b>y zni&T58a!2JtJ4PvGuq zhV>BP6BC4@<(rzsePt{JsTYZ6!d2}O%?tw*+LPOM=8>Aopxi7yN)y|xx;1-snqfH_ z|9J?C#qMcg3IE=HtQ%mz^*p&S}&Ml(jcJ&1qC~8x@hqzWwdI@FC)K_ZEI^sl)o32i7 zAf~T|74p?a!p1IVNF|qOPSzh$q6*u}Ys%;&FdP&YO^AzvgW?4kAa~`btIaH{x&!ltBR!}>` zgVkF91FiTpC-}3#3Tw5IV|B1q^JVe zPyUjIhA%nqOWs+ljGc>?#N7*d+i15T*{edB3czu~sQ}99&vn=y0(Go&Dz?Q|yjHC) z^~s^`5Xfy5VSO=Db>k6b3bb)8>jSqXa+LHA(Z9U;6?D8wZ!uEynh~sYur)ule2*{7 z)qDs@oP>|OC#m>J;RJJ4a%!Q?CS2n+o1pDq7oW`*d!|9xhA_84cYjt}5et?2x_frp z)0!8a|27)hJ$u9=X(HwO?R1%x22Kn-xM7S*qRm2Ve&r>lXug*UHTf3TVtqgp4Vx{x zBeK;mnOVQp$!&-3aFeeeaFI%^^FPThSBLO(;YZNz1n@}Jl*2V7{)TEaDq(^1c37^_ zq`LC_zxtbKey7*F{J&9S;LTQ#zZv{ACOYm`a5*8_aUs=IK)>aU|58Oddpid%&bJ=v zaNFaAjH;Y)Jz>{;Za`g~JVIHD&7c1so67~;ZejjDBHzxAWe1Sq&>iWKTh#o{Gl@!P zG%e7lx;q|I|m;4Xcs@>k$0pgVMpS>UX=|R_ScL4ZzaQ5FeCCM8* z0UV2-)}ZQ%!Y9%D!-s@Dn9f9UrDBC=t-SEGRcFlB#4gWEjpKGgLDH{Kx`QG+e56{D z0UtqHI3tp>v8l@~xv#$WX%0aF-iGWgHD)=gB*q2(bNTdz^Y*4DGGnD zr?E1-Hd0G20^*MBY7hDzuSxd})oFUHBv`wFIsG1 z;K*I)_AaTpK#>8mE7GjUpnV%6o~;fzi>=sS1r=%XVu%N8)o^unBxhK%a~)y5*WsU> zYYhJ|gY$`6O&w?PsL}Hx+p#ftMHOkq%jxBH6TAEvl2XNO0v%h|0~tw>`T?tc?pJIS z)oK-Cam9u_ng_pz4FoUd#gev@B1}*LhVNoBVh8F=RUGoI*tPCXZN-hBk+kMrc; z7h)CwV^ae!gz1c<`Z4HxFcD1c(@^vq+~wp><}w-)Z3x_6%ZpKia3~`yMN0g7JyARG zMHppGl76JTeFKT~)SEOZQ8i|cR~f|(33*LAg;+YNwcC&1^jvx}TGd(bzaq%$t9gokb%_7PmyDjK@x<-fd zXK&JUCrYV8b!Inin~@?3MTAcQgR)&AiF-?<`len58B!4m6xr!Zt5ZbOlAD&~sgfss zkm9+FW*zE@w1p|M95{MFToOMM?05sA7I6&G=qL@b3Kyb9NW7IKPvYnCxC@DEv+G7a zb)#kYtW_%q}xg5(J?#rm#D@BZhs8`tcmz8R9nmaam zN6C42+$h9HaT4`@NN_`Mbi|w&>lZQG{W{9P{L#jwGMAc6C!7bV>W+JDa66B93-L3! z$@De**{q2#G|=J#vCj8Y>Kt1(W*)%<`;xh9ng>8_`={sT_A0p%U_oW+K(WsQX(AFp_9;Q-cR#`HGgz{+#>ft+4(LyzE@O@_zp-j~7fUElJNc(ho3KXGZDjt4t`8*MEguzXsy zBGaIcpaig)%|}oI*lp?~C;^zKrMbi0VKA$cl|BN4LBuPfi4bAz+SSR=1EVwoxj_>o z6(IMOtM93V7=*6t79;svrE!9LU%{B6_>GGiuM)e#H!!x^i87(G5Unx$p!&xo7Ht-G zXKyO3)ybt2PgEY14(WGzS{@lt%D> z0ppk$k&4{F5bABT38)Q$Lj7=1?Gc8F_qMBDD|fya>-@5suf5rw^kO3@82cHqKkVTW4}Dlr2z`=>e?5 z@F*FEVsoJ;6PKz`3S+AD7lYy!2w{gc%AF@~{_kqG>{AetZ!(PwbBPTR9Z*9Y7vdY& zWIkDr7`TvhYjP;E)kM<7Rzs03au+$6W}kNtVaH$M`a3rz$w$&MLY2VD`RB=ceCA8#(MH#=#KkRVW`h+g8k)qJkRghF~k zJa}lKjM+74){V(TQLVn2ILaPz&R)^0YW}k0nuMENf_!NgCF@DJ*(C(p2rxi=tKzP3 znFo7SS+^H9IoSJrr}Jy{b3rB8qJhsfza^JS@NPMfU#QsyaQ;f4PTek0#Zo0~9#oP> zUUB9@5Bc~;!XmPuFHlO$D4oHv>}9V`J-cmE+Z&p)PicLP3F|bwwjy4*nBLIQCMoMg z%Jb^OvC~l>ribU7c>SU6pip;sDxG^@aMtjG>(M8;P3GrAzouvvu|}YE=B*Z+WVF2* z4Tyu=k4{-$(dbU{j8yH2pN)Y;aG(OZ-F`d;>Fh0%Sr4lmh@e@b4vF}iO!k&c_J8EQ z%X%aWSxwmo(|u1S(%CyWQXrsFkiXMB(|wQFg+GIQeg;L|Kv6ul@VHrzE=3Gj7Q=>Y z_bS>zs$LS4WKU;5SJ{+ZhKs@3)lJz`sbv|*YBkk0Wj|Nnl%1Pu%6>d(%AVGo&dyzs z&Yspn!v%0dcJ2}pe2NElSNK^Xdl$H8rJ-wXTSK;~Rh^`9B)&|~8pAWme||c9>T)Fr zKhxRHb^=AWTi#CT9qDazD|EvUw?+k*Zk5@y%+5~d>l@*T1k0qn1ocKe)-q)c-$q36 z71$Fado7Ar4`tYH%5DqYIrMpIH;5@lWmKp*hR}+I_f!(MEf%(o49S(}1O0;T{VxB- zV!jd6!v2>~0oX}Zz)01vs+{0bs>GXQqZdY&Z*=}mk^CCwQvSoFxzJ4l#5)LH{&h=p zbwyNJRjoECs~rS%1=2Q?<@g`78LOqcY@~SO6jHtUa`4MnpxXGo|9^^goS=79ttJCJ z`za1nf%J|6Gh!sHm+GL-=j0jn9J|p;D74BdnRSxC!5`1pkbQErQ8yI0G6=4DQUlL^ z0lxQ=nflEDDjLKxS`^Ed*s{ZxWIM?SaAiC4*+$))CF321){|miR)-IX@WINGRK05$ zc$tJ$noO^z)}kaH(@aK3XjJH5q3US$M$;Y<78lH|HNBK36%}HLx4y9X316SOG(mM5 zD$&BO)wYtu6ac18<<*w-b{UBw_;xE`i`5;f#D(Xcrm6_879KS9*Bhg#Ry3*VMW;U) zDcm+leyF*F!c^!m$y`8&wwzE8QBjd)6+U2#I$O+>NNR9BeWLZF6rmd2Z1Ild0)@35 z2B6f%B|g2?r>6kPwzssCpvt=}gWJw2PY>+`a6YNLfF#xtpveyb8!_DlOl*)?VWYqX zE9*%6^MPa@tJJ79Z2@IYt3EEUFsDwq?Zs)RI-p{+b-TMBC0s(3t7<>#VsQh6TIOt5 zNcte5Cd)es*=RxE(^V))&gf!dIt~CDNujmvhH*PTu#O7zZSs<^Yr%w|F0vcFE{FD+5!j2v9$owpF7o-9aB~qIw|}o4baUMjiUlSLhaOMyigW zLLsTcm~f)yIh?AdY-0y%D-X_A&4b%>$Ai0#PFPk6P!wf74MLjv6pY+VtwayzEwMZ? zzFKG9E*@dszQuYNUU#4}Z*kqe#da*&aan1ta&{iWsEQj`lBuHYP;CKzI=>mGOXF;n zgyNHKqLL;rz&xn(&@Bk0DnYwv$gy^ixM;DNT#E1X@fIJ~BwO!W34s=sk_X$d-p+&g zmCdO^kRHWX{^?K47%4aVm%>t))77)g^5u5UGE$qIOW8at{Ro#TZG9w)4kVw|`L>|wEezcvkXC=;K{Jo>$2G z9);j>FU8^gp}q`tQxrbKW5R^q64v{$Sz*Jrxpoay!>y(t78S(yEy>SO>VC1#J8_4Q z{!&eJ@UkmGsvAjxrbKyA*nlc0DzemEatCpuaiTJnivXD@E!W<#3k8(}TCN4zpJka? z-dA}2Z&ibH;JjX=6at^ozPtPPJG-KgF(CH)#?L~15NyZO`rls76yqQk_OIZ@NL3F} zB5&$f_6Mn{V4PImmbm~cOe z`XIJP`%%KZ6DB-CP_bsmkNo}<5MEqJYTAIpTIcE|U89{^L>ET1aGq9+ulBp;I^0GQ z_)5akPhQTW*n!)bLd4Y6oD@ev5$6@oR_r`-yo+a!kZ@~{JagqwsYI&@NSEuI8nhb= z(f_Orb~*p~wx+y}D#Z}j(+oFD`zDi_uv^t_d268GlEOa90mW;ftJ2mK?W6pQZcTZH zsq^R^DQu;~`)whe8M#fUd}~VfcJZUTCxu&6jLVemPpQWd)}NPyc+)-wF;ZRR?@B;x`5iq|@c|_RGG;FFy4N0bIMd>wFzwXwjLSDKALx06w%018$`1gW|eyK(r6J%$sI)t*;`? z^PWsKb zwH-#Qbr^|oC|Ab@N#hmVeAVT@8X!(>c!rQbwzbN}5r#bKU|JqE2Sa^*~jrU zsdU40msa5L6-}TmteejBUipf?xym;2GqSgUq~B7rjS^^eB8EAKR!80y{D^dW z8{iGs@oXizoVmp9^9j0}CIz!VvR~qTK)? zWxoW(fPipY;X@!o!$=f}egnceWXjzr1mgZtKuC}k?qxuC1H{YF6Yg$%&F@`LtWCO} z;4}h&(5@i_ro@$KVl|=1V$Io25+c_ zo_MNjlkM1~3sozb1q?-H^v$MZnm{O7)7WKOg6?DKvo6)umOMtD#4LlJiEI12A-W@( z`UrJUciCQ{Z7$P6oihz}m?&b-g>zV8o07d$A&dx!3jkpTuT>XSsuyC{Zb~*0J(Ku% zeC`kU+}~3i{IWh^AE$H&9X?Q}kdu_~%f^*knb>V)$mo$zJC0(Pe~mYR-*u$^5~m#A z6y=of(zg*#IU6QX;*?_c@E>|3c15tBi~%A*b&$zG^;m|vhC&t~ z@U1_AgOeO1o|`+NdT#FhoUZMrpiQ~=A1o`-MgUR98f6?HGBI)%K;l@?`&~iB$zj!;XLA#G1nCvE5SC%Rts8igILKq9~DdQ}*tVqC`TX zD5<8+grW*D5|PpZ;$Ynpy#^_JEZZh`ca-xQ<87P&$k+-WEhpZEcLM=kpxXFUK#+G8 ziBNEsz$i%@>FRb%EugS{z?uxj$hM=xsl$lH6-TL#SXL*yc_~i>M=Yz8UvQa2TCqk# zD=j38R$3K~O)IVjZ6_(xift(gX=U~IqqI_Iz?HO$=`3pg8ENI6Wwhd4N-M`BnYq}8 zx{)1YQ;oV?hGFX(s7767RHMEV)hK*Ls0M10qLQa89m$-I;i_=>G$A01s3&#Lh-Yf= zlxmEAjLMjv^|RQDAL?~+<%OFgb!d5~l*RPQ=kaa&64E?&O+{xu)^Q_`v(YzjeX2y) z=2qy2O_QXr#tZM(>6T+w63l{O#a6t(tQv{;O1dF9^v z>^7GPjlcr%d&|XV$MnH42ARfcqkhctQ%zhsD;2z88oIh-<9R(`i zfL^<$BC{p>dj3E%GltDXsr3b7`e?v^By7>*L!6K?tfcq%C);$Qlr@8ZWz}zP5dU&k zYOOm|fQN^xcvu5Ex99lX&TDM&-(jd8hmiPm`>yJ7QK~N*E!Dk9!yP4*vYPH_{6$DY zfXH+QOI&oi!PjN3A-rXGfzHddP-Du75FnCW<+L?@??0~tn z>X3yXoJ$`_MZ#mHGnyORNsx@{8%Zz~a#OO3N3TV$PEJ<=Q-4R7ue0S68Q*G@1|sLx z8sc>p7n_c6NU9eod0jGa4_lJzH&u0#g`1Km6Y^DtpztClWn1xnSVwE**;SUu?ohZ& zhy>;A9W&bnJBW5jYyVOxbX&ehs(khz@s>iZt9xx8YvHgNXRw2>o!&0#qFCuMi1` zyI0Q))JBDo;ofXfEZmg5n~+lOAt=n%p?F&0gZ4Dn*H~9* zRUwqN!rdBLr$%rN#B+m>qtRk@QyNycE!Ghml66FJWbL?t_{u-MYT2telZ7ugM!)R2 z(7sd}Uuxx7Q#~2@#V(#EzVbzViN6K7ou{M>{E4%;^mBZY`Si(n!{$I3lr?IWp;W-snJ=r`3CK1l~; z7$fmwOwYi^@2DjVABQbBpX%M(1(6wjp=|_F*x@SNB11$qQQP2R*UUs!2Hxlt{jtw8uiI{qjLsd{#@X8aXfc?AU2WUXMx^3hGIV8>cIrLpDbj5j*Jhk#h?Ah1QnfyFdeao873va98QtsSPL>LWq}So z=S+CKuY5|Yd0w@vJtzfT>LjK<>I0#04{=R>dI{k!m5}lNWV?zen)o^bsT6AzW=~!& zRiu|^Px3xr?oyIs*RD#!7%?X0Iu#`+qKTZBE5`6>+5%TuDzfmv#4!(os)`Q72jdL;@xg*;lwa|CBrvSFjgfMFG||-!0IFr&)gBQP)bG5*K4uk(ses+$ns2OzFMMF2#@cX{-gNIe@? z7>d;GTAj`76h_U<3lEYPJAm{;Mh;)c`N=>7*=%dDR!|#bNy-viZnf+e>xg8J95VQu zyr^Ak%xahOce1+9+28++Aeub%saL4J@JcpaeO$VcZE{m~tG_u5O>+*DyLkz;Q%*hg zs+--Iah~b48)==;8DV&G3#g8WbR1a3;4d)Faoh&?HD^~|O6IJ24>^?9U`j1Lz2T!b zYgLYu&t^;tvbSbxZ*>Z%7TnUap8fRv%&h#fw@^H)?i|MGLgvKhC3K*Z$Dg6^?ww${ z$jO3>)(hQk{mm$JyF-}P3vlD$*x+%T7ol;lHc=w~yHnxCw)B#jm=1CjYetB)HCVLp-<=u9X2EexIR{8^7o zFPfFV)+^wAU+2G1D4afr%R>;u?stmB(!Y}*Z#qD?OSXvSCH+9~w^Ys#cn}TF87GG4D%K6(9zxMAZ;%^_^H~!WP zjOF|-MaqQyt&R-)#^3g}(wB|D36Qb)oBBZMw_$zjh@4?XQW%pSfq0LN_+Ohf@c)S4E~ic5zJq zrR$PjIzaZh^@KKuF#DWRea7Kmlrn05A7+eoYBk0t6QO{ ze$jNh`UzsHqfl`KO}(V?tRc)zOQM-hCYL|?Qxid{*9j^0sDC!WYhzC=DyW;~g=|7A z>dRGRgiZADHMDE?JQZKG=UM4Rd)~kDDq_$3H_I8?^V*3)^X1xp3n{4gC)WoouCbnA zbFmiHj?yBI!Mo}SI0Z)TqPqcT&qUX5^mv52Cg2q3*tD5_l>hC-T(#p7zk=4RkED&G zLihC178q6wCDkgpH})%6*$!vJwcr-8{a7cMcOP; zQ+pMLUEx{76OJ|Xd{wOBm;GW5AwSqi&rK-*?{f`Lj3@u^_3tN=|KFI9`gc3O=>^7e z`QJmzgz~?g4ErYk_qEcOP5ujzvE;w{U_$w?J`lCPfN0e;ktUa4kb`?4{OlC-kc&|_j55>j~!ov(c?zRvd~-j$k|z+@I_p0Zf;6ea*KO%Hk9 z%c6(;#P7RmF_yd+vyd-1K2-T-@u3gi5miw_e$-AUm-x|``pKv6bUoWke@&>LG)FS- zMnCz)gdA#b^%ITkSo(=@aYFq>$ZKpX!2?A0GUz8S4=gWPKQSanV=3t;jvz4&@2a1u z`Qli+)la0Eps}QsU#f~Ea2*jbgdWghUp0^pk)mHwY~#UJ6c_VgD~j`ZU_r4l*~kOS zi;c;nc{tcJBR_EwIHZEXV@_PgQAZvW@Z<8BWlOy}@?BHWWkEE~@+5SHMUaV-BQ(0`z0k7)bJ#QMmh z@cl&k$Y1Rd%rLG3M@kL=e)5GKYO_!f!JQ|Rej!1x-6Igh}g$Vqd zts#MnzTNue_Why~zC_`yP}+*h7jJVE&S5It>8#Fh7RT`YXT$fRaC;x?ls|~<4QO`G zA4pD~GebMcQaL4l>=s?g@HIZM*C*m}f3fGRycMw&bvM+s zgh}syQjy;G5MW)UT3qjW9l$e0L#I?9mP3TO{BqoU1%1Rv%nmg3nTgf1Vc#4RO49$cLO}O>p6ryCc z3oURvGiV4?UELjw1@~z7-t2VuScmpk?6vF)K3cxgOTS7fC|$! zc>0k=BNi?^9L+NZ1&vchVTqA1t0C9h9(cL@6>eNwQRs4H-Sl~p^*_`2$XaQ1y|jmR zm-P1%btgP^Z@NX)&7{WL6Szcuo|+TBUmL#n^81f?`>g{oPu=$gwYSDDJC_EILEUVk z>F2H#XHO7+g2cyKFO>u4f%# zmqAW%Dz1w<&2^OBKt8x_IPm#1dpT&DF4LrHkmkz}*iKx`Q|f}!r7kGF)#n@V@p6Nq z+bhj{9D|`-f$g%(t|-9PU(MxL$NU{ZF=uAK)JZAI`A(u;UkVL|an(J+DJRDM>)U&0dShW8#6>^j>>f^m}x`4+`ie1^q`L40m zH&y;P);UG&E<6Tyq-wt#p#6}?sAB#0bP;m|V*CZRg7WT{ctEUR#|}GQXIQG&y|waE z$7&wx6svj17RPEz`oj+R)L0xQ)DJ$02obj!Pk%TzeE(Pd!P}h5^p@S~4?942=??=! zdqPP%%@>9V%^qp*S=)w57xjlY5$O*JpUCL5q)5c{hk72QKcwuf*B=5R(jOKOM)U`r z=t5RI!3Cjf&=5*`p+C&NE-IEM)E|ULFQfj@PqRm=X5Q}f2gS1$()UZEZ_%~r+tKwFqifOkPSQoS6^yeT z_(E8u?`lhQBwd^z)RAcPExHzci=_R!HTotI(YMe(Lf`*Dl&p&hq*NO;ge{J~Py1n% zY$l{{;nB-T-y)EaswO`_P^_H3%K@FaX;TzXqwgiwBtJjc39-Dw^!I-Li%px8T!^ZMd`bXQfy1mZC97*`-qE0-xtvMQS@DQzSDWw_C@*1m9oMuAq&`*_!!v(L<)d`^%(YUopA71W}RYt`MrR&9+x zL}HiXR=fU+l<1Vcp*M4+dfOY)eUD8(x%=o#>|z1-p^j8_Yy=_9dsj#!dOl6g(x>@t zXGJVC{qR&LLE6F8u{6YRj#-C5l7<-0K|>2u_`W)PujY^EvnzFHj5+9@`s~K}ynGH? zK}uu}>NiwH=Acpu_H9jjUn`w(4l3JHomz$Ls3(+en6hw_EzU}IG~0Xc)x`u%04aTm zrMp9mv}mioPfPAbH(^j z605%#<;`OV5#~VH667*2R4O7J9{S^&nSQ3KCYS^sZlG*2H@cCk*D(hXORFI@z48S% zh@R@rOb%3cqedoo#M$31f;!SLa_s;rf| zMB$(H#0;}@Ju^G8^O|(`#nppv3MwjoB&se^`*t8CmR(F(@)Pq{j^?||TkJUlNW3OM0xqkiqABg?9rLhUuuX`dHce8%|SN}Tm zr5@MUPn_$o{&k?gI7qv~|6Trd`(fsBCSF_6{=ey8S9hMc#b>`M(9Zd?aQyXb0U}*v zfPB&YL+S&iYo=y8NF@oEs|9jE10E3=e^ekw3Zq~D8E6*uC?{LqUxg7|2$kc=` z!AeV6@wmqEtg3mR;MiV%6Xrf@q~d;%@#QZ=q<3a`ctBtf`dsYdsAOA3>s&Jxt> zq|gyOYVwxF*i@Fby>!I4y}l?5c?#A~x`nz%KRpk-$KCABd53}N%+~axW}nWY?LCma zA^T?2DQ3UvT(N~S{sxRQVA1<%8s|){k=?jlwbNWB8FI1c*#&FVAQGFp_#t(K~KX3c`#QMUb z@cl&k!ngKKU)TtY<@!QzNL)e{5m%Q`CStpg^w>9jVP7kK+4KbgGM2ueKA2EnP#^5M zzF=$$HKLub)T82K(i2*JT!LP4&45EuseE~*=bV4OL}x#7jl_V$TFmXrUmGd`q2PD^ z^Lwdps5%3WEymI%1R8u|T=#rgcAAw3GogXuH|vk-lAkBzZuJe7GLh9~vpS=wZ`31# z%k_;fd3~coNrP7!8W`<)lH^vMnMJp%dSn7sdIF>)kr2HmpjH?C}p=c5#>(yT=S}w=-7feZ~S}7HW9IJq+3Mny@VrGw_~1@bxko=>M*f}o_yti&U|edpsdt6Pn|NS zJ-TwTd^ZWjq@xGtD)kp06{_xeC!Usm^W;`-ZXU;b zHC7p-UZyV7c=ntz=WBPuC-=y{yD^e+H}kbCCe+yWc7Kv%hb7OlVf9;yDY{K}8iony zNHD{fVSm!g1Iz!h`PwG0H|_o!I!DK^T zFM>|vGwNj*ip_8<)hs_%@tc^o!=u~=CfifZ!D1=lWUt|--zAA?&Z}@^#CyBJ`dA4Z zwo%tn0^AAxAbe=i!+0C4>jW3tZ7+F>8?4b_^NL6N$Xk8PhSfd$u+zkA&;F9vnM(T7 zc9zLX`ci3z7y2)L5%w&mG@k$BXT$f>m;So{fkD_i|HXb#SlW};O>O^!h3tPIlr}VM z@8N;4T$%NdBrrlEw*SE=A}E|QqgjUK=%l%ryyBcW5VLTKh|I$Bb7DA)`yYssbv}WX zrVScG?UvB~ho0SNO(3J!nuJGDt!ZEPKhSK>tNwSt|A81<(~BjosT|Om_k1A=sQEX^ z0Z`i00EBVS8r=Mm`8p-fkqZmHRNlibpXvD(B;-h)i z{s+B{?th>Z)1V4hl>D2TJ|e3AXBuDhJaG>t`j(ShiM~S(p)?=*!Rm?ULthQwzk>52 z3HFNWeYX)O<-D(AeZYiNFl`|8Fw0n4;E6#`hi5QeE-vd#$K}DD+4rTwxswlxs z=yW0sic1{rP7tphspt+`Ft)4=si-o*YJ&ON$VBD z+B9QPN11tr<(kc^iHYfU(k0vzWs@hNzMnb$SQ%c*%!&K2^z8d4Yc>ODm5dpJ?M5KGCDM z<~*XAQg!KQ^gh*dtm^5WJ@ZuYiF4^n&nL?KA8TOUW3dQR0XTu_3rK-+RRG>!5WbJ7 z0AE+5=!c@oWa2H5zqjmvt}T!$~r~ya?-K4I}p{ht#B?dxKK}WIGG8PxC4R&4#-m zak+X_N!g`tBc#rXtq=e&g)IOdTQu!>BTye>tFCwagX$GCuwB=%r*;EGyMt*~m%Zi2 znE%iNUsY$iTPicTcOP^ajadE0WD6LxD`bo_-RpWEBIO8j#Yxf#d7Pb7d1G|BVXU}hRj@I2=wSKlmVw*rXqlAEyNYdZF( z;x2Nl;^9NMsDe{8ZZ6jT)BUZR25)`+8Pu$NyF0J=jwkqn2@^OVS%FdL|6k`7m&q5g zAsrZ(&~*-ehKZAT#}%Zfv-j$XB<$p(%6KL>^U#$`D|(zi=t$KJgqXSrM-i?ObY2-} z@LBl&g>3P?4u&(YjcZjM--NsGFMosBKyGYb*;`^Ou7U_;@GIUG863JjDBm+Fe@2bA zG>nm|7;+SRRRm}KZ}JX(;N8@^U##;=5(8fL6T(U^<8M>;nE)BELvO(C0fnr^a3MOg zJiYIHw(ai(Fn9JWuN*occ1Q}9XdC|ZKW%$^I(MRx{8Q=N-$f|?o}pi#$?tDthlnvy zVCVf!*{7@v+p2=T{}x3qEK+2Rras0yZ-Pq)Be&>o%W4ReTQEIMCkoSeb>x$Vj|FYh z7NMrpZLC{lH2r76CeytrxrF~O%14a9%&4vud6?TZokwy{iGVn=L*vFPCXNwep1TB zbG0(^GGQyEt1alq|wuEdVW${_V`Z?oh;riVD!_o;g)|^<@zaImFdT$st|7% z{JL%i-ma2?&rIs>OiNRXN2=DeyG!3REKtzo3yu!Dr=+k*ZLPCUc&O(UWi8#B(uNgf zJPtv;g4cH2n|m5iQnBgH*lz-qv=q#df7E;FRx!<}KGi+DB`vx3txM?B z?%BCOk^gd$?^a%rO8f;mj-oVjFPu$zVSCyW1l!w>5@37lh>7j>62kVx1)H)jh{LVtQEbm}1h&T} zq74oq&<_F)O{KBDH4Iz4iW!;VF;=F#ALXCHfUdj@? ztt5+xpq;odHDoY7ig&xs{jvC@SUe5AodUgm1bWl7fYZf!GSjw}-Qx|=nAYXv4G@^u zV3)nm_fv=5p!aGSt?)yWF5w|)Il(82uu$t~tZ}v4;+gjbfL;Wac`ru20iY3XyO?f1 zpb!X`u$)y{SfIkYXJ0y3lyJ4WrhE1}i+r6(NC__7oj&#s_^5CZ(*SFU#akonp0vGR zIP9gJdw6R^3(ZHss@0`+2CklI-o*zZT=Q^+m#qrAq-cw|FOG9v{;s0!Fg7-Fj?8C- zIPd*YGk`gASh=;5g_Dt)SL=<7+?>wdT9#>~>Pp^fPs)?8(Wa8f&-shy4ngl|J0i&K zAFM1)+5ARI4`Orr=)qo5(a&ySZgghskVd%4 z%0EqNn~~|haXH#xdgLdA-)2fc8-^a$q^(k)9u|CJSZ~87xLyx85RS~O1(NbK4M^;e zcDh7G!qB?ErvlVj8H!J5pB{RwSbWu};yG9U0@t*w_Xp@9c?ud7hU&j!|hu#?B=k#sUtUtv%K2N@;vz}RUeEUU5eSE)VgXu}X zNw0igMcV`E+zBv(DM{{~M3Eh7dtZ>7lGM~W)StI9K0lNE@N?!T%jV1@_YVCkDnBSr zgCw7zc-x9mQ`+N_Bli|QX+lC{nbUN>ErB+^Br=xOB|$MV^R)AAEF)>7Hi#DKC&x+k zD+_M3nx~z~ZJNkTYI{4?EPD^+u_WDnN%i1orkC$egFc>J2BOaZ%a;s(Tf{Y$$Ckln zWsG9ECzkEx7O_ZWG{B9u7}uhm@m>n3JdKk(u); zw-}A!fM1_!E`sxq(8a@TZ%St$Fn%H$U$US0%C;aqa>uf#eO-t8y7CdsgOS^fO(QcO zJcs{NMebaorev4g>K z{HrRBDb6vl#|CqhpUyr}EPq$_^(IPGH+*W6M)W9Rkr5qlJR2ELj0i{k>eIW7XG-Il zY{2wCJW2iO`NAV*d_m)ScRKf;fI0b_gT6;!9rkl^5JzUVQ+6@x`*=Kf-tO^hKHrq{ zo8ywy1)4DkKU+2&sdCB~RUR<9$~_v->6z|-1bcomcsd+GgNfbH1~WMx7P*ldnfb4u zDk0MU$KJcZS6N;8-vNTgik=fC8m-l%9+9ZE#A;1cG=YH6ffGb=l-66kl%h~YNtD)G zG{NTS;k2~Ujx&R8I@8YBj?*$T)_ZFZ1Z-`r1Lt}6e)eVUwbx#2?X}n5yQnvd#s~6fk3@QQ+@svgmZ8IHmY=JdOo{5v zf6HA!Z+@0gQE!I+Oz0E+sS=+sRbqcrCC0%IE5z{YRoagcgT}Xd_k;CSWQG$iXcQ-7 z6zroKET1#GC`uAe+xK&a+)jMR1ADoHw699BfbWh=<~0;D=c-zX7u)&8mJ3Q6BzYMs z4sn4dMsbQ_c}j7IGq=r7yF?@UMz z%J43v%)WyIu%>x*nRHRff>TH%aq%DTUf{$9m!3-L_=NH{kZ3lX=$n5P6o56&Ok68RJ7Qcvi4N)(3Y=GD6D;!=Ax#!Z^WqA&n z$Cve6n3mHXT_2=Li?EAHR~7NqHm7GuY_t*IJ0fxbeA?l!I)T9qgWZN!(>E-;c*=`j ziW}enIvg4efdocOj-e2Gag1`&xU1_dS00JELn0)|2OY?QcbeC6y_PGwAQQk2dp9W* zulu}1anm~&h^|d2U(ATfRsD=FR1%XKb=~=_uedO^=UN*r^7LR#bn}G<#}MJ8z0@#4 zKU_tu23Y8ML+c)1Y8vNvT*4A4bogh0C;*w2q?9!{ z`06p4XA$7N2eALdr3mZTEvO?`wF@6K)Xx7iLv0$J9Th~C*4c1~l~E|@5$Rp2^Qwh{ z>}-dEM$%jR11fu%_>jt;;N7UKr2jiswq$m#0I40vm$hCjB?mOv$Qc{-`?cij9a*fe zZjZhI4HzHjhX#(IKn8it)i;Lv>O^N@eY?Ha`bG~xbNA1pzVv-hLpqrlW-s{5khc8* z&__)nA+ zpIKBGbVA^~fcE<^H;c0_m4KUdXNmB{;!<=d}+K>PHY##g9-m@Zslbq>}~uUu^XwB8s(Q9qq1P11GIZ#U<1 z2Ds)5qceAGP;js^zg|*i=FM`c5*stmZB*yn%Ex}j4>IS1;$ictVAxC~dFlLYQ2lz4 z@$$}0(Jz#CA@F#q4iPf?K@O$Om~864wTdaM8va}vZdkUdFKP}Zzwx4N7tvKxL?+7` zi7@fl24Ui6J{A#ZDL)wqAD<%AUk4xSK4f{%Bv%Hu<}$0B^(XBqCh z4SZw{aCtOkv^;U)@BlA$Uqf-8{IJg*avhoTL0Kt!k99cQX0=U4)!v3JgRaY0n+LU| z+FVtXJVNx$KMB!?5kggvpi)Kr-E!m08T&pT#- zw~mz+K}7bV^>DBbvyElVd%(S`jU@$et^zp))ta}Y`E6f+PbAM@r@!C%tl(ZYri2}z zNp}S_X!-$aUov$P!Z+azD&a(x zBwLfR(3%%B-xU_Xz=A)DLZ<8{-UMXIh3ceat|&?4KpOm$FSwMCRI#?4640 z1nuQAhauU1Dr-ZaXw&5@F92DE)U0d=e9qQMoEwWXtc3JWhJ0Ik_c9_XDY30jiP*z? zTK9!>ZdGEgDnVK`^*ih7Dx)V;U1FJTG~bTnhqN6W$~y`unjhwAp+c1v_>r6Yq z@09Y_=ex>|R%IdmYL0NMRO4UrRTHpLd^Ob=Cc(h|5z#22)n%9-JC@--@nWtjrMP}q z4!&Tija8!Xlf8?G-UmQZkU4YJtB}fm_y_Vq(Z$8E--1}-<7=$d6s9{NK%*gUsgi?J0xlB^)C^n|wLIZ(U|+Gsn-*Hm^T65k@R+=(11Y{;C;a){P-70#ZIHrAZtu+4mZkwSeePdJEH zl|b|-i3ta@7V!<{kHV?6tdaD8*yFv5{5S>e6`TAggVAr#jBAN2r zbp=gs-_saCF1_Y`Dlz7wKU3~&Y;~6 z{-bj9y+sYiy|>$*i}KFvODyc%8Rab^DCA|Nj+U3v(>x2FL~eJ0c@wR-jP774Ev`#@ zmcMTqPk9tYd4lzr9*YdJtY!HikuKki9cX*EHDT+vtLKH2wKTckwzpe?u=08MVORexBk4x3py7uBN7Y1WoOl+6}ciF}j}YIJIs28w0Zhd-uoXy^Zsn z29d6}U5>7%PH!iuK~_P$yf^S-2`Gd>ivmU>{rYu;q!D@w2BbqCAzBV>x7gEBX7*I8 zvWdf>Yr>Nw%v%J1QN=W zYo0%+LiV{R{!zY*Uso#~3}&jH zk?zZDX0IH(J4i9!nV`c{fN zR7a8aa8jwPUXz#A(jK;uSlWZ|PMw*uABzH9KV&~|+Jn<)Tz!w7y){JE6^tmC;;ur9 zJVg6}v0{kk3LStPclG3I znOzn5P7tWbx@|*)R6J&@iUrCb6&JZF_pN)+;<}?*?Z0|I8@)Jav>cXGMfW2HdW0Kg z&XHFa8})#cP+!nCA~(uH&toSuHCo*;a|bOc{U-96EEOx$xQX(V8(vgnQ^QP3#Au#y zkP7;D*X*CkGHA>Ha;z5`57rBfkM3aO1xTnc6gOT(Fi7JIN>rcrM`{0_;Hb}Gn${O^ zqq{*2BYrDQB4*X)H3`FTph<|UnFl1Cu7~VfosoqmVO_QznuIu&GzmM9zJER9S(0q0 z9`THN8G^CSq|J3?l^zk39-+w0muR=7a7=mx^M%u40LJiMR@Q<%o~)b$=njfk`}D`F zh|u&1&CB|4g7lm1Y66BBz*pZ$4N~7YWS*@OSKrDt`oBn~XQOQSzwK>w{*Fn%2Op1e_IB*7vv_!x@7x%v+*zmE@GRdsk?U!$ zS&<-3^N^LbYnoCQ#YZNn>xxAa=D*AyImDFC_(1^u(Oa4w=J~(WVpnp=7H`&LbCN^e zCT+vqFEq05-;BFfa>d5*P81e zZ-{*Tp$WCmHPx*m*|Mfc)ALDxQ&ZhDZO7I2G}o_=e7y%*+En)_Uwio4(==wO7n$&e z=dbUrE?UnOLZIyG%(Uldf9@B_noYt^3d4>5(zD8^}>DKrP1?sofCt0yVsu9P(sh=}YC~$OGRW8i|gJjw2JMga>2Pe8pFj z=}GH*cQ5#J`AaEp$mY<$E15p6!mDS>@^~`R^jveKiCtaI^+R26tZA$}KH)&s`m|`YBeFToW z58+q1-rKl3F=PdOXnod%Dl)Rk-|RZ{4O0SNn&7{K|Ewr7(s2nxC%c*Wf`3zT$fmF+ zHmZb_9jPo!Y=5^Mn@C;nx=lO*vMZu5`p-N5i}c^k)_=zx#aq7rnuk27fuqiVwO9uV zH!6Zm)g*<8pKCbo3cAp8Jx#AKYaX(C&@NnHUAR-iUrIT29m~^2?d_-k62~9c5V@Jr z1YLi!*VDpf*+wQ;S`t^|;*PvQQb{&|(teHLnGhhjS;y#%2coBP&<<{8K z$T$YeBB$EyXR~kR{72ZzW&El4$O3()c21;5|J+kU+#$v@NhQF%PG{3({yf^V&dMDE-* zHLbjMLnADxygwH7Sq4uc6-lH?S@m*BR1y4ZzSs#uh0eXg-?Pw*URdciTVNvZu- zC;aN>)UYXj`D)9u%1b9I+J0)xL>f{ez2C-!k;g_y9vk5+8xtMNk#D7(BkE_9c$H_) zgFj%wa?E0-n8hr9O2*HQBl#*JdG4IrT!`P}F9*Lj3%|#KU-*K<@1_ENH#z)nuFV~P zIrzPKrP2z&HZGrG-O zd-KZL=NgaO6CM+3dNFe6pOZtVV_^JljNCXMCR!NmTMgH}&d^xzqmSIMPMVFUwVN%; z^dVor;ZX+rMeN4s1gz;5d{U@Ip_vv+jXmHWSba$CY`X?D@L6tUJF9-sP1&ldJ4i=+ zd}v|IqSHxR+0!WTojT^F)0qyV#?Hyq&D~^1qk8t zToZRdwtcR6D;Cvy zJXBxwr-zdTKhu+0{`nHGVv)_}H;}7(Yl0Sf_HXvD)1E|iR6#dnZ+)npauVZq!lIqe z91S)03_i1B`Io1w8RJnrEmhsW;O`)Br5IfmXmHw;vFXqd3LhRhI z^zNYaE-QT!1#AWHLqvu(oX>j*?@tuJHM~=T5VOxR|a;VD_z2Ny*Me`Hcdjw{qlxZlD$v*GQqg>uA~Dp|#IJK)^^p(+ts(P7`5aRTH#z zxkq_aUA-F{Sx%+CTvbM$SV-`1F2P}i1S^#wJ$4K+?Ej@V~=j z0o0*qEqlO40{-EayjZ`wVO`x&p)$W7x`+bu>!JTdz^#Wm6OtJ-6?GxVUdC~}4}E2OKL=NGMz7SFijr#8r_hFTgbwZh3J!Ok2l9#l!}w~jfv=~4Y^fj% zPHs>+>#0aan@y?^+{l66u7-6x z64-L)bUtVW^K3m)*N#`<(?OsvdjM~$IAZ{C@o^DAs<i!6>1#I09%0wGhg7^Ygbr(Bc3=XA41#0|aqsNVETxgbtL%sXy8R-=e8DrWY2i zWhiYIzDB#_8)OsgA}m|sEkV3GO7Y!<%~0wLGQp}13l{3A2o|6o5;S!=0}i%>I*ek+ zXCsD<543mGdPggZt$zyGSZqC%C`E|fb*j^^gb+2nop$8UE65|nEvP77gfa+1xO zhP&?%DimozbfOokc#JAAZT*Ue42V-@9-1DxD;Ym~2D)23a%VDrZdWosN}A7kP4L#w z>EkSYJX#+=&&N-BsoC*MoA|j>QP&W4lu~_Bsc^||ieJm9kXEJ3Rki%D4@byBAVq-W zM~Y14Bmf1A2|7OYIW_ODrg(e?R5LnqXH$GsS5y2jMIEiE5sLa0QM)T@jG|(SI*O=+ z6m^86_EXf6MD4Gr5sIo-)b2#>tEiZwMk?wcqV`hMeu|1JYJZ~kP*n8{b%-D$cHgef z_>BQ{BlW?0f)9J~VNLKMszMr+d=Cm4mm2=Z)e>Ng&TB{^&x2Jwq5F9})ZIPGIR9nL zoL+kP{Ur8M$hTv@K9;wDv*)T7C`31|1x*-s#qK%m?jn^)uU6~nPi_$36B`Qoq4ZH> zKSjIuR}910H@+hKfT|_E4Kw)XZI;iOIkkMgO5w_XX}8BT)>kLDU?-od9;RoK>IMje zUZfkK3PsTkkOfh610daa zL|&rk4N6lK9h8h8)-`!&#f+w;;d-H?CR^ftyCz$9I%x92O1f9q6^Asiz@aWjw9XVD3tseOUbNtbuDx=lUr`Q9uNanNMj%z9Xhz^H_R(a`nqudLKa*&? zEcTJkW&;TVPQs(Tkp6V0Ohcyb+oHC>69&pzE7GV5h6iC2e1sQLhA68{Pr}_nI2weP z@N`36%Q#wc7W%~5EazzEP!?Y7PH~}x)e6_JhGtJ>zC9P)acMdn!^7#|T;ileP6aA^ zndx3AT`&A;%|X59hJl`Ky0{ z!X7A{Y0L|acSp&etD1TIY@L83UMP=QlC0&8{GTAly)I3XG^p<18zR;H^gO}TD(7(~{Ec#1OpTMGnkv-Q^`oofn!*`g>KLI+MwaQ`4715JlQ>shU0+yo%yTy(Kg6MsU1jnC1_C z0Gm=$TQOkf{#V?F!;6wiy)Lvt$Ix;bT3$_mrxdV0YWj}^8RA`|Oy%6oQUFEm^% z7isAZo;yn5QN62!dP8`|kX~APUw8!PpzsJ_Q`7}d01m?cX38fdFbE0g>;m5Z7AP9v z>f2`jR~mqj(nVN^eEFgx17c>z(%~U>;?QcoVvrAvTg9loikXgXj)_pVKh70$zO=G_ z&67&rrPjNXk+Wsi><_vpq=Y-lSZsZvup&6u8!_t=4)GMbLWqP%%FG zw%%dITJIdYATf116eUXVJ53=*1(*73o^5}UUcJm-scKi10GF&)z z+Qy)^KYlJ`(y=y2GFF9EK%3 z9|)<^QB*grkT+m|tEm5eqHROLoR1 z(di|u2%U*oeIjz><0NXT|6L!a%9r|cs$2`)9$2$s$pES&YXKR7Kg3nn3YX3VD@Db4 z7Z|rO&v|r_`A?~sf@8#SDkU^L=_ST@i>V7=rs{<+?)o0*UQm{m3qyh}?V+kbn@)CK zmN}AJn@YSaf8!0HDsX!9`B;dun_1AVXDUS@u41t9LaIh#>CUiB#C> z{_17|n-s}_Y*FBDOW{0xHA^tIht_ZGuG0El6u`J1qdYNN9T$6mGoWl|6M{D%G{|B2 zW!YNAr^g=iw$2Q>evH{FC1s1&7jIZ6Wp``&dL#K$p?r1Q0wl)p;xpm;2_DPz$Z2|sPLaS(7KXn)oCG}0g0X8OJPQFLl&{w0xC7twn2>hzZ0Y;phOxH zm|{EX;#>5r2_5@xBcvI{?RwIs=GgcBAW(4Z8?a(AxYCLR${-bU^92b^GWM<89Q(q$ z3yysQ*8LYYdU4R`z_HI&e0IE|88;jMyG}#VG#zBf?`JhnnOihOWUtC7jNlU#ieFDy z^Y}7_iFYE>DJo{K(x{ZrP|Om@!oUz6O(1{XD7J3;x8T?}V9OiG^_OA2(0Fs~3mcDP z-wriifb`e+mLOi7r=P|<^6aPmp<`b?`M~)JJfuPQ2)Af$>I*scHAoh+c6MtCO0f5B!oDOKxC!J9cS|@I!5(4+zIxd?)0G7-g4+p>lZf9fIcb-rf_nq8*iE^j zIqP_Od|?od0j4ORJqTOxqYO2O(N2{P1RP^YV^J@CYNAq`|15`z;Lnao(-EwvuU$9#a{fqUUxkox7#1foctRZjq zX9WwR!=?CiAw_nPk33V(D5EAksFMbkOO?6q07amY4m93X+NWS!KEul0LJ_OGqux=a@42trdwP4TtDgD_kaXXIF*BD;<^RYR??6suKr6lxV= z=_Kw#ty2fCRREb7RINd!usrR~3u+}K(6VMQe!p6~IB0Dk1zl@R3bI_|EJpIW?N-~7 zhPT;sk?GQ6{L+ae4K-$qrJlxvq~Y2iUaeJnF%uIAn|RTHDbok$iE3$t!6}KMsiN2m z$gKdKyJmMG@IGN)6F}GBh3$e432wWft0z9a_As$2uig$Pj_(YLb zFd!ZrqCz|@a(Hm)K}{2NP|H4gEHFMN)lMT)3Tn5WoC?`?wz^Ir*zlJWP@r~AX2kc) zNy(gEH}9}=U;`60HdC>6vpch|jR90{!Z)MYjKFhCgk0YM;p` zf7(ZE4mx=#phtVJ3prD!<~gPwSezVEf?1#rgYY=Pg7Y+CKCFH8Hapb#Pi9u_xf5+- zjmL1(#xc5ZeYcF#R5B0li;wXYy*n4Cx^n<3?<~>30e%xnw$lLr8+B#SiAfki9a&2{ zGgEt=y23UN0=v3BGT(ND6y~*;DHEbvsL-F@MX>tQyShMsdS7dACfPUf8d${D&t=(L zkXHR$#7FUc`z+#nh8@Iwkm*piNfPkA!REyL{qc8zjk&Lb@hx25M41bTl)A21kzG6C zkgrHQAjSXcI|SXx%U&)J=(BFB44a0aD$7pShxFJ(dnN5JKQJ%t`^<-L1LUpe!vorz z)lyR~uNozZ>+~6E%SQRO0VH$_$tOL%B&nMW_HS>#s8j$CVsBoBYEoiv&e!(BAp-%H z6^hU$@=5P2N~&%ww4txP`O#9q`e+8By}4TzP|j^U#dVfgIM@scSs3@JaeP&F-={5I zVKHkVePOfM^_DT%)(zV-c~yh*Kmt=5qI#hwu|_Ekw#!{RAWQ7c-Byf~pCLS|w}*I< zX$X(lzwFI@;b|d$PLYGJ~$LD4p4NqP_)=KiR$+9 z?Xouu@KSrTI;cN;bGyY4VsCcM{-An7Ep?PpP%j*Dgz80!wY`6Pb3>u^fxWq9fYyr& z0&9ET-Ynb|R0kh|L%KS9GX{r(y;;5rF;gGr>a2>T*|CxN|AKlCRb?in%YR44vSdvr za^uZJ+7dxvkv{ktXOY%m_R=L5>BXm-MOt5Q^!sN^aEFch!i>E8qs++XpvWH>xvMpf zGyOI3Lp3zIRG)8$3W;&E5-9}(6D%)i7q&_%)j}$NaCkoo#P~YJNQ)Tl^aE^u&PLre zKGx86^`SHTxrg}E4rI|>{I+Ns9$K*HeGIM@@Fve+(d7R=^W%tA1Sd!luWHVaHaxtY zeiyo2bQ2wpZD}|?3iqQlbOuU8b{?*XcqR8^5+94)7J3^l(@ z+)U!Zloxg*_NsZ3C`-){o0QTuRbdky8ae=#E(wCtG23X&oN1@S&a)BB6U$$OEZffVaCeq4&v!xYZYP*}~Do6~@+*`cA~ZXl8U zedl>dEoW#bhNQhvPacvYLj#b^2vcljXecaS*AA*qY}3%7jwv-XXn+i0Xy~RvrZX(m z3qtz68X6j`)?!10;25A*0c4tiY7HtyGx#?b(p;BNH;-)_8vc^jhSTh=4Gl;@x47~F znBARr9?4tY-F|AQbvq3W?;Z2Sh6dqY;n2_^?Ayw7UpzR&iVO|LRxl_$O;Q;eGCXB) z5kN9Dthe~ko>Ewr(A0eUE$|LKFeO1qEoO&bV0L&he;bk5;d@jWGmTX|B`(^U0)zZP zk2!;UwDF!@l*Y#(|2Eo0=98Woz=3pGsIfQSaaSVqr6iC5d30% z{RsYzdx(i*7(wc1j@sqDTLl&e0>1a={-yi7)W4n5{S_gLjxf4ooO)!<+W{1r$zDMW z+7q%wb^t5_C~;ck4vhiIf@xp=w3?Nw5A~;a5taV*E`rjZ-piDQKVCJD4vYbHip{>W;S@B5sj^F@`#(z%a4 zpc>I+^7$=USjD}Qsl&X~C2Z+A2Tza*(5V}*$@H}tfUb>}wI0h(o?O+X2SLd9kRAjB z+JV7gRdP}E>L24;8-FExY8aWBYlgm+>+ESA<#DcjdbcSn8NC;l-{1{dm0O!g?d|Ef zuvaoyahrHnG^^_~yD5|tB=J{>NX!qD1|!fszp-M)kX-hyPv~9w@~Qo2Gb1^2Fmh*k zoEz5Wf0JfqufS)eP{VLesLWnT{MI=yNkF_o&a;)Xj-1xYE(|FHw=&XsdxffKW=LGl z{&{?7{FQ35KSWK24cX^&_zYjb&w6)ulW_rYY8DCYc4Gf_XEop{QUx?G?F`>S%4s@x z!r=1gjY#Lo`ypJD@ga=Fa+x266aS2If65RI$qEr%EK)f!rWbrECgNM8rGv_e4SJc% z3oA|X%BY;!q8IE`6IspgjJH!zr1B;`-i%y^;`L_a`iar5ojiXEQ=8X4{|}j)ZU=o= zAK4%JcIEih5PctGtYkOS?5(kU(F=uS8-|f=jbSIGfMb4G_$;GhB0V9N=y(X+wX!|S zm`{2^{M&%2aj?Xmp(wjO7$0EIeadX)#<*-3wG;@T{6y+(D~VeAUxhlw%1Z0w>ONOb zx-+QP)mI?8#aq>T-nm=yxTsVkUxTs1q0O!H3f}W>C&PA=_oUipl+69N2q-UA&ZWpK zjkpQYRnZWUxvF<1Iryx_pWyRQ=pg}S@-8Q@9Z{n4Vz(-CIcc`kA-Z?^alYxD8+RIr zu8bNWEc|eIwRJGI*+eR*5WM~jX29pd&$J`7atb_6%3|ddrpxA!J7p$WSOz2IlzAG$ zUDjt`(W7f8QCLOxFaQp*^8`>hkJnF+0G_E_cI7oD*ktNeZAFh&6#E1)k83bX`)sS3;q0xb%(2LU@0YoP^#fyc*g!r58ekryK47=h(Q zn^FxU9erpY7kiW?1X!I3doe)vKV*R5Cxq-^x8Sp8 ze!=Ir_Ep(3sBt7u&8o;viNiSka5znv5xJDp1Rmy)*A2A~Cw&eY$z@OaXjoW*VLh9< z?y;~hBJ<}UU$RMhHU#**Vt~Ju2e>c}k^9Insp-am8FnVN%$jqjfGL*{$jU*ARM=Q9|*r+l(ZDW{SNE{;i>GL z9}vR%mO3Q&e>s{F;na!FV~bcT?By&sCZ}&bCW*EBm+a$lBGLT1C`-?^NM6a;d4%=MSlF}@eG)6a zpKE-W>mMC&Y)960ZV}gMLMchc%gHdFj6QP-l_v(O>&Js>1JUh7=bO3E(p)58A;uJ! zi3dEiJ4j?+7NRqKvBNEUg1}5QQVibY)4Umx>)on~2-8U!XF$uI3?C|@$;`sb2nW=g zePJ*9xJ1KvFA{$&r~8N6&jB2O<5~?WZv(z;$H5x)N5m5}F)!&4+trPHag|_bPhjMQ zBY)4}a}i^BHY#$25qSPHcEa<-gOondKbS(TqB8wy8nD*h-20~Bo#-h2Ctjg$)r^Z} zP0fTk?N{8w4R|Nf?7c?v#W!gxCbq)b5hu5AedM!{2!8vk+uDI=xTGCD9l z)L@!W*$~4Rp4r0y)jAX|p;!(Zev|KZ5|c6CT_VbVr__ z`~`~4RwOrik-Ou)1|z(Y9!B|q1eb^evw&XAa31))_@L8Uv!_(KkAhpAbdTxe7`9Jo z~4^&cG6dp30BMo*>{PN)T`oB?!C+i6Z2PNMs`Hv1hO{ zF*;b8sNo5T%KvS(JxOOz^6|{>MN>*tqDttd&lKo&uo^PPw}-pWNvRHQhE!pUu}G8n zNo)`~J&n}4s%g1dWe@P?&ePzW6T&t>+XER7EuV8gCJLYH;TtNNNJUKc;S0;8=q1|ys{26l(m{hk@^K9%THj8`h=YxxhcpDt zA14+BuzomMs4v(=f^|0nQB7Q9vd>{SIa`L4!B6bu1jp=;P(c&vHhi8nX@|=

    mR* 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

    1q^d*N+VEKV=>ST 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 oiTsWuy-5i5EH3hl~Kdv=-n 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%0D2I>0;G}waHa)d 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

    p-mr$4-_1H;|t|_TA6XgfL1>&;JKM%7d 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

    &rwmn1!l6mGFaFJxA1+1>C*!u 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%0Dh_l-__AkoVR4e{P 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¬wr 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⁢43Z=mYO3lKhU~xVe9(61D9UID~ILkec6^y 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

    o{RquLi1XP27pRpC zbP6}naeZ4~L!oG*q|%nXf!Mj+1*M^SBk2fhQI}lgRw(%L-h9g@2O17fc^BS~4zlmo`tuGoMQP1d_tvof)W6c+(rqpvu zb`@&Ic#Bi?4K*A#9OqqP&Ty|r0{I5I#r5s%4k`LJ?GrNFX_Lh~21T9O{sWmhif>YS z0#(29Uzb=P6^54QIFo)qdQu`0Ckq?GIXp_{KSaksVcwJH3~3d-mOo`i2XAoahm09- z0`F}uE0068VA6aFbs{^bpMf|NS?Ejr87)l4N@T%b--v8r86Y)_#_#Z6Y-oNLH*^7@|0`hKY8w%J*T5zUAGQ5Qrr$&Yj`Nd8OcmM#Bw7D zUWg?2l*GA`66EC68uemQm5x?UJ^d4D95{R z48da!!jo4g1}ln#^*xd57df+*LzpFT_}9SDmNR6&MFryaMrG%U-qzN<#4u# z1QIANWb|v9oSN2g6b#(J#1sSU7{toC4NHq##$#p<0+pO)M*j zb0+M0vCtrD1^FEn^T6~c)pJe4F^bg@{uB4)WGA!x?W>vHF(-8eLI5%&+!Kf*V8Kqq z+@UXp>vg6Dye6JX)yu^zjucm`c9p?vg;NoDq&Y@DcIL6WavPC-9Q2z;IW{*TliDTt;fo>Qhij%Cu>!S&$q_h6>_kPFL|d&Zx2hsjd}m?eb0> zeOA@!cMGYq+k#XN>#0*W7^FG}B*d)sY5*T$HYIu`T3H0^hi14*qbemo`9`vjmh$kLFfPJ6v2HLk4@;Y;+fa$>gTE}`-AbkO)7P2;OB1dTUU9Knti zkYuhrPaq4<_9vvRCb!s|@JRiBO&+Wf(Dx)OHgF{^P)=usZ?7N+YIRl((%76$Y(g5F z4Hp2LAsU;v(KA=q_!{#ifkiCH&K$T?I( zsNZPhE+BGiG;-e*0J-03EK)?JRejS2sWW9qX5HbR+&%Lk?ZKK1dTmNZ(>NA%g-bvu5x z(*~LyaBM{!?*i^At8ET(j0d66`s~YIeRkf-E$g!#bQ>R~CEECFKH4CCQuNt+h!KxI zyEPzGc-B+%M%MfQ5L2+bA2mJt>{sydI*LA9Vr>|(F@}&|-t}7SYxj!O#FBlhS5V%H zfz|!SAoF0}h;%`cvqSC8pHQs2|5k)gWF)>_;S+QOL37zeYmFmy@QOM@G*RAp_0jo& z?Cu|RWQAtmL*pwUjcPP-ng4}Is8P%M$Uag8@q3U6BuV%pWU*&x ziwCY_2OPLIcFHTQe5%t_8N?_cJ;Y5^BXoOrd)jNl1dVmja8w6f?>W}nsO$Ze^}6VK zyl3JLAi^Q}V%s=u3I3;iZ^<9Wt|FCre&YJ$oZ|K=?vK;Ku4Ey0#r4QRc^EyfmOfRY zX-p{GR1o`R8=4YjKdjGx5}a{@ojLPI;fV~q1OOHZ{{BGKqV{kF4rVu0G4KTW73=%t zhT-?fPi&&;HU&AWI!u;ve)K2we~;7uf$Tr%f^i=0VPM=q(tP6aA5)udm-<(-zS8xt zWBqM_o5ClRsNd54`TwW=6QX(gcc#YgpNA6tTX`<<8>sQ~_HQ@mY&}N6+rP%!q<;a{ zcltM-^}hq$l>W^{{nY+x`$SLMh-?gY(J>C4C}~;`@Y*uC{}g#Z=X0pc`qnWAU&o7p zStwKE=b5LQvRru=_>7|d%&Wx8c$_`wR;I5s2H5>Nkq0l2QM0B7OXQhR6xB=xJQ zGUge`7-6I*w5WMF6d{x}SEyW9FGqwYiu8z4BZZ)9tj7Fv=RHxFKZYm-Ka7i=gTRTm z+`(@idB^_E{DzB*>_ktE4%-!Ky4k3*kb;%|)%^&zH$J_}OluP39LVCS28wBd(VB@2 zkNBu*Kf4wam64;f&8YKx(15S$@w`u6pDw4=Jjh0O{7B;Ib(x$<=h0|0ncw5o3;mMI zVT)XbBHUI%nK>J`+Kl@Y#|pU5ve}OM2-!KEx21vEy_O>0i(9AH}T=;}N|CnoZNmM%9;0 zab0C+D^k$*R|r1SS=r@>_nNoF{(uC>zF>U}slcOnAN(yL>^XtIxJ zE$0n(gr)7u3Um#TO=5ht%EK?#$99AmTJK>kLVf-Ixx7{5yw1rdIjx3O%^5SB4@h^34$><&HHo#-5P9-3mNov-dVUxKen+>h9g*f@y1WP2=Ry{BIQxyV|D zXK~!NX;-n{kGF-_E}V9_7t07kKY9g#&<;^Vqao6PJ=PXHT{(m}1^%UVrMF~0 zJAJqTGuc|b>PIxB`)~yk#5X>6A%4}0LV6WIqdU(yZAOam-8fs*-AM~G;sCfHl8Zd& zQP@f}ipy5ASBss1bPqe!AYN*$7Tbq7|5ATk0+eOr6^}7tL^c5kt|x$Y8I`rXkARW5 z8s$o0{?+&NBAM zeqJTd1}rMd|IoS&Bla+;P&7s_2kX6o__uV*3;9G1xbJQnOINf zO_cT2@Fgy9m)(l>lus{V-oWnCRqg8R#>y}v{eXw8JL0((pRejd4L?lyeKh>H&H(%( z4gXDa#ntEbPjc>cH7-lkKQuw`D`x!;y8bNIZ>{UUwr4*xdTwgiWh@Q;R4c~NxO{!r7@yDr0JkE(BE<(et4 zPHH%KEr(BxY`jGx^d3;@@2B~$`HlI6Xh)!X=u6l$LWge%?!|`cfNJwI99W)c{1@%C zXl!e#wHjVMbBUnnV&?cN8ZU}1`O~={hjeo+A zMx1a|m7!9jtxJcU?@~*WV?2&3iPmuWfL4Twdl9&}YAjMwf@e3S7gj0!nc5ED{Gk`& z3s9igs)szU@*~lb|H{Lqi0W646l8Y5^B$MekY)F0&zbE!bofu}~ZTdGad&h3zZ+k`_87?+xA#Nj$ zA6_8=%i+LSL2!Ju5@?eEvGefzMTQZ=)r1ZkyevOFqj@fuxfQ_>5z z_DpgZsfq0b4|)~=T-3HrD79_vvea5yU&YkM{UB~0Fy^=~ALyj!cf=L}n(y&iUZPn) zq)Zbg=r{^09=6}~<%aL#Pu>w@uF3c5MAFC)AbA3QRA4u93#9k?FoM=|i~u87V< zAU@6+Meor;A`YsmM)9eeI$+OGz92E={J&!%?xE?$t0MbUo1J~IWeMEj#9AG;yANNG z7^KU*Ec&(BW}0tl75}2gSbw{7h!@w=^QGzvH0h|`Tt@3&_X)U$rL`~9mxG=^l}76 zzB&_oR{O4OuwJSCP&v3t*SFu@UQJBMmFjA=^&D z5^Ro>C768VF2O&HPlPT^us7z1aNJiYnXFF*ZpOy5gA=oh^GA(tFOw>OsWTS)%Y~CM zU?qs76|LsbmD<(fRv4|3DTXDzXby)$q5#(>k)d0H3~b+O;$=fV3<5gzs&V=c_G+>J zNO${RtNhnV|E;gl|JL05q5pl^f6xUgNK*fAfC_RJL`y3F#OGi9K2|Qm5#q%IdagdY zy1kCZZ~_Kb>=F^4Lva;rhrf9B3h0XvFv15w!%}-bXT7=^N-Vdlh?>zLA^R6I6XW;E zN1S#>_<4LICWjIJi)1vbbxuYU-zC;AP^0lSnXkpxm#p|2@*M-=dPo4Z?i~WE7*=9W z&oIaTpoYHK(^s%=`tZ{6^(FS5n10eejsau{2=7_Af+?4I#JNx?2We6xOdGlg0%J&Y3@L4IQ9V7BJNa>h&j9DM!V+ienM))24H0?+>HUX|G z?dsdNw{>kx!P#+phg*mXFynlDj@1MF9V!;1&*drY1~Xl=bvv;v&3M#~2#Of>`$fHy z?If0rY)o#DBlvU-4$O)DjmC@__nY<{Zarn!d?(7xydWKQjPNZ2=RN|6T_<(@>=DZn zSqCoMHx~34MbDnLUBu;)*kv^F1>f z1b4xIU!|D^`=<^qiTcy5O{UeZu$sYfb_V=Ijl~z4p+@l3e@Y7uP01^X-kDa~{}AG` zjG^VU9 ziT*LIr2neYXxDb71xW(=QSu!r4p=fLaK{B~26p5X>7j%vS@mp2rq=SD5 z7{iC@uqguek1GO5%)Qd)?Rv2du@~2 z%SdYPjWmrJ+oSar?eT@;qqe6{P-XqbJf6Wg;c%+IYrsZ6P|@AmfLI>w!u5fU(bBZE zf~`~b7Q7KSk-$Wy)C}U$->hwj@3pxX;(J|cux&Ume4-lW@i8&#NVxE7uh;-|>PAZT zUNxe+r?2s}`1rcng~*mQ37h=s0H^w)T&eXp)`d=B{bfsXpOWkoTpZ|#2YZBE1^0v@ zm55GDFyg8esOBneTo3rD*30;dsiyt*c-|GJsy|?(hbcTi$>*dG%oHHdO+ug#rtB%$ z6#NZ{u;D~8sxG}1J&_B-U#r)jMYsvQCZA8sM-yaV-R%w`E~z4sUXsKC^(EF*Ie7Wg zJ8YU?Qz&0Ip5UW{u0d-9_6*qRf>qz$54yf`#CyS7ys&^S3%lnrXO) z`RbUTLtG(3(i%#M7v62gM%if)T+7sf{#5bm*5Al(!p2OczN{HlQ4&9PkSQ7CN5t=u`Lt|E&aEw$F@2`$vPf z?dKGDJB|jA8AG6g5v!({uM=+w8t_$&p=fh5X+JD~d#3!*|=T0nE?59rUM?YQs68A+- zi??8c@{Wo-4r=O8q_5|0&cAREM)ov3q5k1wf&;&}<>IBa(s7{hV_L{Mi}7 z4zfg{2KkKJ)2G{K)3B@4g|0Pf+7+^idGup!VovFTg3%$zcf)!U8ih>^q}ihJ zkarc68rLVcS0#~ZoOdTNs)#oZg9$XDu9(r;6s%S&7ZE?|dnYj7=b-d)w$FG=N%YOo zO1|;|Me_sv*PgWyA9Ot2#INBM+R}pgy0U_$f}IY?m1Vdn{trHJ?82bQ#rDl*L#;0g z`(iD#SZ}u0(~a;>DTEiO><1`+4&V*l;4StEFlRzL4~%mT_R9+ouJr-D5oW8N4#QDw zoR9I=^_vFQBGe!H+#d%)I#%-{>481X57$EI(Ae+jf?aVIKze{^lnHCe1zUl z^abBN5c&tc{YH2%cTg$(FdVZrvBjs%Px^NKZ=8!kjFRr`u>!bC1MUze*o=hx6uds0>jC_iN+ z#NuQ;M^;!c)Q3lm@sdsR7`Q4;f`{C$<}tY=3xa0gV*J-1e9W}R_)FmYJh{<^2*Nzl zCJAmd^}GT<>-mN1!sU(i`r963O2ydaAf@EU-mTiq|M1|L`kjC_qx zNO|=n$*=DjAs8`i-#me1Yz!^W6aHj0!@$lntw{XUj0oRa_xP*n`%fz#fgGf-8vm1} z4$l_XH2nr@C0g}5e2oDB`uAXHd7t{*npQs7YhJ>VC48>WL`ik-$(jU)CP9WKLGa}S zhOyQxcPV|dqumDXfWREk6=aPL`PhKK90iwih)Y`DT&q_z?s6n37+Z_kGFpbdF%%#A zfW&S75D5bgjE${$h~8D;vxeanq+)|Oqq1Y_22hvdZ0hG%AYA>poIH7K?CwptDDKiz zz*nI>1itod>qFCXr~;M?s7P2!XwOf~Pp(6<1}43a@#PO(jGS0T3@s2`(fEPG*Srgl zrU43WBG6yyKXw`jqs>EXAqy?I_@v5v;eRX-;Qv*`(mG^cj1Tc7Mfg}GVbei-pmu=8 z51(BGleQ5)1@y2(H0qnyW?c0PoD*s~E^t-+hAVlCYZWSxi}(p(-1sG6WZk z#H*<{Xo~QZoyA8VLd$rwsa0UIuGEp0918(^E(QX4!yw-Lg_jCDgx?1{Yy)tx!&{xe z4n^=B2RnFu-S=O{^^^4z{zM)>-_Obax;?ZFB;_5XNpJ9wV@9XYGIqVA5oRPuT?+dM z%yRwWM&o=v57mMa!RPz;fX_~i&qc&%5%5gGXB_ZJv>*E&0N1EVy8b^|KLaf={15q2 zhzE_s7h_1jIKQb2b@?#Me}?uNXL+PQ_fH(^wlh=s{fA1;??WC;@H=38`F+Z{sr+tg zez!LKulSt-9*@QE2fjT9zjJ4DRDRF(_y?r&yXXFEwvfU`FXLQ49UpP7xA0MHFXAvK zn7=S|xZ_vr@l{=p zikVC@>_60RWP;%r3eWloIrakWg9WRX2Bs^eBMZ-hevua1eONmWsq4^4dnwIHyafex zQP^AwUwz_-f9*Qh5sk<|aOFtrCZ_;YU|;MMB-x{JM22|Uobg1a^c-0kVYZTosNy@M zqi;Ds9wkMH~0&CFYOqF{b;_w&>)E2R)zSw5Ckq z4hQpeW^+1#%`j&+H&cC`#dG4B`_hnxm!ZEv;DS(d>%01*1MS`tAA~w#qXhmab?=T> z67NUj`{a{eX`b2qGyHA>3SjXU)myKDbtl@UT{_;hHi}oH@i1DFRxX_K_oVvQy_^j1 zcN1Pt^5mxbsi!2;5(y|2kekBHoM1_R$36y~qv`zY!ko^<8f*F=s znm-&~iSu8oylSbv9ea+}o<7C|sZyvopC#(tZZ0q3Z83FFEtIEkB$Zse4 zfa@vHB7Jf__{w%n)2FftGr}Pd@pZF!e$K34hHrd7pNOYb`;Dd#?HSyBJ8e{g6Qms^ z0k)nW$D)7gc%**o{bzgGP>}A>r?lI$x&b$EO`JJjb2I67l=(QiAZ&2!DeS zJ@q-HDfO8z@+#QL7Tw*ESEsUeus!Y_021gJ>$jPjkHBkDz702}Uq_d3mwXMb(|0yj z%MjT{XjNtCKWTU3_y^9G_9Y_c&|>4kgnUo3mm)~~3lt!@WMzbZ4L0TN`wT#Rg)dIw z5N;V4awBYDy~Tccq`e{w#D)16eyBWNwuffuUmfkC9g&c(zp@HL&25cYi2CCjYLCQW zDU3JY08)t^DML^bFe0Y25xxT2M2S7897(uaDCxzpFK4RqD~q5A(StmK(_{&{L{k#3 z_5z|As-=bmtX82CzMA+|xUv%e_n} zWcz~$igVI%!2LK|u|6pYy$vUhFL4~&gj06F$UuIZ%u-`$le!0cHTYTKnP)@Zk>F7z z$7?&P79MCo`1r4Z3Pyn=kB4(ZP3??X?<1+u9s|wFh!p*|{>~cZ^mmSw^7fbT_;yLC zHd}rjcVK8AsBtf$U}5N|jOlk4%AE=9`*Z{2z$PH*L^4oF&?bb{+RzbE!-rZcx{~jV;vLAWd^7F9 znpQB&?Wo*TS!n$wQ&@6su4|Giyk5_5umCaU-kU6^`!CqX3~s>P^*~q%=;5&M0Qo0e zhTN3O8PYdhnZE6mN1k~RXP3xUWD2_ogP85tkVhgPAr&(+&6q_e{X+ZR3U0Wkf+$Dj z)A!1paa$p!JmXf83nqPp?Sv}w@Usd(4-9RCP5Zt0MdF?T=M$H>2f#%T9FQ1}fQVg< zQi6Zz?KU8CTA^H8iTzHJi#Y?nBIkvg+Zf@0;}^&h>m-?BQVF{c_-|pqCC&{n5=o=5 zZ)`{d7Q)itBfMrC2I4UDWnnNg7y~W`+McFcF>iNNRH#S3J=u3)Xh($dq3>b1-mp62 zFUyO+r6cd1p>Q}amIuxe`AtcgiS5A`z-1^K8j4mT@8b)bY_!!pV5cg3KFv1)BQR%; znYJ^w40(KSLioakS1o9v-zn*}ZaWxU5peJu0d^?@Cw3xet@YvLp^Sat)=%OSj#%U} zG#T51in<>O`RYzZBXS37$L_>`h_7ex^-MA%uQH$S0Zgdjc;x@b9q~Z+Q2TG3*|B`& zlHQnf7>(!ATX`R7y1PhnrZ^uoF!ryI_qU_`z`l~@Ph z;qVRVl8yfG-OG+S_Q;M{+0q@R9ZhsE#eaql*eMI-fCHt7B$F8%0U$#Myc17@cS!67 zqMBI0Df?Q~7pnO5^qQKZ>kB7*dNh5Z1NDUt_I-o^J&l(m8xOkr4*Vd!Dh}MUtJ6`; zJ|Dinxv@T0wpV(}dHEsr_;2tm1m4z!DycTj$%YiWD_m$RjNBz6~` zvIDt4NroZ!c${8)_{r7Fo%WB|Z-C!gJYQb3i|ph%UmoXjkIa*}zHBXF20r!tCI6Ux2R>ej98g zjyl@8%kyCHy~t7JY){)8Cf8<@A6m8X^6wcA)M4ONfv&2JTW$6Ad?T|4tp*KUU!*HZ4g`y6`!eA(>M&Un+c z+fR)za=(7e{!aY(=>46@-X--{QvQGRmks@|`-?f+WZKuumaMy3u#N6z(aB||F&t6; zKU6;tEy7?SfNp$#;2;`8@y>QaKtI{yXEQpZ%$@6Mlhn92g9D?5WzvHPW~d=AR<$cD zE>HOV!tTWP%myxUu^Xj`pKm_PcUX$x+a8|lmG=%?I`1*h$W=RMWdq|$xekLka_BpX zU&ug75r2SB+@3dT zC%D2rlfnrS?k(E>iGY{2MvFZDBK)k_!8^IPu0%gERlskH&@FW8j<$E!d;Y9v6HwR^;cqj0@Qu#97zn^7UMN6t#80+-BDfrVQYEQ z7)Rp7hm43T)VN9GG=6iil~}Ha013U9N5)VrjVHR{x42g-s*h(NtgWn85R z%G1I)mA@OK6X!9}CFmzQF|2P#?^DMk;+at3ag@UN1*>Z_@GF)MEH%A_m15sR*Vf;} z%XKa%UpkC}pYD2AAJ_y^8gR|rX>@2ge40tm3-m4jxb(Niz}_sh+7 z)36yWMc5ZxObhDWYw1mjsG|Go?q!a>fQ8k|74*T3%um#hZ!YI>a%7B!D~foVxbwr* z_E~`sH_UDOVZL|TxC3oCSeOl!gvoz|B1Dc4bS0D3cfW#;742493wvS(ch1ov_XC(Z zbe3aJWNaqwhctfx)iJ#;r8*GHd_Nz35kk?s#IcXc8G?Af$~zQO?d!}!GW7x}5tsih>6@wN9py)9Z~oESW7aQjuSI?Fv+d}lSHGQn zG<}g7Xv>vXOY$+b6W>SEM?xFh+28Hw=%eyRJxi3A0~!Tq2E z#k;>ss{ae*i4lGpRP-paTK7Z3l@jay4s~#gZt!MkRT94jq7B|R?YEjZPPyv}tX>O& zGyieP;Jpx>lGW5Y9dw3n4f3epVqniO_2}Hy9b{!ysguJy^M0_(nVcs2Fsx?4p2nTt z{SwBVaQUzCSs9-l2w~ybuVZ|5ID)Vg;(k}l%OwBreASPAa>s-5>oc$z2&&E`b?RG7 z;u#neEuW7O-#>M{YTr(b7lDz90IQM+VjW;oe7ui2UU+B*OfHBLALQv+~N?l!R#3f%@29#mh*{RkZ5AP$Wd27$-9 z-VJz1t5)i11mHsa@D3xbdwtp|@+H+lqmn~ZmTOf0`W4paE=NJ+LLefMpR{~YoBByt zK7SeY7o&cRD!hk3T9{8+Z#m;*SJDgG86G|U7#<`g_G8B!AIcNarTV~=d;qt7s&=!6 z--YpS^w`r;8)J6t_1-I8Sf2c>;mi9K-2R}QUg}D;0dAIOj_~rK_&rz)pCE^E&57$1 zXtWZEE*FsaJiIq6ZIBS?@8D%9(jWVbbM;Xet}s3l`JG2ER2vnGHl1%^a4IJ+b@x(qmRoU zdC+T%pDtJkVy{kH-Sd~c>h<({$;I%*suKk5m~VQe1Q*-uJoRPI7IZYeW3L6q4n4&j zM!emu*r+mGyMq7me)HfKv!ABYkt7oO7@(j_ABqghFC)VH`R2j*%)W~>C2oboK~%RN z9kljh&;s(m_bTb4++4@QW=JB1{PL=q#C6N&Mf-6QCr&-|Zc5<^Rb(YJFdvV2j1@xC!TCOl8@^?=-_3h9m!)53Iq($>bKnEgY50CdJth* ztAlT+^iS~fR*0`3kvtf)NIJiXCz;=*iF=cnWuV#|bP<)lyF8s9*}`5t`Sa+T+Q;^c+?AB!WvI&4~UJsZJ%X zdFp)Rn2y&BM_e6v>O|OSbkG$#`y+IP6SoTw>Egoi`oG|Yxjr!{67SPG?75WhZ>*)m zw``Xt2InvXMc1pTH}UxXU?KFF9S4Xx_7HL(cxc+si2eb%stiyO{o*P9E`H)fUkJ#i zIe5l~fVXfv=~qanIjnjf4S==|HUJ_HgEgZb!$^5~fuOX6D6P07J5EOA5)+c~OFWGM zmLwTR2r@qb8HqP8!wnkxVjXF-t3i`XA3xF8_^2~(#BDwj5D%yy3ShnP3QVzQ=<^3> zBk0){$gxWhug(8NV-SMEOv_k#0$NhJFSP}S1#fh{=?VqWU269~fF=5NA+IfGgA+t+ z9f^-z&4{pci+u|EBKWYYdT6bCttt4FgRh<+iE^s3r|5UvpM!pP?}?yDbjb9Np&x#C zqGJbp3$1HA*xZwtq~GUt=QFpq+vA;reeihQhZ`42AF@qc!Uy>TQ*0=A<2M_R&sQ}` zx1YoIK}WWK_#?DG^~m=EJV_1&>MAqWnVz4p>9w~11FE_u-iUxyN6Fz5XcxP|zf@GX<{ z?ZVRr@;$?S=I{3_&Z>6Ig5msi_!!8uy$ui+YUYoffU8j*6QpL7M|E4xvpFERWHLql zp@(o^+h;NQKkCu%L}HYuCzL{2frQo=(%7qz3k>Aw=p8mz>54K?km<$9P?DMs~V?9z)#!qKwtc?VY98MsmtyM?|Z@%Sci6ps#SxCZH? zm|m0I-rjD~>EUdzpKfm^+dBX}Qrep*^D((SgYAh=P;z@$v%OaI6@tF|I=LtI`G=iw zMCK=(%Xi=d{T&w_JkQg4Dt8CjX#vZzJ?fBg_|S8i9+w}uPo6I6Qm~p)z-acZ@q!e`bho1dtOZ{yTpQ&&r`EU3{%b2&|yT%T&R6?JuOyI5qkh_(W?e;`mI~oZ2!zsRfUTk8^$u#o#@zCNv#W2NkB0 z10}@bgn!X;(94nQ->`i<;t;|Je}r#YX12)>xFfzHC8}#UHR$!ZN4^(6!S84xLnE~@ z?*D{|)*EJY7$0uW&Pg>_+R;KRd9hHIK_Sn4#T20Smv0I9|XaJ#f7Kh&D4%a%m76+ zct)$CkpqEduHVkB+ODOqLSV|tFQV?K&#y&5O09FiDMp5(6nlKo7Xdf}W5K?pHN5yj ztFt^?f*QLOmvGabl4%xvGPS3DNrsia#6+|*6wE6vSQY%F@g&l@t{$ynaaOj!r}t9$ z09?--oFl7TiFJ}*^l(=^t{=I2+JKz{nj5#%)EHY%MK(U4Wj~K@g2!mu6vv7LtG$LC zWkPA!eS@Dnc_c0q5x1V-jNpS8j*+oYa~L>owtQD>4jblh*nLd2z6Hw(hrNzZJZ+>o zY+nl;HlgPK4}X2?Kd@dHY`=`W|8_lv*6!BJc&IjE65&ct-Cy$PRD}3z75BM5xr3(I>)93h$u`1I1<5jv5U( z(LwLbd9`_cQLDlUR%-;MOIu&mIvY-ayRrR9Z(IL$y0Q2jV{zB+)kSTPTbNcoI=#i* zcFb*6J-Tg+x$T+Tx_Wd*i@6<`n_fNoxE6CeF}F?i=#G->!D#gHL~(sl*KA?n>LPE7IpVm-&52L69D1-)&;kZOj}jBo-t5na;(TKTPvlkMQ2oaiYTC_$XBPNvMM@!^+K2;Rkk*{RU5&5FOJwXj0dH z-xi{vacNxs$IV;_)_^x^={Xo$CamLxlV@a2Jmj}o*a~}n^<$qRpKuR&;!3mx3(tsX z@mXLT(Bsl*ab6ME3VdX!<^nhVnh`z;{6u{-vlQ~*YA8wDt0n_d;rh1O5CqXdQ)j=* z^LNni(RS4++ae7MtFIi^s<8T=VU!~He^Ykwt-|%g3bRK>uet<76bL2_h-Yk$`P0$2 zIezI!ZM%qVU*ZnnHj^w+lD4{VeJk`WlroBYo41I9Ekg-cqtoBiCfyVSlZ(^C?vW3Wd&YOTbciSvtT-|JhtU%=z}+b`8` zM{|f1Ph&g?@UZi+B?evbDZ8EUXW(J*XH@g&Nx)pq&X6tU#=6H*W97N{5BYq>zsa8o zHKs<5(Dlz_{c2tRlQ&R*v|E3PxBk6SUmmLpBOP7spzD8MgZhsPsSc_hZr%79EZZ)W zy0ID5TI2gocYeT1H>TKH=gbm}4F_f)8knCJ7%x}jz6Md$U)oAVw>scSg5cKIjG~d{JGJ`0cu4AYcQGXOdi6>o z>H9mGglN1_#Wnyl;A`3)bBr*xdRTU_LNuk_bvL^anTR9_+j~3JRrpWK7GV@VO05D} z?&NJd*+)rN8%Wq!+elZZJ%p|<)mP#=M4o-H*5l41z}VgC9?SiW#QyD= zqfVK@kii{u*rQ%3L8bI_CEOy7WRe1}>v zxUd_p|JvO42&z05+B5ljk*;?S>#f!GhOyoubC~>IX{I`MR!;b>Gx=-)KPHi=DbKRIzTE;Glkwy7W>g z1c5*-Re-;-M;(7p)!171KMGiHIsGTB@6ZPNZvd9tkGYsOjjw6FPA$^)?qR)8o&K}l zGN&H!ck4|=z1SaR>;-|^=|JE)L4b&n0n~FyhF}U@e$JK|%YG6NM zaKExK&|b4mG3I}3#2W*&z3PlNPvFvL&a}s2&S1Lv)C>Ov$IYC_@8*LnHr=pi=fh)L zh8~AL0{_M{pyIovHohevs?h z7)%t|4H^+10m1^668YPR&>rGM|2D!Qe8_#n>GwDnsXsu9`sgd318KW~9T|rP3g zbj_&Zxd$^DKbUUvk-hlQAf>3Oa7%Jemb{e`?ufyWGYckGskWLFjcqX>OZ7&QPn!CD zs#i0}8SVDZYDfaR4}e66yu2E6sh>~enfG1GEf5;=v@OOXvHxOxv8!GL2kKY{@&#N{8_iCwMbpPHuYb!9y)*H}=Hk(k43 ztj_PNk8oVLnS?8EoZ!74T&9S;LW-ZL0W2bb=QV)86Tm4N0QGPe zz}u|=fVYP|?eF|q`W0aHM|JhvSp74AMZfMw6K?eyR_E&~To32zdV^VSp04+6)?1+K z_3<=Y&U(Y0dXsd$bk_T;u6MW|^``22)X?1avRRLB)}TGjC147l>aQWJz8?@?(GZps z!T=3{7eQPIpQHi8W~>@<`HS-cKPHGwEF2=3_-$Gbm2u9KxQpUF1Cv+m_Om}fwI~WMBF}9^Ez=D%)qu~Fjl}` z>Mc+dUL8b|x5D(nY$Y)Oy6{T8Y!hb42c9K{@uCl@2BWKp!V^$xY-}m|6Q`#T(sQ4d z@}{3udc>*JNh*DhN}R7!6m$c%rClldeiHl_ulhyspG|`Q94fU0ANUyIS1^=?V?=l+ zZfIr1qb92~3{CgxT<6^r^?3haQK|<+!HQD85~6Lp(?I;mIfl)l^@BXW<&OA4xC$++5FSYN<%}^UW8Ql{Znd%j0T)2SEO?eC*kg8d_gnERTSoe|X(@Q2Cd5F&j zq`(662O?7vEsnrr-$Ca@R5e|6M(I{rx~`Xoi6t&KQx$kJdM7fnRJJFhPa-2*wew`0 zl*q_cdry}xOB*LAGV;{Bo{a27M!s6^$>^KN@T+;Aj8hUBrg{Jwr57$B9gO>a#%cgU zu|f2{E(ZnG@1^E4YEMi%m1$#i+FYmH=}arsY4e@5T&A6+)Al=QXE3d&PV?cO9O0eG zv^F{|gEM5~IecDY867T|KalxfoJK+{%XaDvV%k=nmW4DmrvetE=&~%#B-MWaMhT(@ zl`)Iz{3xppAhD-W!{JL;KH@~s5?}O$(+ze|^onlvEH%ZT#Cdj2C~FX3^K80i73Ffd z879)XswkVTWux;TTU5svvY>*&UTsa%*W`+=GfS=U2$VP;CW4maA3(upYdgU<6y=iB zsggYh*AHxKWPKbzT12a99fC+5o{e`?&_dhk>5%o{S45QMC%W2PhTyV-23#pxzbNu7 zLtO(%5M8wn%QFt{>BAby@$n(;=4} zv?G^y>`1Qu;uRUdsMauc5C_<1jVgJd(~c}eIzBO3ssu@xSo2~~oJCD(9rFOaX!&eyNxtBdn>l6<}Uq;4_OSR4s}=c+@D%?Z5} zRA`cp>|>u4e>Q|N;f=|ETr}OER!BMIMfHZz#6)@-h>2mBOmYd zfaDdZDs1$VREw|-k|#6SUf~}04MFW{);4u*UOO{G@A=HM1FA>^dcp-1(tubTfNC@# zssKcTfOu-S^y(u4{V0c0p;{Nvr5X^61JFVZh$YX6PJfWQWRS)Zz! zbUZ?4&68(k>Hpju*T2e5~ z4*{)@ORb^`6v<|hzT{`f3IHN|bJ)>`-9V84kQB`qny%mi3e@w^6v|hkywTa7Ooq2Y z`A7tJR`SbX!6p=6I#1~PqiT=y5fm$9T{bE)5HPJYNQUpjh;TJ#?XyAe4E$dDKThpU z7f5XhhK6-!3Yup=08W&eb9PG~UfUtFbe9^to%17bsk<2LQa#TU2XBPzjZn$JX-|99 z&SH64rImX;f!J#`b)U*$<7G%ZVz)=_IjN^lJ+W7|(1rJ6L%L4TYF5wflkIa?k2&>< z?@j=F>{Aw1<1<{>)L2yJf!*sQWVG8)_q^JyZq}8(w%D$yjJM=){^yimt;@g3 z^5^UFoji?w{w>NsjP)1X2gc<;IqASRr;vQ#PJU~Ui6GzC>+i{KK3^7qt;GtFqhp2m z;(C5H-dBqS(FeW%y*hq^MUOu2ww?jy;_nX7Uqs#ft~Lribmj5eB2hZcMhxZdeD-ceMOC$Y{xW3k!FSX`E7EY2&n zO}x6~&rs_|kWe!=)=+md4`5vPGx75cR@1{@sTYtdGHS z04O>MLuf~|b`qjmf-nA2zqw9o(ZzVywLC09d~nv?s?*g6NYp9kXlPU^&AcV1|m8lGTn-3(Jqo4ScpJh)I~PmS1TzZ+LeF{`qQcW5}`5JNLE6x*tCYoBfS`m@4p=Ffa8ajUg z`k91&l>>c4Pk~NJzVzxibe2?|H1xRazg9yRp>IXB><`gwRam-_N8D9^B5@ORzYRHSv3KGygUe$)1B z(P^WLcB2HCK}7}&xX9x;8;a@Ri5z`YpY}9T7y?s0tYjHDC4gmMBeGzL&Upzoqd&!D zDKLDAleJ-cPVmJT1(EwFBaG`qFeHv~-JAl)IhMI%z`yVXbU<%O)a66DA6Z83Q=v}6 zPuXOb=%As952W^&i$E#CZ<3(z1bo`dD6SyoS&;wK8E1-7M+>tMb0zt^m=dlBk=h8vig`byqZo{Q4yZfiq?PM5 z>b&ZwMzZTN>bG@2JNfxKznW=>owOXCM)kF>*-6XPY1BmPe4>r)RX=qXe5g~_r8#Lz zr_Eg&2VX@*YIe#VFk31<|l;dR}d{C(Yo7|gHh?xgM1X%m^&!%1tuH&l;J%|6Q zTY8fpLc~)vhg*PasdXmoAA#(;=Kuu&;4Pp|IfpPp)o!`_0Ebo~&U}KyzlM+>zfi!} zP*jG22V)iG`#_B5Ia~M@9kk+XOfN7lD`2+|k!RzvB-o$I8$y*16g9Db7P`@hm?vgQ2l|0(8kb zS7z%jb#5z7LD?@t*t9bFbea+Vqx1{;&iAG4F!C?CM(1-Qp-$~bq;^q9IHR40a{}RF zMJM}3E843|8pPmIj&|W_BTe6qBI=BusA^BmHlri5Mq2+VvFc&uf(EfmWiy8;93%=f z)35xU)=j@;oBznb6u>^z?a29rw)`t@2R;Q^ZXfXqbe(l}cfel;H`FD_sr8{O99+P7=*B*JW`ID8 z@{vUs3@k2+m~BOkgwZe5C1$DBFazx@=uvb!h%Sw7m&@)J4+Aoj{PVf)kV@ zB5KsAK~TvmyJP`PAn1%FiUNwFF6$9lMMX#y#REtpjI*Px_a0vBD!ASkM?g&Eh_~Ra zsGx}S7%neB5%PY2)&H3c;O?`}`#vw9k7oYW-PP6I)z#J2)z$kcKTH`+EE^R2Qj&nDxGL2yFSTurK>$xp1_PJ>T57NNo zDP`X^dsDW?>Q?#i8no0EUL&_dy0mx4T~Ckm0^z)lPG!n1e2~TS7>{=`Sdw^GeaRkh zw%6m`cPovSUMhDZ<)|P&phhKs1S2QC9nvUzn39Pr=r!K|@#Vh1gmN!aPMecPUm|^T zTS*Dg{--ZdhmNOYV8?coeEH{8{te0p?>)KmJ^b&2&kpcj?(wE;O5H_?^z$UXp1#}# zD)$lP5|>a}`gzZ@;zt-RkDk!{`S@qgFb{jxa_7`=d|aNJ>vP<43po-u@IRezAJf6} z484-*EA{S~&#VKRE~erm8O+4DP&LE-&4b?+_#M%MT{ev#H;HumY~ec6ka>@h&rPEZ z^!Nj5V|DCm+SzP%PX^5U7as4m!aG0cpHqCfJ<~MFpTD47V_LZ((>(8*=R3z%wOAK5 zOU2xYbIBO+!|G2xT@9YDPNHigbwZaeJ|=nS@4|mk8vaKqM?1d!BXoVH_BIJ;%74Gyt!lk7*{hpH$=Avvg%;VY`wBW=ZEp!d>_x zbl2HKPZsoBK~WW(UGpctjfaB=ntPM#_VjJcPix~`rcQ#J^v&)~3Xrj_&}69c3L&5C zq2G)F+D1^t&`+KpMt>^YT-coGWCoF9+JruTIZTs&G1zW?hiW(3Nc<2kx(eCYnmpWe z3)OrrXv`b+k6N??TfkzIrggx};7o+z~ z)?Vp}h8?U)59&ATS+=`(l_m)~L%Q|A{BopWOeVKdQm0d9FMm>cdE!?lB8tt#7LIQ6 zCN?`SN3|tOraB zv+Fp;?9Vo@_sG;B|qbl zZ_RNxPuQ6__3{y(xT7LOJe6`XpZ}l?5{E)!5*mial*dOYo90FC^N)zBedJ%g9{7dAL zB~ao0gM6Lj>Oj2*X}CN*cEeE7vmxoMQAwEMO}AN&$MBRxIW{0Dl@{kQa3VNXxd z|CXLMYS{sH1bf}XK92G2_3B81yC%=I6VFCh@;#$2XVb2`5z>r0kz+P%Edvq$1orsRyoYt);@^C^0hC~d~PWpj&2oy@7ZUk^4=c`nhC!?if&MsrByF`QL=rRl>9~fLH!+nDc$hT z`SwjAM6{wuR23&#I%zuPT6 zXn*0rf73sHe3Ru%cPqbBdei@qK7a6kEa4P9<#kFSb8O|1+xUe@s8=-=rJ; z$JzYb{*KA`!_Gm*zkz)M89(DLWPF?V0vX>bCF7s@P#{e^=4eJ@82zgCIyqlFzQ;Yj z*=K|ABag3G_?~}vH+<*qjBlUg44=Q>K1?xD!*~|PuQhE|x(K09ZwbDL=*!oigD-q5 z_!{QFs&s*oHQ6jKp&==`7{rN5pC28||IPRZ{rk;`|D2wA+P_KPi9hzBU^lYy@8>z4Epl3(X>&o-O(c^4g4!8|{ge+C7m8og9 zt*36#a_f)oXVD*JzCYf-o&Fd?KhYoUeShr#v5QwLto#X^v&Fi)_B_4@L5v8B-QJKieG`e4S-q2L)ec_O*JV&v~4i_m$Y8CvZ%WFSB)`Uv z+KFG&)c9OIv4q->rgo>yj`YDF!qt5OE1vh?Y$2ldjK_hZ_${xOQfIOqN`}6-kd~ZpU05eNZqjq@s`7K_oN=+f>#? zcJ8$&Am!|i3XT>@{YG)L<45+Q#-^EmeACr8_7mEl{=eyuXRrJ}>yMjn*{wfnIqFL5 z4;`{_pV;?DyPvH;1WWdZKlc6a`=dKG{&Ihmzz~~klPgL4j+Vl3yJex8=U^GVJRu9o zbp6)J$qoGQqt31EwlzSm1EPT+!@ysVHt-*g|CC{P=;kMygHiuXqkf+qo7mH}zm3Ee zaZz*PIpRqB7;zH;gf+9!E9gi*7Y=T(JL zYI-ZC2YcFScB&sGy2mtsp5Mx|4DDH6zplOzf3EaoK^62yH;5@0mip`pa$XO zWwW-2@Wbs5*)LbU1O-*Ma+iL---rJPdc?uR+=3qC-{}84dXD&C(zBU3^K{4oR4ab- z1bF8*Pe8B^@W{txYmQ)||t6L2rJk95<0t40eQ7dOq{kI|S+7OL6kK0Fz*vwjpQ zx-gZdUa=1B{K05C8C$doRaE8y={y>=lmnOODz-DcToL%=54kP&vR%i6@}Zi;>Cq8ffO>`OhD)mq_%_0< zYERuf>);LU08jzQt&{Ox?k62Qpm*K;0PyqomZNXof&kFu0pYqA0>H-xn7@k8x`hF3 zsfRhiUJPK*c-U6K>I2xl9+nNgbqxXRCJ)O6<_>tPtLPh9wFvGxUGVS*MjSxK{BNe%ZDEg8hRAU`pc{v0CGaA{ldV zxN(|{@%k68Uc0r&*7$UJf)v&_BwBwLel#3gn5%PD4Zu?JxIe=La9L?YTvjc&iEwa^ zuKU0o9QRgs+%xqD#{^|i;a5~a?D+z~6mLWEd2a)f$Mu_g!FISL8LsMyRswM|$4b7SqZEpRiARhCfs`5$njT(<86*U5vIT}K2P>2WTB5IbPA320i`R? ziNvZ#M`9yJhU5Kn-C^$yq<44axL!wObQboEVFz@05Q$D-` zZ;`vHb>0bL#ZnXv+2d8e#o=&WztJQYnnoI^_6tq$8&pXJ(D3XcPtPc^iUO}_q`hf} zCUvH)>kCK5+AN!dABSzoH!A8$du?BHMTSC25bdorzmvAQlEAc!kQB)u1!7b8N3>XV zzTyOzQM7FY!a4BflTO*}daUvX-e&^XIjJ->du)DNmmOrVleO8U`2<~?Ukn#UZLSy> zTo~ZylGd30-eG~upY(>3F)GhrV?^d=l*wlzG&8pcTd4ufrn29{9?%+rE&|PT_S!r}t8sm6;4|;rKg|Cn5dBVeE9zI;~lLf!i!zXxn zf5GKnm6#*}F~d5QjZWe*tUBluZivs=mi2ytIlg6i!d{ksp8@R=F=-P*DnwaqreA5cVT9mW zcR&c#Nc0B@Qr>Il5!Bo3vtOD%JilkCb~EH?_Jtc!`jrv!`2{~*T|d;IAM?`sROWTSmeLL)^JQ;*JrO~ZO#!l!C)tfS_ zzs+p7tmubO%_bU-f79YJo+0fWiLpt5blVfunpZ>h;_yxqQu4V>qb>?4%U#UoQ0?CQ zVo$(L7%^NmUna+6LkdcxPBC9Yb4pKb6`FJGsb%qF_YTdu_SCF!!>Sy;RMN0EFWj!t zEnC%xGhv!N^=VvN& zs8;SgK9{vCRD&CJ^W1k8&b>aYsE%P&oCvr7avL7Zi6WyOa^>W!?-k%3|ZPlLKYJygq^~`CLtS zlO?ZcYp53AP_tn6<@%na^EG?gJhY=i#(@{z$&j)~p|Te!f)cAB6Yf#jpoF9{+HYbS^ru2%C^=kRh<~OT7~CGY;Ey}(O4$< zGzT2yS;-l?oS1e;XpERMwX_Xo3^FY2lKy7_n2K$xC?pL5^EKaKuWg~4M?F9qCOvx( z|HpwA&si-$dG3eX+b6Y)o;Y!;!%j2##NP4zXZ7&BNk+jx?r8m0dn+j1r*lmZ+!#R+ ztbqkt75;e~tHPRjz<=S{t_~0S*jiQH^)BZ|_X71YvSYk+M7p0|wa45`m~l}Q=97du z2Ik$?8~6M_h=aGH={eSeXE!0C>hhpY)V}Ulx*CGOH5a~JxY=x6N@&fc3Uzi73AR)U zxFO_$`2Zo`EgT`{A^ze@dA1JSYHr20S}6DZn2UsBGh=94ihz#>C_V=mthfUIlMSBo z>OEe4Ul5e7Q(3=&Y;l(dW&f)7V)JLLc$ahr$=srydpCbWH|j!|=D!ahTs=RV)@Foi zwc#QXR|%dY7)wT#aY*>mttJx9$}g;s zX!{FI%&EZ{iS=;1(X=pQyC1WOK{vcdn^Ju!S4ozqAr+bBlY;eiIvrfpI&YH};-+ z0!+9E-Jj?VvCetup9NJELvz1#Z+qw@LBA1nlRV-Uc<6?%r>}Pr| znq2m$CD&w<*%SHv{(Lj}Y+ro9C+9Qg&e$N4Ie(TaVaqqn9FF+lzDiR&MrGpFq&@|} zz0eV7YOY8sk$*aD=%T|0T$-$S)Pi76`=njkK~|s-R&aHIg}dL!*mR=RR+nvWd9Tmw z<_nQR+<&0PCc<0?{%6U9vgEhun;Hn^8`irf@@k`q^-Li{5)K{`QkGf35D6k)z%1;Xtn-4N~`aOf-vPEzi;&w$}hQ9lADRIl}NQOu};hsH^ zHeVvS`|hmU&v36jV~B+93^S&ReT~4DegfN=fe$ju$@b?zh8eP9Ik`5gqxgYWJyrT6-4uSZxh$rkBfsJ^Chlx1#J z({tUCOSSR+0@D;Y&(5cTlRy}WEmS|&eeUso@mt`-zL4%cJU=fIO_W7{)WHhbCNhH} zjW;T{{*?@uXzZ&x3fv!-bj_$+<5AoP3M$tFNxuTo$g_B9Dzmbid;DqZo!<uppeJZMG(CXI%GFTVCG7T+hYdA!-Z%{QYwNt+#BK(C1lHPS@dMiGQ~U ztKq57r_6xH(J5^tPkkaDH`aE`nl+V~Z!6h3#QR)WNvjqBi`^lMQ4)M+2=GIIdB#f{ zS#th%BX57!YXOd1cA226e`2CM;d{3)MXb2H)Y7~AV)q@K1fOnT?P`*>v^kSlzsDO` zkpPq6?IQsf7`PxU_m)1;)X~7b)4;#}k#YEGM>`h8=QUYP!PGtJNbES%x_-lNx9`#H z1>$|4*vqJizQjFg0=h1u7)-DubVpV`dNm=o^Yspw?Sf>ADbcWvl`gxzsY}ZMm|9LY zS?o%R)>XC{T(i0AYdSUF=lB;i*z~Qt2;8zI9LgtWusDe1iOAs*A6S0MbJ=C*E4`@`z$x3v}k>(7DoaW6S(31V}5MYW0*zzJel`Ib7jd4%%Cd9 z?wQ;JIp)km-{7vd8$_wHqK8zfvYXbW_ewS|4pqHn8+Uc$!DMKvhmJ*8B-torH7)L& zX1t&e79FGXx9ScFTGWFU`8MVUkgh-y1DRj4PxR^9HQBBge{PqNC`W~88Q-1u%l~OM z8GqT+R?%(jl59CxtLYYf&(3yN@H-NH-9iz+#c#sbmun$eq~Eo#lt1h5km=E2lxY$~s(#Foq*=f^h zrJ6TRB6Om3P!`A;0HvMs^KSc@5t}xPA2cpAHtjKfMG09p?S6iQqpi(E*>u17mSqMb z-ww#R=pm#-FYX>iVv4$}nHV2%(}%24nLAu3gR`^Mk_LPwwll$h=Dv^C;fYGfBjKSB z9|O=^X{#&^@-XI$rWoWA3dVjKRFsy4=InvGB)UK|E`}9S)CM@Q?bx7N?^KKWL^1R3 z7x{0>y1VUs6`fhCKgNr){Qd~@a2~cHN%fImwgIv9ka8HkGH3|?%#hJ` zyw)D-80qV1_rYVlXGRGZd2(-PEhn)uKU~;c9;=n<*6f8Y{!CZc%Bv<8aO)l!b=O+9K9k6X$a0AfIFeeS$6{^zrQcYrm{HfxXFfT|ynxJ2%hT%b_k=OREZ`E0 zx7TYW?!gv|rIvZoNd-6@1kzjcMSW<-y5dmnV%QG5oUQ6wO%xgcjS`z&^^eR$v!!Wk z_;<^<(%t@wZnpWiVRiQG4*4Fb6G)b;0O(PBd*%Ktq8u|9Z{FM3KHbYfy?ZUil=?kI z%Hr4h3E7DhX=}Iq;1fSk1z#{nZ7ceUWtHrdii#;oW|Cvsbw~(hOUIZ^4wH8achEv5 zKQAA^Wb$1kBO5#MES9Bu!_uwkSt^wU3p`Y)c$YS5*hi9I_od8{aoK!-6>_qt0PHs5~f8Mq_A3Qx=QRozy+#M_KH#{K=HmV>cgF zOu07yybe36ma)EG!1}5kcu8FcX15q(T#F|IG@D;Rd8|`@Ia*>)X)LB~BhIo}1aYno zV~WCXl6MssB46TZy!JVfqSr#zPm07>ACS~*bI;*V5Y5a4QsM&mzH zvdI<(Rsm$|H!;?RKT-=58A<*2@?2ST#oyU=ml?Rxy#O%LmVrpguTfTA=TfRz_-G*i zsM?+1Qit^7Kz_%mBS9dBRQYf`RzPFQGT*M=njNaXhc29z6{>xn^_k7!-l5sQE}s6Z za?B#!{5gBkYy`3&s19|9X#qoBl$fY}TO%4D^mAE}3r&5Ko*fjLU3Nq({y+SP)@40h z!{^zV%gfGhC@ZQDO}*WOlUk;LRWBCMagqw?Z>Yy*=!JRU&6Nh4i&hx3xd0E@=-pzQ-^0<-wU1 z4fWY*_Ir?PyHEOv8KtDwLDC7Ws()+~s@+HlxAi_-#~wJEE)Jmrr>P6F@ z1%TJom`8CXWiHd;IOgyTcA z#M(MmK?N0_=Vi@7GGwyKBpmi>Zl7VAF(a4-%kj77=x6ENs99=+_Io#KVf|tPcMOW*O)ThJw5s6-J`^N0L zQ|N;h2_wRDUF>zOv^-E1_|grbI~B@J1!JdYyKPSnH0gsHkQ6&831vNqbFO3XNOV)^ z#z&!$_GIOk$H(TkiZ*Cdn(G<9p<>F9pR@^0>)k~HHB_@2y0w8}6U*DC1lcKi8EFYH z5HV;+ofh zP|u|r9#zR)<0u8}f(v3k2UykIO5v>`ORxUi(}30YO|#7gp5JYO%1w=XWNFVB2M`43i&fX}QC9SFRif$M;2dc^iC4C&C>ozt9J+mp(j&ZT`+~VU z;lGEVnaE(keOdrGt{vWizr(W;{#!E}!abIn^XNmiWpT&<1;L~RYT-sNuny=!1dqsH zcbfmfVl|=KAL+#RUwr`9ljz#y0^}mE*mA`T`OKCu*VhB`QtQ{@0P4nS2*f447sq#^ zn3s6erI>#t344*O!xlK@D73uJ*?}&!?dJU^N(bFWZ5#X*%A9Ms-G3 zexeH@MayC^qfKC*j}(9RRreJKto#ualt)*cuCbSTe41F8ne?r3xjS}UbMx;@&Sc_g zM&#MdF&v?qKNzQ`je#)cy75*w@kMJD5~XO*hpWu)j)!Rc}x4aXPQerH|*jWCaE8BUA8`&XoTJ9_Lhj3`FC zzO7q_Y9Hn|t0USL0pxF#38`fA#Dh_L<354Nv{HRAzI!lKDWUbavzJ-597i^Z#YQ6_70%}feMV#l+QcyVtQ9v#m_zeO~RFo}SYCc^>3p|_{8o0IhvzOJ0_ z#WB;Cd(p^ZlQl-8NoSMOBB3~H4xysLFV*gZMV?a;6M-6Dka&wGyH9UT%FXZn3bWu~ zjuuuV^6XU)GIwVEWc32#<;6+(fS*(A`lj zqB$j~6HJ@zpA!z4Yo1{}JS&eL?yer5ugR3~&|3vnRNTZ?MkCFKxQn(Pi+!d`l}TY9 z6O$>5{=&($^q0>A{bfjOc-GdFqQf(!zl3`RfOI|JE}$Q4eubf%HEO4QM(TJxt1x{MauOX z@l!_+trK*Jpl^tuw%uZV@J~VW1)U@48V|i$&|?LCK+v~5bfTaN`J0FV9YpO}J1Pd! z$Q_A}G|11hXk%SJvIMI;ny1E<=_dZ#!tJr-$j#rV5?Z0TOm^9W8a=WEI}~M73Et^c z$vk%{88q$vdhWGw8|vOR&qKA7WbENOxKx(9a6mu-yw<{7Vl;7`8wwf5At^yokjT(5 znq+8gn>idF*u4;ByB@mhpNX!c%{f9w&Ob~V2@H?Tg9<3~6?uz7g``@wQ2 zLTXMEtmq~0VuAnj>6m>Qv)Nd_RWYTx1FOu>a7@XRALVxF-*D8?S}}H^{-?^U*ECP- zUvI9*PLtj+{Z_I^s<&lU4mAJ5g{`G+M9obytlnc3(Aiv_?S%BnK!qdmVJyu*9e8C2 z8LmhV)h+^$^~L>h>x+-N(--|xYtO&vq22r9-K&y)L4_!+$8yCcaXF&PzD^e=hCO?s zg$#~&t_7zX?J=c4+Kid;rT|mZb5?XePei4NcqcU=hwe;7U==zgD4Mt!HjZ%kmUOc< zwpH`3Bl^121I;E^0y2kfn>eU1op*4kCeuF28i`->>EO`pix2j50H2VlYrvaQoc@4Y zSDBbyNM0kw`Y#e6cnBOSdu|?TB+Fee2Dxt4y0ikiW|2%O>#^Q_mq<&zj>NF3QWGrO zsw#r?hHgLFh(#eJkhZ{MGV}_OFTF<7FvuBB*cZ#wBK- zDeKV6Dx-O!IV2&&y)w7S4M?x^F2lsOTIg~koUHD!!(;hCV!Y@r+o+Zw)vB9m*dsD4 zM}+2_)Jk@YpTqHslUBP((HrCY2Mv5P=v9^&u)5b)`+m(q5btY(Do~40Yf2?l^)Oa@ z>L%m&#J;fF3GjPjPY6`&A<*W_wK`n4366&f5?Ve2^ju%J{7A?lq{5)v2;p;0t{8`SUAjA6< z->?i^=mVw)pzVMT<;4?y!|_vhaGO55w4z}tMsJMGH`=2oA})Rj2wx4&83K6?lIw}G zqOU_!e^1$y;$=r>l=VP5XdcnHf{Fp#Gb$&9=4?*R9Jlx9_LAEX0f4Y3TigyB0Ur}1 zi=qbk6HLeas2yffE5)i&MDXX+Y{0s8rC-OV#COy5l=x2E$eLvju&`gEJ!A8SO1%!N z@o;@HS4cXI#xWTYsdUMsnkDcfG6p88+TnYh`M-l^KSlyupUYWq*K@k@du@i6Xfw2) zR~bW7Wr9CB-oGcJu4sAHze001r5f79H|ntThIaO_y{(~Uvw3i>8d^0rZ9b}zKi_DL zJhTgq+|2Tj=(2l9eCYFZRGv{{uw%3?wajbbdCuqgv@>}&3QveU>ILo*EY2jPQmEER zye^<8G7@Wc77Ri#K?rP#+pbkA-uYHgx$78%w8b)5r)G}xi)G@?t-BG@Gll0ojaj_& zS;EuDU zQaY*(F{Ah7h9CA-KX7b`K1hp-FOPQH{O<4g%2Ry zKw)`R=*2^qMI2{ny!o*J<4`LkgXR$gm{ZEFN4qrcYg8h2;{*1RaPrY`YVB?tBtPx zN@C#pKu}+moHP4d6eKys&zwJKoRfE)FVg_Z)ytmP951UVZjBJp+V zaH&ivYhCTaT6e{IiA$HArrgQ#N?DtqJw568hUYM!|BG*`096Q72_B9}YS(MsJ3n;s{)WG$*J!O;_~f<#rkLZgN%&#dWjaIx z>(R5aU7ErVUww77j{Ymz?)0mZ9OqZC7g+1A&NNT3s(l$AnD)8+RgfX{IT@C~MVf~v zTVvnKp|Q*1o5UgnzMJ8p9|?LGU6A0u9fO9;Wuac&kTB`%dWr#EX4QOj+TP)QxKfG@ z`c^#}j@RVh?`sN{eVcy0-H&&4rdLn|RIEm{Vq<%iM$CK{Sutsz=$D#M{bSqEjUR#G z;!KZ5fx5 z*D?=p@h=L^sX0dhKq{g&=d7ZbVJNbKT6Y$Fnj;j^puU@rFovw;sMH6z!?DzA)AwBX z5r3cbh%3-vxIPu3rus$ElTmq?qPhsLyZ+Zcs*67K&!V~%J*sR~A7hZMo^PaA9hSI> zRGs@l?(K?!9udYjZQ(ChJk)?;^i4Li7@!TRv0LQjJ}^e>1k6ZBzYb*l5y znuuF~HHGX=pX@YV!K%xWn+Gb^1F;?*&pGHn=^rh}@jlo7i&fwsvtcH9<6~GSSWr(P zN0Q~LE-Z^ZC=o>-s?#t1bNwRz((5Hk3idlKjP`ht8Yfkr8#n_6#~W+i)6a5?0~WkR zf+Oj#1U26iF;awd6hW~zKMlaWpxR>4q#Z7Kd!i^{vzAL&g=*gCgZI2?AbRpEN+EC$ zY6?m7`F~k_EE~7XJP1KrY;>p17>GUaD1WPP%>(UH>-rzm63lP(19W`m_I=F+U|j}9 zC8l~j&rK1n`YW4n6MkTN>hKv*l%S(mp6b?4vS~E5J=5qmn4+m$>OP`-&8Ho!G-G zCeMRMw0D3=MbhB?3t#>*l|N53F7*0de5i>#ZKhgDy;c%u#yy5n1U0e0Dxbk?REhnB zi24^@V|~<1^~b0`@f`{7aS!bx=vYAyWf0t59-1NOctJxzE&ST+#K0xGNAs#A{}{gq zGAh?Saep42;jaul$*{%-=ds>F&soX*;n;|RA@M9W;Oz&-2s3bXR&*Kb$gi+g@`hA{ z%c{T;ghL+1nan*&Uir zp}mCZk@rF64X)dd-SNj?0ud9Sr77gk^-Ju%$#r^f@;dHJe&t$|O}WS8Gj zHRVCJ-c@^WdfDo#<6of9IPTHF-#gK|a+(I-A{X)G-xsv}VS0p?Yde-~`LOGFhe;ewg*t;KQ8X)Y}^_0#qX*9Lfou!l&KBb^;6kkBys~&(Uq|ZiHYj=|C zjxgwR3|%3Ge9{kmwvc-cr6BhX3R!!1qj%T&)Do{{%DR!rR;?jnkoYy^I%XqlNCek% zdF>v>C)(uXRg&QES^UGgF$^c-vLyPt3q7K9G5@yLF=UOzPRQ}R@*Z2X@|YZ7vLo@K zts>Db_yF#Rz8Q(0j_=n}Ib;6Tn|FGWlWbhBmGw#nk0&5cWK z8>nEZ>?oVdi@ps_?G$8d!zG~Hy0x^8zK%a9MO-Ff{#SrA8xI`owB_iBbN%f}G`ieK zQuE3TDXr7ps3`C%EuRWkwn(dE|ul33-PjH!7`M{I?O_dg{x z2Zf;`8j5}+6JAC1lvdGi8aCuMBy#W;Zubp!cqSA!L$9o_w?gg>k z8+D^Rbg`gUT5~qKi>gd~{EN?|_~?X0;mV>bV+w`!UZ|2-cg6B)KI1dU!|hymDA~%Q z{Y=Gd`cUiHcN47kvsKRw)gHv9TH)cPf?p2Y$E8Zen{xAgdcM-VYsY|+PZ4p8pnDe) zHx6m2kUPVf+R63HP4eZxY(sg|T;c;VRla)n^1UgaIE=z&(O1iQe9WL#UCNPJYEA4cr*8 zWNrj|_EiJjm*cHF%0-q|-b9U-_cuNCw}MLjOk5`DTn{}+&_@IvDS?fwt;=Gz1rwrA z!P9<{<+%_4A>ml5eJw=HYfC03Og8E6@r5>5%;UU9LH~@f@*eL;%t(3~*ll|isou~E zk7UG6^wkP~I2kE=KQy&a8LI1BRn)#B7S1CYo;5W$RC63j>WzZIS`x=)jtqx7?N;)4Qw73g7Y<=G74t;?xi8h#sIEySV zO2pJ@vuc_uh22YF@f+Fb60T07ji4uR=S7i36x)n;mS=OZ;X=&i2wX*3lEA4^kFd<_ z(_{|_)_ev|?c4H9#3Y(EfLq4dV2^Ii0Lr;3ahIkC{Z}9(efHq!_cCtx)|lnaTVnml zO`68C9=M`hHPVe)V1qW=>bpu4ki)w|T}t702dmAz46Qr5g2bK6KI^`~8df`mjTGDU z0g6cz?uVVHGKXoop;r3GiN%T0VBxAJN3L7k)iru#t7?^0mUFtxTy=SPaP*>~O>es6 zJmE82LHL^@{4?{Gh2{uN&hx2%RO(vm%8jnq6}wH#kC#VZX_#rtvvKp^n-yOLERZ!X2-6E)XxK8#pM#^o!4}0&d%dI;*s$LzDC&F^2Ie1-n zRkNoKXB55XeVZ6=6creg(|bayF|AdYHtTxjv9=8NIPb{>=jxy>qiNqRBBq1dqJ=3@ zDE&dBM^8}g?Kngw4oSjX8;|Z}q0_#L4b|Yn&2BGYtOuv2v42NH@-66=c;}Oay{iJ%`7)>hp82aga z*{VY|J)tCdspvp{<1Y012dH5a!1kiz);_;ZK)aE))-8Utoy=ub7fHAM;9*6*3Dt^e!rUn;Zl>bUjUVbWeveAco6K+c znSRq2bLqXzO;mv%Wq3cU&giGYa|?K)i{RaM;VIiQ24aMmF7QOaL1bXt$-aCKOf%t9 z>%s2osbNOf7Iy=^x61(cLe|=w3pGzSW$9P<=(p2tM z%!Q_Be1C|pRS#LSYepNJ&}-p12ODC=Dce_Yst}r{5F(soWnFnCTKZu0xY;8z*;L{5 zQ<{UT`;w|Xxs%fh*NdY~U|yG5_ptTTW|u`913UBY?0np;?$=Ld&$2YD7gY9n28u;R zx2Xd&>K^mO_(tD!GyhKEqKy+ScjaTPmp1R9b)$k_I+GUDOWH;m%d%bGgO-UeOkvZH zJn$hsah!1%6S>wj7Wk#E791`N`nnqpn~g_bz7u*yL{`&{uH6B$F@VhE+sU-dU8#!~ z5O&$0!9`M@C0(jUM;jN)$S$%s-Kv_9nNmzzKf$2uj=5dqv`9U<%GC5XN&X~?GwJ%M zcY0`clmAKi^BtUc^Kn8=JNjBX;)7R(2h6t-k+Zu=a*hoN2B_tbsdH4z>a`{`b+YoX zxWtQF=}IUfMq^91FgwYrqZ2xlOX?$9D%_WTsdyG@Q~D&7jTlMOb>*VXcYR6DY0zJb4A5 zh+fMRRi04o#dL`qaj}j2XFoIUU91zgxIbL7+w9m&VvX8Pkhj)BzRasCb6rs8$lc3) z%*05@DZ_30qgC=36*wa(@H0q)DVVrdnO^gmhAY!{xBfyqjkX?Olss)nU;wtNc@e}8~EjJ zrYJ?aZle=)s+TyHS>`5s=s|*B6m(6EN0@FQD3oMN&gI0>!gri6xfT)@jupOK;Vbaa zrv>dM=$q<*y*+fkpjQdH4(N=M5p{!@Q-ocJ9~xc$MDqw!$hMpQWp;Ac?XO<8kK%RB z!HmNqf%OsA!l0DV)5qN6D@EPLGKlPaZ%l0l9^Vzp?B#9>gJ}EX=}1&j~(wG`@kmb8byp_!hVXVz`Vhly`k=5FuR}cq+@C?w0YRVPms~-ro#r>UHi&TQi_WiBT0?r zjpmV2rZcUk_AgeHlE3#ldXd&!l4zHq4uFYtvMRCtgtoW9;m zz9o*Jkhf>*0Vv2h+^#dYeQN!gVy2yK>b#7Dxq`t`^y1}PIDE` zai#f3;CIP#U~y-+>UXbX@Y&mL?3!_=f>2eS?e4n3`s)5I(74UhxW8z;588KWU>P)0 zqi)(y;mV5^>b`DfZWmg;#U1!E3-flSc*}W{z%R>*OM*>WN78G_wPIHyU^jr~8ndti zyrBGBgOrT)?C;F?*_)tG0ik`jDElixc12awMk_aPwAtdG3{vKhlB)Nn0MS3xP*iai zOT?=XDEN<{;8{UI=?+RiDfpfmeE%-^9?!S_6Kcc9O+RC#3Wa<|C^HuC^89l)w!}j5Wr;qNfi!vqCiwm{9_9YA9pw*VXilfTsXu*5)V`L;c0>Fq2 z_uiG>F^90gl zPP_o&NqseK{it3y($&BjNK3=%Pv+W(=rec!xklO_zkxJf5ofjx zILwpwFhuVn_=iDSqB|_$^#pgmFWgIob-roFi;5ZXG0ll{SOJpb@A~m1c;?LR@;2o}y_*cp8ZLr5N*c?UZkS!b= zDyL>Q2+O51NGk~*_o(91#uj&0AakXNNWR%pummkoxjlyRY?}-^ts|UPpY2#eZOq-d z2N)mRqNttj)N`ymyQwAjsU><6!S(adEJ1k!Pp60R0WU7avM7de{b~L#J)K~-CZ3Tz z;=IdkJKL}>-uN_og2ELGuLTDfu1jI~i3)bXFjE-DfuUlCoA1llP~M*dPXg{9^3cl! zy+yRjjNoqZ(2;`PF6h_Fd$orS6!dOE-!z=*^L>qYEjeFy%CggY!5!JIA` zULIYHX8eY9RBj(uuPbnmT!B%WiR(B2nr9)Vk?vmBXx&3s4%KMqW;Zo1eXIi|=s1(jHbO zIQRuEG*nZf9*r)G^gOXRB3aisSPkJE$-jUlL%Ek*k0xq9F-}TiCk~Cac7r;2Ply$hWs>km<|k5sqqVM>skskRD?bfP zdD&(0Hi>COA&jm>IXI<|067pC@AJuDSO~er5*l1zSTAefrbqCIh@F_n{4P(5dMsn~~cq3lygm__I%23#wUpCRP&69~?*G}7De&IA^?K#TW zJzZ~}t2tDU+$=~tNecMU%|Fx6pC<6UeB7Mh!r)jpAZ?ba4`@Hq-oLP;J+cvXZ#^9o> z@ZjUM3+q8xpr!g_;OIHQ>|O-eduCYM8J8Y}K#xJn$}P`x+MC&>&;#l-XBh=#pckTq({U@ zl2bihf^c?H0t3Jc} zb8Le4bfg#Hzjid(#c0nieA5@&lkZ0hSK5h2%=qE_HXcgnx^f#Sj_Vjo=32%Fk z_i4gqx??=vbiQ5%tMm4jpAX-i?#I_rt~2Elmw=M~UE$%21>aBbVS=aZ8>yEoP`Iks zyTlLim#F?T-r7p>ZU$-oTx;&1^=7~}gdc@f=by@blap70fGA$)*30-ijI&e?@w zS4a*RUcz5Q$mfb~gimEEW+zm4k|2iz(Ncc&U&YeASwljZ682Ko>cx3U!w&|Qq+ED# zg!Sjys=kQ4wk{tIb?y-e+l7eJMZ_=T8RhYG5}rOuJS!K1=MNrF`iSlYo~GG0Uyo_) z*Mrxt@p1%4KEhTdOt)gv)z?Z$T;HWs;m^M?qx4F58M_K?*^Atl!$to7S5nc!QmSQY z{rRh>B}!caiguy@P9|JpHZymI`R!0}00k5O1hVUV8$rmGSoAvy2gQQOor0FJ&*Qs?@RN<$*)fb9X9AcR2^wgRx^sc}BAmbwdVs^O~BjbK2G$ zWtm1QX8I`z6Es-HHrox$#xaNd^FgG)!|vv9^=|%FB;jiG8xq~}VK$-{uVExcT9*ts z;|0dyBf82C%`_7J(CkJDt6h-QK#$jF7Eb1e>b(3W6V%ZWOer_squ*2L&rc5Y<^@zR zQ5Ed$Ep;drB;+DAOw-|raP&KEI1Wa7u}}eN<0ib#GUx*tk6P3+U)`R*nwl@E<_h16 zKdX{`c5g+!W=lP#TZ+#}&3DPnnY1JMbiv>3_YP68UKCvEzG0JR+pWrr@e%G4tb5fH z!PXJ_$;v8L^|>2+nsxG$)sR=~$@_Lb7f80TILV-$m8}xI-3ohi(Dk9 z36#i}HH^r4HTNP8w_Niw`keE=$}x8Ij>0ZTv4_ZG4M_awzG^{yYzv3q-qRfH#&GA(+ z<#>gf>8*suRtJNKJBbH}YINQnntkHI;pz>Cgo~DjrtYO2J(l_#i)Me14{v)2$s9eV zE|DtZ8sX@%G*t5mKg#06Tj9HTf?PZIHaEYeqBUN*cP4IrVU*S$SRFftYM!*3IXk>j z_Jh!zy;_`mqB*$q1d#~ir^|WJoSBwuGEL&TM_G@zBmIbccI%?*9j!ulyi`*2PUZRd zAev{-m1l>HZ%M~*+w%#v?fMZ==(=-2F3R_ma&V#+qo22Q{Sk;|M_`$eD&?BuDm~{gTRr3#@n2?KpQPN^Jp(Dd#-<{xbH&UJab<^ z)e^#7J~U<`l`@7QcB6Z}eFx3D0?9kstvPF)_ph${GcZpc?Z}srNl{z!`$aQUS_QS8 z@ka=*2Pil*69(;mP9?rIuH^Ydv&ccuh!T(0Hq4C>MRh-T&U zrxTw%Guq~WTZzJ4bV6~cW;iJM6)p{xO5a0+*x@!EsA^WaxsP10 ztG{}bx)|+~#iIstwN1h({-bGF8(s6B9Ux4X+UTWX8S$>eNP+fxFT47snW5SBnTyK$ zao1}6%Sz0ntx|2r*{E!sbAmRwv+sN@)>f!5Q5o!n#!7q_m_xyyO_YTGb%G!$obE56@6Mt)gtD4^XX}l}B!baW0g1WILWhA;vk+ywW zx-zEzM0%qBZce;wHu2y)9NmGNX@l(h{InKX%?XxX3H#Fl?N{DWmGo0YtJzcR)0lEam!d* zs*bQ&-MaWt_ZF48i+ExZGW2lfuKI#*6=8OfxWa3DqHYGdF?X0=P#0WylG%k>f0~DK zh2pwgMd_x=A-5hkp%UBkFmUH5yQ11Xp9Uv-jn;H^6LUYu_9X7hJZ?Hfmn5Y6YaD~R zw2d*L^(9AKn)|=Dq9*U@kfy1sJq^v{2N;^B+N8Yk`Z?Qab*#FS`c5>h%Wubpb0}h? zEH)%=BzJpk+hhomQ&$QxA{6LA6wc5an_N z%Y3(^rh|FX4gRL1iQMdr$_rgVxu*CC`ax8{jc@b%9Z$4GKXB`@TF}Isr9Y&23A=D? z1U!n~cAelp>$f--u>n3Hm94~1M0uloAK6i!MO4^1Id#aKaL7;GGKI+4CALo_vgxMe zx+lGww@`9D0vVcXA7H}5al7O~K7*>Zz9e+t(x%6~{Y`C1oXsfv`7JMx7JrKy#)-}L zv6&U!z|7kJgdMO8c-%V;Y$oD;`g6J_$=+$U_7;Q2`Ta%J8!95XwyV7OAMg(tl*B*5 z{L1@2%sd9Jh)psv*1TMctl`ts)1#Z||TGMZUl z;4a2{*5pv_{iOM|s%5_u)Kj_4>ZtsC)BB!}!o0=Pb6{S$?u|g;ha0xG4u_t6Dco;R z-wE@=v0+%pj~uj*Outx_yT4SojET>ohx^?GydjtCLvAYgW8N&W+ge8E+KXs>;%d*V zHBh4x!M$Lm?lpV8A0G^WqS6#-P-U9;g%oKRE?zFcJz`B>_k;KnK z+-^GES2-;O{#16tj|{9`l89TrFQBC!ba`M^HaW*Cfwbiwb1|W&^UQy|uzm)vJw)Q^ zd)FWYj^)SxgW8BKL_ zHH=Nq&ZSQ?njTBrV9)rsQ?re0;Ld7tR$|)Q;AUKCSCvzlgy=J!zEKh5rGc z^0?yv4xcn(;rsmk-KtN~r#x=chr4Bv7a?i^oC}??wzFDQRm{p{fryRD+E=bAExIJTYNh-*bnYe1>++aws%qPU zGj>UPt}kN~tFIg!-7sZMMo7YCSWfj4oVC~lX8b~%D#InQF6_h5N&IZ zLuvgYy}0SK7JTKg>&GPKpwtHY^JL%a#(xPn{*@kyojaPbsGOmA387lu`Aig6F=pikQGvdzs}SCxs{Wq!jL; z=Bk@g>x~sY{We8-NERME5d{AaZ*Kx0Rk5^TAfSnY62p>#M9#pV zQ9x1Di&u=O=tVLkC@R635ys zmF_{G4aa}`c{T`qgvGVrM$BJP%s~)bU`2ww_ye_Y?luK3(zJ-9CLJZub&n*sTUL+m zuvfSHQ$z1T*+Q8*kPLADsXuj#6aD#XB&n_cfBJLVmj7mdvgBj?^MSu7x2uG!;{UDw z)ZBV(e@;klXcD-^mja`(SY7+##4$t|uE+uk+&^)0syn107sZ|PFRZEL zYe0D7sojGI5#IT+l?Xb$eQ&ei{_Qtj>N3v+vPV_?+2aA$20Lr91?J$tl`y?zeNz9?g*6 zAi?LdGlKc1*gii-dyhj8HB@8Vz5*DRYmE02<8WZa!aVuFpo^GpMXklYF(pYa0-Kjm zD{6~6n)%nBLcNIb@iuaP=TPupZa2qL8JyKpCQxo;SoVpQeI7slOh>6Pb_>hCJT188 zNN{yZq=k9|=2+y%xu>K4HQ{R6&3Aii$b)7b47;42NBFt$9LEwo4mwdl@B7fYVJ!l4 zHMLSky6PURv|Hq_i)Xo1XL%8425>NVE!=ORc#d>+Ynp_gBbe(pv+(6|pMx3g;20jq zF>DRu7`_c-_``B<<2L19RR~*p0zD0_EA&0k;;k}h{0O4y`>F9+C_^+pmIiQ*~irvQ!Noc3I zANh<_j=A3dI12uljDlkij=@>NxIQe~;%2LZh8*f-xWo%=1#OIanFxya09aqbn_1@K z2?ne_Vsw2TFK|uDNiH#gTI)ZIfLO4;d=lb{=lSfMO{C&axDGrUPR~!{|K;%HNpl6h z1o~`0Lg9!x#2tDcsLipf9cu6?Ec9McT(y0ftC9S6VgR1W)sR$47d7#*r0QTl{az|K z{>~^L@aPTMzNl4APlt7@wqyc;wFOS|fM}1x??UT+lS}Mjvz+h)IKhM7Z^!E z_No!!0ZuV?-%aEr^~5zWNf%z*XCnNk?uEC(j;fK!p(>bMTapKCBsZ6Qc5;vWF~UtgsFy1E3C$H z%buL3=6%D^#%z%ta7tL^1RYQ=Rv)#S@tUkdLf27L(`_H}OPz6+C~Ds>g`Px>9(rqE z+IG9=ik`%CY>wW#sXO$fE*g%snOxhBE%!;uvBi+=33;Q|oGExi#4GNA(SF-`fPOv7 zgZ_0uI$A5U6~v2s?WI1mG@OrcjH-$H%q85@8m@m*eJsNLUBh{<#4X~~WwaZvFY+O^ zvpy1>i8m@`qDOIPj|lAt$m>wRX(`MSuNTqoWf!y8a!&OK2}rFiFGf)y{H9f%D_%iZ zCmhdYRz^K-j@-!T4)+8`PRo$Orz20nrm3GXn9JjLfE|s)#H&Cho(M9P^#Fj{xlDWo z$glTcnW4VKJ6^)Ic+pwm^ZepIop=*-1iA`U`!4}?To~1$&P<+=zZX;kRda#W>8-QR z26Z^VrT(f=L#7gPht`Kj$oYSPERNJW-dn$P11j8RUr&}9`4wsyT!~1faW4j07;#@j z+VLw|B__6x6wo{HrY?go4aS=c!;MIw>=da>a>pLh{e|Z=^{*Uh&4en{>1SQ1>QB*{ zH&Itw*>I$xSx!%;~ad)zT`=5H?jm5h@Rq(;*(y0=UQL4(AI5^dkT7flM zQ*TrFxnW>us1M6fG8f<9d4s9jz>Ax)LxMNJ;XoSdvygUs4&drb??#N@{*o@GF zp5-eUv2?q{9{h>0Sdh9G=J}$ndHqQKN4J1!tFdanodPAYhXMaCiH^@ke8PG)T&+j{bMv5ljf6H+5z5)V+gKc5C81EMR2 zmzuIs2FfmKRQ4}GslI!snd`d0V6qs@OXqMt=P4_AsOg;rXxU-5?9OxX^oKlkMP$Y1 zXkHp!t|i{TE=ceQ^jT+g+m5f4$z_IHC>tei< zOvW>uN^VA!zFS<8KX4Ae6b@= zgB}A&C}fa3@<0>+Y&>DRWj{I^2a!RCQ?P%NPLcTlzNk|_Zo++>bjVCBpZtM}9T{+( z#0h~SR{)#t&Ve^|!Drk_3!Ese&!!TZ&sI7m%`#rPs*V+c!frNlSmZ-P6ezc*Dxis8aA2j{Pt#+gH}VPU)fO8P-BtUK z9NQ&4_0ViAYj!Blr_$)2(&#Lsd3(@QQ`4+?O>yqUS-)6zCK{6OnV_MXTg)2^#k|J7_49Vh+6IFjxVtpoAx z^enq<5#S;#sd8MX9yvv%?C5tPdCp~D;HqRCvR6-?N`Z-x;m$H*I0sj`*YarE|q3CGdD;xkNojU7j$!?ok+E2tS~DYONX*nDo2sRdmy z%W?YGyHprVz<@1A$jdwR6BMw%e1bm)UFkqg*R&ri@Yfx(@t3;l`>W6cAV2IgGdAJi zfO8J;gO-rwmR-3PX{xq^ITLt0u*oDu&@LG1GHXXZtQ+9aL)CSXZVJ5(dU{a^x+xVW z^40#%GOslOTBoCCXCtflpzcx|PGMsUFRQv)fdEr-Zua3?4O9!*72J@Wr}*V+lQ6*RKWY7aJ{uwE|yVs*}$D z4)gy-=kLY*XXyO*ASu>8kv~qq) z!6d|nQ{Sg`{$9*KR_A|*`CpR!k=?O*L?2&oi+_?#s!(ru!4%ZRB%ZnVG|e+&+Zv=R zdjlf)GO**nJ5g(*|1|jFCd&5#R3y+rS&8WuLmj0({spMtow|OR zs2}2|q_Bn@L2Q$BjGBi*6-T1y7uZubp_m7r?EYGn5_LXR{-mP{HwO)~9RN)UKgN&o(r6SCk4gPf4ZB^egS+(MM zv&#FBT2>$(HI`K?geb5JaPoQ;D&@tWI_u0v3)WGff1?%aib}O6OX!s|AMJdJwZZz2 z=hoMw{YKh2E0qd}rr1>Bt@u2yYz_a(n}B~%!@o@USsFfBYbzrB0Kg|nC}Z#a&9TwD zL%68N5lf#h(_-n%ehIO31Bd*vVyXTTEtatJr0@I~C2}WBeM!WW$nOu>@sKNeQ$Isx z+>?!xJ`{^`2#^pWG;?(X1LMRKt`KQh)6Nxp1~?M@EcPxsOlf6jjV4j6eINfG#8 z!+rY(;1&{&acDl~dH2N{j*`i#Ng3c`vZa4iM zR)O%UP{WTU{00p_g7AX`KC;^p*83rcVn-=!5}kwbkeKW2i=_vsoKQpY>3;XwE|nDo z8=#xc;8f3mzpEsEJP3(CZ}qXPq($JvzNO~06Z*X~7xjrbbf}>p?gG^G7PCkE<*y0f6ey5XZ)%n%ddsxDLNzhMs0)@!t>M7tlw9ivaoPD1R=4`x|(obpf% zwx?}@5gIqDGhxN$e!@8yB?juB>JP()>Vf(xYT~uuk?ZZ`-a3CrJrU5|2kRU?j-fe> z&`&9Wi@o+kIn~ktP9c%aq7m?lJgO1u9k)>lc>Xo665I#=fHu%Ki5}maB=mUsbsh{(hnTkXvs#Rss3qAm`5dY~!p-+hTxF3&pY~Z>26(}cvU1I!|16k~Q zjz7Vtf*Q_8I37r1`w3?YoXojSJNgjxC4h3g#*fE9KUk3q=#Yu8aos@IZ(Cbw*F&$Oes}2l9fr3n^nw^_e#|(2oI=P! zpy>s@pc;j$r!}5p;+X_I2mqAeF6=jRB14U#U%!Cvp^jj`sYmD^4$ak-oz3(w>v27U z|M~Ra@4CeFpD&i5Kx_E0dE)xpf0+NFDd;bMGXIO+fKm!F3iE%4&}GEG(4L^C%l5_S zxAkb}G4i2;5-Op4X#TS`{3nEW=6}M^a^R@}Xu(w^BBw5tL@@Ecb7Z!5S2+=tFw2t9 z7izKcW$%Po>CQSHH~(L(#mXi4h?yVem`716b%4MXUaT+^(?6w%tX59)Cno_i}UI* zJJr;Nih(2395FV`sohAI)(Wnbk&f}I&d}vO#PTXx9@iNcvAk}&yyS=uUtrLQrd6rx z+UWiz+~ZC?n-FdvFruEx65=_+wLqD1{!()^d?w+acHnDpYm-`_;gcoXb%d|gLLr16 zK)r9(@EcwR{9M4J)*(Wd13I$X%xPe>U8)O#A0%*MKyf^2HQQ&;)LK(>cBV6{E8i47 zm!CyjF0VLSrS8(^MywGA)R?(k)(E=azG*G=$YFh!J9PZzJ=Ew2)btoRFq1-!^EnX+ zyc3@i+Y)A|J2n$|Ey{jUW8Wl9kT5W)u3uqmhil$vP^8a(n{$@WUQ$g8#op0ezVAFn z_R$vUcS)&Zxjds-b9ov++HY%NS*Qw5q?|-pFwUIxyM{4F&ZzS?16A14OpNOUiot?5 zt1_6-pm?a6o7*DZ9d>YkL`4W6{uU36zq51{Q;>DaKgB6r$J4^$+O)ch$j7<>Ia0Pq zT?idk8?RY~=THz3TxAekWDtDZxYoh8TDo(>4=hl{2nzrM=xr~eTe{K;8tr%OyXX`j zx(mptxjWOx@8EYYjxw9I8+)m|a}VK^yj{hw>3c zu0-Y{jc-XSsmS&hfbVCGZv&!usud^)6-gdt6Er@!?AFb3^d&V#!@o@UUo`xqgb!-? z-=w32+cYM}h@m{#30rTra{k)r89-+({aaQpO=% zHQ^Xe6QQ-${&Y-cmweOK^%|&H;SS3tNuyZza{Y}Nb*?4#OL%gXm zU$k|_mI|%V-PDTa0ZHsNq{QWgGd^T+$nozCc9SfdxAP%#2uEw7zx}4#0-fEIOjj!( zHpu|lk7u7fUoVsv(FCMcFVF*I?YSHvdc!K6BszA0>?zU%5m6=GUT{^Fvb&--Gam?>ZB{m4;8|yG4L^_^#1d|I2JW);j?$ zug1m(H>?YFg<@xb)}0_&Nva<4)Xj7d)ua)hWzh6FrW-0T=43CI)SRa-OOqDg{Tym+ zhWstOGwLd|yaEjB#ff>y zVD1O<5dTkV?uGQW(N_k}U{QLPUSlPEWOA08bTS+gaR5__GC8o$=GRf#Dzcpg2QF2m z&817OdIqE&i6S76W1N4){&2qj*q0x>vixX2AL^nC(I3aiVMP|N<~*G=;v73|^e*g& z^lS^zs`I27@Cj&8B^NN-rub=nNa+J-Td6EUMx?4m9a(+I2Dn5XkbuG}3~tbqT~#5l zU|6K9A9~Aef?|$KDp<<_Ro+Y*chA$Pf03^LL-SDoDQFk!PkWOimvd2n#}1+jHC!>_ ziZ$E_!VS`J$^Ni=!Sb=D6afi^iHDgYzbplIS8Od9$Ke-YmT}wwD8eV%^`f7UJaB(T z9ysS~QQePn5Uj&>OujrHQl7b5413RZA`rSmzsa{_HVMWRYBBsIKSGRHasdG32LvN1 zhwXFJ0<$KZtnPY)XG5_S$Fxy=%H>ljpRyV6Jdd}!^@;tCifR2Tcr?TPz>6SERa;gz z+I!i>`k?FO=rv9zFOX;m!en8Kv4wl)PXxMmwSYWr2-Va*bE^z`O{l{l zR3iQt2=yU923Mr&kQgy+Z<=+#-RvU7OtgZvsgc2lV|(N2=-X%K%tPeuditpBQe&IQ za2WO^*!m7>^G-FP>2X8(6iQn(jkK&U;}!CqeG30$nzGOZeI#n!X(Te&Fo@v!la@QJ|9}dz zA{I-~l_09UF0kQo6!>>tAgYnAi<|*8j%fK5(j+zq(2jm8MXE1c(%@x;e=QEb1z6GK z2a@2Ugx4PS z+mFwX_jP{16}=Pz%LW(0OTZm^2_Jn0HMlPYM6n{3k}Gn*0Ncn@D|nDet_pCseV{_4 z4P4-$DYM+SuPSqouXeW`jIs8B#xPSbM3yo;?Bm$fD?(-bAEP3Q^1iT=KNAOA5na*9 ze1T)N92ArA=)g-Acd{XoD=jNgKeOkF_FZaOg?}eb_x)3u&#sUfpsi@9|6Nm{`+hM# z+0stdd^P{np!&E*(cC7? z<@6wB$1vNe4p%muW0<;p1xNS9D2r&<@^Ri6+>oc*n_QpN1zz^PntSJ z4r}>O=$V50!iRZMksTa&0;*mcX8GBuDr)aHuXtnE>EqFkLh1BlzXqbLR-F-o3sNsU z3j%XIM|QN|pqHT@<{WMdAyd_qNs-MfDnxL;=yOX%hvJsAYKux z?rJj-8(97vgw@~?K<>t+dm1)SZ)t-P=uZXLr&c(+Rv=_4FH{%&A+3D=5w!9}-O6iU zLM!{D^)S(WRCO*ArIGCCaogF-SUZfcN-H8bbWv&^R(~w#6|j-|;denggh*f4NYjWk zhQb8tImt**(nzZTDfTXVHu(^wKLJxR=-_h~Z;k!N(QC##=sESgjxKe#E@s=`QA|V^ z^TLZL=6OvP{;k4rglwI4Wqibn4 zyFI!@`uja3STJ9*?_d8To6n2*{MlR>T12T6$#s(408dg_T%itC4z()u38cqxk^_LM+i$;b2&*7 zMVy$(S9tu$3hq3}Fk5!G0#Lr_+aj|Nf419a)0XS$Bgiiz-Im9i?zdiXw+#vvYJ+SL z|5>#`($YLunpEV=#v^`6bo`8wH=8BkjaZY!rQAFDy=scMp{(>F@|67nyN*sKoz%&9 zX{YCjOtHiAA%ZKnB^yg;wsxwiMSp3jjx@fN&cGUIJdeDnU8NtC0>bhkA~i&D(k|dR zrD`o2!?|IWhjW8&FzYp3*Gp(B8R?SFjJN2F`U5ha&5Y5<*jPm4(Oi20f@>1Vbs7n& z!%Ce}wbdZ$s*&gq$Vhv43GI2$;6cyH!8}6Q9|$u6ILCqNQ#O!JAW}|$M0!}~)!(cASioVcL7NRB`iodV zu7<^4I0PKvSVuk&E_OLvM!`UK>oIs_l%Z|YtayUI7eiWD3hg?xEOknB`D ze}e>Ex73}q)_Ig-2(WVjTUV1%P}I{JK8Nt%0p5u>9@OdSOkZK}KCJO3J7M<)-WXjm z9sB)I4Y%PTz*Q07s-)_dRccE{8MbtcoTb8ZC3koz$7(C)ga7!?=sfVZz)c@8c3{ut zGHh}PtBxU8KnKxt7)}C=a=F8_Gb5;QRzoE@64S;eax&~>XzozJ!sa+upNV%;j9%imC#90PBCeojymuVG% zSS@?jCV1PzsXBWSjxv5w!HPuR-hwpMvjuGnLHQmDPsSH}5cJPEtPx$gYQt*{0qTR- zqnS+tZ4##n+26tFWK=4pF6NYL7s1RTjg7TIH>fqg2tQ=np#LTkD%$Utry=v#<1muU zinKVz=bIzA0h0}S>~}UuE}zu>qJkRFCl3OTo+-}YC z&7fB;-r8^_p!kmh#p7-(l3#+!)&|L^psuT~m8KW%_q)9I`#Dnei&1s@sf{C7V+LWo z)P}X(pXvc0eYV@#O>p! znue@;l7$F!>dF2z(QD=WABXQ`4VS6cB3j%z`62IwBAHSy&Rvrw^`T(3Ps$5b%#6SiKFjV8O0ix%I)Z?d&JSx^zspO9)f}A^mBhJI*i?n zAM~>95V4nU5o~&8Xx65+!Q@^x(=AK9A0_HK97LUEUj+e2Q5o!yMvg)Nv!*i-JKr+R zw@&=V4Of#HR%z7&X*kU9e&`Ei!Z~`}>y54BkMQCReqeZe3E_n>yVb%15QbEF+9Yxt z{I7kGXjihfv=q01VhG3U#Q>rK3%&9O5C z4Gjn-MX`x^LAT+)jR;s*_g8Evs-aeckjYJa6-2Ik56uF0>D?IIk1?MbMBM4Z;0Upo zCCr4}!^c4@tA}Yn&n64mZ*qwU28Rdda%PEC8cGY#|n|KvP%=mHW{3uh4RdFnk-0EI!wGx)M5?(is#04M>oRGjO zT`Kc;NvO3ry}=J^9JB)!$F`cI0E(&iD`B~sioA46Mk1qYrdwZ`e^Tu2Pu zAA%gM3Ki6@6)wdXq$JPvoPjr=LP6CuBRcJgOlT<$m z>5YCgikTPOPCX3=lGSTRJn-WE5H$_+F6;UrLlt1ZwJn;#kcZ(kJg6IDqGvrc4f@gJ z(u{r&K7#t+iguy$$wq;A{U2W6Om_gOAEw7-rEVFf*{pc*dvnc!9=}kAM05QWV_siW zTU7y?T6XkF6uMN;I-8RkmY}=J`y-X+pl3{Gb5}Tm?i0h(Q}IW&mMrcN&-p?8vM4Zz zF9IfseFcF8dqM!()@Hp=q~>ujLnFZ<)|Iiv{I0s60ad3Ul%r4`_xcNF*+pTh{^*m~ovLRyFLOME*ya zU$_rE9vF*}K`sp64JstbASB1m0ieV0Nj($WqL(@D5chavFXPQVaoQgo(C(T2ktC-& zG4RggXI|sS*f3fUsdq2|I;`)1O8tl%SC1i|JNzE15@&sSAQ;wv4v+cOhG4Nuys1}q z2={(=AGr55wmI7GlZU~*Z|oHA9f!6q&BdQsKjcnoUL_YbXTY=Sn$*A@ zK>lj6`@QDDtxbw&hk=9q{RkX z&M60ROHj(ku+s#$9t2wV{a1jrc+RhmEDu)WAVF#yUnJFyi-Y#auD#tp@&p@ak7#}v zMI4TuiTv^Yq~v)5l;KwTjG1^CY2Ccr_3=}Mj%g0YXew2lg#PMSVB4Q6TK7P#^fn3E zHmhwr*@H_YD=go?!g~X}Ca-4BO92oGB1Cok6`8=5XI#IIyh)7eQJ|~)x5RHs>Mp&% zfPDnL2~jot>ZfO)y9nXRmaCT5fvpTLwp_IWF3?`not6*gr!HmvH}c2UfH+Ad!p3&< z4w3`P22h>uP(uRMktT@8sjbpYP9aUOzRjXy|;)aoJ%Kh1S8%D&wFQyQELh@FBeqX67nkw$btj0@s{Y8xFW2kc6mUK63PNDj z$g>3F@+oQmf@5M?9@1UNBKvdG`y`i-`tYk2X~Lb36Y!cVug%T+&z@e)>~Z}hvXJji zbBfp=O9SAkRGyk7Q%K?uEwJb5_(L$mqlp`<#-j-deqTlm>ctbYFgm6N3Ntnt{hCM!7XZ9u1sA0=Q5>kzS#XJ56}HUq;A$-kcSU~K9IUsJP3Js;Z`FL zsbXk(xc$e*@{mG_HMB>xflx|2tRt>39MOhiFzsl}5*bzGvY(ibT=~`Eb-1S`xQxwWzLY7 z5L(KXCv&f^-+wIcwEs}vrlj(={Ey4ietLQ%k*h8QEKEL?-d?>LK{Lhf;cq!@isi!S znd)v7p05aGSh5x+!(*@43<#I?98EX;#^a0^x#7nYy)UC`ql~cK&@h;j|5Sf`!$9IY zW$he}$KFYjr=QHfh}vIUgk=C0Sdomnb#eKT z2=!y}q5@;8yP$)}@)P5x?s$H+=4y$1{^<9R-dGN%Uy4_lIiNtQyzU+3Ilmt6P3k;( zyVjzdJW~uLG}I5fc^BDImMe7g^cBp}nx^cGioK*>9XOkawAEovdl-k#PLzM^C=>`{ z!@fY0V5P+1iP`}1Jf;*%r=8by#_-;Wz>sU57Q|KnPSyuWcBJ1?0WmAI!?0>>EkrL= zq96IsY(G@sHDM=YPdFDRyJ{wb{fwcA)@UH$MF=)JLV zqWq%jCXp75*l_&$pO&>*xss5FGJwMA{9se!GlUw_wGpA-PY}vK-&g^0oh$5s?78rr zByo~m#&6^%?XMZhmZCi|mjZ$r1b)v$0G_N`g%1QpM%JnDcM_bdK5-KjNQ`hIlWA2v}0njLaqGfT=6w zc`FW===F^lH53lEYrFC26^!?pgk9vNJM<-xHjbwe!2P)hJO!&IcT;KP2*zmS;C;_K z759HEyF9}xEYIRG_sy!eElyBVu>r{?6|HkzQ_(=qny9WnG&Fc&P2!74c2RrKUd#iX z)%1`P$tqwc)lSb}k~2QOSv-S7#fyK2#lMGRM<7BaD_XUMtDm~n00DiDYj0%Im}ClI zDs227nKbU0?~UIhlO`PVz43cwVKxR@TwjF#()c~Ha5X5J{JrseWFhyn65k^Wx%!R2 zi+$h?Bd^-xJP>i`N3csA?A>d=Bqy2@;B; z2cZe)5UQ>XaBtrSpWs=q&TWXj@NP#J_Cw6~^~vAM`F-Et@tqz!L=f2rbH^>zu%5y# zm=cYt_b}wT#dQnfjm(ynRW9}E@Xos{Z_ysn2;%eZClMQnsu!P)8+C zk_0pQ=yCk>dk5A|_{W}_#6SJPGmvA#Kli_H_(!&NqV4{A`+wk{xj;rHagQ^tI1n@y z+kCDe!e5HbL&h}o@cVf45Rj?>{DN0Z%JMV=p6fL5yn6F#`0eJ?OSltCIP-)RPRb&a z=fV{8sqZY4a?edBrHxb8*D2=H)hC%x_g0vcBQBG&;y06Wn$wD2PN8crGkMN(FhApD z4!mrj4xMQ7?EAr_+~?%E!pZZ5Q`Y(xrWGFNQ}z`G>Wf>=L)RLU=agK7`56cE3kyx2 zo93E4yO*1Xo31hs?M^PB-;@uv({|jhnPszt9@} zd*>HAeZ%Yecc>}%dguFoo$pruHloj)xBVG?&Zso`GxhIj22c8#x_#pc^>50w`BIMo zrrzbvbom|4`?w1I{@~p@f3r*V?~#)<-V4q5(@eepdaq6|!}ZB*U#a>1$433$IYYy@ z+N|>(?yi4bSL*Nnqq-k9nDpCr>hz&SI$zBd`u#Rj{+HkD^l$Fcc&p8CF5w)HdY(^` zYo#O}EMo3Cn~tkxxq*O~K17AhP-A~RqMdn0i;e(i9^40xaOA)#;iM{Oq(Wzz_j{(9 zOx>ZUWX*+>Giub&NX0f#7LN0%HOL|tQQa-yak2UMoNV>jb{u{92nhdmWDb;a>^aw{ z7p7&o_PhUvgGfxkRzi`55tk(_zl?3lp!G3qUV3zVEA z+ov&MeZId3@94ztH&kwDxlm@@ZHsdzYj}6tP|ge_DSra`2V^z%5IYBBH@=)RPUwS} z*+kGSlrtN@1_$2e<4xryaGxBX;gbE;!S9bAj1$L zjlaN=fy%HFdlNYDMu!(Q2RL-exU%{qLl9zPnOVr8%OsXQ#DY}%9jkJuY*TG~=PnWZ zoh20|AmQ_mzGq@7Gr&qWP`dKpr}J#t9`zM2Brr(Wi6mYnGO{ERF;V^ulRBAb0GJVu z1H$_UN0Pv5kLKh_+uzB_#V?$EQgbu{Jn|SDOP~)VxyqekDU;=^OSL%zAX|PDhR6Zrzg>VqXwwrvhz$ zHMYc8qsERULdX48`#%wkpWF(JqtPu?k%s`|A(Vujl;m@Sul~EOtL{xLztKRc)H;7Z zHD9BM5JeA-Vm?tUB8uZGwe`Jbt{5+H)a%M}4eTTEIU2Z}z*CMdKNsc4dI==Q zZtjO)!DiJ|URwCi;mdm)k?Drj;p)3`)W>UtQ0s3&Md?2idkMq@F+zBTqa|3&H8h%e zLGZ|l?hxaP1dnuahZt$cm$KCxEpEqO3;RVVJx$*6GA!jczT-xYC&r+b?)&>AKMH1; z>nt^SGfKyCzARME9r}Yf54LcJ>A&Z-pP+fq9+=bBg$L}%59?U%32sUAV&}tnOx)8x=V+_gel%QfUtWY+8==%q?&*`USi^b1Ek}c&r5vci`rqX) zSv74dyalm&xB_6o)v5XGJQ2z0r89wD!SP>TguT-6L@9ET#Tc~+sf`s8d}A}f=Y2{& zrC2BpXK!7$7`5hyQJxX_J4S8qlS;Ge80_839dLbkpOkTI1&7Azt0_j>4T+}y)f@F= z$3B_~e-@PCP%p@ch3fQ=rJuUrjDA{x!obj{TVSZO(SN8`V_!uz0)cE%ejn!~mDwbx z$S%g!Bk{iI@tx@lLwV1l4B+No{!A1)%$`mzi!rRS(QiO#utdf7L;njx9|?ZeP-yH1;F9qc z+;Rv}xN&==sb_GDzWq4Xl}QN`k!OUgt})97f6jw(i0tWt??^g+uvo|WTRy&MJ zXUj_qKQ@~7sPF#GfvqsGhpK(G!Z2T#fnl_VQonsAV3^-mbE_oTVT2;#jJM2D8K>F0 ze?H*&r}B`2vjA@q{FY59qUm_nX0!FAmGYsoW_rQFUOIw0z5rXn7v-!|2u2X|+4q54Yz6focXQ&EHxd`^;S1 zU_3X;ETbTXMKl$47AFmeCadE&h{Y4!_A^cfXRGtzvWB(isXPL?5?erVKXwlHgg+oc zduEW6(yEF`4k|)N)txVh`EMo6f27VWDI#iqA1FP>nq4{xJf|#%~ctClro?V z68~(1O|(a?f!WqMCjJ-pv{p=;{;iQ>+HOxmF}+Lp0TNFw`#~$FuqiSkm2dA;FH-OS7pgiC+3GFSr5mQE&nnhlt3(i?gLi|3oK6$wnuA z2JpH>Akg|?Uj8~%gC)dO(ClQzR8-Ni|DjwCpLn^)si9IXCq|VMFPEk5mL|w_=8Mi1 zHIU`U)ln(Gkvh6PVA`!K&-!sLK29CYhRf}rtD^(6=CNzk5MVM$gpMfxICWIYCrMc= zs-py)c6S1>FQ$YY97d&8c_2EJ&l02K@=?@KY?+m0tIpe~g}TF;B*Nwzkqe8ihg^{G zOwoRuiy+c=u0VQZbFxUp;lZ|VUr+DpG22Bg&_q}KJ zIlHyU_gzjRO&VA_jko)=%e)0G+@T3bwicD&IPuOKCz_o?|7qBHnZp1S+L1=zZ z^s+gIaOvVvK2tor$EG&n9QEej1d%>r zc@lF5imngGc~0NZm`=Ea_kThvbk>*|V_U&KgNH#giqG{>2BcZ7@ahh|1#X}h!5EoF zhDPr>cc5CZ-UHetQ#kxwV`Yl%SyXoO?KhW?10@RvLy5l!In<`K6$qyUoZ*z7)IB=Fdv---zDrBwMC?o&hCYm zcP=YfTjYMEwhSQ;9^rYGf?9vmZU?cCe#OrO>%giy`7ehp zS?BME{36W^keqkIR_RC_wS5itP8~heJ~gh9+izDl2P!+bh(86Zur6U$7?(#j^-{VVyGvs3(%x#bQ%Lg1G2$oMC)_zUt%iF?Sx66MY z1G(jYQ*|qw0k4*^KSNaDPQWTT1doK_Iw7O#Hj`r@6KYGioO2Fjl}KMXnyKucEIx?O zOG&zAbc#VYoDTCU&Izku(lq753`@=K%Ks(~nb7}mh9RTMZHiphoFRiyir&u~4pzDK zJ0XZl^=c9{CkgysHDZZ0|5*%zr4)@^yo>=!V46uDz^yT+V<}1F3&ZFj>Jwi-OZi!* z`~kXrxK`8=`W!e?8ixN(nV#SNJ(cvl%`UR z+^H@h5c23+=d0(cq}Dq}qt;zfXskr4hHNiB@z-27y zxUh%H8AUyU4v+-J?XV%TCB-wNBv0KHhj)k0&}C(-cfg{g+KKV9KKce_4Ld$>j+${? z-lulp#@a4Pc`wj-bJaB_FR7)gGVSo32KC#;iT3^qzC(L^s63N*8xlP3g(aQKdb(1| zf(KJ4_3%u)H(O3}q~Su9Y=)EY*d@6-yo9^o;iK>f!35I(7F|NG)Wl zkEsvq)J;t7#ncO!dY4YEVJc-*ESsr=P=u7ofgI}vl}wfDjQ?Q9Va#}dsTb+gAX5i3 z^#`QJ`Q39RV)q#PAcZBIv>M!xR^zf`C}$b&=OhN+zbMmrJrfWAJMmege@Q8h-iNLI z?aomds3EPdI1%% zy$xFu<6lfVTu?;&{oD^s@NJshetTl@2o$m_QGD=-+a0=(719B`JZV;e2e&W3h^}#x z`XH$YauG?vBLmzIKS7NEoSlsej1WgJcqGjo9EOki>tOLq^|!P$B5kYi?!qf>FLf{M z1&6&}ZDBoVLX)7sh5NnKj2WqIso`W;H}I(Gs^T8mST*u3i*ZaCDEDdU`Xb+M6>J@-TYG9z$ z6H9t7{7GMSFC3rSxr|Og=KzVW3}OJA?YDJU7@D>j~~b%n)~YBZndG52vDr>2O@*ILA)^6r&ePa8B+^bDj>U>J~#!F6P!% z3Akb@M<0eYLc$!Zd%jW)eMjU?&yg7JxiC~?AkDsk_kX`Dli_p7>S)WZ#fVmn``D)e zUsVgB(Bp2_FUUR?lM8G4IBL0!{@fVceI9wUq3#@Q*ODN3I{z>q1bZ)&pOFQYL0Mz| z_tNGy6t~LBafjQpjnSSRP?4&eSSctNCvNBBgvSAKpAo(nbKWfBTM34%r=tJa?oc6~ zR=LjhMaQIgma<AgNxf^NaSE`e;Zx zh|3pPX!g_&8i9Jasw&V7hJ5b6t%EDZDCdz_es%DNgOM89S@5?*<9f9(SUqvKmyDO9 zVl(9==3QA>-&)ZL*;Qy86w61Yk6ItT9z-9IVwB4=;Io2*(y~#3tXNkKXf+0$tpQgM zu(<D`pw?Z1eF(;KYCs5#Oi zu+2`*3GPh^qhH*it1#(ku`s!m=dQeXuPrKNr^q2C@A4m0F;2(#OrwMfUxzx^EyMYF zEy7|&(gq9n>~KS|bA0|OE9l{IhgN}WAcb&~cufEoL~v9`2c|GIAKC%y%b>inNRP{K z*H^9;OkJBoZC&3_z>z!LvZ5AFOb;zWrh&DCN;#rpkGe-+ z45fCCmRk-wL9FD;>Zs9PW(A-z0{5s1u%P3{SDbzcKZbrpXg%x~RBpmo2I6psX5(oX z0=Qr}Q?_#-LPs3Mg`^119?JueMTRNZqcuN1gta!L4LvZEyun|F8A8Eh`+F5!hu9>OslLRlK22;N>{Kga6Sff6^bI zqp#qIJG>er7)5?%#%+Fealw8lWXC|o@kulYDCAp4Agq!Y&%OjBtXE?j7{Moy0gE3R zqE9tReWShqeL%-8_2?|Ek%iqMyHk}wwf!wIFRCu`-Mw`znntBcH?!>UZ0V*ucAO2tkkEWH6p{lnE z=Z+pi&E%r`Fz?fmE9%1*o>mq2%E0WhQ^H25i)%2&n7N7jwH1?7Fb}x`9-KEvPna`r zCKkD4M`71)J%|z80yjdYLYzS}#hFHk|5PjGVC-(RzO0h=-gN4sn7U}^qwwV}BYwTn zktsC(cEc++$kNc(Sx`&T!yox=tp2%OAd{sWez510SH*5|E6HkCkYRDQ>$FA$#rPEc zj?pP#;XuwpD>Lv@;pEPNAMMf})a7_g-?DMr<`BrxR_=usbYI`_G-uvmmK0KdxapNe!-K%Y%#9U{~O@*c9Z6^FJpnU*W4VaD&(53)Ep!;?k&pm&?0+M^j(Q zKFhuXr%VfYKraJbtgOR2x>YssNf+!?y^#c|YYL4lhhp`Lujv9}^4OR3fC6@>a9Qjq z<`T9Gjz`yDRqPrTeRokBc)gv|9@NJgR`8oUv=JF8Rfb`C#*(>kR-YYW$$qyfb(y>d z)`0w2pAM5r&x$k^`s+P%tS9*ClE$BSGTP}M+a_bg7z7qZz#m2xBT!&nr#O9J$)bLb z;LS%*bBBshslqh&e_G&2>Gbq^&a@~Lz?A@YFZ8X}3=m5}DV1`{(4LBUa8NGhLKxh^ z4^N;(duVC+qx;UFW^Hx*H>S!gESrYlw+KlHn>rA@JP0##FHGCz*<>5c%z%T@Z7KM?t~qdaymFEb;2@30Pg7;Gk?lT(=;h z&zM5$UXRO9U`~9l#Kvd1!7~yPRSsBe9B$q4J!UAq&V8OGa((qU9_(QVv~w7Pua!M= z6kGiR5^GCF;jb$?C8cT}>Ifxw5UOY0fbmb>_VPqeNH9n!O^ z_!Mc|eX!>*y$D&=*rIe-71wcG3}PZ*q1J8c;Id0bfL(?4~zZe)|l9y0IeqGN$}dlK3Nzd$cYlke`Z8$5+LXG;W8Zs)b5#!4b(-E+A_v75OZjkJeO=3??AJXS2Z8ZI{&@O+WO zWwY^sNKn@7TB%h7wp9HM--wMve=$=Kud@Lfa$w|Zi z>9|CdG6A>LaSV%`tN_kR45swEeUa6Wlx<}`Ovp$7l(IsL^Ec(9|AgX#QJJ`(UaD0K z9p@nQ6GJLlj|QH)$K(A`FsidVJcVg5O1?&FU$p0kBaMyQXP@bVY2KMAz4kjfo6vBt z9m-it0?^VeOJ?fMd(clF?OY~*w*+(@_ z?A0fCby`Dux(Q1N4V11Ch-SPx8Z=`a`z) zkjoGBmsPFxhg|a^j~|}lhhI0a>_K_vLmz&4jvv0!A80{mt%~?zHb2zp4@Kq!R)f2% zUgU?@^ao2mfCFI&I9|V8JR3w?%8qvI@(&KD+V+#WdS82e_q*mp5TZ&VSb;#70<+hi zno&ijMtSO-J*YKTWEglj*V=pNHt92UXMVhov}rq6t$0cL=jUSd&r*QLMnkIL{Dob} zCD~-WnDPp%mK*F_)|=vLOu{nkA8~3D!S4=bgNKAedcS!OBwh*%bw26)?Pw>gPTh{A)?*y{4UR;A6RG_q1q~w3UFRn1d2t-)Aug{Gpt!2upt#e)dB7x$)Hrhm z=O~SH&(j*`Kay}B0mJFG|4ZY{t7?KI^2X^7PPx?u2`L(9p5RQ?IIpeKI7^anz7xke zT;uFh#l2qQ{OsSR?QWCs1~#FN0B#*!!J|zcCxkmMu5EP=;v<3TJqwWPy(*$+^cy!(uw_$suedBy%)JT)>5c1iB z#zad~f`6pk*|KoZHSUK`LOqFH!#{Nh@Lw?egBe99;4{h^q1qZ8zsJiuvj)TB^`yLS zu{qK5QR+wVD(m$E%Nst*9y9{Wh2ZZg?gzMgfj#1fPQfqCFi5+zMZZ*(F*V)9)_J%) zKA}P*f>W-6@nQ#LkZK3%?Xzz!l5^%uk-{7MwBA5hoZYH;XQm_dp)A&_Ooew$Vxgar znfv}0WZQP#&g$zuo^QBvXaB8SEnK@P1!MPlm_YEyO9sh2QyJySnG zD&(<<_88-#Li>OMn;m-|&zL_VQ*vX9k62Zf=f(2TrBF^HL;J)SfCx>=W>dm6Rp2Ef zrjL>rn#x63=7Q&>CSMOgnLf}l=0&RMxmH3l_rn`8OrR>e!(Zbe#w|z67ap$7U#Hem zk$`+wXQk=zZ%?6tlF%LrAkv%rk%8SbO+G;F#=@f&a^wQ~5rHlTo9i?SY4_hDR8hj5q34`<#5TWs&tR|5ve-T?|BM$;BqQTxG8289yU69HXvBQgE z*Ru<%Apxw|>v&Yx>bwsyZ*S)P4N+p%V4XUFsTNZ=Gc{kQUd_~tnEDY@JL%M7rVe82 z+el3;7<9BvD!Q<|1)ADdWMe5X;~$`J;jAn$jyoE~vpr}s$xb^tJO;*y>B}C+pBvU$ z(bPwreH~KqMC?H5%SbZbf`Jc48tg0vE7AyBnr)^0WCbsB`7g49cc;1h=UYw3WqV)< z&4l5^vWLM)HBu}!v2p~Y((B|nXz-r1(_Dd1ox6<9{JNx6S7#J{V&lP|N$Nc2<3+Bb zJFb5Sou>Up*i!W+*c&taiBPSf{A_M0%|q)RqZde{#gypJXwlI4dCCHu$8E-glrA;s zVw|G{60E)#F&;*hXwuQ%Ck@5aUB8B6eDmnorzlC+6T2510hhd3bMW7)&oCi^iv%qh zfkNm{-6#%|T8~`=6J2l{jZ80{FKzgeZK$F=GU4*v#Wj%l8Usw;JUidp=#S ze+NKl5Bv^;G4i!~{SJ!4Ky!Uwl-&|-ed=9rfHgZ@`f^*SnNNwxgJdNbPlLV%h; zyl|AYVZ8cU-5_Y(q4ngM;1UiS>?bvj3L^cxgj?^>*1yK#<0@Q;j#lng?|uvdB18$G z7S~AHPfNi;E_HY(7s^3_0re+4sQs_VCf)YB0a#iTyIhwzsS zDvkNge%S0*`ukdXZvacNGn4Zq1|Qq6*Js$D{Mg^BtYAXtz%KDKK|g7}0av&e)~lCU zH8i*>Z$(4r;%f!#9{D4`x(qxz7*ZqJ`nIGGu?dg*z)b{C#rDwbVtY_daRfGn;+Cr? zU%8lM;&x-0hhMnGde1SC5-iq#4lF=td!`+w2nlo~08B^I4ocL(=WF2H`Cc{c+ky`L zOy8*6q|>vPLvT>z07QV>ItjhxgD zj~pJ^4_d?L1NsGs`d7@S5TIaaG@+Y&;k}*n>&up}NGrpIac$H)_-c>D4Ti-zZ8+gC zr#W-k^Ejx1b{dNa+u_*no%zy&-#{~TV*t)z zK-Abt)9`h_tG;B#*5HOy_lXkAs1Fioorl&jtT`hGQKvo$iRv7@YP-FE9{GV54=e&R z!n-2hxSuc1X%CX%r$c@91S@aZ)&&j^8Ma4Zi?OlPZJ;*}&YJ9<_ zDmGSE_VE^M4%o<`wq;7qRozLQp;E2H9abgz-*9&U=W1Pn364FP9=m(g7swQWz=e5s z96U3B^0&2Y*g)wqIa&(2?^=2m6nq=_TzrBwNnBr0ziB2k8;fTW%m)(2{toTTj8_fj z|45f}JIc{fF6md2r;fH}3#NVzE8twszg1f_4Sa*Rgn>7%I(uaYSKUmfzE1zkfv7(A z;K?|6mPYan!gxd5(!jHaA{(7MF>&Y^gQq_DR!eNgxWngjs>C(OMC}9K7EU`weN`-_%?vfa){8}#6&LpP1b&ta&spE_u0U%~bh^X~>et|!baRP&;m)dN5ZS0xF+vE=!>GWd z1Bu-iqGg9Vm8%FOTt$1hWj`W9NcK{BUcfHRwXGh(-*HO_l*ll>G%+~BJWEv!Hcaz( z^6MhqTHjtzg62tp34D7$Smhs7IV` zxiM}p(wO~;&`Rc_`l3^txZpj#*Om_2SPl&&?(e8=&*7l00Yahz1(mTL0q2{7_{}WiS(MR;ATcGW+IKJ*3mr07(EhRz*!pPp05_nqw6=$3lx- zYQ@8{`1>{w>#DyZH})yA20-;+Qz;8TZWTCwNRuChSN&qmPd+&s7^$zC3>dFHK&?Sv z`f!Rd8yh24cS#~{png|U$L8c!-K}flMLpH?NM*|qnBX)n7$E~va}YmIe29^bEhi{g zs0*GUcyhfFbOWBz(>fh3NwVKdV=y0rAw*2YHiMy#kspotYchEUn-TBlEMh4PRZF$O zik@;xe;QkVLu3YTl;hv7g+khIY4ZSv)U^1c4k!cJw$p)MVO>6N^lNaeORc!K( zlDxf;=5fE*A+&DBh#WX#?qHVXFL|)ti+9XRb-77&NqWS7%X?SSqbMZ=q4Ord>WfQL zvIB~W1U5BWk4OAH!NaEZk$*S0A?Z_uJ4~vvA6bLF$BBr>2C{Ly_kp6G>Yh%^ z6{p>77p7H~JRJ$nd?wq0tha1Z{Zk$w1D=%!Y^6Mk2l6akV%(tz@MZuhMIdhqE9#Sk>YM~!xY?Fb#k>=`~_jR^W^y_8T-pJ}OYNF=ZlXSJ8e|{It=F6%@~DhEYL0e9e5z9 zh^pOiAXc{n6{=%g{*hV~p4*@gKAc39JUElYov2qC_rqGC!}Uc+TxLY}Lnnr|5uY4+ z*N2?d1$X%S$7e_X8D+tvS%^O-Go!z&=&PVaaAgJ+V!hr&mJWfR67rQEMVzi7PE%|!v(qw-(^LX94>M@|;01?c-N z`!P|HILC8|VcAh?Q~A|K-xD#RP&i!OxMVDXY;5+R&L$f{&YU@O=1l4t%QO-142VB%9ZfGVZ4qui7Kv~`yVh3H zP}vW#9qfH{D+L{^lzpA#81olDSTWw zV4F!US4h*CRefNFLOPh|pXS|5O&z%n&19B;mqL}DuJ>^Mz`-uGat(4%ov70VxW=-C zIaCt}TilBd0Iy4>g+SKN>r}B1Dv_?JMea+BYmMg8>Mv8-ZoBk6e+KkXz;bp^_~~UUvzMUY!|w&B=JXq&}$0JZ26rr-bYM z+_?yurGD~Zcq}54lv&FC{sa7A6U{NyMBHMw#IN~08o9C?F)=EJr!OkzY;9L1j9`X7 zqk^|HitM#Sk0tilUyuEV6O%SlHGxPPiKkb}@wFgc98FIlGU66@;2`rbXcV=ps%Y~W zI>$=2R%Kl#G=W8upOIXNOzh2~!6sMbi>}zxDVq2YzwGTDD$xr|YckB==we16k~_U) zof5Knp?atL;~>QhKNyo1>{| z#cG(F+_Xz;rf6!!dUr9O{PWAv%JC-5UJD z`MUmR1eS4rQzPEz*{O`KI`2KHdhk56*xfjk&#pHk$Uwh% zj$wg$LUn5MfOVMKI8ua2?uSL>QJgBBig?FcQq%BnJK z;DbUo^Vd~n?tEF#UOuEJ_hAn2osN}YapABba*t(;)Yvnsv=mEFS^4_9jlw&dwGWyH zmM*OVTZ!2w?-R51!*?|J#9WQb8%zRCHyAmev|u1p%H2=wU(htwC;Wkg0i4$&N#t@} zIV5T;sLkz-GoJss7Dz7fe+}hfNKLlmBl&0j{km>D`$IkkxVJM_;x&Rhek7?Wrjnx) zSd_RQh8J`3ZLW~Btd*|HRCJ)f1EW<$pDceh(#T=o)~uFB?d>NRXk?plj~u^WLDR44 z%d(3F0sqYtrAw}MFFsC>q_3>gC}j?Q@q|h_Da!tVO-z}&B~yf)oyl{+uTqO~WB<@C zcuyYc+IsZyX5DAMwzx0uqjw3xlP2Ob`i#b3n{6l0j`B+sF9yZ+;N=57gUfr-Rny7<7KUel&pXA&vo}Y3zHdC;K@?#4i|JK% z3J^lMl>kMtG={rHpw{dq`_-Qy#IA9@J!0eIL8b3e@;FMWN1(r%u!ZVXM|zdj!3L8P z?xh=z$?iQ2{bsdM-q14Oxi=D~-Q>rInmHp-MVc0S5^WveJpwlUeSbDEKe5fju$^#= zuC{n7J-QgH)dtSWAPaGc=oHLcLB900yBLpDo)-V zM^Z@KZS)1nb%QqmF+PLcEqCw3K*HFmmF^Gs>{GB}b4LtSV-q_o;u8})uZ|?O`IXq& zx#>uL*;#?HFa|QSB1c9REo>ll;`Fb(6~>QRxY<7!77|f@!myIWj>4(?W@>i~zDt5? zYFWr{%(Nj4l`dFV!Jn3voPL5tsbEKqb?{x@2dVQj>4v$OVOpB~d_GM17q{h4-)i>u zXuiGuheHeU?CnF!r_{%hTT!ix;-gVPc#ehhe5T8FKad*J(d_Mt^LKghE{4|o*mm#f zXsy7^_h80=iw5$6MYEerTrqKbLAIyAPeSdhPS>&*j`(<pmQ&vtrsY9qSOq4@(H;xpJkL8yKmA3U+V&A;u`>GgeP(}j4A z`H=DSZ)@vrm1laTW>+iZ?Lia^>*G9B`PRBe!N6Qo zby^-(C#uu4)N{P?)bs2i#x))<(AlN7tvA#x(b8FnK^=3Qj>5{u++ZdU?gMKm=nU$B zdn|h=?0yLQB9(BQ(9nYnecCc8zIK=?NrCV3gLY)UxBf)G-RfU&%G3Wt{b7dxPxbqw zm(kSAd5no}(LQEaaw;vaOkXjuGJWl!^sqjMHOif?Ze)5`$zhGfdW0SN@XHF|)NK~{ z3}fnT6pBvY)q!@`^@5!CL9}ce)+ZT_+_^eBeYGroSn?%9PZ=R=+SH>N=Mb;9gbA-E zsI=OTq4xgS8*JzaEjyC@lwKOX zQoFdRw%z%a+4?jAF9^=Hy9A*XnClwlYyt{1vyMe*$Z4kA(4&Q+<0{ja*J}qz*BB?? zGN`$;FyFb9R!e)9aBsUuu|ucNDwa8;FWpW(6L|{vIF4AYSkBG~iSD;I*(OQ*GauTG z))vyV5$WM_9cUayx2G==PHkuDmP+0e*Y%0Vd$NC>*s*7P4+2C*W*kd01YPzWdm9ps zt;4@tk+;+5*CR_BWw)NbEQC4j$sk5c1AQx)K1c;3jRUP-(T=aT)ZTMt?htt_Jb-9o zn)=0l)1}y+yz?M7Et;X3bMwZ^)^nOIAS-tmS%@Fgfm(pUw5mHM_GZb$-uWIAqubBu zQ`E7pSO)LmZ){@IS7G8?G?Yi_OJXMhWc+#1;Vgt~ z>yKqoVspnmHb#OR@VE`5(zBk%Vzbwm6-7T$gHY76Mqlv01b z=fsKSx$`~oBc!yv?Z%;jgB9E)USGObK^IdoW4@PNg%8`;f>Jixv{+GKL&H4=iDkVd z!Qz_+ypdlg^P0bx;&D+8fFrT=60^ylUvgM&=ek;*AdLn-8**l zn3CAS=Yl}6u@yTz#UhVwOue0b3smOj3-rXQvP#aIgIcvO^)}OYT{JPRq-4=2Txu3c zdY!dVvl6FUOE`G3Lj+TIHc#vI6iNOCh(yLllIspVn-3B@34(GBZ?W`ui|)CoLTYG| z&x@jZ`jr4M6L1=yr#uAs^9HHy-U2hy4u=)GDM^ovqijCFGEFc%!w#-t2^0I+TugFl zRo?(yO$|j-gVJZ{FjjIkNx?Ob>?3>nk<>^dYja!0bytTsz^x&BW%|k(S68O5LF!Hz z1hK`hh$g;ijZZ=&>x?3HgKn?hA88Tahirk!`y^_Tuo7~B>Wv~?Io^V_!NN8c=E61x z^VW3a2aFrb)i#9MDyXgQcAL5ib9<{vbt`9|5nnb~WszI1VJsou7d4)h>BpW%sZ8Iq zoWCveXSI9J9=|(7<%?Bhs%?qbNq;Sst5V-qrCzN{J;w&Tmdo1m#BP^2Tsq%5l_i|< z60Y?FQCV^fh33-I!wgNq`M9$t4!$NlAE$eTUSHZBjxkFGOH0=iR8%tu6e1xo&FWm? zCw2Gxg&ra=PrGNH3cg1gr_rUB*K_nOy=f&aDZY~0_rg95|5lZ+h(9(lI=HwJ{|?rT zSP|$9C)tvBJ?(t_+iNXW9OGyNOtgs6LX+@?BaE@?&*$2`35Uz?g?% z@QXYR5FB}G?>zKMUhN(DuXy=1Ht+l)8$@W?y1)=|{fisnpVSI<7}@L&i*~L<-&L)N zH63M~_gi7*yXs~Q-{UyVFL}rgI`-D|FS!Ljz4+4`}IIn2vVd zzCL>B>XzGm2V3sV?;p&#vuSS$&gsq4WMa)Dz5xr!(YM`viIdD7nw;coiKEp5O-yb~ ztSg7LY&A3xwH^+V1Fcx4)QLK*HTGbl|VIiz}y}E z-2Uihk>p&;VzQFtI@&wBv}rfrx!1Ol%$4-5^DI$EP5C!$&BJH#PG>6VuV1Ovc~lbW z|33eRk;ZPh{B`Tylh@ed_>f{2$9pnLnEv-VjK%TNxGj#arMl4ce`$SB#ZNWlwcL$9 zLr7n(+tb5}hdzi&F>=>4#F|L#z+8COn&_dgSTnQQZ}#{~kMOq3oxlurM(m&7m=aCA z-vPTdP2Wv{Du})4@G+5{)8aht!lXe2b@uBPU8eR%&e+J+w82jACU?Yg%%ouA2`$D4 z;ggBV_bN6-t+IZOn~seRspO=f~>u_u|W%uBIdq#N!WAH2VY4;J=4{WSmX4tq zr8a^SE^O^6{bQjf_=5P^EEx`pWoGF(RV*`Kr>GV+@FBYZ=98Sw%-ZTdZO(m~ZJ#_p zSR?c7-MiZxqUSfANF%k(;mBmKL;u1>hWK}fw(hc6`Z2%${j-h?ai3WQw(`n!T_3mM z0nWdTtmncTCFviJI*YD<(di#(2`??TiP!4%4Yg*l`U@|11#)*tr5bB4-M)NG=wD*) z4DC3K8WZYYb$WsNXQNP+TEYFysjZxWV$6{{?o|mjn5gl2z~cbfTg?8w?a~g;-mw+$ zcGM-lAG+t0(cFrvolMQe2chLG{9EIv=~CMthAobTEp8mgh{jTvvA>8dP2!Ymw|#>b ztHIfGjqocNC*~FHlx%W)a81 zJWpjJ3AuJubDg*Vu-vIikNSj%nIhNNgsV$*$8cS*V8t}G$5319bWQxKPuKXun#?he z6S@fzSBItHx@e+PGmn-}(zERdw zUtBpRh?atLkMRLQ?mBZS^7mcy#i*aS;y^HF%YMXDZv4m~Iw+`HZM%x5Z~z1wHs@~` zq=dCa;}TzC`k|KQo7@wh8AZq0tN0{du0!8u(Pc8)e>eWn`loz#e7}ivll{Ii+X}Rj+HHy0C!g`)^?H=$?nb9iL>0i%WWzcxHnV5 zAj`YOJ#_`sz`CY-p@OLVWfUb|>O1EL5v2Wgs;3)wsW1OU56TY+%1`m-cZ=%(0Oebj z26~)3(U*H#<@Tjq%NkD?GIQ@w#nI6LK zyYWgKwF2UakW9eP^xyr;^hUojWq*1a05I^Cv>O^Pf7|SPpT)8`Xra^fj95W%xA|sNaST`t8vH z-fN3yo)?Tve6Prp6?j!@SUQbO&k*D`G*lGi`Li3{~J4EEr)Q%il;}=2-xp)I@^wcgCI`3{7f%`Rh|p;>C~KhIl_Zc_jNNud9;`z|}>mI%WrK zld<$Zu@q4v!u6DFRm4c21uDas$+A5&wLV=slf z8$8M6ZL$!#_XN#F^`5mqs`s$}AwBh4o2$$tJ?00lGVU@yd01Xe&ZD1Dr8X>!7837u zz-?-GjXIWEkBj7yRK)co^d9w^r4gvW7jn@XG$T-@844n`zxudz4qKl-LBE&x#npfg z#*jbhQNJ%p$A8bdxyyg{t1M{g-A)Epz`fcqUK_utytcURGdmwb1luBZ<2xUKt*m2p zdCS#{6@+ah2bn9HzOVs9H-lK+FiOJa{*d5X6Wvh`*e^XGSQ~D$MWRjCa-PUl1o2t)Ic;)N1dJ@zW3t z1yea9?6@*=%YCG|*G||2%D{*9 zjk>=08xz{^ee||7JUzREP7J@s-^)L=$bdVD)FO1OL#6Tg>{_ z`?tg&l+`VB(g4l_Q?tA6HLZN(8CwUFzW?XiW&P0o@&&&lz6uC>PrV}uUgMPtV{C=F zq)9WD+UK5T?|4{HUs(T6(-=+ce*u3JwcG+PAjyV_v%3}EyZj6oho#$d#|n1BcX zA=8L=W8YhTEB#OJK7Y&eX0I|s74edhP_k8jj11op|FIos@oSg^=?7;%HF_sX6kwaX6?8j=s$?wV7Z~2LI;pELt{<;%ntmbn!K9_Ht_EO8TSyFPwOeos8l&b{n-;t*2Ov@ z>wdN`iJ74f?Srg4|6=q@97dNqYVhuWoe_&R#}u~TAD2uX8}Mh5_9g2MwkprAn7LpG z_Bqjsz`2&ud!;10)Mk`9&-==%-TAx zBW;cQw(jUjTj$Y--P$_l7fNbb1iq2#m2!a}9APEh{3} z_#Xf@aaR6liaulMZuv>X|7mv>OAx|lRYQz$p7DB_89zc){O1;lkPqFb``8r`-b=iM z6nR_s53j5Uyss6CXEtb_?S7uqFYsSZ=3r)^`uc$;-uTg3Pklq?)s3>x+2|@%dl! zPiV_O>HkgsYufVHGYld8P#>rXlwYlvr+++KBbgdlYAPZEC6atv6BrvV-0YCIM_czD z%cK0MwH)4)U++&ne82__e$ge+r;Ov(saIX|@%unP+ubH@1Eue%=pooQ#zeu8ccX(4 z+h9CmHFJ=;EwtfxtNl5dYEnZ=QG3+(oQ%tzXNVAmnTR%V-aVqc%<2DFs z)0|D=V=ObeDBAi`HMZN{K%1EcS|s^L{<3rK{b>PIV!J40af6Y)mYKTo?}{WZAghq} zgGnIGLy4vUbUNvoilXWXYq=$(JXY=^iL;fp->z7CAg){Zj{*;Vs098%X-s9r3kZPI zl3V0hP@Nf9T03CFq6&~^ML4cDu5^%V%+I({lB zBAUXS%RxNrK_xA(JTU0JRioy=O!H$CH~|xssjTksyc^ng_iWFT4Sufd#DNSPK<(ts zg!Q1LLTp~7D$1%kNh{(@LlM>p2G9NMB)mN}j7^97?i@gO1R~uj~R(!8)b#c zW>uHXuOS!G6mg+l9wYgxqK#4|;RVv8OBl%lx8`RsX2`{jQw8ci{ve;CiCvwi(UDyp zBe$eUYEDd|1yo&-y`I-u`abm|{&tPOA6;U5%omfMn;&qN-9=S&Y9YPEXfjNvINf>e zD(pdt;2e6`3g5Fx<7aG@WcT5Fpifx8K7j-T<;tVIT$$ld&8BJ(qe+=_q9M~`+N<)I6n{O0 ziQHH+$6xE|R8{&`6%!NdnyBZ+YKavk)yN(9_mg&KHQfdShFxJlc^wWz{)v6t#5QrH z>17!4_5NpunhT4?r8ra^S(4p`DX3{*&u))!ZFV?bH>D&nic7OKRMFI%4EBZbV%WjQ zRPy?fa$_wkU$VCw6|lsv$}E%cW@Z=8ik!PF%4G4F#z{>q%3cIL`O(jmDz1%6cd{`p zm_9A0gnd|r65Xh=2UVrd$REGD z9|SQt;s==XQ{>j~`kzyT<@hXb@-lx%bR$%xvh3e!cb;OHTQB6|@A~*F69->fRG0NJ zc+GE)JyIyveg2k~F)L7CFN-EXS5l0zdjk&*8`#?#I2GrsVzwINN7&Y5{E&&Wa2=~G z-{H@F0jF!-UPEUwzD%=#bI*@9rGCox`K?Qbvs!5B=@$E>i|OQCIZqmFJ_> zuWM3tS(;}@->`XqQqcwR%IN5b@7hrD;|x|#-%7N`Bgu=YQnfEs-IbBb9a$ZOl{~IW zk7k9|8lB$in{|MQk4dYnGS$7*T`}IA;LPt|WK}+_L;>a_jXDEInc4hsxQ)M6>6^4K zXJ>;OuQVVqqirwHTm$yN%kp%`1zbu_lJ08@fjuZf8XS_7*LHFMpLxGAfuDHtJaSGf zKdSEES{!wWNean-JbAi}2i_#i-z5y1)v;@XuR~SnRHNKYCPr7R#%yL8CRSpr>*bDk zDa@8y9Z5c7ZMj~TX=(WoF-R-_XCEff?xjR7z*nyqI}|;<^ND@^@+TfKSE`QGeex+% z=BzxLOy0WBN7>Nc`z7O8!#HM7IHq$5)ZYKQLk;>2~vug*~d$ zciRY_-nUa6_3cBCPXwr8;hFTXGD21tg4o6{Y`oinG!5DI+4c%pRU2g?l&1nHFw;J% zW&`{M_6`A#Jhj}+m{Ptxnf!KbI5v^wxw}zT5|8y(lx^cx3lq>1hB7u#R64w=1)D;KRyS<`M2c&N#`H;X4@L*s6 z9I(FxY|EdmKRBJnQq1Xp|4%U^rZ*-ER#A#c?{=MQP5G0`9IR0vs?-mC>MW(+;2StZ z4ctNvG;lJ#6i){YJU|URl5*{M>Jr8=JC8r^Hy+yQf;LlibZ69E!lxdi)XSB+O?fZ( zslAjsK&gLWDBSrzwLqyC`Sv{8f%aVF+w-fSJ;!^5rH0U+dsOZaUvBMZlv5bfmNmKa zXrX<#EHLHA(pSQB=oebdy=GkUjh#_30{fZcpdGkDt{%CER|G9tSYN+7ao&SWW{D$Pratv z4}RDxTcoB9_0sT6I%qP!uEsO~Yt+wuqi)lZhE+&we1^Mm;y&0sBDegC3f0DQi?C|y zGnz?vcQIdC!*nd?C35p#m=PY3~3@eT{r1x52X{W1A5*i$}D~YAgWbxU#f&W)jrzaKW zp=1Hz{j}G3GC)|Q)SVa1$6>E>_#aG$Fl0A+g-(ev`Q8r%0G5T>K}%sIISLY&Kst@z z>_WG$XOIHU7hP zwc;MU8PT9RbqY575-(_k*_Zj%7(Ty^L#H$?t2-rRx?ZA$l`T!V@rs_W)BHJ~KiEcY zlo&c9J!h|;awm(Yml85t-DL&S`l8$gOA2oRWa5~7r4?MYw zdWNS*$0}1B(slTt-XI@T?+5SIrI)CejnzI_hp}29+7X$py}BYYi%Y5DRz>|B4kH}I zDY$qqz!08@eC`eM@O|ccR4KmzIY}%1u=R%bq+&8salH=DH9pTvFmJ^sTv!rYlyhfJ zcZ?l4tX`NC|?4saA68%=9rIRi-cGEZ-a2-x%FHeL{X5m&Rwo*Ys~~;gOsR{2b2k z624(jwwceSFL0L-@eVY2J3-@hJOtx|@#A+E=r2?JSyk$8+t^Wrioc3l%pfQsm8bdn zaSBW4VWbuoEr|77A0mYl7|WvNH}$4fQ=g2@u1YVp$bYbKb*2#T>5}AlqDs7p-5~?<2jQtI+D3zuP5?@uUQ(6myu6wnDEV789!q8I@#%>! z`;Z}`qM&-h4JB0srndF*PWKk3E(z}8Rp}>1@afvlhm9_YpFDk#S682d%7&+Z1U0Oy zyExilvr@dIXv~;tJcqw~5+3<&!OMlu<=DDrJ z9w78o_9b+Iw)rL$L~|mI;wCxxDn`OjDegY4GIePGk5CwnGTZymVP6q5cH5aKKFd*k zDcNQwXl7e-UujjEW_0;-$-q=As zx3sHAo16l*@I zmWRs(LD@ROx^aM@^i?-@X=K}Mk)ppm|99{8koY)Oon9uTLI?I`GMN5vxo$=+w#yUL z%Pu+w!5!a5lCn!yO;}Dq`9_`!V8IUj|7unGK5@U~LM(k$b^2$8u@3)?VP`I~L)Pz* zH53)W2DxU=9{?Ix7Vnxp{R1roV(ANtn2`I}5wBk{g>qqlY$}>XDmB3FhCBN*qw&M;&y z;Oo~kDYRSU1bJ0@|5$2$tly4Mj$@sV%?@#pZDlNFHx1-er120KDAr*G;`oIaA+8~V z9!g0JLJ)P*6Adg{EWy-FAP$uJp=xsX;V@U@2h2n52F&=UH{A+*^e9*{2-8dCJ!!|6 z?DSIG-N`0TwSoO^RqAEd1M%0*Z7pL#csK^|PuE=QrThv(8iZig@CDuKe4`A8MbYge zg0*?aN+|G6+v?74@d4 z)(_Z#xjwZ$a_2K{2}^WItuNaqc$rM%lO|%q-anGOfi^5Xh>1?`y(5j!S-xAmUWRy( zxtxhwng=_)hqN1;2HMDqMgEtVNA4ge3zg>bt4s6a$qY}QQJ-Lwp+e)E{1N?9fD0(R zwXT+j?wX_>a3m-DcmB4OEhSO!^nZ4Obd83u4o5uII~#%6JRL`Y8zM@OzffDSwUmGx zJg~Z6^_SL`;n1Zi=gn^QdqQCRc;WjuEdl2C1aogb;xUIhs};z0I1{wpv`}b^_qTX= z=-D4Ua}Xi$T;!HI2*nPiZgTIErmf?nZtcsjHlpip*DeU_b2UROej4&;c={)33va}) z_3fSxF7S;gP(P_IwQ>9UMlo{oK?cDchgEj^KSkI9ku)9*2;rufFGD+$Cvt0+u4cQC zE_o(+4J2^d1pavh{OIOI@QY~G8AXWb=UMMpvf|z10-I!nuZR3V*8)+R0Y7%E>Mf08 zhZXt$d%^gwB+5{s2oq0JOzj`l zF@J0+t+8z^rG@%>GGDECQ%@7r4yr5gw~(}uze2howGzhc!+Y=P?+HbFtYqGA{07ON zN0!@GvfuL@$g!;m?4cl6{e7Hlq8YVs7KKUgqvtnyHXJf0*}h=SgL2D5BnhU;GF5m72_eTrlRO?%0tkM~5PCV8%VeoD4SLt-f=Kck zUU#?qerFr{a+rc~E(s?0n`YVMevrlqj{`n%bf)l2r2_Kw|bPR0gX@ zqdTVHTb9dYfgkB-_gZG7rdm3i{Tqp%FM{z%zDdFCiB`Hn_<(+YZ+BdL=sIkMexVGb zu?mKmZ+*GOU3QUwCTlxO(!bjy^&CN785m zOiw)Nha_+FT2}W>g!=2!10naU?jHzx;xThLAaj@rz{+b&XtN#wy5)CmgZVEV_<%rv zpUM$v@)CxPRvGnYAG0OL7ADT7>B_RI#m7UFa?Je|OAeyP=mu-t?;86WB@KqWS$pfN zdm8t!)z`mFUuMbbvXOV24Te#xXC&ZmAXW3h1>XbzNxlW}2M6%qfb;|SGXwZyxt9BK zMwG^Fl3B8s%@_im5h3Z%Z_aN$a{?MlhxM(SK|_gdfr&1Xr$9~m{0a-uv4TQ1=@A6z zSRSvF35E^C@UE#KJ_oC%>EO@kD!6Y-@i`996QdBnAKy0r?av}f6gJNH5u+npnXbnK z(W)DdiYthP$OqjJrCX?UKW2C2*y)&}G$eb@Y#Wjd=ne z%uAw&^DSRJZ#@bp<&ER4k&4ff+Nm?aEWE$vSdD*#j-zJHaUZo$lYn)vv`+*7-0##r zt+Uep+CGg*iTefGr)dn_O{7_kD0S>WSX-_R)98ATHa2@9iFwV(9srSzwfHL+n&mQu zMAb$L&Nl3PbJN1!@=aS+#s*{qa0=X|?{`2C<(qcGknTxrcE9uVQ}dNJx|?>B@vf7t4p>=)LJ|qr7j={R)Br3Bixnt2MzvlvwJs zusM@vKiY~d7f&`AA(rC4a0so?-S@L%?Zc{RHN0@k z4JyLc3O@g%N~<+7KdDY{apTtP&q3!aQQ`)ylWP?$(x1=$C(40wi$#dF&m~%QP4>ZJ zdw;aQt?~L-O?Zw>fpa2uTnc`)ljv5NN10aDMtl)yyj&LRJ(Nh#Wa&(iK`AhTf_P=A z)56hNO|{Fl~9zhvngQo|M`OPBMe)cO3n&Do$G)v5pFwS#RQ$|r`XgUM2- z64bhu-?lbvRQWlS587beCh+Qdnr#(q&1DymB9c{Y0l)Fu7-O-Kr&#(G6cv~^?Wc3&PFhdUw#tihA`whN+a(qbpVg0A1~d^?|+5hQjig)pv7e);gwIOMc8vQTGLtq zJg|28By#`q?Ct0U?&y=vh*S9nMx4QX#2;bO7)(JYo`NZ8!_q6MDm;q4`G>?Q8)?df z(d&4?(<%dvA{rIAH%~HfU%n1F#J<2CAaL(f4dC*_p4}#J-3?qtfqT#wd|Cy6<_m5< zpMvwgTX2jDo`PtR9b{B2wG~0JYozRFgJS6^oEG?)08@8+|D{t0Y{RBj5xH~C=<3uf zt+@Av|3}ZMNv)_#t&OE#l#hBRlq^J5|I|trmR)p0q`SWl)BBUVPQHELyhi)#eETZY zzP*IM)E2Xvsdr1IXuFdR=~56B&l7L7SB=A=b`Exkn@;iWDQsDXr(lXyc zxm|vk-ttfK`R)EV$>O{!qUYD7UdUaRvD*9N*l~pI_!WIFaL!eEQ}SAo)9g#oxj5DQ zb}hXCHG@=*A5v`a&jPvPcq;VxL5@MGIm1}=UG~GbD>ZwPdE7IDi(n+xtLGK%9Qp{4yV~N(HYY)ed z{e|-$ZEcc?5E1U)ogis3idIrg+ICjmq1lrJZah5_ACqBBb-KXG9OP%RCYY6q5d$> zf4o>9lfK<_Pn_~#*zBM@w;SQzB9b8wDX%%$(8J8tVkvx~Gd{Ywo3J#PF-q`q@>6hys9$sE2|t;~+)G?|o3Hw725g|E zN}B8rd^ap8BB+Q2GkROrxynkarhc8JjfwW@^JhT*=jZC=7PZ2r;DdJq#vD7JVr{@A z6EyQKH(;N{2gh&{(iw@=mYU3zGC=-k4X4Kb^-kC*=DBXZI8Vg#P#ZZ!$3%$wkmj#^)DQZDnm0Gqd=LWA4Wvgl+SVBAcZC zqKF}MRH(MC(D<;>WcS67bUY8m^$2NtM^sDGvsoB*Pju8y-Gk5E9mg5djC%>b*lc|m zy1o{^_}%e2z7Y8b{Jgq1XWReC{Nl#?a-}M#*mlT)*(x_d<(3B=WyL7&GL$3S!4w!W zkRu2A^6zh;{Ayo*jLIMOz2$2tuMVAemOAu(@ubWl)Sq|V>E1qPS8GjbGpAZit-0fR zRxs6>^wa!c3ow;jPT=|T8Rv62BVu}ZZar`hVBnxC%m;mt#bC88HoHa#Us3M2p+>1q zEX2kRSZ9aEqCd$FG#d(XZSb*%*Oy2m~re9W)=#Cl{AN;+f%3SIK%e(3-&QBXBK# z$J52w>i@=S*s#Ky-9%^!!>0kN(veuY0>=A3*A%b=jP^kW6Mw z6lE^BRF_+VLKsBoZO0%LREu&?{ur$W4O{ zLrZF)tCpj4{7P*hzwU>_PPT}$MnH*=8Q7=%yy`C&0FNb-_6)+bLI|l?b&I0P>>+iN zX5UNrubP~L zJQk-C4a&h|8L6gxF)j<~NdZ3KIe+i44@_*`-KKrJsH_~t`v>P4M|#IzPJIy~#ZBG* zjrMg86y48$j`y~3IW7RZ!5RrUX*3F`0+t+IgYmD$Z-tfx9r0`*~9!MDF6a17}#LL`$ zBFP$XmD;*}{oF&j0~gq-t%o=83GgM6#@@6tmYMO53Ae}8=Dd+(WzO04C!S@#A~#6s zGWlOxn^%_hmw9!N*~;$+WGr)M=^S7#G}VxX^ybCrelx$Z6w7m__sQmfIa<1xmOV_0 znVYR|=ry^A>e9*fI-7#$pyQXphy28d!9CVg}1LjuioHpwmc+?1hODjrfn zs@+KzN$O@$vG8~rzV)AU!h7oNvgEi7ngzVP13o&8_Med`>wv~9g$rqhHv;OP{Yj;!IqdelcGRgL^zgCko`@Lk1 zLErKFn?{DM>$98rD*gmjgOIn4m7N)-jfXdo><8;;MyV=ulLo6M^VjbktTKTP2J7v~ zUaO;{+g*fSSVh7+8HiMLlNe0TlX><$2Teuso)^VHP41E}#1ou6f`em7u{kuwq@H5* zESZSZBXM(>=;kS9`YI7{WomPt6!h|Lz_wP!+#6yCw27^<*MN1~RyIWLTtTFiMFg$TB2x~@WHUnAbDzUVY!BzY;B z?Y=4tYOfXWI*SbNnOkhET<2Il($;0(v6gRfo2fz{ahsxJ50#eCL8+Vo(E|8C1k2NB z`F_H|b9^a?cu1kg)p&R6bQ;N6kH4e?6I#@Zl1z^&Yv;@GT^l`*>39?dLMUjE``f3+ z@g;&8p+CmvQq40bz43*X_}ksy2YMBuOrJCRT?8EDLkTq(EW}@&Q&9hwu^6eg-%m~u zqX;-T%9JBp&H5_W4`zh%Cdz@U-n_&Plxo%yLuAY2%{keUWsurLoz5ZVL|xKEU2QCr zdw}umRpe|BqG63jS*>V8hQH|fmvsN%q~8-B7qwm%HJ$}|m^jN82kS`a%_wx-Y1%Vd z+Fz8o8>Qm!Np0I!a&N{@D3wK6;P022A#GQNMH^09R-`o1pIYe_LwVZP8a7C)$R78u zk?gVAv&ZCT{;K_r6212aSGWEXg~eU+15-Q}ka6j~CR2v~xe~?W>ceu12Ph5|k9)g! zf!7d*wrhR8R=gl@4oIp>DY8c_<=2#(g*Ng{&OXFb+x!nJTKiMmMQ9=e^*{`o>%mvU zeGjIeVm%o7>xYTUnnW6t4Mi1uGvtYrJ*MryhLUme6 zxxgMFrqxWt5j6KH=P->)E46?Q)Ai>X-P5sO^ z(szV^Qq>}KZrahyw&;^5(i(iLM3$B5-&WFi{9q!DeJpvYH_x=jyAPhBPm!c9|8d8b z80xR3!lfsA;<@B>P=69b5}-bBF@~HTusm2hZg=PG*#!#q#3Qn48NzpMf5F(T!;M=`-`W&eCYced#>0h;081HVm7l8a|-Hp=y{D zlevfgOY*W&o3x2l*p8u4H2&c>Jg~#{M*WV`dG{NQMt)9sD%hH2+bkc$G>3iIG=!6{?Z3KHaq>}jcU#l_}f%x*sWkH z(7j!Qw29dN1aA?X4b4PTE2}aygk1^X!f5%G^>y7z@#2S+O8jAo3PSuIop%MptbC$e zegfB5rSFlJT3f^2ZT#9N2#W9}_P2t+T^?G7ih$LzUU6C?pR{8r zSp57f%=yz-srP>4M3+t2LDvS7tW;sugq5~=`;7YB+f6<`DktI?cfwu5KG!0kF#=d} zi3yA%8!xSmwmzkvnqJGIM!GEjPxk8`?ER?b?zgE>r;Q|a%K~!dST5=jMp?MhSxlYp z0+y?dBR&0!b!GNo(^`=SlIc8QM!deCHseR8J>f z5F&N<>H?j}PuJ`7iPp>GdvT^W-ZeX59Qs0PN4_=M+n+2jC1Kcg6Z*4QqAkSA4k0Nu zkPs{AU#{*{&B3c(52Ct-uEzr)8?!^noT3Hz=Hf1dRWP+zq~|thW^-UG@BB4wpx>?%r|It;|T9DlFyY2 zHPYXr53q)xq^|qRM~t&TyRzDhW5N1Wd`9@>k<;?RCP8VT713!7R|W$54Hrei&kye=2|YwBZM?7-B` zL6^PLciEiIa&;)*+zu|~NKdY?YfG*lvde;os9-@bIu?TWnrl5eTWDj9(bUixvutv+ zsa#{T-Y^}G4LH%*%p>rXJ}%&6a3&D@bO7u=E0H%gRwx*otE}YI8^W=DG-cJ?A_ehRA_9r>^?T#7HfU-?SM~q8=FY3U`6Dv)h%75j}T63lN-%a zC>)<48kq?X{83HYp@WT2*t&9w^dR>qqL*hMCgE9ekDJoVLPEw;!?=&Z>`}S%^|HTZ zUoGwx`p3%b%LdR3*rLCr>`QL(Z;BD9m~2xzH87SqaTlTk5rko%qF%(GvhvOQ=E|!K zQn^U!qW13YAAI!D>!nS)+*Z?F}6qz3~?Ubk!|haXkojEWrzdGe7ty$ zRnKl%p$#T>LT$S#@{hoGCb5cX0Yt5w1@>J%$>1@Un5Xe!@3#HqHj#smf6#ZC_^>Qu zJ$A2bW5*3vBgR>?`=5h*$kNeW`^CtUM7y}~+HEF`_PaHyuPl7DH^E|mtaU$4wqn2B zEx$|eXYzDa6Y_MTXgf1>>VfR?+|kRX^9@UX0HH6FebiMTdhwdi{? zJtFu1-d}gM;`0Nh{5cavc>d#8^IDq@2b9TF3-io^e3>RmH*z@hQ+n}oo*Cz+BUIsO zK239~+jqEv6)u+H)OGXEv-G^P($Z(^d5eFZqv!Yh^ISc@>YwN9`JeuIp`MrNIkR{? z?B7$3uf{_(gzd`x_}qu-9q%#FMcSiU0L>GRk;qm|~wT4m`>ZU&a24(vs{-T#)A zKVBZf+Tr7_9pEDhl=k?T+k>_Zt2BIUZD-SDwPx&JqO zh;zD||65m_-FkBN_ah;w&HfE{xhYHVc{6rt&i?az@Ta9!eqc}BQGUVs$oDxmA%(Pg zMy}zR$MhJ>EK{FgmgW&=cGd$`NF zDsCGWL6UC{$x)I;2&sg+uiowFW{W&iiTRemJW>w_shDWj=eXAASQzFQ9pn&2`y8Wu z4h^YIYTCyVjM=#yC-@v|!yNkrIYj*)Mv>34KFlGboM4D2e2z~=M5%;`!fJUw$gwb& z<5{1>g*hG#a)_5aj7NM95tG6Ab&#Vz$iWu+v5$TUp@l6q zd{Wcj7B{~q@=S)zLP*1lxC(~H%%CPiUZdlzw9h%{B-)DWco(WhyM-7hPQ`!tyD za{sJhb3gUZ8X$L`f7VdAD*r5`yP^JB$a4eyvrz30*K_6ue1YJ-nWX5Sk!PCB(Yju$i|ykl7Hc#MnuizE z@)JqQx0~Hf4J&V}{F?@rwv}Y`a5M)uh?XPNxMqmR_J1L3+wmqs1W7)&2S+AImkBSWB{yxgov> z*zT{ri5K|hrwtq%4zWx|MOx>ZgHh%#Wo+&5PQUh`0&NFJlEWau zu_k@O#^>=vYFBo+v6Yuc*2mrPBPUS#K)s?^skZF&@%cfJbXgl7oU<7W1?uldZa3=5 z{NY&{N$yK(4DX@7P=Jw*5dRZp{mrTLUhSO4n;eW-bsJeT_L1aR5^?Hq*MzzLVYxoB zT!t~_`j-%cEUXE0$(2lgxPoP2 zt>zEhj|X#kw7>b7;JI5|IononhVpBaxu?`~roth6c8vGq$;K;w2v0Vkuysz24~Iee zs1m_{Yq+x)&}%Rbvm_4PP!N<#2%waRM)@TKgGQ(ENA%x)H;E6aTivn~`D6O-b~o35 z7uG>#e##tL+PiCgwo5_3-;`v z=@ePrK*Hp3WJoK*E$)kx_pqttV}2zDDpOlS3}aNvqkmn_l)l4*Td)>z^hi+QFB50; zMvI>=k1hU^{hE{)qPul~;QD;@#Gz_|` z%#7bVvAkPlq-t|?#W$U5CcLkKjFgMAOm-YaC(N?vE>OU82|7Cxv&lAk-4m<7VV`_W zwkK7%Nrf_J<8Li$&g^%uP)~R&7vGz>l^M^DkPBR#FO^W&qe%baL(5+ zgVNrXVsg7GO#r#?8;=?kSsRc8&uhc*CBksp6kU@bSj>1|Fw=(dI%ZEla*^cEX{!gl zV6GoQhS?Y@1bfW|q1^WC!C=0#7>g@_DNF>+5M^szO{q?sW*TiBSnA#%r{c@UT);W7 zNb*mRaJ4MA+DtqAM=fCJ!TuWk5A0H#%1nJQ`a7a4S{Z%Ry;j%r6a}SZdTm?|5k!)& zw*m2#P^(b)Hs#55^R=ghc`Lu6%R@@B4;Ktn72DkoC`NK))`8K2MG1Ot2299ljmtn` z*+U|+aICg+k6Wj&CyLpVXNy{x9LBe!MjREV z`Bebm0{qYGZ20P|*4*t|(^suoKr5{^{{dr5NAO3jdFxZPCVM$O_v`t#PFml8e<934 zyME(Fdbp214BS5ex8+a9Uv98Zzfti>2dp!^ zCq5n|`%|D$t~m6-z>qcdT)1Z=C*Ndz7$%B9pCQoz6SJBK4_Bl_!qok>2B%{ zrMTEB-owon7?8L(^QRyB3c&8bA5u8hmlmnhxY;#m$;?=`t!KUuUhKcZvuP(Eo>uPv zE4&?#{X$bT#U+0q()Z~bck zzx|oO{I}K*@)nEGN9()0z5g%YF(=NUs_ez=g?RnPzYh%F{pwJif-tXUCD=f2h*PVm z36Upn>;TIS=^T$uIc`XY_|*y5aY%UbK11_s*ZV=2pq0)$l3i8t_wK_G z0M7*aHjCxt<(AU&vB?MCHHl+JeKUN&!he6(-r@Ip;zg+sZvH%)mR{gn*zB&lz9S+r zz69P^l4+oUzjU~8;0j#7U!@LmQ#ILQ=}Da6+2R&lp*y1%D@hwxi7gGTfvdW!%XeHo zp}OCWYTP(+dn(_mt2f;db-D(OLzZjYU_F*^yr!0ul?4Uk3*sZr%nUq{kFkDh7AhfD zz9tqKvDKY$wVGE~CbWd6h_-V*6kwito?AqCav$iIe74Pm+uR4(^|u6Cd-S60{%qq0 z^BtjXieiID7uEHO5!H+(dtvsgeWH2mS&&!IPT!njw*Tyc?fU`4EURuiXPUVE0ioW? zapvy3`P;fNT!}IkwZiXAw5PXVMHa;>uN%`U*<4%$4q~E=z z!f&MCL*_RX>Gx>q9D9Gjh6;)G@JzM>?4|!Qk*wGrI*YB4%*%6 zz}wbXORq}euhJXH^|2d8((F^_%FWVt{jr@nE8FyDp|zb*TW2hFDPFnP zbB-<17~{PI##1Y^HTL4ChtGI8@@DGG>ePb`mX?^$PvYMlniC6o&_7AKy;-~8c5+Ab zU&|(Fcs94jyOG`x##IM%VW*f}@H1M+`AH;I(|hz&LEC%$ZLZYTPn|pnWisL1!`J%u zhP&rz`r8gdZvHno#jKK=vLT%R3E(^coR%jogA~%Hx55lDpMlML-DJ>mM;=FVpA7e$ zC4UJ1_ubcT0#v2GS=InnB-t@!jC5Ze(}sQdHn+!qgD|4AEvwzu2mJudRZ{xA!iiOp zE1uPE}6aK_Fn-(os0i1f;cJeLBhVB++&D5P7*NUz43`qnc&$9{~0V~5>1NEKqR zAhDo1F^V@8L(|ega`}SZ_}84M51!)Ot9Zv`UbG^(Z>N4;9vg;>YR05N1>45uAo_3P z^3?+xmu>DG9MSk?Tv(+yoxx}KZNL2s#sV-jh)m@Eq6O+e#qv)(CqC%Vl4wJJaR~2W z4-fRW;!xJ|Xde0}&ISxl!(iHybERrVf#A$<*U z+$TN1-CXPZY0$`%%f*>(x`*cP@78B^sZyI?^Xl{P+v@8O)W;P^;f%WUVOTwP4N#MP zsjqi4nsq5yrsAsvw`<(JJn?mBf@Z0TJ=TxCkY?q}(>8mF?ap?S`z?ek3Yt_OB898) zxYZ7&K4*3^Pn$|nLJmJGSjB>$mqTQnWAE`*vGm|r=9&_B4o*=Bt;d^(m532z>5+(k zO%aB`!LGv&`+lcF=&%EJO<8q%LQ!@4Xe4*tn5y!R>$*l6;<~yR+uVhmWukb8VTBW8 zkt^0tj9mH5#K>jbnYfdy+F$+$iBp$<7Aabb@*U}URuT8ys0U-|du~>S0%?C$dU$^#oVKO~t-#5Rt>ADESmO1IiC(*GPP-4!y?#D5JMBpG-{*ck( z!Vvg6#*-G$l|ah;lDR=EMen%*F&I0v@o4T=3SGMSuVB>*iFU&_KgRXF#VZD*iKNEi zgSx9&*J(h4{gm{q2HG5G-APiX@|tiRxNT<2$x^!gZ7GzM41ykPh@%;>mJ)0b=$8hT#)J)TL#BIKwlveI3Gv4m2{%$9p6a{nUp zo-}ezZv}?K9&>$xy(!>u4{BxmB)4B}`6mSVcWNgx)1%(!fBQu8EB->uoVNUorWy4? zQBH&o<{qk|_Cxq{WN_1!$Q2rTx8Nw)sw7e zLULG~_An0vrV!Mo1MfEezX*Z-*aJH)0Cow$TK*Qc9|FxGtKe%PYqhpH2GyiXITx~- zm^i1_u^w#8wD>C_KGKMWiHPPB9qs;kWY6bQ*v#Ufnb#AMjT15P&Q+<)t-TBBXmI#4 zr+0PjfI3tew)f%RS?6yZ;5*;Mq@4ZMOpKaO@|v>QkNL%UX^CB(xF2(b8iJdxE;G#6 zBYrO=pBdH@_4OPX)N`)txjU@K?Hj;2+RJepB%RC?pNsaD|Mn}EM9;Z^c$a}3f{f{Pi|y$G9O zS)D?4EII}(hlAyC_gfBa@H?Qjsg`_hX9?P1u+q8cUd>cS{a;+#5sAcRjpCsr7Bt(n zO?7Sj8Wt^v=rzom#&n{|;%x*UiM;MQZ}H#d9}!Kw-_gfQ*9DL6$HZii$eS)~rH9+S z^nFSz?HF=;{1}PZCsVA%`F(q)i1}SRt9(00^~9$it?Qt}fdL*OjTaagzjT{=pRe_d zytF-iTJi+aSWQhk*brx`JbOq&+-w*i`;3ijh#Ga_olj*N@LMa|o6}AS%(f>76(xSv zg>UIy+LYJ^(}RnU9Ty_475^nrV*{L2M4sH{Uf8N8Y^ys{=!JXoFxiyHVf1UK>!d9p#_K!VC^Wyp}ub@kB(?+f0cGJWjs#kHUhO3(9)zn1lym3wy-VX(Mb9ZS8!Ndpd`69RT!{6w9L#(^^HCjP({ z%1Nz}Vu>5*Lvl&blHKH6SOi_Qx4ZvPU+nx`vBp&tV{u9x-MUc*Dc&TPr8y+KIkR)@ zdmaY_TJA!htU|f14+ZWtGE{NEuYufRod|X$-|cK?6I&I~PMheiB|F(jDj}qx3b`e+ zlBolADK>(-D-ioBlvI|6nOg95NS`%O(Khdap3)=B&^K@Jx}`9m)$I-*f4N5QyoX9S zX;7pF^}QJI={o)&r9)jy=BUo>4$s6o>YgJfiPbl4Yg9408bUb%LMQrmbpRj+BIN}&p*cJ-&^^ID8DCu%kSwc z`$vNyx(RoaIdfl~KC+6nN$+q~)TX93eFbDw#`<{Je?Q8{J$=icitZn%IX(!s=EWGA zM49X z+1-Y8jWo)*5wO+1Bw0U@%Q-gOai`k(M1z`3+0!gzFDRp~t&>qR z;K0F5%t6z%zaMg;_}B6UY#7y`XiT1m@}jU4tmyU0Ja)t-In;LoI-Ovsflk9dj#Cpt z_MArejjA^GTxyLx^Gi=|I&_xf4kqi6J%4zIvFFw!8QZ>uTg+;SfDrKbSDQV99!|1f z;2F8}vbMGHn;-`K>25cO_X*;&TY>ly%74Dzrpa9S1O8m-^IxI-_bPu=TYk@v*vQO~ zQX$PM@}#L$bBpTsOfR7@20~1@V~1t-5s##b>1{a$J_M7cKXRO*}pcq9Rx_Ws3wwIL9gD&%IgBUS~Im;Gk zES@I)Y>OK*wF7Pj=%`Ref2duf7hC3my#%nx%#9GXjw#}hjhftpR%BNjtvB$wjozDH z4C(A)Pri?pdOCak6H44+CE!!L_76N7eZByIroV>euJYxk1m*sqa%01CIr&gUN+2KV ze$vK`Cy?y95&2q>J&e~_`j=zexEtu7iM(@{bSTK)Dr|=NmAx9i(HQIYxoG4`pDFdsa@TSFM~TfHh(` z@@2UmU6@~)!>9Ae)}X~}xDdm)v6YSxhBd-kV27fY_m28Gos@a>Fxrq&i#p`m64Kj1 zq_(Yr&chHS#QepoXHircB#cuyk1#4l!9Vp8>SYWtQ>omGN875D4E?P|@`e#J%2*Y0h2 zPweO%X`IHu+jsVTXFg8w?z(}P7^kFb$`p}ftF`((1UtLNsT=F*Rm<2mdxO#G>~4V^ zJz$p6$_t0uI@NuR5X+VTzAeA4_kS1W&)#bJ?+^0-gZzuZV{5hrBGs4;VxZK)%@9f3 z*fd@YOnpAUf41A*sxnVo=oz=_i*8m%SG^fQ+cGk>rD+w_LeOzv=}}bb#!zF+&0dd< z$$t;QR2WA-&F$Bt1_`*72I71BB)A5WW|dhciEBx%9%*meK#0VZRRW4Sb=m zx6{1gc5t>i+ZVH2i19yTT*+b1`j%R0eOr1nX3%=W+5 zkobkK$K9^13o%2{n-Y^{PqvrJxU#g#_NE;nm`gmEk^szE0;8+a*&zfB$hwl3)Quva ztgcEIWq$B!w*tE(0)LFu`qYd5j>5#+jxvw`%M4s4M9O+e#;wFVg^`|JBf~jxc18(6 z*#17FOuwnuo6qR4hs3)Tk)CH1rPi--T~lWaWS=&Y>;q+|yH)9IV^`ULuuLTk=H!P+@gMW0FIYfEJ zsNfY)j{M)B>gSo61l;|8fB!Ep%{)&(eNWL>IbN>0&-?=SkMoX=xY3F| zj-ihDcM>(or^b5jsd6j$Ea}cF;s7aS#v=qt`6n$Nk<*^l`^=zqt-`xj+|3b zi%SGII2J`tj;${woDz2M+Ve=_%I(<=M+k0f=M29c<+gT^XOS)ymX*DP2p8&%w#v1j zv07s5TUCbo%?3+I%&}vTD$B{x1H>RPdUD0T*B=#5#&_BxnCe^waj{uZYq0!Tq-C9mpVFrSx(5_708 zn9RHh5S+yGWHo}sd5NeVIH+sGIw4DMb?OF`vM~|?C80zg2&^JC#+gn-@ov2KXk-OJ zNttSUEb=1E6vU}8lH^|MeX5dUvgElh+1FIWuFzVFbqchxNNcH2yjfpyI6gK@8IeD` zxJHK2WJUCLYndIWP8F$tt6e(?gtt{2TRHV;R8S0(0iwz|

    b(8Jw^K)-YNWS|qF! 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⋙TVtC4Q8h1|oxE6%!(ZPOU&!`NxU| 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 z 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

    d}Eu^?fsggeKNbG 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≶&dvQhPij!6*MXfIA`6)_P=;k^vsQ>b1l80u8O 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%0DJ{Szf4mVqU=cq>@vcdQT*~AI_)XDd>FQ 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

    pdrD}hY{k^!no%2DKwVB=D--)ep9!je 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®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�@&h?!gJklGU1>HI>w- zv<-uP2`8z(KUDe2iq(F}RzH1Vu{}*;((b}i9ve%x@KkP3`kb(*=Xk2Jr)PPp;mI#i zTAe*@=BeJEp61E3d{lK|6HnfUPMOXnK1t9a6Qq4rGn%U`-r0!eLeJA{M=27lM%==P zY|fdGO}v`_*O&4yv0Rw+s{v#rY$(r_dfgX zF<}sb=pX$(2*39k5$jtTrnkI|fZn0rIwNYleYKi*+3xzCYwt{r+B?7Y&SDLFXAVs~ zvWP_eO7ZGUNNHIu_o}yFnA(1qm>QP3I^FVxZZ$+@Jcrs53k8=gzy!G4v8r^@B4x(t zGPWc0ZF(Q>^J;e~K*m{_u2EhEt6+BewVc@;M!suzc@@y?5}SwcD%QHsvW~2i@T%dx z_BrkYpv+zBMD2503DT)YkfbQ&429d8bE;$!pA>jQNBPoPS8Jcwb!Z8!19Tmeh+0}( zWebN@C?R_2qfoMa^%QRovacCywm@SgPgouAT(b|mGLnZ*2oAjZmgKwSx-D6DMvNBt zE((XN*@hAor_c}BHmqWGwuRqkgx_oIGBErc!}=(ty(Elmgj$i>%0&zYftUX#P+>&s71sT_EZDP{&vhOAg(tQMC& zE7r)HT;M!6n%G@3Vw=dIvB-_04B7*RP{yrLshq9hc$dek9l!oh4yD{3$JR*gcd@7U zvV9zP(orZ6OUxGJ!FfuPxSuEY z{x0i2hr;L=c97%}L&BQeQzo8;EB(rv;Lq3%FN*TF)6J< zuTsdZ%Y)+`&rDDY5ds+2k40OFAk$P(zlgx$`P-vhwS3^{SMiGlCJ+ zOyllM%hXYsu~cry8Yoq!dA$BL>W+#ZV`mni`isfEp4{d9_$58my+^6sil-m*(D6d_ zG-Ss!^F;k#m{amA@}g7=?GI{zL<=ZWGGsTv>8U5axEK2qsZ9RcXhyL8MDAmg9x!AM zAw81mTiQT=L;ByG?&4cA{R4^m#`Goz!(UW&IGy3?dLm7?dKLHPD_7hk$&QT zxJ9WDsw3NBQKyK~C_U9xKX*k)w_F$*a1GF|gy;^soo95b?~Z6G`6`sQ%g9tzOJrPM z9mPHl)!0`^+EFVP+Pzw?45C(x6a_VoEO#Z6+G#05D>ZzJcEv45!XjF(Wc+WUU2bHG zkbB(UhsgaD4Q$luL)Xc_G>e1tpWO;bWCzQ6gXUSeOOVeb=9Dyo&t+j1@s8m7V>BHC zvFlo8_WLa)pM+9rQM@z$7d+#4)iV^5N_TeM!A-=dPkZN~JbFmj1Hx(gzy}aa7AML~ zoJD?J?@UfF%Gn$}9HeYcx|Tm9SxUcxe|oR1nTzEoGwXBjhcSYo`(d z?)@7QgV|w9vr?**a;Z}0tdV>leNnU9R~PKgj#H-|d*F`j%G(jYYANx+%n|o)zS9Kl z^k9g17*{$L-a>!Jgz*JI+XHYgP^UDr{S(JmaAkwa5mN7 z^S`OygcT>TaLuR5d(AaY5BB@T6nW;JyUD>v?uA?_Lr_o>!8SfNcDmtEi-D)SQ*B3>rIMjCX7jvnYo27!M+=uUGBMp41Pt8&RP>nUZ!&qulBV`J;;2eS(xX-k)OBm!Oz^^#Sd9$ zS{_v%FYDANd!OmvH3IgoHt>B>^giFcO9Ea#Kbg6pKAHJOqG8Y4Sj(rAnbZ5(k|bu;t*ZfdQV)xg?dzJGu0-DYl~uvo2jLs6pTg3!SHTAqRtaU^Fyh_jWhT@kwI+HQ zeZ-3eBHVt(B)XY^e-7oJIl?)?x9P;P?-R8rqT36f5Q| zp_1zGlPG0Qu@h{Bl{l@|u}(-?D$*1T*5z_@A$+{!?L%D~nvAM2n;p<)pNuSm(4eyQ zbBqLcrpQXI=h0mpP88_XhR?!{*_O(xh6|>Gpk~o(eX#T;hxNgh{QMFk=BoQ72fKu{ zob-fTrbnimQk^&i86uX#`UrkpDG{JeC{dM?`O|$u%_oNy+O-PdGWmY68JvH!jKx<) z;Y9!pPP2FJm|9_hzu*&k2TcK)HB+rZ@|K6}cbN-vX*mK{LT}MAo!xyB)4`Aru z{$gyws`%ZHqR10|Nr0{{SE^SM#P8lkPQ4JanHv8CTjiDe1$}c_`Up!s)0lb&h=f+2 zvH2TTlqS2MFXoOE6a$&(!$ck2jX|n(Ain3$Jv-z;y4Rg2&|!^Q6}JCF_{I zpg4_JN|5l_lVSk7R0q$S*dZdz0n1f8@k^Q5==Mr_BYQyiJZl*K~Y*@ldg83i9_Uf5t(V=F*@9fAO)bfkwDg^hG?RT<==7!@YYpri`#`B~Fz{rnqbxsm}=0A1v}$Xi#nt8Q~u6@o*5) zz&41yZq#uL$<(8aj!*~M0A?R$f4RXFg)o?q5{P?LP|2EQM-D$&R%S&p(hq6O^cs#E zAQ?LQo?1uN2fY$vdOM13z*(K3EknF|sr~W0v0eNUt{El!_G0!J>Bk1$EJfZmc2+M= z#&&AK?_r-*YJ{s)c^VZ^LJZb-58T65!ytqmg@pVAufD8{^gvaV!M z?)cR8W``)rdgFLiBdES;M7LVkhv>Nxf(AO|+0|+Q6*r#?j|czwWi#Uk zo_)jCvtYC+wSC`yOux$%sCaPT>w6RF zxK?8mUn!RG>F%H4Wv+|G?pcm~8~k&Fj9s*;?9^SmDcRX&zDc}e8*c;C-V`ud)9qc% z;$xT0{u1hS67`Q&uQ`p%LmibG-01_ik7TpK-rd&WCmyH6hvYgu;lK|6Ze(21z?Z4n zjP-%DtS?l5KkQ}z>#^YnK55C=G^6c_%RU;~69c~Ty<>u( znRxZ}+3dXu05;gB1}}ySGV#YZX0wDjC&qu|elNJm{r;44O22?Y7|bptEyKqPI+n$- zPu8$W72FPdhcOPyTt|04Mn|`R;DHK4jMzZI$m@oI4f^m$eRwO1J<6D=&)FrQxNhLf zG{3+nXt)3Y5M36Xdh#4EwVNnf07`;}zcBl{^8_q%1uva3G0QxF*>m)5_EEK)@yV1s z)mJd@$GTqGJkm{GdKR(p;b5v2XnCCXgp9_#C|5 zmd&PCcXqXOYGxYyM{3qirwD$xK=c&dv9QDxs^%5@$pLkqX}7=-`(uv|*Y8fYpJ%}- z+urYUpo1v907T)A#5{yW27#Qmp-mVVXpUv?#-u7BweQ7fK<{o z5ojZ+4Lx=rxB+qP7&50Q+>O~qZdFo)M;=WOsy@pa4R$!f!4cnNaN(93t73aF@!Pz2 zz9LyZBi`{#^Pv{Fofizfa%r+s>Po{~Z|}VkgWh|PB=6;46;(x%z+wSa3%^Z2^Pzly$1RcXs zuY@(th;+|03Z9$vOfPE8D_)F#&{)lJiOCH&Mz+9R9gF~MAsE0q=#lo5V@tdGbv?a z$%#zc0qEAgGK#itR$sO96}E^bBiXTLl|>m<%5hSuv6~h|Q%v>MD}jRZDPSA1-Re)R zX%`>qsMhGvbjQ|gdEb`b`6hS~bVP%LwI~nkuBaVj`Ce;mqk{V8N-oWpjCfOw2Q{jH zqlJNEOJWyT8QR3Q!e;Jsg1Ogfc5*kkakiqhkrNk+S|*d3+=!074ZTe$8rC++%JB4< zxIK|IJI?=)B&>*~JglIVUoFI?7e1vC+$OD=-L)of=GWRiuMK{ZtBk>MAH+6%~(mI^^NyL21ym zrd1>61gq2<&2gDm(YR2mI&hfmBbGoz4kl5<(#ouXqiYN?;4A@x>(U2>o}!V%coBL> zjoZ3eQk6ubh|vW1GKhq2;~lSKq=|W^8wl2Y+Hb_CD;&ou2s6Yvg2~jIPKwH_W_|LT zUTQ+6i^1Tpy;>DYm@o#z@giM_7J@D>M==;)U&Ns+B|wAFtsxEr=aXTeJS?i1OqG;m zDPb4_Hx$?yd0!T#NtmzKPr3zlaLN_KP6-Zf@yq7ZN|FU8vm{TBuQU%m{)bgcGAXPd zleWmfyvJznx(fy2G~YpJXPS414@TjB42kVtdh3`n890Q{4(-xE;`dO@x>#>(vPZ+0(bEfd_Up* z^ve=UIKZ>=UdGXQ9zOy*IJn4_Yf-uX<;wl7 z%3bQpT}e%~T@RG1!cvv{73G2tyFw?c(5EOg`2Fa7(Y(k;=?;8>wS)!6yv`5LOe}f% z<3+1;`BNiaXSStysQu<5=7M6YM`f=^%4b{tlJj@6*`av1WoZv$nAeBiFcBE_MfVOW z@Ra%Z*MD(Gc3|sYmW-WG(EK|tpjO+z({L_R@a8|Xst{{oii3rNTteQtIo@%Oal^%O z6t@Q3S8C>bYw+DJ`%R|S1?@a))0Be1T7#BszrMIA-l6qt_yfVYL%`wGRDJHUw7qWR zGbg=*-xI9)ApTkE`6%s8r7b1ROCwGhU^`i73y?SzC^&LFoQf+ctQRp)Mt`rrcfIRq z=I3{0A1DS@!L}oragzMhL6~GYWjS3ax_OT9nAGksjvP%1WN_#NHxuza3(~1XW=3-| z%_2!Wne@!k;ItNVm#!sdJb1YC>!a#5X=B2qI2a1C(n??DGnL-&=FLij^X1UZStGPg zO^pkz8Ub?p7{-gQsXA}~k;~eTb@r=xpL_Lo9 z8JUHNg#AuRoR#qt^h{G3=;9qGO%Hl=yG!=Xu*fp z1l0SP`8K~avH39JFT~Icjff|#p(5CSW3zugPC@3ryI9bLX|%3=5f8K%-2HmdUVyjn z;HsiK+w{1ueI)ns_syhK^Xc|xmWTP7Taijxc0-V=oi0zaqrfAP{rO(z_eK1$Yog&i zFVkMH?5Pdf|I$Uh{Z{(Edc_RR_cFg00H&81Q(DLDh2j}a!6m;|OV)t6bU(2COnVnU zf|p)oRouFW`J#q%sjH0#;5O_1d_jtQT#ad6a5#`;$u$ccEo>GEXYNbz!(4X5IYMTA zlMILYhRz^Q6#47ks2xpW4EJAQ)&RUeroL>*efve2d6OEa(`p;|3oYs|`v$l%? zx{~>pu&jT=?%9ueb5@Ify%R33^x~b>>KEid{6_QI83q3`6My~{^`4Ozxy;Z+6Jesn zH7?v!+!4lzn9@=B$3r?0I;y=Yn|a}nC-U20_NJ!4j->f?@b`bAiQL&o zP}>7LJ`T{WsRx6fzfXy+)eI!k!^zDZ7ZImCG5C1VB@GuhT+;BlhR+YY?*sdyxF-`C znUg-q*Wd~(8}HaaU*q4qlmGfByx{gMFqbd&up@ZzFsG|KuI6(xeP}X0g*}?%lj+lu z!KbqH=X9j_sr=i93>kmJF%6mX-(ecI+>`J8B=TZ>@Nc_6Mq{_Nzcaq&1Z_1fs@=oX z^rg&uaou}n(g5qqgBYkTQ>db-eWdu>!`k~tYB#1fwXdR*<4-tY)wR3Rj9sp(UTz1T>Kd*eqE?6`!``P9vZ%@ldM-%79vmpqfa*h3I2Ss(IZdsF9N z#q8zNDn6A8(z%u7=;erp6j_0!tHJSQnWcC`arqSgT84Udsv2Jmt?bNHmwlytqJ zuK|6arI|&+4-em$b#YS$G!+zRq>%0yq82JZfbXb%B{;3jhNnLM!v_Z+HNC{K)&pNP zS+FDMIdork@OLiW&G~M$_VS1C%vwXC9`90)3!CtDU?nr>K3Ei7`A>TxrH1%|wFAc@ z14glPebKwp=ZvZ88=%im1V4FCjy|(5M)WyxQjR`njH1u$UMi%|ufBgYeSVIw!TR^A zEcD5uf*Vg)$FE!|r761nNNGryckod}narG4?6KIlgJ5pa?uPi+4vCkI*Y9bi@v>7( z2S1j_U%cZ|^5k$h&VdpR2hQe$!j?LT@!d47r*H!M#_eq zIuo9je0+=)tBb{d3J`aO2!vInYfn$&w3T-lqGu>4sqGzn1^BsmG63Bsto2A7xV%BO{m zWNQk30Ys}vSyNlAk2GtmtR<>s21X674}L>Fw^l;g!lqd+)DH`!l&dM2ORn^(Q=qBu zy{TF1Cp;1Fc!wh3o%JZ=`C-oiG-g~J5$GfF zJR{E-#mEtT?FgzSz@N{!_u<~K)f!QZFEh1bJA=hP5m&}LF9vsG8kpkKfNklMeV0DO zCPevR3NKRkhJoEYptqE(7S)^sFfj?b~Am zI}s!y-w^VUlpC04fa)>Hs6bMzNxxLmlo(*9E$eE865IF2S`Oz8%E8!e-#fmg;a=Ft zan8VgjGkQ9TrM7}l)Z-REc|tOYLrqpu+GdRnlSjZ?AdpfM>&1@o{@-=%Gx%)`2p4bRvZ#dfDfc>;zM?Z)>enfs$=}IaIO}P_m-I|CExQP?!J&HPUS;+de#KL`k|>P&Elz;WmEj>RbKU8zZ#y|prFGloi&5%^vpm{fMEfS8+%Y#5RcwH2m0lulg;&dcd!Knwc}@ zVwO6aXpHSYJ9GS5{5vff+usO?>b1%0S1(V-zq&IEC z&zbDU20TGy@$+MX#){SbwCi>Jm~WktIsVG@IpuzAi;mH)ek^R(_OMxN01Ch>`F9~a zf!W}xpF7i6O(EVUV1$O=q3T!8$XtC1k-kAc*5_CE`qe#tbr+_dvJl-FQ6C?5&BEA_ z+?j|Oq6WE9cu@A8mogAtwkVD|%>)i*F zL#p@LALgu)XAvv&y+U~dk)=bKLxg~;|Aaiq*(ZBrIeBo*vynXb()gS_7;T>{Buic% zJcga+@Fc03Iq3$z2Gv$J-VsCl-*~p{lWSMvznFcJK~|VNcr+&uLi^-Hp{+35J~5La zffh*&);K#(rg)mdROoEI3mr(43*RV^3rrkgd}j}lT)1E_jurwlXMBG=2<5^d$OSd- zKP4A1y~m5+D@h{bV{fKsReIG= zrmiAL`wj(>hg*=1^a@##I<+!At13iPr3car3d6_O<1Wn@E1Qge@nIg0Y^3U2+upO7Sn0A#EgBYVau(d?Ospx;KD zMk3|i?3wBNkSC!%!`97M*bx~h}h8HAQDvIpHJy4lrLY!w=a}0`vDNF-*3q3xB_Os z@yq6$-^9?aWO1;`7|9=#F~^UUF{hItiSlkT#-t5L$(>pQ0_!ml>qq-XTSQxt+%h8t5tOP8_@h$JQ_nCUHiETWgx8;4zY+SlAnf4!}y_5dfK2p+h z>^;InbvIsB_cqi%PAr?+2Uzm73AbXLg%gP4*?A`rHEfOlaIxH)omP^!b8*(>H`Ph3 z>m-p`uYHpLJW)a_@ooI0r>!L3)vS#r6zJ!nkMvn@d@^1QES{`HFCPbW+zVUaIE5ac zgfDM?(wlQ>eb#U`YePxAn(D~*2-zwtA;X2WZ&9MMfJbQ7`i^ii&f z))(Pi&mV@5pL65|v@g{}?msh0-c59dYgIG^v6E89n6uJ_5bNDM=?ePn#R^GD!=0wgvmu~dm2 z&r&fd)0I-*J~AQR@sLYtR!X9MWMaHyxl5U$l&bcTL*gC3a49pDQqw+iXuM;AOKDX~ z9RVu#cv#Ah+N@S0tpiuPEY`$a%LWKmW|u?$YTCeAWXZ25Boz6Ne=M9&%1pds%=-yr z-b=>3Km9~Oc_xVVd#QccCZ~`s$m}&?R6;dB8_Z@eT5a@n(joeGjeTqRfJ=G;D8c7k z_V<(hPWFIaw0b^IC9mo!wCh~vo0PeBRQYq1^uc`jCx{Qb@>ei#n=4=2bK5J_2z$uH0a@5qD=lD!k5%z7Avvsqfc5ATf z&b`^-SI~;q@-yf4y|=9QXVQtq9Ee4#&3$lp!_FkLkg8F1K0>9b2jTnRvBip9WP?3F zgVoyC6p!Hw^h0n_9(;`he;nXndO4dN{Hf*#(+}JQ*q~AnY(A~!IHunQE-`YhFA9#$ zmmeCj=1r#j$6sT?=EdZxeP!?_*|EXl`FuV3d>>${bl`Y{z4fQ^5A?^zJ#*5> z67*&k{bcjmxY(pzZxZx|<^XqaNz|Wcd^#4{_%Jk5ot>WrRfA7x{5tnEoX>_ZdS(R2 zMzMx-i+j&IXSVvM{$FB?2_DAGqSx5wQ9s#ovMadcEC2pZ4hP?(5f{)+ksFzkeiAY9T@ubsnyA)44y?pijhV!`JhC_?o z#WB>vY|(k=aNP+KeYZdU{2Kr8&((3)2zDzmAXbiW#)fn(hxHRr+@A2`i?=3-2zWZMSs2yUK!!PgMugKFfM$4d%^ta;ivP?>9V- zp>q1OJfn+g^2{i`FVG?B@?YRgV~4IFq064h6<9R!CiI}ZZ!6jYmJ82=I#^6=wbyW% z?q(686+-$#Z7H&g`YSlpae6`a_rY4FE@I+_tqi!MFLZ!s=DJGn*v)haJ8Wsr2$vgW zHVbVmZe(_(Ye3|1pvyz8tE$yQ*VQ_2rO@)vON~=NHE2**Mn%s{QSzMBh*BK8nNayM znM03K;yRZ1<&i}q?$gxusSp?LmE}*crO2zTt^dt#c|)=Krob^J|d4l#U%^%Y8oVA1a#y9r+d z^$QQ{@_DH>N--c5EK|RO4)ggErIn9@ea?HQ7$^<|=uR|Jj028wgW%rQ zn+U%pMec>EwSXdr5DFcTi|h*PdpE+N1V=4Hu1?^>LGEU5haJ|6@<_U72PLMdyN0uS z7NmgTkg`tzmZUSmm6!d00>YO=vA$Ys`2e(}frjt$b@c#L3zY80y%4m6uyIHYI#b1K z1=oNIhV#rx4GBNh1z6!gNN-;D+FAor>)HebB4R)k1sBN(;w2cSb3g_J-M6dt%N?ST zLBL5H)#|h*tOu0CklRbDC>omDt{Y=8C}g$~Z0W{DNy(rF`bKgEx{#>`I%$qzW^y~} zMvw!YmVoita~bf!xX2lFGPv>(s*pCWMeQ))6nR0W?J;mnD3F@>;C&@D7r=tDMIPmN z<}&;M*7ZNH5~Ab&pYN%vA-YS$)#24@U(47`*Bo>sgMKt-0tt#kYfPMUT_=oareOcatZOQV}V_2N6{~OfcdXlimYp zNwz-JYEDyL(`Frps9_8v_UfQ6mY()j>&zhwt1N^~QCM!ucZ_e4Fn4~LolJBo=zWH^ z`-5*YN38RXz34p}SHjh4e%;$t`=?*5)g=)i!>@YV%XQO}+6hOENYmO!MUD6=+U~eQ z7&RVaZ}lUt#*-A2d;f>Mx;MN!#`rai(pUXUhFv@S>2LW>><4>iw$Cbey6(wzW-wj# zN|2qw*1cr9ZjgcN4~|x+>*&ov+kzQ~O(E>c+{H^(OS*0&cXlA3O{N=0ugabKVO=Oz z_nJSrKN-|LsjjS>Ac${Diry*(U#=Gx2SP2q``aqxh}RTh0*z1#qH1aa9oQ#BAVOU)1-S^1Y9( zAl+Guoc|yCZSQ0K%9!|0e*MjT=x-;&v)?W++jMD{sPy_%1q9Z+B7F##K$Emg4XT$b zkMTpg0gqIZz^lkFrDliL5O^+LVNZEy-4VZT2tRAD8_a<86DpLGUy>(s=cud>Ti%pP zbRZ5pq_BS@EDkt90G5>SN0yGgYWu^HmrSp@SblME(jy#M5I*k0lJeK7MpDLEEL>w@ zi|#COG3X1kk2v{vHS+IWXB!+9XW`FzA7=_6|9%V53i9tdf|xvahZlU;>23dw)dDD~ z{uHIb?1AA+%S|Aros0fd3fW#pk>vf{)CXRIDC84|zuR899oO1jNv4p7zo08J8xDRy zmambu|F#rf(?z9l!zFqT)rTv`tnHm%W}j_SlTxtE^s>Ygyb@1=C+@oT(_-}D|L;iOV{(>@7tCNz;|ZmdK#K+gUosJ;%7 zP3%d}T=9AKlzNl#w(6Ww0+HY?4y%jwzA zBB^HFFGmnCc?K8vxBP}*2AP&>fBHMnZ;CcER-|W{Qpm^~0$9dtBwh3MvA-Jh9qpe? z%l;E-MYYo;eN;@(e$S2}UlgFt9IS`;xc1b{L3x9b;9&%d!=Z?#I}Xxi?iwOjuUTG1qcL z8x%RAMdu4lNrjJE#*0%btlHS|og9re#Na{q5l9LL%J5$a(zXbC^MD}uht~yx+ZLe{ zUsPV?Hvbtba}nG@tO|Wp;(%<5iCf)nBVO)xo0rU;M|NivW0@b#u){fU!vv9PwH+wq z+X!{mX-OxGbtWybLLNflkUV zG8NROJ)k|Rk+RygiE^1fz)+V8qQGvR+8oB_A9ZffuueNw*Xotto6vJQ8pv=!o^h4R zF&vS~OvzTrxK{xdC~KL0B0C>fb?`9O`*iiL{$^>FUIB`c#(pZLg_n2|wn+`gW@nWG zrHeja%+(gl&d|;Rj*tFr{$7rrOU4J;7FO)5RWu&r);r1l`p@1(9dl1YcM}( z*^%vXA|Z8>DkDo?uhIh8G^N}bW^TDn{RtLcFXy0#D#JhE+XxXF-5*XjGKU3DhIU#e zWj2CtC>XNT)`E#wBYNf(Egd1#%rs#{dnA0sgnRa=3n`sNQj?O^t&Zyv@-ejFy*XN; z?vf?YV0^wv+R>%O>SOr)bk=O=(j?sv!=^bTsKlzRL<#W!#%*akj@%5ZrZ3cq* zwQ1bdDnK51LBOskjtMZ!GOQ~%sXbmsXEpO-SkcXbF@UB*Zj%?t^tZh7`HWWPgEYtU z-0BWW*Y+f_1_D;uwpCu(i%m$(W(bHkL2(ND)yzt(QhA!}SG>ocb}gT)qk~Oc$FXn% zT}30RqP3beg<5ag)sU4NKk?up9gCpX)_WDLNsX9MVR72k5Ynk*LJKpbYbITz_zhF& z)y+!eXx)7XaVg{RdMj z_PF1GY&hvZCUHQ_#(SVlLJ%hm_|q}!%~HvE0)m>aA{@Zpbm!8L0y0)8`r(^#8H6H1 zgEZx2!#r7sm9plm$PtUQnbKY2h7K%v>eFnHYG6E|KkxRZGlssHjOYXq$WaWyf9r0>ArZDH~11B{93(6 z3du*$l2-nJkTPLRc@y>jr8C1tNTSQpJz@(jzgrUDVQMU&PzWD`wdN5WYwH)%Mm z!Oul_kju9a(9cuo&fB-UzfO!`NZ&{m4CFm9g8S{xD!X?}5gBc4(kRsN>$;%Dv5VDq zHI-0a0gjQPSK6H{e(%P--~0S*+tEv6zxVMxtHmk5_u1KA?|M3Cd2}E9N_W$4?{l*; za%d|F%;Fs^*I0$~VrGa=utn7eC9JTbwqr%u4J^libYF$vaMXtabk-cwh3rucc-t-z z&F$rubZ`2z!OZhhy6CVn-LNq|owJY-0km@k(Uw&Z|G^eesZAgOCw1#W3FY?uhi20m z!gerirMu4>KzbrTmg#vq1lm6g5yF!=6-MM|#E^spl5jjl@#OSvU=s{&KE5x2(eBqA zL~ezes7w+960BFjrS7Vm*`dQLfZ_ql1i`XQ(SuzEEF0YYwJi*F$skyyaOD#%cN6J9 zP-p~#UV(?QQqLGldegUiGZ8Ap#Opl}1XI%|;DdFYfkFBvW9<2U5}>01M)><;DV#FQec>L77?`k0wGSKB>f zFgX1neVIAwo>40DA8JvcRlPD5TGhh(G>7n4m|?KS&TCV9=x$=}d*L`^+3j z!|H1Ii?^j@ku*EEBz`a|RK;slk(c##Cc=|st9Ht!G}NSP>ScAL+?wOjjgRE-Qs!uNjgncNGSe5_`?C zv)r6wuZhCUUXwe2sW5$t>E;O!qgAQdX0zAylvg()`%M+M*T1X1CbH6;Vy}^rCNdSC zX0O4*RbsEv`X_ForhGiYY*D5|kkxQ6x6<*DNb3;e)Fi}ADcz&Z80P(M21Cjht%gs( z%n*@3&5`i@eT6CZd!`O(cGT4jdCCa?2MJAr+8zGD@*uQGUkG#i3)%j{vT0^Urhw+D zFwx*N1`Ftj0>r{CpeqUxySIRzC_uy<&MLyz{Ys&dcVba)cX(bg!F9z1zi4TD82{*AK3HPwk?1MT));!ZbYa_r<=Gm%=anW$UwOv7!e1BNFgi0euX(#+mY zxTfz8dy?N^A-_GzZ_iVuKIdN}c|f%o^|^{f(W)yh+ny0@C{qR-br}q#6Aa-i+$9%L z`X7R@NSOSIgvtM4Gf!_G8&wlauVuQCY@opcq>ohFb29wAszpCByc9@Kl3jR>K@^kV z++x@Lm;Vny2_JpJ;k)2|1>wSdzdgBSM(M!n8hbiTO%iwBzL%RORS=IEe8p9 zonQswFwK4PDA}F#*+eq^c{xoy<(vP23>v$&=iT|GOeS?x{dC+>&@$hQlq$+ayVWm` zs7(87v^wk8VUl?Z%l1PS)k1GHaJejUn=SaVB*+SzSM{WvP23_>smICkR1euC=r7}0 z6nh&6+3bOo+`tkw%S0@ru`-LV!*;JCkcfty4{U1Mh!fqke2JR57W^45P&B!9MTR4G z-O$Qodr2XaPnYB})Q@gEKS+kYygn=KGqQhV#zh`0D9S<+Dx*}ja=SnzuVvlYmX#&U zyYg7jC(1N#aEY|56>JLbB)qV`Z2laNQ-HW#v!vAFVLcjCxM!r1Dg64l;qwQF6&%C=Pv^jBiF z;!P_6c55=gCW1oBUkxriuv9$i0np=RWv(Pgj9?hFRxrbnCk}pS3^bGziQY1^1|1El zMQswki)%z?uY4LviU6aBpzsK$nw^n;vNhIEu#y&*mt?eLNd(x?6?g04lbH*oI^$L` z;$5gCgy@q_jsBqgEsjcKVAxPKA0#ti0Bz_~#C|;#i1@$sok7ILM-$bJn?r4d~k@2)+6pV5d|ziWMo6HGT=Dv)E!e5uSc4k zb|k#rO0%LK+)bVt+Q8i<0sv*D8mQ8^YN`VbPzpv=3qNRp-tW#yhV!b0;qO@B za@Sl3>U+-w^?4KV1ZpLj%x>ai8I8~s;B3UeaBxTPZg^hpHF)1!g!h}2a|*l|W28Yd zIzcFKMnJz9E>(W8IWBC*z;;>SDZt*a^9;N?c~rnoiGkHbqvjfbR^u12xGto8T>dX&ma^~E-MfNdARF2LAtU)Frk%8|0}%M{~$r_P*%zh zmr7G86tz42j-@umW~a5XnDi5;CH+h>=}%5e`p2gvJrd3~*dl8&H2KG;z*Kh{Os`3T zE`h1MSkYytRkZQ6q|ZI8#v1q+o|g0nrzAZR{#Z$=Whlba4=iguPI5+%#m3)oTJF!0 z8d>6E#$%)zuS)e$5@D<*>9#b9AChyVrq~To_FQeMmMrI8e22e(N~N_?rNb1Y&Iu8A z&NP2Gc|^x`$gjzhf?|kA&ka-3T%!88^b$L zP!&oaJtT_mecZDp{NjGcH{=YWsuv$xK?}Srjw?*)GDY+Wg4``|cEmxoK@Nys?oLhU zdvy@(h$`Y|?$}OaCkcQpG2^$3iq^^S;`4Iu3|PfaSVm<Z+FR{$edw^>)^}B#K@c| z(SrqJ91n*gsq$&2UDo;WcGmRI{H)@%GO+~*D;aB<_)jGLhU4k!Tg*$=i4J8gqCFP( zSZ&BNl_efLIvbe<-`~hlt^v>35!NUJT#*Lfn(b8$O7@a1(5*xE<{_JH7#D|hDWQNx z*x4v}@wvz&(H!F&IPq-S2e)RwRgjs5DH8BmaBCR%3R17~OTOS@`{Mv_q6UsBm98y# zHWvj@i7c5fGR++J>JVa)L)n};!GtH5uQ0zA{K3{)l-L*kR3D2U7x9+Z6wUwSwNmHW z#fQWh@QlVIgbDX**e;Hxk%#p2YLdK{Z>rRQ)2l{-{9YxFLhu%V1bY*s3=~B2DRQez z(HI3ZBSk7fOZ4qo4uoEoiZJw=Z3|@K6sv;pBgLyqhF?jv*!?9JyLA^m@t?ub8TW=k zoS#9q{GX9o6G;B5L6|ha1DoU?|64GZipy(7uaZ}0?OA#%uar6Oz6s1V#pkf*&3Z!i6&m*(GhIDDu zzR!A`1XVoDeZ~snKqH<=xD~Uwz@mcGG%%{<5<}U5gndZBfsO&5a)en9ATdk9 zXuFvl#$s$dGTK~<7Mpj-<7qO9$m z`t>aA(vXK9aHY%FrE3_WP&p)ym+7lb*zF6YpJptmUN7SD2V%##Aw$-rC+{I8;J65?Y>&D zv2bP!n{vu$fWd&V$n0dAVK)$~R$5`Bq}Lg$B-BD+Dy5aSa@ZD&VXpDsg-&HK1V?@V zu<{3Ey<1qHh$;ghbC+_OC7X#hTV1F5rPYR`jerXVq}hfk^9wtS2#X-k2cJZA1T+mWQhfSDIKc)0xM zC>nkZw-SxkF%N788=_UWO~#o)0u~f;mH{LE)F+G#=n0Tz<$5l6iY_d!S@pF;z{X?Q z)n&&L=A!^ZtRWkA1jy;kOYD|l#}|%7P>;l*8blu`$(STVlMNNejoX=_QCd%&7fA^*?? zslKA!lJs&)aSQKrC9w_41WCW4t3uCxP>Pd&WdL>eTiZ4oI+ii$q(Kw=*wQ4Mjbr)! zh(PMq_1$0Oe*S(4@MxCx039#glQa{Y!$?IXdPsE*ARle6g)pXF!V zk1IY5bYOfVxOpCoKc~$OoIw4k!}lFbCGU7fL6Yc6D{MReUl|bwuz1Y@Vq~2LM4{K* zrWA2x49)O$NoDMF)Z8F8kGv$YW0_yrHY16tjx$1r)iwAAn!EK-y8JCpM>XfboopqP z{5N3ZcV21@``j2Sa~UV>E@Q`8WYv}YYmOT9;&$79m=`s!&JJ{WeX2G-AvBR8#Hlbg!>pxY0%=G*eVH7tc#fOoZ*a1w3^-q=d%#9eBc>-8E&2xKCf-V> zAp)iv4QRD0+ARi#t*OE@VA+;Dz+wRbsNtC)UW%DIOmoN~8Bnw5rX0(4dZr-niv)~3 z>HtYdUW}`b<6MN;t5!Sawiqk~0*i<05_K81!>jNvfm#evIu01>*U-_Tipe%&Nuo%U zmm}&sxBHSMmfPFhZo|yi+O2rofEMq?lhna(N(5#4%31w`%-jyBuoJUJvV;>SxmT^0ArcDGYDJ%EUyLw7Gy;SKrt{`!N5B6{7ym zL44$`L-U;UekGSpK$gs|aQb?&q5a_(w&=-uH8>)lr9{lMqOSJvI*XyR&}%XC5LOw^ zdK~uX?1yWg;+0%$tjLqtqAVhu4U1+@V<4a_sRD*6K(WwaMZs6J zJg=y6qSW|CAwdVD*06rEJi5087bNxF5_erm_R?e&>sjJ!>Z8~;m$xyBZFjNFUJe&o ztu?wbWQq~sol&w*z5y!9|4ubtpgPl4q9MNW(oOURx`53KSm?e*=0fXTti&>KgSBv> z(4WH-Kvmjl5bCeS@cmD!6OS;3O~8?l@qr_m61nvWxm>!fEM=AS|1@qJPyuW8r5phg zQjh92%}}X>3-LZD1V$?tF?o?`C9hLYaHXPynfP3iB)AZtOFhxYtXQhrb)}o!_gHt zD1}ys(FnstC-JN9H8_%8a_kZQ9*d^nu15tzLNK^Sfe z8DORT3ng&_@K0=fo&=~cpcv6hmor~w*3!osOtBVks>tci+QTPP-RflIIAhDwTyivcR(eB50h zqWe)qqQSZUCK?>f;nR;eBKd=j>I9i7&N(;b&44PzzS`N@>764_%^5Np)D3#aBzVeU zqEEdAFBj=~b=&1XtbroGVH+4#BZ;NkeiOBuo`9*ei7m9#-K?=G^ggfs_4L; zQQ!_sVg&wKdxfwOPdSf7%|=0wN^(*iwl>vHq{Mb70N ztXYEPHiT{T_CO9caK+Tr$!&nE1wPdx3y55B5)ICwgM?1sGU^~90dArZ4^idfAxV4Q zZ;mYD?JazV{ixcu?shEvj=jdMx(8`mGCyrU9DZVxhCUN0?WJs>AulhEuknHliVIm~ ztcnr^^Qgg2OYP}s!yp1g!>6HZcX+~RHNNuqezzR}tnwqJY&$AJp6+6=kIbm0xxs*vP$ZW__^00OihY=|DYJDtNa{XE#FW*V>R;U#oDYDBP>P$mRmTqJG8J>-nH+5SShyihMkv zG4g>*=z|_&MJ<}(^*R%=rU;OHv_T2nD=M@3j54bYEyF5Sq@yw&#;i>BkCuC2Y%Pk# zaOG}j(vTF89?x*N|sBR5C{RHPy^)&@q)t7z>>|ZF8VK zA#|R;jzN0Hw)Th&r8n^Ou|<%v%Q7-}6;$(#%IH>Jh?oxBq?*g@dm%K*WurR21xi(} znrCggfdPD8VRC&&wt{UrB#x6W3b!zx1gAk+a1 zf1Yh7Z-}joSd_9l4<5_n7zVLzs>H1tGz?)dP&2LI={qqnVJlF3RbnvxrC_Gh1h85L z7rF%zZFy--H*CP7z^%vW=})=sB6p^m&6Fu{){r^PRO(z))(SXSe3I^vP?+Z%yR49+ z;i@1JQ#!Mmb1c*oZji5ZE`&AP{RS8p%QjeC_9acPbuuwlkWESDHcHnVZf0Q3v!j&f zWpAhFFsF)pX;7r=hJ!jTft&~N!y=k>bOY!R3sF~u+P$x>O>YgmLRUQ8!l_l#G!Uela04L}|j zfXuhxz<4JsuvJf`>s|=3%T?{BpjusEQco^37z9;&(ySKF`pfE|>Y!~CdNP>xx!PdH z`Ka^+JQK`72$H!v-NZ@(PHbjLt_)_)O{SYTZsV^ju#{DL2JgaRv zT})r&MTUS`a~p-TWgcO3rqgWk7-^bl7O;hkVBii~Xj(~YV?X4#n9fhh00Jbx#isK6JO(lgK zn$WL-3H$?k^1a3&i>%PmkTmmLqs)0WRYeUiv>MZ2v`-#mpH8vz7^0&phw&*I<^+?V z?x~;-H&sayja2Oyc2(&T%&Og*m)EEt;OA@g)Lf&z&vHdbn>S@pzRfT0Gt&|!3kikZ zoz7Y*lQ7gxh0)5tA*NYaTtT4mIo8<3+%SQ0D=EFn#5%}916p0N)z38UfIFlg=T!_^ z@eohIHu0X-{}~+5gtbdAv&4$Xg3w6GEmTk8=oA({x)mg^$VefxD!z zHo?=rR;%^%%#%7b0HPSBDiMXDEGCMG1k^Gk8oos|m~3Sw1f1$%)(3;Cw>*X$u60L( zSzoCPs#t11niku{hX|>%(wp@e#@f+z-HCM5Gg@An^=H-TCI;n+VAdyUU5wv!)Nf)F z;3jX@SCY1^&#Y^xp(e?|2qr0}S;f}9$*Px!)9I|QG*S~=i(FE1vMvqFy4}Y3+}e@$ zA|6XOZA^1E4ga$5^_o}(UqT*03h;JbqvFh9O&8MwwmT_vmhjE7U51Pbk9 zM3+~xlpbV1QSHsRKhhNZ)Om!=~O6%~L|GXI=tMw?li$Ji3jiYL- zgKx(2R1bk5EU3anYA9S6kbjv%XR+H9eil@*0<_-y@tEb*L$K-@ zDDiog&Xp7Qogr0|>OIc?Vbr&IO*=^g$5?>o33y^1-C`YugtL@t7SV}@`PH2L2C{F! zoOVMp(eRhdI_&KwIpAS-;4c$tqT#dEiH0xIA2Wi?XF)c1ac90-ucXUJ8n9W94SE5` zBL$i3Yw?Vs2}J8q7q_Es1*72<3n=3;z^=!9*eReXDzZ>AbE$U883r_-GpFPoTaO;d z`8HZq=#o{;X@Ey0%r?T$P$*Vo{hd!Q8?ta;~ObrO;e!#u=V# zELCI;q6cIH3O~16a=FY12O*@h+Fp-hcff-qci>G}QjAU~V%}g7K<^-8DH7AHX1PKsC6RW8e3c;76 z1Q@1NYvc2pFV`A8k@U>$sCh}Vr3g#2rIRA=kJRReog@g9c`M?Gnj{RJVY>r3(WHPg zDTaY1+7*x;1`Bxq1GNkxG15_<+}t^bVLeCP2?G@uOnhfa>Q+P70vlRdlT_WV-yT2+*v+BrOyA9DxpxR7|InZ_}B*g zI&)pECM8Db;2bx1QeSY6GXkh45j*x`4zN(p5tV9A@|x}c-SW{zU7^3a{85!ykR8xv zRZVEsh!x8$|L<0V?)dLjGk#h%c~vvJsbDX zn;Qx2Z2(0DV3E7?)g)ANc(7q9p z?1_+M;cSxN8QwH7If)dj5h`I(b?AWm&DbBoTx0;S5F1BcOk+jU$ySbc>$cliYS{2V-c2G zl6fwfGsBj$NGaqUO3|ql8t8p`0>lah@bh{dvq=h)Pyve_x6swo5!14Cmn<Ze0FODmTnF~D^wt_UR=dKAL1v@J@| z;sT=q_MFJa2Ddp@keRpX1WH$CX4qKL3+D8B~F%t-XWs%9Pc59D3 z*FZjmqIvOmA!cfwK^*eFJk?M6yl9&j!uMg>ltx|9EjrN=+>uujbe}5&q>(({JWhTW zEV{@%ZAY`Y0Q4}55u{xN$l~73Q+i(Bo=%OnwF>)YKC>sHJadTYxAt6Vx@kBY6--p3 z!l-|hfyE0FzY9U+cQ0;LSe`#g160-V;uLbZ0LgEHMaZ}ySFO_+tU%Sz3;sU_0Hczx zB?gA*(=~&owCK#s_i+s7LLJD6`vxseG%QMW2ybeBG#Yy+E=qj!TT{!*dLA|rsVuRi zm#@tF-qEw2SVhYuLk*s&XvJww`a0m{xG@>LjZ=`fBJr~+@0pYM(P-|{_wn)Vb^1;` zx{XuG6q@*UKJjRt6Pc>k<+yaYklKZp=c|Tu*G$p1xWt@)0Xg3`Z-W{gT zXVUkoSTsNGZ9U*s;c0qF?_MT-&KatE-m5z4Wxvd^LcC4z#z{uc`}T(S0&k@La?)bo z;SKvgVR~z{FwmvivtPylM*)!roBeW2^l7kVzwAYy6KYHL%We9cado>gShK34X7&zt zAPH0_mVSgOurR=u{1~qYW6~xR90qUTM-@x1!rdQh0p>HLDkU-wEnLVOjja7S}r^rhLc;<#$XMXX0B>#i~>K@7EpB;tqaI5FZ5o|1UF zc$yEF<4F?3`UpyALWx%^c*W6FqE5dhWM$r-7-j5<=*v?uI6mh%97?+ggNNo}9-`CF zlxtdW6#H~|KRbHGidC5yqH2P7(0Y~ydFQ1tWqy}qRmAqm zK)uA^hiL5g7Tx|vfeuKfAs2mb`uyv$v+t7J{AaTV`Q(^vVb#ilKo7 ztcvKs@d5&zjat*JaCCpv^B9;_U{d9D7@{Kl^w=}9MAGwPpLj#|5hqYdJW&ryJQ2N9 z;35+n0N#DxsROQWuhx=xJ2)YM)8!KlpM&_F7)GE~|FtA<^Q;*QBs6#y;)+r$6)E#Cpmlc#E|FAG}Iq`J2MTY^yqsyNNSJU;%KMpj? z-xz%h%`uSoT*k=b4le<)j_3ntcjzViD6eY6nmDHpDdEUgr%ljU;+QLgS5dO}TQwWfOFKBAi(%2DI)J z;B&^u5YD1?i7F=%dA*wea9xMjJBg{Lo|!rEv-{0dqoZ;PHkpDIM))vAnKt$wF4uHu zq^Ax3kq4qJGvUf0iafS6-7qYxWeZ<+gNxi4o-_X!zmD6f^2#=BAiL~%yQCXNie?!} z>?6b%GQY^)qPng4&lC+UsR}LpX}jA6EReFVq(Vup)Ukpf2<9C3 z=HXs*j!TEJNbwWOLe}w;tPxCrgWilUgd{HL0HK}M>R3?*dYRC`&~QYBfE#@`T6vs1 z5q(?dlRg=JTkrE-AAMIx>D!`j>sR92qi-Wp#=?NX=eAO){*EZ#5p!fusrhbE5ZAh` zb)kT?#CSp2lWB`*Vu^26n=~!aoMy2N$&?**9L%3iYS)lgqY&J+@?WpLE37@n!|7CM z-9ay#3c2E@_b}d6I`gDP9_3o2GEDnQ<}iZ1=pg7+0@o_%ngb|g?XyB8u??t@%skeZ z`O__j2fPoF1U%l_y$q}JBwwLKi#LcZ`^;wEC1{;AV$r2dlXQBX*s=e09OIK?hl@|V zO~|5)nx0rI*0lJTCgeyQ=_iTR)naA$ z2;7E(;AEOLYk4k_lLaL;4HKXWM(xQaCVQ?fh?KGHD2Y-+&IrXuqAh)LhLE#;b5Xzr zj9){>agt0yz(Hp>2%Ja*Sx_$p-Fv!hv)p7GVxUBl#KN=?A+jK1RV3aZ>?9gcK(tLW zsrB{_wY%TYgED2$Rc^IaGR{s8kS2Fv9fxEg%F)2Js`^RI%R+S+j25Zza(wOC=Ck_xR$e6USU}>Uv33IAVd;^~kd(mU^PApL2K;i-$|7@09(7IIt}~R2e~~>TJ>?jrf^y zF=MZuj3I5|eKWZ~idvK~{O|{gA7a#c;u0@Lw04=ZuN4p_`8ka$2I)VzoywLT|8e^=>&o9xM-^Dx8n9{2B|Em#Z4_S_;;^4 zwTiXTr#0fTxQgEqQiYeaj#0oNmSYi_X{~d2hj*+-71sz}PtQ^yu}l9@SDGCQw{YRKR>oUc8GrD*mGsyHJ(Yldr`-PbJ-9+4{}_dI zDCBzz`Hn&sKQ8J<9VyYi!kKMn!F&GePnNHoeDrLR%Ji4}tq=XTA5q)>@B>%dEo&8J zl?Vy$*07!PxHT+p_Pez4av7TbC>~#4mgO7TXdQkL%~ywt9JCtyD!0W@_blpuAW7Xu z1KLuXq4S~g**`oRy4w3d9dQKvnGKIRRSvl({5>MmOJ5ZMaVaz9YbZ5xRdW?r3{IZa znt3*H&mJ-sU|q5;vGo5TAXzTMBWW!dV~WA?o&5@vAL<6FXz;4V2G zN9RFU`}|8bB$jMb<7lmSdG`IGUfQnAro!~nmlI1K!3EM=`f6gy{qltbt$)*feDb4W ztanxG^GjdVC2@%*Kd~ZWNzBnHU8v4&_p)u(;U^iKO85&~g98gPohjDcEjPGtDn}WF z^-w>lmc1&pu^l>Z;G_Rj)q-!aQJ50$rUdO=77#eo<3~RkwnTAPTj|^|!W7k_c-)y% zQQYOk`JXn?O%8FQIje$XLGI%6bnf#V@*jL-Dbfdf2y&11PEZz46AI2b7G;y&`{6BfkWvZjA){u-GM)-F>8&OD0O)Y8TwekcF%dOT64mFTjB66Lwj`?GMHvSrYN#Y?jf?7!>JsPEugEgLF%W$Y zyOc4@9OYBcg;5Sa`we5C1Wl9_GS2(eATN3KpTXVneWJr#%pqJ|kA446I!SJu;mtbx zgSVt6Sa}$}(dz;#MROq^(axY36rS1X<^HK3(1P6G_Xxt=Cpuc++`wt7S8D$oPwaU|~p@q6|x zMXilLBZ}~{AG1RPhf2cRcqiNr4IC*67ex>bQQAbRNY( zl@oUCkVZES>_|qE4_lH}OMZHM|f@ReFw9|eDwuPuZIFz4;O)y&%xxV7yptM5_gxQfO#05MVend7D^NQ5uTo`^DW&mH24k+}0=OlB=h;Ex~RMP$VdT1WD3{%7## zHJ%$lO!OS)8D8^6$tldtj*q_2vRRg}{*EY0jBbJy2 z<{-}62%}>$SRjM2^Ban#Bn7q*7+$LoK6)(0;qWp`Q4lw6qph>L zSU-^pnH`y*7X^rl!++_C#J<;P<|)#orByv~W`>Z3wUy?-EzbYXmj9Nb$Y^N=S~33t z3+pS*|3R03(e05u80utqHcG_uAQUV98-9kfbD)H=yWd2P>682=!VRxUOA=ftMPS3& z@3VLk$#Gz@g<04pV3-}-*lZ47b@%bfu`k&gOAp!0!u6LSHsyZn7Z-D{>VK~kqW6bS zfBX#T>dq_9l2kG_h1v^}3j~nJmJomm$misk9@p^zW2=Y2HMrCEw;_Y*f|Kq%lXhfD{3(?!dXXaXSU!6sBzZ5lh6clg)ZK*JsyZo%Ov07?2S#a!#HHYdS zVPx4vriSTy-e)Za&fp}ScvyaPaWpK)7QXH59sOj8xlDMagW|6QMH(o^z5!Ene1$P8 z^;yZi+;7as*D1*T#+8`pg51<&cTP@5^=#r4_$k`xnVVYvwaLjg=EL6z@%q-Y>&HCX zq%qjU&4}p;Kk}Y(*xKWb#+ty0+A(&1&Cpr!i3k+H=10&q}$&(TVm+k;Y z$#7*n{p=kkCVuE1iHWz@$*zdnK=L`6i4wJ;pg$MbVD=7Xz9Zq=a0aea-b6u3?Q7^! zlTlksc`S64*ftgAD)SZ^U3AO7WfAD7ZTO-(OWQGbo@bhI!C3RE96p zMaH94_+J67xH-}WTafpK*ZoT&a({TaB6El;ipeeJW9hC%P4EYam}H{Noi=V{mg=x@ zj0HH%gk^U|9P1F!YF`i(qrDH>Pq8~Z`p*>Qb{+4haaOhMuGkSr90{KipQP>c(=vt$b z_nCxqbUN6hpT2*gJ+YRA-?Z2Dri<<(kB|IOS(aGxH1FcaH(nvDio5&#AqzWdlmV*e ze1v<>pZ>Cna@0ato5CJaSXL?vTOgr6B`B+ zDnVEH>TT%di~#H$gMhWDWi2fzyJxX*=}Wr7J;aq6o_C`S*Cm@N!-qvPJL4%p3%zVt zb+`nA<16q{KC+QJ@! z#VxvESLVi~y0khXaFdE@Bt{>N`WTO5>Mai+piEmREd`@|A#P2d0d7_N()o! zR89}@vS8m%1h_J{s3CsG_^!)UHSgST54nmxNcl@LGj8 zmxL#I_p|gN;a*9&(Be9fi1v~Q31y0~8ahiN+M)=nqPrxbgLjX;)T&}xNqCnFr)Oh* zXs#(WeF`V-ia2d{Zc(XeRLnpj#`Zhf^uWALXm})6EO&=XZU?E54*iBbg^y_0+bz7d z+8s%vRt{5@%E8vtL)xO+f-ILL+=>3y6V3bLb=6y$pIJXBh? z-zvDTA1S8!IPUuMyVT zSXE*16OEP+&rCluJG4d1B6p^|@D7Sm32CGOng|;gC_mM?u4<54G7rqP7h0ONL9IbZI|#Wxt=hmJxWYb-tgwBbm-!Iodieox3dWFW#7^d*+9~ z+-MLagG*k&o&8_y#df_*Oj^%1zvDe*=mQ{wu-HhPUE659s7)degeim zW4a-uR+D^o>XJWTjVJe^uj!FFi-6Cfvv|3$7}0r|yC<~Rz$q^c6A%`{0kc!IBiTCJA>`Yq<`!sFZ=oWAp3O; zxC=ORHFxoaBK`5Jau-*5ner=gQ>g7~?*Doz$h~j2m%#!>!$QJp?Wokp*&Jw>8;t5$ zX+_yhS~scWAoJ;ZW;T~XXO`v`eW2{rWQ`mnO0wocGP2qE)FV0{-QI)DO)bTOKh1>; zItn$ec3&ZNlv5y(rR}O*YPQa})}gkaZs+(?%b`oabSe!uYUo0+{q{~>cED=6rO`Wi zu4aJ!d8dv&)e)zsIX)3Kd$x-|C^)gUt6tIR@6y z896BNThb&+W$GO3ds+;B-aGb+PAJZVH*iWZg?X8O?k8F60x$ExfL?BB{iK&!EXgZi z0A{|mmN);{{?;1_&GSys5D$cQ&QIk4WP~=62%=%@ylWU?5W;)xIRBdvYd9?b_q@#6 z&R}_6rQ54BqHs9RD96Gxd+HXu0I!>4H&?2a+*(7EwW;+woD8pKVxPm&zb;1~IUv0o zYw=nU@1mC$q{f9ax=biGo4ujv7LIvWXN*&rPV9F@*TzLBDH_#qPHG@3dJRQ0-`~jk zk`=u|MfW@C9Jz7?@JMNqwN@m+Sr5JJD&Qb#2Rlmp)k#&bHmU$r+?1q(=BR>+AR~Vd zyTcFYSLh&Hm9NSM4CsY+D!sl{h2q1~`f0*V_1d8X*wRR|9A0hstB+x5QT;Rb`kxh(n?>Of?D^tm>QuH>5oG1XtO$m!!)oqHeaCxETc`SmyVp>v-I?_o>yrc1k|pj>~d zf)772W)feCeNBLR1VfQC8e`QI*nsQDr2!7d7K+|Ypi|#C)&%<+?%xx0B(t51QHKTYwhZ zPx2okh>bJ5!@r@4=yBnrm9z_dpR(khxM&W-!>1GlvQVf0R0htyNGa0Wb5s56b(1JV z5zT+Ev~!pR7N>heY~ccWA+zD&_hb7@)2j#nwiI41oOqkgR#zozK3>WHTK?A;>^1Yf z%p2-c&Jm)Yn!~pj*jn+@dxc`W1q{{L2wwiITSLBI;hQd1aM|mLuLr5$^vs%rWT)>r zsrT{s{FI&l%6R!hcCPG7To9ywD{;Y`)QrRh^HOKC4`mBS+9dvMPU??%U(f&TiJECQ zXD+?itR0D(E2< z;9X2oGB@Sz60{y7u-Ci%hyIZKBJhKc8s6C%^PWV_**q?z(vMf`CCN*YNvzS!e7x}t z`u34JnJn!-wZ(_lP!zVi|DNaRXYbLcXuaCcepf?HUTrJHN%>Qli_+PD6Rl59kgoX09unwI0Q`NX{X|`^bd{v5^b@PMC3Qd>*9r_C zpQOmA$xi-9JR}0WrlazVXuRG{Hs=Gt@CAemR z?Bta;u#BUqG=~PMzI4|3fu!>_;(!C1R4e_8>s$P3U-Z(6)kBT`;24}70zKi^ycQ%@ zzXf;)nN)^gN1XWuJK`j;N_;*NtJWhdY<7oX;H?M{ySQ4yK~TmexqjX203r2aK#+j4 zH5>xZjZW0Dm%Z?tb(IBE1Gf-xlZ~!>-NNmz9O70>qSx3;KjGJnon8Vk?yLqw)p$Xt zr|%FH^#C)tr`}Z$P5}W}DE;*SeZP)7XAY9sUGXC1kd1bY!5w7u6|zejCxopPuJWw7 zr7NyzOHaF|onG3?j#OHHkjG|D+5;?|uBW!q5pnZCn&7JhzDjpHj}QnQsE*A>Il3B5 z#A68DLiKw<;*gHfE1<3fqje)}!lxu=ZLlL})WOk4ZV2HDFAz9XnvzR(*IAcF*L#2j zvRF@p&cRyYwSZDY4qz6|RU@QD=u~S~2ssWu^;A7QRUdUFTklD*HcF6ZF5s9GHMg1k z%|ZG0B8G#S7aek;uAykQe)elAun+S@p0n512o?+IY126!Lk!fu! zwrKSbw+oFW4L2i(o7aRJmAeA;>=1fzUw)uSkGgeOEm%g&A)9sRN(;C~0kn8^2Rvqq zO0RB09JxQbaU!w$WHny%8dHg~Y6fYw9hJI>8JrU>NjMB$oNOkdnJX4JhRtpcK~UrT z2rcj?Ru98;=B4_*!2^v!1*V~CT)r{5uad#Yjbc>yR1rRpqu_L@f-dpJoIqP7_|gYk z>)mZMqH1>xBsY5m4R)C?7X~waP#biI3&}B|`-6LuIx6ik#|n-lI9h>of(tj=L}hS= zQ_!$JnEn(dF?nx~XqkHyqO7=`D+Ip=wJ^rv8LtAtUhHN=ptDenKsklPskO;I3@hfL*S(sf(wio*4QihP z>)#b~8$G+Ri&7HawE4|o;)G#B$MzuqkOM|A00=rTno}!{(Q@vm4*YcIlQ3a%X^Uo2 zt_UN`;GRZ7Oxi{gi3HeIvt0@YlXA^=Fm|$9JHsE-3?s7fVF*D3XYj&tg6R}6TFy4R+S15xuS8RrZN!`72(@_Tw05&wL^`*fBl|Tb1VEGrdtd|eIguP8SYDuo0 zU_NJlk2F0~K0$pScp7GMIgkwOq9|^yfj-q$rUH(l0;+;$Ijumq%3YA|6qn)ZEuDdy zSiPGxFR}019e@}aKyKIeL5WA9ihumh7e-oUAVumv5ux<1Z8o{~2Wz3-2x#{zD?75+U;zIk1?hXeFwWyj9|C zhL(`R@fIUAg7lnXEo~Im+Iy({_Lse!E5{DT-rf2bdJE~n;FMH&{MAC!E;_UJVN$yG zsCKyosJ_uS)M_8+E7m_ED3%^96uKGzg;vfQy8UG>zp1Z|CV?D~7dfdc&U zzbIl+CB^{!uC)a$V&V;dTEzRv>t_Jc7FU@R8s)wqKsw@31Eh;biR-5qFD_R9=Vw;`>-Hl4O;P(fR4^I{?=993`_T*y?z@Hie6fdKIeJEuf9*Pp z$d|tB>YrPz|F0=JYJahQ>-&~s{eMX!)90f6Q;Yd8FXo5uR>sJaAwN7>MDq+QA+CQz zSZseu{vz>xQrRCXW`Fs$0^w$gd7mnVez6$3R-rkzB{^8a?qV@NB&tMxFZ9QUin+f+ zk_aD#!4Q6^Si~oabx!Utv|>&%bgUTqM;1!2ng`2x5oy0gM9ElcP1MYd29nPOW%{hP zXnRe9{S8hv` zZti8TWpH2_#-i}`Jhp1n)Hy4IDR-M9LPcycwH-xRGolWTZy2Y*uMaB0gc#l6$=PVs zz5B}3b#L2J0m=3tppVw;>V;9S{4ELUI{$n16H+Rxj)D@5 zDO}>XuKec2Gusuv_U6QGdoOZ#6sgdlZtu;Bu5E94Rl|w%_6kYQ79t`3IjKA)1n9F> zdxh9hSJthALESov#Flq}qHi0$$m0@83d+BcI4@Kw2mNE){i^NC!{koYSd=-}nlo`W zaE(q-7y8@)TX!I+8*9Pf#`P5579vt2^R9JUNM(OrmAOm{)h0L%4xEUB2DpibGRT>V`GO9NIm^ zPr68*c^ttcNR1i^k9e}0aEy9BQB$EPVIlO&*^ta->2$S1=y^*__;XsK>qkhW>oHSR zOGbkNB+^fKk;?AX;RO6FI5XLE@E!b@Zxtn$6MRKuWZX)=+jwDx^|x(c1lb#r^R#|) z6>2B;sHR~r`=xp>dsSmlwX-Nw22HyWvVy8@oG}!z_xZ6HB|+2k0Xy@nCcLVn3bkLE z$06CIsv0rFEXNe_-E@ra>ycmZi`}>9XP#=E&kevV zxn_RuM(g53A(9oN(3b_RH7S83uc<1x+IIR8SflN8Yv^_17xP+cqn&xmm3Z!YT}cO8 z8`Y-3VX~T>Vb6ODj>Aa_ZA_r!Dw-#@Khkj)ouy;rCEsDyOJc9i`^qCr^F3w#W1?CgyjmKfiVAaF{^(rAZ z<itHc~o#^u1xzD<|$e}uS?go8xFg1fo zj7P<-i*ci3LvjYWDN#0@1LRIFf2e?_^^;c{S-begN`|A?a@+iXhHQg#@}zD$Xj5wL zDv%!z%4h{*B5yjMT63(=0xpR)hB|=5GOBd^L+vC_itkYY5LdVAURIh12mJ>D5I;wE z=4X!p%8)1mtWP<~w8Ea8T14WgLYIZ>Qk<)mZU-UZK(TZs5U|#d0P87ga9>5xFwWc- z;Y*j!>b65+TAl4W-6hue>-2U1a8_-bxg>I8cNkG>!viHKL6_Ku5Tb0|p3V|=D05d1 zJ0y!vdaNqW9I>>Vj<0VD@7Gg>QLr#3ot@x;D7o;a3BcstIGy2#rNx;jd8*&=#FQKr z({Fj`Q=Z{=q^#Gm@PCATxabGaufFD%>F?*@GdNl5H4P_(e=vGB344uToOkDZ%?o?T z2~lsi#Wb#5c;Ml#)tET%m!x6CJ!ul>o#1_gnlsL){HRQ;5Y@XZ$(X^A4#~)IfN<9f za@y4W)xUxUS6Vj3lwK$tuf-Mh=w77#Z6<5 z!t}vGDLcW@QNO`>+K9T((n3DDYE<$xT`8&AhZ$;r30q_-7QJRJeT;u46c&@Op*YH{o5ya4TQm z;a@QXD_k^}|i$>d&fZ@Y1qaOPZ z5mAH=Ard*(D=@nQm#-Wt4;*smce+i#4p4D7oM|xqeI-_H0CJ{GeGKle zFsmrry^J|N?>*S#c*R{(t+<%0LPl11kr~<-G^WLVFjs3Os|)FgYF98QA&K9BWsPgT zxU&a3)^N)_ZwC66HYy87c(0r;RCEpfz|(JdLW_!AURHju8-_SZ)VP^|3j}p>AQ4?w zAj=$_aK$SoSNT$4a3!v%7`IHXGubey6-q7@tXI5-s4|MTV}K^Q(R--pE*g9n=p+@E zOn1VCQfWN8R4t@3tlV{%yP%L%YofB&7E-lYDl1K?+ErFwskA8L&aF_D9T7yGiXSe< zkLZ>7t|-1+@uS7~(Bf&Nbrg+?_NtR=Tu}@sT>m(uOYzh@1txG&KKa{DLKxie; zFdzIoxLmYGIu3I- zv9JP31bE7&vp(a!xWnGAugi8~*#3Et?S^Rtsm_8Pfy&Ge?N8SmIz3Q4SFBUU)uv;9 z)6at@bg-4Fe!@JCSof+}dy#K99v<1Y#@M9H!b0ZU6uP5URhu^XO~{C;l=SpA<#^0G z78{1o?M4{%o7UOOHm~Wpy&Mgy4*0!e<8CDIcYI+(ScOevp8pq61EnU#mx#QA}8rjz%ZBecY*6g?K z%vyB4?-`Q_AAgpvC!s_O9XUY4mT>Y#4qOEQG$%E`w!cxcj15~qF1zV(Jp-}30-Qbs11`2s$)I>yJZgQ zs=gvO<$N84sjtsTS_fY`?lTW&3Hlmlsb@CmbR`j#gd7z`GEP2yW+MqW#Q+*23$m7r zff15a(@`4%UXJMsdRKCoVxr+<&Z~4{gqOk2y80O$gK4Ui03*4{cO>QZ5I19Ju5uFq*9;*t zkWw1QfO1S#MN)p&>Z^BKxnO9H%UC?9XtmJfZpstu_esXOWSEX3Z zC-LN9C#)@Ar$YSR?d1~SB_Np8WHrY%np^J$NzvM2R$I(L?P3n$Wuo2h3-HvnR>jo-GOX>~FL)&^RY_;`_ z8Y1YISy(imO5-41pM{~)kXM+ub3jx++{3U6`h+&&X~@E<*Pg(ma0Xd2d;vK{3wkgy z7Ad%bbTa%t6ywy0@G+BOIKhZ;21IxlQ5ppu5FSawzq5GO_8|S1*sWaR&$UWO|EnS` zi_+7oTcpv?v(>C=>MlXgs;c8xCnX4}BZHVi3yPQ)WtE6Ht_AES4ST}qHDOr2Cd_)! z4M}v9r4S&*8v?l5Di+xvcEW>+>?Wd1CXYmYiT2WGJCqlFwo^}#-w&ciIwHIQL%K_& z&Jm%ku`rk35e$bsSy(j8lowtqpmh+UAwMDxv*|?8({F|&s>zex`V@K_(mQ=Ayg30o z!Vy&u|G(_L4S1bZneUxVTS#WWoeF9gP71qw8L_6dO|6r?H8=KTKm zTF>6Q1&+g9XWr|a>z!VZ{j9a_b+7OHYkk}*Cb!Z|BW}(?&s?WU_*O6I3Fq5f_ljw_ zE|Dnj=EO>K5*0r9u*U0FGY4p}#z1TwPlGtE8qk?j`ehvWCmz-SU%@zfox66=$d-#7 zRg9!CI$=Z?C80#}S1P^%Cxnlu8nB*SSCa>W02_7-(BKGT3Z3Smaz7ha*Ng#$=`;gN zp}Hf4$Y2xE*{w*^TrX3t-~*!9)WJe~jB`N76YBU%i`xpXfv1Rx=(Y2T5xe5%NKE)o z_qsXH+)mJG{(S*muwrJzmze#Jhs!+>=Oh1VRP>1wId`e)zq)3S`tgeB=LADvXpl{J z)7zgh%7+Vk5c)``FH_;mDG&tWt5in+C z7x*+-s=tQGtpV3$4UwDpEN3gv5!yb(L(i%%636rlk<}tF;w1_?0FWr?5Q%OD_{D$7 zOb=gvP&3@ISJR@%=+zFJrjEU84Kxa6?iic$O?+n>?$jy>tR!p~{GOFNrb5(93|P&p zb#eAxuejVXh)>r9pdte<1`J%e8ea&60(P?p-*Tfk*>uk7NG<$I}kgjTrR5K z15OpAjJpG6>(xOuc_>@7E-LU*wq{*a3sK=ScWS{IfBG+y)>v^>#7ns4d{y?9@aek& zkSrtwIuU_>*o+AHy0I*lT>)BaK~s>bg}+oTy92M2PL<&{<6F>;p#S8WutSA1^i$-u zWujus7%%lfNF;LFoHJ^%Yv+z@;g8xv;9I9Y#BF*W{^{j*P7JzsqTk(l-@BM8SNvPhEhkg z8l9XMNn2g27n!wIwFJeU)B}0-fQSrfc_GGRta4Z!!z4l2tdL=4qh@`eG2ZJ$Ik^28 zF;)m8JCC+12({DtiBZBsx6p|IP@gv=ah93VV=n}Cq2szdW~v<2txfeYV#lBorxk0I zTc$3`(pZVGiFR9yNpDw0p-El#i|F64INdeLLRL0kkC~2jREc%F)?%P6Bc+8;g#XO^O}jx$N`Ur#V3!W3puGxZD0{=Gfn3k#1a`Ctdj;giVDo~Be8Ylw3>dv<1bC=V&^hw* zh@fmJfto5pO?#*@A<7z*jV@4SHX4SjT%X`_gJ@805ZUBZlJrrEtTHghPxd=ZW*93J zgE6g^-|$g!Kv;ddM5<1WeIKQ28Flf?4#OpzHJd7_(xT@05^r$p59+Z^By|v6?SLyaYr7$SI6z6k}mk za`MTb;XdM35e}G;VajEA#25Go8Cw!umR09;P)}~ZOpXNomtwyfd5QL%A++~etb((! zdj-`8XzAou{n?-}Qdb*+9mD#QcWEjsq22`Fm~t+tRKofK$a+eyqFM*lM2?^*?XZk} zC?B<>YKz3y@hSS@ta=GJL!`&&eu(&c<8v?P0@4-g1!&io)w%29bE})zrsuauYU;8%*R@c z{wozyof{3p8#-zH!)!0v{bxK;W@nrQMF-JR+228Ob-SyX%Sp?h@3RWs>d6Auc(C65 zE*l37KISqu-;8M7);*2CCOr$n%e$u?%Yg;QR+7t~eHO_non6e!G0Qi}1Bv|5X5rlN z?>ETA4YFMsS*9@r>R^uS|9y_(J^KM?+e=meqWbw~0iilDTib7f`0i z4$V-UO071!$HIGx{}CjXyoA%!S7-6@8uN0Ae6r#HL!X+tOYW1yG=1#QpQp?h34YRG zNx73ZQV05tk)`F`yUG`(8*qse3~bChk$}v{I9CV)33v!~`9%WSu)~ zcIilL5oB|FaKbDS?S8|vJv?T9fUqj1w%@F-h z+ME`pu~c8BH50EZX|PooiF!g&y9_!n=m_dHMXhM}P@{s{X;34jP_HU#pwmO$E2xJI zYOEA$pQ3_3;T{&qJq9vW3No#zrWFENCy>nsA}gG$5j``*+UZqJ2bkzq|`DZl{$ zI@SR2q5$?9K%x|2KLG6<9NJ<1KWPBqXz_I9(-7}w$_oUygu+U-GdZR9%P0fngQI*~oy6%AS(=$45-&wcrPPRUlP_L}N(Ok)kYB!E1GMzLCC-@+ zFZyP3z9;d`w5+CG4wL>u?vqvT_)qQ5Q7c}OzdF#N%!r zeP3V*4N^-TH-MNdxf91rS6gQ)bf5k>X0Rv|zvM+WhM+%_FYssaDKHGd8>gzE7CHI9}b7w)7FIgvVn0(^lsK_Nm*V7GKAS%WrU>BnA+`lDea-05a z5^?8d(ri_0Um7Qip7@JL%+?j+iajJv?4wD;z#SH3#R%@54QPQu2qDY?M)REL*X9Tp z0Wq2S?E=LJlYEuT689)NY0d6vft%s3B=poo8IuG}R?C5q@umNN)}DCtfm4Hc3GOOm!K zDPKq$DoNTBaXyDIUy?MeB#~Q}G!i8tASgxr$fd~Fgw-NGu}v`?si6ge5sQ)xDC?$! zo$|0j-5w@0PDR<87Er?;xc3caY*j`v1DB!9I)f(0cW9d&d6II;dKdpogW{|R5y~TO zhlPsu#+VG!`{H!sckgoovfpZC^J^Oa>M3l$^Xk3u1h)jbg^l}k$@ zxmGumPRl;3-sCVNMn=L?*oOI~Yn@tgTK0FR$rHslq)nKL@w1|eah<6c-_r3K*~mxv zh1p*~r|+Os3k)T@4K7QB*D#(y!+1qBHqtQWe^?>MR3eQ;XS#B@j1sW7I&zyZAWqN_9qYcHZAL``mkp&9#ty^}UHM^P=Z8(q*_&4O0^{lqz%oQP<3Z z!I(>L`I`qpPqV<3~Rko?kjCcm_?p!USS`6Z7w-g_Kyvbu^UYHK5J z#LOvvB5IBr(!JscDc<=Jsc2PpUIQ}LQRV`tV^#pH(uZV6bz8K$2&qhBEp|WBQW||o z*Pz@vYNaI%M;mE@UOt*DvWfAFux^l9pvwhh&g*07OU_%qZLN(;je?@3pu3%`&3fr> zKY*3IZFD6{;5#Bj$6&Qc=1z+xbDx$H_@|e}qy)NSCD~2M+&AVVbD3G$`$XfPJOYzg z`??uC(7uwrTZS)`M5$n{&D_em&>g1(Fxmag5jxt};kber*mIoK3)b!DL^1l^y4UEo z#V-UG;*e^!(_G?9K5`sFc~&PnanFv%H>hzYS#m`>JFO@wRyy!7z;82VI9TTm-a{NG zB#4aHeXs@vuS$ws6AYym4Nu>wY0g0}yvOu9R6aS2U-!i9imkvk3aIf=oe!NZN~^at zuQgg$_*|oOJJ~Af1z2H(at^BC@&l2&_o8#~3!?Jo?9`j6dxO+l#!WRY+>D)B+!_Bz zzgOqG=B;!-4iw39<#oR3{;pm!HfC9>?{TwYs}r!s zhDERMabijQ(CK>!s0Ev1slJzZ{f7lx;vxFp93_d}8m}!dT4S*P$z6-q%D2y5BYiI? zbuZcdV&x(FUKbM{n+iLtZ%5nf{kJN6xwq8ya&M{X<=#@$%e|$dmn+rtq=MZRDRWaW z0!8Ew()S{j?9J4@oYVHClA*@d?KxQY`u*Bpu0;7m*nCT!ZwVI<-c;H9|5m{>@n}2K z!1(4M-6hpsZ212c4R13V-bQJ7sS`IZJr_2G&@=wEe-Ced1FK)W&9VB4YlL%3kJuEn zMGirl!Z^P5MeTiQCE0y$+%Xoea7+`I?*Ff8-iHqQ&#X%KpOetp|0-Auk41Bh@q;yI zai}K66U6___yg^C!T=Yeln)ML$Vy;C+AOeqV(1ii+(t5bXHLaZF;a$@Ll)dK+)Tq7n zthb{Dptqx+QPwu$Y%f47ryv9!<;)ANqx8Ax#WkJw^eq+TvD#+}Z`B5>5#Z$J-C8i^ z?Hy^ppH4FoyVQeOcd3@Malmn8DtfY+lLoxl{4B2*Dc--{jBHOHi6~A~;cN%iD4!>t z9Wl5k?ZqRP|LKCHLmurhTRGUc4#{J1l7NGp&fo#OMgb;7m9C=s7p>_n`}QwhvsD9- z4q-_~*3ufWFtU_8UBOGziXF35cTgsL<_4zS@(r3jC6cS{ua-QPDZ$oelO&hC1)KzC z+o8IcQK<_;^}4;>7$#Tm<0yp#44?kjVnFk$J=}gsOh=eMB&IX`rDA|?F&8hkt&hKl zCbm&e#>QbC!2_$E5B-Eya_u0MFZk45$df*8&+JFD-fVe~VGCL}Qp%CD^2HP2a$O)( zmj1~A6UcX>)PrtsOYJ|!&qIcQ2eGVA0@bm@Fj%9hNHc&ENhZp zVU`*xd*f#y5a>1+ylM*V$)y=nPsu<&2q{(t{i==Y-7~i7u zVvKK5B{3x}I)-4OMHjr2H+0pI1H=|bOTJYmqju@>wNCdq@F8PojXL4VD&^%caIrB7 zVh(PMw&Q$^Z%lnL#t)A)!P3T@@bf0cRNPSGTM`f~X-S%3p(Wp+>svBkc{tg{XjIv( z%4DZ>u1~AS-zwSi2|1|Sq;_9zo?4yPVz<6H%zGf*^~!!GID^!iPi8m7dv^+qg;0st z;Z5AdW5q;F!2dk-d{Bl;0_ji|@(@qX9iOZ=k;B66j zBKj!iE3D>k{(2uLB4)yOJhk6WOSNh#*52|}_A7NWU@wk`6_X%v%h!kupYbtmiut-? z?o*7@mC=w&h>m|R_`-)ctD2j0=czxMSv!e2Sk+@K=iaq-`%jD}w1#b?u|xgO9rY-= z-ntdzC$ae%*L%&f)$&52n{F3~n9wl+_hj{?=EijHBWF`ES9fl%pt61$?XiU-UfCKh ztvSNYvdNqO00>yqS_uTgQk&uq9q%MVjGnepE4njIcz4DJVt6y|mFK5IW#!Gdmk26f zuAX~ZLxUwIVF)M$o2t8v58OZ23pIhKl!m#SmPIe-ig%O!#L$p~WR2eB5e; zD14t!XeJ^3rN^v?DcPB0gfqF87U7TSgH#z?kYeILIciiJB^# zN;b4DL^u~RPOX)))}{2abna$i2d6qlHHqP zd|#!rFRA6S9h9|PTo(Sf4Nh__#c>o7u=20+vR-^H@7Ytk+%W<6?XH=E1j=diLJLG@!{Dvp*hti1jx#?CGJiYqOPTZ3}^ssaneiK#$P9}f3&nnZ;KT-sn&vZ|;dw?Op1 zmi;RW=l=!}Ei2U>vmO0DqW(SJ$9Gwd-Qkf6vp9socdLx5tcA+T}B08cbL`{;=P*VHSmWkCL(i+i=Lt4{X zjEY**R*Z^T(_W17t?3}9q%}(k7FxqibjPFqoLIG_OR17!S&*Hj^^Jzf$wu4)Djg)| zO>vz1KygTG28vP9*sLfrT&_)=hu--k!vBYEOoS8x5v%-Rm)Ov_;7?;UxA2(k6Pn1qe-IE5D%YHm*QBqvxU zsG+g#TKmun9)Aiw-PXOD*1EQl6i_%Sgf3X{+ zo*xhz-=~rxC6&%;FU0q z?H%17D;rNxvdKQm5g!Ow-fe}y zSA~Cs!pE;>#{mJ(^@)gQ?x>L=qHxEHZ?1P;&$WDYTk=+>43|FSpttK6IP>Cn`e*J} zj7H&dUbWG0*^l%Kl~;o3eoL797GK@oUGMlZMqj%cs?m5Y6^H^F-w*LvZWM+agnRC? z8vpe$HJ+y$-=!Ke47DQbL4iusA5G(*p{+KroDf57?c z`YP-~@1kQ4*!zKWme(oz7gcIis`83OJ71x8$On@ivgDP3*)=!}Do^oLa(}WiHJ8Vm zb^Ln}D2kF;xJntQ5NbCF^aP09ELm<{m5MUU?1E|GFDo4?y!UuiL*&P4QI&8sc^r7= zTExP1wgx>Og}jSK&rXT27P~U$%!yh>h^s(s2Ah&n5`|Lou9SpIY4fGDgCn6*hDr3L zw5XKU(ozn>>jGn?O^M1+P(JbMoe}VMtA1WIibRGJ$Jg{UgVplOnHHE+t=$=M%%L4#_5 zQs#>_0#kG*} zh$i)T!T9FdVp&@(tJ;zWy{hSBBHYx+JWdIBrN=Glp@_TfP~4VPT|q{5TAnXuPx$P$ z{Hof@$etqR5{FEdJ(t1R1qrxXxOr1jk$R7*QJA=FnPmnlZ@t+EL+pMQVAz`kf#|5k zE<0XeId*C;w%F%2ws{?X?*E16@ER|1r7Cgp#hy3!|Gfe+C%l(a+^AQ*;{@~yLY}fB z|KAT>Ywm=-|8IdG>=hUxwFhuzME0a~GC~9%HMsL^>D9zY22EYBKel z66g@xV zrByYh3ryjcVFRYcYKiNjh&t6op*4}1D|u)YvHB-@sE=>2yzdIC?@*M)8j%B`6cQVW z>N|ppYih3YQ8pqj>RUdlRlhFk`#!48M{yES!zBdQ>6Z&?6+JaSZ-O>m}YV-5LI2lrS0ATLSvP zuJF_Uq`tuy`TJm6)+agLDy4na&O!&p=b|Dx2~pi4B_6h6fa)vBJL1BwtqW`3BMbvd zP}>*QyiZ~4K^OjGg$I2)9kEKEz$S?dz-7Id z#zg+SrnZpvRotnDhr3L-E7Nz$H1Vxy{v%doN9Mn&KXh$q{vLnm0_i^3A9~X2^pRQA zX?*9)M;vUvX=4Az`=dHYc(8ks+4(i$^;`DOWO%EoXFfff_Dd(cPS&@*;lPjV7ZZ2b z%P0KHrqdRUU-#GL2;GhVGHK4)CQJAROa3{@yc6IiLGEK`-1(E4aMSC;v?q%DqT+s| zxc=EJ&{q-DwIJo=W+wcjC-%=|HzLO`zU6(cZGZBiAI;p}N7KXIzdHhoEQ|ZnQ`b=A zvgB1)sZWA_*)(~f%dmv+ag?g(9=oTvpgfbiNs0b=!Xi=gqKTFbMKrT;+d^1ypuCCK^E@p{J{6#1T2V0{Qep4w(&=M z`xwP*XMvElYzSzd_xO)7Wf5rLkP&DF#(!W@ASX7PI(Gr6Vj zK_=OSMdpY`xAemWtZ?jo_@T+j9{z-jR&Ugi!m}2aJ&kwd%GhQ7soWJ%k$tJ$ukuuz zo4ayzjM9{ly`Vmm`?k@yx_wfD*&w90sm;i{Wo66PX%sTKAFD;F%~uU7l7E@pwWDwh z{2k*pCY8Ik4YLUs=WyNoZ4nJjQG+C>ayRJ)EuA@~VPy-b>XTfi)?QF;@{_!pCi}(t zylM-<>5wSc9$xWl#;topf;tV&Q8`z2@)OX332^KEIZ7*|ZWMLXFp~}B1N>lZsiJvf zr0`iQ#N4FO)>Dhh4Z{Bi#Nz0k!VV4@7C}+P4>sK-UUX5@l4pziw_-ap)lHWW*`frI zNMc||mcqxRqJSg7aZc{qLG11n2*#V*`J^`WE=IMHanjdD79c|xUhnhMN7HnbOt`^7LAM>-nwcw~=3# z^T(U`ZBpku`A71VHq)Uya<g7!`8=RFtnPmwPu-lN89Wl?n*US}*c`_;yNzL9 zZw2VZg)WzNSfLhktM)rnA-@7r(I zc{r6%=Vdi(QtNgdrlN)@n(IbDRZw_puVJJrE37nyK9QUKuR>r2vU^T}p?#a@We=Lp zzQ?xEFF=0U^M4ea_9ihwN>g83M$~SzHt4bt`bhy zGfXG@W;5SI7J?Gnb@iJ^FQff3k$gC+L2f&o=T>oln7((kB8#Ox%;fpFoE=&$@ zH0i)`ZX0;oebq)>)$~M$D$0aU$L>wf-C?IAp!9h?Qdjnke zmgqHhzJSY#7`IDS9Ym`o=s%T3``Pkz|KCC{FNRW{jjH)I7OzCs{*SZLFJ?)8jV1X< z^7w_zOJZ633u^|@{zVj+zeGU>7S;?pkX3{e3J*%~+x1+*U7D#gzcR z@kp7csM&UyrqH6u+w`=hsYS}EHu=`(W*=usa6zBA#u8bP23kcZosBUm)7eycQPuA= zr^+5^g`u$HJ%y4>%PQ7t)R0HDQc-q($%>k`v}g>R4Z3i;O(1AXzQ(jC!ADXsM1iQv^?(%8n7K&=p zD9G%Wp~R|5Yq2KvZ>&j#uhy``whpRGRJLluK$p}cRj8M0VpQ0A!PO+HSCgwro2yBC zu_n->VxL51uk!e1_ zbk6Qf7fzk^ehM%-OK@}EfzL`+-;;^)M#dz56;Dc4V-E}}GqKk* zF&4<{xI87t(}&}Ll{c7hstCmWDLhZcps_D!Vr&%cHh^@tiI<7Yk?L3`JC>>*PRBND z!Hopj&V-z$;*&A{IEO zdFdTBf2-v5Ie3M%1Mwa=Tazb|5iIi33eHefc0nu2;8kq4gRXqg!*hZAqzK4^?@iGZ zWy!?$M5SQu>|ivg+C%t%BK27+ur1AU&dt7Dc0vdkQmHCHt$oYR`y4MECC@i+UYkKCBocjyG}oa#G4y1*VoYwOD#8HQSomtHe&oE*r7K30=cjpRwPKhDEraUmfRAe4 zAjc6EudswMxtrR%T`vz+-~x;r?G;Rj=~GG_nCrcEZbEBuq;4y1D4Iz+`+g)87Q*RB zP3Kf1x*<7n0yujXYvRlV;#WdzBglRYN$TSa_o>kEMGWH?8d({1)9=#NxRQP0#B}Vj zs6%+uEixVA`~bhQ8-wcg>K}Y`se2T7jsT9+?v+D@C{RU@ra{7|oY6)!-Y$%|m6T8ib0*`E41@%78s9 zH@k+I6l0K*3$#t?>W!>ZDQwev8{GcQrt&AI_CBip^g5Dvr*Ku5$?i>6?@h<{r>ocV zngvel)(3U#Q+4Yz)py{(EM4~!ZcI{j+=2KnDcj8V;e+uZ$3EUBj*>ge(<=@TFgnd;|*y2*6iy{Wo9PpjgMo}oQO58vBs zbcRbx9lZfcWtO+~7~bJO0lnR#B^KL9c8&MCnN!H$y$g^R!4C-2ZJmK|zhPSX19;`7 z*m3RY^MdT(HhwN$HxB0W5y>yQGGn0Ai z_CXCr{QLR!iv~W0@4@hAoKD!hK(_a?^GcVG=^L0Xyh~Y82y>(MJgb7!2$JGiKb&ID z$h=oUep%eVdX+4QJHzU%{i6AW?~Xnil7D&Xz|HVAdH;XUFw~G$b6F!yd*}Vy5A; z7uW#VIPrtXzJlrXN2T@sG;~K}CfC*7&$osrKccqBdsnLqv(MgQU5Tl;X58ZYbOO3a zlY;(ZY68e+_GsxbSWD zvh4G}vZNmGTY~MY_3Q+O$Lb(S_7OYDX78Vm3e8I#>PY8$+=(I`a{C~=1soS~7Zt*% z?X(8Zw6ZAmKB`RHg+pZ=0U5G*9*@&+_69pjp?jjCg?nuGpTbjX#vI!`1u~~*b_$8i z`#O|8X29&3QK2+8ET%$>kPQ(|-8SWOB0!r79$y23!y;3ej%^2@P$fX2BPmn*rQdYm z6I5hK#dvn;27B@%9os5!dU6dI1YYaGTOD``=cUX$dj5u*K^4NQ^>w@gf^|W*>iRS$ zEM0=OT&zWP|}*6L8i` zf?GpekaGy+TsAkmDPT_J6|KI&T6acn_C+GKG_J?)6=z~k5eHA=$ef4ku*RhOIkppn z((Q`yj2imc^K_n4L+#>u%9GOs%0EV2SoMNd2xlS)*bbO2gLh(cx0Q(12nxi2g>-c4 zRzE?n2)`_Mz6?nh(NI>j22FfZQHZtC&CPy{L|Ss4pYZ`2v&=SXm=6p)cc4|i|A)Jo{J2Zyr>~y zx~MD`9&=}>J({gKi_?NW^(9oIQu8tqWZ5mHb;Abj&ReEuU02gCs97u=`^EEx<&v>N zlsC;I++B)c29)!wa-hOSeBEfNqyfvzFdHPVBvS@Y6twA`g7$>Sr0PhZqh6O!&#iRC zVixqna-7dwio~Cl(BISRd6MLQeZ8L?je6d%O(W6Y(Uh8XIj6JlznlLziEj*8JV&I6 z*cq?8+E#zOjw+L&*Znl>!%ff5%rHNhY>qt932KT?hikftrzW)ADiKf9{U_ICvRL%) zA%|q*I&4VWM1Iw#Ox>^{g1)&XWh4@hrRs*Itk*ps+!jrxfP8iPgIL7l9@7l4iKJO^ z&_vP`%Qle^wgK{U>6(M*l4e`ICIJTqjoSff6Dl3+`8^X#Gxwkgm5!}EctV9Wu(xPo z>C~atn!2ZpUon6_3%g~V$}Q}L+BM$>gnI!aHSZh*6IR|?x#sV)@3<^S`qJymQuDr2 zm74br2HU-*Bup#7bXG2XTUlnFv_VL`9|^~6cnTPR)a?-;)M=zV5UF_|ug}aolfCET ze~f&ov$!FEnR)NyhCmLC3n_TsnTgCi_Q9B{L&D0mTch!Xla1If6wl(X_KcS$PB?tG z+@FJS6pZZft#k_?p`nWo*W-Q~E;Ux`9)KHcXySDj)i6_+tafX>f29qgxVlD=gj;P~ z^!$S%ZHY2#EaG)b?JCD=8wkC{nh?Gwy->khw@YiaoF&MnHBx15h?+)?m!ctYyQAvlH)!cluDj*%h`h=fUX3$^dO5K?vs zrcuK*h2o~#w3c8RR&B-%6BpUwQ~H!ZfP{i&R(NYukqPXIl8jrGamq5<&E=Lu%bX^y z03Xn+^d|n?+k&IHYM{BRkrWbp=UY?-DOc7lCaowp!+x^H9?GJ_m1U*qh&FM_KmA*0 zt>^+mXG1m5f@A61>+Df=u4SYtw?2I|7gy6+H_-|elL)98XG92*PM^HZ&g2*W(kVxg z9W9Dhp(VbLY=>Ey>4t<(%2q8{V62< zatf2Y(V-QWTP!xR6VrgCeG|w}WcOY(3<3O?&*>96ZKrg|0X+fg627kl2y%yY=1%KE z@Hmodw^}nJoG@ghHO!Pac1mhBeqfdITw=2?xq<|T@&|B z-d65f=6FHWDZsE=t?h11O4`mTKudt=*{>UR^j#~LCb;4x5R4drL#??U^`<&8y#8@j z73FYm_|B4Q7OKaG%UP&Qp%O`*aT-YXqZb;*X6UgsuEpFsnhRizby>S2-kiDvXb^E zXv5nn>p!mjj~3fc72i&seoy;taTMGC%t7sM`ah=qJBsb6ivOPWb9}lVswmRu=0798 zJ6vrGOEfdJHa}zkW`)0k_}VPExr+{vxOvb5NN3r09^F!jx)G+|!Y+i=%syfyEDrK3 zafR(5$q1$z^<%A3wBK@I&95@(l_un-W2R_01$n2y~emBlKDVMj*qaog}pSMLpCuWB5$xm3N`o7us%#s>WsvMabvK zR3`Sk#NsK3e_JMowct_qX{i6xhpQr)YW5eO)HB~>f+5cxsp<`EJVsHe*o1mwlvEWE zP-43JcRtqelIJxxfT;iGRP6Z(m@3To!H~Q@pGT}1u+7i7a;7cF{--Kq6?QRTU{gpV zw(D>naQR}?c)C(uo{5>JsOrvWhe@@6^b@(0moNtEuU%B>(e8;@y!YE23okGTUOqE@ zlsTJ{2;?sWAtsJ#F&Nvh6(r@UOm)|aVns->6BCn>Dk0TI989aD5}-x#2QexV!N+RT z6Zt@%Bq^-7#a*C54aSlRJjjapkKjSY<@WaZ@lg*I=+TvMkbe(7f)?puI=%N>4#ToA zjVY@a!uPY3onR8yyiM%Ueu3lZ|7Q8(V-FTe{0$u8?X-s(blG>Lrg`xKq0DY#eD-1R zxSJRk7?XL@CnTeUnegK(YxxFA<|U$hB){L2Jcr#z_e7I3)`xR6y?SbDwL!zOYt%0@ zw1sJeVMLlwE1%7**91ut?X?Eg4GH~{wcfH|xUu-fvH^pSK)6p`jRsGqys1kZ)Cr%q zNGS!f`?rP1;5E=$;KMAe!`|eYI-2F$e*`9>bMyE52(LKjywo>(B}#o~;PSY4~o^ zca=4kO%@JS5ex{X+}XZF%J#a^+4!LCGUeK7KMry8L1`Q?=Yyiqa`>Ped_MAFg=i`B zZH07ExXiQlC}lF?iRq}9?Y8}7>ejq*)0r#678Z-Teoz^1rbG4b3Vd_%Qhka&Z%zi( zVcKQ*w&~CTkk${*qM9cYmRQAFFSzZ3F`=r%rIgb;I1sH*BNb%h>M%UUI>D*01BT=- znU^%Q=^XT2+90N?VZvrYHBV_ojJgQKX-xtmLKgu&^AXc7g7P#Sfsh}fGFi_m`H+>H zxGEP%mk0>eo48uVNlmV&n*!{(^-3e5(E(#G^AUj}!aqUkQ@d1Gp=BuBm6NDY)hFEH z!)6gC-08#8td-v7!=~aB?(<<&aHS1mkGrGP8cQfgZ4mz^zs!$z$oj9DG(S7fn9_<)#+>=cvX9~D>H z`<1}#ss+27UCtjTiZ~l^3o)#}<*WjviK!(9mEiDzboUmUPMYSLOVZ_;NKBc!5zRhM z^U!?FbD8wrOzP6`GLs6nnsnV0@_=S!g5mpj&!K+pi~Kw1(Z6B-?1Iv2WBmO#k95@o z!e~R4wVtTr9Fyt(eON|YGWC%@Ak)Mhr)#E=6K*FNNMXh#HD-$V}*Ln*rmX|g>R9}RHk@iso#i%MDwW1i6@KJ-ss9GPjsu)#I zRJcbk5y~zx8Gdop&D(lF{Jd@6PE?KsquiS4Og*=J!V`g3H@92Tq((q=ORW;Ldb&lw zS!{1Y2hS?f$7pI{b~`K_?N%14Mqv3dMtFEpRN-6Y;l~taB-;pUL_76M{jAy2 zDJ-64EqKZuvR^E+`lY^8mf!DFkxxA+2~eG@VQy7^;yVbd7gTSFks4d;Ag{LQ`9PMJ z$3E<_S1Ffjqf$s8AwGO*M19P5mL={EUqX@*^$&!S-)YNygQNF!p%FgwyG->3BSaun zHKK_>EL{iGB zvXca{LaUZYN9rXanD)LJE&OW4N37~@0cxg=5vJsKsw+clhD23I3y42X-)*jT)^$b$ z)MdnX5FbvM(_=q%3glUnN(|O9e-&g?ghDh15(9`5C)Rc`6WltYdplJ*`8egNdo>;7 zHU;PYwp$M?J>zm2yQcJLyGCpqEOG&=_5i3%_yo+t!Hu~M13!Va*e)|fK8GCBkfK517p%=)SOUUI*bvF6L8JLP~s6MIyhs&$m= zexLwcwNK3{ zz7KGOab@QK8*5>JTE^>E+aO!EJQ3`Q0Iiv?kx(viV~|S@60{p!W6ctgETj5U#7lJ( zkuhN^HWlRNpQ3`=sh6^9_zZpwcpHnl7q#$=d2_O%z|>tDyEwOcU%Jp;PzN#Fw3Popl5A~vKg8Of&!l&nYzZ!qlv9Dgl_g-+#fBby$_Easf|!6W5m{(NYv)5^67;tE zN^+KjES5;6Ysn1;l)5E4S3~1g+BOrDMSV6%F5<3pu3+nMZSxx2(hN|U<$vvU>E@~t z3HUC3js0rY90WoF+JOCHBeGw2HY8q$HbOYO%GPwVy(7o&C+LD46q_oGxNDH3#U!z= z#d@m8(j{lrYez>-qB1npH3qWg!TLZWuqJsbGmtSAK-~s>3Y#cYEJEOxB?QE$wkvfg zO4S5a-a((*VZQiWs-G&PuJWm!$~zL})u;=6j0h!6@heKB@6^#v`XzpikMHtu zdBWj&TgA<1*RVsz!GvEGgH6C4N`kxBftmy+?iC}lmI&bNFBQ`oz=OBh~I%k z{A?A4*j<@hYdQtS<&)B^T~Ss>NqN;Fw$Z4(B8@(8-<#weDCVtK-n`G-sJxObglO%sK)^@j=~`VQ-2kP;e|~fAdV@ z`HxJ}Vl_9f%W}8ePG0#~-XX`$&lAy>;A21kKSd;d2h35jg-LA1wlI?FKes7eJqo(X z4M79MYVvV;6QC!rHvjD8c^JpSmaat3`Rn^mIUA-$wX{g^!{Dp81YZs4pE}9vpaVMO zeFabK0?4O)MW=Y#C93G7a^Qe-WAn#6>T0-2 zg}VfG(7U}8=cl~?W^>N`plUj%Kjt-=A}Fsz<$-UHvYlga4-`PuskPMN;3{_ch6$K6 z9|Hu_u89aNh_%8<%IcayeU-E$k)rjK^_c2xA9CT)&cvS57~lnCH?0c#&uAiX$K6Vt zC$Meul}-Cz;8Ka|7OL&UzaWUewmLs=@rr!LA~iv%wtyA+m_?$kbMnaz*`)bxvc$X9 z^bc{uxG6sO>xS()JUuT+ka5RGzU0|^l4n=!v|X!F-Ae)eFiD@1lj!pj{JGGOw^`}} zQs)uH-S_jj`+i0}M#hjOagdR*izNv?cBVj{sMHI?I>g~@h$0HA=^Jv6|N1`O&l6dj zCRxO(4Bn`0RrU+x=T{7|-onrn!NGF}gpPcbmVR|jt$wp^Una;d)#)|PR#_&_-~?>L zvOw6Sy{M*B7ON(uKo}D`q6Xd3Q`>xXgk6vo(>Qm9zuO|o0oG)w4~P;==Mvp)vtI-l zLxa-n4D*8Sv?LUMB~igHg`p;0R`Kin!8@<^fvVk5a6;D7vFjoQ(wAyuz0V@vC=>y| zk~cc|4NqTB?T`#4WXRxiI<-|5Eew~W&67-cZ$agYM*@)hn(` zxguTEosf_j95;)WF62(h9j35r?bM&7b`@HB9LOYNM{q>B;owEWm9pF zqj@!uxL%XA9(Kr`B*D3vv5;HT$m%NN-U4u{4qm)W)0*ORPfAZZAVXl6D^`e0@0$B9 zI#=B)gqmWmIG?}6m!#==Xdxb?6YRK!Fck)QOMs?y?BmTlWCRS+TBk$@F%F*HVFG&{ z#zA=cLKa}%2)%~xAk7Z@T^=$U;FeK#Krtotu-28jSLq`@-bO_38x-Pr(_11qUPS}lp9WdgumD*Im7qZ$3^#o#g~9k-YJPzt;Ho@!3o$**zUQc88u;#6Cut zY1d3mLi^mp^Hs~A`q}|HJ-6i5bPTovVw03=xzK;)@`@n8*E9cwu1obcfkL4+3zx)t9}p~xcs#%74hx= zUS3w#b*uF^&v$)~P_Fx%LIoFBr)SsUORV5qEFS;qIy`1>I4!>R>EybnXL&3=f6OT6 z`ey^5>lWVZHhh)gp-t|yZ=C;UZ{fi6&v4+`T=7J~ho{_gW*=5zD}oE<;WM6n*!etD znRw`YI#sdZW(r}gOg=3aoiF2~8WH?qd*yn&j@u@Xz2$TiS$fIK4KFlj=?QWWdL5B! z2`6M(WK0hQ?$@73^=E@S`ODYqK;DHsw-~?Q$Jb2E9$=G=gW!_zUP$NuE*8ug0$tEB zo@roPX&XmD4#U-$zV6-4NA5Cwd2YnR-6fm2Rmj1!$XDnnBH6_ob<0*l-6sBg;W1U6 zLm#`%W2l7pC1ccnd%EI)z9)dW^!~$mt&Pycm_iR6mb!ORA*C(Z0ARX*O(lDR3L=`~ zcACqd1SU2RxG%=#@BrV6k{}0LSSm_+Ot?AHR$)H3o+N6=WBRjEP^$tVi{Jm=bG~iv z$|jzGulLou$T>+x#&^hF>kidm;x5D7Cd@=VS@dJps2oI1E9!NF>L@@_|BEW?`c(FP0=eHn@}-ELP*ku&Ao6+cdtsyiLXCIPZJn#=tJl;`t^>wO0iFe* zV+{aP0(jX9nJNW%27q>yx*ZdItSD2h0hES_<%wFMAtDrXhTPdDZj9k%DpUz9KJlc+ z{e->*p-ja?>He0fbj7+<^`78_j_FLrtD3Lf`|(R!&FK}UJ3>h_t6j@PgjnR?COsBm zJ|(PG@@s$zNu*){63M2Zs|<;|`XI0b2}C&Ij1NQ>7vqjF6N6@Inc2FuUuOf0*P)78 zc%_-0PSg8?x4>NE??I-a-~;FgBKx^BW@tDJ7+@y&&T<{A$3O)~G@`I%zX~0*Z&D35 zFvJD(*Xx2PGl~#Fv;sl1)P5yOBDI|D#8YSZrJ_fOwu;*CN|TILa-MMSD>x{HsF(xO zBxj%FznV_1oBY6n-0a&4ChIoiVTQNky7$qre*{okiDYganUI=catIAIPUG|(E~OBG z0T=wXU2N7)iN)e_k2G|MvB70yqm z^C9VfObG~((^Qpv`s_c4%e;(JNs@JlZz@})#IV8SJA>R}k1D2$1kH?khOy8**Q=^! zmj_d!CN%)&8_B|Ul@Xk{u+Y^SoEwQqMKsJ&vlAXrHB)QU(S|c>zxcc`H5z~fFwocg z$iSnIdS8rPz^xuz)ai{rUZq;I2l+sXA5=WzTBS0nL`~Ta-EnD)AXo9BBKtgw0fTZg zK!)e`2yn;)4tT&79#Atu8be0}xW)jz^f=<71`Wz-!B)e(hYD1+Q4ci)l%)>))HbD# z`P4kAYE6?DExvWZUi|mEt+d>N85*JX_HJ2v`j^(1`0@P}i^}&!wPQ)Uar@<8!}( z{pAwuFJGw-vZvW>=pvqP%;9cb@@)e?=;EDq zVojz30c2n+3EQIIt=wJovn2m6Vxfh$AeDh6Ell0MX;YYt2_K)ZcsHFDU+d#-`4O)7 zVOx2G8-3VT9O1yietEX|L|b+ww)(_MVea&awx9_2`LL}U!UG<-UBD}RphJN{57}ko zb1ce@TZi~o`u``cmPbho8I9g&fk?@bo(=dJV# z!UYN-3fv^C&9ub=uFjMcp)N465sP3Oj`20rD?CJjl#E&gq}xGo+tEX)n+(So5$cFO zB7|J)%o0L_Ty3*e#CysEjPWZ&R2dz`G|Yp!nT{$Kp6(5a(|WhWdp?TZ`PMvt={v;l zdlS=m*cgK1*iy3fW9tUogF>47)U4**8HeFtfrYfnViv@jvkx|Bw>0Nk=VV8lvv;6M zt(%_JoZV@f*ek&bbB?`*Cs>Y1V+^`*X5FiJ!+w&$-r&ORNtC9fd}7nyArPk7|B1Z_ zY`_eNTSu^IM?xxh^1E$z@U66W_)Z!nyoUeFq@heVvsPCUYW7+uI?7BlU82b@h1@NI z)iuL}O+K_=cgTpWT?#^*rIc&1u{+bvO~jgA&r%r=g>Sst3i85e{KnZh)*jZ17iy(y zrOL;)Qr2!?_v9SX6|btqznhP*&Exr`!uB^bU><`YRLKZpmV;0WOCVIw2;wjYF;oI! z*wIk$=$@Hb`X^d5t4PgGGcKsBv2i?a$FkFJ;&^)uFxx2OH$3xCwU#D#@S0)+CJg?| zvvi)q4IDq(M$!JtYt8W+SK2^n{jAp?>0C?h(?RsRxXP>mO77w<`mm7p3zobTuRF44 zf-^7gZ`Me>n9O}G2A`Q^<~{55R`k-%=?2{XcI36BXhLJWDnQ_dX{T6n*%?RPO9ps{0Np zwiD)7`&IPPbc3|bOCLH+Iw^Pk3&=Ff(4;443nhnq*+i?LHXbeN4dyf+p%QXZ?|;|L zT|C#T+8Flu4#_?huS$nn(;^)ze*c_*5Qr7AV_$&IjGA@;q(T3H)MbGVNvq|>AZoFL z7sK`h-IMC9iM^?c5%%yxL)Ye2vVGb-BXK{8N?6q>O^ckNVkZr@BZ5_wQ~6Ar2C76e z?ka_PO&M3TdR(TG?lfEjrBK$gfk?gGF7yu>)L<#pK1KC)dR(TM-eXWhrBKs~YBKfq z4k6lXAo&6a<0}=ba|OLVt^T#XS~F4#Z~%Y~DYu#!6MGHASSi4M0NSP8YLCkI&QvLY zIr)}y`y`M9k#ftmiXB@S_B)Ae9c8GhXpBbYgdwT2q>iR5wx;`osi1(`$Mtb@bV{Uq43kb6(+!^O>Ugpkj&|sSzV0p?MH$LXWHDK}uB9AGAGc zh$U8?MVU2`jPZ$W$|qf2@s-8+yA|K%;}gaB zyVOljC{YT%GSyq+;-{^$@f~s(?uJ4mE$D{@JqWY{Tj<&y;?Ei^Q35pu$&66^#%mmd zf=zZ>>XJEEEN7YTeS}VUZH&ThwG+2|AOi}5=ye<<5@LLuudErhY_HwJ*&VE9i@9w9 zLl;}ZO~())E?^{HmAWRhM>t&02D{ zIQQBymI?n((S0U$AOg+}?rdh=E9nL-nu{fy5vP&k*+X5`4wKs)l7B}BQ#hx4L>CSQGCZJ)xc|U&qPL)A|}hQ zLRF|E!!t0bRP_U77UUoZi8ByQl2pSUb!4s3msEv$>JEPz;40y2U~~*c9u%pD7fZo6 zr5iSpnrfIT#s+lsCqD4AL~OCuhD+5DX6(_ z0`+)x%5A>7F>pC=a6M1Gv{r>Oh)}liA*s8K1f!E`mRg|MB*+%REFGupc{%|VjanUe zuvWvfR0`WlZ#804tnkQeN`g$t53+-;vIrY<_tt<-3vfmXm#Wh0%UA=jXlIxG7V99* zO;w$;`0Gr^7VT8&R&^UX%oXi|nl>nRU|(xVQ%35Xs$$T?e5lwik5(&QfP)t1P;LY` zVt^P=l&X1S*++?0L_Ufb^ARIaMCc>Nh>*rOekM9#=EA4PPkIKy(_5Y5y)mAl82`@h zqCbnZj)>2cyeG>`ySyhG@}BGwJO-)jvguj>yWf+&1BsgFQ(3`xq^rl$6;B4$VNmg0 zP(2z{Ji-|#y(jyK-jij2YHJ$(NYBP@O;?ZDd$K$%o98x+Ju=ICXs7b1W8pnn1gQ1J zE2ELW3wv3_$T%DX^A(em5fJ(5QinmVnnW1cM{m}l37$y_|8hPrLVCb(_D72WkW z&qof9=?KRTiRlctDF)~kdp^^cly@1tjCCpNAWov^j9&N?%z)PpQjtvW_H?{?MC7wP z?D{KtHIlcXc+Wy=t7mP>;r01|k9J*})MSw~q3LH2ZgQJNVVf@e+N9w3Fmk8*uhjWY zO+sZOIHusbF$7VZ*t)3DMIoj3)I9E@rd-tFih9OH*A2UIUS^?SV0S!ki!tX4&>(rvm4^QKNJ{?sj@8I`wn@gj}BO{p!&ageTi#Z5)#Z|gQ&F+R%Gk= zIpr|G0iZtzH1doNa{$^FfhMAlVx9suSk&O&limG={g4RGH)$!?-ts7$ZhGM7p{tIt z#hoB<%VR`_8+}ZhVjfq_zbIz;29YFun3o)Q^nTwKoU35S`aod&kk{Q`@(tTdh1qeqXH7~ zYcOf0x(~#%55#-_o)IWiwr6|1_cS7?JbyXv_JX$VjE^Eb_7T(PT(6fr7pwPq)eiY> z@A)p(P>8LE<3oLL9KI%`4)LC2b(g#s2kmm&u8WqNuGly8u?iO76%hPg;m@wL$9H>{ zcogu5Xm&oUkwt)NsSLlvs#R}Y#WMi7?Fl#tS!=1coJ#E=fOCRa806+B!*iMWK=%Do z4eYksYJ?B?gm<`vgc7uRaw=_ zkd7G+9SUCH@=h5z2aHvuiA;03n_uMaiw5vora6+zT^=M~*%XWSOi*?zclsKhd*-Y# z8$2zk+*KV+dyds4yEnxYlr1i`e6!k(ceJqac0^)CritGeJ;+=sdXRrpKlZA!rfh<& zwwt7WNTZO{D*jN9!$Sq7pJSDdLfAY`vk?Z)ore0Xv@gW^Ep{(t514L)*NHv^Q<@ z8fBuYLk{4uLc5V5qBiGU+Cgm|EE#`1!vCVI2 zYbgBL=L$36knx?eQVL^lRg1=V+Nb%kKWLouszkX~;JaCTn%^K+AvV?}ZLV}_2erA% z#T_)xc_B&&AxLbT&(!1c8sqm0Tr)T5M<&J}CkrFF*cbff?-0UX)&r{)9yzV&%>UQ-UkqI15&I!U5_z6sQADA2OUCX|6Hw=eO zNw{DCV(x#zO0N9bK3)uIcv|8`5R=kpYzS3AY$$%C<3sUYNlSuhD&r_4gVqCw>9@fn zP9w*iG70jFScqff)RG<)hB~MBMH*hD*y(qK^zcu<>P2D4qmEanG&!B%^{@LR_1d3W zuQf}bk&>*kBF?2Oj%_`{S}F)mo8mp%TeDQhw)FA~`NE$v{R}M9E3{WG>IM}pC2)5A zdv}t}+`V{%tWPeK_jrbl0&T0j0JhL1!yei0+J z%INKk5;j^%mBv@wV3&m-K2!40yPp3v@5bL}e0mvT$j8olg9!B8*)a)A<7ep^_JSys zoAZ@rPAE*!!-vX(CkR$e&>U=C8vp?c*P&Uwl%OT#mc?Q>UrfQ__zwyCzo{R*?D4SUG`Uqa=-if8~I9smGIGI6$89={3lGnFqyFy zzq*hX|F+QLGw6pygudxd;`g_Wl1+9SKgAjY8~-gMZ8gPuv~j%FqM1kskNZFO`Eehg z#h!_*vzp`~k5Q?+|4xN}kHW{VCKUnH^$Cm)f17!|`MYk{Y&>iJac*Yj7IjMKm^*1i?|AoKt7MBsSHW@yDy)qX4jkoC?sfUOx z@i#t1ci0hp_DUg6;poq4NDhu~%YCWd#@ifz_-c&@%9C7-?+sUeUyUue8}I$Lg1QT{ zE6kFlE!mti0;wrt3E_8E03)e*lJbnvWFPU8{w|UJh(|^|Laab4tTHQId{UIWO7RiT z@o7Uo?E@~&@f@EfHVVAsHKa=f$P1zPq*#RKp^n!GK?VF(zrc*R%#PRixX}`XD$o!L zkvORF8Y06d5%P`Kxbx=6L+_z`{;jJ|e@ndyDcl==_8N5;x(+8GcZMfN36o*c64-*+ z6`pggx(;{bGi(5=TIv()!WcEEnXS z>k@ma>!;?LKQ45VdRuMtOqWg~H6Y`BWfXUfF#WkAYFz}K4YoqZNLp3KQ^UKKyI$#) z%kdD0HCpwXTUbMTS*LwqOr;6agL1%yI#{^77 ziaYwztNycabe4%tr?U$xbzqF=22<7fOl$)i4jiZF4Z^X*)3IGR@4^FAko`LAe5ZU! z@i<}-+pqVs{L_g+Y_~Z!W6@rkNaJ3tdK13ORN+95hRk0WUd?0|<>dpk>>ztat?J(9 z((o|EK=AOE7?nNa$enV7Yy+}h@g4S9Bu@=S804nReYg7pd=M%6j7E8~k{c_%Fj>e1 zpk-odI4@_<;^pi`?NkZTd|o*?qbZ#o4|qC~4N3eT@c`p|+7jeWK2vpIwgUt@VRdDf zyR!G-xdV5obj&Am$6RaI zToFa`<8;tFv$TAw`zjs0!1Q0V4(NSCCBECJ#Z-KqfpEA227JUfoPVubt}|Nok=DPx zerEjrOOGf!B!BW;Zp7$)axQ?G$33G;db1|T&aVj{3--@sbbnwz3_#CBii6Z1k4VMu z$b0P<6MndnPn;zi|JfpX)BW{wv<7)u6PNjij4b^dEcxferL(U(=8^kY?6Wx3I((Th z?TO+(q_{n%3Gnhnme*KcwEKTMG3bS#ZQDPS-AEG`-|{urwq;+we&+T*dMEs^mmPsT zuN{S@r-}`iC9kqR3Hs$x>PT>Li*RRn?q8bZ)3ei*nFZyU+)c8T&?au^SBA9+6!`DD z2wzv&JD#Rcylf$RglAd9cZCnp90@y1{z%oH2``r@U@XS z)z?N$)zF1?K0kfb$6)wp#+S))!bR%*izI-buRrU}UuCXe_QW7}Ddq1>E(~(tvpJDF zV@>j$bgo;rM@~*?0I@aRC0U*Z1}9Ejw%)xZ3qoe*D?v`ppaaTfM}*G3h=h-p^;urO zZ!z8K_BaDe!Z6B*^rtbD7<8}yafJ)6L%~z@7KOtL1uIP|``bZ2Z=-m0+L_JW;<7Bn zvhfrW*g)_<**o+2DywVnCo%=6lPJ_!wT(5}AZm$Byt)CD8GvVMDhyxV8AP?6tJkY9%)~` zfrf5{7!@VrRPL5t5lgJ>DAD>rV!cMCzBRu(|6^dPFfa-#hqlI#6<>97bjxei`EMW+ zmvBd*`jI)7tQ~+zEb_M{KWxMRTdMO|7fX1lfw&+aA$Ws&5&WVxa5HDtbrsHc^P{$eV0rjOxIXfK#s_W~&TE?SMCk+in13LZ36z(9lB*=D1e{t@1h z*`tXzZh~bpB(^lUUUN^U!Nj})&u>|Ess4hlTf?=nB<^s~-D;Z3@c^W@>IG)k#Gi`b5)Zs@Iu9Icq@8|rdW>4ydlf%3hEYDjV_xijsVcx^!8LJso1^V0sZpn-$dX`$sNwOVG z5G7xvojG~%aix6?E!hi^Dj!q((9=Cegt79%%JCM$h%}_Z&^27@!512^1L=^v`4W>uAyy{0LNhrJGa< zOJi(RK%P;kGtPWS-4HkOs5@@q4>3d3uwR5Mjx;<>HI;heF5p?g>O{X%_uH-o;mT%~ z`wTCn3LcvdT&J}y=PR7quT)FXd~5mppv@2)idDYJrU3bg|D$94Zj3}JVzghD|9s@gHo!$6-=d4@ELD{!2K}i zcDjzB0UL*v)|Z=n`>rIX?I+1`mvRSc4xtA5uSd_1rjj2SzBsN6CjH04rO)}XH=aNX zRz7~tlX>sDzZ1;Av~rwcq5VpYFy9bi7D4F5uQk#9nGMp^3}vf}W)SrsOh(ddu{zhr;loBz!0iA23CH znL&D}PQ2s>h|<_)%@Oe@X6!u;df=NncLz^0WZ#BOjcwf;o@Cp<7^D=q#lcgVYYLu< z-J`)%iTh7I)we{ug$GXv<&hiz_58fK|Fqt2#>XJ~vgjO?aBA2Gf1br61ok{sVbT`n z6=VV^eNOuqbUmGiSe)rrpJGHGL!)#5D?{{J8h7oWM$38m`)68Col5BDxEy(!A$u?c zd!f7$JpB`dEPBgb?%Q2+HtjCWwEO9Q(C#GPZjYQE_ovB%%|LUELDxT%_kKkyB|`5+CS z;~UQH-VSDmiL9`ppwX_7`x|6B?>3xdeY#ShH+s+sf&PdlyY=aJ5=Vi6*$d@7!5(JC zD>FQ|`bP59$S1y$QZ;htu8o{VBRVNbBO{Lpxs7B@UjaD0KukeIWzW*|7~V7SFuNQ% zmiTxsGCQww3<8Q%Z0qD3A+j%~e`abk00LQ4$dU@(ijIk<{00O=ReI2DC+m#>fI*wuT%w|~ph15Q)X8&)89bH~!1*2b z7xFz3=M*US)35s0%#s$g_ta);@Q4@@o;m^3qQpCM3RSp`!q&cly3DY;$c}!RQ$fDQ z`7gQf-02jlNliQ@$7SG)q%YVIuZ`6|vyZ!p@+6(F#SiKe?qCzsde>VOhrV6Alu`Xv zRQt`8>oy&QA=uNJ0;^5#oF5t=+}#v;w2AnRSTDyk_wqn@_pNawF81v7ccfT)y2;K4 z;Lxe@gKR=RLMwBR=tVD5!?xbfT)DiQ3E9My)NJ?ni5F`6H+9^txSl)8*Sk^mN`1X1 z)f*Vr`x(%Ey_YrZn$j1VzU%m!wO6Hj{ixS*M-Fu+&Sal35kA?y$r*)i`jj1=^;>(! z`zj*SQouFl(c}%q?z=v@mM`^hD0F>)utOiQu~B<+lx<6!dfj%W4zAgBz=Rt8b~Lkl ziI1DEdxgEbyhJ0@n{-s!mQ~Td^QJvu0G|P17Z6vT=Rv$0`%Dm#+b*SJ(d1Pnn$R@(zMli<9^iC5syRLy zKt4R-dX%eezeV4I49t+$KrWQIUMFMi!{H>Q_N2q9z9GKeDA}WJ|?^QUNVpgGwa{1;MVi zds3{cLlpeh%L&0-g*(+MqOs)qD1?0`HQ6;AA7HU&t>wwziJu&Z{y;U4x!Rimv#_il z0~l3U4xh-X_5oxwRE=hzgXxDD(LK$^-g1LgsR&-PnEP#<5wKjJ!z0Yy1^;r@0MZ%dXrE zJt#=6PX28+C5$9X_k-ykJ&EuH%MA#?uZtMtV#(UVjLC7&VAZ=Jl$AT(mhT&J8wbF# zBGj!XQ=NG4uV(>;@0w&)SI~fY$Q<}rr)T~%R2K_X!l4LRZT6{^Y-3OQ@Nf4a-}hk7 z)FAN$C8n{qVBYM9MmzNtHRm?nL!{n zDuWn14n%*QLby;R_|LW@q(=9S-n@P6*s=MMAOBK`z#5`l?;=dnqai&f-z?VG+|S1e z-y2IO&C$07>cP!H%8)rdf|SXmVDG1UqPc?gBDY_e$@TkBN3K6XIr#&rVSku~XfGUK zqP=&1){}mU4yCu7a%&I{P-9xJXv!a>UitVGEE=<|2(w=Xh`AFe;uh8h8^FxOE-n)4 ztdBf?9i`_UDImd~B{w(jOHQ(qt2CTeGOm&Zxh3xkN)EA-6Ro5l0g+{bB7AIBn5`diY31pyL=7ty&at_rBw}W zpMEq+?p5B2s#PW0{XrJVp3P?^s*dJV*Or2gXPNIciH{X#e+&?n^*c&t3>GZ~@G%j# zd~?-+_Gtbm^;-)f_2uC5Am+_HW-AkGzh`>nJ-AQyb|iH_v_7Iqdc(@)fiy3-Xbe?! zNQlbBQqx0o!(Ur314*lluTS)aziNe92Ap0Im?gfVtu;Ow6xxSEvD76K!by#obQOan zi8eEXYf=w1(UkiuGhMC=!*4A8B`d*K6f*MNLqotAmQ@j)1eZrHS&{&?R16I!&4stn zKY>eeVE~hOt&-egvSO(pm*neJpv@@Zv@{`5LlfFhs}~`H0i5UVu^M;O`5NY)5aVZ` zvoa40YUpK-%n1qciPQ)%TP-0jRwiATot4F`Nm)f-`+eg_Y%a!r`Mc@wLjEx2u`3Q9kvljNH{6d30HH=)6e%X6RItSU4he z87hhHaNX?bY?nH{iZ!t2ZKqe(zu70&y!G_vcY9Rc{JN-9mGI$#%KG*rQzJQ-Xbg86 z=D(-!G({{vb75ifM%GCYX|pZiw1^T|t=U?G+mpXVl9CUG#NeTPQ%$T8$QOC~be?r# zTrdieNBiy5ysn_{VjbF}L0`VUe%=UCez#ZR{VlH?`9kXK&Lfxh<&uvriNzeU zx^#X1;;K~X`8TsH+c`taACDiW{&Sd;KnK#wRrOP6*2R+3OJd1K>&RljqNy`=engb> zGTBX4zLQ)&mYS*(8nN7T4&t6#M!HB(dhDpPhiLcLQNK`UbW}h&JE?H3bz~bSc%M)3 z=mR&|=8B){vHAr^#%^vEQDZ|FL>fOt$yK3zFqkA!D(lzx(g{nVlRHGdjA!Bfvyb`N z$IXK>1v+@FVoSU#j%ehgt?dd-+8Q?FP*VAnD4ez5A$q^kD%P;-TaL_MmP6b3w!D1g zg4D>)Bis6J6>aCScm{3fr4G-Kc4shU+y!RLcBAk*tgXb$xdi6ql++CGbnJqt1uG&%}=UafZNcVyr>XRaA~8Mh;<#*X_>~uNk@}(s-1)(q?9Hp9y`= zST3)e)7^4e5Ts-+mw%9gNp&2`sBsyU)zmoI1`Ov;_s0`io_|7goM|TAt=qODTV*~* z8s-(Kv>lgS!=zrTPt!tfjwT1Wj`2Ry@-ebHmbf@CeG$6^vg1MEVS!YPEU<&O+Cxgg zfORbHFVBCuzJ057>n%@EiRbb~i5Kdd@gYwB#?a;;ewe;ruzXx6G(j={qCdwj%{4>K zM#XFyE%7zZD@{d8zC6Ke)TnJmzk$!+90|j3H7WJ)fWdA*4F7?Qv)|Z0Dcko81-L#Ybpd7LPom_kH4hIQu$r zW8qE-N;PcSMK0nvMNwsKq)zJ_7!4JXM>`Wc2W)SCw@*Uze4ggHW_jPX%slTZL+>u5 zV*xirfu})td1zl`sLoN)yJTz~zY?TS^g$lAeRrmQp+=sH=qP|Kt4Mta6syq#`qjKX zlEVU)a|gH1U;)l;Dx6sR1oWgB9+ch@8AqX%^;phMHx6a6QkdbEyE1wdV$X6-e@x&} z$G+^>;7{x1cZzcPRlrF;sbE$2ZIb#Dn$f;nImd~xngny9iuf>KTlANTvYAp-G09dR zs{?Jo2#@-8_{@IOy<#>MD#yEua$iHDL*;~AWumpCI6L2~5{}(E3|dbO8gFx@u9+;P z@^wn&(FV(CZZGJ&uqu(}D8J>7Xl|l;z%$qxiN)+}Seg2kr1X1eh@8d)3 ziHHSUalbHfBe2EbKc$y|6hn`Amj`2bhfkOEvNQsfH-EYhRU(Zqq8@X6 z-XmCVL9$(Y$1Lq2M8N|#Bk^)Xoh&XyHa>Ye?|qicQitMwBFm@D{Vg^=(eoXH2;~3! z7xR56n$N47EJW$5zNCU)bENm7s+YUiBj%DByJIVQ&R*qQDr9_%YX z#)I{q2d4qX9qg;;uAMefJ;Q_3g~Rh-FdVKI4j+3Q#^>VjJfMRmnGlB?gu_+BVNnQ6 zn>&W2j|U)U76d#VZ2XItPD=N)G1`sglfSitFU_2Qu7Bblh|(**pJM#;y?vqu8{7DpH$HNAQ#KvF%l=_sx3o;SIS-*MA^VZVnmRF*EmqrqAAl=f-`7<+$ zP-aVfulMRlm9Up^re4O6eN2$Ul`l5Rk1FxI0raNS!#d>vqM8VEu?ujV3;}27^z0m=IA0G0!CrRj72W`}r4b zz#|O@i4PMCvC5>_ZjfD?%pG;zX&il(;lnX{iayD zEw0Przm}2~lv&^|Dfv|T=x{(2@`^N^Cm_g|LbX0c$_OWgy`5YuIC>u{X~!rMhO-9P zC#}9?udy_}$@K@2030CL$O^-ttHJ|6z z%X*(tESckVjC&x+dVwsQn!`;QcUC^B_>ueGm-MY%=KGB_n^k=~Zt_5n)%8@XtlyAd z`?@+;CN~gWZEoxsO#wi%T%m8ebZGzDXkw+SI@VWZXH*_vbRV8i#l!2jRzw;LsKFUp z5J}eRpz{Pk)n~DkV5#5?2h4KeEH8s5|RC{ z7(jgaYzEu*Yz-UnW8%vX9c0q+hg1%w zf9)~pOfR&io_G*cT$K|~OKHXrk0#h*aniT_*q(=IH#Z{a>knK#07=biA&kO%{?>(D%e|pMQP!O^JgkP6tu6#)iP}b zE#EgyEiV>gJ*>ThDRHoG?_jmJ0z-3i^iS{`4Oh`{)nfiFt%+2v;g_|pg|VfM0R8FJ ziDj{+=@@Q6^EzH$i7j2PGh`JCTiOw8e(UsD-^De3JA^eD?-ARaziO8vKhI zw>Zz^dHDr-M;-9g2dC!UyiL!Mh5=~IvF8afwt`#`P42_SGqx<9D1s!1oyCt1INoxM zuGwW0a7yQvi3KrzhOkf<@o^I&35EVDaV69wTKW6|1;3p1;#fW>CS$y*;ES;>$5ba; zWBIK?5*Pc`4B-5zm-AuGOkhK9~hpR!39~TsJ72@!?KnP57b}Lcp+I!iN_m zMT@}r*;xH60mh3n?SS!e!+2>9##p56#}UTQ#fmmsZvu?FVg^0CVV1$zP|_XEz9&q0 zFyN>%&&_#W#?C-%ltw)Mw25^PE!FtT~mG04>iM3;4X3?7c-VHTgS?vsc15 zC=fnXr! zIRNRW0IrMWhm*!nF)RQN@D%`Fk^>N200?IrE5^3G;dwfP;VT~C8?k&ZI>Q-IomeG+ z*{;ru9lAW0kNAVp(G&UYHAU%~L`zN42Q@{XNDPV72llQ>tPE904flpgb;t^coY4}C z3~#Q94F79#2>d(da+P{-k6v+4FLDk6v zQR1-kC9v~E*m-Ilx?}2O(;bm1_jk6O@x7}|Q`lD6r<&BG!nm4iR&tmapV%6F)*4*y6;-no z6m1(S86(=&)cMr zp4YT)*Q#p%V!giDFLJm0{G1pu^w)qIW_Xq*2{>$hjBh@0~y|g_qGqP=I zS@*=|_0lzqEp@e(SYpp_YOqZ?EwlHHmbcWNH!E-bcU5tfCBJORo%S3Ks;XPU`}TLM z1k}2Y&FG)b#C;c*QngNJIhg8tZZ8+s`R>MnSA zTmw9EaLw(H$2I7WL3o*?c2H-0l;PD`4Id#RD63_)y_8jFFMD-{YY-X!B5Le?{%z;q zd{bv})LArf2x=@)XEOqIHtO@Mvs^Y0;~9bd_UpG!RaEGXNlb@Ba>~sN@^2zPs|vj* z6+cQ}>?HT;rV`!v5C)gY;0gaQ16udBn?D!YVL=l<9WN|2r@Ex$eub8P*7w51W0O&~{lyY5Mdnro-Wk46 z*nZfRO#8cShxWsEy0^c?+l@J%6c%BO2z{pi%jI|$nUfUwTKMr{`|_#06&&<`x9!k= z*iM)7^xy2dE`AXPWUTp(Z2N0)Bl*@kR)nQYyaAUIL$`hdrrrFSLqC=$jeMy&bX(x- zyp9r~{8#zGSHRD)aGLjZx_UAJ|AhR%ZnylM?47GG+&RYCIZUYiE!|Yg)H)aayqt}G z!hJC(249;~D{y^qVld-_00JD^#i=oeClg@6BT-$s?!J8fh8RikD8q+ZkxPnwo>&>H z$MxBZ(_{9!cv!v(J`eAOnQr$yCd4;hBW($uj`=T~#xVGsSK!hmj~~Sk?vN%B z-WTU%`3VFMGZ;43c3>Cmt?zS!0^|Z8HDO*BPK)uMun7vlf_OC$$UH6uAjKex!UP3y zg$--4Q-n#FncM-SVn>(hYT4E zU9?TjcQmwEA?t%MjE>61FIm%>kxEOlQpuaQCY4}g<1j)UyOT;e9OmOIS^JY9UD4u< z@%cYBI+MSsGbY`;%^6Mp!YC;Za#yR9TqCJ+yV#xI)xfMLTWsfTpIpl`>Su^$Z2Ybj zM%45#nsC22P2X>sw`j{k%ih{D@7XQr*%e+O$pEMO%$r49@W|w4KD(va_;tSWnEnfu z=e;QM<{A4mnIEnxNFGkNyq;&b%t!AaPn5SBl4fEKDA~cam)_r*ksdWgYmpwNBGEWm z=~0vT1nCh(9=b~pqzD0vjPy{L86jMqJpNcfXO?ML1Hf3RP9EKpR059P=J*Vei8Amq zbx$HQQ(#XbGgCk!Qw&>#uE83WPSx5 z7;^~uGcG!W0yC~Sgc38ZK4kPB<#4jsx>cv<{iy_oi!^Gv7Kpvxx%hsT8L#Db#7$fj zx{13#H*ulfrj7j5S@pV#a&i;5dM;vlu&I!$-0e7dE2%r1_%n5z@(OG@-S zaghFATcN*GIj3ss1Zu5*L4RK2M!SxsdRnWeReE|yPjBdHlb$x{X^Wmd)}Nix&V{v! z4cQ$|44|fHufK zg@4maC@`{uKbK74&jWSJx@q!XXX|(D)J3hwPkq02#ZK3H{LZ#$>d_{WTbgTDzu(e4 zV)eF`%3-UUTPlxU{aQ=q5v$*BsqDY{U2s?l4r^PQFW%JN(tORPCncak7hCO`{-;Hd3EZx)?rg$X+479S9i9z4%^w(dc@B5ps%efR&Q!uvU*EP z<>1xNwp1R!dbv8esipFO)m!N43VQmQI=NJxT&1TKdU{Pgy*b;w8VMkUwX$T`3k4Ma z$6%}Oaa8reSFt3~UVZRzRzc5V6%;$)+iVD_K%>?KcK&LuX|!kUeAB2%U6#$W8Z~o1 zP4&Q|st@zP4+HpN2E69b)$He&sajKnJ=n$)-r|~~Z8eRn5pIC4@-9SG0GfsI9MIVn z5aC}vpuPG~9LJXGLqT+LEU^*b(fTHQ(S_ATA4iGm)v$t9wB3M@0Qd+Ksx^@ji(!qK zX0U1%g6`K8u~7iA{J-sd7Q>05|Nhj9?D|ZssLT52%^MzsQzU2j7T)9xf$fs&r%R*wDLdgb^uh>qPkrjAQ zQ6g@mfi_NpBAVi}PS=zDq0uC#e`@iGOJ{h{saouMAuLDjH$PDRaPZ);-sE{e7!QQY zfp8rV#+N9#^^)7k=1=!H`@*zxH9_Y}PSOD$)L>(!&Q+YI)=Jzjv>33rA{B1A0xY{n zNNv5~&IKb3Va7?kQzOgoV_ozh-wNNY2zP?D!<;P@SO!%DHLD2ZRBh!KCF){JH?Zh& zx@?K18)JRBoNnFeaz>WEThn)iwp8GU#Flb|*5m^F)~N6EHGN+Q%?WKLqVv{2Hc9Es z71rqDdg2Qz^>2vp?mOC{n0m6bj)8T*Qpc!N;`5TWiG~qW8YJV;RNIbZL!i?*Yz5p{I-4`?y{}_Jj}9P@I2ga=fm^B^>=2kbZh`fZ_JTb z|IS08<|jrvI(WNe5WaXt?i8XT-+o)gDQ|s=H!ecujj|(!%-OQ0xR4c;d6*U4Cfc#V zn?M~4q13h9ZNM~S^Sw@6*H&L0vaXK}bgX(c={g8S+%myk%mkYlnM(C3um2sKUgu#W zkf*GnY0MiluBP%ky`I;f1#DZLO&jSYbRzQQD(XunNhU-! zf;`=*18ucq-1z4RX6UZNw+ET?q#a)123V)|pc=$U3j>}I2dN*PlWw=#8r?}ojYop_ zS^gX(Mt7Q}2d&Ic3p0dL>hRLNlB`Z7yW2_!-;)QV+iR^R)w+~gUcnoC|2MU~+(x3A zNG*jiS!zGK(9E3V`NghLSG0gf9nEO2l+ZO-X!o`-SCq(i>|#MsuraMB9mCfH*&^t z%#&9BEtwcu+h8Ng%L-m@w_)W)H;dn8Jix=O;9lU4HfGf;M~- z%jMEgIesj!p$grdn)Cff!}-3W*CrV9=(Q>S;eHd8XgW@9@coi9?SVcrWqOv{IE4{@y!LdPqi1zY0IfNcZS_{QJaeqNJ6 zIZ7pl3KAQ}Cu~|>llYLLftr-XR+HFal6M%F8;3K+tB149Fy2)WlFrL%$MSb!1BD-Nvt&+rM)Uwx!>1 zpX1vQ%mF|sq#rR%{)KY-)xaj6O{?l?JHKv{5~X^&+ru&s{!Hd>uFzo@Wx76Jq22`;wZRS=gzWki)1#Dn~c zBvb$A&Xk9^`iK|p_jAalI;)J}4(9LP#Be*E%e4BQfAR8gb_gYy&YvxYE5aJ1?ZIQZ zdoi46C4$Zt`WN49QwXFj2M8GMS?f#)YfQAi_w>$w)!> z!e>WPZvX5^$|4ID>>eXYk{8@pLFxZ?C}qrULn*Vnhf)qVff(qqzjY0z)LHCe%&wsn z8-y;glohW_t_ENx8G**+#8POsYb>Q#plR#is4lS-j+ooM?jV-(P=HU#XU0-MaF<}p ziJ++A34$p-K7TMJI~#Js+kyP(GC%$=2U5CDA+rVBO$vv$;Cs9=fB##76c#DH_p$dt z%E|E2=MSWuSFyW5ip}^EmliLf`n$TnxuJsg-2_t3TkC5{W$oVF>%#ki_CF%1H9M%K z-(B583*GD?in97O->y6swX0u2$TLXUD2h0}I=P1^$}a?j%Iy^LV(*H*L{aYAOBAKO zD`{o}&#PM>|C)Bn5+8)I0=Lql1uj|Q{7oAJj1*sd(LYlNkpzH88A%qV`=CBpLh z8sE&W5ti9q$yo;!_pp^FT*`}vTECw?2scqHG~VIDf1%}m`R*bt@7l>dpEJU8@biLf7x@npBr*z z&#*wsuDYNk6G)kzD~9AMe@#HptaUb3n4pz-@cU*J=uC>31)ZOAS4vD$L0V zR^>((TJEwy${uBXU^%|~ikiaW%mh-}r4hOXQWjdN?vf_g?{DfVCuYNF?!=%Q6+t)j zEBRDMW;T$bh1%T&Q9fRomBat?Aj-?T3!+@Uw;;*`y9=V+6_9&RK@`Gr>f5dnlwvw( zRNqYmr3)p+b{#7;v=?c)HL#%`|L;XmelpZYP=02=|38A#J#Mc#W1;W=MFb^0z2Q0T z|KqTToV)+H)r_s>T%b^<6Mu?XZSGg2(?kA~S)emi_Wz?lOXZOV?KjHWbbbpjV8xd=-dphqT`EQ*K0pJMz1`Y9FZ5Tf2@Q)<;AbFLRLU$XZ*Ct zpU$$)Ivkug!VODc@c>wG46J+p4`5N>Qr7KOQd^gMTG0r1xJm>^FTM;QZck00+^NMo zuU`xwz5~^9=bbb2D8Y#uzcRFl)fU8bHXDoXob^w(mPbX5>j97)J4L5w-cF6`WDV<0 zV<*ItH>)Fd0LzPdP*)7F9l%mat!T0aGW6rNRN!*P#3uI%w^j+JKaWzIK`3GkZgFe( z_j!G+CX`B!ox~|GnMU5)wUISDeItUP4(RaQdjc>`P+s3UG zJGl>z*6O$Bb4e~W+{w?;Y^s0FDff5IO^BCL!@l`b4jegc35TsLn|m!u;h8JxHWpa> zQQN+cHiB`0icw4hVcq;m?-SmF_QbwGRDiyiG0qgaTO)Kgxy?KX`CNW#>-=mT0V0(Mu_6#~N>O zCpT`jVXd~LE$&T@iiCdgZ@OcjHA)O03?*iIN}N0sN}LFVbT(JcZCz_$fD-!}f;AQC z<7mRJd0@J=jZy3EgRhsTAT|-hhdIMF7 zldn3D=6Kz_`mK{|Z*_+(m45Xw&Jv6%R7h{5V>2r+VAE}4LFM`N?Vqq+hQl)a)g(LY zN+dp>s^2g~GKTX&$wooJ6xG#8SgrITg^&2Oau5DF^i_&)aeH5-hd9+sfr_L||Kn@a0C%-6Ju~ zjS4sN!>ygE(FfKy^@&91aY$$VC;LP%Ul>hQ=2xex`{wHmr($+IEwp2(9sr%1p)W*k zk@mWw(g{X{ zNJBfh+_71}w`jntOswIGL>j2N?Mf=$$fhO`DsVGD0KAwdF)vkdVEw#4k(iL@vd;m} zL~hYpR5gv81%ZnSOBJR_d=O3DlwVF$s($mDL5Mn@xOphwz@C|k52lndOQDEmR$tz( z)t2I#{EyfMm|u;|Xgmj8>fiXZ{*#`OhVeYt41F#>-5t5mM&^qrGBOgpFx9{mBQt;z z>oyTqGB-q^ze1?=Ma+ZD`BQE+=NBSaUMvU7BO+32*jpSh=-vQ2P_7^;WX+jCNgqRP z_7w-TXV>MYZk))kjxnixZ>Ih>NJ;B-WXYFU(jP9b{6hE4Z+yOv0@D{v+#=a{f+WB~ zD=xkp?(sTJc+K~C)d;V%cExKevnX9}HEp=cJQ9BoNy=~y&u?5-6&cZ<9$@HKaR1FS z*6%fgfWHCw>8C^%zQ^MJNMHYV?@2;mR9c+NsnL6)1Lps549BclkK>1*nY!_4G}Wqb zl<(!f8$ZhVY{&r^gM4%_$fv&_66zklx=IhG#Y(#hGrbY)-DrI;=zf?NMie&x+? zYd+L%>k;|!sp75Ichqm=$lC=lZDsw=p0#~PG;rOlqBk~QqZ~tC;C{ME^x&x~HAz#q zDiU**&7bxdo~k;Y8*igS+aitMq)L<{vkC$4&!Rg^DVQ7wGvxYx0@mQy8$N%v7wy@U z8noz-8qln%LQ_R{QdT*afMkrBS0RcPxa%2Nk`tW9m^Xs6cENd{NW+oB-q(y?-Wkp3 zizway%Ux#+J`Lb-8d(5`$xt3ZDN?=qoxQoARJg*(oM8eMrXSwX1u*D{p6fC?0xf_6 z8Q4D~8aGE84G&T5UG-X*H8(I-^4yFTUQ_+YoxsoyqG{$GxTPJJM zau7^6TWqE~)x+o~7)N**BLri(hmku!-(zZY%<g~5{+mC5V znO%6tuOXBKo_pk8B*ism=+%KHy=p1Tit+S{S9UP1tLWpsOiub3S3AejPWlik z4`$7AfH_8BW(W-PTl~eCGP+d>zSDb$!5ziHhJgXFnNpHhZvH&$*DTflw(36-)aUwI zcRo|0YUtKT!}G%U9$)kaDk@G*&!lMJBIt}qcl|rUb$Erl);~;eSLz{o1Ed+w-6);$ zl4$)66Y}DR!tL>X3x-R-`$HMW&kx4)a+D7>Cb$dz!zA}D9?F|2kfrv-nRcdRaz=$a zDJ*|%P=0*6geSx2owp62Lid_~D0VCKz!BvOhL_oBCx({@twTYpI4^#X-RdFS3KDJO z?S34$99c$OlMpG2kL##nNar}bCw5c}fXzKKt|wO44@=1D%Oy)%H0EP+T@1}SXEtt}y? z#GMzUd?`7ijN{dlBMK6n)s@q#ANNeV!FrhblkT&AD@{fHmB6eToj<3)g6tw#lr+G@Ia!z9QbVEBfw9ZPbb(8J^eMEI3Qw-HiPa+Lf zA)6Dr$$ue&9j;JLR}HQ8rJf+m3Ul z)^4%N=nxX00);&H-kXNtUAn%p5=(JP$K^BKvvY0U-+wHVS#Xfq?w82Tewsv+rnVrEI`F7vkA}5x6Amkb^ zL#TAjRH%Ui<22OIG0rP&el%{5_h;O>IIzNfBCAFH{Vy1MA+2i`9xu8CRFPRRE|7Nw8FpxjZnG`?Z}+!$@3;r3ir?omT&Z;Q%>!4 zkRG3K95<}Hw3s*s`cx2`AlADS+=76{^#HB?3P@NB9rMEZTfVVd{p58tCL#S5-!Zvq zRO^@-%#Wl$&oh3PK-+nqPl76!F$Io(`paGP5q|D@N(kGFazRP@k4V38esMl9l;n!> zK8_tP*{-b_RGrPy7s7me{90E#91#F7_iVrAkQvPW$8 zXdZU9aU?!tIms9FbLDMi%v1$(&eGW2_m)kDM)3m#uk=$SWvR8t>C>13+ZYnUWtMZ_ zGMyKLucVS64;=?fk4C@;;Pch}p}2!7QwK(q>`qDc;+em>tP*JVBk}ZiP*4uHtDmBPKh)G_v$|g^UqV zuo`BFC9fBcxuzhoaRXSSPZXP&KftH9M4Olv^m(WI3C5&q9z?#vKgD*Nm8da#oR>6P zsm|=sE@jM5Bop=Carev|(j8ixQ@{q&PU=I=rv+V>@y>3{DP_NmgiXw)@eGc8qc3u`+(c z({3wuG4kq2gUGM(9Bae0)_tn+)V({;xDWiJxVpr>m3=95FY^-WjahV5(ZE=8Y)LMQ ze&kscKb)>fYR7BEF9*PHgj}dVaIoQTRyoVpFQ^iJdSPC?KLAm-arFY7<3XIL%;LOA z!@DZzTh$1VZzDxmE@XNI=cK>YxqH+(lg4vr@(Y}Yo-6d@j^>cRM*!K24!x|Cw|bc5O?{m9uxGW z5C*ZHR1?!s&$9v5Q-ad!`v(EVvn^?9(g#k*=+-=V*%-IXJ-yvGwnZEkkjwJ78M$c8 zDCT2yqF8!~ah>e``~C^gRR1Tx!X)ja0ZO7OpZXb-^ufn$l71gVLRC4Id7J({l{rl$ zeXs%X_FB-#Lv*sX_dLFVabr{SJHpBaG=3!6cD{Bo&A4J;!Vo&mU{&N*J}IiEkGEIw zlbv6pUX%s=5yYk=jSo;H-775TRzGU}_~=ObQLZV#{mTlhzCr&KMaj!vmN*l+lz!Gc z4B!(eQX^$XFpQXNe7o@>HSv22`uRs(4zVMBpeuu;ED=N#oV2qc>UOsIxpytbO2%zQ zTx&3*$=gJDCQY8kPt%O#3QgKUdLypI1l?aX;o(Q_5MQo!7a4!9H5PT}WM7Ki8QGU1 zZZI!?ipB?2ib|LeRWZ6_a|)Y7b4Fo|lFH7d@NeUDK|5F9Njq?Aq5D~ir}~y?SJ963 zEOvhiN(vk(Td>tnLAqd5{ZSchv}BAtM((z}`tpy(jqzXZCUb~u2!!D@le!#zZjM|y zBh&^#vq9ec3(rWmSrP#6N&H=i4YB&xW-yKD>`U$+ANlM<$?oD$RSHS+F!wqBWh+YVAewKvER%0}>l>=ll$yH|r@Yo{_i|dp6xcZ5TeGz@9Evo@=$rrFeJZq(ZOI837N9J2Q~Eg1g*vN5xmMC_GV>6_KnH-6ZXH4{R{hxIZAxY^3u zrgku~7`-iS6a{^5OQ@cHkwT$8W&;h1?s6K{!gy6F9Uec$3S6L(<*RT-sB+;m zrYw3U&#ACGMqYBg-qWDg9y!yS+bcyP?3Qj;HuSYROm{t8#){cRt5=KcY)Q}rZTd@sVvo=A}f z-Kk))x8wzMWQ&^|)ckrNlnXt!;wohFPXnHlOg7>WIgvGOvjD<*lp+nf!rJ)J_l5%A z*fi#hWhfkJXfx>s4WXr>w#7X~3`u& zx$LN0uOyRIdCx3y8YQ&ks~&sa0uKhj{oL3z(r}o85aYw7P<@N*i<_n~%MXF8N4pHk z8;BWensB~h=d0(CyqOX@fFapOt@|z*E{V{E$P|FXQ)H3=bbQa~!@#1Lj7#hYV0#%%PH9BJ}v!bx5teSn_O;Jbwa(?b?;o zjGy9d8mbsat1FJ9a7PF!j&0VPN|U%+hMdsL$_lbym zL5jJ>!EjwjuIv%)1V%c<>K*ru4nLfB3lt|c>aZ&uXWCce;9&g>=SjbyjaYK(By*MD zaocbQ#1E1KLGvY{Y2+?4+-m!$Wt+)gRy6jXFRDiTB!CFnVx35tcKJi)i`TxImiZp) zukxn(vE+;r*WjxhrYcJCRh}ObRJqC826GEcvg0Q{l%N+DmM8BAm0pK?IdFYR4&|A| zatPIdAsz@7OQOlML;)KcN`$@t0wu_XejLkaxs)?O5SIAJCIusS4h$WRAObr_3@)We zc@r_`%EYKLixs4sNb+`3u%8JxO)N^(fRHjS%MvXw61;+u=fG7c6L-cfQpcOz`g;A! z(yBeM<113ss{FhVKy_g^x8w% z3t8w}kUkc^Dqo$J4s#3f^l@#!bucdBO}+Fy?5%oS!ZtRA;1d1;0)&3;O@F~9RNatY zG{v`gW9Czon0NV%c&>=9%2a|XhhC)1OI4)(@@0V{D#4Sol?U_-oo&dGi=>F_SgQ*@Mz}4+zrqQ z5saN_aapc*Jr%x&rQ;_NP)8=m5+Ct}xm&e(E2r}i?c;yl205Ndcrl0V`IvV4hNrah zN&Mph!()f=*uXe|Mbph-@n`TWZvu~f*ogGB*1_F4uoz#iOZY4*-qpWk{U*oq%?1aC zxYwI>6`uCLAsia-r49EyNqU*e%Lp7vR7+EQ|H|Y|WsR&pPf_>+YGy8R^AUvVBO$hzs818ZHG&4sn5c-&#xmoj%?_NCC}^Af~q8(2int4!7sHelTya50cU zKjGS%!z^Fw^-^XcPB~yhV90ym6X}2qDiyoaGTMs!luqO z28s0zBmY{r5k`S~G(rWgJ^NDTmSsk@xi6FjkVgQ6; z=>lX>4v+&4C7g0iaBUMbcf~BiU65J_S89HD12-fGoYr##oHAT!*_oKeuRW0NI7Kr+ z;?o7cLQsHgUFHNKH`W$P;@`<+QbU(P!g1r=5T9A4x6$rDkoO|@5k?^8-xH*i1u@TQ zKhhv$h_Lrn@}+#WYkk}}iTNmdNBO`ibknEtRNpeG`?Z`EsL;2SfiB6)lk}Z`kuIsD zk1T5_vpFa8GMdQF_q(na4w~=r--z1^)3vhMn12>Y)zU#eW|uL}Bm{@jp&DNWyENv6 z(i_iU7NyT36aA%mtL!0eagg0mZq)S&siQ#NF{vZ$F(NF&?gU<}9{^rc$uZQlgpW*ID|h26Mf- zR`YPJ`)I2D>XVJMf3#WY)?{Cb-3z>g7Snyu#w&b_RoL*FG4zvga>%9`7L>BScQu+W zBTF0r%V}!o+Eb$}i;cC)$8Us%h{f1CgBe4ShNCIrmuAc^V>NI>Sk|VD2@xvz$+blS ziMfaVpuK=+ezw|kgWsQHjZwiGldlCBU)lUa`_KZQmQ6G>7nfglfu3Ux%N`3FJK7qH z|3DNozRRUW{6cYn@X`{%_sw|Fns`TaBHu5-`if9{KsYAul~qDKezX>DpwMoRuKjk_ zKX?jBXCr(|oDnv;^xzM9!m8`K(&g=u&>s8f2jT~l&o`Pikk-~f$?vhq_4m`IK(+N| zIs|@!a4vLLzh=nYrX-NdjkzCbct;w(XR^23XvEjpXf*y%lVX$suY<06m4<)1#!@W4 zp7D6cU~-k+xoHmpvxYSifduMwlRUt`jOo(<{u@3@Vn_c z`&C5#O?zyXe)^&fI?LbkF^v}P8DIhEi>h=iCFS{_3&qk383pSR-sr&o^cCID9#x(A zb5a>i@vnQFJD$qKwY(jCD3m- z-{QVNUs3&TE`+m~4g$~p-KeOUA@gHC#UEc{2=>4JI_{q@2#Ecow|YTzMJgfA8X^Dw2SmAEIGAz1PzKfhJ} z`@obB9+avpmuY9pdBQKKblIgHT62gm9c=X z>x>`hZf*f)eG8vhyix1s)L5Wr@QxqMg0(lfehYfbCS!H`y{t{9`{IN6QBR;p6ACxU z@r5dlh0Mf`gAIvM86>VTBsO2lTG1p_n^NM=L3H^!F96!-1AN@iKAHN*`}*mV za_7k)`OZVE+ct2?F-x`@IpIi2mh7&RnAum1ZFa-tDS`0ej0YdFk*}SwL;(xoCvgvV_v55E)gnRE2aJ5XC`}oVk36m(-Kg%R|x2t$uXaTA>RS= zd5mJ%Ibon#G@?pA0}GoK>s>g5MenefG#d=jZ=sETq~RiQN&Tk$+D3~g2o>;=?=B)! za`9Y~lnsp(jAH4P7^@t|$Qh?zR9f6|O4i?mIc=pOP-b$iE1BGy6wIoT`87lNG|xUq zz>`-qXD3VFvsD219c!re74_KrMG7IkX1xv9s%{e)iFzv(#5Z#TXYud(>gEqQB2Xa& zAK;CjX@>nCYY+6b@v9l~a3(i?l>syv=8k{HtBo>J^m#-{dM;Lz&nqG?oa2p$lboK6 z3NwPHf6c3V=;u%{)&F}t@9Uhq&5P0{*CI+EV|!`0z}uCQx?<(it`Shp$IGrl-VZW} zHaeyP{Sb{(%bEiEG%3A}whTAp@ZbZPFO#VGtN7{*T0*h-^ryC~?c-p*II7K@Zq<{% zi|2|ll(2{dQ)H1w`LEJJKL!{5o*?YJ`##7WnSCjC{jx7ZT%YVqncIGKrcR;Tn0+a6 z?e?P1Y1Z6gLp`>FFew&{C{VXjn8mNw7-1K9;|N|ivjo#RBL~k^T7e&A2}&eiN$&FO zu>k~ceHjGUoi(fwLhZDSyrGwmskbJ}a(A`)`AU3E;;z?k17#myX*?&@t*usn`LmR; zc3MgEGQS1KE9k6POfUFj#*fA0r^mIE)Z=1z#|l69rW(63;@$i7euy#OyHY0XmwDUt z3tKLXH%9{hRHO@+^e7QnQ$w6$LyJ3FP=KG}GY#tTOcT;HH#wpS;-I}=|nC%)$38_Jt-z5rjX4ZAI zF2o*q-%c%-t)1qDPb@>}(4fI`1D4x=HqGw@W){wYR>UJa#4ftL`p{{pl z0P%hoO6YrEKQN4}QFUAQP7Vl)u&hzSeAZ&y5$4Q`2X3zUj}3t_!FFKZtSoEnz9yoZtGkXS!9JO|tGycz#0UrSWWp;3gAyY7;RLB9X6Zv(UkuK@9%Xo;U$ z!-5&JqXz|`FH5f|ilCS&*LazIPV!qdWTl|87HBDjBFWu$Ek|gqy1zUBGfFduMY-&q z#Z$Qs1@2hPDnmr19xXJAq*ANdArv7?so$V!`S;f&RZVSe#v>v_dW-&cq_XxMufcq( zMNdqe32r2%W#R^YsEvv z$y1W&lqJtEODr7FHgsvcr@ntkjw&5EvUL7T=Ih7y4UgvQoyW-FuHDbiLt8h({F8nj z+;czWD29v@T08#Y^v@}){S5X!N=|#WOy3zlCpqeBDim^)Sh!?WpmtqHLX*0G&#f47 z4{5Mc!%Cj{O{e?tC&9X9zSb>IBgf6=^OEwW4%;X19`^N~+d@6oGgZ&EQtyedo~?IU zy-B{_?Z(gD@QEhA-W8wm9_|>y)v6+JXA17+A>1rJg}L|~J#zQ&6aDuew&LwaBGRCB)9Tc)W2wt>Gn>=rM3j=)`Sc*b zyM5>2`I=-3z9oSD-agKwaqS&_$m8UU7I)q82*n^QVUj%6f7{kyVZ|Ut7PuAv))$EE zad^gk<41k-77Q=(s1G+^x#3HOe*dx^_o@Pu*4cevP%^qZIqmiX8OCqSM~s6$_m*HkL}LS>OTl^Wf%yfVzbW<2nW8~+d6Ro2 zsUmCL)y(el)g8YL=dXL>#|E#b;Oz%I+i&phJVv&emV$MDwu2bwUkjA<1PPW*{Trwc z4s*+Wm!JIbKED65f2TqARF0`m9sM-`%sCsPvi}Zt{nQx$JXiQn zIA5+Cey+M8OL)Fc-CPhUviHJBQH5><7*WCl{$7drGJae%d8%s}ptcsc(=OBuS-|w| z91T7Bq?ZzB2CORiaus$I{kiLX`lB^jG5huOQ4X|^MH)Yp(w8}xTRs@Bbq$a7hV?og zbpxqSow?)515Pz?+}C%l|E5?Tysievjz_clYQd;URLt6Q$x)MXMMf8Wgec-*hEDV` z>st?hy03ykztuv1j(&0j^Y#Oe!9BO(4blIrKiZf6Yu@U+;o4SrL%rb{e~3HsMfFHF+(4v3^ZKhnFbnibJ7BL_Ru$=8E8wj1x^mJ06O9_~!Ry*z}Q z)f({{(e{u%nSB4`uVYoe!jjW ztDxc6CvLWWSG@~<%lFaqu=kz05LC7U|DKCJik_E){mjvfRFpfFHO?*1YAM_ddWqZ%>19yO+NV9wR*h(QEb!mSWdn3*^(#_1*cula| zZbVI@MLzp5{1FZoQ*Sd+VqfHlC+- zK))k;7+;Qi0{RUE?QY}wvP2N`+3N-E!LvV}+L88QFFk+BJhxbJO zoO89d!sy2KX#EU*e)%npB@&9B6@G#&Ob!0_M_x33Ytz11OcINH(<_V<^T_=~$BZJD zetxvq@%JKUMcR5qZ7phy*4rev zKX8b6OwtNhG2PE2>uUTmR-mq3NZJ)jE9aKnDb4K@BP%fghE|pCA4$DUve~x+j(fa6 zAF2qi=XMC+1y1`ns6Ii})g0G3@fJ<=EX9wG+@TNKjlZ;r*y(=ZYoU(a_^+tK0=N8J zWIUVL<;agS{%LV*k1~ZEts-qw)v58)_>Esm%ZShFze>*DvYbe&Sxtl9=qg)ND0YL? zidGFOilak^7uPPYZ_Te7x-rtI^9t+fRz9V#h8p`1T^PAjyHoLxuc)7wkNbQDr~X`j zfG8#6r1eEDFH@)xk5aWb-y&4XH3VK||jBV5(l0UDFk;QxZ$ z>ga{r_w`4?aCe#*Fgp{ZS4^Q~)SNc=n9UYxK$rU7agYJJb6NaHX2t1B7tUo%4IX{A zjJSrZ_>~e=dK16yf#c1llRZa|DrhvCdZe_DtPq5mb{ISjrL%)n0rUpm zRc2+abyHwjza1hz4lq|B1g3DpVeMgx2wbPQSW0p3welMJG0dp-s}z47&HQ&dPn!xC zGA7V7?g!>IOvUtNkS}8|lI?Y@4cuJipOKrdrV6??^`|4Psk_Odw);NAV3qZKi+w2U z{`n(lnd(2`9c0aon%}8m8y-d0JbgnTYa$sN=4!-Jc~g2cZMr&NZGfs>?yLPn)ou%` zWkvj8U+qv;i}`9FyiK)9zS?wE`&L*jt5J4Nx7OByDeIp|k>kH;g8L5uRdAou=;;__FdvnD1!mJa^;Ywsdk98WVho1pRHLy*vhGZk=#RXom!w<4LXL zbJ(iXk2=}*bH_U>g#g4AQm8WQguoO>8n%iFXpecvMz!>bAeP~G3%Yqf_g(k3MZIOC zH}ryaJ+-rrHF>n}A(eEjr>w+%gF>%^uJ+3ip_FbIQod+z9Z9z7eUp3SuUk4Z zy;8ONNT6dw=X0zlYRMgZ6KzBuJ-=9y=E$R7fK+h_s0p6b0T08I)u{t6I;&4!{koo< zPT9BZHeX00WLk1`A;%jI8Lbx^VxBk|vO3jJDl9rjPl`NxmtC?24N4QuG&Qoge%(Ix z?Vt8-tGsPw@uijH6lFdETprvf(pW8=Hi6S-&wBZh#@ErYm8=X$Zh1-C7JjQ@`R1(6 zV!8Q}tajg_U;Qg_MkhK?NW;HLCX+Hr+}~Ku47Z_)G~UdkhR235t`~VVSMiWOhdr=QBgr!LP<$V z%LwR@V3t~zR<@M6W~DilWg;|#`ZkSHx!Xl6+jiTs%eI@9q9PY%G`pyk-L|xwo(WUa z4J|kMf4|Rp-<5KbiNKLxx8q^G21hRy(1 zL%+oZ2HLA&7*)SBduzq=91-8i5>GMY)=y(~EG`c^J z-c%ZxGO=8+8yF9g5bU>Md_DGez;ht|&2B;ZqhUPEAr_vyT1TfH3)8Q;j)?BXD2V8{ zb2ObH3L=P}fFzCRI?Aa=^xy9fBl_8*fkMSzs|H)2>r~7S#Ghy+Cw3*M55bGYM+kI+ z)$JiHSZ!X*wJnPvI!^9(s=g-?{hdDAuB=6NR*eAyn`nMNFT8e^DVWhkg%4OEnx<%TD<^m=s!G;%M%~pP&cGt zeTgq%YMG%!n1%Y!9n$PgY_HvcVBBf@5R&hTfzlz9oE2ARIqZu9m?o6YarzUyE~ zTKVqdde&eD>Xk-8eqXE*<}9A5sKsX59$<5b|Fb#`jYlt5d>+$2>lO}hB4`JGWbj>8 zmmu^zfy)rM>K{WW)=UJY3I^tL{PPD`U|uo`@V;nzN#Le|TG1O%y4gvaTqfx!RZY8u z?BR1*4tgKN>KIKe5K_RX$51!x(-MD~1D7(ujlhK7L6Ug<{D2P}0UA4Cs12OE^c~EW z7=om}-4@Ar3cl0!(P;{bzB(Rbbmu6~aVoz6UqF{D)ZNqAM)JOG)Mr41SlO3f!pc^1 zX+TPNjT_F_uB%X{$KWShYrDfhn^o6}BQ-G#;R6m&;Cw3aPF7gUX{oqDeqi9LtQ0yI8hc^fy&z8^_twl84#Wy@=U9tf4Tz?^CU{ z6OnEq^B@F~=J>@wBg)rI_CIVt1?@L~uH}L1tK0v}=V<>T-Tnl&e*xMDZcwGPn%)l5 zX?{l6!|I)$L2LUI9M5u7H3cDtDUfny5>pr$c~6Mm@Zs|N(y_vU_`uhCp@Gh*)BK)o zyASwAe5_R#(29`E`J)ACPZpfMFsR8KCvvWTmN{~u6-OGuwX1dNBox%X8T6hb^AVB|zeSxBn6b$Hk^7 zkNj6OJV);W6TW<3YfM>UHI1nt)`Q%QRoQKOV&JKtm%Uy5TW<| zVNomG>Ti7#XFn0`bz=2iZD%NVNGdX7>* z{kBbez3uJwIdXe9neCOdZI8!!pbl1)})%_X`%A--}E4l?SRcUtr3`Sphk zw&*?FeRft=OZh4I!0~<{{^O6IX+(0qy4$q`^SjGvW??F1;d&C9L)I4@rz2k^~6MSm!QX@6LI5_Uep-#yv^KkVL@1KwYp8qhui(=ufk@cOe`(u7qJ70$psxbzJk9os&^A$fH=k&=*8!cP) zuAC;9bHqD2q1o?C#~I3%u{$Qjc&UjlDCbG+-nRjxEDYQhGbG^4XvL7}E|XAIR}grP zza&z4Ft=E(99;hP(B zSH&#Hah?f9H1g!^XH1>hZdpb6nW*#sOg=Ijr^lK(-G>b;nN!twO|cGVfokq7=O&D? zeS~Aa_b)e>8zEBz2qXa4jY1uhs8~rj}@Q?9$UB-vRKfPbL9{BgO zC{w%9yorBb;S(yT;Gfzt|3GU2;!e0rN6C6u@jj8z0~Y*ZE-~dqRh?dLXOYs2J*cm9 z!K-Ytbc;JM05Se%!JqyoH4p5LAxWL{o0#dxaX#8L@)HYke%3L$og?0M$80Swt%sHQ zV;~u<%~Kn<7aI+9FG~?SbD}zJW+qN$%lSroIgk->@9rO!gg4kWPjvo-2b>Sr$Gqu^ zd1t>fu>m!t^;x~BNv60m-Yr4={X8s?R=v`r-Tb+)h^+JZcVV5^J`!H%w|K0Jo{YXB zK02fEl~Owq92Sm9e+NnzI7j@zgF4vYf8Ye^WAs}Tu7*O@^=|mn9o1imVSMjMXg%HH zk2vZfa&UaME|ECFR>(mZG{7TpKgH9h z_F@7bMzRwDM<_i-8K0per;kcZ5nZ>ZZH>23`*vt;42RU?^LU5Rh~Zqvkiq$avw`?W z!TfN?$@l~|9Bd~`$kO*<8@vffq6YQr>bT}=65SE)ZS1MG8@g0mg6xjYR%L%<@u<_9 zF#S=4OuAbJ9J&$!)zK5oI3)lM@A)PACyS9X0nIw#mFISQ?@0tprG#+%FIJC!5D%_9 zJ<)`~I@*Mj?#V>&4aFJz2<>T{-qoB1EYBx?hDkGmuA4p)=OIWkq!TC|n-(h4J5~Dm zU9km51ZChBRhUF;rgC3oke=TDrg%V^r_p7rStc?)$f`WR?|`bFA!7*5#=IW_(@ECN9x!K7}?-=Ho=0389z6<@EV;qdpG|-5E}gs(*dk`Xj>StonPs!_rNK zQs_O@jKSH&O6b$*-yH8PV?^H+R0UUq!Z|EmYn(mHWt_sQG(QF3NCY=5yyU6YnxR}D zaPmhV7Vej-W{&`p!--+oWNh{@Ke0eO3K$(Y72A7(_wQlEmFQjj8)HV5qA0AfT#zbHl_BY5{1{##> zX!7BmH3@V;gBDR)>^Cz3TMlnO5{r$S2xl;f=xEK*d)(exQytWf7^J=tYINaLe=O=% z5x&g}BlIahgbQ`48~FsPRDis*?RdWUg*qem2YhwQc!4l&?aft^GV* zo@U%oS#)_G7hff%hbNee6n|@V;{Q1dw#(F|-V+2fWPq_7cR5_63!tQdchsY)QRz=&=dB&TF8V!3JSA=9 z*lR*Vu<*oxxj3g*V`Z3==Q0`qY#pQn?MaBQ9}5iVmGK!s9B3PNz@7@GD>}&70;oBO zs(*jV543Ap?ysia!cjUUOiid8d4m7pemA7KE@?nL`?DEg^E?MnVv^TleVoUV>)SU2n!?AShc^ zXDzq0>IX6ku3o56ScaCT=6b?ufzQL)7c_JM>033Ala*Yy5i5Bk<|OvDrVFu_-{Y7I zHmJ^Ge$@-}u9!`$fK2=f38MjkZZ?l69d!%@)N2* z)O@~%K1_Z_r9%a8=;F}a0(5#$R6WbirHOc4sNY%8tRn1R>q~IQM%xtty&$i8;~Ih4 zgf}t%cQy7e%*OcFU|wwud{eGx5{HBqC^xCU@t7Uf0{BeHeALaly}cXI-p9JV0=9R1 z`}X=Ar9I34i||psb$b zyXdFQeD7`Bo_`ozsUiS1r%o>eX@5*souwD@Y6PGI3iv@KPta24=MBUdxB>@N1CS>t zKfx)_vk;(sd`J928Iq9Zlm!1t@OwIiDmaydoR3ge3R=;(MF0LBOudL?sQ!7q?&5KD zA@@>Xk46_pBP^_0byc6venWR69-Co&*MX+~E!c#+8Xw5uD|gK!YJevvl3mLdT>WMx zh7PuiYn|&_Q!VAe$5Q3CGfw_da88|m7UO~^Kc{(wvR^nV?wd_aQ6={ z99-E3Z-d7oO!c07)CccD-Qp&<{5F^>^wEPJzqn1bsH6|Vr^z3GKnRG#=5F~E>lY%U z4jaiy!uGPB` zGl2~wuM}*sA94K*PSyOpo!?-+M&UlqFgQxcg&O!c&BnU`*k|ITGCQ!l74bdSVJ?B} z%D41N{z8eQA0yv2 z+O_JmGvwVe*k}+~mI!x(TDJtm7e80XA}z0|{_EJHjI}tD=i+%1)U(LO3zEYFeQuO< z`ueY8i!;8`dH1twOk;5%Z5;9vb=`mIyxVj=cWEK4F~wQisixb9Z_3X%7R5rfT~1!$ zb`~~5W=7$Y{Y}XNkmI4(A^!u-t9KMN)6@kAbCt{#&yg>cC^M=vyv}t|RXWqCE^iqND^c zY=2>5&0NBS!8oYL3N+J^0x%t)<7e-rNQH25W39Hd0kB1`_%mW?>e)?P-|Gw_%K#AXByEZI}W!>#Nw(8>ar^ zGi+#G^Pf%mucHx}61+SSL*DP{TTyxVHRY$pG&h;@!GDQ*PWF1RUSrK5oBz-Vsh^)BCcTlg z0|J#+{y}3+U}7el?uDd3uj6s~0dMr zi^*a0ANT=(hccu<1=pjZJk8-bE^^*z@n;PY_>JR~sMuegsiyy+xl{9*WJ-KJkN(jZ zTQUrgK#jp^{yP$d%lg)!T@V}g@z=c@M(3qSME}}<`bwr_@0F0_#xt)9S!{sLN115S z>7&D-zIdl8wke3tfg@lybpV;u_nB0IJ;#pSoMucwE`;xH^~a6cvE{F5*PEXjL&0Ey4U`_?H_}lcJAM{y@FR6s zxE_pw1hOk0gkyq#pvsYCr|%xY%RTD(Cfk0cVrCl5Rv_kroFDK$E4Dywy0Y|Mm;eEe zfyAA5B|wi{_K|3q`JoY!_4E%-$r+a7NtxAIY@Usxh}gz&zuyb?4hn?pDnJu0t!rLb5(P4hhdc9ahhA)QM3iQtbl)c?Nr<(P*^G99tLVmxG%>(R; zf2?CjBl0QKzXj)6*dH}R4)4|Es7WAWD zm_`1LNg&}pCOpmr3`n%dZ8h&B4b$-fnP=!vpa+FGkYw_wXMI+2je5kX^(w%TR{rSgd~ro{1E7 z8TeAu1HEg|t3-4OzTUi@cmy;2CUjYo9Le81vormYBFKbtS_Pj?`sDjvYW$zj4}D0! zdWau`lwZaTCF=|}6v)2dRa{|y7AklmS0 z$5>4(&IL^;qL5&@&7VUZ!f65Z$(7J2FOV*C>;4J7A+}hQ$-y?i!dGw{3x&guVsd_8 z$ip;obdtg8ZD8fD8DyFPU)o+Sv+M;SqK)opD{vf&1gIB4nykA0?iY%UclDFvyI+)P zIeqYIQ0D%59(tagj)zlj|YSk;fs4srJM$%k&= z=5Igjmgu*@SSIe;9NZG5<9z^q zu<#Qyivz3DDv-$K!$os-!a@@cr+}o2{gZU;i1jF``tG+bi8y^Q{(zsML02Mknr6dPso z^H_Th`8o9@FHBxS}L1` zdbrp(18_Lu*7HU>;-+IwV7Cx|5S%4t;*d$zn{(jZGET2&WO^4up0n%Sm>xhi1z?&& ziut?(Or&xxF}XN8(4D2vsFlOedm#D!H$XqvVD?}#74*w(bho3QsURsX%naP1!7j4- z3Gf3o(^kJ!(_bFzdv$%Mjs7xGp9kfWMZEd|WlnsM8i-MCBD7n63Z(n-IS3B<2?`AL`$_SDrdc4O3X^5)8R>6jK1ZIS1{ zbx7mCoA9qvGq{?xm=LD-0Gq)7hHL_UlU{vEqvg&r~?fQnzT!!0j|kA)OQVf zR}qMR2JsD29xz&k@qlJ>S7F@3>1*3?}%dlWtzy1OH7v8#q4L70?ID5>X**9}pwpn-@_<$>E@(UsoJ7p?GZRF$AfqWM zBiLuA;#+GMgP8zX&URU#pA>+VOZ^73YVHnld>Zbwnzq+a!C{-VpiojlkJoV9enVk9 z%)hgUt?g0edvK1H15q5d2dSBC1NZ%xfqoctKEw+a5s|6Jh5J~*IR=s^qolei(uY{$ z5zFB>>?4pn=mE@^8`(hiRP?3}EyKJS#4V^YflMX{W<@}7sfQq#6#+pG60G_2bTI?J zLyR}2?QwM$M)pMWVT@deZY+#+#SttLd5w#0SwP)JCqYpY8G(sz;AV)|=xp=7C0}Og zdlm2)Ei=x|q<8OhzyYQ{yF5+>iwM06dl>o11-jk?tarJrM(#m6*$!%7Pl4rx>m3>* z{Ux#9BZU7TG#D8V=OOn&sIgoR#-)z?wzV~kcvW*Tdamp;Eo`c~$lOW$Ab>o%(t7u+ zf{1^9~-hFIXU&Xm0A%PA zaE30v7{$4vJNy90jD4fqh!JM@9_mtMfkr^#hV4HZ*`u~b%9-5lLoTf!QVNX3Ec~n# z4yxyEg|Qa`3tGy;;d#K1#?C%pKs8lntCK2q?vxHVe*d5XV=Cr7DP8TpTk9P8lBso# zrG7fzG)bjpqgBI;I%v zOFF4m!*%+NOuq@!2>H3Ok_{kMU+tPpT^IWFsDKPdywjdsjD8k^3ANgn&2k$ zVvy`)7gbx(7v-%!+iL*fXm0H{xrPxGh>$HNV+y<~l_0<%e_@}kw=;ESqU@VkY`0EG z6@W0|Go6sGJfI>IAmB~g)LLW^HOC`8#QP`e_rEj8SG$c!6-a*Y?_hjWFavX#*6Hwx z9H_-)LM=FT1(Rm`MBlt-yaya^sfz0!NIsh_ovvHzY*R4a%?CW!U=7qamsp+OqpSS; zWmMUNhRn`GRV-G^Vu9q|Xs>n|7wH8W5d1Nrjr=!|y&I$8tX?o;}taLgPvsP;= zERYdrZ-MtKlb4#w=So>ho<}pfIzqj{fYpfbusnKL*K$~6Bg3*_63>}bW9e}zq%)tfr zy{wis4o93rISvxV%aXFT7|BWJ3<8UgQ`HK#qr7F@|HgM`I(Q6Tfy!P2y%FkZ5&lvC zz7KQ~NIo9l*b1M;9PWXS?=EGs=?|n{K^fBtJbqP%w8PtNxy$jbzGC~q_~-D=ztCN% z$bB#^G<%RBj`M+s7q?+@jc-HykcmkTlE0JG+I;d6Jf3+0YU2Z$>?sPE5p;Tw>?1pn|4@1tSq zg7IgWzh%|K`qU_l?jwq|K<l=Cv8A&d$?i)fS=}l1{e#^O0`Y`Wa*IX9g>Ht$w2IDOkVU2~u%C zR z=iV-9J5+x!pzqI}BtIL~RFt3x8T>)$8Ocjm@COlB;4pt|d;Uz*s)8sIyILUkOg4oh z0_Bn3@N_l?Irkc?frz0cL0ti)wDdT}Zo?Wtu{cvt z2=M1U3(yDLTRCyE8Aklwfv5aNLJ++4$RdOm+6%J7R_bqac%N;LI(2xa11@1kLlMr* zTHQGfW<0#gwH(b6&m+`EFdu6ePoXEq5BR8<2D}&HETXI)^f&1jG>ZdA3t~e-%NZNl0(|N9T5lk!_ z45v-LduqMc?53Wf%w804Ci)2ep287vn7ct!qgfIs?$_@U{rEj_u7%?yAW$X>Sl@z&5g9D|*~0HIo-y$wBWkYkj< z3+KyNU)W8XR6Ppwj-S0r_@j;)rEb17(_tzF1^!f6+tfFEwD$W1rec#wPhJg_MQdI} zFZNY((tvmO0=hNpV3CdPU<10*ft0lr`vi4R>PnSGf6p@- z&k5kpwyvI$YGwVY-0p;)Z^}O1<{V^d`0%yUkHolc{%%>r#ZYOOK&TWWvDd?8$70lM zek%epng0O`wL_eeu@2#i184U1FK!Jzj0Dq9Ln{&-eUB#53>@ePcobG3+Ug!qERc%^ zsdva%v_jGIMy;^mRN#`q ztc#sE>~b6dqUG@)vbD*`D*``(#K6IV{iZnK)>0wMt^HI1@Qt$c7%0Ch&<6j4Qixyf zK=+Mgwx%WudTp4uxHXuU$0T>KvV#BOFId4jU~RCiS&@fN8Uzzm3yglkEJV>nZ69i* z8cXmGg*jREj#UnMOyHm2%LNLIgod%4Cne4in~aB<xU0hnQka>=f7n#*ZMJ<`Elq0m!h+Z$@Ul&1v z5ga}h{k0|2eNG<(n7B)S0+?2UOv?tfC(+{4x=RDyy)7{yQN9b5gIYX3#_7|c3jAvx zU)t!Pk-0(NAsZbW3QyNY2mKD2SPzz3TeY}Vc4nG1WCK;j=J{tQh1CST+It<>Wi>$^ z*>F`^tD-hDJ6IK7iDTpaL9CK~C^)PS;w(?5Ab3o_gJ?X~(i{5(&7fK;9T*s}n2O+~ zeqW=IiG`0klR1HYjX_r)z99F{T<^1H4Zxb)#>lKI>(CxDG2OwXMjXxHfKN9}fS$rG(*;s*2kBUFXsx`;Hk=9!irD9mZN)jEKf@Jfr!*A(B1!9bZvEZGeD+UOWc-5^lOJ7jw{U zSZ;4*Bgf=d@al~4t8;tc!SN`5wYv!CmlbGZ;c3~Mfldai51rDu@0oR z=-G!ES9tb$S07{cr?P;3_8R&0)AL%M{Q~}VWfcF4!oTx)@_9`B3p27K;Gdn5wZT7O zWETEyH1Y4;FMb{V9fRKi|04YE-1+6!3UC41tw5OJg;${Vs$;Cc6D(j~fnzhhqvBtL z?;RWeEWStlJ38N!*;{`lHGjelXr7oL6HmB*O|E|=o zOaB2A{9%-O35O7ZfMdu2mq%}yK6Lsn5eA6;d)%wk#HIy?wcRY)H8H+BoAZ;YzxjRp zD*!zz=wyKV$y2}pU;I3bfJFwcuziQE(ZW}$Re&FAUg)|mtnY;Rp{c*^rv}46OniS> zSqSTIaBA8gmcQADXId*FRd9K~2-`{dj%J5i5@n9zdf4?hmJjp7p3JsMqNAeXO4+x3 zh^wGs{f$AUF{eE8L7Bq;RDT;`*Wa=e!m}1owVAbz4eD86Ji5bKpUiCAtlP-nU%>yO zWJn~EBJn_>gk_-c(9lrjyo!sW}naKAx za{Dzvt0TE>+izr#onb)8$T6O(=Xwt$CU53{Y>`DcUmjOg=)J}Hu0`G%l6AUT&a3y+g9qR_#Cza z9hsj-u*PNIO~nfw#~W?Km7&r{JJRoqdk15 zGO>;q#E!6ynMyjhnLT+<(J|(gp$4}y7qVtMv!}L^*{q+IxeR``rYR1w6tf~`GSfcE z`?nq0n{ej5SHIK~*$0_&{}_1c=8EOz304Nq?2HG!qxL~KSFfsICjKJZAj^U=u%yEs z=!wj>t=O^gv>F^G3r|#FI=E41?SKCFcq+5D^v^RB@k;ow*mn;p?r_#;Fxxik{|-;9 zBlo*R-^|_dzvPc1@3Boc<-N7x(f6193$^)tjId0~`^W zcTt?89e=F5v_nquG_!3haBRFg0)Mp2dp-X^a>jcd%KHeIetS%LZ|##P?>pKj+4UzkuIH%loVN7Q$g3KK)?D#(7&ClWxF~y2$?f z!8Fai)VvCseQ@~nE+RUSmzHkEUg}{ve0mx%<9@2C{_v^wyZglK<>Av_*-s7dwseMN z`wi4!%^cSB``)WS4W1?8@Mzh4TK*qDezPV2-zhSB@Mx)<|AB|=py|4d5`CD&yCFyu z?YAUM4eyEe$0Ln{$QRuqY>YBr#If6>VmXGOPikQp@_nTJ*WmX|J}iWQqm8@qBzTZD zuuO9+8Nt9V#rw?#$fC3L})BT9QbIDigz9QDwS` zHNz?sU!;ksOd0Df5`oI()Xq7U$|M>T?A6QOqnZH+@&Di%8*N`fVN;t^(pw}wAH6FZnE^LWBcV?cM11+@X)dJs9iT6(J$vht6Y1(oQ~8h z-spyw)GjnH^d!-*=v8CWul~{0mY(d;If8z581e?h*BxJgrd#g=2>R7_qW+Q*eqxFx6$g>dTZQpDqgxS zn!dLFN`31*sDU>5(-D2Wv(-*tS_Fl+B=0zVN2ITzF^|=M+b3odwsS9ZeQiMWLA_r&Hhmqw zxD9R9we{~#NEUEcUVr!Pxhk-o@I^`5c4|3}<= zrvHZ}u)GrhMG;|kG7HNqi_Cc8P%Y1CLtjHt`3Uq?ZI$bozAkNurmrn_`Z_Ahm6>9e zj!+x=I;ws*4Kb}`zyBOjw!MD$Aj!nGw^@P4JJ#wOY)S>y)%M^Co%Pi_-!{-ZtW2+D~6=$7bqe=m%2kX#Q5kfwuZ#(zSrDwglUu8>TnY zY@kXm> zGd{K3+u90$1-#%At{Ga7;+Fra{W1deIo>}T%jj5v+{eDZ*r9geZ7?*A%S(6QCoV7b z$oiCb7_9oZ8}kR28?DQI=|AP14=x6RmWAV0>4KMB9p7-X}WelLb^ui{A#`p(K_ zpSx1{;K5q8=N*#+y@*-5OP{0h3&zIc!0HMlwD_Jgtxr7f!C8UASeviGX8IidhG76x zRD%Y9`3ADzLpsgEh88}Tr>Z*x@ChM zv=GJ@w$Z%Bc3%Sfb2C_vT)pGHyXA;WCycuoQ*@VVg(&ck3UudBdgZ_t@0YR8s(j`J zlGYdd|4E=o`0xHqiyUAT`b(d1-}y)p0v8}=!4QPPhD_BRl|8bYRz*aKxaZYHt<4WI zZochl`^4FBXN@-y9>10bgNJnz=|A zyv>`@G_>Y9YI0;&*{5MvYc59_^=%gTi`>8WyxRmT^=hVuYEAx9Go0mNh{h~|mf!YY z+!{fY(0tU@`-DsVgSSKGdHOcthL4^CM}_6UbZ<&+Ljs;;me<%B$liGs*jzrE;@m

    )|N7AgZSS>SdB-JgzLk>63l9VN>`Wd*IJtdwo{J=ut}~-JZ31J-BRJFI zvI0o2LfWSTs*@%?xnPy6g z8UW^r$UKagVrN0sqi{V_y(#$YIobHc+ZeNz9^sl?_^U6baGGhdj|fs)m0 zx{A~Hqx8_=uON-%0p~VXVT}8jKIlGrG?k?U+%d*G=4r+E-Y=XP-y8Qc2M?nLy5DCy zn={bSvIf!&_5nBq?(7Iw3dcZC&8I{El05tXI{6wbE~CpxYM@Vp>5PteXM?V^jDK8O zfM>Tm=&j%<{(_ZtP+G8l(1KUy;Zxn(pWJ4p1B23AUMbHk{;3hn4tkl*KjK;Rl~?P1 zE`7K|CpkoTCeQF~&@i4}T)LbfsVQRpK=z_B;G0I{h`@k@MgCeDL+Ct&dw^Qe#Z@sF z!3M_^1?N};7;3z@vJQhmQ5oVW-N=<_MEw)hXqN7bN39%XSD{w)FzF;5Ilo{uj;X(a zOx%JfK7koA>S0tbGNdOrZni@PJp|8dH8?rb(L67L-@Fhw&|YtxuE)O2dc1=Q4RE)O z?pl&EO}f+e&UZ9RecxoM=?M4JUEP5AQo^l7vjmGN6{HeNK!E5FNNOzh%N-MNPC<|e zFAe&<4s(@?Di5||G|oAbPzk&%5yvvHW8!H~{w5d1`=DPUbb>toq~0vXlYLuO+yqb} z4cxM5Q*r5=#l}x1#yj~<1;>NMAlxvCH4#sW!MjK$V9Ld?iX`fbk_>4Xbo%~+*7KX< zoM0!SP_7`7xC7M{_@_mW4hK08FwwuvyhzdF=?VNcD+J>nMiUP2&z*2f2pI9 zsddB&ECEA;I8lArj{qZMqA;2YR*lG8uH`Hi;``L7&vOQh(_*o{D;Bo`;@#E1`r=7Q ze1!U${TM&VQi*z%g^R3g|1PwTH9+fSy-Z*hBWgxs)`rkbG>?m|E-4=xk6&g1yl90N zN@bBkSIQVFFm&9K-9;Yxf5D|;MkAL_k>-!gr9a30b&E^us2jpOhON`g<8*ha+(yjW zkW)>*iHGV7s`Fx25N!}417z2TsDJp!V1SGYq#~>Y{Cm3S`c_=lMnp;0w3Q>*5S_kN zC<*fNw%kV|!dvHZ9)C2{kV0%6I$>jQNFG0NZ)4L)>>-2(+g#bWk1Pwzr%z!lubEEg zkk#5xm*{1aXA-gcDub*xa@$F^5rH9i-oD0({+uHkB-Dl>v^LJzWcvNUoMF-y&R55y zPulRRtR6UogD8wSe|^dWS%Jnb~cD zR<)(PNZ*C@ejB5&M&bapiVvfN_detU$Jmk!?5ZI=$y+fvv&q9w&k9+QC`kBPKvFqd zJx_Y4`1AC8U*tWEPXJ+f7w$|`!c5keYc+&{)cZVRaa+cJ?{WaMEIV*_Ox2dzmw3@b z-vYn;-omO4Wv2)3?&Lk(!*f!BKW|1M=)I@6KDMR@hJ(4~>?^A?-o1WGwpA?8KWQT4C%3UaaKBUt#Uf^^px?xH@4E?nZ${1VL9Dq;PFI`PP)<>* z;Hf{B@Gl@G@`!Vg?``PhJ=nu@s>^@Z48%OF+Ko9ZCrVJO@TwTRl$x`??0M`LlH8?iWIW%~ z-dhrQxdMg2f^Hm6wGm+&iUM(SWTR~2J7Vw{)Z1x+f6x1sGvhsXX|v1ZNuE9svuweN zAykY#rMf$f(m5{8Vna;Clc)(r!NM6ROVP}I5e~f%@+baW!SIC%muZu8Y37AGQV1n1 zrms#!`)Gp?OIUbVg z7<2gL3eF)~3BUL;(domU76TrimLmH{SBvjS&IAFVFx1aQN22+Kx_RB{1njEMIRI<% zaNS1=N#FRkM(hgec9`x87Cf1!KjNO`zpPZj5B#wp;RES__fpIrIGf1Y`J_h{R=F&| zE>VDgi~%JfpbAhOoGx19gxn4DWuP{+p+q7*e8{Sjxj#ih3R?k!d)F?5eK9b(4$Jw5ko2p^l1{bLk!3~{00lperqTK zeFY2o3tnmW{tQwG@3v9ZLM&^$efU(0DA{hKAn}-gdgmR;o{h%TrzoN~%aMIIjaKOF zdUgg`QG}_Yn%SruDj|L$k*iYTe~Qfti*zBhG)GX3XD#?zMWQN4so;)II6xNxFUls@~$BO9UcUfUO;l> zQ;byw_;9soSekmd->U%)anl>Qv~5Lz?UzNeDXT~Rtj-yo7U%Rmi~jt5(kKi*sy}#Y zz3LOwNMX=eTzUwTj~fxVakT?cn_Mk%X`RY8y8J?DFyGitZY}mSNZ3=^iGh(Z##YmK zv(NjbGh?62_!IHR{b)&`-<f%Aek7zgpciSy>4IU|0CR*5}7nn%FCFHm3s zd>)~i21Frx2YOUKES5waEX50MvMsh6#x41a(PFrlZjRmox|0 zm<5ZBMwj=kn8@H4qvK*@k*?@x|Aoe1S={V*vB`(fq{>8VVf)D__HBr1NZUc2K0biS z=#7YP5}WA=?dN=p`S1x4PVINtDxaV$YfRM|hmQ;ql~dFTRxZO&&X;(HLFs)maTs)P zRX*tC)jk@P6J=hZfhK&y4?~-(W|&RLNq}$-c?dnPdo5s$w>boL;;Xs;352TeTB zCayvgh?B&yUQIwQ0@eI~rYv)#W4-Zjs(gZB>fX~EllEO?&?h#no@w;)Eb!25JP z`o7~ZdU<6okbCc50P7sU!w&E5DU0p!-nd)f{dEZN?g31);QiG#0`D9)u@ge5T9bix)Z7yxwT;dUR!!yqIjkk# z(US%~p#k)4saxKc5f{N}&M3|~=!wU{OxcNmbAo8LQIqWnfv2i!;7MQU3)+{!3QKiBTYV|8A7rd@^+jVyhUQt@sF*bGfD;832&c zcIsi@@^U|Ur1!K_vFX4}j`*H7X#U(gFn}8B1|VeRP9d8`$n@6T_`r;5RYwf;4amoP zCK<>M>o4}s$-nf`NW|s>eq^++slc4LXj^Lrq7CzM1fMJU>AOV;Rmk9bcs84Tufo#E zqV$5~!5O9i+cg*G9X!@LyoaIHaNY%mT>_&rqB!pGQD=yGhnw^H}Ao2QSW0HdGAe|0oHgUdfAL*=EYCM`_4#3Vjr5w%(1mVdAwT{H1CtOX&vRZ$>Wud~5A6l`{;Hj( zL7PxP;?JbvT0%9B#M8;}XK1a(!3j2U@h2lk4Sh>^R*KmFSpEm>W+LSuv6XK|j%wO$ zm5|qp{T{kN?Nid~cZ|}wIWNu; zM9(OWu;}UP`*RSm-@A5T)MNJo2Gx=wuhz*J24D<`vOS$K%%t85*7J{o;wEpIaThF8 zQ$%`gfbw8h7t~K%D$)aDHiqV+W7r4r`l#DK959vl6K2j(kN+9XRnZoawb z)aCsTPL>v-nhz|J$2)K%aM1|jP~Vur!_!q?84Umz9>(+L_~20>iu5{lQFvg`5jh;b zh=GUiR4t40U=0dilbV28bK?d5QQldpx(w@#sjo-645n%(66nh?5#5KLMN5!REgnD@ zhc{{(may2EiN|SXrxZa8Re3w9Vh3A4pkACPbIiwiI?mos0ui7HG3$ZH>4Ei~+gYG0 z?}a%5)AL-6w?y*<_;I8bdOAQGT}ScHN33NTRwKuu&c)C|oSx-xgPNJBS@x#tgz%}r zk>OVWN2n11N5=02jvV(T^`p!9gt+LVJC;BnrSFLr<}ZNoR-?hz(0Y(sweo}N)a%=& zt=7xYR*r5fk!{tY58&J5NU{XMEvPS)t}bWIdv(oqtT|lQ+`0obeY)lxTg@!iyd0gX zVY*T^D=k5Z<_&6qPMXD}f9Q7Rvz@_c$3C0C!ROjGo6kTHp>r`CwSOCEyf13X+z97_XoX8?nm_We z{`+*oSKt$7ejM`Om!D=n6B>2C+xXsp5g(4r+7eoV;~ak%JNF{};H_#K1H|v>_og*} zD`dpDFn`+#+O_!GAmpgmw*nuqrC~f{Jk1S!=^~0rV>Mn6mTHXM8w{0W1h&pFe)1=I zuXhrr#`l01kuP9#IqK`qJhXrc>d&8q7kf>6j1Fa;2lUYVIb45+S$~{azn884j3d@> zfB1kD@mP>&BN1Qxbc8hqr#xBfc;6z%xe)I=@29>(MJku`}K9Xxqv z9AhJ|18KlF0fzq73CB?`oatWxjq+v`q$RWEcxsfhz;vpZ%|Co5nxE?IYq8_K1&KUZ zg#H~wac=v!spHYQ{yGC+0&{KXx9GQR{A)Qzak6hZU|>^#27g|Yf}TdH2~N>1J-5)m z$sa%MNxHOo!viw%lkhV88{d-TAaQ(5CQIq6&VMN57gOcnf^^iqgtFw@bW_9r%vBC zayRO~e1{58bFila>TZF8;17}P?*{YJ{2y4dG(Rq<-ub}LE)GXVeNM=E+1r7n zgvy^ji-&5vU@}sROTPejhJR6PI?N|Y@R}%z*{Ocq)1T)QN&ft}nDrTN8~JgAV#~U? zwJ0p`PseqR!m1XRb3_w(e;OPw=J#c90dHprP_|QO{2*r+bWqO7T4JjcI9xv`WWB z23{PPo-PUnp3yQsp&Q7w>(F;FADv=a`6*~+-sb>afgkT5!cU~NAm^I`=ZJ4gN_WBU zPBrfC?PsCS_@D-RprDGg!np>mMEjabF$eL4{TBhC(-crIjDbT5;;OH+J`~` zlHnMO)3ACFzDw|{sB~`uAB0C7<|5-A_K;Z|Sa^Zp%ILJ>Vo(6|2l&jP5MC4hfR3E5 zihI*qk1Oj1H0Vxzm>kUS&X!Az9Ys02%Kqgao>XG&r~izb!{J~vA@qy+R8Klm2XLeV z0ao8*s3pTL%4u}^mIH7lIbS)eZUZdMNfFI_6EXY{pKbzw2Y}I5UU6V%dZDqs5I64W zPjp!Qp8Np00;59wAc%l`-Jz_ECkbB%2#Q5d#)cu47>9%TNgO!GRA_``d@{D;oX^WV z<_JPn=-8qU_CSxV(P`t=D-(2&2z)H7<8*IVZ;c}cf`)*{g4nNNP6Yr6smVlan4izY zgd)q8CLL68B*n%jZdi6RHpv3rgLYj3Hx|CZ`(tP4oLa!8BrqzbI0FZ@hkH2Zyo3ZC zgFEL`vKym5YfF77&RzdSoQL4=6Bpcn<>Pv4AisFr@_E-NhL} zIG6+6-=P>zkezc*$47zjWmX+u%c=h|PT(60_zDknd+QSM3_)3_z}W8HzSn4QwXAhI zeL*ZV+RtbTlnZomEIc?C(3Ls{;z%5fY4Gj;NIstcV6lmh=ODm|FB#g35?Q); zW866(mNkd&KpQ4M8d8|urNf6+C^u;vrUZ(b|J%AP{Iusbpuvg&AG;rL?bJ)lSA@OOKkBaO_-)F&j^h|72%-n+&jY}wP**FUuYJlk*@sIE>q0RKoZ zC@L%FR?YV!zD0wemUYpgmR6UyJTb;|p({9)*T1pbDo-_ykx0^##xWXoI3?EUg*q*3 z;YxN7io5)G##J8Hip7`sUFg5WRoO~u>0IzFei!5%b}r}%Om}4*@Z@`&(hCguZ|rfy z-!i5}O+r%?7ay4|#WcALwx{c#&(uK|Iu}giM@F!)s&)2ib7hk^`UroptwhdJ7xnN@4FV|%%=i4 zeFWrt%|qx=&Xr(1Ugg6w_m8C-3*lWuPfnyh%hVi6)u&SMuw~!a)$4PBB176EG|AKZ zK%x{w4nQyzr1imY;cpLx5gO)f$ecd%0>~aU7Hda%v>+dZt@VOB=mpWI?G>!gmc{o` zU4e!|(}5*|=jwtjf~xQ51L3$tK-Gg@jCRm_?NC+m7ARU5DHEl5TY^NOU zG{3Ife@~}-m_Cu|PwMoQI(;Mbptaf`>mL;dS@ysO z=qqDW*<=`;vG!FAU!v>EMzk5sp@QxCN2P!#Eht2`>^++2YQBXHKumFf=erag5SLh6s!XhlJ&1i zMJwuY5STkyhsIk&JE3@~=XKr5tos(~HaFOoi0J4x4uEg(7gxnqU-oynb5VEpT}gl} zj$W`S-(xgjTiz3LM11c}I+gW;MQp>4^Bv)1VEg`l!f%Mx?f3Twdvv(J_l&c|NP>Fe z-=q<9cRz^l$f}E>G_072nbwXxjmxwLaQR{gV9_(i+O=PWT6))hE4~CzITyYMb;SMp zpHV$(zs{CNsaIO#x!slhx+?VwPSE(`xfGktk$@x=X#5{zAdDuuowwCto5Ylf&M9@y zp82Wj?fos04f}Tdkiih=&HH>cSZbghtOVQC$e-i6U;o0kJkk60v9eV+fGoIFk3)0g zJ#{bIgsh;P{XUW80g4b|TZ&S$SEs*;%ikHcdZ6xt(X8w*Pf?}sb8kg#&OuUEo%g30 zXTc_Hhv)PCXKtN~O9HoLa(^_igth=2WfcYHaN06cCS-D+FqcDc^h@I{qtp;DhLVme z%dzO;lmVZdc6v?wAiU z-orNEIiKNf&58eu-&s=H z3szm&BZZ4sOj7K!!_gf zI6`C%in(CO1GMJ9if;}FhTC*^PQB+kcgA{`(L~rLfNb<;R!jlY_K6s+O0x~N(6|fd zY(HU4-H{4;f%_WxA$xq6-{~@jC5FbK8898qzb86xFHXab5U;V;I8p&3ihn$Ke_5*f z9(EV$x%__jqcWtJVd)|6EvScLctysrRO`Jg>;<{|8wgwxhNK$57sOHBfHjaYWpRc6 ziR7hYAzo}e*{Ua%P+9p=k4hRwkA=oPjjx+Gu)oqP;{d{pO+^9E37I(`IWL1R5RSCJ zEirbfvp??-_zjIKh*5aSJz643XOeMZy1m#D?HQ`bEp%X zkjPg9Ix>^+h<@DL(i-CVWTEkXs1JeHPCsQNyolrl#>T09)WU$FDXHbhQ$d9lVFBhu z+Z?F^-kAl) zKGh9_$1eRt^aYBEQ;Wd-KooK9#Fk!fUbyMTeAGD^a20>Wjf6qeNdToa72+APcjjv9;Dy_g(sdxULVtg#5GDqe#H@umV)n_+ zH-zyIl|6TTL{w}V*!{Ttm5$o`TTUyf^+smfj z3w<6{sAVp>m*}036He^{_7a9$TgdIZObmeHv0`>Z#8u6^m zXb`Q#Wo*sbqV5wlcSaB78(Up{?}9O+rL5ZhXoyGoVfr%1M-?|zj|}KjKYj*%%Hsdr zKYYk5;viqm#Vq`G8?fNcYR2L~Bbg%Tu}Ko{3s-Hr!neuoNblAeU-za^zVz)?nqx`M;RwFI&EF;ob71AcxP zFv=QpF%Rw4>~D`e@SDN!q#hajC8*|-D{Z=Ij6gb)E?li!LZ_lYczvu6)EP%w}pQ46HMF_xk>J4nHAPBvOZgToof>g?jyoY8u zebxAME;tGQ_a3_4>H7k!;XO3fSv3$Tpm@J^^Q=K>4-a zL)~y?4xipb-JMnY(HeQ>N<}?{C;w`~83d(gS$J-LN1lz_b3WGmqD5jJ+Jq^HVvPfv zi+Ws>o3WDIICg<$CTk16=ryqPR1_k+EMG1{a-Ve9e4FN5EVhGnyy0RGTI13D{3JB4 z`5_Uo^3XzbT81NpJu1=cmfK5F>G!C&cS1KI>$BEZcZu~9c5m~d3+=;(cVe|zlzO9r zkZ=!~03`W7TE=m%UR?rB+ZvBrz}9(lA)@eL93q+2SIDzEqu%zgWo-ZtP$zIFO`hI{ zD)Ig*=J63uo8@)F1#CLfw&0U!Qu@|;qB^{T$Oq@=MztT6Xhh8Uw!9l!P1JjwYFeGT zoBNw3kl_IP@#wgFxQJ{fo8PwJLo11n0YFcUX_V!->u$WS9+s|PP+X@Ha1_hHk)udV zBVe7DA?#M$4{|iya3-g!P@0w#s8MAFNYgNRSGS>h$7A{+w6Lnn&6ws#bZLspG4Z&l z^nL7G2%V+4QUY1K6n@>U&F|^x9T+i2dlANo%aCvx;h@zQ-^g${;wwSnV9OkIJO*8M z8rdH6u~jRZfnv+RX+p=1eLpO`B6YwRJ z7=HIU>@N_AU-6;c9xw_wo*xD7!sTYL9NsS#B0bd7rL$@O_s&jrcwuPnOQHk>A>*8KkzZr^3>g*aak57Mt83#+BoIkW@I zpy4|PHh2p~=(00V;Pg6SW5P-B#e`EJ`?$#(M+Oo{-n}k*{zt))gz3@6j)5aTW<=vi z1qNf{$x-06Il?2=pp^ozxbq_L>hmq&l@B=^I}rT_oHqi>DC}Xho@nTkle(ng<&j+BNzBq&f|M+)b+x!*h54g0QKS-)A z|1jw%HcUU{Q=w;pqMCj}pQ1OLj5f3ekb_0W_t-+%MV^{GUdlOe1fJ;A1`i!8hSqq$XdL$bZj)-jzSHK zr$iS!26)c}cnMs$_h3xfbehKpx+{MI>}KC}6Q5tLT+2b*&I>GgeJ#qE@Vq~H3FV(;5HQ`rj?yX!t|tO>iS=w6@mMB*7veLPnsg~K9lvS z?}SFlpldQt*co`Ca2N+LBVK&wt*QI2X2H~$6%z{fv+9|J|mFa zPSt;+0FxRYlt7$C*npmDQv%PvC8`{>)izon3fr~7-luD*pAV>eZnXos+Jf&b5%^BP zrv?-G`M6gFzP>X7pBxR}!CwMCrGQ%-_#~oMTYg?MNa|!KpbqwGz{c)s>{s!0=IS1z zdWas`;PN-)QznI%uA6L-2{!(fVaae1k?6DwyYfN%-zm`)-cLRDo@K9dqL! zqKgS=kD_Bgl$Iih-Ee`CS94d001@&13vy#I3s=FLMV(*JhS zKj6^@kDmie&HQ&~^&_c{Pxn{0RxD*J2oo5KiUIEazi zvD-?bePZuAjJp>MeQ{M=$~qgdF|JWHzantBk?TJb>3~Dyj>q92k9o>` zXkpX)k0nB)7*(V@+;_kOIC)v|i9hoxPvo_RbjS;IQ(> z;S*9HUQePOz0RQ_0jQl6oeKk^XJldazTy8tMb4NxwICZkk@ zpS_^7za}1~FnhSPw>BYkLn5w^U~r*Fd&EK&(EESW`j80rlmPGBf;8w99K~Poe@F`) zBO&CT>fA&dfO8(@F|O9YjB*bEH>%h_WI_o6$2DomC$Keq;nP{Vo}vVYe>+@Qd zqU~_nj-X!nf5g2DcvMBwH$J&R5-tN06h$RSRI-Q?z;}s)X2=94GFhX5qR7e$vfdC@ zCJU%Q;v|xBb~LNvf_TBpu6I{gWdkZEA(Ie64N(M)NaW@@j>y%JATa;mulk&sGXZyf z|KImKA3kRKbaz#ES65e8->MXR?RkKw>Dqe7{TcoUH>EkjG|G?_=xBd7zajK^m+<8Z{vE>a1YUtB#T9&oz_YF}=J*(ai(%QxXy06s+3nB(*v z1$P(Wo>Ops!o9EH*jf|rHo`qdmrzI^50hFe-5AET7oK{++o)HEr<>|i?Gt`eFZ;(@bub&`aeeawP;rd zdd&uWgkD|+cQ)a;2M)N&g!3ynE4@Y#&ZO5k1-I*5z*Q-@0fZZ`;H>nr0q!JvVIJt~ z@-HTS5XfW4Wt?zJR6cgRufll)?|J;szAOOEo^!Q)h-pqwC2z^|H5U|g3TwrGC%xw} z-Va@9GBwN~6>~kv!c)n=gv|ksmHhB02d*hD*|7*hvuK0MUx>$QO&+{n$-!fVV%~Kj z+&eDcW@COZ_HWgmpD8G?s6p3nWGS3s40|Nrc~cP_MjTYbDJ`$ShdXeW>}EhW#K|b8 z(nnW=oV(!e@mDP8&-p`awvLJ*whpa|;E$O7DaXHI)i@dBmKO`fc?3?cMuZEYw-}Pz z+%)7?s&)Pv_loeV^BnX)4>!O!1GcmOUnO(K$TORW8eAM@#;Yp?WRn&B&85FO$JWxGzQBCdv;J+b zoN<{eSy&Qs2^5B|5%yf-@~SF$&ezJ(M3!Im2CuhbuEYT*I%6_8jMX4#fgdCFut*zu zU)P5PTw<-pc_yR6tBzEIsseMR7>t^Oa+J<<1`1h0N+7k1$^NLP$^Q|0RU(r?uPyI0 zRIl|weT^q{UMBw%z4}_{RfO>-6ez;B1MH`pmWarOla^YiW!!|P1ael$6} zBPt(2MyZ+SZOvg+YyRsek&#){xE?>lzOTwymB}WuY@_p!Y^cLHbZJI0a--e$Qk=!} zdcF%5ZtwtAI=lf?^3LZN=K9%t0(U!gX^hu7@Gq{t@DG_E;w?|H3uOpeN+jg$RP&e&QFUW{7Og_*YgLdvqtjIp?^f(s1 zJ*!#ceLO4P2rFri9%RaPoQ^KVP$y5&uz_{)D*c4@YuWV}4|2KdCyONYO!xOVQo}W( z=SEo{dd8O=Ek-TurI#Ro$x#Y@ducQ4^^fOJLZElJHyZH-BG80|o6&?f(KrlA%zqK3 zax%tg#B6PjZB0CvX<(;et9XZG8YZv3xc}=LO zW)FMjUT5i_nfNVH(#QD-BtZ?MK)5u_aR@* zE24m(j3GZoU6yKf+@wDpj#vDW&&!_qc=zYhZvO{{oR~G>YhvT>7hS}$IXZW@M6Pbv zrtTAMsFaT$T;2s}R2di4{sm;mv7ampV@@dZO7(h|-S8w$Ei8ag#eF(*-n|_6+6F|R z-2?TXfdqK9K`VsxrDz$t%1R!#yci*UWc+BMX9eC#_^rrlu3zDS z7_F+)XQTdFoyydYnbt7VGHxICKwUuevT4lng35BN7qT=Ui#`XjGa~bE2Ri|w zRv--o`J5m*0Ll0Lp!b%x6(cHY7E!DS72r~_?62hej^Rxd3=WB1v!J$nFIu5S=uG4K zM!nXEV@{aL7D=e}I?l=#^;5P#cBAU%kWeF1+>qqp$_#c!<+k{FKN7$LvuUt`&d2Im zd$lX12XpL8f~Ne;+8g?}b$-G4f1rk<#>-nWgt&2&gZhAmQHtiZ{U?g* z8(EfGFZfk?i7cNn>lx4q(mm!#kBXZ0+`?RH^g9qg;h zJs=aLGy|lB)KPl^+M)|jQPxNRo_6VSlvSFs0=c8GRfI(>7pYoq1Xe1Er4O*Ki^;Ds zKVr8q|C~azEat~_#Um@+>nY9H9|Oca7RFMW(Vlre9-QLNa6wzM6}z%G&bgX5lXG0z zU(UgU`h^Z2AUePYcyogXp;$I{%J;(LcRb1%3GP;3$ym~m=PU-_pk9^&C5pIjDR>a$ zxeLZ~HMMu_|H1Kw=3OT8;9KM|<=PO42+p%x4$%k3uF%WipM38J(rV}q8!;HEsptC? zA;kL{(~E%v>2F)o8Ktj41hpyJk9*umG)>3pUPKu9tB@I4{$zn?ls;A9Kgg(5>DO4& z8KvhK>Fh7SXIau2rKcO|FRS#PmUKqxHY0t7NdJ7`hKJpasZ?vQ{O0P1~ zD^&X1mUKqxD~$AVmHt;tI-~SrNf-NoWga8ZpwB#g8X|-~%3j}u2r%sQ>0|Jvu=Qvt-Amb$t0v4X6aWYv}{e7ll?&!zCqA-)$BKC1z{LgE_$d=?SOrI&hW5}Af% zGYo_4uE=`i7PTIkY_3PfTGk^WR^oJ3iCJuvu^#ym&b+mARVA$Jk@XmNoa3-tBx^Gs z4LG5Knd_3}uSeG<*P82+FHwlOE};bnwJwoItm8sBL}%k zDFz}GA6chVFFVCLl9uw0H07lsNA8H$lcIljCBgNRkcoewkl?wvdt~)lub~U zjdjWbYDroKG-X+*gn)#6>wQd`_;qJA(O9QUhNE%KkEVB6r;MP8v~~&Ma~1qkgtx9! zn)T>9h57obd>-bLrOFc&p|^@MZ!hC&Ol!kd07URL%pyw_u5k={osyno4@Bsxy{~}N z2rP@1VF2c$rHzbSVJ@Sw;m{u>z%Y^R)7v7v`+LQ^*PFaM%)-0d(P7$+s(^Pop#Xz- zhr(gGb_*H?Ua<169b-PSmR9pigl~6($S19*KP5*P>uJ6_P<$)Lgi*fr+!y89UszAC z{HsvV&N>?W`Y`;YYim&V4*Ys2hMayqXr#s!Zk~X}xHp^CFa@uVZql#XA8$FoxA1Gv zzny|#Y1vr#b&~X%@N065;@1OFe(e(B*L@$7UyBx@!?UguUd{X=!mIOzSLY!@c=d?z zYB7jp(>|||CSH_;CK~+u8f@ul&1iZDel5o+HM*ffTdv>^Cjw6Rv`(!9hJB~_)T8RH z%~AO_FrV=0Gvw0`L(-J8>ByxOsw}TCi}2|@ftC85OvmTpgaqrGz6!`gAmPtk0Fggw z@)Y~|${t?uFj^Pc&-^1wHTN^$M~e0j+-Sf^h}!#H5|jV8mi&I^|8jwuza;zusHdJ9 zm4wg11b}xgh$#u5E8%4l?k8cMRhER)CH#nl`%4&4j1do0lz=Uh@YfP9mhd)&J&Q`h zzk?#|Sy&Rjn!gK5!iD_3za)GOe=jTvzrx=+Syd(BR~b5+FM9&LKS+2X>`$y&D+|=n zkCj}Qgubin&YzY_j73{$E2lwQs7YQ~h1OSMt$#%4M~}jX zJX_&Y_-%o2pVT3}!}pmm?Qez8ye{@Td!hxOiP!us3omp+&3O8`p;$JD`dL=ChW<-~ zZ{8Z*e{8$fb5{0cML)W#TM_{=4G=DWV!W~bH192xgn7tqFMU>K`OOmkyM(`z@S76; zTEbLQVU}=5n(nybLO|x@lPwZjksAiGLRH zo{LJt>k;RfM~z|wL;a~ysHQA^)@X`SvUH_Y>`+=ov(hTQP+G+&N~@?-TE$07tEg03 z#oJ1&cvWc?FDR|zDWz2`QCh{r71*nWxwoIOU~W#wE#z%aULpr3IjAIGZ3jl3#mlpG zM)b%?^uS?={-+UrStNSQRY0=Ti2h9^`Z2g5)=G?ME}RtZ7oSG%JB(=h4pq^QF?zfa zeH27f(My^UJ<^E&J`#Oa!?Lh;z7hRZBzgjobT^_ujzr(pj+z`d@t?LmyWi8j$l`UUI_; zpE^s^&cwn6CwC*=fx%ZigJIR|_U#Szj;z<$Vmt*go_@a8^BbH>Vb^t!_CL7q0FWK7 z>Ya%Wzw;cv!^VvYb+;_CZxY$^!M*{;n+#zVd;nGieP2#=2YO$Op^vA>VUN9a?4)>( zYm9xjJ&*Th#456V<>{qO^Ui{&@6%e~yBLn9aZRI0k9eo8@U|tu&&;$&9C(}_wy*4o z+!w(HWZG%ok9!p#Jyg^W`CVQ;4*803Vr^TE)mk{>4mZaJs{!976zSeJtRDUa4)bbB z)mpqWa8pi#)7Koj7q~8px33%%2cH1tTrSYSBqQRT_LVadN~`9*!Q$dkwZy#AUGttD zYhRgh9^NdcG^S|D>*hTI2i2$9SJuGhYgcc50!DBrcS?&ZMRTRBbNd?d;hvRFKC8d) z;V8f6c=;dV9OVvJM&9ljV_(?`W%};pniS=K7)Ie{MD%=S6{GdLkO{Axb|%=%`XVUz zj!I8Qs6t^W|HM*rY0AG;M4B|kzH%X2VlUqgPC#ph$LExW?d3dV!`H~md~GTFQ`RLn z+RN7<3N1M;$G)--?cWTGs_?+gCN-ixu9QZHw=GPA< zM_gm1p*@i;&Xa+^@t%|!)m6ze96m>!GjnZVd_tseN>M}XMfg5LeEA>akQCavT3VZr zhN*U6%*HnBXW+-+*VVHDgcFbd`77Qp+=Q_H>c6b-7giUk^wW{9Kl>JvqO|1s5Kc!r ziCDGw?2Paj9OaJXQSKNV<&I5f0B=Xe@|nq)90YP0a3kP0<`sVj`}w}PldM-lDwNqE zSN+%tsE2KBMLlFY@A-h=+rfTx=OGtlaBt{?AxN3%^aYLc!hx=7ogJCAdD*r0M{Y%4 zIiTO{#!27VdD7!zKf>Yrp^}C>aT0YlQM>K`Y=P1~{npED`PDz1pBv~p9p;BKKWWWL zP8X{q0I-*mKm56qV5mWCS!{=G7HEZ`cLqelK%u1dT(Lr4{eS8T+}}BoF5_`*nwH_r+^y9< zdI_fIG+0C9QK-1=TE+I8&B%}Y(iIq=2uD?J)J@xcF_O5AfX%9|8ToO+eAw=-%R_e` z1B+suOU7tpw08lZOs}93VhKp;3l5`0P+3!4iNh%KJV|Pr5BcKzR7*!4;|A#i&}0BB z{&WR$6Z7Lfg}KD!Ik~VNoMdn0n;)44~VvKys@8(Q(SCY`RyRK z93;b$^ch)I^fHXs80^02eSTNq`b0O3>ve@vfcsn8O@qM~I6P=<&7Blil;WsMOiZQG zT?ULEvf|u|R5_kMb|-F=*3qV(9osxK8<-y$d1is{8_t?-kd{3m(c?<- zh%f=DAR=oZ$J09H!Ie6O3UJy>shJcX9p$-|m;3H;c-QrE6t^9+mo>2-B}WfRrrzLf zZ+niXC_lTs=w-M6q6`>Chlv~3{c5B+aEZ>l2bWh<@FAnj;hSRf6_8%(mH}7cpgDN& zu>{YbBe+*V+&A3N7+uB7Pi;47MMWbP9rQyR*q1$a6wK z*jJ{OHq4uaDLJ*J=r-DbcGH5kjQ)pFc^Fw98K)hC(CX{Y6Ce_R}n z{&B~{nYqJTlMn~5+)XeLtRI(CTPKIwSLJuag}$;5g@q3EroHTG91J;RdtIzU!p zEc>)ae}Zn%0DZ(>%7bmFt0}^xcO!e;+N=gx&+~M~HK4UfL_&`JagMICf8vwsPuV{Z zfC;xM{dokGy0MQft`v%Xjv&NWA20wW;I1(TYB$EVi>fATa1cZaqhwW=}> z|CmyRua?RI_!s#*6v*3 z4(14KG5$#|#?_`Hu92UpKyy=YZ>SN~Oj>&RQ(;8fYJ$g)Ra>(yeekEy$H3hC+>yjQ)7B9D=@=(m=>Pi%#k+j% z`M$>BiA9~gZRz$$xXho3>Sfo)`Hlc;OYPeEY2V^u({9Iv@o-hYXaHROdXL)ei^pAn zStM|&h7BFpw6rH&aR_cZ~ycIW)Go!#xv)L@A*G|qbh zSn@H};P7V$u;fo0{;oT2Pk2vMznIp@*|eT~2D4vvi9J&%J8t6Lb)|oJ$Ucw7R_N#DaJM(xfbcaz+I8XXvZ8d};DW^3vavr+^1^z+u>ac3*W zTlv{p&hoB3SEmDwGqWjsGloPRs%(FRMdb0j!l#eK*yw2jtHTvC2 zzb+;{NgosQov8m$%y)u*LCkl&&h{DjKv#CP9UXrZf0}zA{jKWn#&q2dVp{m3yU7;_ zG$%C~`I>BEX4{glo0$)R=A>7n`96Z^wB+k*=0l)4>49jzzs2V3V&+4jIqAk|KHi_S z;7c|0A<&#OG@5U0Y`zpT9|FxusnLA>V)G@N`4DJM+VMZ;IM9zkG+WB;Z019tIcaq? z-)FJ;I+^(pXij=Gn(w99d`V_L1e%lXh~`@qn=jGKhd^`E=xDy{WAi1L`4DJMIxCv* zlGuFlWVsszMuZw5Y+cUJkDv4gIMgg9@&C>r*G76L8ciMK}))w>93jT zqfbhYXS&}^KkuaU1g76lsXZQ`W=M3*pzo}+&;x_-L4im^l*gl zX~P}f-SjaG9}nW-;aXnkVmWpxoW6G7dtD*D zpcUl>Tt^}M&v^w59b7Q$oHz_*m+wOxQr&?SRVW3qyP-V^o-VcdA(f;6|RA{h)oa5MIvM+uDsVM6F-w#7kKh0@|@^h;# zX$VM{UsAt#R?ofrn1(eAC<=A2bfoI1=ThfQbYLsvd!j8JJ52WJH;#3wh zwj5ZuL7DtHl3Lh5xPE z>IHMYu@q2+7AX9{A?Vkhguc;0Utmi*0hDI-A64j^h<>v|55+46yGGI=Ib`4zYP2EZ zD1pMMoUa38raDUM)}jycy|q)F*$31`?&eP*HTQz$M)k=em+bnqwtC{Gy;K)B2RDUuXsFO3p`}X7%uSo1u5Kji zzhsafYS$Kx_)Et9L|D6{$o3hse~au5!EL+tpzk()g2B3h*{5fe*RGv1VtU5o$T-FJ z9Ws86jJ3htyS_p9Yzm@n`y(29YptW_zP*TQ6V*JpY5Jbvd}!v>!4aqu6`jor2PaNH zQac)YI{%P`*9MnN-&X7B)_fS+{ntRzQW@3J=YxKtqfeZ^fdI`w)>tXpIlh_z)^?!Q zG10TGHn*GmP(^T}=Tn9bRv_Ox0yNZC-`czte?s2`XHIXe-H~K#Mj#yAeQX;F{+=UM z=;BCfJ_bsLenjeF1e*0)M^YQwHPh23$oB_ldQJ%P{iObrmtfwK{6z}w-e3{XZaVfo z&~C(nB^>NM9h|jjW(5!t_sr0j$O7Cmo0-0=wmJ{ds*oZS;#lCR3I^MD8Ko7Ww6#;* zJBy=bULa)xPwg#9wu8ZL#|{9`r@`YMRCB?s6Tu~+27>IEik@sf5d0)`n9^kb#i%K| zur>I}F>0|V9Q1Df;M?4v@g7gMKRgQ}A2R3&Wzd8FN)&AM6FujgO;J z-Bwl+T%B~z5GoZ5vK!*+atEZkO4e3Tc%E3~m9EB;U|a>(Vxw$Hhe^>~%0X!Gy~q8v zGcx5qPHldCvAuRjo-L_~Wh1h(cG~>3IWJ;mv>+Q}2OqibcB{)RNky=C?t7gXGi{wL zobKDwtvA7Tt;>B1 z|NkBTzls0S_>@AksShaxm^WG(1v01 zF{J@ZYyJ#>LhFJHrq@%%a*h3Qtz%SkJveP60-@Sq0Ser`1rlnattvR`7*eL6;0W8# zAqyONp<@IM2ZP5>Ang!%^Sj#Wg61O}a!lb+W2`aMew3jW?rMM73DqC$sz%q97+rO_ zIpj|cF0h54V=K6DQSLMNxbGwUnX{dJte-7Qq#STJ6oM-U%ZxdIqmqox0l1i)9c-Vq zmMqpB$Gw2D;9&gROjgI7o&qR*_rCeBoe41ZapVp%_gh`6PdS zTs;kXKY(~d)siNA20f*4x#KV=a4191guGPZzutw3`L5MO9>dMN_QHH5El7YOBjVDsot# zhZT&uexcjp()#WuKMuw$=nl*zKVpA*yYLqtJc1v&3;;j&kRMqqfFTRXkSRa#I{NpL z7wd>BR~%kUZr2Xt(lw%GZn_Q>QM?_uh2t@7-HpSB4K1S=Oj zIxDdUnmWSSqifu1(Y)L5{%SQjN;<&q=K>)7g(FZf49#Fcj=;n|j_l9S0#*XNn_z#qo(Fw&JEY>QRWYh3 zMHdUg=7I{8Bw7zkUN4cGlDsjcjf<8xB&M`nY$2}yb;b2ORdF{N#ihj*2fyuR<6N=D z<=7wY3LzP7oy!|4c6ftRV+d|-<&zf*DPvo?TOv0lJuSaNQ-gv=$rJ)D?9R9vy!U>~ z=^GMkn;UZCydBK4pu*`d+JLn;GP8H`U|=+o&)eQ_;h9)>6{XcB;OKU3909wS;|(8f z!Pk!KP0mbRyOS3I{6&>`gDKktnTK3)TP8bhG++5o$q(Gp7CkS9BHYjZNOvle-s5%< z;~*F?I)ONO-2We^kI7ne`ao`D^2kH10RD&(yx)i%5{<-kVMO*tq#^f>SwPJT#w3AU z`aGB)G23hGZ+P3Wi*Xzsw~9l-<)2as2{S5uKFv#4R8i#5zgu4=qXXLY*bC5QP^+1a zgl|{zkOH2;0WwY@e6|-fj(AiSwaE1lyBdd(NG}@k(AoIFg7a3}_TZA{ zwZW&GF`Tiojp%pAq7}zLOPXtt43$%9ehA#UrB%*mmOv+bx*01!l>!Y9>fX^=4-5ou z%8mzyt3npo>Vc&Nc`=1f*|ih;BNwE#!LsQ)q3&&|Lo8Ou+d_LV$8EvdaiVP(B*(24 z$gl$oNXV2EizZ_#Hgh2ZmUl&4_8`}LY!)&?**&&I!Y3AuUqLNVEzHWMx0sqDG+SbT zvd4OaBz{+L+p!izO>4nGwLkI{G!={yjt@LAkE_wEWwHTX!{FQZgm1&(+rx(_KO+;3 z6Yl8#%QW-+ZkbPz(=y2fqLIgE)f+RMhj2MA0C}+C{g# z88aI6$(#FApX`Z!dFXKnotx?oEZ6|c9fq2wy|;^vJ!;OW`;A6CgJ>g*UrKg}69rdb zWC8{wYlSAVn&^;A+<`>{IDIZc(U?rreNh`w&>mMAmF-kG9>iY04vo0{5hdI97 z!OFxPJ&M;@u#RBV zNRt}X+j&Cw$P&EJg3Kd&Hx5E~9o|3%%Y0X=`hg>8b!O#M(uVMsM_6)rzMJZ1(wD zJH>@)Y7}Hlf!M$Z84ukz7t#XEI!=v_aTp!B7^k`CrgD5@=$Z0iNsDE?ELhZn8+)|$ zu@KQl7HG$XC|wDN{J{N5HjE|e3d@KQFcpWu{*9@#A;r+re(eT9KDrn)}{87@F?!&@GFqcc>u6tOEX$lOUbwK>W`_R@V|n%GW|A!jnN z3^3INGT?H`=cKP8&u2EmZ#x>2kXa+#{Edu$?iboi_p&C_j199ij5Ut_;fUnuUps0{ z6}Wlu6{w!7*eHWvP_f#bqfCbB#+s?&uLj#fjC|}~VC4U&p{8U(CVL&y02S;c)jQ}7 zLlhjvq5^&ug-{E!+f3?VQhel25Y{yfV0mNeS-ofR@<~-M&sx1avwC;m+o5{*pn50% zYxUYhVElqCa7pzZK~31XF|y!V5LP6W8f}AZk?NVFO{fc35jGi3J^7Q!Ef;BRa8T0lYL>mLr7=@9! zj8&uVu~P&JmICHtL;nKW2<~^TO=si&gb#~iS^pp(X*lY+G6letN?ZhocC5dE zJXuv>x8H(NLLt2XJLd4^EQG^$-O!KH0Rp-`4Z20*Pb~V48UGy?%P2C3MV`RY0$YGu zU2ZzW&z$~1+y%SWbFZx%!-(tp17RmdWY&#Fgtvw{?%mD}?gy_17fDryqHIB~4~1G{ z6nO#}FEfiQ#!jOV&mF~1s%z`@hGRyLbA)$UBNeaF(-6yd;D@Bmts8YVe9HcCI51{E zrl*;B`v>i-+r+tWYOqws4t8O?CSVX3*sAp;G+SkK8W}G-Ib%0uyaIGk8T%R;6Hd-J z5gF%VXD=|CMIXd7Ll*tjpHC|KR%HADn_hCN(7L8C`T*6&#m<*uazTn2{H_80R17r6 zlTq{4Xt$Iz_#u_E_dS-JGe=B7P9;%stWX0Hur4B@8iIR08yQ16+Q6Yzovyz_N{mIl z2VZ8Ce4Yg#Hm;@QJXHKSu#hUbhmo_b$l5}ca};uJ0ZuXu6x#IE{J{17WvI%5M+G|B z!XiE64G!R)4uYi(~skJ=uM}ez~2d{ zgITuXHt0>~*zmld9QMSTz26S03MJZCHm7XG#GQz1yS!1FT<(e+9q9Tru;38ob4OLE zllR+^xP02|OxfxVOtR#Q&qe;z9loY=SArwZHSP8WK5QtdUh(Ryzo~9WENP!GablAF zK|TjTW!=6ltRogYtmY#(AQt;-@s7-mXfL*|<$g5}=*k{I(b$k7a{Efp>2daz8&R_f zy=~<^d>{J`RPRWv(oydQ?~WlUAG-oBRH+FW(t4B^#s$*&)B($nxryE#BN=;oT~5NN z^1^r;4a4(_w99U9l4{mSH9t-)Im&9zO%=+D{dky2clp-U0ZWY0HQ8@Rhut7Om2@qh z38TZt;q|a|*dtd%ASv}I3om@sov;e{oEaUMa2eV#yt~VH02T6F${qmmbIOOT88r%> zOsdcD&Bptxxrv~@w5V*ay=**4q|d@1tf#D9t@CEGVv;pz>nid`7V2{TM|jx{$x(?1 z$gaRSZ{uBZ1^WK3?&O0B-A{l`;1;|-5ns;k+)KsX_lpLBoX+ywj^+6_fu4@4y@}}S zz0Q>H4WjlcFFZavkVeZ5;D;JV)%Tr1SmbGPrZnZ_$}nF@Df%Pp39v+3VtHXWa1CBb zeSCkh(}#QMmtKI1v9rPFeNj1(Ee(~^ZJ-!ZlbI?DPZAD!jz~KO??+aBI|iQlxD>y9 zfCG^H`<93Kc;F}4o5|YC=Me+7KeV({O~(Cy?Ya%^VvYxo63(U{pJbXD%GYnjkTTZe zxEAVsbs6%9wO9TiuL;X^w9w_B+=Gg5UPC)C7h}s4h6KOSI^`&fcr;h)4aU(@Ny7RR zTefC@csZcxxbr(L4l%Hl>GsdVs~MiYXjcp7qQ}I$GZKM){m(4cKMr@$bK&R%70?TpD+@5nDCF|1 zVdnZ#ATI?F?8LmL@NoWHlZ^;5q@*oTu@^J8KVpIXVq$+9*irevBg(A&RY0g;Azbc6 zY!iCs4DbaYKAVX*V4-d8*8a!M>O*3JS!;TtqyL0F<~-8m97S>20eewatMmwEvM^Q-V@=kF}$toTAtY#G^0w6p7g@A(^0|Ig7baI)2&dof35M|%4e{BXjb zui&!@|CoX&wat-`1Nex)knsxc806#{o*SXuIKoXtRfn1H>KIfNSJ&`M$P%yA#S+J-n)8@J>*Uj!K|4 z^2sC1^WjM{UdUPOrD{LtNq?4NZdvoFqR%TIgFXqM8~Sq_@SAjfi$YBKJ3>T z&KL9J6`Yk1Y=D#gM89ag6x>sUdr`qv6Rxj=gP;Cmdh4>wS?B zJ@1V8uVR;88SQ3zY{F%yP2hymN_LzvTqj6Ri+8Q9h~|^Td^ac4g%e%=UWP*}Pd?vX z#JT+MOZWQr@EM<6gq^ky-mK8KlVbb!boMRW7e<~xM()pQeO3KS`=kEfsdhK4L%Ron z9_XJK{>P9o`j>AgMZeRUbEW-G!qeOY#*dHiJAoJQR(e+eKGMH0D7dbKYf*655biYv zXQlTf!kPVhr-J(;9dI;Pf%48I+#CgG<%@K{Mf!J`f_sW^G=C9#Sk=F;iZ5k6EX&!% zP*@xAl&;VT-1*CZ33rzF_0>>`xIO);oujJT`nZ*UV5&mwRKUz5B*G|kk|FqKQ6hkoxRP0kI+;v!ZIo#? zBN|Mj{njNC0nQg95@Bpq9+;eAcLu>XzbFq3-soePxiIv6t&3{caQZ*GUeRk+E$Gz? zbnGAxswg_}p4oh8&iPGSf2GjtFpQ|J8KdCm6aI7H?H~_|0UwbEk14nh2xr)-br5d3 zg7c#3<~-pdoGA|`E4Wg^<*4#f2scf^S>-_wz(wT200rkJ+&I9Q@}P@~AI|uxi0>c| z%>KRe9-&Gew+E<#cql4LvuKWAC&(eOa+ExR{z-B@MIVMo@o+9P5Cna1Urz4G zQHHzy?@*#hAxL$?t1Fg%Q>7?v!q|8Upe684Brb2EzR=;5&G=MHB>3CJ>T((^z=)eM zSaM&L28?3gq2z}a1l@E2de*$ZJk)f8xfx*2eF0?PM0)Q*f zEgSaqut78}vBVX(4mNLgWD7=;!;c5WeyP*5r?YGPF_C7DSql z$BlQVWli&T!BygLgG9qYqKyMUqT%c5*hTDR7%s|BNf(!*8R&?YlzP64My#2ZDDrB4HTfU)2mhB@>RF5-rE}AQMjWd@ll@{s@u{xx;q2@Y$hn;?96oqooZ= zw$K9#5A&s;oNw#t$Tu7LWWFY!`o44f=eF+DANFj>F$9n9r6y ze!9JM1HLS+9=I2^Jh9E%>W&Sq&z&A6-41|T%Y6-omssx4KcL(iD;-q5{6=~+(;ozI zgib2`)%T^|p>ND~&+kh2rz22ZY+hGI+IP_%*bGKFj}gy}k#Yi~Pk7rp*%u$izI7$8 zIN_`g`|%uzVqFGE)%*xh5Xtd_nEyw~+Bo1bWrcJzc*f}Kj_p?+{hM5o6b~OlNfa*R zyV2NgLJhSwINAPRA)7f`A>(6p3aJswU$OncixHt;h(8v7xr)QY?B^xd3cd8#Kmuc2 zv_a-Z(&KP$kH+eLmG1Hvz=<_f;=rZjLehBcnh-WMR5YgI?~Ho0`GHISaU~rNoXRg+ zUqGp>xCp4^YT(ivKWAZZIpEB=4T&OJt$q&c>P#RJB(dVSG=q1wqhN30i&B0CezgxA zia_V8wwVMkECsg~Hb=0s)>iM_R?+U;XU+CYb&QU0O1e!sQtTtQfqME1nfny~&`~&h z{F_vRgLY^QUq$d!O2#(sR3y|C@`qi(EB&-{zHrOObW1m#h{PPd$gbZ z;V@6pqCE+FU$D_~>ArKGSi73zX#qW{{wohPteSKa&P@o52qPz`ZKFy zjEa{oRHNeMttP%-QTXy&GqYL8Un=r#NVq7|l4E|EkMwh77{Ff~<)7Y&^BwQHu)Yqz z7G;(4493jp4|N5yank;8{!m4`mE{ii7sOvA!CcC`j!W$tg&TcAtY|OAE-?Bf`8D+P z@U<9x*gO`!ATVdDHU~q5{+G=8$&goBd+C)-R-eVF636dCxc26L@_`zl06eVL&6&=v z;UNmer-qykiTJ(?+AscHWswf;!h~g-?P#{Fck<)f0axInv?u{IwsKF5>^bReh7sR zV@Rn^2*E>1M^};dQXXl+gA{DapOc5#P2(o)qf9Jb%YK+n-=9i-T56g#f zfb@P5MvB+WR(el0Z>#)O!j?AgfYG)sh4Hr#4x^Pbd6+3O>GI*MB9jNH2SSqiq_a zP%Honm)fSmISUkDI#FdNQ?ET0zgY0GSR3$_8TbaD3Li855ST$Unug$ZGR+lW;l1 zSmIDFFk;a>o99q8SJ7ACua5HI6#hC##EB49?FX0o+HsZs4 zQM$HoD#+r$Z;1Af-=Zf#66Jetbq4andsZWp!C#$Kp^2<#B{fd^_Z$I3kPu$>MY_IJ zravWrbU!{UEDm^kDd~gFg3e%X3cP#NGVxAB?y(3s<}K!I!Q^;&h_Cm)Oyb}lxR(kD zGbL$v1Gy^zf4RP`pi@1D8&c}UIk5!2-@&L`dr38gWwoAw1)m{%BkM&)Dhs~=ukyEf zEpfwZ*lMsM87KGMWnul3o4G7=M(x2U8=vAYkLyO4zmp4hQMikGkYHZfIaT{?l}lMC zdub-~`HpLJ_W*g8VDFhnxt0r4hn!p{cJ-Xc{GLiuMAQ03iM>E{>JJ z2v@KHa_1KBDF`d=e3b$4im#FW*|f56Oj}cl|qxP(=HMDISaW>`Pl=a z66b{`teT(dr7FmUksjJvp>nk({kyQm3 zcX;EZfk9~ZtCW1;_Ln!}hi)##|1%LK7WfxoX=5A>=+MAnK+NsOt_F^_&D{{k&5rQ5 z>^GbM)>!Ti2hCS zX)Ojas~9<1(=GTBhn%z)#ICNR*40o2`IxHb|v; zm_~!u>OeCxf8!#~3#dnAe*oV<<6Aq7H5SygQ3Sh(U~Injjf%aHu~Qg(g0NBQV}B6$ zPfYX7bg$_2t%oX0!RCV9Q@8)!3^FioRig9X0tVd6!|7;&e`JOOUQ?Yu?22f`Q)W5+tj!mi-{}W zuTr!p5n13<9|gXV8Kuo|vx`AV&v7EK?WMm(en+b_gJY5A&oL5}e-(ECjF<)Q>SzNB zz^rxoGf##w?P0f5`@>2@yPgdYOc9*an&5;RY1E@R_2l$mC>>)yoqIDww84at z9|GBX#;c4yM}y^=Z*)4j9SV8{E{JkyXu!`}Pi3t!(DOKkm2y&gHKTNVI0>ylpnK_ z*;^t&xc$UoTy`&6rusr*neUUp95=GV1EXfWj*-zY@FW59XUH1GpO7D_tY|?HAvrb& z)a$^d*G^E*#Kxd&!HpFy%jopD5|$BROO%sGRis@VD_!O>|EArkgC-L)@qTe z)z;Tgt6{2E*74ecA*|mCK8N0gi_hesH&7IZ8E;u>Ef+`wQ;4cUp?a98G!y{|xd&0^ z&|gAS=|JW3PjazK%4i1^w6~Yt!nXLAau`To@w^8bc(ki-AA*!=>&(8u2_Tl7kRN`W z?RBITJEa(y$ZIp;6r6mx^_?Uz=TQ+4ucF?1BmS7{Rc-zKTm;nVZ=gQZgImcRGrm*J zq!VQQcBDk)f#`4gBozg{Olv-0h>(~FB9x(E*?@~m0PZlHA{-)V$7*|WT5Ec8S1kqY2mH858KE%vl3Kq1N>kr2@@IKC$}+xQgUZG-{&Et-v>SYxSUT5#Sxy!DuRP;(bEP@n0zQhZ<}v)a$Dc6Xg#$ z*2T2FBhR=04s;D}x$R?l|HAIrjW?LX!kkx)!v1dJXJOX$08SZ;2C&kwR*LQ2Jm0!I zAPE|@>D+5$?G1j3?pHJwb#cg}YrP6cJFb6-uL}_9FGz`?b!_`hd9UZ(f^tl#`qbe+L6X~1XVk>{sZk8rrKephsd{IqQ}nuLXQpM=fi6n6`sEm zPYC!s&|@ivrb!Qd5FRI6Gz4e|9sDoT@$$-jK+dUcN+Qn3Nq-E4sN>}eH&fu(YW=Xx zXRhx!KP$(}^!!H0%V+aeYQI1txQr7lbM-_m>3Eqj1C_t!Pk|V;&Vu>22K?8GIc4(k z=dJbgwxylqe>ukn|H~+c^OD8?^5{TfO5A?WOt@z7OvN*iqB&4l`g+6h3-5?{+4bDa zU^yG)nEXrErTcgjhe0pcR z%~rGoE(@3NTN{U22F*Bp4E=)LbIQl|7tt@{(O>A7YLsm9yA4u~2NPj&xeYU>bOpo|6rgd$iU?J;Jve*J#Mq#NvI*+xF2-i+1Hmt2q^#8-tF;OlARBPvG8b!?_rs`LYxBg}d+N^d~~)8A6* z8!hRKiuhlCS*5>iNoSPdfBA!q6)OF&mUKqxe7QsXOI7-xEa{Aj_+PG2>DL(P4&0$- z8yKyRL}ZkY>}3~4kl^S_`EQT(-&7ExtC8-llm45k|BN|X_~!nMNl5>J%Um*nN}r@R zN7D4DdZlDh@`-!`|K?>c8u^UQb7r`7`d_Zl?mPzt1bU|(1%DSR{yy`0 z@b{c^g}<%-jME{C^uE$SXjoumX*lK#i~nV#EC8I%9f1nn-yv z7@DyUPE@~fgePPS;oQ-Mv!rn!!cpwb7#JrJ($9up(ulqXXUdeG9=HLKbYrVqbAHQ|60hJuAIFw%=x9=0ctw-DYxOgKC*TTVlbPN~8B1>7@%$`LNgar+B!`vljVv7=DnYoo;5gWAh2apU%rG1Ftb(<4w;D;C*Z zwUPyiHmtF`qFR`2ir!|2bWja)P{Zw7pG%|#dLASrSG)PX<81d~D0iFWqM(1YoZTm* ze&~^+t8kUK2j-9$@aghjh8>+m?2i=nFi3)@5J$9H;KU^$cjiH%3hx0zJ@w4Ng9#QH zRDC-=h6>k3sW6UIX!NZuz~pif_73{c-vso^Z++izVqE!MXR^lm+!KTKRLccF)qbt) ze$JdhlwDNK^k};cK42ZwFP1urHF#70a-X=1KBJ|xEyC|uoL`aEstpB7)t??b!m3Ty z9ms_Jb%u#ljeiB-=@jq>@9O~n?eI8>@d#?U z+rYq73z|S$kO}(*q%qnIcf;Hbdla8q0J-?CMGnliYj1W+23hI^PW*TWM!o04=Kjt& zg2D{g3A{JJ3Z8gV5J$E{C*ov{+lZjGb{8e>NLo1LGU=nO|C(KAFP&lN-&oYw_EBe|yrJp18R`M}Sj$ydjZ`Qm!<^dC*ysGpwN~4 z&;}YGvM)@!_P0a%+s*jx&0n_DHN$=v`0p;5|8QsIAh5}W-JlhKl3f~mrkj_hC_3xa zypI&wwJc;nn>?R#R{?-EwEGt0yKFDlCX<-KZO=RI#>Nz$RAJMIs+<~E5NZfx#rZJb zqX~=DYu$Z`xU*Z&{`CSjkP{w7`DR~C$H;+Pd?D7p*p4r}ym$HOa0p_p5TmhrM>5Cw zq?E6;mt}O@OINVl!E2Ma%L9}>GWmp#*yG1a7$WX5KuQp%W~ zQ~aW6bMSSc6it`EG-C*A4645l9Q^0@y(r2Qv$Wvbo_T-9Y|H;Q@$c^;y43cuIalwOHXV;Awq-S-z>eL|B=Jmw}&#M_k$44 z)nw8Ta`|eaoc}()19OCUlS)n~{=XaLz;>K$^&9&a+W215Z#Nx8zg?pG?W|n%+hlB1 z%e{1JhN?4?AsVqwasUDZ{?8R$2I2Tj0{y*XG~fo9aGk&)3a$|{3~;NIGN>H_XE7{jaeU=EXamWLY-C1XDSqw)5{h7i-e!5%D;u>zkqsyE7y=eaVd6VpXK3v zJ50s|dSCgsWnrmMR+To2Vih8KQuuKhED^Dz+dy2%Pnsyl)Ur>TgAU}Hd5|h^ILkBm z`=A5m4HG&f-Hvj|=HPFX?zTHy^fY2JMpC2&uVMGgjMOdu0z_W_790(EeE{!uqVjqN zHe{pndbsS_LQm=-vMmDpxhy5Hjo;qnD15kk>BueMfoSH{L3*cXKot^18T#yuSV5 zuchn%LwQ{)+O{zn{_o^GvxJ9!p$+^qVhUj!Bxe`>p=>BIN^V_y!J%pb*QV<`)~;G zhP?jQNR)pFcrEg}f3JwVe&nxFc^&9UzB-k>PVOMD*UAd4R=ZD?SIY7Xc|Drtd8Hjm zt4{lM^7>y^dHqi`$2=#(IKbj;$=wuxRYg52G5omoAWJgLPn4hd(rdBo;64!-Q`$?X zQNAKcn_|Ev3*2Pf&yrX9ll8RCDnAxtJnC>*jyg~xk2_A2n=RVZ@QPL}&Z{4wdNR49Kk23+1 zdPxoL;B?sk@a=a@fG=Q@36S%(uRlfe0+;4o%gm-0QBrYw?-LaW+A5jlOpgQ z!W-|kpC|lI;1zhg&D5VN1YW%d4ACj zIdZChh%!5Y<#kZAABj-%Y8bsZ3-wq%iEZN2yj5F~oy1w(I4Yh(T4P593v`n6b1)OT zU?CX|zAr7SAmOh=$y6^Zhh9=xEhTh{m3~Z|lCI6)l zA^&9XV)y>B2wd!U|u^nkBW^z8+VIiF| zQ0ZmHZ*Tr`ThCla!^dkzGS|_vp#EPirn|G^5v?q!UCfo0xssMmnqAPL)L^lfZb6uu zSdT;u3=v14VlfU+E98#P!5vXWtSCki`=cmgc$vVZGZ)REAl5OU%oSD3!YN;I1;?EM z?e|-hO7;YVf(tv-*x@dHoXcsQyD4KTOvqf!b1OjJM%@9IbNEb;8)7_u z$KK^Xo51j>=sxZI+p*;*ksR%RL%fNJ`IEFu*CXbn%5bSzKc06Ycx`M-&HWnz?kRa%?Wqb7YAgU79NeK&`^f)w!|qv@FW0R=b6H@Ef}@Z==42LSqmSxbRLHlp?0A82S1B-4}m3tRhE}xPnX2aPuD?toGIDPNR>iNG@ z;ov<66|hzo`K1d}{gCYB4ZVHF@|nwNuAsSo#$JwELBI4RH8NE`iE`TwzZV)5fYHl} zpg63SU5pxRTjzvMll?yonjA(7BVZ<>ouI*gNnMURjIG)qJ!&o3FHvOLz@3n3hHkNE z7-ZUoNutZZr!1>zj7P2KZD@d~&A1)Z;+V+MqxL$sw>||~uO`>mAipNvsBae)Bgdw_ zpCDz_?m!uap7#LDSc|ed$j#XR)t?hUo8|?aD0qsM1HB&r1_;kQ0zasLsp^^K4kPgG zQ9UhJmFs4?)bm0Q3SCSd65djbWK1^3eAY$5r4i21@0y09$X-ILZuu#&?nA<2;~KN( zVneml-tCNLS`<6|8!BA%+x>&S8XRwytBQ0-=Qo@dY~pFbhKW9Prh`KgZA?lhjF@`u zVi`HO*@Sl|(7d%D(Qz=M^mrAfl|Ga4CRe5rC`1q@*w}{5(bgl2Y}#Vd-=NNmHpoGQ z?~t}HS)ttwR+O3Vd!?;W8Swro(Ppt5^=pF^SA)nEaAdvuY79wq(YhbAVNavaCAPYx zF8i_(g*gy)EJiA#UO_6|dn$TE!{U6DZ7UvC!31nP)L2z2&i}@Z8Eh6f{oBeYI69tYIBjdtZLp2 z?DOaQ_7vfj8uaO7DYi8>pv2_sTdQR_Iw2I+j_pdJAZA&3=M$N=BlTy~fl>-O;FyT! zsEcB0AsV+jTvj#z`S-CQ6b}7More^UdSx%08Ay5_zj)ED=?)~TJWrs%#Ey~gAe`*R zAs+K}z7LxyLV`SXY3MMt%aR|;(MDdV>LJrDhWkiF*tD~IvISwVLLypmZYrwn%;@9& zImiCUCy=U`!}|2FFMbt4&S%M(&pKgnXq$e=QF>QKPF6!coTrLDZZGBa2u$XD#mY!DqW+^vY%Ef&E zb}KHw7bCw7jY{OH(LWi+)+hOrb1%Xp;rlq%3kzm(`iGqRs(`CcU}U`SMCPa22cgCw zn+wPI>+owUx=cTaAB)O%>YzD(d~KPH*g+sm+#9+qaCMAz3~s&ay%63wjoZj=uu z?i2db*BI&yIhMWOlZuxuMMv~&0Z!fxy}x=2uwoH)*DF|n!K@Q@*0tf!CfZitq~a&2 zc*mQFKO6B@*~NRQrMy8jF{=u?@#h$?196AVa~ZiEW9P`K9z=qsg8`GZnZH5f3&Y|K z`E4Y4+mh#;{c@tc>@WDh`gp1@w+F--?$I0PpuB~R#o-*BqV8#P`Fde7;dl2&$lVKn zph@a39N}hegjbUtZQi5F_pHHhR@mWd^VTQ-&fhiecfPKjvNzxJW9aY3`~-aEy`l$bs4{~ zRV49+{EevY3`{j+Zesuu6Zoqwf5v>ZisddwU^)w%gj&4x#*^~onvZR8TblY82Nd76 z78CH6Qvu!vz{=SG>{%+;Vxq8>ghlMjguUQYuoD1VKacOc)j3}jwuP{WZ6s`}?-UiL zsg0yvs$31ZqOi&TA8T&{A7zpJ{|5*X6r8A_tY=)K2Jr|=RuH3!1er)s6kSj}P&`o7 zWpyIB2t<=8gww1>guZMY6O_tU9Y;2P2Ei0GU^_5{>|2|Ty&Yba(}7a0{*&-HdnWTx*xyb z+wI$`?g-VT-KgsRX>)a>)a}XHceNl*C(~|?>hgA+>i%@qW^k^e?#);DcBi(g`=IKI z`l>r`b9IMOx8Vlg?#xzo-&9@Nov*rAr0W`2=rlbVaI5m`Ri3v_<)4@t;_1t;)QrYE zSXY<>3uii4z?0tQ^VcQY*}3*R7euBh)0G%-RE30Ld|<8~M#KklJQ$5TJ}{3z$4BD> z^EopV>)bUbrvR}rFu#J=WgJZW{(^|WCm^-rAnDq!2mQS z$G^z87c^J}P-<{@I{?_0FkP)ij)Byc@wkOrqDyYSR8}bBeXi_i_KLjdG zLq{~v%@{-so8W-1KBHw*`t_EfqndA=MJHOCugPA3i5F)(PxooHMm^mOy?*!mFag*x zn%GS`{kGD89%fvjCFdAFzcmQ zP7E5?>O0Sr8JEFd@ZgUwo{na@MC?n~f=&1ssawVG#DFu=n74t+^aU0R`tPK1&t_`rADfaj0EvxdNzs_}HO&*=e(C|vr(b#HvuN%_&qmm_$aA1~^(;^uX_V>uI$=a8)Ij+Y)vMA1Ylu6?KKFt^Y(he^@ z#rkrMVyrz}>Cff2F^A(X5MxA>gAijsdsQo0vg^6%7p)QfKbgh7{owzMWPu^sdp?4v zqq@{LgJk-=n?~p$J0$-r!tF;_1z8zddCC4s zWah!pJz0A9FSn7ecY1Cs-8~qeMJtWT5_w{y*@)_n)}0ILWzwum9orWaIbF z2mc@NJLrGMujZ%!7C%-UOAY|F4;FH@jWw{ixVw0BEbgwnr!}!Se$<+yi$i@NkW6Ln z#|@GqkvmymzN-ncov~h~=U3SN>1V^d|5y84{O|2wy!rN-I>p)YJB?4Wrl?j7`@&%fcITzL(+ZRWk5Qsk1C~wvzo8-bt z@=x=#4bSbWzyC_>JI@JT^PQPzp@O;@%NqK+9+w|Gzgp`jtwddOPyK-uX-qo(( zGg5cF{pc8}8?62=chip8A_wJJzQP}e>gP(-*jYf#iBx>xX5O;e&VO0Y0z7NipI*J_ zxsGZS3orM~q7_@Wt^yE9DUhEj!2Sn}hR4|e?rA{8OMfL(=`ec7{a||kG z^-;y`6XSPQdJPPTO(RnuQ|ftI$tq4fDCM&|Y}|AX!CZpBCvJ+I?5}5& z549lsh3fZh-CjXw==fjQ78@)6AP6o;QSq7}!*kUtX9nI*UwmXoJGkAx2csmH*jviin z!8>wOct5V#JUneQvJe*hoecKp0nwswIoxsKe&B!I4+-Ay?WZ=~FTGOnd;6tq8SWwo zL72nKGZOLad4}zsu@<|=OZ@hEiq}uI2~oJkir-tEG8*&OiL@k_UO{j_TLRnXY%0XR zEt48)LnU2#|3GM`_Z7?CdWnZ%W5uL9C3Ua~m>R}9$3%UUgB?*FbsYIb?-%avpaA6dcg4RzADRJfU9WDyqsL+3ku>b{>?ZeQ1&9{ zNe}y??y}q7Q;bKJqFeZ$nUSP3>fs(B@o)1RHZOug^%U~YB)Am@ofk!WuVN!QW^H3Z z^_Cg_&C+jr4P&%gZ4*qV`K|3F+ZpA$$Z_XZ|M!D4DsPggkynXvi^WZxwB%t2W2*} z|0nW;k5QhNSj5&l-wVlmkI+i;ANl^=+em+w`2M`nlQy>7v_JDxVSk=Y>nA>6ALcM{ zt4iG3q5zs`{C#sh_>{=eBo;{+H5&Kc8g2d1-hB{7Roq*dVdiKL8zXFx8d}o`$Ax;b z{)%VycLsl5b%`{?Nd4_RpjJj}*B=nM>H{9wz|PN$cEF@gGtp=Q17liiJ^WcV5WMc| zwr^!?we~_~w63rQFnWdEh{I!_OKAeVGT!F6?+=F+eDoe?n48?~e-d@4Tq?uLT}SW@ zWXcd&pHf)c=LL}Em3&FzO8as(r3 zGCYRJG-lWG%@-+je`Ra1GYn4SkF}3G| zbyU|Ag{Be#>g)2JTVuZdzEFJXGL;$qL6l&gWXTsjR91)n6&UmR{4Z7v3?wG)=F-3@jV4OoP9w_lX0vRwzVqg&t)+S;HYLH4jiI@?~@FNM|eR32CL+?SzqHS;uo5liyPb{zF?in5elkn{<{=Q zLI^CCS&@c`8kLYFZ_b}JwSX~7-7cz1_Nh5KdFUEJrazbOadXR2iHbwV*->6Rn=X%@ zgh6533LyRJemfKGZu*%Ocy9<$LKC zA6npYA0j9YYz0?-ep56!d0AP*xy?HpAx>HvLa>`peBG()Y(;%;^4?(sDQY80NlOmn@;`Q!i$?Utd zIIVQV8ftFs=S2&FHj*<)x=39_%qI{l+?Q-$kwS}YSSk>oOXqb2VNI(OzgpeW{8DId zTAHe)OlEx;&cUx&U%ka{0}PxYiX~t*l`v44Prl`DQw}qPl8&yr_mhDvf?*LzypjMK zYLcQrJcHr`lesq#JwXWqg;v^kpn2(|MCKEG6^WjywC1+HUtNt%)3HIJ{>d1d^>u6Y zoH(;^oSpl0JcZFv@9E^?4Bp;%@&T)U<3PilxGtdrrbHr{P z5p}LBJ=qL~C!>0W-3Yqndvw8lHWt0joim4w2Wsv#nv=Hj=9U1vyis(^cz^7GcbWAj z-+B{UVBvn6pHT+iJv;~Pgo*j+^O8x;4|{oN4KzQ_{XhSPpE+BSqgW&{<1Mp|pTFG| zKHQ(|gp9OiQ@CC(`-C&ymr&HhK{Z-sTf@*rxQTZ3?c-V6k&J=z1DkgA`AJ$_zHzS2 z?%CU{!_j1*ZS>t|NH|`iLBSNT!E#gMek)(SJJ8fkuiM<~3Aw%cbaiK=q82DK?D>A! zd~AM?_&UFSBA5q&o{1l}z{uvHm!iH>V&@yTiUrDe1O2~o1->6h$zaH>Bb%~qk3dwz z*otopJNnyf`v6^Gh8{#}kYT%IR=+u)(5iv^JCWB*br3g6iZ*HO6 z|7u$GQ#89L!31r^*R@vA)#>`r5$_SEo zWB#S}CIBTApArsbCclW6$V+`;QmRJdQZD&3xaohBKf`@UPi7#0L;f5yExY^wh5Y%1 z8;P>znrZ}R6S&&Nma)JFciw*`o7PW~jPZWhDels~10V09pW+9TqTKg)OY@@J@8 z`5pPwKvr)?qmBI8=b7J?KaaeN{P}@?h4Sa8r%e8wN2Bhs_coC~Bav4oe|%IQ6V%5` z{~}A3cV^_>=UW_55hq0qjERANf&1ag)yRI?t^Unqokxo~?v78qh2J*+KE^Y&(@Wmo z3!K_a{x{jz()vhV?curAr)xK#n35-($_eqebvxfqD*&08L^i60Zu$4CTl#$vUl=+1 zgZgEYJF<>c+qtz+dMls8=(mvqk{)-v{aJM|Qo8^VTc=&(9q3a8vL>;S&-*-W^tt(5 zZn&8S@sQ6K@EQ3`KoR-vKHS*Sd`o)$#iGGfC9*e~l+a9;KDWAe4qmu?O)1vOGd%)Vm^QqeAlPy_%?)1@+u_k<4+o4%f>+15~$vWu%EvVVQ=4rp1ptuJ$r11p81=n=eZyM|3S|u ze`rI`y9G8)&%RZo$1$kT^Q7kAqUSiiY>u8izHUv=m;dp*^y~>H(DU=Rpr^E?ke

    !8+v}VbQ5}B$J~aV97Bq)lN+#3!-EvlGq=I(RRzYYPQA9M-U2U4uOltreKZk? zCbmzs>(!pO<+;6%XyraRyJ1duZQzn6w_uD--Pw+#bQ#^<_7mKnap4>M|26-=bOQf; zcy{Cra=k3X@^}W5|1WQGRP9ZMnYiB4Q*8Q@~mrMWRo~gR2{ADWHEsDsL8XiHpl*C{y z?$9BeFG!ZGVFeRlR`$P@+Z(u*H_P2fJ;pmWKF?_ZCT0DZs&)388wt?f^S)y_jPjyE z>%Pb1cS}cgV;L4WIl`&SP=)Iusj;lNSoCncsESlsJ(Denw%V$5@TPUXWJ36;mpSiI z%2njhbNb*DL1paq$VVIh;0TL?XcS|Ogj|bX2i<<+XBPHkVNHs8+ftqS)0gZnlvpZ{ zlSD}E_==Ie{gFt^&zCiZGFE>80zR)+a8gF2S7rIc3gCDMfB)Qmnv}Vc%NMw*$3U_~ z>9xGX(!>c5_e_PonWAEg+|;9aVre*1Vy07KC z^D_JH4q#l6wRV)Bx&Y{0QgP(3EiJPPKy%I?`G>s#Lwdxj-Z}2|J@GQ5{oJ6Mt&?bZ z{%`BADIY#C{zj0$K1?F^t3U4|HquT#&z(bJCfvY;vF$8j-Xp%Kir)n~%2?!HfpK7z zy3Z+2ry_Ob@L}!GE!A6UsL%g=|D5;&w8I``XRB>#!4$HX>n5TJpD9O&z2;L9es-td zra(010E^U}01PVa9M-wvH|qRaB(C*!PN$9(wE}~%Ku}?f_`fUTDIzpE@8;Q$-0fcn z4;)UVks_`K!hP9TpdA}QRRCP+a(nXEpUr4x?TIE&R#H1`kIL6Yyx_c{_IJ5E@Y2;S zuJm=|_Prj1+b`0GWa+r0kxv7c@IL7#Kf!Q{$8gCIFuVuM1={UHg1>n)_+s`$lylO)90`tQ3+Mg^U%x{2Wu_p2l$+@V z;dCG%3GUL%`QG@rwd&nRKeF|Oyz_F-URRxleE0n+)k91%w}#S zOZF%0mYaPj(sC}HMV)7s-j>wH~Vbg3u!-DL?9Q>wE&;Rt!oFCI1Q5I!XK@L8D0%6TXq1_3g z#L}!%sWEFZ{SAw19NoVtF8uuQAxMim^SN3|XYjRhSEb7}rJ7MTvc6lh=jc1}QzJufxftJkLLqBcU?BDfXR%NkeY zCUukRt+7CJ^6~a!_~owWMT6!Pn>%a(8$Smp0lW%jtAZ(X?QUD3k#%yH-o1u- zt;;T`(FMI&KvusksWJHv+H@6IsfEf6O0bpuH@k%!BeBVEMjEK(cFCs+OOnikgp zV}`4%EH7MhF)Lpz#I2>Auj)}jHX>3)xV+`k>?3t=0#bIH9yyV^ZYFHFnTCRS?#R=8 zi4_KaBKvccUsoKwouGR7sr7c8+c9|i6L0BwY)==JK1ps%Z6wqVxv4;Xt($qWhdPR9 zch5tjqOvwb>ef;9h1dDV?YFCF%$D|erc>z?t(=S zq0-f>7q$bLjRay?6}i6B9V%qVF|o|u4Ja|djyG{I_he>>-`_lf7?u9*Y&LCTE+u;ehHo9_wjjmw&EGCgLrhx4f54DfKu1!t^>b3U)aEm9BQ zg!v6w*D6y+fN4>1ayw5-b9Mbb5Fu4dMdY6A;Ne#ZeqRs&v$eqA%EQ;a!ol6GHGH)p zok84D)#z0z!3pK1dv1~SH&<{fJ)D~bX94ir5OUnBNN3V+P#Jmb>%H~>_0I71PFKBz zuNUN{wE^g>dVga$Rd2Ab7gN32)MMy-Qcq(ybkin(MO#R%&&GEvU;lX3ALiRlt+}Zs z)jojVywLj7N8iumyRA1(lyLu{COy(J8&dubf&U8d>Gj4v;_JV2KlSHPG&PbAXXLF* z`0r2YyH4Px`nUc*HtT!cX6g_2->0koHGGG^dJ4N?9=mMD%@KBktn-{#_Vo@`y#<0R zj|A}zKQ~%`3-$g%y?;dS)9aaA=D+9a`-l3TX#M>;zB2~*t-h&c-j{|?_Ydxqs=m_A zr^z-fZ~@aRHJ0_()q1#(Qr7hJ)Iq>?7x=d~>g{W4Z5OqcL5KU8m49|kcE%m$-5upd zzm9N~u=*TH>7HIMQEQUvq&LESBxivoFTw2VcT8wc-QVQr#RYJ+R_0x7b#O%^yd1Q( zsb7rrnDvv?vjnFgSw4EWPF6rieJ{rDz_DMqX1GA1lyLF=Fc0)(0qx;|_7>2Q9_Yj@ zpm_joe#qN_L6NOI_7ZoTN6~^uS$Jotf*r{SA6ld*otM)R(_&1jP_4*O^1s-MTrAR( zZyFifp>p(UhBvCaqK4)LwSzxgmyIpCZ~5_?zfy8+xe43VqufgW;yK;+$jfF6UP6GWDn3yHj5 zQv;1RbvxBVy|ja`-$nI1d3t{KAL?)A>j$%Z3&6Np)KA~z{_2a??mKr=uPgPqbtYN* zfNH)4L|VQgtL4emOzrKF)?@}vHsYePw4I@Dep4ptY&=%F+2^zIXq<0kC>0qvQ!Mgt zdpQ=)*F>IpYThNhvyDgDm*K|auaZD8_=mCflB%uRO3Tk^;)pUZBu$a|5`*vGdxqlOkwqD9DV*`tDOKqp#ip6=J$xHP^2SF5D;%BA?yl-Xv1NUb_H#BTY{2&)&nMK<4UOewWy+8>$i~Xt!NdCxj zS0q9gAD~*3xmQG1QBF2oB!E4tMmyO_3+!4kVkfi(V9$yrvFpw^GeXESwmVOLM{>(q zR~h`D%8z&3#WuE_c&gXUViTnDy?E$Gz{g6oMK4yPKwRe@IYw`*&u<=X^oIvF$v7bW zMn%V+3yoL-SCd-+y!d>(qB>`FIwp1%jw;m~lIOq&oYIsHtFiy4K^^GP@8;TtyQuj|_AdW~# z+76$@Jau1&<2D1B?0!Qts1acwOuiTgx}m6ufElI9J+qTe)5ngmc18XInKNuyw97eX zKeSMFc8=MVlO^v@65$uRdEb-Vgd2Ohr{@FWCBCxv_wFfGVNAa(p-oeUF{{hoE?c;} zBmk&A4{#!N3xzmg(wa(D7!WH9`)YqswYLGs#PIXp@5XCXt(0n7zpnT7ez~1`_xpOE zU8eE%^|B{aRP{Or^+x)7jjDI6ulJDZjrR2deaGZ|C)B6T(g&XZt=h zFQE@Jfz#coD>}3%{}lGSRu+o3_U+&T%BsXUp!Jsms%zID>*5Z|S1S_>T82)DHVr5c zs+Ik|i$yH@E^B<62H51X*YHV}{FG!!oZUl)%RkUD#KfoGlazgLkxnge_vu1zsH;l! zM^JDX*HE{J1kTKT`K*>9YT2ugsO+~ecA#!mQ3vB=^AW4e^8G-Iu*}cfwOiWxCD+o` zR?F+E5~Go2qkA+@Wqw`Eg*vNK6OA2x{0;|R5gRmY7+#n!UAICA$d|LwoybpAMUzua zEhmh#Imsogo>Q{38nM16j_kt-b!O1Kevt0J1(oXCU8R*C*@~+QA~Ci; zFATAW<2m&~supqkRTm$jS{w!|5RRj$j54?E+^`B$qyUjCxy{A7#3^UWPOvBqcL40e z@}^cp{zW$QP3^!z>QLV3`GMNj&(F5`zC-4Fdi0$gH662E)-ssHr4hQC$u zM}r;6Z5G}skvf6*Iqn~O`5a^8gh#$BDlry3H+s|T0y<@`c2>@7``<2vRi=kq-QM?W zf?<6H{ldPEJTnZrT+#j5hi-vYzPZw9>F8wPgO#-l+qn&UD@|aog#qSLaz_<+&PjM`Fa-7TaB7U7%(F4BznDtO;keu#+gT0Zub6YJ2Q))~b}~S03fPpX zRC6cK8%ki97}(bzH)00bfN4sN1BEN_4roXtJw565S1Z2$&ItZ$7BvkRLsL2K>?4AJ zxneC;$ZMO079}^%W?`8IF@#W~D);mx7;Gf*Ur(8S(s%>L<#iG4n}l z`dl@AmT&q3!I|YzI`)LyTIK~Q{jB{_wBLMxxX&%YvS=z^WkAu>k*DGWr0sI%rh74X zU&(vX)Jz=YcklyOcOb7TH_5SVajZwYp!+M!;5L}^#GSO@qpEC)#!1c_ zc5od~GnopSq2!m|p1)132zp#Ta!#RfXvxN7Z)-`N_$fIoLVc^P{+qS_hG#%tR9!SN zx$2+hH-p9sEZMn(eOc$m@9JAUt)3;28>@#Ehkj+nsIsxXl6L2;0+}GvVxw#P%uKO}a~YwTU-b zBk3!>wMS6t4L3xEAfr|#sS5w(S%p#NC!zQ5%vH%c$D;MVJ(VSf zUMb2B{+QNZFxhsrQaqWD_dI6&asIW8^H6KIv}P#d{0L$BZTN76O|?yc)M)hFNDn7h za8~m|p;qSzMmi_8&CPDW(5mFM-9Lk?D1K34EXF6 z;**)LFWXeHn~@uU6&J|)=Hg-hJ8~b>R*ny}mD_fewlYw=evL~#(R?lL0WKS6a0=9x za>5GdCutv?v)7+dv?H90d;>pImHYpE-EOKY?MZdV3wIWxV|GFN*t#A0#t-ESEu5Vr z734*HN!@^DH<^d_%{@Gv*RBDMQeXS?t5S5N1uM?>c)!Kcl*kFqJ>{G!Rzi+#Ph zs&~GxH&pc|hV?SzQ{?N#O`d|wcE|u7*NSbKn$)W^nm6*3eQRbvZur{T0iTce5iTBQ z6WC9`2cfYd57NOQV7-`m~{6K{h@I`Fi`R-gJ*ozUuW4>t*QYjOCku z3!kD^_$+(a==0Ryf%~wBJF5z~U(j9~d>TAlPoH~yy~|YZK3}g!^&Sc9W$+o1jSpk> zd*|gf%zRhYuyCBSmM`pK!T0d|ciZ@*@H=rJo2?(pf4|4)b~T}1J4G(|bNR_}a^-6t zQ;{4egX}ba=Ps5!HvpB2+|#yWs7y$kpU}f?L{@5B#)>2ZaWLolhCeGX-6?a2z1J?{ zR36Zv7nkFI>1HtjEF^+f9@&OXIlBjb9Ap0!=vT3Al*+YJtswMb97=Hwk|9~%E=tDs z2?+9-JLC^qRbrz8r1BLMwu8v9t*oRw6M~ISbwoLtObgoS48SOv4Avlvq6vSKZ!|I8 z@00M@+ywMW6wIPZwjr!?RfRevT0c3L2)5c4?IN`+saOf3#dAK^W-(ckIO?{R@_F=& z`{X~!CFrA)ZB{X0a$MOGY?>s2hprXzRjn2fR<2G)=xFVP{C0m>8XsPe7@l8|yodxn zQzFf`r`PY0)Jpr^U^_>n_S1;efZDHwKSk}2{e$+aKk&0$rdivv#9s`^+zGl45`_ne z!h_g=jLVBpFRTG!mF{K~Co`cE}*8g#P;xaji7 zIx;``GQ3433Lu+F1YPie5mF)W9-#W5<{8W)(Cd}_URD8&KhrPe$ zgfV(3Aj!RZvajs)C&L-pqo0g2<=uPeI^n3FbfOrr#Am4+G4En<6T_YPu}tC^S!^`$ zD;k4wF^T^6jch~QX_*D?=ohyPElNGXv*temsb-qkmMvK&BSy++ z*syj7S=go6U<+k$9k907oATXP!-EZHfwt6TX1BK!Ot#x(nt2ZJ`&nkwAe)Q|Ruk~T z3Ah{psV%I#B?}Y=rATmAD+J^Zjq0tLx%2=7{{m;U>=lN z@{(?>*!VrcRbyK}%*HlLiVPI+8350gA30!;Lnt*1T}*$spqA@(uhy$wx=~@?KTHI5 z|KKVDw^5&p?_!l@|>-D1pL9A1& zUjNys#1sN2ciU!bU7}iVy-j!KtJB4)KT^lmBO8gK>um7OxzYSbSdzQWG ze%5!lwRj3oG$75hLq3pO+nm~N_oF-$_Iz2cExRG9x1s=+THKA;^Oz6yg(!}d?n_vS zF+^@}NpT+=friKV5RcDC_26?RjhjDydtp>AjF!&plx2xnaX-kz35%N2FtW4<>1TEx zCb-wQN0yTXsqzreQ45GZaqkWDs9y-20QHFNpuTbaL6ik`2RZJRyHiwv-BB3KvB1l{ zJd=AWaQ+7rz#{*qCMqs^EzdrmPbG1KTBfU`i6NN%-@53Zq}kSL6pizo$am#WbHK*e z%BgHOFvp*Vj0bx79(UO|Jz57{YHUzSa|S?_UeK$Je)<9Pq7{;|TPiZ##4vxG%4}oJ zvfH5d%{OHHH=({{e$*lucBcaVTU1d92#Mm?w9pvQIDvTeuL=@=+ji2rzf=Sm{K{G) zKBPq0Zh<$Iyx~jj`m)Hh8z|-aUbt2+VC}E!F5^W_-~B}NWY=*gl5Vd~`}5xOb$xcS z8hK``M3)yC6VmmVMO}ULr9{f_VXy3S}R+#Vo z(rE31_T^Z4eWHIFi47@VyD(Dyz(7{PyS3QlS-rity4C7k=IfQaCugbMVeNct4UuQI zOLS=fgUi66d3sv^vC98B!+MRIxYVkbMebZUhg2ZazqTsB4Z!Q%=r=HC5^551qR%DJ zU_k()T<%~)0IF>Gp2@MWd8x@GMr})491>rXIvUPyfHF+wGVE=iZqO)c4>|SKwHPXg zu#SHVxcd1V7`W*fXp-#s#&9EfRit8m`LQ%|=D$eBGrxSOyTRHZn*3Z8L)#Z6N02qS z>((S1OdVj$Mjc~;&NZC!7V{N&d%AMzmE|*iJ&=-lE($QF(BBw2(CxGhO=}WePIcuI z##G9AZSmS}zTmM{$+KF9^!sH%RQ3Bc zR#LvUDN_Bi0j$C7B7jS*%#>RoEW?%ZH&3 zA(tXl1X;xn*!Wst5TPO4QSNrwNV2xbipJjMTRyKlzb(~irQ628p2ur;+rG-jNnd3R zOE8$h(8CJ!ZHH)La1nL4Ts$r|9MD!QTYjojq>A%aMO+V-6}4Tby)FJ zX#G3SI|P1=#@}#@XYP+kTv*xjW0PpN@VYX=!M5FrRcE9%!hf+;MBlo3+i?x$0$!X7 zN5=-3F+ACER!8Z~|B3$_Rh)nm-SotX=ww%=mv_w|deVs!=h^I-j^|WM^R}c(cg3$_ zD235iKcM2j$-l10zYO8jpP_U*{xWca>o8P);yg8-%8FmFexB|H2fK8Iy!i`+L)l}7Luv~B3hlvWA4pv} zs#B1c$4H(y%)>ken866yx!2UG>2iKrE%5e-)L!ZLt?EbG*57zq*iKk~RqddncELYW#CJd2Ds^E>r3TfDOyQiJ)J#Z#&Nt)K1w%4bs--U%Uv1)vW#?T*jmV4nV`Os2)N{S{w`=gXyZ$OTqAY!pCF=Sp3M1;ye^;iB zf=EyH{W>4)&g9IG=1ZBpPFHngHu=lL&2m>28ThMW*6aSPnH3zxI*Q*GLek{+?i4Ir zrxUJ;y`{J+z5!X!y!`$wf8nIL$Jx6SvmX+LJ^+hAA0eVcLal2w&M~8|CrTn=O})HP z-3kT0C5frw1*rc8!-Cy!m@ivQ$Fb1P5LW;~U!5B*n}>CQPy_6vlAW#SH7arvY!VLxi+yO``_Nxs^GRx{PX=?du)h+6tKL zxE<^d2LwtB_j7jbjd=pba1WiSF$VEdPfOv^VCq!>YxH$SqQ8%aL_vJPxB-x8ETpsj zYsN3%1Br@*?nPQ)KSS!hmF_;|zs@fdljCV3W000#y_YJ@T+*y3(l6b?Bqy~>S{}dsF}t2!l>$BdVV04p+fGJf$Ta8mjja1x)V|x> zcPjr9I`yt+uRcf6sRN*Co4x->H|SM>o!VjQ$-jaFxC|eQ#RIta8;nRZs)4uM!~3!v zc*|+04ZOeq20XH4`}r;WuJZ7T1@BuAZ@S=JvnjkoHwRDdpY*x|yn{VF_8<6&J-iCR zJA6}k-!a2l^|x*QXWw;2(bmAc!L@3##-TnOF6v;3TjT0)^t#Li#_?!LP3}NAs^5S- zF0W))B7$0cw#oBv)<|(aI~uu=nA484S7!@y_RgUoS5T><7+m*+#p^v|~Nz^5{OGO6^vRFy!G zf5vZr-SBDc6qzRDOx;{cvLtOB#NOCsdYJ?|S(LtUe?Zw)5k-lKvFaox-`netQ*3m*PK|UfSf!_$2u_ zPUSng&yM5qatqS>jddcpS2#qDu_$F^1Y)QpB6sGl>b+P?#!y=_kcSgCO7N>E2tVRL zA;Hf_YCG)H*@}p^VDNVYg^a4B^h1ls7%d(WjDj(Pzi!FT5FPqLOR$H4&M$Y_Ij1@Rpt)QwTJ zn!$Po53V4@HWcR(%`IjE15Z*5#vVlauamCQ^~@hzT5LNy!hLuuqK(^pHIgTuik*vd zcl6Y5hV|TmK8CDD(d@mH(8%(+x^K3;XCuUY-_7~258}+qlqmIojup6{Eo!jI{iq~t zEG~%w(UC2mrum0mJ)*2E6A!^uAzosTI8eDtEL9D7r{g8~ZtzD0@NW&^U!R6Q;`iXs zIZKixS<*;w>S0)>yZ9#S=^Yg;zIa@!*rO3zeHR6N};fyUTv(RK!z|xGC9qT zUT(I(;hnb1Q>8BZ`>_cvfFZa9caHV3t|x!oULTuBOSkz-`cAuqm&kc8sx2&R?y2#_ zaJ(L83kI(@xT8 zkNA*0+SlD#<+qiGw+IPEEw>CqXs}?+dBn3#l6YBQ?(3eKm8&z7`_gW;`eYZaGG>wb zy{QcJov|{Wfw-5H(FHN-V-H@>s7e$Ty4|MQ*o`@#vAf?IDBV{9xqE9&<@Q9GX2nW& z-?(s%C>WNJ0)Ls}T)z-(!I(FOdIqJqAar_NX#i5E zfNG#exa&QfkH!Kg>2aAMIJW`^d6UgVQD1vEYBy+U8?8%A2Ve+d%{-qvq2XI$Pj096 zd75uuz9*74xvGu~bz&lde#M-*G~>oTi%y=L*w_8>SOf%WNnq5O$487hReTmdg{OQJ zSxG*soL=n_8Vaao1I4|vFpQ^Eps^ElEd;Ea`1a@$03{ZVEb-QTE}9D_A_^2i~hS2u6v z`K9*zb{7q1UvR#l#uuoW>Si*FE3+#uvZ_V(k-<<00 zqqVhy=8c-R3Yz>HI3_+|O!McMkzL2lKwSW za!RE+DJ&}Uv8Coi`a2%LT-3L?E*BWcVeVu}@<~pNpSFz;_>~i^_hLSnZY!6~tDo_? zEckqsc#j(3E)PzH=!YOX{X zxH*fs@JlQGr^u!eIuM+{T%MvH?y@`72Obu>YyD64{gUwKLie1=;Df;%!m^UO7wZ9~ z_%Nmb=lxmVFHgzDVaiZXy8ygo-M8|;H@V?!OnCL`y-cEPG3A;&2jgLu<)T)GWg8dq zE*F??EhjPYLk1xBf=yX#d&58sSdoR#!pGhC)iegzx>*bon!rLH*Q(Imz#a8ax~aD{0TG8 zY~%~+#@!h=GGLl7Ue58$WU(HZ2Z>Hv1ki}lxD;QlN#f-V+kLl12ILnOL!c7C9+}$t zh7H;1H7MSs~QU zHreLtO{1l|d9i*6mx;T*r+BeGZxTb{=juC}zVjg?Mz4&vakk}~X(JQSm!%EmxZ)c! znPvP@GxcQ>ed*ZIdO0u;dob;~Mdxp5iFc4DZ~Gj&)ifX%sUuz2u#qPU2yM9)8We|xpM0?>6 zB+PClXK(za5hlt`lsDb-Oo;CSmD%%~`|&cP)yZc-s~6P*sr%?1f&dN}9tDwL0-fD`7eau@r0ADvFU=P2aOw#2Jl zu%RVI(v4tT-C$qtDV5Wi!{$5ucr)emDo3xKt$h!R@iWiU=3oAmo0B?D6E-csHI}Q; z9pXQek)igxVoPnJOp`@2rARq;mE*hmb)vShI9Qr8^(D88l+1y^VGU6ichaeATCjO_ z$&U?ok4+?J><}^x~sjS~46`dcjGD+pEW1h~+er*m`O zn%8bSF`3`YMd}_AooITn$})9LInnHWWnar9;7=u_^))xlH`RQ-pI>eP3Av>7(7}0s zRvXHLQ#O}=E`|v7({GFX?7D;rm)eejXmAN%@14`AH&QqxOSe?5>o=`crdl5}^xB6F z^Yw01z0-ZYrO#1sq_1~@PzcuDJk=wnP4$LBunBiTFa*%(r4l^41T-ghfNOuQ7E;2% zB)xVL38J-E%;y`i^P zC(l8@)ohz{lYlT`@*a}gXStgJ?j}PsvZcY@I>Gp4^(lzJdO@yKp!49*8E(|7jbafwu8+Tlw}IPp17~t8?`%+TTv?XKi&BXkOWZ=ogC6 ze?xzZM7d=5D-LBClO-4MNBWgcq0L)p`<)wXyQ7?5-;~>K=g#}t&ipmk?{<_(hAcnY z?RXn<$;a>T`MBWo34GRW$3D8bT(u~*?r`4v&CU*fv!m@l^sxO~YA+tF$38%)>CsI$ zKK;K{9OO4{Cqr?{9KZ1qf3T5c2G&ku6Iu6_i1&7yc%Qh-3{-WQC*G238@#JVW{5ZB zS%~-EC9R2fCBiDbtEmB|iP}~033U7W9JKIcNlE_<-L7mjy4_N{fNf$xH(W&}=iCQj z`mrq$2`;6R`dV%aJ74dAo3A?sUq|v)8*slNs~_meHjuZ8f!ZVP>d7{S7g}FD-Forl z=aHu#uF-E?{1H#R&Z>KY-!}g0JoP?apl?LfeP`meEZDCNbFpjuY#JmSq|9L$U~(*Q zy|_V-$-{p9OH8qWEg*O^ZNYqVAxVb>V$ zJ}U#x)K^HgN`DXYBerwQM(o`aGb48E(~MXlBbm+a?-=__|Fc+k8?Q3;DcSv_SvFqv z{Uo)P8=t@Tl8x7GHXO4gx%t9~JbMo#5=Z0Hc**bFw!n{XQ9wBkRNy2Eh+K050Pc+e ze$>iEc^frGahn$cSVFE1k0_6$b2_Y*?Vvjq>EO_$-X^o>0ON80(qJ>7dvJ%@wD&uO2^Zd z6B3PVxcfz;*&oAr+WmYyEmS-3Pexf+!2J|3*KLeK>u5x+v&5l6HkOZ)4itBVw^&c@ zY(tOMp|n{76Zt>fM_&7N*SM!B@H#Aw^|!6e`xOLZ;*)vt4#Jp|B|Cw+pA9P%%Dms} zal>v%q+*4;kesjO@g~@72aqJ%Y<;LjTSN-$lP1uFTh|7qj@9F(Jo1-#_9^GOU!K^Y z2Z$a`6uA{ViJu8=L}RZ?$lXj2N0ZQ0+d7Pa%iVeN*R-5;V*UK`$em5i@i1aMzFZ&( z?>-n}45ElH5TxENBfl%H@;!&(?c~s{Yv*^0L|?KaT74usjxdEpXdaP~AXUj{$#N(0$YQd-1Pl5 zHLBSLi#sysQADA<%T!Eev)z>mb@8w2Qj^I$nO&Fot<)7;%J~o@e3^}vs$Kr~4Vo;L zmZ^sioQ7YBS~M=<@Q1&=F|C`K)8-#uaFd1vMG1OH59sd@KP&b?>0fxI7hWP8~vUMj|icRk%VtDy& zjImTPch;T!%9=K8>gvE0lMB(9OEj&yS|FsY8=nxtmdmpAcbdp})Hn7wVeRdSNbD&Y zO)l7Pb3jK)XxLzpd{l@xugJxZz&M{=ehRcKKNU)5*^_^tp0P`?@-g=UGGGmUoyq7r z2|sy}FpB3AP<)74i-G}N9NUrR7aT5&jU_DVxyp<-=G^nlAzVUzCE0z_a#@WO$?7() zG{e`-R-|erFNV1}SBf|b+!+{kqWu<(q*Llr(Ere_z(VsDLKgn1e@iTpc|xZ9_y zvfs$h)_WT5d^MW-z%k`(8*{76616qFF0cKvL%d$UBK24EZ!~$mDbvZP^~Yz=yKYxA zq+J*d4m)}IE6pgHoRsI@=6nb2e2fR^fzd>Jh2BrZ9MTfo+D)0ElQaW);+`PdY!|zc zkEAGSi6z|`{-Y%3toaaV<8*F$+n~P80Ygyym`~w zmehN#T;#R{Cp!F#l?^Eb5P$#@Q;0pg!OUpUo&qjAy_;ZoFTtA6bj4!}YitzT1 zF#G}E$NIV0TWM#&zTO$|?NSMF@~wSrGI4+J446x~<}MljG=D()GU4E;lIc0}2Ne9> z8~wL17_qtD6)CoE9IR5vh%-S3Awy<9RfdE+(G;$at&%y6XOAUG0f|Wu=5|lchPsQOqS+yXue&~ z@y6z-vWCF;=_)KAAwSt!GrY&91Qek8M(QNl$xF4-!3-AE+$y%zI%w;wT%T?Q7AUAsIrr< zLP56$H#Xp~ey>8YZx+A$&ZGGGsYicCov_rLFuHcw_XhkOR!Iy8=OJv8{R zXvp6g{WfuA#_kCBM(SP`pVv+pmlLUbo}XBcP{!R+mt`!Hdr82Vhhtox`zw;uTOi+8 z#WqfjajyL5AA^a(J-(_K8YFM(qlFo##zOZoz!f1lEtdi>*a{)9hFdthwNC>fzla>s zfls69oi;v=?FHUe3{(B!Z@0&pe*HWOxh&Q~E*Iq^mwTOMa``M?VJ|kh{J|JrVQ*OO zKAC7rMSAzidHH3d4bGR9zY3azipiAUF_=xc5Z90K=owdQN4qFy+c)RKJ5keQrjL>j$SkS z4a1>(p^4pZW&H%AfCkxFl1vPLY)6E8iNOGjBA`4 zc<3};v-M@gYnZ)TT0(x}$i8N63+>%vyLQG@r{E1g^z!uzRqqn&g?97p{QE9?e~#WiX7Z=4Kg_NI&iKRFV!3{F4nf?Vk^K#S zSjHQM+&XH&8q?rv*OPJXU0SML-!V3Vj5M)fZrUj8)c7MoqSQK7dOewV-Hjkej{?`2 zG4}w?Q&MPrDb4GC^53iHcU*z-U-n}rnb*(Ut##q@i;-B|p$!0NgGmmxysjRpdy3Y) z8|l^7+gas|{^dsc>J_Sfgs(nI)kkkyJzv#d zH^VIQ&)4gsdV_quBGv2V>uG+3&3=IBNO8`>9S|Ew#MkI1vmbZr|Vhy8JS{y=q~o{{$1^!YqPv`f*PHu zMwP!)&3buVM58_&!uB7by~xKA(BeVS1dbVO&u1qPL1|KWzg zTAXN<9jy9=Q0E}uwAM@A#}R5Wq$KA+B{ml}P~w9WD zwG)8I9&gwRP4tLtOnYZA9cL%+m%FVuhver2K(g^$Loz=TBo*Q(2Sm`F3zvZ2Emku2 zUKV>A-2B?_+k+x?a^Xp5jIXf-I$tWrd8)B*$(#F0)m!OOifih;Fm|}O zE3}|Bx$9bNw_)*5-q!Ywo9y51)5@wACrE^vl4otKY89H-*wwCzhjz8De{W+~V-WXy z-CMp+xA>|?He{(&y-1?|F!wE+eQh?kMaTWG>_?^@B%Yf|FWvJpItBJ4`E|``bP%VB z&0;igLiH3(MGZ!er}gIrZJ*pZWDcN5qeD{>eBkXw#MC^pr?LMaV8jPbNLz>yf3gsr zGR-VR5{9utvk=`GnvZUDW&WegN7Yk9eUbs_K@We^K14nQ>_efs-K<1W1z8kmQR(Y9 zNH`_yUiEh@-L1Y5Q(<3-#)xqTXN%i{b2$>^7{C?JaPU47|F*@-zkEWjGLgnQF$Z_f zk4oSt7V*D=?eMF%;H|R zL$D_6s45qQ@Mfhu^P; z$)V+l^Dq){XcK@R`yZAgsX;$zBrmW+eusOPUUUJAF!#+stF_#Xm@Fn)?zf*~c`)A> zz0nbfN3H~I1=n#ph?owpkXHB38g1%X-Rr=#w`LBVLS34!?<)L$7-52c@ZkvHKw;gQ zh*tL#siYCV9sDT=Tbmy^1*ty|sZYMj=X|wpswRwW3`*b0rRMygW|j%$0@bX`S})v0 z>d(8)S7fXhzr}~y_+2XylRSuQt#==RC^rzyH`m{{Kb=bR{s|ZstKq6SVAGnbPNrrj zYPv0arPEaDK40mNsLl$|s+Ucotld!JQAsAKD@GbPO5OtYL?$J(C@xj&)xFZ1kYVB)pKs< z`?-2v9Z7%xgPy-!ovzDAiymz{e31aem2yb5Xi+Z|uY{>G(ffemiSKEOk?oSU)1 zZ8hX4Nna$ivEa!=^;m75u9=h$1FpjLFgt*E+)-8)e+#j?pr-k|GpGS>zOClX?ALnz z+1U8ZQigV<=3uh)!;`TL95me6INvj)Z5=*Eax_oN+CAHNO+f`{!HTW`!XUeQBl+i_7bUcPR`IL+rHP=dmb_H+0MH_10eTOk^Rt_pbONk#9w?C zFr{Ocbte8Q7ec!uXdu*PkK~KH>v@^+;J~i{MNZImS~NN)ZN49=da?Qd7;to&#K;Mq{cQf zO;R-(?d0u%3l_=_xGw&(e3qkMcBd`&>zr`h!;mQH(#^oX=(^Z7F77gj0zZ@~5M&*Z z)jPYZ-{d3_KWsM!bE`K9?R?$B+`O~dH~VfH@2vacg!ZFzwQIw#x8LTh&p3H$`)f7PqmqZK&17Q`}Ds-Ss!#Yb{~m!F;i(Vw2Y?IqAKCO-7$S?qx~+P3GoK1Q8iidO75Md?8bA&9Q#7*D#Xp^_va#p20SD7e(fB z|2p>?L-_1d%aTL05R)y6T!WNF z4{xkses&P*!TfxGL~D9Cy_1HY)=x1x0>*gLPH2nf?dKlE0dZKl@ z!tHjhEEWEv_}p76mb zRqx5L-UGb!^+s7eALtv(`?NpA{7S)*Ni3DJOB9$_P6AWtb430x^p40|6dD~;EZ{{M zhu;x!`co)UO2XfYe z2!f-F*+<7%f81D-1fc{}{0aJ5jBc{@4}XS!7eiOnuxT_Jj$gs?yjs@$w9)+_U$2Ym zSqOQu^s^JF*WcI6UiTciX}F&{zxpK!t{&*TU!T3YC3T+Uk!vQ+ANf=7qpsNz!DUtn z3K{cu6-|IbVDdB;x*bpglFyx>$n4oKf}UG{IXV+_~qtU)ahGZla{ga5h9A*YU*!SO6#uGrx+M6m{aXN|a6 zmk6Qw@wc!$SwCl()m!U|CWpSYNL|9-aWFo8+20{RFpil_CQlYkV;Lpb&2!7|hFheo z4~&0iYw4okh}V@-Gr6%NW0Wdv!Er~NwYp`_DBq-(mFp&PuDap3)-TZfe3<+|Hqx=V z*)>N{lUqN$-R0*hT&8EdKOoTmo zu+ihp1EI%wPmi0AgC0LZr#AC%hD4p1*{$8}r>GWK7+hdwKq(cIr znH^fH0Vw(p_boH@+(k+`Tc0{>i44m4b4;(RMNTqRH=1+XjsHwncgf97F|szO{eC_v^~~?Tlsj? zlX+`Ng28d&F}Jid*P<`{95sGleE_`EL(S?O#{+zI?S!zn(r#)nasSwmjhWobHIN|_ zkM09NnAd*F>oQflPD;TU%Q>;@uISl%|00^);rEA;y8QwoeY~&8yj;_r3oBWH=dxgg z3eXJN3+PV2R=Q6oi|&!Ssl3-7V%5<`m-oirEV{hgRdiWt@w$8c!`#AWh+__hagtq2 z+T9F=Fs3SGulsnq+uoNs%%bngiDZ;Oqm_TZqg5fc7r&{1JTVfwVOT<-j3Wdi+*MP-H_=e5`rsEZiX&!%gBI8Ox_^fc#j#=bqU+ zGnTgmL$|aD>T5VQFdQ1(ZLksq1IZ&}xr%L0xH(-N6uJyZR?B?I-t%A7TjjhO{aR+s zIhH}Z#ASZW<%-pq|5Bw!x;K{Fn18m_E$J~o@CGY6ElEiojHvGkqGXp37@$wfO)voA z6k>pG)#7)nFnLtK07tXl5G1hDeYn&Z00STl!1@1x0gi*wVSvl3i~&w-F7o>o3(R%* zX*UBg>U%QhFl(iB=ZDq-nIoqTG!{96nxOu-eOs|e;>b-{q%RZEhq`dsdWA^~H+@3D zB_=Ci6?a8-Yc4S}WrN$v8tdMTRx0LU`mC|FePBMa{}ttof^EjU%aQ-8!aYcwR-U$>HxbqIPzH)OLlzz z9EGs(KDSU2C-sWM&&ctWuHkQ%&yQ;{$ zgAOs8ee{cHri1?Q)!d7q^FzM;K)>Q?n^2BcgLql#CckN{wU4nDw%Qe5wyf)DthM`5 z##-fB7ODm}cz`iaN4~*4rTesEo}()^VV<8QAH2p5_iXgs^XE%E_w-0}PsPQ?Jw>66 z35?vPyO~6{3;b9wUOhtXcW>;O%}?Vi>E~Nu7OWQG4rMZpH$Q0l4+5cK59o;~?QZ)i ziHO6}5+Sxd1GKS}S|~A@Y=W}P;i#JF%#5S^_lJk%+QE{ zOQSXxj~BHXi-A!u zghz;w8NfB4E8}Z35#>aGqCsB%-Gh*6AZ<>&nprigMzmxPlwaO&J_Id~96g^sQ0@A> zNUao9xwT?jHg)2vfC5gT=bBq8Qa-DofNHf(?a!`=58BAfcCikNIuRSE>EwEk@tsvv zjPm{K;QpLyam@c??QP(ztgd|j90(FDdJ;tii_@e%)}&xfMyR2!HAfS9j-CTivC>K{ zomjM^w?PTju}&vULYp)3w9H7Sw0h^_)H`EG?nrMP2T?KMT~rJZ0YN4B0#68%fI66%`UE$_OfV2zXVeMI4{`aqC6{jZt^7n3U@9@us?4}*lqT7uYKd|T15i{PJ+gL4c>X?>LMIIiq`lXleTNbGi~CJE zHj}T0a7B)IcgjJMsw`;_4J;b$RzRLxuX!uPGySLK4YxZngEd5o_)|FGl?_BwBhMg2 zr@eb9UqJ3@oV9=*uZ#SlqRum9#Oqsd*Revc8>D7rZGL2tPK9JX%8 z^56n0L{k?jV_kLO$NKF)pJJpxtKOTHj2E8l&d<;*L9x4dr2g5d*K(zFkGAvH`Q^9s zi$3@o1|BD17%YEI&C2=a+`~?Znlvx7E6DWikF!-GkVkWuVgG!?^wFqGkmoN^-0au7 zEy#29sz9ELGoGpgQeLN&mw)0TTV(iu`@SRV*L9Ap39>s+A?w8koutJTvCCh597V$@ zT;o3gc*aQ2^PjxZ=(+ui&@(Ab&z8;5^Lr?@@s*|LHt5NeZ3H?qUuqTdA>6XN`8?&A zjylYP7@FMX9~!0oNm)t6okG!&8hH)fK4LJd+1B6kIo8ATzs)C8oekQH0Krw zbx(0-d}JYp=0fnNv#ne!+8BENd}$eo zdi8Gk!2A6*_Pf`AfnT$)G$nah4$tlYnZLGPda&2OO>N?PGp8S{s!CJ-LG(r0D;dhW z>r7;;D80+?y5`s*!@bnM*qE*G7#gby5%o5@v6VH*k5y2 z`;YvMb;r-|0mM|!ghB0K^!k4tWUw_kNMkPFa1;vN4d=sA=eb?F_a4L1e5u2cRLpeV zYKP`)0h%K6vYkmIvP`2NukPSG8|;dk0cMS1-&S&=Uhh7ej9|aQnyy4}Wx4(V`=Nn8 zg4BX2^HXpc9G9jGE2%ds)$LM`_J^^@q`MzSv+gH~MXWClH$Uz`ZCA|yGl3}6dSaJ6 zKX44d@&3Or6e@(3TEfjg3@X^I0*G+A<3Cq8Ybi8T~E?MgU6i=rP#Sv8^RK+>uJQ)M9DFBp1RDhLv;pV^7GqshgM5S>+ zh=(koeZS=%Q9D}MFaw!GME}RD@J{2c`w!^a^!$~PK_}bpa3|3B0NwpJ0G`U(WtT(B zz#3=&{S$&?@+{@&P)8_XNifYNf$L)7`i51Cf8&$$*PXlEL^1n2Zld_){Pp)g%$>hj zoMffQ|2H4$5*)dqL}&Ovk+nP*Kc2eBl9YQ`9c?#Ij`WC(ZZ*c*M5FMYu=S- zV*E9H_R6dDGwMpdw~^-}ulQac-hyf@vSM(%^E(;%FF5$IIq<3cHEpm$#%D7HD0jlj zW#bic>N|IN7nu&paBh~9oo{2po`dpYY|egpaK4B{=j5YMqrK2KI$vbY*c|v}RpjQr z-+Su2IqNd<3nwo?z|wo9=h~efc9+KyzI^Q5yt&>~(d+gn0@DP~?dgY@?mkBt?GRJW zeP{m!K6K50aNpTN#wnxlKfUkF_IvLDI2})+c*9c`%6#8wwW2Dnhq@mZU?edaFk7wh zE53>sH8t_sGt2~rNdL8!OrxoZ4{_T9v#GXKUQh~7ujz2*S(9;RzWf`@eHy^MU^`Y+ zAuSsFoAy|v6c=~OmSozm;kQvCQx@6T{X+k_2`0ZEU4;C$QUl(@f_G6zt0o50t9jGi z0yBG(l6qF;EWhl2B|CG@DbSlMKDa5~dLQ4?YD* zqaIl&>$p$sRy*yO`96$&y{~7-f*07-&+A#984qTKDSW{W!f87C7kin?g$F}gN6b5F zBk_Clj@nTC*1V%`EVhTAdC6;PujKQElh)tMaX7wPem}8`wKNTnV|Bp@FZC1L;d=*| zw$A2HAI7{_wldUCWRBV2|5F`jHNxZeHRyRraoAoqKwHYz+9-4lGJRp~;46reUYhfq=*rwfoTFzxMNb9o za@s=U*tKUr_j#o4`FQKpT6XMp`{ucEKD+e4A7Hp(lx?US#_(y^?KfJDBzM$kF-g35 zYr&uA`Ah83;>zh2ZQqh;p+f*m_HrN4|9&^ELvsD`f4sh{gZjRGdVNu&I$PzWKU(Eg zr&Wm_M>k|Xe8wGfZo@IyvN?0^{kA=%K%!rnR9=(T_2K3}kYGLN&a+hW_i=ORKnbdhP&P)3XZ6~6}hT#+`(zF=-#EHRuIYK5GGo=vBFJfyA^Dy$E@J-|E zG)^<|St{HnI`^5538`Wj-2{Jkwf-sN(x0lmq^$OlJgg{&D7#44*_*DP7i7j`CSIe` z`^0&sHnj(7rdHQ}nS_`-*J5IFwCTg3NiOI(;EiUj)0&1mfg{&!^HDk*x8+|w$RQ-% z&fFq@p;(l@kgZ@ob|pM`mMIMv5M8GG*i6j!`kz^R+Sw&DikeneW^`&J=mL3e;(PO# znSN~^jefP|aq7w^-lBu*$^-rSW1yXNP>3ov{hY;>=YQ6fuU2_GUzNJ@PL=;cy1cgY zUHOj7oqjfd9TqaJzUb?~dK@2mfLfR={IP$QpXaapveDFc0XS7X9oX})u76A|>Z(CB zNFBW{#4e`P$QaYw6J7FST<*PV?iuR-EJ`-@?Dm#TImQtne&dj4QTmH*pu#@8jI;OmzZ z8JN1Vk7LdLlknU4ItwBkU#Bw^q0>$sqVpQbkUK&rN8DXxSKw1c(d67zLU6H@i<@6m z&6*VA7)T5?|8E+Hv3@j>W8y;h_=`qrowBoGtik#}$OYIXfcpd>y(`N}uIFqA-~6KZ zl#BmMxy22CWd^@s{SmnUhW~;;j{mg#@ED`XExHkps~IZh4Rbe|*?tUP@x-j;DtTfJ zn6D3F@BN@&3-`Ug_ZM2T|KxT{xBIWijDCwH)R$e(b(+Of*XO6_um{{6Hm729pz65} zb!BBNHMdCUx}O;w{KSnWX?b(!VFEL;8iP#tALBuO{~cX&M7>{|N4?LmLy$r7KY~k9 z%#L>YEBpP{)Aq*#uOABYTBZ|YgZOP1yM<61st4vzc2G{_Qh%Iv1QNX zuE#2lXfgKqcw3B(KWa-aEyk|?H(QJiF0vFY#>$n#IHZ$LS&VT&O^Y$yT{~82E|Cha ze!~`Hiim0 z)t_l^{U5Bo;GXWM_$-kC7?6YahAVr%chv$O4eLihgF z!H3h@Tlgi{ui4Xfue_oup>^_1c>$;0_jwt@vU|8OxmKo)|JE&-n(AQ5ne6SRfuVD` zHG8T|wpuTBUlCuu^4AgSisio5-xx7sZV@puM0)rJ>#3moFH$4tKI#9~fsPkwU{`GV z0dzk}dyMXXqI@v_l_{zFFBo*JX9LP^`dlclTepDc^d9tSUqoNyD$O_o^?)~nCJ@_k zy_f93nd2q5c_aE7u4L^ujAh*1?|G?fSZT}p=QfnfWv6gJl%4qHlT?t-nYP({3VixZ zM*gI0rZ)0x|AaJC5sX4X&84lYE&e=U_ z&h&8e12hE(PVKW(RU;edcfyR5cOgFOuBjFII=+oR>gMG?;034Si+A!Hofc1B{A)mO zP9A2(==RTAZkEu|mB)cV)x=tB@*3+3`RM9U9;b7Pb$Yb5W@hr5nMUEyuDPA-Vey?0 zHe9&;K8k?Iul^x8lH7SKJWrBXb!5$uhT+j8HHD$MUu}9n)NrxQH4T5Fmj8&@8Cmq- zQVU|t0BWw^_7y(%g4|?I#$P!9;DzT>uo+|9=t2}+R;l-Xs zHZS^fK5wG+=4X(X`9|bk|F6D)V4NC*I$mlHiYAmYR(AF@MsG(oU_2K3nAk%t}=3nL|kLm~vySD66J(lmTqv8Xf8yWNZGBU9z^Z$%z|9zHl z*i#70rHt;fdB>%fF~E{*=N;F0Zuo9$1d<#X`5T4XV+9dxTBUrmCSbp(SzCmPi&~&nR?(c(on>#4xDh@ZV=GlCJ-EB%W zhZ9>V_AJue{OTM}bGORfUb|c)-1N8{AxAF`!4O?xMcf^f%jWszB}#J}WZW%JW!B*4 zS1FmUxZR#zi^U|2OpP9n5h)z`;cwVi;C``_q?{ouy zwB_2*bq^t3@jriJ?TrZUGhm{T?H^9LHdn4)e#Qu&PX!|(YIOU4Q?zN+`D-KaVgtuk(wcmPcXS# zo)RxNRPVL{U#bBv_H`_*5WR3qluucEACW_!(HkT4E$jnx3w{B+U8cF*&xRX0&pYoi# zF0@QCz-bcm-}fJM9G@1{eBrN1Zu>C& z{Dv*P$${#U?OfYaQ}$|f{?TZ-W=(QkG+Eupa{t=FEqkj&oA{DbG#T$J@XC(OV%}}{ z+V>SUtqDb&RuXr=t?9(r@O({#(dA2NlPa7MRCr+yjX94CSe{b^(R+V zm%SXFzbRa^3Rixn_IIpy?k2F>w}E@^DzCk_Fgov;cC_YJ@DZ_PVs^Cbqw3`Dh6|m& zpBja$dQ?X&IjRkxa>$#se(wIj6Bk{sg5BSg+-LW{%;7{*h?QG%oBOI~m$!@*{m1;x zw>aO^w0%bvjz1z^Fjwa7-%iDRf$^5vv#P`O7hh4e2n|+0dFHI}@yW$;PRG~I3U_w$ zc1tyDv~eb;h24h4Y*fGn98Rt=j`IUpPl>TOlO>WS{P|`b?oAJ zQ$yr_eFStSn;XDwsSKA{6>DD#Q3B6F{f=4TwMTf_%I5&|UD7tdwh|?^b_a=f^S1VN z9_DN&Y3FwS`TSc?*|!b(ojl=!Te~w9E_*ax?+krj*^oL+J3*kboo@$_08n~{zNtJ- z4W_se2gu93y#z8y_P@<36ezq2PITTh+e^)b0rj^Q^L8uk(T(9^2LG;y2c6e*kSpDE zV@Un5F<)IY7%nq%>c;`sZ+L;d3rxlWBQU2uFw6L})fEzR#0P7PnqctRwi|E6l22iP zu`J7lfKC5*oT!aUy*}JVze=T~{;koTrr~p%NES`w%X$2r1DBpto`j3tb&_sHgor0S z!sBa7y=JEVvP};gHqNRE*B{mU-H}55+$tpPq;?L3%N~lf2@_`AW*WY|fC5{p^&!)x zLGlMG(npD5ODo0bg^|TBr?ZDruqs@(#J+k8e>TI#`im>Sfw+SmS=`z2A*G*>Xe0{H z#pACeuR6T-X@{SrgS@Ui7~=0vYFYbgh@xu;L&Cicah$V>KQQ0n>wJ|8_B)(U2q&<} zbu@hZ1BiawwFRUB`dmzmubu#0RXGtbtcJsitIb0GbYu}vV$K3p60UzGQ;}qY>NfDF zb1TexnTPr}UE4{2BM?3l?|@a|`c6S3Sdzix+X7)#agFj*#aRPbBQp@c`x&$Uv6ND^ z#_p%eXE1tc(e+4zWR=Gz>sdD(PZxP8`om&tGLj7JBaQZAf}a`B%CJjG^l*S8%ix6W|ckE?j; zd@o#fQ?0nTUMSxKsBX4i59&`3ZF{poUwjACoK7T?ufVI+ei%@9r@C5#zZJYxzF&R0 zU*r8flR5@AWrXK_fa))VPgc8&;-P4VO-~-W~xI!JxhMZ-A%+ zv~L7WGA%4Z!<~{#22@r!X4nbY8Ie-T-EQ2{@Dd}OJV22urs%uWG9xmYr)~pqOw1_p zaG4c{ZjE|%eX+k_vMDZ8+I#%J)?4aP8$o7%?$v(M-K5rF2V6iHtR~4E$DP@==3)ns z*m%DR*q&`U)&X{|_i6KS$7%C1CvnsBF?&o^r_RZD%%<(ZRLm2TZ!jOzKlK+qgpNZJ z?J@;ObSbnUlA^QJmN;ioSn!WlPcVLFmk`m%>ebJrywG_G@#Y7 z(rHp@64P3ctpSb^VG~r&wCp5v53rh+ts8AN?xPpc9-X~b)15r+q3{Q=en~(I>Yb*g ztFcVi^PRl`Bmk7=1JLR{XpkH`;-pv8Bhp`AV>+*{oJ#6u8zbuPD(2;`nXH)HgbW+9 z6LJnSNFLVmrn)=I0Kr=AWQ+^IiwDy{2&uPy60aLcRLSl;zP_ay{H~4JR*NQzh zTYR$p#<46D0xtdEG2+GQKRO{lP8Lo3G3>E8@bLkI#hCMqyUr)R1hyADmsbb8p zm;N~>s2Q4?>+hlyI$tBPGk1QjgH82JB-yF?T@udQ{S}EO0!Nwmh3zm}Fqo&o_@RVy zaUNu$KR$wk4C-Khema=OG`j0A`rSnEXyQ9%YX0Lh^2Se{k^2kw&kU@%e1=89n zQ}g4T!7X*2D|`2&bpK-!rQSa(oWaPYuQcOHPjE3t^}lu6DKo&~>M>ecKOp|lFF&3s1{_x*r-K}q0MjJhDhmN1 zO}NJo>Cbx*sliy^O<~#9nvOaHE|UL}Y#JKHlnKhiz|1CJM$(+O;bHwj;jhxGY#Y)< zs7wJTg+IQNVq52E+OI#%pS6e6GG|sH#V`dkz?z8FGV){>B0mr{hYF=!bdN^X^PtwY@f(zI(u7q)Te1zS zuR#bqYhX>2Yia#=W|HuoVuKT{;j%}%3`_mZv&p%+9HI_|%N}+_x)Fj!{fKM0EsF!VQ`>E= z^tVK1WtnZd%^8Cdma?I^PhTohhvNxJ{HLx?nCgBIM! z9}PsTvxAo>L&xl_+{(%)9`gFMLWar2O?K^D7}awX8s^%EinM*$GY0_=odsB5&24>0Iz zoVz0^Kh_15F%_QfmvGr1+6-381gK(Az?MMs)RHz$N=IyhCyO0u2QLe4pdwCA`b>+d z(XeqTP~oyCy9`*&OAAKML<{2Mup|Ildpwktznxl7rI~Qb(1i|7NYW(FIqcTLCna|( z9|)z{lR}a;eABkE)hAFVZjZDXjX8jFfJvoVv;5noMqP|{=_zXJtiQR0-Qw0c#a@Vj zCcLhScWhk%Ho!-Fp*AnX%CCOdxt9V4Nb=zp^5P{cRkt32UZkJY$g8~8AJeh*#MQPw z;SiMP(ti9oaoCX9jIAPIdDvj(#%^6kJ_!CGzI*N6m0oJXJ=P3l%jPlp1a}hL5f~Wt zk1Vzlori?S$Vje@m$XsFX(+G#K&2OwE|e&P!wYdBv8mCOVqU9%#G2|_#TSr(R2{}S zBg2*x0XCQ!)Q9SypKUM`q{&@ORgHxFy{ph4K7!4)(Y zgsj`F;O#d3yGb^fhk?^d+KOijNV^4dvDJcJ$k*V^LSz@wh5q%G>ig#!X^E$$1^01V z%8!{dbsL5MC0;dEpT|_K3HFo~G-UwN8qFU9T+hym&E4PPj8A6&Ea(27)P11j4xiPH znvJ(yp?c?3dF-61DzvEoqSAC(%U*x=bv!ohZ&Yo$@nTWFAvP8GlllzthII7IP4U$K zQVZg#7uwVi=MWF>8lQotO|o+?BELfooZ5zD)i>4Er;KT;&l)1FENRf?00+KCsyk4& z%iqllt1k#tfrrhSU{8D(fl}Y>eQeNg7qF=BUH&hN*yFAEs@`D_K)rsQ!CSS943HKB zyUYL5wN^|xUyG>*ovMtLto7S@3(O<0zvI^L#7p|zS2(yHHp^eWKgSUgzQdI^iFDN_ z_j?_9Y%uUcw9sjC6ja4i&fd_GgobIVik;Pd{|Dcpp49xjkxFUclp7mREGe5KRTR_< zds@wrMk>)uVYF%RoM@_^vr`R`^6)RKBbSg8(nBeiPehy6O-|k&8PB)Xqp7JIqN%@n zGr2x_ESkD+S-XEm`#$Y_uCC&IR%aDEL&TJA*@uoI-mCqcAx&LFn%>DD(UCl4a0apu zEC-t236Z)XCl&CaP45(p=!nj<1L*f%Se-mpojiIfNPg2hg@7d2JUbfd;c&G5M1CUm z^E|#W5>3q|@OW#*+KM)gGB@oBo8d@{Pxb#O{FE)Ec#@#nu2_FZtfVj2K5$hHpCB-M zv^x9@pF3&~)s(EPE+CppTRa1EyJPd(+o&=z>EK*~G@iF<-fMj*l4mUKKz_Z}g%Pt? z;c0s9o76$ic6r_J{Al4)@CWq_e#lULF%;ED}iG5`a-!}=z`2i`)f<)C*O zxPbw_JpeZ_z(;>NxPbxQ6@VKU;KiQ~ZeW1>0l0wyUi#_a1_rqFs+SDF05AV^a03H; zAOJToz$-rq9_@ci%rVH+#OHb*W5YB6)QLlR{0jZfDyk(Ghi`hz+;}`v3nCtzF~P&5 zk(n-KiCZbyCKiA2(8*CIi(CsV^Od2#H3#&_qvw3^GVL8k19HO$2n<;uW`kKfTdoG# zDmx#t(FO$6^sJZN?SNdmu9x|HTHg3z~D^Wv8ZM=)-L}&*$=jy3hrxot_^&C;!myB6TiRjFs8aHkz?EUnnwbV3)X@lhzMV@tMVrC9xi>fXZ! zb}I^k(3kUcL#T9M6#e*xLj)Hr)^SPnN+n};MH~42H@`6~Z$%|f(p0bUf<}}=%bA68 z2CTlvX~8J^;^=)!^EH$ScUfcwcpU2O&GshL|gMF@SZwr1mxO;NbvJUf1CknCe|!+QTk2j z{a=))5lFRb!1?>H5dqjpnrUJsYhtO%gR%Z?@sa@#wG}V%O^5q8TghGiUtS3YLdpyH zD7hkyb$!y9Hi&5U9~+ESa4K%2|2tq3N%l+XZ-P4m{621@G}fi#8Z4YH50? zK*F$J?Ul6NR30w-42w{)T&aI+sm^1?>)*N8#X;`F?o~qU4~Ow_!n2ronST8NKBHl? zzU?d!Ut~;&J%Z3=9>>QZJpKwm+*(&ow1FDnl_feQNlf81* z6JHxfxk2~x2rp831@84B%iHT-{wl~DZ8u5yvw3AK7c#^&IC6(rCO#p03$Z9>Ys8*+ zAqj(undBnXp^!(PS5Z>)l~c@VeZI~{rI&2Bxyk>cw9&dYA)u#RA!O($ZSpGQ4YB@f zHU%2zBwf=%^EU8Fk33}TC+n=pOx07;9>av-GZYo;W6775xi+S>evRV7c*V=HrVm4! zce%woFIKWn=!?_nrC{Swr266&Cu7MCLa2k&kTt|`b8@RM&TO@aTmw8Rn3)00 zf%hI8OjN9mQ^SIw_-wK~=n*$$u9d2^s*S_+#YQA{nI=FrRK`T9{XQD0)NhjM%z*mg zl4*%)GQZ#QN*L?(mS9TOGOWyI?{mNMA!1bx|g!)7;K*CXq-lseoxeph`>bmZdLgFHfjAnty|*%6(xv_wP!*v8 zFZr66Y>xC9Rc-0~5Wtr13o5xjo1Q4yE%+{jU!O>BN|d}4V?7=ZtylVXOYcY|cO**Q zjkWJ19g`GCrKN9=C3~!UdPv`{^!0|{H-D8nKGdhwHbI-dAjT523PHL)m0zm)yY#x$ z1VXp*oK8uN`cj;u#>>-9)@8<(Q&ah0j;9=RU`p9_sgdKnR@_12SSeL7n&TzA;oD_i z2*tZ4*4|U;@h=|Q;f3DNh#LSZPQ#KLtN|sv<3xv%-e>7A#gd!o6Kk`w@OwNI@hyv( zF&q;i3}`gR!bq1Tu2iBrQR&#*3nSY}_gE>aV*~j1pi??5>yVfeloB@#58nsD)>FO^ zF{GL^7VCN|wa?#CDz-J-aEuRaj@%C$69fgaN+>suK4c>|QPO3N9{PM_wvvZFWLn|+ z)Yvi7dFgRI^y$c*WUHYuTrhzOikG~b2(6DHM;_&-1EA$bq40*&7d? z^oA}ptrU|SLRo>}=?L-5>=X5cxbH!(CnTYDaq#5{E`-h`CuLNP{3tlEPDioP~4U?=~1^X5g&1Of*_vUj2IK~NADr7`%E$|y(5rQ z^@0DuC4jc#`%@OJk*bP4n-M?wu~<3d0yc+w5+Of6&h>{{uilF%cd1Lpxh@g2pAZ&U zK)1w0zPP!7l%O}_p#!nxN+)bEbe}iQXoa3T#o@eVJ z$O(1BVh^IMDNaY?sI|=aGEcWirECaQ>a*taB9Lt0G;QQgZkZH^CdO$>0sqa@9pys zUF`T@NxtM<{qP^lx%F7kKc6D!t_v8ZY0-nV;txVBVTZ9up?XhZDxT-adRqL`14JUP z4%G0lZb9_Z{6)CaOckU11eP5Q#%IRrXjQ-na(wPGpi}sa0e*^n2dw^dVMfOaUxuk| zy!o@sl!T>^{b-Mvmi_*>d6cry`qo+c{?8&xaym#Y?Vxm4QYG(da`Vtt$=6I7@uEJl?6*mWGfL>P zgq(gb`I|de&r@Br#33I;N#N&s2#9 zfFK+bRr!CwMAa%aFXm#pJ#7TyMa(J7LgQQ{J5QKOs8vf2YyE>LY5Rw9sHJ{A3UyBT4l9o+JrvmN4J>8AppwGy1ix0YIig)1E9sU@+_LE!5#t10#Wq%4 zUXuIP)J7GOFfOKqFqa49FAdU5MT0dXhHXVH%Pd120a>hKlaNua61X^vD!dHM77!ay zB76ur#Heta6{e9{B=ocE(<;?Wm$g7iLSOW?z7*b|CE1#@g5Vi?=XV9Cmz);4KPV}D z8SZ6E)LJzSZ2dw{2W1R=TI5cVNcF;)>G6QH=|P#9DziOXW_nOYIBBGEyH0DF7PGY? z%M)@#1h;0Y5=M(JngiV|tEo@@<~qMoj}pE|&F2eATJ%xFfYq?j`I#lxtmq7On+)&; zJjUtVs#ubKHetWhT7>1U)t+jmhD61>v_t?#KN{rh01{LFd1soc=Q&631_0l=*(ODH zzi_AoO9$1(GS=BNR%gHbRTVhIJG87QlosiNDE+EnoV5igNfwZES)fE)9Fv7)3@4EOSaY~)L=qiad#@8H5scHgGaHc zmt>`Gw`MIgttz$2>af*yMm)6HAx~@9L)WF^m(tZ7C5VSM*z`1D!mg^-D6gzr9BSnK zx>UX`sAd~N(x@g@w)T3G#hB4v8SHa09*N{3)>)QZm?&$%E;Y(Z&SZ@?j;kpkJI4AA z0h3sGWjn<7Vy(29-@P*22q!VXL@B09Y(?76o{}1SIX6Zy9VW_-YdH`LedvX_{1^}0 zTg*%19%4BFtED$%o1SvEjLXYW#Y)tonq~JAwXKSS-~3h z%km0Nhqrw26D8r59lT!a+_Dasc3He^v&wnuRV)b`lZ);5QPZXIvaQN5H@*TR9R&+* zJ*+-2)tD^XCYVy!AuetwQPz$(tO24mzfoMBN5snjjyrI3eh?x zV_fx-m`HB7<$lJvGR?s#DA^<9DyH5^8&^^pQbRHdVCsO{fo722(*B})TZ?6u6K3X0 z2WD*oc@wm33k*{6k$j}ve|wCW>t+aIgIi8%>mfxa)atfy_|E53ATW=|xbR!UoD$}soH1SeZBy%wfv9wI?_kcZ*Lp!KX_nbY zteAdp@!xDz%zrqrNXgu9Mn98j4HmjB8qBhC@otO@ zJb&W?YbxW{ilOc4mBpY)Fha)#9W~BzUCRLLn9z3hQzC>XYNNV4tw)+oFt~ZdlpGtb zu++)^qb3?+u6mqn>}&~!$IP+R2@87N++5QQ1g<-lXZQ?{8GpqP=gK)52>7f{Hm8T{ zcfaSe;xmLBJK#Uxm%BhLcMOxXE>jj96O$8ihB)ISEvm4%n4CE4=zu3$S5RI&P0N~u zN?oP}X^Vc-5}Fa>z-VMKVLg-XxL{nkUfCU!w+y!-7#It|KtSM674V!@mvq1%6I@da za!oqfJza2_Ku?if`Q`%I)v8slO((V)nf)IZiVbo*`wR7$mT*l9NBnstWtENMCj5Ur zPe}n5IBa@^cQ-z8WJ0}!zt4UHr(kFw{u9Y;qxg%gwWwc6C24^=A~PzMS_d$*h+RlM zE+4{=D6vc#ft+WA8r>uzW!6LPp8x`#>s)lfP)E!c3%``GvQfgJ?SUSaOK1^^!D6@1 z@+IFni(Q{Ynb}Sso7>6B--p9>lRpN$ld&A zOI`nOO^gGNsbp4oV6KD*VKvDnNmETS81?U@4Nl1!l4o3iPf{aYR*cc0GU#E+x)nEN zY$ES;o+lAjj?=@|mn?p*Yhazo$m(JBcv=s)kdu~%Ko6^nwOTMjPS?Mx-l+)34T-TE z@s0qee5D>T`ZthaM@w3URf+ioyj%3V6n>F|o8zu8$OCf!osR#vC}=x9T47cuRw za+PJ5m*j9SQMtWu0s~!bLG5m|0i7kt4M>s#%8W+I1C%{&(WYXnj8$H5h_#+}~lJsB=@{Dr#ueWF@B$OEETd{rtD7`+6C_HqEKmpBU|Gl1Hq zGa*%04<~J-;hn3M`nokXXi;w)1=cJ1WowlLk`#`_^=`2?sU<;{Kwqd`^Ut+2Fs@d(`>%Uz{MtU+qvpc&=;r?tHN?sKF#d%_9IazWo$x3ik z0XH*92>8of86@;UrvD%{NQqYRVtcOAtlP#4HL(v9|JQl~)$aU)z1kkIZj!qHqMZHW zyLiFMb{oXE=|wXT*j!3HNGZ;wd^JcZ&7_nDDS4Tc^OZ7hwf2aU+ZD@}31n+}=i~0n z59msXW^7DqQK9ZVV~5cNpCe>0dP^*s`Pw_%%u*ciwnr7yw?Uu)Ebqa8N7D|?-D!V z>*Jk?OCXIT`IYD=&A^x{m-1+l9Xj^lzj%>^!=e)8RaQ`7t^Y4dbRh;Y3sWXDWP8r;VjU$f0iHde?U!Mt72+;{j*B+EU)1K|ArtP)vT<)HpDJaMoQMj z4~Qx11WT9+VkIn2C(I5K)B^_57$mfj;FqT{!j8TE=Xr~+om@%lVW#^|sQ;HNXw>3~ zX4$x~ii;a594(k!>3@y}G49;RIY+Ha53FJKvdiTRjL|65RgWiGJ~K`v z7jyTI5^@2tP|a9a5>cIYOVhLsCN_a1Aih>Lvr@|ms=_lX&K-DjL}k!lY}@Y_$6W`&Z-pY5wf6ud~G?k zS1Troq37!6;BBVbb3hry5w8o20tvgRT>lO%D@pfdx~v7YM`72UtGGYfuAE7CVIx@z zLgPM0LT+b3UeK3{*|vBzq)Q5K>p#!sHX@BLUWhc+FVeW0&FSCteUY)`D_k$4k1uUm zK1>Wp+{96BZ%YHfx;EN(W6%M4~^-%F)8d3&4fz!mkOD6o7rnL%fFJ3%%#Jz_&%oLp=!8<`vMyM z2aNzHEb!YXK=*n{6jc?37}L2+W8yU;2)!l<^=uI>pyNp?W1G< z8_WGMgiT3B(ASh_fVilUVN_2RWW-w>Z{{~xF#(J9Oe~&MSn0bQs_p3(@%d2i( zV)D%`V&Rr+7$w!MNEl*NGiiVLp&^KTxcOs}G3J|X%=|aV>)kZqE%H)hs~DyK{5Yeu z{oOOXp`+tE3ZY?e#2+Iv>``QngG^I1(Efsm^?!W^H6-8XGAsy{Bn#yDG;^6f+?sX}zHN?P+_~!E<&#T)JuiL{{#=^}PivuacC*OQwjn?dh#U}C8 zB}YYiBH8(W@|grK-2*24%T@C?hkyPnk~gubhoY18kM`==xq}|BeRqNU3#q?t zqaux`QlIP2=y5`iOzXjwW>ZL6wm1`!_kb_X1mt}&I1GL%&E{R4@f*0Lw<+J&c%rAd zO)RO~Zq1utBC!x5)vZrk8`CYiwsncM)xVif!ibggn?TmuY%SwTx1Y~diw1%dfm(mo z;R#an+TW!`e1YQOHr4)&7y*}LdHw%x%I~=5Ru|oIE#-L=|FJUf>elA>B#&O}pNb@1 zwYOVJm5N7hpce0B#@70Zs5ZYYvn0T--;K2w9+B1M7XmFs8 z>l-KB$YBz%eGgpN=->4;g1~GMir3v9Dd-*x9_cl9Vl!gd|AtBBrlVfnOP?m1zA^j% znP~ptIU?m}26V8?jY>IYbdS1`V=-8R6S&~`n18jvu0~RA9o4@*D|86pr;FWH5c>a2 z>{c$P{$?YyIxnw(yGfW+epwm&?*jUj0X5SHbYE&%a+#e)U?|pTTviqGKu~yn6|-MW zu^upnYRdIc#Y2@ImR?^1XwehhsH**X0<@0Mt@cbG%j|p`Vp|kexL&M z+U8#Mqt_1isvo^}xmW$@wa>lkr~4p=yz%}2K>iCQyqW=+ar_Bq|1tRoeUALwTSoqQ z3xuCx;FqHkgSp3jirR61f~KDF|DdS{5g%IaxBQ;3d!pam6`tLDj^>=-)0blOfdw{w zk}Lg_m`8GXWxt%zJ?`+}V9t$#wqECEdDiS~oN`@Y4PSk8cR+JkziEFhChXN{^E3E8 zlYcjw*;~NVESMg z4_`1N(igs9T4a6rg6c?zo!0E)Z*{~EUvPJ1Abi2dNTM}D+y;a)^E@Bxe^0la^176J zA-&f8^BxUM5ni&R(%j*hOBB44J}u3|G_9{P6tcgi>cwvKt#KIvyW- zQ*o?m3tJ$UdrjN&z->6=p_@v%Nw_!*p1~WML)Ak$QCge3TDEaVt6nXL_0MACXxghV zZ*`0h{sgQgcz|7YI+u3F`rpZIX46q_b}d9{#ozx`G5mZF70(Joi?)pBFe?GZl~ zS{WNJfJ&D#oD^C>ldL`?v>*5M)Tq%p*jRmAgjS=X1Wr|^C#t11WKXba>wB)o|=M$5r?s4HHy zFIMuBQIJS_qxCr@RcJ{a1cEDK{cUpiq|3HE@s_fL78xS|QmBDXHbS?Vy@ctdUMquI zM<*R)FtxVd3Ka!eKV)|OOZ+#Nq1q7_ZcpZHOVj=;uk~96Fmtrm`h!9`!NUkf8%c+K zvsnBY;EHOm|9#%4NLSrPi*JwgNioG+zf~DN2L-~Fbap(&6acJ`Cuc-_um5|ab?)W0 z@Hw3PMj5r}4Sz5F|zp(6?YR|Lf?9*Y_J^PXbb_cDrWKk+LK3O&1BAsV+6 zXcIbuY8P0s))fm>`F5RmFbcZjL@q%FJ<_Khp*Kst{&zvP9%Kr}C;Ds~#C*kDksij5 z9j;GUO(n_>CB_`L$$`ERlV~jJR*E%Hy37NMf~KabFJ;H9FHv;#6HOBb;zQBm@pI!G z{SlwqiGJhaa>&_O>6IL`lK@G+Ax9^eo_3v5sJTeF?BFG*LjU_T2vOEJ?td5Y68pML zhjkI&ArgH>`Wc$uYwQ1!INS<6Sl*_bJtBWo;n(g@bgiRxs z0x_DuJS_n zVfC!FtAaWz0htP+ugadG%w)*Xk<0HEdZEKWy~Nq8wc&G)ac6|xs;E*sS9>8g?K<04 zmi~SXxSf1WU|U|Sgh*$?{mWk0Ng11$g>C1XUi%>I<61Rc$afCr-nKl$7)QAmQNEM- z|AxpiRFo@)M}Wcik%~z^x?`bNII^Y3*J4etBc!VnMX$z_yW<=q3NN9?_T%6`Du8wB z2q!8Wwb z@LL~i#r$$Sv?^Y-QOESQi*iI4_r=?ec(qjre2%L|VsDJBZCSG9Oz;7fcxlea#k~=Z z$m3Lm3$G#aM8!@;z%Es+OOh}+QM3&qf>li3F|3#5N(N#qw9nD+dnH>fl>;Dbkavgy zihd6-*-mqr@OOGEum|)XpW)d8A6Ei}=@l#Kt(Y4K=)PF;%~;bWV5Qzr zY%$fb1;F(HPG@|-Y;}Y_j5T#q=?+8su4yqDbtU}?EC55!l>~-ARkt|7qAf^~%%q+mZMVI>`Cl+FQTN^7nDmeVtC0mUmFFBi;YNIHM zhqjtbrU7$67}GHK*6)y{T|$D)m~yN@d$)(r_%^rVvw7cDDAWUE`y7wbZ5 zbU~9}K!XdsN&RzwV@l*y`k~!}xZ&=OmioyV!Y5}4N6X1UD%yXp4TaYH2#CCT3Sf--Z%8 z{%!tnKV7)6{rPPMW zpw?xUR)^!OZvIjCSdXY{wqA02|AO{>fX)e*UBKfMU^=fuX6(*b^;)NTO^Vz)1)(R& zy43$f2hvaVmyV=s)8y$IFM2iG{JRI!ou?2IHO4YTvea+AMV&{n|KrXBef`Hdou_-j?P6E! z@^t5Iy#&<3OiliJ3Q;D^j3&Fsy zx-}TtwvN?(hg+nk24h)EyDAZ`+0VbO z#E27#5g#Rzy@}+W1Yv8*-Dt&=Xx^91CT%)7ydfTY!A*OEc})a*mS9k9@RB1x#8vx^ zf8zMO=EAa-i7_v8w{nO%EZ#a2llAyjqUopODVj)9!HJ&VNdL(qD5z$+$Cp%B3T>RV zT0B`-S;KdBV)3DoNc>y^v=Wn6v-m-cmd2Cau~ZFT)ARZ_*?dz1kq2Y?Y(zgXv3b#K-j8YW0PD zx`*qwZepue@j4dWp$*gpq{~t%un-^@9OI?#<`SGRfory5rY$%>x?gX5fbx&@Z#=&{q-t8)5=>PooDclKmGpXEaH!e#meb| zG=JVFIcVPw9v%OUKPE3{I0WMLb7TiQHZbFZZptw-@YD4o&%{=+1N+23YP&Me-e-o( zst|l~X7j|{RnNX1#PU+^zv#kYB+Z|;_R=CO9j~BoyCe8c)}J>NUh7wNvaqn?1CxHQ z^#Q23J5uc4S^GawsP}UB&Qk0F)>?P7+ivh!@(&d2z1F>Zykos`i;og#daYNN^Z8Uj zr$uIasDeAqQ?9R}H{gXP;eLIJXFW~frV~79>4zuM4}SWgEB&xN{m`Zd7yl;awRo*i zD<<~8>#@$?PEQ2OX((=pEb>;YY5m)O4OhQ_FLX1ioZAmNYyod>7M#0Wldv{El%)_p zftXxo{qF*mV41=q8O)V{$b(?kJDG{(YLvAQxqMIgH~gR`?E{#vXr;I8=3lHy-MjMc5}YU`F=H}U025=;wrs&yw*G5u=M?;9 z+i)$g@RVzzAK9H28DRR-?{+pTbW?`5V8-I1g#&oKyT7pEK}{n#L7acWp;iHyc~tW< z_}x`DhWzaW%ftRX6(6VtjxMpTNjuE1!egSv zbkSQN&?;zA#ZH}^bGr%nICUz!XqTLsY<{Tc`*eFq@(mafTJII@5YO7g9&v2F*M#U4 z2pV~mmyMW)`@{49h21unPsihAKI^%Ep7!6a{Mnnq>RX^4V0Q?a>nm7wci{EW%9x(r zL48^pFJ){BwFjk8gMfx)tr?~Lgr zX7YsBeu5?rXm_{GE8?QU_3FMwK|`sPU7l^~iId)o8R;zHR0Kr=9YkkHOoxkl>IqP^ zsI#6+3#?ayzk0jtx5)(p4`30EwBRBd=8M9cg@=X#n4HR9nEE2!4QWXgYD^YrH9?p> zT0C$Voo8Lr(kH0oAjhr)K z$o%y0Fe``IaM!KG9Q?(9e{8UO8cA+{Lyr37Q8bkEvESt3PjCII+S2E7(6DJoo>zv6 z%zi|L9W@)gDmL_<0`nG(o6YYo+I|l%kmERBWCkXN-cV>Z;<#FVcVYqFfX&;agzzdU>i?~akcy!hT>p=qYH4;2Z&08YWNkBkx@X>-(yS9}*2X;;zunZvwRhWYoRhX5NZSj&ew=so}OtV7rp3zR48H_axDkK{c_4AOKG=O1HcPjp6{y`oSbZklAY)MM~wMTq08C2jbdU{ARPg9Pgt zQ&|TQJlFr&tIX4EY_;ALI4xCtme^o9cCD2UjD!fAyLp>TX?lwN+@oL_V{ zzA849P`wm%x%9F8VgvZaY}-J3to3U86}LSHC>;>popzp~{R0pG)ujSLyK|f{fTPFL za02ojvU0)oWq|1MO^C(H*s`=rl03Jy)b>V@z~#v_ZRPU!sCX|EX_ zPk8IrX|^$|l-(9d4VMg^yebyjFXgvL+a-%*MTfl=X{{RzedMjks@M~zVhstmUP*x^ zLI+|+y|K`d71EWlqCv*Lt3{L3vUu`@V!YY}8V?=yih6Xc^M$m0dPT=!m97?o+1BZ6 z3E_z$T+B~CuFx1dlMsEZ3e%=e$%=Ky?2Ijw7+bqBmW}kHLExs`u7N;LdltcF+8SRW z??LP30K|JJALIsH-gvZ~c$S|ce6i=#BLpGDNs2ti83M~3>})qU(vli`K0S6azyVyL z6t01(;VZJkgT05XN-}Nhp+@NzQ@0!nj~5;16+b#=1pAE0Ly%{VYjq+2UB!&Y-omZl zfdh<`WNm2zHDAI!)q&%*Jor#}j`Cz3uJ21?RcvMpavF<98qrqKmIIRWXyYmT%-7FP zja&l{^X&3j80~G@8ykTl9Vlox!_yjl=hS5WrdaA~y5QIu4KtM1Fr2Bn=O1S+h^@y3SOO0X$+%?o&XP$WMzjf7T4hY&yU56&#J>ZpX2z4}d z4NzCO=}gS@*z;-GPYf-I>*BlDV(W;7L!{ku+*_6rTa0*lEyu1FMP}uVc zkx@uZ)9M0gY}VxFI>@Zc`#V;_m5R-Ll5!;w6DCbsdGCkayKocOU8dbh-^q;FNMI^17NAE9;E4zc(~dwmUJY zE8N^qQpFL(CzizDsq-`ONgKmWN=~H4PN?8B*s;*g92r``msm#)Jw<>pfwsKkjldW} zfQC{2-ksMc9~5IWhK~)OyCl{$z~^EwgFyKhs<{99?|;cXh4bHQ_|pZLbg?GwrLr#X z^>5=+SFVElf_w^}$L=&|gXMe#2PrWZ*BxFES#W66-f)qHeBlf6k~QVLxusz-PsM(_ zyeuGkRz5RA4QW)44U$OBTpxY5lEm&~0HpWxuU}Vfj6%Sj{D+&bL>iY%$YZJa8k2Nx ze|u*r99~x)GVxAbO_WnX_^;0e@>BZp;~e~iQjJ*{#H$qzr!j=96-^e|RmEN_k!nTk z+ObjDeVxWY>b&s)vlfOw{-z^pPp{t%W4gzYZT|b#vs=O*f9lzTIGYW-!j`E++|%fm zsa)@`wBnYj`R=K-W$G~ZRNgX`Qv}MbY?(UTYn@WiG8N;WpZXE{aj4D=9>MjQ)+r-f zrj85}Ky+64->012GWG26GgHDXQz2psbrZYIPkoVo9Ex*-M^K#GI%QPL)KNhKD9!`L z`7Kk=2gL;~Q@M*{3Q(+F`KceHABW;~6Whydcd7!u$6klwa`bAJ&(lYfDGDs}7pL%X3oKosg zaEXIGf?{0jl<_T7#|H^OUkZvZw@m#qC@yQ6dKnq;mz^no>MQi)Q2c4|2#U*Fr%Y&> zIw42^#Y9kirDf_@!q0s3ik4fhU=zU3v!UPnY`Qp#f^R+FTalS*lW0B!Pf5=(Q4 zxkILpK6#Ke29pH#c+!*3H1g@H@`w2vHK;qlKIIgV+dL*#k6u_pl4n!zu5RiR4>CJ=5t` z43gwpAs}c9+v0oJT->I&pVFJa_5s*R9i@9@JSOic#hGblr&^&Aqc3nosgZRoHbF8< zu$A_>`>xW)8+%4Q+T4zz6ryTNwA3&gfbvK#Hf>D7Rj+u@OQa+2?KH=OUG1&1#$0FhF^{ox5x=bo>j{d0;{up(bQ+G(m)3j~|LT=S`5 zzihA#ofh|Lj=8Ze1*^H&ucfrv(>*UBJk6BB!FvmKh+->o{}ZO6k5C5(bubqEDThuB zibjs^pkm&kAs?^(HTq_i|M*FATmvo+8nDZ+4_O071>adWPv#?_fc#6$+}Y)i&*O94 z(6Uj>6{ex7}vo%Q9InpXJ16J(uhte3{sqmltOC09(*)0FxDVYXj_ok7eA9E7x zzD9)V{ye{QKo&go?e)*H&1QQXqQ}&*=kC?XEcR;bWY(4cAW)kT&%sPmksaC!q8W!) zV=YXAWO-Fz-<_XlqR<^-qR5%RWk1+n&?)S#M8M=98eNSaLdQh4+9-@C^Vtd^FwFmA z-wC!KdfRlINC$}YD-Wf9^YmWS92vu}Wa+ySpToTw`LEUyd^?Jtn)nZ^C0)J#wI3^c zE#Tp1oqMr9lL(&$=jfkFdfpA!G=KjEz>ut-*r-LB;%x617-k z3bsR4{xw0y%Vex@RPXgq?#jhqV|CO_WCzc z!+*|YfjT8;8GpXSc%t3ELi8BaY6n?m>z?8;mkY z{_t^GX7`z8)*o%!IOtzb1rqUVtfF53Yy5UsL4}*oGl(t+QTN4}bkWv#%=Aq1=!wDZ z&yZvG9cp@zfvJDd8=}uv(F=bb@+V3;up7B5ddo7|uy`-!9^v|Gjq8t4jdR}SBL-R| zRO6POx8Kf`Bu7R#ffOla#Pwiu%D$-Fbnket$q(IoHkN%ne-h^X8I>F6_@)q5C})rv zJt=ppm$nDzFAMx-C?%r&=f3JG6M3~wI1|7^|B)bbslU5N8dBkZ>X^>}$6&(`L(9U? z;4bEBE3SCZksN-D`PJdJyU~pTf0IV$3`sw--}Ue6Y&yP@et%?;zJzoQC6nWR|1fn6 z%`cUl;`+BhRut&vdp3nNJg7}hI=|n)gB~ydH?sYou`FS@IiY#rO$JYD;!Q2-uP*r0 z+2@O)JSG8SH2U9E0TWZH2Cf{#6}H9iKtr2YYv`W)E97Dkg6{f3KI75;0Va{|c`nh- z-`F38u<50A|HHMsXl-;^6~8{p(n&$~e4Ts%M2cziCD}nCd{Z0PrQoSp|M;#1yEoBV zB9Q!pjP}goj8Z;O!<>gx;N+x+Gb{AmNEMu^a$iYQcklH#K1zl2Ru@1;V4sRUd18}< z=51DeNRgPRShO360gc{3m2uAR-UO|u*M|IwUVk{9oXIN?C7F21(;xVrQ*t2f32eO$ zc|O0obxM9})XwVGAF+}D!;z_lH$iu(x^))E?XDfwer!zZPe!-?aBOvGb9L)&#qGx~ ztPX7;wK{ajp7+`FJNCSi=g=`8LoRiP9{DpSHF9%mY+%7j6IeLI6IF@@b>!yuB(@&4*grcMq)&tt1G;fkxX0#zaE{)yZ`=$u;eR z7e?p3FUU|YcdjNsZa+CDI`2JIUmbcon*0zms{Qzd4x~D?Gn#z4{pjfEhz-@rgJcxq zY5u7F=o!^5(}&FC<12%q7BAnjPM%*g;$ZvHv#VQbhqidbs$0A>s*&e`YDOzxK!1jE zvy!!i)yYk?zWwMh7;s*TH=OtOqi3~v^kF=*zkTJcxscq2gBeiS@s+QVm}?I+Kz z3AMF&pAlGJ``)4Ld-9{4Yi-|sM)in;E#63dnd#_|7Vj*3IJ3n&+aAto@xs(_j23j@ zPH8_{*nVtyi+4^-?I>RPSkndV$HLVkdaGNi&TXkZ5AL-e8&=hF|M@Mo7Z@u)KCk`Q zS=A%?VnlGdINI#=lRjrXmO%$gf@X|t6TpJ>Aa1WO(UeFuBf{8 zC!<>bd}Qml3)x0SPV==tP>KvkTJIgzdgEBxT`h?^;$qoAO4PBk&~6&7gU89K{FnF_jn~Br5_Ke3M;2G7 z^4qRX0if0yk*@00*ukq)qpptEMGLP^ef_(Mx?P+k zv^|f>sj*j8r@p?^s{>-}kK=WJF*Z@hRvk&#;ryl$u@9Nauf0+lWVmZD`y*f5tA0)Cq{M5n8sjt6BbnoO; zhlnC_;)lyPWOE9QCfhQfXE)N)r9|M96`Yp)d;L%eYNqXwI z%dk}4C>&@15GE9Y=@rVI2+EPZ9hk|Yak9|}@&yU#3qR#wua6aAM=Y}DsCbq9Ri(<) zLkABWdO0AN#njoI2p!HPSG96Z;Q-4ua(OzeHiVz*CykXePX~e$13Z6dkOX5rWmiMu zGB#udB;elG7Ji7c4t8AQZe2DBU1aU$-@YKHh3DOg(Ec<%hZ8JqnL2~)rDT7|KM)y6 zAC;;oS5ok_hg5^-#DgWi38+;JgA880`yi1TkGJG*v<1VzP-y`*wsDB!S{#s^siB)rLz?ILV~8SJ2l z5|VcDk6qfglqjOuaOp`CWaSCwx6BqYw+ESvsfMM$u_(x1O41=H;ZE!x%YhlnV$YF8 z5yHNiVJ-ynt?N?bKWlU(l49&GN^X~6Y>$W7bD9xZM&cXzU5%`C=Hehzy+;g%WugwD z8F5)kCg-?7{&tWxU|EE}JCq9`gfm?)3%Eca;iveTMLU<^e$6ZoN68MLh)+1Kr1d;= zAKfk^$nla1U;(vTgV?P%FtKeQ0266sVss(kYS7XENbF-fPB%M*pE?ON)frdp4$*Z2 zEhiNyyAsvsftx?Z;t#|qA~w!O4Mo`|*Zx+BQ*4KT+2n;d><_8wERK?JS@1OL+m0Yp z1Rhh}13~5@pxLLfk|NA9)q|A4OykA?4SHec0mrn3sh0!znhLS8&5a!7l#)WE$%X*a zXkL#7HFWVz0KCF20s={(daH7o;TJ*wA9HU5UuALS@h2omqTmeziikCBZ*5Yr4HetC zjcsBQd2YGUSP^N}HfyLQg=)}X*;)~sM059YTehXG?z&s7wzaLh+Ll_2XcOK+#ejm~ z8^ITNLgd9a2tktn_jl&GFG0KQ|MThoKYu@xJI~CSGc#vq&YYP!=S&G@9!A_0#e$so zt8P$nvr`OoIqposu_Foq)$>+Ct2D@#Cd(`Z`c0J~I(hY4Z9)&48i~dL?qbcG@mm4; z;oTcmmQSH;b^RDnk8~&&)g>yr5+ri#Y++BQi!@DSeak~DA2?CeD$^E35Q zkmVi^%w=T_kr~Bpy9vD)DaN(fA1$uq$T;rzQP#Js^&{h=iQ6Q+;VChI^@^EmYa_RH z5#1jx#;&jb^cn}GGm1Njwp>B9TzRert8&c z;vPX>8@g^&O{}XX@ms#Kd8lz5Ga@S*^CP#tt^%dF(k2%lq@q6w)}9EKd)dAc7NbFY z9WTxFo*qr;ash1Da97tGN!+h5HZ38|9(f*PW(`ivZ+8? zjNG<|ulJ(Gj7SXSM7vt);&ZmQv4){=+bc>|q0f88og(~V?nTE@>MHft(#UPE3Ba?e zqmDeM1H-FGvF|eWhen=Yn*EwXZTM28?Hh!w+q>;m^7U86E-C~s=+=0}J4x+|Exe*ijDKF@)5*{ZLK) zk!bx_^St^`N+dd{xOT68K|xLZu}J+}I)B<8spo#2Efa?i(hI9UGJC_>$O=k(#H-gT zz0ZUhmU1M3d?Xl_A*CV!3{)m2pCXqE_2@9d6>92Ppqp%gp2r6HP<8fekeu1UI*qu1 z;8G2CsY`WMCBp3&CBk)8iP2~9CKGqu0MyiPVUPp5VfG7WGSNx$ z8zg8hJwzDyLrrJe3bUPxqA&9jc1MJ?tf0CjWT{ob#cdS^Ee$e+m3=4Ne>-tK+I}_fwY1QJ8@~xH6(;)=Hp5 z?pNVKc6G?k6jH%*|4yAnT2KWcb&?8G0V24%Rjd>x6^myD!#k`w*%nvd$Uk&jYynVV zSoJqyP=k$^pAFv3HT#P67VVp%Xk){7+H!^^s{ zqhch~RRLE_GeU7em|;z#natTJGKd#G^j8=mLjBu%A&4G+1nn<)tnoe>kWuOF@INaF z2?E|1utE)or2*p;JA~;GbH8{X>PO;v0bdOmC2TKXg5s}mNyh`lUyVzOP8<@T(|Zl; zjXF1AR&YqTRKT;~mEu>9T^c`vWjgL8&Iwx*^Moz^9sKj5B>ZgL^nT-j zVxi)40jCsa%;c6!9Z!TcUe}e$5C=0ucV3g?hujZIw~g}?tp@(HQgKVn!{OD@|bG-suIIbVba$hsZ5N{!gCKS zvcRkFtC+p*>?ttLntHe_8`bLB?Pu4-*k4V4fi2yQ{C>f_v!B&u74aLYrX{7EYhNo=0BR>d!$Rh_+sB?dTbxGk}S@ETMnwVD@cCti-NBpEvS zhYNNrKuv^~`Xmhy zzTOm_1V9-8V67>_n#4Dj{9+QW63=V)N^;$fZj!?4PumgX!KkP&pYBYTbcy+5_Q?H)E?3Sv0VRGah8s-`|BTc{olxZ!KL<-i`1?1d z@pi&j(`k`nl$w9Y7##X zjQWsLag3ofbzow&7fHkoRpQ?rMtqLL06FrhF)0y3>k%G$q}$el0ck^NJ5fi}A@kr?;l~c`#rfC$@WCcWC6z^TpKJ zJlx0~{xz#3x9t)Ng712X%X2w~t|?wm#)F8lRk0u4Nn%y3`EGtfBmW=?9TlaL(Cs6$ z&4*@n7RmsZgQ$OHXk=v(AJtM1xEkBN{#C?aO~0TT+r0%f9x+%~ZL9RW#COAuejYbn z#8)=*XR56GuB?3 zysVBC#Pn^IjiOP|SiV)c1#!^<04TG~!W`ghNy=EgIQNfN7v)rE#VU*9)f027b7Peg zIvx-6%9bgZ%r$3QvN<*~~0cy(1y_4rt2 zRlM5EsV~M!VN#-e*)??j1cZyhZJH6Z9qcJ$4)&TE!G4qK&2!Z&6G`q?_may%;TlaJG#C zE1t7;JQ>)_Y)Wg1db~|NN(^a#n*n%7B%`*UeQ5fdaf<07XXJ}+Sxo>z= zsx9|w=rT^!&?_5>eG8qI8xCe`Ts=VsIcD$MMDJe7K)wDYV(@IvNU72Qu<-?UVwp^R z&oXovAXieq1^=Oe5gPd;p(i75;rkB)!cg6IBgJfMR=RXJ+(_X@s0#mJ(~ELWRj0&G zV~>|JePZm2-1zjooarU8EAryghv!V69J^w8e0o97^wQWB1@Y;lbEcQYt{5GkJ~n51 zdF+a@@#*7prdP$T7>_rpoar7uGvd?3In!~Tp}RVb2MvNdsu(nk$qC6ZIUzYFCnU$@ zgyfip?a(vlM|9-azb)UPH@cs=qlNfBladk5B$X#^b+oGn6?V zzr%NOJkGcAI4gi)bk0LW-05FIgof8&8=xoIILsWMJl*cbCu1@gpA3&Zz*TCJ{Qr1- zo|-e=n8yF{_?-NIJ3fae$EUM?@DdAh^+q8oGsV~j_veLfzmmZediX86^>qFf9)6j> zvtVi0tp)1ZP~&>dY1WVzUFmn)m01M#4?5zZCcvfZ55i(zB7y zt%YBB;xiF?`2|*toh($cEZ&B8>T$(>S!}hj$O@hhv-;}=ZyQu_t@2$;1}hnTURN?~ z&=V()z{CcZ>}8g`h0I?TKdq}h{5(Ii>L{5?eo%YW*wDyYL0<~k;FiLFJ#oPZtZs05 zjk*VK*%F@=sw#<<#OLOQsv2`+jk)o;d4%#}jd}68!wC(KH4cx@Eg)17Yb=P*9ZhI- ztZ{UF?pQ)&V~u0ubH@`JA8QHBOArEg@7AYos=l2~CbQPL9tlB~%(~ERD}CBUBb^EQ`-ACsZD5ERWBv zB2*P?tcuU|2;oY_i_eV`ipCnFA5?ODZf(n!*ju5h+S*ucZT!+{gr>!6r^PRwL1;#- zc1HZts|Z~ctGz0IX&s@uSZ!VW(wT&2#%gEAFP%kbR;+eb{L(pu=EQ2}#4l|m)EKL6 zj9=PBs3}(4G}u8!)?YJL$WU3!3@(mwMeknr9DZtSW%Db;LicVC{cvU5XgsL2XL}b& z8*Se6UgF!?70VSy`SDSyZ1#+C=aslwk=5R914?ZA{K5qTSxr6MVIw@6DPTqMk*f1I zG;I$(UeK~--iN(JZMNLIplf?%*u2*V<({{4)wPQ+zby3lR|lSXB{6YSMQnTXvCyqw zugLDKYP)D)EsJMn?xwI1pXCs5?0Ge_S!w-^K_xU@_d)gR`4i)__?hOTZ+>@k1qZsg;FXMmWWi}#OYk@8L*x# z9fc%TIdZbPj1bn%dxPpwmF@A`5NJ=pn6$#>&?c!X^l;-Ckf3YsorVTO?HQqmXMEJE zPc5tBb>ri+&T<$hR>kLsX(2g25uabi1%JHuw2D-Hhia?kSH-Bo(ut-N20Q+)HOM^U?5{`5nI6+DpLb7)V{(pv< z0*JM>pdx5mzG(0f&weI&n|nmvfFeeSQmRawmr_J!e>!BN8KGf38DYgCSMJo^Kq@ zS5n+NKa#!AYdCP(+Jgi13ySY2xCU@a4atig9i!RDAkX|Fh*c2j*pnB{=MA5S=YO2v zXv4tfF+;MvhJohA?+)OsEhoamjSV|gwr(05cBoQ%y)gUjXv13;-LP53>ky&gc^BFm zZP=_T=)k(+d4+1SpC!(r-XPR99HloruLw?gy@tKk)`l%g!m>^KU9Rb0jW+C70u_!n z^b0t+CgZdSeA`sK&XBSxaGNW78zEQpGlYbWku;h&Mrq-UQFzfUsA=f7Vl`6oUsm)f z9Arltc39c@FW0y>LgJig_EFWOOAag@4X9I1!!8xYWp|{Z+uGK!-c|D5nudcyU6XyJ zrlD7rs;0tjCrH6)t${5YwXZW^TUR|dZF!FlGaCTM0TbtRuY1%c0D>T`hC%$i~ zI>{(tDD;ovJYftD0qTdQhbPK795&gV+2)G{FDp^0P>1)&GP$XZdu4# zB>LNbQe-p{OQz|~PfI%-acNeZD~e0QNCH*Xpbp##0U0SiXg7&2Qhq!w`@0cWp4F7P z=+4rhc@lMUDAGXo5E6kR91Auab>pO$kabeS z%Z}itY0}AQRm=0HhmSzk+m^aM(=)=IPOfKG%e&y@rjh3F`^DCOkz*2)GLkhPvklxGK!C z*dtg>)--H%HF&ee%_cNkY8v`n4c65(taLT-YZ~@C8ax$g*l0B1yba9*Fu&jsFx;PU zP1qQ1c)}rgGurUBL(m^}L}Y|T8&(NHB=H}vLywN(fjC$J9m*}lU5bPtTvibOvWwpl z(Y1g&T9FvJ3V5gIfEB5yFp2bvfz%yP01_YR8QF1+sNxYmQrSHimqp@Z{y&vH!gZ4l1H15Acno0X{7a%8 zT&kwwB}cnwY8tjW+R-&nIoi=R?^^da>~rIX(^*b=F^ugUqjOiLYqS_Qr9s3>H-Cx1 zhFlOGE<&fiE@EwJh97hhYh1)ychoqBD|r_|DVBx%e?@TX#H#1AtacF~)eRC^0;Jd? z8B(6@br75p_6owTaidh+5Uq>E{N$piv^iXyHTa?imv51V?V^U!WxJyWbm?@|fG+DD zHQF6DxFq9_YM*Gz44)9`c%6#wgPU>ft3n?#YR5RO?@`*dv9UG9rb{Iw9%ZCwQ4%8KC1zg8Xt27cIt&iS{|jPVVMdGlB%P(2@zi-54aAA59%z}>KY*CUIWvqm!!D)5SH5o9j^|}m#Pxs9F#xH+h*nP6_H|Q zK1}r3NyOx$136So0(~i@E$LEp^q*XfkkN7U1jTPhJ9L;FVr=dM6fM%)Jadn6Y$WH_ z`PKQ|T-8gZv&}mZdr90zcI+MsOU~`sGX&Ut;!h%yxjVWd->!KXMn{IDyg8yq1E?QW zP8@gj4g+v_o1{ZvkC3(edrz(bnv-q#dOpLFeQsURWYq1_UxoB zmt)Rv7lY0T<X0tBQ)Xu;m$%Ichy47iO{S9rd$OJW%PXva ztK<0~)2!?=upVyilO&x$6_{FmS3WG&YF;m(epv$ESc zAY8a^imoiODp1dO^GU@`7Ly7Ug6MTN-mCk*G(xBMCjoy-nuD` zN+qG{B8d?GZz#inEnd4Tt~C)1XV zaz-j7=cJSWoKBua!InEWo&4|VWM{iT?xE@Ao72fNFo&?*C!~|Fa>+zjG{2eG{MN9k ziDjcY0ZfCO4+zE;o0a0_I25kpXOZ$YFHx2kVg40+UO`SP_&cKxg!ZJDQcEN8a?gf` z(&%k@evb3J#YnVDEkCoND$EHAy8Y@YMiFN>I?3(ZsC*oL$aX6l7V-riCmwdpjlGb6 zw~Stz-&lBMFh1D-C8iX?Rb(^RAJ{;;r{ge8g)SFEy6f`dpI3>fd0%vbwjng{YnT$h zo`v%CUN-4ZMlD~#*Q-*u_PZ51$=;51Aa!Icb zMOY)_S|x|P{7w8`!bDcK-8o+VD#f4bv@q&=qG;uC`pN z*Eh~GP-+{=Zx_V4Nd9`E7!LqNYMZuE-yedZ5?(2oGb`3z)TAM*J&?vQ-?bXO(fnOr zKH6xzhTOIbTbyjCRKew1m(y&(K?HYlXf|M<%XYEAOZ+RjvYWd`**m>Yd+zRvD>l>` zP$E3wCH_YMtYS_X0+xU5bS%#Q6SH#!BBi`5a};-#7%ASTJI6@z4lnT_sY4{rOG44b zp&4Mj;I7lC$5GVQwnrtD=#GyJ0vnoi+xH3RXz3ce6_lY$HtbH(jH^0aF5vM!hYd%MijFswb`|C}HtDELzg zN-a)bF#|_K&aR_w=F0^i%>|=B+b{rVsaLyHW&2VZ-xPw)J=yaP>c+(YAI(?ZPo<&5 zfSA3PtHGGTIl%YmDCIb|iP97Ixz|#KX^+46ISBa4q&=@Wh{PV1NGs7+8q}2zxDp>D zf6&O^E8pVa;}=QzbPai^Fw0M4<4gFf{n#2B9piDghn>JaPt+8Cl zrucshK+A)s|Ar*arBQ3Jy2=gWl3;vYkA0jCwCg$X?n7J%6;p&pRJlf!7!%M;3(^V| zQ%4NAT9R*7Zs#Q5)`&iQ_inq}y@&bhjhIdrLaks7=KnG`3#sEKR|)=-BUKg3qX-IQ zv~$hSkA4Y%;W&EVSrrHsFA842+}0Ajw|N}?U;je*L#@)aVAg%}BR_|bMwJJj6afhy z@JEv=^suush7n(J7QPPJ_YNyv*;J|(@AF#G6!LLV!`$dk3iU0kS%PLkF_ z*1C$&wu=fy|GY?I0rJBkzlx&F#<7h$CuJlIi67w@bfAYj*rYu=_R?AfF{;G42OY?y zDdmc=F46ty%q(lnYdn7#dU*EG(8HCv(Zn(%L4+5z^xrU2E*l=daac65!px|s$%^DjYsY9r zt*42I=C5h)y0v+Id7Jx=b$~-lYoVtjzsp8?`3FM}-*^f|PFu%!kM&)Q_5JQ*lW22__UU~~KV)#BaQEj{qS{<5PNA1;e*B6;z< zt>WIDQLOaKRk8Ron{yPmBv*q$>y(-!k)z1WX!Q|)z=os9S|W(j0D@(0NjT3ws=~9B zawi{AiZMBv?}8u^4LbMyp-gngDw2}t2Z`lM^ehr5hWu8s4fRwScTO$g`vb6AeLNI= z%+N;`A1wd5&AWzGJkwXf1*fdzJZ&954Tfl_8uOm2H7G|%Le;ztQH^&!^c_X~yl5<0 zODTl0fEUWm3B#lgq&1p(@S`(Xzz*w$hghAJl4$#&*%hr`2!3+S&6ABA#TEPeaICb=aeFqGjYS z&j+J0!ubkEVC;P%$1#$Y=@7bnUlc#kFlYfzjeVLb_GlNHqzV?eXQo+{_FI8u!1 z;EM2em+ezE9JI>s+zMyPO>LpL8)rI)r?e7Hz>-KYE<>1OWK)w0In$&zis}ubiY$s5 z3)f>u#NmfnaJj`=kPcZ9&T~n`a)J@zOr1D;G~AVZpRIj5edn8=4xVCmYTL-5{iagC z%nem4$7rM{1(!!PbR#_zLf ztx31k=9rT&+4-9h`~lzlib$}`c!cOv5RJVhQJwAdIZD!sHsHT9;@^m4x9P0lzF@_@9uF?VQLghz>f%L) zC%ocLPA&Kv`r3k@B50vc25Mz!v?7kefSuf+Wm^Q%YEsUxf8&>}4kP}95?o_EJ;G+} z4}|!Ga2OWZc$0vRe&3SdA^SP)!sj5KWunu?RHwy;T$H<(Sf@9^xe8EuN>)A8>;9vT zVv>v&UnMdHj!|(Bv6LkB?tGo?1P`5dQj0W&C`(hy%XY|(n3@h&;l%`0oU*8TO7IuK zq9GBzpzd10SM!{3ZZ=Aaxw1%a{jT)3txprn!i7{&Yj>@FshGGu{rQ*#Z)oHXKr`#l z1O7V}G#R{`povz9><9catU!V$@r>ZhOWYk^D2%QS%MBa`Wtrc&LJ8~wcKY`?JPQ7V zpj?_CG;vfrhsR8Se>@GX{*yhw8;4&XoB~v52+TeAs}v1hg~Dx>A5ti>!USq^PHd|@%m3k>`1!bP^>IE>oPh4dFDpO*oiy;632pH+qVdb* zdQ?v0~;-r@p8nq<*N+dE*k+#(HF;*Y50`Nk86a*hg!-2pD zm`TAV6YycO?fd|&Twop_h}7LF+4PtkJT$+aU0vcMls$nIhg7l18YS1%p{hQjH){K# z_GyXoBrU34g0ptUHbg^J8xb`(N^l5ObrEE7UKF%0Xf54g4bxUt0-~xS?=g~4B}Uoj zVUpiK&&qmIFG!tC&s3a)W5K1VBqD=@eiYxs&_ z2e8xsIIDxiSa#N|qzHVw{n3ij7Xr^7|CciyS(y3o-U0t7`j!x`lOVt7a=~H{VH|dx zec5t+y>Vv~nP!R$BLNnG6qfH#1A_|+pWzoi$x{CIX#sXyV*k}34fR=u&rV&IY26b( z+!6Z2gj`Lswc>~+G0zPD0Y8?3Zot2pufZb1>3Fu$G&kvhHUt8KNd-_NxxD-LxQ0mx z_=yE=fsb1ds!+oN{+VF6^~tIpvM(dWOu&p{mg&%C0yC*#swG&(%L#svRIok`eP$Z^ zl)=zxk>D=Cj}r-YQxT^>7svx!iTGf7;7a9ognTFkbi5GonRJcfLY+P@46@EUE^AsI zIQpdkKmHB@3hGmxfxBMfSs z2Nj)TQSLB^DF3?}N~|OYnLxHI`d|DZj=uhYucgpgRS+#WPtsx1+Z-lof@|t0zRnsA|TQv@0+ZLQ7*ZFst%QYL)-xZW(8m8KSf8C#TfJV@UPaR*v&;@Ry z?0i^09o=#C48Pp+x}i7Vf70EEr@03@ zIKoZ$WybmOR#H-E*!)l9Or3e+_>T?VKcsMJ>pjcAmmFfoB@oEYnoXEj2HOY~5=i6M z@+Clt^#ainBnbcN3@qiG7%N%E*N!-!^S^!yKCfw;&5T|^65kEclvh7w}JRYa?SY`{4mToE2^ zarcGC+wYQaSZNc(u{HAZHqj#8qFV)m$$UrZ*I{Gt)xT7Y&6bwJNd0Pg;=xe_3k0iS zq<$4{ha&ZxY;mpRL0atQBlV1TjOZ}IuaJEx*7JN8VsMY29v+&FPYhQiCf}%cw2H6~ ztwsS*&Ol^}uOp4I)!8pp&pvc^B?6w=onl5>J$sAHKe5->fk{zS;;MaFUVT~kqQq5K zGg>jgKZJdsZw9AZqS;T$iM8DM$dLJUEd22L@|3IxWqF&QKZi&C&&#l6Z7V&t>uX=?t0;g`Pwa#JSDe^6#05Y&T{&ZrKGx=FxA8~@8{ z_DLlOm*7$5-4P!jmRACfo}E8}oy4mZYP(D`-%OfN@-*`{(CCJbZlFRm&)M0l_#;9m z+*GzuC?Fwsf0PP6M~5*yBvP)CHj_Xl0xG4l$Rh`6^MEjWcR?h^@~7897{xdP2zUu4;Q4E=Og5o<#~yOBJ`lIUBYs+ ziQf+$f(3p=(5vaJ;W{!tIxOqOXksDo*}QQSxvh&34s13@i@B1{DKIbat}>n@S!4A0C#NgW@)Bryjk8pRv1KfwaJ0#i%p!KFs} zM_9)?!%-BabWDekHZxpM5qnYl0S*T7wY3cm8K8Dk+I!MaD&aNjs0|)w|JVwA7cu!t zquFmETTRQZj&0IWa8X5UOQ^fd!E%dKdBETHyA*;afDAIVr!!6CP>W3DL3 znhNBHM?(CEeisi$^G>TCiEeC9zT+pyxNIL!_7Yq-OAL{jFzX)rJ99UqRmPNX)-Eq} z5{p6Ltj)SY#16*Zey!Uv=}@TnD!bx?igUN*2GBBB1;;G3O6oeb$Swr0ayDkr!s=H( zq(t@wv9}Um%!_Sm-gU5eV|jajZd>hucmBG0yCR88ilmWJUOuELd`ToRWxggwAofks|T`}vNSisD;2i(y#zmJe;6GVZm$hs+o{A5)GdPn?f4b^v3 z5MS%y?zmIm{HL*4#AV?y{!J;+pNaZYra#gam@-p;=JV%{Ho%d>2DLcL*i4m#_rsg} zFAP0Cx-`NAzy6x%=|MWQ$c}<}FHp{!>07>E(L%rGLHAu~8>0RGAA@gZ4(a>-Uj*N5 z0<|sif6RBJd7xt64}xRxojPI|7K!WGUpJ5yF{L0W36WwOaY;dz!s^}*gm;4 zZ%bjrhjs%gk`+yQB2{D0Qfp-_#K583+|Jx$>-5zKjDON&gIm_~KYS+^1)E=lOXdgX zQZQw|(~_11n^pYVb=n#FI;oUXx<36_{b1{)bX zet7_t3o$QoQ!N`3c`MQMldIRu-lj$gqqvR8Q7SPZ2PR^08l?yPfd`0l+t8W6L2`|T zr?E_z;9@e-QURW9mcQ&yR#)Dcn@pIWQukHnzRKNKmHW~<3`o>{)$*0So-pU3iCosa zj;>)Pm1n^hRYf&Oc6zD(6b_aGSI2U?Eh&@3ATGJ=V;Wooxq7>OG;wB>I4}P@cjCl^ zBR`9S2UT&X^avmRuYYE~%l%0|!e4PS_i02j@z*xpC>6|*qSh-a)FSTM^1{41Vo#bl z(S*CxNr5z7s@L$IbKOzVlAC2Aol#8YLmU3PDGc7>zq8alo2%}z?HRpAk@F^a>o}cL zk^EQFy02+mP3xhiF?xWCZRufu`#q-cIbQpf)1tqO0#D-dANUq#tlMS#I`>p?$Q5T##8%$vm#=kZ*d50xuG*T!E{R;z_LXql^ zcE+?KxNTN*1q4OV0Pz3!;ivwDyUE#kaDw^M( zEHO{u5(FqTz%Vo@6cq~Lc);OE=Kqa8^AFO{At|^eLUTyS}0)YhyK4tXe1 z%TM8#guBD15}=!cimesQX+%k@Hk!XydwYSZBb`NFG#^b%f2idhLkil&L{)JBuWZTQ z@rQ^_)Vgn?O_8P7t;t!F|-Q?KEsUv~bwWYLr$bv3`#HmoaS=ld{ zx(p{9@&*_<*0pLR(LSVVu&*j4+c2_sA72rlieQ1t*4&T)ny1F8deG}DLG2y^4Xd>f zfCx)iM^=n6IbhI90KRX78VI3NvvMe->3XTXUkfm{2krgp``deU&|d0N#GpLB)^f^- z>tRm2(5c~~tf@Q~J2BaQv1a(6rSr46j;4(L;P&~ND3&N^r}hZ zPSAM#2F2Pyy_P@}PP$z~0q&*QkvS=#L}^VvZcTMpN8JLFg1W?FD81myMscI^>ENVC~*k`9s%F$PHQ(Uc(|N|N2`YAxbm%^*ri{UD;d zE|I@H8=-YH7t81*(bdW%(UXMGsLG_gMuXY}sGBjap;w`9ndT~u8ve#wg8I~^SS%z_ zYpLH;YKlhpFqx<_-8`DeOngG8hU!ty7%g5Nlan+2i72ih$jkKRhq~{GaBc@8T1G~9 z@R3A5-w?P_0}h;-lD$I&E~I(5*Q-K>(3PRujxrqMM-q5=@>1Be+^VJ*g%JUfV8kwDZT<_6j$ zv$eh)MHF-``Ruf21}C~2Js5_l3zaUXs-0M>k{Yzb1^_VbtV1yJ#B08*3j!Rotg>_r z4KPQmjYMo!PvOzdi~wg4(c!3>-DyW0Mo=A$;oT8ilw^8|y}ylzNXlRXp=Rm|4MN#T zvxdidozc?H8Eiv&+k~9fP<8VLz_5WKv@WP_r*Dj7)26ov48hk1M%6qhxwnB?C-PbC{AUmGS24l`1u;hE-l;O>QXpvFgd!A`fBP zibC&LV>lRBU8zfn=tt|-mvpF?S$>qKkz>!1opX6Cer>$YqT$>esA+0)5)D*xg(uss zO_?Po$_j*->AErlx0h^HV@AWN8iU3hIug_vGUw#3;p_P{pO)$nwtuR3tw5|c^hdi? zR4L0{8myr(Hp|a*t}m430xwNsRBh!GG3X=GO9D(Hq!&%(ChM$9JSX3w8qdyGdN~AP z)TRbUMqRjZ(xnUTmO*cw&a`G@M-JEoCSMvhs*c#eO0>R)L|Im~i(V04>LxNR4s^z- z98h=(T@se~WUXdaM-q3KQ92aByjsqbv8;|1vyRZ2LiCUj1wevGOk~f66*qX+3lCB> z`Y#WJ+Xd(Hm3xU+XX%dNc%m!?Z)-Jp8MPd%D04BV<y-jVw{Ghk8$PQwlWiQ)J@?TRzfi>mZ>5rT2`kLXJx>P#i}Bt%^;sw z%-p$jzM+2-~! zm@y%FWsF90o{ZO-vIPeD6G7^}l3{4%PXl|!+X76wo~BIhs9nXlexm-xJjm?ot=cj~ znAx_pyXF-?7fC={jSw|vtMWvOJH3WZ=agVGA?IM@8A5VO5O4ub1(?{x$vr_3*QmHW z;^e5nYcNLzK~kahwAZlJd4A{>fsl=!BSz>&M&|)S_K^)+Gms_=+Uk&+F9?wG^p;p1 zi#(h#m<}pElC1ewLe8B6_xKuRLG=@5C#v@f`Bo{EN62tl}Vy(h|Y{ zcf$sU%~&$U;t^znqlfO)`Eb~tCgl7yY%q5pPW~y3WN+{qp0>s_P71Yv&2n*$y0|ZS zTG+r#$TiY^%NmT zzrYvEW*p-L&S;#&nY0(0hum<$=?%-A96WP0#F#i}Zre3b`Wc~XY7)7)L)r~n)p}n1 zrYEQF8qU;Ktz!^^A?f(W1T1<|@v;gQ8hO;=de<=n8#w8a2oE~V4c|`dWgQ#I@w@Vg z>8x>_WmP8cVgZKTsITE_$l~h5fOQ#b<0dK)zzpyMSXPRe!Ld?om4@oD&l*}Mj_RD( zARDOZMNV>P=x~F>7B||7AOV~@R0~u?hk8M^Zs>5`xQ>vzQ6sUyu1m0h9uc1hJVs?{<6N9n0P8dhw&gGRrBJ+=+CQNU_0!v;XRt+ zB2J|^M~lOO*Q-dwo34^TV9Rq>a*OoEMA?T(Gg>6Ze^TrVI=tzKdytT8{ab`w>uutR zxtFRvNKgBXlUk`Pe#N-GGGxvNke7YTOM3n>0&pXb!>z!5)~aa3O4n%fkyYcQsXQ2v z@jCOKeH`=T-Gdavm5xhdI6gMSiIc20kVTE<>#3B03e@e&uAK}jJ;%Swjqg#X!$wL3MpGUb9ucDv0jO)Ks3 zRX>fRqO?d8fY{P+J0s>-#w=2N9>!Y^%~~7s>X4FvZ%D;Mni5?&KVyQ!PZ|!YlQi&3 zy};8~L%TX%5AGzF9lW}8GJ`IZ)+yId!Pws$_#BYy84RZIC4)k9r1+@#jz+)n9rlME zoD;h^35Ng#$=F3m5Gg5W7Z;B zM_HH<42%iR;YCY2qMSvyxo&beNL|hT8>^9cSQG51}q^DHGbDWkzx`KD*>18v;^dg zah$NrK-QikVbqG=PZhH*lR0d-=w<73i7)v+P?S^37NbYN${ftaT)>FIC4@|{`16yZU0=+_N9-x zq?4=ic~{^G08WT(K3dUs;m51nzEVUC+46BHG?F}L6IIO7AMZ>On_HE?iHHeAprAFH znBf&|H+(|k;tb*^azuGmxB%71Gb~hCg};!t3(sL%>XAx@74KY9lM6qoiK@dAqC)w$ zIM)&VDH~_KLkN~wun$}7-V^zp#4C%(kchMLJNf#wvUl_jC3vn2jvzQ$Tm?t*u?x>5 zk>!CaF_;U6+OC9BU_R?gfIb&OS_X9=^yxi`Pu}n4IH{v+hyyMs>Yp6&2?Re!kQv(1 zdooU^tPW)|eA(Pf+686|Gk`?in_toPoi7l@dgZPWyGwUT1xxzNxT-BY?tR$%X%K3E zQW|(19b&E_m$U~y=Jk~8ary>V1Wy&?&O}!A?_JIq=Hh-8st2Xm(Cg}aKEJwPYvi}- z^DXU7Cn16+=e?-wbIT2aiiNj+q2SvaLamiL zC5(@F^6NM=I{%WAc@Oik)_r_--mm5R`18f2JXleIZ;rrEAr(~>(xQzgtB`=w|6S?=b=_Fi2Ov^q0sG*D)Mls z_1qw`xa>bdxBpU+cZXU(6hs!4Z4KSda+g)ME!3JHM1H*NiqP%fRpg9N>pR>-tMs$W zM&2~L?37UJt3kxa%C5QTD`oYe)-6Fqxa{Q0qfM#7D~B zx#{C&?}l1+zb>R7F57a`sb$ZETEDM|g|`;I5xS$9p!8c395RTMvHewAo_y&uSH#vb z3R>#`L2(Q}1pqi-4A*niAn3$-u^D$NalQ8ZokXF6c6YcG?ExG%;NXSBO!}0_W#J+s zL&Y=Y?P5`Y3XcyMoc2n=qYW^!zy}%lf)IWR+aQ&-Q1Kk}1w(z$;q79H6+@KnmkB~}^$Xu54%6jr2v*Ddbd>O6b5I?fHdf9hNpRVVI^uZ(l_>?#sg zi;Z1-%^D3v1UsnbPGhO1fA9~Q9rMPUaYcV>_kFG2sS75=ZF-uO*N1D!7;6 zW+sRF6x@%pK%ymFlFKF?Lmd#9WhPU76SAf*E_CXv1zhCxt`AOz^D$@xVirX_0;w2p+D<6ZbVjVFcgwX z2Rx}Bn&BXviLg4i#6_T-*!NVZm}za_{itqITmd-+R8Ax~7nvctPJWjX;i;i6Hy+XZ zpALC}X5OyWg zL=Doe%1Ap%8c}sY6v3J4;H-3TPCD3_4mPEOQd81@VEAr2xG)`TNeA1~!A0rd;&gCH zI(TO~cy~IuG#$Jz9lSpsd>|csC>>mu4nC3&u1E*l)4|p0pq~!D5d{6SmoNZgh(uTd z?e_C-=ZoPaDrg+5t4vSR6eY`jzg6k@Pq26y5BXaag`iWe_&hh?{PrMn7IRxVVU7Q( zeAvx{*A1v7i)VDYyC01m_gcpKs+Y371=W=vyKqqAqS)mxcaUEOk+M zmSvT|C96A2EbuR|DljAhyus96Vg)g9AF#@((%vu|$@hh`1j;}yCxVf?C|pDYpevbj zcZUn?qi-uyY>n7yFY`y^ywfJs^{WBYLnHE0^rYguh&TRQO2*L0Md3UvC-o8uW-qQ_ z3N+N)xETv@7A8|_l^0|sMEKuqfr=<4!Uk2S2z%PyqP~vAT?bAPh^VMYPD%Ir=UEK9 z5QEt7f6TrimLNEk*zJ$9n7@ZozN=Q6Qe8y+ZA#qJ9 zQlX;Ms=EeL>h0T(r_?TsNmFXGeP>eYFBbFnP^t*`4osc&m?|XVZ&PY}(5i=AtKLVc zcH#%kKHmT{DAnt7W>Bh=7*Q(ARf+X4n0*CA_-`ysQA&l1Qg_`sm{J=AGH6Ww$zsx! z`jvfWQtHPR^Y>6{{qdA)|GOwPA1Jk|)@6SmrRoez#+Yg|zzj;=>2hXJs*xDsT$)Tt zQtBZh{FS$+D5XM0sq23_m{LCz$RJ83EGA8dOpQ3RUTESm(lA9I0aCg|vutVQ8QMG-<`B;+htLf3QA8pJz2aI<~k z;kE_%{USjjWLHA|7*&Bol+=m=H}JD8GTj*mZ&5w%XhTbeG~{1W6!M_0uex2^uUgz~ zt17g=&n@UIuX)GTTyXcoS)+gH)Bl_4X%hO@(+Jf9&$)seb93;Zep=H|B zJtBX^+F?ukQU6IM41!5Ll%!G*1z<7+fb38NLxglEX+;U2BuK$m{}Egmz$mqxums<$ zf?uil=({EOUBYkA80o)PEG)~;nm5vG_OnCZ+c`oT{xXgYe6Jp7?XKV`l7WiT{iI!{ zBmFljQ6*X@qv)U>SV%>*yJ@pugnNFwFH(`M-!NI^eFKR0q{iXc} zL&a`xXqcC4qomO<@;+q0uEJGH&~zc-YD$1zyNhvEBgWOtKlU9r4>=9QPHDft&%QaV zp=yCB^*m9{N3}DgRQ^t*!&`!+HSs5x|^<02x%~&8vA>jsW%6E zHFZ`%obN|Dh{%xt+N#3keq~T|iGQm3xxsf~Q0Jf{&I`Rb+edCLhN9Eq|MuSo2D*10dtZU+b|yRFA3^_H{>2rPY{j>N?_?{k4!)DE zsNwsAT7gaz&W&|~o*260OFAPM-RakU-!}Beb4mK}|D!?PUGjc9`u{qAaFf3id?%ay z&EPxP=<&4wT#(WLR?4pS%lx=ACH)_euyb&uMe$# z>td~9x>cIB8PA)`l8eq;K>3Haht?hxz?-49Z|wK(RC*mlo3wXBYmZiWiQI)S+ykMt zJ1!2beez=Ne}?k?4F9-bnwDKe*25Yn3pF3szKfAP)fN`bM@`4Y{Q9wPivZMsVapnW z73hkvcEB2j<;;oe@Ds=<@ot0>Smw-}5~H*ExI3&pFac++Lyl|UL?F@T8XH*mq204s zP&YA$d9rj40bsO~CVI{$qK_IfZJn`}<;7MW(I!I|AH4$EwL{dec7rH%zzKfoZY4lh!ybru+C-gf(J;v6gn9|U4W_*q5K z`?Z2dv3?rWMFMd_6JOJp2(~_m7XB9Fd4}f6Ao>Nq?hfnZLNCxdQ#FN_S=qFi?$vAO z*B{{@{($G`J@h&6sfS+?V_mE!@$n2r&)KdLig96@=Z1zpsquV3&?NOI3~ zx#zqIyyT!84hjA~JL&@Jnm33;5~5j8sW4w0|3+{+CoB zGVk?nq;yZ|b*zi!Lu+)K&2Gm_(~I0cVp+KMMpsaBS(qMtCwb&W!FQ5JeunRVFpm_& z`+vnE4~s3L5+{x*?#OI=mmB9?zTt6wSmQfhpr<+#BPK`h84!z1az&P|B%_4QZlzOf zQWbeIi0n`2a>l0R@hmejqG#$o19a2zOp^sLj{)KsCxL)z9>*(_Ec74AG=DQUSy%DM zK}<6-;sVt+$u?DO$1%k~#ZBJFHZ!?piif6n%0HfMim81t&$Iz*7x>c^qVRMVmOns!NIL%eyxWz{=eSq*CxWqLq zAyi0=UUk@^hT*}LW@>fd3-$!I9<@U7By=hvnei&2BIEPQ==l2#MZu+c?HTOwn^(o6 z#B=}v6vhq~TQh)CMk-(n3T3=4M#!=PmsH+4d(#_TcpH_Kj1EY@P+h0$_CHI)6Z#UW zIj}TwQ$DqTtO615PgC?eu+6)JB}x2|c-xh}L1MrMjm`44kLmpe<6z%w-BaHl7zp$^ zZ99f$>nto3bhFF#)|DNBclzK`Z1xm+kFN+VS=+trH64n(&0G%`cIIE}@(8*qv5nZZ zn}@B$d4*+n;!NX>`D~EOFg-vJ29>QuoMiQ)vjJJVe{*_BoJFBLE8Zl{0J?6hG$(w-TR|DPJz`*&5F+W-;l z5&i|f0}vTRUn^fH8#kt*Cbc_*b=l*~i-5mwDb0+%?CvcS7ZhD|&w&32;ID-A_Og(W zwSb!KIllGPQ*u3^Qvqh{2_EMm50NGcFXY!A!r|F>R;%3})GAyU4kLV5aU;xz?5x1s zJt6<)<)Uwsbka4;mzcvuP%_EEL(C$xOt+I4-^I9Vi(dQa=Paaet1uS=tCdJH-|Ao^ zT@@~|LzF_QX|H$ya}XFBV+UKDB5;(_#Bw8lF>YHaO6{NrZQa@Ff4)J%JMtnhwe+V;tgWVb zJz*+{j7(!1n~90cLhCXM8=0*(hKYPhOsF#n6D6lH6=q^0BbZ)KVTWLUK$B`gaic2%uP^XxAZ|WG+Hu)Ha|Y7{}#}3*SSuMCMIWj zhr85cG~K!k;n*p?1 zv0G$N_&IO({!!`zlyULymLw^G`nKD@UkA2(|+Mw+)~@#KRZg+R0;-uLn`$y*<3-V8jij=ll> z>%{le)%H%d?6dEpG}9lAnJXGuhj&!Pdb!OO}*fgv32cO`ZM^XU#=}=^3k8& zD>?YK4?Dm}D*^~&EKT5G{)R$qAUp*>!FdY*l5kH#j4EwpF#D@PB# z^tOQqkVNdTh)#=mVfD(RhhDab?H2Ls>I;t^!Zc%gfkk#%PrTaIauPA$Q9ut^JeAC#~*F1WtPju}Nd4GH8B}3Y|`kH$Wao)et zzFx4u8RSe>`I@7LSkm`q)cU|`;t+E-X4Lzzg%4j_L%(f!TYsOn@D{a@8-%^~^@2fl zTKF{!8-YoG%i{J~T$hCpS-3}K_5Brkq~@L=+q}7t1vly|-5_*M!sfK3ToM>XE%c{ctf%eC6s_?mZ+1{)E@undRZ9QViKNe)oJD}F{;1&KC-iN=KqW%v2Q&D0?zx4|^O^GzWIx5n< zYLv9Z1EPpdSYc(M^Z5liM>yO`-ABn7Bq-gLjE9SKN4>pj#;4CaZ_@dNjW;xWtD&jk zrmx>vc&o_SS^I3>HPgbB0I`EfSOj12KxT)guXyTmklsgCXTIM^5z?a9i zE$&Kn!CBHKYvYm+w6jh=J$p)HGKODezRS7 z`8cElvT{aMtiH}9+B+&|%7fDB%Rg;sP`)|ruc`)htWrvTP5O1#PPt&;IuXDn|}=EQmPtM44}_pq6UcC}ZoT70>6lm~Uc4!^8b;3^5HG;+G{>q7;3?EB+LKJ1k)*QdCO{h zwKd9W301CL>_5@_9wPskB@f>-@VK1(d5H^NtD;WN9C;57n zm;Vg%YiiklHf^TN?H}NIEC$q&cmV)qJk`3qc3HZ-_gpto-XgcqshK?Pq_V+^0ck|>*d|*%DYgcIsfn<5_r)S8O_s$>E?HjN1PD_@TZr|#@|Gj-dc}p|Odp|vY z_O8*hC8N9tUZlKVQIF&3IqmN&@6P|Vyid9EMyR}io@FZUv&r((^nA^xL&kW?7@xD> z&mRl_Du0AA!XwYS>8^q0zftAjkG)~>$D7Cc4;~%F6aSlZc;XI{Q}Zp88ET%J|GW&2 zjlV(GtA*s$dbMr&M-<}B31f!KDfh8?cfrSD;$Hl#%%T1MoU(Uahh+?iEz z2PX_#bpGeP91gQWEt^QJiOH2RXHl`Tu)pRNiMA_n!3aGraoT@8Kd~pzGSjk!Ea*vqCLZz$-moS>QFVDnJc= zYgKkf^O4+8Yd2NO?{D6HEY$ikLG=O8*k<@3R6gNp%$mo}kR=iX&FgrOmJ<)vX5PQ{ z{2|Hj1UD;d-krz6&9Yjzeihc#b4LoAK{$=eA)Zq zXE^vFf-lO1uLXX12D~a<>wvei+3G&ZAK~?YdyR0a9vxN>&w>6%pq>0l)uR;nWf}0o zTk3#s5%9eR?AB}HF9%-!2$T3LY!E0{xyv<0xxU38*I&E^-a0J8V{KK5OWeEOD4zx|5tA@|F=Be!RMrQ$KR$gMLGTC z1snfg@QB#G8!YO#_qSobE2de+{F*<39P|mpZF7<=W*1j5O#-tjuih?d@eH1$F5o&z>gUOj~ZSI{v^TwTj&vQ^dp$Y;ec)*AD83OFRn1AQ7qoLKm;lc-0CBnR@eL#hh?dm0A_Ss?r}Cxq^$ zA%7dOFrV%?wRHW1ya<=ntBIka(+1tDKtpzY|$?zIud@)%$H&U+~`y>lvW#p35KP z7yo9~Qva7O^(>_hRl$i1Mm63w;Q!A78~8cd!&9U0%D07er+*neLI0^+jp8>_xCxJ? z8Jv;#idzqbTDY+zPgA(SKhx?o8;ah-R`%;f{u^(@|LKQ;XFYbd1xDb?5@H-hr3aBW za5?*2=p9?-kFZi&U*MRW@tIjvFdzJr?hScefs)ZThGN*`z~$(FFpj zo}oby@?wlN;=7k6is}IeRUMMig?GYgdVa)sYU578^~)b8 zGa7VRV7<^?oZ?fH4s{nZ!&B>ja39h9##jwxW-mn1w7x^Fiyb{QB|9(Fa*zJU{MjQK*ag8l|3A(pg~85# zQ=J-W>9KswOlBx;&;-r%KlXs24n)Ylmkc-o4z+y2imue`MWJB-Ky7Jj`+_i8{B=LI z@lfx@A6*DG|M1T=z3x@mSgBZFaOL2|Ik$-4n&*$2%0Z?ZR}(a*{&1eY59s>K`(k#M zuD^b84jqxfd$k^zaNqMkeieRm;pzYRYr5xqs#xNJ-_4ymKqCgX*t5Ab0eWi z9ebk7S+AV;x}4uu&Qp|g%j4_FmmGtCA!kp*-@ez%nxq`JxE$5W(FLaChC+fICPeu6 zx=iogPbPI{_g7SS!o}`Z?0-8{eX~LJV}~k}F53#zxM+cxG$`K%b{LwUcHwp>gEznsu?<#L5*(4KyA6^oz54c=c~My0fNiV zFf^#B9`OH!*_D5dZ+#R0CG;9^X}q@t4WU$OnB-;oXTXp2cJ=xDn@&N*mx+6xfA&4u zS+aA_!&X^D!}C|hDq?a~^L&Zv5@NM6*!pc|pB7^nL(@Z|P$YhFNhH32Rb|F}FBX+% z$W^$jUbK((1qPtkV`5!u59gL7U^h-2rt&3BoNtmZ7&Y{3Si+DMLelh^o zw`51rYktvpva|jiwsP=0fNJsqYnNX~?^yM^H>K7U@=bO5GS{bG zW*9@H`+(|tlFK()`DE%zdGnQTl*^Ynaofq)vo=_NpLyNd_};zb+voC?E8h#?V@PJ! zvrYNF@83fX)WRPxuvU#(NlyR29dsxue$%S20NwphRL%Am@nM$kolD`Y3t?l8Eo4|TPOhY`<@~z+M=F0^kpJc&e@;gJx)026CmNiO^6p#WynF8B zS>@(8JpZ?InZO8Yr)n91EtN`tp~SDcTPFka*sQPiq+dblRv#~p)Mu_sxL}#43zFG+ z{;;3e%*+jkMpnBiT0n?(U2`>7T__|*A03&d$GX~;l6RO~F!K9pay0R=r;GIH^U>vJ z@%fhm#i0Rz&lriaj+xrIR{V3wHbs7Zx8f0T(YvX(^Yf2LfIek}2_dx0o!N5v9LO9h z*B|w&8^8B3em`m@?D5Zf?Y#k$5hiV!)c&~kg#MFE1BB_kfy+wm>WYd;di~fa%4Ff2 zwC_sr@)ktJ)vNsWS8UH}=#WM30k!`m#V{Q*_m}?y%AVgR>B)HbTyUrjx5+_@;z-}g zeeuuvS7WC@W3F6|{KnKg@8OUCbfEkGQ*zi^xc&X#pyy-C)_iLoNREbDq!Z*ZF`DN~ zbi7BcPMlK@%H>}m91wcHKMVX2+U!uvt4)W7GkUO{6DjkWx#xl+KLGd)WU8Z z-M=D|q|R<^-1@)WWpr*?3Z1J}qSiAAbsSM z9fI`iA2finj$;Sn4}f0zQfnXHaKe4P#U-^U*YGbG9z#Gu%Z={y@6$IHt# ztwIuRISBh}{dJki8o{$CNc^Rc0Qtf+b2%+~zwDs`X3?9$Ts^Pi%XcwV_V|^}bebj{ zD_|}vIjn_rkYTblk=a;_00T}*hNsx_#Y`_B*upd~w!SQ%r5c~4rMG;blju`|$4(p* zTBxe2h|(bXO71^Y9iEux@>KLJ_we8(-j(84JP&oCJ-AuI#esCD_*1AqCHhmYKU8U; z=_?$YTy-y3ORc!`I_!n2I;~P|D%Okf6dLz5BXkFD|IROIib@v?28H0_pxoV>ds5`Yz=RJNaXyBRDIV*BiD`iiucqEeNMhoEQHuK)i~V zTHXEczXm9BSZyGKAvCS?|J*2XXl3O5eUd-}S?fOD>M&XB&nG|!lfr0|B+|r~T_2&; zXK0)g#&p_}nlE1SBW*MZinKHP4P6rg?RnplNJfZOhguL;IiIdUKK*})d;2)Ar~Lna zs-fwE_oO11JD6Q9S+zu|n9-#7FcFDXE+Qpz(QfZiHr3=kqu$9Hu*$Loq%xJ;mUCvCi}Qs=Vnkt_K(zjW6~mo(8rziu~49_S(+N$9nH(WB#~_L z`^GYR-3H72)aG+Q-M$P_)d$;%j|anDQ+paRem`*ieC4lhrSccP@(fiT=qqQ-WuLF6 zGK^31wrk_-J*|3g_N_|sNvun>;1ipGUYw%oFGQjG0i%mQ!id={ff0>z5I#qEQErvJlr>1Ap78* ztr_2>1fu5lU2&rS(cgm&^Wfjq&TU%IUBiYxP|!iM+|Sj2#9wwq-pK`i5T9}PeAXU! z&u_N3A1EH-8^SLMOD#?O@T{1DM7B39R6ufVg(87!dp~mxKG^Fz(tsAg1L(HWKx)So zS;uD%;+FHVP#N=gtUNi#7Fs#Df$m?!k#lUf(&QkRW2E{;m>1#4n^}lWbBXTH;HLdI zzGbIo{+wyD%l?N-M*l!5ERR1ght7)lkF6p#Q}`19wl(>v#1v~*%9Xpy4Px!7v07f1 zC-%{(R3tvn(Lp`^mdERCy;t6g!->d~=LufBN^b&mYY1j-YP>PcA1GhNS3D5Pf0b27 zZ^JrA@F{hc*b4rrY3R8%gK`QVJ2@;V`%3CC{tM@a@)IcEHMjhPu>1#*bSgi${5Z=0 zhxZv|jvW`4|A)%2;J+;RqbUDaZuwDRdGqJolUsfS!@?W#)v-(>S7Ji2JsZaPXtG|6H z|9n;WJgZ+6sI6asA#l<{7&QK6WcKfIfSD zg0(X69b=x)@ha54KVKP`u!uJql;=IVhfF(|!2i_9bo&7ndL+At?V`#yr8*i?(+d5< zukHP7wbP+3n{@Ihx99_+Z?xoDtc84#Rb}IjZSorD^=evxHCXSr%%Z}3ymU2h8P;_- zg7rX;^-6uLr8mtaZu$Ey@w@MK_$hujESfwU(Pd?9S9cd$w&aJtD*=O;L;RECF_1DdED8O5`iQ*P zzLF^2grGtJ6++c{gsHw+`f_~wsIYuVQ2w3wGUdIhoGI^Bv7>!6`?;NhDu1PliOkZ^ z+l*uj8X+-P^>Xpc)Ti0~+{=M>K4zQxqgt*X%x5J&rHuXIG@iowTq$qUua*V#xlH@j zKH(W9cUM<)fiN3(FBExe^WH5>j!O}pc)cEBXn+%>G3u|Y3VO(EX6IENnp zcX>haA)RPtfw>@MKWuHp)y-Y^Zq5R#qb~>yPx3jv-(@cb(O=8)Arc#We2A_;%Zd-V zrRUAL@gWuYG^w5WZWAGz#fMxA+3MqEe9Vatd2B#-e8?R%2lvm!hr~wfM3cpa5F~Re&u?P2B03`%3vE6uK_kO{BT`FfHOQU_+&v$&X?_>j^d&?1OvcnxGz-|(Nt zMR6PwMBY~qf*6>vyamBTYVK0`hOF`uME;&tK8Tqa=P~+&iqEy;w$G9YlJZwflv1i>&}Rk$Dj32zA?+3_KzT+pntK`cy)2~I@}uRND-m6CU*>=WGFgJsh&99p8 z|35RH<;EQO!s1zWhUk$ml9DfueLR#eg8geuPI-%G3CfRD`6W+<<+J>GSff#+yDKw+ zSKQ?RH+z`bT+FW*pWY4q0d}CHrS6b}TIFGn;+l5dL@lK-QjHmm!8K>i3$gae!oHm% zHAmRHlA-0v=|$QbeW*(c5Ou=J9nl5;6-bZ2ghvnU;rOVsck>)z?)Vz{k|@_5q*_7Hr3h4EtxO zRGvJM7A6%`V4mwk#mN+Q_go_spR+>C0bIr5hP+7i^ZZPg7fdsLfW4bY1>OB1#Scqv zq&hF?7}Q@q)dmD(N%BmBTrTadn<5Ha{cG$6*zfS!h0ZQy35ANRVW?(^Q6pkRsw;UK zQu9fq`UHMNlQmM$3^5(>)z}k8$nnxwnwHZm0!#Y1$2;>OoK2!ju6>Lu+WzuVL-?Qd zFr?;%AnZr@{R2P>q>ofD;+MjHo)T!n0iNb>p1W#`R<9tR0c4xj5W0KM-sn_^tWgZC z8^?MIW~XK%e8%nel5HFXNj8p{kgpw3_3N9Pp5j}R+hf@_QcDAiE8zE1spofZ#g*=) zI#O?i#M`^j5v|v;v!Rz4crxT`jt8DLrMJHU?q6QCMsK*9MsN3xcA(K-E8YE|gOrjT z?J}Ge8*h+ZX1uR3umD*&$|*yj+fqawFdtAt>mL+tLA)S-NbQ$xiy^0=nr z@OWbZT62G6uUN88M&+(D+_FP2afBEOI zzFyt2ZGGg`7W|`QP{`?{MScCGe>B(KA$#0^@yB|9>hQ1C=TJYLDSal`502-HJN4Oc zKLFlO_*3@*&8*!_`zZY}f9g2cgZ!!efX%vho0esiym2l1L;ZM$_2ooR{qMzEsQ*Y- z{mCuXH-D-fe72(se!nK2{I|W)1XV*6XbWIxw!4>`~(yVR_& zEV7V3f}zs>RYIf8gqQY9C{D7UJ8V}-K5z{7s&9NTw5RAOwhCzD$aDYH?h-KXs16e) zmQ+@|?n{iUufGb4{Uya%_~)&{xX`nKB`p0&QiIozKG52%PmP1rJ>7YIb`nh-?H)Gh z{hY(I3IUH?u+o6_-VI=>&YN3{k83{mmxpN|W^x1?8<$EfW#(L~d+zNl4M-;ZM@gs_ZDeCR4EksMmM?`M5KtNbLIEUf7JS*&yNxct(- zL-H%%h$fFK!f8`f`9f%+q&YvoBYV}Gx3}~xUcpz)|MND8$#DC&8Ez9VhZhTc?L+b7 z(~-ohuclB%ZST)Mz;dD>)@QrvMPjr2_A4&vvi(1HQbl4ilZMZvds$*!p*surFY?NP z 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 z z{9yxXA03?}phx=2xI`c~)0p46witgn;H8`?y&3SS{RH429>C!O@JkQiU;%gx0L@m{ zxl|fE`zdNQrAG0eH)EF$U(ii+a|&7UuG{_Qrs0-=ZmZ>Lvp8RO^^!2+Lj#qZ3P-uP zI|m4eg>@T9nQ8W=H|;bCg24Wg0d6LSli!^g0%j`+d&R^I{b69_RYTM8KJE*&Mmm41 zaQ_9cB^qp{Kj58x%=B-pnFU4moz!@%T>HhGI?y#U9v++2Pvp1T8%(G)a={@&p5q_g z$ZxllLx16Zo~`YfJn!#oRDiS6+C{4GRLivoPoyHmY}enU6WQGfAgq5unBZh0&e~vT znAQ;Kl;>_Jv@sxV%MyZRWwAR?!;;Bj7tq(of3nfI;#@}KXzT4pw~-NQHX46snJy@? z?`)qN-46>v0eFZ#cvV+h94#XaS{vPJR%_#$T=|0hM%i7St+ZoWC)V4vc{KKW%Or-R zVP;rmY3|*p!!15?Ue@~-a*Mfrd*_6wCp$~HGh2U2GJ!+LdoM>kn0L!45< z?T=Yqc%=QX$zvv{m`i7ii+vy)MpkY(oByAW|BD0u3;yRE_WuL^KHpS{x|)-Z${cR5 z&NiADItrSYq)DnB(AX7E?AzBv7dlv_Y+I;Vpuku;Vnx)FhZ&zW_ zSfm~+=@u)qHpcrlR-8>6SNb+)s*Q=;wo#PTM!0^6LoOt)tsum4po< z@=qj&qox_%rbV7m9_W0X&D}+3F|IcWRPBI6x-hPLGTt_K@A1;B$V;`%jU2{;_mW@rba_;VHt-T-4q&<0rXz$t1wD%x*SbLI`eS0IUy~bxX2M`ARm zhleT6;~9J9EP}*ZE!b@j%iK69x7aFM$=f|8b2yxcF}==C-+fzan4T<5ANH7b6{f91 zOg~Oz`cIf5#|1y4dN{66`PyAnTj~YnjtTAE%za{^;!bfi&*jouW3ThNaaM!@d(z+sJ_0B#G#lO5#m-BNj`f z@JRI)D&F_`$dxx_k=omOnMG<*JIy6h%l0+G)=To-Q`gw&brJpnUA^5&{ik2e=xTy3 z;anJQim$(7WLE!GKOWZ4>c7>-|~v0{S{z^^OngW$0^*k$B@(0e#gUkwsrW z?4Ca#*r-NxgUyl`n>0R`|MkqsHCm5!wceChg zq_6#`Y6tW+Nwr6ZwKMcp=xg7WO&=}92mfF4#rB@HO?a@U-)-#EP#xRn_VN)90Zx_x zpm<->NP4D;EdgooW$mEvK!7G`yT6lmK=JB*jIJT@D4&of7AezgwY`ou=oLhdjrvSv zP92D`b3+JPNJ=}*zlr+=3Iq@dg?mw!xcf-Ft|z9bTDrHc1TXCMf)Y?nwlhE*-HLuT z;btZvgx|yje=tB&1i=D`5>jLPBBm2bT-*DG59Jox=x$3_98x>2JMNtweKmfOln^eB zt>M(7Aqh)#|6xhGmBcCnW}_Xd?chQ*Qug=aZeX^(`fdfWCZVrp1O>(KhRP8%(hMw> zgRxmjfW62N{8WFb=6-B8;c`lU%k4hh!6Ka(MSWR6MtVQH}TrVD( zolHni^ZYep?Jb;7_^JEZP+bpx=}OSlu?V3#f@XBazVKSKB~yu57^@Z>$Y+ix9Ld*= zy(?RKGks)x`8s>qM5Xg}o=$^qmBvFe{{T*O7GAW4e4Qh|R2T+JL*=%cuaneTsAiE< zn}y?#B_99h=j&|sZT#CdE$1c0<-98UM63s zx25MM?NmU0BX``E=rEe%b1Qj~l`k@#A9DcjQ|IwtC=XD66y=-c>rCgzY$;#o2+DWO zg`duk`2ob#EMI3`mGDQN6yji}^ zbpFtvldsdKo=m6gwENdeX~*;{#z%4AIr%!3&gy^2*BMOMvFW6pc-5OytN0H&9{7av z3rQje?w}{W_j2nl4lcFt9+dw(M|2JiJ4|(k|C*uc-*Y~n-2#S zMo=Nl*E!0^G*u}#AO z+}OUYWpKSP==v(x`z4`TW?l|E-(fx(J3q0}b>FC%OU@nJrG=k;ZkHGwzt7kk6^5`qA9__yPV) z{hZn8<_d!PHW{R$&Z+;BD6Luh&FU{b+~XhAPuX4-;-6JtQg}AE3FTkYS1sj*GIDUm zIuYkDNoxgQG|?ab&#Nvrdn*Q(rr3_9@uLf4JbP+St=HNCH}5uA+3;?? z!gkd^@G{)^2Uk%TWes?tw<0)1iF|?=Aoj4d*x$40IJ_+?y6mbi(FS!>23a>H)uM>D zCTEXUTzpGmWai$%%MX(FvP*nRNn|GXULXog_qw_m*A8w-r!Q6MqH>vOqXkJI5d_B@ z&YWWSBSDN({WVo~kgA(^T@Qs@$O$rr?$*>(t~he-M;ZpHfoc;Kra9`e}pR2?by1OyF*G&_6-nd`nPC=+W166tSGK($5+|qkocNA<+-d8bDuBJzz zIQP_YM)6%09Zf1a>DS#TI~7Zij@Qe*XXmS@`yfE<`BO$ z&`jm1D)Uy#rd!fBY#ysY;!BSMM{n=DNnKJKLvt!mP-WhZQsv7J3M+@W3-08c3UgI~ zx3g4Xe$TLi4Us%z*6Gow6cFWsieMxY(bA<+H|F$B7~3!c00FE{dB$SdO`L?_-q)$UX4wNjT|9K;`b*y9LiNgxVCJy5)^upG9)hgCD@_2sXto%+gPRuV9D9jfV$b$3h z&!clITCFA^#lUXmQ?GjJ6bNkVM63A$*a8o>HDFss$O7Ja;v%eJO>S0@L2n)2>o<=XJD-i-pZ_%aLEqkI(UhsnZLG)ngAzc5PhYDg( zQcI**h5I{xveZ*Bu<+T9pJek;J(zJT1u*k)NoVF^BIAkheI>6_O6ti)PWADRw$Rb~ zg7V~HUCI-&u6ccz{$WFTZN(0Gj6q7q?f9o#xDW2N_(CL}{scDl-?{IXf7n=F+i}-u ztA%FA&XT5VKV94Z9XeW=@6tT9g1YT6)yY@c}OkUTcoYA}(bR%W~KJluzDC27Ak zr&zQfr^>r*%JerZs(r~lL~-pmjID8kg_s}qJcQC2`P|CQOqXj&9X}}NyTl=PzP{sC zMfy!O_RINBej-a#r&I!#L^WP3})jpWGlUVwmI-*Lvlb9=mpi-742g z=;{zs8Pqigfn-ow}(hv2Z@6^J-qN{55gKTCoiaDtMvGI#2qmw!u~I zNi{?)U^lmlc1?2Zo@F5P>-kyjq0i{Q)ULFfreF6|i~y9{0S_EWc-g^xM&>FQbeFM& z`bs0&oft!Qww?IsE{2Lk3p{@Zl|WyGqwZ;RKPtge*O#}S5|S_-F1 z)AwmZIInVQsZYZ7rjl@dH9WD^hayZrWs{~Pb_}}8dw0``3ApJOpp|W_6VSQQom(vqgeuu1K{1xan-luvR%n=M` zxIn{vTw4)BgzPdF+?&J5(KKV7_Omi}+Y0ygObOGlJloV$ypMm6&3rjOa3)snJP0za z-C>s=I(Am(w3lml(q68Oj4g7(_w41r|FcZcUg)UQdnkGD>ufiWc=9Jc+wqa#@lD4o z3ZtW65(Pry%vkTaMfB~NVx%>AjduEI;xpTB$!wwTPqtHpLttwk>W%1Tc6YO=El?NddBtkF&w#HZe8uc@C69KIv^9 zf8DI>HK^aPWk=>Latp4-w%9(TPsn7(V$E!hpqSyGlG8@i^dJH$wJ+p7n+d2rxX*z^ zo$SJ+;?dU?h~IOjpu6Y!$~SL3-_}v-X@lgS8I)Lpr_rCVT+!=wPQ5bPgC3e|37@cS z5bNwdBCj$jyOn|Lh1fwCawF5{WpW&@xiHW8J57u#Jxx5fyHoxNr2+0vOGS{Xh|%RO z<5U$tc!&Cs&fuA~8wBx(3DzNwOz9Tz|CeZelW_nq#t^9=yH++u}&)$3M4rKPf*=ZX2Yhe(6vYX1=6*xHCrr&d3@4R z5Me2u=^jVv)XWlV?F3C%;xglLYDa>^Y+p_y`H9D?rOMI0);IPK`PY<7ZQXY%VcpLZ z=-L4v?9J+mPq0;g1+PN2pr;tYdJZ+oR=0>|#l0WApMJ*|kID&AECEBsHEoP0Clt8* zuQli0waWz_w=Pr8CpaCW5#-ZE)^B>W_e9t=? ze6JJ0+5ra(-#6$7TxvY8LVT-WX({CdSDg0^zFrU2tMc`}-ivy-`Fh#vPgM1Se0J_2 z0>H?Cgn>LO8_y;^tR*_xTKRVwzGS#4dwf~NDamZ&1bi|yXlJdoAx5-W5`|) z*+IuWMAff*jlRcS0%*aomxB{qYY(@S9RH%+dR2#V=j$&Vy5~|YSkJ%@vo_kq`{YMz z?0d2Vk#R~vk_*_z6|iRaa=pL@>JSw6JNS6;P@1T(s3rGj>B$n1yO*BIy6%r;&T(1J zdbtZR@YyOyH!IXw=}?Lm#>4!rNW5mqi>48v34?V9l8(kM9i$s3bieH;{hba#>zCfE z!6e?O0UC@io?Mn8`Y<1`JLn>#&wKhq4~iCrK5O@Y8Vp!d6d<-JsS4JCmJDy>!j zeqVoTR{i1W`t5@HqkaAN`%(Wz-}v*yL%Q+4verwek9DK6`6<_1Z%n}m>D%q;;mi>n z?MWapRdDwAaHjBz*yPN4zQzmv`c`>k7-UIR`AxtH^pD1?vdTZ@%O9rl+WUaNx5_W_ z<+D3Efd!cwM*kKpvVy(8QV?V9faPm%<-9^i1wmrE$zG3&cV(ip^bhfTLbqgVq-ZyH z#;!ZcUKZ>bG($PKKc}M9r%D3RnQ)MiWw(%`H#@Y^$ zEu^x2>VrP)yA~HJ{bbbzHWu@bq;CiLzRev&-`3J+i`PXc2dXCrC`ZwX1p%+fn|6MeNV^H_d-?`&;1NFWI6k1Y0M)AR!KlSQSXn-}mZd zG*G___Cy>=3;rCnUgd@l*wWPa660(7(i3g-@&>3hc1GpvTYH3hZE#%UIKO`S(&ylC z|2^kv{uvAFvzD*#^E@r7X8wWy-rqf}2hI8$im%ItC2<8OHX-Z8I&vRU>%KO1ia1PN%zbV0n zSP}WENase}-&D+ZCwo|_vmu&r+$WxI<6a?J`*8+a8tddRoBvvdOp zdm9Akm|MTK2B3&kJKm+~C%g@u_g{dW$$Q#fhyy;Y!0wQF9eaH80XP9A!jwy7I{4F4_w#Bz?qN{D~TpP*A@?4vIxr<5E(=s+^%nm zG4j694xMAcC}K531jH-33+^aL3{g+|N`cGA*U6-*r?Ef9x>A#e!?e%}O_5a$#!RGhA7dxpJ zTfx$(F021qkealh|Gwras(HSz`9_oWzp!Rj|E*@&e_wAe)w_s#VgCtUt7!nytUzMJ zn?ABPsRJas_?3FX^~=i8wZe@<3Jo=oj(mY9*7jch4tMP|xgH2Ep)T}-4N-%ewLtq~ zw;fn~dhuiuhAp06zj-`?LPs3HxwNX537oqj`Z zv?UW*qQJF23rzFzmUHP#fp(AjE+J8h@I3yyqXWbr;z4}&7tisRHWh@gK?;?|tbFEf z&vR{N=N!g3&-C+i=#R|L{*1rP?4tnl^toKD$3yb2M4ubo=+eD$j=`xAoY@{u<5u9T z1U~#(P(uDZ3plAW*ydRu;ktJ>`1&1H{|?P}UBDN_9oyQHkF`dAX_l`wHyi=``O&Fc zh@(sMcPYX@a5KTdx7~V3-Y}$xWThzGL}aj&6n)g z`22hX97cG4f&M%(zn%U(?EArJ@5vw&HLtvFc-ud_pW#f)zu|lhOa1~e)7_4)*mu!L zlKglMZBAjys7b<42M;BA!#)CZ6zl-8Mb?Lrsdf)!%@1EINz5eHiqMZ z!cA{HsXnQ8VyWdnPW$%>K>)|5*a`02``~9(>@-#trwp~sM{@R0UN1J`K#0n0}5PJa9AHGMaUzpLU~V!n&wLRDatX996-$-$aP8J=#^ z05skYeWIayIiu5YTbeBYKNblKL(hmpWS%0%BGIu}gOgv8oY1FY^k=v_&{AY_yzVMm zFjEZk`*M52vB@B*cW$c^J4-GuW59|?fojHKm{rXpectevysDgYAH=ZfsGa&Q-$7~9 zTd0d-S!>L8Bks`Y#!XF_@FO)cqJcAZau;$4pF+QkHH(#|?j&HV#;Q4+w3dhZM{tiu z%9rz?B)@1|X(Wk?Rg(#phyh9iNooWV-Q!D!|eVM1sBBb;izS zoda*TEBz{sZ~ZY+)0d*D-81FgZ5Pujv)?9ee>I?g2Z(#*PH@da#B_;$0u(RzN5}2D zOIQW{RQHxsMSquGxv44D2sOf=76>b%Hh6vg4VyyK!6SU+WSx}Y2bF`cw(H$XNd!~d z`^*Wq3Iwhl{D8|J+yo0LRUVxy4VsN-_7q$TNP#{zX!!)SETevge~~ZYXVA~k?bA4Us21qwBq|4{ zr!4vzuVjd|T}Ll5`q}%EEc%)Kz<;Bk6NC>f?i#ebvs(UN>8EW)^5MA)sWRXz4K97GrAfaP^1`E1&c0fW~sk$u-l6;WOf6k`(_UWgT zuPxBef&O*my5GPxa`{h0%|kymEzr*mk7d!%O|OOY(_j2&uPpwv=LMRA1{a@Zf7A4H z=xr^~&mGr!6hrz6j-mwoXDC%Pn^8cebjL|9|LH{KfPNm&@SlSoGWywnvC+>5BWWoh*3WOmMkHmJnucsNjxAL|FZ!71pJiJ5y7kF1~58is| zg@)h9SG0^@;5d0x9!z#}MH3B^4Bin1!zYZtfNto(`t;5wmzd)+-9Jpa9o?jVFei4K zhRnzp+>J>_5{xey>^HhRNFt00Mz3)ec#UEKp1~ZJrCsOblb9fJ=Ll0+G48R?4Mb;^ z{Lk-5^>_LaUp&DsEU@6wa4(mJ?e7VjklEltxQZH7K{bzkq{~Q(bcT3=-`wqjj8CP` z6zM-Z-&3Mr_~JO(~VyZH_)M`x9cRO;srpupWI4Fe1H5&JImNR`b*@9y_93>fWTK~6-o`J2+g2162y zvl0wr=;W3nWZ|2&_2{_Uj{xPyv^PPdkRKCXT+Pi%(_W2K->CNKeQmAr1E=#O(jBzK z$W}dZgnQ#J{*7y|CCSR*p0%M3(y542Ss%L$0xrY5`S)eAEj(Y*Zgr$uYf*cZ1%p1I8owjgWW0i`7=?KnODB**y-iWp9J3c>BeK-JtPVeJah^myptS>uiN-aUAd zwO6h7-WD0w4p_9F_8tKbvo~aJnHy#8`E$>p-|40FP}khZdQX)AR$~yo#Z-0TO0EB? z*|ypF{f6-*D@4uJD!+jL+(Ewme6^p?((o6`r1e|cdEiAGrbx|jRa(h^S>siDifAEi z6|e2RXUZtZc8kQC$ghde>27mE4o6a!v3>M+PYks_m+VKIC(tH+esvvveimGs_4y)} zuJ(i=R-5~=ii@A5pQv@8#M-O3e>;z81rjH|!$%BlQjY)>?M!=GSJn`ZWS|7(S zBFWtp3;TQh8l10X@2_cL$F7{6I-S?*zp)2zV<%r5xLEfYi`Z0K{|VpwL9&H3FyZ>?g^rf}y-eI7MQ7p#h3i%Pu*6cznxVJ}yvJmFlN>CmYMys?q&_Y&=#J zHTgGNtiyknT-{;#mL_XHQnQkxAP}k6-dXyza7yXmp!(tMG5cD{%1348SwHej?k4b2 zG8uo1{9)^3yQ`T_i*}HpapS_QA(L1%JpEa<5<9zZ1TltjAzcx^=Mann6 zmsw-}JHdGy-M(K~7zy7OH2?m9zCZV2`2E(*ci*+@e=>p$>-@Q}@v_LE)hQX)jDDN> zbKjrvjfOhMpBrO1)Id)^4QYSw>`T6}n~k8ov_IFM-^h4~3*FTt1Tl6(>C=+hv?vPB zw>Bhac%Fj%i2pQL?{G(90Ppc$;|1rXTM0{-c{r=bePi?Z*V3nD!fd=-aCG=wAu7Yn z`vk#xVZyZnhxXG7!uyc|BtW5>Nq))MhGYD#OaEXmA`t&ibD636i*+Y2WL8N*dbuDc0Q_I?2^A_LTz~hWR_1GK! zqzJ~8{L*7*nKqijVp`o4@WI6A1`NB(z(bOl|MVJ>hJ58AUVR3G{<7G%!p8;Qn@(@A*LYaJiv$%U+=L3@EV;F8vRH=YuM0eYT5WjJPYh zRMfHQll(XwYew=oMqf^iD6R-igqKA^zN&MCGA4g@rzV_VXkd1=Rk-gQH3GK z>tnwTcOxIC{Jnc&lgRveo9CCQC&&H3p$M}h#r4k$Mi;Z_Mt4WjOMA*5ZG>K1S>knr z>TkVXRIM)}bhi4PUEQ>HkmDep>SN@!UCd};;$^I$+WN}BHa>;Dnm9PVlFX>8r@F&? z@}VFuS9Vm3Pj9i+{wKF-u=V@A-Rbw$UWV!L3H|<_@nG^+({AYBxxa#<)Gb7$u>64O zW=p_E9r1K}B%{*!RxqwNc=-8(e+lp{PVIq@Y2g;%g7Tb%EgVY=jrVGOYW3CVJWTq6 zixn1r9NcdK;h0y@eR4Z4lh^H(sq1q${R|eV4CQX7A-u|6$GA$TslJNdxR01V*MpcY zS=-4SvV%XRBh28eH=yAtaVy#;|)bm{woEb zXu0WRh)Yv6d^B9IS;}|LqICyJj#6w`uv8yRYcvFI@9+F-wLwq)0yx3C3;jm!!9fOgj=%=% zZ_!79eT3#R>&J3rjS9gw-j|k#+<0IA6xCnFfLeBd49|AQ`|pS8`+Izc$&42KVL9+^ zeddMmE#0E0!=Fn}b8gGflbhF!o{kV;CiZA#*bF^ge?0W`KDSN$G(GL{#ebnEbJzS7 zJ#`m-|6l28rLBbwJ^fM1#SY*6f1#&`ZwtC_^z?5u3`{wq5V6o&9|IVXnwu2O82$X^%%>N?&aHKgkal20b6> zCY0J#{7xtZ9BI}EOvPkSZN`y)DdxpgL|synR<``mUaR%L$`6m;ydC+WvBZ#A(HSHH zdTS#jHi29-dYdO!BqXxshX;NAIjSG|are1aqS<#c`jV;3v0s~k7cl|b zT?w}x5VxfwlJkT3sn7L6=heB#UNXch!FL}YZdv!kE2k`43oRg}C=nSWPy&3~wMg~B zdMA+a`Q2dN*eOWaNvZi3zZI!|OiwbSRckLLmP28~4TC5tn;3%lMPm69Un13i)lbA5 zZJ{h7ZJXQMMVn@;wP?SA6C%}0N={aQM{ZPVq;F)vcQd`zHGwZWS}==esiw0D1wuIP z{)S?I8r=1#^uSXr#{5K3@Q`bD0?12thpK_T0}C~CoTGpM3w(yc^5jj+!5$2oW~-M1 z@M!?xlB;~nZ>h5Mm?4vN*n<0R?f3#U(s(a50;as zDE8z`8Z=47N<=UBtw=t}1x%9|8YZ~Smxbrur9EF#k+6Yp9HaS0#>Olqm;0#O)eSEu z{h$``2t*r7iulR-2KGYBJhp}>n;~+1altz}Yc{saz=a``v2%{-7x$bZ+H0f=dg-Vl zhPki>u7FIB&R z64Acj_`9Cd3ole#b=?BW_nd_iapu$)EaY&0q-KT9hQc$sRdm`=md$&-N#~{5X{wP% zjl|^Ay0$7TD_L^T&}c(`F^`z~pk(_Y&3=GL2nw$Ggjbk^^|PI=>5(HUl2b=S6a9<1 zIdZ8g5ND~-z8bQI`0EM06s$2U%m@ zz>z)>CAu*_W^q_DM`i5P$sPN)jnq7(H5~)tCM}5PJ z;)7{2*6*g(Wr;8SOSj7vEg<4Ui?ZU!f|1?m9+~17-Mvg&sfFaH?$Z20o>P+jG?p`H z)b+St`_R;(;zOh2zRG4kFt*X;@S#FZ{s0h%{?fo>(I_^5ZaumBR(!2s5o2D?+oAwFKQjM}w@T z*uEJ$8clZtfB_xF9%;OLwx^&tkSh`&r@jm+>D6%jQ%~j6lg;6)%t4x;nj=LvocJ_J z858+dksLczj=yT1Z!Ak5#eP_kyljNKbGmJ23bL#ISTIabCUCT0hzfWA3%y zq@fpSG^#|k99E0ZS3ENqi{I&Hm?F2Tzvk*t1qn8|zu*%MPrKdg>mfnVl_7~OeiyCn z{hPL&5U>5^F0Ui;*a5g%g6Y=cMG>JL%>%nNXV4EifZ*_XEHd|0Z+Z5=tlO(V-`2X9 z4wsN=n!$H;-E_;(ckXVNOF zQFea*_G;}^fEYh^dwP6N0Z83f9^XR+Y5#3&F7HFl@oGNPzCUOjtcgOh;siWZ%YGJv zhJY`j!tQrs_Se7c<3@bEs)U`DyisA>@3DJo4G}C{#^0!_e)c6s8ule5e3gh?jq1pQ2`FwG+kB~mtznGAU zw7=PeF7zwL=6b{*xqF#BFuPjr|44Nis4xP;UAa_dm-fvkJ%-Y)x^sNXr>kY%ibczp ztK|!5nK>WBtI%G$D=nu;;?^|V50-lqZl8GGY*UgNT~`llXTe(NVI3@3d*}25O+3%N z$dXVmQvVS?9-iL{@^HrK3lTG2Kh2qhOn;T9)WijPXeA;@v2TOLknd+4 z&!jPST|n~p*GbmT+dk@H@rBd5^8jC!uI zajn9R>_f$n|C^?&$geE1Hg*!1_Yl60|9rhd*_jQ_G)d98;{sDOdg+1t;<~w){fi=% z>>(;NgS)xC19?gQ>&mC}2@AJZWuQ?e&qSpUUGiJeVC8NmN4S?i@#7elH2L2R_N}~M zksQr+Q=h~-88Ro?+j8!pY+NV<2jbr-OfaK~y(uZA!+DMGjGaAf#?hzYi>v$vhX|cr zrNg)%6CGV>{5;V)^uM__J#8S*Xw5+GLJg>E&t(i`2L>4G`X}&0>Y5J=@y8HL@__$K zAqH0S+7kS`4>9=fw*vlt9{y7=0sleT1^zu*@JHmr|5Y0Pi9Z2huR(m?XyBFto<$&e+ct9GS0E(|&(m!TJepLz&f#{Cyi-C2K#}_WbUGs14nA&hKitJEX3{QxxhO;5GAL z8`~=36^!kjFM!u|;A?nkbUj}EGk96QY<$0YiSgBu8b7|>fgVhzjqm-3wlKb(eVglk zq|IP_4^o?Zs?FEyvd4F+mO%D=&QyCky5rlM4<$;itQcAt67s< z45dyco$Z~=+f}=8=$y+A5tyBYkF=OR*$DL!LQlP%+tPN<2!8cZZn6J@km9*pL?}2G zX~8@*)>R<`N`vMQEjq}Yg$2taHUDAgWNww<^De(b6KtfqUQdYMZrE2O#wx2Fw{v`9 z+p zlfkCpy`P0m{i@tz8%4z18MRY#u*q=nZSf(0z6tG>6|Bq|Sah1EU)GN0>G5Z2B7wgU z+fb35@i6@v!bY{moDzvI>R9Y~rRLke(-yTq6IjJt=;}4C=-S>p-Abg*j@mSgU$@kL z7Qfl)kIngwkDk!&7M|xErSLfvC2-DOeBt7RFC0#Um((ICYJ?_!>Nmn`PY z+SCf^K$r<)6Bk^j=4*Q&xzOi1A3TB_=%z@=$VbIO#zc$rq#{AEkNYDKsg7j1)?I6$ zA~la&XV$uD{@LOup1jI{cKy$D0%`%sO~7p|uz8o?hQ&dVvc#5f9b=|-{QzOuR!R|a zJv_2+WatkZ6wDkS(@ty>~UPkes%_=A^dw*@neNcg1k7 zkih7O6r>qo&@D}JCH1Ln)~>7xCjJl338VZ6MNtiu%T~Khd~p@CWfSW5csra6WbPtf z%Mq~cly!bTDCRXL3(RPF%65mrLDD<1s;V?HCYNd~imYcC;iO&ss=7Y5pP*p>!WK-~ z`B0XzL@Fo&WfhNkI+gl(R*$p~R5$S{8{q_{4Pn0z#cAVXaLeva-M=jYC z_pNv;Dk@L(upku$G+OweKU1F8j~C4H;IuE*5Az3UvN$^H*Mef{ zkJV~imf`nyk#E3?S5LpGDfK-QkwYJh$DNFaCyVr+Bre6Bhe# z_)hiOdCT}#{qyJG%lZ?&F>&K;pN(B)GD~cXWY|Jma!(Fbf!f}$Vr+D$8#{;{9-Uu# z$>>Wjp74h;(Y|HHg|Xq$`TlX@ME~Nv8Tc&6U4HH#D%wKJgd6l(| zcQv!8`UC^Xw7hQoX5-K7Z{$3}L@q>9k>%@8ssuI{Ts-FBu@_huBh|I`a`d=!{&3D{ zM(j`qBD&xY7fg&@F#6zF^iU;$X}3J~+xd0^NF8^{$LX&*rDFr#K6yT}96jE5{^eh7 z3H0Il0gy=ox_flNr8GL`B8CB=`vSC*6H?G+^YLUnx~bUwo8Z3w+)m>M@L%{#I%m^Q z{qSri%ia`kY8yK)-c%5S|JyN;U_B)NNW^W7$ky-PG_G*0+4Xr5O-}CSDlgT`%3civ zb!$^z<8I-6MU$;J=j|AKq~RF0T2bBNLcdQ0>&Wf7kJm#tAvf)2JNAI?QSy!L{|n@% z+#8>k@ApF!4G2!^Y}-OhGV+h5nuKGnV^=7M%+x)57`gZUVqQ~Xi`0$L`Bz3;Etj*Z zN&q;Pqc}^b$j||=Xvm+D0y6wc<&p#Us{Al{YR~9sBEl>4IiA&>guR_*B<{n8HBDCQ z5HhNJ=avh}oM+nB=sM+6-3;(`4sl z>jyr6PVSLg^&J0WPiFHve!B1WvH^;J$pF>qTkU|hgBhUK44es;Smpy`#6$aXAr1Vr zDb>S<2YSJlPnxbs^(i1Fb8F2`e2Gu%i4$7Kw4$|f4F?9!qSPj8&UQ)PTo*NGR9rh? z?y)p?!`>wSJieeb;p$ou3Cq|{s<?Wv(JQrHDOT5g3Q|Bxe_a#T80zxQ1-Z z$`FdmjXZ!FBH{8Qz$>*O<6DCttI5^xX(Lw-4b&aSOfzyX527ne)kWlZr6;Q|J#|PT zRcc(OP9sUjwwxAvM$RhYz@?4o>8W?&gJWmg?bJFyuzB&0l{;)++>>lsHd)of7{2>= ztjxc^z+QD{Doc1(3Y9S0GjF7NDdG~VsOw7`L>d7>`u!w%Y|psMk8f!cnK_=4_+WZs z5iLp#+$%Lw4QJMqJ`647W4CBx*yLy;J_~G8hf_%79U!xWM=*@kT*yGAhVx%Q_i{X7 z^y7lwVS8aQ?&)s3pX+uq^lrNqzP%vQo?kR&a^;|+)N8QD08VuD@zfv2?5y=51?%W# z$k)&KeNi(f^6n|Z`%WiF2@Git$J9+1LeOqQRQoiN6rZ&;h z@XDvuAvcj3gDmNwPu*&%KLMJ&!9K4T4xr?e$xQsLa#2$cOW&W+ciqReo$oil#P@}KXWEKHq*66Gg=S2J4up{*sXElF zbQ!)oA|h*rk9 zKG@9`#bJQ_j2nFc2Al?8kbWN&u#+jg_@C|=KaB>Z^XUrJ~1W}ILU;dofa zqMRXFGlxJe|8{LWoNEN4sSI#8;`xIDTA5&n};*O!)X{;GH%Rdij7Bo{&c}_ zRVA^pJh9F#9L@L{!?~8C{~vSj0v=V7w2vncAPPEBL8G9?B`OLoAfO;b6Ou?GL8G9e zctJsAy@4_T)+hvLB922eE(o}IK|w{q`<06r1PKZ%f)`fQfTHwaKoAg+i}QQms&nR? znS{W%-}n5Vzt1C?)8|xmb#+yBb$4~OnTT!$vR14wOX;4TjrzzR8D`vbu?46>;}|~1 zHlDV-PiV7sG4b?PJYPkCXS34XpLqHLj~ZMZa4TB;1H~S?x1Xf#hlg9sNF6^D3U(8h znJY%LGRq*$;+M0Jdx8Y>O$#CZMpimaiU0W`RQe-`NgzI~)m)BhYH7)^R~jVEqZn~m zS(Oj|ROgNc$KXv_835pV3r;KQ>D!8v%LcT^Om%iy3jlC9>6?NE7KXkL?2Tf#aB1LA zEO}OCcU|hgHk^xOnYh2Db$&B{AH4P-+5O5Cf1~bwQcErj=cmCPKB0SVTFJSf2*Hf& zR8D1{h?on8&H0DzZU~be^`Gjo)oSk-XBTyglstg!O_3_tCybucabPKuUA1yk9 zlCOa(!>o|fl4S^?%V69^eg^8pz0~QfI=)_nDn|XYxD8x__}dY9gpyqgBFuP25=bN$ z_N9A%l7E#o1YaSXD!pS>GvfAPOhpB+W!q6QWN*Z0w)*UK zrt_X;I2=P*>h1&96XKr8xZV3G{rw^ zR2O*_h$bVECMBT(*oEi;`Z@2Rg7BCQ@&U*E7x7HlKs95TR$BOzsv=Qoi6<$Z~jnyx}6zJCi7s6rxMKGgM0FUfYzN=)a`R*72?oHrA z(o~VPu{#*@6Obn8{-a_Jtee0{r+sFcf;S`h`3gRZ;4^B27Xw`F-l@Q#cFzn@_!Ykb z{#=D0O87wzyz8E)5guLwF0-UBq2qB&g`Yt9%h`6#J7^kexu4~EEPp}1r~ScnM$VXV zfruBn-j-2N-7^E6q1>8#acc|rT<_Nuau=GpX~LlAHULvojlf@e0VrIA8iYaX0I6fp zU9h9##yh3}>ziB6vKJwESlJx-yPl^#pAS1u;Av!kTl{=KgbG5r87PjN>c|`51|m9w zpFY$|&hz%eP)wiD-^mQgYzJC@4Q+*gYo36fU}{qG5Jd*(eC35ouyrzyzo|cocOnZh z8>Rjn&|6C+tNB;SnCkSe%dPOeAaJ!A@G5I->_3Inm_B&YquWR85}2be^0wxA zZNMl@Q>ez@!yV}mxHq*y2`p!Bh7fALgF8g>7b)ojLR*G2!xc6iuhk(& z-{91nt#7lB5^Z>UJ+z^-YQy{ILmS>Y8loS6j&vYY*cu?lLNu$gM%gjz?A=l1SXX_F zX`?M)`(_K#{_~Jspd>@YXsQiYe6H#bt_M&t@}Ff3ojd;$fHQ4?Q(4hxD*v%|-Ucs= z{9YO-Z##cGNPpj6o1Rn~{mPDqNzarYwc*d4RR=xa!7-{$&tQk1I_(vEan;Mps5{9h zOzXFr;dV9YwdlGjK}@m{|I$?Yv1lFo@hk1eZC%ihk!H2}aViX8kUyMxC}|IT{rk3OUAul}&U_V22*{SmwUiSmuCYWHTCKQLrc3e*5>#FKJC?Op%aAch$% zMxjwk2ev%T9Um|$h<{CiCL_CFA3vd&$PuW@F&!oEx)R&prto=4Z2yD-^!rV55?fiz ze^7e!D@oqrng~?-XlEpVlI6U zdVhvzO0!rOy|->W6o0>-;ib14PxaAz^|Tm&iyV3z#OS>SMGk+{4oYvQdgy)c*F({J zdK|qc9D?2#{~e?ENhJOjc}R}Y`x1&AdJ)TW5dH?>Kp%|1O+54_j=!bPDQDHczY|Z& z*}DAu=o3Px*+`~>kUIVQz3^n~82^4D%i!O~+kZPZ4~Ky57~Cn6r;CZ-fF~uSh0M}t z!KICj0$4YZkA^8dw5x;P6DFx5tA?91lG7pBqO%($yWBe%v=le}eSSeAn*xCL_P_wxNf%3qyiEIJ^;S#EWht z9)!P6o=>j35lzsDy2l3({rAARaQQzNPlx3H)+sUiH@suh-#DKB`_L{GS#IUvSDo}P zh4)(z{k?uZ4Eo=MQ{d7+6HkYvzr9O;rbBjZTtEHeF|j`+|F>h% zb?M)Lr$f>|Y;uhMgWtCKpAt|1ev~`(%V1I`{TIVKu805C>kotebK~gGJRJI8dpt(} z%(ra%8^+V$!$ZFeE_KrXAiUdp=x=g3^xp#~!sY*9JROq%TPMZn-|(hQe}j1X??byB z{>xxfC;dy|9oIvDuXTsP|2Hv6yY$b*(;?|^@6w;?(4QPn{{oad^vmE=C;g4^(CgickA@`_cJj4-F#qQ;xfh)$(a7WX6q|!!O2O931BE_ zU{9lxiJTO_^*Q<;0UqgdQOYZ7u1Tft7!4@OOvjzz^RVonWHPSWgF>XxKu%+)1!fv>S)Ear zyB_fVXHuhCmoClCuv*}?%`Z~4#(w{LhW-8z)OKk5hr!&H-wk*=r2GzhEY|eFuZf(- zkN>Yr8ODD`T|$cAiH)7J-QKwb&N6%F-*u0j%fF9v01{-^Gk%^MM}Oww(EnOxjQ*Lg z+V&%H{MUA2{10Y6gic~JUX3+lrrV4Fd}uafV%^P1K{M+2zwUuE;_`nmo({?Xt&hg& z-|&h}f8zL$cB%acW|q}Q|6=&4_0XTU_E7Y{iNV~Ze8n{!EAd#PJ{Hj{O^b zQ2(W|P5eRpukqg|?2#D%2hXwjpE&-b+@XK?LFvC3-Z`0n5c;eC za~SlW8%KZU;n4qDMU4KLvu*kl$A1s~Lk~*-gK%)`p})!D(0>n{5tsji@pMT3Z=DdM ze*MFEkiB2cKcaNme#V)Q_H432W@{?#FM>-{PB`9VHgjOY#V75y2wFCHf|mI4Y*OOLx`UgU;vQ$M5ogmWs$4ZnW{Z(3PI zwk;_LH_z-7T35t06*UYvNHsqkCA+#Wu>wS}`QA+n?7h3>-({nd5l4c=X(e}Y@d3dK zc|4PopJBeQ!9o7T;H|HG1UMnLj_{=!^c7!NH;5~R{hChOg|GK51z*GJux7UcU%P|f z3Hxq_O0m{z3sBVVD^JG{Q1DM*`O#8EvrI{7r+Q(>Ckz|ag`o+jNr=I2GFU?s=HO>u z_|gvfjJjo}%j}6xi3OF)wnTOQ^sd^^H>`*VhtH)px0Ke?Z&8H{nsGdq+6z$n}VnOssT zyt4OaE3%$C9#u^RY0?BH zG|@mI+Bb;#I@aR~s~sQdN{|eFP9~Fh``|180N6yN_BcI;dvPcMDpC*Qr;3!w8ANJ& z&xWq>h)h}IfJ69a%Mrrjw*iyNRd10if1WLrcc@UVT7v+8$!Sw^q9Y~ddMq8tooQnl z1r9XvU&BEm1FJ8o z=IC6c^+Jm>&>);Ag`Pz!Z25X?lhl*RdTaw()%@SloDU#^QS%O{NT}^*)MgdorOM|B zh2QWY;3?luoZ0{_U%_(97ldZ0;N`$#u2;O2QAfj$B;K8Pt9V-~`~<>Nz8$;`wcOA0 zIQv9bTki^?f%1Q_z|3G*X=(eA-*icEPS?0Zk@N> zu>%a!oyU`-%t!fGTjrU2sV%q)Uklb$Z0JtBHJJzSF29v^wsa8utJOvb%p-xe{aJS` zl{>#`@a-!#Rq_M`k!!v95~lL zrLkU$g%xz`ZK?1R2p`w~TJC4LZJ)MnlqUXX0gAe%h^QSn2376BrwR7yd1_CU#cP)m z>{H_SMmh0~FK0JJ;ly&d6B%fYB}99iTZx{v9hZ;sQ;m}NialF#fLg{vrtR;AALbIJ zas;WoOR2n?R9@jw=`th=?GT34l0zL2nV(erQD3kbe==Ow7i65WZF+Er5XZx-;cJ6{ zlK1fl(}R*@QvGi8JbXv_w%QR#?0mQxpzl}kJ>^$(`MU4B>-#x; zPdTibumLadHA){n9UEW8pLz3t4#iQi)@K#3DRs(@luk)VzIg9EX7&q*AWYa>VJZ z=DhWOt9j>7k)7ZcHol_Eqeu?G;-|H^{5cde3^+;s`B6m0aPdb_mCCr|&tHdE=Ea{y zcGBmfPi#4V`zXlHYa43G`E}4*>q~T%Ef0ZxI5|o8+M#g#aZ2HFHifsa%8D*q9#;zY z?@_|p^(by~8FD*QKef1g6fntAX3l?(vu{)%dI~RbZy@U7DhHE|;l9PlPeS{3?}K*R z&hKd!8^^bxWeJ-4Zz!*Ith50AYi28aE5dvI%!yi_!gAY=PZzv^M81E;>mA2?5-%>v zw#V_l3cut%zhyBM=%_45_8q_{EH!&=Ds+f|CJ3fkas2=fn zw5>Cyn~K9DFtsUvK~dsQ1kG5+rYZB zf%9SGu!Qj_{n_3Mwt!%^eD)_;UkA*c2PFYa?XqXS+En51BfM8Wchm?ugIR9tY!dPA z!}kgHeiqfZ$~pk)s5J8xt{vfQxn6bz;1)Y@?r=ODaO$6QreLXmTB`7y-v+!#uFW7V z|BB@z$1j*-ExMdVK5)$Xqz?JCcZ=iZ*qpEU#=pU?qYpBjJONGR?`pXxb1eofcsdz?r{`euDl1%oBm=*4=4udbq6q?AC(&)tY{0^3=rTftt zv1!W-RkA8`Y~TO}i)(-klNVo**rCs{xkt_oi|zTlZ#?JgLUWkZ@pz9fSO!4bXDPu? z^E$j-dxkVWa3EDz40R;Iou!aD8L=Q|U8hV&?w2kD)7vLS+Itk-^V6{>h2b&jg@L7M zkZte_wd8bfT(U`RNz!)5mK+1*uK%O@vlk!R`g1i2)mdi|OTj>NUy_M_>JW@O|In9K zvWrKU_oL?nCQ|pZ#;&iTXLfbZR(kHTX9l_m6(m{x@v)BgT-ZRL&qRTE1*idI%Sgl~ z>?&z#-HESl|7xV&PRIr6)eOo9&fy`ylJz;^#tFlPX4pmkT4yOc3VFZ^|eI{M_+GuKXUbT*8-2elFOp6Tvs`mzJBlMYbmKy zedYZkw!YGfF-dM!_3P_H6GdN#H;2BS8mFWX(}U~hz~3DGJPkbmFZA=qYKLLI;J4^8 z%cJL_pBH*Q;GOk{t)D|<{cr0h1>(QZ&+E@Vn0^kC8nFKJACd0~uR;!O{cO`Prk^L{ zbX9_WehR_2+Bo!?wQB^vi1796C$0ze=;zO(AxUPM!Z#zlt)H_RK)+^yu7sM4Q8V>( zwtxm9K@gGw3cunNz}xycl<R$rk20UxwS)s2*F2NuX8NtNVl`zJxeG$lVqr0$Qway zzwjme%;7Fb$pcJfQ~pm?4&`@FxKAq{EDs(J*ub9$e8Kke11h6x$9gXHl=Am~+P<9eXya(B56O9(44hAk0D68GmsGyJvPmsAqI>W(l1}OZBmjUnbR|~^eb`3SK zZWlIC&O7OMGx?pZC)rXDFhxxlt;ee^KS6=4g)u$Z@s-dynDAabS*ztmELS}NJKtz9 zIZ9EO*Aa|iuQvjxa+c=bon-9x$TlME_uwIXzij{A%AdB*A-|&P z+-)d?Jc_Ijj9AkabOI^>16aq?uRUCnmZHKq$G zQ&_+1-IMs<*1N|@2^DTMdPEe^SAHjc7J_PI`4f$P9*|-og7^WgZzZJ-Q&`&27yMja zW7mw^CkU~iXZ0m)zX`H%|frWZzNK8?tv$w<{b1UR2*qX`m|!I zkW}z<;Yj==4k`Ml*%*9P4W)D94;NB?tRwJ`_%G7F_fRJKj0`H^29L`-`urqbnHN_{ z?dhzYHb0+P@w49857cu&Sc1S`gW9ZFfQ#w#G(6b)-19k;yL>DXF>h?3%eMZ8~L>#`BSOp@7u+_w0QYvY80Nei!VSi8h{TU zwM))LiTUWuebI$|gtsjkzlf|fxb%J>TKFj%PZswH_sPf!tpQJmk47Sr7?V3znOmWa zIhf+3nYbH?|Hcf4!ZZSWtzk`K5arlQMVv$a(}NfGiP1Aoo} z2n8JdZ1_w0UGqX2kw={M$9*fMukLsOeP#Oxsc1&dLQoYo2hhlb?s^%9#`<%=Ee~eC z!nY&5$3G|tU)w>_KwZ%)hgrpv%)f51lMwojX{bq$eaGZF$)9pFtQUY%Oo44F8Z>Q> z$coGcqIUTpCO>pbD_NOgJ4~+D`}Xsw*S2@Xd%^zRO0n0{?Sar+orG~orm4c+M>w%_ zOGU2DjxW^yv0Uujt19o%^}>phSZW_@Hgc12Una49#=r(i?~}{2=_)yRtaCv%&eWi+ z4SyjjCCNGkzqC6f07Yz|-Qu((;e?0pYk;{~)PHVa2^$^Y(E?D)O}&%g;4y zVYMKSRB2Mexu(6gVf0M2p&RP8Hlpw2{bgtUSJK(-V15U&uD^gZ-}q@MV3FJteykv$c$lpNLDqh~{rPHB9P*yd@dp(gG_c3@N_x z-30AgU+`!_Tgu!XKl5cNve8MhZsdc&#p_r%pj)E`*81n`;=HSW61R^g`xj%{ zmF;m^QXT9p>gU!z>*8<)0?D>p2o5wyUijSL6Siya>f!9E(LSF^r7VxD6<< zKDzufk&_-Xz+>7rB$BVl`ervI@5|3?>B<<`f=D-!*NF<3LO9zGm=37ZYi%*)Wb9tebKAX8HI zTDxDN^pv689_M}I=L1qua~}`#lZLn~q-rESot5+6ELnuI;|$>br=du43Pqkrqg9@P z!~ZW4yOSIm{g6iqD6{1;IridMojsS|0Ny(GyZdtC|D5UIPfQ*!{sZ!u1I{Jb?%!Y_ zBKJ`q88BFYeAl!!zThXI%$)WkG9Dm(AHq3t#14z)^4^?O(-vQ&SQdbEf>X}LEmQTW zRNawP+amqhPDi8{gRX?yhtoWPrz+BRTn)xKh|CKCjJXil7Tkm;S!Uu7by73oM=v$9 zuu#(0BN3*p67}RWAd31RxuV?tH1Wm!|52qlb&e{9?~z+X#&f&Tj-E^g(O{N$(8`5L zus)~#Rz2ve@JpTsyy$@)ztdgI=dfJ#<^^sne0?f!KGVLm+5?N}G}~$GKk+E~JRCn9 zeIAV8v9@yWsjD>jLJ#-BQY-=~#=VAZZ61*IUD^LgE;Citmz^|r}=_+L8Un*4StMblLnIDAzVX`yZm>4$VH+{0{6E{ z9+`*f3M^gJY6}qfzs}k+hOdz_e06e0DPPdw6MMVx2mI8%j<;R_<>J)A@MmMlydsrD zusCVqD=--i?EMR=&;wP;p?nNV@I6C-Rq>Yl7GzxYkCh=>;(LKiVtfZ&Z(RlCYA5qB zoXb$$kkCYPB&pHKxa5)3AOpq`YlQGgfW_GT$c<8ex-Y#D( z{odmV^slXCYqmhUS1+lh-DOZY-G6Kd1P*_ zUtC1{R9@2`>#OxHnTmSF&wEhDg}_J2+$DMNHye-cFHXdh*5_;p{cgWEO%>05#AC~S zI_W=7>GuvnRnP+5<)`D%>W`$|d4vtebFW)e>3v)T9 zlOx_-j_o4oo2!3MPQtNAvMbNY2CBzqEAv1ciLx62rDoN6VJ(f!_Exq|D~mj4-mSt~ z2rs0-YR9#cWi4d!CRDU=QKB8qSpY$dnp+_r|!SgS9{VVWpTVi)m= zu-obUDttx(nJ%BJ5adL^k*V8BfdwKd4gCMGF<_35?!ntS`#Re~7u>#8`kL%>rjpoK zkLh2vN)vg69r2^lAgd2}7<=#ZHy3$}&jAk3As@5u!#AS;xZ5Ek$$tc|Inrlbg-c}C z2=UQiz-zw;DM?meeed2c#2FQ&anKogz4*@<&_&6xtMB$-d!HWb~3(6QA3N-uY}xvgC-hbBJdr z$-LPu&ga{gEI{gxXgN6=h&IIS))kG4AD9va(o^ws_N!A+j3_Tmeerl}&&g5V z*P2w|%m2vj?<+%p6omc~ds&h7;YslFumoh@T_wwhx0P=xIRk{lhVLGSyQQAd;@f2q ziw)jo#5(RkQW`GE_(i{NkGjp>`gNWbZOp-47dN0N^pSvrs~^bvSfnw>yV!<6O9Wwr z^RVWnzJaWVMSj+0uJ2c@Q2CG@fkGI1xkxOqd2}^p4Ep5HOk0?Q-$gikCS3%D&*Ur9 z@T>hC)`N`yD}qHp^6-9{nIb8FnFo=?k1u&1hm!qZDa?kGvKDDKaWXZ8xP5b1ONyYL zmLoG6$+T&xT$uI9DtX>&PFlq)iE;XEsk!ldeMLWmxo|T%1xu3~1&|P*=H#i{^$YG} z@R)rYk$P+`B}Hx){lQVavyR-4U^UH3&-EUd3e+oYFt5n%31|oo)j{;GLHYqR7nuq{ zElz0eHYYQCw}xeww}y^Jn%jO0v`3HfMNS09z>?8%!sU*)9oI(wBkKcL#T#fN#&U%l zZ@PS*_yLnDFdeC#9a0v{D+C2*&+PK{EnaCo+RsZi~=Ij?B6~i z7=F2!DAvDj&r+cZsC?+zcBn7OoCSun^Pa^+tY_PyXK5iqf0>uSKbk53AejNnWqn(9 z67)10ul?!2n0>j>?v8ia5VZKxm9f5@*hPD48eTy%(%GNw?5SNG9ozQQX(s=u4-3J(id6LZ2MRxz(;_V-< z8Dkh8w|OW`G_|ZlQPT;Tj3O&sWMvdV_PYAY1JFWfC(fqgm@-sV)|Ig25BCG>mXh(E z!xxRbZY~#uCuJ_fBh6zK|5kMQ&oi(YC*dLl^bM0deeu;_P%Y%;sK$BYzvx2wg1trC ze}`oSK))f}>)2>U-e&JD6os(l`5iSY1FuJ3#+{sv9oNcu@7}a11Aei|cA(@o2La&? zmla*Qo;NuvmoYjZnoEL3qs_zD#x7IB9S}AYtV@?WUz`%96G11^1?0HT(&_kXF0Bna zNf-(6YfodP>M^+BYY2|gWd!%t1x}U%{OE~V`#OB+f+yi6Yu`rjm53C=D`a{UvT<7! z5U1h`_xm>d9;NgfP4-dIe^GojBZ2mCf)!!^ML|7BzTMe8pxF>uKmK`K6V&x^m^Mne~_)kb8cn%M3h&W zw(pAkcb)+Gm#DaktRdYYR-N7x`JWHO&PkzlREf3L9n^qW{TL2!OS&y7>d)-z{om}s zY8RBet1}Qgm*c@km104)jpxDPP@8~J$ho&E4+UD|Oy1;`U?q=@HRjG zPWYdJH-R6O0uO$?s4&|eM4k6)oqM|g<~0Y#<;Qh^`QOOLeZy<>gS+r17i(^H+0&*< zTW8XS8^EY9H;}gD9NJudREY{C@MHOF!jFE0xA}1j;a3B10zb+G9{iZ1FjeJ%`IpwY zsWV`nabR426amJ|4=dt$Vmjayg!UAKzAXq3PmN~KPrp(oOqv5EFlJy9ykra{(J1~l z<6r;qg3u1Q2k-8D9CCBO%;|w!XXK!#zh42;v89?#7s)*?@P~1~a+jNVXZm>eqxSr$ znfX{hIt_E)p)yYj)r8XUqgkjpCE9l&c_cSma$e{BE<;O`aFGP)?F$+>&%AU!vx8LQ zaQ*K56)&KqSuPGIBDs&z#r{f05?8 zx*-Qr&av;ss>9GE{|NZIG!!3*f^5fm4N298k@^T$8Zsc+?0ZG}vxt4u2_NIsT1D2s za&a+bGI|XdsPB%)@G6Z97I9u^is)*JSyBvO0ZG2!7>46orezg`0gSPwfXZW*X4viDI_?aKWv2ZXVv~X z`LlM8@TVQfartvkPf)cUBq#9a5gHrt=Rs6?5dMULFOEN}0>YnDiSiLe>E%y%pag&V zC4x;;Fp~qYt80U$0IV+l*tbRCJO@^o33GhzAbcUiP+2}& z9&wi#Lk75>ASd{%bBBw(g>r{NE5rfpi5x*01>xTC`5@yXuszWnD-J)IZ*PZ@3iQat zeWkLdgwDWC!DjltzholIHA0-r#{aypY(z#OqsETHWt525+lEfzWOtJDO?B>2{7lMO zAVPiT)xeCk$8cZ2BmhaX*K^@KQt~-n``M(=2FpLh1EjI&0pa!=*SVjaU+^LG=|Cvwq}-60%SoxE4x_R5|)E?PZaluf{=s76X~Y z%bbhq?FiUuAPz)K;j1e3V+&AyWP;*1;VWt2QG*&SBu-dj4TDWIJr!{&5tmBivesUN zR$Zb9y%XKt&>yYNx*%RYQ#)MZ4y6;+CjC$&oJ zlRzC?9^-vP7o`B-`}m$C$%aj zf0p#nd1JxRv#FjHSwA8a()0nRrH9-RbuXk`M$`cy0QYIw?WJNf-VL?xYJwe5ZhVO$ zfL-9;C-k4Bol1o?BaN!z<5jp4j!m!+VrBybOH-KPrI??th(<9YVoXB`7)GImu=+<4 z19{g`k@%Yvfwqe2WmL``P2(ca`vWA_Zwl?X8StXCwDTCWlp%O%>CPT#=^$_*p`~d~ zORZ}l<>oYn+7vSJT*Z-V&kp9d#sb%hW;=!F_v&pA&**m zO#N@zjqMK+aO{uWUyr{at$2{M*!}f)(()8&OlSr57aYRXsTiJhK8ZSdg_}SIn}CMm zB>$0kpKgsqc9=@JA6?AsuX6u7d0)}un_b}GC(+6bHk)&4Fj?)PX{wZbbss2sK)Eur zJ19BMp`-z_^{8%FiFzV=mAm{|SrGaX!+<{xm0Z3XN_QRj#eQ<`Ll!c7;ucrvOJHn= zq>>`JcGrK|tj0opo1~HpPEYD!i?tuu;^8A%?Jj91GGWUDWVH-Zn559h$Y=if@}cMv zE?@P}(Hb^IX1D~p`zf?!q{bJVOK}eE!&P@w>d*3#(>C-4ZwX8-U+D|#I(Cg=UMTE; zj5&v!ilf;BeL{cchqmQ~tk9-BtcizeoQU_F8?C{}|HpPCPhgRGZ>IEaF?o761*0PC z#;f5+e)zoIyHqaa=^ao|(MDF_;zOIXe^{*cfuZ%-_b}Hg@*Sl>-b#@-Ao81ueAPm( zq&owLkI2!CXyjSbTEP|&>@)>ieigvlDj3I82W$-#B2uk-7{|YK@e+=JloT?D9Wwp? zft?8R5LgvjT#=m&cKODC3QV#Jt9x=>g})U}yRP^;smQ8L-_3vFXhAjmV-Fw#`@sHg zi+$z$@G$Rb`~&CvY!LY2RQxv2e~n$c&|+LeETcbruuu6Gf7^L4=$A?O5-X#cRB!Ze z$=H?3v#m~UnlJbxzA6gQ0lA&`9%tl*O8vHy+BZ&8D~du;G3V}BTkc@EpZJsB_s6Wb zybYM?5r4+NJ|}%Ge0>tt&`GMu8h#~MyK;u~2umH--Vd#!Nqc_NUpU%T6?rHpR3lk7 zoc=bYiti5g(__-Otky&pP-NcRSsj2Z@`i0MLpAee$>&{m_QU7FRp0?C>Vb+PkGuNN zH{1lGuUgcpAUw7Md^I?7QNNF4+L6)9l|;faSm?{Ta5 zlZUZ1#Bf~kFu+RR;o4s*rn_<_u0{T|@06%){n5$6f;zC2W@8+m_cav6+f4G%XS}EgKcuX;7htNQ26yti#$%vn^Wi@yj ztvPzpx)5Onp{0&~Mo^2MW&r8M$|iztM{qo~@isgZg$EV)Dc|4=rt^XFik70EkIR8S z(1_!!z4$zWu}1V635fHP|$LM)Y_8DCnE3zpq~o9ZH*COMgFr7Lp&o{0csEZGmK2 zSi^?#FXQh5-0`V~&)kh~=$*d>!HSKy=mnBofe1_CiVC%jn=3F4DpQ<1nn#2MVmgCAv2hT`YkS0r z<2xu;ab)bh!ZraSb2AR=P%KVjCE@G%3L9tN3zizw9GG2!{0*fdkX`VxBaoXfa|H5M z95i*bB1{C;+0t?7$)eCu2wQ)Q2*dr=c!i3OC{!W)4<3p_w~Q{}!iasetujB{Ia37d zcna2-9Sy($9U8L8EX4mmDg8O8#Fi)Y=O7Sb7GtV_{`3w8!=J^c7+|JuaP1RP&7nT0 zx*?SvS0T}G$EeA~Hy8k|-4G_}2guQJsL}M+`g*WF%8#tq{C+8Fyj*MaO3+`B=*ZKA z$LdzcE#^1OlX&zg8}R{(XQ$tmAHnky@f@Leyb|;-@R0H!e})ABL5b` zzaL@q1%yuoO0xqE5>MUDuQHvc1YB8$p#+4_C0`i`1yhxiR{r1dBRt z%*!)rI`i9*VxB+UYKHE?>|{&iD)LJ_6QABYthM@!q{h}+oLBq5uxs>ZiT{9-4+_F% zYe*L>e8pQKE=tBDh6fDLqQY2@z*HKOkdQq#v(?Q_I!@CO7)$5Qpv@(m&F%rS+8v*lxEhn$WH8S$n|2~MxQh5{Y3z*}n&iYqy9 zart`#za)RJ#IiR*e}KBjcua4`ZnZDCSl(p!mpYe%&={Y6~S2nM$#{hx) zI`~V0QTvlovf7_Wox}R>^w!4|53&0C%7fJB|EH&}r=%PtZ(ri}tHiTt{2LNmTTu*D z_V`GDZ7e{nhWLl^8+>0ZzsYTVKHs7Lb1bIB=;!_3{5&$=qfwae!quyS`x>gY+JnD# zJ$=JB`Y}T>o4Z7#-4+kP#qe0EK>s76=8u@mcjNCe#q(c+DW3l*`eic7rW}gomlWFK z_<>L+E1v%A3&Ia?<1=p5#sVkgA8_#Jux7uW^5r;p@awjI8*8_$Wn!W{tRQ>|`s|aE zj|Fwfn-GAKVXlS1wD>q6MVoMGeL>*EhsczYf1ulZK`eu~{c)*0WDl4A&yfc&DeG)L zXe}>M%w{??Oe+Xq0k~EEf5nsklk~@kHrj?wXu#hw%6gcM_i_9?b(`?d7km{&l7~5F z!Q*P@?}EAfgW6Y-HMjuga>?X<(Qs4jhE%jT@iin%;E1g=;M-_m9oAQ>#W~9%6)Jbh zP_WAvly%2=ZpZ9JNg=t|h_Vg-YBvo*BL}jP=r1p0ezNCF-hR6En_B&J0(yBJXk=GC zMC`9ern5dW(wl&f@=TY~?lWIdmiq!@M-p7Z)*x@*5#6x-l?mrp=V(It~XG!2NyfVCR{!^+R1kR`jqo8&b{g7OE@X0qj(1p3(r zVf!op14>MA6h1c3eXO-ytF?5{TH2tN?4hhe{b9CYzEex^LUL9b6zqhbk&es{E$cm| z)A?uzh;CX7T^U*8?4OyoTs$8i^S@2+=ah`qQ>C$9GKNRjReJa@UbMr1#+-wafnaUN zIR5X!3luKEzogxVkI?t!T-H|p`yooI&+IPF0`Z#XOUNqBg2fd3dkLIB+mzCbqFtS8 z(>EIQX~$z*MC8Ih9VnH8;21KftHU3auW=v=`!(dEWAd@}LY7iKdE_GUca=x;GlFSY z@BAr=d?{lEF@CPa-jYR2WW(M5ozfdnIIr-qtueUO)AhRnweV*Tl#jIk#hG{%fc8Zf z&U))E|DB*Z10){6{S!>KRTwT&hj5qwf}&6)a;!bxP~R3qX?FQrbEdZZ6toA<$FH<8 zy6!FBwX@EQQh3;KL)6E&*8ZvEl5LUb_e0?5$0>fgL5HO8JnU5+CVg%HhxC=gWv87! z2z}t!xXm0igpu_93qsq;j4^OCclAofFhZTj;#$l7Q?Mq?Xu&->iE(gexEa`pk>~VBw&pvTl(RIN>k3bJ8DjOL^|QyTfoRSg^sMH*&y=_Fc`Bive8+oT>YgqXDe(!8Y4Zt!S!oa5@!?eXS0;Uo6gQnuSx8h47zGr|> zP7atZT6#1~&(m6dxCpgmu@>GA;7ZJ<$83qQP9}@?O%VFt9t_C$h>y0;{Gz2#v-Cxl zeuTELexA_b=^W8JPD2>zS!VyG0p#;^`|s=a-zxkS{rrnRLi>j7ZnABWFSw0Q-2W&H z?eqoT#1qf*d>CcYz{AN z+!D4$`&!0Zj32a%vJgBXM z54D94WNA)ln=i;cf9wR8f}NkIB2f$`ZaruKo17TWB;jSYYt#mkw}_AK8ULB^GW(!` z(U0wrMw2+Pfo1rC{8tZ4d%wCF?PXphv^O`4@((^pdtEzNOtUv`2@%BRC5T6#+awLl zO-gl`d*VJQ$7EaYO?SobC;qVF|G5Y7=Q{XZ$=?QLP<~>y+8)o*e>tI*bA70D9=lHZ z&w3Ywj`G{?Ur^wE&;9ne_s7J)9~pb^vB%EchrK#rTtZ(hLhr*UbJKaycVY{N!4_iC z@1ZI9D?(P14t~r6ZjTkR{gA~w!EJlJnf4mXELXkzI2LPvHOr8@P4IEuzo-IfSUP^f zb+uoy1YLwNtk_)KU3ykRx^XQ9%B9Ce0^lLaX*isVGZ$vlIg&4S!NSUWn7Cjj`$)p! z6~u>-agKfFv+YzVY;gli>i@j+1*XeI zfMNH6*Qw?`1hw)P)@?qLj$=Y_Wg&wJwCDIix|z@|uDLvFm=2o@bxq`q--i>Z92UD_ z){j1EEf=T~E2@D5_+3GAwK?!_o<@|9o0pLT8I9-KOwxQMze8FB#{w zGSjWwuq@%u-_867g&)mt1V4^dehdPPSqwfU*t6kKN!7nIfWwSa$h|iJauakRvV`;P zm_HYe=?NGL11F5B;O~kSqb_24f?fWmT=F<#8qU#xaTQ%odi!zP#cR=3*yK6t02b9A zEpEWM6!0zfS$(6$o4<*9i@A8(pSFGAVK^~SkRN_w%a3&@h8UHbiRHqlc5Ll@wfo(> zf=|=Hg#;JDFQzammkk6^!-*6bR zvrBwS55kZvHI#=XAdhX1XGj@Hp?#r$05hllL4thrffZNz7y*YHlHKe&mme+913yZ^ zrv!eqfvHjXsH{sqen(x7zI=e+<*P>jvtZDtJmiF_QAL+WrUGr=VYXkb@Zq&TQb+sE zvFF#Wf`FST?4cq=}JPnZN4cX2?Xnz7f(`W+g z#^l?T6@&95A`R==Pank{~y;}M>~&m+Ue?h6-{8h{5&F&pZCKDP=3xR6@Ip2JvKjkv!2tpAeKgYAvUeB0+ zue7ssUzeYQ&OtjDqx}i;Ih-c2UVb)4dj`x)!N1}_UvHfQpF;WBSL<1Eh0D)2p$yjv z>r6gyfyG|}SLz8wDsok&D_2$SZdC`*v(XDO{XS@ z!qB$4M?vabC&-+IM!H`(>msfHDgDypa`0=u&dZk5aJ2;=6Xb6VL|^z7nXLXKD?6L$!asw{_C~BNN)s$#RTCvG$MF_7{8Fe>U3>z9hCED*4~F z|K3}@{eMz?!^DKu(f~NkKfG1NO$nyyQ0=erwocmLETR3n*lKG?tp7)9`!DshzYW_Dz9hCED&e%Bx2u06 z2`}ux33Ca!!=UbCA4aCb@-3P)7P^1_9441Qa*8EpR9MpIoPg52`8;R2)eM#*Upenp zEUGxC7*%6QS$9yluKd;WSn@%zt?Zt#U@;1~w62?T47Z)f1W{&M71xF&(~vLtG!(Ni zuq0VFRj?`!y13xCQNQ7aihoR5@8V>{d>5GCq1NGsC@N);)*$2{V|f254DY`INl`Q; z*IDDTM!Zc+%Xt1Av(YcS8(0M1-2@^Sy1JvJ7T=~rl?Djo-1t3HidyyJM#+soK-Mum z@58_ihFo+ef+DzofjMti)Wa$&S;eZ3Ri4d?EL35-q6ZiZS>73z&Rn9zE$$8C`U8P= z1C6}1zP77ZakBpc*`EjxgIV5J6uuRF+2S8*Zqn<|#y*}$U5-^MyKM$gB}B>+dhFZrA7`j&w+h@>sX6_y zsmQcFJmrhbFDCLJ)FcaCGImt!!q9*6LhBLWxiu$Lb-la3&i2EbkoL=77uav_PgC{0 z7@1B2>$#~WcQNz;!hD0CbOv`5k7r3!Xd$v5`;l9h=ujQ=Jmw_b0;i)53p9Y;XVb< zk5R}WY}o5vhVxZ4O$hdFhaCp)`{Ss>)x(8nD+|H16N#iE>mja<-3VTa{<&winu(c0 z$ETu3$g5ZadU0ec_DG5W2Wg#mCLTY`U>WS^`IHqs<>(g!FutM5odx1Th%QB^oF>sXw86m>xG;yA7gpWTJbcG zf@D)*%TSzTkH3-)3k|tvhdgoMtLSp#ca(yy=I9vWk{8YIcS=uQ&v^yEB{J z*`L*Fciwrrb|>Pz*`2?d1@f)-E>~wO%7wLcwum2Ss;BPKCCHqDLaON@W#_f28n_&o-8 z#PfN30QMX2F)s7{=ydDSyBlyQhu!kTUlD$6x^*+!RvTWzF<^A}!Em(U2_5*x48p*Q zJ+0nRa6ctq2yNDXur9)?p92 z+i-j>iAzH37h*1nkD+{bV5_jAMFjC<)hU@QHSMwO4I$~xUCFd0e=b#w@mqFhcd|Dh zAxe1hKx^O$EI|MrB+4UCTTOqwVf+k_8Ik{M%~dGD`3KDFIaQB=fKQa40u*DIc{#F* z1`qv&2u3YC!?(p+={FVxT1ElSf;>G4I1A^&qfCS6zx_(Fmv%3u!f5u&2#D1@W(?vdc@EZX zKgI~0)VmFr_{_s8IkfLLGwTTqPc)@BBIAULC!N-LtMMK|%OSjm(5OCorHgc1rEI(AZbT zA<`;IJh%#h3Q=Ab)naGPbny=Zdoo6~EEtsXKtb|KgiT_6lv`t_W2H#PckX9nN|Xix zSRMEajy=!w5-VvYV9kD2|{(!H18{8}^!+ijf^AM2lu2|RMBPsY?%llLA2l|4^ zP3-bh_#+^P8j~1%JpUmuD+wt;jzoDlAnHT-uKL|9efu(>!V_P|Q$aYqjDMInWEOor z26pe2uS*M(e3L!`HO2T_)%7D^`Sq#zAW({kXDLU(s+K<><@4#k=&SkD^`}6c!)^)8 zf8Tvu6?^M1GAG|EQhOeymZ?UmcxMeoS-3ZjcN>XMzvkK}q6-%RO1;icp$4wJK+d3l z=W&TajIUUK`)Ic4#rz?_7TUUyB87fifqpa9tkqLP`%B|$7>XJqFQ}c<7MFLyI8}(Q zgyQB7w>Z8#{$ik%;oU8q_krqUd@|HZkx#P8F>tE<4-n|UkG3}A$%O}p%fI%#FSe@V z-lHeV-|@UJuwIONpN;ptVqEZR{n=JfK4JaynPdQ;+~a&w5DKu!x(Nl4*ZJxC{tD-P z4qPjI!(uB-(9n(r=BMd*XD58eVylJcyHx$If&1Me;$yM31w*Om1@I;5ci*8%NY4q# zcPzF(_I$TT1g88=_q&gXkHywgp6|BlcMm6g$6~9*^PSP}Zg#%YYFTPsiZZ9)=daW6 zE{Ok*rPdkV@7Cyd$2#AEHWpdQC?J1V>ig{&1+ig{&Xl)e;u*h1E0=}=*_p6-uN)Jn|g(!>B z^N@b`vhyA2VUhKOeiWmpOuu`;`A+e%)Vj-quXG@k;(F&JDD6P&GCa9@*&pw-ocF3% z{jGNLiRg7#yg%7_5BRQ@FAlx~-XDPX;nB+u)@BK3$9UZu{HI+y58@8H)Hw@wsr{gM zyELpS&MvKlDYKe_t750eq`;&3;U>j0L$UnU16V9#_E@*e#o?Q6Wg=|Y|W=m_FCf}#5O9f-LOZ&ml@%Jv8Ox_cwqwza04U$(A1sFnohTC z(i<6CoX46vCe$=;c3kUM-GZ8qlA7{pk7##;4>|Sh#4-!YhHE`Exj&)Ad@xY?bCb5{ z^X{nU6V~nF&zF7U>bZ^eJTKkEdhC&sL*!SiEHHnW$d~3N3CyQTB*6!@n)y}&>Y>GVZgTyX(f-Ur-(FX~NxwHHEfbpZt?4IosBmy}hf5ug>> z=jp5s8{$~?0fG1I2Jq?|6! z1T06q6o=&kVkvR3Fx`vkWn;NrvGgaFz6n@vKOzpxP6)r%o((zD27X6@TN3#A1mIKR zx$qu=wqA7fiE`+*F8E0WxstCI$Saj%U-_kwftbXVXY12+ zG>LkvPb&T856}!bvQm!4BR*Bhm%)X=X+gvx7_PpQ7xSC&#P{)y2wgUwtzkfF(y!O9 z8>uZmt1DWZNiKN0ZXb5?JWk-pKyM|X#b)hw3Or7MH=hsSjYQ}Heh(Lldw?Gz@L~{Y zp0!(ZW%QxW3n(xHTZ430uNPZvaxq<|B zu&`n5o$qjJ?VS^0ZiC!SjebF#GE+H)wig#w990dNh0TDYsG`wYyfH)a5HZNLH0Y~* z|4!WZQ#{|#=J&rA#=ggVuPrA~$U7tJbH8_7g(D$s-Z*wwI@+ArlI*_^Gynze0Zn0Y z6XZ&v!&wk6r>`pt{w$0Z4oZhR2)bP*CtIU1=ds88!tlt{!oX52ry^&~jhqW%;@*C- ztQY)T7`PBb7fLDSCm@>Bs$?K83YTCSdV3pmSpZ=oy1ICOIxk(p*?R6#r(!O-&HQmA zX2ue{9ID2BH5hU`FuIy(Qh^o+oU(nvVo>gT-@|k>avB zPV=K24BErUY2nV(JQRuhOTkd&mUP6L{bmMH$tAUjzdyRpzBD)srI0%7AyBIGnp)y{ zZ#n>Z{n8RHnv0zJg1b>O(w5-rcC23{1wqS1HUS$^3&Hawb4!e*ra}_h>5yYWF(MfZ z&zlIAm_KM-l{(zFM1?9%Gt=>5QD`qtD^Qzy+D(TxiQtuAj{ZRFUq(4eDH%tN+>C%L z&vHzq86bRy=-9b8ONk~%%k@`_v|M#Ay7NZzy&~(fC(xa@^cQLIr0z7w!q!^jVDFVr z5SneWueHRwSqg(_HxPh$vr$Mz_OPX<2o0m~;M^a2rZhvl@%X3Njq*WT`vXqr%;#4L zIn^CO&eLEd{F#cZg@`A%iT@nr!u{BQiX0&>9RRY{0a)i5TsN8u>@w@Z_$8L)XK1{+ z0wQSPUKX2vBtD=FmEX>KuhM!iW4*Z9l58ko6!Q&ak4LKiSso|VQ3$xnPPbb?%%8x+~qM8;Kqw7Zzdh5#A(>`hT~91(mD3Y5>L zwSu-HXaJzr6=d>JTH2VU=}KL6G7z>jlV+i3%<6u^suk@4`5N)% z@>K<2y|1s{;42<#io9f=*P^Fcbb;10h4s9``aN9O{~x#=t{J+Nb<)`}gMnb-CDP;; z{ecB7zlsR%00Ok!vq-CnUCnU><(w2pULMNJJk^~0B(}KU#V>0I5W3?nqPH-MIg%S* zW3lw}c-(?~Wv%_yL+r=f{=wr6B8&MGqu^&c{zMpW%#hwO|A0&V@a&tY&r%t_NWqw2 zu-f|j<@>$Xf&Lx*iB4FN)w~B7`28oFHb9TBP0}?DU|ylcSd292xdAvYuUoCz=tcF1 zV(@z?RSIwD$pXHrzYEXTb;09$iZs0HxXZd3wL;!QzdHq&qX5re%CnV=C(?`Oq-=;s zCw-3XztUS6cM)Hej73ZaNAx$EPR8UNS9`&IDZq*_C-McaXiO8uv929(Oi~jGyT-e)`J8AlT;V^+(p`DMxBw za5`J{2~SNmEC?enaE!anV%&vaVIr7EfV7!yLE2&^?T3GXv>hNhu5lmwu~6aicOn$i z;qQxzV<2(7tvH?_j@N)Afxp)QO!+&KjJXq#60Yd*w-s=Jzt<9ccp?csNP=rU(tyiq zPc&yJ0X1iXfY+3ObYl3s65z2OW-Sa&UHs*#k8qPdp+$i`Y5t~J6kK2Vb11}&LPn-w z0eV2Wp0zR6=6WCaj))qiIB)I4HI47db@(U3^$R4x;ZNvZPIQ$>wsRLYI#eD$wc$Lq8UOo_i4pmN9Qc5*zvzVnU_Hp@3KC^L`?0IUGN49#6I!ant>tJZ_6wv!nQ8=EJrByNlAybL4RDM_|IzU$rf?zyD-4cuDsf5Gop`h ze*c+ZK(iDX>Th`z3@8O-65=)5(0qB~sJ;GV%s$xm7EO)W+nmO=ZNuu1m#*T36LoIMCY)f{=8qBxR>qm8yLL>$imM}j;S0nB4>uLtD9_5gA0 z!Gbfy9$Z53fr%vCNfKOpkOW+6Z;w|3#sYX@Yb79+7*0_Fy!K!@bfhkOPzOJMPpQq% z(TCz^xVP~0tJ6WsRZ7bJ6(D6INQ~p>B`?D@a_ws;(B<&6m*S`-j$VqR8*y9)90~l~ z5B>4*^C&(SOp&g{j!ntN z`oEHRT_#B6Qa&2lf+V&DiE(^RMfOn-pO-`596r|+N;A`m<2J?dWf(X%0(SzRCjm_P zJc@Sod4>G3H6RBog=mH;np23TvsUc2qw693ktH7E!F6W%d)eSB?CCw6sfxd67uH~J^ zy1${J%v*x~?eZ`h+8Ydr8||h2OB^#4$L}HFXaXDw{rfh+w155V z-;WjY$I}4$v_if|$j?Akf&$zNNc8VSg_uK#*A$|h5Yqq=M{hFeb&XheRxJIykNsPu zXl@~zS&HUDqUomzx^v9G@vg;E-ZUO%AiiWg$}Ww(uQ=xz;77d7>Uo`6hbJCo!e~1lg*h^iidLpk zIpgy)@^=r-^d~kdgNS(nFKSHDr5Y1+tdMs-_N|z2E0$1~ zYk`6n7;qK9v$A&y%GyLG$I6S5uhS_nwn`yxpi^rszY|Z+yAIZk@~#Y3W1fgRSZBI$cn|W+TX^1gwV2?~_OBS1zlNI#tMf!x+GRlS z{LQO9 zcucW**B~wgw#e&*>IW#qjKKcvLBL`N>2E(R3N4Bb?3!S|^nG+-f17^J&!b(A-r1Qm zQ!MrG#}W(tJ1q1+0E`IHg(+!su01=ae<UK1Jss2X3o&T^p@Gq3BJ21EvIt7bEZJG`8tI^HBplVQmOJc$q8DS73Jozn{juW-DAv8mniJ{2Y%z ze$MFG8m@C!Xi33fyJV>;MG5RI)@l7MIHkdL)*HUD!kn zYd}#E#SIl)xnn?7Dj*8;d%n(nPcjK@KcCO{zaNj*%=@nAo_p>&=bn4+xkAFZ*0h2a zMRxNA`lvv>Ca;Q99Ye%yHHl%aK<8@t3{2;Ad2XZ5G5N(I-UfFQK9MHLlZp(KxxgyU zUI{KSXcrV&L7h=rLQjxH(=M}OX}_VYA14We3B zYH*!~8@rvirql3qtFxVDwVn^urN)4Z$nWY>7wYfjb*ZuXdtF`XBK^I#E~Sk??=!)5R`cIxGXGi4(`N3XKljY+qCbD}d{g|27c?YRe$h=PPGhel zThDeU_Fa4Tk;Kz)-reNjBJj8XJZ{@9at1ecwCq>^ZX<_9wO{BMR*U^D|NV~6i?zgG z_1_D4AMX!fy8A@h8-A|FCM+|)iu2NPE#rzH9be`<&VwIEGy3HrZ|nEMcKr?w`sKc| z$uo(wfFAyXyzBg5^L5AWzt=yh;J?Vr0cVyp8uy1RW$8O496yz#^Ro(cEiQg_zU$1C z#Rudy4U{%Z*!p2c>mox0eTy6p0jMXt_X1;ec= z`y_P#{IW$8ht{vC9qfKPQtxWoGi_(Nvhz2lV!DE+^SzHh(3IiGrAg)t-jY9Y-7iq` z4Hs0!FUxHn&U{zIFB{gdzV?aOCnYP&7Txe9_gdQAn<-hv0|_knUoPI5%E*~w+)A|Z z!g{qxl(E>i`g{?HxI0;(xO2&H>{F#RE>T+TGDz&jw7hyn+^+etmL=aJPgf3Z64{%A zaAg&@XF%-5;b?!@)X$L%N^~&p9^8E+r^6=VM!*`~TYGFo#oX-1cT>8tt=$85+T_l- z)OtUWiYl{UPhYl~HimOrj|ydyG@yf~fm!AB?w?uwH~H`!t$;VcbwlICPSHVG*#WWM zOF!a=ceSAA=4KU&+!WNg$LdT_oesYJq=FO&>vO1Ip+BZqXzU$vJNG5hLG!4^8b1sQ z=wX->4Yk=_RB-^Fn-%$-gXg-u7VK0BJO5;)8u{6b+@DcL_Nj_@Ev$ks%P+ug9yht; z1{j|9Q_%+kgf6D3=G)Cau)aC2zX~ijX|$E>812%@PvbJZ_W)Oky_251O_5XeUwYV1($@&XsRJPn9S1m%{~!tmiW}-_`~3s=7qG6r|UMnRNK5XXJWSw4DDoyYzRo zOJ4J;7V25HEbL#-;fi87F%eBV+;mcn>dCSjUAraR>!;|vk@J!rH-?{XI-wY}raw+wo!yO=ItmW6-jege zWgAGoM7?vR!gCWZ&04#IKW>Wb6vi1Twi8}qJV6Jq497aKU9{gw=4ot3# zZ{IeuaH}-*wjrTFf#$Y{;67~juweX8X#8WO9j%Y#FpAn=;Wkr1rrc+W^w;LuCU({c zB`3OHO{IVo_U2hW9C&D%`)1r^FKS-iIw0N|Y06OGr^LpWwt+u3zPR0Y-*(^SZNB3t zm2=~C{?0#ae(!+A?4bw#5F1a4*87gJ@!@c6XiZu^oY^{Wj<;F0u5)9T6t`jMt+lnk z*kp(<$d~|B9-Dw1PLkT9U+afpxGbUgks>@0c%(V3Xo-AgQZH105iGMsNnGX=8{|-_ zbs3KLaZ5-G#|}#$tws)OY2tyPiBmJ1hy_iQk%&J7jxCd|flJWgbjJ%I%34|&5wuX4 z*}_Rd3n3CSCdb3WnmN|Dm#g+T{azpG)zV(qpz6Ow1`KkUk(+-(=?P}hdj#u` zYuNo=_-vCeUE9DT$2raAVU}6@g;D507UL?rA179pXIXen;gE2K&(^xhLD7&e z$_BMfQ9Y)4PNOe6A}Go>QmsNQ*!kD$L$6`!{WaR=Hd*(Ti+zQ|f(kE?6(3YeE+o?Z z{$(D>ZU6K@PPN=(a&bK9{#lc+yE@3leo5WFvRzOXldk->iEE- z)`0_=dH)JV{ko7L<9rwal=_WCyjH=zjZV-+Q;9kZi8tE!+;pBPsgJdA`qBP_)h$ zt?|5z!PN$HH+(Fm7vM@2=xxJ%1$+Fqxh9ayx}yt)UkAt|_!oA6h5R6F*~6U(O=N@a6k;!#TH=Hggaj zz~Pw1TzFY<9|-EofvGv+`+mgt{h-HxvYr+UhS!7qsO5+1WncAWEc@}{A`ZU zvSVT_v)8hWX?Zv(aa>CYKPhQoy}nX0v}9>jY;&O2qRm&toH)DWe!K_T!nu#Jw?FF@ znb&IfFslxm0PF|seQYwbgK!YfU>uXguc z?_1fORtCksrDRc6+2X7ES8Q4ws+~o5g+F-v${s;?yu_GF)OIrX#Cg9N?V(#vx@tGq zOU~#PX%@A={@&N_be8YtDN#-niJolf;%NX{bgNDbGToE5ytPOha&Byq` ze|ep?XWpL+$jH~o52)m-=Z3BM@Ha}is@CUyfgc&^->3$w;-lQ(Y-53gNX z7*^!)krX;Sn#^WE!%CL&-w|5o;j=c%P}dWhxp@x2RmTYET^S!unf06nWT1b{6eQ4u zU-5c)^KL=^(QmR*_&Zlj>aPl=wZ! zss`c$Dh$z>hM@1O6*1i~YD;OLoX%mNVtvlEj3ElZz-4UWBYo|gpJwSV7Ov4>$o1z% zz9DVEt7)iQLk!Dp??dzvMShyqRV5-9yGf@>@7L9C!dVCKMo3OY{?1Ns1A7Vb{?e~LXTf7NEv-C+1YyC-fOZi@1YPrko z`L#k646BS`M_ib1Y$Aghi_d7i+hDc_I6WdqEnh}i?r@8B&Cle6@9gFC;Lx#YoEcXfjXwA$^afz>S(<|<=bGEm*34=}J$ zgO+j?uI(5(LzBhn0jZ!HaKoS*$KZYb>NGxN$1rpai?*Umk9P}Q3%N-EMrseaC%{@4 z$sceMl|~-jmL00UhoT^$VHFAL4YTRhyH?eu#4tjWrMv|&SgOu`Lz5eVREBP;4_fNw zq`HTHtw3k{cBIF-=aGzVvVTVfI$K>G>sja?DYCQEE6L&PRF+y-b2v5PJqwd(13_Si zGOU7h8N4>R2Zm-dH>u>`DB$@g@J*v`s9rwae5|pL^ZbXFWT^ghfNRPsAR|5HC944J z;)Cx=C3CDN_AiD3Ilc-5AF_sN3$n-x-K1j}gZS-3Kr6F1_Y5_K_SbKi7@5uDv5c#?{gBSUUKn{8im>ztw*LV1o85^< zpuF#1Svb~}wSJ6qhqr!AaQmk}7P)Txtcv;98uq{xuPtX$coYYIEC`e?$a`KmG_Xlc z4$~ocfqs>1Y0I;;D&C284wQOr>W=x|YUcw!)X!p2T6E=<%bJ-5*8mxF4q_?CZ!vxm zgSTB*Se_;gTd65`s>I|1X#!8K=D+wUfN9tHU?a`3v^jSW zoiJ_nS*@g*%S7YEGLaleQ|AosrCz~Y&Sl>#KB#%@X;ph4cEz2k3e17@chrdnjv^`M_F z!NBLUAk?rsqikhrEI(H`1njb8)9W&Wj#uul@dtR(*ti#3UkSE1G3IREFXX4WLD27y z2W0e{hFILRz((n|T@I(@@n;#oICbSMJLA}hHwCVOk6k)0C?HudoJ@7n!Eg{cSq~-sq(!d z^?(}AGipE+W=)h5A|q5^O$t&X1D5T_!o_{hlnRG#J%t9`mT@A^G}4+v^}W?B04rB|Caq===YMv?{)kZK@FRoFml6f-c$>w zh^1ca-mT$XcF|+NCAsWatwxPlKwYtbBZ$wQ08mLg#CiPYghZ!j8DMIlbcT)`j8>3Q z9Gg=pLn8MSZyT&ZG2&v;qwdz0inX}hO7<^eBBo}tA#snt;#XO*h;$nBO^>BjiGi@i z@TlvwQm9`YyWiFm7@GH4$Lhps@O%K4k(1|)*t^_OxP*?wjG{ce`TH<{%;dW|c1vNS z{Y8PVhCYUgI!9K=AGJkO9ebwm2~}h6rs;3OPwL5ut~hTk3RC+zlGE~3I4p8sAA?7Y z4OTnJVL$(nsuX&VK?C8fw@wAcmFx%#LWx3K8ubQA)hG_@UuNg>8GMFdy%Wf zm6Zw2eO{HgE+=bJXwnIjx*nVD!bAPSV5@V7aV!;Mj@G&(@9~tc6L26P_&MOSJK(+C zIaabVwzXta1;Iny7dKkbhQSa(#{NT8K2lRqBvgZMKW74_ys8W#MzDp>&~R+NC(~pP zuAZCRVc`ypy{EY;)!Yc_nv+TVO3pMCYaf|*s=@wg( zlMHp}z!j6a7G?_z?hJO#S~2x!196*?YbHzGQFr^XFG`Pn6P;>>S-kHZ$6sf~>!sJW zOjfwC%%G&YY~j!U+TuZ`W!|Ur<^0UFcSwk5!F&ud>&7Sbeg;iEhaa z-6;P)G@Rg^uc>mEEkFmco}3$we#SA|YuU@AYqnTX-S6Nx_u$`;&d&|Ujwvgff91yH z=OnjIOu!^GTj@D6_LIDLi;4wXmW+9%U^Exu@8>gMRcu*O$x>R6y?9W?2{7 z(ZJonX);eOBO%HK`Aj9jmxlZb9(6kx0A^%6Z zK($Cd%OyC`U1=o@B!3`pEAK7J8!5&fAD8QHt?)#9t>!qGQn?QUklSODpU~rAs2O<> zSC-o}(dX@Fd6!DOqa9%W*x(NP&0$#xehrw-FPGuc45WtC38VsSBW={AB8B5Bh9Ih! z^Tonj$R8~{1mkr){dN%k-E4x3i5VTLKg7@|@B8>g1-$AOs()0>m=)PTY-Yei!)Tq$ z^rV=^Yn$j~1*=Mk2x~o-Cf76fo^+ZjJN!b&S;=?QAU(qkKb?KICPU0rjJnhW!h)0A z3WV}d{cpfUn&-EO1mpm#RO~3Z`&MW)_?^RVWJi8hsG*d>n7PnG8LFFtG=AM*Z^%%u ze({8qYx2b=_ia}Z-JD%@^uC_hCyr>K`{j1uqH6TN18sEBMtYS86tCMY+$ zrXx`Yxn}{$inq5OnVp~9$GFeGU0)D!xwyI?LXuas&`3rU=2uI*#LHu|NK5t&(b9zK zK62G7Zg1) zvnb&O`xa&qD}tpSY}D#M3w~>-vXbA7{R5lxAtGQNEH$D+!E~?let{{cVyjQ7sK;3a z*zcSCE3>$RLRR3;Vj~+&J`F{7h4tivimc=U7LNCK;MoEj%!ZX9qo_;3aeUG$0H%a()A|=U*jVr`1YUL?81p(e@80r(-0-=g zGWXJYZ#YPBd@Vv82#^@Egp@W$_9+(MAcy2|8Jcz|`ib@C2j8|gW(lRc`9ZH&FrL~` zFBhnEqW4w1bEpy6zi#>yX;pFIC_vCfY=4576ZL}(=S^k3_2ChvL2vnu@{ZkGYB+K;X`LIb^2knMs6nGW5?3 znmL`JC126HOwWa7CZ8hd<(?jmtIx-luphYfS+|kJ2LBjD@Tc@*#I%JU1LNlu57bMs z&3vdphe#Jd5;yvVeUAnbrZDWGxFYsRc;*}F)2h%N3pMs})rlAVEG33Qzi`5Vq3K@^ zf}?N#JkjYDrjf`cplftu0Fm*x^J@sazUN#4Iq#d!!sIZT8Hs;`Er+i`vo_qrlv9cT z7!vNa2pjZ3#g<;2fey;gDSU#tZdKe59q)CSGf3rhh+yk9S*qOy1hmOrdz9B%?LuJU z(Za?wZNVYdx_*c7+5l2$O-m|7Bp?dhfn-&%WeeY3oxP@2AJ59J-8qaL43{mcB@}pl zVS)P9VUzaIfS!kmL$ZxVid-Vt%D+VWJ`-XpXekZ^mjosB{Lq-t<-R?dDdsT`57#`` zNsnTyAHBVCy_J$#!b*HcJ!LCFQZrw}FRF}v%g#YnCQZ7f=l=Z7b_bm7w@HU@K^DNdZVA#vh&(XBg$ZhDsT8$&nv z?)h2OsZc~9+BRgm!$!yu!~XZ$KuFW)-V z*y=Nm^BFxc=94iypVXQAXz0^#>13Fh-|47ZI;|n)W}i?|wlZ{Uv$zb6{EKv2KgKuG zooCmB4EarvA%hR_^uXCC$k1kqjNg)x6_5@Q3QB7qmIjgwb1#9jvS&lVT>DKcABB4r6y$0IRp z*J>)xl>O9GM{rTrmiY5Tb2{&Q>fE#=F5OpG2na9lZLwCxkCT7suRID)L`Br*@Urrt zSXHb;Rs4^@CWk!Ap;t@S+Ak<~Vr#h*(3Jnk=I&BVl&uAS?CTrcH=`hW@^J_tc`AGH zSpT8_DY5jX$S|-!i?MTrD3vY{L+-KnynC|_wwPnXh=x-UJE1Q~JSMuP0~^u3S49_e zNdDb#%Sh{Jo72C6KEYR>JOwtFo-Sqz*_gbJ!Zm~9C&1M)!fs+MigRkO;xSw;iPAD0^OE2g6#GdQ?pRU}HTY`)XKyyrU+$*Rv@9Vs z-9TF{?%$Ca%}=-Jr<^5Uf)iC^rjHFz%$Wbw@p3-y7mnV5$NO(9V(;_ZUFN z!I3Sb`{n43sfsfzV}xO>7*aiI$)HiF2WBWaiig$CIlCRmJG{@(5|7aww$&>Dog<(2 z`0={%2LRO`fPny@-v308>E3Th_fEHG23GpDK;a(4i*1L_g|DW8ra=mI8^xoaJs4QnCtQd1m4FH z1=k^Tbt>1u0;#-#pJB)}wP|2^r`p4vJfdQYxE_+Tsbg+!UnyQ+E|(EOy0B(_Tzb|Q zxYw<0^NO_Hn9SCJESTcrx$KmPC-UWkskzq+_C&vF|G0K7Wr!}!F`-CN-_31Kk!C5-0S5#jbX@`Y&qcHPMUR zl^CSqPmzJ{?#?#kk}nvt`DZ5jJ^OctJPlN!YFy!mY%TzUx{|~b32WV8x=KpB3igBX zK6bw3_6eF@;_zS*lXn%&d|O#Us{1hn}Ro_X*=2iAXi{|~PV zlZD|~@}oucWref1iylMM_X;aEcggZ_=pXaKW!r1lw_zdPG{9{Y@0QFh*t&J)s*XSD zC35U33q_8e_s#x;#5fysmlMCaVN>lzE&4e0SGQ0VS}4emm-5^*BdUxA`4N%Z}_^5t>fg&0Y7ZQu_&3L+> zl`J9JkCMXmFMI1`>UvbMufwC3yHAMSr0o63o;iYldgo`y;r{<&q$>zij5an@qwL{F ziNI>=ett+v&#_f?D3q;wpz@IO^>SD`dvH$?r?L zg7z}r>=0d8luWUM%pfN9d!|K&d9_GgaTV_Tss1@3_bvz&D8DxQ%mS{%INjGLWmlU& z$x%jRJfoBh?uf3n_R?2fq_+rp%O57n?4s((SL7Ft*lqu+N?TQRl2u~~jx zamac46Q3!VpHThfh;KO0v=s%(9<_xyn-kXc&Z<_F?9~Lll}~4* z+>hr;W#Y-jBo|J4U;KA`@#snmo%i-4g#V2$qr)~vOF!Z z+r+m9ylsQi`Z+6bL=WTt`M3(4?te0k+*$pUz(D1e(0K=a!u*5%i*YLzi!af8{9$^Q zs&1WFrv_T8fx4P=pcBk?Y%CP5@B87p9yr3BU% zsKB@pV%|WH%A=8_5tyd?8q3$&|MY)uPq_=WZI!0{$B)qO{-}W``t3iLtCbgR-->jQ zjf$7bUbP4|Jvu-{zR?V2Tk9u1sc6l0>q^-S5=wRwjb)*iX88`D{E!Z&$@oDm=U3<; zR~@XFo9!P$vkqR$X1PdJQxj>pbw34Z5SlR&j`1V6THWzS(~2l~8}dCggJraglOMUQ zC{eDh|W z+7 zuNZ{mdouDluW}FP_`d4dTr)%U7XX=LnQto`kE|BGjBfLSVIbr;h>)Nmh)E%oL;iD=Hi{S3Trfy@){9N zv3u%R0T~>;?+e8E^B5syf51Gw@8_w<9B4i9Od)T{lmCm&R}c-_<|`-5=1ZHFxiXar zQ?9rV%7(sV3Oa}nadmfb{&uMbd3NkD#WioW&hB`h&g6E}j=zJcdwJrT`;R;H`RCNu zRPufF3zI*O_;#w*&ZD#=u_SpF_vyzd{Z+w|=vSo%Z}$!E>NxkHi#viqw;3$T8u0ag}`Gdd{Xg)a+DdtL2&VhWM38H0o^%xHSwiUw-eZcUb z_=R~@b-xHTp~?6e0F+0q8m5U^0L!}wHK`Y-K>~E~4GI1s&eRK{G@7rD4;a?k#aF#E zx;T;+b>NSIY;pD&Bp3b@$C6eRzrKLhPo6zBHG7j#K_~+w=@_prywl4rs*Y2l7SEBk zPt~ol!4t4AbFHcjAS%uRni2e<>-^I(vt*8QWF{pIqeHjbPd2$TR)WNodW1moTt27` z*a=&2L;WIHL-J)%?^bQGD)p-Jcj0|2sTuO^WuHG<`D>JaUfcZpe14_!zgGV7ZS$}7 z`Gv}tt5fn`_4<3Cx|>qJBNZw+Xcl^yZoz`Gz4&dYszS??K9V55S-YDEf zCowZ=^ld-^)@%xO1f+=HE++w6T2Bv##JwOaA+Zgm?3Y0)^?#=cw`{YaqxM|@`xRX# zb>P56npTuIyQ4vI?O4~%Ko~GG-T&o5|4iT50ER@)*mURj@?(e2AIhMi`aK!AJI!~# z0TxjO9j^mRWL;KvBcM8CIZusr30J;n2}nZ{OD>hG_x8}h{M82F~^cZ4{*r`UO5nB6e)PlXb;wc7KDfcM0&lx||$$r(si2qvm;aJx~x9dV_b6s&RttbWB+9~cnUw^df zpW^X;_H^+6$R@*k@CvOhx*D-KRgPbSLP2Y*gVtuB?T1-FMKW{Uod;`(eG6xw6O3Oi z){&U3Ov8PU?|0n_`t2*Yy9n+n7%W5eok8-MT%=$AlGO9`ZPbaS?lS98o3U?akD`)0 z!a90Ei)Gem^@Xw(e|eJTWDm_r+=Qu$|6awn<6at$8<+GY#T;jiQPvlnX|Wj`i!RNg z_-59HN_^8NP9PCR_sy)aN}S~rhmlyL#EX>ps3pFzg!X*PjcWN~WyLJZo>+3%KcNRk zUVhGseLMS76G{K5B$84^ z^y_Ur5Q1lx;wPlh7dN$I))b(vPV_tEMG^Q`_g6geX8l=dv8{|phfUuc&+uaQy zx!AqTyMt({qnATxcf%qZJG00=jHAB=%xUy@WpPHIwVdvwoHY$m@ z6JJ7Zv!0_rI|s24NhR3Gm^hUH`;kH6*waSdpvRjA>?9?yYq-JR8=gOY6S$wD9q_z6 z{cs=y%-P6~({Hk zZf=0L51*s{LFxL6#q8@Z|5wJizt~{ou2#JTHg2OYZwY(XhFt_pXxVn_@gcav9rJUS zhZkg(I`iA4-7WpvZtlB-g)1Uy#QT7r zP`y;RaCCxfAcOc>6+aUMbAe=yTl^i`jj9LtHzC4*{R6FXD}cW$wN}=)I^0Nts8|>1 z>G=FvelLKt{|2_tLoQ$gw0^1WS3~vk$C{nZW{;X;6@^rGZ+&Yx$zKLeI#}KYw+cM9 zQyy>D(q}q1AoIJrZ+K-4(b|=HDaxS7sBdf8>$DZTQBVQMF7De4B4isqmeQVTr?<97 z&jWn@TU39IpVw^FKgHM2)MvIp;>29>{Gp4lH$?S5*1RsZ^s4wk1Vj>ZgK1}r-52&a z+M*-^1w}xtR6=F;P97yTvOK2QTz0Bsk0{ed8M7DoTJ?wf)*H^ge2xA#dN|MiJ8(V% z9PRY38sPNmMXP=R31K(nXr>2|o5BPUGS-lB-h`BL$ND~s)rT&`K;u6?OCSB!N87c% z&d6SC1T0pHo=nO`PP6qHfuP2RtqUtMW{O+2&ftG>DQzF(+rCF_e?gz^*54FsJFq`K z;_F?fdi(l%7pUIT>3Xf}ZkVrU@2t1TUo$mF*Nv6f&0Jd2<+iH+x zv9}M-DV#<^R^*2G&~kb0yu(L0J~S+DPWa%^o8jnIR;Pb+bmBkq zr~Uj>3pYzJKep{{XxSMD`*s#K(axi^la`NteEKs=zfb92K4MCgb-tYF6jem=nYRIB zeMNSa0w+fbE6uu6HLtmtVpa3LEhS%P$K?zYgS+t&YR?Oeruq((gaIF`k8xTVtfi!v*jD+!UuvRpE0^L+ARFlu^TV&A_7 z0dv3oW{0W1Py8fa3!hx;-s&Zrifpnuvw0V5ni`6&p8Kp#d-t7b&^@zb3un`Ue=Q1a z?iQLzZe|OdmS4j?G;C zlxf`ifF+rXs?X^ql}BCCsq(0^bB;Q_OZm-MOhVJI$kq>zFt6yKAB1(eqGKgLD)luW zG(A#SRDRSIJ5}C1qHv&+PE=9>NuBj|lD_i!%GFm`UwM4(tgkA4D-+eamJKg_EftmiyY{Vb2eS~Eo7iSQ#@G>#|BFqi71zxpx^ORM*8+v z=z6NlXz$wv?b-`9Orr?}9jKR9Y)|-1=7-hSNf*(G1}dNgHy}i5u_0_Yb05;Ck6%W8 zcE!AzAV_w! zVF5w&$uDQ3@KjOaH$MdMB(7?#*DpkAPSIb^j-&HE;wOk?%A@OHcH zLp3qk0_swpgAEqEFI$`z8Pq`}NUoSLSjjy8pM?Q!VSHz`$Ir;C?sJE^=Y^uOf9nF0 zEyiB&RF{1ay3s;=!%QkAuc9-P4`(AEPR~J3>?DqD z0wNF=?PbJ>b~2)KC4Amwgh>U-h+IjM6I(=s1VyW8kf6vA4etQ~qM=195E!EEY}Y*c z?|H0Krj zfz)`BA3D-8If1C*u{Yf&5U40jT;>vCA~$5HobrHgHQ#P+!KX!FMWKfG)rQFv6CPBT z=rD4p1)9+ngkH-{0=ZMH5h*p);BF?3P^KcbC{pV7|IEfc@)gEClSY$giDGv4sV6J- zS*6-L|yWl~jxDALCEEP53Q4vWRNj!#@{k7W(iN@jR zAU@qL{|vaj7bZro(+eQiW5n-oSz{o*F^A4|WS?9Bzjs&r)EP?EC6nZ{N*(D_A5!W9 zrOFRJLpDgiPRj?y)Rki(%3s_4f+T8szmTF4@jtV~9cLLFTfT|!7!Mh1>wrBB9&h$d zHUwe5?7Z?M!erPE{Bh;C92v$Q;aZli@pdkdsPNBCDz(jd>z~(2M~b3@S`RB_0-uoO8*?zHpYECPiA z`ej=x`g3+5@{J_df%#n(ATb#!}(I!je& zPhTgKSu|2d!S)yCx4F~i<=BExt?zZSX=j7vOkl5j+NZy(^o>dn>~**M^f^l3?E5`k z{oV&Wz?#W#!h-dtV81@x*Q-~(4t|V#tKKMIFZ0kdk9ua#GyT`st5&^V1c%?}r|AV^ zsav;2C}t}&Ojew+d@#!xdCO4(s^p4+kyqCc!sge0sHHA5I@yokAx=Wh!P$>EXt5s$ z#TE~Wy`hQB4b5nZHI0$_#8M|YT6(Cs8rc>dIm{(?&0o1(#|A_sZ5=( zJCSzBtYKHus-oL4Aa~>!T3Wtav1dm4z$~=g=o4oWPSOiF!b$Z0_&9LY`8IQPsAT_! zjiQ|7Lv|soA=ijXt->6;FB0m-ofdO}U|Z<{I34GO1Ow-ETXfdI<;GJnjjfpOO=Ar@x)t*qTe7Mu){Uc{)rNt;P*bCB{;lo% zA6aGVBb6TP`^{e1c4FPHkJaokyG&iOe0%2kmHYW4gR_&`>Eq#?bsunc6r3$jOq(6< zIk65Q#`U;uI}j(c*_NmGsW13;=1ixZ0S2d==98XO(n(5s#3g*vok}{5B-ji3ull>4 z@wDr&oc@|`ZNu=h&WvptJkRA}>x^yTY?0`81>*X!#rb)*9wJACW^8j)ky)&-NI_`E z&n~=&eR#uizBeqV{jbE`WLHevi!=Cx&QIYB`AiCJ!3%PYMsSoyQv5<9asx#efx?{$ z48Jly-7zoswNS%q)d(!%W_QwlQho*T5GSS+JHZ?}VJX2fvS>?|+t~wd3nEnCOkMIS zRbtVWZ1=j)<;oiwcAR>RA6uxtkrd9pJ5`sB%o|e~yPmMiT+NErW`&|tjYdx>4wrQd z-KeXDXyPd^+k$bSJ+L?D%^=-Dd_*2+5*QkAY_J}gM zY9-)$H*bAjOc!^s;2~#p`u^0eh9kc&uHVgn*t#h8*o*90-EpMe4?vq+BlctV^)KGD z@y~f4IPMZPCHg&d7xU5#eC_zx-C{*l_xAbB6II2t2fhs8D!4t730>C!y5F#B<-GTC z@V!5z{)@Xc0C#s@IV(~Z0eJAm0Uo}d8SrHbzEgIDZ;P1De}XS?dPE<Ckm}esKCzqy-tZGutLnDv+F59_3_wf^!9tOS zkqh7rwIkeZD-EZ^1oHstBzv&`^J$ezJJ#z(Wp|4H8DAhJ(oQ+W8b{qiftWrDsW=ZO zJjt8TjO+8`1G`BwGW7&f4bNL!5Z<}TT?_e$6J8A~kST`<85Ftl!f^EZ8up>-;-UJ# z(5zeku0c5cpFlInL-X`hp!pFffhJQ+dzb~9`~$@6^}!c>&FfUN4>be-Rd=6HAFcGT z()Vdg@7MbLO6B)g{?BdbT^zUu$TYxi`WU7Ux02g3t)pRl9G->hm!TV}Ts|4wjT%WWZUVRJS(8W#CjysKvN(KL5jiOw zPb{&F-jRVi`rqLG(zdbC?!HQELr(+^J;z_=-pyYsYB>2W@~2Et@>{ekuUrk0OKVL* zd|>*R@}{@d7#t3v!IfoKyGx+_a7BT1D2Xgg>O_H8#1nLj8uc^Gjo8lSgpffEova{9 zCV~#MFGZ?J9C6O=oJ@8lL40#v2OWYBq_+3&vEv;m)SMxqWUh*SU7Z*>j55PqY8#C! zgpFK24FuP-gxLU?TzBJ5+rbk$=60QD`eo9pOeHtItAZ~XlKi-cU*N9anQ_r#eGydY zHoR@r|HR*+#jSJ!u+RR*WB*?(Yyq^m+?F)Dhs1%@l)I}q4aBwv9Cx3f84y4BbX!2( zFQPg3Vr%{Ma=w82NuH8K-_+S70h|`QKQIWRzvQ*rs-LHp5=RsP#M}=w=0x`{v?g*G zwPS;MG}v6{dihEl|4gN?e5LoE^_7m?vC=B7?38;KJ(xfJfIrzsxcFkZb^WYb`Np?0 zC1}ObK|57#s&D01TJf{-F9Pl-e_$!Qdua%`2UB@&4zr$oT&eXwwVzTon@I&@cbEB2 zOVz2iLDbtP==3Vzsq_jn*`P4TudjiGW_MFTk;f!V;X33wv&J3loB#9~npe={r0x`C z+6!#|H&a9oN9R7L+e! zPt%T`pbPc^aj52t|j~E7A_QB!oaI>TNRW;-5$Pyr`5o99+2g?0m!dBAepSa z=^ZHZO7UsVf8VrmMO5uFsu^{(>LZ-v!5jOSmw=>B3x_`XNcJ4!wrS@4gUx5KFYW%s zMOs&K(o6KNJ5Dk7wT91|l*y&ajg>9lz9F)!nTyJzY-d@ z@wlhn5W;dIw?e}gSu5T5f9k>Xez(az1wz}co}nyDt?APa_sb{Gy;LV)5I1syo2>u} zy3O_AHh^v#VDgZ^UKAcjf3nim*_?KN{mBPY?!+DY*vR@xJ^)jJV!Anbgqi%3RYNJp zbleRjSI48aF5+>`euE+6P059kEx0|a zQwDD9ar^Oe?`~LTxC-+o$K3Nht~Nf=imT*XlnnId!B({UIn; z<_vQ$9O}Evb$d^epxMfV$mHPHYlfit6Ub;?AMU=_ZHT`IuDQqiA?Dc-xrZ*p$$gBg z9XW)xB2%t{9{KasL^$bpk_I)_RQI?41`0-7Q#rfYaD%35c5G@Ji(VuAv6r=Vp4xhp zw!#+U!$i(j(wMyD@h!9BUIS#w)VWuBfX}DLmMV3) zQh!IPt%l^m)XLbw|Bw3t?W>`=NP0i8OtZze-w)g%c=*zOptQ|?AVa@zbH6#bE6-yk ze>v>PtTRj26WHJj8D}~BL4(^AIZx>6v5!4e^E?0eByV2k)UI})Ew!<36~%eos$b12 z7-o{u+73wTww5n?g$U_A%c01 zP?_j=zh2qxy(7$@!#5D30Au^TjZ18_>okWiQL}lW$uAjK=CTc?B`$8l-DS_ua<#dg zve1ybW=HmmsSTE1w?;rd0+7RrPRnVsUIpy}4KF>ji2XNZcJ5`v%I0Z{Xk$LZ>JX_4 zeszrW*W9=<9+>_DMs^Q|vGPNPaT&ui)H@PA>i5YUM)?l@yaqp9tsVR?@g!$^_{)Lq z4@Lho{7+H_sI$2j7Hupt_z5FnzdA-v3x1^{18pStHyK*be4LR8XhzaSBYBh&+DO*6 zjO27JUq2zO{3CNWE&b&`jOQ!-(%O$_664wS>;GXqivMBnS-hu}@*~pt(Mldvzz5cc z`NPQ@m@k!N?OP}ss7AZi{tADh(S;Krh-yk?xfh9#ZgSX6wZ)RqHC`@@&5bi5j#~v- zk%*P|a-#S9=ZaTvs3xk{G_~;@C##ul=>A>04Zod9%XHn!<8c!o4xdc|jqUy?*_1a7 z!t!0@#!3{l;0YXzd; z{tK2{=4U28vuV2cU(e5AJc<4{^Yilpo1aG?Zk?ZtS28~xnYVWH^Bik-$N9lKzl;h& ze41+i7R=4y+*I0X-4>MX)gSxXfpsMmy72u&Q8MOOxCT81^`d?IV9~StLMQBFb&)1s z?}LaZuFLI=XH9iBf$4NZ^u>*IAOpmODl1Pv5w?ZRTa3JsDNXl5kd^tfI}4aZ@6#Eg zMA1Fm0zee~!DTV@xmDH|_pK4@6CXl%+-0E+{NfD4oBg&KJqXBDr%`P*`8Y8p?#C{T-{J11P!s;uzZ)x zBvvZMR4gPGX@~_I5Wz_Ib0b7>T?P@H^B_c!Gk*snc%B6zC&zm+ZO*Q5o%dY? zz<-?gH1WMltE%1e0QDQW*@6hzCF!*;*V01uCeu)&HdYAip4D%QF; zf~?*_)ips?PZew3vq64$<$J2&y)vGSQF~b=3MOZ`Ac`GxEUMtp@81vxZcn0#0(ViG zCcgDFk>XE_ep7K4_HKE}#$NLRHMUq!YA!Q-gA_)0TymQXvg!Ln=xUEf7fu3LNz7rb^(W|iteiX!_6(fvKx#2! zG_-q1UyjFAO$8`m*Hqy8ePLYqwqt~Ugzb9wGeb=t%%>lRyLPVe--Y+XfBy_si4pa4 zZ^41*jmoD663OG zePQLhfBvR-D9gp;&0h|QRL?yepzvdM(G`c1Xm6Z%Tr3gL@9myP;`R9ttsYLMbD48usa!F~UB3q&~;i+Nm3PAdHYEPtOP z(-5iLlc+(Wf6Y@1RG$ed6xLfP%d zyDFMuM6{y1ODGsFTTr_qd0-2Dg=Tb_2{sAHgxbj%LJj@N3r??+PKjU70+2;Andzk0tex46~gLz&s$L2Zn z9CRG4Hu*Xm;x;?f|Ndd`=Gmn*|0eHAh>>@~1VdmIY9~A~wHzvl531zsP65IW;-!)J z!18d}{Hwa~cB-Z7@e$pU;JJ^);mfPy=b|~Rs?C>2YF27FjT~N`xP%SyaBOv}BKudD zjmoQCPYqb_&)KJ2_upa(nuh=X>@)nQG_EOpm#k`jE`w`LVep~) zTPPF6bkt5Rep)Gu_o8rouYo0B((sKu+nT1|Qxk{FmYsESqSK+_IEJ!Sk>WP(A(bGE z*_ToV)xq_oPf^d>s(6oz_^G9;SEbh$o775HMcJ||pQ&m((M*$RuDBp0-kv6>kM17J zQ7wJ<*mGeai zVwY6LPbsa8UE8;5Ksgn%k{cnw**EeF32`dzyqeE%cN`WAHFB_dn+UX~a&-WC)L7&? zI8AiGuxtxnI3+q@WOm7lWIq^$!E3B6Jx%HP(cs-4xQB-0rAEN=+rT>?8^ggX|0>Z0 zV)AA`Y^lF-cYm$i0mA^-&N?v9Mt{n?dUwrp3>l@lE*nsD)t(+{f#*CN0Dd1IP#(Xk z5{{M_QjA8}?fq(E4Ev`@7}M#T1;z%HhwtW%TQZxN{BXR3MtgZ6*Tt&h<)FN=_FvVp zi*uXr^LmWBDp@}~9Pq{#`&Y$Gc3~{*&ukK0zfQuFJVn7@tYdtDaQ^lsecyJm0hPY< z<~q@Jb?i_>n(zm-%`4OWqvga;8cF@mZLs(5Pr{x}42QE?Jo&&-PC_d32N@C48&u

    AFJkl-Ej=>O?N&y-m_SIU~j9>iwP186p5Esq~6uqZ&tOc z=(o9q+)mZLL0`c|WAjGHT%kUGRWRq$&tyabqVwY?segjgFGA<&YG9mVU~FUqB}mfz zDIAwdn{{fuZ?Vir`B;ty5qZwwIS$JYAdz0nyDS+Xy{6%(xsSqAweHy3_;mpy!M1IJnrjp zT6LarH^p9qYwz*}Bv0_p?zq70uDrnAu3kKY_-W5?O<6$Rk`?Z@7topH8#$32?;F{7 z2I^I7rL6zCzl*>8ul;q&=x_fW`&%}>ZGW&T+^aZLe!ZH<)M87}5AxEZM9JVuW^T#6 zH#}Kry)LcYOOHJ5k&ZAJHK!;L%X({9XR!QkWk zF?6|Awc5{t=R1I@#9hK5`FxytZW$zthbQ}euEDRW%_9bTZI^Uy`bYik>O$$RW2@=; zfE{~&^CcU7y30y?p!vHh1+jR4aAoX`ASiTr^Jn7@v{SYv;mvEu5$RMj{-Mwln~#3D z`rKrt;bT=T&!HI{e%3ipjz7nIOR59GgTT{n?A0EEG?Dx-=KEJ>3Hy)qwU7E!z-RjV z&5r$j{9@br{$J1+=Y#)+o}d0lYk#lOcf0Xjn%N%SB$1oGX!3#{9C3 zONanb3fWfb#rr(F59C(jrbO}q@kGEpO+iG{32j*!Tt%|+L<`FRN1-b)+mQV3bO%7UC zL?|ICA|z4cV@w`=TRc?@O&QD^#Rd4TL2(?!%|3<>y4i&dm{7fT(fVFuV1ydZ=R3J8 z|H+W2#{M^l<24+nu815Fju%%aPEJ*ZruV2$oXEw(Fv@Gz!1@)}^r)!YDiV%d&kxaK z<1v)>H$Kue1iODSa!h&M>*<{9uo`NB*N zO}FYDsM3MDS1n0i!KjS>5rmASQLoU1q+DX~k?|)SBRLkDw6#No__i7QnP8C=gbDU2 z`yo}i86|^1W+$Ep=v#;>YC^AC!e4C9j_fpPVs_Rw`@pT;;4fJ;>6vNXC9PlB8Y@t6 z*LrZohAJJ8Cd{5=!qL)3VdcQ`j>g((2vLI22OM;GL6#P~-& zCFmb{W*M-0oqd~12=ZWMLA|HXldy~`A;`;X$$N`fPvj{f$jfiZd%@=^A;_D_Uk~T_ zM-3Jw=pV2=p+5%8>wmR2m7ss*HR_M$r4Hs-Q&b81N8S?svAm-RctxHP^pCvd`eS*= z{=xE;pnv3jr$3f=N*=$OqDs&|^492&<-IlfK;9^t)gya2wnM&EA zGz*!>R?q51*NPgNvygOPn4+Q+gx*+Aoo|W?6cH7kEjI{oG# zz1X)COQ(+u(#H;m1YGI`4y1UfcKRcanlLkC%9yWMB19WkQdeN=m z%)j5t&q}A;gpfY6Q29A6>1!Cg%5NEM<)2KKHzFiG?-EPDC!PLWP(D{)_TV9%es_?b z_dCdoai!BI1?dwOdc67c$ffG@U)XIZJ2glfrnKj-fs|r7u^^48Bdgsq7$9l=g0y0# z&AeTACnChV<3hslrkt*K^v+`FDt9L3G+kM-oF8uQowdN`^JZBJsMmNJMhaZFGUX9u zz|shb`|d)h+i6rKzIm(u9FEOUnzb2@-Oz^i();B;YGhNSlk|4Ac33z*S(QYGd$w3R znk1xFG7Cy#8hMPYP>> z5nhH^(%(B*2pg;2tsFh+@8VPWj`vIb1>!&FQ!tw7x0>JKrX0r~{c~TC3@#gk@3g)q z)7!$q*o3|YtFMOn4;=hktx{LQy<lpq{%b9spz_!qTTG{o2Lp@*k)lt(yr-kG8ZUTC((!N`HB%7OUFNO{WVk zH@Ky|EjzVStn@xD>G|pM`r(d#Fb&VlbieAzT|(46-~JQnbjJ_(LV<9iejC&2%awi# zVTOIWEmQTY2Hhyh3oEZ;2LCjr57&hTOP5Hn^qZAF>O3u0wZF!vMsb0DdPe9$2xp;!y`|R=`Is9Q$()twx7!p5{K-|O z8~2NM-*_8KWkuv@3Yfhs(eHaw+|9l~&v?$8DxlX|5;qMYPnkmqK@3Ay) zdJFHcSSg6V(zh`#-u+g!u_7{tf|q+JZXv}T}Chj`|rsh|786sTc8Qe($hQa*xaEi4lI}oq5Al)2U^i1j^+=hgSi&(BghoK;xH5XYPHZ5%G^Ge=RCpl zz$W@a0Z;V%@)jDM=({^Cp0kusnm&M>#mae%oS-|s&k=M7-NbVqCZGOZuo|_Wx9d+s zzeGgkZUo7&|Fh!8)cG~S%c$2xJ@E4%UKc}H?Y`OQzYh%ajg*-EK3xaaEIq4n09FA& z?>~sx8*jd;%dWD^r}f43IMvd$YqGPN@68}4;KfYxqnWVXQCggg5j#42YICF5kR$yt zBD)tWNJ7Q*g;F4IBWYR<0{A1_~0lr^Jbsgn@eJr>oEU& z|E6EioQLO3i`HUNK$0}x-zlCt;)#wpoi6ZecJaLLwPwTdKk(jw{ccLFoT+Bjm{-Pp zd){8gyMPL?68o{Wby~K#G0^Q{)$wr!y5@>ac(pr+_AK1P=e8~@QtyTDZncMnn;KbW zspjy| zLtyaW{2PwZ2JBeSEU(Is%-7jH_L$Y~5t^m3Z_lMcye29}q}FJ?4Y$U0DcY~YHuz}Y z@^6Bc53P=KS{2~qWHsy&Vk`x-%6EbPL~6~H;U$e}XA0vd|F!+ML}(y{_Q&CbvkCqV zG47eN^xPGsQ@D%5kS&gkt4KDJ(IN#mi@)(F| zMRo-}SYOf7tlC#lio6FL4+qJKY^S;3r<&IZUMPK|b?-RM5OVyx9(vMa*Cpd0)M`B` zW4TX>esgGaYwq|W*z2E-y{7r7zzx-RXANW&M;;SQCAuJwr|TEl`bf(uhF6eP`b2o&2oYdos%9`*MR-?iT2ILUC58 z!P~sKYUleZ_GP$j=^tIsn4jo`BFYaG%5^o*moM_=<*AsIt7K;RQi>~TL2K~<(zjJw zs+E^JEsf>+#-3NUeDQ3&l21ApoGrB!`Z;Vd^tA!Uv$M8! z7mFDKyRc&*IXs2xCF5{%JDlGQxAB`+4p%F@C&4NA(4xxt=)%Ks`teVNUikNHJxw0E z`BREuOUIQC>3sk_(?++l1)-Sr}`RawrJfM;q)FCXl3B$v4R^M@{@hXmEI@ibc5XBd4Cv? z*1{s(QPLxMq&G{WC|0ZPQ zq`Ai#l&jszPvUkRf*#-h8u*@52@v8P??0`=Tf5BKjABRnx6j_eG}O{i01oO zG)a$R(^K0sJZh60{j}8N)!#>*Tx)K!vBt#Gp1i9rDeUFhtlv|SD^VR*HD;&FzU3R}e z{vcC*R99D5S6A1&yNfe8#~|zW8Mx397ojGLL#dxjd?PcA1xgduAK-&bF>ygT!O9r* zXMuf|()z1QpZ%R*%c$Vsc^4RvY5V|Yf3mu90H^h;OO7PDXKX&$JRU_LH z0Pzk{r_NcFl+L`I3kjHqmQM zpCb#T((0TwZj#y>skU4rM|vi5mMmV{NcRn#nj-F*Baeo8y`2w#KtgDW?;>U!tVfS4 zt4DX_HZ%GSCGKubeK)wz#h_y2b zUIfFr%XpjH-Mx&bPK=9sB?n=N4b3{bTX;IA{mg|K-hzBs;@pt~r^ULFXVzqWPtP(R zAnSWZp?w_R5M~(&*lVW{CR9giYYoqI|7Pj0W}01wM?nFDBRO5tb41AKf^)5i7T@IXuya zev)Q2KGo=aKmxztPbS+O0Qe&b=5~8zJv9eE2AkROrf5efO-M^#Ot02WOSJnM-M--E z7J8-sI7(cQ<<~Lep?`XcMe}AJl!k9v@IOVdqT&A>@jvC5ifZw{fSX)NpQ?MT z(*W7Ci-y$dYz$9kaA!?v=}wRK@_2b4(~a$dz^3qAIA`S7d9MZB2<3Ftt_W50)7}&r zp7h*XLAVuGqnz}l7>~rB>?N{I&DqpUxFQ9)Iz?P5X=|9Q!vgb6LTOipDG24P!3C#c zOVd(4RWb)a!yBc}&MKtaM=Lr{s%v!Lv`qDIzEWD^C6dD@DbMO@#>N@-Yx{(SJVi{C zWp{7`tvtvvIWo;LKr~s09SYYv@tX;rHlB&ID(ElYZ@Evg0_lrmZqxIfoL10^qxbL- zJZ4#7X;qq(op`wqY9=ZsyuRxQ0i?jAc>_##CB?__?D#M;H4vpruApj&3&M@eI!*Pp97OrgENH_O?i`C{ys+G6D9+0kjy!M_WA+vx zO7gP@!c*^q9wSsp+SG5JC4R@FAhmaT@;y%d!=^vIgz0{Z>Dzr^`jHlN#L+QfSE+mP zyU#WnJe=@b={zMQI?ER)i&{6>Eq!Tr2<6`oHIf*ld7~0P%;%S;vQg<7#ksXoE?tVf z7nvV1^&WUtw@5frB=s)i@?;(v;{@0-_1B|6)~|V_EjHlvq~hG^QXg$wb4ey#oJ>)3 zPMY&-=ym-A=yNyEHdT&ZJp2*^-r@0mOfS^qKitxt~&suNf_ zztXm?UD-K^%U(VN$!>Wb^MLimi@{>fzDK^}1->&z&KhTr{PdK>OnaQNQ4`0GKkG+V zL%~eBC#y6?O5PWxZ`Hpn{#k#RIj=Vt|Kk-Hh-^Le+}_N<@tbz(NkpeRuZHT$}Hq)6IpV~ZtR89jBsf`gsNNTW3B3z!R&tlNRCcCE(Q=LiV&XoWCi5jSmyyN|FntEls-4 z15&RC^_s|!u`i8rkRLo-BkFv&(2{hd)cU;V_L`NFT{0Z7Yp&I+bFW63(Mfkqzd`BN+ju>);1lS(IG(<{Cm)=??0EW~ z0;8qxoCNwFh^D{0-1d8a`i6!z6!G+36s1p6YvRH0XpvOX?7Eq-P%jV{;#_dn{*`Z->i<~iTBtFo@k!uBP?uv%1&tr zmm3-IG|j(4bH7TjF46L1;4?eMVCrIC-H;E(Mo!0a&9K3_Foz;$tkgrA6J)8!ttz3s z#Ch=}5y*vGpgdjU{VQL?#^3{rh`{+vmM;Zd)#E2ZKLF+r~O837hj>t}ny8*CY|8QVnSMP1q3C=ZDpV86l=;<>#Y#-OYYr{_d8ldV6 zCKQshS6}apzaP<_Mgieh8kHAOgbM_3k{Z?bRl2zg!i$9PaplCu!r19%mZXQX@Ut5I zVeSWW=dT?Vd{?p`iTJN@v*=7GJmpGoV~Oi8l$*)iXCulxMvfi}n!cgAH>1sQ{_=WM z%x?embtyQGd7SGQ$evMpfFUh_s4vorp9i-dELRyD~U7Y-X zBzc0DWO2f^C66FZlK)1Q)!GQB9k>)Cp9E12!) zLV%8Ex7V1-n8O+6_lHJ`ld;SI|atf6_L8`Tc30k{kJx;VBuwAKcv)YeB?C18b$ z*GH1*Ty0X^lh=Q?BHtylYOulh1Qc8v+{ic+#Qg#W={N{mCePEQP_*EH6rF4+@>a~W zq=+g^Fqf*zJD5SAz_9(%IuW#M4~e!chIT>>?J);MyDNfr>mkwR#nASNq5T-19Dv#) zZBiJee!0AH{VU1@`F!(5$^B+%Q7nFc;F5f^VKK8?%-{4kuB>Vv189N#3fQ=a!jDj& z_1GUAomO?0J5y2C9((6DP#BTcCDL?h{d3 z9*(9hj;77wm+?_dc@0#$Hk{92=gT>IA+Il*%{+5jsi+s>FZj=QRTY~hykSh#5j~}% z;FMIw_v6;U-y->(w4SIs1kfZJwrt3$h z+`0gns$ba};y;vY-(NmfALcIfdn?W-t!f2nv}rGQ_E2+y3-i$urd8HlUeFuKr1iUs z0XOEH(@`k-R5N`OPnXcWh+Y`0DgmCBvwESq^X4R@7x=ye+BR9iet0s^VR~?9f`QO= zXon-~7o8lB-^_?^Ec6WZKA_qUv(qwUk3lxSL7G%a0eI$R%R zU*&X-btrYWIRJBETKF9^_N5-IT!#FMcMOsClZ^H})TCdPUGy`QdWFnlE!}ZlWIl)q z`ai5KZ{di^Q*Q4X{~X z8$_w_J^WWbPFkvtU)hcIf3W;z^+wILG;>t;GWJr>@H21f+fW(p5y{l#lV$C9n{U1y z9WdW4@!)Vq@+r)HvJww^^u6<@_+(AW#7_$jySlFL)oM~rI0aP4+SfO!g!2iS$u=#V zO_52y0p|52xz$2FI`^2YgMO^2dyRO5H$z@QoQrVPhfLV@U(-mw2P4!Hb)JS~2H2I* z2)VuVzokxNrbAoaif)qL(EZHlh3qTs4Pt-YgS({U`Dc#9>d>nvC3@(UMF`AzB+Ac+ z@2^k_1?sQso9^W&ij> z$ukc5^2eP07NUo~LxT9~UTa|CJsrHLM4@H6{L%1^n5Ut3OE^b{liXQt2TAf<|CpI4 zRq`vqLgz%>l4#=lkxgsIz{V=Q{U-jR#GPgoFq*HbpIc=st~;t2>ybF#QiyTPoKYK< zOT*DhZH~e^nipr%O~Rh`R&atW;_+rwFFDnWs-z^{c@#_Ej5uW2F^-P!jeinxkQq^C z)u4$Eu^n6nI*ugotl0S0sT2R^_+n@nwwZC3x2ZtS*SiB<$ov{p92{as`ghO8Mq2A* zzwM%6jkA%Z!7g4Eiid=n%&&St6uHcP`gJ9u5ysg>r$PzkHK-F~I!`1yV$p<$k{6k; z&PRWVJSO9p?1IjNkXG5 zZO&^TbyrVOe~PG=ZQ!lEz?SdryeFAtvO3oyW8qVc7!~lIL&VP|^Dsf4-bG##<>_Um zfc{e!?BK{Qc=LG&bZowp0U=?XZ7}+ZC7^Glt<7|*ekE3FQ{gL|*+lq`lJMy&RGjcx zIZwO~?HkC`CHdAX!RM<;*r_yUCSMpitdZVWayuqFOiRv`Nq!;`-YSfFO};T#q^~)E}&&7w|2xItm3mD zYmH+Ze@W~;B=l&g&vv`y6Uqb+l6JmFbkU=JZL_LgGm?Wh-06*cMCOS3_z>c|b7(B9 zHDjU~lwf{!db0|pu>VmRa|XCj&n{v zh5g~MSNGc=#`vQXq2K%63w2$LPM?bME($c5n{}M+n%0wk`pU;=CV7v&fTxeQrl3Fm zfgJ|^Stn0!G@n~er47R)gW)Z{n=xxrvV45wFAfZ6*5_w}1>?*kr`0E*V1MWPq`6Qx zUd7kT8ht3^6J1JHzu@?M*{|uo;C)#f;9xRygrd0fI_;rGv$HSIhY3FO^E`P`@O*#Z zD_`)UE^JiT7j5xoc(p980xuyektYm^XGCkTz1|+|U6i}nThU+=F2htN_e}!~q?JfE z*X&doW{^F@WcQ^#$SdMTZ3US2Tu_RRPBrF2f?%cX3%W|Xw{$4C4!26VdFO~dKyPa^ozA78;PKVB4-*QGfF z-#~|n0n-fwlD63X(7uqh0t1`!-hRmzAK^2chfz;r4%)y|eD2Nmt-lQWRyBBBB&xdx z4L}na&QGr&s0m&@GfmV|EZRhQ9V}EcnQk)|HEAXTx)Ymu#x~Q%2_3MRzHT$)5}RQt z)XWrfmVuovLml6nAE=es%w@Kj-p7dcMoR3+B3=adpZlwHZ^dBnf7BZ)r<#dmc9h|_ftkmJ z*()(Y&g6bHPnBKOTVLp>Z$KMzejHUJs&1k?*t9wXL3tmZE>T-DU-a}WqHuB2n&QAI z+{{fYD!-_Ik|}^jh%=~B2)>UX!c+fbWc~XWNzbRXk7Oni?pHT5_=L^8?Um)NkZ)H4 zBYAp>Qk*@NT4Nfng?y(d+1y^%vp9iciv#`Be03MuUFG#uWaW;f6>2ijvQFj{GBQv+OV? zV+BPt-<#vG=^0L8&9&>{0My@TMju-|Fq&TWPj~+DU^lQ)BHF)9NeOx-!}*9j5y@dU zj@n@ug!TM;6u&JrIljwP*A1i_gzMBEmX46U)CUK7TZXge#2L5>$#P{1DE_>d3$w`ZiU=!@*XBQ!y~lhojFZ z+fbj=q-}`^hIfL}gV45ou9u_0A8Zj*i0>((4ogGB)R&{ih|JHXkaav-t-1n%AiImn z{?=y0)`-$=X0v;n?5QGM$NZw%KB?jIy%@=_@TC_*MP*T7b`kSx`nu+U1w2T5aj4Ic zCa$vVBlM@8-$&Csx4d{`T_!Uz8BX(7ybV@aZ&Ubd^c(`h5+${8E~>;7R&TCnsEi8Y zlO}T^g3k6?sDwltbm>%E|M^$;Yqls*ZJRyaZT8+svr?^*rVUS!r`M8Tm)t#2oGBuf zGD0p9kHNkO5pL_hN7`r|`$yDwGOeTW8A_wlXj;n$Xl7DZ2Q3EGc<(E`3951iK#&)@mB|(Rs zYG!9**NM@GJRmCJEl5UD^65o*EsGIf4wEsZFAf&;U~)gu39F`slWp3^pd1h8cJDc= zicRQ*Uq;La&=0ijm7sA|%E-)k?T&zbuf}AGY%r20Eq_J2x01*&W~wtj;_zqV@%D(d zLZk7i)W@PQucDawYP58?jcKN@73#3?#tC)FovsX9-5u@~p{a;#22E({0@;S9{@m3N4pJdtH|&^a_7KU~~bmCOcahl}~! z^r^8f!9f^dJGJ{rrFqYL+6+%W^ctQ23I@*UusB2ud4(zoC{s-dLJZ0H=|*Q z;)zYViFe>_i@mq=_ZK3Z@K($=xWGQp6hq1VCWhT8xeR9`I!LttP6(vkjjj2B3$bS$ zn@ObQbi@F2)6APvt}e>Wkk%mWDb<3Fu?Al(lQwNF!RiI$Ee z;VovYL6ZUCB)Mohz@2b&gC_sLc&IKVXUO@=%siKz1pv;JF_xSTpa^RPw|3Nl>3PxM z0pZi}cped+dtE%I3eSBmo}$o%e5dd8tSo_9;dhz;MHp<%nZh6fAL`QujumQF)x^yl zye4K(2$R_pwzAVhGsjzDuBQdKy=dmyz~4rst0ag179v^dYoQj<%*ebjGcEL@ zm8(K%mL{vgOBLx}575R6+pqLqjtKHjD(jW65uX(2C5zxtKDX`C zc^kK1=gm9?$!f%Pk2}-68LjofF}3*IQ%f!;f%&ru58kpe`a((H^tY;;|;hHjsTA#sp50$X&d74F%(_!8I)M0KXRng zuC?9@B6A~4aKa215!*1jddvG*#LmZ`+#7$H^CUV$?d$ZWoXCr)AC|2TDFy8FXDfhq zzU_1UlTrE%-Sy?hmC08|e0Tn&&mz~^>n=23k~r%UaaO%`vCV`K&if}v+E1%$-hv$XI6pa z43g`gcfX&pO~;c?KakyUZ*n5ze}yzy@R#r{RYnWF zFEbpHO9KnqID>G{Xc{1E{t9%LjyiMRxj1XEx9gRP?ejub8Fjo}U(K3i{{AKFW%Kv_ zEaUCz`f*k@us>9hwbuN-Qf}o2eW(%tw3$Vra?(k^*w>}rc4RM|=5Nzextv%G)H&~u z!pNRjBiiDR9PM`>gJ+QS^^h~D4|aW)+d7WEG&m1Y+jcO!y1a1$m+Xh=8|+Kxy~I=R zDWfa5+6VHuuU)>Sr;4=nPS%5n`JVDEKEWMg@Qn#@=(1^nJ%L^2+cL{{ALqS*E8nrP zRQ=FpFC8*JzCBU+VW!8EANPIq!xYow==aj5_fO=nfFsd-dUfrwPd7q)1sP&`>c#PJ zd1EW@!HIudZ*6)X(M23*P}w#%R`$^T zb@2RxP|8LPD#uDVh=~IoEPb4oPuZ6QE6S;Z=Ic|?bq|aB<2M2p|z+0g11!}TGM zQs3aOSv>UFiS0aO(N~0yPy>hPd5%0%)RC9}rUl*}vLv~T%qD<$z){(A= zh2(XK6~m8ii}{@mtiC2AU)p{+AAeQW#!OS}v5N*r$_{sSjx$kI9+STr1icGF-D{zm ziz=H7yEY)dK6aml*qV>;CY9sGzVcaV_2`6rkGU&7evxBLc*A)~D#B$EZ=9`hgW3RM!1~m!B|#R{Cd7hM(g4A6!vtx62@^)aQ7* z?R@zNO;qdlSK!+K=g(8wuLyVM6dhO6D$2Pl&Lui?gLEk+D_n+wo7)#?Tj~HBNhY3EKkN*_!n|+zv!We~NP%rG&U?Aa7~} z$*gkAo@+&k`7FizXO{N?#XhK?;x4~)o8G5vx}KQk;`Kca=irgtHo|`aSM=$wE=(TByfO{84;^bM>vLd}f-{xlYHKk?1<-s>S@QyKom3xCB#Qx}5!w<9i&t zNmub=Dt)H8&#-uaf5_%5oFuo!lJb2=jXGbU2jseGEVkX~r#V?) zrV!ks=7E8H4dPLwT1vP#8La#`?+q~bM!NUr-pENbi3M`kO0NEWbd|XU6CVd==(Qw8 zu1iGEKhO$F-T6#iq48&a^o~!R|6vahwTm7! zk-xyUKm+I8qVh<5vLOw+G;ZQM@{S94mFMZsEoUKFf}Ec}G;Fu$R(*sR^*$Uh%E09Y zyK_M2?;*P#W!vbvG?cZsh%aJk9&g20^t6ft@e-MFE1qgJpUj>1l~})=8J22!i_GEx zE>J4y9>h>)C=C|{hT#X)U3Y9req{3ZY9FucI(N)Z5%bS7HJraJ;@+C-^3Z;0D7Pn_ z6{KhgE`TH~jf{l5fs>q5uQcOOaTen+&5py@%Nd6=86WO*dp&8<+emA#-qToBZHcd@ zjIOTrVH$h_GaKulH~e(&TtIW7oVKuClJ=Jx-J>&$x49|THhYKj;XG07t(0%gQvD5m zFj$IY z>C`i=hUKcTaw%i@4v+6w{d6!JTVo-C<|QExfw^#bC^T!#c+_`RL}iEWX1h=R_=jxa zae;H3#UHqGqWzO5%&pN0WB0qxh@hD?#49n9yxB?m!VHuSpiL&vA1uTMBV0~#upbA( z3pvdY=C(RkO!kh(1=ktH=K56Q^qX_t<%VyId&TvCnfec3;9ElfdD^k*dpGWD-}Vv{ z53Fl%pnFl;ugaQmE?Jnuy}N?kwd32=UyJ=eGs%~`>Vf_`oX^mH^_hmYH0&(?l_BE@ zk+Dt_B$O9g3K^>)ugUNQnDH`!?HyR3u3F{OdmZ+d+2(Yh#UdWIxKf2ox2?r#$~k)x zCgkm>-B#ZE%m54&Vk_D!TE&Qk)7KJHb|%EEfS9n}33c_*sW$Is<$Y@j{hBaD&Y70b zcz&&AN`&?7NSp{n&tJM+BEIi-=M?5Zt~34^+^}4hs7VWK=32%HB-;0u%yltWkIDWn z9)bk1=ayc#r#XlE18uXMN$N9QzoaqQDKF zOM(yVOe?A@wDais&&_0ej933X<-1yXALo=GtHjNi)k7TJf=VW# zBL}DU-*4V5V=C4EMmz9yvo8r((cQ?p6xA5v&ZOc$GriIv?=*K%u84%XB>ai4X7~f= zc`L?~J4L_pxQ3we#-tiA=_ z%hqZ$^4L8F(a(&2mJmTXehT>xq?wC`)aY+I2RCk=WN=|eIwK7_d_)%qQo>qw(u?$U zhk3Y4A8pIOPja?C~Dq8mt# zk0y(A5$w|68lLM|0?JEU+1$@dI#l&HUC(LGn*{2%GjW{R9i*|1eFSuI+gS8EOqtS? z3K6+m@P*{gT9kqymP2#t)QZ6L?0hs!4sh>(*Kq5vx1Hk(!&$)JUby&A6 z0IdD!{JGf3UDoL_xx1ORocH=6cZ%&I4P@@kI)hPF7~xWBu^|i>YVC^pGa~!>;vwHk zndsGkWrkM-+u@U<)8}m}i-YIVIbZqD=#=T=OH8Mn0O)+l=RB2a2Y^U?o90}BW`}Jl zq&~(Ik4#KfNAZ?HHcqchvsX7NrUm(2_+n?Ysb64wg1#`w0-HIgnC_&5(igaAm*gsN z(N<(E1@Zbytb3aF{Tzkkt2k&d;|e&lT9vMzXfM7~w~d?ygE=abl!(7y@D^S+`MM-q z7FQF<}Bxs`k{hS*psa2C-VBMhEM=T+f41ZiSRo_!zGN)_3zNT+_!D~2LoW=Wt&d4~91@DS_Ry}n z^4Z3z9)`%8JE7F}r|XH=9zA>WCx`~}Q*#Sf+R_?_XEqMcz)Sk~XL))rl=t%-w&Y`O z>gKuj8nuBc!(%nmX@3JxiU=VOrhtF1LaldYm)55XRqv;2S>7UW(?+Mc{4MQPd=n|WhZR0Yf1~=TDNH+G2PVhbVf~J~Ela$gP^$0NME_;i z>k{Ex((q$Oq^>TtD%ZY-4<+d1y3|*iz`t$+k4S)xQu*&3G{40iTsKI4?m+nxdGsqQrL!=f7aL~M@1vZvu7wOOp9pg|AIY7D zQW?_I6WkH#4?|zy@o4Knswrbkmy&_bnKrFh^}u<)(`+!4w#U8ts#TJWGb)tVojm6k z6U;W~_`1}iT>4yIHy~byS(cB%yp}5dg3t!@wkxwPbsK;5F?*NRe?xha9vsge2# z>reD+rnxnh9!#A{G3nmcI9>JN5{{G}uam|zor(|34jlh3G@AEyc%%-?;S)1TotOD@ zmw78r)ih`Sf$FA91E}eAffy~G{m2TYo@E;_mj`#w^l-n4qdCybgFNQ0$_^e!th|Au zJ7zZXR_gwmO6lfX28sHe$!~7(QGl;_V%4nMshMdsmBx_p&Te%|z5jF7F^G zM+SRr$$_9v-pX%bFve9)R6pf(mH`>cn?nKT@3#Evf?%f)fOUk!TsNe~ZzA~D8Iv^c z6_u~F<^L8;eO&mfy_Mq)emCS(zGr8hMyfRAw7$@+t2HOFuHFnUY4JWB-p(-vu6>r8 z)W)^Xs{0!I?3eNVh1p{)ohPW>BTT#A3LRJ~2)1iwXyrhG_6nGG8~EeyOE0v;Qh7E> z;be;veFnbSwjWi!!1u{mJ9z6U6+Gg3l5{+xjm7pfe<`ZM~aRZ-86xep4^?Vp9*UjkWc3#3owrO)M?Abb{)2a_e0{ zfnZ*1lGwpiUTSM?Hv^v2!M3yQOv-P%-}dKdmCsp8l1_x2V$0W>@;$bbsx4p=xKS-ap0sODsc}b%tUV<>~X1@ z3FZa)g9Q<2cYzA*W2c5RKCZJk@as&AslCP2MI}yk8|hD0ut!Uh>gUI4pt{tPNkWc1 zcF8ITrgkEMOK#TnSDvRT9(&!fJTJ=tl`Qg}U)7}^<5qRfx?B1=Z|4~__-jbw_Xd8; z#hYeD) zt`Ggt==?NeU!(K+Q%TqlDSLQd?m;rD2l3x8kl^gE&Og|`JKyp zfR}X(s@Sz$?IS!~)^eV>TKAgKpFB`HEuS8lGH39^xm66*dgDBxLR?dd*b%|hlWB-; z)_KM|g1b3SFO&v{VV2#N?(BO(-%r+=cNO^BQRl2${1Z=E*QI`+ZMhtI_tfYezE@{& z%3kUFSdH5ECF)XVxFzj)U_W(wwVwI?q~aemIZ+6A@>80!KX1dMlqB?5ddFk3)@ z3w$g!*o@)b(GCX?^qkp%3+uALL%-A&-xCnV;N$x8fw9yl>BU*rGvNWEY6 z9(tc{UiS&K9Q(cnE)~$h1$+X!yFf1igIwSg0S~&saRMq`;0OV4xTrk>_PW529|N4` z7W+oPy{#?Rmjh^!n^}RoOw?_}=NFgu&|uOQDlOFMoxdSoC%IUEmsod9E#=-!th(q9Qvtyg3fj8KB>Cw zdw9ey!pYIX{XAuzS#F_wDCEp`fg1(n~#J|7w8? z1#EVKvjj|cfv$;U_NxR%P9jO|+mO~dF>S(B$UMR}JA4@V+1vq<=q>*c=rs#RZNK@T?1X1dRQ&Mg8MH051KD1-=pRgqyQmz^g7W zS3sQ$Oaow07rhx9ynj?fZXNzM=L@&cZ*8H~{bM8l4i%hN6n1GcS(q_}pay`hFXT8;L~hH%bbT(qLFZey&`Y+^NHQXY?mB})uTv(A>< z(vyj4mkZehrG+|$@ijRkUCJ*J6<4{yc>>0`K(>GfTp&xp1Q%#8-~tzDC7{#=_F;=V z&$_@?0e8BzZxHaJo3li~bQhQ{;AH)26Vv{xa-)U91n^7kg&1>r(bab$`G&Jxhs1-c3-ae6$lvQ0%r?&&;_~)_@i5= zlYnR4oOA&nxj-^N96i1EK!Z1t#^YXNAorFT8oTIL`%5m?y7xeIlM7S{xWxtjD&P$l zcv-+_F7Tv)%`Whe0G|tt5s>1Nb(ersTwoAD9F2J|K*OD)C#E)z8VKD3EsfVU=XYz) z=1WDKC`6lIx4^Lij&gHa3TW#BKfepm-UYS@SmD-L4-nT-6+tMS%{Zds(w2Ng+6twG zIvrIEaSd+W*Mw-D3p^(v#ckqI0WDl$f`C>oFhamQx6Um9aSdIvk%sO~Y<$^27@Zqz z<0n1A?;qT{U4>||3v?8)(*?W&_P9VZ0sCBF`#S*DF5m#fHD0uWp8bSpDK4!AZ@fBd zNptF7vn+m37%p`&ye8ls7kEy7~YN_zr5~v$^lYnhOwd{^zFWo2hoqq4DF|b@4BN@P7e+B7^=3R2=HG zyj_kPFSfkVQ*xOvnA|UTMM{ykYJHyf!H#|OR^pGheuoijLGEH4e*HNU@qSjx%zzxd>I{kihwO#Qk3?rylnQ?vd?&zjmF8t%@l4L6kL*RE?AH@J59gsd#i zwDR|^tn|QY{&J2qdp>`;6Hyqbt#2L2HGlc0GWDhn$DVJ_%CFgQuXk;VZ~8n!E^MvY zaHDrmN?~AbVRr4~&gdE6AL*Muzhza;d>wruoeuc21+!lVraog0+9_Xsc)Ce_z2-||iN>Vl*dwX;VoYDJA^ zzN8<)T;mITS(vn1MYl8)RfT~cYo~8%DCDuR>@O`fb4l1IVhXcY`#LWcA)k_2JALGu zw1VU-vr-BIt1S(4MQipfOTv0z=bgg4>j>%k5(cOmYgdmlh;d3x8qKE*_UJOp=K7%BtCLyLX)#@(1M}QMp6N+i5*Y&tqFBxt)D%XTuqra-J~$W0hy|1|;||B$a)Q(F zVwK1(u)|)Ew9Xy&-ALY&f}}8wFKktqUFS=h6KQgOvx21EYO;`^L3R)d0zat9!oaFR zD|Wu@*s%LxFLD>*##)M~$>i&avk;*78ju=NN;7@g2!WU(`KMYzQa$68v|NLd^kX3> zz>*MEbs1oBVMM}Kk;YV8T^J`^Tghd}J4R%C6|6LWI4(#P?nf85OP z6`T1GzTeE(n&Zy=MTckR!yewy2*+^*un%=(?M zb`xhRwr*R@`z_f`mg~bbf2~RIZ?DvrGh6M#EWR_-Ed8?%vJ#8$6iQfs?Ig6TuGo{b z&CWYvXPHe{Vuk$x%WJ~QnlQKQtg=g~kh6#;ET9RCr^UYCx|z6U9)|f6SttIz<-y)xrHy8 zU2!tI;$(Kk$?S@g*%c?VD^4ENQBQyL_XS$`0+b0*CO{dkG8G0W6QE3BP)F~B>$mc0 zpW{}8)zoO#pa~u}<;B7A3yOpHEh`S*v$i;RtK$#ev(+E`zg_;&$?^=C_oMzR`~M^V zi~E0Y|110d*8i*hf1&p;o8$msnRk5v*|ntYFnj;mBNn$%0d4+S^R>f0(B{8(Iz9qb za`j>D!Vy0msd{WmWdpFE`o``HvT;!i-@Aw1zlxik|LhSkv?dW~SAMSHO~F>5*^1WM+S*f^rauBu8kWM{WX0YDkNkr|}ku zAxZRDhXEjt2}@5?w}GMJKz;+2cQv%@J8(rsTY;#kV0d7rXjdF1q&ns_h>40dSYo1L z-3AhssOcic?ZIncD8gePQL$ExAw}aHHDzL=;>%v8Y$GZMuxbqVt!X2?Mp~$Xc2_Mc zF4lKIWx6pJ&w;gcqT*uB9WypK4Gb;v8c3Rq*Fbo!xZn*?HuGn`5tpXU0~tZIF`wOo zDjDy=?%})pvks`9+y@b9u|5PNEyj_c@IHT3w5Acz6_U?rtStq!2$gZst{Ew#^-PdrNU-9A}R6ChM1&SBP%8;2UIG%506rb zx5O;xU31K^o+DOg*UP&W0 z@#-b&r!Z1uEkHRc@l_l`zp(8-sFNZlI{%uI*>jkbOdNA$Jw`MQCS+844z6kNj2v!F zb3kJghsEkdb+h+>r)~~noQfvHBCB)cK#?$@{{97>^Dp~1e&)tfoPWcJo3(uKajJRQ zJW6%VodcOVD&|@_D(M<2%-10r zWU9oODRCCc0gaP5^$};2H2E}PT8Vy}a9eRdPAE^thf-a;Bci_t#+w`}=b9TT3abun zX{b|l;gyQ$9^~7B zN+G$d=_>b6rl%Kn$8NZj%e zzjm7bShL(^+J8Dv4(2LxTau&Dv~(CIOI)9{Wq}qMM^4|FQMdM#7IIY?ousCgjIbdHW$MsIhN~)Pz+MCzrl4{nE z^VHSMyt_BozyV4*a53|i-q&aKqz^r=-vh4ocYBuh3*B8^yU(1#xP>zq+jRzGlg?ml z)ESI@oWUT55q}kdMh+}LpH-@L=42N~GWPM^oqg0kPGn@_WYHmv`c!j%MYc#kPtAoB zPuRz)E~+%@O?!T%)odu`XhuQu3t44+nbFsl3&(DCI@D~qg+m(py{k3v-SzAn>Ud)9 zJbW}Y7xdn?zA$^AvbHvd)H-DqW^d=CZEY>inVKPEx2`>w#8XktwO`_%QOedM^uN>W zf>7JzYHRsM-PM) zYNnsNA*bybeM4GDORjVL9F=SX@<}o6A`Njan*)p>e?>J6$8YVC?i&kHRfMDkhF^7bkA-nFHFL4tG!jg|Hw;CK)fjSaB#WPWAgN6@BEjrKvTo{PC5s&7 zT#}_MNMeDql11a|ph>fDDecS`H4GvDhoPxW2P*AOkgT=Pq~WGR;*uucVnaA$rEr}( z9zt_Sy9k&GHc0AtCgR|V)dfAHTteC@q%3hsQyQtF=?zen(goFIgo*^_9{<-v5kdu( z@j|r~f;ePCGVUO8DWx~c454E8-c)zp!ikdu=&n-Eo`~o}>#j`=OaE=%<&G#`B&)i1 z|G!sV5g|)A{HtTx;H=O8LVs;)SR!UO(O-KKq>PdL|AYR5R4Zz6#$-=OlM>T1YZw-< z#Kv)`Wq&1hHy$Gi@S&C1#)dWjwh~LUs}1v{$@cue*JN>=>u)$$hi$?Ew*P@T+t{#L zTyLVz_8LKJYPSDB)@hJx%!wukYm8#sD4$ak#a83nJsz8C_pyyh=JRLl+vn++ggmA3 z*D`c**|=m5&z$Z$mm&sT0j~Z0nB|tB_Y%#un7R`mqgI-Lcmr*J;|y|LyG&c-f~Y-~ zXp1G9VKEa-+96_n>36*4Ww;bIy3G7D2A95W`Q=rDwr~giA2YHN4Xl`LCEQW7s;Npk zfHh@$Weh2ub1l~4SK6t^N|7xPF`jA??53E_qz0nql7M(iDSknF+bS5-H=|o%;b5Jw zp)pJ%{*URAngly2rapu}YW@g_w|wHeR&8|!jah>SHr^aHbP|o6ngshMYTJmQs97T* z-lU1|*8)5JY09-^ki(&JIzird9rS<9dP%fgVn&PbN9`2>@sm5gUu$WMW4RFvh4H#8 zYMCTjB{c~KNz@n-@`xRx-|;3$e6P0B5ax&Jm9ac@?EG-gt_1Uers5`7%3+>dP0Rus zbGJ0+`|*EkhGiNtTy44*ondVb{|t*;jd~h!TxvQPnP!=Xdzu|+U8cq8TtiaaO~v7w zYjHj7Z+ciqd$9@E<#12911zNKpxGBN>$)G_S=ZDHmN@maApXpP$l6%UWA|Nf7!@RK z^@skFC2vuag_1);cc=f8GeZC5cu?`VclY;J{JI6Zp6nfg)oeSm=hr9m9#y>mq#*f* z^uw(W5?vwiJE{-{v^~uFAm-tqnW!r0m+{}y1TXKe2?{$NensG(gxyaE4Cr~dRX{|c zR-2B^*W@s+h2(y{4*TS{z1n}Fy`lHvp7xPmt)*A->uh14!#m+4?d-SA`tf}JH>Q@` zpxvqeS7%nFYw55M2jc%`dSx0ZOjv0D8`CRp73xWg?3YdV>^gh+=h&f_+5f^si|b#1 z)4%vt_VCZPLoTw1d&>QjHTFO|Pff-e-P^Fc&)kjP^4+`i;m0n*thD+5;QLuUBMb7Y zWYl|L^_Cgry%&;R<_rCdMfay=lZx@0>JZJ}jtDi@c}#W1)B0(faS&bp3x*=B)+Z-kwGJeMe6!<(J*+ z^ES*dsVn(^*c|;goz~7S^bXwV^A6nMO~3u^TfMzk{p9Wa*+LqtJ`x(Lm9m|bIYRQX zkjyklHuMW!o==qp`&C(+P^DT`YD|^-LT~T6i>R|Tu?{7MeZ_z0cvq!Ruz@0-6L72* z4oq0A=UZaZZ|`qvlpIak;7HnVlg58vZ72EVNoo(Sj!G9>y+`#rFM+jUVx~x$ zDN;6wl<%lkZLvl8E>cz*QdSyL>f`xr1|nZLIBwZ{-uJ=*$8KD^KaM6$jq%;!7%UtK zT#a(w4!_7qDH56l#zuMnpK+L@n&NQDdFf4AT=ud{*MG+4 zvT7I2f5zytwJw_fjMpC2#DBnRcOH~wx@h89^KTDBOiU7_RpQ?>GB}wDgA*_7MuPHP zax9CHsWtJk9#un8;Wm{9yOnAwyVcCUIE@jh6H^g$Xf@N$j>xS4_qr_hFVugZ`Wxp+ z@_PCSyX&o-z%!51&hPNw@`$p&8&c2lE=nVYS5K7v1Zn&Uze@jcrg>?C_bhJz>BWS2 zcVm7`gag|W;pcuxgx}nn2v6CP2+!V}2ru812#3E2`!Y!M?9llGu>Mo{p?cnYKIAJnD23TN=h&Ke(&tTHO`L>&O0_`h2z*C3!US! zQpoz$d2OJ1{&$))@Au}%2Tp;_`l~ZGzlF-Y>Wr`{&pU70AHQ+d+8+U@J#REorp&q2 z{P0#N%q#EjG$YkpajSroc0yx=e>-*O*&GurrmDdL=c`yh7lGdEb%qlhPIXQaFw)J* z5byzSe=4W7fH8AyF-0_U9(9ZTAYhscDBO^<%>|YUI4MOGdn@J$xY`9i5fF3%g$j4> zIm@E{gMg#%w7_HmR}uhG2m%65dE_Jk=AGv77*Zmm!}~M5M?URlPg#<)?Va7`dH*9K zPco+=B*;hJbNzaFoC1b0meHjC1W#Er=iP(VUw$d|Qw~+17^=z6h=bLCu0Qo_-a2^u zdQaW0oF1bw^8RpM2j;(1aftfUMtD4_&Ne92%jEm@fA>K3|4{Y+>?v#RynC?v%db}d z4^{sjkEew*;$Zc64^sdCcJTgBEA^DMaLzbb{V_LEzv58!M|wPI&Ne7KVE=Q6sQ-tm ze={%hIPV^;{_@+@|3lX=JK7m>u=>y4q5l8%5dFW)Q}#>ejDyu5bEo=$sQN=Zp7zc* zC_G^Quen?OKU97C-_d#ZVD+CHss10TJ~13SIU^2M|C&Rt1mKv9T*p@z+48x1t*T?)|_+oFd<}R%G@W{|GUReBP&O`z3Ak zm5uZC^j5S%t7fk(3^dfYH|OcfH}x#Y-8b^IBJW$P{X;hSlj?omsdw{sQ*9DYg`f9u zqZXwWTv8XH4H-!yT6CiNrqLXv$hKai4Tq7(P4 zY%Jw|ZLh3Q|7QNWi+CbSk-O4LjxFEABmZ~87F)h9KT}x-*pYu+T4{^A{4ATo8(4v5 ze%{zBo0}477PvM=PijYA-1iNNixu?Mf~N{xn0{Pi=ri8`pO#M%O2HcNXi<HxvWHWho{T3eL#ef;>mSZT)Ri^%xgV_N@^@YoevlO5gPY@$oQEoi{<3Ry$r+M+pN+e-gwwqAkN30V+xz)= zLyu`7oCgwWH1kc<{0P6Q^S^{oy0yrAPYvNV{rFbaOuyB;BtI>}@X8nHhxqBTvf}?l znK%;e#xG0Fu5wGwQIZ$Qm#7LaCtnF_N{xm;C1LJ>spkOu111z4x##%1)|c;1^*;V3B^7jz@TWr-`9s%dwNmh$ zH9gFfZh89CR9@q(r81hS1bp3jZc<6}3_fFI@DSg%6CcQGb>ZbjSC(8&nPsQhYH!*y zC>{@G&Qh6yzRNEyxl+F_z3j@uk~{RP=+cWWD`6v)({-w?cdu!#H19*cV(HEM48r_O zLh~HyF>0XX`}*JB>cY(_QL?IjMg&&JOXk+Ucon>1kVbMX21#D<+K+8yjqZ6 z6sVTA>Eh3=8~I3C?{iAa{pHn3djF45cy4gFUn6!92Wj4l8=-+i-`yWj$S$HGubFbA zuyr^``!sxWh7gwlKBetkFx@#mE?!ZnUH=m%H`XtS#!+eaFfWJJ&x*lkg`RG# z{~!j}Hxg&;wHSQM1LRMR!QR&7KNN$Dc$GA)9Tzms`i9@P@jD`)k@$226bI3Nl=@SU zm8HNtgnegZ=pm!01%dQT1wikq^qxvDX00?K(RxQp*|?;iA{)gFbVgC2vHmWmg80Vd zP5&bn4q8*TgZ7Ua4bIZPkd;q`e#mO;9kfl*oq=RR?C*}|ePAN*s4^T}*!_n_6AF&w z`-CxEMr@HOn&iI5rC@wa@pptVUB~+wqaTQIsiDr`J!7>?Y-HN)CDc3z`}H4oS`#nDpe^C+Ip9EfQxi(U`HO37JDHL8JO2iJqd@ui_XWuax(-I*D)C4#mSKh zgcPO13seZ-XG)hrs!DwGOQDR4)%_~*DxEiSiU^=!p6v2;qsBYjI@->}8qJP4rRd6a zsNLj5eBFd^T(q7d&e1_jU$`6Hw)3HK6QRLRr5y=Ccu%B#Hzp}s#>5u2@jNgpcHl~Y z{G!0Vz?ZCQB^Yn@Ezrw8tXhdo!8Inr=(yW#Ku-fJ{0vI8))`gV0{xj(O4uBNHEwZE zDU!3LR58xcNVZSzd$x*4zQ$<|HVP6b*4gVf{+-2`1j<>3GbGoUpcSG?>|ZP2&YjB< z1mZg2Z`cAn`MABXOFH2q$y3lES0mNo;BJ>P2cZDFWRxty136DJYObW?#_}EL{?jWV5igS*IObqT~3r_;`O{CB5#Pixhn?8 z^u2S*GQ*z=oPJYxTK?Qn3V*JEZ!UMTt1W*#Ux`2UAIBNYlM>{k`uGr$0@`)xXNn{j$7N{=hDn)Cew%pZJbFuDR^##;QDtfow}6L~a(3 zoqJ7akJJ^jF~_ApL*foLG%hVa2<}4DPVBYn>RXjuv&dtsi>^x%F z6_BQX*ZjkERXqrkr=`|KRrM(wQEW;WfV(@N=V3^`M_G$RfX^|)Mgx%N%`#;i+VR}*OAJy z{Ee>X5(}0v^bibI@X7JoR*26X3?1Hz-_xaF>JXB}?I(eXgE`j&_LH_L2QCVZPjl`E zJ3YFun3mZJmt3iRW97=yqrznr=@sqyB2grB5?*;{n4xd1~Ha@qNQ4>LWl0PuO zQ~yrvTQx7Ow*pyo{uU7&UCq;&=&}uJ?!(heHArhK>nBCa8|FYf`wvBxmy1_wq@DeH zUDfyW5rSVU#%@}h!f$DVP)@CcF_d@JACbWD5ysj4bhSF*{h&HNBK;)aRg`X_rIqNU zvw9KVRdKVNr)`~z1)vY6t|3EXFawA&SO#du;9cON;Cbxkk;18@>L1HS2Gls0GcA0% zwd3xLQxA&&eV(F47i!Mf6@R!tn8A3JoDi|Y{K4xos+KVjtoqVZPMZ3~h;Cqwty*I< zeCT^;3$_6Woo|^dH1)tMMj+m7lVnn-Uz*~n`q~cYLzl=@+Ua~k4SIUstMH{WeZ1}l zDDMsgzZ&h(#wBy><#ND*~)QswzP5ZQkdI}TeHa;G`osUJlTzn-FEZNN2jWf-5P_re2 z;8r@nibFXUi0qGBt4*`Q6;!=$#$v~`OorWgP?jsC@F@CVTI%8t9#b3`3Ss@(D<#u> zhEeKqlSTal?{`J0TU`7e<7Xg*rqeB0nAmvAoGzD0xyfh79+JXNdkW$KQ(#1gi5VyGlAi^?7y0e0 zp3~&8WaL9B%*VfzR%GYn zSeB^lmD^`j$;&pp3{ezS}(C9U*(RnXiUX|Oyn%{1e*qY+71(;=Ru*>Ivia0P+6 zN7-3T|9167k`z;qDOvxtr9*mirA78>nnf0|k&I?_KPj;!KJhXGb#7{_!Do6((i-`K zt^Hegq|?=|KdBRK{)$0odK9L5vGq^{_LiL3xBvkyJxVmSVdX2mfLQCLdA6Cze4*c) zgQ+Kh1G#8bm)f3R`X{OToHiulGbMD08|^y3_*{08jb-ngw!k$uJkcPZD;F7K`_Xru?5XpdUqMa%A{Vdoaumf|{!|+>)!mRlfOl<}E@ZdB_NDF@; z?`U-gg7}@&@S>eV{BHLhzl}JUdC7lehK*(|3#P78$v_KLY{i(?8nC(MpTNHvuo>|e zrSF_m%xb5NxfIOAywX2c(q*VyRsjLP*_ z&MNJN5A#bjGkX<0S^nJA{@053A|HNexbzLhz&ht?cBj;6!lsV zSkIVh+?K}H0XekNoXJ`#qz|HgoXB`cx#+ETw7)R!W13$fqi~pY6_-r#=WZKuK>tYGyP3{;rFP5UnKkY^$9X zkds)zLrnM?H_(Pv=HVRE1LjvjV7fuPg>(B(BXUsx$JobZeu@4f9>Twpmj&1hx!ymd z>Z0P%eJr{^7Qvo#{1Y2IY|=+%`;&H#xSRP#OEl=rS14JWY?7?w{X16{a|faGvdEGG z;i%J1rN?L*9vRa{N_S5D%$;xAu%5*Ln)#+tvtzcwOu_ok{FSpyQxTk!Y0lO;aaEEd zRVFaPw#wVK%CiX_{3n2HkjfpS?>GCHrT!sH{O7hC{z)%S;D>Ry`hz(G_~}12^&DE%<1X>`&U| z{h+7c`v<-tY#WhRv}kQX%NdWPOXJV1BG{Eo(9+(xz(aYL-1Q9cPw#AOtRfzq(r>Wo zGw*#?@nT6QWS!CrZTbeKzovAZ_#nN9O&|F*cpf7?ZZ*~ZLiTMiwen*+lw0S0u#BFt zc#jhtN?9OBEe2(~0VaRRh+=>6h+pY<(n5dk{E@_hMKz&js!LAx=YBf!27m5?5m);I z827oO(@Jmk2Zpos^VQ0RY)Ae~o|{tjxTP?7w(02)H$vg}cR=}LHhrW`@B9<#i^)6}^CE_G0>$ZjbU2HXs@>rndA@(qw>y`1-kJYMZ#$azS=wGd%k**F z9nh90nh6lB(RtjaZy!cqw%$%UF@lvo%BF7`L;5nMkFx25Z2BLc1Wz^TuDlM7_HSmD z=^r7$bKc;m?cZemiuSMcj)U~=9QyVLijK^V^^N}MW0bK*I`5iUWxjuga+cYuv*{(>MJ_{U<$QpS%8+VCs)kAW;&y$Vgz1df*}kC)Ad& z1xvlm;8+PGfHq z-RPSgi=DO8K6H7uM4O-B5&sYzYRlwi5_o&Mb2 zBiq$?)qHs)$y<4~YKjM&;&^auj0Y=GT9|LxJL6gQWiOv++G;lljK<#aeF76a&IDE+ zluH-W&}x6EkK;Vb3K4D~*X>_%Ftsb$h*;Zn7(B=O;2H2E5cb#2VAW%FY_RjszjL9# z^QV6ATeFIiW_c@)ppen9#Yvx* z59X89uFpR-Bnw9HRpN-=`W%;2?=ea=SDaF2780uw5pw+u%tq8U1Wd z!v`iuJML2+ssXlkn#?dBBcCPzvD=$w0YhK7i(H2w;Sie<^LaN z-yRr6k^G;K1fqZw#S1DLK@=5)T|fZ|>;|*0t5HFG zoqD2oo}8y1z6c5l0m4J&CCZ6BeA2`66on{4exFbE%-Bs09)z#J2 zJGC;Gp*)48e z41X6Ycc=iK&Ss;sk?8o2rWmt+5(XEcSQ(WUq7KH9n{-{W2zdAxSD^b<{1xhlo)Hwz zE#VWKAH&bhWS8-A)534@W3l%5yHsBGbW@-atMmX;Es}m;fVjev(=f1sB!%C=+VF?j zc`!E)4b|*q8}N_o_9du`4@$kwcD=WBJwDg$cGPS7N$P!Q*DFK4CFejKmG>(yeq?9x zu~mS8)W&5s;k$tOvcbRbe39Ag8`vU9jdRB%l$L!39@W(Z4dxcG(LhpX{*k?F+1v|u zkn&K!3@);APb0vyzW|G1b_>=F=C)?hL|jyX-`oG)OSrgKC81IBb1ycJ5xBwn4zCa^ zE(uLd1WT0b@MhO}4X%XTf1+G{`Jc?Vg}^#)NfD_HcK8=cD{IloU+_b+84TBE?2au) zMRKz07fsJByhgv1@TZ2cdG#hLG$hT(Gn=cdwP9_ss{WYO%+tA$mGx5=eAF(hyFcAj zBb&HbjJ$z+@6hHzwmFOgfwHG{*;OpN$ts(v%fj!FVNFelAOy32nUGgkjqz+pTZLHFfscQFdVuE2WK3V&Af5xE=6-h%I%!!y7C5$IyS z5ztZY*`mB&m!CEZ(U^3W?_oJ)G?ZK9McovZt=Dzu>bmcBfu1+sigG4l>$=aHsQW$3 zzKfLIycK2ZP=@$dDyj6e#LgA`_rXAQ<=enG)TIzjMn)lhuZ+TSyo!uMiY{BoGJ6z$ z-y`)#vI%<>M(_cnz_wq&Z;nDk($o0Ge;9}>@DqRX^q&&_=X(9841XZcaXMB}hEW-c z68@8Qt19~veEu5-$1jD!r2cpvwO6*AqvK2no?`nA&Q37tY*eESm_qRh<|eY6wGd;L z-AD_S)BVG@dc|>tlC%Ur+@Wz0!=#V!)0Lwpw6p!G_*#57G9E?ae@4uGau;{7dljn( zei3;t@lD->Z(^o#4xI24I(i;2KOPHQ)eQ7z9zge$7kADthM$>rCBfl)fKZ2W)WdFT zC>`J&$?fX4pY;Seo!A9C^pOgDF`DM;Fs+iRjTiIqLgsDcOD3zM z^3jjniBfypp!l5(rfxpKsry``@-G6CR7wyNuwymsM&*jHCt+i)rn~E=U3SyzZ_;e{ zbM0n#(<7K6&C(<2AoX+izv=V{cHs%$VFF#Kn(p^LO(!l z0*NTMUMf2H8`;9g_`(li4xgRYBy%vtsy8;!L)K%&LEa zWJKh1f4f-VQ^zYGMr|Gl9Jlhe04`i%MUNklS;%SN811!rdk3 zfxEx`8J6x9NHwOFlk2EYQF=p=kKaT`c5*>_ftVE3>;oExvpk3J0K7c$9GT z+W^!-PP~0h6#U(1WxTmDe}byxl;6V8LzxO zeZEYGm$7{H1!1ya8+N4B;DC?L=PFWYx7T8uKKQ#1pFfZ9&dq_eW|Ao z?5p)w-PegjhuwqFIGB!vn)nnd67m~-lvLCdULv_MnUUc7>V~+E7`$eQK*FcRuoB46 z0JOU4Gqf28C-9Voht>y>1rH5Z-I%*qv z4nJeXcOb>t5-U8ydF>LS{v_H&h6=M}bg8SV{M%{ODk32LQagTi}{s-!k?2??0^in!! zpmz%Du~h8kN<9@g_Df>(iP+yjFhRR9h?`@gnLa7gg^d!Vc45gZGCOkj-55?uv)j za(+C3hIToiX`co|w9#GV2JiXdzRliQ_S9+{Q={kXimT$7zXEpGyE2!mQm{Z8huzEC zpz`fUM>Ey=Ha|5rCJ>1z7ca~lU+v93T*1AnLt%5Y)Rl8ZjoMxy$_GOqHlLk zu`rq&@3hiqiiQ`(1&cUubVU@0*)`{I@|GNv)G{QQSbIM_J0g6>@OrjFI8vkAD12A# z+t(wnqUleQI^`MfW08{Nu6eP^Se)3~mLFNpI^>n~$k`trAsI3h2Lu!|;8MBWCcE>- z`#448xy^WgvnzCed`{Ri&3ONTcz5Xj7I}V51ydoE>S1sSSwMkhYMPd!Qa&L})(M}Ac?a!3wH2i})lK5VC91DZQ}$mY!;ZLz!G+^+~6 z5P!p-A61yg@IoEhfX>A~pnWX1I=_kq*g>37jOM8sMDykMSj2|4+R8q-rB`a6ZfDs- zv?ELRQ10jR(9V3jol$5)?<)z^WH zajiK?yw3_$w8FgDO4a!z+{wmhsG?;w1>tOclq;4JboveAvCz({I*1Lv1(b}(eh z3>L#b6BP@M#mkwLRpJUEy~53K8;w|reO>^W-Hg7(sb3_J>&X}HmtYT-TtW=c!6+?v z%^PBBxNhKGX~4U(rVAz#AjDAR%iEg}LOB#(fN@g=Z^<~hKLnqU>BVvKyaGNA1plx- z`v9=8w`Us{z*k(M`>SE*sQDupWc80ZQcYSV%ktSAOPzrg-LHT6-RaC4p_Wei`q3nN>ov#XgpVI=3vW>goBiWyAO}5FOMyTI&=fci!al1aL>z-g903< z6n(uP&|1&-iwfBysQo$OL%T_QY9SR^c@hsL2OcPATX66Z?SJwf+V88|Z^QP#L%-5~ zR3EFQeVpQnx*OHd$5rOsSbY?Bi+6U&sQL>KH2m}MKhzWxdtj4)gXd1yhxQ1#a`qcD zc_Fwv)NdkQxohqeJhJ^SF=?(zz5X?|beXmDe;t-g#^O(LzybQHRatce0vMR{DL~D& z5N9yXjt{>Xu^;yST86Z}Q*}ez)Vbw$yaO%N+=Bi^4$82`I`-n6rpRn!?%ry}zvj&s zzD<1>e7jxq?Q_&r^TAK(Cr8EB&tXtmoQ)EF(E9lW@YNm`WSJmk5cf`@r}8H#TjVdV+6*fiJn+?0CZ`4V!gkS z@r)o9*87Vqcr}jST!&cSZ!IUDgD`O4NvY#c0T0t8{t;N`n7`}3Nswk4)ren*x;gtN ze2N;j{$dr5>QRa~K3FIeV}fsaVtj4{zK1-WIEH6P#jgFMm5&<_)WDjh)^jm(+foh{ z_lWnl1s){Q^0zYAxe|)gBKU9-fa*y8!*&^nUFk%Q^Sf_)2DIxnj3bmz&IB+!S#raJ z#c3sh&zVHWT@5sxvw!>~rs%`N=qsy>I#(w05)Mr0j#o$;TH$I~!9hYtlfhAh!sTR% zPAF3Ol?VC8(~C3YIrPLYLtUBtP}=rTL63MOVPz_oL~I-gsi2URWzi+8KaL+jITEy# z_R!SX2aU0VQbxIq`|5?|xDl&%l<|3;ae9%Yd^pbwSoG7A(bUVbkj|yyuRx)&`0kpi z+M={eo71F~C;clS({nAhCo|a9r_>{?BgDzXZsg!pSIFHVj<0Y&6W)L;;7SE1z#=bM z6@hX%4cgztB&1Qo`k8)!bNylW{Oq}Q&u{!k_l&sEV4M!i!x9o;(z))oAx~TcNnDLO zbx}QVNGJ6DkohZ&NmPD#==$NkXwqT_mJ-{yZ7p;i5l>E~2DCwPjg`opyIeHxwNALQO~vyGV=t-LMQj&j3Sl@l-N@(>0^7AHefy3)thSgUl2wNO`-ZC6h4sD z8vc$Hmtaxyp`x@zqmuJJmMSg4pOsw7X0DIghrB8fq~cw5dyz%3(z_pm=Y2x@#fTym z{jXi*Fk4L@w8&FrA8o?u2d8A?_D*@I0A7kPN7YP@+8a2Mm-O? ze8;Yun1=Or(^YYC6N~wysp+bT*Kpxkx9>_xg+>S>)GuCT*21IA#B1>ngRO-_T?CC1 z&8`$Yn4h2pZoVRl`kOKH5j=%!mn7mjyw@SImS+G-zZGM&1$IPi>(Pk)gE!uFLaMjZ zp@OsoS>LDV6`LjhP#PI49V&uhyHgZ}dL^c16Mx`4@7&?yCT+6e?|`2; zU%>Nbc=jT#8fk6&)R^D3#$ApkIp_iq*q2xFS%tb*-gztRBapNofsN)kRE_XMi?HEm zQll$4S<^gF9xR&uJg6V3-)vl`+2eW#)`6}%^U8%ZEuJ!j@zwQ<(Od9rvjw1|@(eDv z@SH^~#$yB-A6cgFtf5;;|KgBMfqKG9XjqJj=3xA{kfY7u`phDZ{&Nc{4dJ~ufZRf% z$~2V!d{mK>sF1|z#w_0YV}6bQnhjT;?9{`2MdW3&OGop@K?g9c!RSB@ATMKsQ_}Jd zHN<;w^zB5B$>0>jzmV7jp&}6J%r9Mir$AAt9xM3Ydj5x-yr?MmSc+0)DM~@IxgM~x zmf-e*PcjL?2ul*R9*7)zM{t7CXN4dSS`x6C7pEoT1oBY!o4BfP$I3#1lzWHqq%!4z zcKLCkK;+zWAB~fi@s%w0nfSa{;_1kYbj7cYj$bo-q~+VF%oB0JVx|Z)+;*`=@abBf z33s*IdJIGJF}D1yLBL^^XN@cP0A z){dX>WhieOV0_LosrJ?_ohcd4IIpWbB#&Mp08rt6PGQf!JSBNz_fK% zq`}rY+gV*2)8eS=mDMUFqrgt zfYEhS#pU$7w41dT8j0yDFGX$t1+_3)qEe?w@6Cj@x@IzvK+~%HGt{-_Q3|xBtHjAd zs3Q=vR#JK`0>q@4q!CG;MimJ4rU*Hc*=%>O{#BJ(rOJL-iM+^tV3aIVk;P$+QA z*Cb15d_zgj=f+It3d!KG{-}lnO# zVZDo6rFUR=pmNPqO#yd$qU;xgp=#?Iu7J50W%&Olox`)=Sr{0NFw}??_0V9Pl0$u8 zKU}dCC{E1}T-(N|+=_}N@dJ>K`Vh|H9#g~G$;F6|RSR*qrh%vS8pmPNe&TsDa)lW643!am5ciU&07PoPn;9RXNsD8JqDnmn0uHQo#NDz_?G6mKo0)4 zn(~a`G5ZzZha*tL?<(Tw1Ktu}Y!NxC)nv63=;g8If{@WA2y@p>x_yik18sB_d!|!m~cX3f`V0bXeG^t|^Jg;Wb=cZUaw)+oFXyRE!A_YZ+YY zf~&#AEP-D&x1%8)hEUb$jrR-eaM(z?7ZdV_x({UJ?VMIv`Xi&Y-c7D#+UTE{Q6xHzzePBUe?klUAgo+aL zG~1va{axE0GoCJMI4->&Mm2={F{OEM(M$H7zz8lm_KHP`M22{r_QRE=8C#H0l2-+V zG+7uT(18I#U^6d;R#TOh;vpWh1yGWWmx9!W0ud^ejT)fprozCO9@^3hdil55c&Ta=5oUMdvXm^mQJKAnpL(Dx!m5Lyks-L6vhwT9`@a=H; z-|)Boh<@~ULi)kOlh99V7^VN(lhbefSNb)+Q(p$YRTlj#NI&=zOFu;a59!D0eN{hO z)6e$)SNhQ(=*M1p%=m+!vGj9VaEw16Rp~V+r~fofzx(9lukjuJ67ZdE(Z8JZgDBmtTRsV#hpY8px^rOEM(hq)~gnoPcHT?rmPJiqFO25YU_veA{`_}j` zCH>$_Ed5Z4Kcv5o^jB;8U-&=JkN!?5|KMjV{U_A_t4~h7v}r0FL=|5y6a-wEjlKTkrx?f>ZUFFrZ_xRT_*(68~GIv4m_c|Bh) zCjH<`Ed5Z4KcxR-(*LNYpZxsa=pdC33K{ogYO{b%ZRODobd z5Ol`S(+CmQ^wd|Y@Vf_^^wD}}*S@-V^d6pte7uMUYp<{GLhG6u!+$e-5{huCfh?|% zke49L_kl&2QCWdXY670&&{yg+H`~<&^m~FOcOvMOCHE$rl?R-?$&@x4{ZrsrxW8cD~lPT8?o20i=jr*A8x7B`g8~-; zh5UvAg2SM|eJQG{fXm?l)^d12D%UjO8EBGnIwl};b;nZ}*WToIDEBgSpe8(maow<( zt6@8DB#kBw3w0gJw2m3r`F9BmI3AQEh>;#@J?xM*y}F0QF?>L&<9%VT?1h*?KB}bu zMD}m3hu^9}{|A8=`sZrc?*C<|jzs;rj$feRK6w&wR-9oH;TCCnzW;r0^Eg8}fv?m{ zane0O!#_%RYaM?D;iu?+xr(>@%^+w3K)D_UEJjxH<0_DhDL2hJ*2A_uGwN@JjF<^d z(Ve|Cd7V+Y2JpPgi0joQ@*8VBh&Fb4tEK6k>KQ~*qecsh^cNRmX^r4gs0f)j4D%eq z83NmWF;CMS=pj)sNM0fyU6i~h^LaX8OdG7~Q;QIeEh>p`h1=G+l2sGqwaCp9*zyx5 zYijx6L7%GUk-QjKE`gAe_~PX7htd5V)%9ULeougpC0c&=eF#4G1b<`XX9rBkaiJbd zeuS?ebpc?x=1u=VZsOUX`6=nn!cXk|H0LMt-Dn}mPwr14y%(W4ZWVbD0=NUsMOjI0 zTZBQgS;zYBKyTahx0FYO$!^R;nvVdJNd`Zg*&VKC!6;mND2|4s3`^Gi|Tt7IGtk*ioip z(2l)N`COrH#h~fvqh~o%fFU~&$RwMq@z~if3QTIlh+GlU5_-AfaT;NYgdBf3#*f-O zlvNTys>BJ{8nJ(__=4o{s;K(CDhaHG za@zd4*)RNgKLq~h`&V+$L(6I;_!h&TGiYdz;}2wR|9i1ASBwGE_w0I*){|k&8}sMf zfypUqXD;QK*VjMH-pFw6tg{y97f+`~}ur=7$jz@mX4(!qvBD{`-2Kyn^sN6=; z0fs4{0BMrlkG>17Wf;C@3*NxZQhwmzVjePsY@c${#Yj^&Lfw=qMz5Ul_7!@*zi9Cq}W{{)O|NB9dl%Yal!jR#dRsTbDaTMj7JedliuXu0}#lexMVy(l?38S zw?`r4uK4ASKE02I2K*-3+q}=gw>Qyu44K^5kqMICG@ZY=LC)P|q}lhd(NS%m&Ws~Y zmG{VSet>4VC@bmQvfG^F}I34S1*YifEA)juaL4tX=UtDA{X$R*gvSZ@mQWOQ+! zq?-i`(@U{~m8Rf+siKGP@IHc!E*aU;lF|BNin6tWc25#jJ>|6XLYlS-8`Ut)p z)Muus%2*77J%R3o_L$fvM?Q)Qe}wCn2LV{mFW@_J09u)SQNn&*!Ta&-hNQ!U^--VB z#?%A<31tnw2a=Ica|S8`C}l-rt2i?$(hhFJdIxpQgNSFd9X$Wl0UKUw*#j4jJ()p( zsqqz}>hl9o^)-Tj?w|e*ReumP#i;tlw3=4Vy}3pZz?JkhTLDGJq#~Xi-mbTh5NqF$ z-AJT!!6`oj_r{rjHbHA-e~+d~TBwmdM|Jk`&gS6`<|6O~T9#c{63+YAuq6j?uny;-h9ULBiLc9Qzn#OH+4GzRv<_zGC+_V2aQch=y^gI=XMdYp3xAL^<(r%m=NazG8J0TXN_GE3A^?{_XcuF{h;!l9 zZ$khcm<|D`g$P7GtDNhFqN4d`^<`8?^!a-Am}UN3g}IDTXN zT-dmD;@6w_1sY_50q%KQ%b`Yle77kVnl6LRy@ay`&2Fnjf3)u`YU)=uz;^Uyf9&!(|gfzybp^i(v7{@N2I1DZo+ z7;~N+*zBbH+U|KV($`1fCnevjxd#&2sXg%z;Rd8b7^1mBR^*9!o=%#AP@j811@T~CZ5&4qygzG$4^-1;|R1ZxN zk$;>bFPWxT^?nVJpEcDI`G?S$-n{Gy^Jp#NIle`3A6pe(UYOl9c_FTk!tioa@zTdL zqsK?Yj=3^FgDYX63XbpZS6xs+=L%6EnjXX55o;Z*C5|t?&wNs=JFtPp<_9q0_Bco0<0TG{6rL(hU4C8TxwxjN)_hc|<{|!}5x9p4tkwt|{R#*S z)Cf4&$&D~9=7Tcf>-(eiaLM^#cks>>?B5&y0!$vry@#_-$HMQ%BT@!D#p5%!+#Jo@lfJkb(2QmZX#d_NjoBNn?`^lVzc@*o6@L%p1G?e)UO++-}6KGl#ucr zO*VYU%ZST6v>dZ{6MjMYGa(#szp4_`QH=b~z@B{LgTn5|M&$!`6&GitE=!+ z(fPUrnM0_^6h9uyvUeYf|1AXtW|-v z_}Z5{n0Tc-kk}`uZu~yU5zG$`g@4vQJs*wXBMCzie>XdctW@4D2RMwA;7~Uc1zW?_80w59*5wM%H zq%A5Bmb_#?0!xM&9@jJ2@_sprMBXQKrL21=LC)W5F6S>dmvdZekNe;M&+>KS$>pmb zUY$U`E)*VBfOR^5IXD&*89w#Gd+UPN!Up|}+u3}-!VJBKD!yM^czUbBUKxk4eHe$I zQ3|nY`vu0K4C51HhLT|z?07E{;b3<*8Z+w&ley9GpHIn&4~FjF7|B6&r_Sw^EbcP%q2 zNAqpd=fM5~jlFZ8SOt%vrhSzvx5e|j1K>(nAdH|=%+#O(S-0fj(_zk_lE|>2c z7@N;cGW z>&Q;K3eSOBOP(Hj2-F z;Ij^|s@0M4GP=uVMD_cypnyYFGdZX7u*+QOw)hI8R>c)xco^@?8L=> z4**jLdN`HN|MavbWMjvkcZ0v)$&rs~pDV=u2k4jg6F31z;X@W-p=E8aX1QmjR{8OMppApPfa!|H>2z)Bc;VCvTzRWwpGd@H?1v0jA zh#}3Wd>)+!I_fnNT|3KvQ}f4(JbgbM^7JU`z)p=^4|!T}zsQqQ-$qacF_8K)W9>hv zF&h3=!b`9tlzSoJCusN?K*FAH(f}W3>L}JX!4`p*=6zJCb1P5<_h0LFhO?c|G#*>m zp`EU}9jDdW3{khwJIiq+(C-;V+PxXBU<+3+n#B3AdZt(g8(^_=n{yaCj8= zB0#{=MxwN_0Uwm&aUI{Ukh?x;2ETA(O5_e-(rY8kRrllM0)!=1{7F@CpA1C5X`t^+ zC>7-F=x5-|K+rAGf*EL9FP$1;;zZ6;abJstyzUrASf87MbME^s(Q_W-hu)y8dm?rbz%OPWcAVfLk{02Inxf%7gqN&z zTtq>5pAF9u)^zmH@D?(<|0tF%%n(L6(88R>fwuW=p3SGIJkp*eSD)NoMeLE-7YcZjCJJE}TI+Z3^4&#RZkB%nez(IoK%boUsg^1hYoFGPk+waAAE)6f3BM8T0)7UN zwe3>{;GOo#RtKzuBl@qV==Rdt-d(!AY_{jq?M-pC*8}aDxN#mfj!J0R=|@mQY}Jq` z53FNVFfCOa7u8XBvg84DA~#ira@QeMU7e#laT>!l&>yp9MBbxz?Rp%xLA-d)-I{(j z)s?(mL;;J?qwU!Ml&Qb!npd;tHJY+AcKQz>6XRLjz)qh4P_-JPq1qGb9u0LNp(bdk znGSxW5vmMO;D_p|;l7>>I9{C^u9opOyZ&G7T?@~2PPJEyL`ztM<^ndZvt{G5AxPK_ zXd`wGGP{&!&elPDd|~b){D`qPh*5Dh2V3LqfsNCuE@&^%BfQ)x-wwlA>zQxY$6;I8 zCY*DM8pIy^A_h@%8f-jVfn@89DDb%zDGm4gM8GZ3aDxc9 zT+UaPo(<-SJvgJ?I#zP${1+rGKVVSig%)`@m@o^Iz85864V$L(geGheskv}?oA zj?9Y9>>A}k>{=mdrI)meR%M`W*TZ&q>UNXZ?qJ=n)0D-r-Ltj5tPyX8{@GdBt%>TV zIxW6;zdP9JK6!``E@#AL&YdPiYGbV&jgiD6a+1EL--S0Nw~+_aIJug zo{g`lpiFinEl-AGwgLt#K5D3{u`HX6yFRSt#tPj!B#xd~l{8OJ>{9-M;Yk)Ys-3$n z!-M%?(H+9SW#hq*!I~dl=GE7OPciZ`PE@wJJrVl|1B-h$EFY|k_+U>&jad)VEn`># zP?#eg<`Wv)P_ow^zjWp3?0(^&*e$ zt!s-9uU7VJQf_Rp46I7~MGc&85x;}7<;>Z|cj9|!zz)%^U0dF=(@N6dV* zpDG$_?~dH2$9F8??;!n{u3*2g)nWKw0;ay-VBAG7w4%}Y!jx07#JL@R6%G5FY1*() z%;Hn=dGb_e_;OgAW}XJDsz06x7qRybw(#7d9?%%vP7Ges6!atoGeDV8K$*}p+@(T+ znIp1Uf#N75Zzdy+$^{r!eeaP`C1FBXulHoA{j3iESNHbwedz6Py0_)bgKuZ|HUqVE zZ?#m7TD`$ujv&ng|5l%l5N^Fs=n4(}Frhc0Rl#*y1bU{1=AuMBt-+=f>=g}GO0XAg zFq%!>=|By31HeWZ8S8#BhOZ|Bm%5Ca#;b%B-s}{pBOhJsclo}Fcb&4D3|;+`F>ICj zH+FZi?kW;gcdR^f{TsEvFJge2Er1b~qkm1Out@B0H`K69uK0&?Z3b*D zzi%S8)>_zdx*=Ayw=Ke6hy02|Y4~M*Wod!oA1Tdp02BC&uHh^EVOee$e8en~%ZNrj zg$^QGl&J^5fn`w;TYZ}Oqd*v6o54Cs&kqr6k`i7g{#N)F8R2*D0q^$ep?ZyZ@&|9V zMmRcDFN=!B*mJA<@JwsId|tPA2iyBew>OmS&9mE^0i^ZNmr8r#e-RJIY*X@m#La~t zIZ(IPp6$J<+e>15gYEWc$#r{i(wBuikPjP?Wsi?-cR_gfVb?2ny1U}VR=}$do$ae5By`adYEpPs*ClHhU-PR zC4du`Dr%9VwH_(b&Zq>Was<(;tn4^+_>)o~V&6M8cQ^|$WPrmNwM)X4= z@w0n;{93O#u+aF2rSL44Tv4WtBL0G6TyX$Pl)?%KnP*fUXyQ#&!3imWrJ=mjd`oeF zU};@rg6kP<8hP#k^Yle4M&VLvVisHEjb*&+UhLVgXpW~K)bD>5_EnAs`yM7Sq1^YG zZk~8N;qO2rxYpoKC1P+If9^LrJL5g<($V+}iR#Bs%P9a^=OSkjrWV%)qK)WyqCid3 zNW>9|$21aIL}EI)44yLY$M&ha0SUPd!Oj=Jy{O3#>+|kBn60|%w%)xHZQY5s%uA@Q z(e*fxYJ}u)J;6|lI&zaRz|ZHtX?>s^G%@h>7@3*14aw`qv4fPt%O}JY$+%&?i zLI1$n=}%53+)^M%xS)n>Pq=cxg;(gf)C67r`zVypB;FH!ZW2hp@| zmeVA5nO>0hI(RwpnAsd2njLqakL)sRf467TFYBg9vgrlrGKMcB&~$j7HBU^?a9@uE z+#4FMJK?5iIL*4+`Z-$ z&1t!g$jk8qTaIjp^iti%e=uBN3fHhHH*LY+2%qQlhdj56Q|3*xYhain+Yim+t*vhm{tqb!19ocuFK0%1J1_?Pcgk5Uw87SQ zyWQ{`dfe@KY$qv3>_!s`nQ4pDAf;4=d5#=PbU4&49 zi+FL#X0{eKKg9?B&rrdC_U*v`OO1aL@gEGjV)QGH`1jHBa{^y_DBi%n)ZqpX;_q5- z`hJ8neSrFbJwiCsMFLyFexoC^0Z&Bu+jjQI)Ured9#{jVIBY^_vCWH9&kqrNzrPLm z9@O{_MMA!s2RdTpy%ef$J_7#)c9IOL5C$>s#r__Q^j9S%-PUnTq`MUPfR?tSU3GsR z_Lrmu{0C&itDd?)=Q?-?WZpbW_oogH7CieA?kHNd?eZ2~p3d?!(4N_s!x7O3wMf5D ze<{Q3@YmqtIsGN;_6*yqzbS9Ac@F>JulNl|AkkX} zSx<>G{1p%#cW^AyMRAG9FTBc?)wq8)C}+1Z^H;*cM{wifr4Dy8pK1c`jsMZ`@mv#c zU|Nyb1G*QPjF~@Lufo?0AAY_Sc;{;Vy@ted;Sa`Z24HPF{4!NW3`8Ue4EI%P_;(4P zqv1yqegXIqRUcADlD!i{1?wlRQOnU9=7TwsxY;1~dER~IovKy-aI@;Y5 z{jIgOfFXAmXwYs1y;*~9Wjc9R8>OrBA@ijxFe)gNF&tx>$OroVP z@o59Jcw?3Mtkx^F=sMxovRlxP8*qAg5Rs33CS=QnC>+vLRvP|S(68h}V62|TZwzUY zw^YW_8pKte1a|;Sx+xrF=9%%jG2EFo4L<^ME%6j(I8jQh<^Dt16=G=R#iCe?-`iaqg@8D`bDde+KTN z`Wd;4W}dKJyVP?v+Y@O(@RP&g9e`^f)une(O{O6GwIEFn2sL@qT{#7*#!N|kV&Gw~ zT2-DI=k8mcIsx~`7NqoFk(lO4J5uwn6~1|f1E0sV+>K-w`vTw@!}k#|RaTxBnBXTS zIRB~PhY)_AhQE;T6EwWjuS^4cgzr5y-0x+8o1@|OyahP&2mLzvuAl-o-!1>aGYJa? z&v?qB%@l7pnd5N1IMx%mx;p1Zu%S}8)u5K&Zi`!QJ$`DzHA44P_HWUBFZ*8vykh7c zEhhIqB^|yshsTr~(bw#zF7Ve*tcwhI7)}2$2szrtxIH z_RrQObugYoF3 zvEwK9&#ibU_}kKp94N$qVgj7e@gF37{P`yE<8#fA3rW`m&@1+n7FgS@G^(=bZ8Scr zx@!1$3BOLm|L`W@d)n~P_{a{bWGy5psxJ0=B8qP-FV2i@z{TBi4{wVT;|@Js;1<05 zIq<%h{VoDNF?f%be(mwsaET6lvkB+3;iCBV(D*t7)YXplGZ|wGuUnRl;D0K812L73vf3N)$_#6bDF?764)w1knH2+D% zw3!&IC==Jkk@R|M0*YdSa5E~@EY zqG6b+$k&>1u1I#5qYBgPJSVPe$5Bxs1ZjxvZ5%SRdnBL7afj|nPo=9C_%v&Sd_d+1 zPDrawpXfYz+2qB+O`K0bho12P8k`cs;mhs% zAbJSxxN$x&8NxlByebLyOJDdP;c?JW-GU>~WKrrM`5Y147^Xkzcx%$)f1sEA=oJ%Slz8 zV;NA20kl)#)6Y;;-Aru8A5c1~! z>V6Sv(VFOdd!$(46AAyQhJTOn2^!ux|GW)&d%lg@L31oAw(YkSkKugU2Hd+KK4ts^NPP-lFG+zXQIfhIi7l112Lv zPb^|GKbg12jHWd|z&;6SNuFzcjjeDl^t}PX#mBBkuM0I7$FkRtflUn7ccWL!`e^-2 zHd`H`P*sR%K;6tc5o5OPTA6OS7h8T?x7>j(m+O|D^rVoUSDT+hbK%qO!5;jWMXs;Hd z4ui(yGp25aPeO@Xg~@f{T(K8M zFQqJpEoKEb4j_jT6-$uSy~?OO9sGzG!V)mW9qg5E_^)R%2@mIC+y@2k#P_iF;ksJ& zz_3hQ&x(bu;lBoT=<<((caN`{Wt8|o#Sp`|N(!DdH_Ce0c0 zrvADxh166^oo%W!!WgCj#;K(mIFm0zx&O!mZ`Oim&~|47Q_+CA9oVWTqn$bKJI=oW z(}ETBn6aBV#jaEK8-8Zu$YOUme$ZM_weY=MlVa?cUaDQW6+i%&M_?bKBrtVZVb0+)M!9WqC5c zGL7rLH{&@EXBG++J_M8oO=-kASzh+wxt@nc?n9SKRAj580!2dku8i$BfTe^STdi^+3kQI{j4x9~aIQP8fWpc$24K|f@EXz+`i zfH`q$?NwqEGOmS9;2BED{X4mk`!DlE?tLh-V`F~k5M6RhTDG);9k>k4-oDp z4d=8aZoq}{oh9_j2?77i*MLgIzkpyscpXUDf^5!YHRN;g`>4<gm}1+~03@6Z78b!Yry}=ycispiqDIrEaa{suW~PV z7`Aey^fv}U7F_v*olF|(Bc2WpVUV*vzP{{lN-{11zOaJ*A^(3unkzH_-gV>AiD#GT zQ`R-{kapg9_5luZ*!}=iWio=c;VpW;jN&r^_)JMzcntV(7FjS0_`KeH^2bwPoh!(1 zZ{eFg(0e_5<1UR?=FZWVBmZLYDTCU^`@eCa*XVU~n}F&4gI>fRSXKu)_&$}Kli#N{ zKDr;%Gs1CGfk1F@vhTN6#>1DOfxx_c}zQD|xL3YAlvS%vMMLr_1DW?UT&9cHhHY1SKNqO}Ts)xf z4x4PCO+f%%#`zNr!tAtNwc8<8J8>>T!9Mk5*3V6{8qn>AvZr}9=FbxLAhZx)EWxaW z#mhdR;bZAm>Za63#Gf-^D0|L@0wpX`x3JQOx{@Cp;c#7euxWNvINg#LElE^ln7GSO z-4$#n!_O4X$l!Iv3k;rjyYL}7ArCx{e~|2y% z;KGeTfzQ0BRy-I#((p6q3#yMJ^Xf`m@{LP&2En+r&Z@Nqfc7CCHn zAz+M$-$IM{Sd=&?^(f&*Gzj1Si0i`eeG|y9db2HZBjA9gU@Y(A6;gNTCa}Z%72b=e zJc}Q=dP2pIWM^zGVGMeX6*YVxw=v16WF9JUth|p%SMJdb8bwF3fc*l8g=>mg&IM&5E=yZ= z4~HJjS|4ouDE>}DPB(G-HHg^p z>(Zg5vC(e!MS8lmc~6GFCnPq)^YhS(F^l_hAi_IcnCz97zu}igptCrNemLUE=6~1+ zxTxm?7WSBP29hzm?&6RzH&%PEhgIWU@R8OD&T*RbQ1)7!)fKj=)kr&VkdMV7C3BCs zvbemG%*JWwNW>A>2&sqJ#mVf%PBnQ@roCog?pnVGqj>an?DtMbyQ*`JOj*lan0g)r z{+O}~d2Benk4#y2qR5`I*5}gK!?>7jqWo6#4creD&{GiXiY=alsQZDnJjD+~g@A*4 z#bb*b+JK`jV=m2|hq|_Ykz>Okn3fP@S%9WdDBqD#_l2WxDtqINIRpR6JPf!rz`;yc zZpDys6g9HR#4WPl0zaFld~x7-o#Fc)uhdz+g#-1);J_%&f&M(cd_Fh>XVn=fUfa*+ zz^T$L?WlahoN^#UcA>=i_QbR6WYgu~(}F9co8jzcobF}|&lxX5_vogj;}Z*`Bi+oy z^#|JC#q=|BAo`I$NCTO6!5vZ7_}8*9ze+c@!j3?G&9eT%S$3&4jENQE)X<2+k}|4~;yCC1KJcHq z4)$FIKmUm55>9M2kX|nDp@{G!>0_rk>PP(%tUQC$lNYvUKcNoao`XL2AxR~?$l*Tl zdrXLUqK`?|{jj(Xgtr1JKYD3k?kDZ1H>;+bG?V>2n$c#X9>;jN0;W%YIShp3t83Jc zg|dhXb+{Vo9oOcZ!M4+*E zeo%Y`|Ci`5|4@EvyeF?Dcz+t>r&pBlBDWmeU$oO@6mQ0zKkD>i*p$G{af?LCe9L-A zZ$rW-Uaa|5lALD~|G>6E!2y_!cuz}y(+$ai`pPYapT;%+&;WGxF+NX|#>Hhx5FcoR zNGG{+zL;mu#&;83N1KwV}+6*Y$+$@ zAH*|b#-{*3HsLK)#^o|bjrkZOeg95wA7a=^kKO+1Sb{qZ^%CmD7HcZ^gL0r?-?CUD z%%P83i7Tcs{Tp-Y=vB?B_1EFv4$v>x3jGs5)R*||ins_smr*smCpCcvb@Vd6kydIw zZ5U~R^P+ZkWobXG`hNq->u&&xcU*#^&_I|a2IM#wp)JGz1Bu3$-_N4fudQKHI4>X` zRZe4}o5fW^sKoBm*rr^;or=xB+qiQ>f#KHO(u%-)(`s(U#sL^=L z@aN;Lta#G!1I=N77_a;Gl)EFV+L5AithOW+wNndOU}&6rt}rvsF+bB&0$qsxEnG$f z)(}+|^1eze2Yy?)oW<`-@znIRniUpJuZ&(ID@)$oJ_R=sJ4g9H&`@(XrX8_U;mf4fyH^38OFKY!B=kYFi>Zfe zb=iG|PH#~!(#QxZ?TO0YrI89iL2e&PE=01x?m{3NSfQmwRz@-^5a?yVTTRowjbd-7 zg6V?o-%`<^PxqIBd}4d5>p?^dqz|;8pJH~7_NQIl4k5|M9+-R*sFNYb z&?Bn>vfxSYL17T|i_T1p`}0kZsK=9GSk;f03KQPC5@^jwn^FGaPFK+VBhUsjoX9-| z9Wu`Wu(o4ro^IkEHo;qL_yu*?Hx<<7Lsx)N9QBN5Lo3ZKg49RF~u;5*xE!8K56Km@f%c2j99fdk;LCT{$+tne$dLu&V`zS%OYW94Mvr*1{rP5 zQ?h3o-pl=<=J;$G5XEQtO((;r`xbsL{{IJ`aN{51Gbm7(FY~9l6ctBR;~7G3zJ~{K z3V9#l7g-w+aSnWH=Yq%wvQpGHy}$vG+6}`9Riu5!#nh@#54jL=Du~ByxH%G>)N+o- z5!mHcE&?X|)V*+R^ljFj!O>>aA>5jYmU~M$rZ9l(G`G6~!?9@k3)Yl)ktOQu%GvID z)`C*?0O4*4jUh2w=+5HK>ABby68H)Ra8XZ;tYP80qh#+3ihl4Fv9Z}~CpS&&g{i($G z?JUb%a`?+;*Z$1{_-5aj=PfbM;h5*v=*EGN8IE~w9aDcy^JnoVeY<3NkgL~jM`eZ?o?l)$CAnFr6<*tqgVWS516t-G-H5m;}0^`{qO+LP$&6{r>}or{kWPrA&f?qi4_wafKZ2DgQP+ z8u0{})Oz*qm1IwYD<=VWuLKKRh4>y0kmR091=ts7uh*j&{^|Kxw@;~4-(2Eof40^B zRTLfAhaqe~rzp;Ijw^U?DNFjJqzv7#SJ6A!zlm+%>NjF%Vb5U7SXIjlx3aak(&c7k z>?>efXuN-^PGrmX9nJEdU-3|UoVRmBQ5*y_lByORg+kyK%Fh227j@g!nK`^6&$Avy zgNMSQLQzXyv=~MA-m7aJ>@BtCqv(Qm+@{&CcIcvKjQ8<*+p*sE6;tBx^PW~QrA3?v zcQk5zeT~<8&&G>uydC($@ZSl!aHu5k?cu!%72>>ufiM3_3Y-nE7M(Bi+vhzozomj4 z%x_2VRccj#0Vgwe;G4yF0R|%d+~;$fbl&Rdi}}ht1wHv1@AI}n>tnqw1+N!;jn_!Q zwN^n8^gLIpsZJ4k48I3}C?5K>ru^3{NIAYuq>C5csEfa~iU;W8&O>w~Yph~!Ua4c} z3G$tY{G~u%PJ}tAN4)OFlE9Y?!K~0D`w8s-r-QLfo3T5i1?URkBMWXy43@q4q`cbw z*Mru|%X_|gCz`b6Rd4$5eK{enBxjl7KMI~mGQmEz8f7_~r*E@7$T83J^AbAG1s`|C zY7Vg_u`8m@({|d`%V*fJvL1_>UU?$*G^m^crKWYfGQUPs$9Bx zXhHxT?NcN1#Hk#cQz{1l*sjDicSQH$-+)^G6?A)KX(-(wuO?X?K&K_aYq4!(4no{H zl6WG%tJ;Wp2Y6Sl0XTX9acVzqGXP~F&K!jxOJ=%oAHAOQr3veYXMy#1h=kIkkFh;P9!#-dWKs?mz(8Rv3; ziO8Pd<)-sEQq()(`pk0)IL4#x37)~eWaUR0C{8vf0}qFU9H;-$@0%cTb;fS(QhL%e z)P@BIIX;Z=&`|+N{`_LeM zodmrK@SU8;-FpNLdGk_FXhKv0w(UjlbRFOK!`8OXaVePCNk zNx(P~pc57|3)4s75`M!!hFFHWUz{?hspfwChGg*&Od_^6D7mE|)iVv>2!N;0|F%w zT#~T!=>%jn9>q@B$H0#f)yHpxd1Ui1oUi*#<1kGhqTdEe@zxxP(ZTwJoCL$)KMgBT z|62qD0m(HJi7Xf&WHcR&A4Y5{kt!z5j_g4C@u0e%Eq2w@4R)0uzQ=q#22H7+ol#D% z%X|zK2zA&x1wOk04AmFsBKGtHeNJ>g8UtBPgy!MDNDyPY%7Oufl#L`Aw3iWS`w;sb zW(e2|tL+sDVSOYwbU(XPrJqz;@c)yq8(h>=Hi zDo8OiC_3n?OM7cX7NfekF`AdGHl8Vb?bj82eL?fJU0d*V%ULpC(aEvb@m1%5n{xrH zUerKyF9Fa-q7=&A)&@X-(?AK1kNFKI(Cq~Jb&d$%E08DZPoGDqKMk6`fJNWsz*nxC z5^9L~Jn+G!lyOo>D+yku&buBX+gW4Kff(!n1}0Z_QiVXLr7=={l{$1C-uxgs2!FF3 z9ya5F@dkXq9(CfD(Ae?&_2&Y8c-MPX0uDk@Z{XL;_v_oC2^S7vP?enDtC#hmWR|HN zuH(N~Z>+NRtAA>Pa30rAtINjUDIywdviGWpCI>ORwYPLo-U_9!RW4^vM= zxijNu#H*Nos*I(*fuaM?HuS5#V?_hu+ z3tH&fgKH`1pFt3?qlONhYAQy7Z<(D*cMN67q%%<(iI>$JLLpFYi8jr(d=s_x(zvYuZ|G+sj+M{R~qnVNfs) z_$JhFDJ>mgKMUS=O?&%!yV`^2tS!!b-yy&_@=ct;LDjbc6ICTk$J3s(+orHs~i z$;Har{NV`BU=i#b9r))67#&9Vo~y1;qCtWmrW2)|u*F;O3!mS@E}bW-0(po7u)Tf; z2g%NvLvN4+hCwhF-wP>#jms&j{ND2wYZV5*#Wqf0pLP|@PiIB^#OC=FgpCp07Bg`TK^` zn?KKuc|M%d{QVWtXEV6wm{Y#YBM2oqB+zW#rJ4Mh&ttxEzMm5FzBNpp<9%R1E*$KG z6BnKG0|)YFe1nUaFg&$18|@1NpA`lg%ztzQgsqRk=_AZ%P+&jL_!0JNdcJ%n7cHPZ zpv;LHg!;_SX+a^DnoIM+*yCA%ne}xwgWWA?ay@h`@6|bCk-qEJ~*fk-jh;xAP%hli>;sNTxk2DKG4R zK`HE*QW7le0Lxg|5w}Y&O>yV^=F(v)$t`$hcK@(nYTF#96NR{r0>V?2o{fTovKq_^4{! zhZ?#X;ZWR*ONTG8I{dMwOV_VJ@BBbDh!J?MvchX<&+!~y%JsLDzs~Xn(RwfQd0ynX zU|jfVYyGY3QyRj)==;eg&Y^I=a|f-l^gRxrTNVY6F@`E(?4m3LEFQvg`B=WMAzqC` z6>>8;F0H9F`Ml*tIY+(QgNf->0Isj7xlN$T>;{He_7`6bT8j5oXOf3?yE++_27iUF zLna2kgs>wqKUkO~iY?i+f%UBZz$ViaM>dab`iJ3nL~f4k(sEP4j_UEBrqdmq)EjBS zhMy_q7$wzfHdYgd)$cd`OuZAqsN9L_>S{wA(Shf|qeCVHD(5cb1$ft|(7_*=vAB(F zqeF31Uw_*2?+>+ub9n=xk^iN^+YmfmgFi^{b~bpDIHdqTXS=;T_<-P@h%3eqwx^-k zwml!?7nTg2A;OEv7fSn0^>F0h78d4V|NAsS_k}d{x17c+lzS@sn+H7L!#iEzQg-t; z1`p$E>%9MEJd=sf;BSP99l=C%7E09cVZxu@qBtIu5Cy5H{yI)V%GN!$!O4iv;r#5H z0l*>HhJ)@eM16PgfegvVo(#t0WWc?+qz}uun(v4!^K7_^>399URzW5HIQ-%t1vB=Fz(mCA{J0pAl+7z7UZ31hqA^ zY={YxKmM7(ZFFd5J}TgVZ4JJhiobi+v$8mu|JkyWw;U#KoY>9l9U-{y>5m#$rUz zHfxGRQT)kx9T}t}SS^^hV94>oSkmGSv`JU*48hPe6!ZrAP}4T)<`qy`6>KB&kO&+W z^Ls~T7#NbD;Qaw!!FM-0fRMahf!~iU<*WmKQ$=~>iuweJhAfe9hT;?nJmo39)x_aZ zesY0>4LA8x9Q?x@L>R11JUEE(uhhf$S&|`%B*DpPh%c!Pg`9A`r`a}K`-LPrMO_r6 zalw}>9xBM%6K)OpMBJ({=NC^ed5=M9j~ZABxpOkS-`i!?6^MDhpGTHvxPr%i3_WXiWZaS-0okoK>5Di~ zAwsX-MkTG!-z&6w24FpbxujmLF3@yZ8KIV)!wyBc3%pEIyYN1L-EMJW^L^jP7x};U zg*b%7u#S0Vq;%z1aS8?gQM`Tuwx zvhVwz+nhOb=FFLyGpDV>SDXajMFQVy;8s6JnbB6OP$5&iCia9~rx(^h2j+HdJ#fD- zyzmX)tIIMKJ$of|Ud=^937XGWS0%~vkH>lTDa~9-X;GP7dl(?l%q}%=PdOk@=}XNS zukUl8^8VE_Eq!TzP3T|-SG`AzAc%xKY0r1~#rZ>a3vxsX5*mm&hjW(8Uzp;!|1;G~ z(6eNj5x2Y4G68a}zR8Z~WdN)vDN${it^jTiGjNHMOm&B|NoaLBY0ASi$m_B!`9PhQ zq3Wel@qaX9E|rn+RPLjD`Iv7T&5lOtms;9SvrcgiV%n$GLEGrZ1jG{}db~goH7yIL zj|YfvtIJ+_q3UP3B(W>UW3w1R89Z|`ZO90o;QH7B6%C0b5$KAJzPKRfsT9FgszahJ zrMkFX;5n}n%HO;NUwbNFBaa|aZLEIWLfREb;ZXn>>!Yyd znunmQyc^pb zv4R{6ql^8~g_Dl%F(=>Ol2g@S`5{g;Hx@gwC}Wi*|ERX8H5^+!fPtY-{lftYGV zev$XfRo=hhVk_^@lrc`MGX=NFc};eh45g?6WTKgyitN~qvRSjtB=>`8dE?@KI~DhV zr_lt!j#O|z$>^NhRjry{68a{+=!`isIz^tjIAgN%mQsu5!~J=JlG?$OCb9c$@6zsi zb6^v49|_<($1)ivZd%2ehjc@-joK_vyXLnEfl2&_^S7%U=khMOqS{M_gt(MlT(CX3 z3EO|%|43H)yB4t0m#5&<%xR_L)#aon{?%Cm48Ga=h|wA&tj^u}B%$I~dIou(<@WBJ zR5a+}V~c{Keo9gC_#JA(rk~LkKoqAR#absa+9K_Fvh{i%S{oNwUa6)V@2bF(reZu7 zt%2)}m&8kb&Qt6$#gFKNE+^hzb!P^unLa4(S3>GmA0%PBOha$|AjjAOY!}R3cY{$B z1iZh<`$#6w=;$9qEtB}a(qkRtp^BUhM9Qn~N>#$oQLzlJxXMQep7K2Ns8)@ZCephb zHw2pwQgx(vq&+A>Z#IBRnbP?G^**qZ?I*e zo7Og&m*^A48v_$LprzBjp^FF6+rj2dL7uCapUD^2y`88=%t01WvKI5KrhDv_wlC+? zFIfvZ%d2}Z;%f5%?ohnpm0c6)Z~krz?`@E*b*3SpS=Hy_Y;&W{nk!jzDz5M$(XS!+ zlP-0M^@0fi6O(uZaiv#EhtjP7o9Rsssi$Xrm93<5qzTb7>AG1_<~s~+V~HN7r?saf>fiFKz>L$s zCsd$(TJ9r2HZ79e9LMdWQTue=h@3KB3T#QoZTB|YD*A{>#|r?%>;NP-Ey)MA{{+8_ zP8S|%_ra0d+Ir`eOTkF{)2XRCPntkNyc8pkZ9dRhL7`dB@f1bH){>w%IIL{k6Yt6f zz914_b#6;#13wBI5Wyu}-qSpo4_(&v?@1G`8wpFnDb-!bstVZ#Gpd9fRW;I}Ri9e& zPVD~^x0QcdeJ-Wcc_pFjzmaxni~SD=ClznoX{h=TI9(CVhB*Zv8VEBN$wd> z#$Qa+RBP<1oJOK>VV`K0PZRxF`MqMBncg=^VX8NCBN3b3_vyU9*huYlrq^%81XoO9 z9l>BtoWA;|>HH}<9xC~jw%lL_GI$J=C&_pI2d0xROz5n->Pswq=IWkQ4ZE)H=YA;S zLv@jT5n}7fJANwSY1K3y;+CdZ8k)bI6YpXPD3=}uFOKzRoz)J4v5a!e^O#DBJp+!u zeL(R?u(|Lg5t+<@H$@8&I8n39V!Ld*7{KqVQB=qp;V#`n#Xu{%N&KwEVHyn~{-&ZB zBJ6`4+ThQ{@~1?c!9UCu0a1?`tP_JSvX%M(jBOFvfh>ltjX6}JY{BBD{@s_*6egUuF=mwl`Uv+_>+@ss$+4=y0* z2>s}(lIS~tR_E0--pElWY?Z1`eyBM>HE)< zf1bWifcEL@sBff(Iy2->OW!CdghMsa_sBzRYa$(Q_axExEr<6tr|%BJEK}+GH|J1w zGJTKXLo$62;{6Ev7W>hy1mKH1;)XH;AJe%ee3s(^9*xTNREYHs}&$&b>i+ zocf)f&7zZIruEik&|m$6EhgmkMGr)U{2JL&5^rznPx}!3x5n3oZO6i9XVT|px}jc7 z>DYYHKTXRMp#$%iH1iNOaiWb49PyFPr>Q1yy}0~0Q~}e8YG$LM0Jnke0-8+A#d!Sl zeg#-!pEf?v?BIh6XtJEx^?B_<#s3iCa$zjIT;lm{2JU7s&W06P|DOn>|3w8mCZAc>C4T({!BORe*1;oEn5IdGks^f$gm zdbfDkIzavKTbqS5eOw~T1RreEof)=@Pe`|$Mz-civ2y;`I*Xfbl2d(sWDSV^4%J%| zKSPC2k1-C<+yJ!jYukS@TC4nVl>Sc;P&>Iq7d+M%UM$FR_58`WQ29sbRrVio?MT+n z&|TT-iSnK*+4u;J>jZ&?ozs`NfojBff?|T6HC^d|sO4TSLIW6{O8<9Mx04CGE>BZ> zR=4L(1d9*s2OpTbh5#a_^j77HzvWqwHeGf#;RQ8RY$oQ*=&&!l)js5yG4i0ZO#|1+ z2}I28_flmOzMzQ;N+VB*2p^s_PWajBSgy>&iFR*w8mb(7qBs-11!B6!e zH|;FaD$YFYs|(3z`N!it`;?Y^zDD55-vbzvR$D!G>lVRd^j0D}KB8D~X&e3$B}c}ULLy4yF$uYpK#_F@|&ZgP31 z{5<721hipTF4e^@*j19vOQh(-eKrd$mn^4g7Ek3vf7Q7+o-{DaJuaa;~1i?x`5^7kw*63Bme<1p?s%5y4s*Xo@WW}0jcsaUjh#|ccx z$A6YOUIaHxi$`LQxZ@)5od>yDaW5eso3%e${-4#v`7VE1`2U_G`9DlDdI>Njp`3Ha z?V=abm`jH&8K5>Tx`kOS9YBbczzum|JfBvJL2|J9gUl%Da;

    e|Q$ee-Rl!QEOcN*1ksHMo=1iMF4;L|eS-@z1M-uyxF^iwPFv_@;$ zYZimMW^(xL`}u@Ra`SU^Qcs1{Gv3zoFR4dv+l3Go!MMshP@f-0(ojQ!@p z9&Eul%IwCWKSMG0t+^-5y56SqF4_S(%|9R)RJY@UJvgVIvjuq?6f;*s2k7|^Y5y0@ zn9}f_eM-aAv6e9uJ17>9%Z7KFNShtqHWrd(^>@KjrP9_qit;otTgTEL9tdV=M~CrK zt%)Jy7pQ2oU3coH1|{n%nV8WI{7LNZOzeB5l-{`4YN6mrKFB$Z&?_e7taT(%t+TC>4YN49wav>Gq zX~M=~Tq~8LqJJgLH1Nt1(}O(6`{Nzvt^rIl=QDc-;s+}d&Df@{V?y`PGYflHrNX;F?coXkf^30D_WbH! z;5~hLalw6E+6BL&`M?db3JnkgzrbOt7z4l!P7pkqt}jAH6O}&9_y(oFE$L0`&6j_M z`X=o>g8Fh{mCSZr?3Y+oJJFh6uMNEP`xW{P3p?5G^ym_uO0&q# zqMy{8qT}+?W|#rQ)lT4eTX<9rJT>mANBoY{O6BgqlJcQ21lJL!n|NN-9NhTpI=~4MN89B+e92bEtp2`L) z+A|c%$ZV{>sTp1F^>IUp9vfaJ#Y%$JNP-mKo zi_sMfhNWlNOuF!+(t^F7s_PhQ4segxA-DE50W6Cv{=l>#Zu?nK3I{9`^WQRCG(gaY z)*bsi2}Q!sIR6I<)6DszVgcY| z`P;?QYo!z^Wfh5@l0^UU`@H<&D;X^60%)Nivl%EM6%V8`At}EeB$27Q*VN*?8Xcl( zMeM&87g5sO&c-78Ruf*7z8*hA-9e`pBFi0X=OyMe?COC*I)>)6anh4sa)RC4_?dXI z1=qn*qF+*x)-aSB!nb!hS$$|^oaHOHEaZE%RGX`$d7CM=ELy3bimk;!`-BQZj+?Vo+&nX}!j#|tvt-1UNP>KC9zYiH}1uD|gW zU5|fu>6}Vb&GB>Xkv{8a@aR$~@dv^)pFLW79A462Ia+#LkD)x!4c{TWmtNG6-*m{8 zQSnqtVZXD@U%RbkN#7S_M>z4CQbaUlPSt44-`^T+MLPcWaq+j=zhFZ_t) z=D;p)pKtJlCs#Ml9AC`&_gYM&E6v6Oc_hz~Tu!v4oBIm?y-Ff6`(geHX8GcjXEp|5Q3>J_#Rd#4)ZDPcJXIH88Vq)JYy)N4ey&jh( zxGKEv576swjweB{$)>+&zuT8kWXI)Y#_t{4VYuvk^vqRdZ)gKC_~o2I#Y6QZrz>WB z&Rd!{X+h;YL()dps;$2m=q_#*lw=C#%IcPJsq>P;j%dn(t0Ia`2kwqj_(O;-^^fBmR5f=c32J&uZ}2Y(1}# zDPE(|B9hL_@7HTc|3zQ?&Q5==A#yTNA|K#=uwNA7yM48>9DnV1*`Wg&p2|o0j`zz7 z{F-X`zsfUrEnc@Qh`arAll5MIZ7jE>O^v@c$_AKwtv6(mYc2oZ_0=}?ENN3uVR78; zBS{r2YkY0ijFiWcHf!w9JM!aeBM$8R)cYJ6DD*O+4gHE{O-}cQ-YF`c)jBbrMYAr{ z^kkSqoBK)S?^P7Hso|lxO+A0xtZ`b8#J@?`lhEOQcXwCkP`P}%Us~GTr&MRiX!6$B z*zax+#};6>wdNAfqf2TxwTylm=ii>Wq!E<&of^~1SrHiTnL9AOs6v8l-cNbY-0~Kv z`!8+Drxt<1p1Bjb%wj`NE`P}L*KWwwZf)!%5%uRz%m7Wk+HZ60Tc&63HLZB%x`a*i zd#7~0ni}O_Ki}ye``XmfDEj5v4P@DBF|;vf(5aeetJU8)-$}?o)nlqQnfYOk0U=^;YsPn%x)fB6s0+>Y&U>7|nAto>@9luB zo6y(A17~KD9=+>$lA6*49=5JOE|M((>)~qMsN7p@*TdFw7nCzxG_h8=O0$lQH`AWe;N6R-oriJfsd zCC;-oT?PvDmg!sn` zhBCuz`8cm7HR1_UL1^lwx#rX-D2(Php)OileY-;jL-{zWfR*@;QfB*@Ff zP6R2`a+x^~iTz}9mclrOz7Ia^IqXAhuG#mngs{%N7`C*8V=;f+Kk*#PftI1VEcjk42c% zACKn@zgeTuPsOYr67e8W=#`{GvT*w34s1Q16F+C6FHQU7quOImI|{xUsf}Q}oL_u- z6HMDRXA)8>Z~pebcxnlJf}X!>VT0gI;g*ZfB`%}5mZ zZ)mD}Gy%*1f+qNp5LeHHXE*#bE>~6r(?l+}7srXX;4)OT2iaY9$*sGKF7+U|ZObm;geH(q?zL9 z_a&*L65@!KhYHw`OV(3Ax**Mr=%^c<)+;jG@~XR;ruixM)+?<4k1ukUPj*#FD~!nZ zeI-k#c@y~+&3~2;!Rk9aBe#yOUa5`rJ_9uxcHLF1bYo{XpYP&TWH)Mr#ZH%~1ba>1 zMXXSGRYZDUDT`yI@U9O5^WhE(=DDGRS(Cf*@z?TkAs+<^>}4-rBY^0>hRqxn$*WP! zqOVDfe-_uj5o$*4O-Ho-T7h+L#w!Prgl2YsKr<)Wwy%-4OEF-5%SYJ~U&41AcQkON zKQiiT_?@CdxLj%!7W zw7si-2-36GFuWEFjV*^bV(4-E!`L>O& zlUYE%A}{pGm^*)dafQT?L>ONJc|SH4^eGOauHzetsZZ) zge1%Dsaa-M<9;gT$C9`>m*?n3LWc?YN%?0T-<8JmYsBCABJ$dhM>Qm%pv{S2c184~ zqF7heM?h=sEpY5A_h9Tml{N83U)gHT6+ViM>yx6;K2P}?K16)!PP<2iIJZEhcsn%) z)_TL7Z#C%!Yo^zWqcL}zm94JJ&>U-S&KrSz|Rz1BP zTu}T7@6Ce|S$I8_>nWycQ#xv+7s~Wb9>U2@Lm23yJ-Es8Utd{_emEUo6S19pUwU!e zcTb?eAKJ3h-)31;Z*HMC{@N`WI#jVlj{-VW@d|>AXEXY*VR76hZA^b2nm{v=5jsd{ z0a{8V#x^GAlO4}Emyr17XvCT_&U4rKl=c2~>9183+x@eI3!Jgd4(h)p9dLZ7d^ns4>ur8eOZ;s11WxFExq&pY?OTc7>xDg0xyBFBUd#Rd_4VJ{Iz{$D}80V z>M~?g4M!+`zbOCRM5*A)B$mPWwEGuQ?GHsX!uWiL`q?jwOxdnPN^DC~0ol(r1~O2~ zWz&TsqJ-;*oAj>Mz-V8=?lAjCv`^DdXS+Ugw!inwl3=v?iRva?fm%{Cgv!FF9& zcJjhqBzqGt?L3t~CSJ1Hb|hXpcq+e7yyRf)NxYoQ5v{~auBUQO;-!nH^4`Qto~Lqa z;-v?%*%L24J(ZgiFTIdN6EA(3toDT&3al4qFabwqL1z6@dAC6ICjxI9+Q@K zeS~Tcix8R5J{n2mkea5~!IwnhGuQ92as%>2b$>`;q^#U0KGrxo`e?eqSR}{R5;ifE z!EBrx%{;BdM%=PNv>0xvP9)O4qapf$kerQX`jh<#?K&c{ho(s|(@yf(cXW}b60dam z=u7k0)xZ{*dsj%=zN3eGDsQ)GW72|cy_n=Zm1Atu1nya~NmCL@a!-M;@6)qD19!z} z>cZK)Br*)qvQIy&8P2vDUP;byv&|rzXiufbW~fQdAOa#y)N2Oy=?g7fqZ!%@c=Lo% zN<76iq5;ttU%}IcZ^6@Jwx?4Mom zaq!D4A{~nG$^Voo(xUEC@n_)aI%^P2lJN3tW>Z5^sCao+dTf)urJS&jRH7hC06RTCUA2l|OF=^ydbG+tqpCE5}^6FkP+La>l^_N^+ z%*_M{+{NDsYz8$JP4raFBNQlO$K~6774a;I7N3FZz4MgONHmD*VNE?+dFZfo;!{4` zar;7^NKcE(HBYv7aow?mApTyqB01VWPlxR<@}y()v^?o(Ji-&}D+k^uqm+cdsK1x5 z@9^xvaQ@P1k*;|v@>I^SPjq^^eVPy`_w{{3J2H)jXZaeK%7YL_;2s`i@B@>pbt_iz zgps$*kxTPeLEjy&;eUPTwyg9ZJ_Rj&b+y7ccKSTES#n{W-{)F(>MqTu7RZEIpzE;rghRTGrGY{ z;|n6GxtU*Yc=E|yL)OFD)oqE`G-mpM#~+zlp?SIGMdOPhn2GnskRuD+z1bVSD-Y*@ z{8aXN*rd1P& z3P`^dRIWN8V$0g#*Dy%;pt3IaRzCJe9UeL32D(ZA;~gdk zvMj-PImGJhRUJXoHIY^y&r*-@WBo|ckNlGejMW2yY_Y5jtnA|XT+2~fS80DY`g)G? zj_YZ|tqJU3}HNhOg5LTZwret?Z;rJLGMQ|DA@s(|zlO$fB7R~m0o=ZCVl`JaFl zG=C~WdJC2ndrCI=%YHJR6AyD_zwBhu`6@cU7rq`^mY1+MSc*v=FR(FH_V)b<&M1PF zid847oBdRl@Ez6nf&(*jAGnW9?P-461fC*l8aF%jdFpVp)qa$YnV5Z+ZkYA*jD$)x zps;!-HKA8)LtTmal}tQ>SI#>>0!Lfihw=i}EAjY=OTj;V3Y;sbBjSVxQGA95keS=Y z11OH2t>>+5d*<1_hY7HJxZ6{d{`3U$hOW34BU@gj&pOULvvH+w>nd zDz!FYAf6tLk&=WjwySu;Ju2QIGNftFPL5TyPT%RY&?R>%n@U-#S`!HiS48uUWlJ?fy4?j@`d2h-1ZFpU3ITwafQ$U(^>ei#o3J!<3m6X<=*-X2!c>{uk~Z zH{P=22{j%+xx26Ib4)rjCih6g`kdhd7Obdj@G=XgWCigbtZ(AC;)KL&qQ9bjC{rcv zr4+Y{_!4Kk=(eDQ*s-W!(bzA~_Jt0f!2ONkAbe%3`Bg`CbJ`?|76Nvi;u?8X?P~EX zGe>>StfpqEKI5;`d_J=uOd^M|+z0*t_C2{a_ zo|!L#?Eyq4S{n=ufL%ZMHt!{JZLq)WGoKSHaah1Pn$R&W|9Iy1Evjg28#r-M5joBF zn+{twFkGi4X@WlQtbXD(T7u!?W8@I{f^X{Ikap_lFAD?bp9X#%vpj)a*;fe`?fJC@E;(zC?tHW7O{V@ z{^An|n=VFZc{uhvS&wNh_C#XayxVi?0n|&8j8;2~J^yGO{IS@n@jbD7>1=oYNV+E< zvdYDyfzR^pch&%&Gce2Zyw@Qv(2RovZ@x2#>yOu|opIpSJ8$;ObDP>3`|k|ge7k-2 zRL%s-83(<=z&OphWX6G;?+o0ksY_<;FY}fb+vnho^T=7@dA^WEtYYF|uZ?EP2XC8q ziEv3YwlwdI1N^O+_$!gkNh$Hn{n+1Vqn>)6_f&5>*%Nw=T54n2#eG(LWY2 z<)Xp4p^G&0i%EDkc+%_7`j(_Z`4c#M#w}><*Yyi+XvNL8flf1S!C9odabDxr#s=@{ zwe!}KcKX09f9=NHVyC_Y(@vXrAey8ZF7)FQE_T>6=}i8n1=`JO?F;R|@LrxC{2?{7 z=->D1WC=JUVQ$Ew3uF;RqtzDi9KpB z-cD?n6@dGZOp>QyXyJ%7Jw=YaIK_@_28Tl(Y4ca{`)W2V$ISu~S3y+vu{ z8m{n-rUy5cIBQbdxAV=`zgpwx9i@?@R_Yg3MMW7GJg1+MkiErlY}{GPg96HoLvz8Cy4c4h266c-mkBr+VK6TEArE;&h;f^oXgPXb( zi85E5CnN2OeBsOX`O@(hDFL&v-Xe42$0F<9&M7JpO-FU<Ff5RJ%hIQOJ8IFJBSQcD#~9O z>C!sZHZDgwt9y>>GSD~Upg6kR%|7;v{8gT}in|o|ysyh;zS?Nctd)G@A$!(``SoL| zpx7Vo@Rh2G8YIMpj}3*l@pBPF+vF^3Ze&#|3eATxe~+cGoR^668Ugm4G+Ldh18H8b$^tO9sX#b`%*{ z6bq6uJ83wCKT(VuTpGlRmCj9L$cB5rEQ$20ckzBjc*tRhU>%aaATf_P+ytN#q<8ht zXwxMIjYuDoBkSw9e z{Xj@Gsy-6;3Fal6PDF5qnXPL1QMY;Z}?Y^RKM6vj&suKF>S6w<~qN z^>r(zZ%hxJp6&k)c2ht8)FWwmFX)H_e!1pa#ffURey>Gb1#ZM0Y8P9 zcvzxG?8SQy?{ge$Yh4(gdFeq?vTSiw~e|ZX0CgQ0csENGhpj z;%T}ThtRfM@17bslPJXfks_>fOMQhL04Vp&Tq2*;Z5tsq+f!A?yPl85m9>Ox9cb?( z#>m^K+&r5>StRXv7Yg?lqQ#N{bt_a;Su#}_s3)*Q+(myRP9CdBKx(~GZf9wSLO_V# z>vZkx>FS`sA@wHjvv~eXaVHYon?{8(7=Bvxx_}2>WDbi6?f@EF9k7+|5y7fD$!pRJ~HJydfhOPLq z8Ygpx#woUtCu$s+!%?#2TERLWT#c!ndV~U@`vC_n?pqQ=UfXpGhDIStY z%#|rL`hY7;Qc zA*JGQ;geN(Q$+@*JDCshWWK~W*f+D1M`x)g@-L80H1qa1-E=;Ke$H)#iSwM;eqGu5 z92{@gCFWs2T5!rRGJ76$$Xb0Jf8bE6`b9q0he5s9%BZ;wG)2!JNsJz)j~^h4GmBdHWixZ?+AH)}ZGW(YFb0olB+W<864{hz3&D z9qBh8If-UYqC;ZDZi)R`^sgCsTr=_|Ffi;LD4TuRay5j-m-z+Z(V*NP4k{^|QC)a- zGMB$BP)p>eKqUH(wqf%pxUHTj*8pqGc;`oR0+~d^92R)Pg%41HX^80{Om$4{c8(2< zVxz96>547ooRjrC-#B<#{g@s*p-IHYA=z%Xsbdgz$kO@5AtsddChrg~$^fPUj@Jfy zc|+UMgCC-42^XFs&DGGHkVZlqYwuSjfMnAbQT}uNM?!xi^yc~`$wkCgpOIw-u!u2K zCy5%z9v(|b0e0S@M88s^;Jrh4b@08;df2dc#@4h7w$xk8&GVat(`oFf`E~>fC%+^k zG$q5q7k*5(*{Pw|G0lYwZzcsYG7I-7x;mQAm&j*jqrLK7HhO3E7MgUG=BLue0;pOr z-kH2+p#&lqhne{JRC6K0>(kpzLUXipI`X&ZDAEp225x$ z65m;uzm@~>TwQD?9+0jpzPNt6u)k!X>+MVdO$!g(S$=-COkt>X_3Pr<+@M`ICjl%4 zI!iMPqm~4;aTosmFG%|e|IlnIQrpjp99!vVfps4x=ZnEQ?pMQ1G-v80D5fojYm(2|M4Q}_)#$88w8~)c(##k} z#8(#R!cvEpjd+jiS?X1^G?~luBu)i$XZl$wN3dMM>sw4`Yed=B_-VnYE*a%UtEe8W zKxg+Op8^=?l!?5WLc13JmS@odFE3K3zVYUG4oDSmbH;*!A!J=kY-_La+t5T z@~tlOc%J1Sk9(g>JpK@W)HN+h2^`n2x71YRESlcVu-AuX>ZF)FR4^&n(+q4AH ztSNo4rsLHp$$g^BNR@dv*jI)@0}*mqR%l;~KvDU*ko$FL;exnnTx8DKbqFc92Jz85 zV*}*gkMm%sj^q?r9FEYwmccVi$}Y{0ty4RJFMMy7+53IGRO}rW&+&L}C1uwTPW#@R zQat=?H*^?)vEe0u`hfxY?|K)^dG*y-lP15`SM03x%)PMKd6$iGy5IBqYHz5vCFcyf z;Ag-=xo#h?{?=Ev$DhB`UvMC}D$0G*$rfMbA6aJd7NOkCia*PQsR>MEczZDu5Hj(- zXfy_J;Udqm1|e%!%YI6P%=XX9Q>6Dj{FoQXW6$zAnMH0rCpaC?l1IoJblCA>Vw}V` zvrL+-%WT85{L5eEblm@pn>VSCGCpBE;d)j0%C7FfFuryJ!x+if>3r6GLWkgS&{ca* zXhH|~;pouYrA&fq`Fr%3OE;!U&XNBuO@e%dFWHrr1D z`$_JbHud(?jeIgg78?PzTIe1811bUmp%V`n@2u%~6dI`smPbcnSUiV~_KT(UBot1_zIBhO%XS7=)i>ZM$@ z2P`h)BR=Qi8lu}nlX)`?GSd50JBlwn4QTfR8iRXfICD0yJQV|UL{iqE4d=ZV?^V3Z z;`i?#6d`x&>r%6a9HL!e+7hfbw5&*iHdoMEnpyi-l^suBi0tUm)v)mR^Ee{6`Bf`F z>TM~DReqfPcd}C0(z;6zk&Ft)GqL|MVO!t(Z&RO~gM$c{oJ)O=*!o2LAVaH+qBHgA(D1%&qJ|SOe`b;;Sg~{$HlJ*ar?(tsDbTchZpmEli)bS%Fx`s&< zr{}@*Gk}O`@d)c}^`{IRXdn3T({yy(AgcgW^%Ev1RuLplBX$Y_?i66NtZB`t9%P|d|!5KQQs-pBS$B7$GP>I-FU@D^K_^6)uw$k4@>%``f(B z4Uq`1qq^keuVqo@5;GYuAzTW<<%+Vn8kfAYr0fZljovHlLFv-8d_~8#%L2yX5=tUO zMGE_z!$`DYg!Ck{MRvB6r542|vgnas15O+Jv86y}21JOB_Gqt(J

    4Jj=;|!=KLIf68a()Te4aB3XSYzJ{#|^2KeVQg0N>!p5f7UTFH(^d*zcTq4FEmP0U$g zx-Qs3rJh-f`C3wD*gM?N9S0n7)kcsPUzFfy@tvcmQuGbt#_nvLFA7xWJCU3+x|rJe zJCKu*J)JL|9onw>`xSh$8ldm;(eB&?yhV$c-33kIGMeuC!|A(ZIDK_uAp+_ z^Sz{aeS02w)w55`|6j`d2jA>RZy`@&{tHW38~b+>#i4I(@;_45e;Qg`prZQ<8U<>?#sXk?&=l4pFT--?u5eVLu{5FZ2frj>I; z{nDD1cpS+vPW$04l$h(5nBkTv&q^aSzRZDmBgIKY_Mwvj6x zEuwRz@ZcYqXkUIM6z{1#KnKE^Tlgez)&sWiYsukrbEsq0TDek5Vys!dg^0(gI!5>x z4jQJyf0Mt&8JlIcY`4=oqa-|m6-=BU4rT;D)+@#8X-T5IWet$a&hO5=4^a@SWHD}rWG3>XQ|Q@ zdKwX%bO0N0dyfy`B)&Ssv)x#jX(q&hOqTyq|7IR^)#e(^Lmc5`4rC{-sTad+1W>_1 zbOb~YmnYFexR}TV4}W`%UhL%3HJ+c7=OGQU&-PS(B7Kje<9%=FrY^a=$P<)2Y4myk zfM!R(VEM854fpTh?R!}V8@taRz8lGl*wAJ5X7|6XKb(Zt0!9AtuaLLIFiA|eM{D{l z;ffq(>>MvzA#GLxbLL0av2XSi?=wT+vZZHf>8V-NEZc#U^0&v!|H+oO=afumx2Qz< zi4wcV^2JDh+$Okuw`^@m*-ixXP^^Wo+tSO!fghDRh=o)5<(@; z$37>)wi_0ef^d+({!J!cX9l8~BCHM`75!RG;vq~7_fo;)BI2iNh zxwBx96M-E#$AX+VgFFp5HAGxq!gM2h8DEQp|y8w8De` zpu*4N6`m&*rr8SH<8u+m_}`>LIVzK=Z-FiTwiI6)FTV3kiq`@u@U+tF2(27-rxYhH zTN6BSM%inGGRo3jLUe_zeh=yX<8u`akOLR<>dHB9OG;~-f}F!}LFupaQH33m0>LEX zi}}dZ8|4R%q*B~35@B(8T(*{v{#n47Z4N%I-QV&C@N1~JNa6VceM<|y$bj+Azrjq2 z!e<-Jiq9bX%{&QD{DM)HF?@#iXd!=6=wFW|9`+8!>(x6%k705$F-wTi`G$44I!zzt zG7VGlaf4L!;JfqyEAFD!(vv4vWMrgy7U5{^?PtZHSG9w&SeEM3;B6u!6>DOUKrbyX zJ~t4ptO=e4+pM^_OIlzWYAsB*VpF^mJ_jbodqd08W0g{V1wnua%O-c)RZuVMU|qV` zv#6iC;+hXHktT!R$(N$a#=vVO&cWDmQqHqzDof1LboqLM&HS8Z4tyiGEMqm;E{z96 z65o?97CRf_!X1`fZFPKlEQ8R5(%dwAwA);7+lzWDrs3aIRS12ih(GLi+2kJMD;wBB zwlwT7o7>}UI_JNBCOv;obUu?VF(1TQo2&AZlsqYt#B)m+)KB=V;S zG5s(!#wDc_US~cp67mJXCne_cS63xud#xx=@5K_AIMRExn4cnrn;wL!Yd?w8`$xRG z^!~o2bh0T4dSA@PqtN??Z;lY{BT_tv;(9Fx^k$CvlhXSSe{<3mJ5 z_(e>DDDKTo__F$Yd**C4xWi!00*X$yo#3x^)t>1sSG2Z__C}#>iFYECV+b#D6J`&7 z!{a;5ICMD=o`+84Z~j`svpy(yQ!;&XM4s?3V&LUpI$vZ1mPU}HJ|&TH=^U^fP}z7- z24=^Y074mv1@hbS6Ye1gU9_v=)3u+IvzMeEQ0r63rKfGQD6;^aRPSHkKYG<0~av z*?W|n@<)Wx9E8y!nD?*p{I)-US^r1!O}Ikyy&!DNN}@Te%M@rQ$4MSMhL^?X(<@Hp ziZ=&=KeN)uI#U`k&#}Hq87k>}>rOOuHe97>zeGcO%ilNyB8E;|Z{S+D&gm!3KewsA zv5qgPsxqlmgdxR}7yy6&4c_+>!PXPmCTNtN_|nn1g9JI{C<^YZ>bCRi+m1A0QJk9#8-T6RyfjA~uxf#(9VUd< z759P2;M8;+w4$Q?QRCvg4_y7Z_R+tW^TXd|N>|Uq=c*miL#Ce`xwI#;--?0hX*ex9 z`vfGNszN+UPBL*seB1k_QyWaHD^1gI3YJhC<`BCa9+aP{o7}Pci zoOf(KY%d!Whze?_pHrH?HBKJldz>8=$6i*RV(i22xKxd!2hn`~_~=k}HxLvRW4{8V z2OZ;sD)b#*v9mE6fdXuDn`Z0lP!s{%g^6dG-wQ8g>^ce=K?Fl>RijNz@2{-rEJ2f%il?#=mZyF%_Wbp#=h8ogw zJX9F6ik(9eG)VjxEc3%l0{jNv1(Mt(5T2r-3qnlj(Agbz_+>r`B`s!;kzt-6$wEol zBjO3Yd;U4xH!-lxZz2X8>*11kQHD(L7o$e4ZTdOOD|-hX}!*s=Gn8h=MQBzV4k8FjY_lZZ|b&zOW^j z(nC@>YzxaO9;gdX>Y$OQllCJE9#(ncCJ%AKPobRdM}|tt+DBBLNZvl&`8XQwaI$>t z+Pg065bVe*d7Mvo+}OM-U$*wCX4Cck=KfRm-Svh+9u)taWR13(yG{(Jb#LL?Bb=Q+ zu{CFfFUtsDozbnHRiGDh=diIt7Bg#Npm+o#w_ ze_BlsZP-6?r^|rB;%vfwcSgok!~dPfW;f6}+&{zX;M$3p)C!A+gklKc%m)W^o%uk9 zUGJ!z2tgu)-d%~PSV+$q=u5(xWxVnvMw2m;^2ocIBCZ1RE_BFhy2JEsB~CW?U@a`{ zBl+f#k0p)fth~R}JULq_KesX;R*XV`tjWFp$~}w-lS*0@-g`otEIAoAsmEO zn729V&)e6$(L+;8?IO=raiB+XKJNM~<=SiU!~g+$kEi+EL=?0N+GLY+QRwBrZ8JNC3qB1)ZH11$IJM>^M3M`kuTbdf@TD6 zip<6{+JV1vAf>IWMv zi~njuLyy}kz+A%8#+pLpgN03(Ni+088W;X zIwcsh9N^NK0P&7G<{3zTy(yM^^q|*Y^&Q8pWlQqc7WW;K<#}}J>8qI_)$c3XdO!6e zXuFPfX)R1^=I{!Td<94r@rE7vC2q41(`-0%3|VCO#P^;OxAH2(b&?EMaZ5$(P=T3y z;XTgPl1UaNxdsJ~!t+T<^Hjd5q_x95+FFL!Q~8xZ5-#jWDzk@OvbmQOy`j4D8cQbW zq*+g!KXXkMnN0X$7F zo+OX3j3Ep0O(J4{T>gfru0{iI9%w_8k=`$RYrRMTHCBM7qwL+zCaFhCAg-RhvfN; z<rc&EDttNGhMCYURxCl}g&1)TMhp`w5wq(fN4|P5USHh!QD9BY@uqq@;^Kjrm;CIVy}FW_0ABl=M{in2JziGx$#WS@<4G zv@7SYaa;zz*rh4;D}1*k^3_FuaTNFlCc(Ghs+97n@SS@!`0n94!o+%=g1<&t37X;W zile~yc_Lq3bn5Vw_7#6`NxF-_U;HQdMCEt{{=PW-=is|5(QXs|=6F-uxAIRSUtM(V zu#|L#PvW7(;hTD8N;>l++Wlwgaoy4AvD?qW`}$Gn@nBJEdqTG}6Zz_*-H!tAEt2ly z^S#oP@~Pu}y{vf6>Crih67l(-GT!Hrz4>^LJPLfR6Zz_*;cHXcSA1@T^Ty%po(doM zJn5JJ8$Q42@^kPW4WD!RrNE=(pN!A7LsQZf-ei1EElEjF#pkJX>!UtJUhyB`dytGr!1v^tlsM{m-;ijxY5t7AB&B}E--U^M zbiFJyH26mREPVYE?Ka`B`%&QQl*m^X9eEV^_F~wJ!*|gCAK+U@#v|}I z|8zM_!!*&k_9R;J}o0S%1#> z-{Af0Y5xnnQ!h$wulf2jCsp1#0^TctH%XwB`DE|YGwNT>7N#%$xw6;28moATqnl8? z*ruWFUuQ}WwqP3(XyYmeInPyxl>q6LEl@4_*?!r*7XoR8CUBlK`gkTLME70pN2G?X zVkJM`7nzcyUaip~b(!i9Y`v13h%B&uuvM@q1GMG21LYS9HoK`z%u+h6MD3ixNwkn-lzy@9|-nXoX7zMlE#tiZQ@&y?=Mfj?qj zB(?P{alY4+)OBKSJc;b0No>i;q)dAme|vr$1CtzzQ}!pZtHrKfwaVx5FOl$X%gtxA zHSD0Q3JVTy7Y;bkT*}F4)PmuIOpwcjT}28%dYuV!`F%RErh?4)#M&#o0c*8YiMkxe z&KHdp#Lx*}88b!PW&c zn9!T0zvW5IpA5gsPf75~DaFs*B*BAxwKo}Fg)hr2rOeUc%Zu)9o!nktGkEi&tyAF3 zi*`zZFE0iDP#yI(%YR`Ce0kAfN5Ge7&iq;Ua-+ji;LB|WZ*KIKX6ciUP3})_3jCou z>Pvwym;NT>FE{#DGQ5hvToah@Dk7c;T9QfqyEqM?e(G|}z#2{d z?Z}FOp^!GPkruKKbwEchS@A6qk>2Lk4 z+i1CNAK@6e7wW*umBVcNxeq_yJVO%JtAUun( zpg3l4z4OKCwN+nF@mIY&<(f8YG?ef?7wc6TdcHs}Tb1>6t|;Vi5qaVahtg9h? zB<@X}nROPX@l{a7qY2ST!@_9ev297>3+J)*qZoGb+sg?djlK2-W_iGW47M5FxSUR_N8Hk#!siC}Pw>5UeEEXYfm zr9cSx#@!-$1kTaZH;eCroXxqPU{Aq@hwM`(Kxqf@aB!pOAeV8!Msm2)*^H%YY&gC_ z%`{=r^?>xjn|Zb7K&}j08*Cf9*zQNTLdjkt)Wdkb5|jpFWPh=aVmz-0k0NLG+9n(0 zU_JgVCu%u4#V)=YF>K4m^i_{=e zXKvV~7(mv8F)W@amG{uf6$8gffj9Hp@`@w9`PK*IvOmRvI^d#gTXykBJV z^=9`Kt?@fTmZy^!F>W@LxgJyTR6a+|=Hu;(!0S}mRA-Lg)Itg%@nVjXwsk$^juT=C zZ;3vjABwmi`k=)I)oxz=PpM}FMo=LfVSy6#+{`MLo?F)xkynI1TvDntZ|I|3>0{2i4Jy~U@&$c`8N!2?DBFm3 zMzC#SfRcGQgYvOq_IMHDNd*f~FLPu8xFovr)A zt(-N5VCYs|^q8I7ll6T^$k*)0qjfN^CV92ldulxLQs99CtxXI-&wWKEFeA4b ziGU<+5=`^HE`!nnCx}2c$RC-UV?J<`&i6w&8yGg>Lw%q?%N+upOT)Khd7YEHgbs4$ z?o3(<9c&T!CB#iUF`bFyX%zavAvSp?0(>Qz0jfKTtzQ_1K=2-V++5jeS8*WNWh^o^C0-LmAm4Awal%MefX|% z+G|hcU`o^RcKD`DYCfxB-t|T%`ZML$Kv(&9*g|9~#IwTW z4QLHA0>@abmEFR}>B2oYV`C_C3%SfsR`QjvJgR~A^33?chhiP9e81{09+0qJ6+*oF1B=S4ntZiLY^^HjfMI=i>I~ ztVSzNj8C(#V!zO@z1K}TvsFF-<9S4KkRD5#$a_NUedmgDI563}XE_vmNNObRpLg%_ zv!I`bn6u;D+%9RWd8Uy^gCbp9fQ}p zgygO>oBzJ6apY(=INW6j_wZh?apz~7IpdUG0#WGYO>MpK(52AJo3|>xhyprJFJtbA z-=D6*_3Sz{-j?qr<^N{OFO>3=Z29|>%I8u(w#edL`Xu)@3HkN_-?5hy-(`q`Oe?VR zdwOWeQI_4=uM4U?Rck4iSkJIWe3W20$@Yl2d$@7t(nDO-^8iJ+sFe@#kgy#@WXxeB z5Mh(v(cE+&LxwbwS1KWl*6TXyEV+$hRHPOIQ_G?E>qY=21|V_ic6O9H`_LpJZJJM& zEr>6BUx~wxdwBeqp$&?eM32Z*WI^uyLe{hRM%k5;^1|ndT6Kg7`660v7k)QuiJcqq zDw%t%b8==oiU|f6wa;H=vZC6T$-01vTUAr!d33oaH{& z*6xEp>GE*BFEo`JhsCF<(CSCEGDndUsGDXg%6Bw|_Hp)BxftKfGklTQ@L^w;?*i_X zy#OJ~*JfqF20kT}S@dF^TSW+!(R>~`<(yqGJUh5Pw&~~RqhY+`@G>70vZXx8eK3r_ zR}`|YJxT(vBW2@HC_O$WSx+0;D$Snyy zlvp%`?`lv1x4VhAK(RBW*j2VzGLQV}77#vE5ne$lt_2lQ3gwC@RhCtVBze0pe4@-s zfgsNo>>&X7xrf3{5}R8jwEaEq|48O-x9`0T((G!`NK1Vo5SDY3_1@ zqHn9P7yXT-eqG2lwuXR^XD|Gv64|yDnbTj+L_Noz%iX;nw^X^!G%UT$WR5TGHK*Qf zkL7!5F`iX8;;$CkIXoMTksW)EWT%5>TTn`PJ&!JndMGs8EVxmJaLXo!uphW!EFOQA zu~_4G7`WL)vv!=~(bmAP5H-(>nF8&2-V3S_UEgFy!i|(*&?nYx=Wiij8V`+x7E)ctD z)`DY;_AGB<W;w(lvavN|J2DGv=&wT%nXjG~ z-Nsh)$(JqC!gNm7OqXogu#cUM=!N<+(3{pWJe6od>5)pnv=Lh{7Jf1`+Zzsws>NqG z<81{&IgJIJn$ecLiIO~lD^bkxl;x?E!O%&$z9hnFHXAjXz~46X!SSMaW4+|Kqvt_! z6xP~+hf?TkTYmVouY%|g&C>34z zRQ9AMuLcN-b&9XIUe1@>L#36+kxcwlDf`*i5L1|&(!zP7`sj)-5vp1317mcYq@HH= zdsetx4W9FBLf_lsD~@W2>udzmrJVR&^6CnUyjxy+>+4OZf=f1wYuh0eqt`=!A62?O_reypY zBMfJ@aH@ARIPa4L@6UGIU`eF4yaC;`x!0=n4)T@(U3LO=@uYFdA3 zJ?PhzzmQhZh=h(bs`|K-S|5QB{m%1NtC1X)+T1H#qzAbM)Mq4)0M%p3` zmlTP=GGr1*Aj5992U;kgn?2Ay0;=;s6GK2(2uOMHkt477B31iW_6Ullh-t+W3?rcoFcT7gc zwAA`@XF9m0uRu*{^`%r@dIh_ZbCYFId`B>f(%xGu(##=z27_? zWz+tb^4F)zpYY}kkN=)O!hdqA{GVDV-_*X&q4s||kJE_n9UX4}^WpEa^nKr5T5NwU z1%3OcQ_8o0-#=*oZK?8QEtF5u_k5oaeHZ;QgA?Fs^i2CX{tXO&uh93ec5azI3VQlZqmXSoAEexetM9Q{i&icK4XQ)p{xEOgWtl>LYGv=ceny85!Ewh*Zh(>hrQ- z0x*F4QlSr~=y|^Gq*B@zu(Hpv0z;zMol~%m1<7IEtQcOIWyw##X@$O*EQ zv=g#`8smwo~~c0%)8TuAUx!9mP9@g6>iiZ1EI7R)cd1b?UL_q=Y2U z&Fn<0IR+D3W|OwHFQqM_+dL$T!T=)`^#(D;8|Rp8=0%CEqCNFOzX&0 z#Rrs>Em~jKs^Y@#t1G{0!_9$_st0(RYCp*|kDH^d{?gbw7irki82cUAyH>Rk5lx_Ko$LMMNxay+e^wlp>$mO?!~3{^W{MD1sQ>Ivuh5tM~;8)4^!FhwdU$ z6vMYRMT@t~iTBGa;cn@oUW+OgRW53E3iODW`%~>3J?Z$hvm@0y`8IJvtGSWtRs1T7 zU%Dk4zqWO>>_azvL|#VU#l?qiA@lp{#M^u|{TUyc86QK#mVvG`^P6A~vM__kL@%T& zDL*hvuMV_V=v}{muCCGi$CmFB@`~#w)wf(GH6e+3_c@Dl+9w2syMGSnRcKGJZdy_7 zL$|RX7HiDOZ@dx-L2i-qgLksj(64o0PnO@p$X$!)f7i;bp(GB=-Lzxymn5#byv*#V<9ckk-7m=v0G@AKEY5aiea%MC(?4Il|eb-Sll_5)c`9YDF z+6PG3vRmsuze{)~SV&nAWik;iaiuo-5x;*K6EkCU5pLk5OEx^Y+x+SGkJ1l;Nhu%= z91PW=*kP;vY=7=pKiij<#x^xg_40q*dIMkVycs(xu^;NEw>+S`3kR!H;Eh`ne}=Gw<(oGV}hdZTI_Z+lv^6Nvp=78lp9S z;zVl~?kGjdCq$-Zp$(#B^`}*2uF^y7HRTr@MQ@d|ZND^7C~Fa3G67Pck=vl>DKFsU zjyx5!+d~rJEH~jkOy-*2M778wz^S^p$c{Q{KQ^!EOyvX2b~_YrvM`rO)jXQx#{WwD zK%faq=%40gwC1SpOMUQ*8=Ipc5vguXMefvMV@9MNW~>pR$p3kgf0$%DI2Lu_<-bI) zWG-r}%9VHAWEX~xtTeNSKXb(y#-^%IDHbhLz_S0KP|T8ek2bEXl`rtJ6;StQ z4$eq?&QnNSMo&{p^Wc~wpZrUpJ|$A5@m=jk!^Vy zDPh%x+_JhC#{a4zeurJ<7^piifbYOxhWV(7t;2_+aWd;B_U;j>zLOFY$7dcIsh;f1 zwhD~Ub`+`=qrf@yZ)lxN@=~pEcLtc3`qJ(A+VNT$`77MVd@^BrN#F1h#d|LJ1>Voq zdsVkXq}un%_{=2cb;~JmT!3@E$GJm5!L5Re_nbEY!hPj0j^qt(i1*;m*_U=@>dKfr zC^zE%L3DEDC4M1U04so>ko2O-ySl#MD9K#hUkvR8Lv_OPoKvh%rf6HQXyS1+{YbuO z0@T+cz7ht3@K2dS>thSFH@LQ6=C^Lh;5@AC)eX6$rxnK%#j)>|v3SFK@BKReE2g-m zm0z`a|I4i6P8t1rt-9&VzLA&u9PWCMJBc)X@4EIyCf|?OA(v-S8$;-^b7=Z5CzyN( z`+g>u^K4W}DWwVbM2OKW7tSYWQAZj--qdTFVcY{ch8XWutonBL^&O@99)k`Wvf5Dh zQ`P{huVIRf!!i%oL2z9>+~%`^8=HjFQp&@1Hn@c1T&KB1JlqEhfZNx@)d}vXB%E#X zTKm4#P@I?86S$`F)^NPhJ45gXd-zJhuLG~qdr_+1M?Ad32f4O{e|;Yo^2h_&vU3q<60k?J9QR5W!bO$LXZVVSdI3mA1%H`2CQcd2Tk zV>9NORUI#=7%>C#es!&Cbjh6$zWqe{g0z%V@XZqrL9`2JMoM+#Ch-jC=jO+LDT=+R ze8}BOO)VEIfigFmH2kTwYeP}y2gRAI4O|QRXxUrd6C%e3u>(c3GFV=f_IjfUend^SHG%rB>vDMj+0Vi|DTsHgbLTY?P#1{_IkJcq0$;E5_`H?cOzNcHxizTfwLPx#8Rpzptjx|%Mztw-dRCSpV| zaOpFai0?c4C~-Exq$0eGPeJ^>=0P(C&2h+TlY5{it-9B&st0r5)nCg#thC4q7tO;R zhM(JV+p}Ni#iZ&x{a~W{=c#gvTYT(ZdOp?cf70Oc`viXL_Vg*zVs21x21UGJBER#I_FAo27}0L$GBH;Z~Xk+LK$BJuo@vG+X#q1lRHiI^FngX zDBR!|V%g&{i&RFVyEP9Yqj!5b57wFq=+<1%OAJ|h(uUiwvmS>Qw>{xCm_g!#ax#Qs z4W?O$@t4tdE>d+R?O+!nQq`Fs7BkfNVQfAb$fxYh3mUg4jf-EGQ+pve;UB`k)xCK! zsLOaT)uPnnK2!d2t;NA&1c>J48`?XBCAI;iuw28b>KN5n`AY655C+G5yCYSKaH46( z9k;A6v5cH0UF>!qp>wE_DHo|pFHG5t=L%ngw_xpD0TAW6LuJQS<^EtjetWLtuREq! z(xg37sCzwQHF92r`sbK66kEHv%DA54ZqpqRF!nsFnB^n!;A>+G+*01VOV>8(TM3EG z;4du(+)kz**U1~hvTI6X4KO!xoDDFZ*19YDn^A(n;o5>cbDk1z7jK^%EwI@CTdt;P z;yIILOzhjO4K}9z!VUEeuhgK7NYx9}&^W`MVpX|c^0MXy`xA}%))6;2Rbd#eHs6%` z^w}u&a-)m;QF@t31_3`BwN0YvE-Jv>?GTJ7lTO;fC@Y7uX{HZMIEorSFzJ~3HSgUZ zYLWb(iTs}@CL{mUX!7qX3wv(2ql$!Xz9j#H2b?QFI#__N)&u5vK&_hRve%lCSO7#o zSF*dB=uXOy5B+8ktaFdv^!A?pN-xBR2^a@Xa4z1)3-UoW4(&3bvrrCJNiv8?4XRgXz6 zne_l2V+QyHOCxDKb?0aZ)w#99{Te#WIPmK#x69EcrX6&jVGrcM*3nN6!YbMQ7!%g8 z|9tVWi0F%IPtg8u)Z0zHHb6g$PVXO^kKZ~PdoQYJrLDwCf1_|paUryvlK%sKH2%(c zk}S9P7oHUdig0{jCALuz@*cR-OH@J|1^r_`1bYQhLZf(rV`1xA*5Ir(rR(<#_U~!! zeP$-@y%arU`vtQG(%!Ccg83rc-j5gw4KMlrD~`QZbY|t3nKB721a4eOJ%dB4ojI*& z!+S-QUnLV2$pI1#mW!JANWD|ajDuVbh-&eS9%p48sXDPO;5Fy#CX6kL8n6B{6uD{N zscn{I_y9FToB6O<`m2*YGX>jv>2fK189Sr(Bi{C>GiEf_lGhrWOd}d2EJmp9qoh(v z+NyK-s0wq6EMyYRvG>{R>Q{cdIjwsN(VJ^({jsaHE@RAE()nl#7!7&Fu^+izfdQyw z4uikP`jD+_adVQjT}rgDt(aT6x$RB0(XzUvefjDg__E@~ZSj5(1|x?@B5Eb?lH$M+ z>yca8kX@T=1df0sWy=<4f>v>#{WNJ^p&6wgR$B5b^PeDwpi_<$w3qpP@=19avkn2A zKsl(JBNn(9$8T+{J=I>WH>SAOU=VY~wn==5N_rLJenak1TEyg^tNtmHFOzXCTQxgT z!y7+daHY;UmM5rkQ5s-)<{DeR_B`#r#Kh7a%lS@L)Uid}-^TZ(jrQI@ZI$mDAXhYW zrCG(Y(YW$CQmqNe6sJ^Q9_AWFCUXK(emSD9kK-5jL8wG_&^^oDxtR0*w$H!O9#mF= z+}9O5@oVDjE&SY}D00^#PSgM|qc1QPqX8l3K?ofxS`_Xt2Ot&#zaR=Rp~j3v9*=>( zX#H(UI46@*HY}Xu>^Ui%OT{H&U7{cHwu1+>B%I|OxC?}{x(w~xFgU1Ze0Rnvi-I}3 zs*~cKp4Xjxw;X9h^b#;8olQqEYO!fMNJQRIO*I{JO$$Wy3_X%ge+@fcN zl@ggSTGMHxyOYmiXgBv7DQNYpvzwz|l?%tUpg+Fp#zB)hW3=vxh_}7*G>qqXr$eC6 zg36I@#kWH~%0vsjB&9Jlk1WU{Xh7%`CSH97j8*7xt>_UoAB-aZxbor$^OJq_QoYvA z^slIII);d(qoldiXv0*0U)@&0dY?} z#kZtX9QlkF&(eN*x^XE-XF7^MNGP+h=})athPvfPm=fJym+f6`gNV?z1e~GCqd}f* z^4&c)HWo9yJM?3JppP-0xPO+crk+-~UB{_G^vhwiCc%}*jo1$ztPT!wAnln4pFaPOp{W6^k_(J_s?1>C6-_uZVKORM6825J6K|gF= zk~kf-?gDB`>Kj(rh8d7=H-W0Dz6vx} z)g^mpLVMzQ>hLTc?>{}RPc`~-hi=YmwrEH<2gM4oz_`PihRY+S(mTU&nFEpYaHB6$Mo)|-q zUo9@qMp^0m7#(vcK!7JiZhehzrt~Oj0U6Hjz<(rY0sk9vN7b$}_Vmat ziEZcR@kx_bVM)z#q~BAjf%DLGaHQg9yquetTWkEm6Gs?>I9uo5vW8V{sG(&b@KWj6DFvGcJC{8QJ0}fDB zVBxGSBGMZr%0l_Fiul9h(mPAIj5^VXQR?RB!}KZ>I1%A>-yaeHy$z5?RJ_wMg8K<%2*LTGVgE32iJb-XViM?EUsGE_%-a^?QbDW` zZIyzEcX~$m@M(TdJR&?_4FBEUSiq-dz0pqdPPNXqh-tN+W$WEID``Cew=gYgn=x#N z3N$h7UhbJroDETuOjOvsa;$6Sjx-fEkkw;iHESBtFd%xbZT?CsfQgpI@|kxM+i4{r zN|Fj}%~=3FZa|^8pXlvhY^{}1G|ML5YR)T|-u+{Hc?~yY$_83bQhZ6`w)S$Db5$bU zUcOh8kJ-y_3r_p9VJC&Rm)CW*{uuEL{ZR)^W-rI0D3nbHTgQj(DfxWEwWOD<# z9}7}R8o%Rb_oeY@X0K0g%wsrm*%zLvu65DO2I=*ajz>k|VyxJG;`qj#itVEDfsI|i zA0B&G;Wgea=)QFL$k@AjY+BoyeU4S`4?w0xI{b2+RAPA{4$eOx;+sb8&hgbl`PK3`zdNDt;d3tsOl0B^F_+pCH=rH=8XsM!76-rCXDUm(-dZ7mvi zg>TMsvyLXJd4Rf~!gO67R8vbC?_&8HJXne08{pi2SRpaDmjYe6I zWGe}2p-$EjQ7DH{zILCxMOjeh=zckiDKuk6R!hEB&yT|7kEs2KwaIPR6Mu_5%WN&a zkA6|ND>}wrYEIGb*k|rm`70@yuN}3|X8p!%ceTCKa+VK;daWge8^P<+nl^ZrH!%Sf z%|cTLQsmyVQ;HRFH*VvG#@PJWf=T3$X`C>LoX8V0o}}Ew*lUsE1(h2w@%K9u7bjbr z^>xTYs*BChw$Q@NO=QU$cRldP(oLm!8J`7<^erX=iy;yqFi{t}yf3Z92%BZ~IorHU zGC;xLHF9yR1Et}Gasi>Db2L>{#e^@$^h|xTI%>EmM8sXonZ)9n4!MaDG{Ey3Pe-)E8fVC(lbc$d9Y%4D(duh1l_vK~d7bY(xCTGx?ym(RZ;^E~* zuREL2cma~Ul;49 zO)nF3*Rn(D#;^quEn6qs_^@;RX6HCk`FuYskd0e3wmGcf=4yrro{7+k4&BFPg(htgV=1$1P?Mxk5o!KlSsr zU2vkz5`)tpdwM#{AA`HI4*U=w}ori8vs$^AH=dn8!PpTj8xB;RIwu^hiFEmN}(~)8vp33kHmtm${ocg96>DWm7@#H?$A-% zQT3r@IY1N*@!{yju?-hzu;(RY(V7{#6YVedhWqtA8(l-sBE3$e>UOI|HVL=$DeGo$ zUbvSgC#16K?@D3bK(PWF*dLqUig8;R?LB@mYb{>du8(;)5?iabjk&R@k zN#tsXrRI-%&tB11TJwzO2km&_3hgXb6pBiBb`zDKi*nLBWYHl?5)mlG#l{=ugK=j~ z6mJqM8HwnHplp>*7%0yy_xcf=7-lv|7qg$QYRZQxmCz&Hn>=peMK(y=X|1 z+J9{d3q<#psCC0T8=Y@H5T>)Y=scGeG^2AT(K$P$5$t}UH2G~tZ=e5#UXxzpXG79k z#kFPIuvT`_)4LhHUDD{Sxea>%O-q{5dp1L`;pH&BlFxK|;o@79^YOwPg8BF!Onwt3 z?kkVC?e*IK?Yzva7yd8jWoq7`beepp-?uoMn|?yyWtgX(ml^(f+ILG`t4q0+x|Vdc zKBI~*=l1&Z_r51j6j|P!(0EfkmYu*OQD!nE>%)P?u{W?k^3kK(khbN3;+ibxDYgBP zqc?6WT4jA5L2R0jIawo@JDGwlQ{xYC_nm>*F7X{_K1bAFe8(Hf9T<%izowN&j)vr5 zck+*ZQ4y&s*K|03Z;V}LW!B`Zy4iT%2?NP?jWM)YmAI1+@ot(kD9zIN_OEmy?*@02 ze_dTCGFg?7m>4xiV8Ov=;%Xze{0uoqx^dhNF_O72xCSO(QfbLL_!5kGdt(bUMNS{0 z#+zk41`H)-#3K{mNGdo5OI80!H8wwu|IY^6ci8rmS!8Rmu_s7a)M(vPYg?PRB8r|~!toOybLSj#`eLR~}CoFs(YTsh_1^eb;ovL+mb3j~uJ8g5jX=YfK@SBVw z)-_hjNb{)|cQNCI^BUyHkts0!48^t8HD#nY;kC_Jj$Js2u-2Ve1z`NJpKcLTxNUqj zwItr-pK0!mT^Qf2@7{%8=G6}OvcCJcqmAtF`mTz>o_GO>)cz(6Wi2)$9$36st&Cys zD~wcC@KlqpWS}&1kaBe;v?3>%^E)@}Cbgn2F_spv|EK!nhYf+WIgfZ6Cf|d_0@VXN z8Dn^xv{trA8zBuBV3j0f5EKnjguksiyDyPr4hJ7b`-k0^221KO=7pP64H7fc<$%kM zbY-_t{}k$<0q!L(HAI-(Nb2sF9Lsc`B=M8u4o4Y_G+E1Uf1#-Jier7A(MLFKAbw+8 zuXKI6w^M(6=bIv>+OSVPWxol_C!}RV`fJ@>TGM?A!Y}Hy#?Rxgq}&|N!Xh$io>SDT{>HQ1W#9ghi>IJNW>!W;4>tzcD570I?5fUL zuBtjctg6WFiK(53sr{dzUH!RzllL)~%cQJ=eO_U>)(}Rkh5C7JFNxVBCT4;Dj2~9A zguYg+pZ7;R1pr$nbw?`?wPoWQPo;Ww1y^f^+GAN;KIakx^=zW6Az(c*D7Oupj1vQb zUg10KJzS!SibJ{Dcv?}+isccN(SpQ{mKov)UiDDK)?L6{omh`yi9Nd$m{a}hhQn9i zpXipn^;L!?GgAD5{cx9XD>)3}(_UCSE0n%2Gy8LMi1!vzfR5#@s?Nr{F*)-L%`@ zMibwv!_J8hX=M8TmEC6;TpGsE(&<4qmj|&R>N*pNhyC4qdQ)lJ^I}6z>Af2?mcV0V>Is zLYDhxr1+y4!cS4AjW6VCSBCB%&H~;tA$~8@!DcnL+s9sd@?mHWygi1t@^f5EafEN| zX#8Dx2mDo_GAQ4e2zTG#DeU*UjLO`^KT%Y2>%N=6nF)$xUHF4;8p`O>H)uzrY&{JUdisVg32M79P1Muqm*rKnfY>>e#_!Z=8Saa<_fPP?#EcEVmc!L?8RZ|_a8g)G zr^l|E-ZYrLarY98X{GJR;rD)2E%%y&I~K=@A7puWPksq4@41JM>zD$AuvvRk`}@DI zAKN|0$VETy+>O7`x2=9Wrid>s>Bm#0qr86n<_L}dZS`aO9c=u58)y7Jn$(Z&Ze#@S z+C1`Ah{m?T#ca-+pOP*_K$It=Lh`Qh|*Ae+4|$Qq`64;@oh+V zk$8FLz9wtOZ@1G99S1PKPSFjtql6YV)AQ?5T21lHDfvAfxik4quCA2-T#j9m<@%$Z z@6*}&rcgQg9;sSy0?nLjyD(+}?4o7d>Cu`~NJWX>wI%*~n}9(+p;S8wd8f;tXs29; zs@quL%7yQyjh5I}C|@Z@L$h7>B&4-Q2rK^O%Cf9|9o0|$tlENBuh6=&w42r~;R|*&%q#>>QKIxJ_E$xyIW7*Nw!chNZ9FkD{UsO;^T-$cijht1 zLDz+D0!130HvOb6>OA>3jXuK2#Jb;Uv^!>i2B2Selu=Ltn2HB>4_#m_-a|4f8um6C zti{hI+ELQZPr+UPxp9IL2dpCbLu2_ZHc2plOc;=1_sN<@WJOjuPV%*nu4pVq-6;QM zrxRx#nqlf9xF!;P%2eng+Z#{ct%0X34>foFvlgE22CwaGqqypMx{$$OYi(GX6JTNeP$OB4Q5v@DSmU>JQ0En>AoHg znl^sz+aXP_rAStJ4>u&rY=mRe7Qwq|&SqM#cLT05A3XEQ-TDQ%<`us$=l0(YyK(}! zUxiTFfY04#e%)7R(clAN1VZ#TJ|~6feMU{g>}fvcoi<>glcti;r#QSXp_b z>Q3Gl+>7QYAImw&@)O;UZA?0@k0BjT@R3fQ_A-=gf%b}4E~^hY)amtl-lq5rfn#n z*s6SvE`CM$Mbmy)UHJQ(`rdsG-x&wZ{A;gM5Us`H@Ci!UOt$@7fnN0Xf4V>J{#5yE zwkiMSn<@GRwhPhs>O1TQ7Nya5RQUU!_5BVcwFUYD(qp%3M4Ob? zCwjk^_T9V~1gaj4iqT0yGMLni>sGtJ$#c)!XA=-M>_~aDxZAM4up6&4T)xo7e0rZ} z>eJAn55n!4gTbeW1v7t>`G+og`1jhwnfriFnae~kGY)&#rd42i`NCAW`ovgn!3(WG z&7XRbz6S)hPbV;)J{<JuzW~E-DmRYIiosF)naf9Z^vAmkA(ak1bc57xOs&=<(wM~=L z7w~3RFg2?kIf-r!y-SLfj#6x<0O zZetJN-hf`{Qg(`jY`@T0wskG@k94>kR|DKXz2N4h#O+OW0+V+UY0WF^v+YXbIe!M1 z`{vlTNXk5pvuGqX-FJ;!$%}#Ac3U{PJU62A3XwSj1@-64ykXR&@6+*TW^+pAL6xlh zUHoBsbaRm}Kk$Dl-zrsp|Np7H(W7OVTi5IN+N=A&v)%ju<$GoC7U2ih(kDpCX7`uF z?JlIf5r6#hAMn(Dz08$FyFOeTl9a#h^M;32fad2c&wy4%8oKk!_o~d_TUQJeX4Q1l zuvYgZUOYwHE7-dj7CbAcy9zD?!L$@cm}b9m7i6^8hVr)ViEDJD#n^1YVqPVc5r4Hh zQ?`y+>H<`*Y8)bWE2Nx3B#3;2w+`SrK9JFjKZYewYqw|=azKeO?u{nbY}LaeC^i(O zvepe04C!iMK`8Si=Rf1aVxBLPi_l$CU8f71XFOl}`n8aJ_+3`xgQA^tMn#rQ+=V%YUAR z))<%Gevjvao4`}(@!TprWggG@B59u2PuZ$H%pUZcU&e2a)=cQ^vPW_e0rN)Y0*gs&i2*bM{b`-ZwgFGT~{w z&y>13pSm;*9wf*~)8;7PX|?OKSaZrE_k#LJyIju;fhp0oMHb(IZC*4;yB@_BBJOrL z`X}}#@po7}*`XlE*vyfBkalomKSA7r7o}X8%*$+dG)A4fas%6QK3|#!E!W2DYL6?j za14zq8f0!>CUp{f;X!ddh@~uvotS;rFl(FkSJjpO5Viku20Q_>xfRKKM%cuez9|>ocS!+tB#)8w846G991MG?Fojkm)PHwm7j`xP;o;w z>)EG0o^Qv4$95u>ukOPI;Q6=56CN*TgC|j%ChucC{NsWjuU2uNmY}cR7CJ}J6#@N6 zdALgiSLxx-5nOK%cVUQn$IwX>csRP!=412cDn1zQh2wdW_FfP+V#^ElzQ)tMVH!_+ zM5^WDus%hqx9OJvKm z)mP29&hA0%EObt!`e`aF!5(Bzn~;+csZs<%G=2^Wi1RZw5~39vXCv%qoh!GR6FMHS zjH=~+#xx$6?!jLm$KP8laj@V0SA(70B`PS=`2_FR; z%)$98mit8~tJbw{_p7)w3h$EbKd1EmH|vb=pO1s@_0Veb-j3XG;u1e^qv7sGsRi@i z(;n_|!M&M;`*1FB|Mqa<9y?ob)uHJf|EtB@ar3Jt`48Ejk1fPTAj^=lZ_6L%N}k-< z$l9R`$dNkv!h(A!3l&IO(;wlyQTr3)NDQYxC9!#05sY&abCYRm{F&4h?(JWFUXfd* zrD7{ih##8c_V`U2uijn7U!7uU6{()7n##7+dVSsVi{5yJS`$s+`yorp3REiwr3(G(1 zYR<8+XW>sKB&{<$q?G2Bj9BioPxKG#yUY(0e*tHcy))J$KVQg|Fv{d^tWaL*QML-9 z+#8gMEn#@I@$W&ezR3sZSMw~b6W^kl3D?!PWlBCR6~DVA9;0A#UT^rp8u#rr)W4s2 z5HDEWi@nv=?nfv?;{*q1&E9(m<&?NFTz~BlgXuX77!9sfIa?duJs#&Y;T*>IhNn{P zrA+NP9^@84+$$=7p)Ws5<{=IRs|Ci#l8F zwij97q0E_&_VlzK{d0j$bQzNdQzyaP*rP1LX&a~)_+;4^`A{T++E`*9a}G$f836>uyV4j zVIB0>d<c#u6lLFkpvcHs70IvDbnISyY?Se=Ngy055t|Q(HqB2ZL*8Q ztthYykAZEkA5MEnvp?58vIf=?D)o$T#5-MCPN>u~@Tl3eH4Kf}a7R-9#tMjhkrbYD zp8*zJDzsO7z_9e^07%%^1>x}|)69IN&(qBioEEMS*pGI?{o=|F!%Z@On(MvV z%kNe2>vcm@P#`pY;UkO=TU$R!wb(ji@hfW@8}7Gt+U8XT|AOG(@$g%?C&jh)@S}N^ zl>TRdPu{of>J09%_b5B(1B2^y1voSqUV|j64x3yRs@j_Rp~|vJ{eBk?bzP>eYZ4~< zC)Ix(H1quzo*ixdtC$GyR%BXq4WyqjmWuzR5t!53DyVZ;-Mm^ZuBzL3#um$lu*-`m zTQgo~JFuNQy9qZ7M9<&3N`9-j?3Btaow$!q_W;N7KC>$JohFxC$gsv#C}cmS!T9&) zmGJLS6^Ivnsf?ZC4@?Mak1M2#jQ?jsbi)e0OOU`SjS zmUq|N!`Ut<(cg^%af>MZu|1t zBKZsoJQFG78n&`~#jz;j8hZY^n~s$)a2p=j+PE%qIjJ7Y-ctA)sxilxXnpVWMvHUg zvn)=i9OXkEcX==c^M+j5O)%M$?nDhmb|xoC5~?bfwPl80jdP!+DocS3%IyO+zYSAe zJ}qDq;Ijhc?IZkkXTxbvDD)dRR#rZ+FOUa0vU8OMH8sJ0VwF~zZ`kdZf(_~w)-Ng1 zR9;8o_4WtVbp~OCRu}OtiFXWEXUnZ79Rhq>^6Oue3;caLBx-YWS9UJJ= zyXssvebbP|R4+f+GDQkgBpDZC%NzFFy%r`t>fmCIhbwSffpW^!G6||wXB(N8S?*4( zAsgs=kJ;PCt7i0lQS8&Am}80M6|RilG0FdF`Rakso1nBH)V`+1D~ z{TX@QFEdU_E#DFMZ=_m>o8_x9U%hPbZx2=p=_-|I6RG}LRmnZf$CCgr zxR)1^svZDFrmo?4!QJ*^Ixh}d;f(_G1%H4De#lUMrdRTj`L!`0^I^9S9*I<4N`)2xIh(>o zHM^B?1-Rys;x%^Td-dbI7Q!~)ZI_WKv^j4guSm+SzNpq(N1yManc+(6U27KCO7|`m zRedJK60LwHo`<6#3dZgT9-fX*lBdmk7JVB9KtUf5qDM68ngWw@6I za&*_%zXe5>c#@KqvD(7iIq~5>sxwS^j+n+^Cs5PzCnjZY4d3|+5PwBCgpl`-_P;X0sBGroR7Jn`PuNR=H3*cTL zIxEhV=tSZtLy{MtFL)CcpMM0{9 zRI_VI%{A7yV^&$;R^>vRKX|HOE=5W{w17=l<@$~(8Yam(H{5fsJ-BQQN4o=gJxU!2 zJ%gds0G-W-6XDATA8gDb;JB8rsl=$WX`7VIq`x-Gr18^xoS+H4VhH6 zzfAIEox`eUoQq86BXuV)^i0>1WMI<{{D6u^)}okrl<6F)S}Ivn$4|^>V6<<~6p3x9 zV&ibOz=5j40%O+fY>0%pwA~M0pSg}mCw5GM7Db5r;M29?C5uadn?WW-|7yU25g2^3 zQFOZ1&LWrM2#Z!k5;LH|>$M^iu|{_TIVed*7Maq%9X%Ao@w~l<3mb-PX0|^J@ zkF2U|i&$>lqXIWOfii;1!t{LjceVVo+D2)twXn~l8?{_;u*=3@YziwB4Oo29T%e%S!6*l$WcL7uHS?aTRLFX|{y@g*g z&n}&F6|a&@xYghADqv!y>O3r)L<#>iEy0ZciZ@ZORwW;9;ZnBqo$r%qc#RTaq|g5PYlEH-9k^?tfUB< zN!WDZOb&GP?WV5CG5$AoMYo3S7@vW&_eLsEuW0Apcg1+#guCJtmO{Y<<)?1aVscA@Q@HsXjw;1D~AxnDF zb7O=1R-6$xj@e#|AA&eGxG#AZChgh%B=#2M=t)~{s&1&CuvPmMO5o1bu=7^ME0o~+ zcac^aBOT{z3Y6Bg$qh&xgOEq2XhSj3Uz+}e=q@X#17-}%Za7Ib_ofv8On>*f*D1rK zQ&RDLX`E`@SLB2^b(oRkIdvXY1Y}&xFr6?sFmPJ6;=LI-tQ$4mR7%o%w1!gn#Ymtl z-HWJT`tkOE$WV>hZ25@L1-6b@U?(-i_q~%9w617u0#I3J!!)ANqdPd3=zc zLk|t=ec^NLshvV}rMkYlT~MS5(loJqdNeEiYY&VdTFpE~_DNc&0g-r(IitzGMQ3*= zuo6v?I7yR&|8i;&l@09$+#BO+rIC3gkAK#$`$?En4LvurH#n+yX z4KzbCbb<_6lc7$tydgI32qELuO1JbYZzc^*nn}gy%1m11?jsAn<@I~2H zb<~@kVW&LB``W$x|XswPDI$DQ=0bbZ$KgE0guHuh638{R1Yb^JYo2 zAbGnP$0T{*%uJfDtH5)^mSmYr70Tokm zx+$xSe7DB z^TJhqr26#){&AmvXt<6QuI@q;FPJ4y=~vW&d36!5lIGQv&+wEU1F39Td*MR-F2b4> zVZXAa?QZwTRu2c+NgmlHLN>!AyE25V2xKy!y}5NFbF#baW5@>OHK)m3mUp3|!E>*C zKr4UuR-zV#IVcR$%k*D6f@B`!cYiGfv(>;?;(*04F!#p@13Hh|UdpvO zbNX_s&?IyM$&l`vhj$SDSc37DjB$QzARSU(pv2HR3uzY{ba+*&?pscF>-;K(OCUuD zDU&boG5gymJwExf4G~zi~ z?%W-JLJsZt$(hSn`%RL&0EpI*V*rPQU#``;`(6yTx!l^LWs>(}AF!r%6qDFp)*(Q# z#_b{$K1SnSA+A)A5qs@HJcWCHsrA{L!|1azYO#IPOet7XCosZ673+FB0!D?B{C2Nvq6Pt>}LiiEv_EXF3!y zm+?fe=DBv(NbXM4{Xf7&_Zq$lY9S1bMH-P`g@#18A z(XD0&UiVRtb#NWWtVVxejH#FN(M;^G4sbiomeMC*vhiAzojZi=D;lyx-K3tF<$s|X zpNU(O!_d;WKljdw`vH8>D7g)Ck=e;gnxit*Pv^<&a|QXOlM~1@ngp1rKL1XU)hngS z{!I{{=E*6#SD~crEj6N0t10cTD9M&N4I|ap8DbqAp36Y=Yokb2U&M|e^v-i16C+4# zzkg|bhV2xnEv2!K-MP=JC9nA1gBNQmekys zII&Ykst(IDO8Gm$rgiw47nOC&F&;KdlpOjP$dfsvux4f)_yAz5!$flKbm!Xy(k zAWC8h;=*+8RJ`Yao5+7tQk$d>Qj8zCSH z`EuE4eKfxzrvg$iykf0&K^`yHS}d!3XeVzcZFexa7nZ@@X~>gW?H2B@X+97*pMCL|CY&5)ga{OJHuFzt*GLfw@rSo;Z@SA$VW9MW-~SgcZ!EA z72Mk%?i0lW5A<*sgy1p+$JtTAg*C@V?&v&5qsHD_P?M6Z^1&@i)qtc>Y5b1)L&-uG z#s%W#j--ynJ=AXYvnu?55Lvg16^t-y7z_fLJLOH|Tj@aBzZXnq+H&|c zN~ok5jHUxqs2=pFlo=<9s>GxE=>RtF8{K$e(jqHZ&q;{7FR>7x3|n=jhxmlz4dm(e zr*n~WNeb3MO+LXRu@5ynWB<6zp4U7@2PNm{Y*+J)pP#ecS8Pt%{9JyqZc59!I3xDG zRc&bybRw-ZuA^Dkv35Iam`)XG{ZaM3`U^9Fy&T$=hZ6a0E zRgA?>`rgzjK%uqn_+Y;P$R)uj_+ek$Hz2X>RswCMs2@(ZBwFy@IIXlk1k4j9jWN52EL;V1OpHEn@o5!<7nd zuph_Sf~(mUE+05inIkG+3-o7S58pxXMIQcLMdzO4;V%i*yAk0}Obg)Jd$8MN!_EnBZ1$bHoL{ya>jWkJ%T`4uzr-6!Ppt*G5F|q6u+kRD8lSg;IV{#s z;b@Vncu-JlisD!fhG~|qy1wDP<*!=ra+V!rxB_XHEdKdf#iEmssfz?3JF*s=izFoK z=PUodhRrZD3dz85r2A^I_3ZWi;gt5EQEHbdjyXZvERFuqD(r5JV#!AkIT75-TMQ6} z=qGn0n6Z9#9QSfHuB43U9*#Y{Gs3)Q)tlh4yUJJBUe)PV(T1t!k9}3k-=bIaZ*U32 zM1HDW*&=(Z#qSj6X_6VhJPK>3+RmFi-IB9CJ=zyaLHh`36Ik6Lf3`Npi0zNYUN4T# zS0G?<>}^{|pgojPeHwLH@a1NHRIh)TM$@Jhk>VfRk7#Q3#FKnc-ZK;g_lw~WAsAB^ zttA2tk?V%6V>~VzdKSyJdmM;mwYrtW#I@gz8BvT#f?o;kVB zI)$WU%p<>@LVIqaJ+{vJ=vDgVbXrQkgh$*~gj%CEg=Cs*@8Mq&y!`S8f4AUw_V9{q zO^(<(z$@24q3&a4(bF+kAzK~XN4syf8?2-{buR&X5{VTWD4hRTX!MN`{>mi&qlN$9 z)C_%>hwz^b{={%~NYZ{&ei+4PYQIup?>>{`-+|#^EGxBFa=+v^U7$pW7>kYvq89Qn zwFoCe9m``fR7E0HkI3NHI%0c%xTR8x<~;W}s+U=3Mv6aifBTdma25-EKGdD1ixa{8 zB{<|Vx%d-X()8su-}7y_e$?6|tx8t}Su_EgOc`#})*rQea$_Dx-XS9g3{a{)j(FRn zUSam+cW31-Iuz5jBLPcf_99Ut3*ie4lq@AI&mti8+nkZA*8JwSJ{$4B%Iw#=$IX{! z>E|`eY(1b9{60*i>M=@HZqAHMJ%Jxo)lnjPlTem@5}90WI8Y&&xShR@VH(5D?aJ2a zI_nd?aydIFM*kw2g;_BGq+j5r?&#uF24uT=A4$J}EIuN4l$>$PCDF$|)7UuoFSOic zboNSSRQDyOW~5{~z#CDt5Hzqn-!0oM&_tm^D=||=V%GVz@<7i8|K&0cDs zdvpy;DrHlX#3lw)h3QXj2GBt>Lv)$w7oW@4nF8Nwh*#hV6Eg+`>u znClv#oA!j)XZND=6ynAPu*Ry`N6#tQUrwT*O+$ql^lC@VVY6)_yAI3P+q15QsMVw* zQ|j(7DP$Ls1>c7oJ)J)22cLGNc?rb{HPI`rX!9Url96ijV049_2W849rc+$~xC?mZ ztffIlCAXTjeRQVm`A*k^*~ktWxPxzC1#~2*ftht7xlC!c#6_C6XV0--A0+x@B_wbX zhv;(;=(`F3eo!yIApaD0e}SN8)75F=dJ;Q;i1TkA|IfwXxA|MCgqqs#dMEKG+tukw z72RkpUGMt%T5?0iN`irx8f6J>B85WCHT49kgx?$-`w&xL9hMzw25qzTJJ;uLTFA3{ zaCaWIhWvb*SBQTLw@e4w^2it3v-h47tG)OyxrYMg|9R??`0u67PVMp z*NJ&wCTksch^iT4=LbI{UttozP7fmghrOe<2V=AR=;Z0FowBDl&XtrY++`$3Q1rDF zH@{ALLs3?eBGN@NUvE}IQSvK@X{QM)Uhrmw*}64+wYbd-dFkU=pVi=;*DxEq##M1> zgx~+td0gh}fd0TFCZDXrE<0B?Hdb7N7dujAD|MRVkIdpi8Uqh;miz=i>_F;Tx0GB` zkUaD(3psk6TII>Z2*ay_b}r^DJL-0*T3wH1m_FJnf}2~N6M31z0slK7*Vx^CX>7Uq zbKOoq==4|le(pnttWCC`8wQIZ7FBkbM0AthEfgbs+U2u{teK8evvF5aOwtg&z1 z?AgY@j(y=@HzA7`+`be1tAnq`KiSEie^+Q^ZEGb@1d98oJf1gC0MDKtPqFZfPvX(Z z7mp{;@c8@Z=nGRgZkGpxnK99z0hqL>+@2n9x$qtUUJ_U|jULNyWanjQd>))8Cxzvk zuH+D`?Qi%je>NMKz;f_4J27*Pbjn1qp-*}KThsHv*gDtwP!Uvh8j7bA3v5Q}jYIDb8%vsp=c zLW|w;Mku+HIqYoY%4&37!JbU|!yHp*?P2F~SLu-l0SO7nG~7epLmueM^!gQE>Km4- zzqjhQh84SWu2I99*Z<@`&FUX_y*AZ-{awcWasAfp3ug)MidkwoV!gQbA$}yTe1-YR zzOStC-^FtKE_xED>$~!GB#)XEanvmK%Ru+{mjd;r`%{YLWT|r>bl_dAb>)^e6*suu zNco@KF+Ie}D6gpu*ez@`$@tVho}0#%Kju`xHqpy`iqd?=qGY(~^Hw*y<*F&zdOg;@ z4$Yc-zdoOD^)*lTQOJ3jmrS2MejNH@5hc-Qn}^^)UpEuwwbafvCe4CJq*^R*>-ray z=b5CQ$J|0TgU39c5yJDb$Md}KJniv}=2a5UQ1Fnq!p5f?>)~<*Clk)rr`HMcN)H+K zJM0Z)q8FnlHD28z9{$?`;O$6Qyr8$BkJ=Xc%UYm&1C4zox}U9v?uHkA`vpIT`nCL( zo`2uJzg_QN*ZU{zy)9DZ*>+dK1A0=k?S6BmcU(q$y&228xwYn9e{?dre^lx5brHTV zC=H*dp9!5c(BEv{$cN4*1fkIa-A(oX^g^h9DOERdhd-#lwXgq%KGeV3*T0MEZ@+E* zFVFh@`tgUwxC^T3ewb9E1m=J5ENBP$@;McW9Zcb)WGpd{FLo<#*21gK4WS#EfJQO% zW7p`{%k&CBN}8a@;z+-ZEU|Qq9S=lf(dqrTGI0=bVvW)FPB5LKdK>vvXTjScU4`IE6H=d$KQw+}=B9ZJs>vJ{i{TTyI-_gCo3 zLbH7EGb0d{TN^8~+~@TN;YFy|wdIrFh0Q0$FFC$d?Ow+4o{1%QHuf+3MN6`8zcEA2 zpFb>$S8N5M{5nqXFV4t#@B7NHGh^@7Vn1ha>-kN6*o{4CF{k}4Jyhk^Ha8s{5{l4I z+PAn(cE;l3Y$7l!7qsd1(S)_#mxcok^)yl;VPk(I>

    dgIZF?(U9+pyRMIBu5fj8G!tAm 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 z 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 gVDos{ruV%56( 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%0A9b9?7>Y0t@1 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:u5q6vHM@(^}JEx3B8 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

      E_j@`KPO-#c;WNl1b4FPmS?2z81lKp2 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 ucpfSMGDV%15D@TSBMNXDz&yt*Xu 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%0DjMw|z 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%0D-#{Z2T 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%0D; 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 literal 0 HcmV?d00001 diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/__init__.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/__init__.pyi new file mode 100644 index 0000000..c3148f1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/__init__.pyi @@ -0,0 +1,67 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import padding +from cryptography.hazmat.primitives._serialization import ( + KeySerializationEncryptionBuilder, +) +from cryptography.utils import Buffer + +class PKCS7PaddingContext(padding.PaddingContext): + def __init__(self, block_size: int) -> None: ... + def update(self, data: Buffer) -> bytes: ... + def finalize(self) -> bytes: ... + +class ANSIX923PaddingContext(padding.PaddingContext): + def __init__(self, block_size: int) -> None: ... + def update(self, data: Buffer) -> bytes: ... + def finalize(self) -> bytes: ... + +class PKCS7UnpaddingContext(padding.PaddingContext): + def __init__(self, block_size: int) -> None: ... + def update(self, data: Buffer) -> bytes: ... + def finalize(self) -> bytes: ... + +class ANSIX923UnpaddingContext(padding.PaddingContext): + def __init__(self, block_size: int) -> None: ... + def update(self, data: Buffer) -> bytes: ... + def finalize(self) -> bytes: ... + +class Encoding: + PEM: typing.ClassVar[Encoding] + DER: typing.ClassVar[Encoding] + OpenSSH: typing.ClassVar[Encoding] + Raw: typing.ClassVar[Encoding] + X962: typing.ClassVar[Encoding] + SMIME: typing.ClassVar[Encoding] + +class PrivateFormat: + PKCS8: typing.ClassVar[PrivateFormat] + TraditionalOpenSSL: typing.ClassVar[PrivateFormat] + Raw: typing.ClassVar[PrivateFormat] + OpenSSH: typing.ClassVar[PrivateFormat] + PKCS12: typing.ClassVar[PrivateFormat] + def encryption_builder(self) -> KeySerializationEncryptionBuilder: ... + +class PublicFormat: + SubjectPublicKeyInfo: typing.ClassVar[PublicFormat] + PKCS1: typing.ClassVar[PublicFormat] + OpenSSH: typing.ClassVar[PublicFormat] + Raw: typing.ClassVar[PublicFormat] + CompressedPoint: typing.ClassVar[PublicFormat] + UncompressedPoint: typing.ClassVar[PublicFormat] + +class ParameterFormat: + PKCS3: typing.ClassVar[ParameterFormat] + +class ObjectIdentifier: + def __init__(self, value: str) -> None: ... + @property + def dotted_string(self) -> str: ... + @property + def _name(self) -> str: ... + +T = typing.TypeVar("T") diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/_openssl.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/_openssl.pyi new file mode 100644 index 0000000..3d4ea4e --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/_openssl.pyi @@ -0,0 +1,8 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +lib: typing.Any +ffi: typing.Any diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/asn1.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/asn1.pyi new file mode 100644 index 0000000..3b5f208 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/asn1.pyi @@ -0,0 +1,7 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +def decode_dss_signature(signature: bytes) -> tuple[int, int]: ... +def encode_dss_signature(r: int, s: int) -> bytes: ... +def parse_spki_for_data(data: bytes) -> bytes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/cobblestone.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/cobblestone.pyi new file mode 100644 index 0000000..95e9583 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/cobblestone.pyi @@ -0,0 +1,33 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.utils import Buffer + +class Cobblestone128Encryptor: + def __init__(self, key: Buffer, context: Buffer) -> None: ... + @staticmethod + def generate_key() -> bytes: ... + def update(self, data: Buffer) -> bytes: ... + def update_into(self, data: Buffer, buf: Buffer) -> int: ... + def finalize(self) -> bytes: ... + +class Cobblestone128Decryptor: + def __init__(self, key: Buffer, context: Buffer) -> None: ... + def update(self, data: Buffer) -> bytes: ... + def update_into(self, data: Buffer, buf: Buffer) -> int: ... + def finalize(self) -> bytes: ... + +class Cobblestone256Encryptor: + def __init__(self, key: Buffer, context: Buffer) -> None: ... + @staticmethod + def generate_key() -> bytes: ... + def update(self, data: Buffer) -> bytes: ... + def update_into(self, data: Buffer, buf: Buffer) -> int: ... + def finalize(self) -> bytes: ... + +class Cobblestone256Decryptor: + def __init__(self, key: Buffer, context: Buffer) -> None: ... + def update(self, data: Buffer) -> bytes: ... + def update_into(self, data: Buffer, buf: Buffer) -> int: ... + def finalize(self) -> bytes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi new file mode 100644 index 0000000..66fc065 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi @@ -0,0 +1,133 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import datetime +import typing + +T = typing.TypeVar("T") + +def decode_der(cls: type[T], value: bytes) -> T: ... +def encode_der(value: typing.Any) -> bytes: ... +def non_root_python_to_rust(cls: type) -> Type: ... + +# Type is a Rust enum with tuple variants. For now, we express the type +# annotations like this: +class Type: + Sequence: typing.ClassVar[type] + SequenceOf: typing.ClassVar[type] + Set: typing.ClassVar[type] + SetOf: typing.ClassVar[type] + Option: typing.ClassVar[type] + Choice: typing.ClassVar[type] + ValueSet: typing.ClassVar[type] + PyBool: typing.ClassVar[type] + PyInt: typing.ClassVar[type] + PyBytes: typing.ClassVar[type] + PyStr: typing.ClassVar[type] + +class Annotation: + default: typing.Any | None + encoding: Encoding | None + size: Size | None + def __new__( + cls, + default: typing.Any | None = None, + encoding: Encoding | None = None, + size: Size | None = None, + ) -> Annotation: ... + def is_empty(self) -> bool: ... + +# Encoding is a Rust enum with tuple variants. For now, we express the type +# annotations like this: +class Encoding: + Implicit: typing.ClassVar[type] + Explicit: typing.ClassVar[type] + +class Size: + min: int + max: int | None + + def __new__(cls, min: int, max: int | None) -> Size: ... + @staticmethod + def exact(n: int) -> Size: ... + +class AnnotatedType: + inner: Type + annotation: Annotation + + def __new__(cls, inner: Type, annotation: Annotation) -> AnnotatedType: ... + +class AnnotatedTypeObject: + annotated_type: AnnotatedType + value: typing.Any + + def __new__( + cls, annotated_type: AnnotatedType, value: typing.Any + ) -> AnnotatedTypeObject: ... + +class Variant: + python_class: type + ann_type: AnnotatedType + tag_name: str | None + + def __new__( + cls, + python_class: type, + ann_type: AnnotatedType, + tag_name: str | None, + ) -> Variant: ... + +class PrintableString: + def __new__(cls, inner: str) -> PrintableString: ... + def __repr__(self) -> str: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def as_str(self) -> str: ... + +class IA5String: + def __new__(cls, inner: str) -> IA5String: ... + def __repr__(self) -> str: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def as_str(self) -> str: ... + +class UTCTime: + def __new__(cls, inner: datetime.datetime) -> UTCTime: ... + def __repr__(self) -> str: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def as_datetime(self) -> datetime.datetime: ... + +class GeneralizedTime: + def __new__(cls, inner: datetime.datetime) -> GeneralizedTime: ... + def __repr__(self) -> str: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def as_datetime(self) -> datetime.datetime: ... + +class BitString: + def __new__(cls, data: bytes, padding_bits: int) -> BitString: ... + def __repr__(self) -> str: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def as_bytes(self) -> bytes: ... + def padding_bits(self) -> int: ... + +class Tlv: + @property + def tag_bytes(self) -> bytes: ... + @property + def data(self) -> memoryview: ... + def parse(self, cls: type): ... + +class SetOf(typing.Generic[T]): + def __new__(cls, inner: list[T]) -> SetOf[T]: ... + def as_list(self) -> list[T]: ... + def __eq__(self, other: object) -> bool: ... + def __repr__(self) -> str: ... + +class Null: + def __new__(cls) -> Null: ... + def __repr__(self) -> str: ... + def __eq__(self, other: object) -> bool: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/exceptions.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/exceptions.pyi new file mode 100644 index 0000000..09f46b1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/exceptions.pyi @@ -0,0 +1,17 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +class _Reasons: + BACKEND_MISSING_INTERFACE: _Reasons + UNSUPPORTED_HASH: _Reasons + UNSUPPORTED_CIPHER: _Reasons + UNSUPPORTED_PADDING: _Reasons + UNSUPPORTED_MGF: _Reasons + UNSUPPORTED_PUBLIC_KEY_ALGORITHM: _Reasons + UNSUPPORTED_ELLIPTIC_CURVE: _Reasons + UNSUPPORTED_SERIALIZATION: _Reasons + UNSUPPORTED_X509: _Reasons + UNSUPPORTED_EXCHANGE_ALGORITHM: _Reasons + UNSUPPORTED_DIFFIE_HELLMAN: _Reasons + UNSUPPORTED_MAC: _Reasons diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/ocsp.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/ocsp.pyi new file mode 100644 index 0000000..103e96c --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/ocsp.pyi @@ -0,0 +1,117 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import datetime +from collections.abc import Iterator + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes +from cryptography.x509 import ocsp + +class OCSPRequest: + @property + def issuer_key_hash(self) -> bytes: ... + @property + def issuer_name_hash(self) -> bytes: ... + @property + def hash_algorithm(self) -> hashes.HashAlgorithm: ... + @property + def serial_number(self) -> int: ... + def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... + @property + def extensions(self) -> x509.Extensions: ... + +class OCSPResponse: + @property + def responses(self) -> Iterator[OCSPSingleResponse]: ... + @property + def response_status(self) -> ocsp.OCSPResponseStatus: ... + @property + def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... + @property + def signature_hash_algorithm( + self, + ) -> hashes.HashAlgorithm | None: ... + @property + def signature(self) -> bytes: ... + @property + def tbs_response_bytes(self) -> bytes: ... + @property + def certificates(self) -> list[x509.Certificate]: ... + @property + def responder_key_hash(self) -> bytes | None: ... + @property + def responder_name(self) -> x509.Name | None: ... + @property + def produced_at(self) -> datetime.datetime: ... + @property + def produced_at_utc(self) -> datetime.datetime: ... + @property + def certificate_status(self) -> ocsp.OCSPCertStatus: ... + @property + def revocation_time(self) -> datetime.datetime | None: ... + @property + def revocation_time_utc(self) -> datetime.datetime | None: ... + @property + def revocation_reason(self) -> x509.ReasonFlags | None: ... + @property + def this_update(self) -> datetime.datetime: ... + @property + def this_update_utc(self) -> datetime.datetime: ... + @property + def next_update(self) -> datetime.datetime | None: ... + @property + def next_update_utc(self) -> datetime.datetime | None: ... + @property + def issuer_key_hash(self) -> bytes: ... + @property + def issuer_name_hash(self) -> bytes: ... + @property + def hash_algorithm(self) -> hashes.HashAlgorithm: ... + @property + def serial_number(self) -> int: ... + @property + def extensions(self) -> x509.Extensions: ... + @property + def single_extensions(self) -> x509.Extensions: ... + def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... + +class OCSPSingleResponse: + @property + def certificate_status(self) -> ocsp.OCSPCertStatus: ... + @property + def revocation_time(self) -> datetime.datetime | None: ... + @property + def revocation_time_utc(self) -> datetime.datetime | None: ... + @property + def revocation_reason(self) -> x509.ReasonFlags | None: ... + @property + def this_update(self) -> datetime.datetime: ... + @property + def this_update_utc(self) -> datetime.datetime: ... + @property + def next_update(self) -> datetime.datetime | None: ... + @property + def next_update_utc(self) -> datetime.datetime | None: ... + @property + def issuer_key_hash(self) -> bytes: ... + @property + def issuer_name_hash(self) -> bytes: ... + @property + def hash_algorithm(self) -> hashes.HashAlgorithm: ... + @property + def serial_number(self) -> int: ... + +def load_der_ocsp_request(data: bytes) -> ocsp.OCSPRequest: ... +def load_der_ocsp_response(data: bytes) -> ocsp.OCSPResponse: ... +def create_ocsp_request( + builder: ocsp.OCSPRequestBuilder, +) -> ocsp.OCSPRequest: ... +def create_ocsp_response( + status: ocsp.OCSPResponseStatus, + builder: ocsp.OCSPResponseBuilder | None, + private_key: PrivateKeyTypes | None, + hash_algorithm: hashes.HashAlgorithm | None, +) -> ocsp.OCSPResponse: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi new file mode 100644 index 0000000..e41ba78 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -0,0 +1,82 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.bindings._rust.openssl import ( + aead, + ciphers, + cmac, + dh, + dsa, + ec, + ed448, + ed25519, + hashes, + hmac, + hpke, + kdf, + keys, + keywrap, + mldsa, + mlkem, + poly1305, + rsa, + x448, + x25519, +) + +__all__ = [ + "aead", + "ciphers", + "cmac", + "dh", + "dsa", + "ec", + "ed448", + "ed25519", + "hashes", + "hmac", + "hpke", + "kdf", + "keys", + "keywrap", + "mldsa", + "mlkem", + "openssl_version", + "openssl_version_text", + "poly1305", + "raise_openssl_error", + "rsa", + "x448", + "x25519", +] + +CRYPTOGRAPHY_IS_LIBRESSL: bool +CRYPTOGRAPHY_IS_BORINGSSL: bool +CRYPTOGRAPHY_IS_AWSLC: bool +CRYPTOGRAPHY_OPENSSL_309_OR_GREATER: bool +CRYPTOGRAPHY_OPENSSL_320_OR_GREATER: bool +CRYPTOGRAPHY_OPENSSL_330_OR_GREATER: bool +CRYPTOGRAPHY_OPENSSL_350_OR_GREATER: bool + +class Providers: ... + +_legacy_provider_loaded: bool +_providers: Providers + +def openssl_version() -> int: ... +def openssl_version_text() -> str: ... +def raise_openssl_error() -> typing.NoReturn: ... +def capture_error_stack() -> list[OpenSSLError]: ... +def is_fips_enabled() -> bool: ... +def enable_fips(providers: Providers) -> None: ... + +class OpenSSLError: + @property + def lib(self) -> int: ... + @property + def reason(self) -> int: ... + @property + def reason_text(self) -> bytes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/aead.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/aead.pyi new file mode 100644 index 0000000..eb44608 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/aead.pyi @@ -0,0 +1,189 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from collections.abc import Sequence + +from cryptography.utils import Buffer + +class AESGCM: + def __init__(self, key: Buffer) -> None: ... + @staticmethod + def generate_key(bit_length: int) -> bytes: ... + def encrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def decrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def encrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + def decrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + +class ChaCha20Poly1305: + def __init__(self, key: Buffer) -> None: ... + @staticmethod + def generate_key() -> bytes: ... + def encrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def encrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + def decrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def decrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + +class AESCCM: + def __init__(self, key: Buffer, tag_length: int = 16) -> None: ... + @staticmethod + def generate_key(bit_length: int) -> bytes: ... + def encrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def encrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + def decrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def decrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + +class AESSIV: + def __init__(self, key: Buffer) -> None: ... + @staticmethod + def generate_key(bit_length: int) -> bytes: ... + def encrypt( + self, + data: Buffer, + associated_data: Sequence[Buffer] | None, + ) -> bytes: ... + def encrypt_into( + self, + data: Buffer, + associated_data: Sequence[Buffer] | None, + buf: Buffer, + ) -> int: ... + def decrypt( + self, + data: Buffer, + associated_data: Sequence[Buffer] | None, + ) -> bytes: ... + def decrypt_into( + self, + data: Buffer, + associated_data: Sequence[Buffer] | None, + buf: Buffer, + ) -> int: ... + +class AESOCB3: + def __init__(self, key: Buffer) -> None: ... + @staticmethod + def generate_key(bit_length: int) -> bytes: ... + def encrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def encrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + def decrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def decrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + +class AESGCMSIV: + def __init__(self, key: Buffer) -> None: ... + @staticmethod + def generate_key(bit_length: int) -> bytes: ... + def encrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def encrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... + def decrypt( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + ) -> bytes: ... + def decrypt_into( + self, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, + buf: Buffer, + ) -> int: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi new file mode 100644 index 0000000..a48fb01 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi @@ -0,0 +1,38 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import ciphers +from cryptography.hazmat.primitives.ciphers import modes + +@typing.overload +def create_encryption_ctx( + algorithm: ciphers.CipherAlgorithm, mode: modes.ModeWithAuthenticationTag +) -> ciphers.AEADEncryptionContext: ... +@typing.overload +def create_encryption_ctx( + algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None +) -> ciphers.CipherContext: ... +@typing.overload +def create_decryption_ctx( + algorithm: ciphers.CipherAlgorithm, mode: modes.ModeWithAuthenticationTag +) -> ciphers.AEADDecryptionContext: ... +@typing.overload +def create_decryption_ctx( + algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None +) -> ciphers.CipherContext: ... +def cipher_supported( + algorithm: ciphers.CipherAlgorithm, mode: modes.Mode +) -> bool: ... +def _advance( + ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int +) -> None: ... +def _advance_aad( + ctx: ciphers.AEADEncryptionContext | ciphers.AEADDecryptionContext, n: int +) -> None: ... + +class CipherContext: ... +class AEADEncryptionContext: ... +class AEADDecryptionContext: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi new file mode 100644 index 0000000..9c03508 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi @@ -0,0 +1,18 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import ciphers + +class CMAC: + def __init__( + self, + algorithm: ciphers.BlockCipherAlgorithm, + backend: typing.Any = None, + ) -> None: ... + def update(self, data: bytes) -> None: ... + def finalize(self) -> bytes: ... + def verify(self, signature: bytes) -> None: ... + def copy(self) -> CMAC: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dh.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dh.pyi new file mode 100644 index 0000000..08733d7 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dh.pyi @@ -0,0 +1,51 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives.asymmetric import dh + +MIN_MODULUS_SIZE: int + +class DHPrivateKey: ... +class DHPublicKey: ... +class DHParameters: ... + +class DHPrivateNumbers: + def __init__(self, x: int, public_numbers: DHPublicNumbers) -> None: ... + def private_key(self, backend: typing.Any = None) -> dh.DHPrivateKey: ... + @property + def x(self) -> int: ... + @property + def public_numbers(self) -> DHPublicNumbers: ... + +class DHPublicNumbers: + def __init__( + self, y: int, parameter_numbers: DHParameterNumbers + ) -> None: ... + def public_key(self, backend: typing.Any = None) -> dh.DHPublicKey: ... + @property + def y(self) -> int: ... + @property + def parameter_numbers(self) -> DHParameterNumbers: ... + +class DHParameterNumbers: + def __init__(self, p: int, g: int, q: int | None = None) -> None: ... + def parameters(self, backend: typing.Any = None) -> dh.DHParameters: ... + @property + def p(self) -> int: ... + @property + def g(self) -> int: ... + @property + def q(self) -> int | None: ... + +def generate_parameters( + generator: int, key_size: int, backend: typing.Any = None +) -> dh.DHParameters: ... +def from_pem_parameters( + data: bytes, backend: typing.Any = None +) -> dh.DHParameters: ... +def from_der_parameters( + data: bytes, backend: typing.Any = None +) -> dh.DHParameters: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi new file mode 100644 index 0000000..0922a4c --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi @@ -0,0 +1,41 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives.asymmetric import dsa + +class DSAPrivateKey: ... +class DSAPublicKey: ... +class DSAParameters: ... + +class DSAPrivateNumbers: + def __init__(self, x: int, public_numbers: DSAPublicNumbers) -> None: ... + @property + def x(self) -> int: ... + @property + def public_numbers(self) -> DSAPublicNumbers: ... + def private_key(self, backend: typing.Any = None) -> dsa.DSAPrivateKey: ... + +class DSAPublicNumbers: + def __init__( + self, y: int, parameter_numbers: DSAParameterNumbers + ) -> None: ... + @property + def y(self) -> int: ... + @property + def parameter_numbers(self) -> DSAParameterNumbers: ... + def public_key(self, backend: typing.Any = None) -> dsa.DSAPublicKey: ... + +class DSAParameterNumbers: + def __init__(self, p: int, q: int, g: int) -> None: ... + @property + def p(self) -> int: ... + @property + def q(self) -> int: ... + @property + def g(self) -> int: ... + def parameters(self, backend: typing.Any = None) -> dsa.DSAParameters: ... + +def generate_parameters(key_size: int) -> dsa.DSAParameters: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ec.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ec.pyi new file mode 100644 index 0000000..5c3b7bf --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ec.pyi @@ -0,0 +1,52 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives.asymmetric import ec + +class ECPrivateKey: ... +class ECPublicKey: ... + +class EllipticCurvePrivateNumbers: + def __init__( + self, private_value: int, public_numbers: EllipticCurvePublicNumbers + ) -> None: ... + def private_key( + self, backend: typing.Any = None + ) -> ec.EllipticCurvePrivateKey: ... + @property + def private_value(self) -> int: ... + @property + def public_numbers(self) -> EllipticCurvePublicNumbers: ... + +class EllipticCurvePublicNumbers: + def __init__(self, x: int, y: int, curve: ec.EllipticCurve) -> None: ... + def public_key( + self, backend: typing.Any = None + ) -> ec.EllipticCurvePublicKey: ... + @property + def x(self) -> int: ... + @property + def y(self) -> int: ... + @property + def curve(self) -> ec.EllipticCurve: ... + def __eq__(self, other: object) -> bool: ... + +def curve_supported(curve: ec.EllipticCurve) -> bool: ... +def generate_private_key( + curve: ec.EllipticCurve, backend: typing.Any = None +) -> ec.EllipticCurvePrivateKey: ... +def from_private_numbers( + numbers: ec.EllipticCurvePrivateNumbers, +) -> ec.EllipticCurvePrivateKey: ... +def from_public_numbers( + numbers: ec.EllipticCurvePublicNumbers, +) -> ec.EllipticCurvePublicKey: ... +def from_public_bytes( + curve: ec.EllipticCurve, data: bytes +) -> ec.EllipticCurvePublicKey: ... +def derive_private_key( + private_value: int, curve: ec.EllipticCurve +) -> ec.EllipticCurvePrivateKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi new file mode 100644 index 0000000..f85b3d1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.utils import Buffer + +class Ed25519PrivateKey: ... +class Ed25519PublicKey: ... + +def generate_key() -> ed25519.Ed25519PrivateKey: ... +def from_private_bytes(data: Buffer) -> ed25519.Ed25519PrivateKey: ... +def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi new file mode 100644 index 0000000..c8ca0ec --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import ed448 +from cryptography.utils import Buffer + +class Ed448PrivateKey: ... +class Ed448PublicKey: ... + +def generate_key() -> ed448.Ed448PrivateKey: ... +def from_private_bytes(data: Buffer) -> ed448.Ed448PrivateKey: ... +def from_public_bytes(data: bytes) -> ed448.Ed448PublicKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi new file mode 100644 index 0000000..106b531 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi @@ -0,0 +1,30 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes +from cryptography.utils import Buffer + +class Hash(hashes.HashContext): + def __init__( + self, algorithm: hashes.HashAlgorithm, backend: typing.Any = None + ) -> None: ... + @property + def algorithm(self) -> hashes.HashAlgorithm: ... + def update(self, data: Buffer) -> None: ... + def finalize(self) -> bytes: ... + def copy(self) -> Hash: ... + @staticmethod + def hash(algorithm: hashes.HashAlgorithm, data: Buffer) -> bytes: ... + +def hash_supported(algorithm: hashes.HashAlgorithm) -> bool: ... + +class XOFHash: + def __init__(self, algorithm: hashes.ExtendableOutputFunction) -> None: ... + @property + def algorithm(self) -> hashes.ExtendableOutputFunction: ... + def update(self, data: Buffer) -> None: ... + def squeeze(self, length: int) -> bytes: ... + def copy(self) -> XOFHash: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi new file mode 100644 index 0000000..3883d1b --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi @@ -0,0 +1,22 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives import hashes +from cryptography.utils import Buffer + +class HMAC(hashes.HashContext): + def __init__( + self, + key: Buffer, + algorithm: hashes.HashAlgorithm, + backend: typing.Any = None, + ) -> None: ... + @property + def algorithm(self) -> hashes.HashAlgorithm: ... + def update(self, data: Buffer) -> None: ... + def finalize(self) -> bytes: ... + def verify(self, signature: bytes) -> None: ... + def copy(self) -> HMAC: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi new file mode 100644 index 0000000..7ea1711 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi @@ -0,0 +1,109 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import ec, mlkem, x25519 +from cryptography.utils import Buffer + +class KEM: + X25519: KEM + P256: KEM + P384: KEM + P521: KEM + MLKEM768: KEM + MLKEM1024: KEM + MLKEM768_X25519: KEM + MLKEM1024_P384: KEM + def enc_length(self) -> int: ... + +class KDF: + HKDF_SHA256: KDF + HKDF_SHA384: KDF + HKDF_SHA512: KDF + SHAKE128: KDF + SHAKE256: KDF + +class AEAD: + AES_128_GCM: AEAD + AES_256_GCM: AEAD + CHACHA20_POLY1305: AEAD + +class MLKEM768X25519PrivateKey: + def __init__( + self, + mlkem_key: mlkem.MLKEM768PrivateKey, + x25519_key: x25519.X25519PrivateKey, + ) -> None: ... + def public_key(self) -> MLKEM768X25519PublicKey: ... + +class MLKEM768X25519PublicKey: + def __init__( + self, + mlkem_key: mlkem.MLKEM768PublicKey, + x25519_key: x25519.X25519PublicKey, + ) -> None: ... + +class MLKEM1024P384PrivateKey: + def __init__( + self, + mlkem_key: mlkem.MLKEM1024PrivateKey, + p384_key: ec.EllipticCurvePrivateKey, + ) -> None: ... + def public_key(self) -> MLKEM1024P384PublicKey: ... + +class MLKEM1024P384PublicKey: + def __init__( + self, + mlkem_key: mlkem.MLKEM1024PublicKey, + p384_key: ec.EllipticCurvePublicKey, + ) -> None: ... + +class Suite: + def __init__(self, kem: KEM, kdf: KDF, aead: AEAD) -> None: ... + def encrypt( + self, + plaintext: Buffer, + public_key: x25519.X25519PublicKey + | ec.EllipticCurvePublicKey + | mlkem.MLKEM768PublicKey + | mlkem.MLKEM1024PublicKey + | MLKEM768X25519PublicKey + | MLKEM1024P384PublicKey, + info: Buffer | None = None, + ) -> bytes: ... + def decrypt( + self, + ciphertext: Buffer, + private_key: x25519.X25519PrivateKey + | ec.EllipticCurvePrivateKey + | mlkem.MLKEM768PrivateKey + | mlkem.MLKEM1024PrivateKey + | MLKEM768X25519PrivateKey + | MLKEM1024P384PrivateKey, + info: Buffer | None = None, + ) -> bytes: ... + +def _encrypt_with_aad( + suite: Suite, + plaintext: Buffer, + public_key: x25519.X25519PublicKey + | ec.EllipticCurvePublicKey + | mlkem.MLKEM768PublicKey + | mlkem.MLKEM1024PublicKey + | MLKEM768X25519PublicKey + | MLKEM1024P384PublicKey, + info: Buffer | None = None, + aad: Buffer | None = None, +) -> bytes: ... +def _decrypt_with_aad( + suite: Suite, + ciphertext: Buffer, + private_key: x25519.X25519PrivateKey + | ec.EllipticCurvePrivateKey + | mlkem.MLKEM768PrivateKey + | mlkem.MLKEM1024PrivateKey + | MLKEM768X25519PrivateKey + | MLKEM1024P384PrivateKey, + info: Buffer | None = None, + aad: Buffer | None = None, +) -> bytes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi new file mode 100644 index 0000000..bb37b96 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi @@ -0,0 +1,205 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives.hashes import HashAlgorithm +from cryptography.hazmat.primitives.kdf.kbkdf import CounterLocation, Mode +from cryptography.utils import Buffer + +class PBKDF2HMAC: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + salt: bytes, + iterations: int, + backend: typing.Any = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class Scrypt: + def __init__( + self, + salt: bytes, + length: int, + n: int, + r: int, + p: int, + backend: typing.Any = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class Argon2d: + def __init__( + self, + *, + salt: bytes, + length: int, + iterations: int, + lanes: int, + memory_cost: int, + ad: bytes | None = None, + secret: bytes | None = None, + ) -> None: ... + def derive(self, key_material: bytes) -> bytes: ... + def derive_into(self, key_material: bytes, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + def derive_phc_encoded(self, key_material: bytes) -> str: ... + @classmethod + def verify_phc_encoded( + cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None + ) -> None: ... + +class Argon2i: + def __init__( + self, + *, + salt: bytes, + length: int, + iterations: int, + lanes: int, + memory_cost: int, + ad: bytes | None = None, + secret: bytes | None = None, + ) -> None: ... + def derive(self, key_material: bytes) -> bytes: ... + def derive_into(self, key_material: bytes, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + def derive_phc_encoded(self, key_material: bytes) -> str: ... + @classmethod + def verify_phc_encoded( + cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None + ) -> None: ... + +class Argon2id: + def __init__( + self, + *, + salt: bytes, + length: int, + iterations: int, + lanes: int, + memory_cost: int, + ad: bytes | None = None, + secret: bytes | None = None, + ) -> None: ... + def derive(self, key_material: bytes) -> bytes: ... + def derive_into(self, key_material: bytes, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + def derive_phc_encoded(self, key_material: bytes) -> str: ... + @classmethod + def verify_phc_encoded( + cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None + ) -> None: ... + +class HKDF: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + salt: bytes | None, + info: bytes | None, + backend: typing.Any = None, + ): ... + @staticmethod + def extract( + algorithm: HashAlgorithm, salt: bytes | None, key_material: Buffer + ) -> bytes: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class HKDFExpand: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + info: bytes | None, + backend: typing.Any = None, + ): ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class X963KDF: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + sharedinfo: bytes | None, + backend: typing.Any = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class ConcatKDFHash: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + otherinfo: bytes | None, + backend: typing.Any = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class ConcatKDFHMAC: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + salt: bytes | None, + otherinfo: bytes | None, + backend: typing.Any = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class KBKDFHMAC: + def __init__( + self, + algorithm: HashAlgorithm, + mode: Mode, + length: int, + rlen: int, + llen: int | None, + location: CounterLocation, + label: bytes | None, + context: bytes | None, + fixed: bytes | None, + backend: typing.Any = None, + *, + break_location: int | None = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class KBKDFCMAC: + def __init__( + self, + algorithm: typing.Any, + mode: Mode, + length: int, + rlen: int, + llen: int | None, + location: CounterLocation, + label: bytes | None, + context: bytes | None, + fixed: bytes | None, + backend: typing.Any = None, + *, + break_location: int | None = None, + ) -> None: ... + def derive(self, key_material: Buffer) -> bytes: ... + def derive_into(self, key_material: Buffer, buffer: Buffer) -> int: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keys.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keys.pyi new file mode 100644 index 0000000..404057e --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keys.pyi @@ -0,0 +1,34 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives.asymmetric.types import ( + PrivateKeyTypes, + PublicKeyTypes, +) +from cryptography.utils import Buffer + +def load_der_private_key( + data: Buffer, + password: bytes | None, + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, +) -> PrivateKeyTypes: ... +def load_pem_private_key( + data: Buffer, + password: bytes | None, + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, +) -> PrivateKeyTypes: ... +def load_der_public_key( + data: bytes, + backend: typing.Any = None, +) -> PublicKeyTypes: ... +def load_pem_public_key( + data: bytes, + backend: typing.Any = None, +) -> PublicKeyTypes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keywrap.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keywrap.pyi new file mode 100644 index 0000000..dd445ea --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/keywrap.pyi @@ -0,0 +1,28 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.utils import Buffer + +def aes_key_wrap( + wrapping_key: Buffer, + key_to_wrap: Buffer, + backend: typing.Any = None, +) -> bytes: ... +def aes_key_unwrap( + wrapping_key: Buffer, + wrapped_key: Buffer, + backend: typing.Any = None, +) -> bytes: ... +def aes_key_wrap_with_padding( + wrapping_key: Buffer, + key_to_wrap: Buffer, + backend: typing.Any = None, +) -> bytes: ... +def aes_key_unwrap_with_padding( + wrapping_key: Buffer, + wrapped_key: Buffer, + backend: typing.Any = None, +) -> bytes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi new file mode 100644 index 0000000..cea9cb1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi @@ -0,0 +1,35 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import mldsa +from cryptography.utils import Buffer + +class MLDSA44PrivateKey: ... +class MLDSA44PublicKey: ... +class MLDSA65PrivateKey: ... +class MLDSA65PublicKey: ... +class MLDSA87PrivateKey: ... +class MLDSA87PublicKey: ... + +class MLDSAMuHasher: + def __init__( + self, + public_key: mldsa.MLDSA44PublicKey + | mldsa.MLDSA65PublicKey + | mldsa.MLDSA87PublicKey, + context: Buffer | None = None, + ) -> None: ... + def update(self, data: Buffer) -> None: ... + def copy(self) -> MLDSAMuHasher: ... + def finalize(self) -> bytes: ... + +def generate_mldsa44_key() -> mldsa.MLDSA44PrivateKey: ... +def from_mldsa44_public_bytes(data: bytes) -> mldsa.MLDSA44PublicKey: ... +def from_mldsa44_seed_bytes(data: Buffer) -> mldsa.MLDSA44PrivateKey: ... +def generate_mldsa65_key() -> mldsa.MLDSA65PrivateKey: ... +def from_mldsa65_public_bytes(data: bytes) -> mldsa.MLDSA65PublicKey: ... +def from_mldsa65_seed_bytes(data: Buffer) -> mldsa.MLDSA65PrivateKey: ... +def generate_mldsa87_key() -> mldsa.MLDSA87PrivateKey: ... +def from_mldsa87_public_bytes(data: bytes) -> mldsa.MLDSA87PublicKey: ... +def from_mldsa87_seed_bytes(data: Buffer) -> mldsa.MLDSA87PrivateKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi new file mode 100644 index 0000000..768a340 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi @@ -0,0 +1,18 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import mlkem +from cryptography.utils import Buffer + +class MLKEM768PrivateKey: ... +class MLKEM768PublicKey: ... +class MLKEM1024PrivateKey: ... +class MLKEM1024PublicKey: ... + +def generate_mlkem768_key() -> mlkem.MLKEM768PrivateKey: ... +def from_mlkem768_seed_bytes(data: Buffer) -> mlkem.MLKEM768PrivateKey: ... +def from_mlkem768_public_bytes(data: Buffer) -> mlkem.MLKEM768PublicKey: ... +def generate_mlkem1024_key() -> mlkem.MLKEM1024PrivateKey: ... +def from_mlkem1024_seed_bytes(data: Buffer) -> mlkem.MLKEM1024PrivateKey: ... +def from_mlkem1024_public_bytes(data: Buffer) -> mlkem.MLKEM1024PublicKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi new file mode 100644 index 0000000..45a2a39 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi @@ -0,0 +1,15 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.utils import Buffer + +class Poly1305: + def __init__(self, key: Buffer) -> None: ... + @staticmethod + def generate_tag(key: Buffer, data: Buffer) -> bytes: ... + @staticmethod + def verify_tag(key: Buffer, data: Buffer, tag: bytes) -> None: ... + def update(self, data: Buffer) -> None: ... + def finalize(self) -> bytes: ... + def verify(self, tag: bytes) -> None: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi new file mode 100644 index 0000000..ef7752d --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi @@ -0,0 +1,55 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing + +from cryptography.hazmat.primitives.asymmetric import rsa + +class RSAPrivateKey: ... +class RSAPublicKey: ... + +class RSAPrivateNumbers: + def __init__( + self, + p: int, + q: int, + d: int, + dmp1: int, + dmq1: int, + iqmp: int, + public_numbers: RSAPublicNumbers, + ) -> None: ... + @property + def p(self) -> int: ... + @property + def q(self) -> int: ... + @property + def d(self) -> int: ... + @property + def dmp1(self) -> int: ... + @property + def dmq1(self) -> int: ... + @property + def iqmp(self) -> int: ... + @property + def public_numbers(self) -> RSAPublicNumbers: ... + def private_key( + self, + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, + ) -> rsa.RSAPrivateKey: ... + +class RSAPublicNumbers: + def __init__(self, e: int, n: int) -> None: ... + @property + def n(self) -> int: ... + @property + def e(self) -> int: ... + def public_key(self, backend: typing.Any = None) -> rsa.RSAPublicKey: ... + +def generate_private_key( + public_exponent: int, + key_size: int, +) -> rsa.RSAPrivateKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi new file mode 100644 index 0000000..38d2add --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import x25519 +from cryptography.utils import Buffer + +class X25519PrivateKey: ... +class X25519PublicKey: ... + +def generate_key() -> x25519.X25519PrivateKey: ... +def from_private_bytes(data: Buffer) -> x25519.X25519PrivateKey: ... +def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x448.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x448.pyi new file mode 100644 index 0000000..3ac0980 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/openssl/x448.pyi @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.primitives.asymmetric import x448 +from cryptography.utils import Buffer + +class X448PrivateKey: ... +class X448PublicKey: ... + +def generate_key() -> x448.X448PrivateKey: ... +def from_private_bytes(data: Buffer) -> x448.X448PrivateKey: ... +def from_public_bytes(data: bytes) -> x448.X448PublicKey: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs12.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs12.pyi new file mode 100644 index 0000000..b25becb --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs12.pyi @@ -0,0 +1,52 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import typing +from collections.abc import Iterable + +from cryptography import x509 +from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes +from cryptography.hazmat.primitives.serialization import ( + KeySerializationEncryption, +) +from cryptography.hazmat.primitives.serialization.pkcs12 import ( + PKCS12KeyAndCertificates, + PKCS12PrivateKeyTypes, +) +from cryptography.utils import Buffer + +class PKCS12Certificate: + def __init__( + self, cert: x509.Certificate, friendly_name: bytes | None + ) -> None: ... + @property + def friendly_name(self) -> bytes | None: ... + @property + def certificate(self) -> x509.Certificate: ... + +def load_key_and_certificates( + data: Buffer, + password: Buffer | None, + backend: typing.Any = None, +) -> tuple[ + PrivateKeyTypes | None, + x509.Certificate | None, + list[x509.Certificate], +]: ... +def load_pkcs12( + data: bytes, + password: bytes | None, + backend: typing.Any = None, +) -> PKCS12KeyAndCertificates: ... +def serialize_java_truststore( + certs: Iterable[PKCS12Certificate], + encryption_algorithm: KeySerializationEncryption, +) -> bytes: ... +def serialize_key_and_certificates( + name: bytes | None, + key: PKCS12PrivateKeyTypes | None, + cert: x509.Certificate | None, + cas: Iterable[x509.Certificate | PKCS12Certificate] | None, + encryption_algorithm: KeySerializationEncryption, +) -> bytes: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs7.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs7.pyi new file mode 100644 index 0000000..358b135 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/pkcs7.pyi @@ -0,0 +1,50 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from collections.abc import Iterable + +from cryptography import x509 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.serialization import pkcs7 + +def serialize_certificates( + certs: list[x509.Certificate], + encoding: serialization.Encoding, +) -> bytes: ... +def encrypt_and_serialize( + builder: pkcs7.PKCS7EnvelopeBuilder, + content_encryption_algorithm: pkcs7.ContentEncryptionAlgorithm, + encoding: serialization.Encoding, + options: Iterable[pkcs7.PKCS7Options], +) -> bytes: ... +def sign_and_serialize( + builder: pkcs7.PKCS7SignatureBuilder, + encoding: serialization.Encoding, + options: Iterable[pkcs7.PKCS7Options], +) -> bytes: ... +def decrypt_der( + data: bytes, + certificate: x509.Certificate, + private_key: rsa.RSAPrivateKey, + options: Iterable[pkcs7.PKCS7Options], +) -> bytes: ... +def decrypt_pem( + data: bytes, + certificate: x509.Certificate, + private_key: rsa.RSAPrivateKey, + options: Iterable[pkcs7.PKCS7Options], +) -> bytes: ... +def decrypt_smime( + data: bytes, + certificate: x509.Certificate, + private_key: rsa.RSAPrivateKey, + options: Iterable[pkcs7.PKCS7Options], +) -> bytes: ... +def load_pem_pkcs7_certificates( + data: bytes, +) -> list[x509.Certificate]: ... +def load_der_pkcs7_certificates( + data: bytes, +) -> list[x509.Certificate]: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/test_support.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/test_support.pyi new file mode 100644 index 0000000..c6c6d0b --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/test_support.pyi @@ -0,0 +1,23 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography import x509 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.serialization import pkcs7 +from cryptography.utils import Buffer + +class TestCertificate: + not_after_tag: int + not_before_tag: int + issuer_value_tags: list[int] + subject_value_tags: list[int] + +def test_parse_certificate(data: bytes) -> TestCertificate: ... +def pkcs7_verify( + encoding: serialization.Encoding, + sig: bytes, + msg: Buffer | None, + certs: list[x509.Certificate], + options: list[pkcs7.PKCS7Options], +) -> None: ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/x509.pyi b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/x509.pyi new file mode 100644 index 0000000..4438cc7 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/_rust/x509.pyi @@ -0,0 +1,313 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +import datetime +import typing +from collections.abc import Iterator + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric.ec import ECDSA +from cryptography.hazmat.primitives.asymmetric.padding import PSS, PKCS1v15 +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPublicKeyTypes, + CertificatePublicKeyTypes, + PrivateKeyTypes, +) +from cryptography.x509 import certificate_transparency + +def load_pem_x509_certificate( + data: bytes, backend: typing.Any = None +) -> x509.Certificate: ... +def load_der_x509_certificate( + data: bytes, backend: typing.Any = None +) -> x509.Certificate: ... +def load_pem_x509_certificates( + data: bytes, +) -> list[x509.Certificate]: ... +def load_pem_x509_crl( + data: bytes, backend: typing.Any = None +) -> x509.CertificateRevocationList: ... +def load_der_x509_crl( + data: bytes, backend: typing.Any = None +) -> x509.CertificateRevocationList: ... +def load_pem_x509_csr( + data: bytes, backend: typing.Any = None +) -> x509.CertificateSigningRequest: ... +def load_der_x509_csr( + data: bytes, backend: typing.Any = None +) -> x509.CertificateSigningRequest: ... +def encode_name_bytes(name: x509.Name) -> bytes: ... +def parse_name_bytes(data: bytes) -> x509.Name: ... +def encode_extension_value(extension: x509.ExtensionType) -> bytes: ... +def create_x509_certificate( + builder: x509.CertificateBuilder, + private_key: PrivateKeyTypes | None, + hash_algorithm: hashes.HashAlgorithm | None, + rsa_padding: PKCS1v15 | PSS | None, + ecdsa_deterministic: bool | None, +) -> x509.Certificate: ... +def create_x509_csr( + builder: x509.CertificateSigningRequestBuilder, + private_key: PrivateKeyTypes, + hash_algorithm: hashes.HashAlgorithm | None, + rsa_padding: PKCS1v15 | PSS | None, + ecdsa_deterministic: bool | None, +) -> x509.CertificateSigningRequest: ... +def create_revoked_certificate( + builder: x509.RevokedCertificateBuilder, +) -> x509.RevokedCertificate: ... +def create_x509_crl( + builder: x509.CertificateRevocationListBuilder, + private_key: PrivateKeyTypes, + hash_algorithm: hashes.HashAlgorithm | None, + rsa_padding: PKCS1v15 | PSS | None, + ecdsa_deterministic: bool | None, +) -> x509.CertificateRevocationList: ... + +class Sct: + @property + def version(self) -> certificate_transparency.Version: ... + @property + def log_id(self) -> bytes: ... + @property + def timestamp(self) -> datetime.datetime: ... + @property + def entry_type(self) -> certificate_transparency.LogEntryType: ... + @property + def signature_hash_algorithm(self) -> hashes.HashAlgorithm: ... + @property + def signature_algorithm( + self, + ) -> certificate_transparency.SignatureAlgorithm: ... + @property + def signature(self) -> bytes: ... + @property + def extension_bytes(self) -> bytes: ... + +class Certificate: + def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... + @property + def serial_number(self) -> int: ... + @property + def version(self) -> x509.Version: ... + def public_key(self) -> CertificatePublicKeyTypes: ... + @property + def public_key_algorithm_oid(self) -> x509.ObjectIdentifier: ... + @property + def not_valid_before(self) -> datetime.datetime: ... + @property + def not_valid_before_utc(self) -> datetime.datetime: ... + @property + def not_valid_after(self) -> datetime.datetime: ... + @property + def not_valid_after_utc(self) -> datetime.datetime: ... + @property + def issuer(self) -> x509.Name: ... + @property + def subject(self) -> x509.Name: ... + @property + def signature_hash_algorithm( + self, + ) -> hashes.HashAlgorithm | None: ... + @property + def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... + @property + def signature_algorithm_parameters( + self, + ) -> PSS | PKCS1v15 | ECDSA | None: ... + @property + def extensions(self) -> x509.Extensions: ... + @property + def signature(self) -> bytes: ... + @property + def tbs_certificate_bytes(self) -> bytes: ... + @property + def tbs_precertificate_bytes(self) -> bytes: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... + def verify_directly_issued_by(self, issuer: Certificate) -> None: ... + +class RevokedCertificate: + @property + def serial_number(self) -> int: ... + @property + def revocation_date(self) -> datetime.datetime: ... + @property + def revocation_date_utc(self) -> datetime.datetime: ... + @property + def extensions(self) -> x509.Extensions: ... + +class CertificateRevocationList: + def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... + def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... + def get_revoked_certificate_by_serial_number( + self, serial_number: int + ) -> x509.RevokedCertificate | None: ... + @property + def signature_hash_algorithm( + self, + ) -> hashes.HashAlgorithm | None: ... + @property + def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... + @property + def signature_algorithm_parameters( + self, + ) -> PSS | PKCS1v15 | ECDSA | None: ... + @property + def issuer(self) -> x509.Name: ... + @property + def next_update(self) -> datetime.datetime | None: ... + @property + def next_update_utc(self) -> datetime.datetime | None: ... + @property + def last_update(self) -> datetime.datetime: ... + @property + def last_update_utc(self) -> datetime.datetime: ... + @property + def extensions(self) -> x509.Extensions: ... + @property + def signature(self) -> bytes: ... + @property + def tbs_certlist_bytes(self) -> bytes: ... + def __eq__(self, other: object) -> bool: ... + def __len__(self) -> int: ... + @typing.overload + def __getitem__(self, idx: int) -> x509.RevokedCertificate: ... + @typing.overload + def __getitem__(self, idx: slice) -> list[x509.RevokedCertificate]: ... + def __iter__(self) -> Iterator[x509.RevokedCertificate]: ... + def is_signature_valid( + self, public_key: CertificateIssuerPublicKeyTypes + ) -> bool: ... + +class CertificateSigningRequest: + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def public_key(self) -> CertificatePublicKeyTypes: ... + @property + def subject(self) -> x509.Name: ... + @property + def signature_hash_algorithm( + self, + ) -> hashes.HashAlgorithm | None: ... + @property + def signature_algorithm_oid(self) -> x509.ObjectIdentifier: ... + @property + def signature_algorithm_parameters( + self, + ) -> PSS | PKCS1v15 | ECDSA | None: ... + @property + def extensions(self) -> x509.Extensions: ... + @property + def attributes(self) -> x509.Attributes: ... + def public_bytes(self, encoding: serialization.Encoding) -> bytes: ... + @property + def signature(self) -> bytes: ... + @property + def tbs_certrequest_bytes(self) -> bytes: ... + @property + def is_signature_valid(self) -> bool: ... + +class PolicyBuilder: + def time(self, time: datetime.datetime) -> PolicyBuilder: ... + def store(self, store: Store) -> PolicyBuilder: ... + def max_chain_depth(self, max_chain_depth: int) -> PolicyBuilder: ... + def extension_policies( + self, *, ca_policy: ExtensionPolicy, ee_policy: ExtensionPolicy + ) -> PolicyBuilder: ... + def build_client_verifier(self) -> ClientVerifier: ... + def build_server_verifier( + self, subject: x509.verification.Subject + ) -> ServerVerifier: ... + +class Policy: + @property + def max_chain_depth(self) -> int: ... + @property + def subject(self) -> x509.verification.Subject | None: ... + @property + def validation_time(self) -> datetime.datetime: ... + @property + def extended_key_usage(self) -> x509.ObjectIdentifier: ... + @property + def minimum_rsa_modulus(self) -> int: ... + +class Criticality: + CRITICAL: Criticality + AGNOSTIC: Criticality + NON_CRITICAL: Criticality + +T = typing.TypeVar("T", contravariant=True, bound=x509.ExtensionType) + +MaybeExtensionValidatorCallback = typing.Callable[ + [ + Policy, + x509.Certificate, + T | None, + ], + None, +] + +PresentExtensionValidatorCallback = typing.Callable[ + [Policy, x509.Certificate, T], + None, +] + +class ExtensionPolicy: + @staticmethod + def permit_all() -> ExtensionPolicy: ... + @staticmethod + def webpki_defaults_ca() -> ExtensionPolicy: ... + @staticmethod + def webpki_defaults_ee() -> ExtensionPolicy: ... + def require_not_present( + self, extension_type: type[x509.ExtensionType] + ) -> ExtensionPolicy: ... + def may_be_present( + self, + extension_type: type[T], + criticality: Criticality, + validator: MaybeExtensionValidatorCallback[T] | None, + ) -> ExtensionPolicy: ... + def require_present( + self, + extension_type: type[T], + criticality: Criticality, + validator: PresentExtensionValidatorCallback[T] | None, + ) -> ExtensionPolicy: ... + +class VerifiedClient: + @property + def subjects(self) -> list[x509.GeneralName] | None: ... + @property + def chain(self) -> list[x509.Certificate]: ... + +class ClientVerifier: + @property + def policy(self) -> Policy: ... + @property + def store(self) -> Store: ... + def verify( + self, + leaf: x509.Certificate, + intermediates: list[x509.Certificate], + ) -> VerifiedClient: ... + +class ServerVerifier: + @property + def policy(self) -> Policy: ... + @property + def store(self) -> Store: ... + def verify( + self, + leaf: x509.Certificate, + intermediates: list[x509.Certificate], + ) -> list[x509.Certificate]: ... + +class Store: + def __init__(self, certs: list[x509.Certificate]) -> None: ... + +class VerificationError(Exception): ... diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/__init__.py new file mode 100644 index 0000000..41d7318 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/_conditional.py b/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/_conditional.py new file mode 100644 index 0000000..1e447a5 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/_conditional.py @@ -0,0 +1,199 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + + +def cryptography_has_set_cert_cb() -> list[str]: + return [ + "SSL_CTX_set_cert_cb", + "SSL_set_cert_cb", + ] + + +def cryptography_has_ssl_st() -> list[str]: + return [ + "SSL_ST_BEFORE", + "SSL_ST_OK", + "SSL_ST_INIT", + "SSL_ST_RENEGOTIATE", + ] + + +def cryptography_has_tls_st() -> list[str]: + return [ + "TLS_ST_BEFORE", + "TLS_ST_OK", + ] + + +def cryptography_has_ssl_sigalgs() -> list[str]: + return [ + "SSL_CTX_set1_sigalgs_list", + ] + + +def cryptography_has_psk() -> list[str]: + return [ + "SSL_CTX_use_psk_identity_hint", + "SSL_CTX_set_psk_server_callback", + "SSL_CTX_set_psk_client_callback", + ] + + +def cryptography_has_psk_tlsv13() -> list[str]: + return [ + "SSL_CTX_set_psk_find_session_callback", + "SSL_CTX_set_psk_use_session_callback", + "Cryptography_SSL_SESSION_new", + "SSL_CIPHER_find", + "SSL_SESSION_set1_master_key", + "SSL_SESSION_set_cipher", + "SSL_SESSION_set_protocol_version", + ] + + +def cryptography_has_custom_ext() -> list[str]: + return [ + "SSL_CTX_add_client_custom_ext", + "SSL_CTX_add_server_custom_ext", + "SSL_extension_supported", + ] + + +def cryptography_has_tlsv13_functions() -> list[str]: + return [ + "SSL_CTX_set_ciphersuites", + ] + + +def cryptography_has_tlsv13_hs_functions() -> list[str]: + return [ + "SSL_VERIFY_POST_HANDSHAKE", + "SSL_verify_client_post_handshake", + "SSL_CTX_set_post_handshake_auth", + "SSL_set_post_handshake_auth", + "SSL_SESSION_get_max_early_data", + "SSL_write_early_data", + "SSL_read_early_data", + "SSL_CTX_set_max_early_data", + ] + + +def cryptography_has_ssl_verify_client_post_handshake() -> list[str]: + return [ + "SSL_verify_client_post_handshake", + ] + + +def cryptography_has_engine() -> list[str]: + return [ + "ENGINE_by_id", + "ENGINE_init", + "ENGINE_finish", + "ENGINE_get_default_RAND", + "ENGINE_set_default_RAND", + "ENGINE_unregister_RAND", + "ENGINE_ctrl_cmd", + "ENGINE_free", + "ENGINE_get_name", + "ENGINE_ctrl_cmd_string", + "ENGINE_load_builtin_engines", + "ENGINE_load_private_key", + "ENGINE_load_public_key", + "SSL_CTX_set_client_cert_engine", + ] + + +def cryptography_has_verified_chain() -> list[str]: + return [ + "SSL_get0_verified_chain", + ] + + +def cryptography_has_srtp() -> list[str]: + return [ + "SSL_CTX_set_tlsext_use_srtp", + "SSL_set_tlsext_use_srtp", + "SSL_get_selected_srtp_profile", + ] + + +def cryptography_has_dtls_get_data_mtu() -> list[str]: + return [ + "DTLS_get_data_mtu", + ] + + +def cryptography_has_ssl_cookie() -> list[str]: + return [ + "SSL_OP_COOKIE_EXCHANGE", + "DTLS1_COOKIE_LENGTH", + "DTLSv1_listen", + "SSL_CTX_set_cookie_generate_cb", + "SSL_CTX_set_cookie_verify_cb", + ] + + +def cryptography_has_prime_checks() -> list[str]: + return [ + "BN_prime_checks_for_size", + ] + + +def cryptography_has_unexpected_eof_while_reading() -> list[str]: + return ["SSL_R_UNEXPECTED_EOF_WHILE_READING"] + + +def cryptography_has_ssl_op_ignore_unexpected_eof() -> list[str]: + return [ + "SSL_OP_IGNORE_UNEXPECTED_EOF", + ] + + +def cryptography_has_get_extms_support() -> list[str]: + return ["SSL_get_extms_support"] + + +def cryptography_has_ssl_get0_group_name() -> list[str]: + return ["SSL_get0_group_name"] + + +# This is a mapping of +# {condition: function-returning-names-dependent-on-that-condition} so we can +# loop over them and delete unsupported names at runtime. It will be removed +# when cffi supports #if in cdef. We use functions instead of just a dict of +# lists so we can use coverage to measure which are used. +CONDITIONAL_NAMES = { + "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb, + "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st, + "Cryptography_HAS_TLS_ST": cryptography_has_tls_st, + "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs, + "Cryptography_HAS_PSK": cryptography_has_psk, + "Cryptography_HAS_PSK_TLSv1_3": cryptography_has_psk_tlsv13, + "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, + "Cryptography_HAS_TLSv1_3_FUNCTIONS": cryptography_has_tlsv13_functions, + "Cryptography_HAS_TLSv1_3_HS_FUNCTIONS": ( + cryptography_has_tlsv13_hs_functions + ), + "Cryptography_HAS_SSL_VERIFY_CLIENT_POST_HANDSHAKE": ( + cryptography_has_ssl_verify_client_post_handshake + ), + "Cryptography_HAS_ENGINE": cryptography_has_engine, + "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, + "Cryptography_HAS_SRTP": cryptography_has_srtp, + "Cryptography_HAS_DTLS_GET_DATA_MTU": cryptography_has_dtls_get_data_mtu, + "Cryptography_HAS_SSL_COOKIE": cryptography_has_ssl_cookie, + "Cryptography_HAS_PRIME_CHECKS": cryptography_has_prime_checks, + "Cryptography_HAS_UNEXPECTED_EOF_WHILE_READING": ( + cryptography_has_unexpected_eof_while_reading + ), + "Cryptography_HAS_SSL_OP_IGNORE_UNEXPECTED_EOF": ( + cryptography_has_ssl_op_ignore_unexpected_eof + ), + "Cryptography_HAS_GET_EXTMS_SUPPORT": cryptography_has_get_extms_support, + "Cryptography_HAS_SSL_GET0_GROUP_NAME": ( + cryptography_has_ssl_get0_group_name + ), +} diff --git a/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/binding.py b/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/binding.py new file mode 100644 index 0000000..6e13df1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/bindings/openssl/binding.py @@ -0,0 +1,107 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import threading +import types +import typing +from collections.abc import Callable, Mapping + +import cryptography +from cryptography.exceptions import InternalError +from cryptography.hazmat.bindings._rust import _openssl, openssl +from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES + + +def _openssl_assert(ok: bool) -> None: + if not ok: + errors = openssl.capture_error_stack() + + raise InternalError( + "Unknown OpenSSL error. This error is commonly encountered when " + "another library is not cleaning up the OpenSSL error stack. If " + "you are using cryptography with another library that uses " + "OpenSSL try disabling it before reporting a bug. Otherwise " + "please file an issue at https://github.com/pyca/cryptography/" + "issues with information on how to reproduce " + f"this. ({errors!r})", + errors, + ) + + +def build_conditional_library( + lib: typing.Any, + conditional_names: Mapping[str, Callable[[], list[str]]], +) -> typing.Any: + conditional_lib = types.ModuleType("lib") + conditional_lib._original_lib = lib # type: ignore[attr-defined] + excluded_names = set() + for condition, names_cb in conditional_names.items(): + if not getattr(lib, condition): + excluded_names.update(names_cb()) + + for attr in dir(lib): + if attr not in excluded_names: + setattr(conditional_lib, attr, getattr(lib, attr)) + + return conditional_lib + + +class Binding: + """ + OpenSSL API wrapper. + """ + + lib: typing.ClassVar[typing.Any] = None + ffi: typing.Any = _openssl.ffi + _lib_loaded = False + _init_lock = threading.Lock() + + def __init__(self) -> None: + self._ensure_ffi_initialized() + + @classmethod + def _ensure_ffi_initialized(cls) -> None: + with cls._init_lock: + if not cls._lib_loaded: + cls.lib = build_conditional_library( + _openssl.lib, CONDITIONAL_NAMES + ) + cls._lib_loaded = True + + @classmethod + def init_static_locks(cls) -> None: + cls._ensure_ffi_initialized() + + +def _verify_package_version(version: str) -> None: + # Occasionally we run into situations where the version of the Python + # package does not match the version of the shared object that is loaded. + # This may occur in environments where multiple versions of cryptography + # are installed and available in the python path. To avoid errors cropping + # up later this code checks that the currently imported package and the + # shared object that were loaded have the same version and raise an + # ImportError if they do not + so_package_version = _openssl.ffi.string( + _openssl.lib.CRYPTOGRAPHY_PACKAGE_VERSION + ) + if version.encode("ascii") != so_package_version: + raise ImportError( + "The version of cryptography does not match the loaded " + "shared object. This can happen if you have multiple copies of " + "cryptography installed in your Python path. Please try creating " + "a new virtual environment to resolve this issue. " + f"Loaded python version: {version}, " + f"shared object version: {so_package_version}" + ) + + _openssl_assert( + _openssl.lib.OpenSSL_version_num() == openssl.openssl_version(), + ) + + +_verify_package_version(cryptography.__version__) + +Binding.init_static_locks() diff --git a/source/target-vendors/cp312/cryptography/hazmat/decrepit/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/decrepit/__init__.py new file mode 100644 index 0000000..41d7318 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/decrepit/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations diff --git a/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/__init__.py new file mode 100644 index 0000000..41d7318 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations diff --git a/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/algorithms.py b/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/algorithms.py new file mode 100644 index 0000000..72dad04 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/algorithms.py @@ -0,0 +1,145 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import warnings + +from cryptography import utils +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, + _verify_key_size, +) + + +class ARC4(CipherAlgorithm): + name = "RC4" + key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class TripleDES(BlockCipherAlgorithm): + name = "3DES" + block_size = 64 + key_sizes = frozenset([64, 128, 192]) + + def __init__(self, key: bytes): + # Check the key type before the length-based deprecation warnings so + # an invalid key type doesn't trigger a spurious warning. + utils._check_byteslike("key", key) + if len(key) == 8: + warnings.warn( + "Single-key TripleDES (8-byte keys) is deprecated and " + "support will be removed in a future release. Use 24-byte " + "keys instead (e.g., key + key + key).", + utils.DeprecatedIn47, + stacklevel=2, + ) + key = key + key + key + elif len(key) == 16: + warnings.warn( + "Two-key TripleDES (16-byte keys) is deprecated and " + "support will be removed in a future release. Use 24-byte " + "keys instead (e.g., key + key[:8]).", + utils.DeprecatedIn47, + stacklevel=2, + ) + key = key + key[:8] + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +# Not actually supported, marker for tests +class _DES: + key_size = 64 + + +class Blowfish(BlockCipherAlgorithm): + name = "Blowfish" + block_size = 64 + key_sizes = frozenset(range(32, 449, 8)) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class CAST5(BlockCipherAlgorithm): + name = "CAST5" + block_size = 64 + key_sizes = frozenset(range(40, 129, 8)) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class SEED(BlockCipherAlgorithm): + name = "SEED" + block_size = 128 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class IDEA(BlockCipherAlgorithm): + name = "IDEA" + block_size = 64 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class Camellia(BlockCipherAlgorithm): + name = "camellia" + block_size = 128 + key_sizes = frozenset([128, 192, 256]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +# This class only allows RC2 with a 128-bit key. No support for +# effective key bits or other key sizes is provided. +class RC2(BlockCipherAlgorithm): + name = "RC2" + block_size = 64 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 diff --git a/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/modes.py b/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/modes.py new file mode 100644 index 0000000..1786bb0 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/decrepit/ciphers/modes.py @@ -0,0 +1,53 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography import utils +from cryptography.hazmat.primitives._modes import ( + ModeWithInitializationVector, + _check_iv_and_key_length, +) + + +class OFB(ModeWithInitializationVector): + name = "OFB" + + def __init__(self, initialization_vector: utils.Buffer): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> utils.Buffer: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class CFB(ModeWithInitializationVector): + name = "CFB" + + def __init__(self, initialization_vector: utils.Buffer): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> utils.Buffer: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class CFB8(ModeWithInitializationVector): + name = "CFB8" + + def __init__(self, initialization_vector: utils.Buffer): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> utils.Buffer: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/__init__.py new file mode 100644 index 0000000..41d7318 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/_asymmetric.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/_asymmetric.py new file mode 100644 index 0000000..ea55ffd --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/_asymmetric.py @@ -0,0 +1,19 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +# This exists to break an import cycle. It is normally accessible from the +# asymmetric padding module. + + +class AsymmetricPadding(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this padding (e.g. "PSS", "PKCS1"). + """ diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/_cipheralgorithm.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/_cipheralgorithm.py new file mode 100644 index 0000000..305a9fd --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/_cipheralgorithm.py @@ -0,0 +1,60 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography import utils + +# This exists to break an import cycle. It is normally accessible from the +# ciphers module. + + +class CipherAlgorithm(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this mode (e.g. "AES", "Camellia"). + """ + + @property + @abc.abstractmethod + def key_sizes(self) -> frozenset[int]: + """ + Valid key sizes for this algorithm in bits + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The size of the key being used as an integer in bits (e.g. 128, 256). + """ + + +class BlockCipherAlgorithm(CipherAlgorithm): + key: utils.Buffer + + @property + @abc.abstractmethod + def block_size(self) -> int: + """ + The size of a block as an integer in bits (e.g. 64, 128). + """ + + +def _verify_key_size( + algorithm: CipherAlgorithm, key: utils.Buffer +) -> utils.Buffer: + # Verify that the key is instance of bytes + utils._check_byteslike("key", key) + + # Verify that the key size matches the expected key size + if len(key) * 8 not in algorithm.key_sizes: + raise ValueError( + f"Invalid key size ({len(key) * 8}) for {algorithm.name}." + ) + return key diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/_modes.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/_modes.py new file mode 100644 index 0000000..deae8bc --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/_modes.py @@ -0,0 +1,105 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) + + +class Mode(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this mode (e.g. "ECB", "CBC"). + """ + + @abc.abstractmethod + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + """ + Checks that all the necessary invariants of this (mode, algorithm) + combination are met. + """ + + +class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def initialization_vector(self) -> utils.Buffer: + """ + The value of the initialization vector for this mode as bytes. + """ + + +class ModeWithTweak(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def tweak(self) -> utils.Buffer: + """ + The value of the tweak for this mode as bytes. + """ + + +class ModeWithNonce(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def nonce(self) -> utils.Buffer: + """ + The value of the nonce for this mode as bytes. + """ + + +class ModeWithAuthenticationTag(Mode, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def tag(self) -> bytes | None: + """ + The value of the tag supplied to the constructor of this mode. + """ + + +def _check_aes_key_length(self: Mode, algorithm: CipherAlgorithm) -> None: + if algorithm.key_size > 256 and algorithm.name == "AES": + raise ValueError( + "Only 128, 192, and 256 bit keys are allowed for this AES mode" + ) + + +def _check_iv_length( + self: ModeWithInitializationVector, algorithm: BlockCipherAlgorithm +) -> None: + iv_len = len(self.initialization_vector) + if iv_len * 8 != algorithm.block_size: + raise ValueError(f"Invalid IV size ({iv_len}) for {self.name}.") + + +def _check_nonce_length( + nonce: utils.Buffer, name: str, algorithm: CipherAlgorithm +) -> None: + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + f"{name} requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + if len(nonce) * 8 != algorithm.block_size: + raise ValueError(f"Invalid nonce size ({len(nonce)}) for {name}.") + + +def _check_iv_and_key_length( + self: ModeWithInitializationVector, algorithm: CipherAlgorithm +) -> None: + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + f"{self} requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + _check_aes_key_length(self, algorithm) + _check_iv_length(self, algorithm) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/_serialization.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/_serialization.py new file mode 100644 index 0000000..9c3c474 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/_serialization.py @@ -0,0 +1,136 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography import utils +from cryptography.hazmat.bindings._rust import Encoding as Encoding +from cryptography.hazmat.bindings._rust import ( + ParameterFormat as ParameterFormat, +) +from cryptography.hazmat.bindings._rust import PrivateFormat as PrivateFormat +from cryptography.hazmat.bindings._rust import PublicFormat as PublicFormat +from cryptography.hazmat.primitives.hashes import HashAlgorithm + +# This exists to break an import cycle. These classes are normally accessible +# from the serialization module. + + +class PBES(utils.Enum): + PBESv1SHA1And3KeyTripleDESCBC = "PBESv1 using SHA1 and 3-Key TripleDES" + PBESv2SHA256AndAES256CBC = "PBESv2 using SHA256 PBKDF2 and AES256 CBC" + + +class KeySerializationEncryption(metaclass=abc.ABCMeta): + pass + + +class BestAvailableEncryption(KeySerializationEncryption): + def __init__(self, password: bytes): + if not isinstance(password, bytes) or len(password) == 0: + raise ValueError("Password must be 1 or more bytes.") + + self.password = password + + +class NoEncryption(KeySerializationEncryption): + pass + + +class KeySerializationEncryptionBuilder: + def __init__( + self, + format: PrivateFormat, + *, + _kdf_rounds: int | None = None, + _hmac_hash: HashAlgorithm | None = None, + _key_cert_algorithm: PBES | None = None, + ) -> None: + self._format = format + + self._kdf_rounds = _kdf_rounds + self._hmac_hash = _hmac_hash + self._key_cert_algorithm = _key_cert_algorithm + + def kdf_rounds(self, rounds: int) -> KeySerializationEncryptionBuilder: + if self._kdf_rounds is not None: + raise ValueError("kdf_rounds already set") + + if not isinstance(rounds, int): + raise TypeError("kdf_rounds must be an integer") + + if rounds < 1: + raise ValueError("kdf_rounds must be a positive integer") + + return KeySerializationEncryptionBuilder( + self._format, + _kdf_rounds=rounds, + _hmac_hash=self._hmac_hash, + _key_cert_algorithm=self._key_cert_algorithm, + ) + + def hmac_hash( + self, algorithm: HashAlgorithm + ) -> KeySerializationEncryptionBuilder: + if self._format is not PrivateFormat.PKCS12: + raise TypeError( + "hmac_hash only supported with PrivateFormat.PKCS12" + ) + + if self._hmac_hash is not None: + raise ValueError("hmac_hash already set") + return KeySerializationEncryptionBuilder( + self._format, + _kdf_rounds=self._kdf_rounds, + _hmac_hash=algorithm, + _key_cert_algorithm=self._key_cert_algorithm, + ) + + def key_cert_algorithm( + self, algorithm: PBES + ) -> KeySerializationEncryptionBuilder: + if self._format is not PrivateFormat.PKCS12: + raise TypeError( + "key_cert_algorithm only supported with PrivateFormat.PKCS12" + ) + if self._key_cert_algorithm is not None: + raise ValueError("key_cert_algorithm already set") + return KeySerializationEncryptionBuilder( + self._format, + _kdf_rounds=self._kdf_rounds, + _hmac_hash=self._hmac_hash, + _key_cert_algorithm=algorithm, + ) + + def build(self, password: bytes) -> KeySerializationEncryption: + if not isinstance(password, bytes) or len(password) == 0: + raise ValueError("Password must be 1 or more bytes.") + + return _KeySerializationEncryption( + self._format, + password, + kdf_rounds=self._kdf_rounds, + hmac_hash=self._hmac_hash, + key_cert_algorithm=self._key_cert_algorithm, + ) + + +class _KeySerializationEncryption(KeySerializationEncryption): + def __init__( + self, + format: PrivateFormat, + password: bytes, + *, + kdf_rounds: int | None, + hmac_hash: HashAlgorithm | None, + key_cert_algorithm: PBES | None, + ): + self._format = format + self.password = password + + self._kdf_rounds = kdf_rounds + self._hmac_hash = hmac_hash + self._key_cert_algorithm = key_cert_algorithm diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/__init__.py new file mode 100644 index 0000000..41d7318 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dh.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dh.py new file mode 100644 index 0000000..814fdd3 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dh.py @@ -0,0 +1,253 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography import utils +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization + +_FFDH_DEPRECATION_MSG = ( + "Diffie-Hellman over finite fields (FFDH) is deprecated and support " + "will be removed in a future release. Use a more modern key exchange " + "algorithm." +) + +generate_parameters = rust_openssl.dh.generate_parameters + + +DHPrivateNumbers = rust_openssl.dh.DHPrivateNumbers +DHPublicNumbers = rust_openssl.dh.DHPublicNumbers +DHParameterNumbers = rust_openssl.dh.DHParameterNumbers + + +class DHParameters(metaclass=abc.ABCMeta): + @abc.abstractmethod + def generate_private_key(self) -> DHPrivateKey: + """ + Generates and returns a DHPrivateKey. + """ + + @abc.abstractmethod + def parameter_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.ParameterFormat, + ) -> bytes: + """ + Returns the parameters serialized as bytes. + """ + + @abc.abstractmethod + def parameter_numbers(self) -> DHParameterNumbers: + """ + Returns a DHParameterNumbers. + """ + + +DHParametersWithSerialization = DHParameters +DHParameters.register(rust_openssl.dh.DHParameters) + + +class DHPublicKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def parameters(self) -> DHParameters: + """ + The DHParameters object associated with this public key. + """ + + @abc.abstractmethod + def public_numbers(self) -> DHPublicNumbers: + """ + Returns a DHPublicNumbers. + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> DHPublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> DHPublicKey: + """ + Returns a deep copy. + """ + + +DHPublicKeyWithSerialization = DHPublicKey +DHPublicKey.register(rust_openssl.dh.DHPublicKey) + + +class DHPrivateKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self) -> DHPublicKey: + """ + The DHPublicKey associated with this private key. + """ + + @abc.abstractmethod + def parameters(self) -> DHParameters: + """ + The DHParameters object associated with this private key. + """ + + @abc.abstractmethod + def exchange(self, peer_public_key: DHPublicKey) -> bytes: + """ + Given peer's DHPublicKey, carry out the key exchange and + return shared key as bytes. + """ + + @abc.abstractmethod + def private_numbers(self) -> DHPrivateNumbers: + """ + Returns a DHPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def __copy__(self) -> DHPrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> DHPrivateKey: + """ + Returns a deep copy. + """ + + +DHPrivateKeyWithSerialization = DHPrivateKey +DHPrivateKey.register(rust_openssl.dh.DHPrivateKey) + +# Aliases that do not emit the deprecation warning on attribute access, for +# internal use (e.g. the unions in +# cryptography.hazmat.primitives.asymmetric.types, which are evaluated at +# import time). +_DHPublicKey = DHPublicKey +_DHPrivateKey = DHPrivateKey + +utils.deprecated( + generate_parameters, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="generate_parameters", +) + +utils.deprecated( + DHPrivateNumbers, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHPrivateNumbers", +) + +utils.deprecated( + DHPublicNumbers, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHPublicNumbers", +) + +utils.deprecated( + DHParameterNumbers, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHParameterNumbers", +) + +utils.deprecated( + DHParameters, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHParameters", +) + +utils.deprecated( + DHParameters, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHParametersWithSerialization", +) + +utils.deprecated( + DHPublicKey, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHPublicKey", +) + +utils.deprecated( + DHPublicKey, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHPublicKeyWithSerialization", +) + +utils.deprecated( + DHPrivateKey, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHPrivateKey", +) + +utils.deprecated( + DHPrivateKey, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="DHPrivateKeyWithSerialization", +) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dsa.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dsa.py new file mode 100644 index 0000000..f245557 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -0,0 +1,179 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import typing + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils +from cryptography.utils import Buffer + + +class DSAParameters(metaclass=abc.ABCMeta): + @abc.abstractmethod + def generate_private_key(self) -> DSAPrivateKey: + """ + Generates and returns a DSAPrivateKey. + """ + + @abc.abstractmethod + def parameter_numbers(self) -> DSAParameterNumbers: + """ + Returns a DSAParameterNumbers. + """ + + +DSAParametersWithNumbers = DSAParameters +DSAParameters.register(rust_openssl.dsa.DSAParameters) + + +class DSAPrivateKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def public_key(self) -> DSAPublicKey: + """ + The DSAPublicKey associated with this private key. + """ + + @abc.abstractmethod + def parameters(self) -> DSAParameters: + """ + The DSAParameters object associated with this private key. + """ + + @abc.abstractmethod + def sign( + self, + data: Buffer, + algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, + ) -> bytes: + """ + Signs the data + """ + + @abc.abstractmethod + def private_numbers(self) -> DSAPrivateNumbers: + """ + Returns a DSAPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def __copy__(self) -> DSAPrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> DSAPrivateKey: + """ + Returns a deep copy. + """ + + +DSAPrivateKeyWithSerialization = DSAPrivateKey +DSAPrivateKey.register(rust_openssl.dsa.DSAPrivateKey) + + +class DSAPublicKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the prime modulus. + """ + + @abc.abstractmethod + def parameters(self) -> DSAParameters: + """ + The DSAParameters object associated with this public key. + """ + + @abc.abstractmethod + def public_numbers(self) -> DSAPublicNumbers: + """ + Returns a DSAPublicNumbers. + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify( + self, + signature: Buffer, + data: Buffer, + algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, + ) -> None: + """ + Verifies the signature of the data. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> DSAPublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> DSAPublicKey: + """ + Returns a deep copy. + """ + + +DSAPublicKeyWithSerialization = DSAPublicKey +DSAPublicKey.register(rust_openssl.dsa.DSAPublicKey) + +DSAPrivateNumbers = rust_openssl.dsa.DSAPrivateNumbers +DSAPublicNumbers = rust_openssl.dsa.DSAPublicNumbers +DSAParameterNumbers = rust_openssl.dsa.DSAParameterNumbers + + +def generate_parameters( + key_size: int, backend: typing.Any = None +) -> DSAParameters: + if key_size not in (1024, 2048, 3072, 4096): + raise ValueError("Key size must be 1024, 2048, 3072, or 4096 bits.") + + return rust_openssl.dsa.generate_parameters(key_size) + + +def generate_private_key( + key_size: int, backend: typing.Any = None +) -> DSAPrivateKey: + parameters = generate_parameters(key_size) + return parameters.generate_private_key() diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ec.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ec.py new file mode 100644 index 0000000..39e6751 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ec.py @@ -0,0 +1,369 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import typing + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat._oid import ObjectIdentifier +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils + + +class EllipticCurveOID: + SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1") + SECP224R1 = ObjectIdentifier("1.3.132.0.33") + SECP256K1 = ObjectIdentifier("1.3.132.0.10") + SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7") + SECP384R1 = ObjectIdentifier("1.3.132.0.34") + SECP521R1 = ObjectIdentifier("1.3.132.0.35") + BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7") + BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11") + BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13") + + +class EllipticCurve(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + The name of the curve. e.g. secp256r1. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + Bit size of a secret scalar for the curve. + """ + + @property + @abc.abstractmethod + def group_order(self) -> int: + """ + The order of the curve's group. + """ + + +class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def algorithm( + self, + ) -> asym_utils.Prehashed | hashes.HashAlgorithm: + """ + The digest algorithm used with this signature. + """ + + +class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): + @abc.abstractmethod + def exchange( + self, algorithm: ECDH, peer_public_key: EllipticCurvePublicKey + ) -> bytes: + """ + Performs a key exchange operation using the provided algorithm with the + provided peer's public key. + """ + + @abc.abstractmethod + def public_key(self) -> EllipticCurvePublicKey: + """ + The EllipticCurvePublicKey for this private key. + """ + + @property + @abc.abstractmethod + def curve(self) -> EllipticCurve: + """ + The EllipticCurve that this key is on. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + Bit size of a secret scalar for the curve. + """ + + @abc.abstractmethod + def sign( + self, + data: utils.Buffer, + signature_algorithm: EllipticCurveSignatureAlgorithm, + ) -> bytes: + """ + Signs the data + """ + + @abc.abstractmethod + def private_numbers(self) -> EllipticCurvePrivateNumbers: + """ + Returns an EllipticCurvePrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def __copy__(self) -> EllipticCurvePrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> EllipticCurvePrivateKey: + """ + Returns a deep copy. + """ + + +EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey +EllipticCurvePrivateKey.register(rust_openssl.ec.ECPrivateKey) + + +class EllipticCurvePublicKey(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def curve(self) -> EllipticCurve: + """ + The EllipticCurve that this key is on. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + Bit size of a secret scalar for the curve. + """ + + @abc.abstractmethod + def public_numbers(self) -> EllipticCurvePublicNumbers: + """ + Returns an EllipticCurvePublicNumbers. + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify( + self, + signature: utils.Buffer, + data: utils.Buffer, + signature_algorithm: EllipticCurveSignatureAlgorithm, + ) -> None: + """ + Verifies the signature of the data. + """ + + @classmethod + def from_encoded_point( + cls, curve: EllipticCurve, data: bytes + ) -> EllipticCurvePublicKey: + utils._check_bytes("data", data) + + if len(data) == 0: + raise ValueError("data must not be an empty byte string") + + if data[0] not in [0x02, 0x03, 0x04]: + raise ValueError("Unsupported elliptic curve point type") + + return rust_openssl.ec.from_public_bytes(curve, data) + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> EllipticCurvePublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> EllipticCurvePublicKey: + """ + Returns a deep copy. + """ + + +EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey +EllipticCurvePublicKey.register(rust_openssl.ec.ECPublicKey) + +EllipticCurvePrivateNumbers = rust_openssl.ec.EllipticCurvePrivateNumbers +EllipticCurvePublicNumbers = rust_openssl.ec.EllipticCurvePublicNumbers + + +class SECP521R1(EllipticCurve): + name = "secp521r1" + key_size = 521 + group_order = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409 # noqa: E501 + + +class SECP384R1(EllipticCurve): + name = "secp384r1" + key_size = 384 + group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973 # noqa: E501 + + +class SECP256R1(EllipticCurve): + name = "secp256r1" + key_size = 256 + group_order = ( + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + ) + + +class SECP256K1(EllipticCurve): + name = "secp256k1" + key_size = 256 + group_order = ( + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 + ) + + +class SECP224R1(EllipticCurve): + name = "secp224r1" + key_size = 224 + group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D + + +class SECP192R1(EllipticCurve): + name = "secp192r1" + key_size = 192 + group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 + + +class BrainpoolP256R1(EllipticCurve): + name = "brainpoolP256r1" + key_size = 256 + group_order = ( + 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 + ) + + +class BrainpoolP384R1(EllipticCurve): + name = "brainpoolP384r1" + key_size = 384 + group_order = 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565 # noqa: E501 + + +class BrainpoolP512R1(EllipticCurve): + name = "brainpoolP512r1" + key_size = 512 + group_order = 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069 # noqa: E501 + + +_CURVE_TYPES: dict[str, EllipticCurve] = { + "prime192v1": SECP192R1(), + "prime256v1": SECP256R1(), + "secp192r1": SECP192R1(), + "secp224r1": SECP224R1(), + "secp256r1": SECP256R1(), + "secp384r1": SECP384R1(), + "secp521r1": SECP521R1(), + "secp256k1": SECP256K1(), + "brainpoolP256r1": BrainpoolP256R1(), + "brainpoolP384r1": BrainpoolP384R1(), + "brainpoolP512r1": BrainpoolP512R1(), +} + + +class ECDSA(EllipticCurveSignatureAlgorithm): + def __init__( + self, + algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, + deterministic_signing: bool = False, + ): + from cryptography.hazmat.backends.openssl.backend import backend + + if ( + deterministic_signing + and not backend.ecdsa_deterministic_supported() + ): + raise UnsupportedAlgorithm( + "ECDSA with deterministic signature (RFC 6979) is not " + "supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + self._algorithm = algorithm + self._deterministic_signing = deterministic_signing + + @property + def algorithm( + self, + ) -> asym_utils.Prehashed | hashes.HashAlgorithm: + return self._algorithm + + @property + def deterministic_signing( + self, + ) -> bool: + return self._deterministic_signing + + +generate_private_key = rust_openssl.ec.generate_private_key + + +def derive_private_key( + private_value: int, + curve: EllipticCurve, + backend: typing.Any = None, +) -> EllipticCurvePrivateKey: + if not isinstance(private_value, int): + raise TypeError("private_value must be an integer type.") + + if private_value <= 0: + raise ValueError("private_value must be a positive integer.") + + return rust_openssl.ec.derive_private_key(private_value, curve) + + +class ECDH: + pass + + +_OID_TO_CURVE = { + EllipticCurveOID.SECP192R1: SECP192R1, + EllipticCurveOID.SECP224R1: SECP224R1, + EllipticCurveOID.SECP256K1: SECP256K1, + EllipticCurveOID.SECP256R1: SECP256R1, + EllipticCurveOID.SECP384R1: SECP384R1, + EllipticCurveOID.SECP521R1: SECP521R1, + EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1, + EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1, + EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1, +} + + +def get_curve_for_oid(oid: ObjectIdentifier) -> type[EllipticCurve]: + try: + return _OID_TO_CURVE[oid] + except KeyError: + raise LookupError( + "The provided object identifier has no matching elliptic " + "curve class" + ) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed25519.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed25519.py new file mode 100644 index 0000000..70aec5b --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -0,0 +1,116 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer + + +class Ed25519PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> Ed25519PublicKey: + return rust_openssl.ed25519.from_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + + @abc.abstractmethod + def verify(self, signature: Buffer, data: Buffer) -> None: + """ + Verify the signature. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> Ed25519PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> Ed25519PublicKey: + """ + Returns a deep copy. + """ + + +Ed25519PublicKey.register(rust_openssl.ed25519.Ed25519PublicKey) + + +class Ed25519PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> Ed25519PrivateKey: + return rust_openssl.ed25519.generate_key() + + @classmethod + def from_private_bytes(cls, data: Buffer) -> Ed25519PrivateKey: + return rust_openssl.ed25519.from_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> Ed25519PublicKey: + """ + The Ed25519PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def sign(self, data: Buffer) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def __copy__(self) -> Ed25519PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> Ed25519PrivateKey: + """ + Returns a deep copy. + """ + + +Ed25519PrivateKey.register(rust_openssl.ed25519.Ed25519PrivateKey) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed448.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed448.py new file mode 100644 index 0000000..9ecb478 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -0,0 +1,143 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer + + +class Ed448PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> Ed448PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.ed448.from_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + + @abc.abstractmethod + def verify(self, signature: Buffer, data: Buffer) -> None: + """ + Verify the signature. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> Ed448PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> Ed448PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "ed448"): + Ed448PublicKey.register(rust_openssl.ed448.Ed448PublicKey) + + +class Ed448PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> Ed448PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.ed448.generate_key() + + @classmethod + def from_private_bytes(cls, data: Buffer) -> Ed448PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.ed448_supported(): + raise UnsupportedAlgorithm( + "ed448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.ed448.from_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> Ed448PublicKey: + """ + The Ed448PublicKey derived from the private key. + """ + + @abc.abstractmethod + def sign(self, data: Buffer) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def __copy__(self) -> Ed448PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> Ed448PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "x448"): + Ed448PrivateKey.register(rust_openssl.ed448.Ed448PrivateKey) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mldsa.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mldsa.py new file mode 100644 index 0000000..beba90f --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mldsa.py @@ -0,0 +1,505 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer + + +class MLDSA44PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> MLDSA44PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-44 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.from_mldsa44_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + + The public key is 1,312 bytes for MLDSA-44. + """ + + @abc.abstractmethod + def verify( + self, + signature: Buffer, + data: Buffer, + context: Buffer | None = None, + ) -> None: + """ + Verify the signature. + """ + + @abc.abstractmethod + def verify_mu( + self, + signature: Buffer, + mu: Buffer, + ) -> None: + """ + Verify the signature over a precomputed mu (message representative). + + mu must be 64 bytes. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> MLDSA44PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLDSA44PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mldsa"): + MLDSA44PublicKey.register(rust_openssl.mldsa.MLDSA44PublicKey) + + +class MLDSA44PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> MLDSA44PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-44 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.generate_mldsa44_key() + + @classmethod + def from_seed_bytes(cls, data: Buffer) -> MLDSA44PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-44 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.from_mldsa44_seed_bytes(data) + + @abc.abstractmethod + def public_key(self) -> MLDSA44PublicKey: + """ + The MLDSA44PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + + This method only returns the serialization of the seed form of the + private key, never the expanded one. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + + This method only returns the seed form of the private key (32 bytes). + """ + + @abc.abstractmethod + def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def sign_mu(self, mu: Buffer) -> bytes: + """ + Signs a precomputed mu (message representative). + + mu must be 64 bytes and already incorporates the context, so no + context is accepted here. + """ + + @abc.abstractmethod + def __copy__(self) -> MLDSA44PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLDSA44PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mldsa"): + MLDSA44PrivateKey.register(rust_openssl.mldsa.MLDSA44PrivateKey) + + +class MLDSA65PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> MLDSA65PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-65 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.from_mldsa65_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + + The public key is 1,952 bytes for MLDSA-65. + """ + + @abc.abstractmethod + def verify( + self, + signature: Buffer, + data: Buffer, + context: Buffer | None = None, + ) -> None: + """ + Verify the signature. + """ + + @abc.abstractmethod + def verify_mu( + self, + signature: Buffer, + mu: Buffer, + ) -> None: + """ + Verify the signature over a precomputed mu (message representative). + + mu must be 64 bytes. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> MLDSA65PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLDSA65PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mldsa"): + MLDSA65PublicKey.register(rust_openssl.mldsa.MLDSA65PublicKey) + + +class MLDSA65PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> MLDSA65PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-65 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.generate_mldsa65_key() + + @classmethod + def from_seed_bytes(cls, data: Buffer) -> MLDSA65PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-65 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.from_mldsa65_seed_bytes(data) + + @abc.abstractmethod + def public_key(self) -> MLDSA65PublicKey: + """ + The MLDSA65PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + + This method only returns the serialization of the seed form of the + private key, never the expanded one. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + + This method only returns the seed form of the private key (32 bytes). + """ + + @abc.abstractmethod + def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def sign_mu(self, mu: Buffer) -> bytes: + """ + Signs a precomputed mu (message representative). + + mu must be 64 bytes and already incorporates the context, so no + context is accepted here. + """ + + @abc.abstractmethod + def __copy__(self) -> MLDSA65PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLDSA65PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mldsa"): + MLDSA65PrivateKey.register(rust_openssl.mldsa.MLDSA65PrivateKey) + + +class MLDSA87PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> MLDSA87PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-87 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.from_mldsa87_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + + The public key is 2,592 bytes for MLDSA-87. + """ + + @abc.abstractmethod + def verify( + self, + signature: Buffer, + data: Buffer, + context: Buffer | None = None, + ) -> None: + """ + Verify the signature. + """ + + @abc.abstractmethod + def verify_mu( + self, + signature: Buffer, + mu: Buffer, + ) -> None: + """ + Verify the signature over a precomputed mu (message representative). + + mu must be 64 bytes. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> MLDSA87PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLDSA87PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mldsa"): + MLDSA87PublicKey.register(rust_openssl.mldsa.MLDSA87PublicKey) + + +class MLDSA87PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> MLDSA87PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-87 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.generate_mldsa87_key() + + @classmethod + def from_seed_bytes(cls, data: Buffer) -> MLDSA87PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mldsa_supported(): + raise UnsupportedAlgorithm( + "ML-DSA-87 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mldsa.from_mldsa87_seed_bytes(data) + + @abc.abstractmethod + def public_key(self) -> MLDSA87PublicKey: + """ + The MLDSA87PublicKey derived from the private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + + This method only returns the serialization of the seed form of the + private key, never the expanded one. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + + This method only returns the seed form of the private key (32 bytes). + """ + + @abc.abstractmethod + def sign(self, data: Buffer, context: Buffer | None = None) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def sign_mu(self, mu: Buffer) -> bytes: + """ + Signs a precomputed mu (message representative). + + mu must be 64 bytes and already incorporates the context, so no + context is accepted here. + """ + + @abc.abstractmethod + def __copy__(self) -> MLDSA87PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLDSA87PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mldsa"): + MLDSA87PrivateKey.register(rust_openssl.mldsa.MLDSA87PrivateKey) + MLDSAMuHasher = rust_openssl.mldsa.MLDSAMuHasher diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mlkem.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mlkem.py new file mode 100644 index 0000000..64bca11 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/mlkem.py @@ -0,0 +1,278 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer + + +class MLKEM768PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: Buffer) -> MLKEM768PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mlkem_supported(): + raise UnsupportedAlgorithm( + "ML-KEM-768 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mlkem.from_mlkem768_public_bytes(data) + + @abc.abstractmethod + def encapsulate(self) -> tuple[bytes, bytes]: + """ + Encapsulate: returns (shared_secret, ciphertext). + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + + The public key is 1,184 bytes for ML-KEM-768. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> MLKEM768PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLKEM768PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mlkem"): + MLKEM768PublicKey.register(rust_openssl.mlkem.MLKEM768PublicKey) + + +class MLKEM768PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> MLKEM768PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mlkem_supported(): + raise UnsupportedAlgorithm( + "ML-KEM-768 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mlkem.generate_mlkem768_key() + + @classmethod + def from_seed_bytes(cls, data: Buffer) -> MLKEM768PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mlkem_supported(): + raise UnsupportedAlgorithm( + "ML-KEM-768 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mlkem.from_mlkem768_seed_bytes(data) + + @abc.abstractmethod + def decapsulate(self, ciphertext: Buffer) -> bytes: + """ + Decapsulate: returns shared_secret. + """ + + @abc.abstractmethod + def public_key(self) -> MLKEM768PublicKey: + """ + The MLKEM768PublicKey derived from this private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key (64-byte seed). + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def __copy__(self) -> MLKEM768PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLKEM768PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mlkem"): + MLKEM768PrivateKey.register(rust_openssl.mlkem.MLKEM768PrivateKey) + + +class MLKEM1024PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: Buffer) -> MLKEM1024PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mlkem_supported(): + raise UnsupportedAlgorithm( + "ML-KEM-1024 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mlkem.from_mlkem1024_public_bytes(data) + + @abc.abstractmethod + def encapsulate(self) -> tuple[bytes, bytes]: + """ + Encapsulate: returns (shared_secret, ciphertext). + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + + The public key is 1,568 bytes for ML-KEM-1024. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> MLKEM1024PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLKEM1024PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mlkem"): + MLKEM1024PublicKey.register(rust_openssl.mlkem.MLKEM1024PublicKey) + + +class MLKEM1024PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> MLKEM1024PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mlkem_supported(): + raise UnsupportedAlgorithm( + "ML-KEM-1024 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mlkem.generate_mlkem1024_key() + + @classmethod + def from_seed_bytes(cls, data: Buffer) -> MLKEM1024PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.mlkem_supported(): + raise UnsupportedAlgorithm( + "ML-KEM-1024 is not supported by this backend.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + return rust_openssl.mlkem.from_mlkem1024_seed_bytes(data) + + @abc.abstractmethod + def decapsulate(self, ciphertext: Buffer) -> bytes: + """ + Decapsulate: returns shared_secret. + """ + + @abc.abstractmethod + def public_key(self) -> MLKEM1024PublicKey: + """ + The MLKEM1024PublicKey derived from this private key. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key (64-byte seed). + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def __copy__(self) -> MLKEM1024PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> MLKEM1024PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "mlkem"): + MLKEM1024PrivateKey.register(rust_openssl.mlkem.MLKEM1024PrivateKey) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/padding.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/padding.py new file mode 100644 index 0000000..1fd2873 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/padding.py @@ -0,0 +1,141 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives._asymmetric import ( + AsymmetricPadding as AsymmetricPadding, +) +from cryptography.hazmat.primitives.asymmetric import rsa + + +class PKCS1v15(AsymmetricPadding): + name = "EMSA-PKCS1-v1_5" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PKCS1v15): + return NotImplemented + + return True + + +class _MaxLength: + "Sentinel value for `MAX_LENGTH`." + + +class _Auto: + "Sentinel value for `AUTO`." + + +class _DigestLength: + "Sentinel value for `DIGEST_LENGTH`." + + +class PSS(AsymmetricPadding): + MAX_LENGTH = _MaxLength() + AUTO = _Auto() + DIGEST_LENGTH = _DigestLength() + name = "EMSA-PSS" + _salt_length: int | _MaxLength | _Auto | _DigestLength + + def __init__( + self, + mgf: MGF, + salt_length: int | _MaxLength | _Auto | _DigestLength, + ) -> None: + self._mgf = mgf + + if not isinstance( + salt_length, (int, _MaxLength, _Auto, _DigestLength) + ): + raise TypeError( + "salt_length must be an integer, MAX_LENGTH, " + "DIGEST_LENGTH, or AUTO" + ) + + if isinstance(salt_length, int) and salt_length < 0: + raise ValueError("salt_length must be zero or greater.") + + self._salt_length = salt_length + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PSS): + return NotImplemented + + return ( + self._mgf == other._mgf and self._salt_length == other._salt_length + ) + + @property + def mgf(self) -> MGF: + return self._mgf + + +class OAEP(AsymmetricPadding): + name = "EME-OAEP" + + def __init__( + self, + mgf: MGF, + algorithm: hashes.HashAlgorithm, + label: bytes | None, + ): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + self._mgf = mgf + self._algorithm = algorithm + self._label = label + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OAEP): + return NotImplemented + + return ( + self._mgf == other._mgf + and self._algorithm == other._algorithm + and self._label == other._label + ) + + @property + def algorithm(self) -> hashes.HashAlgorithm: + return self._algorithm + + @property + def mgf(self) -> MGF: + return self._mgf + + +class MGF(metaclass=abc.ABCMeta): + _algorithm: hashes.HashAlgorithm + + +class MGF1(MGF): + def __init__(self, algorithm: hashes.HashAlgorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of hashes.HashAlgorithm.") + + self._algorithm = algorithm + + def __eq__(self, other: object) -> bool: + if not isinstance(other, MGF1): + return NotImplemented + + return self._algorithm == other._algorithm + + +def calculate_max_pss_salt_length( + key: rsa.RSAPrivateKey | rsa.RSAPublicKey, + hash_algorithm: hashes.HashAlgorithm, +) -> int: + if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): + raise TypeError("key must be an RSA public or private key") + # bit length - 1 per RFC 3447 + emlen = (key.key_size + 6) // 8 + salt_length = emlen - hash_algorithm.digest_size - 2 + assert salt_length >= 0 + return salt_length diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/rsa.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/rsa.py new file mode 100644 index 0000000..d730ceb --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -0,0 +1,295 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import random +import typing +from math import gcd, lcm + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization, hashes +from cryptography.hazmat.primitives._asymmetric import AsymmetricPadding +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils + + +class RSAPrivateKey(metaclass=abc.ABCMeta): + @abc.abstractmethod + def decrypt(self, ciphertext: bytes, padding: AsymmetricPadding) -> bytes: + """ + Decrypts the provided ciphertext. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the public modulus. + """ + + @abc.abstractmethod + def public_key(self) -> RSAPublicKey: + """ + The RSAPublicKey associated with this private key. + """ + + @abc.abstractmethod + def sign( + self, + data: bytes, + padding: AsymmetricPadding, + algorithm: asym_utils.Prehashed + | hashes.HashAlgorithm + | asym_utils.NoDigestInfo, + ) -> bytes: + """ + Signs the data. + """ + + @abc.abstractmethod + def private_numbers(self) -> RSAPrivateNumbers: + """ + Returns an RSAPrivateNumbers. + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def __copy__(self) -> RSAPrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> RSAPrivateKey: + """ + Returns a deep copy. + """ + + +RSAPrivateKeyWithSerialization = RSAPrivateKey +RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey) + + +class RSAPublicKey(metaclass=abc.ABCMeta): + @abc.abstractmethod + def encrypt(self, plaintext: bytes, padding: AsymmetricPadding) -> bytes: + """ + Encrypts the given plaintext. + """ + + @property + @abc.abstractmethod + def key_size(self) -> int: + """ + The bit length of the public modulus. + """ + + @abc.abstractmethod + def public_numbers(self) -> RSAPublicNumbers: + """ + Returns an RSAPublicNumbers + """ + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + Returns the key serialized as bytes. + """ + + @abc.abstractmethod + def verify( + self, + signature: bytes, + data: bytes, + padding: AsymmetricPadding, + algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, + ) -> None: + """ + Verifies the signature of the data. + """ + + @abc.abstractmethod + def recover_data_from_signature( + self, + signature: bytes, + padding: AsymmetricPadding, + algorithm: hashes.HashAlgorithm | asym_utils.NoDigestInfo | None, + ) -> bytes: + """ + Recovers the original data from the signature. + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> RSAPublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> RSAPublicKey: + """ + Returns a deep copy. + """ + + +RSAPublicKeyWithSerialization = RSAPublicKey +RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey) + +RSAPrivateNumbers = rust_openssl.rsa.RSAPrivateNumbers +RSAPublicNumbers = rust_openssl.rsa.RSAPublicNumbers + + +def generate_private_key( + public_exponent: int, + key_size: int, + backend: typing.Any = None, +) -> RSAPrivateKey: + _verify_rsa_parameters(public_exponent, key_size) + return rust_openssl.rsa.generate_private_key(public_exponent, key_size) + + +def _verify_rsa_parameters(public_exponent: int, key_size: int) -> None: + if public_exponent not in (3, 65537): + raise ValueError( + "public_exponent must be either 3 (for legacy compatibility) or " + "65537. Almost everyone should choose 65537 here!" + ) + + if key_size < 1024: + raise ValueError("key_size must be at least 1024-bits.") + + +def _modinv(e: int, m: int) -> int: + """ + Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1 + """ + x1, x2 = 1, 0 + a, b = e, m + while b > 0: + q, r = divmod(a, b) + xn = x1 - q * x2 + a, b, x1, x2 = b, r, x2, xn + return x1 % m + + +def rsa_crt_iqmp(p: int, q: int) -> int: + """ + Compute the CRT (q ** -1) % p value from RSA primes p and q. + """ + if p <= 1 or q <= 1: + raise ValueError("Values can't be <= 1") + return _modinv(q, p) + + +def rsa_crt_dmp1(private_exponent: int, p: int) -> int: + """ + Compute the CRT private_exponent % (p - 1) value from the RSA + private_exponent (d) and p. + """ + if private_exponent <= 1 or p <= 1: + raise ValueError("Values can't be <= 1") + return private_exponent % (p - 1) + + +def rsa_crt_dmq1(private_exponent: int, q: int) -> int: + """ + Compute the CRT private_exponent % (q - 1) value from the RSA + private_exponent (d) and q. + """ + if private_exponent <= 1 or q <= 1: + raise ValueError("Values can't be <= 1") + return private_exponent % (q - 1) + + +def rsa_recover_private_exponent(e: int, p: int, q: int) -> int: + """ + Compute the RSA private_exponent (d) given the public exponent (e) + and the RSA primes p and q. + + This uses the Carmichael totient function to generate the + smallest possible working value of the private exponent. + """ + # This lambda_n is the Carmichael totient function. + # The original RSA paper uses the Euler totient function + # here: phi_n = (p - 1) * (q - 1) + # Either version of the private exponent will work, but the + # one generated by the older formulation may be larger + # than necessary. (lambda_n always divides phi_n) + if e <= 1 or p <= 1 or q <= 1: + raise ValueError("Values can't be <= 1") + return _modinv(e, lcm(p - 1, q - 1)) + + +# Controls the number of iterations rsa_recover_prime_factors will perform +# to obtain the prime factors. +_MAX_RECOVERY_ATTEMPTS = 500 + + +def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]: + """ + Compute factors p and q from the private exponent d. We assume that n has + no more than two factors. This function is adapted from code in PyCrypto. + """ + # reject invalid values early + if d <= 1 or e <= 1: + raise ValueError("d, e can't be <= 1") + if 17 != pow(17, e * d, n): + raise ValueError("n, d, e don't match") + # See 8.2.2(i) in Handbook of Applied Cryptography. + ktot = d * e - 1 + # The quantity d*e-1 is a multiple of phi(n), even, + # and can be represented as t*2^s. + t = ktot + while t % 2 == 0: + t = t // 2 + # Cycle through all multiplicative inverses in Zn. + # The algorithm is non-deterministic, but there is a 50% chance + # any candidate a leads to successful factoring. + # See "Digitalized Signatures and Public Key Functions as Intractable + # as Factorization", M. Rabin, 1979 + spotted = False + tries = 0 + while not spotted and tries < _MAX_RECOVERY_ATTEMPTS: + a = random.randint(2, n - 1) + tries += 1 + k = t + # Cycle through all values a^{t*2^i}=a^k + while k < ktot: + cand = pow(a, k, n) + # Check if a^k is a non-trivial root of unity (mod n) + if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: + # We have found a number such that (cand-1)(cand+1)=0 (mod n). + # Either of the terms divides n. + p = gcd(cand + 1, n) + spotted = True + break + k *= 2 + if not spotted: + raise ValueError("Unable to compute factors p and q from exponent d.") + # Found ! + q, r = divmod(n, p) + assert r == 0 + p, q = sorted((p, q), reverse=True) + return (p, q) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/types.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/types.py new file mode 100644 index 0000000..dbf4b74 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/types.py @@ -0,0 +1,94 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import typing + +from cryptography.hazmat.primitives.asymmetric import ( + dh, + dsa, + ec, + ed448, + ed25519, + mldsa, + mlkem, + rsa, + x448, + x25519, +) + +# Every asymmetric key type. These use the private DH aliases so that +# importing this module doesn't trigger the FFDH deprecation warning. +PublicKeyTypes = typing.Union[ + dh._DHPublicKey, + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + mldsa.MLDSA44PublicKey, + mldsa.MLDSA65PublicKey, + mldsa.MLDSA87PublicKey, + mlkem.MLKEM768PublicKey, + mlkem.MLKEM1024PublicKey, + x25519.X25519PublicKey, + x448.X448PublicKey, +] +# Every asymmetric key type +PrivateKeyTypes = typing.Union[ + dh._DHPrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + mldsa.MLDSA44PrivateKey, + mldsa.MLDSA65PrivateKey, + mldsa.MLDSA87PrivateKey, + mlkem.MLKEM768PrivateKey, + mlkem.MLKEM1024PrivateKey, + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + x25519.X25519PrivateKey, + x448.X448PrivateKey, +] +# Just the key types we allow to be used for x509 signing. This mirrors +# the certificate public key types +CertificateIssuerPrivateKeyTypes = typing.Union[ + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + mldsa.MLDSA44PrivateKey, + mldsa.MLDSA65PrivateKey, + mldsa.MLDSA87PrivateKey, +] +# Just the key types we allow to be used for x509 signing. This mirrors +# the certificate private key types +CertificateIssuerPublicKeyTypes = typing.Union[ + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + mldsa.MLDSA44PublicKey, + mldsa.MLDSA65PublicKey, + mldsa.MLDSA87PublicKey, +] +# This type removes DHPublicKey. x448/x25519/mlkem can be a public key +# but cannot be used in signing so they are allowed here. +CertificatePublicKeyTypes = typing.Union[ + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + mldsa.MLDSA44PublicKey, + mldsa.MLDSA65PublicKey, + mldsa.MLDSA87PublicKey, + mlkem.MLKEM768PublicKey, + mlkem.MLKEM1024PublicKey, + x25519.X25519PublicKey, + x448.X448PublicKey, +] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/utils.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/utils.py new file mode 100644 index 0000000..c01c342 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/utils.py @@ -0,0 +1,28 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import asn1 +from cryptography.hazmat.primitives import hashes + +decode_dss_signature = asn1.decode_dss_signature +encode_dss_signature = asn1.encode_dss_signature + + +class NoDigestInfo: + pass + + +class Prehashed: + def __init__(self, algorithm: hashes.HashAlgorithm): + if not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Expected instance of HashAlgorithm.") + + self._algorithm = algorithm + self._digest_size = algorithm.digest_size + + @property + def digest_size(self) -> int: + return self._digest_size diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x25519.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x25519.py new file mode 100644 index 0000000..7498998 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -0,0 +1,134 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer + + +class X25519PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> X25519PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return rust_openssl.x25519.from_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> X25519PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> X25519PublicKey: + """ + Returns a deep copy. + """ + + +X25519PublicKey.register(rust_openssl.x25519.X25519PublicKey) + + +class X25519PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> X25519PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + return rust_openssl.x25519.generate_key() + + @classmethod + def from_private_bytes(cls, data: Buffer) -> X25519PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x25519_supported(): + raise UnsupportedAlgorithm( + "X25519 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return rust_openssl.x25519.from_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> X25519PublicKey: + """ + Returns the public key associated with this private key + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def exchange(self, peer_public_key: X25519PublicKey) -> bytes: + """ + Performs a key exchange operation using the provided peer's public key. + """ + + @abc.abstractmethod + def __copy__(self) -> X25519PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> X25519PrivateKey: + """ + Returns a deep copy. + """ + + +X25519PrivateKey.register(rust_openssl.x25519.X25519PrivateKey) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x448.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x448.py new file mode 100644 index 0000000..b9dc826 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/asymmetric/x448.py @@ -0,0 +1,137 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer + + +class X448PublicKey(metaclass=abc.ABCMeta): + @classmethod + def from_public_bytes(cls, data: bytes) -> X448PublicKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return rust_openssl.x448.from_public_bytes(data) + + @abc.abstractmethod + def public_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PublicFormat, + ) -> bytes: + """ + The serialized bytes of the public key. + """ + + @abc.abstractmethod + def public_bytes_raw(self) -> bytes: + """ + The raw bytes of the public key. + Equivalent to public_bytes(Raw, Raw). + """ + + @abc.abstractmethod + def __eq__(self, other: object) -> bool: + """ + Checks equality. + """ + + @abc.abstractmethod + def __copy__(self) -> X448PublicKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> X448PublicKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "x448"): + X448PublicKey.register(rust_openssl.x448.X448PublicKey) + + +class X448PrivateKey(metaclass=abc.ABCMeta): + @classmethod + def generate(cls) -> X448PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return rust_openssl.x448.generate_key() + + @classmethod + def from_private_bytes(cls, data: Buffer) -> X448PrivateKey: + from cryptography.hazmat.backends.openssl.backend import backend + + if not backend.x448_supported(): + raise UnsupportedAlgorithm( + "X448 is not supported by this version of OpenSSL.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + return rust_openssl.x448.from_private_bytes(data) + + @abc.abstractmethod + def public_key(self) -> X448PublicKey: + """ + Returns the public key associated with this private key + """ + + @abc.abstractmethod + def private_bytes( + self, + encoding: _serialization.Encoding, + format: _serialization.PrivateFormat, + encryption_algorithm: _serialization.KeySerializationEncryption, + ) -> bytes: + """ + The serialized bytes of the private key. + """ + + @abc.abstractmethod + def private_bytes_raw(self) -> bytes: + """ + The raw bytes of the private key. + Equivalent to private_bytes(Raw, Raw, NoEncryption()). + """ + + @abc.abstractmethod + def exchange(self, peer_public_key: X448PublicKey) -> bytes: + """ + Performs a key exchange operation using the provided peer's public key. + """ + + @abc.abstractmethod + def __copy__(self) -> X448PrivateKey: + """ + Returns a copy. + """ + + @abc.abstractmethod + def __deepcopy__(self, memo: dict) -> X448PrivateKey: + """ + Returns a deep copy. + """ + + +if hasattr(rust_openssl, "x448"): + X448PrivateKey.register(rust_openssl.x448.X448PrivateKey) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/__init__.py new file mode 100644 index 0000000..10c15d0 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/__init__.py @@ -0,0 +1,27 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) +from cryptography.hazmat.primitives.ciphers.base import ( + AEADCipherContext, + AEADDecryptionContext, + AEADEncryptionContext, + Cipher, + CipherContext, +) + +__all__ = [ + "AEADCipherContext", + "AEADDecryptionContext", + "AEADEncryptionContext", + "BlockCipherAlgorithm", + "Cipher", + "CipherAlgorithm", + "CipherContext", +] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/aead.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/aead.py new file mode 100644 index 0000000..c8a582d --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/aead.py @@ -0,0 +1,23 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +__all__ = [ + "AESCCM", + "AESGCM", + "AESGCMSIV", + "AESOCB3", + "AESSIV", + "ChaCha20Poly1305", +] + +AESGCM = rust_openssl.aead.AESGCM +ChaCha20Poly1305 = rust_openssl.aead.ChaCha20Poly1305 +AESCCM = rust_openssl.aead.AESCCM +AESSIV = rust_openssl.aead.AESSIV +AESOCB3 = rust_openssl.aead.AESOCB3 +AESGCMSIV = rust_openssl.aead.AESGCMSIV diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/algorithms.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/algorithms.py new file mode 100644 index 0000000..6b20dd5 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -0,0 +1,138 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography import utils +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + ARC4 as ARC4, +) +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + CAST5 as CAST5, +) +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + IDEA as IDEA, +) +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + SEED as SEED, +) +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + Blowfish as Blowfish, +) +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + Camellia as Camellia, +) +from cryptography.hazmat.decrepit.ciphers.algorithms import ( + TripleDES as TripleDES, +) +from cryptography.hazmat.primitives._cipheralgorithm import _verify_key_size +from cryptography.hazmat.primitives.ciphers import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) + + +class AES(BlockCipherAlgorithm): + name = "AES" + block_size = 128 + # 512 added to support AES-256-XTS, which uses 512-bit keys + key_sizes = frozenset([128, 192, 256, 512]) + + def __init__(self, key: utils.Buffer): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class AES128(BlockCipherAlgorithm): + name = "AES" + block_size = 128 + key_sizes = frozenset([128]) + key_size = 128 + + def __init__(self, key: utils.Buffer): + self.key = _verify_key_size(self, key) + + +class AES256(BlockCipherAlgorithm): + name = "AES" + block_size = 128 + key_sizes = frozenset([256]) + key_size = 256 + + def __init__(self, key: utils.Buffer): + self.key = _verify_key_size(self, key) + + +utils.deprecated( + Camellia, + __name__, + "Camellia has been moved to " + "cryptography.hazmat.decrepit.ciphers.algorithms.Camellia and " + "will be removed from " + "cryptography.hazmat.primitives.ciphers.algorithms in 49.0.0.", + utils.DeprecatedIn43, + name="Camellia", +) + + +utils.deprecated( + ARC4, + __name__, + "ARC4 has been moved to " + "cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and " + "will be removed from " + "cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.", + utils.DeprecatedIn43, + name="ARC4", +) + + +utils.deprecated( + TripleDES, + __name__, + "TripleDES has been moved to " + "cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and " + "will be removed from " + "cryptography.hazmat.primitives.ciphers.algorithms in 48.0.0.", + utils.DeprecatedIn43, + name="TripleDES", +) + + +class ChaCha20(CipherAlgorithm): + name = "ChaCha20" + key_sizes = frozenset([256]) + + def __init__(self, key: utils.Buffer, nonce: utils.Buffer): + self.key = _verify_key_size(self, key) + utils._check_byteslike("nonce", nonce) + + if len(nonce) != 16: + raise ValueError("nonce must be 128-bits (16 bytes)") + + self._nonce = nonce + + @property + def nonce(self) -> utils.Buffer: + return self._nonce + + @property + def key_size(self) -> int: + return len(self.key) * 8 + + +class SM4(BlockCipherAlgorithm): + name = "SM4" + block_size = 128 + key_sizes = frozenset([128]) + + def __init__(self, key: bytes): + self.key = _verify_key_size(self, key) + + @property + def key_size(self) -> int: + return len(self.key) * 8 diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/base.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/base.py new file mode 100644 index 0000000..24fceea --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/base.py @@ -0,0 +1,146 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import typing + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm +from cryptography.hazmat.primitives.ciphers import modes +from cryptography.utils import Buffer + + +class CipherContext(metaclass=abc.ABCMeta): + @abc.abstractmethod + def update(self, data: Buffer) -> bytes: + """ + Processes the provided bytes through the cipher and returns the results + as bytes. + """ + + @abc.abstractmethod + def update_into(self, data: Buffer, buf: Buffer) -> int: + """ + Processes the provided bytes and writes the resulting data into the + provided buffer. Returns the number of bytes written. + """ + + @abc.abstractmethod + def finalize(self) -> bytes: + """ + Returns the results of processing the final block as bytes. + """ + + @abc.abstractmethod + def reset_nonce(self, nonce: bytes) -> None: + """ + Resets the nonce for the cipher context to the provided value. + Raises an exception if it does not support reset or if the + provided nonce does not have a valid length. + """ + + +class AEADCipherContext(CipherContext, metaclass=abc.ABCMeta): + @abc.abstractmethod + def authenticate_additional_data(self, data: Buffer) -> None: + """ + Authenticates the provided bytes. + """ + + +class AEADDecryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): + @abc.abstractmethod + def finalize_with_tag(self, tag: bytes) -> bytes: + """ + Returns the results of processing the final block as bytes and allows + delayed passing of the authentication tag. + """ + + +class AEADEncryptionContext(AEADCipherContext, metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def tag(self) -> bytes: + """ + Returns tag bytes. This is only available after encryption is + finalized. + """ + + +Mode = typing.TypeVar( + "Mode", bound=typing.Optional[modes.Mode], covariant=True +) + + +class Cipher(typing.Generic[Mode]): + def __init__( + self, + algorithm: CipherAlgorithm, + mode: Mode, + backend: typing.Any = None, + ) -> None: + if not isinstance(algorithm, CipherAlgorithm): + raise TypeError("Expected interface of CipherAlgorithm.") + + if mode is not None: + # mypy needs this assert to narrow the type from our generic + # type. Maybe it won't some time in the future. + assert isinstance(mode, modes.Mode) + mode.validate_for_algorithm(algorithm) + + self.algorithm = algorithm + self.mode = mode + + @typing.overload + def encryptor( + self: Cipher[modes.ModeWithAuthenticationTag], + ) -> AEADEncryptionContext: ... + + @typing.overload + def encryptor( + self: _CIPHER_TYPE, + ) -> CipherContext: ... + + def encryptor(self): + if isinstance(self.mode, modes.ModeWithAuthenticationTag): + if self.mode.tag is not None: + raise ValueError( + "Authentication tag must be None when encrypting." + ) + + return rust_openssl.ciphers.create_encryption_ctx( + self.algorithm, self.mode + ) + + @typing.overload + def decryptor( + self: Cipher[modes.ModeWithAuthenticationTag], + ) -> AEADDecryptionContext: ... + + @typing.overload + def decryptor( + self: _CIPHER_TYPE, + ) -> CipherContext: ... + + def decryptor(self): + return rust_openssl.ciphers.create_decryption_ctx( + self.algorithm, self.mode + ) + + +_CIPHER_TYPE = Cipher[ + typing.Union[ + modes.ModeWithNonce, + modes.ModeWithTweak, + modes.ECB, + modes.ModeWithInitializationVector, + None, + ] +] + +CipherContext.register(rust_openssl.ciphers.CipherContext) +AEADEncryptionContext.register(rust_openssl.ciphers.AEADEncryptionContext) +AEADDecryptionContext.register(rust_openssl.ciphers.AEADDecryptionContext) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/modes.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/modes.py new file mode 100644 index 0000000..c2008e9 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/ciphers/modes.py @@ -0,0 +1,192 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.decrepit.ciphers.modes import CFB as CFB +from cryptography.hazmat.decrepit.ciphers.modes import CFB8 as CFB8 +from cryptography.hazmat.decrepit.ciphers.modes import OFB as OFB +from cryptography.hazmat.primitives._cipheralgorithm import ( + BlockCipherAlgorithm, + CipherAlgorithm, +) +from cryptography.hazmat.primitives._modes import ( + Mode as Mode, +) +from cryptography.hazmat.primitives._modes import ( + ModeWithAuthenticationTag as ModeWithAuthenticationTag, +) +from cryptography.hazmat.primitives._modes import ( + ModeWithInitializationVector as ModeWithInitializationVector, +) +from cryptography.hazmat.primitives._modes import ( + ModeWithNonce as ModeWithNonce, +) +from cryptography.hazmat.primitives._modes import ( + ModeWithTweak as ModeWithTweak, +) +from cryptography.hazmat.primitives._modes import ( + _check_aes_key_length, + _check_iv_and_key_length, + _check_nonce_length, +) +from cryptography.hazmat.primitives.ciphers import algorithms + + +class CBC(ModeWithInitializationVector): + name = "CBC" + + def __init__(self, initialization_vector: utils.Buffer): + utils._check_byteslike("initialization_vector", initialization_vector) + self._initialization_vector = initialization_vector + + @property + def initialization_vector(self) -> utils.Buffer: + return self._initialization_vector + + validate_for_algorithm = _check_iv_and_key_length + + +class XTS(ModeWithTweak): + name = "XTS" + + def __init__(self, tweak: utils.Buffer): + utils._check_byteslike("tweak", tweak) + + if len(tweak) != 16: + raise ValueError("tweak must be 128-bits (16 bytes)") + + self._tweak = tweak + + @property + def tweak(self) -> utils.Buffer: + return self._tweak + + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + if isinstance(algorithm, (algorithms.AES128, algorithms.AES256)): + raise TypeError( + "The AES128 and AES256 classes do not support XTS, please use " + "the standard AES class instead." + ) + + if algorithm.key_size not in (256, 512): + raise ValueError( + "The XTS specification requires a 256-bit key for AES-128-XTS" + " and 512-bit key for AES-256-XTS" + ) + + +class ECB(Mode): + name = "ECB" + + validate_for_algorithm = _check_aes_key_length + + +class CTR(ModeWithNonce): + name = "CTR" + + def __init__(self, nonce: utils.Buffer): + utils._check_byteslike("nonce", nonce) + self._nonce = nonce + + @property + def nonce(self) -> utils.Buffer: + return self._nonce + + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + _check_aes_key_length(self, algorithm) + _check_nonce_length(self.nonce, self.name, algorithm) + + +class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): + name = "GCM" + _MAX_ENCRYPTED_BYTES = (2**39 - 256) // 8 + _MAX_AAD_BYTES = (2**64 - 1) // 8 + + def __init__( + self, + initialization_vector: utils.Buffer, + tag: bytes | None = None, + min_tag_length: int = 16, + ): + # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive + # This is a sane limit anyway so we'll enforce it here. + utils._check_byteslike("initialization_vector", initialization_vector) + if len(initialization_vector) < 8 or len(initialization_vector) > 128: + raise ValueError( + "initialization_vector must be between 8 and 128 bytes (64 " + "and 1024 bits)." + ) + self._initialization_vector = initialization_vector + if min_tag_length < 4: + raise ValueError("min_tag_length must be >= 4") + if tag is not None: + utils._check_bytes("tag", tag) + if len(tag) < min_tag_length: + raise ValueError( + f"Authentication tag must be {min_tag_length} bytes or " + "longer." + ) + self._tag = tag + self._min_tag_length = min_tag_length + + @property + def tag(self) -> bytes | None: + return self._tag + + @property + def initialization_vector(self) -> utils.Buffer: + return self._initialization_vector + + def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: + _check_aes_key_length(self, algorithm) + if not isinstance(algorithm, BlockCipherAlgorithm): + raise UnsupportedAlgorithm( + "GCM requires a block cipher algorithm", + _Reasons.UNSUPPORTED_CIPHER, + ) + block_size_bytes = algorithm.block_size // 8 + if self._tag is not None and len(self._tag) > block_size_bytes: + raise ValueError( + f"Authentication tag cannot be more than {block_size_bytes} " + "bytes." + ) + + +utils.deprecated( + OFB, + __name__, + "OFB has been moved to " + "cryptography.hazmat.decrepit.ciphers.modes.OFB and " + "will be removed from " + "cryptography.hazmat.primitives.ciphers.modes in 49.0.0.", + utils.DeprecatedIn47, + name="OFB", +) + + +utils.deprecated( + CFB, + __name__, + "CFB has been moved to " + "cryptography.hazmat.decrepit.ciphers.modes.CFB and " + "will be removed from " + "cryptography.hazmat.primitives.ciphers.modes in 49.0.0.", + utils.DeprecatedIn47, + name="CFB", +) + + +utils.deprecated( + CFB8, + __name__, + "CFB8 has been moved to " + "cryptography.hazmat.decrepit.ciphers.modes.CFB8 and " + "will be removed from " + "cryptography.hazmat.primitives.ciphers.modes in 49.0.0.", + utils.DeprecatedIn47, + name="CFB8", +) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/cmac.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/cmac.py new file mode 100644 index 0000000..2c67ce2 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/cmac.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +__all__ = ["CMAC"] +CMAC = rust_openssl.cmac.CMAC diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/constant_time.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/constant_time.py new file mode 100644 index 0000000..3975c71 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/constant_time.py @@ -0,0 +1,14 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import hmac + + +def bytes_eq(a: bytes, b: bytes) -> bool: + if not isinstance(a, bytes) or not isinstance(b, bytes): + raise TypeError("a and b must be bytes.") + + return hmac.compare_digest(a, b) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/hashes.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/hashes.py new file mode 100644 index 0000000..50ed355 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/hashes.py @@ -0,0 +1,357 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import sys + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.utils import Buffer + +__all__ = [ + "MD5", + "SHA1", + "SHA3_224", + "SHA3_256", + "SHA3_384", + "SHA3_512", + "SHA224", + "SHA256", + "SHA384", + "SHA512", + "SHA512_224", + "SHA512_256", + "SHAKE128", + "SHAKE256", + "SM3", + "BLAKE2b", + "BLAKE2s", + "ExtendableOutputFunction", + "Hash", + "HashAlgorithm", + "HashContext", + "XOFHash", +] + + +class HashAlgorithm(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def name(self) -> str: + """ + A string naming this algorithm (e.g. "sha256", "md5"). + """ + + @property + @abc.abstractmethod + def digest_size(self) -> int: + """ + The size of the resulting digest in bytes. + """ + + @property + @abc.abstractmethod + def block_size(self) -> int | None: + """ + The internal block size of the hash function, or None if the hash + function does not use blocks internally (e.g. SHA3). + """ + + +class HashContext(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def algorithm(self) -> HashAlgorithm: + """ + A HashAlgorithm that will be used by this context. + """ + + @abc.abstractmethod + def update(self, data: Buffer) -> None: + """ + Processes the provided bytes through the hash. + """ + + @abc.abstractmethod + def finalize(self) -> bytes: + """ + Finalizes the hash context and returns the hash digest as bytes. + """ + + @abc.abstractmethod + def copy(self) -> HashContext: + """ + Return a HashContext that is a copy of the current context. + """ + + +Hash = rust_openssl.hashes.Hash +HashContext.register(Hash) + +XOFHash = rust_openssl.hashes.XOFHash + + +class ExtendableOutputFunction(metaclass=abc.ABCMeta): + """ + An interface for extendable output functions. + """ + + +class SHA1(HashAlgorithm): + name = "sha1" + digest_size = 20 + block_size = 64 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA1): + return NotImplemented + + return True + + +class SHA512_224(HashAlgorithm): # noqa: N801 + name = "sha512-224" + digest_size = 28 + block_size = 128 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA512_224): + return NotImplemented + + return True + + +class SHA512_256(HashAlgorithm): # noqa: N801 + name = "sha512-256" + digest_size = 32 + block_size = 128 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA512_256): + return NotImplemented + + return True + + +class SHA224(HashAlgorithm): + name = "sha224" + digest_size = 28 + block_size = 64 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA224): + return NotImplemented + + return True + + +class SHA256(HashAlgorithm): + name = "sha256" + digest_size = 32 + block_size = 64 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA256): + return NotImplemented + + return True + + +class SHA384(HashAlgorithm): + name = "sha384" + digest_size = 48 + block_size = 128 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA384): + return NotImplemented + + return True + + +class SHA512(HashAlgorithm): + name = "sha512" + digest_size = 64 + block_size = 128 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA512): + return NotImplemented + + return True + + +class SHA3_224(HashAlgorithm): # noqa: N801 + name = "sha3-224" + digest_size = 28 + block_size = None + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA3_224): + return NotImplemented + + return True + + +class SHA3_256(HashAlgorithm): # noqa: N801 + name = "sha3-256" + digest_size = 32 + block_size = None + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA3_256): + return NotImplemented + + return True + + +class SHA3_384(HashAlgorithm): # noqa: N801 + name = "sha3-384" + digest_size = 48 + block_size = None + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA3_384): + return NotImplemented + + return True + + +class SHA3_512(HashAlgorithm): # noqa: N801 + name = "sha3-512" + digest_size = 64 + block_size = None + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHA3_512): + return NotImplemented + + return True + + +class SHAKE128(HashAlgorithm, ExtendableOutputFunction): + name = "shake128" + block_size = None + + def __init__(self, digest_size: int): + if not isinstance(digest_size, int): + raise TypeError("digest_size must be an integer") + + if digest_size < 1: + raise ValueError("digest_size must be a positive integer") + + self._digest_size = digest_size + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHAKE128): + return NotImplemented + + return self._digest_size == other._digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + @classmethod + def xof(cls): + return cls(sys.maxsize) + + +class SHAKE256(HashAlgorithm, ExtendableOutputFunction): + name = "shake256" + block_size = None + + def __init__(self, digest_size: int): + if not isinstance(digest_size, int): + raise TypeError("digest_size must be an integer") + + if digest_size < 1: + raise ValueError("digest_size must be a positive integer") + + self._digest_size = digest_size + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SHAKE256): + return NotImplemented + + return self._digest_size == other._digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + @classmethod + def xof(cls): + return cls(sys.maxsize) + + +class MD5(HashAlgorithm): + name = "md5" + digest_size = 16 + block_size = 64 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, MD5): + return NotImplemented + + return True + + +class BLAKE2b(HashAlgorithm): + name = "blake2b" + _max_digest_size = 64 + _min_digest_size = 1 + block_size = 128 + + def __init__(self, digest_size: int): + if digest_size != 64: + raise ValueError("Digest size must be 64") + + self._digest_size = digest_size + + def __eq__(self, other: object) -> bool: + if not isinstance(other, BLAKE2b): + return NotImplemented + + return self._digest_size == other._digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + +class BLAKE2s(HashAlgorithm): + name = "blake2s" + block_size = 64 + _max_digest_size = 32 + _min_digest_size = 1 + + def __init__(self, digest_size: int): + if digest_size != 32: + raise ValueError("Digest size must be 32") + + self._digest_size = digest_size + + def __eq__(self, other: object) -> bool: + if not isinstance(other, BLAKE2s): + return NotImplemented + + return self._digest_size == other._digest_size + + @property + def digest_size(self) -> int: + return self._digest_size + + +class SM3(HashAlgorithm): + name = "sm3" + digest_size = 32 + block_size = 64 + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SM3): + return NotImplemented + + return True diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/hmac.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/hmac.py new file mode 100644 index 0000000..a9442d5 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/hmac.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives import hashes + +__all__ = ["HMAC"] + +HMAC = rust_openssl.hmac.HMAC +hashes.HashContext.register(HMAC) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/hpke.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/hpke.py new file mode 100644 index 0000000..c802808 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/hpke.py @@ -0,0 +1,27 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +AEAD = rust_openssl.hpke.AEAD +KDF = rust_openssl.hpke.KDF +KEM = rust_openssl.hpke.KEM +MLKEM768X25519PrivateKey = rust_openssl.hpke.MLKEM768X25519PrivateKey +MLKEM768X25519PublicKey = rust_openssl.hpke.MLKEM768X25519PublicKey +MLKEM1024P384PrivateKey = rust_openssl.hpke.MLKEM1024P384PrivateKey +MLKEM1024P384PublicKey = rust_openssl.hpke.MLKEM1024P384PublicKey +Suite = rust_openssl.hpke.Suite + +__all__ = [ + "AEAD", + "KDF", + "KEM", + "MLKEM768X25519PrivateKey", + "MLKEM768X25519PublicKey", + "MLKEM1024P384PrivateKey", + "MLKEM1024P384PublicKey", + "Suite", +] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/__init__.py new file mode 100644 index 0000000..26c45bd --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/__init__.py @@ -0,0 +1,32 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography.utils import Buffer + + +class KeyDerivationFunction(metaclass=abc.ABCMeta): + @abc.abstractmethod + def derive(self, key_material: bytes) -> bytes: + """ + Deterministically generates and returns a new key based on the existing + key material. + """ + + @abc.abstractmethod + def derive_into(self, key_material: bytes, buffer: Buffer) -> None: + """ + Deterministically generates a new key based on the existing key + material and stores it in the provided buffer. + """ + + @abc.abstractmethod + def verify(self, key_material: bytes, expected_key: bytes) -> None: + """ + Checks whether the key generated by the key material matches the + expected derived key. Raises an exception if they do not match. + """ diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/argon2.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/argon2.py new file mode 100644 index 0000000..03e84d4 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/argon2.py @@ -0,0 +1,17 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +Argon2d = rust_openssl.kdf.Argon2d +Argon2i = rust_openssl.kdf.Argon2i +Argon2id = rust_openssl.kdf.Argon2id +KeyDerivationFunction.register(Argon2d) +KeyDerivationFunction.register(Argon2i) +KeyDerivationFunction.register(Argon2id) + +__all__ = ["Argon2d", "Argon2i", "Argon2id"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/concatkdf.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/concatkdf.py new file mode 100644 index 0000000..398dc5d --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +ConcatKDFHash = rust_openssl.kdf.ConcatKDFHash +ConcatKDFHMAC = rust_openssl.kdf.ConcatKDFHMAC + +KeyDerivationFunction.register(ConcatKDFHash) +KeyDerivationFunction.register(ConcatKDFHMAC) + +__all__ = ["ConcatKDFHMAC", "ConcatKDFHash"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/hkdf.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/hkdf.py new file mode 100644 index 0000000..1e162d9 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/hkdf.py @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +HKDF = rust_openssl.kdf.HKDF +HKDFExpand = rust_openssl.kdf.HKDFExpand + +KeyDerivationFunction.register(HKDF) +KeyDerivationFunction.register(HKDFExpand) + +__all__ = ["HKDF", "HKDFExpand"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/kbkdf.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/kbkdf.py new file mode 100644 index 0000000..e559df8 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography import utils +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + + +class Mode(utils.Enum): + CounterMode = "ctr" + + +class CounterLocation(utils.Enum): + BeforeFixed = "before_fixed" + AfterFixed = "after_fixed" + MiddleFixed = "middle_fixed" + + +KBKDFHMAC = rust_openssl.kdf.KBKDFHMAC +KeyDerivationFunction.register(KBKDFHMAC) + +KBKDFCMAC = rust_openssl.kdf.KBKDFCMAC +KeyDerivationFunction.register(KBKDFCMAC) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/pbkdf2.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/pbkdf2.py new file mode 100644 index 0000000..771d80d --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +PBKDF2HMAC = rust_openssl.kdf.PBKDF2HMAC +KeyDerivationFunction.register(PBKDF2HMAC) + +__all__ = ["PBKDF2HMAC"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/scrypt.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/scrypt.py new file mode 100644 index 0000000..f791cee --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/scrypt.py @@ -0,0 +1,19 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import sys + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +# This is used by the scrypt tests to skip tests that require more memory +# than the MEM_LIMIT +_MEM_LIMIT = sys.maxsize // 2 + +Scrypt = rust_openssl.kdf.Scrypt +KeyDerivationFunction.register(Scrypt) + +__all__ = ["Scrypt"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/x963kdf.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/x963kdf.py new file mode 100644 index 0000000..8c4e2d3 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -0,0 +1,13 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.hazmat.primitives.kdf import KeyDerivationFunction + +X963KDF = rust_openssl.kdf.X963KDF +KeyDerivationFunction.register(X963KDF) + +__all__ = ["X963KDF"] diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/keywrap.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/keywrap.py new file mode 100644 index 0000000..123d97b --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/keywrap.py @@ -0,0 +1,25 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +__all__ = [ + "InvalidUnwrap", + "aes_key_unwrap", + "aes_key_unwrap_with_padding", + "aes_key_wrap", + "aes_key_wrap_with_padding", +] + + +class InvalidUnwrap(Exception): + pass + + +aes_key_wrap = rust_openssl.keywrap.aes_key_wrap +aes_key_unwrap = rust_openssl.keywrap.aes_key_unwrap +aes_key_wrap_with_padding = rust_openssl.keywrap.aes_key_wrap_with_padding +aes_key_unwrap_with_padding = rust_openssl.keywrap.aes_key_unwrap_with_padding diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/padding.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/padding.py new file mode 100644 index 0000000..f9cd1f1 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/padding.py @@ -0,0 +1,69 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc + +from cryptography import utils +from cryptography.hazmat.bindings._rust import ( + ANSIX923PaddingContext, + ANSIX923UnpaddingContext, + PKCS7PaddingContext, + PKCS7UnpaddingContext, +) + + +class PaddingContext(metaclass=abc.ABCMeta): + @abc.abstractmethod + def update(self, data: utils.Buffer) -> bytes: + """ + Pads the provided bytes and returns any available data as bytes. + """ + + @abc.abstractmethod + def finalize(self) -> bytes: + """ + Finalize the padding, returns bytes. + """ + + +def _byte_padding_check(block_size: int) -> None: + if not (0 <= block_size <= 2040): + raise ValueError("block_size must be in range(0, 2041).") + + if block_size % 8 != 0: + raise ValueError("block_size must be a multiple of 8.") + + +class PKCS7: + def __init__(self, block_size: int): + _byte_padding_check(block_size) + self.block_size = block_size + + def padder(self) -> PaddingContext: + return PKCS7PaddingContext(self.block_size) + + def unpadder(self) -> PaddingContext: + return PKCS7UnpaddingContext(self.block_size) + + +PaddingContext.register(PKCS7PaddingContext) +PaddingContext.register(PKCS7UnpaddingContext) + + +class ANSIX923: + def __init__(self, block_size: int): + _byte_padding_check(block_size) + self.block_size = block_size + + def padder(self) -> PaddingContext: + return ANSIX923PaddingContext(self.block_size) + + def unpadder(self) -> PaddingContext: + return ANSIX923UnpaddingContext(self.block_size) + + +PaddingContext.register(ANSIX923PaddingContext) +PaddingContext.register(ANSIX923UnpaddingContext) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/poly1305.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/poly1305.py new file mode 100644 index 0000000..7f5a77a --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/poly1305.py @@ -0,0 +1,11 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +__all__ = ["Poly1305"] + +Poly1305 = rust_openssl.poly1305.Poly1305 diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/__init__.py new file mode 100644 index 0000000..40beb21 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/__init__.py @@ -0,0 +1,85 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography import utils +from cryptography.hazmat.primitives._serialization import ( + BestAvailableEncryption, + Encoding, + KeySerializationEncryption, + NoEncryption, + ParameterFormat, + PrivateFormat, + PublicFormat, + _KeySerializationEncryption, +) +from cryptography.hazmat.primitives.asymmetric.dh import _FFDH_DEPRECATION_MSG +from cryptography.hazmat.primitives.serialization.base import ( + load_der_parameters, + load_der_private_key, + load_der_public_key, + load_pem_parameters, + load_pem_private_key, + load_pem_public_key, +) +from cryptography.hazmat.primitives.serialization.ssh import ( + SSHCertificate, + SSHCertificateBuilder, + SSHCertificateType, + SSHCertPrivateKeyTypes, + SSHCertPublicKeyTypes, + SSHPrivateKeyTypes, + SSHPublicKeyTypes, + load_ssh_private_key, + load_ssh_public_identity, + load_ssh_public_key, + ssh_key_fingerprint, +) + +__all__ = [ + "BestAvailableEncryption", + "Encoding", + "KeySerializationEncryption", + "NoEncryption", + "ParameterFormat", + "PrivateFormat", + "PublicFormat", + "SSHCertPrivateKeyTypes", + "SSHCertPublicKeyTypes", + "SSHCertificate", + "SSHCertificateBuilder", + "SSHCertificateType", + "SSHPrivateKeyTypes", + "SSHPublicKeyTypes", + "_KeySerializationEncryption", + "load_der_parameters", + "load_der_private_key", + "load_der_public_key", + "load_pem_parameters", + "load_pem_private_key", + "load_pem_public_key", + "load_ssh_private_key", + "load_ssh_public_identity", + "load_ssh_public_key", + "ssh_key_fingerprint", +] + +# These can only load FFDH parameters, so the functions themselves are +# deprecated alongside the rest of FFDH. +utils.deprecated( + load_pem_parameters, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="load_pem_parameters", +) + +utils.deprecated( + load_der_parameters, + __name__, + _FFDH_DEPRECATION_MSG, + utils.DeprecatedIn50, + name="load_der_parameters", +) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/base.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/base.py new file mode 100644 index 0000000..f2b503b --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/base.py @@ -0,0 +1,16 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat.bindings._rust import openssl as rust_openssl + +load_pem_private_key = rust_openssl.keys.load_pem_private_key +load_der_private_key = rust_openssl.keys.load_der_private_key + +load_pem_public_key = rust_openssl.keys.load_pem_public_key +load_der_public_key = rust_openssl.keys.load_der_public_key + +load_pem_parameters = rust_openssl.dh.from_pem_parameters +load_der_parameters = rust_openssl.dh.from_der_parameters diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs12.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs12.py new file mode 100644 index 0000000..58884ff --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs12.py @@ -0,0 +1,176 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import typing +from collections.abc import Iterable + +from cryptography import x509 +from cryptography.hazmat.bindings._rust import pkcs12 as rust_pkcs12 +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives._serialization import PBES as PBES +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed448, + ed25519, + rsa, +) +from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes + +__all__ = [ + "PBES", + "PKCS12Certificate", + "PKCS12KeyAndCertificates", + "PKCS12PrivateKeyTypes", + "load_key_and_certificates", + "load_pkcs12", + "serialize_java_truststore", + "serialize_key_and_certificates", +] + +PKCS12PrivateKeyTypes = typing.Union[ + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, +] + + +PKCS12Certificate = rust_pkcs12.PKCS12Certificate + + +class PKCS12KeyAndCertificates: + def __init__( + self, + key: PrivateKeyTypes | None, + cert: PKCS12Certificate | None, + additional_certs: list[PKCS12Certificate], + ): + if key is not None and not isinstance( + key, + ( + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + ), + ): + raise TypeError( + "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" + " private key, or None." + ) + if cert is not None and not isinstance(cert, PKCS12Certificate): + raise TypeError("cert must be a PKCS12Certificate object or None") + if not all( + isinstance(add_cert, PKCS12Certificate) + for add_cert in additional_certs + ): + raise TypeError( + "all values in additional_certs must be PKCS12Certificate" + " objects" + ) + self._key = key + self._cert = cert + self._additional_certs = additional_certs + + @property + def key(self) -> PrivateKeyTypes | None: + return self._key + + @property + def cert(self) -> PKCS12Certificate | None: + return self._cert + + @property + def additional_certs(self) -> list[PKCS12Certificate]: + return self._additional_certs + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PKCS12KeyAndCertificates): + return NotImplemented + + return ( + self.key == other.key + and self.cert == other.cert + and self.additional_certs == other.additional_certs + ) + + def __hash__(self) -> int: + return hash((self.key, self.cert, tuple(self.additional_certs))) + + def __repr__(self) -> str: + fmt = ( + "" + ) + return fmt.format(self.key, self.cert, self.additional_certs) + + +load_key_and_certificates = rust_pkcs12.load_key_and_certificates +load_pkcs12 = rust_pkcs12.load_pkcs12 + + +_PKCS12CATypes = typing.Union[ + x509.Certificate, + PKCS12Certificate, +] + + +def serialize_java_truststore( + certs: Iterable[PKCS12Certificate], + encryption_algorithm: serialization.KeySerializationEncryption, +) -> bytes: + if not certs: + raise ValueError("You must supply at least one cert") + + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Key encryption algorithm must be a " + "KeySerializationEncryption instance" + ) + + return rust_pkcs12.serialize_java_truststore(certs, encryption_algorithm) + + +def serialize_key_and_certificates( + name: bytes | None, + key: PKCS12PrivateKeyTypes | None, + cert: x509.Certificate | None, + cas: Iterable[_PKCS12CATypes] | None, + encryption_algorithm: serialization.KeySerializationEncryption, +) -> bytes: + if key is not None and not isinstance( + key, + ( + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + ), + ): + raise TypeError( + "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448" + " private key, or None." + ) + + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Key encryption algorithm must be a " + "KeySerializationEncryption instance" + ) + + if key is None and cert is None and not cas: + raise ValueError("You must supply at least one of key, cert, or cas") + + return rust_pkcs12.serialize_key_and_certificates( + name, key, cert, cas, encryption_algorithm + ) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs7.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs7.py new file mode 100644 index 0000000..76b667a --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -0,0 +1,412 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import email.base64mime +import email.generator +import email.message +import email.policy +import io +import typing +from collections.abc import Iterable + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa +from cryptography.hazmat.primitives.ciphers import ( + algorithms, +) +from cryptography.utils import _check_byteslike + +load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates + +load_der_pkcs7_certificates = rust_pkcs7.load_der_pkcs7_certificates + +serialize_certificates = rust_pkcs7.serialize_certificates + +PKCS7HashTypes = typing.Union[ + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, +] + +PKCS7PrivateKeyTypes = typing.Union[ + rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey +] + +ContentEncryptionAlgorithm = typing.Union[ + type[algorithms.AES128], type[algorithms.AES256] +] + + +class PKCS7Options(utils.Enum): + Text = "Add text/plain MIME type" + Binary = "Don't translate input data into canonical MIME format" + DetachedSignature = "Don't embed data in the PKCS7 structure" + NoCapabilities = "Don't embed SMIME capabilities" + NoAttributes = "Don't embed authenticatedAttributes" + NoCerts = "Don't embed signer certificate" + + +class PKCS7SignatureBuilder: + def __init__( + self, + data: utils.Buffer | None = None, + signers: list[ + tuple[ + x509.Certificate, + PKCS7PrivateKeyTypes, + PKCS7HashTypes, + padding.PSS | padding.PKCS1v15 | None, + ] + ] = [], + additional_certs: list[x509.Certificate] = [], + ): + self._data = data + self._signers = signers + self._additional_certs = additional_certs + + def set_data(self, data: utils.Buffer) -> PKCS7SignatureBuilder: + _check_byteslike("data", data) + if self._data is not None: + raise ValueError("data may only be set once") + + return PKCS7SignatureBuilder(data, self._signers) + + def add_signer( + self, + certificate: x509.Certificate, + private_key: PKCS7PrivateKeyTypes, + hash_algorithm: PKCS7HashTypes, + *, + rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ) -> PKCS7SignatureBuilder: + if not isinstance( + hash_algorithm, + ( + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ): + raise TypeError( + "hash_algorithm must be one of hashes.SHA224, " + "SHA256, SHA384, or SHA512" + ) + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + if not isinstance( + private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey) + ): + raise TypeError("Only RSA & EC keys are supported at this time.") + + if rsa_padding is not None: + if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): + raise TypeError("Padding must be PSS or PKCS1v15") + if not isinstance(private_key, rsa.RSAPrivateKey): + raise TypeError("Padding is only supported for RSA keys") + + return PKCS7SignatureBuilder( + self._data, + [ + *self._signers, + (certificate, private_key, hash_algorithm, rsa_padding), + ], + ) + + def add_certificate( + self, certificate: x509.Certificate + ) -> PKCS7SignatureBuilder: + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + return PKCS7SignatureBuilder( + self._data, self._signers, [*self._additional_certs, certificate] + ) + + def sign( + self, + encoding: serialization.Encoding, + options: Iterable[PKCS7Options], + backend: typing.Any = None, + ) -> bytes: + if len(self._signers) == 0: + raise ValueError("Must have at least one signer") + if self._data is None: + raise ValueError("You must add data to sign") + options = list(options) + if not all(isinstance(x, PKCS7Options) for x in options): + raise ValueError("options must be from the PKCS7Options enum") + if encoding not in ( + serialization.Encoding.PEM, + serialization.Encoding.DER, + serialization.Encoding.SMIME, + ): + raise ValueError( + "Must be PEM, DER, or SMIME from the Encoding enum" + ) + + # Text is a meaningless option unless it is accompanied by + # DetachedSignature + if ( + PKCS7Options.Text in options + and PKCS7Options.DetachedSignature not in options + ): + raise ValueError( + "When passing the Text option you must also pass " + "DetachedSignature" + ) + + if PKCS7Options.Text in options and encoding in ( + serialization.Encoding.DER, + serialization.Encoding.PEM, + ): + raise ValueError( + "The Text option is only available for SMIME serialization" + ) + + # No attributes implies no capabilities so we'll error if you try to + # pass both. + if ( + PKCS7Options.NoAttributes in options + and PKCS7Options.NoCapabilities in options + ): + raise ValueError( + "NoAttributes is a superset of NoCapabilities. Do not pass " + "both values." + ) + + return rust_pkcs7.sign_and_serialize(self, encoding, options) + + +class PKCS7EnvelopeBuilder: + def __init__( + self, + *, + _data: bytes | None = None, + _recipients: list[x509.Certificate] | None = None, + _content_encryption_algorithm: ContentEncryptionAlgorithm + | None = None, + ): + from cryptography.hazmat.backends.openssl.backend import ( + backend as ossl, + ) + + if not ossl.rsa_encryption_supported(padding=padding.PKCS1v15()): + raise UnsupportedAlgorithm( + "RSA with PKCS1 v1.5 padding is not supported by this version" + " of OpenSSL.", + _Reasons.UNSUPPORTED_PADDING, + ) + self._data = _data + self._recipients = _recipients if _recipients is not None else [] + self._content_encryption_algorithm = _content_encryption_algorithm + + def set_data(self, data: bytes) -> PKCS7EnvelopeBuilder: + _check_byteslike("data", data) + if self._data is not None: + raise ValueError("data may only be set once") + + return PKCS7EnvelopeBuilder( + _data=data, + _recipients=self._recipients, + _content_encryption_algorithm=self._content_encryption_algorithm, + ) + + def add_recipient( + self, + certificate: x509.Certificate, + ) -> PKCS7EnvelopeBuilder: + if not isinstance(certificate, x509.Certificate): + raise TypeError("certificate must be a x509.Certificate") + + if not isinstance(certificate.public_key(), rsa.RSAPublicKey): + raise TypeError("Only RSA keys are supported at this time.") + + return PKCS7EnvelopeBuilder( + _data=self._data, + _recipients=[ + *self._recipients, + certificate, + ], + _content_encryption_algorithm=self._content_encryption_algorithm, + ) + + def set_content_encryption_algorithm( + self, content_encryption_algorithm: ContentEncryptionAlgorithm + ) -> PKCS7EnvelopeBuilder: + if self._content_encryption_algorithm is not None: + raise ValueError("Content encryption algo may only be set once") + if content_encryption_algorithm not in { + algorithms.AES128, + algorithms.AES256, + }: + raise TypeError("Only AES128 and AES256 are supported") + + return PKCS7EnvelopeBuilder( + _data=self._data, + _recipients=self._recipients, + _content_encryption_algorithm=content_encryption_algorithm, + ) + + def encrypt( + self, + encoding: serialization.Encoding, + options: Iterable[PKCS7Options], + ) -> bytes: + if len(self._recipients) == 0: + raise ValueError("Must have at least one recipient") + if self._data is None: + raise ValueError("You must add data to encrypt") + + # The default content encryption algorithm is AES-128-CBC, which the + # S/MIME v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7) + # however rest of S/MIME v3.2 is not currently supported + content_encryption_algorithm = ( + self._content_encryption_algorithm or algorithms.AES128 + ) + + options = list(options) + if not all(isinstance(x, PKCS7Options) for x in options): + raise ValueError("options must be from the PKCS7Options enum") + if encoding not in ( + serialization.Encoding.PEM, + serialization.Encoding.DER, + serialization.Encoding.SMIME, + ): + raise ValueError( + "Must be PEM, DER, or SMIME from the Encoding enum" + ) + + # Only allow options that make sense for encryption + if any( + opt not in [PKCS7Options.Text, PKCS7Options.Binary] + for opt in options + ): + raise ValueError( + "Only the following options are supported for encryption: " + "Text, Binary" + ) + elif PKCS7Options.Text in options and PKCS7Options.Binary in options: + # OpenSSL accepts both options at the same time, but ignores Text. + # We fail defensively to avoid unexpected outputs. + raise ValueError( + "Cannot use Binary and Text options at the same time" + ) + + return rust_pkcs7.encrypt_and_serialize( + self, content_encryption_algorithm, encoding, options + ) + + +pkcs7_decrypt_der = rust_pkcs7.decrypt_der +pkcs7_decrypt_pem = rust_pkcs7.decrypt_pem +pkcs7_decrypt_smime = rust_pkcs7.decrypt_smime + + +def _smime_signed_encode( + data: bytes, signature: bytes, micalg: str, text_mode: bool +) -> bytes: + # This function works pretty hard to replicate what OpenSSL does + # precisely. For good and for ill. + + m = email.message.Message() + m.add_header("MIME-Version", "1.0") + m.add_header( + "Content-Type", + "multipart/signed", + protocol="application/x-pkcs7-signature", + micalg=micalg, + ) + + m.preamble = "This is an S/MIME signed message\n" + + msg_part = OpenSSLMimePart() + msg_part.set_payload(data) + if text_mode: + msg_part.add_header("Content-Type", "text/plain") + m.attach(msg_part) + + sig_part = email.message.MIMEPart() + sig_part.add_header( + "Content-Type", "application/x-pkcs7-signature", name="smime.p7s" + ) + sig_part.add_header("Content-Transfer-Encoding", "base64") + sig_part.add_header( + "Content-Disposition", "attachment", filename="smime.p7s" + ) + sig_part.set_payload( + email.base64mime.body_encode(signature, maxlinelen=65) + ) + del sig_part["MIME-Version"] + m.attach(sig_part) + + fp = io.BytesIO() + g = email.generator.BytesGenerator( + fp, + maxheaderlen=0, + mangle_from_=False, + policy=m.policy.clone(linesep="\r\n"), + ) + g.flatten(m) + return fp.getvalue() + + +def _smime_enveloped_encode(data: bytes) -> bytes: + m = email.message.Message() + m.add_header("MIME-Version", "1.0") + m.add_header("Content-Disposition", "attachment", filename="smime.p7m") + m.add_header( + "Content-Type", + "application/pkcs7-mime", + smime_type="enveloped-data", + name="smime.p7m", + ) + m.add_header("Content-Transfer-Encoding", "base64") + + m.set_payload(email.base64mime.body_encode(data, maxlinelen=65)) + + return m.as_bytes(policy=m.policy.clone(linesep="\n", max_line_length=0)) + + +def _smime_enveloped_decode(data: bytes) -> bytes: + m = email.message_from_bytes(data) + if m.get_content_type() not in { + "application/x-pkcs7-mime", + "application/pkcs7-mime", + }: + raise ValueError("Not an S/MIME enveloped message") + return bytes(m.get_payload(decode=True)) + + +def _smime_remove_text_headers(data: bytes) -> bytes: + m = email.message_from_bytes(data) + # Using get() instead of get_content_type() since it has None as default, + # where the latter has "text/plain". Both methods are case-insensitive. + content_type = m.get("content-type") + if content_type is None: + raise ValueError( + "Decrypted MIME data has no 'Content-Type' header. " + "Please remove the 'Text' option to parse it manually." + ) + if "text/plain" not in content_type: + raise ValueError( + f"Decrypted MIME data content type is '{content_type}', not " + "'text/plain'. Remove the 'Text' option to parse it manually." + ) + return bytes(m.get_payload(decode=True)) + + +class OpenSSLMimePart(email.message.MIMEPart): + # A MIMEPart subclass that replicates OpenSSL's behavior of not including + # a newline if there are no headers. + def _write_headers(self, generator) -> None: + if list(self.raw_items()): + generator._write_headers(self) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/ssh.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/ssh.py new file mode 100644 index 0000000..230e147 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/serialization/ssh.py @@ -0,0 +1,1615 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import binascii +import enum +import os +import re +import typing +import warnings +from dataclasses import dataclass + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + padding, + rsa, +) +from cryptography.hazmat.primitives.asymmetric import utils as asym_utils +from cryptography.hazmat.primitives.ciphers import ( + AEADDecryptionContext, + Cipher, + algorithms, + modes, +) +from cryptography.hazmat.primitives.serialization import ( + Encoding, + KeySerializationEncryption, + NoEncryption, + PrivateFormat, + PublicFormat, + _KeySerializationEncryption, +) + +try: + from bcrypt import kdf as _bcrypt_kdf + + _bcrypt_supported = True +except ImportError: + _bcrypt_supported = False + + def _bcrypt_kdf( + password: bytes, + salt: bytes, + desired_key_bytes: int, + rounds: int, + ignore_few_rounds: bool = False, + ) -> bytes: + raise UnsupportedAlgorithm("Need bcrypt module") + + +_SSH_ED25519 = b"ssh-ed25519" +_SSH_RSA = b"ssh-rsa" +_SSH_DSA = b"ssh-dss" +_ECDSA_NISTP256 = b"ecdsa-sha2-nistp256" +_ECDSA_NISTP384 = b"ecdsa-sha2-nistp384" +_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521" +_CERT_SUFFIX = b"-cert-v01@openssh.com" + +# U2F application string suffixed pubkey +_SK_SSH_ED25519 = b"sk-ssh-ed25519@openssh.com" +_SK_SSH_ECDSA_NISTP256 = b"sk-ecdsa-sha2-nistp256@openssh.com" + +# These are not key types, only algorithms, so they cannot appear +# as a public key type +_SSH_RSA_SHA256 = b"rsa-sha2-256" +_SSH_RSA_SHA512 = b"rsa-sha2-512" + +_SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)") +_SK_MAGIC = b"openssh-key-v1\0" +_SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----" +_SK_END = b"-----END OPENSSH PRIVATE KEY-----" +_BCRYPT = b"bcrypt" +_NONE = b"none" +_DEFAULT_CIPHER = b"aes256-ctr" +_DEFAULT_ROUNDS = 16 + +# re is only way to work on bytes-like data +_PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL) + +# padding for max blocksize +_PADDING = memoryview(bytearray(range(1, 1 + 16))) + + +@dataclass +class _SSHCipher: + alg: type[algorithms.AES] + key_len: int + mode: type[modes.CTR] | type[modes.CBC] | type[modes.GCM] + block_len: int + iv_len: int + tag_len: int | None + is_aead: bool + + +# ciphers that are actually used in key wrapping +_SSH_CIPHERS: dict[bytes, _SSHCipher] = { + b"aes256-ctr": _SSHCipher( + alg=algorithms.AES, + key_len=32, + mode=modes.CTR, + block_len=16, + iv_len=16, + tag_len=None, + is_aead=False, + ), + b"aes256-cbc": _SSHCipher( + alg=algorithms.AES, + key_len=32, + mode=modes.CBC, + block_len=16, + iv_len=16, + tag_len=None, + is_aead=False, + ), + b"aes256-gcm@openssh.com": _SSHCipher( + alg=algorithms.AES, + key_len=32, + mode=modes.GCM, + block_len=16, + iv_len=12, + tag_len=16, + is_aead=True, + ), +} + +# map local curve name to key type +_ECDSA_KEY_TYPE = { + "secp256r1": _ECDSA_NISTP256, + "secp384r1": _ECDSA_NISTP384, + "secp521r1": _ECDSA_NISTP521, +} + + +def _get_ssh_key_type(key: SSHPrivateKeyTypes | SSHPublicKeyTypes) -> bytes: + if isinstance(key, ec.EllipticCurvePrivateKey): + key_type = _ecdsa_key_type(key.public_key()) + elif isinstance(key, ec.EllipticCurvePublicKey): + key_type = _ecdsa_key_type(key) + elif isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)): + key_type = _SSH_RSA + elif isinstance(key, (dsa.DSAPrivateKey, dsa.DSAPublicKey)): + key_type = _SSH_DSA + elif isinstance( + key, (ed25519.Ed25519PrivateKey, ed25519.Ed25519PublicKey) + ): + key_type = _SSH_ED25519 + else: + raise ValueError("Unsupported key type") + + return key_type + + +def _ecdsa_key_type(public_key: ec.EllipticCurvePublicKey) -> bytes: + """Return SSH key_type and curve_name for private key.""" + curve = public_key.curve + if curve.name not in _ECDSA_KEY_TYPE: + raise ValueError( + f"Unsupported curve for ssh private key: {curve.name!r}" + ) + return _ECDSA_KEY_TYPE[curve.name] + + +def _check_block_size(data: utils.Buffer, block_len: int) -> None: + """Require data to be full blocks""" + if not data or len(data) % block_len != 0: + raise ValueError("Corrupt data: missing padding") + + +def _check_empty(data: utils.Buffer) -> None: + """All data should have been parsed.""" + if data: + raise ValueError("Corrupt data: unparsed data") + + +def _init_cipher( + ciphername: bytes, + password: bytes | None, + salt: bytes, + rounds: int, +) -> Cipher[modes.CBC | modes.CTR | modes.GCM]: + """Generate key + iv and return cipher.""" + if not password: + raise TypeError( + "Key is password-protected, but password was not provided." + ) + + ciph = _SSH_CIPHERS[ciphername] + seed = _bcrypt_kdf( + password, salt, ciph.key_len + ciph.iv_len, rounds, True + ) + return Cipher( + ciph.alg(seed[: ciph.key_len]), + ciph.mode(seed[ciph.key_len :]), + ) + + +def _get_u32(data: memoryview) -> tuple[int, memoryview]: + """Uint32""" + if len(data) < 4: + raise ValueError("Invalid data") + return int.from_bytes(data[:4], byteorder="big"), data[4:] + + +def _get_u64(data: memoryview) -> tuple[int, memoryview]: + """Uint64""" + if len(data) < 8: + raise ValueError("Invalid data") + return int.from_bytes(data[:8], byteorder="big"), data[8:] + + +def _get_sshstr(data: memoryview) -> tuple[memoryview, memoryview]: + """Bytes with u32 length prefix""" + n, data = _get_u32(data) + if n > len(data): + raise ValueError("Invalid data") + return data[:n], data[n:] + + +def _get_mpint(data: memoryview) -> tuple[int, memoryview]: + """Big integer.""" + val, data = _get_sshstr(data) + if val and val[0] > 0x7F: + raise ValueError("Invalid data") + return int.from_bytes(val, "big"), data + + +def _to_mpint(val: int) -> bytes: + """Storage format for signed bigint.""" + if val < 0: + raise ValueError("negative mpint not allowed") + if not val: + return b"" + nbytes = (val.bit_length() + 8) // 8 + return utils.int_to_bytes(val, nbytes) + + +class _FragList: + """Build recursive structure without data copy.""" + + flist: list[utils.Buffer] + + def __init__(self, init: list[utils.Buffer] | None = None) -> None: + self.flist = [] + if init: + self.flist.extend(init) + + def put_raw(self, val: utils.Buffer) -> None: + """Add plain bytes""" + self.flist.append(val) + + def put_u32(self, val: int) -> None: + """Big-endian uint32""" + self.flist.append(val.to_bytes(length=4, byteorder="big")) + + def put_u64(self, val: int) -> None: + """Big-endian uint64""" + self.flist.append(val.to_bytes(length=8, byteorder="big")) + + def put_sshstr(self, val: bytes | _FragList) -> None: + """Bytes prefixed with u32 length""" + if isinstance(val, (bytes, memoryview, bytearray)): + self.put_u32(len(val)) + self.flist.append(val) + else: + self.put_u32(val.size()) + self.flist.extend(val.flist) + + def put_mpint(self, val: int) -> None: + """Big-endian bigint prefixed with u32 length""" + self.put_sshstr(_to_mpint(val)) + + def size(self) -> int: + """Current number of bytes""" + return sum(map(len, self.flist)) + + def render(self, dstbuf: memoryview, pos: int = 0) -> int: + """Write into bytearray""" + for frag in self.flist: + flen = len(frag) + start, pos = pos, pos + flen + dstbuf[start:pos] = frag + return pos + + def tobytes(self) -> bytes: + """Return as bytes""" + buf = memoryview(bytearray(self.size())) + self.render(buf) + return buf.tobytes() + + +class _SSHFormatRSA: + """Format for RSA keys. + + Public: + mpint e, n + Private: + mpint n, e, d, iqmp, p, q + """ + + def get_public( + self, data: memoryview + ) -> tuple[tuple[int, int], memoryview]: + """RSA public fields""" + e, data = _get_mpint(data) + n, data = _get_mpint(data) + return (e, n), data + + def load_public( + self, data: memoryview + ) -> tuple[rsa.RSAPublicKey, memoryview]: + """Make RSA public key from data.""" + (e, n), data = self.get_public(data) + public_numbers = rsa.RSAPublicNumbers(e, n) + public_key = public_numbers.public_key() + return public_key, data + + def load_private( + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool + ) -> tuple[rsa.RSAPrivateKey, memoryview]: + """Make RSA private key from data.""" + n, data = _get_mpint(data) + e, data = _get_mpint(data) + d, data = _get_mpint(data) + iqmp, data = _get_mpint(data) + p, data = _get_mpint(data) + q, data = _get_mpint(data) + + if (e, n) != pubfields: + raise ValueError("Corrupt data: rsa field mismatch") + dmp1 = rsa.rsa_crt_dmp1(d, p) + dmq1 = rsa.rsa_crt_dmq1(d, q) + public_numbers = rsa.RSAPublicNumbers(e, n) + private_numbers = rsa.RSAPrivateNumbers( + p, q, d, dmp1, dmq1, iqmp, public_numbers + ) + private_key = private_numbers.private_key( + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation + ) + return private_key, data + + def encode_public( + self, public_key: rsa.RSAPublicKey, f_pub: _FragList + ) -> None: + """Write RSA public key""" + pubn = public_key.public_numbers() + f_pub.put_mpint(pubn.e) + f_pub.put_mpint(pubn.n) + + def encode_private( + self, private_key: rsa.RSAPrivateKey, f_priv: _FragList + ) -> None: + """Write RSA private key""" + private_numbers = private_key.private_numbers() + public_numbers = private_numbers.public_numbers + + f_priv.put_mpint(public_numbers.n) + f_priv.put_mpint(public_numbers.e) + + f_priv.put_mpint(private_numbers.d) + f_priv.put_mpint(private_numbers.iqmp) + f_priv.put_mpint(private_numbers.p) + f_priv.put_mpint(private_numbers.q) + + +class _SSHFormatDSA: + """Format for DSA keys. + + Public: + mpint p, q, g, y + Private: + mpint p, q, g, y, x + """ + + def get_public(self, data: memoryview) -> tuple[tuple, memoryview]: + """DSA public fields""" + p, data = _get_mpint(data) + q, data = _get_mpint(data) + g, data = _get_mpint(data) + y, data = _get_mpint(data) + return (p, q, g, y), data + + def load_public( + self, data: memoryview + ) -> tuple[dsa.DSAPublicKey, memoryview]: + """Make DSA public key from data.""" + (p, q, g, y), data = self.get_public(data) + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + self._validate(public_numbers) + public_key = public_numbers.public_key() + return public_key, data + + def load_private( + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool + ) -> tuple[dsa.DSAPrivateKey, memoryview]: + """Make DSA private key from data.""" + (p, q, g, y), data = self.get_public(data) + x, data = _get_mpint(data) + + if (p, q, g, y) != pubfields: + raise ValueError("Corrupt data: dsa field mismatch") + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) + self._validate(public_numbers) + private_numbers = dsa.DSAPrivateNumbers(x, public_numbers) + private_key = private_numbers.private_key() + return private_key, data + + def encode_public( + self, public_key: dsa.DSAPublicKey, f_pub: _FragList + ) -> None: + """Write DSA public key""" + public_numbers = public_key.public_numbers() + parameter_numbers = public_numbers.parameter_numbers + self._validate(public_numbers) + + f_pub.put_mpint(parameter_numbers.p) + f_pub.put_mpint(parameter_numbers.q) + f_pub.put_mpint(parameter_numbers.g) + f_pub.put_mpint(public_numbers.y) + + def encode_private( + self, private_key: dsa.DSAPrivateKey, f_priv: _FragList + ) -> None: + """Write DSA private key""" + self.encode_public(private_key.public_key(), f_priv) + f_priv.put_mpint(private_key.private_numbers().x) + + def _validate(self, public_numbers: dsa.DSAPublicNumbers) -> None: + parameter_numbers = public_numbers.parameter_numbers + if parameter_numbers.p.bit_length() != 1024: + raise ValueError("SSH supports only 1024 bit DSA keys") + + +class _SSHFormatECDSA: + """Format for ECDSA keys. + + Public: + str curve + bytes point + Private: + str curve + bytes point + mpint secret + """ + + def __init__(self, ssh_curve_name: bytes, curve: ec.EllipticCurve): + self.ssh_curve_name = ssh_curve_name + self.curve = curve + + def get_public( + self, data: memoryview + ) -> tuple[tuple[memoryview, memoryview], memoryview]: + """ECDSA public fields""" + curve, data = _get_sshstr(data) + point, data = _get_sshstr(data) + if curve != self.ssh_curve_name: + raise ValueError("Curve name mismatch") + if len(point) == 0: + raise ValueError("Invalid EC point: empty data") + if point[0] != 4: + raise NotImplementedError("Need uncompressed point") + return (curve, point), data + + def load_public( + self, data: memoryview + ) -> tuple[ec.EllipticCurvePublicKey, memoryview]: + """Make ECDSA public key from data.""" + (_, point), data = self.get_public(data) + public_key = ec.EllipticCurvePublicKey.from_encoded_point( + self.curve, point.tobytes() + ) + return public_key, data + + def load_private( + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool + ) -> tuple[ec.EllipticCurvePrivateKey, memoryview]: + """Make ECDSA private key from data.""" + (curve_name, point), data = self.get_public(data) + secret, data = _get_mpint(data) + + if (curve_name, point) != pubfields: + raise ValueError("Corrupt data: ecdsa field mismatch") + private_key = ec.derive_private_key(secret, self.curve) + return private_key, data + + def encode_public( + self, public_key: ec.EllipticCurvePublicKey, f_pub: _FragList + ) -> None: + """Write ECDSA public key""" + point = public_key.public_bytes( + Encoding.X962, PublicFormat.UncompressedPoint + ) + f_pub.put_sshstr(self.ssh_curve_name) + f_pub.put_sshstr(point) + + def encode_private( + self, private_key: ec.EllipticCurvePrivateKey, f_priv: _FragList + ) -> None: + """Write ECDSA private key""" + public_key = private_key.public_key() + private_numbers = private_key.private_numbers() + + self.encode_public(public_key, f_priv) + f_priv.put_mpint(private_numbers.private_value) + + +class _SSHFormatEd25519: + """Format for Ed25519 keys. + + Public: + bytes point + Private: + bytes point + bytes secret_and_point + """ + + def get_public( + self, data: memoryview + ) -> tuple[tuple[memoryview], memoryview]: + """Ed25519 public fields""" + point, data = _get_sshstr(data) + return (point,), data + + def load_public( + self, data: memoryview + ) -> tuple[ed25519.Ed25519PublicKey, memoryview]: + """Make Ed25519 public key from data.""" + (point,), data = self.get_public(data) + public_key = ed25519.Ed25519PublicKey.from_public_bytes( + point.tobytes() + ) + return public_key, data + + def load_private( + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool + ) -> tuple[ed25519.Ed25519PrivateKey, memoryview]: + """Make Ed25519 private key from data.""" + (point,), data = self.get_public(data) + keypair, data = _get_sshstr(data) + + secret = keypair[:32] + point2 = keypair[32:] + if point != point2 or (point,) != pubfields: + raise ValueError("Corrupt data: ed25519 field mismatch") + private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret) + return private_key, data + + def encode_public( + self, public_key: ed25519.Ed25519PublicKey, f_pub: _FragList + ) -> None: + """Write Ed25519 public key""" + raw_public_key = public_key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) + f_pub.put_sshstr(raw_public_key) + + def encode_private( + self, private_key: ed25519.Ed25519PrivateKey, f_priv: _FragList + ) -> None: + """Write Ed25519 private key""" + public_key = private_key.public_key() + raw_private_key = private_key.private_bytes( + Encoding.Raw, PrivateFormat.Raw, NoEncryption() + ) + raw_public_key = public_key.public_bytes( + Encoding.Raw, PublicFormat.Raw + ) + f_keypair = _FragList([raw_private_key, raw_public_key]) + + self.encode_public(public_key, f_priv) + f_priv.put_sshstr(f_keypair) + + +def load_application(data) -> tuple[memoryview, memoryview]: + """ + U2F application strings + """ + application, data = _get_sshstr(data) + if not application.tobytes().startswith(b"ssh:"): + raise ValueError( + "U2F application string does not start with b'ssh:' " + f"({application})" + ) + return application, data + + +class _SSHFormatSKEd25519: + """ + The format of a sk-ssh-ed25519@openssh.com public key is: + + string "sk-ssh-ed25519@openssh.com" + string public key + string application (user-specified, but typically "ssh:") + """ + + def load_public( + self, data: memoryview + ) -> tuple[ed25519.Ed25519PublicKey, memoryview]: + """Make Ed25519 public key from data.""" + public_key, data = _lookup_kformat(_SSH_ED25519).load_public(data) + _, data = load_application(data) + return public_key, data + + def get_public(self, data: memoryview) -> typing.NoReturn: + # Confusingly `get_public` is an entry point used by private key + # loading. + raise UnsupportedAlgorithm( + "sk-ssh-ed25519 private keys cannot be loaded" + ) + + +class _SSHFormatSKECDSA: + """ + The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is: + + string "sk-ecdsa-sha2-nistp256@openssh.com" + string curve name + ec_point Q + string application (user-specified, but typically "ssh:") + """ + + def load_public( + self, data: memoryview + ) -> tuple[ec.EllipticCurvePublicKey, memoryview]: + """Make ECDSA public key from data.""" + public_key, data = _lookup_kformat(_ECDSA_NISTP256).load_public(data) + _, data = load_application(data) + return public_key, data + + def get_public(self, data: memoryview) -> typing.NoReturn: + # Confusingly `get_public` is an entry point used by private key + # loading. + raise UnsupportedAlgorithm( + "sk-ecdsa-sha2-nistp256 private keys cannot be loaded" + ) + + +_KEY_FORMATS = { + _SSH_RSA: _SSHFormatRSA(), + _SSH_DSA: _SSHFormatDSA(), + _SSH_ED25519: _SSHFormatEd25519(), + _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()), + _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()), + _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()), + _SK_SSH_ED25519: _SSHFormatSKEd25519(), + _SK_SSH_ECDSA_NISTP256: _SSHFormatSKECDSA(), +} + + +def _lookup_kformat(key_type: utils.Buffer): + """Return valid format or throw error""" + if not isinstance(key_type, bytes): + key_type = memoryview(key_type).tobytes() + if key_type in _KEY_FORMATS: + return _KEY_FORMATS[key_type] + raise UnsupportedAlgorithm(f"Unsupported key type: {key_type!r}") + + +SSHPrivateKeyTypes = typing.Union[ + ec.EllipticCurvePrivateKey, + rsa.RSAPrivateKey, + dsa.DSAPrivateKey, + ed25519.Ed25519PrivateKey, +] + + +def load_ssh_private_key( + data: utils.Buffer, + password: bytes | None, + backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, +) -> SSHPrivateKeyTypes: + """Load private key from OpenSSH custom encoding.""" + utils._check_byteslike("data", data) + if password is not None: + utils._check_bytes("password", password) + + m = _PEM_RC.search(data) + if not m: + raise ValueError("Not OpenSSH private key format") + p1 = m.start(1) + p2 = m.end(1) + data = binascii.a2b_base64(memoryview(data)[p1:p2]) + if not data.startswith(_SK_MAGIC): + raise ValueError("Not OpenSSH private key format") + data = memoryview(data)[len(_SK_MAGIC) :] + + # parse header + ciphername, data = _get_sshstr(data) + kdfname, data = _get_sshstr(data) + kdfoptions, data = _get_sshstr(data) + nkeys, data = _get_u32(data) + if nkeys != 1: + raise ValueError("Only one key supported") + + # load public key data + pubdata, data = _get_sshstr(data) + pub_key_type, pubdata = _get_sshstr(pubdata) + kformat = _lookup_kformat(pub_key_type) + pubfields, pubdata = kformat.get_public(pubdata) + _check_empty(pubdata) + + if ciphername != _NONE or kdfname != _NONE: + ciphername_bytes = ciphername.tobytes() + if ciphername_bytes not in _SSH_CIPHERS: + raise UnsupportedAlgorithm( + f"Unsupported cipher: {ciphername_bytes!r}" + ) + if kdfname != _BCRYPT: + raise UnsupportedAlgorithm(f"Unsupported KDF: {kdfname!r}") + blklen = _SSH_CIPHERS[ciphername_bytes].block_len + tag_len = _SSH_CIPHERS[ciphername_bytes].tag_len + # load secret data + edata, data = _get_sshstr(data) + # see https://bugzilla.mindrot.org/show_bug.cgi?id=3553 for + # information about how OpenSSH handles AEAD tags + if _SSH_CIPHERS[ciphername_bytes].is_aead: + tag = bytes(data) + if len(tag) != tag_len: + raise ValueError("Corrupt data: invalid tag length for cipher") + else: + _check_empty(data) + _check_block_size(edata, blklen) + salt, kbuf = _get_sshstr(kdfoptions) + rounds, kbuf = _get_u32(kbuf) + _check_empty(kbuf) + ciph = _init_cipher(ciphername_bytes, password, salt.tobytes(), rounds) + dec = ciph.decryptor() + edata = memoryview(dec.update(edata)) + if _SSH_CIPHERS[ciphername_bytes].is_aead: + assert isinstance(dec, AEADDecryptionContext) + _check_empty(dec.finalize_with_tag(tag)) + else: + # _check_block_size requires data to be a full block so there + # should be no output from finalize + _check_empty(dec.finalize()) + else: + if password: + raise TypeError( + "Password was given but private key is not encrypted." + ) + # load secret data + edata, data = _get_sshstr(data) + _check_empty(data) + blklen = 8 + _check_block_size(edata, blklen) + ck1, edata = _get_u32(edata) + ck2, edata = _get_u32(edata) + if ck1 != ck2: + raise ValueError("Corrupt data: broken checksum") + + # load per-key struct + key_type, edata = _get_sshstr(edata) + if key_type != pub_key_type: + raise ValueError("Corrupt data: key type mismatch") + private_key, edata = kformat.load_private( + edata, + pubfields, + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, + ) + # We don't use the comment + _, edata = _get_sshstr(edata) + + # yes, SSH does padding check *after* all other parsing is done. + # need to follow as it writes zero-byte padding too. + if edata != _PADDING[: len(edata)]: + raise ValueError("Corrupt data: invalid padding") + + if isinstance(private_key, dsa.DSAPrivateKey): + warnings.warn( + "SSH DSA keys are deprecated and will be removed in a future " + "release.", + utils.DeprecatedIn40, + stacklevel=2, + ) + + return private_key + + +def _serialize_ssh_private_key( + private_key: SSHPrivateKeyTypes, + password: bytes, + encryption_algorithm: KeySerializationEncryption, +) -> bytes: + """Serialize private key with OpenSSH custom encoding.""" + utils._check_bytes("password", password) + if isinstance(private_key, dsa.DSAPrivateKey): + warnings.warn( + "SSH DSA key support is deprecated and will be " + "removed in a future release", + utils.DeprecatedIn40, + stacklevel=4, + ) + + key_type = _get_ssh_key_type(private_key) + kformat = _lookup_kformat(key_type) + + # setup parameters + f_kdfoptions = _FragList() + if password: + ciphername = _DEFAULT_CIPHER + blklen = _SSH_CIPHERS[ciphername].block_len + kdfname = _BCRYPT + rounds = _DEFAULT_ROUNDS + if ( + isinstance(encryption_algorithm, _KeySerializationEncryption) + and encryption_algorithm._kdf_rounds is not None + ): + rounds = encryption_algorithm._kdf_rounds + salt = os.urandom(16) + f_kdfoptions.put_sshstr(salt) + f_kdfoptions.put_u32(rounds) + ciph = _init_cipher(ciphername, password, salt, rounds) + else: + ciphername = kdfname = _NONE + blklen = 8 + ciph = None + nkeys = 1 + checkval = os.urandom(4) + comment = b"" + + # encode public and private parts together + f_public_key = _FragList() + f_public_key.put_sshstr(key_type) + kformat.encode_public(private_key.public_key(), f_public_key) + + f_secrets = _FragList([checkval, checkval]) + f_secrets.put_sshstr(key_type) + kformat.encode_private(private_key, f_secrets) + f_secrets.put_sshstr(comment) + f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)]) + + # top-level structure + f_main = _FragList() + f_main.put_raw(_SK_MAGIC) + f_main.put_sshstr(ciphername) + f_main.put_sshstr(kdfname) + f_main.put_sshstr(f_kdfoptions) + f_main.put_u32(nkeys) + f_main.put_sshstr(f_public_key) + f_main.put_sshstr(f_secrets) + + # copy result info bytearray + slen = f_secrets.size() + mlen = f_main.size() + buf = memoryview(bytearray(mlen + blklen)) + f_main.render(buf) + ofs = mlen - slen + + # encrypt in-place + if ciph is not None: + ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:]) + + return bytes(buf[:mlen]) + + +SSHPublicKeyTypes = typing.Union[ + ec.EllipticCurvePublicKey, + rsa.RSAPublicKey, + dsa.DSAPublicKey, + ed25519.Ed25519PublicKey, +] + +SSHCertPublicKeyTypes = typing.Union[ + ec.EllipticCurvePublicKey, + rsa.RSAPublicKey, + ed25519.Ed25519PublicKey, +] + + +class SSHCertificateType(enum.Enum): + USER = 1 + HOST = 2 + + +class SSHCertificate: + def __init__( + self, + _nonce: memoryview, + _public_key: SSHPublicKeyTypes, + _serial: int, + _cctype: int, + _key_id: memoryview, + _valid_principals: list[bytes], + _valid_after: int, + _valid_before: int, + _critical_options: dict[bytes, bytes], + _extensions: dict[bytes, bytes], + _sig_type: memoryview, + _sig_key: memoryview, + _inner_sig_type: memoryview, + _signature: memoryview, + _tbs_cert_body: memoryview, + _cert_key_type: bytes, + _cert_body: memoryview, + ): + self._nonce = _nonce + self._public_key = _public_key + self._serial = _serial + try: + self._type = SSHCertificateType(_cctype) + except ValueError: + raise ValueError("Invalid certificate type") + self._key_id = _key_id + self._valid_principals = _valid_principals + self._valid_after = _valid_after + self._valid_before = _valid_before + self._critical_options = _critical_options + self._extensions = _extensions + self._sig_type = _sig_type + self._sig_key = _sig_key + self._inner_sig_type = _inner_sig_type + self._signature = _signature + self._cert_key_type = _cert_key_type + self._cert_body = _cert_body + self._tbs_cert_body = _tbs_cert_body + + @property + def nonce(self) -> bytes: + return bytes(self._nonce) + + def public_key(self) -> SSHCertPublicKeyTypes: + # make mypy happy until we remove DSA support entirely and + # the underlying union won't have a disallowed type + return typing.cast(SSHCertPublicKeyTypes, self._public_key) + + @property + def serial(self) -> int: + return self._serial + + @property + def type(self) -> SSHCertificateType: + return self._type + + @property + def key_id(self) -> bytes: + return bytes(self._key_id) + + @property + def valid_principals(self) -> list[bytes]: + return self._valid_principals + + @property + def valid_before(self) -> int: + return self._valid_before + + @property + def valid_after(self) -> int: + return self._valid_after + + @property + def critical_options(self) -> dict[bytes, bytes]: + return self._critical_options + + @property + def extensions(self) -> dict[bytes, bytes]: + return self._extensions + + def signature_key(self) -> SSHCertPublicKeyTypes: + sigformat = _lookup_kformat(self._sig_type) + signature_key, sigkey_rest = sigformat.load_public(self._sig_key) + _check_empty(sigkey_rest) + return signature_key + + def public_bytes(self) -> bytes: + return ( + bytes(self._cert_key_type) + + b" " + + binascii.b2a_base64(bytes(self._cert_body), newline=False) + ) + + def verify_cert_signature(self) -> None: + signature_key = self.signature_key() + if isinstance(signature_key, ed25519.Ed25519PublicKey): + signature_key.verify( + bytes(self._signature), bytes(self._tbs_cert_body) + ) + elif isinstance(signature_key, ec.EllipticCurvePublicKey): + # The signature is encoded as a pair of big-endian integers + r, data = _get_mpint(self._signature) + s, data = _get_mpint(data) + _check_empty(data) + computed_sig = asym_utils.encode_dss_signature(r, s) + hash_alg = _get_ec_hash_alg(signature_key.curve) + signature_key.verify( + computed_sig, bytes(self._tbs_cert_body), ec.ECDSA(hash_alg) + ) + else: + assert isinstance(signature_key, rsa.RSAPublicKey) + if self._inner_sig_type == _SSH_RSA: + hash_alg = hashes.SHA1() + elif self._inner_sig_type == _SSH_RSA_SHA256: + hash_alg = hashes.SHA256() + else: + assert self._inner_sig_type == _SSH_RSA_SHA512 + hash_alg = hashes.SHA512() + signature_key.verify( + bytes(self._signature), + bytes(self._tbs_cert_body), + padding.PKCS1v15(), + hash_alg, + ) + + +def _get_ec_hash_alg(curve: ec.EllipticCurve) -> hashes.HashAlgorithm: + if isinstance(curve, ec.SECP256R1): + return hashes.SHA256() + elif isinstance(curve, ec.SECP384R1): + return hashes.SHA384() + else: + assert isinstance(curve, ec.SECP521R1) + return hashes.SHA512() + + +def _load_ssh_public_identity( + data: utils.Buffer, + _legacy_dsa_allowed=False, +) -> SSHCertificate | SSHPublicKeyTypes: + utils._check_byteslike("data", data) + + m = _SSH_PUBKEY_RC.match(data) + if not m: + raise ValueError("Invalid line format") + key_type = orig_key_type = m.group(1) + key_body = m.group(2) + with_cert = False + if key_type.endswith(_CERT_SUFFIX): + with_cert = True + key_type = key_type[: -len(_CERT_SUFFIX)] + if key_type == _SSH_DSA and not _legacy_dsa_allowed: + raise UnsupportedAlgorithm( + "DSA keys aren't supported in SSH certificates" + ) + kformat = _lookup_kformat(key_type) + + try: + rest = memoryview(binascii.a2b_base64(key_body)) + except (TypeError, binascii.Error): + raise ValueError("Invalid format") + + if with_cert: + cert_body = rest + inner_key_type, rest = _get_sshstr(rest) + if inner_key_type != orig_key_type: + raise ValueError("Invalid key format") + if with_cert: + nonce, rest = _get_sshstr(rest) + public_key, rest = kformat.load_public(rest) + if with_cert: + serial, rest = _get_u64(rest) + cctype, rest = _get_u32(rest) + key_id, rest = _get_sshstr(rest) + principals, rest = _get_sshstr(rest) + valid_principals = [] + while principals: + principal, principals = _get_sshstr(principals) + valid_principals.append(bytes(principal)) + valid_after, rest = _get_u64(rest) + valid_before, rest = _get_u64(rest) + crit_options, rest = _get_sshstr(rest) + critical_options = _parse_exts_opts(crit_options) + exts, rest = _get_sshstr(rest) + extensions = _parse_exts_opts(exts) + # Get the reserved field, which is unused. + _, rest = _get_sshstr(rest) + sig_key_raw, rest = _get_sshstr(rest) + sig_type, sig_key = _get_sshstr(sig_key_raw) + if sig_type == _SSH_DSA and not _legacy_dsa_allowed: + raise UnsupportedAlgorithm( + "DSA signatures aren't supported in SSH certificates" + ) + # Get the entire cert body and subtract the signature + tbs_cert_body = cert_body[: -len(rest)] + signature_raw, rest = _get_sshstr(rest) + _check_empty(rest) + inner_sig_type, sig_rest = _get_sshstr(signature_raw) + # RSA certs can have multiple algorithm types + if ( + sig_type == _SSH_RSA + and inner_sig_type + not in [_SSH_RSA_SHA256, _SSH_RSA_SHA512, _SSH_RSA] + ) or (sig_type != _SSH_RSA and inner_sig_type != sig_type): + raise ValueError("Signature key type does not match") + signature, sig_rest = _get_sshstr(sig_rest) + _check_empty(sig_rest) + return SSHCertificate( + nonce, + public_key, + serial, + cctype, + key_id, + valid_principals, + valid_after, + valid_before, + critical_options, + extensions, + sig_type, + sig_key, + inner_sig_type, + signature, + tbs_cert_body, + orig_key_type, + cert_body, + ) + else: + _check_empty(rest) + return public_key + + +def load_ssh_public_identity( + data: utils.Buffer, +) -> SSHCertificate | SSHPublicKeyTypes: + return _load_ssh_public_identity(data) + + +def _parse_exts_opts(exts_opts: memoryview) -> dict[bytes, bytes]: + result: dict[bytes, bytes] = {} + last_name = None + while exts_opts: + name, exts_opts = _get_sshstr(exts_opts) + bname: bytes = bytes(name) + if bname in result: + raise ValueError("Duplicate name") + if last_name is not None and bname < last_name: + raise ValueError("Fields not lexically sorted") + value, exts_opts = _get_sshstr(exts_opts) + if len(value) > 0: + value, extra = _get_sshstr(value) + if len(extra) > 0: + raise ValueError("Unexpected extra data after value") + result[bname] = bytes(value) + last_name = bname + return result + + +def ssh_key_fingerprint( + key: SSHPublicKeyTypes, + hash_algorithm: hashes.MD5 | hashes.SHA1 | hashes.SHA256, +) -> bytes: + if not isinstance( + hash_algorithm, + (hashes.MD5, hashes.SHA1, hashes.SHA256), + ): + raise TypeError("hash_algorithm must be either MD5, SHA1, or SHA256") + + key_type = _get_ssh_key_type(key) + kformat = _lookup_kformat(key_type) + + f_pub = _FragList() + f_pub.put_sshstr(key_type) + kformat.encode_public(key, f_pub) + + ssh_binary_data = f_pub.tobytes() + + # Hash the binary data + hash_obj = hashes.Hash(hash_algorithm) + hash_obj.update(ssh_binary_data) + return hash_obj.finalize() + + +def load_ssh_public_key( + data: utils.Buffer, backend: typing.Any = None +) -> SSHPublicKeyTypes: + cert_or_key = _load_ssh_public_identity(data, _legacy_dsa_allowed=True) + public_key: SSHPublicKeyTypes + if isinstance(cert_or_key, SSHCertificate): + public_key = cert_or_key.public_key() + else: + public_key = cert_or_key + + if isinstance(public_key, dsa.DSAPublicKey): + warnings.warn( + "SSH DSA keys are deprecated and will be removed in a future " + "release.", + utils.DeprecatedIn40, + stacklevel=2, + ) + return public_key + + +def serialize_ssh_public_key(public_key: SSHPublicKeyTypes) -> bytes: + """One-line public key format for OpenSSH""" + if isinstance(public_key, dsa.DSAPublicKey): + warnings.warn( + "SSH DSA key support is deprecated and will be " + "removed in a future release", + utils.DeprecatedIn40, + stacklevel=4, + ) + key_type = _get_ssh_key_type(public_key) + kformat = _lookup_kformat(key_type) + + f_pub = _FragList() + f_pub.put_sshstr(key_type) + kformat.encode_public(public_key, f_pub) + + pub = binascii.b2a_base64(f_pub.tobytes()).strip() + return b"".join([key_type, b" ", pub]) + + +SSHCertPrivateKeyTypes = typing.Union[ + ec.EllipticCurvePrivateKey, + rsa.RSAPrivateKey, + ed25519.Ed25519PrivateKey, +] + + +# This is an undocumented limit enforced in the openssh codebase for sshd and +# ssh-keygen, but it is undefined in the ssh certificates spec. +_SSHKEY_CERT_MAX_PRINCIPALS = 256 + + +class SSHCertificateBuilder: + def __init__( + self, + _public_key: SSHCertPublicKeyTypes | None = None, + _serial: int | None = None, + _type: SSHCertificateType | None = None, + _key_id: bytes | None = None, + _valid_principals: list[bytes] = [], + _valid_for_all_principals: bool = False, + _valid_before: int | None = None, + _valid_after: int | None = None, + _critical_options: list[tuple[bytes, bytes]] = [], + _extensions: list[tuple[bytes, bytes]] = [], + ): + self._public_key = _public_key + self._serial = _serial + self._type = _type + self._key_id = _key_id + self._valid_principals = _valid_principals + self._valid_for_all_principals = _valid_for_all_principals + self._valid_before = _valid_before + self._valid_after = _valid_after + self._critical_options = _critical_options + self._extensions = _extensions + + def public_key( + self, public_key: SSHCertPublicKeyTypes + ) -> SSHCertificateBuilder: + if not isinstance( + public_key, + ( + ec.EllipticCurvePublicKey, + rsa.RSAPublicKey, + ed25519.Ed25519PublicKey, + ), + ): + raise TypeError("Unsupported key type") + if self._public_key is not None: + raise ValueError("public_key already set") + + return SSHCertificateBuilder( + _public_key=public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def serial(self, serial: int) -> SSHCertificateBuilder: + if not isinstance(serial, int): + raise TypeError("serial must be an integer") + if not 0 <= serial < 2**64: + raise ValueError("serial must be between 0 and 2**64") + if self._serial is not None: + raise ValueError("serial already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def type(self, type: SSHCertificateType) -> SSHCertificateBuilder: + if not isinstance(type, SSHCertificateType): + raise TypeError("type must be an SSHCertificateType") + if self._type is not None: + raise ValueError("type already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def key_id(self, key_id: bytes) -> SSHCertificateBuilder: + if not isinstance(key_id, bytes): + raise TypeError("key_id must be bytes") + if self._key_id is not None: + raise ValueError("key_id already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_principals( + self, valid_principals: list[bytes] + ) -> SSHCertificateBuilder: + if self._valid_for_all_principals: + raise ValueError( + "Principals can't be set because the cert is valid " + "for all principals" + ) + if ( + not all(isinstance(x, bytes) for x in valid_principals) + or not valid_principals + ): + raise TypeError( + "principals must be a list of bytes and can't be empty" + ) + if self._valid_principals: + raise ValueError("valid_principals already set") + + if len(valid_principals) > _SSHKEY_CERT_MAX_PRINCIPALS: + raise ValueError( + "Reached or exceeded the maximum number of valid_principals" + ) + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_for_all_principals(self): + if self._valid_principals: + raise ValueError( + "valid_principals already set, can't set " + "valid_for_all_principals" + ) + if self._valid_for_all_principals: + raise ValueError("valid_for_all_principals already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=True, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_before(self, valid_before: int | float) -> SSHCertificateBuilder: + if not isinstance(valid_before, (int, float)): + raise TypeError("valid_before must be an int or float") + valid_before = int(valid_before) + if valid_before < 0 or valid_before >= 2**64: + raise ValueError("valid_before must [0, 2**64)") + if self._valid_before is not None: + raise ValueError("valid_before already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def valid_after(self, valid_after: int | float) -> SSHCertificateBuilder: + if not isinstance(valid_after, (int, float)): + raise TypeError("valid_after must be an int or float") + valid_after = int(valid_after) + if valid_after < 0 or valid_after >= 2**64: + raise ValueError("valid_after must [0, 2**64)") + if self._valid_after is not None: + raise ValueError("valid_after already set") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=valid_after, + _critical_options=self._critical_options, + _extensions=self._extensions, + ) + + def add_critical_option( + self, name: bytes, value: bytes + ) -> SSHCertificateBuilder: + if not isinstance(name, bytes) or not isinstance(value, bytes): + raise TypeError("name and value must be bytes") + # This is O(n**2) + if name in [name for name, _ in self._critical_options]: + raise ValueError("Duplicate critical option name") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=[*self._critical_options, (name, value)], + _extensions=self._extensions, + ) + + def add_extension( + self, name: bytes, value: bytes + ) -> SSHCertificateBuilder: + if not isinstance(name, bytes) or not isinstance(value, bytes): + raise TypeError("name and value must be bytes") + # This is O(n**2) + if name in [name for name, _ in self._extensions]: + raise ValueError("Duplicate extension name") + + return SSHCertificateBuilder( + _public_key=self._public_key, + _serial=self._serial, + _type=self._type, + _key_id=self._key_id, + _valid_principals=self._valid_principals, + _valid_for_all_principals=self._valid_for_all_principals, + _valid_before=self._valid_before, + _valid_after=self._valid_after, + _critical_options=self._critical_options, + _extensions=[*self._extensions, (name, value)], + ) + + def sign(self, private_key: SSHCertPrivateKeyTypes) -> SSHCertificate: + if not isinstance( + private_key, + ( + ec.EllipticCurvePrivateKey, + rsa.RSAPrivateKey, + ed25519.Ed25519PrivateKey, + ), + ): + raise TypeError("Unsupported private key type") + + if self._public_key is None: + raise ValueError("public_key must be set") + + # Not required + serial = 0 if self._serial is None else self._serial + + if self._type is None: + raise ValueError("type must be set") + + # Not required + key_id = b"" if self._key_id is None else self._key_id + + # A zero length list is valid, but means the certificate + # is valid for any principal of the specified type. We require + # the user to explicitly set valid_for_all_principals to get + # that behavior. + if not self._valid_principals and not self._valid_for_all_principals: + raise ValueError( + "valid_principals must be set if valid_for_all_principals " + "is False" + ) + + if self._valid_before is None: + raise ValueError("valid_before must be set") + + if self._valid_after is None: + raise ValueError("valid_after must be set") + + if self._valid_after > self._valid_before: + raise ValueError("valid_after must be earlier than valid_before") + + # lexically sort our byte strings + self._critical_options.sort(key=lambda x: x[0]) + self._extensions.sort(key=lambda x: x[0]) + + key_type = _get_ssh_key_type(self._public_key) + cert_prefix = key_type + _CERT_SUFFIX + + # Marshal the bytes to be signed + nonce = os.urandom(32) + kformat = _lookup_kformat(key_type) + f = _FragList() + f.put_sshstr(cert_prefix) + f.put_sshstr(nonce) + kformat.encode_public(self._public_key, f) + f.put_u64(serial) + f.put_u32(self._type.value) + f.put_sshstr(key_id) + fprincipals = _FragList() + for p in self._valid_principals: + fprincipals.put_sshstr(p) + f.put_sshstr(fprincipals.tobytes()) + f.put_u64(self._valid_after) + f.put_u64(self._valid_before) + fcrit = _FragList() + for name, value in self._critical_options: + fcrit.put_sshstr(name) + if len(value) > 0: + foptval = _FragList() + foptval.put_sshstr(value) + fcrit.put_sshstr(foptval.tobytes()) + else: + fcrit.put_sshstr(value) + f.put_sshstr(fcrit.tobytes()) + fext = _FragList() + for name, value in self._extensions: + fext.put_sshstr(name) + if len(value) > 0: + fextval = _FragList() + fextval.put_sshstr(value) + fext.put_sshstr(fextval.tobytes()) + else: + fext.put_sshstr(value) + f.put_sshstr(fext.tobytes()) + f.put_sshstr(b"") # RESERVED FIELD + # encode CA public key + ca_type = _get_ssh_key_type(private_key) + caformat = _lookup_kformat(ca_type) + caf = _FragList() + caf.put_sshstr(ca_type) + caformat.encode_public(private_key.public_key(), caf) + f.put_sshstr(caf.tobytes()) + # Sigs according to the rules defined for the CA's public key + # (RFC4253 section 6.6 for ssh-rsa, RFC5656 for ECDSA, + # and RFC8032 for Ed25519). + if isinstance(private_key, ed25519.Ed25519PrivateKey): + signature = private_key.sign(f.tobytes()) + fsig = _FragList() + fsig.put_sshstr(ca_type) + fsig.put_sshstr(signature) + f.put_sshstr(fsig.tobytes()) + elif isinstance(private_key, ec.EllipticCurvePrivateKey): + hash_alg = _get_ec_hash_alg(private_key.curve) + signature = private_key.sign(f.tobytes(), ec.ECDSA(hash_alg)) + r, s = asym_utils.decode_dss_signature(signature) + fsig = _FragList() + fsig.put_sshstr(ca_type) + fsigblob = _FragList() + fsigblob.put_mpint(r) + fsigblob.put_mpint(s) + fsig.put_sshstr(fsigblob.tobytes()) + f.put_sshstr(fsig.tobytes()) + + else: + assert isinstance(private_key, rsa.RSAPrivateKey) + # Just like Golang, we're going to use SHA512 for RSA + # https://cs.opensource.google/go/x/crypto/+/refs/tags/ + # v0.4.0:ssh/certs.go;l=445 + # RFC 8332 defines SHA256 and 512 as options + fsig = _FragList() + fsig.put_sshstr(_SSH_RSA_SHA512) + signature = private_key.sign( + f.tobytes(), padding.PKCS1v15(), hashes.SHA512() + ) + fsig.put_sshstr(signature) + f.put_sshstr(fsig.tobytes()) + + cert_data = binascii.b2a_base64(f.tobytes()).strip() + # load_ssh_public_identity returns a union, but this is + # guaranteed to be an SSHCertificate, so we cast to make + # mypy happy. + return typing.cast( + SSHCertificate, + load_ssh_public_identity(b"".join([cert_prefix, b" ", cert_data])), + ) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/__init__.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/__init__.py new file mode 100644 index 0000000..c1af423 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/__init__.py @@ -0,0 +1,9 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + + +class InvalidToken(Exception): + pass diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/hotp.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/hotp.py new file mode 100644 index 0000000..21fb000 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/hotp.py @@ -0,0 +1,101 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import base64 +import typing +from urllib.parse import quote, urlencode + +from cryptography.hazmat.primitives import constant_time, hmac +from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 +from cryptography.hazmat.primitives.twofactor import InvalidToken +from cryptography.utils import Buffer + +HOTPHashTypes = typing.Union[SHA1, SHA256, SHA512] + + +def _generate_uri( + hotp: HOTP, + type_name: str, + account_name: str, + issuer: str | None, + extra_parameters: list[tuple[str, int]], +) -> str: + parameters = [ + ("digits", hotp._length), + ("secret", base64.b32encode(hotp._key)), + ("algorithm", hotp._algorithm.name.upper()), + ] + + if issuer is not None: + parameters.append(("issuer", issuer)) + + parameters.extend(extra_parameters) + + label = ( + f"{quote(issuer)}:{quote(account_name)}" + if issuer + else quote(account_name) + ) + return f"otpauth://{type_name}/{label}?{urlencode(parameters)}" + + +class HOTP: + def __init__( + self, + key: Buffer, + length: int, + algorithm: HOTPHashTypes, + backend: typing.Any = None, + enforce_key_length: bool = True, + ) -> None: + if len(key) < 16 and enforce_key_length is True: + raise ValueError("Key length has to be at least 128 bits.") + + if not isinstance(length, int): + raise TypeError("Length parameter must be an integer type.") + + if length < 6 or length > 8: + raise ValueError("Length of HOTP has to be between 6 and 8.") + + if not isinstance(algorithm, (SHA1, SHA256, SHA512)): + raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.") + + self._key = key + self._length = length + self._algorithm = algorithm + + def generate(self, counter: int) -> bytes: + if not isinstance(counter, int): + raise TypeError("Counter parameter must be an integer type.") + + truncated_value = self._dynamic_truncate(counter) + hotp = truncated_value % (10**self._length) + return "{0:0{1}}".format(hotp, self._length).encode() + + def verify(self, hotp: bytes, counter: int) -> None: + if not constant_time.bytes_eq(self.generate(counter), hotp): + raise InvalidToken("Supplied HOTP value does not match.") + + def _dynamic_truncate(self, counter: int) -> int: + ctx = hmac.HMAC(self._key, self._algorithm) + + try: + ctx.update(counter.to_bytes(length=8, byteorder="big")) + except OverflowError: + raise ValueError(f"Counter must be between 0 and {2**64 - 1}.") + + hmac_value = ctx.finalize() + + offset = hmac_value[len(hmac_value) - 1] & 0b1111 + p = hmac_value[offset : offset + 4] + return int.from_bytes(p, byteorder="big") & 0x7FFFFFFF + + def get_provisioning_uri( + self, account_name: str, counter: int, issuer: str | None + ) -> str: + return _generate_uri( + self, "hotp", account_name, issuer, [("counter", int(counter))] + ) diff --git a/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/totp.py b/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/totp.py new file mode 100644 index 0000000..10c725c --- /dev/null +++ b/source/target-vendors/cp312/cryptography/hazmat/primitives/twofactor/totp.py @@ -0,0 +1,56 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import typing + +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.twofactor import InvalidToken +from cryptography.hazmat.primitives.twofactor.hotp import ( + HOTP, + HOTPHashTypes, + _generate_uri, +) +from cryptography.utils import Buffer + + +class TOTP: + def __init__( + self, + key: Buffer, + length: int, + algorithm: HOTPHashTypes, + time_step: int, + backend: typing.Any = None, + enforce_key_length: bool = True, + ): + self._time_step = time_step + self._hotp = HOTP( + key, length, algorithm, enforce_key_length=enforce_key_length + ) + + def generate(self, time: int | float) -> bytes: + if not isinstance(time, (int, float)): + raise TypeError( + "Time parameter must be an integer type or float type." + ) + + counter = int(time / self._time_step) + return self._hotp.generate(counter) + + def verify(self, totp: bytes, time: int) -> None: + if not constant_time.bytes_eq(self.generate(time), totp): + raise InvalidToken("Supplied TOTP value does not match.") + + def get_provisioning_uri( + self, account_name: str, issuer: str | None + ) -> str: + return _generate_uri( + self._hotp, + "totp", + account_name, + issuer, + [("period", int(self._time_step))], + ) diff --git a/source/target-vendors/cp312/cryptography/py.typed b/source/target-vendors/cp312/cryptography/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/cryptography/utils.py b/source/target-vendors/cp312/cryptography/utils.py new file mode 100644 index 0000000..90bd42d --- /dev/null +++ b/source/target-vendors/cp312/cryptography/utils.py @@ -0,0 +1,136 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import enum +import sys +import types +import typing +import warnings +from collections.abc import Sequence + + +# We use a UserWarning subclass, instead of DeprecationWarning, because CPython +# decided deprecation warnings should be invisible by default. +class CryptographyDeprecationWarning(UserWarning): + pass + + +# Several APIs were deprecated with no specific end-of-life date because of the +# ubiquity of their use. They should not be removed until we agree on when that +# cycle ends. +DeprecatedIn36 = CryptographyDeprecationWarning +DeprecatedIn40 = CryptographyDeprecationWarning +DeprecatedIn41 = CryptographyDeprecationWarning +DeprecatedIn42 = CryptographyDeprecationWarning +DeprecatedIn43 = CryptographyDeprecationWarning +DeprecatedIn47 = CryptographyDeprecationWarning +DeprecatedIn50 = CryptographyDeprecationWarning + + +# If you're wondering why we don't use `Buffer`, it's because `Buffer` would +# be more accurately named: Bufferable. It means something which has an +# `__buffer__`. Which means you can't actually treat the result as a buffer +# (and do things like take a `len()`). +Buffer = typing.Union[bytes, bytearray, memoryview] + + +def _check_bytes(name: str, value: bytes) -> None: + if not isinstance(value, bytes): + raise TypeError(f"{name} must be bytes") + + +def _check_byteslike(name: str, value: Buffer) -> None: + if isinstance(value, (bytes, bytearray, memoryview)): + return + try: + memoryview(value) + except TypeError: + raise TypeError(f"{name} must be bytes-like") + + +def int_to_bytes(integer: int, length: int | None = None) -> bytes: + if length == 0: + raise ValueError("length argument can't be 0") + return integer.to_bytes( + length or (integer.bit_length() + 7) // 8 or 1, "big" + ) + + +class InterfaceNotImplemented(Exception): + pass + + +class _DeprecatedValue: + def __init__(self, value: object, message: str, warning_class): + self.value = value + self.message = message + self.warning_class = warning_class + + +class _ModuleWithDeprecations(types.ModuleType): + def __init__(self, module: types.ModuleType): + super().__init__(module.__name__) + self.__dict__["_module"] = module + + def __getattr__(self, name: str) -> typing.Any: + obj = getattr(self._module, name) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + obj = obj.value + else: + # Cache non-deprecated attributes in our own `__dict__` so that + # subsequent lookups are ordinary module attribute accesses and + # don't pay for this `__getattr__` (which would otherwise defeat + # CPython's LOAD_ATTR module caching for every attribute of the + # module). `__setattr__` and `__delattr__` keep the cache + # coherent. + self.__dict__[name] = obj + return obj + + def __setattr__(self, attr: str, value: object) -> None: + if isinstance(value, _DeprecatedValue): + self.__dict__.pop(attr, None) + else: + self.__dict__[attr] = value + setattr(self._module, attr, value) + + def __delattr__(self, attr: str) -> None: + obj = getattr(self._module, attr) + if isinstance(obj, _DeprecatedValue): + warnings.warn(obj.message, obj.warning_class, stacklevel=2) + + self.__dict__.pop(attr, None) + delattr(self._module, attr) + + def __dir__(self) -> Sequence[str]: + return ["_module", *dir(self._module)] + + +def deprecated( + value: object, + module_name: str, + message: str, + warning_class: type[Warning], + name: str | None = None, +) -> _DeprecatedValue: + module = sys.modules[module_name] + if not isinstance(module, _ModuleWithDeprecations): + sys.modules[module_name] = module = _ModuleWithDeprecations(module) + dv = _DeprecatedValue(value, message, warning_class) + # Maintain backwards compatibility with `name is None` for pyOpenSSL. + if name is not None: + setattr(module, name, dv) + return dv + + +# Python 3.10 changed representation of enums. We use well-defined object +# representation and string representation from Python 3.9. +class Enum(enum.Enum): + def __repr__(self) -> str: + return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" + + def __str__(self) -> str: + return f"{self.__class__.__name__}.{self._name_}" diff --git a/source/target-vendors/cp312/cryptography/x509/__init__.py b/source/target-vendors/cp312/cryptography/x509/__init__.py new file mode 100644 index 0000000..6442b00 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/__init__.py @@ -0,0 +1,270 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.x509 import certificate_transparency, oid, verification +from cryptography.x509.base import ( + Attribute, + AttributeNotFound, + Attributes, + Certificate, + CertificateBuilder, + CertificateRevocationList, + CertificateRevocationListBuilder, + CertificateSigningRequest, + CertificateSigningRequestBuilder, + InvalidVersion, + RevokedCertificate, + RevokedCertificateBuilder, + Version, + load_der_x509_certificate, + load_der_x509_crl, + load_der_x509_csr, + load_pem_x509_certificate, + load_pem_x509_certificates, + load_pem_x509_crl, + load_pem_x509_csr, + random_serial_number, +) +from cryptography.x509.extensions import ( + AccessDescription, + Admission, + Admissions, + AuthorityInformationAccess, + AuthorityKeyIdentifier, + BasicConstraints, + CertificateIssuer, + CertificatePolicies, + CRLDistributionPoints, + CRLNumber, + CRLReason, + DeltaCRLIndicator, + DistributionPoint, + DuplicateExtension, + ExtendedKeyUsage, + Extension, + ExtensionNotFound, + Extensions, + ExtensionType, + FreshestCRL, + GeneralNames, + InhibitAnyPolicy, + InvalidityDate, + IssuerAlternativeName, + IssuingDistributionPoint, + KeyUsage, + MSCertificateTemplate, + NameConstraints, + NamingAuthority, + NoticeReference, + OCSPAcceptableResponses, + OCSPNoCheck, + OCSPNonce, + PolicyConstraints, + PolicyInformation, + PrecertificateSignedCertificateTimestamps, + PrecertPoison, + PrivateKeyUsagePeriod, + ProfessionInfo, + ReasonFlags, + SignedCertificateTimestamps, + SubjectAlternativeName, + SubjectInformationAccess, + SubjectKeyIdentifier, + TLSFeature, + TLSFeatureType, + UnrecognizedExtension, + UserNotice, +) +from cryptography.x509.general_name import ( + DirectoryName, + DNSName, + GeneralName, + IPAddress, + OtherName, + RegisteredID, + RFC822Name, + UniformResourceIdentifier, + UnsupportedGeneralNameType, +) +from cryptography.x509.name import ( + Name, + NameAttribute, + RelativeDistinguishedName, +) +from cryptography.x509.oid import ( + AuthorityInformationAccessOID, + CertificatePoliciesOID, + CRLEntryExtensionOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + ObjectIdentifier, + PublicKeyAlgorithmOID, + SignatureAlgorithmOID, +) + +OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS +OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER +OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS +OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES +OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS +OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE +OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL +OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY +OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME +OID_KEY_USAGE = ExtensionOID.KEY_USAGE +OID_PRIVATE_KEY_USAGE_PERIOD = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD +OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS +OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK +OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS +OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS +OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME +OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES +OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS +OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER + +OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1 +OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224 +OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256 +OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1 +OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224 +OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256 +OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384 +OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512 +OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5 +OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1 +OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224 +OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256 +OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384 +OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512 +OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS + +OID_COMMON_NAME = NameOID.COMMON_NAME +OID_COUNTRY_NAME = NameOID.COUNTRY_NAME +OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT +OID_DN_QUALIFIER = NameOID.DN_QUALIFIER +OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS +OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER +OID_GIVEN_NAME = NameOID.GIVEN_NAME +OID_LOCALITY_NAME = NameOID.LOCALITY_NAME +OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME +OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME +OID_PSEUDONYM = NameOID.PSEUDONYM +OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER +OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME +OID_SURNAME = NameOID.SURNAME +OID_TITLE = NameOID.TITLE + +OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH +OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING +OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION +OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING +OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH +OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING + +OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY +OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER +OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE + +OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER +OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON +OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE + +OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS +OID_OCSP = AuthorityInformationAccessOID.OCSP + +__all__ = [ + "OID_CA_ISSUERS", + "OID_OCSP", + "AccessDescription", + "Admission", + "Admissions", + "Attribute", + "AttributeNotFound", + "Attributes", + "AuthorityInformationAccess", + "AuthorityKeyIdentifier", + "BasicConstraints", + "CRLDistributionPoints", + "CRLNumber", + "CRLReason", + "Certificate", + "CertificateBuilder", + "CertificateIssuer", + "CertificatePolicies", + "CertificateRevocationList", + "CertificateRevocationListBuilder", + "CertificateSigningRequest", + "CertificateSigningRequestBuilder", + "DNSName", + "DeltaCRLIndicator", + "DirectoryName", + "DistributionPoint", + "DuplicateExtension", + "ExtendedKeyUsage", + "Extension", + "ExtensionNotFound", + "ExtensionType", + "Extensions", + "FreshestCRL", + "GeneralName", + "GeneralNames", + "IPAddress", + "InhibitAnyPolicy", + "InvalidVersion", + "InvalidityDate", + "IssuerAlternativeName", + "IssuingDistributionPoint", + "KeyUsage", + "MSCertificateTemplate", + "Name", + "NameAttribute", + "NameConstraints", + "NameOID", + "NamingAuthority", + "NoticeReference", + "OCSPAcceptableResponses", + "OCSPNoCheck", + "OCSPNonce", + "ObjectIdentifier", + "OtherName", + "PolicyConstraints", + "PolicyInformation", + "PrecertPoison", + "PrecertificateSignedCertificateTimestamps", + "PrivateKeyUsagePeriod", + "ProfessionInfo", + "PublicKeyAlgorithmOID", + "RFC822Name", + "ReasonFlags", + "RegisteredID", + "RelativeDistinguishedName", + "RevokedCertificate", + "RevokedCertificateBuilder", + "SignatureAlgorithmOID", + "SignedCertificateTimestamps", + "SubjectAlternativeName", + "SubjectInformationAccess", + "SubjectKeyIdentifier", + "TLSFeature", + "TLSFeatureType", + "UniformResourceIdentifier", + "UnrecognizedExtension", + "UnsupportedGeneralNameType", + "UserNotice", + "Version", + "certificate_transparency", + "load_der_x509_certificate", + "load_der_x509_crl", + "load_der_x509_csr", + "load_pem_x509_certificate", + "load_pem_x509_certificates", + "load_pem_x509_crl", + "load_pem_x509_csr", + "oid", + "random_serial_number", + "verification", +] diff --git a/source/target-vendors/cp312/cryptography/x509/base.py b/source/target-vendors/cp312/cryptography/x509/base.py new file mode 100644 index 0000000..3ded5dc --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/base.py @@ -0,0 +1,834 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import datetime +import os +import typing +from collections.abc import Iterable + +from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed448, + ed25519, + mldsa, + mlkem, + padding, + rsa, + x448, + x25519, +) +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPrivateKeyTypes, + CertificatePublicKeyTypes, +) +from cryptography.x509.extensions import ( + Extension, + ExtensionType, + _make_sequence_methods, +) +from cryptography.x509.name import Name, _ASN1Type +from cryptography.x509.oid import ObjectIdentifier + +_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) + +# This must be kept in sync with sign.rs's list of allowable types in +# identify_hash_type +_AllowedHashTypes = typing.Union[ + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, +] + + +class AttributeNotFound(Exception): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: + super().__init__(msg) + self.oid = oid + + +def _reject_duplicate_extension( + extension: Extension[ExtensionType], + extensions: list[Extension[ExtensionType]], +) -> None: + # This is quadratic in the number of extensions + for e in extensions: + if e.oid == extension.oid: + raise ValueError("This extension has already been set.") + + +def _reject_duplicate_attribute( + oid: ObjectIdentifier, + attributes: list[tuple[ObjectIdentifier, bytes, int | None]], +) -> None: + # This is quadratic in the number of attributes + for attr_oid, _, _ in attributes: + if attr_oid == oid: + raise ValueError("This attribute has already been set.") + + +def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: + """Normalizes a datetime to a naive datetime in UTC. + + time -- datetime to normalize. Assumed to be in UTC if not timezone + aware. + """ + if time.tzinfo is not None: + offset = time.utcoffset() + offset = offset if offset else datetime.timedelta() + return time.replace(tzinfo=None) - offset + else: + return time + + +class Attribute: + def __init__( + self, + oid: ObjectIdentifier, + value: bytes, + _type: int = _ASN1Type.UTF8String.value, + ) -> None: + self._oid = oid + self._value = value + self._type = _type + + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def value(self) -> bytes: + return self._value + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Attribute): + return NotImplemented + + return ( + self.oid == other.oid + and self.value == other.value + and self._type == other._type + ) + + def __hash__(self) -> int: + return hash((self.oid, self.value, self._type)) + + +class Attributes: + def __init__( + self, + attributes: Iterable[Attribute], + ) -> None: + self._attributes = list(attributes) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes") + + def __repr__(self) -> str: + return f"" + + def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute: + for attr in self: + if attr.oid == oid: + return attr + + raise AttributeNotFound(f"No {oid} attribute was found", oid) + + +class Version(utils.Enum): + v1 = 0 + v3 = 2 + + +class InvalidVersion(Exception): + def __init__(self, msg: str, parsed_version: int) -> None: + super().__init__(msg) + self.parsed_version = parsed_version + + +Certificate = rust_x509.Certificate +RevokedCertificate = rust_x509.RevokedCertificate + + +CertificateRevocationList = rust_x509.CertificateRevocationList +CertificateSigningRequest = rust_x509.CertificateSigningRequest + + +load_pem_x509_certificate = rust_x509.load_pem_x509_certificate +load_der_x509_certificate = rust_x509.load_der_x509_certificate + +load_pem_x509_certificates = rust_x509.load_pem_x509_certificates + +load_pem_x509_csr = rust_x509.load_pem_x509_csr +load_der_x509_csr = rust_x509.load_der_x509_csr + +load_pem_x509_crl = rust_x509.load_pem_x509_crl +load_der_x509_crl = rust_x509.load_der_x509_crl + + +class CertificateSigningRequestBuilder: + def __init__( + self, + subject_name: Name | None = None, + extensions: list[Extension[ExtensionType]] = [], + attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [], + ): + """ + Creates an empty X.509 certificate request (v1). + """ + self._subject_name = subject_name + self._extensions = extensions + self._attributes = attributes + + def subject_name(self, name: Name) -> CertificateSigningRequestBuilder: + """ + Sets the certificate requestor's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError("Expecting x509.Name object.") + if self._subject_name is not None: + raise ValueError("The subject name may only be set once.") + return CertificateSigningRequestBuilder( + name, self._extensions, self._attributes + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> CertificateSigningRequestBuilder: + """ + Adds an X.509 extension to the certificate request. + """ + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return CertificateSigningRequestBuilder( + self._subject_name, + [*self._extensions, extension], + self._attributes, + ) + + def add_attribute( + self, + oid: ObjectIdentifier, + value: bytes, + *, + _tag: _ASN1Type | None = None, + ) -> CertificateSigningRequestBuilder: + """ + Adds an X.509 attribute with an OID and associated value. + """ + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + + if not isinstance(value, bytes): + raise TypeError("value must be bytes") + + if _tag is not None and not isinstance(_tag, _ASN1Type): + raise TypeError("tag must be _ASN1Type") + + _reject_duplicate_attribute(oid, self._attributes) + + if _tag is not None: + tag = _tag.value + else: + tag = None + + return CertificateSigningRequestBuilder( + self._subject_name, + self._extensions, + [*self._attributes, (oid, value, tag)], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: _AllowedHashTypes | None, + backend: typing.Any = None, + *, + rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ecdsa_deterministic: bool | None = None, + ) -> CertificateSigningRequest: + """ + Signs the request using the requestor's private key. + """ + if self._subject_name is None: + raise ValueError("A CertificateSigningRequest must have a subject") + + if rsa_padding is not None: + if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): + raise TypeError("Padding must be PSS or PKCS1v15") + if not isinstance(private_key, rsa.RSAPrivateKey): + raise TypeError("Padding is only supported for RSA keys") + + if ecdsa_deterministic is not None: + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise TypeError( + "Deterministic ECDSA is only supported for EC keys" + ) + + return rust_x509.create_x509_csr( + self, + private_key, + algorithm, + rsa_padding, + ecdsa_deterministic, + ) + + +class CertificateBuilder: + _extensions: list[Extension[ExtensionType]] + + def __init__( + self, + issuer_name: Name | None = None, + subject_name: Name | None = None, + public_key: CertificatePublicKeyTypes | None = None, + serial_number: int | None = None, + not_valid_before: datetime.datetime | None = None, + not_valid_after: datetime.datetime | None = None, + extensions: list[Extension[ExtensionType]] = [], + public_key_rsa_padding: type[padding.PSS] | None = None, + ) -> None: + self._version = Version.v3 + self._issuer_name = issuer_name + self._subject_name = subject_name + self._public_key = public_key + self._serial_number = serial_number + self._not_valid_before = not_valid_before + self._not_valid_after = not_valid_after + self._extensions = extensions + self._public_key_rsa_padding = public_key_rsa_padding + + def issuer_name(self, name: Name) -> CertificateBuilder: + """ + Sets the CA's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError("Expecting x509.Name object.") + if self._issuer_name is not None: + raise ValueError("The issuer name may only be set once.") + return CertificateBuilder( + name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + self._public_key_rsa_padding, + ) + + def subject_name(self, name: Name) -> CertificateBuilder: + """ + Sets the requestor's distinguished name. + """ + if not isinstance(name, Name): + raise TypeError("Expecting x509.Name object.") + if self._subject_name is not None: + raise ValueError("The subject name may only be set once.") + return CertificateBuilder( + self._issuer_name, + name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + self._public_key_rsa_padding, + ) + + def public_key( + self, + key: CertificatePublicKeyTypes, + *, + rsa_padding: type[padding.PSS] | None = None, + ) -> CertificateBuilder: + """ + Sets the requestor's public key (as found in the signing request). + """ + if not isinstance( + key, + ( + dsa.DSAPublicKey, + rsa.RSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + mldsa.MLDSA44PublicKey, + mldsa.MLDSA65PublicKey, + mldsa.MLDSA87PublicKey, + mlkem.MLKEM768PublicKey, + mlkem.MLKEM1024PublicKey, + x25519.X25519PublicKey, + x448.X448PublicKey, + ), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " EllipticCurvePublicKey, Ed25519PublicKey," + " Ed448PublicKey, MLDSA44PublicKey, MLDSA65PublicKey," + " MLDSA87PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey," + " X25519PublicKey or X448PublicKey." + ) + if rsa_padding is not None: + if rsa_padding is not padding.PSS: + raise TypeError( + "rsa_padding must be the PSS class, not an instance" + ) + if not isinstance(key, rsa.RSAPublicKey): + raise TypeError( + "rsa_padding is only supported with RSA public keys" + ) + if self._public_key is not None: + raise ValueError("The public key may only be set once.") + return CertificateBuilder( + self._issuer_name, + self._subject_name, + key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + rsa_padding, + ) + + def serial_number(self, number: int) -> CertificateBuilder: + """ + Sets the certificate serial number. + """ + if not isinstance(number, int): + raise TypeError("Serial number must be of integral type.") + if self._serial_number is not None: + raise ValueError("The serial number may only be set once.") + if number <= 0: + raise ValueError("The serial number should be positive.") + + # ASN.1 integers are always signed, so most significant bit must be + # zero. + if number.bit_length() >= 160: # As defined in RFC 5280 + raise ValueError( + "The serial number should not be more than 159 bits." + ) + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + number, + self._not_valid_before, + self._not_valid_after, + self._extensions, + self._public_key_rsa_padding, + ) + + def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder: + """ + Sets the certificate activation time. + """ + if not isinstance(time, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._not_valid_before is not None: + raise ValueError("The not valid before may only be set once.") + time = _convert_to_naive_utc_time(time) + if time < _EARLIEST_UTC_TIME: + raise ValueError( + "The not valid before date must be on or after" + " 1950 January 1)." + ) + if self._not_valid_after is not None and time > self._not_valid_after: + raise ValueError( + "The not valid before date must be before the not valid after " + "date." + ) + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + time, + self._not_valid_after, + self._extensions, + self._public_key_rsa_padding, + ) + + def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder: + """ + Sets the certificate expiration time. + """ + if not isinstance(time, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._not_valid_after is not None: + raise ValueError("The not valid after may only be set once.") + time = _convert_to_naive_utc_time(time) + if time < _EARLIEST_UTC_TIME: + raise ValueError( + "The not valid after date must be on or after 1950 January 1." + ) + if ( + self._not_valid_before is not None + and time < self._not_valid_before + ): + raise ValueError( + "The not valid after date must be after the not valid before " + "date." + ) + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + time, + self._extensions, + self._public_key_rsa_padding, + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> CertificateBuilder: + """ + Adds an X.509 extension to the certificate. + """ + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return CertificateBuilder( + self._issuer_name, + self._subject_name, + self._public_key, + self._serial_number, + self._not_valid_before, + self._not_valid_after, + [*self._extensions, extension], + self._public_key_rsa_padding, + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: _AllowedHashTypes | None, + backend: typing.Any = None, + *, + rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ecdsa_deterministic: bool | None = None, + ) -> Certificate: + """ + Signs the certificate using the CA's private key. + """ + if self._subject_name is None: + raise ValueError("A certificate must have a subject name") + + if self._issuer_name is None: + raise ValueError("A certificate must have an issuer name") + + if self._serial_number is None: + raise ValueError("A certificate must have a serial number") + + if self._not_valid_before is None: + raise ValueError("A certificate must have a not valid before time") + + if self._not_valid_after is None: + raise ValueError("A certificate must have a not valid after time") + + if self._public_key is None: + raise ValueError("A certificate must have a public key") + + if private_key is None: + raise TypeError("Need private key to sign certificate") + + if rsa_padding is not None: + if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): + raise TypeError("Padding must be PSS or PKCS1v15") + if not isinstance(private_key, rsa.RSAPrivateKey): + raise TypeError("Padding is only supported for RSA keys") + + if ecdsa_deterministic is not None: + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise TypeError( + "Deterministic ECDSA is only supported for EC keys" + ) + + return rust_x509.create_x509_certificate( + self, + private_key, + algorithm, + rsa_padding, + ecdsa_deterministic, + ) + + def create_unsigned(self) -> Certificate: + """ + Creates an unsigned certificate, per RFC 9925. + """ + if self._subject_name is None: + raise ValueError("A certificate must have a subject name") + + if self._issuer_name is None: + raise ValueError("A certificate must have an issuer name") + + if self._serial_number is None: + raise ValueError("A certificate must have a serial number") + + if self._not_valid_before is None: + raise ValueError("A certificate must have a not valid before time") + + if self._not_valid_after is None: + raise ValueError("A certificate must have a not valid after time") + + if self._public_key is None: + raise ValueError("A certificate must have a public key") + + return rust_x509.create_x509_certificate( + self, + private_key=None, + hash_algorithm=None, + rsa_padding=None, + ecdsa_deterministic=None, + ) + + +class CertificateRevocationListBuilder: + _extensions: list[Extension[ExtensionType]] + _revoked_certificates: list[RevokedCertificate] + + def __init__( + self, + issuer_name: Name | None = None, + last_update: datetime.datetime | None = None, + next_update: datetime.datetime | None = None, + extensions: list[Extension[ExtensionType]] = [], + revoked_certificates: list[RevokedCertificate] = [], + ): + self._issuer_name = issuer_name + self._last_update = last_update + self._next_update = next_update + self._extensions = extensions + self._revoked_certificates = revoked_certificates + + def issuer_name( + self, issuer_name: Name + ) -> CertificateRevocationListBuilder: + if not isinstance(issuer_name, Name): + raise TypeError("Expecting x509.Name object.") + if self._issuer_name is not None: + raise ValueError("The issuer name may only be set once.") + return CertificateRevocationListBuilder( + issuer_name, + self._last_update, + self._next_update, + self._extensions, + self._revoked_certificates, + ) + + def last_update( + self, last_update: datetime.datetime + ) -> CertificateRevocationListBuilder: + if not isinstance(last_update, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._last_update is not None: + raise ValueError("Last update may only be set once.") + last_update = _convert_to_naive_utc_time(last_update) + if last_update < _EARLIEST_UTC_TIME: + raise ValueError( + "The last update date must be on or after 1950 January 1." + ) + if self._next_update is not None and last_update > self._next_update: + raise ValueError( + "The last update date must be before the next update date." + ) + return CertificateRevocationListBuilder( + self._issuer_name, + last_update, + self._next_update, + self._extensions, + self._revoked_certificates, + ) + + def next_update( + self, next_update: datetime.datetime + ) -> CertificateRevocationListBuilder: + if not isinstance(next_update, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._next_update is not None: + raise ValueError("Last update may only be set once.") + next_update = _convert_to_naive_utc_time(next_update) + if next_update < _EARLIEST_UTC_TIME: + raise ValueError( + "The last update date must be on or after 1950 January 1." + ) + if self._last_update is not None and next_update < self._last_update: + raise ValueError( + "The next update date must be after the last update date." + ) + return CertificateRevocationListBuilder( + self._issuer_name, + self._last_update, + next_update, + self._extensions, + self._revoked_certificates, + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> CertificateRevocationListBuilder: + """ + Adds an X.509 extension to the certificate revocation list. + """ + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + return CertificateRevocationListBuilder( + self._issuer_name, + self._last_update, + self._next_update, + [*self._extensions, extension], + self._revoked_certificates, + ) + + def add_revoked_certificate( + self, revoked_certificate: RevokedCertificate + ) -> CertificateRevocationListBuilder: + """ + Adds a revoked certificate to the CRL. + """ + if not isinstance(revoked_certificate, RevokedCertificate): + raise TypeError("Must be an instance of RevokedCertificate") + + return CertificateRevocationListBuilder( + self._issuer_name, + self._last_update, + self._next_update, + self._extensions, + [*self._revoked_certificates, revoked_certificate], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: _AllowedHashTypes | None, + backend: typing.Any = None, + *, + rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ecdsa_deterministic: bool | None = None, + ) -> CertificateRevocationList: + if self._issuer_name is None: + raise ValueError("A CRL must have an issuer name") + + if self._last_update is None: + raise ValueError("A CRL must have a last update time") + + if self._next_update is None: + raise ValueError("A CRL must have a next update time") + + if rsa_padding is not None: + if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): + raise TypeError("Padding must be PSS or PKCS1v15") + if not isinstance(private_key, rsa.RSAPrivateKey): + raise TypeError("Padding is only supported for RSA keys") + + if ecdsa_deterministic is not None: + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise TypeError( + "Deterministic ECDSA is only supported for EC keys" + ) + + return rust_x509.create_x509_crl( + self, + private_key, + algorithm, + rsa_padding, + ecdsa_deterministic, + ) + + +class RevokedCertificateBuilder: + def __init__( + self, + serial_number: int | None = None, + revocation_date: datetime.datetime | None = None, + extensions: list[Extension[ExtensionType]] = [], + ): + self._serial_number = serial_number + self._revocation_date = revocation_date + self._extensions = extensions + + def serial_number(self, number: int) -> RevokedCertificateBuilder: + if not isinstance(number, int): + raise TypeError("Serial number must be of integral type.") + if self._serial_number is not None: + raise ValueError("The serial number may only be set once.") + if number <= 0: + raise ValueError("The serial number should be positive") + + # ASN.1 integers are always signed, so most significant bit must be + # zero. + if number.bit_length() >= 160: # As defined in RFC 5280 + raise ValueError( + "The serial number should not be more than 159 bits." + ) + return RevokedCertificateBuilder( + number, self._revocation_date, self._extensions + ) + + def revocation_date( + self, time: datetime.datetime + ) -> RevokedCertificateBuilder: + if not isinstance(time, datetime.datetime): + raise TypeError("Expecting datetime object.") + if self._revocation_date is not None: + raise ValueError("The revocation date may only be set once.") + time = _convert_to_naive_utc_time(time) + if time < _EARLIEST_UTC_TIME: + raise ValueError( + "The revocation date must be on or after 1950 January 1." + ) + return RevokedCertificateBuilder( + self._serial_number, time, self._extensions + ) + + def add_extension( + self, extval: ExtensionType, critical: bool + ) -> RevokedCertificateBuilder: + if not isinstance(extval, ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + return RevokedCertificateBuilder( + self._serial_number, + self._revocation_date, + [*self._extensions, extension], + ) + + def build(self, backend: typing.Any = None) -> RevokedCertificate: + if self._serial_number is None: + raise ValueError("A revoked certificate must have a serial number") + if self._revocation_date is None: + raise ValueError( + "A revoked certificate must have a revocation date" + ) + return rust_x509.create_revoked_certificate(self) + + +def random_serial_number() -> int: + return int.from_bytes(os.urandom(20), "big") >> 1 diff --git a/source/target-vendors/cp312/cryptography/x509/certificate_transparency.py b/source/target-vendors/cp312/cryptography/x509/certificate_transparency.py new file mode 100644 index 0000000..fb66cc6 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/certificate_transparency.py @@ -0,0 +1,35 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 + + +class LogEntryType(utils.Enum): + X509_CERTIFICATE = 0 + PRE_CERTIFICATE = 1 + + +class Version(utils.Enum): + v1 = 0 + + +class SignatureAlgorithm(utils.Enum): + """ + Signature algorithms that are valid for SCTs. + + These are exactly the same as SignatureAlgorithm in RFC 5246 (TLS 1.2). + + See: + """ + + ANONYMOUS = 0 + RSA = 1 + DSA = 2 + ECDSA = 3 + + +SignedCertificateTimestamp = rust_x509.Sct diff --git a/source/target-vendors/cp312/cryptography/x509/extensions.py b/source/target-vendors/cp312/cryptography/x509/extensions.py new file mode 100644 index 0000000..dc7728e --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/extensions.py @@ -0,0 +1,2533 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import datetime +import hashlib +import ipaddress +import typing +from collections.abc import Iterable, Iterator + +from cryptography import utils +from cryptography.hazmat.bindings._rust import asn1 +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.hazmat.primitives import _serialization, constant_time +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPublicKeyTypes, + CertificatePublicKeyTypes, +) +from cryptography.x509.certificate_transparency import ( + SignedCertificateTimestamp, +) +from cryptography.x509.general_name import ( + DirectoryName, + DNSName, + GeneralName, + IPAddress, + OtherName, + RegisteredID, + RFC822Name, + UniformResourceIdentifier, + _IPAddressTypes, +) +from cryptography.x509.name import Name, RelativeDistinguishedName +from cryptography.x509.oid import ( + CRLEntryExtensionOID, + ExtensionOID, + ObjectIdentifier, + OCSPExtensionOID, +) + +ExtensionTypeVar = typing.TypeVar( + "ExtensionTypeVar", bound="ExtensionType", covariant=True +) + + +def _key_identifier_from_public_key( + public_key: CertificatePublicKeyTypes, +) -> bytes: + if isinstance(public_key, RSAPublicKey): + data = public_key.public_bytes( + _serialization.Encoding.DER, + _serialization.PublicFormat.PKCS1, + ) + elif isinstance(public_key, EllipticCurvePublicKey): + data = public_key.public_bytes( + _serialization.Encoding.X962, + _serialization.PublicFormat.UncompressedPoint, + ) + else: + # This is a very slow way to do this. + serialized = public_key.public_bytes( + _serialization.Encoding.DER, + _serialization.PublicFormat.SubjectPublicKeyInfo, + ) + data = asn1.parse_spki_for_data(serialized) + + return hashlib.sha1(data).digest() + + +def _make_sequence_methods(field_name: str): + def len_method(self) -> int: + return len(getattr(self, field_name)) + + def iter_method(self): + return iter(getattr(self, field_name)) + + def getitem_method(self, idx): + return getattr(self, field_name)[idx] + + return len_method, iter_method, getitem_method + + +class DuplicateExtension(Exception): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: + super().__init__(msg) + self.oid = oid + + +class ExtensionNotFound(Exception): + def __init__(self, msg: str, oid: ObjectIdentifier) -> None: + super().__init__(msg) + self.oid = oid + + +class ExtensionType(metaclass=abc.ABCMeta): + oid: typing.ClassVar[ObjectIdentifier] + + def public_bytes(self) -> bytes: + """ + Serializes the extension type to DER. + """ + raise NotImplementedError( + f"public_bytes is not implemented for extension type {self!r}" + ) + + +class Extensions: + def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None: + self._extensions = list(extensions) + + def get_extension_for_oid( + self, oid: ObjectIdentifier + ) -> Extension[ExtensionType]: + for ext in self: + if ext.oid == oid: + return ext + + raise ExtensionNotFound(f"No {oid} extension was found", oid) + + def get_extension_for_class( + self, extclass: type[ExtensionTypeVar] + ) -> Extension[ExtensionTypeVar]: + if extclass is UnrecognizedExtension: + raise TypeError( + "UnrecognizedExtension can't be used with " + "get_extension_for_class because more than one instance of the" + " class may be present." + ) + + for ext in self: + if isinstance(ext.value, extclass): + return ext + + raise ExtensionNotFound( + f"No {extclass} extension was found", extclass.oid + ) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") + + def __repr__(self) -> str: + return f"" + + +class CRLNumber(ExtensionType): + oid = ExtensionOID.CRL_NUMBER + + def __init__(self, crl_number: int) -> None: + if not isinstance(crl_number, int): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CRLNumber): + return NotImplemented + + return self.crl_number == other.crl_number + + def __hash__(self) -> int: + return hash(self.crl_number) + + def __repr__(self) -> str: + return f"" + + @property + def crl_number(self) -> int: + return self._crl_number + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class AuthorityKeyIdentifier(ExtensionType): + oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER + + def __init__( + self, + key_identifier: bytes | None, + authority_cert_issuer: Iterable[GeneralName] | None, + authority_cert_serial_number: int | None, + ) -> None: + if (authority_cert_issuer is None) != ( + authority_cert_serial_number is None + ): + raise ValueError( + "authority_cert_issuer and authority_cert_serial_number " + "must both be present or both None" + ) + + if authority_cert_issuer is not None: + authority_cert_issuer = list(authority_cert_issuer) + if not all( + isinstance(x, GeneralName) for x in authority_cert_issuer + ): + raise TypeError( + "authority_cert_issuer must be a list of GeneralName " + "objects" + ) + + if authority_cert_serial_number is not None and not isinstance( + authority_cert_serial_number, int + ): + raise TypeError("authority_cert_serial_number must be an integer") + + self._key_identifier = key_identifier + self._authority_cert_issuer = authority_cert_issuer + self._authority_cert_serial_number = authority_cert_serial_number + + # This takes a subset of CertificatePublicKeyTypes because an issuer + # cannot have an X25519/X448 key. This introduces some unfortunate + # asymmetry that requires typing users to explicitly + # narrow their type, but we should make this accurate and not just + # convenient. + @classmethod + def from_issuer_public_key( + cls, public_key: CertificateIssuerPublicKeyTypes + ) -> AuthorityKeyIdentifier: + digest = _key_identifier_from_public_key(public_key) + return cls( + key_identifier=digest, + authority_cert_issuer=None, + authority_cert_serial_number=None, + ) + + @classmethod + def from_issuer_subject_key_identifier( + cls, ski: SubjectKeyIdentifier + ) -> AuthorityKeyIdentifier: + return cls( + key_identifier=ski.digest, + authority_cert_issuer=None, + authority_cert_serial_number=None, + ) + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AuthorityKeyIdentifier): + return NotImplemented + + return ( + self.key_identifier == other.key_identifier + and self.authority_cert_issuer == other.authority_cert_issuer + and self.authority_cert_serial_number + == other.authority_cert_serial_number + ) + + def __hash__(self) -> int: + if self.authority_cert_issuer is None: + aci = None + else: + aci = tuple(self.authority_cert_issuer) + return hash( + (self.key_identifier, aci, self.authority_cert_serial_number) + ) + + @property + def key_identifier(self) -> bytes | None: + return self._key_identifier + + @property + def authority_cert_issuer( + self, + ) -> list[GeneralName] | None: + return self._authority_cert_issuer + + @property + def authority_cert_serial_number(self) -> int | None: + return self._authority_cert_serial_number + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class SubjectKeyIdentifier(ExtensionType): + oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER + + def __init__(self, digest: bytes) -> None: + self._digest = digest + + @classmethod + def from_public_key( + cls, public_key: CertificatePublicKeyTypes + ) -> SubjectKeyIdentifier: + return cls(_key_identifier_from_public_key(public_key)) + + @property + def digest(self) -> bytes: + return self._digest + + @property + def key_identifier(self) -> bytes: + return self._digest + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SubjectKeyIdentifier): + return NotImplemented + + return constant_time.bytes_eq(self.digest, other.digest) + + def __hash__(self) -> int: + return hash(self.digest) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class AuthorityInformationAccess(ExtensionType): + oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS + + def __init__(self, descriptions: Iterable[AccessDescription]) -> None: + descriptions = list(descriptions) + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AuthorityInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __hash__(self) -> int: + return hash(tuple(self._descriptions)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class SubjectInformationAccess(ExtensionType): + oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS + + def __init__(self, descriptions: Iterable[AccessDescription]) -> None: + descriptions = list(descriptions) + if not all(isinstance(x, AccessDescription) for x in descriptions): + raise TypeError( + "Every item in the descriptions list must be an " + "AccessDescription" + ) + + self._descriptions = descriptions + + __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SubjectInformationAccess): + return NotImplemented + + return self._descriptions == other._descriptions + + def __hash__(self) -> int: + return hash(tuple(self._descriptions)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class AccessDescription: + def __init__( + self, access_method: ObjectIdentifier, access_location: GeneralName + ) -> None: + if not isinstance(access_method, ObjectIdentifier): + raise TypeError("access_method must be an ObjectIdentifier") + + if not isinstance(access_location, GeneralName): + raise TypeError("access_location must be a GeneralName") + + self._access_method = access_method + self._access_location = access_location + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, AccessDescription): + return NotImplemented + + return ( + self.access_method == other.access_method + and self.access_location == other.access_location + ) + + def __hash__(self) -> int: + return hash((self.access_method, self.access_location)) + + @property + def access_method(self) -> ObjectIdentifier: + return self._access_method + + @property + def access_location(self) -> GeneralName: + return self._access_location + + +class BasicConstraints(ExtensionType): + oid = ExtensionOID.BASIC_CONSTRAINTS + + def __init__(self, ca: bool, path_length: int | None) -> None: + if not isinstance(ca, bool): + raise TypeError("ca must be a boolean value") + + if path_length is not None and not ca: + raise ValueError("path_length must be None when ca is False") + + if path_length is not None and ( + not isinstance(path_length, int) or path_length < 0 + ): + raise TypeError( + "path_length must be a non-negative integer or None" + ) + + self._ca = ca + self._path_length = path_length + + @property + def ca(self) -> bool: + return self._ca + + @property + def path_length(self) -> int | None: + return self._path_length + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, BasicConstraints): + return NotImplemented + + return self.ca == other.ca and self.path_length == other.path_length + + def __hash__(self) -> int: + return hash((self.ca, self.path_length)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class DeltaCRLIndicator(ExtensionType): + oid = ExtensionOID.DELTA_CRL_INDICATOR + + def __init__(self, crl_number: int) -> None: + if not isinstance(crl_number, int): + raise TypeError("crl_number must be an integer") + + self._crl_number = crl_number + + @property + def crl_number(self) -> int: + return self._crl_number + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DeltaCRLIndicator): + return NotImplemented + + return self.crl_number == other.crl_number + + def __hash__(self) -> int: + return hash(self.crl_number) + + def __repr__(self) -> str: + return f"" + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CRLDistributionPoints(ExtensionType): + oid = ExtensionOID.CRL_DISTRIBUTION_POINTS + + def __init__( + self, distribution_points: Iterable[DistributionPoint] + ) -> None: + distribution_points = list(distribution_points) + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_distribution_points" + ) + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CRLDistributionPoints): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __hash__(self) -> int: + return hash(tuple(self._distribution_points)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class FreshestCRL(ExtensionType): + oid = ExtensionOID.FRESHEST_CRL + + def __init__( + self, distribution_points: Iterable[DistributionPoint] + ) -> None: + distribution_points = list(distribution_points) + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_distribution_points" + ) + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, FreshestCRL): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __hash__(self) -> int: + return hash(tuple(self._distribution_points)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class DistributionPoint: + def __init__( + self, + full_name: Iterable[GeneralName] | None, + relative_name: RelativeDistinguishedName | None, + reasons: frozenset[ReasonFlags] | None, + crl_issuer: Iterable[GeneralName] | None, + ) -> None: + if full_name and relative_name: + raise ValueError( + "You cannot provide both full_name and relative_name, at " + "least one must be None." + ) + if not full_name and not relative_name and not crl_issuer: + raise ValueError( + "Either full_name, relative_name or crl_issuer must be " + "provided." + ) + + if full_name is not None: + full_name = list(full_name) + if not all(isinstance(x, GeneralName) for x in full_name): + raise TypeError( + "full_name must be a list of GeneralName objects" + ) + + if relative_name: + if not isinstance(relative_name, RelativeDistinguishedName): + raise TypeError( + "relative_name must be a RelativeDistinguishedName" + ) + + if crl_issuer is not None: + crl_issuer = list(crl_issuer) + if not all(isinstance(x, GeneralName) for x in crl_issuer): + raise TypeError( + "crl_issuer must be None or a list of general names" + ) + + if reasons and ( + not isinstance(reasons, frozenset) + or not all(isinstance(x, ReasonFlags) for x in reasons) + ): + raise TypeError("reasons must be None or frozenset of ReasonFlags") + + if reasons and ( + ReasonFlags.unspecified in reasons + or ReasonFlags.remove_from_crl in reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in a " + "DistributionPoint" + ) + + self._full_name = full_name + self._relative_name = relative_name + self._reasons = reasons + self._crl_issuer = crl_issuer + + def __repr__(self) -> str: + return ( + "".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name + and self.relative_name == other.relative_name + and self.reasons == other.reasons + and self.crl_issuer == other.crl_issuer + ) + + def __hash__(self) -> int: + if self.full_name is not None: + fn: tuple[GeneralName, ...] | None = tuple(self.full_name) + else: + fn = None + + if self.crl_issuer is not None: + crl_issuer: tuple[GeneralName, ...] | None = tuple(self.crl_issuer) + else: + crl_issuer = None + + return hash((fn, self.relative_name, self.reasons, crl_issuer)) + + @property + def full_name(self) -> list[GeneralName] | None: + return self._full_name + + @property + def relative_name(self) -> RelativeDistinguishedName | None: + return self._relative_name + + @property + def reasons(self) -> frozenset[ReasonFlags] | None: + return self._reasons + + @property + def crl_issuer(self) -> list[GeneralName] | None: + return self._crl_issuer + + +class ReasonFlags(utils.Enum): + unspecified = "unspecified" + key_compromise = "keyCompromise" + ca_compromise = "cACompromise" + affiliation_changed = "affiliationChanged" + superseded = "superseded" + cessation_of_operation = "cessationOfOperation" + certificate_hold = "certificateHold" + privilege_withdrawn = "privilegeWithdrawn" + aa_compromise = "aACompromise" + remove_from_crl = "removeFromCRL" + + +# These are distribution point bit string mappings. Not to be confused with +# CRLReason reason flags bit string mappings. +# ReasonFlags ::= BIT STRING { +# unused (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# privilegeWithdrawn (7), +# aACompromise (8) } +_REASON_BIT_MAPPING = { + 1: ReasonFlags.key_compromise, + 2: ReasonFlags.ca_compromise, + 3: ReasonFlags.affiliation_changed, + 4: ReasonFlags.superseded, + 5: ReasonFlags.cessation_of_operation, + 6: ReasonFlags.certificate_hold, + 7: ReasonFlags.privilege_withdrawn, + 8: ReasonFlags.aa_compromise, +} + +_CRLREASONFLAGS = { + ReasonFlags.key_compromise: 1, + ReasonFlags.ca_compromise: 2, + ReasonFlags.affiliation_changed: 3, + ReasonFlags.superseded: 4, + ReasonFlags.cessation_of_operation: 5, + ReasonFlags.certificate_hold: 6, + ReasonFlags.privilege_withdrawn: 7, + ReasonFlags.aa_compromise: 8, +} + +# CRLReason ::= ENUMERATED { +# unspecified (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# -- value 7 is not used +# removeFromCRL (8), +# privilegeWithdrawn (9), +# aACompromise (10) } +_CRL_ENTRY_REASON_ENUM_TO_CODE = { + ReasonFlags.unspecified: 0, + ReasonFlags.key_compromise: 1, + ReasonFlags.ca_compromise: 2, + ReasonFlags.affiliation_changed: 3, + ReasonFlags.superseded: 4, + ReasonFlags.cessation_of_operation: 5, + ReasonFlags.certificate_hold: 6, + ReasonFlags.remove_from_crl: 8, + ReasonFlags.privilege_withdrawn: 9, + ReasonFlags.aa_compromise: 10, +} + + +class PolicyConstraints(ExtensionType): + oid = ExtensionOID.POLICY_CONSTRAINTS + + def __init__( + self, + require_explicit_policy: int | None, + inhibit_policy_mapping: int | None, + ) -> None: + if require_explicit_policy is not None and not isinstance( + require_explicit_policy, int + ): + raise TypeError( + "require_explicit_policy must be a non-negative integer or " + "None" + ) + + if inhibit_policy_mapping is not None and not isinstance( + inhibit_policy_mapping, int + ): + raise TypeError( + "inhibit_policy_mapping must be a non-negative integer or None" + ) + + if inhibit_policy_mapping is None and require_explicit_policy is None: + raise ValueError( + "At least one of require_explicit_policy and " + "inhibit_policy_mapping must not be None" + ) + + self._require_explicit_policy = require_explicit_policy + self._inhibit_policy_mapping = inhibit_policy_mapping + + def __repr__(self) -> str: + return ( + "".format(self) + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PolicyConstraints): + return NotImplemented + + return ( + self.require_explicit_policy == other.require_explicit_policy + and self.inhibit_policy_mapping == other.inhibit_policy_mapping + ) + + def __hash__(self) -> int: + return hash( + (self.require_explicit_policy, self.inhibit_policy_mapping) + ) + + @property + def require_explicit_policy(self) -> int | None: + return self._require_explicit_policy + + @property + def inhibit_policy_mapping(self) -> int | None: + return self._inhibit_policy_mapping + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CertificatePolicies(ExtensionType): + oid = ExtensionOID.CERTIFICATE_POLICIES + + def __init__(self, policies: Iterable[PolicyInformation]) -> None: + policies = list(policies) + if not all(isinstance(x, PolicyInformation) for x in policies): + raise TypeError( + "Every item in the policies list must be a PolicyInformation" + ) + + self._policies = policies + + __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CertificatePolicies): + return NotImplemented + + return self._policies == other._policies + + def __hash__(self) -> int: + return hash(tuple(self._policies)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PolicyInformation: + def __init__( + self, + policy_identifier: ObjectIdentifier, + policy_qualifiers: Iterable[str | UserNotice] | None, + ) -> None: + if not isinstance(policy_identifier, ObjectIdentifier): + raise TypeError("policy_identifier must be an ObjectIdentifier") + + self._policy_identifier = policy_identifier + + if policy_qualifiers is not None: + policy_qualifiers = list(policy_qualifiers) + if not all( + isinstance(x, (str, UserNotice)) for x in policy_qualifiers + ): + raise TypeError( + "policy_qualifiers must be a list of strings and/or " + "UserNotice objects or None" + ) + + self._policy_qualifiers = policy_qualifiers + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PolicyInformation): + return NotImplemented + + return ( + self.policy_identifier == other.policy_identifier + and self.policy_qualifiers == other.policy_qualifiers + ) + + def __hash__(self) -> int: + if self.policy_qualifiers is not None: + pq = tuple(self.policy_qualifiers) + else: + pq = None + + return hash((self.policy_identifier, pq)) + + @property + def policy_identifier(self) -> ObjectIdentifier: + return self._policy_identifier + + @property + def policy_qualifiers( + self, + ) -> list[str | UserNotice] | None: + return self._policy_qualifiers + + +class UserNotice: + def __init__( + self, + notice_reference: NoticeReference | None, + explicit_text: str | None, + ) -> None: + if notice_reference and not isinstance( + notice_reference, NoticeReference + ): + raise TypeError( + "notice_reference must be None or a NoticeReference" + ) + + self._notice_reference = notice_reference + self._explicit_text = explicit_text + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UserNotice): + return NotImplemented + + return ( + self.notice_reference == other.notice_reference + and self.explicit_text == other.explicit_text + ) + + def __hash__(self) -> int: + return hash((self.notice_reference, self.explicit_text)) + + @property + def notice_reference(self) -> NoticeReference | None: + return self._notice_reference + + @property + def explicit_text(self) -> str | None: + return self._explicit_text + + +class NoticeReference: + def __init__( + self, + organization: str | None, + notice_numbers: Iterable[int], + ) -> None: + self._organization = organization + notice_numbers = list(notice_numbers) + if not all(isinstance(x, int) for x in notice_numbers): + raise TypeError("notice_numbers must be a list of integers") + + self._notice_numbers = notice_numbers + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NoticeReference): + return NotImplemented + + return ( + self.organization == other.organization + and self.notice_numbers == other.notice_numbers + ) + + def __hash__(self) -> int: + return hash((self.organization, tuple(self.notice_numbers))) + + @property + def organization(self) -> str | None: + return self._organization + + @property + def notice_numbers(self) -> list[int]: + return self._notice_numbers + + +class ExtendedKeyUsage(ExtensionType): + oid = ExtensionOID.EXTENDED_KEY_USAGE + + def __init__(self, usages: Iterable[ObjectIdentifier]) -> None: + usages = list(usages) + if not all(isinstance(x, ObjectIdentifier) for x in usages): + raise TypeError( + "Every item in the usages list must be an ObjectIdentifier" + ) + + self._usages = usages + + __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ExtendedKeyUsage): + return NotImplemented + + return self._usages == other._usages + + def __hash__(self) -> int: + return hash(tuple(self._usages)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class OCSPNoCheck(ExtensionType): + oid = ExtensionOID.OCSP_NO_CHECK + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OCSPNoCheck): + return NotImplemented + + return True + + def __hash__(self) -> int: + return hash(OCSPNoCheck) + + def __repr__(self) -> str: + return "" + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PrecertPoison(ExtensionType): + oid = ExtensionOID.PRECERT_POISON + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PrecertPoison): + return NotImplemented + + return True + + def __hash__(self) -> int: + return hash(PrecertPoison) + + def __repr__(self) -> str: + return "" + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class TLSFeature(ExtensionType): + oid = ExtensionOID.TLS_FEATURE + + def __init__(self, features: Iterable[TLSFeatureType]) -> None: + features = list(features) + if ( + not all(isinstance(x, TLSFeatureType) for x in features) + or len(features) == 0 + ): + raise TypeError( + "features must be a list of elements from the TLSFeatureType " + "enum" + ) + + self._features = features + + __len__, __iter__, __getitem__ = _make_sequence_methods("_features") + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, TLSFeature): + return NotImplemented + + return self._features == other._features + + def __hash__(self) -> int: + return hash(tuple(self._features)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class TLSFeatureType(utils.Enum): + # status_request is defined in RFC 6066 and is used for what is commonly + # called OCSP Must-Staple when present in the TLS Feature extension in an + # X.509 certificate. + status_request = 5 + # status_request_v2 is defined in RFC 6961 and allows multiple OCSP + # responses to be provided. It is not currently in use by clients or + # servers. + status_request_v2 = 17 + + +_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} + + +class InhibitAnyPolicy(ExtensionType): + oid = ExtensionOID.INHIBIT_ANY_POLICY + + def __init__(self, skip_certs: int) -> None: + if not isinstance(skip_certs, int): + raise TypeError("skip_certs must be an integer") + + if skip_certs < 0: + raise ValueError("skip_certs must be a non-negative integer") + + self._skip_certs = skip_certs + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, InhibitAnyPolicy): + return NotImplemented + + return self.skip_certs == other.skip_certs + + def __hash__(self) -> int: + return hash(self.skip_certs) + + @property + def skip_certs(self) -> int: + return self._skip_certs + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class KeyUsage(ExtensionType): + oid = ExtensionOID.KEY_USAGE + + def __init__( + self, + digital_signature: bool, + content_commitment: bool, + key_encipherment: bool, + data_encipherment: bool, + key_agreement: bool, + key_cert_sign: bool, + crl_sign: bool, + encipher_only: bool, + decipher_only: bool, + ) -> None: + if not key_agreement and (encipher_only or decipher_only): + raise ValueError( + "encipher_only and decipher_only can only be true when " + "key_agreement is true" + ) + + self._digital_signature = digital_signature + self._content_commitment = content_commitment + self._key_encipherment = key_encipherment + self._data_encipherment = data_encipherment + self._key_agreement = key_agreement + self._key_cert_sign = key_cert_sign + self._crl_sign = crl_sign + self._encipher_only = encipher_only + self._decipher_only = decipher_only + + @property + def digital_signature(self) -> bool: + return self._digital_signature + + @property + def content_commitment(self) -> bool: + return self._content_commitment + + @property + def key_encipherment(self) -> bool: + return self._key_encipherment + + @property + def data_encipherment(self) -> bool: + return self._data_encipherment + + @property + def key_agreement(self) -> bool: + return self._key_agreement + + @property + def key_cert_sign(self) -> bool: + return self._key_cert_sign + + @property + def crl_sign(self) -> bool: + return self._crl_sign + + @property + def encipher_only(self) -> bool: + if not self.key_agreement: + raise ValueError( + "encipher_only is undefined unless key_agreement is true" + ) + else: + return self._encipher_only + + @property + def decipher_only(self) -> bool: + if not self.key_agreement: + raise ValueError( + "decipher_only is undefined unless key_agreement is true" + ) + else: + return self._decipher_only + + def __repr__(self) -> str: + try: + encipher_only = self.encipher_only + decipher_only = self.decipher_only + except ValueError: + # Users found None confusing because even though encipher/decipher + # have no meaning unless key_agreement is true, to construct an + # instance of the class you still need to pass False. + encipher_only = False + decipher_only = False + + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, KeyUsage): + return NotImplemented + + return ( + self.digital_signature == other.digital_signature + and self.content_commitment == other.content_commitment + and self.key_encipherment == other.key_encipherment + and self.data_encipherment == other.data_encipherment + and self.key_agreement == other.key_agreement + and self.key_cert_sign == other.key_cert_sign + and self.crl_sign == other.crl_sign + and self._encipher_only == other._encipher_only + and self._decipher_only == other._decipher_only + ) + + def __hash__(self) -> int: + return hash( + ( + self.digital_signature, + self.content_commitment, + self.key_encipherment, + self.data_encipherment, + self.key_agreement, + self.key_cert_sign, + self.crl_sign, + self._encipher_only, + self._decipher_only, + ) + ) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PrivateKeyUsagePeriod(ExtensionType): + oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD + + def __init__( + self, + not_before: datetime.datetime | None, + not_after: datetime.datetime | None, + ) -> None: + if ( + not isinstance(not_before, datetime.datetime) + and not_before is not None + ): + raise TypeError("not_before must be a datetime.datetime or None") + + if ( + not isinstance(not_after, datetime.datetime) + and not_after is not None + ): + raise TypeError("not_after must be a datetime.datetime or None") + + if not_before is None and not_after is None: + raise ValueError( + "At least one of not_before and not_after must not be None" + ) + + if ( + not_before is not None + and not_after is not None + and not_before > not_after + ): + raise ValueError("not_before must be before not_after") + + self._not_before = not_before + self._not_after = not_after + + @property + def not_before(self) -> datetime.datetime | None: + return self._not_before + + @property + def not_after(self) -> datetime.datetime | None: + return self._not_after + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PrivateKeyUsagePeriod): + return NotImplemented + + return ( + self.not_before == other.not_before + and self.not_after == other.not_after + ) + + def __hash__(self) -> int: + return hash((self.not_before, self.not_after)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class NameConstraints(ExtensionType): + oid = ExtensionOID.NAME_CONSTRAINTS + + def __init__( + self, + permitted_subtrees: Iterable[GeneralName] | None, + excluded_subtrees: Iterable[GeneralName] | None, + ) -> None: + if permitted_subtrees is not None: + permitted_subtrees = list(permitted_subtrees) + if not permitted_subtrees: + raise ValueError( + "permitted_subtrees must be a non-empty list or None" + ) + if not all(isinstance(x, GeneralName) for x in permitted_subtrees): + raise TypeError( + "permitted_subtrees must be a list of GeneralName objects " + "or None" + ) + + self._validate_tree(permitted_subtrees) + + if excluded_subtrees is not None: + excluded_subtrees = list(excluded_subtrees) + if not excluded_subtrees: + raise ValueError( + "excluded_subtrees must be a non-empty list or None" + ) + if not all(isinstance(x, GeneralName) for x in excluded_subtrees): + raise TypeError( + "excluded_subtrees must be a list of GeneralName objects " + "or None" + ) + + self._validate_tree(excluded_subtrees) + + if permitted_subtrees is None and excluded_subtrees is None: + raise ValueError( + "At least one of permitted_subtrees and excluded_subtrees " + "must not be None" + ) + + self._permitted_subtrees = permitted_subtrees + self._excluded_subtrees = excluded_subtrees + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NameConstraints): + return NotImplemented + + return ( + self.excluded_subtrees == other.excluded_subtrees + and self.permitted_subtrees == other.permitted_subtrees + ) + + def _validate_tree(self, tree: Iterable[GeneralName]) -> None: + self._validate_ip_name(tree) + self._validate_dns_name(tree) + + def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None: + if any( + isinstance(name, IPAddress) + and not isinstance( + name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) + ) + for name in tree + ): + raise TypeError( + "IPAddress name constraints must be an IPv4Network or" + " IPv6Network object" + ) + + def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None: + if any( + isinstance(name, DNSName) and "*" in name.value for name in tree + ): + raise ValueError( + "DNSName name constraints must not contain the '*' wildcard" + " character" + ) + + def __repr__(self) -> str: + return ( + f"" + ) + + def __hash__(self) -> int: + if self.permitted_subtrees is not None: + ps: tuple[GeneralName, ...] | None = tuple(self.permitted_subtrees) + else: + ps = None + + if self.excluded_subtrees is not None: + es: tuple[GeneralName, ...] | None = tuple(self.excluded_subtrees) + else: + es = None + + return hash((ps, es)) + + @property + def permitted_subtrees( + self, + ) -> list[GeneralName] | None: + return self._permitted_subtrees + + @property + def excluded_subtrees( + self, + ) -> list[GeneralName] | None: + return self._excluded_subtrees + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class Extension(typing.Generic[ExtensionTypeVar]): + def __init__( + self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar + ) -> None: + if not isinstance(oid, ObjectIdentifier): + raise TypeError( + "oid argument must be an ObjectIdentifier instance." + ) + + if not isinstance(critical, bool): + raise TypeError("critical must be a boolean value") + + self._oid = oid + self._critical = critical + self._value = value + + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def critical(self) -> bool: + return self._critical + + @property + def value(self) -> ExtensionTypeVar: + return self._value + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Extension): + return NotImplemented + + return ( + self.oid == other.oid + and self.critical == other.critical + and self.value == other.value + ) + + def __hash__(self) -> int: + return hash((self.oid, self.critical, self.value)) + + +class GeneralNames: + def __init__(self, general_names: Iterable[GeneralName]) -> None: + general_names = list(general_names) + if not all(isinstance(x, GeneralName) for x in general_names): + raise TypeError( + "Every item in the general_names list must be an " + "object conforming to the GeneralName interface" + ) + + self._general_names = general_names + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: type[DNSName] + | type[UniformResourceIdentifier] + | type[RFC822Name], + ) -> list[str]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[DirectoryName], + ) -> list[Name]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[RegisteredID], + ) -> list[ObjectIdentifier]: ... + + @typing.overload + def get_values_for_type( + self, type: type[IPAddress] + ) -> list[_IPAddressTypes]: ... + + @typing.overload + def get_values_for_type( + self, type: type[OtherName] + ) -> list[OtherName]: ... + + def get_values_for_type( + self, + type: type[DNSName] + | type[DirectoryName] + | type[IPAddress] + | type[OtherName] + | type[RFC822Name] + | type[RegisteredID] + | type[UniformResourceIdentifier], + ) -> ( + list[_IPAddressTypes] + | list[str] + | list[OtherName] + | list[Name] + | list[ObjectIdentifier] + ): + # Return the value of each GeneralName, except for OtherName instances + # which we return directly because it has two important properties not + # just one value. + objs = (i for i in self if isinstance(i, type)) + if type != OtherName: + return [i.value for i in objs] # type: ignore[return-value,unused-ignore] + return list(objs) # type: ignore[return-value,unused-ignore] + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, GeneralNames): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(tuple(self._general_names)) + + +class SubjectAlternativeName(ExtensionType): + oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME + + def __init__(self, general_names: Iterable[GeneralName]) -> None: + self._general_names = GeneralNames(general_names) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: type[DNSName] + | type[UniformResourceIdentifier] + | type[RFC822Name], + ) -> list[str]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[DirectoryName], + ) -> list[Name]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[RegisteredID], + ) -> list[ObjectIdentifier]: ... + + @typing.overload + def get_values_for_type( + self, type: type[IPAddress] + ) -> list[_IPAddressTypes]: ... + + @typing.overload + def get_values_for_type( + self, type: type[OtherName] + ) -> list[OtherName]: ... + + def get_values_for_type( + self, + type: type[DNSName] + | type[DirectoryName] + | type[IPAddress] + | type[OtherName] + | type[RFC822Name] + | type[RegisteredID] + | type[UniformResourceIdentifier], + ) -> ( + list[_IPAddressTypes] + | list[str] + | list[OtherName] + | list[Name] + | list[ObjectIdentifier] + ): + return self._general_names.get_values_for_type(type) + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SubjectAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(self._general_names) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class IssuerAlternativeName(ExtensionType): + oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME + + def __init__(self, general_names: Iterable[GeneralName]) -> None: + self._general_names = GeneralNames(general_names) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: type[DNSName] + | type[UniformResourceIdentifier] + | type[RFC822Name], + ) -> list[str]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[DirectoryName], + ) -> list[Name]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[RegisteredID], + ) -> list[ObjectIdentifier]: ... + + @typing.overload + def get_values_for_type( + self, type: type[IPAddress] + ) -> list[_IPAddressTypes]: ... + + @typing.overload + def get_values_for_type( + self, type: type[OtherName] + ) -> list[OtherName]: ... + + def get_values_for_type( + self, + type: type[DNSName] + | type[DirectoryName] + | type[IPAddress] + | type[OtherName] + | type[RFC822Name] + | type[RegisteredID] + | type[UniformResourceIdentifier], + ) -> ( + list[_IPAddressTypes] + | list[str] + | list[OtherName] + | list[Name] + | list[ObjectIdentifier] + ): + return self._general_names.get_values_for_type(type) + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, IssuerAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(self._general_names) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CertificateIssuer(ExtensionType): + oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER + + def __init__(self, general_names: Iterable[GeneralName]) -> None: + self._general_names = GeneralNames(general_names) + + __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") + + @typing.overload + def get_values_for_type( + self, + type: type[DNSName] + | type[UniformResourceIdentifier] + | type[RFC822Name], + ) -> list[str]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[DirectoryName], + ) -> list[Name]: ... + + @typing.overload + def get_values_for_type( + self, + type: type[RegisteredID], + ) -> list[ObjectIdentifier]: ... + + @typing.overload + def get_values_for_type( + self, type: type[IPAddress] + ) -> list[_IPAddressTypes]: ... + + @typing.overload + def get_values_for_type( + self, type: type[OtherName] + ) -> list[OtherName]: ... + + def get_values_for_type( + self, + type: type[DNSName] + | type[DirectoryName] + | type[IPAddress] + | type[OtherName] + | type[RFC822Name] + | type[RegisteredID] + | type[UniformResourceIdentifier], + ) -> ( + list[_IPAddressTypes] + | list[str] + | list[OtherName] + | list[Name] + | list[ObjectIdentifier] + ): + return self._general_names.get_values_for_type(type) + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CertificateIssuer): + return NotImplemented + + return self._general_names == other._general_names + + def __hash__(self) -> int: + return hash(self._general_names) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class CRLReason(ExtensionType): + oid = CRLEntryExtensionOID.CRL_REASON + + def __init__(self, reason: ReasonFlags) -> None: + if not isinstance(reason, ReasonFlags): + raise TypeError("reason must be an element from ReasonFlags") + + self._reason = reason + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CRLReason): + return NotImplemented + + return self.reason == other.reason + + def __hash__(self) -> int: + return hash(self.reason) + + @property + def reason(self) -> ReasonFlags: + return self._reason + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class InvalidityDate(ExtensionType): + oid = CRLEntryExtensionOID.INVALIDITY_DATE + + def __init__(self, invalidity_date: datetime.datetime) -> None: + if not isinstance(invalidity_date, datetime.datetime): + raise TypeError("invalidity_date must be a datetime.datetime") + + self._invalidity_date = invalidity_date + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, InvalidityDate): + return NotImplemented + + return self.invalidity_date == other.invalidity_date + + def __hash__(self) -> int: + return hash(self.invalidity_date) + + @property + def invalidity_date(self) -> datetime.datetime: + return self._invalidity_date + + @property + def invalidity_date_utc(self) -> datetime.datetime: + if self._invalidity_date.tzinfo is None: + return self._invalidity_date.replace(tzinfo=datetime.timezone.utc) + else: + return self._invalidity_date.astimezone(tz=datetime.timezone.utc) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class PrecertificateSignedCertificateTimestamps(ExtensionType): + oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS + + def __init__( + self, + signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], + ) -> None: + signed_certificate_timestamps = list(signed_certificate_timestamps) + if not all( + isinstance(sct, SignedCertificateTimestamp) + for sct in signed_certificate_timestamps + ): + raise TypeError( + "Every item in the signed_certificate_timestamps list must be " + "a SignedCertificateTimestamp" + ) + self._signed_certificate_timestamps = signed_certificate_timestamps + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_signed_certificate_timestamps" + ) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash(tuple(self._signed_certificate_timestamps)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PrecertificateSignedCertificateTimestamps): + return NotImplemented + + return ( + self._signed_certificate_timestamps + == other._signed_certificate_timestamps + ) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class SignedCertificateTimestamps(ExtensionType): + oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS + + def __init__( + self, + signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], + ) -> None: + signed_certificate_timestamps = list(signed_certificate_timestamps) + if not all( + isinstance(sct, SignedCertificateTimestamp) + for sct in signed_certificate_timestamps + ): + raise TypeError( + "Every item in the signed_certificate_timestamps list must be " + "a SignedCertificateTimestamp" + ) + self._signed_certificate_timestamps = signed_certificate_timestamps + + __len__, __iter__, __getitem__ = _make_sequence_methods( + "_signed_certificate_timestamps" + ) + + def __repr__(self) -> str: + return f"" + + def __hash__(self) -> int: + return hash(tuple(self._signed_certificate_timestamps)) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, SignedCertificateTimestamps): + return NotImplemented + + return ( + self._signed_certificate_timestamps + == other._signed_certificate_timestamps + ) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class OCSPNonce(ExtensionType): + oid = OCSPExtensionOID.NONCE + + def __init__(self, nonce: bytes) -> None: + if not isinstance(nonce, bytes): + raise TypeError("nonce must be bytes") + + self._nonce = nonce + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OCSPNonce): + return NotImplemented + + return self.nonce == other.nonce + + def __hash__(self) -> int: + return hash(self.nonce) + + def __repr__(self) -> str: + return f"" + + @property + def nonce(self) -> bytes: + return self._nonce + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class OCSPAcceptableResponses(ExtensionType): + oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES + + def __init__(self, responses: Iterable[ObjectIdentifier]) -> None: + responses = list(responses) + if any(not isinstance(r, ObjectIdentifier) for r in responses): + raise TypeError("All responses must be ObjectIdentifiers") + + self._responses = responses + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OCSPAcceptableResponses): + return NotImplemented + + return self._responses == other._responses + + def __hash__(self) -> int: + return hash(tuple(self._responses)) + + def __repr__(self) -> str: + return f"" + + def __iter__(self) -> Iterator[ObjectIdentifier]: + return iter(self._responses) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class IssuingDistributionPoint(ExtensionType): + oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT + + def __init__( + self, + full_name: Iterable[GeneralName] | None, + relative_name: RelativeDistinguishedName | None, + only_contains_user_certs: bool, + only_contains_ca_certs: bool, + only_some_reasons: frozenset[ReasonFlags] | None, + indirect_crl: bool, + only_contains_attribute_certs: bool, + ) -> None: + if full_name is not None: + full_name = list(full_name) + + if only_some_reasons and ( + not isinstance(only_some_reasons, frozenset) + or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) + ): + raise TypeError( + "only_some_reasons must be None or frozenset of ReasonFlags" + ) + + if only_some_reasons and ( + ReasonFlags.unspecified in only_some_reasons + or ReasonFlags.remove_from_crl in only_some_reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in an " + "IssuingDistributionPoint" + ) + + if not ( + isinstance(only_contains_user_certs, bool) + and isinstance(only_contains_ca_certs, bool) + and isinstance(indirect_crl, bool) + and isinstance(only_contains_attribute_certs, bool) + ): + raise TypeError( + "only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl and only_contains_attribute_certs " + "must all be boolean." + ) + + # Per RFC5280 Section 5.2.5, the Issuing Distribution Point extension + # in a CRL can have only one of onlyContainsUserCerts, + # onlyContainsCACerts, onlyContainsAttributeCerts set to TRUE. + crl_constraints = [ + only_contains_user_certs, + only_contains_ca_certs, + only_contains_attribute_certs, + ] + + if len([x for x in crl_constraints if x]) > 1: + raise ValueError( + "Only one of the following can be set to True: " + "only_contains_user_certs, only_contains_ca_certs, " + "only_contains_attribute_certs" + ) + + if not any( + [ + only_contains_user_certs, + only_contains_ca_certs, + indirect_crl, + only_contains_attribute_certs, + full_name, + relative_name, + only_some_reasons, + ] + ): + raise ValueError( + "Cannot create empty extension: " + "if only_contains_user_certs, only_contains_ca_certs, " + "indirect_crl, and only_contains_attribute_certs are all False" + ", then either full_name, relative_name, or only_some_reasons " + "must have a value." + ) + + self._only_contains_user_certs = only_contains_user_certs + self._only_contains_ca_certs = only_contains_ca_certs + self._indirect_crl = indirect_crl + self._only_contains_attribute_certs = only_contains_attribute_certs + self._only_some_reasons = only_some_reasons + self._full_name = full_name + self._relative_name = relative_name + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, IssuingDistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name + and self.relative_name == other.relative_name + and self.only_contains_user_certs == other.only_contains_user_certs + and self.only_contains_ca_certs == other.only_contains_ca_certs + and self.only_some_reasons == other.only_some_reasons + and self.indirect_crl == other.indirect_crl + and self.only_contains_attribute_certs + == other.only_contains_attribute_certs + ) + + def __hash__(self) -> int: + if self.full_name is not None: + full_name: tuple[GeneralName, ...] | None = tuple(self.full_name) + else: + full_name = None + + return hash( + ( + full_name, + self.relative_name, + self.only_contains_user_certs, + self.only_contains_ca_certs, + self.only_some_reasons, + self.indirect_crl, + self.only_contains_attribute_certs, + ) + ) + + @property + def full_name(self) -> list[GeneralName] | None: + return self._full_name + + @property + def relative_name(self) -> RelativeDistinguishedName | None: + return self._relative_name + + @property + def only_contains_user_certs(self) -> bool: + return self._only_contains_user_certs + + @property + def only_contains_ca_certs(self) -> bool: + return self._only_contains_ca_certs + + @property + def only_some_reasons( + self, + ) -> frozenset[ReasonFlags] | None: + return self._only_some_reasons + + @property + def indirect_crl(self) -> bool: + return self._indirect_crl + + @property + def only_contains_attribute_certs(self) -> bool: + return self._only_contains_attribute_certs + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class MSCertificateTemplate(ExtensionType): + oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE + + def __init__( + self, + template_id: ObjectIdentifier, + major_version: int | None, + minor_version: int | None, + ) -> None: + if not isinstance(template_id, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + self._template_id = template_id + if ( + major_version is not None and not isinstance(major_version, int) + ) or ( + minor_version is not None and not isinstance(minor_version, int) + ): + raise TypeError( + "major_version and minor_version must be integers or None" + ) + self._major_version = major_version + self._minor_version = minor_version + + @property + def template_id(self) -> ObjectIdentifier: + return self._template_id + + @property + def major_version(self) -> int | None: + return self._major_version + + @property + def minor_version(self) -> int | None: + return self._minor_version + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, MSCertificateTemplate): + return NotImplemented + + return ( + self.template_id == other.template_id + and self.major_version == other.major_version + and self.minor_version == other.minor_version + ) + + def __hash__(self) -> int: + return hash((self.template_id, self.major_version, self.minor_version)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class NamingAuthority: + def __init__( + self, + id: ObjectIdentifier | None, + url: str | None, + text: str | None, + ) -> None: + if id is not None and not isinstance(id, ObjectIdentifier): + raise TypeError("id must be an ObjectIdentifier") + + if url is not None and not isinstance(url, str): + raise TypeError("url must be a str") + + if text is not None and not isinstance(text, str): + raise TypeError("text must be a str") + + self._id = id + self._url = url + self._text = text + + @property + def id(self) -> ObjectIdentifier | None: + return self._id + + @property + def url(self) -> str | None: + return self._url + + @property + def text(self) -> str | None: + return self._text + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NamingAuthority): + return NotImplemented + + return ( + self.id == other.id + and self.url == other.url + and self.text == other.text + ) + + def __hash__(self) -> int: + return hash( + ( + self.id, + self.url, + self.text, + ) + ) + + +class ProfessionInfo: + def __init__( + self, + naming_authority: NamingAuthority | None, + profession_items: Iterable[str], + profession_oids: Iterable[ObjectIdentifier] | None, + registration_number: str | None, + add_profession_info: bytes | None, + ) -> None: + if naming_authority is not None and not isinstance( + naming_authority, NamingAuthority + ): + raise TypeError("naming_authority must be a NamingAuthority") + + profession_items = list(profession_items) + if not all(isinstance(item, str) for item in profession_items): + raise TypeError( + "Every item in the profession_items list must be a str" + ) + + if profession_oids is not None: + profession_oids = list(profession_oids) + if not all( + isinstance(oid, ObjectIdentifier) for oid in profession_oids + ): + raise TypeError( + "Every item in the profession_oids list must be an " + "ObjectIdentifier" + ) + + if registration_number is not None and not isinstance( + registration_number, str + ): + raise TypeError("registration_number must be a str") + + if add_profession_info is not None and not isinstance( + add_profession_info, bytes + ): + raise TypeError("add_profession_info must be bytes") + + self._naming_authority = naming_authority + self._profession_items = profession_items + self._profession_oids = profession_oids + self._registration_number = registration_number + self._add_profession_info = add_profession_info + + @property + def naming_authority(self) -> NamingAuthority | None: + return self._naming_authority + + @property + def profession_items(self) -> list[str]: + return self._profession_items + + @property + def profession_oids(self) -> list[ObjectIdentifier] | None: + return self._profession_oids + + @property + def registration_number(self) -> str | None: + return self._registration_number + + @property + def add_profession_info(self) -> bytes | None: + return self._add_profession_info + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, ProfessionInfo): + return NotImplemented + + return ( + self.naming_authority == other.naming_authority + and self.profession_items == other.profession_items + and self.profession_oids == other.profession_oids + and self.registration_number == other.registration_number + and self.add_profession_info == other.add_profession_info + ) + + def __hash__(self) -> int: + if self.profession_oids is not None: + profession_oids = tuple(self.profession_oids) + else: + profession_oids = None + return hash( + ( + self.naming_authority, + tuple(self.profession_items), + profession_oids, + self.registration_number, + self.add_profession_info, + ) + ) + + +class Admission: + def __init__( + self, + admission_authority: GeneralName | None, + naming_authority: NamingAuthority | None, + profession_infos: Iterable[ProfessionInfo], + ) -> None: + if admission_authority is not None and not isinstance( + admission_authority, GeneralName + ): + raise TypeError("admission_authority must be a GeneralName") + + if naming_authority is not None and not isinstance( + naming_authority, NamingAuthority + ): + raise TypeError("naming_authority must be a NamingAuthority") + + profession_infos = list(profession_infos) + if not all( + isinstance(info, ProfessionInfo) for info in profession_infos + ): + raise TypeError( + "Every item in the profession_infos list must be a " + "ProfessionInfo" + ) + + self._admission_authority = admission_authority + self._naming_authority = naming_authority + self._profession_infos = profession_infos + + @property + def admission_authority(self) -> GeneralName | None: + return self._admission_authority + + @property + def naming_authority(self) -> NamingAuthority | None: + return self._naming_authority + + @property + def profession_infos(self) -> list[ProfessionInfo]: + return self._profession_infos + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Admission): + return NotImplemented + + return ( + self.admission_authority == other.admission_authority + and self.naming_authority == other.naming_authority + and self.profession_infos == other.profession_infos + ) + + def __hash__(self) -> int: + return hash( + ( + self.admission_authority, + self.naming_authority, + tuple(self.profession_infos), + ) + ) + + +class Admissions(ExtensionType): + oid = ExtensionOID.ADMISSIONS + + def __init__( + self, + authority: GeneralName | None, + admissions: Iterable[Admission], + ) -> None: + if authority is not None and not isinstance(authority, GeneralName): + raise TypeError("authority must be a GeneralName") + + admissions = list(admissions) + if not all( + isinstance(admission, Admission) for admission in admissions + ): + raise TypeError( + "Every item in the contents_of_admissions list must be an " + "Admission" + ) + + self._authority = authority + self._admissions = admissions + + __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions") + + @property + def authority(self) -> GeneralName | None: + return self._authority + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Admissions): + return NotImplemented + + return ( + self.authority == other.authority + and self._admissions == other._admissions + ) + + def __hash__(self) -> int: + return hash((self.authority, tuple(self._admissions))) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + +class UnrecognizedExtension(ExtensionType): + def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid must be an ObjectIdentifier") + self._oid = oid + self._value = value + + @property + def oid(self) -> ObjectIdentifier: # type: ignore[override] + return self._oid + + @property + def value(self) -> bytes: + return self._value + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UnrecognizedExtension): + return NotImplemented + + return self.oid == other.oid and self.value == other.value + + def __hash__(self) -> int: + return hash((self.oid, self.value)) + + def public_bytes(self) -> bytes: + return self.value diff --git a/source/target-vendors/cp312/cryptography/x509/general_name.py b/source/target-vendors/cp312/cryptography/x509/general_name.py new file mode 100644 index 0000000..672f287 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/general_name.py @@ -0,0 +1,281 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import abc +import ipaddress +import typing +from email.utils import parseaddr + +from cryptography.x509.name import Name +from cryptography.x509.oid import ObjectIdentifier + +_IPAddressTypes = typing.Union[ + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network, +] + + +class UnsupportedGeneralNameType(Exception): + pass + + +class GeneralName(metaclass=abc.ABCMeta): + @property + @abc.abstractmethod + def value(self) -> typing.Any: + """ + Return the value of the object + """ + + +class RFC822Name(GeneralName): + def __init__(self, value: str) -> None: + if isinstance(value, str): + try: + value.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "RFC822Name values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "a library like idna." + ) + else: + raise TypeError("value must be string") + + name, address = parseaddr(value) + if name or not address: + # parseaddr has found a name (e.g. Name ) or the entire + # value is an empty string. + raise ValueError("Invalid rfc822name value") + + self._value = value + + @property + def value(self) -> str: + return self._value + + @classmethod + def _init_without_validation(cls, value: str) -> RFC822Name: + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RFC822Name): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class DNSName(GeneralName): + def __init__(self, value: str) -> None: + if isinstance(value, str): + try: + value.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "DNSName values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "a library like idna." + ) + else: + raise TypeError("value must be string") + + self._value = value + + @property + def value(self) -> str: + return self._value + + @classmethod + def _init_without_validation(cls, value: str) -> DNSName: + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DNSName): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class UniformResourceIdentifier(GeneralName): + def __init__(self, value: str) -> None: + if isinstance(value, str): + try: + value.encode("ascii") + except UnicodeEncodeError: + raise ValueError( + "URI values should be passed as an A-label string. " + "This means unicode characters should be encoded via " + "a library like idna." + ) + else: + raise TypeError("value must be string") + + self._value = value + + @property + def value(self) -> str: + return self._value + + @classmethod + def _init_without_validation(cls, value: str) -> UniformResourceIdentifier: + instance = cls.__new__(cls) + instance._value = value + return instance + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, UniformResourceIdentifier): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class DirectoryName(GeneralName): + def __init__(self, value: Name) -> None: + if not isinstance(value, Name): + raise TypeError("value must be a Name") + + self._value = value + + @property + def value(self) -> Name: + return self._value + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, DirectoryName): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class RegisteredID(GeneralName): + def __init__(self, value: ObjectIdentifier) -> None: + if not isinstance(value, ObjectIdentifier): + raise TypeError("value must be an ObjectIdentifier") + + self._value = value + + @property + def value(self) -> ObjectIdentifier: + return self._value + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RegisteredID): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class IPAddress(GeneralName): + def __init__(self, value: _IPAddressTypes) -> None: + if not isinstance( + value, + ( + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network, + ), + ): + raise TypeError( + "value must be an instance of ipaddress.IPv4Address, " + "ipaddress.IPv6Address, ipaddress.IPv4Network, or " + "ipaddress.IPv6Network" + ) + + self._value = value + + @property + def value(self) -> _IPAddressTypes: + return self._value + + def _packed(self) -> bytes: + if isinstance( + self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address) + ): + return self.value.packed + else: + return ( + self.value.network_address.packed + self.value.netmask.packed + ) + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, IPAddress): + return NotImplemented + + return self.value == other.value + + def __hash__(self) -> int: + return hash(self.value) + + +class OtherName(GeneralName): + def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None: + if not isinstance(type_id, ObjectIdentifier): + raise TypeError("type_id must be an ObjectIdentifier") + if not isinstance(value, bytes): + raise TypeError("value must be a binary string") + + self._type_id = type_id + self._value = value + + @property + def type_id(self) -> ObjectIdentifier: + return self._type_id + + @property + def value(self) -> bytes: + return self._value + + def __repr__(self) -> str: + return f"" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, OtherName): + return NotImplemented + + return self.type_id == other.type_id and self.value == other.value + + def __hash__(self) -> int: + return hash((self.type_id, self.value)) diff --git a/source/target-vendors/cp312/cryptography/x509/name.py b/source/target-vendors/cp312/cryptography/x509/name.py new file mode 100644 index 0000000..2e54edc --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/name.py @@ -0,0 +1,489 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import binascii +import re +import sys +import typing +import warnings +from collections.abc import Iterable, Iterator + +from cryptography import utils +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.x509.oid import NameOID, ObjectIdentifier + + +class _ASN1Type(utils.Enum): + BitString = 3 + OctetString = 4 + UTF8String = 12 + NumericString = 18 + PrintableString = 19 + T61String = 20 + IA5String = 22 + UTCTime = 23 + GeneralizedTime = 24 + VisibleString = 26 + UniversalString = 28 + BMPString = 30 + + +_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type} +_NAMEOID_DEFAULT_TYPE: dict[ObjectIdentifier, _ASN1Type] = { + NameOID.COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString, + NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString, + NameOID.DN_QUALIFIER: _ASN1Type.PrintableString, + NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String, + NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String, +} + +# Type alias +_OidNameMap = typing.Mapping[ObjectIdentifier, str] +_NameOidMap = typing.Mapping[str, ObjectIdentifier] + +#: Short attribute names from RFC 4514: +#: https://tools.ietf.org/html/rfc4514#page-7 +_NAMEOID_TO_NAME: _OidNameMap = { + NameOID.COMMON_NAME: "CN", + NameOID.LOCALITY_NAME: "L", + NameOID.STATE_OR_PROVINCE_NAME: "ST", + NameOID.ORGANIZATION_NAME: "O", + NameOID.ORGANIZATIONAL_UNIT_NAME: "OU", + NameOID.COUNTRY_NAME: "C", + NameOID.STREET_ADDRESS: "STREET", + NameOID.DOMAIN_COMPONENT: "DC", + NameOID.USER_ID: "UID", +} +_NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()} + +_NAMEOID_LENGTH_LIMIT = { + NameOID.COUNTRY_NAME: (2, 2), + NameOID.JURISDICTION_COUNTRY_NAME: (2, 2), + NameOID.COMMON_NAME: (1, 64), +} + + +def _escape_dn_value(val: str | bytes) -> str: + """Escape special characters in RFC4514 Distinguished Name value.""" + + if not val: + return "" + + # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character + # followed by the hexadecimal encoding of the octets. + if isinstance(val, bytes): + return "#" + binascii.hexlify(val).decode("utf8") + + # See https://tools.ietf.org/html/rfc4514#section-2.4 + val = val.replace("\\", "\\\\") + val = val.replace('"', '\\"') + val = val.replace("+", "\\+") + val = val.replace(",", "\\,") + val = val.replace(";", "\\;") + val = val.replace("<", "\\<") + val = val.replace(">", "\\>") + val = val.replace("\0", "\\00") + + if val[0] == "#" or (val[0] == " " and len(val) > 1): + val = "\\" + val + if val[-1] == " ": + val = val[:-1] + "\\ " + + return val + + +def _unescape_dn_value(val: str) -> str: + if not val: + return "" + + # See https://tools.ietf.org/html/rfc4514#section-3 + + # special = escaped / SPACE / SHARP / EQUALS + # escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE + def sub(m): + val = m.group(0) + # Special character escape + if len(val) == 2: + return val[1:] + + # Unicode string of hex + return binascii.unhexlify(val.replace("\\", "")).decode() + + return _RFC4514NameParser._PAIR_MULTI_RE.sub(sub, val) + + +NameAttributeValueType = typing.TypeVar( + "NameAttributeValueType", + typing.Union[str, bytes], + str, + bytes, + covariant=True, +) + + +class NameAttribute(typing.Generic[NameAttributeValueType]): + def __init__( + self, + oid: ObjectIdentifier, + value: NameAttributeValueType, + _type: _ASN1Type | None = None, + *, + _validate: bool = True, + ) -> None: + if not isinstance(oid, ObjectIdentifier): + raise TypeError( + "oid argument must be an ObjectIdentifier instance." + ) + if _type == _ASN1Type.BitString: + if oid != NameOID.X500_UNIQUE_IDENTIFIER: + raise TypeError( + "oid must be X500_UNIQUE_IDENTIFIER for BitString type." + ) + if not isinstance(value, bytes): + raise TypeError("value must be bytes for BitString") + elif not isinstance(value, str): + raise TypeError("value argument must be a str") + + length_limits = _NAMEOID_LENGTH_LIMIT.get(oid) + if length_limits is not None: + min_length, max_length = length_limits + assert isinstance(value, str) + c_len = len(value.encode("utf8")) + if c_len < min_length or c_len > max_length: + msg = ( + f"Attribute's length must be >= {min_length} and " + f"<= {max_length}, but it was {c_len}" + ) + if _validate is True: + raise ValueError(msg) + else: + warnings.warn(msg, stacklevel=2) + + # The appropriate ASN1 string type varies by OID and is defined across + # multiple RFCs including 2459, 3280, and 5280. In general UTF8String + # is preferred (2459), but 3280 and 5280 specify several OIDs with + # alternate types. This means when we see the sentinel value we need + # to look up whether the OID has a non-UTF8 type. If it does, set it + # to that. Otherwise, UTF8! + if _type is None: + _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String) + + if not isinstance(_type, _ASN1Type): + raise TypeError("_type must be from the _ASN1Type enum") + + self._oid = oid + self._value: NameAttributeValueType = value + self._type: _ASN1Type = _type + + @property + def oid(self) -> ObjectIdentifier: + return self._oid + + @property + def value(self) -> NameAttributeValueType: + return self._value + + @property + def rfc4514_attribute_name(self) -> str: + """ + The short attribute name (for example "CN") if available, + otherwise the OID dotted string. + """ + return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string) + + def rfc4514_string( + self, attr_name_overrides: _OidNameMap | None = None + ) -> str: + """ + Format as RFC4514 Distinguished Name string. + + Use short attribute name if available, otherwise fall back to OID + dotted string. + """ + attr_name = ( + attr_name_overrides.get(self.oid) if attr_name_overrides else None + ) + if attr_name is None: + attr_name = self.rfc4514_attribute_name + + return f"{attr_name}={_escape_dn_value(self.value)}" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, NameAttribute): + return NotImplemented + + return self.oid == other.oid and self.value == other.value + + def __hash__(self) -> int: + return hash((self.oid, self.value)) + + def __repr__(self) -> str: + return f"" + + +class RelativeDistinguishedName: + def __init__(self, attributes: Iterable[NameAttribute[str | bytes]]): + attributes = list(attributes) + if not attributes: + raise ValueError("a relative distinguished name cannot be empty") + if not all(isinstance(x, NameAttribute) for x in attributes): + raise TypeError("attributes must be an iterable of NameAttribute") + + # Keep list and frozenset to preserve attribute order where it matters + self._attributes = attributes + self._attribute_set = frozenset(attributes) + + if len(self._attribute_set) != len(attributes): + raise ValueError("duplicate attributes are not allowed") + + def get_attributes_for_oid( + self, + oid: ObjectIdentifier, + ) -> list[NameAttribute[str | bytes]]: + return [i for i in self if i.oid == oid] + + def rfc4514_string( + self, attr_name_overrides: _OidNameMap | None = None + ) -> str: + """ + Format as RFC4514 Distinguished Name string. + + Within each RDN, attributes are joined by '+', although that is rarely + used in certificates. + """ + return "+".join( + attr.rfc4514_string(attr_name_overrides) + for attr in self._attributes + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, RelativeDistinguishedName): + return NotImplemented + + return self._attribute_set == other._attribute_set + + def __hash__(self) -> int: + return hash(self._attribute_set) + + def __iter__(self) -> Iterator[NameAttribute[str | bytes]]: + return iter(self._attributes) + + def __len__(self) -> int: + return len(self._attributes) + + def __repr__(self) -> str: + return f"" + + +class Name: + @typing.overload + def __init__( + self, attributes: Iterable[NameAttribute[str | bytes]] + ) -> None: ... + + @typing.overload + def __init__( + self, attributes: Iterable[RelativeDistinguishedName] + ) -> None: ... + + def __init__( + self, + attributes: Iterable[ + NameAttribute[str | bytes] | RelativeDistinguishedName + ], + ) -> None: + attributes = list(attributes) + if all(isinstance(x, NameAttribute) for x in attributes): + self._attributes = [ + RelativeDistinguishedName([typing.cast(NameAttribute, x)]) + for x in attributes + ] + elif all(isinstance(x, RelativeDistinguishedName) for x in attributes): + self._attributes = typing.cast( + list[RelativeDistinguishedName], attributes + ) + else: + raise TypeError( + "attributes must be a list of NameAttribute" + " or a list RelativeDistinguishedName" + ) + + @classmethod + def from_rfc4514_string( + cls, + data: str, + attr_name_overrides: _NameOidMap | None = None, + ) -> Name: + return _RFC4514NameParser(data, attr_name_overrides or {}).parse() + + @classmethod + def from_bytes(cls, data: bytes) -> Name: + """ + Parse a DER encoded X.509 name (the inverse of ``public_bytes``). + """ + return rust_x509.parse_name_bytes(data) + + def rfc4514_string( + self, attr_name_overrides: _OidNameMap | None = None + ) -> str: + """ + Format as RFC4514 Distinguished Name string. + For example 'CN=foobar.com,O=Foo Corp,C=US' + + An X.509 name is a two-level structure: a list of sets of attributes. + Each list element is separated by ',' and within each list element, set + elements are separated by '+'. The latter is almost never used in + real world certificates. According to RFC4514 section 2.1 the + RDNSequence must be reversed when converting to string representation. + """ + return ",".join( + attr.rfc4514_string(attr_name_overrides) + for attr in reversed(self._attributes) + ) + + def get_attributes_for_oid( + self, + oid: ObjectIdentifier, + ) -> list[NameAttribute[str | bytes]]: + return [i for i in self if i.oid == oid] + + @property + def rdns(self) -> list[RelativeDistinguishedName]: + return self._attributes + + def public_bytes(self, backend: typing.Any = None) -> bytes: + return rust_x509.encode_name_bytes(self) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Name): + return NotImplemented + + return self._attributes == other._attributes + + def __hash__(self) -> int: + # TODO: this is relatively expensive, if this looks like a bottleneck + # for you, consider optimizing! + return hash(tuple(self._attributes)) + + def __iter__(self) -> Iterator[NameAttribute[str | bytes]]: + for rdn in self._attributes: + yield from rdn + + def __len__(self) -> int: + return sum(len(rdn) for rdn in self._attributes) + + def __repr__(self) -> str: + return f"" + + +class _RFC4514NameParser: + _OID_RE = re.compile(r"(0|([1-9]\d*))(\.(0|([1-9]\d*)))+") + _DESCR_RE = re.compile(r"[a-zA-Z][a-zA-Z\d-]*") + + _ESCAPE_SPECIAL = r"[\\ #=\"\+,;<>]" + _ESCAPE_HEX = r"[\da-zA-Z]{2}" + _PAIR = rf"\\({_ESCAPE_SPECIAL}|{_ESCAPE_HEX})" + _PAIR_MULTI_RE = re.compile(rf"(\\{_ESCAPE_SPECIAL})|((\\{_ESCAPE_HEX})+)") + _LUTF1 = r"[\x01-\x1f\x21\x24-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" + _SUTF1 = r"[\x01-\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" + _TUTF1 = r"[\x01-\x1F\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]" + _UTFMB = rf"[\x80-{chr(sys.maxunicode)}]" + _LEADCHAR = rf"{_LUTF1}|{_UTFMB}" + _STRINGCHAR = rf"{_SUTF1}|{_UTFMB}" + _TRAILCHAR = rf"{_TUTF1}|{_UTFMB}" + _STRING_RE = re.compile( + rf""" + ( + ({_LEADCHAR}|{_PAIR}) + ( + ({_STRINGCHAR}|{_PAIR})* + ({_TRAILCHAR}|{_PAIR}) + )? + )? + """, + re.VERBOSE, + ) + _HEXSTRING_RE = re.compile(r"#([\da-zA-Z]{2})+") + + def __init__(self, data: str, attr_name_overrides: _NameOidMap) -> None: + self._data = data + self._idx = 0 + + self._attr_name_overrides = attr_name_overrides + + def _has_data(self) -> bool: + return self._idx < len(self._data) + + def _peek(self) -> str | None: + if self._has_data(): + return self._data[self._idx] + return None + + def _read_char(self, ch: str) -> None: + if self._peek() != ch: + raise ValueError + self._idx += 1 + + def _read_re(self, pat) -> str: + match = pat.match(self._data, pos=self._idx) + if match is None: + raise ValueError + val = match.group() + self._idx += len(val) + return val + + def parse(self) -> Name: + """ + Parses the `data` string and converts it to a Name. + + According to RFC4514 section 2.1 the RDNSequence must be + reversed when converting to string representation. So, when + we parse it, we need to reverse again to get the RDNs on the + correct order. + """ + + if not self._has_data(): + return Name([]) + + rdns = [self._parse_rdn()] + + while self._has_data(): + self._read_char(",") + rdns.append(self._parse_rdn()) + + return Name(reversed(rdns)) + + def _parse_rdn(self) -> RelativeDistinguishedName: + nas = [self._parse_na()] + while self._peek() == "+": + self._read_char("+") + nas.append(self._parse_na()) + + return RelativeDistinguishedName(nas) + + def _parse_na(self) -> NameAttribute[str]: + try: + oid_value = self._read_re(self._OID_RE) + except ValueError: + name = self._read_re(self._DESCR_RE) + oid = self._attr_name_overrides.get( + name, _NAME_TO_NAMEOID.get(name) + ) + if oid is None: + raise ValueError + else: + oid = ObjectIdentifier(oid_value) + + self._read_char("=") + if self._peek() == "#": + value = self._read_re(self._HEXSTRING_RE) + value = binascii.unhexlify(value[1:]).decode() + else: + raw_value = self._read_re(self._STRING_RE) + value = _unescape_dn_value(raw_value) + + return NameAttribute(oid, value) diff --git a/source/target-vendors/cp312/cryptography/x509/ocsp.py b/source/target-vendors/cp312/cryptography/x509/ocsp.py new file mode 100644 index 0000000..f61ed80 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/ocsp.py @@ -0,0 +1,379 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import datetime +from collections.abc import Iterable + +from cryptography import utils, x509 +from cryptography.hazmat.bindings._rust import ocsp +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.types import ( + CertificateIssuerPrivateKeyTypes, +) +from cryptography.x509.base import _reject_duplicate_extension + + +class OCSPResponderEncoding(utils.Enum): + HASH = "By Hash" + NAME = "By Name" + + +class OCSPResponseStatus(utils.Enum): + SUCCESSFUL = 0 + MALFORMED_REQUEST = 1 + INTERNAL_ERROR = 2 + TRY_LATER = 3 + SIG_REQUIRED = 5 + UNAUTHORIZED = 6 + + +_ALLOWED_HASHES = ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, +) + + +def _verify_algorithm(algorithm: hashes.HashAlgorithm) -> None: + if not isinstance(algorithm, _ALLOWED_HASHES): + raise ValueError( + "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512" + ) + + +class OCSPCertStatus(utils.Enum): + GOOD = 0 + REVOKED = 1 + UNKNOWN = 2 + + +class _SingleResponse: + def __init__( + self, + resp: tuple[x509.Certificate, x509.Certificate] | None, + resp_hash: tuple[bytes, bytes, int] | None, + algorithm: hashes.HashAlgorithm, + cert_status: OCSPCertStatus, + this_update: datetime.datetime, + next_update: datetime.datetime | None, + revocation_time: datetime.datetime | None, + revocation_reason: x509.ReasonFlags | None, + ): + _verify_algorithm(algorithm) + if not isinstance(this_update, datetime.datetime): + raise TypeError("this_update must be a datetime object") + if next_update is not None and not isinstance( + next_update, datetime.datetime + ): + raise TypeError("next_update must be a datetime object or None") + + self._resp = resp + self._resp_hash = resp_hash + self._algorithm = algorithm + self._this_update = this_update + self._next_update = next_update + + if not isinstance(cert_status, OCSPCertStatus): + raise TypeError( + "cert_status must be an item from the OCSPCertStatus enum" + ) + if cert_status is not OCSPCertStatus.REVOKED: + if revocation_time is not None: + raise ValueError( + "revocation_time can only be provided if the certificate " + "is revoked" + ) + if revocation_reason is not None: + raise ValueError( + "revocation_reason can only be provided if the certificate" + " is revoked" + ) + else: + if not isinstance(revocation_time, datetime.datetime): + raise TypeError("revocation_time must be a datetime object") + + if revocation_reason is not None and not isinstance( + revocation_reason, x509.ReasonFlags + ): + raise TypeError( + "revocation_reason must be an item from the ReasonFlags " + "enum or None" + ) + + self._cert_status = cert_status + self._revocation_time = revocation_time + self._revocation_reason = revocation_reason + + +OCSPRequest = ocsp.OCSPRequest +OCSPResponse = ocsp.OCSPResponse +OCSPSingleResponse = ocsp.OCSPSingleResponse + + +class OCSPRequestBuilder: + def __init__( + self, + request: tuple[ + x509.Certificate, x509.Certificate, hashes.HashAlgorithm + ] + | None = None, + request_hash: tuple[bytes, bytes, int, hashes.HashAlgorithm] + | None = None, + extensions: list[x509.Extension[x509.ExtensionType]] = [], + ) -> None: + self._request = request + self._request_hash = request_hash + self._extensions = extensions + + def add_certificate( + self, + cert: x509.Certificate, + issuer: x509.Certificate, + algorithm: hashes.HashAlgorithm, + ) -> OCSPRequestBuilder: + if self._request is not None or self._request_hash is not None: + raise ValueError("Only one certificate can be added to a request") + + _verify_algorithm(algorithm) + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate + ): + raise TypeError("cert and issuer must be a Certificate") + + return OCSPRequestBuilder( + (cert, issuer, algorithm), self._request_hash, self._extensions + ) + + def add_certificate_by_hash( + self, + issuer_name_hash: bytes, + issuer_key_hash: bytes, + serial_number: int, + algorithm: hashes.HashAlgorithm, + ) -> OCSPRequestBuilder: + if self._request is not None or self._request_hash is not None: + raise ValueError("Only one certificate can be added to a request") + + if not isinstance(serial_number, int): + raise TypeError("serial_number must be an integer") + + _verify_algorithm(algorithm) + utils._check_bytes("issuer_name_hash", issuer_name_hash) + utils._check_bytes("issuer_key_hash", issuer_key_hash) + if algorithm.digest_size != len( + issuer_name_hash + ) or algorithm.digest_size != len(issuer_key_hash): + raise ValueError( + "issuer_name_hash and issuer_key_hash must be the same length " + "as the digest size of the algorithm" + ) + + return OCSPRequestBuilder( + self._request, + (issuer_name_hash, issuer_key_hash, serial_number, algorithm), + self._extensions, + ) + + def add_extension( + self, extval: x509.ExtensionType, critical: bool + ) -> OCSPRequestBuilder: + if not isinstance(extval, x509.ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = x509.Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return OCSPRequestBuilder( + self._request, self._request_hash, [*self._extensions, extension] + ) + + def build(self) -> OCSPRequest: + if self._request is None and self._request_hash is None: + raise ValueError("You must add a certificate before building") + + return ocsp.create_ocsp_request(self) + + +class OCSPResponseBuilder: + def __init__( + self, + response: _SingleResponse | None = None, + responder_id: tuple[x509.Certificate, OCSPResponderEncoding] + | None = None, + certs: list[x509.Certificate] | None = None, + extensions: list[x509.Extension[x509.ExtensionType]] = [], + ): + self._response = response + self._responder_id = responder_id + self._certs = certs + self._extensions = extensions + + def add_response( + self, + cert: x509.Certificate, + issuer: x509.Certificate, + algorithm: hashes.HashAlgorithm, + cert_status: OCSPCertStatus, + this_update: datetime.datetime, + next_update: datetime.datetime | None, + revocation_time: datetime.datetime | None, + revocation_reason: x509.ReasonFlags | None, + ) -> OCSPResponseBuilder: + if self._response is not None: + raise ValueError("Only one response per OCSPResponse.") + + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate + ): + raise TypeError("cert and issuer must be a Certificate") + + singleresp = _SingleResponse( + (cert, issuer), + None, + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, + ) + return OCSPResponseBuilder( + singleresp, + self._responder_id, + self._certs, + self._extensions, + ) + + def add_response_by_hash( + self, + issuer_name_hash: bytes, + issuer_key_hash: bytes, + serial_number: int, + algorithm: hashes.HashAlgorithm, + cert_status: OCSPCertStatus, + this_update: datetime.datetime, + next_update: datetime.datetime | None, + revocation_time: datetime.datetime | None, + revocation_reason: x509.ReasonFlags | None, + ) -> OCSPResponseBuilder: + if self._response is not None: + raise ValueError("Only one response per OCSPResponse.") + + if not isinstance(serial_number, int): + raise TypeError("serial_number must be an integer") + + utils._check_bytes("issuer_name_hash", issuer_name_hash) + utils._check_bytes("issuer_key_hash", issuer_key_hash) + _verify_algorithm(algorithm) + if algorithm.digest_size != len( + issuer_name_hash + ) or algorithm.digest_size != len(issuer_key_hash): + raise ValueError( + "issuer_name_hash and issuer_key_hash must be the same length " + "as the digest size of the algorithm" + ) + + singleresp = _SingleResponse( + None, + (issuer_name_hash, issuer_key_hash, serial_number), + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, + ) + return OCSPResponseBuilder( + singleresp, + self._responder_id, + self._certs, + self._extensions, + ) + + def responder_id( + self, encoding: OCSPResponderEncoding, responder_cert: x509.Certificate + ) -> OCSPResponseBuilder: + if self._responder_id is not None: + raise ValueError("responder_id can only be set once") + if not isinstance(responder_cert, x509.Certificate): + raise TypeError("responder_cert must be a Certificate") + if not isinstance(encoding, OCSPResponderEncoding): + raise TypeError( + "encoding must be an element from OCSPResponderEncoding" + ) + + return OCSPResponseBuilder( + self._response, + (responder_cert, encoding), + self._certs, + self._extensions, + ) + + def certificates( + self, certs: Iterable[x509.Certificate] + ) -> OCSPResponseBuilder: + if self._certs is not None: + raise ValueError("certificates may only be set once") + certs = list(certs) + if len(certs) == 0: + raise ValueError("certs must not be an empty list") + if not all(isinstance(x, x509.Certificate) for x in certs): + raise TypeError("certs must be a list of Certificates") + return OCSPResponseBuilder( + self._response, + self._responder_id, + certs, + self._extensions, + ) + + def add_extension( + self, extval: x509.ExtensionType, critical: bool + ) -> OCSPResponseBuilder: + if not isinstance(extval, x509.ExtensionType): + raise TypeError("extension must be an ExtensionType") + + extension = x509.Extension(extval.oid, critical, extval) + _reject_duplicate_extension(extension, self._extensions) + + return OCSPResponseBuilder( + self._response, + self._responder_id, + self._certs, + [*self._extensions, extension], + ) + + def sign( + self, + private_key: CertificateIssuerPrivateKeyTypes, + algorithm: hashes.HashAlgorithm | None, + ) -> OCSPResponse: + if self._response is None: + raise ValueError("You must add a response before signing") + if self._responder_id is None: + raise ValueError("You must add a responder_id before signing") + + return ocsp.create_ocsp_response( + OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm + ) + + @classmethod + def build_unsuccessful( + cls, response_status: OCSPResponseStatus + ) -> OCSPResponse: + if not isinstance(response_status, OCSPResponseStatus): + raise TypeError( + "response_status must be an item from OCSPResponseStatus" + ) + if response_status is OCSPResponseStatus.SUCCESSFUL: + raise ValueError("response_status cannot be SUCCESSFUL") + + return ocsp.create_ocsp_response(response_status, None, None, None) + + +load_der_ocsp_request = ocsp.load_der_ocsp_request +load_der_ocsp_response = ocsp.load_der_ocsp_response diff --git a/source/target-vendors/cp312/cryptography/x509/oid.py b/source/target-vendors/cp312/cryptography/x509/oid.py new file mode 100644 index 0000000..520fc7a --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/oid.py @@ -0,0 +1,37 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +from cryptography.hazmat._oid import ( + AttributeOID, + AuthorityInformationAccessOID, + CertificatePoliciesOID, + CRLEntryExtensionOID, + ExtendedKeyUsageOID, + ExtensionOID, + NameOID, + ObjectIdentifier, + OCSPExtensionOID, + OtherNameFormOID, + PublicKeyAlgorithmOID, + SignatureAlgorithmOID, + SubjectInformationAccessOID, +) + +__all__ = [ + "AttributeOID", + "AuthorityInformationAccessOID", + "CRLEntryExtensionOID", + "CertificatePoliciesOID", + "ExtendedKeyUsageOID", + "ExtensionOID", + "NameOID", + "OCSPExtensionOID", + "ObjectIdentifier", + "OtherNameFormOID", + "PublicKeyAlgorithmOID", + "SignatureAlgorithmOID", + "SubjectInformationAccessOID", +] diff --git a/source/target-vendors/cp312/cryptography/x509/verification.py b/source/target-vendors/cp312/cryptography/x509/verification.py new file mode 100644 index 0000000..2db4324 --- /dev/null +++ b/source/target-vendors/cp312/cryptography/x509/verification.py @@ -0,0 +1,34 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import typing + +from cryptography.hazmat.bindings._rust import x509 as rust_x509 +from cryptography.x509.general_name import DNSName, IPAddress + +__all__ = [ + "ClientVerifier", + "Criticality", + "ExtensionPolicy", + "Policy", + "PolicyBuilder", + "ServerVerifier", + "Store", + "Subject", + "VerificationError", + "VerifiedClient", +] + +Store = rust_x509.Store +Subject = typing.Union[DNSName, IPAddress] +VerifiedClient = rust_x509.VerifiedClient +ClientVerifier = rust_x509.ClientVerifier +ServerVerifier = rust_x509.ServerVerifier +PolicyBuilder = rust_x509.PolicyBuilder +Policy = rust_x509.Policy +ExtensionPolicy = rust_x509.ExtensionPolicy +Criticality = rust_x509.Criticality +VerificationError = rust_x509.VerificationError diff --git a/source/target-vendors/cp312/dotenv/__init__.py b/source/target-vendors/cp312/dotenv/__init__.py new file mode 100644 index 0000000..dde24a0 --- /dev/null +++ b/source/target-vendors/cp312/dotenv/__init__.py @@ -0,0 +1,51 @@ +from typing import Any, Optional + +from .main import dotenv_values, find_dotenv, get_key, load_dotenv, set_key, unset_key + + +def load_ipython_extension(ipython: Any) -> None: + from .ipython import load_ipython_extension + + load_ipython_extension(ipython) + + +def get_cli_string( + path: Optional[str] = None, + action: Optional[str] = None, + key: Optional[str] = None, + value: Optional[str] = None, + quote: Optional[str] = None, +): + """Returns a string suitable for running as a shell script. + + Useful for converting a arguments passed to a fabric task + to be passed to a `local` or `run` command. + """ + command = ["dotenv"] + if quote: + command.append(f"-q {quote}") + if path: + command.append(f"-f {path}") + if action: + command.append(action) + if key: + command.append(key) + if value: + if " " in value: + command.append(f'"{value}"') + else: + command.append(value) + + return " ".join(command).strip() + + +__all__ = [ + "get_cli_string", + "load_dotenv", + "dotenv_values", + "get_key", + "set_key", + "unset_key", + "find_dotenv", + "load_ipython_extension", +] diff --git a/source/target-vendors/cp312/dotenv/__main__.py b/source/target-vendors/cp312/dotenv/__main__.py new file mode 100644 index 0000000..3977f55 --- /dev/null +++ b/source/target-vendors/cp312/dotenv/__main__.py @@ -0,0 +1,6 @@ +"""Entry point for cli, enables execution with `python -m dotenv`""" + +from .cli import cli + +if __name__ == "__main__": + cli() diff --git a/source/target-vendors/cp312/dotenv/cli.py b/source/target-vendors/cp312/dotenv/cli.py new file mode 100644 index 0000000..79613e2 --- /dev/null +++ b/source/target-vendors/cp312/dotenv/cli.py @@ -0,0 +1,247 @@ +import json +import os +import shlex +import sys +from contextlib import contextmanager +from typing import IO, Any, Dict, Iterator, List, Optional + +if sys.platform == "win32": + from subprocess import Popen + +try: + import click +except ImportError: + sys.stderr.write( + "It seems python-dotenv is not installed with cli option. \n" + 'Run pip install "python-dotenv[cli]" to fix this.' + ) + sys.exit(1) + +from .main import dotenv_values, set_key, unset_key +from .version import __version__ + + +def enumerate_env() -> Optional[str]: + """ + Return a path for the ${pwd}/.env file. + + If pwd does not exist, return None. + """ + try: + cwd = os.getcwd() + except FileNotFoundError: + return None + path = os.path.join(cwd, ".env") + return path + + +@click.group() +@click.option( + "-f", + "--file", + default=enumerate_env(), + type=click.Path(file_okay=True), + help="Location of the .env file, defaults to .env file in current working directory.", +) +@click.option( + "-q", + "--quote", + default="always", + type=click.Choice(["always", "never", "auto"]), + help="Whether to quote or not the variable values. Default mode is always. This does not affect parsing.", +) +@click.option( + "-e", + "--export", + default=False, + type=click.BOOL, + help="Whether to write the dot file as an executable bash script.", +) +@click.version_option(version=__version__) +@click.pass_context +def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None: + """This script is used to set, get or unset values from a .env file.""" + ctx.obj = {"QUOTE": quote, "EXPORT": export, "FILE": file} + + +@contextmanager +def stream_file(path: os.PathLike) -> Iterator[IO[str]]: + """ + Open a file and yield the corresponding (decoded) stream. + + Exits with error code 2 if the file cannot be opened. + """ + + try: + with open(path) as stream: + yield stream + except OSError as exc: + print(f"Error opening env file: {exc}", file=sys.stderr) + sys.exit(2) + + +@cli.command(name="list") +@click.pass_context +@click.option( + "--format", + "output_format", + default="simple", + type=click.Choice(["simple", "json", "shell", "export"]), + help="The format in which to display the list. Default format is simple, " + "which displays name=value without quotes.", +) +def list_values(ctx: click.Context, output_format: str) -> None: + """Display all the stored key/value.""" + file = ctx.obj["FILE"] + + with stream_file(file) as stream: + values = dotenv_values(stream=stream) + + if output_format == "json": + click.echo(json.dumps(values, indent=2, sort_keys=True)) + else: + prefix = "export " if output_format == "export" else "" + for k in sorted(values): + v = values[k] + if v is not None: + if output_format in ("export", "shell"): + v = shlex.quote(v) + click.echo(f"{prefix}{k}={v}") + + +@cli.command(name="set") +@click.pass_context +@click.argument("key", required=True) +@click.argument("value", required=True) +def set_value(ctx: click.Context, key: Any, value: Any) -> None: + """ + Store the given key/value. + + This doesn't follow symlinks, to avoid accidentally modifying a file at a + potentially untrusted path. + """ + + file = ctx.obj["FILE"] + quote = ctx.obj["QUOTE"] + export = ctx.obj["EXPORT"] + success, key, value = set_key(file, key, value, quote, export) + if success: + click.echo(f"{key}={value}") + else: + sys.exit(1) + + +@cli.command() +@click.pass_context +@click.argument("key", required=True) +def get(ctx: click.Context, key: Any) -> None: + """Retrieve the value for the given key.""" + file = ctx.obj["FILE"] + + with stream_file(file) as stream: + values = dotenv_values(stream=stream) + + stored_value = values.get(key) + if stored_value: + click.echo(stored_value) + else: + sys.exit(1) + + +@cli.command() +@click.pass_context +@click.argument("key", required=True) +def unset(ctx: click.Context, key: Any) -> None: + """ + Removes the given key. + + This doesn't follow symlinks, to avoid accidentally modifying a file at a + potentially untrusted path. + """ + file = ctx.obj["FILE"] + quote = ctx.obj["QUOTE"] + success, key = unset_key(file, key, quote) + if success: + click.echo(f"Successfully removed {key}") + else: + sys.exit(1) + + +@cli.command( + context_settings={ + "allow_extra_args": True, + "allow_interspersed_args": False, + "ignore_unknown_options": True, + } +) +@click.pass_context +@click.option( + "--override/--no-override", + default=True, + help="Override variables from the environment file with those from the .env file.", +) +@click.argument("commandline", nargs=-1, type=click.UNPROCESSED) +def run(ctx: click.Context, override: bool, commandline: tuple[str, ...]) -> None: + """Run command with environment variables present.""" + file = ctx.obj["FILE"] + if not os.path.isfile(file): + raise click.BadParameter( + f"Invalid value for '-f' \"{file}\" does not exist.", ctx=ctx + ) + dotenv_as_dict = { + k: v + for (k, v) in dotenv_values(file).items() + if v is not None and (override or k not in os.environ) + } + + if not commandline: + click.echo("No command given.") + sys.exit(1) + + run_command([*commandline, *ctx.args], dotenv_as_dict) + + +def run_command(command: List[str], env: Dict[str, str]) -> None: + """Replace the current process with the specified command. + + Replaces the current process with the specified command and the variables from `env` + added in the current environment variables. + + Parameters + ---------- + command: List[str] + The command and it's parameters + env: Dict + The additional environment variables + + Returns + ------- + None + This function does not return any value. It replaces the current process with the new one. + + """ + # copy the current environment variables and add the vales from + # `env` + cmd_env = os.environ.copy() + cmd_env.update(env) + + if sys.platform == "win32": + # execvpe on Windows returns control immediately + # rather than once the command has finished. + try: + p = Popen( + command, universal_newlines=True, bufsize=0, shell=False, env=cmd_env + ) + except FileNotFoundError: + print(f"Command not found: {command[0]}", file=sys.stderr) + sys.exit(1) + + _, _ = p.communicate() + + sys.exit(p.returncode) + else: + try: + os.execvpe(command[0], args=command, env=cmd_env) + except FileNotFoundError: + print(f"Command not found: {command[0]}", file=sys.stderr) + sys.exit(1) diff --git a/source/target-vendors/cp312/dotenv/ipython.py b/source/target-vendors/cp312/dotenv/ipython.py new file mode 100644 index 0000000..4e7edbb --- /dev/null +++ b/source/target-vendors/cp312/dotenv/ipython.py @@ -0,0 +1,50 @@ +from IPython.core.magic import Magics, line_magic, magics_class # type: ignore +from IPython.core.magic_arguments import ( + argument, + magic_arguments, + parse_argstring, +) # type: ignore + +from .main import find_dotenv, load_dotenv + + +@magics_class +class IPythonDotEnv(Magics): + @magic_arguments() + @argument( + "-o", + "--override", + action="store_true", + help="Indicate to override existing variables", + ) + @argument( + "-v", + "--verbose", + action="store_true", + help="Indicate function calls to be verbose", + ) + @argument( + "dotenv_path", + nargs="?", + type=str, + default=".env", + help="Search in increasingly higher folders for the `dotenv_path`", + ) + @line_magic + def dotenv(self, line): + args = parse_argstring(self.dotenv, line) + # Locate the .env file + dotenv_path = args.dotenv_path + try: + dotenv_path = find_dotenv(dotenv_path, True, True) + except IOError: + print("cannot find .env file") + return + + # Load the .env file + load_dotenv(dotenv_path, verbose=args.verbose, override=args.override) + + +def load_ipython_extension(ipython): + """Register the %dotenv magic.""" + ipython.register_magics(IPythonDotEnv) diff --git a/source/target-vendors/cp312/dotenv/main.py b/source/target-vendors/cp312/dotenv/main.py new file mode 100644 index 0000000..3123690 --- /dev/null +++ b/source/target-vendors/cp312/dotenv/main.py @@ -0,0 +1,487 @@ +import io +import logging +import os +import pathlib +import stat +import sys +import tempfile +from collections import OrderedDict +from contextlib import contextmanager +from typing import IO, Dict, Iterable, Iterator, Mapping, Optional, Tuple, Union + +from .parser import Binding, parse_stream +from .variables import parse_variables + +# A type alias for a string path to be used for the paths in this file. +# These paths may flow to `open()` and `os.replace()`. +StrPath = Union[str, "os.PathLike[str]"] + +logger = logging.getLogger(__name__) + + +def _load_dotenv_disabled() -> bool: + """ + Determine if dotenv loading has been disabled. + """ + if "PYTHON_DOTENV_DISABLED" not in os.environ: + return False + value = os.environ["PYTHON_DOTENV_DISABLED"].casefold() + return value in {"1", "true", "t", "yes", "y"} + + +def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding]: + for mapping in mappings: + if mapping.error: + logger.warning( + "python-dotenv could not parse statement starting at line %s", + mapping.original.line, + ) + yield mapping + + +class DotEnv: + def __init__( + self, + dotenv_path: Optional[StrPath], + stream: Optional[IO[str]] = None, + verbose: bool = False, + encoding: Optional[str] = None, + interpolate: bool = True, + override: bool = True, + ) -> None: + self.dotenv_path: Optional[StrPath] = dotenv_path + self.stream: Optional[IO[str]] = stream + self._dict: Optional[Dict[str, Optional[str]]] = None + self.verbose: bool = verbose + self.encoding: Optional[str] = encoding + self.interpolate: bool = interpolate + self.override: bool = override + + @contextmanager + def _get_stream(self) -> Iterator[IO[str]]: + if self.dotenv_path and _is_file_or_fifo(self.dotenv_path): + with open(self.dotenv_path, encoding=self.encoding) as stream: + yield stream + elif self.stream is not None: + yield self.stream + else: + if self.verbose: + logger.info( + "python-dotenv could not find configuration file %s.", + self.dotenv_path or ".env", + ) + yield io.StringIO("") + + def dict(self) -> Dict[str, Optional[str]]: + """Return dotenv as dict""" + if self._dict is not None: + return self._dict + + raw_values = self.parse() + + if self.interpolate: + self._dict = OrderedDict( + resolve_variables(raw_values, override=self.override) + ) + else: + self._dict = OrderedDict(raw_values) + + return self._dict + + def parse(self) -> Iterator[Tuple[str, Optional[str]]]: + with self._get_stream() as stream: + for mapping in with_warn_for_invalid_lines(parse_stream(stream)): + if mapping.key is not None: + yield mapping.key, mapping.value + + def set_as_environment_variables(self) -> bool: + """ + Load the current dotenv as system environment variable. + """ + if not self.dict(): + return False + + for k, v in self.dict().items(): + if k in os.environ and not self.override: + continue + if v is not None: + os.environ[k] = v + + return True + + def get(self, key: str) -> Optional[str]: + """ """ + data = self.dict() + + if key in data: + return data[key] + + if self.verbose: + logger.warning("Key %s not found in %s.", key, self.dotenv_path) + + return None + + +def get_key( + dotenv_path: StrPath, + key_to_get: str, + encoding: Optional[str] = "utf-8", +) -> Optional[str]: + """ + Get the value of a given key from the given .env. + + Returns `None` if the key isn't found or doesn't have a value. + """ + return DotEnv(dotenv_path, verbose=True, encoding=encoding).get(key_to_get) + + +@contextmanager +def rewrite( + path: StrPath, + encoding: Optional[str], + follow_symlinks: bool = False, +) -> Iterator[Tuple[IO[str], IO[str]]]: + if follow_symlinks: + path = os.path.realpath(path) + + try: + source: IO[str] = open(path, encoding=encoding) + try: + path_stat = os.lstat(path) + original_mode: Optional[int] = ( + stat.S_IMODE(path_stat.st_mode) + if stat.S_ISREG(path_stat.st_mode) + else None + ) + except BaseException: + source.close() + raise + except FileNotFoundError: + source = io.StringIO("") + original_mode = None + + with tempfile.NamedTemporaryFile( + mode="w", + encoding=encoding, + delete=False, + prefix=".tmp_", + dir=os.path.dirname(os.path.abspath(path)), + ) as dest: + dest_path = pathlib.Path(dest.name) + error = None + + try: + with source: + yield (source, dest) + except BaseException as err: + error = err + + if error is None: + try: + if original_mode is not None: + os.chmod(dest_path, original_mode) + + os.replace(dest_path, path) + except BaseException: + dest_path.unlink(missing_ok=True) + raise + else: + dest_path.unlink(missing_ok=True) + raise error from None + + +def set_key( + dotenv_path: StrPath, + key_to_set: str, + value_to_set: str, + quote_mode: str = "always", + export: bool = False, + encoding: Optional[str] = "utf-8", + follow_symlinks: bool = False, +) -> Tuple[Optional[bool], str, str]: + """ + Adds or Updates a key/value to the given .env + + The target .env file is created if it doesn't exist. + + This function doesn't follow symlinks by default, to avoid accidentally + modifying a file at a potentially untrusted path. If you don't need this + protection and need symlinks to be followed, use `follow_symlinks`. + """ + if quote_mode not in ("always", "auto", "never"): + raise ValueError(f"Unknown quote_mode: {quote_mode}") + + quote = quote_mode == "always" or ( + quote_mode == "auto" and not value_to_set.isalnum() + ) + + if quote: + # The single-quoted-value parser decodes `\\` and `\'`, so both have to + # be escaped here for the value to survive a write/read round-trip. + # Backslashes first, otherwise the backslash added by the quote + # escaping would be escaped in turn. + escaped = value_to_set.replace("\\", "\\\\").replace("'", "\\'") + value_out = f"'{escaped}'" + else: + value_out = value_to_set + if export: + line_out = f"export {key_to_set}={value_out}\n" + else: + line_out = f"{key_to_set}={value_out}\n" + + with rewrite(dotenv_path, encoding=encoding, follow_symlinks=follow_symlinks) as ( + source, + dest, + ): + replaced = False + missing_newline = False + for mapping in with_warn_for_invalid_lines(parse_stream(source)): + if mapping.key == key_to_set: + dest.write(line_out) + replaced = True + else: + dest.write(mapping.original.string) + missing_newline = not mapping.original.string.endswith("\n") + if not replaced: + if missing_newline: + dest.write("\n") + dest.write(line_out) + + return True, key_to_set, value_to_set + + +def unset_key( + dotenv_path: StrPath, + key_to_unset: str, + quote_mode: str = "always", + encoding: Optional[str] = "utf-8", + follow_symlinks: bool = False, +) -> Tuple[Optional[bool], str]: + """ + Removes a given key from the given `.env` file. + + If the .env path given doesn't exist, fails. + If the given key doesn't exist in the .env, fails. + + This function doesn't follow symlinks by default, to avoid accidentally + modifying a file at a potentially untrusted path. If you don't need this + protection and need symlinks to be followed, use `follow_symlinks`. + """ + if not os.path.exists(dotenv_path): + logger.warning("Can't delete from %s - it doesn't exist.", dotenv_path) + return None, key_to_unset + + removed = False + with rewrite(dotenv_path, encoding=encoding, follow_symlinks=follow_symlinks) as ( + source, + dest, + ): + for mapping in with_warn_for_invalid_lines(parse_stream(source)): + if mapping.key == key_to_unset: + removed = True + else: + dest.write(mapping.original.string) + + if not removed: + logger.warning( + "Key %s not removed from %s - key doesn't exist.", key_to_unset, dotenv_path + ) + return None, key_to_unset + + return removed, key_to_unset + + +def resolve_variables( + values: Iterable[Tuple[str, Optional[str]]], + override: bool, +) -> Mapping[str, Optional[str]]: + new_values: Dict[str, Optional[str]] = {} + + for name, value in values: + if value is None: + result = None + else: + atoms = parse_variables(value) + env: Dict[str, Optional[str]] = {} + if override: + env.update(os.environ) # type: ignore + env.update(new_values) + else: + env.update(new_values) + env.update(os.environ) # type: ignore + result = "".join(atom.resolve(env) for atom in atoms) + + new_values[name] = result + + return new_values + + +def _walk_to_root(path: str) -> Iterator[str]: + """ + Yield directories starting from the given directory up to the root + """ + if not os.path.exists(path): + raise IOError("Starting path not found") + + if os.path.isfile(path): + path = os.path.dirname(path) + + last_dir = None + current_dir = os.path.abspath(path) + while last_dir != current_dir: + yield current_dir + parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir)) + last_dir, current_dir = current_dir, parent_dir + + +def find_dotenv( + filename: str = ".env", + raise_error_if_not_found: bool = False, + usecwd: bool = False, +) -> str: + """ + Search in increasingly higher folders for the given file + + Returns path to the file if found, or an empty string otherwise + """ + + def _is_interactive(): + """Decide whether this is running in a REPL or IPython notebook""" + if hasattr(sys, "ps1") or hasattr(sys, "ps2"): + return True + try: + main = __import__("__main__", None, None, fromlist=["__file__"]) + except ModuleNotFoundError: + return False + return not hasattr(main, "__file__") + + def _is_debugger(): + return sys.gettrace() is not None + + if usecwd or _is_interactive() or _is_debugger() or getattr(sys, "frozen", False): + # Should work without __file__, e.g. in REPL or IPython notebook. + path = os.getcwd() + else: + # will work for .py files + frame = sys._getframe() + current_file = __file__ + + while frame.f_code.co_filename == current_file or not os.path.exists( + frame.f_code.co_filename + ): + assert frame.f_back is not None + frame = frame.f_back + frame_filename = frame.f_code.co_filename + path = os.path.dirname(os.path.abspath(frame_filename)) + + for dirname in _walk_to_root(path): + check_path = os.path.join(dirname, filename) + if _is_file_or_fifo(check_path): + return check_path + + if raise_error_if_not_found: + raise IOError("File not found") + + return "" + + +def load_dotenv( + dotenv_path: Optional[StrPath] = None, + stream: Optional[IO[str]] = None, + verbose: bool = False, + override: bool = False, + interpolate: bool = True, + encoding: Optional[str] = "utf-8", +) -> bool: + """Parse a .env file and then load all the variables found as environment variables. + + Parameters: + dotenv_path: Absolute or relative path to .env file. + stream: Text stream (such as `io.StringIO`) with .env content, used if + `dotenv_path` is `None`. + verbose: Whether to output a warning the .env file is missing. + override: Whether to override the system environment variables with the variables + from the `.env` file. + interpolate: Whether to interpolate variables using POSIX variable expansion. + encoding: Encoding to be used to read the file. + Returns: + Bool: True if at least one environment variable is set else False + + If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the + .env file with its default parameters. If you need to change the default parameters + of `find_dotenv()`, you can explicitly call `find_dotenv()` and pass the result + to this function as `dotenv_path`. + + If the environment variable `PYTHON_DOTENV_DISABLED` is set to a truthy value, + .env loading is disabled. + """ + if _load_dotenv_disabled(): + logger.debug( + "python-dotenv: .env loading disabled by PYTHON_DOTENV_DISABLED environment variable" + ) + return False + + if dotenv_path is None and stream is None: + dotenv_path = find_dotenv() + + dotenv = DotEnv( + dotenv_path=dotenv_path, + stream=stream, + verbose=verbose, + interpolate=interpolate, + override=override, + encoding=encoding, + ) + return dotenv.set_as_environment_variables() + + +def dotenv_values( + dotenv_path: Optional[StrPath] = None, + stream: Optional[IO[str]] = None, + verbose: bool = False, + interpolate: bool = True, + encoding: Optional[str] = "utf-8", +) -> Dict[str, Optional[str]]: + """ + Parse a .env file and return its content as a dict. + + The returned dict will have `None` values for keys without values in the .env file. + For example, `foo=bar` results in `{"foo": "bar"}` whereas `foo` alone results in + `{"foo": None}` + + Parameters: + dotenv_path: Absolute or relative path to the .env file. + stream: `StringIO` object with .env content, used if `dotenv_path` is `None`. + verbose: Whether to output a warning if the .env file is missing. + interpolate: Whether to interpolate variables using POSIX variable expansion. + encoding: Encoding to be used to read the file. + + If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the + .env file. + """ + if dotenv_path is None and stream is None: + dotenv_path = find_dotenv() + + return DotEnv( + dotenv_path=dotenv_path, + stream=stream, + verbose=verbose, + interpolate=interpolate, + override=True, + encoding=encoding, + ).dict() + + +def _is_file_or_fifo(path: StrPath) -> bool: + """ + Return True if `path` exists and is either a regular file or a FIFO. + """ + if os.path.isfile(path): + return True + + try: + st = os.stat(path) + except (FileNotFoundError, OSError): + return False + + return stat.S_ISFIFO(st.st_mode) diff --git a/source/target-vendors/cp312/dotenv/parser.py b/source/target-vendors/cp312/dotenv/parser.py new file mode 100644 index 0000000..02648ab --- /dev/null +++ b/source/target-vendors/cp312/dotenv/parser.py @@ -0,0 +1,184 @@ +import codecs +import re +from typing import ( + IO, + Iterator, + Match, + NamedTuple, + Optional, + Pattern, + Sequence, +) + + +def make_regex(string: str, extra_flags: int = 0) -> Pattern[str]: + return re.compile(string, re.UNICODE | extra_flags) + + +_newline = make_regex(r"(\r\n|\n|\r)") +_multiline_whitespace = make_regex(r"\s*", extra_flags=re.MULTILINE) +_whitespace = make_regex(r"[^\S\r\n]*") +_export = make_regex(r"(?:export[^\S\r\n]+)?") +_single_quoted_key = make_regex(r"'([^']+)'") +_unquoted_key = make_regex(r"([^=\#\s]+)") +_equal_sign = make_regex(r"(=[^\S\r\n]*)") +# A backslash always escapes the character after it, so that an escaped +# backslash (`\\`) is not mistaken for the start of an escaped quote. +_single_quoted_value = make_regex(r"'((?:\\.|[^'\\])*)'", extra_flags=re.DOTALL) +_double_quoted_value = make_regex(r'"((?:\\.|[^"\\])*)"', extra_flags=re.DOTALL) +_unquoted_value = make_regex(r"([^\r\n]*)") +_comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?") +_end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)") +_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?") +_double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]") +_single_quote_escapes = make_regex(r"\\[\\']") + + +class Original(NamedTuple): + string: str + line: int + + +class Binding(NamedTuple): + key: Optional[str] + value: Optional[str] + original: Original + error: bool + + +class Position: + def __init__(self, chars: int, line: int) -> None: + self.chars = chars + self.line = line + + @classmethod + def start(cls) -> "Position": + return cls(chars=0, line=1) + + def set(self, other: "Position") -> None: + self.chars = other.chars + self.line = other.line + + def advance(self, string: str) -> None: + self.chars += len(string) + self.line += len(re.findall(_newline, string)) + + +class Error(Exception): + pass + + +class Reader: + def __init__(self, stream: IO[str]) -> None: + self.string = stream.read().removeprefix("\ufeff") + self.position = Position.start() + self.mark = Position.start() + + def has_next(self) -> bool: + return self.position.chars < len(self.string) + + def set_mark(self) -> None: + self.mark.set(self.position) + + def get_marked(self) -> Original: + return Original( + string=self.string[self.mark.chars : self.position.chars], + line=self.mark.line, + ) + + def peek(self, count: int) -> str: + return self.string[self.position.chars : self.position.chars + count] + + def read(self, count: int) -> str: + result = self.string[self.position.chars : self.position.chars + count] + if len(result) < count: + raise Error("read: End of string") + self.position.advance(result) + return result + + def read_regex(self, regex: Pattern[str]) -> Sequence[str]: + match = regex.match(self.string, self.position.chars) + if match is None: + raise Error("read_regex: Pattern not found") + self.position.advance(self.string[match.start() : match.end()]) + return match.groups() + + +def decode_escapes(regex: Pattern[str], string: str) -> str: + def decode_match(match: Match[str]) -> str: + return codecs.decode(match.group(0), "unicode-escape") # type: ignore + + return regex.sub(decode_match, string) + + +def parse_key(reader: Reader) -> Optional[str]: + char = reader.peek(1) + if char == "#": + return None + elif char == "'": + (key,) = reader.read_regex(_single_quoted_key) + else: + (key,) = reader.read_regex(_unquoted_key) + return key + + +def parse_unquoted_value(reader: Reader) -> str: + (part,) = reader.read_regex(_unquoted_value) + return re.sub(r"\s+#.*", "", part).rstrip() + + +def parse_value(reader: Reader) -> str: + char = reader.peek(1) + if char == "'": + (value,) = reader.read_regex(_single_quoted_value) + return decode_escapes(_single_quote_escapes, value) + elif char == '"': + (value,) = reader.read_regex(_double_quoted_value) + return decode_escapes(_double_quote_escapes, value) + elif char in ("", "\n", "\r"): + return "" + else: + return parse_unquoted_value(reader) + + +def parse_binding(reader: Reader) -> Binding: + reader.set_mark() + try: + reader.read_regex(_multiline_whitespace) + if not reader.has_next(): + return Binding( + key=None, + value=None, + original=reader.get_marked(), + error=False, + ) + reader.read_regex(_export) + key = parse_key(reader) + reader.read_regex(_whitespace) + if reader.peek(1) == "=": + reader.read_regex(_equal_sign) + value: Optional[str] = parse_value(reader) + else: + value = None + reader.read_regex(_comment) + reader.read_regex(_end_of_line) + return Binding( + key=key, + value=value, + original=reader.get_marked(), + error=False, + ) + except Error: + reader.read_regex(_rest_of_line) + return Binding( + key=None, + value=None, + original=reader.get_marked(), + error=True, + ) + + +def parse_stream(stream: IO[str]) -> Iterator[Binding]: + reader = Reader(stream) + while reader.has_next(): + yield parse_binding(reader) diff --git a/source/target-vendors/cp312/dotenv/py.typed b/source/target-vendors/cp312/dotenv/py.typed new file mode 100644 index 0000000..7632ecf --- /dev/null +++ b/source/target-vendors/cp312/dotenv/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 diff --git a/source/target-vendors/cp312/dotenv/variables.py b/source/target-vendors/cp312/dotenv/variables.py new file mode 100644 index 0000000..667f2f2 --- /dev/null +++ b/source/target-vendors/cp312/dotenv/variables.py @@ -0,0 +1,86 @@ +import re +from abc import ABCMeta, abstractmethod +from typing import Iterator, Mapping, Optional, Pattern + +_posix_variable: Pattern[str] = re.compile( + r""" + \$\{ + (?P[^\}:]*) + (?::- + (?P[^\}]*) + )? + \} + """, + re.VERBOSE, +) + + +class Atom(metaclass=ABCMeta): + def __ne__(self, other: object) -> bool: + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + return not result + + @abstractmethod + def resolve(self, env: Mapping[str, Optional[str]]) -> str: ... + + +class Literal(Atom): + def __init__(self, value: str) -> None: + self.value = value + + def __repr__(self) -> str: + return f"Literal(value={self.value})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, self.__class__): + return NotImplemented + return self.value == other.value + + def __hash__(self) -> int: + return hash((self.__class__, self.value)) + + def resolve(self, env: Mapping[str, Optional[str]]) -> str: + return self.value + + +class Variable(Atom): + def __init__(self, name: str, default: Optional[str]) -> None: + self.name = name + self.default = default + + def __repr__(self) -> str: + return f"Variable(name={self.name}, default={self.default})" + + def __eq__(self, other: object) -> bool: + if not isinstance(other, self.__class__): + return NotImplemented + return (self.name, self.default) == (other.name, other.default) + + def __hash__(self) -> int: + return hash((self.__class__, self.name, self.default)) + + def resolve(self, env: Mapping[str, Optional[str]]) -> str: + default = self.default if self.default is not None else "" + result = env.get(self.name, default) + return result if result is not None else "" + + +def parse_variables(value: str) -> Iterator[Atom]: + cursor = 0 + + for match in _posix_variable.finditer(value): + (start, end) = match.span() + name = match["name"] + default = match["default"] + + if start > cursor: + yield Literal(value=value[cursor:start]) + + yield Variable(name=name, default=default) + cursor = end + + length = len(value) + if cursor < length: + yield Literal(value=value[cursor:length]) diff --git a/source/target-vendors/cp312/dotenv/version.py b/source/target-vendors/cp312/dotenv/version.py new file mode 100644 index 0000000..10aa336 --- /dev/null +++ b/source/target-vendors/cp312/dotenv/version.py @@ -0,0 +1 @@ +__version__ = "1.2.3" diff --git a/source/target-vendors/cp312/h11-0.16.0.dist-info/METADATA b/source/target-vendors/cp312/h11-0.16.0.dist-info/METADATA new file mode 100644 index 0000000..8a2f639 --- /dev/null +++ b/source/target-vendors/cp312/h11-0.16.0.dist-info/METADATA @@ -0,0 +1,202 @@ +Metadata-Version: 2.4 +Name: h11 +Version: 0.16.0 +Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1 +Home-page: https://github.com/python-hyper/h11 +Author: Nathaniel J. Smith +Author-email: njs@pobox.com +License: MIT +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: System :: Networking +Requires-Python: >=3.8 +License-File: LICENSE.txt +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: license +Dynamic: license-file +Dynamic: requires-python +Dynamic: summary + +h11 +=== + +.. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master + :target: https://travis-ci.org/python-hyper/h11 + :alt: Automated test status + +.. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg + :target: https://codecov.io/gh/python-hyper/h11 + :alt: Test coverage + +.. image:: https://readthedocs.org/projects/h11/badge/?version=latest + :target: http://h11.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +This is a little HTTP/1.1 library written from scratch in Python, +heavily inspired by `hyper-h2 `_. + +It's a "bring-your-own-I/O" library; h11 contains no IO code +whatsoever. This means you can hook h11 up to your favorite network +API, and that could be anything you want: synchronous, threaded, +asynchronous, or your own implementation of `RFC 6214 +`_ -- h11 won't judge you. +(Compare this to the current state of the art, where every time a `new +network API `_ comes along then someone +gets to start over reimplementing the entire HTTP protocol from +scratch.) Cory Benfield made an `excellent blog post describing the +benefits of this approach +`_, or if you like video +then here's his `PyCon 2016 talk on the same theme +`_. + +This also means that h11 is not immediately useful out of the box: +it's a toolkit for building programs that speak HTTP, not something +that could directly replace ``requests`` or ``twisted.web`` or +whatever. But h11 makes it much easier to implement something like +``requests`` or ``twisted.web``. + +At a high level, working with h11 goes like this: + +1) First, create an ``h11.Connection`` object to track the state of a + single HTTP/1.1 connection. + +2) When you read data off the network, pass it to + ``conn.receive_data(...)``; you'll get back a list of objects + representing high-level HTTP "events". + +3) When you want to send a high-level HTTP event, create the + corresponding "event" object and pass it to ``conn.send(...)``; + this will give you back some bytes that you can then push out + through the network. + +For example, a client might instantiate and then send a +``h11.Request`` object, then zero or more ``h11.Data`` objects for the +request body (e.g., if this is a POST), and then a +``h11.EndOfMessage`` to indicate the end of the message. Then the +server would then send back a ``h11.Response``, some ``h11.Data``, and +its own ``h11.EndOfMessage``. If either side violates the protocol, +you'll get a ``h11.ProtocolError`` exception. + +h11 is suitable for implementing both servers and clients, and has a +pleasantly symmetric API: the events you send as a client are exactly +the ones that you receive as a server and vice-versa. + +`Here's an example of a tiny HTTP client +`_ + +It also has `a fine manual `_. + +FAQ +--- + +*Whyyyyy?* + +I wanted to play with HTTP in `Curio +`__ and `Trio +`__, which at the time didn't have any +HTTP libraries. So I thought, no big deal, Python has, like, a dozen +different implementations of HTTP, surely I can find one that's +reusable. I didn't find one, but I did find Cory's call-to-arms +blog-post. So I figured, well, fine, if I have to implement HTTP from +scratch, at least I can make sure no-one *else* has to ever again. + +*Should I use it?* + +Maybe. You should be aware that it's a very young project. But, it's +feature complete and has an exhaustive test-suite and complete docs, +so the next step is for people to try using it and see how it goes +:-). If you do then please let us know -- if nothing else we'll want +to talk to you before making any incompatible changes! + +*What are the features/limitations?* + +Roughly speaking, it's trying to be a robust, complete, and non-hacky +implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230: +HTTP/1.1 Message Syntax and Routing +`_. That is, it mostly focuses on +implementing HTTP at the level of taking bytes on and off the wire, +and the headers related to that, and tries to be anal about spec +conformance. It doesn't know about higher-level concerns like URL +routing, conditional GETs, cross-origin cookie policies, or content +negotiation. But it does know how to take care of framing, +cross-version differences in keep-alive handling, and the "obsolete +line folding" rule, so you can focus your energies on the hard / +interesting parts for your application, and it tries to support the +full specification in the sense that any useful HTTP/1.1 conformant +application should be able to use h11. + +It's pure Python, and has no dependencies outside of the standard +library. + +It has a test suite with 100.0% coverage for both statements and +branches. + +Currently it supports Python 3 (testing on 3.8-3.12) and PyPy 3. +The last Python 2-compatible version was h11 0.11.x. +(Originally it had a Cython wrapper for `http-parser +`_ and a beautiful nested state +machine implemented with ``yield from`` to postprocess the output. But +I had to take these out -- the new *parser* needs fewer lines-of-code +than the old *parser wrapper*, is written in pure Python, uses no +exotic language syntax, and has more features. It's sad, really; that +old state machine was really slick. I just need a few sentences here +to mourn that.) + +I don't know how fast it is. I haven't benchmarked or profiled it yet, +so it's probably got a few pointless hot spots, and I've been trying +to err on the side of simplicity and robustness instead of +micro-optimization. But at the architectural level I tried hard to +avoid fundamentally bad decisions, e.g., I believe that all the +parsing algorithms remain linear-time even in the face of pathological +input like slowloris, and there are no byte-by-byte loops. (I also +believe that it maintains bounded memory usage in the face of +arbitrary/pathological input.) + +The whole library is ~800 lines-of-code. You can read and understand +the whole thing in less than an hour. Most of the energy invested in +this so far has been spent on trying to keep things simple by +minimizing special-cases and ad hoc state manipulation; even though it +is now quite small and simple, I'm still annoyed that I haven't +figured out how to make it even smaller and simpler. (Unfortunately, +HTTP does not lend itself to simplicity.) + +The API is ~feature complete and I don't expect the general outlines +to change much, but you can't judge an API's ergonomics until you +actually document and use it, so I'd expect some changes in the +details. + +*How do I try it?* + +.. code-block:: sh + + $ pip install h11 + $ git clone git@github.com:python-hyper/h11 + $ cd h11/examples + $ python basic-client.py + +and go from there. + +*License?* + +MIT + +*Code of conduct?* + +Contributors are requested to follow our `code of conduct +`_ in +all project spaces. diff --git a/source/target-vendors/cp312/h11-0.16.0.dist-info/RECORD b/source/target-vendors/cp312/h11-0.16.0.dist-info/RECORD new file mode 100644 index 0000000..0ec9e3e --- /dev/null +++ b/source/target-vendors/cp312/h11-0.16.0.dist-info/RECORD @@ -0,0 +1,17 @@ +h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507 +h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815 +h11/_connection.py,sha256=k9YRVf6koZqbttBW36xSWaJpWdZwa-xQVU9AHEo9DuI,26863 +h11/_events.py,sha256=I97aXoal1Wu7dkL548BANBUCkOIbe-x5CioYA9IBY14,11792 +h11/_headers.py,sha256=P7D-lBNxHwdLZPLimmYwrPG-9ZkjElvvJZJdZAgSP-4,10412 +h11/_readers.py,sha256=a4RypORUCC3d0q_kxPuBIM7jTD8iLt5X91TH0FsduN4,8590 +h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252 +h11/_state.py,sha256=_5LG_BGR8FCcFQeBPH-TMHgm_-B-EUcWCnQof_9XjFE,13231 +h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888 +h11/_version.py,sha256=GVSsbPSPDcOuF6ptfIiXnVJoaEm3ygXbMnqlr_Giahw,686 +h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081 +h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7 +h11-0.16.0.dist-info/licenses/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124 +h11-0.16.0.dist-info/METADATA,sha256=KPMmCYrAn8unm48YD5YIfIQf4kViFct7hyqcfVzRnWQ,8348 +h11-0.16.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91 +h11-0.16.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4 +h11-0.16.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/h11-0.16.0.dist-info/WHEEL b/source/target-vendors/cp312/h11-0.16.0.dist-info/WHEEL new file mode 100644 index 0000000..1eb3c49 --- /dev/null +++ b/source/target-vendors/cp312/h11-0.16.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (78.1.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/h11-0.16.0.dist-info/licenses/LICENSE.txt b/source/target-vendors/cp312/h11-0.16.0.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..8f080ea --- /dev/null +++ b/source/target-vendors/cp312/h11-0.16.0.dist-info/licenses/LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Nathaniel J. Smith and other contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/source/target-vendors/cp312/h11-0.16.0.dist-info/top_level.txt b/source/target-vendors/cp312/h11-0.16.0.dist-info/top_level.txt new file mode 100644 index 0000000..0d24def --- /dev/null +++ b/source/target-vendors/cp312/h11-0.16.0.dist-info/top_level.txt @@ -0,0 +1 @@ +h11 diff --git a/source/target-vendors/cp312/h11/__init__.py b/source/target-vendors/cp312/h11/__init__.py new file mode 100644 index 0000000..989e92c --- /dev/null +++ b/source/target-vendors/cp312/h11/__init__.py @@ -0,0 +1,62 @@ +# A highish-level implementation of the HTTP/1.1 wire protocol (RFC 7230), +# containing no networking code at all, loosely modelled on hyper-h2's generic +# implementation of HTTP/2 (and in particular the h2.connection.H2Connection +# class). There's still a bunch of subtle details you need to get right if you +# want to make this actually useful, because it doesn't implement all the +# semantics to check that what you're asking to write to the wire is sensible, +# but at least it gets you out of dealing with the wire itself. + +from h11._connection import Connection, NEED_DATA, PAUSED +from h11._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from h11._state import ( + CLIENT, + CLOSED, + DONE, + ERROR, + IDLE, + MIGHT_SWITCH_PROTOCOL, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, + SWITCHED_PROTOCOL, +) +from h11._util import LocalProtocolError, ProtocolError, RemoteProtocolError +from h11._version import __version__ + +PRODUCT_ID = "python-h11/" + __version__ + + +__all__ = ( + "Connection", + "NEED_DATA", + "PAUSED", + "ConnectionClosed", + "Data", + "EndOfMessage", + "Event", + "InformationalResponse", + "Request", + "Response", + "CLIENT", + "CLOSED", + "DONE", + "ERROR", + "IDLE", + "MUST_CLOSE", + "SEND_BODY", + "SEND_RESPONSE", + "SERVER", + "SWITCHED_PROTOCOL", + "ProtocolError", + "LocalProtocolError", + "RemoteProtocolError", +) diff --git a/source/target-vendors/cp312/h11/_abnf.py b/source/target-vendors/cp312/h11/_abnf.py new file mode 100644 index 0000000..933587f --- /dev/null +++ b/source/target-vendors/cp312/h11/_abnf.py @@ -0,0 +1,132 @@ +# We use native strings for all the re patterns, to take advantage of string +# formatting, and then convert to bytestrings when compiling the final re +# objects. + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#whitespace +# OWS = *( SP / HTAB ) +# ; optional whitespace +OWS = r"[ \t]*" + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.token.separators +# token = 1*tchar +# +# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" +# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~" +# / DIGIT / ALPHA +# ; any VCHAR, except delimiters +token = r"[-!#$%&'*+.^_`|~0-9a-zA-Z]+" + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#header.fields +# field-name = token +field_name = token + +# The standard says: +# +# field-value = *( field-content / obs-fold ) +# field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +# field-vchar = VCHAR / obs-text +# obs-fold = CRLF 1*( SP / HTAB ) +# ; obsolete line folding +# ; see Section 3.2.4 +# +# https://tools.ietf.org/html/rfc5234#appendix-B.1 +# +# VCHAR = %x21-7E +# ; visible (printing) characters +# +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.quoted-string +# obs-text = %x80-FF +# +# However, the standard definition of field-content is WRONG! It disallows +# fields containing a single visible character surrounded by whitespace, +# e.g. "foo a bar". +# +# See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189 +# +# So our definition of field_content attempts to fix it up... +# +# Also, we allow lots of control characters, because apparently people assume +# that they're legal in practice (e.g., google analytics makes cookies with +# \x01 in them!): +# https://github.com/python-hyper/h11/issues/57 +# We still don't allow NUL or whitespace, because those are often treated as +# meta-characters and letting them through can lead to nasty issues like SSRF. +vchar = r"[\x21-\x7e]" +vchar_or_obs_text = r"[^\x00\s]" +field_vchar = vchar_or_obs_text +field_content = r"{field_vchar}+(?:[ \t]+{field_vchar}+)*".format(**globals()) + +# We handle obs-fold at a different level, and our fixed-up field_content +# already grows to swallow the whole value, so ? instead of * +field_value = r"({field_content})?".format(**globals()) + +# header-field = field-name ":" OWS field-value OWS +header_field = ( + r"(?P{field_name})" + r":" + r"{OWS}" + r"(?P{field_value})" + r"{OWS}".format(**globals()) +) + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#request.line +# +# request-line = method SP request-target SP HTTP-version CRLF +# method = token +# HTTP-version = HTTP-name "/" DIGIT "." DIGIT +# HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive +# +# request-target is complicated (see RFC 7230 sec 5.3) -- could be path, full +# URL, host+port (for connect), or even "*", but in any case we are guaranteed +# that it contists of the visible printing characters. +method = token +request_target = r"{vchar}+".format(**globals()) +http_version = r"HTTP/(?P[0-9]\.[0-9])" +request_line = ( + r"(?P{method})" + r" " + r"(?P{request_target})" + r" " + r"{http_version}".format(**globals()) +) + +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#status.line +# +# status-line = HTTP-version SP status-code SP reason-phrase CRLF +# status-code = 3DIGIT +# reason-phrase = *( HTAB / SP / VCHAR / obs-text ) +status_code = r"[0-9]{3}" +reason_phrase = r"([ \t]|{vchar_or_obs_text})*".format(**globals()) +status_line = ( + r"{http_version}" + r" " + r"(?P{status_code})" + # However, there are apparently a few too many servers out there that just + # leave out the reason phrase: + # https://github.com/scrapy/scrapy/issues/345#issuecomment-281756036 + # https://github.com/seanmonstar/httparse/issues/29 + # so make it optional. ?: is a non-capturing group. + r"(?: (?P{reason_phrase}))?".format(**globals()) +) + +HEXDIG = r"[0-9A-Fa-f]" +# Actually +# +# chunk-size = 1*HEXDIG +# +# but we impose an upper-limit to avoid ridiculosity. len(str(2**64)) == 20 +chunk_size = r"({HEXDIG}){{1,20}}".format(**globals()) +# Actually +# +# chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] ) +# +# but we aren't parsing the things so we don't really care. +chunk_ext = r";.*" +chunk_header = ( + r"(?P{chunk_size})" + r"(?P{chunk_ext})?" + r"{OWS}\r\n".format( + **globals() + ) # Even though the specification does not allow for extra whitespaces, + # we are lenient with trailing whitespaces because some servers on the wild use it. +) diff --git a/source/target-vendors/cp312/h11/_connection.py b/source/target-vendors/cp312/h11/_connection.py new file mode 100644 index 0000000..e37d82a --- /dev/null +++ b/source/target-vendors/cp312/h11/_connection.py @@ -0,0 +1,659 @@ +# This contains the main Connection class. Everything in h11 revolves around +# this. +from typing import ( + Any, + Callable, + cast, + Dict, + List, + Optional, + overload, + Tuple, + Type, + Union, +) + +from ._events import ( + ConnectionClosed, + Data, + EndOfMessage, + Event, + InformationalResponse, + Request, + Response, +) +from ._headers import get_comma_header, has_expect_100_continue, set_comma_header +from ._readers import READERS, ReadersType +from ._receivebuffer import ReceiveBuffer +from ._state import ( + _SWITCH_CONNECT, + _SWITCH_UPGRADE, + CLIENT, + ConnectionState, + DONE, + ERROR, + MIGHT_SWITCH_PROTOCOL, + SEND_BODY, + SERVER, + SWITCHED_PROTOCOL, +) +from ._util import ( # Import the internal things we need + LocalProtocolError, + RemoteProtocolError, + Sentinel, +) +from ._writers import WRITERS, WritersType + +# Everything in __all__ gets re-exported as part of the h11 public API. +__all__ = ["Connection", "NEED_DATA", "PAUSED"] + + +class NEED_DATA(Sentinel, metaclass=Sentinel): + pass + + +class PAUSED(Sentinel, metaclass=Sentinel): + pass + + +# If we ever have this much buffered without it making a complete parseable +# event, we error out. The only time we really buffer is when reading the +# request/response line + headers together, so this is effectively the limit on +# the size of that. +# +# Some precedents for defaults: +# - node.js: 80 * 1024 +# - tomcat: 8 * 1024 +# - IIS: 16 * 1024 +# - Apache: <8 KiB per line> +DEFAULT_MAX_INCOMPLETE_EVENT_SIZE = 16 * 1024 + + +# RFC 7230's rules for connection lifecycles: +# - If either side says they want to close the connection, then the connection +# must close. +# - HTTP/1.1 defaults to keep-alive unless someone says Connection: close +# - HTTP/1.0 defaults to close unless both sides say Connection: keep-alive +# (and even this is a mess -- e.g. if you're implementing a proxy then +# sending Connection: keep-alive is forbidden). +# +# We simplify life by simply not supporting keep-alive with HTTP/1.0 peers. So +# our rule is: +# - If someone says Connection: close, we will close +# - If someone uses HTTP/1.0, we will close. +def _keep_alive(event: Union[Request, Response]) -> bool: + connection = get_comma_header(event.headers, b"connection") + if b"close" in connection: + return False + if getattr(event, "http_version", b"1.1") < b"1.1": + return False + return True + + +def _body_framing( + request_method: bytes, event: Union[Request, Response] +) -> Tuple[str, Union[Tuple[()], Tuple[int]]]: + # Called when we enter SEND_BODY to figure out framing information for + # this body. + # + # These are the only two events that can trigger a SEND_BODY state: + assert type(event) in (Request, Response) + # Returns one of: + # + # ("content-length", count) + # ("chunked", ()) + # ("http/1.0", ()) + # + # which are (lookup key, *args) for constructing body reader/writer + # objects. + # + # Reference: https://tools.ietf.org/html/rfc7230#section-3.3.3 + # + # Step 1: some responses always have an empty body, regardless of what the + # headers say. + if type(event) is Response: + if ( + event.status_code in (204, 304) + or request_method == b"HEAD" + or (request_method == b"CONNECT" and 200 <= event.status_code < 300) + ): + return ("content-length", (0,)) + # Section 3.3.3 also lists another case -- responses with status_code + # < 200. For us these are InformationalResponses, not Responses, so + # they can't get into this function in the first place. + assert event.status_code >= 200 + + # Step 2: check for Transfer-Encoding (T-E beats C-L): + transfer_encodings = get_comma_header(event.headers, b"transfer-encoding") + if transfer_encodings: + assert transfer_encodings == [b"chunked"] + return ("chunked", ()) + + # Step 3: check for Content-Length + content_lengths = get_comma_header(event.headers, b"content-length") + if content_lengths: + return ("content-length", (int(content_lengths[0]),)) + + # Step 4: no applicable headers; fallback/default depends on type + if type(event) is Request: + return ("content-length", (0,)) + else: + return ("http/1.0", ()) + + +################################################################ +# +# The main Connection class +# +################################################################ + + +class Connection: + """An object encapsulating the state of an HTTP connection. + + Args: + our_role: If you're implementing a client, pass :data:`h11.CLIENT`. If + you're implementing a server, pass :data:`h11.SERVER`. + + max_incomplete_event_size (int): + The maximum number of bytes we're willing to buffer of an + incomplete event. In practice this mostly sets a limit on the + maximum size of the request/response line + headers. If this is + exceeded, then :meth:`next_event` will raise + :exc:`RemoteProtocolError`. + + """ + + def __init__( + self, + our_role: Type[Sentinel], + max_incomplete_event_size: int = DEFAULT_MAX_INCOMPLETE_EVENT_SIZE, + ) -> None: + self._max_incomplete_event_size = max_incomplete_event_size + # State and role tracking + if our_role not in (CLIENT, SERVER): + raise ValueError(f"expected CLIENT or SERVER, not {our_role!r}") + self.our_role = our_role + self.their_role: Type[Sentinel] + if our_role is CLIENT: + self.their_role = SERVER + else: + self.their_role = CLIENT + self._cstate = ConnectionState() + + # Callables for converting data->events or vice-versa given the + # current state + self._writer = self._get_io_object(self.our_role, None, WRITERS) + self._reader = self._get_io_object(self.their_role, None, READERS) + + # Holds any unprocessed received data + self._receive_buffer = ReceiveBuffer() + # If this is true, then it indicates that the incoming connection was + # closed *after* the end of whatever's in self._receive_buffer: + self._receive_buffer_closed = False + + # Extra bits of state that don't fit into the state machine. + # + # These two are only used to interpret framing headers for figuring + # out how to read/write response bodies. their_http_version is also + # made available as a convenient public API. + self.their_http_version: Optional[bytes] = None + self._request_method: Optional[bytes] = None + # This is pure flow-control and doesn't at all affect the set of legal + # transitions, so no need to bother ConnectionState with it: + self.client_is_waiting_for_100_continue = False + + @property + def states(self) -> Dict[Type[Sentinel], Type[Sentinel]]: + """A dictionary like:: + + {CLIENT: , SERVER: } + + See :ref:`state-machine` for details. + + """ + return dict(self._cstate.states) + + @property + def our_state(self) -> Type[Sentinel]: + """The current state of whichever role we are playing. See + :ref:`state-machine` for details. + """ + return self._cstate.states[self.our_role] + + @property + def their_state(self) -> Type[Sentinel]: + """The current state of whichever role we are NOT playing. See + :ref:`state-machine` for details. + """ + return self._cstate.states[self.their_role] + + @property + def they_are_waiting_for_100_continue(self) -> bool: + return self.their_role is CLIENT and self.client_is_waiting_for_100_continue + + def start_next_cycle(self) -> None: + """Attempt to reset our connection state for a new request/response + cycle. + + If both client and server are in :data:`DONE` state, then resets them + both to :data:`IDLE` state in preparation for a new request/response + cycle on this same connection. Otherwise, raises a + :exc:`LocalProtocolError`. + + See :ref:`keepalive-and-pipelining`. + + """ + old_states = dict(self._cstate.states) + self._cstate.start_next_cycle() + self._request_method = None + # self.their_http_version gets left alone, since it presumably lasts + # beyond a single request/response cycle + assert not self.client_is_waiting_for_100_continue + self._respond_to_state_changes(old_states) + + def _process_error(self, role: Type[Sentinel]) -> None: + old_states = dict(self._cstate.states) + self._cstate.process_error(role) + self._respond_to_state_changes(old_states) + + def _server_switch_event(self, event: Event) -> Optional[Type[Sentinel]]: + if type(event) is InformationalResponse and event.status_code == 101: + return _SWITCH_UPGRADE + if type(event) is Response: + if ( + _SWITCH_CONNECT in self._cstate.pending_switch_proposals + and 200 <= event.status_code < 300 + ): + return _SWITCH_CONNECT + return None + + # All events go through here + def _process_event(self, role: Type[Sentinel], event: Event) -> None: + # First, pass the event through the state machine to make sure it + # succeeds. + old_states = dict(self._cstate.states) + if role is CLIENT and type(event) is Request: + if event.method == b"CONNECT": + self._cstate.process_client_switch_proposal(_SWITCH_CONNECT) + if get_comma_header(event.headers, b"upgrade"): + self._cstate.process_client_switch_proposal(_SWITCH_UPGRADE) + server_switch_event = None + if role is SERVER: + server_switch_event = self._server_switch_event(event) + self._cstate.process_event(role, type(event), server_switch_event) + + # Then perform the updates triggered by it. + + if type(event) is Request: + self._request_method = event.method + + if role is self.their_role and type(event) in ( + Request, + Response, + InformationalResponse, + ): + event = cast(Union[Request, Response, InformationalResponse], event) + self.their_http_version = event.http_version + + # Keep alive handling + # + # RFC 7230 doesn't really say what one should do if Connection: close + # shows up on a 1xx InformationalResponse. I think the idea is that + # this is not supposed to happen. In any case, if it does happen, we + # ignore it. + if type(event) in (Request, Response) and not _keep_alive( + cast(Union[Request, Response], event) + ): + self._cstate.process_keep_alive_disabled() + + # 100-continue + if type(event) is Request and has_expect_100_continue(event): + self.client_is_waiting_for_100_continue = True + if type(event) in (InformationalResponse, Response): + self.client_is_waiting_for_100_continue = False + if role is CLIENT and type(event) in (Data, EndOfMessage): + self.client_is_waiting_for_100_continue = False + + self._respond_to_state_changes(old_states, event) + + def _get_io_object( + self, + role: Type[Sentinel], + event: Optional[Event], + io_dict: Union[ReadersType, WritersType], + ) -> Optional[Callable[..., Any]]: + # event may be None; it's only used when entering SEND_BODY + state = self._cstate.states[role] + if state is SEND_BODY: + # Special case: the io_dict has a dict of reader/writer factories + # that depend on the request/response framing. + framing_type, args = _body_framing( + cast(bytes, self._request_method), cast(Union[Request, Response], event) + ) + return io_dict[SEND_BODY][framing_type](*args) # type: ignore[index] + else: + # General case: the io_dict just has the appropriate reader/writer + # for this state + return io_dict.get((role, state)) # type: ignore[return-value] + + # This must be called after any action that might have caused + # self._cstate.states to change. + def _respond_to_state_changes( + self, + old_states: Dict[Type[Sentinel], Type[Sentinel]], + event: Optional[Event] = None, + ) -> None: + # Update reader/writer + if self.our_state != old_states[self.our_role]: + self._writer = self._get_io_object(self.our_role, event, WRITERS) + if self.their_state != old_states[self.their_role]: + self._reader = self._get_io_object(self.their_role, event, READERS) + + @property + def trailing_data(self) -> Tuple[bytes, bool]: + """Data that has been received, but not yet processed, represented as + a tuple with two elements, where the first is a byte-string containing + the unprocessed data itself, and the second is a bool that is True if + the receive connection was closed. + + See :ref:`switching-protocols` for discussion of why you'd want this. + """ + return (bytes(self._receive_buffer), self._receive_buffer_closed) + + def receive_data(self, data: bytes) -> None: + """Add data to our internal receive buffer. + + This does not actually do any processing on the data, just stores + it. To trigger processing, you have to call :meth:`next_event`. + + Args: + data (:term:`bytes-like object`): + The new data that was just received. + + Special case: If *data* is an empty byte-string like ``b""``, + then this indicates that the remote side has closed the + connection (end of file). Normally this is convenient, because + standard Python APIs like :meth:`file.read` or + :meth:`socket.recv` use ``b""`` to indicate end-of-file, while + other failures to read are indicated using other mechanisms + like raising :exc:`TimeoutError`. When using such an API you + can just blindly pass through whatever you get from ``read`` + to :meth:`receive_data`, and everything will work. + + But, if you have an API where reading an empty string is a + valid non-EOF condition, then you need to be aware of this and + make sure to check for such strings and avoid passing them to + :meth:`receive_data`. + + Returns: + Nothing, but after calling this you should call :meth:`next_event` + to parse the newly received data. + + Raises: + RuntimeError: + Raised if you pass an empty *data*, indicating EOF, and then + pass a non-empty *data*, indicating more data that somehow + arrived after the EOF. + + (Calling ``receive_data(b"")`` multiple times is fine, + and equivalent to calling it once.) + + """ + if data: + if self._receive_buffer_closed: + raise RuntimeError("received close, then received more data?") + self._receive_buffer += data + else: + self._receive_buffer_closed = True + + def _extract_next_receive_event( + self, + ) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: + state = self.their_state + # We don't pause immediately when they enter DONE, because even in + # DONE state we can still process a ConnectionClosed() event. But + # if we have data in our buffer, then we definitely aren't getting + # a ConnectionClosed() immediately and we need to pause. + if state is DONE and self._receive_buffer: + return PAUSED + if state is MIGHT_SWITCH_PROTOCOL or state is SWITCHED_PROTOCOL: + return PAUSED + assert self._reader is not None + event = self._reader(self._receive_buffer) + if event is None: + if not self._receive_buffer and self._receive_buffer_closed: + # In some unusual cases (basically just HTTP/1.0 bodies), EOF + # triggers an actual protocol event; in that case, we want to + # return that event, and then the state will change and we'll + # get called again to generate the actual ConnectionClosed(). + if hasattr(self._reader, "read_eof"): + event = self._reader.read_eof() + else: + event = ConnectionClosed() + if event is None: + event = NEED_DATA + return event # type: ignore[no-any-return] + + def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: + """Parse the next event out of our receive buffer, update our internal + state, and return it. + + This is a mutating operation -- think of it like calling :func:`next` + on an iterator. + + Returns: + : One of three things: + + 1) An event object -- see :ref:`events`. + + 2) The special constant :data:`NEED_DATA`, which indicates that + you need to read more data from your socket and pass it to + :meth:`receive_data` before this method will be able to return + any more events. + + 3) The special constant :data:`PAUSED`, which indicates that we + are not in a state where we can process incoming data (usually + because the peer has finished their part of the current + request/response cycle, and you have not yet called + :meth:`start_next_cycle`). See :ref:`flow-control` for details. + + Raises: + RemoteProtocolError: + The peer has misbehaved. You should close the connection + (possibly after sending some kind of 4xx response). + + Once this method returns :class:`ConnectionClosed` once, then all + subsequent calls will also return :class:`ConnectionClosed`. + + If this method raises any exception besides :exc:`RemoteProtocolError` + then that's a bug -- if it happens please file a bug report! + + If this method raises any exception then it also sets + :attr:`Connection.their_state` to :data:`ERROR` -- see + :ref:`error-handling` for discussion. + + """ + + if self.their_state is ERROR: + raise RemoteProtocolError("Can't receive data when peer state is ERROR") + try: + event = self._extract_next_receive_event() + if event not in [NEED_DATA, PAUSED]: + self._process_event(self.their_role, cast(Event, event)) + if event is NEED_DATA: + if len(self._receive_buffer) > self._max_incomplete_event_size: + # 431 is "Request header fields too large" which is pretty + # much the only situation where we can get here + raise RemoteProtocolError( + "Receive buffer too long", error_status_hint=431 + ) + if self._receive_buffer_closed: + # We're still trying to complete some event, but that's + # never going to happen because no more data is coming + raise RemoteProtocolError("peer unexpectedly closed connection") + return event + except BaseException as exc: + self._process_error(self.their_role) + if isinstance(exc, LocalProtocolError): + exc._reraise_as_remote_protocol_error() + else: + raise + + @overload + def send(self, event: ConnectionClosed) -> None: + ... + + @overload + def send( + self, event: Union[Request, InformationalResponse, Response, Data, EndOfMessage] + ) -> bytes: + ... + + @overload + def send(self, event: Event) -> Optional[bytes]: + ... + + def send(self, event: Event) -> Optional[bytes]: + """Convert a high-level event into bytes that can be sent to the peer, + while updating our internal state machine. + + Args: + event: The :ref:`event ` to send. + + Returns: + If ``type(event) is ConnectionClosed``, then returns + ``None``. Otherwise, returns a :term:`bytes-like object`. + + Raises: + LocalProtocolError: + Sending this event at this time would violate our + understanding of the HTTP/1.1 protocol. + + If this method raises any exception then it also sets + :attr:`Connection.our_state` to :data:`ERROR` -- see + :ref:`error-handling` for discussion. + + """ + data_list = self.send_with_data_passthrough(event) + if data_list is None: + return None + else: + return b"".join(data_list) + + def send_with_data_passthrough(self, event: Event) -> Optional[List[bytes]]: + """Identical to :meth:`send`, except that in situations where + :meth:`send` returns a single :term:`bytes-like object`, this instead + returns a list of them -- and when sending a :class:`Data` event, this + list is guaranteed to contain the exact object you passed in as + :attr:`Data.data`. See :ref:`sendfile` for discussion. + + """ + if self.our_state is ERROR: + raise LocalProtocolError("Can't send data when our state is ERROR") + try: + if type(event) is Response: + event = self._clean_up_response_headers_for_sending(event) + # We want to call _process_event before calling the writer, + # because if someone tries to do something invalid then this will + # give a sensible error message, while our writers all just assume + # they will only receive valid events. But, _process_event might + # change self._writer. So we have to do a little dance: + writer = self._writer + self._process_event(self.our_role, event) + if type(event) is ConnectionClosed: + return None + else: + # In any situation where writer is None, process_event should + # have raised ProtocolError + assert writer is not None + data_list: List[bytes] = [] + writer(event, data_list.append) + return data_list + except: + self._process_error(self.our_role) + raise + + def send_failed(self) -> None: + """Notify the state machine that we failed to send the data it gave + us. + + This causes :attr:`Connection.our_state` to immediately become + :data:`ERROR` -- see :ref:`error-handling` for discussion. + + """ + self._process_error(self.our_role) + + # When sending a Response, we take responsibility for a few things: + # + # - Sometimes you MUST set Connection: close. We take care of those + # times. (You can also set it yourself if you want, and if you do then + # we'll respect that and close the connection at the right time. But you + # don't have to worry about that unless you want to.) + # + # - The user has to set Content-Length if they want it. Otherwise, for + # responses that have bodies (e.g. not HEAD), then we will automatically + # select the right mechanism for streaming a body of unknown length, + # which depends on depending on the peer's HTTP version. + # + # This function's *only* responsibility is making sure headers are set up + # right -- everything downstream just looks at the headers. There are no + # side channels. + def _clean_up_response_headers_for_sending(self, response: Response) -> Response: + assert type(response) is Response + + headers = response.headers + need_close = False + + # HEAD requests need some special handling: they always act like they + # have Content-Length: 0, and that's how _body_framing treats + # them. But their headers are supposed to match what we would send if + # the request was a GET. (Technically there is one deviation allowed: + # we're allowed to leave out the framing headers -- see + # https://tools.ietf.org/html/rfc7231#section-4.3.2 . But it's just as + # easy to get them right.) + method_for_choosing_headers = cast(bytes, self._request_method) + if method_for_choosing_headers == b"HEAD": + method_for_choosing_headers = b"GET" + framing_type, _ = _body_framing(method_for_choosing_headers, response) + if framing_type in ("chunked", "http/1.0"): + # This response has a body of unknown length. + # If our peer is HTTP/1.1, we use Transfer-Encoding: chunked + # If our peer is HTTP/1.0, we use no framing headers, and close the + # connection afterwards. + # + # Make sure to clear Content-Length (in principle user could have + # set both and then we ignored Content-Length b/c + # Transfer-Encoding overwrote it -- this would be naughty of them, + # but the HTTP spec says that if our peer does this then we have + # to fix it instead of erroring out, so we'll accord the user the + # same respect). + headers = set_comma_header(headers, b"content-length", []) + if self.their_http_version is None or self.their_http_version < b"1.1": + # Either we never got a valid request and are sending back an + # error (their_http_version is None), so we assume the worst; + # or else we did get a valid HTTP/1.0 request, so we know that + # they don't understand chunked encoding. + headers = set_comma_header(headers, b"transfer-encoding", []) + # This is actually redundant ATM, since currently we + # unconditionally disable keep-alive when talking to HTTP/1.0 + # peers. But let's be defensive just in case we add + # Connection: keep-alive support later: + if self._request_method != b"HEAD": + need_close = True + else: + headers = set_comma_header(headers, b"transfer-encoding", [b"chunked"]) + + if not self._cstate.keep_alive or need_close: + # Make sure Connection: close is set + connection = set(get_comma_header(headers, b"connection")) + connection.discard(b"keep-alive") + connection.add(b"close") + headers = set_comma_header(headers, b"connection", sorted(connection)) + + return Response( + headers=headers, + status_code=response.status_code, + http_version=response.http_version, + reason=response.reason, + ) diff --git a/source/target-vendors/cp312/h11/_events.py b/source/target-vendors/cp312/h11/_events.py new file mode 100644 index 0000000..ca1c3ad --- /dev/null +++ b/source/target-vendors/cp312/h11/_events.py @@ -0,0 +1,369 @@ +# High level events that make up HTTP/1.1 conversations. Loosely inspired by +# the corresponding events in hyper-h2: +# +# http://python-hyper.org/h2/en/stable/api.html#events +# +# Don't subclass these. Stuff will break. + +import re +from abc import ABC +from dataclasses import dataclass +from typing import List, Tuple, Union + +from ._abnf import method, request_target +from ._headers import Headers, normalize_and_validate +from ._util import bytesify, LocalProtocolError, validate + +# Everything in __all__ gets re-exported as part of the h11 public API. +__all__ = [ + "Event", + "Request", + "InformationalResponse", + "Response", + "Data", + "EndOfMessage", + "ConnectionClosed", +] + +method_re = re.compile(method.encode("ascii")) +request_target_re = re.compile(request_target.encode("ascii")) + + +class Event(ABC): + """ + Base class for h11 events. + """ + + __slots__ = () + + +@dataclass(init=False, frozen=True) +class Request(Event): + """The beginning of an HTTP request. + + Fields: + + .. attribute:: method + + An HTTP method, e.g. ``b"GET"`` or ``b"POST"``. Always a byte + string. :term:`Bytes-like objects ` and native + strings containing only ascii characters will be automatically + converted to byte strings. + + .. attribute:: target + + The target of an HTTP request, e.g. ``b"/index.html"``, or one of the + more exotic formats described in `RFC 7320, section 5.3 + `_. Always a byte + string. :term:`Bytes-like objects ` and native + strings containing only ascii characters will be automatically + converted to byte strings. + + .. attribute:: headers + + Request headers, represented as a list of (name, value) pairs. See + :ref:`the header normalization rules ` for details. + + .. attribute:: http_version + + The HTTP protocol version, represented as a byte string like + ``b"1.1"``. See :ref:`the HTTP version normalization rules + ` for details. + + """ + + __slots__ = ("method", "headers", "target", "http_version") + + method: bytes + headers: Headers + target: bytes + http_version: bytes + + def __init__( + self, + *, + method: Union[bytes, str], + headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], + target: Union[bytes, str], + http_version: Union[bytes, str] = b"1.1", + _parsed: bool = False, + ) -> None: + super().__init__() + if isinstance(headers, Headers): + object.__setattr__(self, "headers", headers) + else: + object.__setattr__( + self, "headers", normalize_and_validate(headers, _parsed=_parsed) + ) + if not _parsed: + object.__setattr__(self, "method", bytesify(method)) + object.__setattr__(self, "target", bytesify(target)) + object.__setattr__(self, "http_version", bytesify(http_version)) + else: + object.__setattr__(self, "method", method) + object.__setattr__(self, "target", target) + object.__setattr__(self, "http_version", http_version) + + # "A server MUST respond with a 400 (Bad Request) status code to any + # HTTP/1.1 request message that lacks a Host header field and to any + # request message that contains more than one Host header field or a + # Host header field with an invalid field-value." + # -- https://tools.ietf.org/html/rfc7230#section-5.4 + host_count = 0 + for name, value in self.headers: + if name == b"host": + host_count += 1 + if self.http_version == b"1.1" and host_count == 0: + raise LocalProtocolError("Missing mandatory Host: header") + if host_count > 1: + raise LocalProtocolError("Found multiple Host: headers") + + validate(method_re, self.method, "Illegal method characters") + validate(request_target_re, self.target, "Illegal target characters") + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class _ResponseBase(Event): + __slots__ = ("headers", "http_version", "reason", "status_code") + + headers: Headers + http_version: bytes + reason: bytes + status_code: int + + def __init__( + self, + *, + headers: Union[Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]]], + status_code: int, + http_version: Union[bytes, str] = b"1.1", + reason: Union[bytes, str] = b"", + _parsed: bool = False, + ) -> None: + super().__init__() + if isinstance(headers, Headers): + object.__setattr__(self, "headers", headers) + else: + object.__setattr__( + self, "headers", normalize_and_validate(headers, _parsed=_parsed) + ) + if not _parsed: + object.__setattr__(self, "reason", bytesify(reason)) + object.__setattr__(self, "http_version", bytesify(http_version)) + if not isinstance(status_code, int): + raise LocalProtocolError("status code must be integer") + # Because IntEnum objects are instances of int, but aren't + # duck-compatible (sigh), see gh-72. + object.__setattr__(self, "status_code", int(status_code)) + else: + object.__setattr__(self, "reason", reason) + object.__setattr__(self, "http_version", http_version) + object.__setattr__(self, "status_code", status_code) + + self.__post_init__() + + def __post_init__(self) -> None: + pass + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class InformationalResponse(_ResponseBase): + """An HTTP informational response. + + Fields: + + .. attribute:: status_code + + The status code of this response, as an integer. For an + :class:`InformationalResponse`, this is always in the range [100, + 200). + + .. attribute:: headers + + Request headers, represented as a list of (name, value) pairs. See + :ref:`the header normalization rules ` for + details. + + .. attribute:: http_version + + The HTTP protocol version, represented as a byte string like + ``b"1.1"``. See :ref:`the HTTP version normalization rules + ` for details. + + .. attribute:: reason + + The reason phrase of this response, as a byte string. For example: + ``b"OK"``, or ``b"Not Found"``. + + """ + + def __post_init__(self) -> None: + if not (100 <= self.status_code < 200): + raise LocalProtocolError( + "InformationalResponse status_code should be in range " + "[100, 200), not {}".format(self.status_code) + ) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class Response(_ResponseBase): + """The beginning of an HTTP response. + + Fields: + + .. attribute:: status_code + + The status code of this response, as an integer. For an + :class:`Response`, this is always in the range [200, + 1000). + + .. attribute:: headers + + Request headers, represented as a list of (name, value) pairs. See + :ref:`the header normalization rules ` for details. + + .. attribute:: http_version + + The HTTP protocol version, represented as a byte string like + ``b"1.1"``. See :ref:`the HTTP version normalization rules + ` for details. + + .. attribute:: reason + + The reason phrase of this response, as a byte string. For example: + ``b"OK"``, or ``b"Not Found"``. + + """ + + def __post_init__(self) -> None: + if not (200 <= self.status_code < 1000): + raise LocalProtocolError( + "Response status_code should be in range [200, 1000), not {}".format( + self.status_code + ) + ) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(init=False, frozen=True) +class Data(Event): + """Part of an HTTP message body. + + Fields: + + .. attribute:: data + + A :term:`bytes-like object` containing part of a message body. Or, if + using the ``combine=False`` argument to :meth:`Connection.send`, then + any object that your socket writing code knows what to do with, and for + which calling :func:`len` returns the number of bytes that will be + written -- see :ref:`sendfile` for details. + + .. attribute:: chunk_start + + A marker that indicates whether this data object is from the start of a + chunked transfer encoding chunk. This field is ignored when when a Data + event is provided to :meth:`Connection.send`: it is only valid on + events emitted from :meth:`Connection.next_event`. You probably + shouldn't use this attribute at all; see + :ref:`chunk-delimiters-are-bad` for details. + + .. attribute:: chunk_end + + A marker that indicates whether this data object is the last for a + given chunked transfer encoding chunk. This field is ignored when when + a Data event is provided to :meth:`Connection.send`: it is only valid + on events emitted from :meth:`Connection.next_event`. You probably + shouldn't use this attribute at all; see + :ref:`chunk-delimiters-are-bad` for details. + + """ + + __slots__ = ("data", "chunk_start", "chunk_end") + + data: bytes + chunk_start: bool + chunk_end: bool + + def __init__( + self, data: bytes, chunk_start: bool = False, chunk_end: bool = False + ) -> None: + object.__setattr__(self, "data", data) + object.__setattr__(self, "chunk_start", chunk_start) + object.__setattr__(self, "chunk_end", chunk_end) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +# XX FIXME: "A recipient MUST ignore (or consider as an error) any fields that +# are forbidden to be sent in a trailer, since processing them as if they were +# present in the header section might bypass external security filters." +# https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#chunked.trailer.part +# Unfortunately, the list of forbidden fields is long and vague :-/ +@dataclass(init=False, frozen=True) +class EndOfMessage(Event): + """The end of an HTTP message. + + Fields: + + .. attribute:: headers + + Default value: ``[]`` + + Any trailing headers attached to this message, represented as a list of + (name, value) pairs. See :ref:`the header normalization rules + ` for details. + + Must be empty unless ``Transfer-Encoding: chunked`` is in use. + + """ + + __slots__ = ("headers",) + + headers: Headers + + def __init__( + self, + *, + headers: Union[ + Headers, List[Tuple[bytes, bytes]], List[Tuple[str, str]], None + ] = None, + _parsed: bool = False, + ) -> None: + super().__init__() + if headers is None: + headers = Headers([]) + elif not isinstance(headers, Headers): + headers = normalize_and_validate(headers, _parsed=_parsed) + + object.__setattr__(self, "headers", headers) + + # This is an unhashable type. + __hash__ = None # type: ignore + + +@dataclass(frozen=True) +class ConnectionClosed(Event): + """This event indicates that the sender has closed their outgoing + connection. + + Note that this does not necessarily mean that they can't *receive* further + data, because TCP connections are composed to two one-way channels which + can be closed independently. See :ref:`closing` for details. + + No fields. + """ + + pass diff --git a/source/target-vendors/cp312/h11/_headers.py b/source/target-vendors/cp312/h11/_headers.py new file mode 100644 index 0000000..31da3e2 --- /dev/null +++ b/source/target-vendors/cp312/h11/_headers.py @@ -0,0 +1,282 @@ +import re +from typing import AnyStr, cast, List, overload, Sequence, Tuple, TYPE_CHECKING, Union + +from ._abnf import field_name, field_value +from ._util import bytesify, LocalProtocolError, validate + +if TYPE_CHECKING: + from ._events import Request + +try: + from typing import Literal +except ImportError: + from typing_extensions import Literal # type: ignore + +CONTENT_LENGTH_MAX_DIGITS = 20 # allow up to 1 billion TB - 1 + + +# Facts +# ----- +# +# Headers are: +# keys: case-insensitive ascii +# values: mixture of ascii and raw bytes +# +# "Historically, HTTP has allowed field content with text in the ISO-8859-1 +# charset [ISO-8859-1], supporting other charsets only through use of +# [RFC2047] encoding. In practice, most HTTP header field values use only a +# subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD +# limit their field values to US-ASCII octets. A recipient SHOULD treat other +# octets in field content (obs-text) as opaque data." +# And it deprecates all non-ascii values +# +# Leading/trailing whitespace in header names is forbidden +# +# Values get leading/trailing whitespace stripped +# +# Content-Disposition actually needs to contain unicode semantically; to +# accomplish this it has a terrifically weird way of encoding the filename +# itself as ascii (and even this still has lots of cross-browser +# incompatibilities) +# +# Order is important: +# "a proxy MUST NOT change the order of these field values when forwarding a +# message" +# (and there are several headers where the order indicates a preference) +# +# Multiple occurences of the same header: +# "A sender MUST NOT generate multiple header fields with the same field name +# in a message unless either the entire field value for that header field is +# defined as a comma-separated list [or the header is Set-Cookie which gets a +# special exception]" - RFC 7230. (cookies are in RFC 6265) +# +# So every header aside from Set-Cookie can be merged by b", ".join if it +# occurs repeatedly. But, of course, they can't necessarily be split by +# .split(b","), because quoting. +# +# Given all this mess (case insensitive, duplicates allowed, order is +# important, ...), there doesn't appear to be any standard way to handle +# headers in Python -- they're almost like dicts, but... actually just +# aren't. For now we punt and just use a super simple representation: headers +# are a list of pairs +# +# [(name1, value1), (name2, value2), ...] +# +# where all entries are bytestrings, names are lowercase and have no +# leading/trailing whitespace, and values are bytestrings with no +# leading/trailing whitespace. Searching and updating are done via naive O(n) +# methods. +# +# Maybe a dict-of-lists would be better? + +_content_length_re = re.compile(rb"[0-9]+") +_field_name_re = re.compile(field_name.encode("ascii")) +_field_value_re = re.compile(field_value.encode("ascii")) + + +class Headers(Sequence[Tuple[bytes, bytes]]): + """ + A list-like interface that allows iterating over headers as byte-pairs + of (lowercased-name, value). + + Internally we actually store the representation as three-tuples, + including both the raw original casing, in order to preserve casing + over-the-wire, and the lowercased name, for case-insensitive comparisions. + + r = Request( + method="GET", + target="/", + headers=[("Host", "example.org"), ("Connection", "keep-alive")], + http_version="1.1", + ) + assert r.headers == [ + (b"host", b"example.org"), + (b"connection", b"keep-alive") + ] + assert r.headers.raw_items() == [ + (b"Host", b"example.org"), + (b"Connection", b"keep-alive") + ] + """ + + __slots__ = "_full_items" + + def __init__(self, full_items: List[Tuple[bytes, bytes, bytes]]) -> None: + self._full_items = full_items + + def __bool__(self) -> bool: + return bool(self._full_items) + + def __eq__(self, other: object) -> bool: + return list(self) == list(other) # type: ignore + + def __len__(self) -> int: + return len(self._full_items) + + def __repr__(self) -> str: + return "" % repr(list(self)) + + def __getitem__(self, idx: int) -> Tuple[bytes, bytes]: # type: ignore[override] + _, name, value = self._full_items[idx] + return (name, value) + + def raw_items(self) -> List[Tuple[bytes, bytes]]: + return [(raw_name, value) for raw_name, _, value in self._full_items] + + +HeaderTypes = Union[ + List[Tuple[bytes, bytes]], + List[Tuple[bytes, str]], + List[Tuple[str, bytes]], + List[Tuple[str, str]], +] + + +@overload +def normalize_and_validate(headers: Headers, _parsed: Literal[True]) -> Headers: + ... + + +@overload +def normalize_and_validate(headers: HeaderTypes, _parsed: Literal[False]) -> Headers: + ... + + +@overload +def normalize_and_validate( + headers: Union[Headers, HeaderTypes], _parsed: bool = False +) -> Headers: + ... + + +def normalize_and_validate( + headers: Union[Headers, HeaderTypes], _parsed: bool = False +) -> Headers: + new_headers = [] + seen_content_length = None + saw_transfer_encoding = False + for name, value in headers: + # For headers coming out of the parser, we can safely skip some steps, + # because it always returns bytes and has already run these regexes + # over the data: + if not _parsed: + name = bytesify(name) + value = bytesify(value) + validate(_field_name_re, name, "Illegal header name {!r}", name) + validate(_field_value_re, value, "Illegal header value {!r}", value) + assert isinstance(name, bytes) + assert isinstance(value, bytes) + + raw_name = name + name = name.lower() + if name == b"content-length": + lengths = {length.strip() for length in value.split(b",")} + if len(lengths) != 1: + raise LocalProtocolError("conflicting Content-Length headers") + value = lengths.pop() + validate(_content_length_re, value, "bad Content-Length") + if len(value) > CONTENT_LENGTH_MAX_DIGITS: + raise LocalProtocolError("bad Content-Length") + if seen_content_length is None: + seen_content_length = value + new_headers.append((raw_name, name, value)) + elif seen_content_length != value: + raise LocalProtocolError("conflicting Content-Length headers") + elif name == b"transfer-encoding": + # "A server that receives a request message with a transfer coding + # it does not understand SHOULD respond with 501 (Not + # Implemented)." + # https://tools.ietf.org/html/rfc7230#section-3.3.1 + if saw_transfer_encoding: + raise LocalProtocolError( + "multiple Transfer-Encoding headers", error_status_hint=501 + ) + # "All transfer-coding names are case-insensitive" + # -- https://tools.ietf.org/html/rfc7230#section-4 + value = value.lower() + if value != b"chunked": + raise LocalProtocolError( + "Only Transfer-Encoding: chunked is supported", + error_status_hint=501, + ) + saw_transfer_encoding = True + new_headers.append((raw_name, name, value)) + else: + new_headers.append((raw_name, name, value)) + return Headers(new_headers) + + +def get_comma_header(headers: Headers, name: bytes) -> List[bytes]: + # Should only be used for headers whose value is a list of + # comma-separated, case-insensitive values. + # + # The header name `name` is expected to be lower-case bytes. + # + # Connection: meets these criteria (including cast insensitivity). + # + # Content-Length: technically is just a single value (1*DIGIT), but the + # standard makes reference to implementations that do multiple values, and + # using this doesn't hurt. Ditto, case insensitivity doesn't things either + # way. + # + # Transfer-Encoding: is more complex (allows for quoted strings), so + # splitting on , is actually wrong. For example, this is legal: + # + # Transfer-Encoding: foo; options="1,2", chunked + # + # and should be parsed as + # + # foo; options="1,2" + # chunked + # + # but this naive function will parse it as + # + # foo; options="1 + # 2" + # chunked + # + # However, this is okay because the only thing we are going to do with + # any Transfer-Encoding is reject ones that aren't just "chunked", so + # both of these will be treated the same anyway. + # + # Expect: the only legal value is the literal string + # "100-continue". Splitting on commas is harmless. Case insensitive. + # + out: List[bytes] = [] + for _, found_name, found_raw_value in headers._full_items: + if found_name == name: + found_raw_value = found_raw_value.lower() + for found_split_value in found_raw_value.split(b","): + found_split_value = found_split_value.strip() + if found_split_value: + out.append(found_split_value) + return out + + +def set_comma_header(headers: Headers, name: bytes, new_values: List[bytes]) -> Headers: + # The header name `name` is expected to be lower-case bytes. + # + # Note that when we store the header we use title casing for the header + # names, in order to match the conventional HTTP header style. + # + # Simply calling `.title()` is a blunt approach, but it's correct + # here given the cases where we're using `set_comma_header`... + # + # Connection, Content-Length, Transfer-Encoding. + new_headers: List[Tuple[bytes, bytes]] = [] + for found_raw_name, found_name, found_raw_value in headers._full_items: + if found_name != name: + new_headers.append((found_raw_name, found_raw_value)) + for new_value in new_values: + new_headers.append((name.title(), new_value)) + return normalize_and_validate(new_headers) + + +def has_expect_100_continue(request: "Request") -> bool: + # https://tools.ietf.org/html/rfc7231#section-5.1.1 + # "A server that receives a 100-continue expectation in an HTTP/1.0 request + # MUST ignore that expectation." + if request.http_version < b"1.1": + return False + expect = get_comma_header(request.headers, b"expect") + return b"100-continue" in expect diff --git a/source/target-vendors/cp312/h11/_readers.py b/source/target-vendors/cp312/h11/_readers.py new file mode 100644 index 0000000..576804c --- /dev/null +++ b/source/target-vendors/cp312/h11/_readers.py @@ -0,0 +1,250 @@ +# Code to read HTTP data +# +# Strategy: each reader is a callable which takes a ReceiveBuffer object, and +# either: +# 1) consumes some of it and returns an Event +# 2) raises a LocalProtocolError (for consistency -- e.g. we call validate() +# and it might raise a LocalProtocolError, so simpler just to always use +# this) +# 3) returns None, meaning "I need more data" +# +# If they have a .read_eof attribute, then this will be called if an EOF is +# received -- but this is optional. Either way, the actual ConnectionClosed +# event will be generated afterwards. +# +# READERS is a dict describing how to pick a reader. It maps states to either: +# - a reader +# - or, for body readers, a dict of per-framing reader factories + +import re +from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Tuple, Type, Union + +from ._abnf import chunk_header, header_field, request_line, status_line +from ._events import Data, EndOfMessage, InformationalResponse, Request, Response +from ._receivebuffer import ReceiveBuffer +from ._state import ( + CLIENT, + CLOSED, + DONE, + IDLE, + MUST_CLOSE, + SEND_BODY, + SEND_RESPONSE, + SERVER, +) +from ._util import LocalProtocolError, RemoteProtocolError, Sentinel, validate + +__all__ = ["READERS"] + +header_field_re = re.compile(header_field.encode("ascii")) +obs_fold_re = re.compile(rb"[ \t]+") + + +def _obsolete_line_fold(lines: Iterable[bytes]) -> Iterable[bytes]: + it = iter(lines) + last: Optional[bytes] = None + for line in it: + match = obs_fold_re.match(line) + if match: + if last is None: + raise LocalProtocolError("continuation line at start of headers") + if not isinstance(last, bytearray): + # Cast to a mutable type, avoiding copy on append to ensure O(n) time + last = bytearray(last) + last += b" " + last += line[match.end() :] + else: + if last is not None: + yield last + last = line + if last is not None: + yield last + + +def _decode_header_lines( + lines: Iterable[bytes], +) -> Iterable[Tuple[bytes, bytes]]: + for line in _obsolete_line_fold(lines): + matches = validate(header_field_re, line, "illegal header line: {!r}", line) + yield (matches["field_name"], matches["field_value"]) + + +request_line_re = re.compile(request_line.encode("ascii")) + + +def maybe_read_from_IDLE_client(buf: ReceiveBuffer) -> Optional[Request]: + lines = buf.maybe_extract_lines() + if lines is None: + if buf.is_next_line_obviously_invalid_request_line(): + raise LocalProtocolError("illegal request line") + return None + if not lines: + raise LocalProtocolError("no request line received") + matches = validate( + request_line_re, lines[0], "illegal request line: {!r}", lines[0] + ) + return Request( + headers=list(_decode_header_lines(lines[1:])), _parsed=True, **matches + ) + + +status_line_re = re.compile(status_line.encode("ascii")) + + +def maybe_read_from_SEND_RESPONSE_server( + buf: ReceiveBuffer, +) -> Union[InformationalResponse, Response, None]: + lines = buf.maybe_extract_lines() + if lines is None: + if buf.is_next_line_obviously_invalid_request_line(): + raise LocalProtocolError("illegal request line") + return None + if not lines: + raise LocalProtocolError("no response line received") + matches = validate(status_line_re, lines[0], "illegal status line: {!r}", lines[0]) + http_version = ( + b"1.1" if matches["http_version"] is None else matches["http_version"] + ) + reason = b"" if matches["reason"] is None else matches["reason"] + status_code = int(matches["status_code"]) + class_: Union[Type[InformationalResponse], Type[Response]] = ( + InformationalResponse if status_code < 200 else Response + ) + return class_( + headers=list(_decode_header_lines(lines[1:])), + _parsed=True, + status_code=status_code, + reason=reason, + http_version=http_version, + ) + + +class ContentLengthReader: + def __init__(self, length: int) -> None: + self._length = length + self._remaining = length + + def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: + if self._remaining == 0: + return EndOfMessage() + data = buf.maybe_extract_at_most(self._remaining) + if data is None: + return None + self._remaining -= len(data) + return Data(data=data) + + def read_eof(self) -> NoReturn: + raise RemoteProtocolError( + "peer closed connection without sending complete message body " + "(received {} bytes, expected {})".format( + self._length - self._remaining, self._length + ) + ) + + +chunk_header_re = re.compile(chunk_header.encode("ascii")) + + +class ChunkedReader: + def __init__(self) -> None: + self._bytes_in_chunk = 0 + # After reading a chunk, we have to throw away the trailing \r\n. + # This tracks the bytes that we need to match and throw away. + self._bytes_to_discard = b"" + self._reading_trailer = False + + def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: + if self._reading_trailer: + lines = buf.maybe_extract_lines() + if lines is None: + return None + return EndOfMessage(headers=list(_decode_header_lines(lines))) + if self._bytes_to_discard: + data = buf.maybe_extract_at_most(len(self._bytes_to_discard)) + if data is None: + return None + if data != self._bytes_to_discard[: len(data)]: + raise LocalProtocolError( + f"malformed chunk footer: {data!r} (expected {self._bytes_to_discard!r})" + ) + self._bytes_to_discard = self._bytes_to_discard[len(data) :] + if self._bytes_to_discard: + return None + # else, fall through and read some more + assert self._bytes_to_discard == b"" + if self._bytes_in_chunk == 0: + # We need to refill our chunk count + chunk_header = buf.maybe_extract_next_line() + if chunk_header is None: + return None + matches = validate( + chunk_header_re, + chunk_header, + "illegal chunk header: {!r}", + chunk_header, + ) + # XX FIXME: we discard chunk extensions. Does anyone care? + self._bytes_in_chunk = int(matches["chunk_size"], base=16) + if self._bytes_in_chunk == 0: + self._reading_trailer = True + return self(buf) + chunk_start = True + else: + chunk_start = False + assert self._bytes_in_chunk > 0 + data = buf.maybe_extract_at_most(self._bytes_in_chunk) + if data is None: + return None + self._bytes_in_chunk -= len(data) + if self._bytes_in_chunk == 0: + self._bytes_to_discard = b"\r\n" + chunk_end = True + else: + chunk_end = False + return Data(data=data, chunk_start=chunk_start, chunk_end=chunk_end) + + def read_eof(self) -> NoReturn: + raise RemoteProtocolError( + "peer closed connection without sending complete message body " + "(incomplete chunked read)" + ) + + +class Http10Reader: + def __call__(self, buf: ReceiveBuffer) -> Optional[Data]: + data = buf.maybe_extract_at_most(999999999) + if data is None: + return None + return Data(data=data) + + def read_eof(self) -> EndOfMessage: + return EndOfMessage() + + +def expect_nothing(buf: ReceiveBuffer) -> None: + if buf: + raise LocalProtocolError("Got data when expecting EOF") + return None + + +ReadersType = Dict[ + Union[Type[Sentinel], Tuple[Type[Sentinel], Type[Sentinel]]], + Union[Callable[..., Any], Dict[str, Callable[..., Any]]], +] + +READERS: ReadersType = { + (CLIENT, IDLE): maybe_read_from_IDLE_client, + (SERVER, IDLE): maybe_read_from_SEND_RESPONSE_server, + (SERVER, SEND_RESPONSE): maybe_read_from_SEND_RESPONSE_server, + (CLIENT, DONE): expect_nothing, + (CLIENT, MUST_CLOSE): expect_nothing, + (CLIENT, CLOSED): expect_nothing, + (SERVER, DONE): expect_nothing, + (SERVER, MUST_CLOSE): expect_nothing, + (SERVER, CLOSED): expect_nothing, + SEND_BODY: { + "chunked": ChunkedReader, + "content-length": ContentLengthReader, + "http/1.0": Http10Reader, + }, +} diff --git a/source/target-vendors/cp312/h11/_receivebuffer.py b/source/target-vendors/cp312/h11/_receivebuffer.py new file mode 100644 index 0000000..e5c4e08 --- /dev/null +++ b/source/target-vendors/cp312/h11/_receivebuffer.py @@ -0,0 +1,153 @@ +import re +import sys +from typing import List, Optional, Union + +__all__ = ["ReceiveBuffer"] + + +# Operations we want to support: +# - find next \r\n or \r\n\r\n (\n or \n\n are also acceptable), +# or wait until there is one +# - read at-most-N bytes +# Goals: +# - on average, do this fast +# - worst case, do this in O(n) where n is the number of bytes processed +# Plan: +# - store bytearray, offset, how far we've searched for a separator token +# - use the how-far-we've-searched data to avoid rescanning +# - while doing a stream of uninterrupted processing, advance offset instead +# of constantly copying +# WARNING: +# - I haven't benchmarked or profiled any of this yet. +# +# Note that starting in Python 3.4, deleting the initial n bytes from a +# bytearray is amortized O(n), thanks to some excellent work by Antoine +# Martin: +# +# https://bugs.python.org/issue19087 +# +# This means that if we only supported 3.4+, we could get rid of the code here +# involving self._start and self.compress, because it's doing exactly the same +# thing that bytearray now does internally. +# +# BUT unfortunately, we still support 2.7, and reading short segments out of a +# long buffer MUST be O(bytes read) to avoid DoS issues, so we can't actually +# delete this code. Yet: +# +# https://pythonclock.org/ +# +# (Two things to double-check first though: make sure PyPy also has the +# optimization, and benchmark to make sure it's a win, since we do have a +# slightly clever thing where we delay calling compress() until we've +# processed a whole event, which could in theory be slightly more efficient +# than the internal bytearray support.) +blank_line_regex = re.compile(b"\n\r?\n", re.MULTILINE) + + +class ReceiveBuffer: + def __init__(self) -> None: + self._data = bytearray() + self._next_line_search = 0 + self._multiple_lines_search = 0 + + def __iadd__(self, byteslike: Union[bytes, bytearray]) -> "ReceiveBuffer": + self._data += byteslike + return self + + def __bool__(self) -> bool: + return bool(len(self)) + + def __len__(self) -> int: + return len(self._data) + + # for @property unprocessed_data + def __bytes__(self) -> bytes: + return bytes(self._data) + + def _extract(self, count: int) -> bytearray: + # extracting an initial slice of the data buffer and return it + out = self._data[:count] + del self._data[:count] + + self._next_line_search = 0 + self._multiple_lines_search = 0 + + return out + + def maybe_extract_at_most(self, count: int) -> Optional[bytearray]: + """ + Extract a fixed number of bytes from the buffer. + """ + out = self._data[:count] + if not out: + return None + + return self._extract(count) + + def maybe_extract_next_line(self) -> Optional[bytearray]: + """ + Extract the first line, if it is completed in the buffer. + """ + # Only search in buffer space that we've not already looked at. + search_start_index = max(0, self._next_line_search - 1) + partial_idx = self._data.find(b"\r\n", search_start_index) + + if partial_idx == -1: + self._next_line_search = len(self._data) + return None + + # + 2 is to compensate len(b"\r\n") + idx = partial_idx + 2 + + return self._extract(idx) + + def maybe_extract_lines(self) -> Optional[List[bytearray]]: + """ + Extract everything up to the first blank line, and return a list of lines. + """ + # Handle the case where we have an immediate empty line. + if self._data[:1] == b"\n": + self._extract(1) + return [] + + if self._data[:2] == b"\r\n": + self._extract(2) + return [] + + # Only search in buffer space that we've not already looked at. + match = blank_line_regex.search(self._data, self._multiple_lines_search) + if match is None: + self._multiple_lines_search = max(0, len(self._data) - 2) + return None + + # Truncate the buffer and return it. + idx = match.span(0)[-1] + out = self._extract(idx) + lines = out.split(b"\n") + + for line in lines: + if line.endswith(b"\r"): + del line[-1] + + assert lines[-2] == lines[-1] == b"" + + del lines[-2:] + + return lines + + # In theory we should wait until `\r\n` before starting to validate + # incoming data. However it's interesting to detect (very) invalid data + # early given they might not even contain `\r\n` at all (hence only + # timeout will get rid of them). + # This is not a 100% effective detection but more of a cheap sanity check + # allowing for early abort in some useful cases. + # This is especially interesting when peer is messing up with HTTPS and + # sent us a TLS stream where we were expecting plain HTTP given all + # versions of TLS so far start handshake with a 0x16 message type code. + def is_next_line_obviously_invalid_request_line(self) -> bool: + try: + # HTTP header line must not contain non-printable characters + # and should not start with a space + return self._data[0] < 0x21 + except IndexError: + return False diff --git a/source/target-vendors/cp312/h11/_state.py b/source/target-vendors/cp312/h11/_state.py new file mode 100644 index 0000000..3ad444b --- /dev/null +++ b/source/target-vendors/cp312/h11/_state.py @@ -0,0 +1,365 @@ +################################################################ +# The core state machine +################################################################ +# +# Rule 1: everything that affects the state machine and state transitions must +# live here in this file. As much as possible goes into the table-based +# representation, but for the bits that don't quite fit, the actual code and +# state must nonetheless live here. +# +# Rule 2: this file does not know about what role we're playing; it only knows +# about HTTP request/response cycles in the abstract. This ensures that we +# don't cheat and apply different rules to local and remote parties. +# +# +# Theory of operation +# =================== +# +# Possibly the simplest way to think about this is that we actually have 5 +# different state machines here. Yes, 5. These are: +# +# 1) The client state, with its complicated automaton (see the docs) +# 2) The server state, with its complicated automaton (see the docs) +# 3) The keep-alive state, with possible states {True, False} +# 4) The SWITCH_CONNECT state, with possible states {False, True} +# 5) The SWITCH_UPGRADE state, with possible states {False, True} +# +# For (3)-(5), the first state listed is the initial state. +# +# (1)-(3) are stored explicitly in member variables. The last +# two are stored implicitly in the pending_switch_proposals set as: +# (state of 4) == (_SWITCH_CONNECT in pending_switch_proposals) +# (state of 5) == (_SWITCH_UPGRADE in pending_switch_proposals) +# +# And each of these machines has two different kinds of transitions: +# +# a) Event-triggered +# b) State-triggered +# +# Event triggered is the obvious thing that you'd think it is: some event +# happens, and if it's the right event at the right time then a transition +# happens. But there are somewhat complicated rules for which machines can +# "see" which events. (As a rule of thumb, if a machine "sees" an event, this +# means two things: the event can affect the machine, and if the machine is +# not in a state where it expects that event then it's an error.) These rules +# are: +# +# 1) The client machine sees all h11.events objects emitted by the client. +# +# 2) The server machine sees all h11.events objects emitted by the server. +# +# It also sees the client's Request event. +# +# And sometimes, server events are annotated with a _SWITCH_* event. For +# example, we can have a (Response, _SWITCH_CONNECT) event, which is +# different from a regular Response event. +# +# 3) The keep-alive machine sees the process_keep_alive_disabled() event +# (which is derived from Request/Response events), and this event +# transitions it from True -> False, or from False -> False. There's no way +# to transition back. +# +# 4&5) The _SWITCH_* machines transition from False->True when we get a +# Request that proposes the relevant type of switch (via +# process_client_switch_proposals), and they go from True->False when we +# get a Response that has no _SWITCH_* annotation. +# +# So that's event-triggered transitions. +# +# State-triggered transitions are less standard. What they do here is couple +# the machines together. The way this works is, when certain *joint* +# configurations of states are achieved, then we automatically transition to a +# new *joint* state. So, for example, if we're ever in a joint state with +# +# client: DONE +# keep-alive: False +# +# then the client state immediately transitions to: +# +# client: MUST_CLOSE +# +# This is fundamentally different from an event-based transition, because it +# doesn't matter how we arrived at the {client: DONE, keep-alive: False} state +# -- maybe the client transitioned SEND_BODY -> DONE, or keep-alive +# transitioned True -> False. Either way, once this precondition is satisfied, +# this transition is immediately triggered. +# +# What if two conflicting state-based transitions get enabled at the same +# time? In practice there's only one case where this arises (client DONE -> +# MIGHT_SWITCH_PROTOCOL versus DONE -> MUST_CLOSE), and we resolve it by +# explicitly prioritizing the DONE -> MIGHT_SWITCH_PROTOCOL transition. +# +# Implementation +# -------------- +# +# The event-triggered transitions for the server and client machines are all +# stored explicitly in a table. Ditto for the state-triggered transitions that +# involve just the server and client state. +# +# The transitions for the other machines, and the state-triggered transitions +# that involve the other machines, are written out as explicit Python code. +# +# It'd be nice if there were some cleaner way to do all this. This isn't +# *too* terrible, but I feel like it could probably be better. +# +# WARNING +# ------- +# +# The script that generates the state machine diagrams for the docs knows how +# to read out the EVENT_TRIGGERED_TRANSITIONS and STATE_TRIGGERED_TRANSITIONS +# tables. But it can't automatically read the transitions that are written +# directly in Python code. So if you touch those, you need to also update the +# script to keep it in sync! +from typing import cast, Dict, Optional, Set, Tuple, Type, Union + +from ._events import * +from ._util import LocalProtocolError, Sentinel + +# Everything in __all__ gets re-exported as part of the h11 public API. +__all__ = [ + "CLIENT", + "SERVER", + "IDLE", + "SEND_RESPONSE", + "SEND_BODY", + "DONE", + "MUST_CLOSE", + "CLOSED", + "MIGHT_SWITCH_PROTOCOL", + "SWITCHED_PROTOCOL", + "ERROR", +] + + +class CLIENT(Sentinel, metaclass=Sentinel): + pass + + +class SERVER(Sentinel, metaclass=Sentinel): + pass + + +# States +class IDLE(Sentinel, metaclass=Sentinel): + pass + + +class SEND_RESPONSE(Sentinel, metaclass=Sentinel): + pass + + +class SEND_BODY(Sentinel, metaclass=Sentinel): + pass + + +class DONE(Sentinel, metaclass=Sentinel): + pass + + +class MUST_CLOSE(Sentinel, metaclass=Sentinel): + pass + + +class CLOSED(Sentinel, metaclass=Sentinel): + pass + + +class ERROR(Sentinel, metaclass=Sentinel): + pass + + +# Switch types +class MIGHT_SWITCH_PROTOCOL(Sentinel, metaclass=Sentinel): + pass + + +class SWITCHED_PROTOCOL(Sentinel, metaclass=Sentinel): + pass + + +class _SWITCH_UPGRADE(Sentinel, metaclass=Sentinel): + pass + + +class _SWITCH_CONNECT(Sentinel, metaclass=Sentinel): + pass + + +EventTransitionType = Dict[ + Type[Sentinel], + Dict[ + Type[Sentinel], + Dict[Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], Type[Sentinel]], + ], +] + +EVENT_TRIGGERED_TRANSITIONS: EventTransitionType = { + CLIENT: { + IDLE: {Request: SEND_BODY, ConnectionClosed: CLOSED}, + SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, + DONE: {ConnectionClosed: CLOSED}, + MUST_CLOSE: {ConnectionClosed: CLOSED}, + CLOSED: {ConnectionClosed: CLOSED}, + MIGHT_SWITCH_PROTOCOL: {}, + SWITCHED_PROTOCOL: {}, + ERROR: {}, + }, + SERVER: { + IDLE: { + ConnectionClosed: CLOSED, + Response: SEND_BODY, + # Special case: server sees client Request events, in this form + (Request, CLIENT): SEND_RESPONSE, + }, + SEND_RESPONSE: { + InformationalResponse: SEND_RESPONSE, + Response: SEND_BODY, + (InformationalResponse, _SWITCH_UPGRADE): SWITCHED_PROTOCOL, + (Response, _SWITCH_CONNECT): SWITCHED_PROTOCOL, + }, + SEND_BODY: {Data: SEND_BODY, EndOfMessage: DONE}, + DONE: {ConnectionClosed: CLOSED}, + MUST_CLOSE: {ConnectionClosed: CLOSED}, + CLOSED: {ConnectionClosed: CLOSED}, + SWITCHED_PROTOCOL: {}, + ERROR: {}, + }, +} + +StateTransitionType = Dict[ + Tuple[Type[Sentinel], Type[Sentinel]], Dict[Type[Sentinel], Type[Sentinel]] +] + +# NB: there are also some special-case state-triggered transitions hard-coded +# into _fire_state_triggered_transitions below. +STATE_TRIGGERED_TRANSITIONS: StateTransitionType = { + # (Client state, Server state) -> new states + # Protocol negotiation + (MIGHT_SWITCH_PROTOCOL, SWITCHED_PROTOCOL): {CLIENT: SWITCHED_PROTOCOL}, + # Socket shutdown + (CLOSED, DONE): {SERVER: MUST_CLOSE}, + (CLOSED, IDLE): {SERVER: MUST_CLOSE}, + (ERROR, DONE): {SERVER: MUST_CLOSE}, + (DONE, CLOSED): {CLIENT: MUST_CLOSE}, + (IDLE, CLOSED): {CLIENT: MUST_CLOSE}, + (DONE, ERROR): {CLIENT: MUST_CLOSE}, +} + + +class ConnectionState: + def __init__(self) -> None: + # Extra bits of state that don't quite fit into the state model. + + # If this is False then it enables the automatic DONE -> MUST_CLOSE + # transition. Don't set this directly; call .keep_alive_disabled() + self.keep_alive = True + + # This is a subset of {UPGRADE, CONNECT}, containing the proposals + # made by the client for switching protocols. + self.pending_switch_proposals: Set[Type[Sentinel]] = set() + + self.states: Dict[Type[Sentinel], Type[Sentinel]] = {CLIENT: IDLE, SERVER: IDLE} + + def process_error(self, role: Type[Sentinel]) -> None: + self.states[role] = ERROR + self._fire_state_triggered_transitions() + + def process_keep_alive_disabled(self) -> None: + self.keep_alive = False + self._fire_state_triggered_transitions() + + def process_client_switch_proposal(self, switch_event: Type[Sentinel]) -> None: + self.pending_switch_proposals.add(switch_event) + self._fire_state_triggered_transitions() + + def process_event( + self, + role: Type[Sentinel], + event_type: Type[Event], + server_switch_event: Optional[Type[Sentinel]] = None, + ) -> None: + _event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]] = event_type + if server_switch_event is not None: + assert role is SERVER + if server_switch_event not in self.pending_switch_proposals: + raise LocalProtocolError( + "Received server _SWITCH_UPGRADE event without a pending proposal" + ) + _event_type = (event_type, server_switch_event) + if server_switch_event is None and _event_type is Response: + self.pending_switch_proposals = set() + self._fire_event_triggered_transitions(role, _event_type) + # Special case: the server state does get to see Request + # events. + if _event_type is Request: + assert role is CLIENT + self._fire_event_triggered_transitions(SERVER, (Request, CLIENT)) + self._fire_state_triggered_transitions() + + def _fire_event_triggered_transitions( + self, + role: Type[Sentinel], + event_type: Union[Type[Event], Tuple[Type[Event], Type[Sentinel]]], + ) -> None: + state = self.states[role] + try: + new_state = EVENT_TRIGGERED_TRANSITIONS[role][state][event_type] + except KeyError: + event_type = cast(Type[Event], event_type) + raise LocalProtocolError( + "can't handle event type {} when role={} and state={}".format( + event_type.__name__, role, self.states[role] + ) + ) from None + self.states[role] = new_state + + def _fire_state_triggered_transitions(self) -> None: + # We apply these rules repeatedly until converging on a fixed point + while True: + start_states = dict(self.states) + + # It could happen that both these special-case transitions are + # enabled at the same time: + # + # DONE -> MIGHT_SWITCH_PROTOCOL + # DONE -> MUST_CLOSE + # + # For example, this will always be true of a HTTP/1.0 client + # requesting CONNECT. If this happens, the protocol switch takes + # priority. From there the client will either go to + # SWITCHED_PROTOCOL, in which case it's none of our business when + # they close the connection, or else the server will deny the + # request, in which case the client will go back to DONE and then + # from there to MUST_CLOSE. + if self.pending_switch_proposals: + if self.states[CLIENT] is DONE: + self.states[CLIENT] = MIGHT_SWITCH_PROTOCOL + + if not self.pending_switch_proposals: + if self.states[CLIENT] is MIGHT_SWITCH_PROTOCOL: + self.states[CLIENT] = DONE + + if not self.keep_alive: + for role in (CLIENT, SERVER): + if self.states[role] is DONE: + self.states[role] = MUST_CLOSE + + # Tabular state-triggered transitions + joint_state = (self.states[CLIENT], self.states[SERVER]) + changes = STATE_TRIGGERED_TRANSITIONS.get(joint_state, {}) + self.states.update(changes) + + if self.states == start_states: + # Fixed point reached + return + + def start_next_cycle(self) -> None: + if self.states != {CLIENT: DONE, SERVER: DONE}: + raise LocalProtocolError( + f"not in a reusable state. self.states={self.states}" + ) + # Can't reach DONE/DONE with any of these active, but still, let's be + # sure. + assert self.keep_alive + assert not self.pending_switch_proposals + self.states = {CLIENT: IDLE, SERVER: IDLE} diff --git a/source/target-vendors/cp312/h11/_util.py b/source/target-vendors/cp312/h11/_util.py new file mode 100644 index 0000000..6718445 --- /dev/null +++ b/source/target-vendors/cp312/h11/_util.py @@ -0,0 +1,135 @@ +from typing import Any, Dict, NoReturn, Pattern, Tuple, Type, TypeVar, Union + +__all__ = [ + "ProtocolError", + "LocalProtocolError", + "RemoteProtocolError", + "validate", + "bytesify", +] + + +class ProtocolError(Exception): + """Exception indicating a violation of the HTTP/1.1 protocol. + + This as an abstract base class, with two concrete base classes: + :exc:`LocalProtocolError`, which indicates that you tried to do something + that HTTP/1.1 says is illegal, and :exc:`RemoteProtocolError`, which + indicates that the remote peer tried to do something that HTTP/1.1 says is + illegal. See :ref:`error-handling` for details. + + In addition to the normal :exc:`Exception` features, it has one attribute: + + .. attribute:: error_status_hint + + This gives a suggestion as to what status code a server might use if + this error occurred as part of a request. + + For a :exc:`RemoteProtocolError`, this is useful as a suggestion for + how you might want to respond to a misbehaving peer, if you're + implementing a server. + + For a :exc:`LocalProtocolError`, this can be taken as a suggestion for + how your peer might have responded to *you* if h11 had allowed you to + continue. + + The default is 400 Bad Request, a generic catch-all for protocol + violations. + + """ + + def __init__(self, msg: str, error_status_hint: int = 400) -> None: + if type(self) is ProtocolError: + raise TypeError("tried to directly instantiate ProtocolError") + Exception.__init__(self, msg) + self.error_status_hint = error_status_hint + + +# Strategy: there are a number of public APIs where a LocalProtocolError can +# be raised (send(), all the different event constructors, ...), and only one +# public API where RemoteProtocolError can be raised +# (receive_data()). Therefore we always raise LocalProtocolError internally, +# and then receive_data will translate this into a RemoteProtocolError. +# +# Internally: +# LocalProtocolError is the generic "ProtocolError". +# Externally: +# LocalProtocolError is for local errors and RemoteProtocolError is for +# remote errors. +class LocalProtocolError(ProtocolError): + def _reraise_as_remote_protocol_error(self) -> NoReturn: + # After catching a LocalProtocolError, use this method to re-raise it + # as a RemoteProtocolError. This method must be called from inside an + # except: block. + # + # An easy way to get an equivalent RemoteProtocolError is just to + # modify 'self' in place. + self.__class__ = RemoteProtocolError # type: ignore + # But the re-raising is somewhat non-trivial -- you might think that + # now that we've modified the in-flight exception object, that just + # doing 'raise' to re-raise it would be enough. But it turns out that + # this doesn't work, because Python tracks the exception type + # (exc_info[0]) separately from the exception object (exc_info[1]), + # and we only modified the latter. So we really do need to re-raise + # the new type explicitly. + # On py3, the traceback is part of the exception object, so our + # in-place modification preserved it and we can just re-raise: + raise self + + +class RemoteProtocolError(ProtocolError): + pass + + +def validate( + regex: Pattern[bytes], data: bytes, msg: str = "malformed data", *format_args: Any +) -> Dict[str, bytes]: + match = regex.fullmatch(data) + if not match: + if format_args: + msg = msg.format(*format_args) + raise LocalProtocolError(msg) + return match.groupdict() + + +# Sentinel values +# +# - Inherit identity-based comparison and hashing from object +# - Have a nice repr +# - Have a *bonus property*: type(sentinel) is sentinel +# +# The bonus property is useful if you want to take the return value from +# next_event() and do some sort of dispatch based on type(event). + +_T_Sentinel = TypeVar("_T_Sentinel", bound="Sentinel") + + +class Sentinel(type): + def __new__( + cls: Type[_T_Sentinel], + name: str, + bases: Tuple[type, ...], + namespace: Dict[str, Any], + **kwds: Any + ) -> _T_Sentinel: + assert bases == (Sentinel,) + v = super().__new__(cls, name, bases, namespace, **kwds) + v.__class__ = v # type: ignore + return v + + def __repr__(self) -> str: + return self.__name__ + + +# Used for methods, request targets, HTTP versions, header names, and header +# values. Accepts ascii-strings, or bytes/bytearray/memoryview/..., and always +# returns bytes. +def bytesify(s: Union[bytes, bytearray, memoryview, int, str]) -> bytes: + # Fast-path: + if type(s) is bytes: + return s + if isinstance(s, str): + s = s.encode("ascii") + if isinstance(s, int): + raise TypeError("expected bytes-like object, not int") + return bytes(s) diff --git a/source/target-vendors/cp312/h11/_version.py b/source/target-vendors/cp312/h11/_version.py new file mode 100644 index 0000000..76e7327 --- /dev/null +++ b/source/target-vendors/cp312/h11/_version.py @@ -0,0 +1,16 @@ +# This file must be kept very simple, because it is consumed from several +# places -- it is imported by h11/__init__.py, execfile'd by setup.py, etc. + +# We use a simple scheme: +# 1.0.0 -> 1.0.0+dev -> 1.1.0 -> 1.1.0+dev +# where the +dev versions are never released into the wild, they're just what +# we stick into the VCS in between releases. +# +# This is compatible with PEP 440: +# http://legacy.python.org/dev/peps/pep-0440/ +# via the use of the "local suffix" "+dev", which is disallowed on index +# servers and causes 1.0.0+dev to sort after plain 1.0.0, which is what we +# want. (Contrast with the special suffix 1.0.0.dev, which sorts *before* +# 1.0.0.) + +__version__ = "0.16.0" diff --git a/source/target-vendors/cp312/h11/_writers.py b/source/target-vendors/cp312/h11/_writers.py new file mode 100644 index 0000000..939cdb9 --- /dev/null +++ b/source/target-vendors/cp312/h11/_writers.py @@ -0,0 +1,145 @@ +# Code to read HTTP data +# +# Strategy: each writer takes an event + a write-some-bytes function, which is +# calls. +# +# WRITERS is a dict describing how to pick a reader. It maps states to either: +# - a writer +# - or, for body writers, a dict of framin-dependent writer factories + +from typing import Any, Callable, Dict, List, Tuple, Type, Union + +from ._events import Data, EndOfMessage, Event, InformationalResponse, Request, Response +from ._headers import Headers +from ._state import CLIENT, IDLE, SEND_BODY, SEND_RESPONSE, SERVER +from ._util import LocalProtocolError, Sentinel + +__all__ = ["WRITERS"] + +Writer = Callable[[bytes], Any] + + +def write_headers(headers: Headers, write: Writer) -> None: + # "Since the Host field-value is critical information for handling a + # request, a user agent SHOULD generate Host as the first header field + # following the request-line." - RFC 7230 + raw_items = headers._full_items + for raw_name, name, value in raw_items: + if name == b"host": + write(b"%s: %s\r\n" % (raw_name, value)) + for raw_name, name, value in raw_items: + if name != b"host": + write(b"%s: %s\r\n" % (raw_name, value)) + write(b"\r\n") + + +def write_request(request: Request, write: Writer) -> None: + if request.http_version != b"1.1": + raise LocalProtocolError("I only send HTTP/1.1") + write(b"%s %s HTTP/1.1\r\n" % (request.method, request.target)) + write_headers(request.headers, write) + + +# Shared between InformationalResponse and Response +def write_any_response( + response: Union[InformationalResponse, Response], write: Writer +) -> None: + if response.http_version != b"1.1": + raise LocalProtocolError("I only send HTTP/1.1") + status_bytes = str(response.status_code).encode("ascii") + # We don't bother sending ascii status messages like "OK"; they're + # optional and ignored by the protocol. (But the space after the numeric + # status code is mandatory.) + # + # XX FIXME: could at least make an effort to pull out the status message + # from stdlib's http.HTTPStatus table. Or maybe just steal their enums + # (either by import or copy/paste). We already accept them as status codes + # since they're of type IntEnum < int. + write(b"HTTP/1.1 %s %s\r\n" % (status_bytes, response.reason)) + write_headers(response.headers, write) + + +class BodyWriter: + def __call__(self, event: Event, write: Writer) -> None: + if type(event) is Data: + self.send_data(event.data, write) + elif type(event) is EndOfMessage: + self.send_eom(event.headers, write) + else: # pragma: no cover + assert False + + def send_data(self, data: bytes, write: Writer) -> None: + pass + + def send_eom(self, headers: Headers, write: Writer) -> None: + pass + + +# +# These are all careful not to do anything to 'data' except call len(data) and +# write(data). This allows us to transparently pass-through funny objects, +# like placeholder objects referring to files on disk that will be sent via +# sendfile(2). +# +class ContentLengthWriter(BodyWriter): + def __init__(self, length: int) -> None: + self._length = length + + def send_data(self, data: bytes, write: Writer) -> None: + self._length -= len(data) + if self._length < 0: + raise LocalProtocolError("Too much data for declared Content-Length") + write(data) + + def send_eom(self, headers: Headers, write: Writer) -> None: + if self._length != 0: + raise LocalProtocolError("Too little data for declared Content-Length") + if headers: + raise LocalProtocolError("Content-Length and trailers don't mix") + + +class ChunkedWriter(BodyWriter): + def send_data(self, data: bytes, write: Writer) -> None: + # if we encoded 0-length data in the naive way, it would look like an + # end-of-message. + if not data: + return + write(b"%x\r\n" % len(data)) + write(data) + write(b"\r\n") + + def send_eom(self, headers: Headers, write: Writer) -> None: + write(b"0\r\n") + write_headers(headers, write) + + +class Http10Writer(BodyWriter): + def send_data(self, data: bytes, write: Writer) -> None: + write(data) + + def send_eom(self, headers: Headers, write: Writer) -> None: + if headers: + raise LocalProtocolError("can't send trailers to HTTP/1.0 client") + # no need to close the socket ourselves, that will be taken care of by + # Connection: close machinery + + +WritersType = Dict[ + Union[Tuple[Type[Sentinel], Type[Sentinel]], Type[Sentinel]], + Union[ + Dict[str, Type[BodyWriter]], + Callable[[Union[InformationalResponse, Response], Writer], None], + Callable[[Request, Writer], None], + ], +] + +WRITERS: WritersType = { + (CLIENT, IDLE): write_request, + (SERVER, IDLE): write_any_response, + (SERVER, SEND_RESPONSE): write_any_response, + SEND_BODY: { + "chunked": ChunkedWriter, + "content-length": ContentLengthWriter, + "http/1.0": Http10Writer, + }, +} diff --git a/source/target-vendors/cp312/h11/py.typed b/source/target-vendors/cp312/h11/py.typed new file mode 100644 index 0000000..f5642f7 --- /dev/null +++ b/source/target-vendors/cp312/h11/py.typed @@ -0,0 +1 @@ +Marker diff --git a/source/target-vendors/cp312/httpcore-1.0.9.dist-info/METADATA b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/METADATA new file mode 100644 index 0000000..8056834 --- /dev/null +++ b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/METADATA @@ -0,0 +1,625 @@ +Metadata-Version: 2.4 +Name: httpcore +Version: 1.0.9 +Summary: A minimal low-level HTTP client. +Project-URL: Documentation, https://www.encode.io/httpcore +Project-URL: Homepage, https://www.encode.io/httpcore/ +Project-URL: Source, https://github.com/encode/httpcore +Author-email: Tom Christie +License-Expression: BSD-3-Clause +License-File: LICENSE.md +Classifier: Development Status :: 3 - Alpha +Classifier: Environment :: Web Environment +Classifier: Framework :: AsyncIO +Classifier: Framework :: Trio +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.8 +Requires-Dist: certifi +Requires-Dist: h11>=0.16 +Provides-Extra: asyncio +Requires-Dist: anyio<5.0,>=4.0; extra == 'asyncio' +Provides-Extra: http2 +Requires-Dist: h2<5,>=3; extra == 'http2' +Provides-Extra: socks +Requires-Dist: socksio==1.*; extra == 'socks' +Provides-Extra: trio +Requires-Dist: trio<1.0,>=0.22.0; extra == 'trio' +Description-Content-Type: text/markdown + +# HTTP Core + +[![Test Suite](https://github.com/encode/httpcore/workflows/Test%20Suite/badge.svg)](https://github.com/encode/httpcore/actions) +[![Package version](https://badge.fury.io/py/httpcore.svg)](https://pypi.org/project/httpcore/) + +> *Do one thing, and do it well.* + +The HTTP Core package provides a minimal low-level HTTP client, which does +one thing only. Sending HTTP requests. + +It does not provide any high level model abstractions over the API, +does not handle redirects, multipart uploads, building authentication headers, +transparent HTTP caching, URL parsing, session cookie handling, +content or charset decoding, handling JSON, environment based configuration +defaults, or any of that Jazz. + +Some things HTTP Core does do: + +* Sending HTTP requests. +* Thread-safe / task-safe connection pooling. +* HTTP(S) proxy & SOCKS proxy support. +* Supports HTTP/1.1 and HTTP/2. +* Provides both sync and async interfaces. +* Async backend support for `asyncio` and `trio`. + +## Requirements + +Python 3.8+ + +## Installation + +For HTTP/1.1 only support, install with: + +```shell +$ pip install httpcore +``` + +There are also a number of optional extras available... + +```shell +$ pip install httpcore['asyncio,trio,http2,socks'] +``` + +## Sending requests + +Send an HTTP request: + +```python +import httpcore + +response = httpcore.request("GET", "https://www.example.com/") + +print(response) +# +print(response.status) +# 200 +print(response.headers) +# [(b'Accept-Ranges', b'bytes'), (b'Age', b'557328'), (b'Cache-Control', b'max-age=604800'), ...] +print(response.content) +# b'\n\n\nExample Domain\n\n\n ...' +``` + +The top-level `httpcore.request()` function is provided for convenience. In practice whenever you're working with `httpcore` you'll want to use the connection pooling functionality that it provides. + +```python +import httpcore + +http = httpcore.ConnectionPool() +response = http.request("GET", "https://www.example.com/") +``` + +Once you're ready to get going, [head over to the documentation](https://www.encode.io/httpcore/). + +## Motivation + +You *probably* don't want to be using HTTP Core directly. It might make sense if +you're writing something like a proxy service in Python, and you just want +something at the lowest possible level, but more typically you'll want to use +a higher level client library, such as `httpx`. + +The motivation for `httpcore` is: + +* To provide a reusable low-level client library, that other packages can then build on top of. +* To provide a *really clear interface split* between the networking code and client logic, + so that each is easier to understand and reason about in isolation. + +## Dependencies + +The `httpcore` package has the following dependencies... + +* `h11` +* `certifi` + +And the following optional extras... + +* `anyio` - Required by `pip install httpcore['asyncio']`. +* `trio` - Required by `pip install httpcore['trio']`. +* `h2` - Required by `pip install httpcore['http2']`. +* `socksio` - Required by `pip install httpcore['socks']`. + +## Versioning + +We use [SEMVER for our versioning policy](https://semver.org/). + +For changes between package versions please see our [project changelog](CHANGELOG.md). + +We recommend pinning your requirements either the most current major version, or a more specific version range: + +```python +pip install 'httpcore==1.*' +``` +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## Version 1.0.9 (April 24th, 2025) + +- Resolve https://github.com/advisories/GHSA-vqfr-h8mv-ghfj with h11 dependency update. (#1008) + +## Version 1.0.8 (April 11th, 2025) + +- Fix `AttributeError` when importing on Python 3.14. (#1005) + +## Version 1.0.7 (November 15th, 2024) + +- Support `proxy=…` configuration on `ConnectionPool()`. (#974) + +## Version 1.0.6 (October 1st, 2024) + +- Relax `trio` dependency pinning. (#956) +- Handle `trio` raising `NotImplementedError` on unsupported platforms. (#955) +- Handle mapping `ssl.SSLError` to `httpcore.ConnectError`. (#918) + +## 1.0.5 (March 27th, 2024) + +- Handle `EndOfStream` exception for anyio backend. (#899) +- Allow trio `0.25.*` series in package dependancies. (#903) + +## 1.0.4 (February 21st, 2024) + +- Add `target` request extension. (#888) +- Fix support for connection `Upgrade` and `CONNECT` when some data in the stream has been read. (#882) + +## 1.0.3 (February 13th, 2024) + +- Fix support for async cancellations. (#880) +- Fix trace extension when used with socks proxy. (#849) +- Fix SSL context for connections using the "wss" scheme (#869) + +## 1.0.2 (November 10th, 2023) + +- Fix `float("inf")` timeouts in `Event.wait` function. (#846) + +## 1.0.1 (November 3rd, 2023) + +- Fix pool timeout to account for the total time spent retrying. (#823) +- Raise a neater RuntimeError when the correct async deps are not installed. (#826) +- Add support for synchronous TLS-in-TLS streams. (#840) + +## 1.0.0 (October 6th, 2023) + +From version 1.0 our async support is now optional, as the package has minimal dependencies by default. + +For async support use either `pip install 'httpcore[asyncio]'` or `pip install 'httpcore[trio]'`. + +The project versioning policy is now explicitly governed by SEMVER. See https://semver.org/. + +- Async support becomes fully optional. (#809) +- Add support for Python 3.12. (#807) + +## 0.18.0 (September 8th, 2023) + +- Add support for HTTPS proxies. (#745, #786) +- Drop Python 3.7 support. (#727) +- Handle `sni_hostname` extension with SOCKS proxy. (#774) +- Handle HTTP/1.1 half-closed connections gracefully. (#641) +- Change the type of `Extensions` from `Mapping[Str, Any]` to `MutableMapping[Str, Any]`. (#762) + +## 0.17.3 (July 5th, 2023) + +- Support async cancellations, ensuring that the connection pool is left in a clean state when cancellations occur. (#726) +- The networking backend interface has [been added to the public API](https://www.encode.io/httpcore/network-backends). Some classes which were previously private implementation detail are now part of the top-level public API. (#699) +- Graceful handling of HTTP/2 GoAway frames, with requests being transparently retried on a new connection. (#730) +- Add exceptions when a synchronous `trace callback` is passed to an asynchronous request or an asynchronous `trace callback` is passed to a synchronous request. (#717) +- Drop Python 3.7 support. (#727) + +## 0.17.2 (May 23th, 2023) + +- Add `socket_options` argument to `ConnectionPool` and `HTTProxy` classes. (#668) +- Improve logging with per-module logger names. (#690) +- Add `sni_hostname` request extension. (#696) +- Resolve race condition during import of `anyio` package. (#692) +- Enable TCP_NODELAY for all synchronous sockets. (#651) + +## 0.17.1 (May 17th, 2023) + +- If 'retries' is set, then allow retries if an SSL handshake error occurs. (#669) +- Improve correctness of tracebacks on network exceptions, by raising properly chained exceptions. (#678) +- Prevent connection-hanging behaviour when HTTP/2 connections are closed by a server-sent 'GoAway' frame. (#679) +- Fix edge-case exception when removing requests from the connection pool. (#680) +- Fix pool timeout edge-case. (#688) + +## 0.17.0 (March 16th, 2023) + +- Add DEBUG level logging. (#648) +- Respect HTTP/2 max concurrent streams when settings updates are sent by server. (#652) +- Increase the allowable HTTP header size to 100kB. (#647) +- Add `retries` option to SOCKS proxy classes. (#643) + +## 0.16.3 (December 20th, 2022) + +- Allow `ws` and `wss` schemes. Allows us to properly support websocket upgrade connections. (#625) +- Forwarding HTTP proxies use a connection-per-remote-host. Required by some proxy implementations. (#637) +- Don't raise `RuntimeError` when closing a connection pool with active connections. Removes some error cases when cancellations are used. (#631) +- Lazy import `anyio`, so that it's no longer a hard dependancy, and isn't imported if unused. (#639) + +## 0.16.2 (November 25th, 2022) + +- Revert 'Fix async cancellation behaviour', which introduced race conditions. (#627) +- Raise `RuntimeError` if attempting to us UNIX domain sockets on Windows. (#619) + +## 0.16.1 (November 17th, 2022) + +- Fix HTTP/1.1 interim informational responses, such as "100 Continue". (#605) + +## 0.16.0 (October 11th, 2022) + +- Support HTTP/1.1 informational responses. (#581) +- Fix async cancellation behaviour. (#580) +- Support `h11` 0.14. (#579) + +## 0.15.0 (May 17th, 2022) + +- Drop Python 3.6 support (#535) +- Ensure HTTP proxy CONNECT requests include `timeout` configuration. (#506) +- Switch to explicit `typing.Optional` for type hints. (#513) +- For `trio` map OSError exceptions to `ConnectError`. (#543) + +## 0.14.7 (February 4th, 2022) + +- Requests which raise a PoolTimeout need to be removed from the pool queue. (#502) +- Fix AttributeError that happened when Socks5Connection were terminated. (#501) + +## 0.14.6 (February 1st, 2022) + +- Fix SOCKS support for `http://` URLs. (#492) +- Resolve race condition around exceptions during streaming a response. (#491) + +## 0.14.5 (January 18th, 2022) + +- SOCKS proxy support. (#478) +- Add proxy_auth argument to HTTPProxy. (#481) +- Improve error message on 'RemoteProtocolError' exception when server disconnects without sending a response. (#479) + +## 0.14.4 (January 5th, 2022) + +- Support HTTP/2 on HTTPS tunnelling proxies. (#468) +- Fix proxy headers missing on HTTP forwarding. (#456) +- Only instantiate SSL context if required. (#457) +- More robust HTTP/2 handling. (#253, #439, #440, #441) + +## 0.14.3 (November 17th, 2021) + +- Fix race condition when removing closed connections from the pool. (#437) + +## 0.14.2 (November 16th, 2021) + +- Failed connections no longer remain in the pool. (Pull #433) + +## 0.14.1 (November 12th, 2021) + +- `max_connections` becomes optional. (Pull #429) +- `certifi` is now included in the install dependancies. (Pull #428) +- `h2` is now strictly optional. (Pull #428) + +## 0.14.0 (November 11th, 2021) + +The 0.14 release is a complete reworking of `httpcore`, comprehensively addressing some underlying issues in the connection pooling, as well as substantially redesigning the API to be more user friendly. + +Some of the lower-level API design also makes the components more easily testable in isolation, and the package now has 100% test coverage. + +See [discussion #419](https://github.com/encode/httpcore/discussions/419) for a little more background. + +There's some other neat bits in there too, such as the "trace" extension, which gives a hook into inspecting the internal events that occur during the request/response cycle. This extension is needed for the HTTPX cli, in order to... + +* Log the point at which the connection is established, and the IP/port on which it is made. +* Determine if the outgoing request should log as HTTP/1.1 or HTTP/2, rather than having to assume it's HTTP/2 if the --http2 flag was passed. (Which may not actually be true.) +* Log SSL version info / certificate info. + +Note that `curio` support is not currently available in 0.14.0. If you're using `httpcore` with `curio` please get in touch, so we can assess if we ought to prioritize it as a feature or not. + +## 0.13.7 (September 13th, 2021) + +- Fix broken error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #403) + +## 0.13.6 (June 15th, 2021) + +### Fixed + +- Close sockets when read or write timeouts occur. (Pull #365) + +## 0.13.5 (June 14th, 2021) + +### Fixed + +- Resolved niggles with AnyIO EOF behaviours. (Pull #358, #362) + +## 0.13.4 (June 9th, 2021) + +### Added + +- Improved error messaging when URL scheme is missing, or a non HTTP(S) scheme is used. (Pull #354) + +### Fixed + +- Switched to `anyio` as the default backend implementation when running with `asyncio`. Resolves some awkward [TLS timeout issues](https://github.com/encode/httpx/discussions/1511). + +## 0.13.3 (May 6th, 2021) + +### Added + +- Support HTTP/2 prior knowledge, using `httpcore.SyncConnectionPool(http1=False)`. (Pull #333) + +### Fixed + +- Handle cases where environment does not provide `select.poll` support. (Pull #331) + +## 0.13.2 (April 29th, 2021) + +### Added + +- Improve error message for specific case of `RemoteProtocolError` where server disconnects without sending a response. (Pull #313) + +## 0.13.1 (April 28th, 2021) + +### Fixed + +- More resiliant testing for closed connections. (Pull #311) +- Don't raise exceptions on ungraceful connection closes. (Pull #310) + +## 0.13.0 (April 21st, 2021) + +The 0.13 release updates the core API in order to match the HTTPX Transport API, +introduced in HTTPX 0.18 onwards. + +An example of making requests with the new interface is: + +```python +with httpcore.SyncConnectionPool() as http: + status_code, headers, stream, extensions = http.handle_request( + method=b'GET', + url=(b'https', b'example.org', 443, b'/'), + headers=[(b'host', b'example.org'), (b'user-agent', b'httpcore')] + stream=httpcore.ByteStream(b''), + extensions={} + ) + body = stream.read() + print(status_code, body) +``` + +### Changed + +- The `.request()` method is now `handle_request()`. (Pull #296) +- The `.arequest()` method is now `.handle_async_request()`. (Pull #296) +- The `headers` argument is no longer optional. (Pull #296) +- The `stream` argument is no longer optional. (Pull #296) +- The `ext` argument is now named `extensions`, and is no longer optional. (Pull #296) +- The `"reason"` extension keyword is now named `"reason_phrase"`. (Pull #296) +- The `"reason_phrase"` and `"http_version"` extensions now use byte strings for their values. (Pull #296) +- The `httpcore.PlainByteStream()` class becomes `httpcore.ByteStream()`. (Pull #296) + +### Added + +- Streams now support a `.read()` interface. (Pull #296) + +### Fixed + +- Task cancellation no longer leaks connections from the connection pool. (Pull #305) + +## 0.12.3 (December 7th, 2020) + +### Fixed + +- Abort SSL connections on close rather than waiting for remote EOF when using `asyncio`. (Pull #167) +- Fix exception raised in case of connect timeouts when using the `anyio` backend. (Pull #236) +- Fix `Host` header precedence for `:authority` in HTTP/2. (Pull #241, #243) +- Handle extra edge case when detecting for socket readability when using `asyncio`. (Pull #242, #244) +- Fix `asyncio` SSL warning when using proxy tunneling. (Pull #249) + +## 0.12.2 (November 20th, 2020) + +### Fixed + +- Properly wrap connect errors on the asyncio backend. (Pull #235) +- Fix `ImportError` occurring on Python 3.9 when using the HTTP/1.1 sync client in a multithreaded context. (Pull #237) + +## 0.12.1 (November 7th, 2020) + +### Added + +- Add connect retries. (Pull #221) + +### Fixed + +- Tweak detection of dropped connections, resolving an issue with open files limits on Linux. (Pull #185) +- Avoid leaking connections when establishing an HTTP tunnel to a proxy has failed. (Pull #223) +- Properly wrap OS errors when using `trio`. (Pull #225) + +## 0.12.0 (October 6th, 2020) + +### Changed + +- HTTP header casing is now preserved, rather than always sent in lowercase. (#216 and python-hyper/h11#104) + +### Added + +- Add Python 3.9 to officially supported versions. + +### Fixed + +- Gracefully handle a stdlib asyncio bug when a connection is closed while it is in a paused-for-reading state. (#201) + +## 0.11.1 (September 28nd, 2020) + +### Fixed + +- Add await to async semaphore release() coroutine (#197) +- Drop incorrect curio classifier (#192) + +## 0.11.0 (September 22nd, 2020) + +The Transport API with 0.11.0 has a couple of significant changes. + +Firstly we've moved changed the request interface in order to allow extensions, which will later enable us to support features +such as trailing headers, HTTP/2 server push, and CONNECT/Upgrade connections. + +The interface changes from: + +```python +def request(method, url, headers, stream, timeout): + return (http_version, status_code, reason, headers, stream) +``` + +To instead including an optional dictionary of extensions on the request and response: + +```python +def request(method, url, headers, stream, ext): + return (status_code, headers, stream, ext) +``` + +Having an open-ended extensions point will allow us to add later support for various optional features, that wouldn't otherwise be supported without these API changes. + +In particular: + +* Trailing headers support. +* HTTP/2 Server Push +* sendfile. +* Exposing raw connection on CONNECT, Upgrade, HTTP/2 bi-di streaming. +* Exposing debug information out of the API, including template name, template context. + +Currently extensions are limited to: + +* request: `timeout` - Optional. Timeout dictionary. +* response: `http_version` - Optional. Include the HTTP version used on the response. +* response: `reason` - Optional. Include the reason phrase used on the response. Only valid with HTTP/1.*. + +See https://github.com/encode/httpx/issues/1274#issuecomment-694884553 for the history behind this. + +Secondly, the async version of `request` is now namespaced as `arequest`. + +This allows concrete transports to support both sync and async implementations on the same class. + +### Added + +- Add curio support. (Pull #168) +- Add anyio support, with `backend="anyio"`. (Pull #169) + +### Changed + +- Update the Transport API to use 'ext' for optional extensions. (Pull #190) +- Update the Transport API to use `.request` and `.arequest` so implementations can support both sync and async. (Pull #189) + +## 0.10.2 (August 20th, 2020) + +### Added + +- Added Unix Domain Socket support. (Pull #139) + +### Fixed + +- Always include the port on proxy CONNECT requests. (Pull #154) +- Fix `max_keepalive_connections` configuration. (Pull #153) +- Fixes behaviour in HTTP/1.1 where server disconnects can be used to signal the end of the response body. (Pull #164) + +## 0.10.1 (August 7th, 2020) + +- Include `max_keepalive_connections` on `AsyncHTTPProxy`/`SyncHTTPProxy` classes. + +## 0.10.0 (August 7th, 2020) + +The most notable change in the 0.10.0 release is that HTTP/2 support is now fully optional. + +Use either `pip install httpcore` for HTTP/1.1 support only, or `pip install httpcore[http2]` for HTTP/1.1 and HTTP/2 support. + +### Added + +- HTTP/2 support becomes optional. (Pull #121, #130) +- Add `local_address=...` support. (Pull #100, #134) +- Add `PlainByteStream`, `IteratorByteStream`, `AsyncIteratorByteStream`. The `AsyncByteSteam` and `SyncByteStream` classes are now pure interface classes. (#133) +- Add `LocalProtocolError`, `RemoteProtocolError` exceptions. (Pull #129) +- Add `UnsupportedProtocol` exception. (Pull #128) +- Add `.get_connection_info()` method. (Pull #102, #137) +- Add better TRACE logs. (Pull #101) + +### Changed + +- `max_keepalive` is deprecated in favour of `max_keepalive_connections`. (Pull #140) + +### Fixed + +- Improve handling of server disconnects. (Pull #112) + +## 0.9.1 (May 27th, 2020) + +### Fixed + +- Proper host resolution for sync case, including IPv6 support. (Pull #97) +- Close outstanding connections when connection pool is closed. (Pull #98) + +## 0.9.0 (May 21th, 2020) + +### Changed + +- URL port becomes an `Optional[int]` instead of `int`. (Pull #92) + +### Fixed + +- Honor HTTP/2 max concurrent streams settings. (Pull #89, #90) +- Remove incorrect debug log. (Pull #83) + +## 0.8.4 (May 11th, 2020) + +### Added + +- Logging via HTTPCORE_LOG_LEVEL and HTTPX_LOG_LEVEL environment variables +and TRACE level logging. (Pull #79) + +### Fixed + +- Reuse of connections on HTTP/2 in close concurrency situations. (Pull #81) + +## 0.8.3 (May 6rd, 2020) + +### Fixed + +- Include `Host` and `Accept` headers on proxy "CONNECT" requests. +- De-duplicate any headers also contained in proxy_headers. +- HTTP/2 flag not being passed down to proxy connections. + +## 0.8.2 (May 3rd, 2020) + +### Fixed + +- Fix connections using proxy forwarding requests not being added to the +connection pool properly. (Pull #70) + +## 0.8.1 (April 30th, 2020) + +### Changed + +- Allow inherintance of both `httpcore.AsyncByteStream`, `httpcore.SyncByteStream` without type conflicts. + +## 0.8.0 (April 30th, 2020) + +### Fixed + +- Fixed tunnel proxy support. + +### Added + +- New `TimeoutException` base class. + +## 0.7.0 (March 5th, 2020) + +- First integration with HTTPX. diff --git a/source/target-vendors/cp312/httpcore-1.0.9.dist-info/RECORD b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/RECORD new file mode 100644 index 0000000..d9a731a --- /dev/null +++ b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/RECORD @@ -0,0 +1,36 @@ +httpcore/__init__.py,sha256=9kT_kqChCCJUTHww24ZmR_ezcdbpRYWksD-gYNzkZP8,3445 +httpcore/_api.py,sha256=unZmeDschBWCGCPCwkS3Wot9euK6bg_kKxLtGTxw214,3146 +httpcore/_exceptions.py,sha256=looCKga3_YVYu3s-d3L9RMPRJyhsY7fiuuGxvkOD0c0,1184 +httpcore/_models.py,sha256=IO2CcXcdpovRcLTdGFGB6RyBZdEm2h_TOmoCc4rEKho,17623 +httpcore/_ssl.py,sha256=srqmSNU4iOUvWF-SrJvb8G_YEbHFELOXQOwdDIBTS9c,187 +httpcore/_synchronization.py,sha256=zSi13mAColBnknjZBknUC6hKNDQT4C6ijnezZ-r0T2s,9434 +httpcore/_trace.py,sha256=ck6ZoIzYTkdNAIfq5MGeKqBXDtqjOX-qfYwmZFbrGco,3952 +httpcore/_utils.py,sha256=_RLgXYOAYC350ikALV59GZ68IJrdocRZxPs9PjmzdFY,1537 +httpcore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +httpcore/_async/__init__.py,sha256=EWdl2v4thnAHzJpqjU4h2a8DUiGAvNiWrkii9pfhTf0,1221 +httpcore/_async/connection.py,sha256=6OcPXqMEfc0BU38_-iHUNDd1vKSTc2UVT09XqNb_BOk,8449 +httpcore/_async/connection_pool.py,sha256=DOIQ2s2ZCf9qfwxhzMprTPLqCL8OxGXiKF6qRHxvVyY,17307 +httpcore/_async/http11.py,sha256=-qM9bV7PjSQF5vxs37-eUXOIFwbIjPcZbNliuX9TtBw,13880 +httpcore/_async/http2.py,sha256=azX1fcmtXaIwjputFlZ4vd92J8xwjGOa9ax9QIv4394,23936 +httpcore/_async/http_proxy.py,sha256=2zVkrlv-Ds-rWGaqaXlrhEJiAQFPo23BT3Gq_sWoBXU,14701 +httpcore/_async/interfaces.py,sha256=jTiaWL83pgpGC9ziv90ZfwaKNMmHwmOalzaKiuTxATo,4455 +httpcore/_async/socks_proxy.py,sha256=lLKgLlggPfhFlqi0ODeBkOWvt9CghBBUyqsnsU1tx6Q,13841 +httpcore/_backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +httpcore/_backends/anyio.py,sha256=x8PgEhXRC8bVqsdzk_YJx8Y6d9Tub06CuUSwnbmtqoY,5252 +httpcore/_backends/auto.py,sha256=zO136PKZmsaTDK-HRk84eA-MUg8_2wJf4NvmK432Aio,1662 +httpcore/_backends/base.py,sha256=aShgRdZnMmRhFWHetjumlM73f8Kz1YOAyCUP_4kHslA,3042 +httpcore/_backends/mock.py,sha256=er9T436uSe7NLrfiLa4x6Nuqg5ivQ693CxWYCWsgbH4,4077 +httpcore/_backends/sync.py,sha256=bhE4d9iK9Umxdsdsgm2EfKnXaBms2WggGYU-7jmUujU,7977 +httpcore/_backends/trio.py,sha256=LHu4_Mr5MswQmmT3yE4oLgf9b_JJfeVS4BjDxeJc7Ro,5996 +httpcore/_sync/__init__.py,sha256=JBDIgXt5la1LCJ1sLQeKhjKFpLnpNr8Svs6z2ni3fgg,1141 +httpcore/_sync/connection.py,sha256=9exGOb3PB-Mp2T1-sckSeL2t-tJ_9-NXomV8ihmWCgU,8238 +httpcore/_sync/connection_pool.py,sha256=a-T8LTsUxc7r0Ww1atfHSDoWPjQ0fA8Ul7S3-F0Mj70,16955 +httpcore/_sync/http11.py,sha256=IFobD1Md5JFlJGKWnh1_Q3epikUryI8qo09v8MiJIEA,13476 +httpcore/_sync/http2.py,sha256=AxU4yhcq68Bn5vqdJYtiXKYUj7nvhYbxz3v4rT4xnvA,23400 +httpcore/_sync/http_proxy.py,sha256=_al_6crKuEZu2wyvu493RZImJdBJnj5oGKNjLOJL2Zo,14463 +httpcore/_sync/interfaces.py,sha256=snXON42vUDHO5JBJvo8D4VWk2Wat44z2OXXHDrjbl94,4344 +httpcore/_sync/socks_proxy.py,sha256=zegZW9Snqj2_992DFJa8_CppOVBkVL4AgwduRkStakQ,13614 +httpcore-1.0.9.dist-info/METADATA,sha256=_i1P2mGZEol4d54M8n88BFxTGGP83Zh-rMdPOhjUHCE,21529 +httpcore-1.0.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 +httpcore-1.0.9.dist-info/licenses/LICENSE.md,sha256=_ctZFUx0y6uhahEkL3dAvqnyPW_rVUeRfYxflKgDkqU,1518 +httpcore-1.0.9.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/httpcore-1.0.9.dist-info/WHEEL b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/WHEEL new file mode 100644 index 0000000..12228d4 --- /dev/null +++ b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.27.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/httpcore-1.0.9.dist-info/licenses/LICENSE.md b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/licenses/LICENSE.md new file mode 100644 index 0000000..311b2b5 --- /dev/null +++ b/source/target-vendors/cp312/httpcore-1.0.9.dist-info/licenses/LICENSE.md @@ -0,0 +1,27 @@ +Copyright © 2020, [Encode OSS Ltd](https://www.encode.io/). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/httpcore/__init__.py b/source/target-vendors/cp312/httpcore/__init__.py new file mode 100644 index 0000000..9a92dc4 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/__init__.py @@ -0,0 +1,141 @@ +from ._api import request, stream +from ._async import ( + AsyncConnectionInterface, + AsyncConnectionPool, + AsyncHTTP2Connection, + AsyncHTTP11Connection, + AsyncHTTPConnection, + AsyncHTTPProxy, + AsyncSOCKSProxy, +) +from ._backends.base import ( + SOCKET_OPTION, + AsyncNetworkBackend, + AsyncNetworkStream, + NetworkBackend, + NetworkStream, +) +from ._backends.mock import AsyncMockBackend, AsyncMockStream, MockBackend, MockStream +from ._backends.sync import SyncBackend +from ._exceptions import ( + ConnectError, + ConnectionNotAvailable, + ConnectTimeout, + LocalProtocolError, + NetworkError, + PoolTimeout, + ProtocolError, + ProxyError, + ReadError, + ReadTimeout, + RemoteProtocolError, + TimeoutException, + UnsupportedProtocol, + WriteError, + WriteTimeout, +) +from ._models import URL, Origin, Proxy, Request, Response +from ._ssl import default_ssl_context +from ._sync import ( + ConnectionInterface, + ConnectionPool, + HTTP2Connection, + HTTP11Connection, + HTTPConnection, + HTTPProxy, + SOCKSProxy, +) + +# The 'httpcore.AnyIOBackend' class is conditional on 'anyio' being installed. +try: + from ._backends.anyio import AnyIOBackend +except ImportError: # pragma: nocover + + class AnyIOBackend: # type: ignore + def __init__(self, *args, **kwargs): # type: ignore + msg = ( + "Attempted to use 'httpcore.AnyIOBackend' but 'anyio' is not installed." + ) + raise RuntimeError(msg) + + +# The 'httpcore.TrioBackend' class is conditional on 'trio' being installed. +try: + from ._backends.trio import TrioBackend +except ImportError: # pragma: nocover + + class TrioBackend: # type: ignore + def __init__(self, *args, **kwargs): # type: ignore + msg = "Attempted to use 'httpcore.TrioBackend' but 'trio' is not installed." + raise RuntimeError(msg) + + +__all__ = [ + # top-level requests + "request", + "stream", + # models + "Origin", + "URL", + "Request", + "Response", + "Proxy", + # async + "AsyncHTTPConnection", + "AsyncConnectionPool", + "AsyncHTTPProxy", + "AsyncHTTP11Connection", + "AsyncHTTP2Connection", + "AsyncConnectionInterface", + "AsyncSOCKSProxy", + # sync + "HTTPConnection", + "ConnectionPool", + "HTTPProxy", + "HTTP11Connection", + "HTTP2Connection", + "ConnectionInterface", + "SOCKSProxy", + # network backends, implementations + "SyncBackend", + "AnyIOBackend", + "TrioBackend", + # network backends, mock implementations + "AsyncMockBackend", + "AsyncMockStream", + "MockBackend", + "MockStream", + # network backends, interface + "AsyncNetworkStream", + "AsyncNetworkBackend", + "NetworkStream", + "NetworkBackend", + # util + "default_ssl_context", + "SOCKET_OPTION", + # exceptions + "ConnectionNotAvailable", + "ProxyError", + "ProtocolError", + "LocalProtocolError", + "RemoteProtocolError", + "UnsupportedProtocol", + "TimeoutException", + "PoolTimeout", + "ConnectTimeout", + "ReadTimeout", + "WriteTimeout", + "NetworkError", + "ConnectError", + "ReadError", + "WriteError", +] + +__version__ = "1.0.9" + + +__locals = locals() +for __name in __all__: + # Exclude SOCKET_OPTION, it causes AttributeError on Python 3.14 + if not __name.startswith(("__", "SOCKET_OPTION")): + setattr(__locals[__name], "__module__", "httpcore") # noqa diff --git a/source/target-vendors/cp312/httpcore/_api.py b/source/target-vendors/cp312/httpcore/_api.py new file mode 100644 index 0000000..38b961d --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_api.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +import contextlib +import typing + +from ._models import URL, Extensions, HeaderTypes, Response +from ._sync.connection_pool import ConnectionPool + + +def request( + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes | typing.Iterator[bytes] | None = None, + extensions: Extensions | None = None, +) -> Response: + """ + Sends an HTTP request, returning the response. + + ``` + response = httpcore.request("GET", "https://www.example.com/") + ``` + + Arguments: + method: The HTTP method for the request. Typically one of `"GET"`, + `"OPTIONS"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, or `"DELETE"`. + url: The URL of the HTTP request. Either as an instance of `httpcore.URL`, + or as str/bytes. + headers: The HTTP request headers. Either as a dictionary of str/bytes, + or as a list of two-tuples of str/bytes. + content: The content of the request body. Either as bytes, + or as a bytes iterator. + extensions: A dictionary of optional extra information included on the request. + Possible keys include `"timeout"`. + + Returns: + An instance of `httpcore.Response`. + """ + with ConnectionPool() as pool: + return pool.request( + method=method, + url=url, + headers=headers, + content=content, + extensions=extensions, + ) + + +@contextlib.contextmanager +def stream( + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes | typing.Iterator[bytes] | None = None, + extensions: Extensions | None = None, +) -> typing.Iterator[Response]: + """ + Sends an HTTP request, returning the response within a content manager. + + ``` + with httpcore.stream("GET", "https://www.example.com/") as response: + ... + ``` + + When using the `stream()` function, the body of the response will not be + automatically read. If you want to access the response body you should + either use `content = response.read()`, or `for chunk in response.iter_content()`. + + Arguments: + method: The HTTP method for the request. Typically one of `"GET"`, + `"OPTIONS"`, `"HEAD"`, `"POST"`, `"PUT"`, `"PATCH"`, or `"DELETE"`. + url: The URL of the HTTP request. Either as an instance of `httpcore.URL`, + or as str/bytes. + headers: The HTTP request headers. Either as a dictionary of str/bytes, + or as a list of two-tuples of str/bytes. + content: The content of the request body. Either as bytes, + or as a bytes iterator. + extensions: A dictionary of optional extra information included on the request. + Possible keys include `"timeout"`. + + Returns: + An instance of `httpcore.Response`. + """ + with ConnectionPool() as pool: + with pool.stream( + method=method, + url=url, + headers=headers, + content=content, + extensions=extensions, + ) as response: + yield response diff --git a/source/target-vendors/cp312/httpcore/_async/__init__.py b/source/target-vendors/cp312/httpcore/_async/__init__.py new file mode 100644 index 0000000..88dc7f0 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/__init__.py @@ -0,0 +1,39 @@ +from .connection import AsyncHTTPConnection +from .connection_pool import AsyncConnectionPool +from .http11 import AsyncHTTP11Connection +from .http_proxy import AsyncHTTPProxy +from .interfaces import AsyncConnectionInterface + +try: + from .http2 import AsyncHTTP2Connection +except ImportError: # pragma: nocover + + class AsyncHTTP2Connection: # type: ignore + def __init__(self, *args, **kwargs) -> None: # type: ignore + raise RuntimeError( + "Attempted to use http2 support, but the `h2` package is not " + "installed. Use 'pip install httpcore[http2]'." + ) + + +try: + from .socks_proxy import AsyncSOCKSProxy +except ImportError: # pragma: nocover + + class AsyncSOCKSProxy: # type: ignore + def __init__(self, *args, **kwargs) -> None: # type: ignore + raise RuntimeError( + "Attempted to use SOCKS support, but the `socksio` package is not " + "installed. Use 'pip install httpcore[socks]'." + ) + + +__all__ = [ + "AsyncHTTPConnection", + "AsyncConnectionPool", + "AsyncHTTPProxy", + "AsyncHTTP11Connection", + "AsyncHTTP2Connection", + "AsyncConnectionInterface", + "AsyncSOCKSProxy", +] diff --git a/source/target-vendors/cp312/httpcore/_async/connection.py b/source/target-vendors/cp312/httpcore/_async/connection.py new file mode 100644 index 0000000..b42581d --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/connection.py @@ -0,0 +1,222 @@ +from __future__ import annotations + +import itertools +import logging +import ssl +import types +import typing + +from .._backends.auto import AutoBackend +from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream +from .._exceptions import ConnectError, ConnectTimeout +from .._models import Origin, Request, Response +from .._ssl import default_ssl_context +from .._synchronization import AsyncLock +from .._trace import Trace +from .http11 import AsyncHTTP11Connection +from .interfaces import AsyncConnectionInterface + +RETRIES_BACKOFF_FACTOR = 0.5 # 0s, 0.5s, 1s, 2s, 4s, etc. + + +logger = logging.getLogger("httpcore.connection") + + +def exponential_backoff(factor: float) -> typing.Iterator[float]: + """ + Generate a geometric sequence that has a ratio of 2 and starts with 0. + + For example: + - `factor = 2`: `0, 2, 4, 8, 16, 32, 64, ...` + - `factor = 3`: `0, 3, 6, 12, 24, 48, 96, ...` + """ + yield 0 + for n in itertools.count(): + yield factor * 2**n + + +class AsyncHTTPConnection(AsyncConnectionInterface): + def __init__( + self, + origin: Origin, + ssl_context: ssl.SSLContext | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + local_address: str | None = None, + uds: str | None = None, + network_backend: AsyncNetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + self._origin = origin + self._ssl_context = ssl_context + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + self._retries = retries + self._local_address = local_address + self._uds = uds + + self._network_backend: AsyncNetworkBackend = ( + AutoBackend() if network_backend is None else network_backend + ) + self._connection: AsyncConnectionInterface | None = None + self._connect_failed: bool = False + self._request_lock = AsyncLock() + self._socket_options = socket_options + + async def handle_async_request(self, request: Request) -> Response: + if not self.can_handle_request(request.url.origin): + raise RuntimeError( + f"Attempted to send request to {request.url.origin} on connection to {self._origin}" + ) + + try: + async with self._request_lock: + if self._connection is None: + stream = await self._connect(request) + + ssl_object = stream.get_extra_info("ssl_object") + http2_negotiated = ( + ssl_object is not None + and ssl_object.selected_alpn_protocol() == "h2" + ) + if http2_negotiated or (self._http2 and not self._http1): + from .http2 import AsyncHTTP2Connection + + self._connection = AsyncHTTP2Connection( + origin=self._origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + else: + self._connection = AsyncHTTP11Connection( + origin=self._origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + except BaseException as exc: + self._connect_failed = True + raise exc + + return await self._connection.handle_async_request(request) + + async def _connect(self, request: Request) -> AsyncNetworkStream: + timeouts = request.extensions.get("timeout", {}) + sni_hostname = request.extensions.get("sni_hostname", None) + timeout = timeouts.get("connect", None) + + retries_left = self._retries + delays = exponential_backoff(factor=RETRIES_BACKOFF_FACTOR) + + while True: + try: + if self._uds is None: + kwargs = { + "host": self._origin.host.decode("ascii"), + "port": self._origin.port, + "local_address": self._local_address, + "timeout": timeout, + "socket_options": self._socket_options, + } + async with Trace("connect_tcp", logger, request, kwargs) as trace: + stream = await self._network_backend.connect_tcp(**kwargs) + trace.return_value = stream + else: + kwargs = { + "path": self._uds, + "timeout": timeout, + "socket_options": self._socket_options, + } + async with Trace( + "connect_unix_socket", logger, request, kwargs + ) as trace: + stream = await self._network_backend.connect_unix_socket( + **kwargs + ) + trace.return_value = stream + + if self._origin.scheme in (b"https", b"wss"): + ssl_context = ( + default_ssl_context() + if self._ssl_context is None + else self._ssl_context + ) + alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] + ssl_context.set_alpn_protocols(alpn_protocols) + + kwargs = { + "ssl_context": ssl_context, + "server_hostname": sni_hostname + or self._origin.host.decode("ascii"), + "timeout": timeout, + } + async with Trace("start_tls", logger, request, kwargs) as trace: + stream = await stream.start_tls(**kwargs) + trace.return_value = stream + return stream + except (ConnectError, ConnectTimeout): + if retries_left <= 0: + raise + retries_left -= 1 + delay = next(delays) + async with Trace("retry", logger, request, kwargs) as trace: + await self._network_backend.sleep(delay) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._origin + + async def aclose(self) -> None: + if self._connection is not None: + async with Trace("close", logger, None, {}): + await self._connection.aclose() + + def is_available(self) -> bool: + if self._connection is None: + # If HTTP/2 support is enabled, and the resulting connection could + # end up as HTTP/2 then we should indicate the connection as being + # available to service multiple requests. + return ( + self._http2 + and (self._origin.scheme == b"https" or not self._http1) + and not self._connect_failed + ) + return self._connection.is_available() + + def has_expired(self) -> bool: + if self._connection is None: + return self._connect_failed + return self._connection.has_expired() + + def is_idle(self) -> bool: + if self._connection is None: + return self._connect_failed + return self._connection.is_idle() + + def is_closed(self) -> bool: + if self._connection is None: + return self._connect_failed + return self._connection.is_closed() + + def info(self) -> str: + if self._connection is None: + return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + return self._connection.info() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" + + # These context managers are not used in the standard flow, but are + # useful for testing or working with connection instances directly. + + async def __aenter__(self) -> AsyncHTTPConnection: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + await self.aclose() diff --git a/source/target-vendors/cp312/httpcore/_async/connection_pool.py b/source/target-vendors/cp312/httpcore/_async/connection_pool.py new file mode 100644 index 0000000..96e973d --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/connection_pool.py @@ -0,0 +1,420 @@ +from __future__ import annotations + +import ssl +import sys +import types +import typing + +from .._backends.auto import AutoBackend +from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend +from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol +from .._models import Origin, Proxy, Request, Response +from .._synchronization import AsyncEvent, AsyncShieldCancellation, AsyncThreadLock +from .connection import AsyncHTTPConnection +from .interfaces import AsyncConnectionInterface, AsyncRequestInterface + + +class AsyncPoolRequest: + def __init__(self, request: Request) -> None: + self.request = request + self.connection: AsyncConnectionInterface | None = None + self._connection_acquired = AsyncEvent() + + def assign_to_connection(self, connection: AsyncConnectionInterface | None) -> None: + self.connection = connection + self._connection_acquired.set() + + def clear_connection(self) -> None: + self.connection = None + self._connection_acquired = AsyncEvent() + + async def wait_for_connection( + self, timeout: float | None = None + ) -> AsyncConnectionInterface: + if self.connection is None: + await self._connection_acquired.wait(timeout=timeout) + assert self.connection is not None + return self.connection + + def is_queued(self) -> bool: + return self.connection is None + + +class AsyncConnectionPool(AsyncRequestInterface): + """ + A connection pool for making HTTP requests. + """ + + def __init__( + self, + ssl_context: ssl.SSLContext | None = None, + proxy: Proxy | None = None, + max_connections: int | None = 10, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + local_address: str | None = None, + uds: str | None = None, + network_backend: AsyncNetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + """ + A connection pool for making HTTP requests. + + Parameters: + ssl_context: An SSL context to use for verifying connections. + If not specified, the default `httpcore.default_ssl_context()` + will be used. + max_connections: The maximum number of concurrent HTTP connections that + the pool should allow. Any attempt to send a request on a pool that + would exceed this amount will block until a connection is available. + max_keepalive_connections: The maximum number of idle HTTP connections + that will be maintained in the pool. + keepalive_expiry: The duration in seconds that an idle HTTP connection + may be maintained for before being expired from the pool. + http1: A boolean indicating if HTTP/1.1 requests should be supported + by the connection pool. Defaults to True. + http2: A boolean indicating if HTTP/2 requests should be supported by + the connection pool. Defaults to False. + retries: The maximum number of retries when trying to establish a + connection. + local_address: Local address to connect from. Can also be used to connect + using a particular address family. Using `local_address="0.0.0.0"` + will connect using an `AF_INET` address (IPv4), while using + `local_address="::"` will connect using an `AF_INET6` address (IPv6). + uds: Path to a Unix Domain Socket to use instead of TCP sockets. + network_backend: A backend instance to use for handling network I/O. + socket_options: Socket options that have to be included + in the TCP socket when the connection was established. + """ + self._ssl_context = ssl_context + self._proxy = proxy + self._max_connections = ( + sys.maxsize if max_connections is None else max_connections + ) + self._max_keepalive_connections = ( + sys.maxsize + if max_keepalive_connections is None + else max_keepalive_connections + ) + self._max_keepalive_connections = min( + self._max_connections, self._max_keepalive_connections + ) + + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + self._retries = retries + self._local_address = local_address + self._uds = uds + + self._network_backend = ( + AutoBackend() if network_backend is None else network_backend + ) + self._socket_options = socket_options + + # The mutable state on a connection pool is the queue of incoming requests, + # and the set of connections that are servicing those requests. + self._connections: list[AsyncConnectionInterface] = [] + self._requests: list[AsyncPoolRequest] = [] + + # We only mutate the state of the connection pool within an 'optional_thread_lock' + # context. This holds a threading lock unless we're running in async mode, + # in which case it is a no-op. + self._optional_thread_lock = AsyncThreadLock() + + def create_connection(self, origin: Origin) -> AsyncConnectionInterface: + if self._proxy is not None: + if self._proxy.url.scheme in (b"socks5", b"socks5h"): + from .socks_proxy import AsyncSocks5Connection + + return AsyncSocks5Connection( + proxy_origin=self._proxy.url.origin, + proxy_auth=self._proxy.auth, + remote_origin=origin, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + elif origin.scheme == b"http": + from .http_proxy import AsyncForwardHTTPConnection + + return AsyncForwardHTTPConnection( + proxy_origin=self._proxy.url.origin, + proxy_headers=self._proxy.headers, + proxy_ssl_context=self._proxy.ssl_context, + remote_origin=origin, + keepalive_expiry=self._keepalive_expiry, + network_backend=self._network_backend, + ) + from .http_proxy import AsyncTunnelHTTPConnection + + return AsyncTunnelHTTPConnection( + proxy_origin=self._proxy.url.origin, + proxy_headers=self._proxy.headers, + proxy_ssl_context=self._proxy.ssl_context, + remote_origin=origin, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + + return AsyncHTTPConnection( + origin=origin, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + retries=self._retries, + local_address=self._local_address, + uds=self._uds, + network_backend=self._network_backend, + socket_options=self._socket_options, + ) + + @property + def connections(self) -> list[AsyncConnectionInterface]: + """ + Return a list of the connections currently in the pool. + + For example: + + ```python + >>> pool.connections + [ + , + , + , + ] + ``` + """ + return list(self._connections) + + async def handle_async_request(self, request: Request) -> Response: + """ + Send an HTTP request, and return an HTTP response. + + This is the core implementation that is called into by `.request()` or `.stream()`. + """ + scheme = request.url.scheme.decode() + if scheme == "": + raise UnsupportedProtocol( + "Request URL is missing an 'http://' or 'https://' protocol." + ) + if scheme not in ("http", "https", "ws", "wss"): + raise UnsupportedProtocol( + f"Request URL has an unsupported protocol '{scheme}://'." + ) + + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("pool", None) + + with self._optional_thread_lock: + # Add the incoming request to our request queue. + pool_request = AsyncPoolRequest(request) + self._requests.append(pool_request) + + try: + while True: + with self._optional_thread_lock: + # Assign incoming requests to available connections, + # closing or creating new connections as required. + closing = self._assign_requests_to_connections() + await self._close_connections(closing) + + # Wait until this request has an assigned connection. + connection = await pool_request.wait_for_connection(timeout=timeout) + + try: + # Send the request on the assigned connection. + response = await connection.handle_async_request( + pool_request.request + ) + except ConnectionNotAvailable: + # In some cases a connection may initially be available to + # handle a request, but then become unavailable. + # + # In this case we clear the connection and try again. + pool_request.clear_connection() + else: + break # pragma: nocover + + except BaseException as exc: + with self._optional_thread_lock: + # For any exception or cancellation we remove the request from + # the queue, and then re-assign requests to connections. + self._requests.remove(pool_request) + closing = self._assign_requests_to_connections() + + await self._close_connections(closing) + raise exc from None + + # Return the response. Note that in this case we still have to manage + # the point at which the response is closed. + assert isinstance(response.stream, typing.AsyncIterable) + return Response( + status=response.status, + headers=response.headers, + content=PoolByteStream( + stream=response.stream, pool_request=pool_request, pool=self + ), + extensions=response.extensions, + ) + + def _assign_requests_to_connections(self) -> list[AsyncConnectionInterface]: + """ + Manage the state of the connection pool, assigning incoming + requests to connections as available. + + Called whenever a new request is added or removed from the pool. + + Any closing connections are returned, allowing the I/O for closing + those connections to be handled seperately. + """ + closing_connections = [] + + # First we handle cleaning up any connections that are closed, + # have expired their keep-alive, or surplus idle connections. + for connection in list(self._connections): + if connection.is_closed(): + # log: "removing closed connection" + self._connections.remove(connection) + elif connection.has_expired(): + # log: "closing expired connection" + self._connections.remove(connection) + closing_connections.append(connection) + elif ( + connection.is_idle() + and len([connection.is_idle() for connection in self._connections]) + > self._max_keepalive_connections + ): + # log: "closing idle connection" + self._connections.remove(connection) + closing_connections.append(connection) + + # Assign queued requests to connections. + queued_requests = [request for request in self._requests if request.is_queued()] + for pool_request in queued_requests: + origin = pool_request.request.url.origin + available_connections = [ + connection + for connection in self._connections + if connection.can_handle_request(origin) and connection.is_available() + ] + idle_connections = [ + connection for connection in self._connections if connection.is_idle() + ] + + # There are three cases for how we may be able to handle the request: + # + # 1. There is an existing connection that can handle the request. + # 2. We can create a new connection to handle the request. + # 3. We can close an idle connection and then create a new connection + # to handle the request. + if available_connections: + # log: "reusing existing connection" + connection = available_connections[0] + pool_request.assign_to_connection(connection) + elif len(self._connections) < self._max_connections: + # log: "creating new connection" + connection = self.create_connection(origin) + self._connections.append(connection) + pool_request.assign_to_connection(connection) + elif idle_connections: + # log: "closing idle connection" + connection = idle_connections[0] + self._connections.remove(connection) + closing_connections.append(connection) + # log: "creating new connection" + connection = self.create_connection(origin) + self._connections.append(connection) + pool_request.assign_to_connection(connection) + + return closing_connections + + async def _close_connections(self, closing: list[AsyncConnectionInterface]) -> None: + # Close connections which have been removed from the pool. + with AsyncShieldCancellation(): + for connection in closing: + await connection.aclose() + + async def aclose(self) -> None: + # Explicitly close the connection pool. + # Clears all existing requests and connections. + with self._optional_thread_lock: + closing_connections = list(self._connections) + self._connections = [] + await self._close_connections(closing_connections) + + async def __aenter__(self) -> AsyncConnectionPool: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + await self.aclose() + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + with self._optional_thread_lock: + request_is_queued = [request.is_queued() for request in self._requests] + connection_is_idle = [ + connection.is_idle() for connection in self._connections + ] + + num_active_requests = request_is_queued.count(False) + num_queued_requests = request_is_queued.count(True) + num_active_connections = connection_is_idle.count(False) + num_idle_connections = connection_is_idle.count(True) + + requests_info = ( + f"Requests: {num_active_requests} active, {num_queued_requests} queued" + ) + connection_info = ( + f"Connections: {num_active_connections} active, {num_idle_connections} idle" + ) + + return f"<{class_name} [{requests_info} | {connection_info}]>" + + +class PoolByteStream: + def __init__( + self, + stream: typing.AsyncIterable[bytes], + pool_request: AsyncPoolRequest, + pool: AsyncConnectionPool, + ) -> None: + self._stream = stream + self._pool_request = pool_request + self._pool = pool + self._closed = False + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + try: + async for part in self._stream: + yield part + except BaseException as exc: + await self.aclose() + raise exc from None + + async def aclose(self) -> None: + if not self._closed: + self._closed = True + with AsyncShieldCancellation(): + if hasattr(self._stream, "aclose"): + await self._stream.aclose() + + with self._pool._optional_thread_lock: + self._pool._requests.remove(self._pool_request) + closing = self._pool._assign_requests_to_connections() + + await self._pool._close_connections(closing) diff --git a/source/target-vendors/cp312/httpcore/_async/http11.py b/source/target-vendors/cp312/httpcore/_async/http11.py new file mode 100644 index 0000000..e6d6d70 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/http11.py @@ -0,0 +1,379 @@ +from __future__ import annotations + +import enum +import logging +import ssl +import time +import types +import typing + +import h11 + +from .._backends.base import AsyncNetworkStream +from .._exceptions import ( + ConnectionNotAvailable, + LocalProtocolError, + RemoteProtocolError, + WriteError, + map_exceptions, +) +from .._models import Origin, Request, Response +from .._synchronization import AsyncLock, AsyncShieldCancellation +from .._trace import Trace +from .interfaces import AsyncConnectionInterface + +logger = logging.getLogger("httpcore.http11") + + +# A subset of `h11.Event` types supported by `_send_event` +H11SendEvent = typing.Union[ + h11.Request, + h11.Data, + h11.EndOfMessage, +] + + +class HTTPConnectionState(enum.IntEnum): + NEW = 0 + ACTIVE = 1 + IDLE = 2 + CLOSED = 3 + + +class AsyncHTTP11Connection(AsyncConnectionInterface): + READ_NUM_BYTES = 64 * 1024 + MAX_INCOMPLETE_EVENT_SIZE = 100 * 1024 + + def __init__( + self, + origin: Origin, + stream: AsyncNetworkStream, + keepalive_expiry: float | None = None, + ) -> None: + self._origin = origin + self._network_stream = stream + self._keepalive_expiry: float | None = keepalive_expiry + self._expire_at: float | None = None + self._state = HTTPConnectionState.NEW + self._state_lock = AsyncLock() + self._request_count = 0 + self._h11_state = h11.Connection( + our_role=h11.CLIENT, + max_incomplete_event_size=self.MAX_INCOMPLETE_EVENT_SIZE, + ) + + async def handle_async_request(self, request: Request) -> Response: + if not self.can_handle_request(request.url.origin): + raise RuntimeError( + f"Attempted to send request to {request.url.origin} on connection " + f"to {self._origin}" + ) + + async with self._state_lock: + if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): + self._request_count += 1 + self._state = HTTPConnectionState.ACTIVE + self._expire_at = None + else: + raise ConnectionNotAvailable() + + try: + kwargs = {"request": request} + try: + async with Trace( + "send_request_headers", logger, request, kwargs + ) as trace: + await self._send_request_headers(**kwargs) + async with Trace("send_request_body", logger, request, kwargs) as trace: + await self._send_request_body(**kwargs) + except WriteError: + # If we get a write error while we're writing the request, + # then we supress this error and move on to attempting to + # read the response. Servers can sometimes close the request + # pre-emptively and then respond with a well formed HTTP + # error response. + pass + + async with Trace( + "receive_response_headers", logger, request, kwargs + ) as trace: + ( + http_version, + status, + reason_phrase, + headers, + trailing_data, + ) = await self._receive_response_headers(**kwargs) + trace.return_value = ( + http_version, + status, + reason_phrase, + headers, + ) + + network_stream = self._network_stream + + # CONNECT or Upgrade request + if (status == 101) or ( + (request.method == b"CONNECT") and (200 <= status < 300) + ): + network_stream = AsyncHTTP11UpgradeStream(network_stream, trailing_data) + + return Response( + status=status, + headers=headers, + content=HTTP11ConnectionByteStream(self, request), + extensions={ + "http_version": http_version, + "reason_phrase": reason_phrase, + "network_stream": network_stream, + }, + ) + except BaseException as exc: + with AsyncShieldCancellation(): + async with Trace("response_closed", logger, request) as trace: + await self._response_closed() + raise exc + + # Sending the request... + + async def _send_request_headers(self, request: Request) -> None: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("write", None) + + with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): + event = h11.Request( + method=request.method, + target=request.url.target, + headers=request.headers, + ) + await self._send_event(event, timeout=timeout) + + async def _send_request_body(self, request: Request) -> None: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("write", None) + + assert isinstance(request.stream, typing.AsyncIterable) + async for chunk in request.stream: + event = h11.Data(data=chunk) + await self._send_event(event, timeout=timeout) + + await self._send_event(h11.EndOfMessage(), timeout=timeout) + + async def _send_event(self, event: h11.Event, timeout: float | None = None) -> None: + bytes_to_send = self._h11_state.send(event) + if bytes_to_send is not None: + await self._network_stream.write(bytes_to_send, timeout=timeout) + + # Receiving the response... + + async def _receive_response_headers( + self, request: Request + ) -> tuple[bytes, int, bytes, list[tuple[bytes, bytes]], bytes]: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("read", None) + + while True: + event = await self._receive_event(timeout=timeout) + if isinstance(event, h11.Response): + break + if ( + isinstance(event, h11.InformationalResponse) + and event.status_code == 101 + ): + break + + http_version = b"HTTP/" + event.http_version + + # h11 version 0.11+ supports a `raw_items` interface to get the + # raw header casing, rather than the enforced lowercase headers. + headers = event.headers.raw_items() + + trailing_data, _ = self._h11_state.trailing_data + + return http_version, event.status_code, event.reason, headers, trailing_data + + async def _receive_response_body( + self, request: Request + ) -> typing.AsyncIterator[bytes]: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("read", None) + + while True: + event = await self._receive_event(timeout=timeout) + if isinstance(event, h11.Data): + yield bytes(event.data) + elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): + break + + async def _receive_event( + self, timeout: float | None = None + ) -> h11.Event | type[h11.PAUSED]: + while True: + with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): + event = self._h11_state.next_event() + + if event is h11.NEED_DATA: + data = await self._network_stream.read( + self.READ_NUM_BYTES, timeout=timeout + ) + + # If we feed this case through h11 we'll raise an exception like: + # + # httpcore.RemoteProtocolError: can't handle event type + # ConnectionClosed when role=SERVER and state=SEND_RESPONSE + # + # Which is accurate, but not very informative from an end-user + # perspective. Instead we handle this case distinctly and treat + # it as a ConnectError. + if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: + msg = "Server disconnected without sending a response." + raise RemoteProtocolError(msg) + + self._h11_state.receive_data(data) + else: + # mypy fails to narrow the type in the above if statement above + return event # type: ignore[return-value] + + async def _response_closed(self) -> None: + async with self._state_lock: + if ( + self._h11_state.our_state is h11.DONE + and self._h11_state.their_state is h11.DONE + ): + self._state = HTTPConnectionState.IDLE + self._h11_state.start_next_cycle() + if self._keepalive_expiry is not None: + now = time.monotonic() + self._expire_at = now + self._keepalive_expiry + else: + await self.aclose() + + # Once the connection is no longer required... + + async def aclose(self) -> None: + # Note that this method unilaterally closes the connection, and does + # not have any kind of locking in place around it. + self._state = HTTPConnectionState.CLOSED + await self._network_stream.aclose() + + # The AsyncConnectionInterface methods provide information about the state of + # the connection, allowing for a connection pooling implementation to + # determine when to reuse and when to close the connection... + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._origin + + def is_available(self) -> bool: + # Note that HTTP/1.1 connections in the "NEW" state are not treated as + # being "available". The control flow which created the connection will + # be able to send an outgoing request, but the connection will not be + # acquired from the connection pool for any other request. + return self._state == HTTPConnectionState.IDLE + + def has_expired(self) -> bool: + now = time.monotonic() + keepalive_expired = self._expire_at is not None and now > self._expire_at + + # If the HTTP connection is idle but the socket is readable, then the + # only valid state is that the socket is about to return b"", indicating + # a server-initiated disconnect. + server_disconnected = ( + self._state == HTTPConnectionState.IDLE + and self._network_stream.get_extra_info("is_readable") + ) + + return keepalive_expired or server_disconnected + + def is_idle(self) -> bool: + return self._state == HTTPConnectionState.IDLE + + def is_closed(self) -> bool: + return self._state == HTTPConnectionState.CLOSED + + def info(self) -> str: + origin = str(self._origin) + return ( + f"{origin!r}, HTTP/1.1, {self._state.name}, " + f"Request Count: {self._request_count}" + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + origin = str(self._origin) + return ( + f"<{class_name} [{origin!r}, {self._state.name}, " + f"Request Count: {self._request_count}]>" + ) + + # These context managers are not used in the standard flow, but are + # useful for testing or working with connection instances directly. + + async def __aenter__(self) -> AsyncHTTP11Connection: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + await self.aclose() + + +class HTTP11ConnectionByteStream: + def __init__(self, connection: AsyncHTTP11Connection, request: Request) -> None: + self._connection = connection + self._request = request + self._closed = False + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + kwargs = {"request": self._request} + try: + async with Trace("receive_response_body", logger, self._request, kwargs): + async for chunk in self._connection._receive_response_body(**kwargs): + yield chunk + except BaseException as exc: + # If we get an exception while streaming the response, + # we want to close the response (and possibly the connection) + # before raising that exception. + with AsyncShieldCancellation(): + await self.aclose() + raise exc + + async def aclose(self) -> None: + if not self._closed: + self._closed = True + async with Trace("response_closed", logger, self._request): + await self._connection._response_closed() + + +class AsyncHTTP11UpgradeStream(AsyncNetworkStream): + def __init__(self, stream: AsyncNetworkStream, leading_data: bytes) -> None: + self._stream = stream + self._leading_data = leading_data + + async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + if self._leading_data: + buffer = self._leading_data[:max_bytes] + self._leading_data = self._leading_data[max_bytes:] + return buffer + else: + return await self._stream.read(max_bytes, timeout) + + async def write(self, buffer: bytes, timeout: float | None = None) -> None: + await self._stream.write(buffer, timeout) + + async def aclose(self) -> None: + await self._stream.aclose() + + async def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> AsyncNetworkStream: + return await self._stream.start_tls(ssl_context, server_hostname, timeout) + + def get_extra_info(self, info: str) -> typing.Any: + return self._stream.get_extra_info(info) diff --git a/source/target-vendors/cp312/httpcore/_async/http2.py b/source/target-vendors/cp312/httpcore/_async/http2.py new file mode 100644 index 0000000..dbd0bee --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/http2.py @@ -0,0 +1,592 @@ +from __future__ import annotations + +import enum +import logging +import time +import types +import typing + +import h2.config +import h2.connection +import h2.events +import h2.exceptions +import h2.settings + +from .._backends.base import AsyncNetworkStream +from .._exceptions import ( + ConnectionNotAvailable, + LocalProtocolError, + RemoteProtocolError, +) +from .._models import Origin, Request, Response +from .._synchronization import AsyncLock, AsyncSemaphore, AsyncShieldCancellation +from .._trace import Trace +from .interfaces import AsyncConnectionInterface + +logger = logging.getLogger("httpcore.http2") + + +def has_body_headers(request: Request) -> bool: + return any( + k.lower() == b"content-length" or k.lower() == b"transfer-encoding" + for k, v in request.headers + ) + + +class HTTPConnectionState(enum.IntEnum): + ACTIVE = 1 + IDLE = 2 + CLOSED = 3 + + +class AsyncHTTP2Connection(AsyncConnectionInterface): + READ_NUM_BYTES = 64 * 1024 + CONFIG = h2.config.H2Configuration(validate_inbound_headers=False) + + def __init__( + self, + origin: Origin, + stream: AsyncNetworkStream, + keepalive_expiry: float | None = None, + ): + self._origin = origin + self._network_stream = stream + self._keepalive_expiry: float | None = keepalive_expiry + self._h2_state = h2.connection.H2Connection(config=self.CONFIG) + self._state = HTTPConnectionState.IDLE + self._expire_at: float | None = None + self._request_count = 0 + self._init_lock = AsyncLock() + self._state_lock = AsyncLock() + self._read_lock = AsyncLock() + self._write_lock = AsyncLock() + self._sent_connection_init = False + self._used_all_stream_ids = False + self._connection_error = False + + # Mapping from stream ID to response stream events. + self._events: dict[ + int, + list[ + h2.events.ResponseReceived + | h2.events.DataReceived + | h2.events.StreamEnded + | h2.events.StreamReset, + ], + ] = {} + + # Connection terminated events are stored as state since + # we need to handle them for all streams. + self._connection_terminated: h2.events.ConnectionTerminated | None = None + + self._read_exception: Exception | None = None + self._write_exception: Exception | None = None + + async def handle_async_request(self, request: Request) -> Response: + if not self.can_handle_request(request.url.origin): + # This cannot occur in normal operation, since the connection pool + # will only send requests on connections that handle them. + # It's in place simply for resilience as a guard against incorrect + # usage, for anyone working directly with httpcore connections. + raise RuntimeError( + f"Attempted to send request to {request.url.origin} on connection " + f"to {self._origin}" + ) + + async with self._state_lock: + if self._state in (HTTPConnectionState.ACTIVE, HTTPConnectionState.IDLE): + self._request_count += 1 + self._expire_at = None + self._state = HTTPConnectionState.ACTIVE + else: + raise ConnectionNotAvailable() + + async with self._init_lock: + if not self._sent_connection_init: + try: + sci_kwargs = {"request": request} + async with Trace( + "send_connection_init", logger, request, sci_kwargs + ): + await self._send_connection_init(**sci_kwargs) + except BaseException as exc: + with AsyncShieldCancellation(): + await self.aclose() + raise exc + + self._sent_connection_init = True + + # Initially start with just 1 until the remote server provides + # its max_concurrent_streams value + self._max_streams = 1 + + local_settings_max_streams = ( + self._h2_state.local_settings.max_concurrent_streams + ) + self._max_streams_semaphore = AsyncSemaphore(local_settings_max_streams) + + for _ in range(local_settings_max_streams - self._max_streams): + await self._max_streams_semaphore.acquire() + + await self._max_streams_semaphore.acquire() + + try: + stream_id = self._h2_state.get_next_available_stream_id() + self._events[stream_id] = [] + except h2.exceptions.NoAvailableStreamIDError: # pragma: nocover + self._used_all_stream_ids = True + self._request_count -= 1 + raise ConnectionNotAvailable() + + try: + kwargs = {"request": request, "stream_id": stream_id} + async with Trace("send_request_headers", logger, request, kwargs): + await self._send_request_headers(request=request, stream_id=stream_id) + async with Trace("send_request_body", logger, request, kwargs): + await self._send_request_body(request=request, stream_id=stream_id) + async with Trace( + "receive_response_headers", logger, request, kwargs + ) as trace: + status, headers = await self._receive_response( + request=request, stream_id=stream_id + ) + trace.return_value = (status, headers) + + return Response( + status=status, + headers=headers, + content=HTTP2ConnectionByteStream(self, request, stream_id=stream_id), + extensions={ + "http_version": b"HTTP/2", + "network_stream": self._network_stream, + "stream_id": stream_id, + }, + ) + except BaseException as exc: # noqa: PIE786 + with AsyncShieldCancellation(): + kwargs = {"stream_id": stream_id} + async with Trace("response_closed", logger, request, kwargs): + await self._response_closed(stream_id=stream_id) + + if isinstance(exc, h2.exceptions.ProtocolError): + # One case where h2 can raise a protocol error is when a + # closed frame has been seen by the state machine. + # + # This happens when one stream is reading, and encounters + # a GOAWAY event. Other flows of control may then raise + # a protocol error at any point they interact with the 'h2_state'. + # + # In this case we'll have stored the event, and should raise + # it as a RemoteProtocolError. + if self._connection_terminated: # pragma: nocover + raise RemoteProtocolError(self._connection_terminated) + # If h2 raises a protocol error in some other state then we + # must somehow have made a protocol violation. + raise LocalProtocolError(exc) # pragma: nocover + + raise exc + + async def _send_connection_init(self, request: Request) -> None: + """ + The HTTP/2 connection requires some initial setup before we can start + using individual request/response streams on it. + """ + # Need to set these manually here instead of manipulating via + # __setitem__() otherwise the H2Connection will emit SettingsUpdate + # frames in addition to sending the undesired defaults. + self._h2_state.local_settings = h2.settings.Settings( + client=True, + initial_values={ + # Disable PUSH_PROMISE frames from the server since we don't do anything + # with them for now. Maybe when we support caching? + h2.settings.SettingCodes.ENABLE_PUSH: 0, + # These two are taken from h2 for safe defaults + h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100, + h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 65536, + }, + ) + + # Some websites (*cough* Yahoo *cough*) balk at this setting being + # present in the initial handshake since it's not defined in the original + # RFC despite the RFC mandating ignoring settings you don't know about. + del self._h2_state.local_settings[ + h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL + ] + + self._h2_state.initiate_connection() + self._h2_state.increment_flow_control_window(2**24) + await self._write_outgoing_data(request) + + # Sending the request... + + async def _send_request_headers(self, request: Request, stream_id: int) -> None: + """ + Send the request headers to a given stream ID. + """ + end_stream = not has_body_headers(request) + + # In HTTP/2 the ':authority' pseudo-header is used instead of 'Host'. + # In order to gracefully handle HTTP/1.1 and HTTP/2 we always require + # HTTP/1.1 style headers, and map them appropriately if we end up on + # an HTTP/2 connection. + authority = [v for k, v in request.headers if k.lower() == b"host"][0] + + headers = [ + (b":method", request.method), + (b":authority", authority), + (b":scheme", request.url.scheme), + (b":path", request.url.target), + ] + [ + (k.lower(), v) + for k, v in request.headers + if k.lower() + not in ( + b"host", + b"transfer-encoding", + ) + ] + + self._h2_state.send_headers(stream_id, headers, end_stream=end_stream) + self._h2_state.increment_flow_control_window(2**24, stream_id=stream_id) + await self._write_outgoing_data(request) + + async def _send_request_body(self, request: Request, stream_id: int) -> None: + """ + Iterate over the request body sending it to a given stream ID. + """ + if not has_body_headers(request): + return + + assert isinstance(request.stream, typing.AsyncIterable) + async for data in request.stream: + await self._send_stream_data(request, stream_id, data) + await self._send_end_stream(request, stream_id) + + async def _send_stream_data( + self, request: Request, stream_id: int, data: bytes + ) -> None: + """ + Send a single chunk of data in one or more data frames. + """ + while data: + max_flow = await self._wait_for_outgoing_flow(request, stream_id) + chunk_size = min(len(data), max_flow) + chunk, data = data[:chunk_size], data[chunk_size:] + self._h2_state.send_data(stream_id, chunk) + await self._write_outgoing_data(request) + + async def _send_end_stream(self, request: Request, stream_id: int) -> None: + """ + Send an empty data frame on on a given stream ID with the END_STREAM flag set. + """ + self._h2_state.end_stream(stream_id) + await self._write_outgoing_data(request) + + # Receiving the response... + + async def _receive_response( + self, request: Request, stream_id: int + ) -> tuple[int, list[tuple[bytes, bytes]]]: + """ + Return the response status code and headers for a given stream ID. + """ + while True: + event = await self._receive_stream_event(request, stream_id) + if isinstance(event, h2.events.ResponseReceived): + break + + status_code = 200 + headers = [] + assert event.headers is not None + for k, v in event.headers: + if k == b":status": + status_code = int(v.decode("ascii", errors="ignore")) + elif not k.startswith(b":"): + headers.append((k, v)) + + return (status_code, headers) + + async def _receive_response_body( + self, request: Request, stream_id: int + ) -> typing.AsyncIterator[bytes]: + """ + Iterator that returns the bytes of the response body for a given stream ID. + """ + while True: + event = await self._receive_stream_event(request, stream_id) + if isinstance(event, h2.events.DataReceived): + assert event.flow_controlled_length is not None + assert event.data is not None + amount = event.flow_controlled_length + self._h2_state.acknowledge_received_data(amount, stream_id) + await self._write_outgoing_data(request) + yield event.data + elif isinstance(event, h2.events.StreamEnded): + break + + async def _receive_stream_event( + self, request: Request, stream_id: int + ) -> h2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEnded: + """ + Return the next available event for a given stream ID. + + Will read more data from the network if required. + """ + while not self._events.get(stream_id): + await self._receive_events(request, stream_id) + event = self._events[stream_id].pop(0) + if isinstance(event, h2.events.StreamReset): + raise RemoteProtocolError(event) + return event + + async def _receive_events( + self, request: Request, stream_id: int | None = None + ) -> None: + """ + Read some data from the network until we see one or more events + for a given stream ID. + """ + async with self._read_lock: + if self._connection_terminated is not None: + last_stream_id = self._connection_terminated.last_stream_id + if stream_id and last_stream_id and stream_id > last_stream_id: + self._request_count -= 1 + raise ConnectionNotAvailable() + raise RemoteProtocolError(self._connection_terminated) + + # This conditional is a bit icky. We don't want to block reading if we've + # actually got an event to return for a given stream. We need to do that + # check *within* the atomic read lock. Though it also need to be optional, + # because when we call it from `_wait_for_outgoing_flow` we *do* want to + # block until we've available flow control, event when we have events + # pending for the stream ID we're attempting to send on. + if stream_id is None or not self._events.get(stream_id): + events = await self._read_incoming_data(request) + for event in events: + if isinstance(event, h2.events.RemoteSettingsChanged): + async with Trace( + "receive_remote_settings", logger, request + ) as trace: + await self._receive_remote_settings_change(event) + trace.return_value = event + + elif isinstance( + event, + ( + h2.events.ResponseReceived, + h2.events.DataReceived, + h2.events.StreamEnded, + h2.events.StreamReset, + ), + ): + if event.stream_id in self._events: + self._events[event.stream_id].append(event) + + elif isinstance(event, h2.events.ConnectionTerminated): + self._connection_terminated = event + + await self._write_outgoing_data(request) + + async def _receive_remote_settings_change( + self, event: h2.events.RemoteSettingsChanged + ) -> None: + max_concurrent_streams = event.changed_settings.get( + h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS + ) + if max_concurrent_streams: + new_max_streams = min( + max_concurrent_streams.new_value, + self._h2_state.local_settings.max_concurrent_streams, + ) + if new_max_streams and new_max_streams != self._max_streams: + while new_max_streams > self._max_streams: + await self._max_streams_semaphore.release() + self._max_streams += 1 + while new_max_streams < self._max_streams: + await self._max_streams_semaphore.acquire() + self._max_streams -= 1 + + async def _response_closed(self, stream_id: int) -> None: + await self._max_streams_semaphore.release() + del self._events[stream_id] + async with self._state_lock: + if self._connection_terminated and not self._events: + await self.aclose() + + elif self._state == HTTPConnectionState.ACTIVE and not self._events: + self._state = HTTPConnectionState.IDLE + if self._keepalive_expiry is not None: + now = time.monotonic() + self._expire_at = now + self._keepalive_expiry + if self._used_all_stream_ids: # pragma: nocover + await self.aclose() + + async def aclose(self) -> None: + # Note that this method unilaterally closes the connection, and does + # not have any kind of locking in place around it. + self._h2_state.close_connection() + self._state = HTTPConnectionState.CLOSED + await self._network_stream.aclose() + + # Wrappers around network read/write operations... + + async def _read_incoming_data(self, request: Request) -> list[h2.events.Event]: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("read", None) + + if self._read_exception is not None: + raise self._read_exception # pragma: nocover + + try: + data = await self._network_stream.read(self.READ_NUM_BYTES, timeout) + if data == b"": + raise RemoteProtocolError("Server disconnected") + except Exception as exc: + # If we get a network error we should: + # + # 1. Save the exception and just raise it immediately on any future reads. + # (For example, this means that a single read timeout or disconnect will + # immediately close all pending streams. Without requiring multiple + # sequential timeouts.) + # 2. Mark the connection as errored, so that we don't accept any other + # incoming requests. + self._read_exception = exc + self._connection_error = True + raise exc + + events: list[h2.events.Event] = self._h2_state.receive_data(data) + + return events + + async def _write_outgoing_data(self, request: Request) -> None: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("write", None) + + async with self._write_lock: + data_to_send = self._h2_state.data_to_send() + + if self._write_exception is not None: + raise self._write_exception # pragma: nocover + + try: + await self._network_stream.write(data_to_send, timeout) + except Exception as exc: # pragma: nocover + # If we get a network error we should: + # + # 1. Save the exception and just raise it immediately on any future write. + # (For example, this means that a single write timeout or disconnect will + # immediately close all pending streams. Without requiring multiple + # sequential timeouts.) + # 2. Mark the connection as errored, so that we don't accept any other + # incoming requests. + self._write_exception = exc + self._connection_error = True + raise exc + + # Flow control... + + async def _wait_for_outgoing_flow(self, request: Request, stream_id: int) -> int: + """ + Returns the maximum allowable outgoing flow for a given stream. + + If the allowable flow is zero, then waits on the network until + WindowUpdated frames have increased the flow rate. + https://tools.ietf.org/html/rfc7540#section-6.9 + """ + local_flow: int = self._h2_state.local_flow_control_window(stream_id) + max_frame_size: int = self._h2_state.max_outbound_frame_size + flow = min(local_flow, max_frame_size) + while flow == 0: + await self._receive_events(request) + local_flow = self._h2_state.local_flow_control_window(stream_id) + max_frame_size = self._h2_state.max_outbound_frame_size + flow = min(local_flow, max_frame_size) + return flow + + # Interface for connection pooling... + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._origin + + def is_available(self) -> bool: + return ( + self._state != HTTPConnectionState.CLOSED + and not self._connection_error + and not self._used_all_stream_ids + and not ( + self._h2_state.state_machine.state + == h2.connection.ConnectionState.CLOSED + ) + ) + + def has_expired(self) -> bool: + now = time.monotonic() + return self._expire_at is not None and now > self._expire_at + + def is_idle(self) -> bool: + return self._state == HTTPConnectionState.IDLE + + def is_closed(self) -> bool: + return self._state == HTTPConnectionState.CLOSED + + def info(self) -> str: + origin = str(self._origin) + return ( + f"{origin!r}, HTTP/2, {self._state.name}, " + f"Request Count: {self._request_count}" + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + origin = str(self._origin) + return ( + f"<{class_name} [{origin!r}, {self._state.name}, " + f"Request Count: {self._request_count}]>" + ) + + # These context managers are not used in the standard flow, but are + # useful for testing or working with connection instances directly. + + async def __aenter__(self) -> AsyncHTTP2Connection: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + await self.aclose() + + +class HTTP2ConnectionByteStream: + def __init__( + self, connection: AsyncHTTP2Connection, request: Request, stream_id: int + ) -> None: + self._connection = connection + self._request = request + self._stream_id = stream_id + self._closed = False + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + kwargs = {"request": self._request, "stream_id": self._stream_id} + try: + async with Trace("receive_response_body", logger, self._request, kwargs): + async for chunk in self._connection._receive_response_body( + request=self._request, stream_id=self._stream_id + ): + yield chunk + except BaseException as exc: + # If we get an exception while streaming the response, + # we want to close the response (and possibly the connection) + # before raising that exception. + with AsyncShieldCancellation(): + await self.aclose() + raise exc + + async def aclose(self) -> None: + if not self._closed: + self._closed = True + kwargs = {"stream_id": self._stream_id} + async with Trace("response_closed", logger, self._request, kwargs): + await self._connection._response_closed(stream_id=self._stream_id) diff --git a/source/target-vendors/cp312/httpcore/_async/http_proxy.py b/source/target-vendors/cp312/httpcore/_async/http_proxy.py new file mode 100644 index 0000000..cc9d920 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/http_proxy.py @@ -0,0 +1,367 @@ +from __future__ import annotations + +import base64 +import logging +import ssl +import typing + +from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend +from .._exceptions import ProxyError +from .._models import ( + URL, + Origin, + Request, + Response, + enforce_bytes, + enforce_headers, + enforce_url, +) +from .._ssl import default_ssl_context +from .._synchronization import AsyncLock +from .._trace import Trace +from .connection import AsyncHTTPConnection +from .connection_pool import AsyncConnectionPool +from .http11 import AsyncHTTP11Connection +from .interfaces import AsyncConnectionInterface + +ByteOrStr = typing.Union[bytes, str] +HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] +HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] + + +logger = logging.getLogger("httpcore.proxy") + + +def merge_headers( + default_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, + override_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, +) -> list[tuple[bytes, bytes]]: + """ + Append default_headers and override_headers, de-duplicating if a key exists + in both cases. + """ + default_headers = [] if default_headers is None else list(default_headers) + override_headers = [] if override_headers is None else list(override_headers) + has_override = set(key.lower() for key, value in override_headers) + default_headers = [ + (key, value) + for key, value in default_headers + if key.lower() not in has_override + ] + return default_headers + override_headers + + +class AsyncHTTPProxy(AsyncConnectionPool): # pragma: nocover + """ + A connection pool that sends requests via an HTTP proxy. + """ + + def __init__( + self, + proxy_url: URL | bytes | str, + proxy_auth: tuple[bytes | str, bytes | str] | None = None, + proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, + ssl_context: ssl.SSLContext | None = None, + proxy_ssl_context: ssl.SSLContext | None = None, + max_connections: int | None = 10, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + local_address: str | None = None, + uds: str | None = None, + network_backend: AsyncNetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + """ + A connection pool for making HTTP requests. + + Parameters: + proxy_url: The URL to use when connecting to the proxy server. + For example `"http://127.0.0.1:8080/"`. + proxy_auth: Any proxy authentication as a two-tuple of + (username, password). May be either bytes or ascii-only str. + proxy_headers: Any HTTP headers to use for the proxy requests. + For example `{"Proxy-Authorization": "Basic :"}`. + ssl_context: An SSL context to use for verifying connections. + If not specified, the default `httpcore.default_ssl_context()` + will be used. + proxy_ssl_context: The same as `ssl_context`, but for a proxy server rather than a remote origin. + max_connections: The maximum number of concurrent HTTP connections that + the pool should allow. Any attempt to send a request on a pool that + would exceed this amount will block until a connection is available. + max_keepalive_connections: The maximum number of idle HTTP connections + that will be maintained in the pool. + keepalive_expiry: The duration in seconds that an idle HTTP connection + may be maintained for before being expired from the pool. + http1: A boolean indicating if HTTP/1.1 requests should be supported + by the connection pool. Defaults to True. + http2: A boolean indicating if HTTP/2 requests should be supported by + the connection pool. Defaults to False. + retries: The maximum number of retries when trying to establish + a connection. + local_address: Local address to connect from. Can also be used to + connect using a particular address family. Using + `local_address="0.0.0.0"` will connect using an `AF_INET` address + (IPv4), while using `local_address="::"` will connect using an + `AF_INET6` address (IPv6). + uds: Path to a Unix Domain Socket to use instead of TCP sockets. + network_backend: A backend instance to use for handling network I/O. + """ + super().__init__( + ssl_context=ssl_context, + max_connections=max_connections, + max_keepalive_connections=max_keepalive_connections, + keepalive_expiry=keepalive_expiry, + http1=http1, + http2=http2, + network_backend=network_backend, + retries=retries, + local_address=local_address, + uds=uds, + socket_options=socket_options, + ) + + self._proxy_url = enforce_url(proxy_url, name="proxy_url") + if ( + self._proxy_url.scheme == b"http" and proxy_ssl_context is not None + ): # pragma: no cover + raise RuntimeError( + "The `proxy_ssl_context` argument is not allowed for the http scheme" + ) + + self._ssl_context = ssl_context + self._proxy_ssl_context = proxy_ssl_context + self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") + if proxy_auth is not None: + username = enforce_bytes(proxy_auth[0], name="proxy_auth") + password = enforce_bytes(proxy_auth[1], name="proxy_auth") + userpass = username + b":" + password + authorization = b"Basic " + base64.b64encode(userpass) + self._proxy_headers = [ + (b"Proxy-Authorization", authorization) + ] + self._proxy_headers + + def create_connection(self, origin: Origin) -> AsyncConnectionInterface: + if origin.scheme == b"http": + return AsyncForwardHTTPConnection( + proxy_origin=self._proxy_url.origin, + proxy_headers=self._proxy_headers, + remote_origin=origin, + keepalive_expiry=self._keepalive_expiry, + network_backend=self._network_backend, + proxy_ssl_context=self._proxy_ssl_context, + ) + return AsyncTunnelHTTPConnection( + proxy_origin=self._proxy_url.origin, + proxy_headers=self._proxy_headers, + remote_origin=origin, + ssl_context=self._ssl_context, + proxy_ssl_context=self._proxy_ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + + +class AsyncForwardHTTPConnection(AsyncConnectionInterface): + def __init__( + self, + proxy_origin: Origin, + remote_origin: Origin, + proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, + keepalive_expiry: float | None = None, + network_backend: AsyncNetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + proxy_ssl_context: ssl.SSLContext | None = None, + ) -> None: + self._connection = AsyncHTTPConnection( + origin=proxy_origin, + keepalive_expiry=keepalive_expiry, + network_backend=network_backend, + socket_options=socket_options, + ssl_context=proxy_ssl_context, + ) + self._proxy_origin = proxy_origin + self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") + self._remote_origin = remote_origin + + async def handle_async_request(self, request: Request) -> Response: + headers = merge_headers(self._proxy_headers, request.headers) + url = URL( + scheme=self._proxy_origin.scheme, + host=self._proxy_origin.host, + port=self._proxy_origin.port, + target=bytes(request.url), + ) + proxy_request = Request( + method=request.method, + url=url, + headers=headers, + content=request.stream, + extensions=request.extensions, + ) + return await self._connection.handle_async_request(proxy_request) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._remote_origin + + async def aclose(self) -> None: + await self._connection.aclose() + + def info(self) -> str: + return self._connection.info() + + def is_available(self) -> bool: + return self._connection.is_available() + + def has_expired(self) -> bool: + return self._connection.has_expired() + + def is_idle(self) -> bool: + return self._connection.is_idle() + + def is_closed(self) -> bool: + return self._connection.is_closed() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" + + +class AsyncTunnelHTTPConnection(AsyncConnectionInterface): + def __init__( + self, + proxy_origin: Origin, + remote_origin: Origin, + ssl_context: ssl.SSLContext | None = None, + proxy_ssl_context: ssl.SSLContext | None = None, + proxy_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + network_backend: AsyncNetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + self._connection: AsyncConnectionInterface = AsyncHTTPConnection( + origin=proxy_origin, + keepalive_expiry=keepalive_expiry, + network_backend=network_backend, + socket_options=socket_options, + ssl_context=proxy_ssl_context, + ) + self._proxy_origin = proxy_origin + self._remote_origin = remote_origin + self._ssl_context = ssl_context + self._proxy_ssl_context = proxy_ssl_context + self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + self._connect_lock = AsyncLock() + self._connected = False + + async def handle_async_request(self, request: Request) -> Response: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("connect", None) + + async with self._connect_lock: + if not self._connected: + target = b"%b:%d" % (self._remote_origin.host, self._remote_origin.port) + + connect_url = URL( + scheme=self._proxy_origin.scheme, + host=self._proxy_origin.host, + port=self._proxy_origin.port, + target=target, + ) + connect_headers = merge_headers( + [(b"Host", target), (b"Accept", b"*/*")], self._proxy_headers + ) + connect_request = Request( + method=b"CONNECT", + url=connect_url, + headers=connect_headers, + extensions=request.extensions, + ) + connect_response = await self._connection.handle_async_request( + connect_request + ) + + if connect_response.status < 200 or connect_response.status > 299: + reason_bytes = connect_response.extensions.get("reason_phrase", b"") + reason_str = reason_bytes.decode("ascii", errors="ignore") + msg = "%d %s" % (connect_response.status, reason_str) + await self._connection.aclose() + raise ProxyError(msg) + + stream = connect_response.extensions["network_stream"] + + # Upgrade the stream to SSL + ssl_context = ( + default_ssl_context() + if self._ssl_context is None + else self._ssl_context + ) + alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] + ssl_context.set_alpn_protocols(alpn_protocols) + + kwargs = { + "ssl_context": ssl_context, + "server_hostname": self._remote_origin.host.decode("ascii"), + "timeout": timeout, + } + async with Trace("start_tls", logger, request, kwargs) as trace: + stream = await stream.start_tls(**kwargs) + trace.return_value = stream + + # Determine if we should be using HTTP/1.1 or HTTP/2 + ssl_object = stream.get_extra_info("ssl_object") + http2_negotiated = ( + ssl_object is not None + and ssl_object.selected_alpn_protocol() == "h2" + ) + + # Create the HTTP/1.1 or HTTP/2 connection + if http2_negotiated or (self._http2 and not self._http1): + from .http2 import AsyncHTTP2Connection + + self._connection = AsyncHTTP2Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + else: + self._connection = AsyncHTTP11Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + + self._connected = True + return await self._connection.handle_async_request(request) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._remote_origin + + async def aclose(self) -> None: + await self._connection.aclose() + + def info(self) -> str: + return self._connection.info() + + def is_available(self) -> bool: + return self._connection.is_available() + + def has_expired(self) -> bool: + return self._connection.has_expired() + + def is_idle(self) -> bool: + return self._connection.is_idle() + + def is_closed(self) -> bool: + return self._connection.is_closed() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/source/target-vendors/cp312/httpcore/_async/interfaces.py b/source/target-vendors/cp312/httpcore/_async/interfaces.py new file mode 100644 index 0000000..361583b --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/interfaces.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +import contextlib +import typing + +from .._models import ( + URL, + Extensions, + HeaderTypes, + Origin, + Request, + Response, + enforce_bytes, + enforce_headers, + enforce_url, + include_request_headers, +) + + +class AsyncRequestInterface: + async def request( + self, + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes | typing.AsyncIterator[bytes] | None = None, + extensions: Extensions | None = None, + ) -> Response: + # Strict type checking on our parameters. + method = enforce_bytes(method, name="method") + url = enforce_url(url, name="url") + headers = enforce_headers(headers, name="headers") + + # Include Host header, and optionally Content-Length or Transfer-Encoding. + headers = include_request_headers(headers, url=url, content=content) + + request = Request( + method=method, + url=url, + headers=headers, + content=content, + extensions=extensions, + ) + response = await self.handle_async_request(request) + try: + await response.aread() + finally: + await response.aclose() + return response + + @contextlib.asynccontextmanager + async def stream( + self, + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes | typing.AsyncIterator[bytes] | None = None, + extensions: Extensions | None = None, + ) -> typing.AsyncIterator[Response]: + # Strict type checking on our parameters. + method = enforce_bytes(method, name="method") + url = enforce_url(url, name="url") + headers = enforce_headers(headers, name="headers") + + # Include Host header, and optionally Content-Length or Transfer-Encoding. + headers = include_request_headers(headers, url=url, content=content) + + request = Request( + method=method, + url=url, + headers=headers, + content=content, + extensions=extensions, + ) + response = await self.handle_async_request(request) + try: + yield response + finally: + await response.aclose() + + async def handle_async_request(self, request: Request) -> Response: + raise NotImplementedError() # pragma: nocover + + +class AsyncConnectionInterface(AsyncRequestInterface): + async def aclose(self) -> None: + raise NotImplementedError() # pragma: nocover + + def info(self) -> str: + raise NotImplementedError() # pragma: nocover + + def can_handle_request(self, origin: Origin) -> bool: + raise NotImplementedError() # pragma: nocover + + def is_available(self) -> bool: + """ + Return `True` if the connection is currently able to accept an + outgoing request. + + An HTTP/1.1 connection will only be available if it is currently idle. + + An HTTP/2 connection will be available so long as the stream ID space is + not yet exhausted, and the connection is not in an error state. + + While the connection is being established we may not yet know if it is going + to result in an HTTP/1.1 or HTTP/2 connection. The connection should be + treated as being available, but might ultimately raise `NewConnectionRequired` + required exceptions if multiple requests are attempted over a connection + that ends up being established as HTTP/1.1. + """ + raise NotImplementedError() # pragma: nocover + + def has_expired(self) -> bool: + """ + Return `True` if the connection is in a state where it should be closed. + + This either means that the connection is idle and it has passed the + expiry time on its keep-alive, or that server has sent an EOF. + """ + raise NotImplementedError() # pragma: nocover + + def is_idle(self) -> bool: + """ + Return `True` if the connection is currently idle. + """ + raise NotImplementedError() # pragma: nocover + + def is_closed(self) -> bool: + """ + Return `True` if the connection has been closed. + + Used when a response is closed to determine if the connection may be + returned to the connection pool or not. + """ + raise NotImplementedError() # pragma: nocover diff --git a/source/target-vendors/cp312/httpcore/_async/socks_proxy.py b/source/target-vendors/cp312/httpcore/_async/socks_proxy.py new file mode 100644 index 0000000..b363f55 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_async/socks_proxy.py @@ -0,0 +1,341 @@ +from __future__ import annotations + +import logging +import ssl + +import socksio + +from .._backends.auto import AutoBackend +from .._backends.base import AsyncNetworkBackend, AsyncNetworkStream +from .._exceptions import ConnectionNotAvailable, ProxyError +from .._models import URL, Origin, Request, Response, enforce_bytes, enforce_url +from .._ssl import default_ssl_context +from .._synchronization import AsyncLock +from .._trace import Trace +from .connection_pool import AsyncConnectionPool +from .http11 import AsyncHTTP11Connection +from .interfaces import AsyncConnectionInterface + +logger = logging.getLogger("httpcore.socks") + + +AUTH_METHODS = { + b"\x00": "NO AUTHENTICATION REQUIRED", + b"\x01": "GSSAPI", + b"\x02": "USERNAME/PASSWORD", + b"\xff": "NO ACCEPTABLE METHODS", +} + +REPLY_CODES = { + b"\x00": "Succeeded", + b"\x01": "General SOCKS server failure", + b"\x02": "Connection not allowed by ruleset", + b"\x03": "Network unreachable", + b"\x04": "Host unreachable", + b"\x05": "Connection refused", + b"\x06": "TTL expired", + b"\x07": "Command not supported", + b"\x08": "Address type not supported", +} + + +async def _init_socks5_connection( + stream: AsyncNetworkStream, + *, + host: bytes, + port: int, + auth: tuple[bytes, bytes] | None = None, +) -> None: + conn = socksio.socks5.SOCKS5Connection() + + # Auth method request + auth_method = ( + socksio.socks5.SOCKS5AuthMethod.NO_AUTH_REQUIRED + if auth is None + else socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD + ) + conn.send(socksio.socks5.SOCKS5AuthMethodsRequest([auth_method])) + outgoing_bytes = conn.data_to_send() + await stream.write(outgoing_bytes) + + # Auth method response + incoming_bytes = await stream.read(max_bytes=4096) + response = conn.receive_data(incoming_bytes) + assert isinstance(response, socksio.socks5.SOCKS5AuthReply) + if response.method != auth_method: + requested = AUTH_METHODS.get(auth_method, "UNKNOWN") + responded = AUTH_METHODS.get(response.method, "UNKNOWN") + raise ProxyError( + f"Requested {requested} from proxy server, but got {responded}." + ) + + if response.method == socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD: + # Username/password request + assert auth is not None + username, password = auth + conn.send(socksio.socks5.SOCKS5UsernamePasswordRequest(username, password)) + outgoing_bytes = conn.data_to_send() + await stream.write(outgoing_bytes) + + # Username/password response + incoming_bytes = await stream.read(max_bytes=4096) + response = conn.receive_data(incoming_bytes) + assert isinstance(response, socksio.socks5.SOCKS5UsernamePasswordReply) + if not response.success: + raise ProxyError("Invalid username/password") + + # Connect request + conn.send( + socksio.socks5.SOCKS5CommandRequest.from_address( + socksio.socks5.SOCKS5Command.CONNECT, (host, port) + ) + ) + outgoing_bytes = conn.data_to_send() + await stream.write(outgoing_bytes) + + # Connect response + incoming_bytes = await stream.read(max_bytes=4096) + response = conn.receive_data(incoming_bytes) + assert isinstance(response, socksio.socks5.SOCKS5Reply) + if response.reply_code != socksio.socks5.SOCKS5ReplyCode.SUCCEEDED: + reply_code = REPLY_CODES.get(response.reply_code, "UNKOWN") + raise ProxyError(f"Proxy Server could not connect: {reply_code}.") + + +class AsyncSOCKSProxy(AsyncConnectionPool): # pragma: nocover + """ + A connection pool that sends requests via an HTTP proxy. + """ + + def __init__( + self, + proxy_url: URL | bytes | str, + proxy_auth: tuple[bytes | str, bytes | str] | None = None, + ssl_context: ssl.SSLContext | None = None, + max_connections: int | None = 10, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + network_backend: AsyncNetworkBackend | None = None, + ) -> None: + """ + A connection pool for making HTTP requests. + + Parameters: + proxy_url: The URL to use when connecting to the proxy server. + For example `"http://127.0.0.1:8080/"`. + ssl_context: An SSL context to use for verifying connections. + If not specified, the default `httpcore.default_ssl_context()` + will be used. + max_connections: The maximum number of concurrent HTTP connections that + the pool should allow. Any attempt to send a request on a pool that + would exceed this amount will block until a connection is available. + max_keepalive_connections: The maximum number of idle HTTP connections + that will be maintained in the pool. + keepalive_expiry: The duration in seconds that an idle HTTP connection + may be maintained for before being expired from the pool. + http1: A boolean indicating if HTTP/1.1 requests should be supported + by the connection pool. Defaults to True. + http2: A boolean indicating if HTTP/2 requests should be supported by + the connection pool. Defaults to False. + retries: The maximum number of retries when trying to establish + a connection. + local_address: Local address to connect from. Can also be used to + connect using a particular address family. Using + `local_address="0.0.0.0"` will connect using an `AF_INET` address + (IPv4), while using `local_address="::"` will connect using an + `AF_INET6` address (IPv6). + uds: Path to a Unix Domain Socket to use instead of TCP sockets. + network_backend: A backend instance to use for handling network I/O. + """ + super().__init__( + ssl_context=ssl_context, + max_connections=max_connections, + max_keepalive_connections=max_keepalive_connections, + keepalive_expiry=keepalive_expiry, + http1=http1, + http2=http2, + network_backend=network_backend, + retries=retries, + ) + self._ssl_context = ssl_context + self._proxy_url = enforce_url(proxy_url, name="proxy_url") + if proxy_auth is not None: + username, password = proxy_auth + username_bytes = enforce_bytes(username, name="proxy_auth") + password_bytes = enforce_bytes(password, name="proxy_auth") + self._proxy_auth: tuple[bytes, bytes] | None = ( + username_bytes, + password_bytes, + ) + else: + self._proxy_auth = None + + def create_connection(self, origin: Origin) -> AsyncConnectionInterface: + return AsyncSocks5Connection( + proxy_origin=self._proxy_url.origin, + remote_origin=origin, + proxy_auth=self._proxy_auth, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + + +class AsyncSocks5Connection(AsyncConnectionInterface): + def __init__( + self, + proxy_origin: Origin, + remote_origin: Origin, + proxy_auth: tuple[bytes, bytes] | None = None, + ssl_context: ssl.SSLContext | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + network_backend: AsyncNetworkBackend | None = None, + ) -> None: + self._proxy_origin = proxy_origin + self._remote_origin = remote_origin + self._proxy_auth = proxy_auth + self._ssl_context = ssl_context + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + + self._network_backend: AsyncNetworkBackend = ( + AutoBackend() if network_backend is None else network_backend + ) + self._connect_lock = AsyncLock() + self._connection: AsyncConnectionInterface | None = None + self._connect_failed = False + + async def handle_async_request(self, request: Request) -> Response: + timeouts = request.extensions.get("timeout", {}) + sni_hostname = request.extensions.get("sni_hostname", None) + timeout = timeouts.get("connect", None) + + async with self._connect_lock: + if self._connection is None: + try: + # Connect to the proxy + kwargs = { + "host": self._proxy_origin.host.decode("ascii"), + "port": self._proxy_origin.port, + "timeout": timeout, + } + async with Trace("connect_tcp", logger, request, kwargs) as trace: + stream = await self._network_backend.connect_tcp(**kwargs) + trace.return_value = stream + + # Connect to the remote host using socks5 + kwargs = { + "stream": stream, + "host": self._remote_origin.host.decode("ascii"), + "port": self._remote_origin.port, + "auth": self._proxy_auth, + } + async with Trace( + "setup_socks5_connection", logger, request, kwargs + ) as trace: + await _init_socks5_connection(**kwargs) + trace.return_value = stream + + # Upgrade the stream to SSL + if self._remote_origin.scheme == b"https": + ssl_context = ( + default_ssl_context() + if self._ssl_context is None + else self._ssl_context + ) + alpn_protocols = ( + ["http/1.1", "h2"] if self._http2 else ["http/1.1"] + ) + ssl_context.set_alpn_protocols(alpn_protocols) + + kwargs = { + "ssl_context": ssl_context, + "server_hostname": sni_hostname + or self._remote_origin.host.decode("ascii"), + "timeout": timeout, + } + async with Trace("start_tls", logger, request, kwargs) as trace: + stream = await stream.start_tls(**kwargs) + trace.return_value = stream + + # Determine if we should be using HTTP/1.1 or HTTP/2 + ssl_object = stream.get_extra_info("ssl_object") + http2_negotiated = ( + ssl_object is not None + and ssl_object.selected_alpn_protocol() == "h2" + ) + + # Create the HTTP/1.1 or HTTP/2 connection + if http2_negotiated or ( + self._http2 and not self._http1 + ): # pragma: nocover + from .http2 import AsyncHTTP2Connection + + self._connection = AsyncHTTP2Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + else: + self._connection = AsyncHTTP11Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + except Exception as exc: + self._connect_failed = True + raise exc + elif not self._connection.is_available(): # pragma: nocover + raise ConnectionNotAvailable() + + return await self._connection.handle_async_request(request) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._remote_origin + + async def aclose(self) -> None: + if self._connection is not None: + await self._connection.aclose() + + def is_available(self) -> bool: + if self._connection is None: # pragma: nocover + # If HTTP/2 support is enabled, and the resulting connection could + # end up as HTTP/2 then we should indicate the connection as being + # available to service multiple requests. + return ( + self._http2 + and (self._remote_origin.scheme == b"https" or not self._http1) + and not self._connect_failed + ) + return self._connection.is_available() + + def has_expired(self) -> bool: + if self._connection is None: # pragma: nocover + return self._connect_failed + return self._connection.has_expired() + + def is_idle(self) -> bool: + if self._connection is None: # pragma: nocover + return self._connect_failed + return self._connection.is_idle() + + def is_closed(self) -> bool: + if self._connection is None: # pragma: nocover + return self._connect_failed + return self._connection.is_closed() + + def info(self) -> str: + if self._connection is None: # pragma: nocover + return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + return self._connection.info() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/source/target-vendors/cp312/httpcore/_backends/__init__.py b/source/target-vendors/cp312/httpcore/_backends/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/httpcore/_backends/anyio.py b/source/target-vendors/cp312/httpcore/_backends/anyio.py new file mode 100644 index 0000000..a140095 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_backends/anyio.py @@ -0,0 +1,146 @@ +from __future__ import annotations + +import ssl +import typing + +import anyio + +from .._exceptions import ( + ConnectError, + ConnectTimeout, + ReadError, + ReadTimeout, + WriteError, + WriteTimeout, + map_exceptions, +) +from .._utils import is_socket_readable +from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream + + +class AnyIOStream(AsyncNetworkStream): + def __init__(self, stream: anyio.abc.ByteStream) -> None: + self._stream = stream + + async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + exc_map = { + TimeoutError: ReadTimeout, + anyio.BrokenResourceError: ReadError, + anyio.ClosedResourceError: ReadError, + anyio.EndOfStream: ReadError, + } + with map_exceptions(exc_map): + with anyio.fail_after(timeout): + try: + return await self._stream.receive(max_bytes=max_bytes) + except anyio.EndOfStream: # pragma: nocover + return b"" + + async def write(self, buffer: bytes, timeout: float | None = None) -> None: + if not buffer: + return + + exc_map = { + TimeoutError: WriteTimeout, + anyio.BrokenResourceError: WriteError, + anyio.ClosedResourceError: WriteError, + } + with map_exceptions(exc_map): + with anyio.fail_after(timeout): + await self._stream.send(item=buffer) + + async def aclose(self) -> None: + await self._stream.aclose() + + async def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> AsyncNetworkStream: + exc_map = { + TimeoutError: ConnectTimeout, + anyio.BrokenResourceError: ConnectError, + anyio.EndOfStream: ConnectError, + ssl.SSLError: ConnectError, + } + with map_exceptions(exc_map): + try: + with anyio.fail_after(timeout): + ssl_stream = await anyio.streams.tls.TLSStream.wrap( + self._stream, + ssl_context=ssl_context, + hostname=server_hostname, + standard_compatible=False, + server_side=False, + ) + except Exception as exc: # pragma: nocover + await self.aclose() + raise exc + return AnyIOStream(ssl_stream) + + def get_extra_info(self, info: str) -> typing.Any: + if info == "ssl_object": + return self._stream.extra(anyio.streams.tls.TLSAttribute.ssl_object, None) + if info == "client_addr": + return self._stream.extra(anyio.abc.SocketAttribute.local_address, None) + if info == "server_addr": + return self._stream.extra(anyio.abc.SocketAttribute.remote_address, None) + if info == "socket": + return self._stream.extra(anyio.abc.SocketAttribute.raw_socket, None) + if info == "is_readable": + sock = self._stream.extra(anyio.abc.SocketAttribute.raw_socket, None) + return is_socket_readable(sock) + return None + + +class AnyIOBackend(AsyncNetworkBackend): + async def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: # pragma: nocover + if socket_options is None: + socket_options = [] + exc_map = { + TimeoutError: ConnectTimeout, + OSError: ConnectError, + anyio.BrokenResourceError: ConnectError, + } + with map_exceptions(exc_map): + with anyio.fail_after(timeout): + stream: anyio.abc.ByteStream = await anyio.connect_tcp( + remote_host=host, + remote_port=port, + local_host=local_address, + ) + # By default TCP sockets opened in `asyncio` include TCP_NODELAY. + for option in socket_options: + stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover + return AnyIOStream(stream) + + async def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: # pragma: nocover + if socket_options is None: + socket_options = [] + exc_map = { + TimeoutError: ConnectTimeout, + OSError: ConnectError, + anyio.BrokenResourceError: ConnectError, + } + with map_exceptions(exc_map): + with anyio.fail_after(timeout): + stream: anyio.abc.ByteStream = await anyio.connect_unix(path) + for option in socket_options: + stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover + return AnyIOStream(stream) + + async def sleep(self, seconds: float) -> None: + await anyio.sleep(seconds) # pragma: nocover diff --git a/source/target-vendors/cp312/httpcore/_backends/auto.py b/source/target-vendors/cp312/httpcore/_backends/auto.py new file mode 100644 index 0000000..49f0e69 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_backends/auto.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +import typing + +from .._synchronization import current_async_library +from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream + + +class AutoBackend(AsyncNetworkBackend): + async def _init_backend(self) -> None: + if not (hasattr(self, "_backend")): + backend = current_async_library() + if backend == "trio": + from .trio import TrioBackend + + self._backend: AsyncNetworkBackend = TrioBackend() + else: + from .anyio import AnyIOBackend + + self._backend = AnyIOBackend() + + async def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: + await self._init_backend() + return await self._backend.connect_tcp( + host, + port, + timeout=timeout, + local_address=local_address, + socket_options=socket_options, + ) + + async def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: # pragma: nocover + await self._init_backend() + return await self._backend.connect_unix_socket( + path, timeout=timeout, socket_options=socket_options + ) + + async def sleep(self, seconds: float) -> None: # pragma: nocover + await self._init_backend() + return await self._backend.sleep(seconds) diff --git a/source/target-vendors/cp312/httpcore/_backends/base.py b/source/target-vendors/cp312/httpcore/_backends/base.py new file mode 100644 index 0000000..cf55c8b --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_backends/base.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +import ssl +import time +import typing + +SOCKET_OPTION = typing.Union[ + typing.Tuple[int, int, int], + typing.Tuple[int, int, typing.Union[bytes, bytearray]], + typing.Tuple[int, int, None, int], +] + + +class NetworkStream: + def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + raise NotImplementedError() # pragma: nocover + + def write(self, buffer: bytes, timeout: float | None = None) -> None: + raise NotImplementedError() # pragma: nocover + + def close(self) -> None: + raise NotImplementedError() # pragma: nocover + + def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> NetworkStream: + raise NotImplementedError() # pragma: nocover + + def get_extra_info(self, info: str) -> typing.Any: + return None # pragma: nocover + + +class NetworkBackend: + def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> NetworkStream: + raise NotImplementedError() # pragma: nocover + + def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> NetworkStream: + raise NotImplementedError() # pragma: nocover + + def sleep(self, seconds: float) -> None: + time.sleep(seconds) # pragma: nocover + + +class AsyncNetworkStream: + async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + raise NotImplementedError() # pragma: nocover + + async def write(self, buffer: bytes, timeout: float | None = None) -> None: + raise NotImplementedError() # pragma: nocover + + async def aclose(self) -> None: + raise NotImplementedError() # pragma: nocover + + async def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> AsyncNetworkStream: + raise NotImplementedError() # pragma: nocover + + def get_extra_info(self, info: str) -> typing.Any: + return None # pragma: nocover + + +class AsyncNetworkBackend: + async def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: + raise NotImplementedError() # pragma: nocover + + async def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: + raise NotImplementedError() # pragma: nocover + + async def sleep(self, seconds: float) -> None: + raise NotImplementedError() # pragma: nocover diff --git a/source/target-vendors/cp312/httpcore/_backends/mock.py b/source/target-vendors/cp312/httpcore/_backends/mock.py new file mode 100644 index 0000000..9b6edca --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_backends/mock.py @@ -0,0 +1,143 @@ +from __future__ import annotations + +import ssl +import typing + +from .._exceptions import ReadError +from .base import ( + SOCKET_OPTION, + AsyncNetworkBackend, + AsyncNetworkStream, + NetworkBackend, + NetworkStream, +) + + +class MockSSLObject: + def __init__(self, http2: bool): + self._http2 = http2 + + def selected_alpn_protocol(self) -> str: + return "h2" if self._http2 else "http/1.1" + + +class MockStream(NetworkStream): + def __init__(self, buffer: list[bytes], http2: bool = False) -> None: + self._buffer = buffer + self._http2 = http2 + self._closed = False + + def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + if self._closed: + raise ReadError("Connection closed") + if not self._buffer: + return b"" + return self._buffer.pop(0) + + def write(self, buffer: bytes, timeout: float | None = None) -> None: + pass + + def close(self) -> None: + self._closed = True + + def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> NetworkStream: + return self + + def get_extra_info(self, info: str) -> typing.Any: + return MockSSLObject(http2=self._http2) if info == "ssl_object" else None + + def __repr__(self) -> str: + return "" + + +class MockBackend(NetworkBackend): + def __init__(self, buffer: list[bytes], http2: bool = False) -> None: + self._buffer = buffer + self._http2 = http2 + + def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> NetworkStream: + return MockStream(list(self._buffer), http2=self._http2) + + def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> NetworkStream: + return MockStream(list(self._buffer), http2=self._http2) + + def sleep(self, seconds: float) -> None: + pass + + +class AsyncMockStream(AsyncNetworkStream): + def __init__(self, buffer: list[bytes], http2: bool = False) -> None: + self._buffer = buffer + self._http2 = http2 + self._closed = False + + async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + if self._closed: + raise ReadError("Connection closed") + if not self._buffer: + return b"" + return self._buffer.pop(0) + + async def write(self, buffer: bytes, timeout: float | None = None) -> None: + pass + + async def aclose(self) -> None: + self._closed = True + + async def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> AsyncNetworkStream: + return self + + def get_extra_info(self, info: str) -> typing.Any: + return MockSSLObject(http2=self._http2) if info == "ssl_object" else None + + def __repr__(self) -> str: + return "" + + +class AsyncMockBackend(AsyncNetworkBackend): + def __init__(self, buffer: list[bytes], http2: bool = False) -> None: + self._buffer = buffer + self._http2 = http2 + + async def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: + return AsyncMockStream(list(self._buffer), http2=self._http2) + + async def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: + return AsyncMockStream(list(self._buffer), http2=self._http2) + + async def sleep(self, seconds: float) -> None: + pass diff --git a/source/target-vendors/cp312/httpcore/_backends/sync.py b/source/target-vendors/cp312/httpcore/_backends/sync.py new file mode 100644 index 0000000..4018a09 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_backends/sync.py @@ -0,0 +1,241 @@ +from __future__ import annotations + +import functools +import socket +import ssl +import sys +import typing + +from .._exceptions import ( + ConnectError, + ConnectTimeout, + ExceptionMapping, + ReadError, + ReadTimeout, + WriteError, + WriteTimeout, + map_exceptions, +) +from .._utils import is_socket_readable +from .base import SOCKET_OPTION, NetworkBackend, NetworkStream + + +class TLSinTLSStream(NetworkStream): # pragma: no cover + """ + Because the standard `SSLContext.wrap_socket` method does + not work for `SSLSocket` objects, we need this class + to implement TLS stream using an underlying `SSLObject` + instance in order to support TLS on top of TLS. + """ + + # Defined in RFC 8449 + TLS_RECORD_SIZE = 16384 + + def __init__( + self, + sock: socket.socket, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ): + self._sock = sock + self._incoming = ssl.MemoryBIO() + self._outgoing = ssl.MemoryBIO() + + self.ssl_obj = ssl_context.wrap_bio( + incoming=self._incoming, + outgoing=self._outgoing, + server_hostname=server_hostname, + ) + + self._sock.settimeout(timeout) + self._perform_io(self.ssl_obj.do_handshake) + + def _perform_io( + self, + func: typing.Callable[..., typing.Any], + ) -> typing.Any: + ret = None + + while True: + errno = None + try: + ret = func() + except (ssl.SSLWantReadError, ssl.SSLWantWriteError) as e: + errno = e.errno + + self._sock.sendall(self._outgoing.read()) + + if errno == ssl.SSL_ERROR_WANT_READ: + buf = self._sock.recv(self.TLS_RECORD_SIZE) + + if buf: + self._incoming.write(buf) + else: + self._incoming.write_eof() + if errno is None: + return ret + + def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError} + with map_exceptions(exc_map): + self._sock.settimeout(timeout) + return typing.cast( + bytes, self._perform_io(functools.partial(self.ssl_obj.read, max_bytes)) + ) + + def write(self, buffer: bytes, timeout: float | None = None) -> None: + exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError} + with map_exceptions(exc_map): + self._sock.settimeout(timeout) + while buffer: + nsent = self._perform_io(functools.partial(self.ssl_obj.write, buffer)) + buffer = buffer[nsent:] + + def close(self) -> None: + self._sock.close() + + def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> NetworkStream: + raise NotImplementedError() + + def get_extra_info(self, info: str) -> typing.Any: + if info == "ssl_object": + return self.ssl_obj + if info == "client_addr": + return self._sock.getsockname() + if info == "server_addr": + return self._sock.getpeername() + if info == "socket": + return self._sock + if info == "is_readable": + return is_socket_readable(self._sock) + return None + + +class SyncStream(NetworkStream): + def __init__(self, sock: socket.socket) -> None: + self._sock = sock + + def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError} + with map_exceptions(exc_map): + self._sock.settimeout(timeout) + return self._sock.recv(max_bytes) + + def write(self, buffer: bytes, timeout: float | None = None) -> None: + if not buffer: + return + + exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError} + with map_exceptions(exc_map): + while buffer: + self._sock.settimeout(timeout) + n = self._sock.send(buffer) + buffer = buffer[n:] + + def close(self) -> None: + self._sock.close() + + def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> NetworkStream: + exc_map: ExceptionMapping = { + socket.timeout: ConnectTimeout, + OSError: ConnectError, + } + with map_exceptions(exc_map): + try: + if isinstance(self._sock, ssl.SSLSocket): # pragma: no cover + # If the underlying socket has already been upgraded + # to the TLS layer (i.e. is an instance of SSLSocket), + # we need some additional smarts to support TLS-in-TLS. + return TLSinTLSStream( + self._sock, ssl_context, server_hostname, timeout + ) + else: + self._sock.settimeout(timeout) + sock = ssl_context.wrap_socket( + self._sock, server_hostname=server_hostname + ) + except Exception as exc: # pragma: nocover + self.close() + raise exc + return SyncStream(sock) + + def get_extra_info(self, info: str) -> typing.Any: + if info == "ssl_object" and isinstance(self._sock, ssl.SSLSocket): + return self._sock._sslobj # type: ignore + if info == "client_addr": + return self._sock.getsockname() + if info == "server_addr": + return self._sock.getpeername() + if info == "socket": + return self._sock + if info == "is_readable": + return is_socket_readable(self._sock) + return None + + +class SyncBackend(NetworkBackend): + def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> NetworkStream: + # Note that we automatically include `TCP_NODELAY` + # in addition to any other custom socket options. + if socket_options is None: + socket_options = [] # pragma: no cover + address = (host, port) + source_address = None if local_address is None else (local_address, 0) + exc_map: ExceptionMapping = { + socket.timeout: ConnectTimeout, + OSError: ConnectError, + } + + with map_exceptions(exc_map): + sock = socket.create_connection( + address, + timeout, + source_address=source_address, + ) + for option in socket_options: + sock.setsockopt(*option) # pragma: no cover + sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + return SyncStream(sock) + + def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> NetworkStream: # pragma: nocover + if sys.platform == "win32": + raise RuntimeError( + "Attempted to connect to a UNIX socket on a Windows system." + ) + if socket_options is None: + socket_options = [] + + exc_map: ExceptionMapping = { + socket.timeout: ConnectTimeout, + OSError: ConnectError, + } + with map_exceptions(exc_map): + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + for option in socket_options: + sock.setsockopt(*option) + sock.settimeout(timeout) + sock.connect(path) + return SyncStream(sock) diff --git a/source/target-vendors/cp312/httpcore/_backends/trio.py b/source/target-vendors/cp312/httpcore/_backends/trio.py new file mode 100644 index 0000000..6f53f5f --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_backends/trio.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +import ssl +import typing + +import trio + +from .._exceptions import ( + ConnectError, + ConnectTimeout, + ExceptionMapping, + ReadError, + ReadTimeout, + WriteError, + WriteTimeout, + map_exceptions, +) +from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream + + +class TrioStream(AsyncNetworkStream): + def __init__(self, stream: trio.abc.Stream) -> None: + self._stream = stream + + async def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + timeout_or_inf = float("inf") if timeout is None else timeout + exc_map: ExceptionMapping = { + trio.TooSlowError: ReadTimeout, + trio.BrokenResourceError: ReadError, + trio.ClosedResourceError: ReadError, + } + with map_exceptions(exc_map): + with trio.fail_after(timeout_or_inf): + data: bytes = await self._stream.receive_some(max_bytes=max_bytes) + return data + + async def write(self, buffer: bytes, timeout: float | None = None) -> None: + if not buffer: + return + + timeout_or_inf = float("inf") if timeout is None else timeout + exc_map: ExceptionMapping = { + trio.TooSlowError: WriteTimeout, + trio.BrokenResourceError: WriteError, + trio.ClosedResourceError: WriteError, + } + with map_exceptions(exc_map): + with trio.fail_after(timeout_or_inf): + await self._stream.send_all(data=buffer) + + async def aclose(self) -> None: + await self._stream.aclose() + + async def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> AsyncNetworkStream: + timeout_or_inf = float("inf") if timeout is None else timeout + exc_map: ExceptionMapping = { + trio.TooSlowError: ConnectTimeout, + trio.BrokenResourceError: ConnectError, + } + ssl_stream = trio.SSLStream( + self._stream, + ssl_context=ssl_context, + server_hostname=server_hostname, + https_compatible=True, + server_side=False, + ) + with map_exceptions(exc_map): + try: + with trio.fail_after(timeout_or_inf): + await ssl_stream.do_handshake() + except Exception as exc: # pragma: nocover + await self.aclose() + raise exc + return TrioStream(ssl_stream) + + def get_extra_info(self, info: str) -> typing.Any: + if info == "ssl_object" and isinstance(self._stream, trio.SSLStream): + # Type checkers cannot see `_ssl_object` attribute because trio._ssl.SSLStream uses __getattr__/__setattr__. + # Tracked at https://github.com/python-trio/trio/issues/542 + return self._stream._ssl_object # type: ignore[attr-defined] + if info == "client_addr": + return self._get_socket_stream().socket.getsockname() + if info == "server_addr": + return self._get_socket_stream().socket.getpeername() + if info == "socket": + stream = self._stream + while isinstance(stream, trio.SSLStream): + stream = stream.transport_stream + assert isinstance(stream, trio.SocketStream) + return stream.socket + if info == "is_readable": + socket = self.get_extra_info("socket") + return socket.is_readable() + return None + + def _get_socket_stream(self) -> trio.SocketStream: + stream = self._stream + while isinstance(stream, trio.SSLStream): + stream = stream.transport_stream + assert isinstance(stream, trio.SocketStream) + return stream + + +class TrioBackend(AsyncNetworkBackend): + async def connect_tcp( + self, + host: str, + port: int, + timeout: float | None = None, + local_address: str | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: + # By default for TCP sockets, trio enables TCP_NODELAY. + # https://trio.readthedocs.io/en/stable/reference-io.html#trio.SocketStream + if socket_options is None: + socket_options = [] # pragma: no cover + timeout_or_inf = float("inf") if timeout is None else timeout + exc_map: ExceptionMapping = { + trio.TooSlowError: ConnectTimeout, + trio.BrokenResourceError: ConnectError, + OSError: ConnectError, + } + with map_exceptions(exc_map): + with trio.fail_after(timeout_or_inf): + stream: trio.abc.Stream = await trio.open_tcp_stream( + host=host, port=port, local_address=local_address + ) + for option in socket_options: + stream.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover + return TrioStream(stream) + + async def connect_unix_socket( + self, + path: str, + timeout: float | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> AsyncNetworkStream: # pragma: nocover + if socket_options is None: + socket_options = [] + timeout_or_inf = float("inf") if timeout is None else timeout + exc_map: ExceptionMapping = { + trio.TooSlowError: ConnectTimeout, + trio.BrokenResourceError: ConnectError, + OSError: ConnectError, + } + with map_exceptions(exc_map): + with trio.fail_after(timeout_or_inf): + stream: trio.abc.Stream = await trio.open_unix_socket(path) + for option in socket_options: + stream.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover + return TrioStream(stream) + + async def sleep(self, seconds: float) -> None: + await trio.sleep(seconds) # pragma: nocover diff --git a/source/target-vendors/cp312/httpcore/_exceptions.py b/source/target-vendors/cp312/httpcore/_exceptions.py new file mode 100644 index 0000000..bc28d44 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_exceptions.py @@ -0,0 +1,81 @@ +import contextlib +import typing + +ExceptionMapping = typing.Mapping[typing.Type[Exception], typing.Type[Exception]] + + +@contextlib.contextmanager +def map_exceptions(map: ExceptionMapping) -> typing.Iterator[None]: + try: + yield + except Exception as exc: # noqa: PIE786 + for from_exc, to_exc in map.items(): + if isinstance(exc, from_exc): + raise to_exc(exc) from exc + raise # pragma: nocover + + +class ConnectionNotAvailable(Exception): + pass + + +class ProxyError(Exception): + pass + + +class UnsupportedProtocol(Exception): + pass + + +class ProtocolError(Exception): + pass + + +class RemoteProtocolError(ProtocolError): + pass + + +class LocalProtocolError(ProtocolError): + pass + + +# Timeout errors + + +class TimeoutException(Exception): + pass + + +class PoolTimeout(TimeoutException): + pass + + +class ConnectTimeout(TimeoutException): + pass + + +class ReadTimeout(TimeoutException): + pass + + +class WriteTimeout(TimeoutException): + pass + + +# Network errors + + +class NetworkError(Exception): + pass + + +class ConnectError(NetworkError): + pass + + +class ReadError(NetworkError): + pass + + +class WriteError(NetworkError): + pass diff --git a/source/target-vendors/cp312/httpcore/_models.py b/source/target-vendors/cp312/httpcore/_models.py new file mode 100644 index 0000000..8a65f13 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_models.py @@ -0,0 +1,516 @@ +from __future__ import annotations + +import base64 +import ssl +import typing +import urllib.parse + +# Functions for typechecking... + + +ByteOrStr = typing.Union[bytes, str] +HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] +HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] +HeaderTypes = typing.Union[HeadersAsSequence, HeadersAsMapping, None] + +Extensions = typing.MutableMapping[str, typing.Any] + + +def enforce_bytes(value: bytes | str, *, name: str) -> bytes: + """ + Any arguments that are ultimately represented as bytes can be specified + either as bytes or as strings. + + However we enforce that any string arguments must only contain characters in + the plain ASCII range. chr(0)...chr(127). If you need to use characters + outside that range then be precise, and use a byte-wise argument. + """ + if isinstance(value, str): + try: + return value.encode("ascii") + except UnicodeEncodeError: + raise TypeError(f"{name} strings may not include unicode characters.") + elif isinstance(value, bytes): + return value + + seen_type = type(value).__name__ + raise TypeError(f"{name} must be bytes or str, but got {seen_type}.") + + +def enforce_url(value: URL | bytes | str, *, name: str) -> URL: + """ + Type check for URL parameters. + """ + if isinstance(value, (bytes, str)): + return URL(value) + elif isinstance(value, URL): + return value + + seen_type = type(value).__name__ + raise TypeError(f"{name} must be a URL, bytes, or str, but got {seen_type}.") + + +def enforce_headers( + value: HeadersAsMapping | HeadersAsSequence | None = None, *, name: str +) -> list[tuple[bytes, bytes]]: + """ + Convienence function that ensure all items in request or response headers + are either bytes or strings in the plain ASCII range. + """ + if value is None: + return [] + elif isinstance(value, typing.Mapping): + return [ + ( + enforce_bytes(k, name="header name"), + enforce_bytes(v, name="header value"), + ) + for k, v in value.items() + ] + elif isinstance(value, typing.Sequence): + return [ + ( + enforce_bytes(k, name="header name"), + enforce_bytes(v, name="header value"), + ) + for k, v in value + ] + + seen_type = type(value).__name__ + raise TypeError( + f"{name} must be a mapping or sequence of two-tuples, but got {seen_type}." + ) + + +def enforce_stream( + value: bytes | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None, + *, + name: str, +) -> typing.Iterable[bytes] | typing.AsyncIterable[bytes]: + if value is None: + return ByteStream(b"") + elif isinstance(value, bytes): + return ByteStream(value) + return value + + +# * https://tools.ietf.org/html/rfc3986#section-3.2.3 +# * https://url.spec.whatwg.org/#url-miscellaneous +# * https://url.spec.whatwg.org/#scheme-state +DEFAULT_PORTS = { + b"ftp": 21, + b"http": 80, + b"https": 443, + b"ws": 80, + b"wss": 443, +} + + +def include_request_headers( + headers: list[tuple[bytes, bytes]], + *, + url: "URL", + content: None | bytes | typing.Iterable[bytes] | typing.AsyncIterable[bytes], +) -> list[tuple[bytes, bytes]]: + headers_set = set(k.lower() for k, v in headers) + + if b"host" not in headers_set: + default_port = DEFAULT_PORTS.get(url.scheme) + if url.port is None or url.port == default_port: + header_value = url.host + else: + header_value = b"%b:%d" % (url.host, url.port) + headers = [(b"Host", header_value)] + headers + + if ( + content is not None + and b"content-length" not in headers_set + and b"transfer-encoding" not in headers_set + ): + if isinstance(content, bytes): + content_length = str(len(content)).encode("ascii") + headers += [(b"Content-Length", content_length)] + else: + headers += [(b"Transfer-Encoding", b"chunked")] # pragma: nocover + + return headers + + +# Interfaces for byte streams... + + +class ByteStream: + """ + A container for non-streaming content, and that supports both sync and async + stream iteration. + """ + + def __init__(self, content: bytes) -> None: + self._content = content + + def __iter__(self) -> typing.Iterator[bytes]: + yield self._content + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + yield self._content + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{len(self._content)} bytes]>" + + +class Origin: + def __init__(self, scheme: bytes, host: bytes, port: int) -> None: + self.scheme = scheme + self.host = host + self.port = port + + def __eq__(self, other: typing.Any) -> bool: + return ( + isinstance(other, Origin) + and self.scheme == other.scheme + and self.host == other.host + and self.port == other.port + ) + + def __str__(self) -> str: + scheme = self.scheme.decode("ascii") + host = self.host.decode("ascii") + port = str(self.port) + return f"{scheme}://{host}:{port}" + + +class URL: + """ + Represents the URL against which an HTTP request may be made. + + The URL may either be specified as a plain string, for convienence: + + ```python + url = httpcore.URL("https://www.example.com/") + ``` + + Or be constructed with explicitily pre-parsed components: + + ```python + url = httpcore.URL(scheme=b'https', host=b'www.example.com', port=None, target=b'/') + ``` + + Using this second more explicit style allows integrations that are using + `httpcore` to pass through URLs that have already been parsed in order to use + libraries such as `rfc-3986` rather than relying on the stdlib. It also ensures + that URL parsing is treated identically at both the networking level and at any + higher layers of abstraction. + + The four components are important here, as they allow the URL to be precisely + specified in a pre-parsed format. They also allow certain types of request to + be created that could not otherwise be expressed. + + For example, an HTTP request to `http://www.example.com/` forwarded via a proxy + at `http://localhost:8080`... + + ```python + # Constructs an HTTP request with a complete URL as the target: + # GET https://www.example.com/ HTTP/1.1 + url = httpcore.URL( + scheme=b'http', + host=b'localhost', + port=8080, + target=b'https://www.example.com/' + ) + request = httpcore.Request( + method="GET", + url=url + ) + ``` + + Another example is constructing an `OPTIONS *` request... + + ```python + # Constructs an 'OPTIONS *' HTTP request: + # OPTIONS * HTTP/1.1 + url = httpcore.URL(scheme=b'https', host=b'www.example.com', target=b'*') + request = httpcore.Request(method="OPTIONS", url=url) + ``` + + This kind of request is not possible to formulate with a URL string, + because the `/` delimiter is always used to demark the target from the + host/port portion of the URL. + + For convenience, string-like arguments may be specified either as strings or + as bytes. However, once a request is being issue over-the-wire, the URL + components are always ultimately required to be a bytewise representation. + + In order to avoid any ambiguity over character encodings, when strings are used + as arguments, they must be strictly limited to the ASCII range `chr(0)`-`chr(127)`. + If you require a bytewise representation that is outside this range you must + handle the character encoding directly, and pass a bytes instance. + """ + + def __init__( + self, + url: bytes | str = "", + *, + scheme: bytes | str = b"", + host: bytes | str = b"", + port: int | None = None, + target: bytes | str = b"", + ) -> None: + """ + Parameters: + url: The complete URL as a string or bytes. + scheme: The URL scheme as a string or bytes. + Typically either `"http"` or `"https"`. + host: The URL host as a string or bytes. Such as `"www.example.com"`. + port: The port to connect to. Either an integer or `None`. + target: The target of the HTTP request. Such as `"/items?search=red"`. + """ + if url: + parsed = urllib.parse.urlparse(enforce_bytes(url, name="url")) + self.scheme = parsed.scheme + self.host = parsed.hostname or b"" + self.port = parsed.port + self.target = (parsed.path or b"/") + ( + b"?" + parsed.query if parsed.query else b"" + ) + else: + self.scheme = enforce_bytes(scheme, name="scheme") + self.host = enforce_bytes(host, name="host") + self.port = port + self.target = enforce_bytes(target, name="target") + + @property + def origin(self) -> Origin: + default_port = { + b"http": 80, + b"https": 443, + b"ws": 80, + b"wss": 443, + b"socks5": 1080, + b"socks5h": 1080, + }[self.scheme] + return Origin( + scheme=self.scheme, host=self.host, port=self.port or default_port + ) + + def __eq__(self, other: typing.Any) -> bool: + return ( + isinstance(other, URL) + and other.scheme == self.scheme + and other.host == self.host + and other.port == self.port + and other.target == self.target + ) + + def __bytes__(self) -> bytes: + if self.port is None: + return b"%b://%b%b" % (self.scheme, self.host, self.target) + return b"%b://%b:%d%b" % (self.scheme, self.host, self.port, self.target) + + def __repr__(self) -> str: + return ( + f"{self.__class__.__name__}(scheme={self.scheme!r}, " + f"host={self.host!r}, port={self.port!r}, target={self.target!r})" + ) + + +class Request: + """ + An HTTP request. + """ + + def __init__( + self, + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes + | typing.Iterable[bytes] + | typing.AsyncIterable[bytes] + | None = None, + extensions: Extensions | None = None, + ) -> None: + """ + Parameters: + method: The HTTP request method, either as a string or bytes. + For example: `GET`. + url: The request URL, either as a `URL` instance, or as a string or bytes. + For example: `"https://www.example.com".` + headers: The HTTP request headers. + content: The content of the request body. + extensions: A dictionary of optional extra information included on + the request. Possible keys include `"timeout"`, and `"trace"`. + """ + self.method: bytes = enforce_bytes(method, name="method") + self.url: URL = enforce_url(url, name="url") + self.headers: list[tuple[bytes, bytes]] = enforce_headers( + headers, name="headers" + ) + self.stream: typing.Iterable[bytes] | typing.AsyncIterable[bytes] = ( + enforce_stream(content, name="content") + ) + self.extensions = {} if extensions is None else extensions + + if "target" in self.extensions: + self.url = URL( + scheme=self.url.scheme, + host=self.url.host, + port=self.url.port, + target=self.extensions["target"], + ) + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.method!r}]>" + + +class Response: + """ + An HTTP response. + """ + + def __init__( + self, + status: int, + *, + headers: HeaderTypes = None, + content: bytes + | typing.Iterable[bytes] + | typing.AsyncIterable[bytes] + | None = None, + extensions: Extensions | None = None, + ) -> None: + """ + Parameters: + status: The HTTP status code of the response. For example `200`. + headers: The HTTP response headers. + content: The content of the response body. + extensions: A dictionary of optional extra information included on + the responseself.Possible keys include `"http_version"`, + `"reason_phrase"`, and `"network_stream"`. + """ + self.status: int = status + self.headers: list[tuple[bytes, bytes]] = enforce_headers( + headers, name="headers" + ) + self.stream: typing.Iterable[bytes] | typing.AsyncIterable[bytes] = ( + enforce_stream(content, name="content") + ) + self.extensions = {} if extensions is None else extensions + + self._stream_consumed = False + + @property + def content(self) -> bytes: + if not hasattr(self, "_content"): + if isinstance(self.stream, typing.Iterable): + raise RuntimeError( + "Attempted to access 'response.content' on a streaming response. " + "Call 'response.read()' first." + ) + else: + raise RuntimeError( + "Attempted to access 'response.content' on a streaming response. " + "Call 'await response.aread()' first." + ) + return self._content + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.status}]>" + + # Sync interface... + + def read(self) -> bytes: + if not isinstance(self.stream, typing.Iterable): # pragma: nocover + raise RuntimeError( + "Attempted to read an asynchronous response using 'response.read()'. " + "You should use 'await response.aread()' instead." + ) + if not hasattr(self, "_content"): + self._content = b"".join([part for part in self.iter_stream()]) + return self._content + + def iter_stream(self) -> typing.Iterator[bytes]: + if not isinstance(self.stream, typing.Iterable): # pragma: nocover + raise RuntimeError( + "Attempted to stream an asynchronous response using 'for ... in " + "response.iter_stream()'. " + "You should use 'async for ... in response.aiter_stream()' instead." + ) + if self._stream_consumed: + raise RuntimeError( + "Attempted to call 'for ... in response.iter_stream()' more than once." + ) + self._stream_consumed = True + for chunk in self.stream: + yield chunk + + def close(self) -> None: + if not isinstance(self.stream, typing.Iterable): # pragma: nocover + raise RuntimeError( + "Attempted to close an asynchronous response using 'response.close()'. " + "You should use 'await response.aclose()' instead." + ) + if hasattr(self.stream, "close"): + self.stream.close() + + # Async interface... + + async def aread(self) -> bytes: + if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover + raise RuntimeError( + "Attempted to read an synchronous response using " + "'await response.aread()'. " + "You should use 'response.read()' instead." + ) + if not hasattr(self, "_content"): + self._content = b"".join([part async for part in self.aiter_stream()]) + return self._content + + async def aiter_stream(self) -> typing.AsyncIterator[bytes]: + if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover + raise RuntimeError( + "Attempted to stream an synchronous response using 'async for ... in " + "response.aiter_stream()'. " + "You should use 'for ... in response.iter_stream()' instead." + ) + if self._stream_consumed: + raise RuntimeError( + "Attempted to call 'async for ... in response.aiter_stream()' " + "more than once." + ) + self._stream_consumed = True + async for chunk in self.stream: + yield chunk + + async def aclose(self) -> None: + if not isinstance(self.stream, typing.AsyncIterable): # pragma: nocover + raise RuntimeError( + "Attempted to close a synchronous response using " + "'await response.aclose()'. " + "You should use 'response.close()' instead." + ) + if hasattr(self.stream, "aclose"): + await self.stream.aclose() + + +class Proxy: + def __init__( + self, + url: URL | bytes | str, + auth: tuple[bytes | str, bytes | str] | None = None, + headers: HeadersAsMapping | HeadersAsSequence | None = None, + ssl_context: ssl.SSLContext | None = None, + ): + self.url = enforce_url(url, name="url") + self.headers = enforce_headers(headers, name="headers") + self.ssl_context = ssl_context + + if auth is not None: + username = enforce_bytes(auth[0], name="auth") + password = enforce_bytes(auth[1], name="auth") + userpass = username + b":" + password + authorization = b"Basic " + base64.b64encode(userpass) + self.auth: tuple[bytes, bytes] | None = (username, password) + self.headers = [(b"Proxy-Authorization", authorization)] + self.headers + else: + self.auth = None diff --git a/source/target-vendors/cp312/httpcore/_ssl.py b/source/target-vendors/cp312/httpcore/_ssl.py new file mode 100644 index 0000000..c99c5a6 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_ssl.py @@ -0,0 +1,9 @@ +import ssl + +import certifi + + +def default_ssl_context() -> ssl.SSLContext: + context = ssl.create_default_context() + context.load_verify_locations(certifi.where()) + return context diff --git a/source/target-vendors/cp312/httpcore/_sync/__init__.py b/source/target-vendors/cp312/httpcore/_sync/__init__.py new file mode 100644 index 0000000..b476d76 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/__init__.py @@ -0,0 +1,39 @@ +from .connection import HTTPConnection +from .connection_pool import ConnectionPool +from .http11 import HTTP11Connection +from .http_proxy import HTTPProxy +from .interfaces import ConnectionInterface + +try: + from .http2 import HTTP2Connection +except ImportError: # pragma: nocover + + class HTTP2Connection: # type: ignore + def __init__(self, *args, **kwargs) -> None: # type: ignore + raise RuntimeError( + "Attempted to use http2 support, but the `h2` package is not " + "installed. Use 'pip install httpcore[http2]'." + ) + + +try: + from .socks_proxy import SOCKSProxy +except ImportError: # pragma: nocover + + class SOCKSProxy: # type: ignore + def __init__(self, *args, **kwargs) -> None: # type: ignore + raise RuntimeError( + "Attempted to use SOCKS support, but the `socksio` package is not " + "installed. Use 'pip install httpcore[socks]'." + ) + + +__all__ = [ + "HTTPConnection", + "ConnectionPool", + "HTTPProxy", + "HTTP11Connection", + "HTTP2Connection", + "ConnectionInterface", + "SOCKSProxy", +] diff --git a/source/target-vendors/cp312/httpcore/_sync/connection.py b/source/target-vendors/cp312/httpcore/_sync/connection.py new file mode 100644 index 0000000..363f8be --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/connection.py @@ -0,0 +1,222 @@ +from __future__ import annotations + +import itertools +import logging +import ssl +import types +import typing + +from .._backends.sync import SyncBackend +from .._backends.base import SOCKET_OPTION, NetworkBackend, NetworkStream +from .._exceptions import ConnectError, ConnectTimeout +from .._models import Origin, Request, Response +from .._ssl import default_ssl_context +from .._synchronization import Lock +from .._trace import Trace +from .http11 import HTTP11Connection +from .interfaces import ConnectionInterface + +RETRIES_BACKOFF_FACTOR = 0.5 # 0s, 0.5s, 1s, 2s, 4s, etc. + + +logger = logging.getLogger("httpcore.connection") + + +def exponential_backoff(factor: float) -> typing.Iterator[float]: + """ + Generate a geometric sequence that has a ratio of 2 and starts with 0. + + For example: + - `factor = 2`: `0, 2, 4, 8, 16, 32, 64, ...` + - `factor = 3`: `0, 3, 6, 12, 24, 48, 96, ...` + """ + yield 0 + for n in itertools.count(): + yield factor * 2**n + + +class HTTPConnection(ConnectionInterface): + def __init__( + self, + origin: Origin, + ssl_context: ssl.SSLContext | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + local_address: str | None = None, + uds: str | None = None, + network_backend: NetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + self._origin = origin + self._ssl_context = ssl_context + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + self._retries = retries + self._local_address = local_address + self._uds = uds + + self._network_backend: NetworkBackend = ( + SyncBackend() if network_backend is None else network_backend + ) + self._connection: ConnectionInterface | None = None + self._connect_failed: bool = False + self._request_lock = Lock() + self._socket_options = socket_options + + def handle_request(self, request: Request) -> Response: + if not self.can_handle_request(request.url.origin): + raise RuntimeError( + f"Attempted to send request to {request.url.origin} on connection to {self._origin}" + ) + + try: + with self._request_lock: + if self._connection is None: + stream = self._connect(request) + + ssl_object = stream.get_extra_info("ssl_object") + http2_negotiated = ( + ssl_object is not None + and ssl_object.selected_alpn_protocol() == "h2" + ) + if http2_negotiated or (self._http2 and not self._http1): + from .http2 import HTTP2Connection + + self._connection = HTTP2Connection( + origin=self._origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + else: + self._connection = HTTP11Connection( + origin=self._origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + except BaseException as exc: + self._connect_failed = True + raise exc + + return self._connection.handle_request(request) + + def _connect(self, request: Request) -> NetworkStream: + timeouts = request.extensions.get("timeout", {}) + sni_hostname = request.extensions.get("sni_hostname", None) + timeout = timeouts.get("connect", None) + + retries_left = self._retries + delays = exponential_backoff(factor=RETRIES_BACKOFF_FACTOR) + + while True: + try: + if self._uds is None: + kwargs = { + "host": self._origin.host.decode("ascii"), + "port": self._origin.port, + "local_address": self._local_address, + "timeout": timeout, + "socket_options": self._socket_options, + } + with Trace("connect_tcp", logger, request, kwargs) as trace: + stream = self._network_backend.connect_tcp(**kwargs) + trace.return_value = stream + else: + kwargs = { + "path": self._uds, + "timeout": timeout, + "socket_options": self._socket_options, + } + with Trace( + "connect_unix_socket", logger, request, kwargs + ) as trace: + stream = self._network_backend.connect_unix_socket( + **kwargs + ) + trace.return_value = stream + + if self._origin.scheme in (b"https", b"wss"): + ssl_context = ( + default_ssl_context() + if self._ssl_context is None + else self._ssl_context + ) + alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] + ssl_context.set_alpn_protocols(alpn_protocols) + + kwargs = { + "ssl_context": ssl_context, + "server_hostname": sni_hostname + or self._origin.host.decode("ascii"), + "timeout": timeout, + } + with Trace("start_tls", logger, request, kwargs) as trace: + stream = stream.start_tls(**kwargs) + trace.return_value = stream + return stream + except (ConnectError, ConnectTimeout): + if retries_left <= 0: + raise + retries_left -= 1 + delay = next(delays) + with Trace("retry", logger, request, kwargs) as trace: + self._network_backend.sleep(delay) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._origin + + def close(self) -> None: + if self._connection is not None: + with Trace("close", logger, None, {}): + self._connection.close() + + def is_available(self) -> bool: + if self._connection is None: + # If HTTP/2 support is enabled, and the resulting connection could + # end up as HTTP/2 then we should indicate the connection as being + # available to service multiple requests. + return ( + self._http2 + and (self._origin.scheme == b"https" or not self._http1) + and not self._connect_failed + ) + return self._connection.is_available() + + def has_expired(self) -> bool: + if self._connection is None: + return self._connect_failed + return self._connection.has_expired() + + def is_idle(self) -> bool: + if self._connection is None: + return self._connect_failed + return self._connection.is_idle() + + def is_closed(self) -> bool: + if self._connection is None: + return self._connect_failed + return self._connection.is_closed() + + def info(self) -> str: + if self._connection is None: + return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + return self._connection.info() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" + + # These context managers are not used in the standard flow, but are + # useful for testing or working with connection instances directly. + + def __enter__(self) -> HTTPConnection: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + self.close() diff --git a/source/target-vendors/cp312/httpcore/_sync/connection_pool.py b/source/target-vendors/cp312/httpcore/_sync/connection_pool.py new file mode 100644 index 0000000..9ccfa53 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/connection_pool.py @@ -0,0 +1,420 @@ +from __future__ import annotations + +import ssl +import sys +import types +import typing + +from .._backends.sync import SyncBackend +from .._backends.base import SOCKET_OPTION, NetworkBackend +from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol +from .._models import Origin, Proxy, Request, Response +from .._synchronization import Event, ShieldCancellation, ThreadLock +from .connection import HTTPConnection +from .interfaces import ConnectionInterface, RequestInterface + + +class PoolRequest: + def __init__(self, request: Request) -> None: + self.request = request + self.connection: ConnectionInterface | None = None + self._connection_acquired = Event() + + def assign_to_connection(self, connection: ConnectionInterface | None) -> None: + self.connection = connection + self._connection_acquired.set() + + def clear_connection(self) -> None: + self.connection = None + self._connection_acquired = Event() + + def wait_for_connection( + self, timeout: float | None = None + ) -> ConnectionInterface: + if self.connection is None: + self._connection_acquired.wait(timeout=timeout) + assert self.connection is not None + return self.connection + + def is_queued(self) -> bool: + return self.connection is None + + +class ConnectionPool(RequestInterface): + """ + A connection pool for making HTTP requests. + """ + + def __init__( + self, + ssl_context: ssl.SSLContext | None = None, + proxy: Proxy | None = None, + max_connections: int | None = 10, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + local_address: str | None = None, + uds: str | None = None, + network_backend: NetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + """ + A connection pool for making HTTP requests. + + Parameters: + ssl_context: An SSL context to use for verifying connections. + If not specified, the default `httpcore.default_ssl_context()` + will be used. + max_connections: The maximum number of concurrent HTTP connections that + the pool should allow. Any attempt to send a request on a pool that + would exceed this amount will block until a connection is available. + max_keepalive_connections: The maximum number of idle HTTP connections + that will be maintained in the pool. + keepalive_expiry: The duration in seconds that an idle HTTP connection + may be maintained for before being expired from the pool. + http1: A boolean indicating if HTTP/1.1 requests should be supported + by the connection pool. Defaults to True. + http2: A boolean indicating if HTTP/2 requests should be supported by + the connection pool. Defaults to False. + retries: The maximum number of retries when trying to establish a + connection. + local_address: Local address to connect from. Can also be used to connect + using a particular address family. Using `local_address="0.0.0.0"` + will connect using an `AF_INET` address (IPv4), while using + `local_address="::"` will connect using an `AF_INET6` address (IPv6). + uds: Path to a Unix Domain Socket to use instead of TCP sockets. + network_backend: A backend instance to use for handling network I/O. + socket_options: Socket options that have to be included + in the TCP socket when the connection was established. + """ + self._ssl_context = ssl_context + self._proxy = proxy + self._max_connections = ( + sys.maxsize if max_connections is None else max_connections + ) + self._max_keepalive_connections = ( + sys.maxsize + if max_keepalive_connections is None + else max_keepalive_connections + ) + self._max_keepalive_connections = min( + self._max_connections, self._max_keepalive_connections + ) + + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + self._retries = retries + self._local_address = local_address + self._uds = uds + + self._network_backend = ( + SyncBackend() if network_backend is None else network_backend + ) + self._socket_options = socket_options + + # The mutable state on a connection pool is the queue of incoming requests, + # and the set of connections that are servicing those requests. + self._connections: list[ConnectionInterface] = [] + self._requests: list[PoolRequest] = [] + + # We only mutate the state of the connection pool within an 'optional_thread_lock' + # context. This holds a threading lock unless we're running in async mode, + # in which case it is a no-op. + self._optional_thread_lock = ThreadLock() + + def create_connection(self, origin: Origin) -> ConnectionInterface: + if self._proxy is not None: + if self._proxy.url.scheme in (b"socks5", b"socks5h"): + from .socks_proxy import Socks5Connection + + return Socks5Connection( + proxy_origin=self._proxy.url.origin, + proxy_auth=self._proxy.auth, + remote_origin=origin, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + elif origin.scheme == b"http": + from .http_proxy import ForwardHTTPConnection + + return ForwardHTTPConnection( + proxy_origin=self._proxy.url.origin, + proxy_headers=self._proxy.headers, + proxy_ssl_context=self._proxy.ssl_context, + remote_origin=origin, + keepalive_expiry=self._keepalive_expiry, + network_backend=self._network_backend, + ) + from .http_proxy import TunnelHTTPConnection + + return TunnelHTTPConnection( + proxy_origin=self._proxy.url.origin, + proxy_headers=self._proxy.headers, + proxy_ssl_context=self._proxy.ssl_context, + remote_origin=origin, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + + return HTTPConnection( + origin=origin, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + retries=self._retries, + local_address=self._local_address, + uds=self._uds, + network_backend=self._network_backend, + socket_options=self._socket_options, + ) + + @property + def connections(self) -> list[ConnectionInterface]: + """ + Return a list of the connections currently in the pool. + + For example: + + ```python + >>> pool.connections + [ + , + , + , + ] + ``` + """ + return list(self._connections) + + def handle_request(self, request: Request) -> Response: + """ + Send an HTTP request, and return an HTTP response. + + This is the core implementation that is called into by `.request()` or `.stream()`. + """ + scheme = request.url.scheme.decode() + if scheme == "": + raise UnsupportedProtocol( + "Request URL is missing an 'http://' or 'https://' protocol." + ) + if scheme not in ("http", "https", "ws", "wss"): + raise UnsupportedProtocol( + f"Request URL has an unsupported protocol '{scheme}://'." + ) + + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("pool", None) + + with self._optional_thread_lock: + # Add the incoming request to our request queue. + pool_request = PoolRequest(request) + self._requests.append(pool_request) + + try: + while True: + with self._optional_thread_lock: + # Assign incoming requests to available connections, + # closing or creating new connections as required. + closing = self._assign_requests_to_connections() + self._close_connections(closing) + + # Wait until this request has an assigned connection. + connection = pool_request.wait_for_connection(timeout=timeout) + + try: + # Send the request on the assigned connection. + response = connection.handle_request( + pool_request.request + ) + except ConnectionNotAvailable: + # In some cases a connection may initially be available to + # handle a request, but then become unavailable. + # + # In this case we clear the connection and try again. + pool_request.clear_connection() + else: + break # pragma: nocover + + except BaseException as exc: + with self._optional_thread_lock: + # For any exception or cancellation we remove the request from + # the queue, and then re-assign requests to connections. + self._requests.remove(pool_request) + closing = self._assign_requests_to_connections() + + self._close_connections(closing) + raise exc from None + + # Return the response. Note that in this case we still have to manage + # the point at which the response is closed. + assert isinstance(response.stream, typing.Iterable) + return Response( + status=response.status, + headers=response.headers, + content=PoolByteStream( + stream=response.stream, pool_request=pool_request, pool=self + ), + extensions=response.extensions, + ) + + def _assign_requests_to_connections(self) -> list[ConnectionInterface]: + """ + Manage the state of the connection pool, assigning incoming + requests to connections as available. + + Called whenever a new request is added or removed from the pool. + + Any closing connections are returned, allowing the I/O for closing + those connections to be handled seperately. + """ + closing_connections = [] + + # First we handle cleaning up any connections that are closed, + # have expired their keep-alive, or surplus idle connections. + for connection in list(self._connections): + if connection.is_closed(): + # log: "removing closed connection" + self._connections.remove(connection) + elif connection.has_expired(): + # log: "closing expired connection" + self._connections.remove(connection) + closing_connections.append(connection) + elif ( + connection.is_idle() + and len([connection.is_idle() for connection in self._connections]) + > self._max_keepalive_connections + ): + # log: "closing idle connection" + self._connections.remove(connection) + closing_connections.append(connection) + + # Assign queued requests to connections. + queued_requests = [request for request in self._requests if request.is_queued()] + for pool_request in queued_requests: + origin = pool_request.request.url.origin + available_connections = [ + connection + for connection in self._connections + if connection.can_handle_request(origin) and connection.is_available() + ] + idle_connections = [ + connection for connection in self._connections if connection.is_idle() + ] + + # There are three cases for how we may be able to handle the request: + # + # 1. There is an existing connection that can handle the request. + # 2. We can create a new connection to handle the request. + # 3. We can close an idle connection and then create a new connection + # to handle the request. + if available_connections: + # log: "reusing existing connection" + connection = available_connections[0] + pool_request.assign_to_connection(connection) + elif len(self._connections) < self._max_connections: + # log: "creating new connection" + connection = self.create_connection(origin) + self._connections.append(connection) + pool_request.assign_to_connection(connection) + elif idle_connections: + # log: "closing idle connection" + connection = idle_connections[0] + self._connections.remove(connection) + closing_connections.append(connection) + # log: "creating new connection" + connection = self.create_connection(origin) + self._connections.append(connection) + pool_request.assign_to_connection(connection) + + return closing_connections + + def _close_connections(self, closing: list[ConnectionInterface]) -> None: + # Close connections which have been removed from the pool. + with ShieldCancellation(): + for connection in closing: + connection.close() + + def close(self) -> None: + # Explicitly close the connection pool. + # Clears all existing requests and connections. + with self._optional_thread_lock: + closing_connections = list(self._connections) + self._connections = [] + self._close_connections(closing_connections) + + def __enter__(self) -> ConnectionPool: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + self.close() + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + with self._optional_thread_lock: + request_is_queued = [request.is_queued() for request in self._requests] + connection_is_idle = [ + connection.is_idle() for connection in self._connections + ] + + num_active_requests = request_is_queued.count(False) + num_queued_requests = request_is_queued.count(True) + num_active_connections = connection_is_idle.count(False) + num_idle_connections = connection_is_idle.count(True) + + requests_info = ( + f"Requests: {num_active_requests} active, {num_queued_requests} queued" + ) + connection_info = ( + f"Connections: {num_active_connections} active, {num_idle_connections} idle" + ) + + return f"<{class_name} [{requests_info} | {connection_info}]>" + + +class PoolByteStream: + def __init__( + self, + stream: typing.Iterable[bytes], + pool_request: PoolRequest, + pool: ConnectionPool, + ) -> None: + self._stream = stream + self._pool_request = pool_request + self._pool = pool + self._closed = False + + def __iter__(self) -> typing.Iterator[bytes]: + try: + for part in self._stream: + yield part + except BaseException as exc: + self.close() + raise exc from None + + def close(self) -> None: + if not self._closed: + self._closed = True + with ShieldCancellation(): + if hasattr(self._stream, "close"): + self._stream.close() + + with self._pool._optional_thread_lock: + self._pool._requests.remove(self._pool_request) + closing = self._pool._assign_requests_to_connections() + + self._pool._close_connections(closing) diff --git a/source/target-vendors/cp312/httpcore/_sync/http11.py b/source/target-vendors/cp312/httpcore/_sync/http11.py new file mode 100644 index 0000000..ebd3a97 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/http11.py @@ -0,0 +1,379 @@ +from __future__ import annotations + +import enum +import logging +import ssl +import time +import types +import typing + +import h11 + +from .._backends.base import NetworkStream +from .._exceptions import ( + ConnectionNotAvailable, + LocalProtocolError, + RemoteProtocolError, + WriteError, + map_exceptions, +) +from .._models import Origin, Request, Response +from .._synchronization import Lock, ShieldCancellation +from .._trace import Trace +from .interfaces import ConnectionInterface + +logger = logging.getLogger("httpcore.http11") + + +# A subset of `h11.Event` types supported by `_send_event` +H11SendEvent = typing.Union[ + h11.Request, + h11.Data, + h11.EndOfMessage, +] + + +class HTTPConnectionState(enum.IntEnum): + NEW = 0 + ACTIVE = 1 + IDLE = 2 + CLOSED = 3 + + +class HTTP11Connection(ConnectionInterface): + READ_NUM_BYTES = 64 * 1024 + MAX_INCOMPLETE_EVENT_SIZE = 100 * 1024 + + def __init__( + self, + origin: Origin, + stream: NetworkStream, + keepalive_expiry: float | None = None, + ) -> None: + self._origin = origin + self._network_stream = stream + self._keepalive_expiry: float | None = keepalive_expiry + self._expire_at: float | None = None + self._state = HTTPConnectionState.NEW + self._state_lock = Lock() + self._request_count = 0 + self._h11_state = h11.Connection( + our_role=h11.CLIENT, + max_incomplete_event_size=self.MAX_INCOMPLETE_EVENT_SIZE, + ) + + def handle_request(self, request: Request) -> Response: + if not self.can_handle_request(request.url.origin): + raise RuntimeError( + f"Attempted to send request to {request.url.origin} on connection " + f"to {self._origin}" + ) + + with self._state_lock: + if self._state in (HTTPConnectionState.NEW, HTTPConnectionState.IDLE): + self._request_count += 1 + self._state = HTTPConnectionState.ACTIVE + self._expire_at = None + else: + raise ConnectionNotAvailable() + + try: + kwargs = {"request": request} + try: + with Trace( + "send_request_headers", logger, request, kwargs + ) as trace: + self._send_request_headers(**kwargs) + with Trace("send_request_body", logger, request, kwargs) as trace: + self._send_request_body(**kwargs) + except WriteError: + # If we get a write error while we're writing the request, + # then we supress this error and move on to attempting to + # read the response. Servers can sometimes close the request + # pre-emptively and then respond with a well formed HTTP + # error response. + pass + + with Trace( + "receive_response_headers", logger, request, kwargs + ) as trace: + ( + http_version, + status, + reason_phrase, + headers, + trailing_data, + ) = self._receive_response_headers(**kwargs) + trace.return_value = ( + http_version, + status, + reason_phrase, + headers, + ) + + network_stream = self._network_stream + + # CONNECT or Upgrade request + if (status == 101) or ( + (request.method == b"CONNECT") and (200 <= status < 300) + ): + network_stream = HTTP11UpgradeStream(network_stream, trailing_data) + + return Response( + status=status, + headers=headers, + content=HTTP11ConnectionByteStream(self, request), + extensions={ + "http_version": http_version, + "reason_phrase": reason_phrase, + "network_stream": network_stream, + }, + ) + except BaseException as exc: + with ShieldCancellation(): + with Trace("response_closed", logger, request) as trace: + self._response_closed() + raise exc + + # Sending the request... + + def _send_request_headers(self, request: Request) -> None: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("write", None) + + with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): + event = h11.Request( + method=request.method, + target=request.url.target, + headers=request.headers, + ) + self._send_event(event, timeout=timeout) + + def _send_request_body(self, request: Request) -> None: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("write", None) + + assert isinstance(request.stream, typing.Iterable) + for chunk in request.stream: + event = h11.Data(data=chunk) + self._send_event(event, timeout=timeout) + + self._send_event(h11.EndOfMessage(), timeout=timeout) + + def _send_event(self, event: h11.Event, timeout: float | None = None) -> None: + bytes_to_send = self._h11_state.send(event) + if bytes_to_send is not None: + self._network_stream.write(bytes_to_send, timeout=timeout) + + # Receiving the response... + + def _receive_response_headers( + self, request: Request + ) -> tuple[bytes, int, bytes, list[tuple[bytes, bytes]], bytes]: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("read", None) + + while True: + event = self._receive_event(timeout=timeout) + if isinstance(event, h11.Response): + break + if ( + isinstance(event, h11.InformationalResponse) + and event.status_code == 101 + ): + break + + http_version = b"HTTP/" + event.http_version + + # h11 version 0.11+ supports a `raw_items` interface to get the + # raw header casing, rather than the enforced lowercase headers. + headers = event.headers.raw_items() + + trailing_data, _ = self._h11_state.trailing_data + + return http_version, event.status_code, event.reason, headers, trailing_data + + def _receive_response_body( + self, request: Request + ) -> typing.Iterator[bytes]: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("read", None) + + while True: + event = self._receive_event(timeout=timeout) + if isinstance(event, h11.Data): + yield bytes(event.data) + elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): + break + + def _receive_event( + self, timeout: float | None = None + ) -> h11.Event | type[h11.PAUSED]: + while True: + with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): + event = self._h11_state.next_event() + + if event is h11.NEED_DATA: + data = self._network_stream.read( + self.READ_NUM_BYTES, timeout=timeout + ) + + # If we feed this case through h11 we'll raise an exception like: + # + # httpcore.RemoteProtocolError: can't handle event type + # ConnectionClosed when role=SERVER and state=SEND_RESPONSE + # + # Which is accurate, but not very informative from an end-user + # perspective. Instead we handle this case distinctly and treat + # it as a ConnectError. + if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: + msg = "Server disconnected without sending a response." + raise RemoteProtocolError(msg) + + self._h11_state.receive_data(data) + else: + # mypy fails to narrow the type in the above if statement above + return event # type: ignore[return-value] + + def _response_closed(self) -> None: + with self._state_lock: + if ( + self._h11_state.our_state is h11.DONE + and self._h11_state.their_state is h11.DONE + ): + self._state = HTTPConnectionState.IDLE + self._h11_state.start_next_cycle() + if self._keepalive_expiry is not None: + now = time.monotonic() + self._expire_at = now + self._keepalive_expiry + else: + self.close() + + # Once the connection is no longer required... + + def close(self) -> None: + # Note that this method unilaterally closes the connection, and does + # not have any kind of locking in place around it. + self._state = HTTPConnectionState.CLOSED + self._network_stream.close() + + # The ConnectionInterface methods provide information about the state of + # the connection, allowing for a connection pooling implementation to + # determine when to reuse and when to close the connection... + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._origin + + def is_available(self) -> bool: + # Note that HTTP/1.1 connections in the "NEW" state are not treated as + # being "available". The control flow which created the connection will + # be able to send an outgoing request, but the connection will not be + # acquired from the connection pool for any other request. + return self._state == HTTPConnectionState.IDLE + + def has_expired(self) -> bool: + now = time.monotonic() + keepalive_expired = self._expire_at is not None and now > self._expire_at + + # If the HTTP connection is idle but the socket is readable, then the + # only valid state is that the socket is about to return b"", indicating + # a server-initiated disconnect. + server_disconnected = ( + self._state == HTTPConnectionState.IDLE + and self._network_stream.get_extra_info("is_readable") + ) + + return keepalive_expired or server_disconnected + + def is_idle(self) -> bool: + return self._state == HTTPConnectionState.IDLE + + def is_closed(self) -> bool: + return self._state == HTTPConnectionState.CLOSED + + def info(self) -> str: + origin = str(self._origin) + return ( + f"{origin!r}, HTTP/1.1, {self._state.name}, " + f"Request Count: {self._request_count}" + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + origin = str(self._origin) + return ( + f"<{class_name} [{origin!r}, {self._state.name}, " + f"Request Count: {self._request_count}]>" + ) + + # These context managers are not used in the standard flow, but are + # useful for testing or working with connection instances directly. + + def __enter__(self) -> HTTP11Connection: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + self.close() + + +class HTTP11ConnectionByteStream: + def __init__(self, connection: HTTP11Connection, request: Request) -> None: + self._connection = connection + self._request = request + self._closed = False + + def __iter__(self) -> typing.Iterator[bytes]: + kwargs = {"request": self._request} + try: + with Trace("receive_response_body", logger, self._request, kwargs): + for chunk in self._connection._receive_response_body(**kwargs): + yield chunk + except BaseException as exc: + # If we get an exception while streaming the response, + # we want to close the response (and possibly the connection) + # before raising that exception. + with ShieldCancellation(): + self.close() + raise exc + + def close(self) -> None: + if not self._closed: + self._closed = True + with Trace("response_closed", logger, self._request): + self._connection._response_closed() + + +class HTTP11UpgradeStream(NetworkStream): + def __init__(self, stream: NetworkStream, leading_data: bytes) -> None: + self._stream = stream + self._leading_data = leading_data + + def read(self, max_bytes: int, timeout: float | None = None) -> bytes: + if self._leading_data: + buffer = self._leading_data[:max_bytes] + self._leading_data = self._leading_data[max_bytes:] + return buffer + else: + return self._stream.read(max_bytes, timeout) + + def write(self, buffer: bytes, timeout: float | None = None) -> None: + self._stream.write(buffer, timeout) + + def close(self) -> None: + self._stream.close() + + def start_tls( + self, + ssl_context: ssl.SSLContext, + server_hostname: str | None = None, + timeout: float | None = None, + ) -> NetworkStream: + return self._stream.start_tls(ssl_context, server_hostname, timeout) + + def get_extra_info(self, info: str) -> typing.Any: + return self._stream.get_extra_info(info) diff --git a/source/target-vendors/cp312/httpcore/_sync/http2.py b/source/target-vendors/cp312/httpcore/_sync/http2.py new file mode 100644 index 0000000..ddcc189 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/http2.py @@ -0,0 +1,592 @@ +from __future__ import annotations + +import enum +import logging +import time +import types +import typing + +import h2.config +import h2.connection +import h2.events +import h2.exceptions +import h2.settings + +from .._backends.base import NetworkStream +from .._exceptions import ( + ConnectionNotAvailable, + LocalProtocolError, + RemoteProtocolError, +) +from .._models import Origin, Request, Response +from .._synchronization import Lock, Semaphore, ShieldCancellation +from .._trace import Trace +from .interfaces import ConnectionInterface + +logger = logging.getLogger("httpcore.http2") + + +def has_body_headers(request: Request) -> bool: + return any( + k.lower() == b"content-length" or k.lower() == b"transfer-encoding" + for k, v in request.headers + ) + + +class HTTPConnectionState(enum.IntEnum): + ACTIVE = 1 + IDLE = 2 + CLOSED = 3 + + +class HTTP2Connection(ConnectionInterface): + READ_NUM_BYTES = 64 * 1024 + CONFIG = h2.config.H2Configuration(validate_inbound_headers=False) + + def __init__( + self, + origin: Origin, + stream: NetworkStream, + keepalive_expiry: float | None = None, + ): + self._origin = origin + self._network_stream = stream + self._keepalive_expiry: float | None = keepalive_expiry + self._h2_state = h2.connection.H2Connection(config=self.CONFIG) + self._state = HTTPConnectionState.IDLE + self._expire_at: float | None = None + self._request_count = 0 + self._init_lock = Lock() + self._state_lock = Lock() + self._read_lock = Lock() + self._write_lock = Lock() + self._sent_connection_init = False + self._used_all_stream_ids = False + self._connection_error = False + + # Mapping from stream ID to response stream events. + self._events: dict[ + int, + list[ + h2.events.ResponseReceived + | h2.events.DataReceived + | h2.events.StreamEnded + | h2.events.StreamReset, + ], + ] = {} + + # Connection terminated events are stored as state since + # we need to handle them for all streams. + self._connection_terminated: h2.events.ConnectionTerminated | None = None + + self._read_exception: Exception | None = None + self._write_exception: Exception | None = None + + def handle_request(self, request: Request) -> Response: + if not self.can_handle_request(request.url.origin): + # This cannot occur in normal operation, since the connection pool + # will only send requests on connections that handle them. + # It's in place simply for resilience as a guard against incorrect + # usage, for anyone working directly with httpcore connections. + raise RuntimeError( + f"Attempted to send request to {request.url.origin} on connection " + f"to {self._origin}" + ) + + with self._state_lock: + if self._state in (HTTPConnectionState.ACTIVE, HTTPConnectionState.IDLE): + self._request_count += 1 + self._expire_at = None + self._state = HTTPConnectionState.ACTIVE + else: + raise ConnectionNotAvailable() + + with self._init_lock: + if not self._sent_connection_init: + try: + sci_kwargs = {"request": request} + with Trace( + "send_connection_init", logger, request, sci_kwargs + ): + self._send_connection_init(**sci_kwargs) + except BaseException as exc: + with ShieldCancellation(): + self.close() + raise exc + + self._sent_connection_init = True + + # Initially start with just 1 until the remote server provides + # its max_concurrent_streams value + self._max_streams = 1 + + local_settings_max_streams = ( + self._h2_state.local_settings.max_concurrent_streams + ) + self._max_streams_semaphore = Semaphore(local_settings_max_streams) + + for _ in range(local_settings_max_streams - self._max_streams): + self._max_streams_semaphore.acquire() + + self._max_streams_semaphore.acquire() + + try: + stream_id = self._h2_state.get_next_available_stream_id() + self._events[stream_id] = [] + except h2.exceptions.NoAvailableStreamIDError: # pragma: nocover + self._used_all_stream_ids = True + self._request_count -= 1 + raise ConnectionNotAvailable() + + try: + kwargs = {"request": request, "stream_id": stream_id} + with Trace("send_request_headers", logger, request, kwargs): + self._send_request_headers(request=request, stream_id=stream_id) + with Trace("send_request_body", logger, request, kwargs): + self._send_request_body(request=request, stream_id=stream_id) + with Trace( + "receive_response_headers", logger, request, kwargs + ) as trace: + status, headers = self._receive_response( + request=request, stream_id=stream_id + ) + trace.return_value = (status, headers) + + return Response( + status=status, + headers=headers, + content=HTTP2ConnectionByteStream(self, request, stream_id=stream_id), + extensions={ + "http_version": b"HTTP/2", + "network_stream": self._network_stream, + "stream_id": stream_id, + }, + ) + except BaseException as exc: # noqa: PIE786 + with ShieldCancellation(): + kwargs = {"stream_id": stream_id} + with Trace("response_closed", logger, request, kwargs): + self._response_closed(stream_id=stream_id) + + if isinstance(exc, h2.exceptions.ProtocolError): + # One case where h2 can raise a protocol error is when a + # closed frame has been seen by the state machine. + # + # This happens when one stream is reading, and encounters + # a GOAWAY event. Other flows of control may then raise + # a protocol error at any point they interact with the 'h2_state'. + # + # In this case we'll have stored the event, and should raise + # it as a RemoteProtocolError. + if self._connection_terminated: # pragma: nocover + raise RemoteProtocolError(self._connection_terminated) + # If h2 raises a protocol error in some other state then we + # must somehow have made a protocol violation. + raise LocalProtocolError(exc) # pragma: nocover + + raise exc + + def _send_connection_init(self, request: Request) -> None: + """ + The HTTP/2 connection requires some initial setup before we can start + using individual request/response streams on it. + """ + # Need to set these manually here instead of manipulating via + # __setitem__() otherwise the H2Connection will emit SettingsUpdate + # frames in addition to sending the undesired defaults. + self._h2_state.local_settings = h2.settings.Settings( + client=True, + initial_values={ + # Disable PUSH_PROMISE frames from the server since we don't do anything + # with them for now. Maybe when we support caching? + h2.settings.SettingCodes.ENABLE_PUSH: 0, + # These two are taken from h2 for safe defaults + h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS: 100, + h2.settings.SettingCodes.MAX_HEADER_LIST_SIZE: 65536, + }, + ) + + # Some websites (*cough* Yahoo *cough*) balk at this setting being + # present in the initial handshake since it's not defined in the original + # RFC despite the RFC mandating ignoring settings you don't know about. + del self._h2_state.local_settings[ + h2.settings.SettingCodes.ENABLE_CONNECT_PROTOCOL + ] + + self._h2_state.initiate_connection() + self._h2_state.increment_flow_control_window(2**24) + self._write_outgoing_data(request) + + # Sending the request... + + def _send_request_headers(self, request: Request, stream_id: int) -> None: + """ + Send the request headers to a given stream ID. + """ + end_stream = not has_body_headers(request) + + # In HTTP/2 the ':authority' pseudo-header is used instead of 'Host'. + # In order to gracefully handle HTTP/1.1 and HTTP/2 we always require + # HTTP/1.1 style headers, and map them appropriately if we end up on + # an HTTP/2 connection. + authority = [v for k, v in request.headers if k.lower() == b"host"][0] + + headers = [ + (b":method", request.method), + (b":authority", authority), + (b":scheme", request.url.scheme), + (b":path", request.url.target), + ] + [ + (k.lower(), v) + for k, v in request.headers + if k.lower() + not in ( + b"host", + b"transfer-encoding", + ) + ] + + self._h2_state.send_headers(stream_id, headers, end_stream=end_stream) + self._h2_state.increment_flow_control_window(2**24, stream_id=stream_id) + self._write_outgoing_data(request) + + def _send_request_body(self, request: Request, stream_id: int) -> None: + """ + Iterate over the request body sending it to a given stream ID. + """ + if not has_body_headers(request): + return + + assert isinstance(request.stream, typing.Iterable) + for data in request.stream: + self._send_stream_data(request, stream_id, data) + self._send_end_stream(request, stream_id) + + def _send_stream_data( + self, request: Request, stream_id: int, data: bytes + ) -> None: + """ + Send a single chunk of data in one or more data frames. + """ + while data: + max_flow = self._wait_for_outgoing_flow(request, stream_id) + chunk_size = min(len(data), max_flow) + chunk, data = data[:chunk_size], data[chunk_size:] + self._h2_state.send_data(stream_id, chunk) + self._write_outgoing_data(request) + + def _send_end_stream(self, request: Request, stream_id: int) -> None: + """ + Send an empty data frame on on a given stream ID with the END_STREAM flag set. + """ + self._h2_state.end_stream(stream_id) + self._write_outgoing_data(request) + + # Receiving the response... + + def _receive_response( + self, request: Request, stream_id: int + ) -> tuple[int, list[tuple[bytes, bytes]]]: + """ + Return the response status code and headers for a given stream ID. + """ + while True: + event = self._receive_stream_event(request, stream_id) + if isinstance(event, h2.events.ResponseReceived): + break + + status_code = 200 + headers = [] + assert event.headers is not None + for k, v in event.headers: + if k == b":status": + status_code = int(v.decode("ascii", errors="ignore")) + elif not k.startswith(b":"): + headers.append((k, v)) + + return (status_code, headers) + + def _receive_response_body( + self, request: Request, stream_id: int + ) -> typing.Iterator[bytes]: + """ + Iterator that returns the bytes of the response body for a given stream ID. + """ + while True: + event = self._receive_stream_event(request, stream_id) + if isinstance(event, h2.events.DataReceived): + assert event.flow_controlled_length is not None + assert event.data is not None + amount = event.flow_controlled_length + self._h2_state.acknowledge_received_data(amount, stream_id) + self._write_outgoing_data(request) + yield event.data + elif isinstance(event, h2.events.StreamEnded): + break + + def _receive_stream_event( + self, request: Request, stream_id: int + ) -> h2.events.ResponseReceived | h2.events.DataReceived | h2.events.StreamEnded: + """ + Return the next available event for a given stream ID. + + Will read more data from the network if required. + """ + while not self._events.get(stream_id): + self._receive_events(request, stream_id) + event = self._events[stream_id].pop(0) + if isinstance(event, h2.events.StreamReset): + raise RemoteProtocolError(event) + return event + + def _receive_events( + self, request: Request, stream_id: int | None = None + ) -> None: + """ + Read some data from the network until we see one or more events + for a given stream ID. + """ + with self._read_lock: + if self._connection_terminated is not None: + last_stream_id = self._connection_terminated.last_stream_id + if stream_id and last_stream_id and stream_id > last_stream_id: + self._request_count -= 1 + raise ConnectionNotAvailable() + raise RemoteProtocolError(self._connection_terminated) + + # This conditional is a bit icky. We don't want to block reading if we've + # actually got an event to return for a given stream. We need to do that + # check *within* the atomic read lock. Though it also need to be optional, + # because when we call it from `_wait_for_outgoing_flow` we *do* want to + # block until we've available flow control, event when we have events + # pending for the stream ID we're attempting to send on. + if stream_id is None or not self._events.get(stream_id): + events = self._read_incoming_data(request) + for event in events: + if isinstance(event, h2.events.RemoteSettingsChanged): + with Trace( + "receive_remote_settings", logger, request + ) as trace: + self._receive_remote_settings_change(event) + trace.return_value = event + + elif isinstance( + event, + ( + h2.events.ResponseReceived, + h2.events.DataReceived, + h2.events.StreamEnded, + h2.events.StreamReset, + ), + ): + if event.stream_id in self._events: + self._events[event.stream_id].append(event) + + elif isinstance(event, h2.events.ConnectionTerminated): + self._connection_terminated = event + + self._write_outgoing_data(request) + + def _receive_remote_settings_change( + self, event: h2.events.RemoteSettingsChanged + ) -> None: + max_concurrent_streams = event.changed_settings.get( + h2.settings.SettingCodes.MAX_CONCURRENT_STREAMS + ) + if max_concurrent_streams: + new_max_streams = min( + max_concurrent_streams.new_value, + self._h2_state.local_settings.max_concurrent_streams, + ) + if new_max_streams and new_max_streams != self._max_streams: + while new_max_streams > self._max_streams: + self._max_streams_semaphore.release() + self._max_streams += 1 + while new_max_streams < self._max_streams: + self._max_streams_semaphore.acquire() + self._max_streams -= 1 + + def _response_closed(self, stream_id: int) -> None: + self._max_streams_semaphore.release() + del self._events[stream_id] + with self._state_lock: + if self._connection_terminated and not self._events: + self.close() + + elif self._state == HTTPConnectionState.ACTIVE and not self._events: + self._state = HTTPConnectionState.IDLE + if self._keepalive_expiry is not None: + now = time.monotonic() + self._expire_at = now + self._keepalive_expiry + if self._used_all_stream_ids: # pragma: nocover + self.close() + + def close(self) -> None: + # Note that this method unilaterally closes the connection, and does + # not have any kind of locking in place around it. + self._h2_state.close_connection() + self._state = HTTPConnectionState.CLOSED + self._network_stream.close() + + # Wrappers around network read/write operations... + + def _read_incoming_data(self, request: Request) -> list[h2.events.Event]: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("read", None) + + if self._read_exception is not None: + raise self._read_exception # pragma: nocover + + try: + data = self._network_stream.read(self.READ_NUM_BYTES, timeout) + if data == b"": + raise RemoteProtocolError("Server disconnected") + except Exception as exc: + # If we get a network error we should: + # + # 1. Save the exception and just raise it immediately on any future reads. + # (For example, this means that a single read timeout or disconnect will + # immediately close all pending streams. Without requiring multiple + # sequential timeouts.) + # 2. Mark the connection as errored, so that we don't accept any other + # incoming requests. + self._read_exception = exc + self._connection_error = True + raise exc + + events: list[h2.events.Event] = self._h2_state.receive_data(data) + + return events + + def _write_outgoing_data(self, request: Request) -> None: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("write", None) + + with self._write_lock: + data_to_send = self._h2_state.data_to_send() + + if self._write_exception is not None: + raise self._write_exception # pragma: nocover + + try: + self._network_stream.write(data_to_send, timeout) + except Exception as exc: # pragma: nocover + # If we get a network error we should: + # + # 1. Save the exception and just raise it immediately on any future write. + # (For example, this means that a single write timeout or disconnect will + # immediately close all pending streams. Without requiring multiple + # sequential timeouts.) + # 2. Mark the connection as errored, so that we don't accept any other + # incoming requests. + self._write_exception = exc + self._connection_error = True + raise exc + + # Flow control... + + def _wait_for_outgoing_flow(self, request: Request, stream_id: int) -> int: + """ + Returns the maximum allowable outgoing flow for a given stream. + + If the allowable flow is zero, then waits on the network until + WindowUpdated frames have increased the flow rate. + https://tools.ietf.org/html/rfc7540#section-6.9 + """ + local_flow: int = self._h2_state.local_flow_control_window(stream_id) + max_frame_size: int = self._h2_state.max_outbound_frame_size + flow = min(local_flow, max_frame_size) + while flow == 0: + self._receive_events(request) + local_flow = self._h2_state.local_flow_control_window(stream_id) + max_frame_size = self._h2_state.max_outbound_frame_size + flow = min(local_flow, max_frame_size) + return flow + + # Interface for connection pooling... + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._origin + + def is_available(self) -> bool: + return ( + self._state != HTTPConnectionState.CLOSED + and not self._connection_error + and not self._used_all_stream_ids + and not ( + self._h2_state.state_machine.state + == h2.connection.ConnectionState.CLOSED + ) + ) + + def has_expired(self) -> bool: + now = time.monotonic() + return self._expire_at is not None and now > self._expire_at + + def is_idle(self) -> bool: + return self._state == HTTPConnectionState.IDLE + + def is_closed(self) -> bool: + return self._state == HTTPConnectionState.CLOSED + + def info(self) -> str: + origin = str(self._origin) + return ( + f"{origin!r}, HTTP/2, {self._state.name}, " + f"Request Count: {self._request_count}" + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + origin = str(self._origin) + return ( + f"<{class_name} [{origin!r}, {self._state.name}, " + f"Request Count: {self._request_count}]>" + ) + + # These context managers are not used in the standard flow, but are + # useful for testing or working with connection instances directly. + + def __enter__(self) -> HTTP2Connection: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + self.close() + + +class HTTP2ConnectionByteStream: + def __init__( + self, connection: HTTP2Connection, request: Request, stream_id: int + ) -> None: + self._connection = connection + self._request = request + self._stream_id = stream_id + self._closed = False + + def __iter__(self) -> typing.Iterator[bytes]: + kwargs = {"request": self._request, "stream_id": self._stream_id} + try: + with Trace("receive_response_body", logger, self._request, kwargs): + for chunk in self._connection._receive_response_body( + request=self._request, stream_id=self._stream_id + ): + yield chunk + except BaseException as exc: + # If we get an exception while streaming the response, + # we want to close the response (and possibly the connection) + # before raising that exception. + with ShieldCancellation(): + self.close() + raise exc + + def close(self) -> None: + if not self._closed: + self._closed = True + kwargs = {"stream_id": self._stream_id} + with Trace("response_closed", logger, self._request, kwargs): + self._connection._response_closed(stream_id=self._stream_id) diff --git a/source/target-vendors/cp312/httpcore/_sync/http_proxy.py b/source/target-vendors/cp312/httpcore/_sync/http_proxy.py new file mode 100644 index 0000000..ecca88f --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/http_proxy.py @@ -0,0 +1,367 @@ +from __future__ import annotations + +import base64 +import logging +import ssl +import typing + +from .._backends.base import SOCKET_OPTION, NetworkBackend +from .._exceptions import ProxyError +from .._models import ( + URL, + Origin, + Request, + Response, + enforce_bytes, + enforce_headers, + enforce_url, +) +from .._ssl import default_ssl_context +from .._synchronization import Lock +from .._trace import Trace +from .connection import HTTPConnection +from .connection_pool import ConnectionPool +from .http11 import HTTP11Connection +from .interfaces import ConnectionInterface + +ByteOrStr = typing.Union[bytes, str] +HeadersAsSequence = typing.Sequence[typing.Tuple[ByteOrStr, ByteOrStr]] +HeadersAsMapping = typing.Mapping[ByteOrStr, ByteOrStr] + + +logger = logging.getLogger("httpcore.proxy") + + +def merge_headers( + default_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, + override_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, +) -> list[tuple[bytes, bytes]]: + """ + Append default_headers and override_headers, de-duplicating if a key exists + in both cases. + """ + default_headers = [] if default_headers is None else list(default_headers) + override_headers = [] if override_headers is None else list(override_headers) + has_override = set(key.lower() for key, value in override_headers) + default_headers = [ + (key, value) + for key, value in default_headers + if key.lower() not in has_override + ] + return default_headers + override_headers + + +class HTTPProxy(ConnectionPool): # pragma: nocover + """ + A connection pool that sends requests via an HTTP proxy. + """ + + def __init__( + self, + proxy_url: URL | bytes | str, + proxy_auth: tuple[bytes | str, bytes | str] | None = None, + proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, + ssl_context: ssl.SSLContext | None = None, + proxy_ssl_context: ssl.SSLContext | None = None, + max_connections: int | None = 10, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + local_address: str | None = None, + uds: str | None = None, + network_backend: NetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + """ + A connection pool for making HTTP requests. + + Parameters: + proxy_url: The URL to use when connecting to the proxy server. + For example `"http://127.0.0.1:8080/"`. + proxy_auth: Any proxy authentication as a two-tuple of + (username, password). May be either bytes or ascii-only str. + proxy_headers: Any HTTP headers to use for the proxy requests. + For example `{"Proxy-Authorization": "Basic :"}`. + ssl_context: An SSL context to use for verifying connections. + If not specified, the default `httpcore.default_ssl_context()` + will be used. + proxy_ssl_context: The same as `ssl_context`, but for a proxy server rather than a remote origin. + max_connections: The maximum number of concurrent HTTP connections that + the pool should allow. Any attempt to send a request on a pool that + would exceed this amount will block until a connection is available. + max_keepalive_connections: The maximum number of idle HTTP connections + that will be maintained in the pool. + keepalive_expiry: The duration in seconds that an idle HTTP connection + may be maintained for before being expired from the pool. + http1: A boolean indicating if HTTP/1.1 requests should be supported + by the connection pool. Defaults to True. + http2: A boolean indicating if HTTP/2 requests should be supported by + the connection pool. Defaults to False. + retries: The maximum number of retries when trying to establish + a connection. + local_address: Local address to connect from. Can also be used to + connect using a particular address family. Using + `local_address="0.0.0.0"` will connect using an `AF_INET` address + (IPv4), while using `local_address="::"` will connect using an + `AF_INET6` address (IPv6). + uds: Path to a Unix Domain Socket to use instead of TCP sockets. + network_backend: A backend instance to use for handling network I/O. + """ + super().__init__( + ssl_context=ssl_context, + max_connections=max_connections, + max_keepalive_connections=max_keepalive_connections, + keepalive_expiry=keepalive_expiry, + http1=http1, + http2=http2, + network_backend=network_backend, + retries=retries, + local_address=local_address, + uds=uds, + socket_options=socket_options, + ) + + self._proxy_url = enforce_url(proxy_url, name="proxy_url") + if ( + self._proxy_url.scheme == b"http" and proxy_ssl_context is not None + ): # pragma: no cover + raise RuntimeError( + "The `proxy_ssl_context` argument is not allowed for the http scheme" + ) + + self._ssl_context = ssl_context + self._proxy_ssl_context = proxy_ssl_context + self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") + if proxy_auth is not None: + username = enforce_bytes(proxy_auth[0], name="proxy_auth") + password = enforce_bytes(proxy_auth[1], name="proxy_auth") + userpass = username + b":" + password + authorization = b"Basic " + base64.b64encode(userpass) + self._proxy_headers = [ + (b"Proxy-Authorization", authorization) + ] + self._proxy_headers + + def create_connection(self, origin: Origin) -> ConnectionInterface: + if origin.scheme == b"http": + return ForwardHTTPConnection( + proxy_origin=self._proxy_url.origin, + proxy_headers=self._proxy_headers, + remote_origin=origin, + keepalive_expiry=self._keepalive_expiry, + network_backend=self._network_backend, + proxy_ssl_context=self._proxy_ssl_context, + ) + return TunnelHTTPConnection( + proxy_origin=self._proxy_url.origin, + proxy_headers=self._proxy_headers, + remote_origin=origin, + ssl_context=self._ssl_context, + proxy_ssl_context=self._proxy_ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + + +class ForwardHTTPConnection(ConnectionInterface): + def __init__( + self, + proxy_origin: Origin, + remote_origin: Origin, + proxy_headers: HeadersAsMapping | HeadersAsSequence | None = None, + keepalive_expiry: float | None = None, + network_backend: NetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + proxy_ssl_context: ssl.SSLContext | None = None, + ) -> None: + self._connection = HTTPConnection( + origin=proxy_origin, + keepalive_expiry=keepalive_expiry, + network_backend=network_backend, + socket_options=socket_options, + ssl_context=proxy_ssl_context, + ) + self._proxy_origin = proxy_origin + self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") + self._remote_origin = remote_origin + + def handle_request(self, request: Request) -> Response: + headers = merge_headers(self._proxy_headers, request.headers) + url = URL( + scheme=self._proxy_origin.scheme, + host=self._proxy_origin.host, + port=self._proxy_origin.port, + target=bytes(request.url), + ) + proxy_request = Request( + method=request.method, + url=url, + headers=headers, + content=request.stream, + extensions=request.extensions, + ) + return self._connection.handle_request(proxy_request) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._remote_origin + + def close(self) -> None: + self._connection.close() + + def info(self) -> str: + return self._connection.info() + + def is_available(self) -> bool: + return self._connection.is_available() + + def has_expired(self) -> bool: + return self._connection.has_expired() + + def is_idle(self) -> bool: + return self._connection.is_idle() + + def is_closed(self) -> bool: + return self._connection.is_closed() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" + + +class TunnelHTTPConnection(ConnectionInterface): + def __init__( + self, + proxy_origin: Origin, + remote_origin: Origin, + ssl_context: ssl.SSLContext | None = None, + proxy_ssl_context: ssl.SSLContext | None = None, + proxy_headers: typing.Sequence[tuple[bytes, bytes]] | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + network_backend: NetworkBackend | None = None, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + self._connection: ConnectionInterface = HTTPConnection( + origin=proxy_origin, + keepalive_expiry=keepalive_expiry, + network_backend=network_backend, + socket_options=socket_options, + ssl_context=proxy_ssl_context, + ) + self._proxy_origin = proxy_origin + self._remote_origin = remote_origin + self._ssl_context = ssl_context + self._proxy_ssl_context = proxy_ssl_context + self._proxy_headers = enforce_headers(proxy_headers, name="proxy_headers") + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + self._connect_lock = Lock() + self._connected = False + + def handle_request(self, request: Request) -> Response: + timeouts = request.extensions.get("timeout", {}) + timeout = timeouts.get("connect", None) + + with self._connect_lock: + if not self._connected: + target = b"%b:%d" % (self._remote_origin.host, self._remote_origin.port) + + connect_url = URL( + scheme=self._proxy_origin.scheme, + host=self._proxy_origin.host, + port=self._proxy_origin.port, + target=target, + ) + connect_headers = merge_headers( + [(b"Host", target), (b"Accept", b"*/*")], self._proxy_headers + ) + connect_request = Request( + method=b"CONNECT", + url=connect_url, + headers=connect_headers, + extensions=request.extensions, + ) + connect_response = self._connection.handle_request( + connect_request + ) + + if connect_response.status < 200 or connect_response.status > 299: + reason_bytes = connect_response.extensions.get("reason_phrase", b"") + reason_str = reason_bytes.decode("ascii", errors="ignore") + msg = "%d %s" % (connect_response.status, reason_str) + self._connection.close() + raise ProxyError(msg) + + stream = connect_response.extensions["network_stream"] + + # Upgrade the stream to SSL + ssl_context = ( + default_ssl_context() + if self._ssl_context is None + else self._ssl_context + ) + alpn_protocols = ["http/1.1", "h2"] if self._http2 else ["http/1.1"] + ssl_context.set_alpn_protocols(alpn_protocols) + + kwargs = { + "ssl_context": ssl_context, + "server_hostname": self._remote_origin.host.decode("ascii"), + "timeout": timeout, + } + with Trace("start_tls", logger, request, kwargs) as trace: + stream = stream.start_tls(**kwargs) + trace.return_value = stream + + # Determine if we should be using HTTP/1.1 or HTTP/2 + ssl_object = stream.get_extra_info("ssl_object") + http2_negotiated = ( + ssl_object is not None + and ssl_object.selected_alpn_protocol() == "h2" + ) + + # Create the HTTP/1.1 or HTTP/2 connection + if http2_negotiated or (self._http2 and not self._http1): + from .http2 import HTTP2Connection + + self._connection = HTTP2Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + else: + self._connection = HTTP11Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + + self._connected = True + return self._connection.handle_request(request) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._remote_origin + + def close(self) -> None: + self._connection.close() + + def info(self) -> str: + return self._connection.info() + + def is_available(self) -> bool: + return self._connection.is_available() + + def has_expired(self) -> bool: + return self._connection.has_expired() + + def is_idle(self) -> bool: + return self._connection.is_idle() + + def is_closed(self) -> bool: + return self._connection.is_closed() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/source/target-vendors/cp312/httpcore/_sync/interfaces.py b/source/target-vendors/cp312/httpcore/_sync/interfaces.py new file mode 100644 index 0000000..e673d4c --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/interfaces.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +import contextlib +import typing + +from .._models import ( + URL, + Extensions, + HeaderTypes, + Origin, + Request, + Response, + enforce_bytes, + enforce_headers, + enforce_url, + include_request_headers, +) + + +class RequestInterface: + def request( + self, + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes | typing.Iterator[bytes] | None = None, + extensions: Extensions | None = None, + ) -> Response: + # Strict type checking on our parameters. + method = enforce_bytes(method, name="method") + url = enforce_url(url, name="url") + headers = enforce_headers(headers, name="headers") + + # Include Host header, and optionally Content-Length or Transfer-Encoding. + headers = include_request_headers(headers, url=url, content=content) + + request = Request( + method=method, + url=url, + headers=headers, + content=content, + extensions=extensions, + ) + response = self.handle_request(request) + try: + response.read() + finally: + response.close() + return response + + @contextlib.contextmanager + def stream( + self, + method: bytes | str, + url: URL | bytes | str, + *, + headers: HeaderTypes = None, + content: bytes | typing.Iterator[bytes] | None = None, + extensions: Extensions | None = None, + ) -> typing.Iterator[Response]: + # Strict type checking on our parameters. + method = enforce_bytes(method, name="method") + url = enforce_url(url, name="url") + headers = enforce_headers(headers, name="headers") + + # Include Host header, and optionally Content-Length or Transfer-Encoding. + headers = include_request_headers(headers, url=url, content=content) + + request = Request( + method=method, + url=url, + headers=headers, + content=content, + extensions=extensions, + ) + response = self.handle_request(request) + try: + yield response + finally: + response.close() + + def handle_request(self, request: Request) -> Response: + raise NotImplementedError() # pragma: nocover + + +class ConnectionInterface(RequestInterface): + def close(self) -> None: + raise NotImplementedError() # pragma: nocover + + def info(self) -> str: + raise NotImplementedError() # pragma: nocover + + def can_handle_request(self, origin: Origin) -> bool: + raise NotImplementedError() # pragma: nocover + + def is_available(self) -> bool: + """ + Return `True` if the connection is currently able to accept an + outgoing request. + + An HTTP/1.1 connection will only be available if it is currently idle. + + An HTTP/2 connection will be available so long as the stream ID space is + not yet exhausted, and the connection is not in an error state. + + While the connection is being established we may not yet know if it is going + to result in an HTTP/1.1 or HTTP/2 connection. The connection should be + treated as being available, but might ultimately raise `NewConnectionRequired` + required exceptions if multiple requests are attempted over a connection + that ends up being established as HTTP/1.1. + """ + raise NotImplementedError() # pragma: nocover + + def has_expired(self) -> bool: + """ + Return `True` if the connection is in a state where it should be closed. + + This either means that the connection is idle and it has passed the + expiry time on its keep-alive, or that server has sent an EOF. + """ + raise NotImplementedError() # pragma: nocover + + def is_idle(self) -> bool: + """ + Return `True` if the connection is currently idle. + """ + raise NotImplementedError() # pragma: nocover + + def is_closed(self) -> bool: + """ + Return `True` if the connection has been closed. + + Used when a response is closed to determine if the connection may be + returned to the connection pool or not. + """ + raise NotImplementedError() # pragma: nocover diff --git a/source/target-vendors/cp312/httpcore/_sync/socks_proxy.py b/source/target-vendors/cp312/httpcore/_sync/socks_proxy.py new file mode 100644 index 0000000..0ca96dd --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_sync/socks_proxy.py @@ -0,0 +1,341 @@ +from __future__ import annotations + +import logging +import ssl + +import socksio + +from .._backends.sync import SyncBackend +from .._backends.base import NetworkBackend, NetworkStream +from .._exceptions import ConnectionNotAvailable, ProxyError +from .._models import URL, Origin, Request, Response, enforce_bytes, enforce_url +from .._ssl import default_ssl_context +from .._synchronization import Lock +from .._trace import Trace +from .connection_pool import ConnectionPool +from .http11 import HTTP11Connection +from .interfaces import ConnectionInterface + +logger = logging.getLogger("httpcore.socks") + + +AUTH_METHODS = { + b"\x00": "NO AUTHENTICATION REQUIRED", + b"\x01": "GSSAPI", + b"\x02": "USERNAME/PASSWORD", + b"\xff": "NO ACCEPTABLE METHODS", +} + +REPLY_CODES = { + b"\x00": "Succeeded", + b"\x01": "General SOCKS server failure", + b"\x02": "Connection not allowed by ruleset", + b"\x03": "Network unreachable", + b"\x04": "Host unreachable", + b"\x05": "Connection refused", + b"\x06": "TTL expired", + b"\x07": "Command not supported", + b"\x08": "Address type not supported", +} + + +def _init_socks5_connection( + stream: NetworkStream, + *, + host: bytes, + port: int, + auth: tuple[bytes, bytes] | None = None, +) -> None: + conn = socksio.socks5.SOCKS5Connection() + + # Auth method request + auth_method = ( + socksio.socks5.SOCKS5AuthMethod.NO_AUTH_REQUIRED + if auth is None + else socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD + ) + conn.send(socksio.socks5.SOCKS5AuthMethodsRequest([auth_method])) + outgoing_bytes = conn.data_to_send() + stream.write(outgoing_bytes) + + # Auth method response + incoming_bytes = stream.read(max_bytes=4096) + response = conn.receive_data(incoming_bytes) + assert isinstance(response, socksio.socks5.SOCKS5AuthReply) + if response.method != auth_method: + requested = AUTH_METHODS.get(auth_method, "UNKNOWN") + responded = AUTH_METHODS.get(response.method, "UNKNOWN") + raise ProxyError( + f"Requested {requested} from proxy server, but got {responded}." + ) + + if response.method == socksio.socks5.SOCKS5AuthMethod.USERNAME_PASSWORD: + # Username/password request + assert auth is not None + username, password = auth + conn.send(socksio.socks5.SOCKS5UsernamePasswordRequest(username, password)) + outgoing_bytes = conn.data_to_send() + stream.write(outgoing_bytes) + + # Username/password response + incoming_bytes = stream.read(max_bytes=4096) + response = conn.receive_data(incoming_bytes) + assert isinstance(response, socksio.socks5.SOCKS5UsernamePasswordReply) + if not response.success: + raise ProxyError("Invalid username/password") + + # Connect request + conn.send( + socksio.socks5.SOCKS5CommandRequest.from_address( + socksio.socks5.SOCKS5Command.CONNECT, (host, port) + ) + ) + outgoing_bytes = conn.data_to_send() + stream.write(outgoing_bytes) + + # Connect response + incoming_bytes = stream.read(max_bytes=4096) + response = conn.receive_data(incoming_bytes) + assert isinstance(response, socksio.socks5.SOCKS5Reply) + if response.reply_code != socksio.socks5.SOCKS5ReplyCode.SUCCEEDED: + reply_code = REPLY_CODES.get(response.reply_code, "UNKOWN") + raise ProxyError(f"Proxy Server could not connect: {reply_code}.") + + +class SOCKSProxy(ConnectionPool): # pragma: nocover + """ + A connection pool that sends requests via an HTTP proxy. + """ + + def __init__( + self, + proxy_url: URL | bytes | str, + proxy_auth: tuple[bytes | str, bytes | str] | None = None, + ssl_context: ssl.SSLContext | None = None, + max_connections: int | None = 10, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + retries: int = 0, + network_backend: NetworkBackend | None = None, + ) -> None: + """ + A connection pool for making HTTP requests. + + Parameters: + proxy_url: The URL to use when connecting to the proxy server. + For example `"http://127.0.0.1:8080/"`. + ssl_context: An SSL context to use for verifying connections. + If not specified, the default `httpcore.default_ssl_context()` + will be used. + max_connections: The maximum number of concurrent HTTP connections that + the pool should allow. Any attempt to send a request on a pool that + would exceed this amount will block until a connection is available. + max_keepalive_connections: The maximum number of idle HTTP connections + that will be maintained in the pool. + keepalive_expiry: The duration in seconds that an idle HTTP connection + may be maintained for before being expired from the pool. + http1: A boolean indicating if HTTP/1.1 requests should be supported + by the connection pool. Defaults to True. + http2: A boolean indicating if HTTP/2 requests should be supported by + the connection pool. Defaults to False. + retries: The maximum number of retries when trying to establish + a connection. + local_address: Local address to connect from. Can also be used to + connect using a particular address family. Using + `local_address="0.0.0.0"` will connect using an `AF_INET` address + (IPv4), while using `local_address="::"` will connect using an + `AF_INET6` address (IPv6). + uds: Path to a Unix Domain Socket to use instead of TCP sockets. + network_backend: A backend instance to use for handling network I/O. + """ + super().__init__( + ssl_context=ssl_context, + max_connections=max_connections, + max_keepalive_connections=max_keepalive_connections, + keepalive_expiry=keepalive_expiry, + http1=http1, + http2=http2, + network_backend=network_backend, + retries=retries, + ) + self._ssl_context = ssl_context + self._proxy_url = enforce_url(proxy_url, name="proxy_url") + if proxy_auth is not None: + username, password = proxy_auth + username_bytes = enforce_bytes(username, name="proxy_auth") + password_bytes = enforce_bytes(password, name="proxy_auth") + self._proxy_auth: tuple[bytes, bytes] | None = ( + username_bytes, + password_bytes, + ) + else: + self._proxy_auth = None + + def create_connection(self, origin: Origin) -> ConnectionInterface: + return Socks5Connection( + proxy_origin=self._proxy_url.origin, + remote_origin=origin, + proxy_auth=self._proxy_auth, + ssl_context=self._ssl_context, + keepalive_expiry=self._keepalive_expiry, + http1=self._http1, + http2=self._http2, + network_backend=self._network_backend, + ) + + +class Socks5Connection(ConnectionInterface): + def __init__( + self, + proxy_origin: Origin, + remote_origin: Origin, + proxy_auth: tuple[bytes, bytes] | None = None, + ssl_context: ssl.SSLContext | None = None, + keepalive_expiry: float | None = None, + http1: bool = True, + http2: bool = False, + network_backend: NetworkBackend | None = None, + ) -> None: + self._proxy_origin = proxy_origin + self._remote_origin = remote_origin + self._proxy_auth = proxy_auth + self._ssl_context = ssl_context + self._keepalive_expiry = keepalive_expiry + self._http1 = http1 + self._http2 = http2 + + self._network_backend: NetworkBackend = ( + SyncBackend() if network_backend is None else network_backend + ) + self._connect_lock = Lock() + self._connection: ConnectionInterface | None = None + self._connect_failed = False + + def handle_request(self, request: Request) -> Response: + timeouts = request.extensions.get("timeout", {}) + sni_hostname = request.extensions.get("sni_hostname", None) + timeout = timeouts.get("connect", None) + + with self._connect_lock: + if self._connection is None: + try: + # Connect to the proxy + kwargs = { + "host": self._proxy_origin.host.decode("ascii"), + "port": self._proxy_origin.port, + "timeout": timeout, + } + with Trace("connect_tcp", logger, request, kwargs) as trace: + stream = self._network_backend.connect_tcp(**kwargs) + trace.return_value = stream + + # Connect to the remote host using socks5 + kwargs = { + "stream": stream, + "host": self._remote_origin.host.decode("ascii"), + "port": self._remote_origin.port, + "auth": self._proxy_auth, + } + with Trace( + "setup_socks5_connection", logger, request, kwargs + ) as trace: + _init_socks5_connection(**kwargs) + trace.return_value = stream + + # Upgrade the stream to SSL + if self._remote_origin.scheme == b"https": + ssl_context = ( + default_ssl_context() + if self._ssl_context is None + else self._ssl_context + ) + alpn_protocols = ( + ["http/1.1", "h2"] if self._http2 else ["http/1.1"] + ) + ssl_context.set_alpn_protocols(alpn_protocols) + + kwargs = { + "ssl_context": ssl_context, + "server_hostname": sni_hostname + or self._remote_origin.host.decode("ascii"), + "timeout": timeout, + } + with Trace("start_tls", logger, request, kwargs) as trace: + stream = stream.start_tls(**kwargs) + trace.return_value = stream + + # Determine if we should be using HTTP/1.1 or HTTP/2 + ssl_object = stream.get_extra_info("ssl_object") + http2_negotiated = ( + ssl_object is not None + and ssl_object.selected_alpn_protocol() == "h2" + ) + + # Create the HTTP/1.1 or HTTP/2 connection + if http2_negotiated or ( + self._http2 and not self._http1 + ): # pragma: nocover + from .http2 import HTTP2Connection + + self._connection = HTTP2Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + else: + self._connection = HTTP11Connection( + origin=self._remote_origin, + stream=stream, + keepalive_expiry=self._keepalive_expiry, + ) + except Exception as exc: + self._connect_failed = True + raise exc + elif not self._connection.is_available(): # pragma: nocover + raise ConnectionNotAvailable() + + return self._connection.handle_request(request) + + def can_handle_request(self, origin: Origin) -> bool: + return origin == self._remote_origin + + def close(self) -> None: + if self._connection is not None: + self._connection.close() + + def is_available(self) -> bool: + if self._connection is None: # pragma: nocover + # If HTTP/2 support is enabled, and the resulting connection could + # end up as HTTP/2 then we should indicate the connection as being + # available to service multiple requests. + return ( + self._http2 + and (self._remote_origin.scheme == b"https" or not self._http1) + and not self._connect_failed + ) + return self._connection.is_available() + + def has_expired(self) -> bool: + if self._connection is None: # pragma: nocover + return self._connect_failed + return self._connection.has_expired() + + def is_idle(self) -> bool: + if self._connection is None: # pragma: nocover + return self._connect_failed + return self._connection.is_idle() + + def is_closed(self) -> bool: + if self._connection is None: # pragma: nocover + return self._connect_failed + return self._connection.is_closed() + + def info(self) -> str: + if self._connection is None: # pragma: nocover + return "CONNECTION FAILED" if self._connect_failed else "CONNECTING" + return self._connection.info() + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} [{self.info()}]>" diff --git a/source/target-vendors/cp312/httpcore/_synchronization.py b/source/target-vendors/cp312/httpcore/_synchronization.py new file mode 100644 index 0000000..2ecc9e9 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_synchronization.py @@ -0,0 +1,318 @@ +from __future__ import annotations + +import threading +import types + +from ._exceptions import ExceptionMapping, PoolTimeout, map_exceptions + +# Our async synchronization primatives use either 'anyio' or 'trio' depending +# on if they're running under asyncio or trio. + +try: + import trio +except (ImportError, NotImplementedError): # pragma: nocover + trio = None # type: ignore + +try: + import anyio +except ImportError: # pragma: nocover + anyio = None # type: ignore + + +def current_async_library() -> str: + # Determine if we're running under trio or asyncio. + # See https://sniffio.readthedocs.io/en/latest/ + try: + import sniffio + except ImportError: # pragma: nocover + environment = "asyncio" + else: + environment = sniffio.current_async_library() + + if environment not in ("asyncio", "trio"): # pragma: nocover + raise RuntimeError("Running under an unsupported async environment.") + + if environment == "asyncio" and anyio is None: # pragma: nocover + raise RuntimeError( + "Running with asyncio requires installation of 'httpcore[asyncio]'." + ) + + if environment == "trio" and trio is None: # pragma: nocover + raise RuntimeError( + "Running with trio requires installation of 'httpcore[trio]'." + ) + + return environment + + +class AsyncLock: + """ + This is a standard lock. + + In the sync case `Lock` provides thread locking. + In the async case `AsyncLock` provides async locking. + """ + + def __init__(self) -> None: + self._backend = "" + + def setup(self) -> None: + """ + Detect if we're running under 'asyncio' or 'trio' and create + a lock with the correct implementation. + """ + self._backend = current_async_library() + if self._backend == "trio": + self._trio_lock = trio.Lock() + elif self._backend == "asyncio": + self._anyio_lock = anyio.Lock() + + async def __aenter__(self) -> AsyncLock: + if not self._backend: + self.setup() + + if self._backend == "trio": + await self._trio_lock.acquire() + elif self._backend == "asyncio": + await self._anyio_lock.acquire() + + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + if self._backend == "trio": + self._trio_lock.release() + elif self._backend == "asyncio": + self._anyio_lock.release() + + +class AsyncThreadLock: + """ + This is a threading-only lock for no-I/O contexts. + + In the sync case `ThreadLock` provides thread locking. + In the async case `AsyncThreadLock` is a no-op. + """ + + def __enter__(self) -> AsyncThreadLock: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + pass + + +class AsyncEvent: + def __init__(self) -> None: + self._backend = "" + + def setup(self) -> None: + """ + Detect if we're running under 'asyncio' or 'trio' and create + a lock with the correct implementation. + """ + self._backend = current_async_library() + if self._backend == "trio": + self._trio_event = trio.Event() + elif self._backend == "asyncio": + self._anyio_event = anyio.Event() + + def set(self) -> None: + if not self._backend: + self.setup() + + if self._backend == "trio": + self._trio_event.set() + elif self._backend == "asyncio": + self._anyio_event.set() + + async def wait(self, timeout: float | None = None) -> None: + if not self._backend: + self.setup() + + if self._backend == "trio": + trio_exc_map: ExceptionMapping = {trio.TooSlowError: PoolTimeout} + timeout_or_inf = float("inf") if timeout is None else timeout + with map_exceptions(trio_exc_map): + with trio.fail_after(timeout_or_inf): + await self._trio_event.wait() + elif self._backend == "asyncio": + anyio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout} + with map_exceptions(anyio_exc_map): + with anyio.fail_after(timeout): + await self._anyio_event.wait() + + +class AsyncSemaphore: + def __init__(self, bound: int) -> None: + self._bound = bound + self._backend = "" + + def setup(self) -> None: + """ + Detect if we're running under 'asyncio' or 'trio' and create + a semaphore with the correct implementation. + """ + self._backend = current_async_library() + if self._backend == "trio": + self._trio_semaphore = trio.Semaphore( + initial_value=self._bound, max_value=self._bound + ) + elif self._backend == "asyncio": + self._anyio_semaphore = anyio.Semaphore( + initial_value=self._bound, max_value=self._bound + ) + + async def acquire(self) -> None: + if not self._backend: + self.setup() + + if self._backend == "trio": + await self._trio_semaphore.acquire() + elif self._backend == "asyncio": + await self._anyio_semaphore.acquire() + + async def release(self) -> None: + if self._backend == "trio": + self._trio_semaphore.release() + elif self._backend == "asyncio": + self._anyio_semaphore.release() + + +class AsyncShieldCancellation: + # For certain portions of our codebase where we're dealing with + # closing connections during exception handling we want to shield + # the operation from being cancelled. + # + # with AsyncShieldCancellation(): + # ... # clean-up operations, shielded from cancellation. + + def __init__(self) -> None: + """ + Detect if we're running under 'asyncio' or 'trio' and create + a shielded scope with the correct implementation. + """ + self._backend = current_async_library() + + if self._backend == "trio": + self._trio_shield = trio.CancelScope(shield=True) + elif self._backend == "asyncio": + self._anyio_shield = anyio.CancelScope(shield=True) + + def __enter__(self) -> AsyncShieldCancellation: + if self._backend == "trio": + self._trio_shield.__enter__() + elif self._backend == "asyncio": + self._anyio_shield.__enter__() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + if self._backend == "trio": + self._trio_shield.__exit__(exc_type, exc_value, traceback) + elif self._backend == "asyncio": + self._anyio_shield.__exit__(exc_type, exc_value, traceback) + + +# Our thread-based synchronization primitives... + + +class Lock: + """ + This is a standard lock. + + In the sync case `Lock` provides thread locking. + In the async case `AsyncLock` provides async locking. + """ + + def __init__(self) -> None: + self._lock = threading.Lock() + + def __enter__(self) -> Lock: + self._lock.acquire() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + self._lock.release() + + +class ThreadLock: + """ + This is a threading-only lock for no-I/O contexts. + + In the sync case `ThreadLock` provides thread locking. + In the async case `AsyncThreadLock` is a no-op. + """ + + def __init__(self) -> None: + self._lock = threading.Lock() + + def __enter__(self) -> ThreadLock: + self._lock.acquire() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + self._lock.release() + + +class Event: + def __init__(self) -> None: + self._event = threading.Event() + + def set(self) -> None: + self._event.set() + + def wait(self, timeout: float | None = None) -> None: + if timeout == float("inf"): # pragma: no cover + timeout = None + if not self._event.wait(timeout=timeout): + raise PoolTimeout() # pragma: nocover + + +class Semaphore: + def __init__(self, bound: int) -> None: + self._semaphore = threading.Semaphore(value=bound) + + def acquire(self) -> None: + self._semaphore.acquire() + + def release(self) -> None: + self._semaphore.release() + + +class ShieldCancellation: + # Thread-synchronous codebases don't support cancellation semantics. + # We have this class because we need to mirror the async and sync + # cases within our package, but it's just a no-op. + def __enter__(self) -> ShieldCancellation: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + pass diff --git a/source/target-vendors/cp312/httpcore/_trace.py b/source/target-vendors/cp312/httpcore/_trace.py new file mode 100644 index 0000000..5f1cd7c --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_trace.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +import inspect +import logging +import types +import typing + +from ._models import Request + + +class Trace: + def __init__( + self, + name: str, + logger: logging.Logger, + request: Request | None = None, + kwargs: dict[str, typing.Any] | None = None, + ) -> None: + self.name = name + self.logger = logger + self.trace_extension = ( + None if request is None else request.extensions.get("trace") + ) + self.debug = self.logger.isEnabledFor(logging.DEBUG) + self.kwargs = kwargs or {} + self.return_value: typing.Any = None + self.should_trace = self.debug or self.trace_extension is not None + self.prefix = self.logger.name.split(".")[-1] + + def trace(self, name: str, info: dict[str, typing.Any]) -> None: + if self.trace_extension is not None: + prefix_and_name = f"{self.prefix}.{name}" + ret = self.trace_extension(prefix_and_name, info) + if inspect.iscoroutine(ret): # pragma: no cover + raise TypeError( + "If you are using a synchronous interface, " + "the callback of the `trace` extension should " + "be a normal function instead of an asynchronous function." + ) + + if self.debug: + if not info or "return_value" in info and info["return_value"] is None: + message = name + else: + args = " ".join([f"{key}={value!r}" for key, value in info.items()]) + message = f"{name} {args}" + self.logger.debug(message) + + def __enter__(self) -> Trace: + if self.should_trace: + info = self.kwargs + self.trace(f"{self.name}.started", info) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + if self.should_trace: + if exc_value is None: + info = {"return_value": self.return_value} + self.trace(f"{self.name}.complete", info) + else: + info = {"exception": exc_value} + self.trace(f"{self.name}.failed", info) + + async def atrace(self, name: str, info: dict[str, typing.Any]) -> None: + if self.trace_extension is not None: + prefix_and_name = f"{self.prefix}.{name}" + coro = self.trace_extension(prefix_and_name, info) + if not inspect.iscoroutine(coro): # pragma: no cover + raise TypeError( + "If you're using an asynchronous interface, " + "the callback of the `trace` extension should " + "be an asynchronous function rather than a normal function." + ) + await coro + + if self.debug: + if not info or "return_value" in info and info["return_value"] is None: + message = name + else: + args = " ".join([f"{key}={value!r}" for key, value in info.items()]) + message = f"{name} {args}" + self.logger.debug(message) + + async def __aenter__(self) -> Trace: + if self.should_trace: + info = self.kwargs + await self.atrace(f"{self.name}.started", info) + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: types.TracebackType | None = None, + ) -> None: + if self.should_trace: + if exc_value is None: + info = {"return_value": self.return_value} + await self.atrace(f"{self.name}.complete", info) + else: + info = {"exception": exc_value} + await self.atrace(f"{self.name}.failed", info) diff --git a/source/target-vendors/cp312/httpcore/_utils.py b/source/target-vendors/cp312/httpcore/_utils.py new file mode 100644 index 0000000..c44ff93 --- /dev/null +++ b/source/target-vendors/cp312/httpcore/_utils.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import select +import socket +import sys + + +def is_socket_readable(sock: socket.socket | None) -> bool: + """ + Return whether a socket, as identifed by its file descriptor, is readable. + "A socket is readable" means that the read buffer isn't empty, i.e. that calling + .recv() on it would immediately return some data. + """ + # NOTE: we want check for readability without actually attempting to read, because + # we don't want to block forever if it's not readable. + + # In the case that the socket no longer exists, or cannot return a file + # descriptor, we treat it as being readable, as if it the next read operation + # on it is ready to return the terminating `b""`. + sock_fd = None if sock is None else sock.fileno() + if sock_fd is None or sock_fd < 0: # pragma: nocover + return True + + # The implementation below was stolen from: + # https://github.com/python-trio/trio/blob/20ee2b1b7376db637435d80e266212a35837ddcc/trio/_socket.py#L471-L478 + # See also: https://github.com/encode/httpcore/pull/193#issuecomment-703129316 + + # Use select.select on Windows, and when poll is unavailable and select.poll + # everywhere else. (E.g. When eventlet is in use. See #327) + if ( + sys.platform == "win32" or getattr(select, "poll", None) is None + ): # pragma: nocover + rready, _, _ = select.select([sock_fd], [], [], 0) + return bool(rready) + p = select.poll() + p.register(sock_fd, select.POLLIN) + return bool(p.poll(0)) diff --git a/source/target-vendors/cp312/httpcore/py.typed b/source/target-vendors/cp312/httpcore/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/httpx-0.28.1.dist-info/METADATA b/source/target-vendors/cp312/httpx-0.28.1.dist-info/METADATA new file mode 100644 index 0000000..b0d2b19 --- /dev/null +++ b/source/target-vendors/cp312/httpx-0.28.1.dist-info/METADATA @@ -0,0 +1,203 @@ +Metadata-Version: 2.3 +Name: httpx +Version: 0.28.1 +Summary: The next generation HTTP client. +Project-URL: Changelog, https://github.com/encode/httpx/blob/master/CHANGELOG.md +Project-URL: Documentation, https://www.python-httpx.org +Project-URL: Homepage, https://github.com/encode/httpx +Project-URL: Source, https://github.com/encode/httpx +Author-email: Tom Christie +License: BSD-3-Clause +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: Framework :: AsyncIO +Classifier: Framework :: Trio +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.8 +Requires-Dist: anyio +Requires-Dist: certifi +Requires-Dist: httpcore==1.* +Requires-Dist: idna +Provides-Extra: brotli +Requires-Dist: brotli; (platform_python_implementation == 'CPython') and extra == 'brotli' +Requires-Dist: brotlicffi; (platform_python_implementation != 'CPython') and extra == 'brotli' +Provides-Extra: cli +Requires-Dist: click==8.*; extra == 'cli' +Requires-Dist: pygments==2.*; extra == 'cli' +Requires-Dist: rich<14,>=10; extra == 'cli' +Provides-Extra: http2 +Requires-Dist: h2<5,>=3; extra == 'http2' +Provides-Extra: socks +Requires-Dist: socksio==1.*; extra == 'socks' +Provides-Extra: zstd +Requires-Dist: zstandard>=0.18.0; extra == 'zstd' +Description-Content-Type: text/markdown + +

      + HTTPX +

      + +

      HTTPX - A next-generation HTTP client for Python.

      + +

      + + Test Suite + + + Package version + +

      + +HTTPX is a fully featured HTTP client library for Python 3. It includes **an integrated command line client**, has support for both **HTTP/1.1 and HTTP/2**, and provides both **sync and async APIs**. + +--- + +Install HTTPX using pip: + +```shell +$ pip install httpx +``` + +Now, let's get started: + +```pycon +>>> import httpx +>>> r = httpx.get('https://www.example.org/') +>>> r + +>>> r.status_code +200 +>>> r.headers['content-type'] +'text/html; charset=UTF-8' +>>> r.text +'\n\n\nExample Domain...' +``` + +Or, using the command-line client. + +```shell +$ pip install 'httpx[cli]' # The command line client is an optional dependency. +``` + +Which now allows us to use HTTPX directly from the command-line... + +

      + httpx --help +

      + +Sending a request... + +

      + httpx http://httpbin.org/json +

      + +## Features + +HTTPX builds on the well-established usability of `requests`, and gives you: + +* A broadly [requests-compatible API](https://www.python-httpx.org/compatibility/). +* An integrated command-line client. +* HTTP/1.1 [and HTTP/2 support](https://www.python-httpx.org/http2/). +* Standard synchronous interface, but with [async support if you need it](https://www.python-httpx.org/async/). +* Ability to make requests directly to [WSGI applications](https://www.python-httpx.org/advanced/transports/#wsgi-transport) or [ASGI applications](https://www.python-httpx.org/advanced/transports/#asgi-transport). +* Strict timeouts everywhere. +* Fully type annotated. +* 100% test coverage. + +Plus all the standard features of `requests`... + +* International Domains and URLs +* Keep-Alive & Connection Pooling +* Sessions with Cookie Persistence +* Browser-style SSL Verification +* Basic/Digest Authentication +* Elegant Key/Value Cookies +* Automatic Decompression +* Automatic Content Decoding +* Unicode Response Bodies +* Multipart File Uploads +* HTTP(S) Proxy Support +* Connection Timeouts +* Streaming Downloads +* .netrc Support +* Chunked Requests + +## Installation + +Install with pip: + +```shell +$ pip install httpx +``` + +Or, to include the optional HTTP/2 support, use: + +```shell +$ pip install httpx[http2] +``` + +HTTPX requires Python 3.8+. + +## Documentation + +Project documentation is available at [https://www.python-httpx.org/](https://www.python-httpx.org/). + +For a run-through of all the basics, head over to the [QuickStart](https://www.python-httpx.org/quickstart/). + +For more advanced topics, see the [Advanced Usage](https://www.python-httpx.org/advanced/) section, the [async support](https://www.python-httpx.org/async/) section, or the [HTTP/2](https://www.python-httpx.org/http2/) section. + +The [Developer Interface](https://www.python-httpx.org/api/) provides a comprehensive API reference. + +To find out about tools that integrate with HTTPX, see [Third Party Packages](https://www.python-httpx.org/third_party_packages/). + +## Contribute + +If you want to contribute with HTTPX check out the [Contributing Guide](https://www.python-httpx.org/contributing/) to learn how to start. + +## Dependencies + +The HTTPX project relies on these excellent libraries: + +* `httpcore` - The underlying transport implementation for `httpx`. + * `h11` - HTTP/1.1 support. +* `certifi` - SSL certificates. +* `idna` - Internationalized domain name support. +* `sniffio` - Async library autodetection. + +As well as these optional installs: + +* `h2` - HTTP/2 support. *(Optional, with `httpx[http2]`)* +* `socksio` - SOCKS proxy support. *(Optional, with `httpx[socks]`)* +* `rich` - Rich terminal support. *(Optional, with `httpx[cli]`)* +* `click` - Command line client support. *(Optional, with `httpx[cli]`)* +* `brotli` or `brotlicffi` - Decoding for "brotli" compressed responses. *(Optional, with `httpx[brotli]`)* +* `zstandard` - Decoding for "zstd" compressed responses. *(Optional, with `httpx[zstd]`)* + +A huge amount of credit is due to `requests` for the API layout that +much of this work follows, as well as to `urllib3` for plenty of design +inspiration around the lower-level networking details. + +--- + +

      HTTPX is BSD licensed code.
      Designed & crafted with care.

      — 🦋 —

      + +## Release Information + +### Fixed + +* Reintroduced supposedly-private `URLTypes` shortcut. (#2673) + + +--- + +[Full changelog](https://github.com/encode/httpx/blob/master/CHANGELOG.md) diff --git a/source/target-vendors/cp312/httpx-0.28.1.dist-info/RECORD b/source/target-vendors/cp312/httpx-0.28.1.dist-info/RECORD new file mode 100644 index 0000000..eecd0e7 --- /dev/null +++ b/source/target-vendors/cp312/httpx-0.28.1.dist-info/RECORD @@ -0,0 +1,29 @@ +httpx/__init__.py,sha256=CsaZe6yZj0rHg6322AWKWHGTMVr9txgEfD5P3_Rrz60,2171 +httpx/__version__.py,sha256=LoUyYeOXTieGzuP_64UL0wxdtxjuu_QbOvE7NOg-IqU,108 +httpx/_api.py,sha256=r_Zgs4jIpcPJLqK5dbbSayqo_iVMKFaxZCd-oOHxLEs,11743 +httpx/_auth.py,sha256=Yr3QwaUSK17rGYx-7j-FdicFIzz4Y9FFV-1F4-7RXX4,11891 +httpx/_client.py,sha256=xD-UG67-WMkeltAAOeGGj-cZ2RRTAm19sWRxlFY7_40,65714 +httpx/_config.py,sha256=pPp2U-wicfcKsF-KYRE1LYdt3e6ERGeIoXZ8Gjo3LWc,8547 +httpx/_content.py,sha256=LGGzrJTR3OvN4Mb1GVVNLXkXJH-6oKlwAttO9p5w_yg,8161 +httpx/_decoders.py,sha256=p0dX8I0NEHexs3UGp4SsZutiMhsXrrWl6-GnqVb0iKM,12041 +httpx/_exceptions.py,sha256=bxW7fxzgVMAdNTbwT0Vnq04gJDW1_gI_GFiQPuMyjL0,8527 +httpx/_main.py,sha256=Cg9GMabiTT_swaDfUgIRitSwxLRMSwUDOm7LdSGqlA4,15626 +httpx/_models.py,sha256=4__Guyv1gLxuZChwim8kfQNiIOcJ9acreFOSurvZfms,44700 +httpx/_multipart.py,sha256=KOHEZZl6oohg9mPaKyyu345qq1rJLg35TUG3YAzXB3Y,9843 +httpx/_status_codes.py,sha256=DYn-2ufBgMeXy5s8x3_TB7wjAuAAMewTakPrm5rXEsc,5639 +httpx/_types.py,sha256=Jyh41GQq7AOev8IOWKDAg7zCbvHAfufmW5g_PiTtErY,2965 +httpx/_urlparse.py,sha256=ZAmH47ONfkxrrj-PPYhGeiHjb6AjKCS-ANWIN4OL_KY,18546 +httpx/_urls.py,sha256=dX99VR1DSOHpgo9Aq7PzYO4FKdxqKjwyNp8grf8dHN0,21550 +httpx/_utils.py,sha256=_TVeqAKvxJkKHdz7dFeb4s0LZqQXgeFkXSgfiHBK_1o,8285 +httpx/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +httpx/_transports/__init__.py,sha256=GbUoBSAOp7z-l-9j5YhMhR3DMIcn6FVLhj072O3Nnno,275 +httpx/_transports/asgi.py,sha256=HRfiDYMPt4wQH2gFgHZg4c-i3sblo6bL5GTqcET-xz8,5501 +httpx/_transports/base.py,sha256=kZS_VMbViYfF570pogUCJ1bulz-ybfL51Pqs9yktebU,2523 +httpx/_transports/default.py,sha256=AzeaRUyVwCccTyyNJexDf0n1dFfzzydpdIQgvw7PLnk,13983 +httpx/_transports/mock.py,sha256=PTo0d567RITXxGrki6kN7_67wwAxfwiMDcuXJiZCjEo,1232 +httpx/_transports/wsgi.py,sha256=NcPX3Xap_EwCFZWO_OaSyQNuInCYx1QMNbO8GAei6jY,4825 +httpx-0.28.1.dist-info/METADATA,sha256=_rubD48-gNV8gZnDBPNcQzboWB0dGNeYPJJ2a4J5OyU,7052 +httpx-0.28.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87 +httpx-0.28.1.dist-info/entry_points.txt,sha256=2lVkdQmxLA1pNMgSN2eV89o90HCZezhmNwsy6ryKDSA,37 +httpx-0.28.1.dist-info/licenses/LICENSE.md,sha256=TsWdVE8StfU5o6cW_TIaxYzNgDC0ZSIfLIgCAM3yjY0,1508 +httpx-0.28.1.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/httpx-0.28.1.dist-info/WHEEL b/source/target-vendors/cp312/httpx-0.28.1.dist-info/WHEEL new file mode 100644 index 0000000..21aaa72 --- /dev/null +++ b/source/target-vendors/cp312/httpx-0.28.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.26.3 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/httpx-0.28.1.dist-info/entry_points.txt b/source/target-vendors/cp312/httpx-0.28.1.dist-info/entry_points.txt new file mode 100644 index 0000000..8ae9600 --- /dev/null +++ b/source/target-vendors/cp312/httpx-0.28.1.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +httpx = httpx:main diff --git a/source/target-vendors/cp312/httpx-0.28.1.dist-info/licenses/LICENSE.md b/source/target-vendors/cp312/httpx-0.28.1.dist-info/licenses/LICENSE.md new file mode 100644 index 0000000..ab79d16 --- /dev/null +++ b/source/target-vendors/cp312/httpx-0.28.1.dist-info/licenses/LICENSE.md @@ -0,0 +1,12 @@ +Copyright © 2019, [Encode OSS Ltd](https://www.encode.io/). +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/httpx/__init__.py b/source/target-vendors/cp312/httpx/__init__.py new file mode 100644 index 0000000..e9addde --- /dev/null +++ b/source/target-vendors/cp312/httpx/__init__.py @@ -0,0 +1,105 @@ +from .__version__ import __description__, __title__, __version__ +from ._api import * +from ._auth import * +from ._client import * +from ._config import * +from ._content import * +from ._exceptions import * +from ._models import * +from ._status_codes import * +from ._transports import * +from ._types import * +from ._urls import * + +try: + from ._main import main +except ImportError: # pragma: no cover + + def main() -> None: # type: ignore + import sys + + print( + "The httpx command line client could not run because the required " + "dependencies were not installed.\nMake sure you've installed " + "everything with: pip install 'httpx[cli]'" + ) + sys.exit(1) + + +__all__ = [ + "__description__", + "__title__", + "__version__", + "ASGITransport", + "AsyncBaseTransport", + "AsyncByteStream", + "AsyncClient", + "AsyncHTTPTransport", + "Auth", + "BaseTransport", + "BasicAuth", + "ByteStream", + "Client", + "CloseError", + "codes", + "ConnectError", + "ConnectTimeout", + "CookieConflict", + "Cookies", + "create_ssl_context", + "DecodingError", + "delete", + "DigestAuth", + "get", + "head", + "Headers", + "HTTPError", + "HTTPStatusError", + "HTTPTransport", + "InvalidURL", + "Limits", + "LocalProtocolError", + "main", + "MockTransport", + "NetRCAuth", + "NetworkError", + "options", + "patch", + "PoolTimeout", + "post", + "ProtocolError", + "Proxy", + "ProxyError", + "put", + "QueryParams", + "ReadError", + "ReadTimeout", + "RemoteProtocolError", + "request", + "Request", + "RequestError", + "RequestNotRead", + "Response", + "ResponseNotRead", + "stream", + "StreamClosed", + "StreamConsumed", + "StreamError", + "SyncByteStream", + "Timeout", + "TimeoutException", + "TooManyRedirects", + "TransportError", + "UnsupportedProtocol", + "URL", + "USE_CLIENT_DEFAULT", + "WriteError", + "WriteTimeout", + "WSGITransport", +] + + +__locals = locals() +for __name in __all__: + if not __name.startswith("__"): + setattr(__locals[__name], "__module__", "httpx") # noqa diff --git a/source/target-vendors/cp312/httpx/__version__.py b/source/target-vendors/cp312/httpx/__version__.py new file mode 100644 index 0000000..801bfac --- /dev/null +++ b/source/target-vendors/cp312/httpx/__version__.py @@ -0,0 +1,3 @@ +__title__ = "httpx" +__description__ = "A next generation HTTP client, for Python 3." +__version__ = "0.28.1" diff --git a/source/target-vendors/cp312/httpx/_api.py b/source/target-vendors/cp312/httpx/_api.py new file mode 100644 index 0000000..c3cda1e --- /dev/null +++ b/source/target-vendors/cp312/httpx/_api.py @@ -0,0 +1,438 @@ +from __future__ import annotations + +import typing +from contextlib import contextmanager + +from ._client import Client +from ._config import DEFAULT_TIMEOUT_CONFIG +from ._models import Response +from ._types import ( + AuthTypes, + CookieTypes, + HeaderTypes, + ProxyTypes, + QueryParamTypes, + RequestContent, + RequestData, + RequestFiles, + TimeoutTypes, +) +from ._urls import URL + +if typing.TYPE_CHECKING: + import ssl # pragma: no cover + + +__all__ = [ + "delete", + "get", + "head", + "options", + "patch", + "post", + "put", + "request", + "stream", +] + + +def request( + method: str, + url: URL | str, + *, + params: QueryParamTypes | None = None, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + trust_env: bool = True, +) -> Response: + """ + Sends an HTTP request. + + **Parameters:** + + * **method** - HTTP method for the new `Request` object: `GET`, `OPTIONS`, + `HEAD`, `POST`, `PUT`, `PATCH`, or `DELETE`. + * **url** - URL for the new `Request` object. + * **params** - *(optional)* Query parameters to include in the URL, as a + string, dictionary, or sequence of two-tuples. + * **content** - *(optional)* Binary content to include in the body of the + request, as bytes or a byte iterator. + * **data** - *(optional)* Form data to include in the body of the request, + as a dictionary. + * **files** - *(optional)* A dictionary of upload files to include in the + body of the request. + * **json** - *(optional)* A JSON serializable object to include in the body + of the request. + * **headers** - *(optional)* Dictionary of HTTP headers to include in the + request. + * **cookies** - *(optional)* Dictionary of Cookie items to include in the + request. + * **auth** - *(optional)* An authentication class to use when sending the + request. + * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. + * **timeout** - *(optional)* The timeout configuration to use when sending + the request. + * **follow_redirects** - *(optional)* Enables or disables HTTP redirects. + * **verify** - *(optional)* Either `True` to use an SSL context with the + default CA bundle, `False` to disable verification, or an instance of + `ssl.SSLContext` to use a custom context. + * **trust_env** - *(optional)* Enables or disables usage of environment + variables for configuration. + + **Returns:** `Response` + + Usage: + + ``` + >>> import httpx + >>> response = httpx.request('GET', 'https://httpbin.org/get') + >>> response + + ``` + """ + with Client( + cookies=cookies, + proxy=proxy, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) as client: + return client.request( + method=method, + url=url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + auth=auth, + follow_redirects=follow_redirects, + ) + + +@contextmanager +def stream( + method: str, + url: URL | str, + *, + params: QueryParamTypes | None = None, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + trust_env: bool = True, +) -> typing.Iterator[Response]: + """ + Alternative to `httpx.request()` that streams the response body + instead of loading it into memory at once. + + **Parameters**: See `httpx.request`. + + See also: [Streaming Responses][0] + + [0]: /quickstart#streaming-responses + """ + with Client( + cookies=cookies, + proxy=proxy, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) as client: + with client.stream( + method=method, + url=url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + auth=auth, + follow_redirects=follow_redirects, + ) as response: + yield response + + +def get( + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + trust_env: bool = True, +) -> Response: + """ + Sends a `GET` request. + + **Parameters**: See `httpx.request`. + + Note that the `data`, `files`, `json` and `content` parameters are not available + on this function, as `GET` requests should not include a request body. + """ + return request( + "GET", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) + + +def options( + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + trust_env: bool = True, +) -> Response: + """ + Sends an `OPTIONS` request. + + **Parameters**: See `httpx.request`. + + Note that the `data`, `files`, `json` and `content` parameters are not available + on this function, as `OPTIONS` requests should not include a request body. + """ + return request( + "OPTIONS", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) + + +def head( + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + trust_env: bool = True, +) -> Response: + """ + Sends a `HEAD` request. + + **Parameters**: See `httpx.request`. + + Note that the `data`, `files`, `json` and `content` parameters are not available + on this function, as `HEAD` requests should not include a request body. + """ + return request( + "HEAD", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) + + +def post( + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + trust_env: bool = True, +) -> Response: + """ + Sends a `POST` request. + + **Parameters**: See `httpx.request`. + """ + return request( + "POST", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) + + +def put( + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + trust_env: bool = True, +) -> Response: + """ + Sends a `PUT` request. + + **Parameters**: See `httpx.request`. + """ + return request( + "PUT", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) + + +def patch( + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + verify: ssl.SSLContext | str | bool = True, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + trust_env: bool = True, +) -> Response: + """ + Sends a `PATCH` request. + + **Parameters**: See `httpx.request`. + """ + return request( + "PATCH", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) + + +def delete( + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | None = None, + proxy: ProxyTypes | None = None, + follow_redirects: bool = False, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + verify: ssl.SSLContext | str | bool = True, + trust_env: bool = True, +) -> Response: + """ + Sends a `DELETE` request. + + **Parameters**: See `httpx.request`. + + Note that the `data`, `files`, `json` and `content` parameters are not available + on this function, as `DELETE` requests should not include a request body. + """ + return request( + "DELETE", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + proxy=proxy, + follow_redirects=follow_redirects, + verify=verify, + timeout=timeout, + trust_env=trust_env, + ) diff --git a/source/target-vendors/cp312/httpx/_auth.py b/source/target-vendors/cp312/httpx/_auth.py new file mode 100644 index 0000000..b03971a --- /dev/null +++ b/source/target-vendors/cp312/httpx/_auth.py @@ -0,0 +1,348 @@ +from __future__ import annotations + +import hashlib +import os +import re +import time +import typing +from base64 import b64encode +from urllib.request import parse_http_list + +from ._exceptions import ProtocolError +from ._models import Cookies, Request, Response +from ._utils import to_bytes, to_str, unquote + +if typing.TYPE_CHECKING: # pragma: no cover + from hashlib import _Hash + + +__all__ = ["Auth", "BasicAuth", "DigestAuth", "NetRCAuth"] + + +class Auth: + """ + Base class for all authentication schemes. + + To implement a custom authentication scheme, subclass `Auth` and override + the `.auth_flow()` method. + + If the authentication scheme does I/O such as disk access or network calls, or uses + synchronization primitives such as locks, you should override `.sync_auth_flow()` + and/or `.async_auth_flow()` instead of `.auth_flow()` to provide specialized + implementations that will be used by `Client` and `AsyncClient` respectively. + """ + + requires_request_body = False + requires_response_body = False + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + """ + Execute the authentication flow. + + To dispatch a request, `yield` it: + + ``` + yield request + ``` + + The client will `.send()` the response back into the flow generator. You can + access it like so: + + ``` + response = yield request + ``` + + A `return` (or reaching the end of the generator) will result in the + client returning the last response obtained from the server. + + You can dispatch as many requests as is necessary. + """ + yield request + + def sync_auth_flow( + self, request: Request + ) -> typing.Generator[Request, Response, None]: + """ + Execute the authentication flow synchronously. + + By default, this defers to `.auth_flow()`. You should override this method + when the authentication scheme does I/O and/or uses concurrency primitives. + """ + if self.requires_request_body: + request.read() + + flow = self.auth_flow(request) + request = next(flow) + + while True: + response = yield request + if self.requires_response_body: + response.read() + + try: + request = flow.send(response) + except StopIteration: + break + + async def async_auth_flow( + self, request: Request + ) -> typing.AsyncGenerator[Request, Response]: + """ + Execute the authentication flow asynchronously. + + By default, this defers to `.auth_flow()`. You should override this method + when the authentication scheme does I/O and/or uses concurrency primitives. + """ + if self.requires_request_body: + await request.aread() + + flow = self.auth_flow(request) + request = next(flow) + + while True: + response = yield request + if self.requires_response_body: + await response.aread() + + try: + request = flow.send(response) + except StopIteration: + break + + +class FunctionAuth(Auth): + """ + Allows the 'auth' argument to be passed as a simple callable function, + that takes the request, and returns a new, modified request. + """ + + def __init__(self, func: typing.Callable[[Request], Request]) -> None: + self._func = func + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + yield self._func(request) + + +class BasicAuth(Auth): + """ + Allows the 'auth' argument to be passed as a (username, password) pair, + and uses HTTP Basic authentication. + """ + + def __init__(self, username: str | bytes, password: str | bytes) -> None: + self._auth_header = self._build_auth_header(username, password) + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + request.headers["Authorization"] = self._auth_header + yield request + + def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str: + userpass = b":".join((to_bytes(username), to_bytes(password))) + token = b64encode(userpass).decode() + return f"Basic {token}" + + +class NetRCAuth(Auth): + """ + Use a 'netrc' file to lookup basic auth credentials based on the url host. + """ + + def __init__(self, file: str | None = None) -> None: + # Lazily import 'netrc'. + # There's no need for us to load this module unless 'NetRCAuth' is being used. + import netrc + + self._netrc_info = netrc.netrc(file) + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + auth_info = self._netrc_info.authenticators(request.url.host) + if auth_info is None or not auth_info[2]: + # The netrc file did not have authentication credentials for this host. + yield request + else: + # Build a basic auth header with credentials from the netrc file. + request.headers["Authorization"] = self._build_auth_header( + username=auth_info[0], password=auth_info[2] + ) + yield request + + def _build_auth_header(self, username: str | bytes, password: str | bytes) -> str: + userpass = b":".join((to_bytes(username), to_bytes(password))) + token = b64encode(userpass).decode() + return f"Basic {token}" + + +class DigestAuth(Auth): + _ALGORITHM_TO_HASH_FUNCTION: dict[str, typing.Callable[[bytes], _Hash]] = { + "MD5": hashlib.md5, + "MD5-SESS": hashlib.md5, + "SHA": hashlib.sha1, + "SHA-SESS": hashlib.sha1, + "SHA-256": hashlib.sha256, + "SHA-256-SESS": hashlib.sha256, + "SHA-512": hashlib.sha512, + "SHA-512-SESS": hashlib.sha512, + } + + def __init__(self, username: str | bytes, password: str | bytes) -> None: + self._username = to_bytes(username) + self._password = to_bytes(password) + self._last_challenge: _DigestAuthChallenge | None = None + self._nonce_count = 1 + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + if self._last_challenge: + request.headers["Authorization"] = self._build_auth_header( + request, self._last_challenge + ) + + response = yield request + + if response.status_code != 401 or "www-authenticate" not in response.headers: + # If the response is not a 401 then we don't + # need to build an authenticated request. + return + + for auth_header in response.headers.get_list("www-authenticate"): + if auth_header.lower().startswith("digest "): + break + else: + # If the response does not include a 'WWW-Authenticate: Digest ...' + # header, then we don't need to build an authenticated request. + return + + self._last_challenge = self._parse_challenge(request, response, auth_header) + self._nonce_count = 1 + + request.headers["Authorization"] = self._build_auth_header( + request, self._last_challenge + ) + if response.cookies: + Cookies(response.cookies).set_cookie_header(request=request) + yield request + + def _parse_challenge( + self, request: Request, response: Response, auth_header: str + ) -> _DigestAuthChallenge: + """ + Returns a challenge from a Digest WWW-Authenticate header. + These take the form of: + `Digest realm="realm@host.com",qop="auth,auth-int",nonce="abc",opaque="xyz"` + """ + scheme, _, fields = auth_header.partition(" ") + + # This method should only ever have been called with a Digest auth header. + assert scheme.lower() == "digest" + + header_dict: dict[str, str] = {} + for field in parse_http_list(fields): + key, value = field.strip().split("=", 1) + header_dict[key] = unquote(value) + + try: + realm = header_dict["realm"].encode() + nonce = header_dict["nonce"].encode() + algorithm = header_dict.get("algorithm", "MD5") + opaque = header_dict["opaque"].encode() if "opaque" in header_dict else None + qop = header_dict["qop"].encode() if "qop" in header_dict else None + return _DigestAuthChallenge( + realm=realm, nonce=nonce, algorithm=algorithm, opaque=opaque, qop=qop + ) + except KeyError as exc: + message = "Malformed Digest WWW-Authenticate header" + raise ProtocolError(message, request=request) from exc + + def _build_auth_header( + self, request: Request, challenge: _DigestAuthChallenge + ) -> str: + hash_func = self._ALGORITHM_TO_HASH_FUNCTION[challenge.algorithm.upper()] + + def digest(data: bytes) -> bytes: + return hash_func(data).hexdigest().encode() + + A1 = b":".join((self._username, challenge.realm, self._password)) + + path = request.url.raw_path + A2 = b":".join((request.method.encode(), path)) + # TODO: implement auth-int + HA2 = digest(A2) + + nc_value = b"%08x" % self._nonce_count + cnonce = self._get_client_nonce(self._nonce_count, challenge.nonce) + self._nonce_count += 1 + + HA1 = digest(A1) + if challenge.algorithm.lower().endswith("-sess"): + HA1 = digest(b":".join((HA1, challenge.nonce, cnonce))) + + qop = self._resolve_qop(challenge.qop, request=request) + if qop is None: + # Following RFC 2069 + digest_data = [HA1, challenge.nonce, HA2] + else: + # Following RFC 2617/7616 + digest_data = [HA1, challenge.nonce, nc_value, cnonce, qop, HA2] + + format_args = { + "username": self._username, + "realm": challenge.realm, + "nonce": challenge.nonce, + "uri": path, + "response": digest(b":".join(digest_data)), + "algorithm": challenge.algorithm.encode(), + } + if challenge.opaque: + format_args["opaque"] = challenge.opaque + if qop: + format_args["qop"] = b"auth" + format_args["nc"] = nc_value + format_args["cnonce"] = cnonce + + return "Digest " + self._get_header_value(format_args) + + def _get_client_nonce(self, nonce_count: int, nonce: bytes) -> bytes: + s = str(nonce_count).encode() + s += nonce + s += time.ctime().encode() + s += os.urandom(8) + + return hashlib.sha1(s).hexdigest()[:16].encode() + + def _get_header_value(self, header_fields: dict[str, bytes]) -> str: + NON_QUOTED_FIELDS = ("algorithm", "qop", "nc") + QUOTED_TEMPLATE = '{}="{}"' + NON_QUOTED_TEMPLATE = "{}={}" + + header_value = "" + for i, (field, value) in enumerate(header_fields.items()): + if i > 0: + header_value += ", " + template = ( + QUOTED_TEMPLATE + if field not in NON_QUOTED_FIELDS + else NON_QUOTED_TEMPLATE + ) + header_value += template.format(field, to_str(value)) + + return header_value + + def _resolve_qop(self, qop: bytes | None, request: Request) -> bytes | None: + if qop is None: + return None + qops = re.split(b", ?", qop) + if b"auth" in qops: + return b"auth" + + if qops == [b"auth-int"]: + raise NotImplementedError("Digest auth-int support is not yet implemented") + + message = f'Unexpected qop value "{qop!r}" in digest auth' + raise ProtocolError(message, request=request) + + +class _DigestAuthChallenge(typing.NamedTuple): + realm: bytes + nonce: bytes + algorithm: str + opaque: bytes | None + qop: bytes | None diff --git a/source/target-vendors/cp312/httpx/_client.py b/source/target-vendors/cp312/httpx/_client.py new file mode 100644 index 0000000..2249231 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_client.py @@ -0,0 +1,2019 @@ +from __future__ import annotations + +import datetime +import enum +import logging +import time +import typing +import warnings +from contextlib import asynccontextmanager, contextmanager +from types import TracebackType + +from .__version__ import __version__ +from ._auth import Auth, BasicAuth, FunctionAuth +from ._config import ( + DEFAULT_LIMITS, + DEFAULT_MAX_REDIRECTS, + DEFAULT_TIMEOUT_CONFIG, + Limits, + Proxy, + Timeout, +) +from ._decoders import SUPPORTED_DECODERS +from ._exceptions import ( + InvalidURL, + RemoteProtocolError, + TooManyRedirects, + request_context, +) +from ._models import Cookies, Headers, Request, Response +from ._status_codes import codes +from ._transports.base import AsyncBaseTransport, BaseTransport +from ._transports.default import AsyncHTTPTransport, HTTPTransport +from ._types import ( + AsyncByteStream, + AuthTypes, + CertTypes, + CookieTypes, + HeaderTypes, + ProxyTypes, + QueryParamTypes, + RequestContent, + RequestData, + RequestExtensions, + RequestFiles, + SyncByteStream, + TimeoutTypes, +) +from ._urls import URL, QueryParams +from ._utils import URLPattern, get_environment_proxies + +if typing.TYPE_CHECKING: + import ssl # pragma: no cover + +__all__ = ["USE_CLIENT_DEFAULT", "AsyncClient", "Client"] + +# The type annotation for @classmethod and context managers here follows PEP 484 +# https://www.python.org/dev/peps/pep-0484/#annotating-instance-and-class-methods +T = typing.TypeVar("T", bound="Client") +U = typing.TypeVar("U", bound="AsyncClient") + + +def _is_https_redirect(url: URL, location: URL) -> bool: + """ + Return 'True' if 'location' is a HTTPS upgrade of 'url' + """ + if url.host != location.host: + return False + + return ( + url.scheme == "http" + and _port_or_default(url) == 80 + and location.scheme == "https" + and _port_or_default(location) == 443 + ) + + +def _port_or_default(url: URL) -> int | None: + if url.port is not None: + return url.port + return {"http": 80, "https": 443}.get(url.scheme) + + +def _same_origin(url: URL, other: URL) -> bool: + """ + Return 'True' if the given URLs share the same origin. + """ + return ( + url.scheme == other.scheme + and url.host == other.host + and _port_or_default(url) == _port_or_default(other) + ) + + +class UseClientDefault: + """ + For some parameters such as `auth=...` and `timeout=...` we need to be able + to indicate the default "unset" state, in a way that is distinctly different + to using `None`. + + The default "unset" state indicates that whatever default is set on the + client should be used. This is different to setting `None`, which + explicitly disables the parameter, possibly overriding a client default. + + For example we use `timeout=USE_CLIENT_DEFAULT` in the `request()` signature. + Omitting the `timeout` parameter will send a request using whatever default + timeout has been configured on the client. Including `timeout=None` will + ensure no timeout is used. + + Note that user code shouldn't need to use the `USE_CLIENT_DEFAULT` constant, + but it is used internally when a parameter is not included. + """ + + +USE_CLIENT_DEFAULT = UseClientDefault() + + +logger = logging.getLogger("httpx") + +USER_AGENT = f"python-httpx/{__version__}" +ACCEPT_ENCODING = ", ".join( + [key for key in SUPPORTED_DECODERS.keys() if key != "identity"] +) + + +class ClientState(enum.Enum): + # UNOPENED: + # The client has been instantiated, but has not been used to send a request, + # or been opened by entering the context of a `with` block. + UNOPENED = 1 + # OPENED: + # The client has either sent a request, or is within a `with` block. + OPENED = 2 + # CLOSED: + # The client has either exited the `with` block, or `close()` has + # been called explicitly. + CLOSED = 3 + + +class BoundSyncStream(SyncByteStream): + """ + A byte stream that is bound to a given response instance, and that + ensures the `response.elapsed` is set once the response is closed. + """ + + def __init__( + self, stream: SyncByteStream, response: Response, start: float + ) -> None: + self._stream = stream + self._response = response + self._start = start + + def __iter__(self) -> typing.Iterator[bytes]: + for chunk in self._stream: + yield chunk + + def close(self) -> None: + elapsed = time.perf_counter() - self._start + self._response.elapsed = datetime.timedelta(seconds=elapsed) + self._stream.close() + + +class BoundAsyncStream(AsyncByteStream): + """ + An async byte stream that is bound to a given response instance, and that + ensures the `response.elapsed` is set once the response is closed. + """ + + def __init__( + self, stream: AsyncByteStream, response: Response, start: float + ) -> None: + self._stream = stream + self._response = response + self._start = start + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + async for chunk in self._stream: + yield chunk + + async def aclose(self) -> None: + elapsed = time.perf_counter() - self._start + self._response.elapsed = datetime.timedelta(seconds=elapsed) + await self._stream.aclose() + + +EventHook = typing.Callable[..., typing.Any] + + +class BaseClient: + def __init__( + self, + *, + auth: AuthTypes | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + follow_redirects: bool = False, + max_redirects: int = DEFAULT_MAX_REDIRECTS, + event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, + base_url: URL | str = "", + trust_env: bool = True, + default_encoding: str | typing.Callable[[bytes], str] = "utf-8", + ) -> None: + event_hooks = {} if event_hooks is None else event_hooks + + self._base_url = self._enforce_trailing_slash(URL(base_url)) + + self._auth = self._build_auth(auth) + self._params = QueryParams(params) + self.headers = Headers(headers) + self._cookies = Cookies(cookies) + self._timeout = Timeout(timeout) + self.follow_redirects = follow_redirects + self.max_redirects = max_redirects + self._event_hooks = { + "request": list(event_hooks.get("request", [])), + "response": list(event_hooks.get("response", [])), + } + self._trust_env = trust_env + self._default_encoding = default_encoding + self._state = ClientState.UNOPENED + + @property + def is_closed(self) -> bool: + """ + Check if the client being closed + """ + return self._state == ClientState.CLOSED + + @property + def trust_env(self) -> bool: + return self._trust_env + + def _enforce_trailing_slash(self, url: URL) -> URL: + if url.raw_path.endswith(b"/"): + return url + return url.copy_with(raw_path=url.raw_path + b"/") + + def _get_proxy_map( + self, proxy: ProxyTypes | None, allow_env_proxies: bool + ) -> dict[str, Proxy | None]: + if proxy is None: + if allow_env_proxies: + return { + key: None if url is None else Proxy(url=url) + for key, url in get_environment_proxies().items() + } + return {} + else: + proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy + return {"all://": proxy} + + @property + def timeout(self) -> Timeout: + return self._timeout + + @timeout.setter + def timeout(self, timeout: TimeoutTypes) -> None: + self._timeout = Timeout(timeout) + + @property + def event_hooks(self) -> dict[str, list[EventHook]]: + return self._event_hooks + + @event_hooks.setter + def event_hooks(self, event_hooks: dict[str, list[EventHook]]) -> None: + self._event_hooks = { + "request": list(event_hooks.get("request", [])), + "response": list(event_hooks.get("response", [])), + } + + @property + def auth(self) -> Auth | None: + """ + Authentication class used when none is passed at the request-level. + + See also [Authentication][0]. + + [0]: /quickstart/#authentication + """ + return self._auth + + @auth.setter + def auth(self, auth: AuthTypes) -> None: + self._auth = self._build_auth(auth) + + @property + def base_url(self) -> URL: + """ + Base URL to use when sending requests with relative URLs. + """ + return self._base_url + + @base_url.setter + def base_url(self, url: URL | str) -> None: + self._base_url = self._enforce_trailing_slash(URL(url)) + + @property + def headers(self) -> Headers: + """ + HTTP headers to include when sending requests. + """ + return self._headers + + @headers.setter + def headers(self, headers: HeaderTypes) -> None: + client_headers = Headers( + { + b"Accept": b"*/*", + b"Accept-Encoding": ACCEPT_ENCODING.encode("ascii"), + b"Connection": b"keep-alive", + b"User-Agent": USER_AGENT.encode("ascii"), + } + ) + client_headers.update(headers) + self._headers = client_headers + + @property + def cookies(self) -> Cookies: + """ + Cookie values to include when sending requests. + """ + return self._cookies + + @cookies.setter + def cookies(self, cookies: CookieTypes) -> None: + self._cookies = Cookies(cookies) + + @property + def params(self) -> QueryParams: + """ + Query parameters to include in the URL when sending requests. + """ + return self._params + + @params.setter + def params(self, params: QueryParamTypes) -> None: + self._params = QueryParams(params) + + def build_request( + self, + method: str, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Request: + """ + Build and return a request instance. + + * The `params`, `headers` and `cookies` arguments + are merged with any values set on the client. + * The `url` argument is merged with any `base_url` set on the client. + + See also: [Request instances][0] + + [0]: /advanced/clients/#request-instances + """ + url = self._merge_url(url) + headers = self._merge_headers(headers) + cookies = self._merge_cookies(cookies) + params = self._merge_queryparams(params) + extensions = {} if extensions is None else extensions + if "timeout" not in extensions: + timeout = ( + self.timeout + if isinstance(timeout, UseClientDefault) + else Timeout(timeout) + ) + extensions = dict(**extensions, timeout=timeout.as_dict()) + return Request( + method, + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + extensions=extensions, + ) + + def _merge_url(self, url: URL | str) -> URL: + """ + Merge a URL argument together with any 'base_url' on the client, + to create the URL used for the outgoing request. + """ + merge_url = URL(url) + if merge_url.is_relative_url: + # To merge URLs we always append to the base URL. To get this + # behaviour correct we always ensure the base URL ends in a '/' + # separator, and strip any leading '/' from the merge URL. + # + # So, eg... + # + # >>> client = Client(base_url="https://www.example.com/subpath") + # >>> client.base_url + # URL('https://www.example.com/subpath/') + # >>> client.build_request("GET", "/path").url + # URL('https://www.example.com/subpath/path') + merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") + return self.base_url.copy_with(raw_path=merge_raw_path) + return merge_url + + def _merge_cookies(self, cookies: CookieTypes | None = None) -> CookieTypes | None: + """ + Merge a cookies argument together with any cookies on the client, + to create the cookies used for the outgoing request. + """ + if cookies or self.cookies: + merged_cookies = Cookies(self.cookies) + merged_cookies.update(cookies) + return merged_cookies + return cookies + + def _merge_headers(self, headers: HeaderTypes | None = None) -> HeaderTypes | None: + """ + Merge a headers argument together with any headers on the client, + to create the headers used for the outgoing request. + """ + merged_headers = Headers(self.headers) + merged_headers.update(headers) + return merged_headers + + def _merge_queryparams( + self, params: QueryParamTypes | None = None + ) -> QueryParamTypes | None: + """ + Merge a queryparams argument together with any queryparams on the client, + to create the queryparams used for the outgoing request. + """ + if params or self.params: + merged_queryparams = QueryParams(self.params) + return merged_queryparams.merge(params) + return params + + def _build_auth(self, auth: AuthTypes | None) -> Auth | None: + if auth is None: + return None + elif isinstance(auth, tuple): + return BasicAuth(username=auth[0], password=auth[1]) + elif isinstance(auth, Auth): + return auth + elif callable(auth): + return FunctionAuth(func=auth) + else: + raise TypeError(f'Invalid "auth" argument: {auth!r}') + + def _build_request_auth( + self, + request: Request, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + ) -> Auth: + auth = ( + self._auth if isinstance(auth, UseClientDefault) else self._build_auth(auth) + ) + + if auth is not None: + return auth + + username, password = request.url.username, request.url.password + if username or password: + return BasicAuth(username=username, password=password) + + return Auth() + + def _build_redirect_request(self, request: Request, response: Response) -> Request: + """ + Given a request and a redirect response, return a new request that + should be used to effect the redirect. + """ + method = self._redirect_method(request, response) + url = self._redirect_url(request, response) + headers = self._redirect_headers(request, url, method) + stream = self._redirect_stream(request, method) + cookies = Cookies(self.cookies) + return Request( + method=method, + url=url, + headers=headers, + cookies=cookies, + stream=stream, + extensions=request.extensions, + ) + + def _redirect_method(self, request: Request, response: Response) -> str: + """ + When being redirected we may want to change the method of the request + based on certain specs or browser behavior. + """ + method = request.method + + # https://tools.ietf.org/html/rfc7231#section-6.4.4 + if response.status_code == codes.SEE_OTHER and method != "HEAD": + method = "GET" + + # Do what the browsers do, despite standards... + # Turn 302s into GETs. + if response.status_code == codes.FOUND and method != "HEAD": + method = "GET" + + # If a POST is responded to with a 301, turn it into a GET. + # This bizarre behaviour is explained in 'requests' issue 1704. + if response.status_code == codes.MOVED_PERMANENTLY and method == "POST": + method = "GET" + + return method + + def _redirect_url(self, request: Request, response: Response) -> URL: + """ + Return the URL for the redirect to follow. + """ + location = response.headers["Location"] + + try: + url = URL(location) + except InvalidURL as exc: + raise RemoteProtocolError( + f"Invalid URL in location header: {exc}.", request=request + ) from None + + # Handle malformed 'Location' headers that are "absolute" form, have no host. + # See: https://github.com/encode/httpx/issues/771 + if url.scheme and not url.host: + url = url.copy_with(host=request.url.host) + + # Facilitate relative 'Location' headers, as allowed by RFC 7231. + # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') + if url.is_relative_url: + url = request.url.join(url) + + # Attach previous fragment if needed (RFC 7231 7.1.2) + if request.url.fragment and not url.fragment: + url = url.copy_with(fragment=request.url.fragment) + + return url + + def _redirect_headers(self, request: Request, url: URL, method: str) -> Headers: + """ + Return the headers that should be used for the redirect request. + """ + headers = Headers(request.headers) + + if not _same_origin(url, request.url): + if not _is_https_redirect(request.url, url): + # Strip Authorization headers when responses are redirected + # away from the origin. (Except for direct HTTP to HTTPS redirects.) + headers.pop("Authorization", None) + + # Update the Host header. + headers["Host"] = url.netloc.decode("ascii") + + if method != request.method and method == "GET": + # If we've switch to a 'GET' request, then strip any headers which + # are only relevant to the request body. + headers.pop("Content-Length", None) + headers.pop("Transfer-Encoding", None) + + # We should use the client cookie store to determine any cookie header, + # rather than whatever was on the original outgoing request. + headers.pop("Cookie", None) + + return headers + + def _redirect_stream( + self, request: Request, method: str + ) -> SyncByteStream | AsyncByteStream | None: + """ + Return the body that should be used for the redirect request. + """ + if method != request.method and method == "GET": + return None + + return request.stream + + def _set_timeout(self, request: Request) -> None: + if "timeout" not in request.extensions: + timeout = ( + self.timeout + if isinstance(self.timeout, UseClientDefault) + else Timeout(self.timeout) + ) + request.extensions = dict(**request.extensions, timeout=timeout.as_dict()) + + +class Client(BaseClient): + """ + An HTTP client, with connection pooling, HTTP/2, redirects, cookie persistence, etc. + + It can be shared between threads. + + Usage: + + ```python + >>> client = httpx.Client() + >>> response = client.get('https://example.org') + ``` + + **Parameters:** + + * **auth** - *(optional)* An authentication class to use when sending + requests. + * **params** - *(optional)* Query parameters to include in request URLs, as + a string, dictionary, or sequence of two-tuples. + * **headers** - *(optional)* Dictionary of HTTP headers to include when + sending requests. + * **cookies** - *(optional)* Dictionary of Cookie items to include when + sending requests. + * **verify** - *(optional)* Either `True` to use an SSL context with the + default CA bundle, `False` to disable verification, or an instance of + `ssl.SSLContext` to use a custom context. + * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be + enabled. Defaults to `False`. + * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. + * **timeout** - *(optional)* The timeout configuration to use when sending + requests. + * **limits** - *(optional)* The limits configuration to use. + * **max_redirects** - *(optional)* The maximum number of redirect responses + that should be followed. + * **base_url** - *(optional)* A URL to use as the base when building + request URLs. + * **transport** - *(optional)* A transport class to use for sending requests + over the network. + * **trust_env** - *(optional)* Enables or disables usage of environment + variables for configuration. + * **default_encoding** - *(optional)* The default encoding to use for decoding + response text, if no charset information is included in a response Content-Type + header. Set to a callable for automatic character set detection. Default: "utf-8". + """ + + def __init__( + self, + *, + auth: AuthTypes | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + proxy: ProxyTypes | None = None, + mounts: None | (typing.Mapping[str, BaseTransport | None]) = None, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + follow_redirects: bool = False, + limits: Limits = DEFAULT_LIMITS, + max_redirects: int = DEFAULT_MAX_REDIRECTS, + event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, + base_url: URL | str = "", + transport: BaseTransport | None = None, + default_encoding: str | typing.Callable[[bytes], str] = "utf-8", + ) -> None: + super().__init__( + auth=auth, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + follow_redirects=follow_redirects, + max_redirects=max_redirects, + event_hooks=event_hooks, + base_url=base_url, + trust_env=trust_env, + default_encoding=default_encoding, + ) + + if http2: + try: + import h2 # noqa + except ImportError: # pragma: no cover + raise ImportError( + "Using http2=True, but the 'h2' package is not installed. " + "Make sure to install httpx using `pip install httpx[http2]`." + ) from None + + allow_env_proxies = trust_env and transport is None + proxy_map = self._get_proxy_map(proxy, allow_env_proxies) + + self._transport = self._init_transport( + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + transport=transport, + ) + self._mounts: dict[URLPattern, BaseTransport | None] = { + URLPattern(key): None + if proxy is None + else self._init_proxy_transport( + proxy, + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + ) + for key, proxy in proxy_map.items() + } + if mounts is not None: + self._mounts.update( + {URLPattern(key): transport for key, transport in mounts.items()} + ) + + self._mounts = dict(sorted(self._mounts.items())) + + def _init_transport( + self, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + limits: Limits = DEFAULT_LIMITS, + transport: BaseTransport | None = None, + ) -> BaseTransport: + if transport is not None: + return transport + + return HTTPTransport( + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + ) + + def _init_proxy_transport( + self, + proxy: Proxy, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + limits: Limits = DEFAULT_LIMITS, + ) -> BaseTransport: + return HTTPTransport( + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + proxy=proxy, + ) + + def _transport_for_url(self, url: URL) -> BaseTransport: + """ + Returns the transport instance that should be used for a given URL. + This will either be the standard connection pool, or a proxy. + """ + for pattern, transport in self._mounts.items(): + if pattern.matches(url): + return self._transport if transport is None else transport + + return self._transport + + def request( + self, + method: str, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Build and send a request. + + Equivalent to: + + ```python + request = client.build_request(...) + response = client.send(request, ...) + ``` + + See `Client.build_request()`, `Client.send()` and + [Merging of configuration][0] for how the various parameters + are merged with client-level configuration. + + [0]: /advanced/clients/#merging-of-configuration + """ + if cookies is not None: + message = ( + "Setting per-request cookies=<...> is being deprecated, because " + "the expected behaviour on cookie persistence is ambiguous. Set " + "cookies directly on the client instance instead." + ) + warnings.warn(message, DeprecationWarning, stacklevel=2) + + request = self.build_request( + method=method, + url=url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + extensions=extensions, + ) + return self.send(request, auth=auth, follow_redirects=follow_redirects) + + @contextmanager + def stream( + self, + method: str, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> typing.Iterator[Response]: + """ + Alternative to `httpx.request()` that streams the response body + instead of loading it into memory at once. + + **Parameters**: See `httpx.request`. + + See also: [Streaming Responses][0] + + [0]: /quickstart#streaming-responses + """ + request = self.build_request( + method=method, + url=url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + extensions=extensions, + ) + response = self.send( + request=request, + auth=auth, + follow_redirects=follow_redirects, + stream=True, + ) + try: + yield response + finally: + response.close() + + def send( + self, + request: Request, + *, + stream: bool = False, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + ) -> Response: + """ + Send a request. + + The request is sent as-is, unmodified. + + Typically you'll want to build one with `Client.build_request()` + so that any client-level configuration is merged into the request, + but passing an explicit `httpx.Request()` is supported as well. + + See also: [Request instances][0] + + [0]: /advanced/clients/#request-instances + """ + if self._state == ClientState.CLOSED: + raise RuntimeError("Cannot send a request, as the client has been closed.") + + self._state = ClientState.OPENED + follow_redirects = ( + self.follow_redirects + if isinstance(follow_redirects, UseClientDefault) + else follow_redirects + ) + + self._set_timeout(request) + + auth = self._build_request_auth(request, auth) + + response = self._send_handling_auth( + request, + auth=auth, + follow_redirects=follow_redirects, + history=[], + ) + try: + if not stream: + response.read() + + return response + + except BaseException as exc: + response.close() + raise exc + + def _send_handling_auth( + self, + request: Request, + auth: Auth, + follow_redirects: bool, + history: list[Response], + ) -> Response: + auth_flow = auth.sync_auth_flow(request) + try: + request = next(auth_flow) + + while True: + response = self._send_handling_redirects( + request, + follow_redirects=follow_redirects, + history=history, + ) + try: + try: + next_request = auth_flow.send(response) + except StopIteration: + return response + + response.history = list(history) + response.read() + request = next_request + history.append(response) + + except BaseException as exc: + response.close() + raise exc + finally: + auth_flow.close() + + def _send_handling_redirects( + self, + request: Request, + follow_redirects: bool, + history: list[Response], + ) -> Response: + while True: + if len(history) > self.max_redirects: + raise TooManyRedirects( + "Exceeded maximum allowed redirects.", request=request + ) + + for hook in self._event_hooks["request"]: + hook(request) + + response = self._send_single_request(request) + try: + for hook in self._event_hooks["response"]: + hook(response) + response.history = list(history) + + if not response.has_redirect_location: + return response + + request = self._build_redirect_request(request, response) + history = history + [response] + + if follow_redirects: + response.read() + else: + response.next_request = request + return response + + except BaseException as exc: + response.close() + raise exc + + def _send_single_request(self, request: Request) -> Response: + """ + Sends a single request, without handling any redirections. + """ + transport = self._transport_for_url(request.url) + start = time.perf_counter() + + if not isinstance(request.stream, SyncByteStream): + raise RuntimeError( + "Attempted to send an async request with a sync Client instance." + ) + + with request_context(request=request): + response = transport.handle_request(request) + + assert isinstance(response.stream, SyncByteStream) + + response.request = request + response.stream = BoundSyncStream( + response.stream, response=response, start=start + ) + self.cookies.extract_cookies(response) + response.default_encoding = self._default_encoding + + logger.info( + 'HTTP Request: %s %s "%s %d %s"', + request.method, + request.url, + response.http_version, + response.status_code, + response.reason_phrase, + ) + + return response + + def get( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `GET` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "GET", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def options( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send an `OPTIONS` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "OPTIONS", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def head( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `HEAD` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "HEAD", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def post( + self, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `POST` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "POST", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def put( + self, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `PUT` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "PUT", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def patch( + self, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `PATCH` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "PATCH", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def delete( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `DELETE` request. + + **Parameters**: See `httpx.request`. + """ + return self.request( + "DELETE", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def close(self) -> None: + """ + Close transport and proxies. + """ + if self._state != ClientState.CLOSED: + self._state = ClientState.CLOSED + + self._transport.close() + for transport in self._mounts.values(): + if transport is not None: + transport.close() + + def __enter__(self: T) -> T: + if self._state != ClientState.UNOPENED: + msg = { + ClientState.OPENED: "Cannot open a client instance more than once.", + ClientState.CLOSED: ( + "Cannot reopen a client instance, once it has been closed." + ), + }[self._state] + raise RuntimeError(msg) + + self._state = ClientState.OPENED + + self._transport.__enter__() + for transport in self._mounts.values(): + if transport is not None: + transport.__enter__() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, + ) -> None: + self._state = ClientState.CLOSED + + self._transport.__exit__(exc_type, exc_value, traceback) + for transport in self._mounts.values(): + if transport is not None: + transport.__exit__(exc_type, exc_value, traceback) + + +class AsyncClient(BaseClient): + """ + An asynchronous HTTP client, with connection pooling, HTTP/2, redirects, + cookie persistence, etc. + + It can be shared between tasks. + + Usage: + + ```python + >>> async with httpx.AsyncClient() as client: + >>> response = await client.get('https://example.org') + ``` + + **Parameters:** + + * **auth** - *(optional)* An authentication class to use when sending + requests. + * **params** - *(optional)* Query parameters to include in request URLs, as + a string, dictionary, or sequence of two-tuples. + * **headers** - *(optional)* Dictionary of HTTP headers to include when + sending requests. + * **cookies** - *(optional)* Dictionary of Cookie items to include when + sending requests. + * **verify** - *(optional)* Either `True` to use an SSL context with the + default CA bundle, `False` to disable verification, or an instance of + `ssl.SSLContext` to use a custom context. + * **http2** - *(optional)* A boolean indicating if HTTP/2 support should be + enabled. Defaults to `False`. + * **proxy** - *(optional)* A proxy URL where all the traffic should be routed. + * **timeout** - *(optional)* The timeout configuration to use when sending + requests. + * **limits** - *(optional)* The limits configuration to use. + * **max_redirects** - *(optional)* The maximum number of redirect responses + that should be followed. + * **base_url** - *(optional)* A URL to use as the base when building + request URLs. + * **transport** - *(optional)* A transport class to use for sending requests + over the network. + * **trust_env** - *(optional)* Enables or disables usage of environment + variables for configuration. + * **default_encoding** - *(optional)* The default encoding to use for decoding + response text, if no charset information is included in a response Content-Type + header. Set to a callable for automatic character set detection. Default: "utf-8". + """ + + def __init__( + self, + *, + auth: AuthTypes | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + http1: bool = True, + http2: bool = False, + proxy: ProxyTypes | None = None, + mounts: None | (typing.Mapping[str, AsyncBaseTransport | None]) = None, + timeout: TimeoutTypes = DEFAULT_TIMEOUT_CONFIG, + follow_redirects: bool = False, + limits: Limits = DEFAULT_LIMITS, + max_redirects: int = DEFAULT_MAX_REDIRECTS, + event_hooks: None | (typing.Mapping[str, list[EventHook]]) = None, + base_url: URL | str = "", + transport: AsyncBaseTransport | None = None, + trust_env: bool = True, + default_encoding: str | typing.Callable[[bytes], str] = "utf-8", + ) -> None: + super().__init__( + auth=auth, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + follow_redirects=follow_redirects, + max_redirects=max_redirects, + event_hooks=event_hooks, + base_url=base_url, + trust_env=trust_env, + default_encoding=default_encoding, + ) + + if http2: + try: + import h2 # noqa + except ImportError: # pragma: no cover + raise ImportError( + "Using http2=True, but the 'h2' package is not installed. " + "Make sure to install httpx using `pip install httpx[http2]`." + ) from None + + allow_env_proxies = trust_env and transport is None + proxy_map = self._get_proxy_map(proxy, allow_env_proxies) + + self._transport = self._init_transport( + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + transport=transport, + ) + + self._mounts: dict[URLPattern, AsyncBaseTransport | None] = { + URLPattern(key): None + if proxy is None + else self._init_proxy_transport( + proxy, + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + ) + for key, proxy in proxy_map.items() + } + if mounts is not None: + self._mounts.update( + {URLPattern(key): transport for key, transport in mounts.items()} + ) + self._mounts = dict(sorted(self._mounts.items())) + + def _init_transport( + self, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + limits: Limits = DEFAULT_LIMITS, + transport: AsyncBaseTransport | None = None, + ) -> AsyncBaseTransport: + if transport is not None: + return transport + + return AsyncHTTPTransport( + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + ) + + def _init_proxy_transport( + self, + proxy: Proxy, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + limits: Limits = DEFAULT_LIMITS, + ) -> AsyncBaseTransport: + return AsyncHTTPTransport( + verify=verify, + cert=cert, + trust_env=trust_env, + http1=http1, + http2=http2, + limits=limits, + proxy=proxy, + ) + + def _transport_for_url(self, url: URL) -> AsyncBaseTransport: + """ + Returns the transport instance that should be used for a given URL. + This will either be the standard connection pool, or a proxy. + """ + for pattern, transport in self._mounts.items(): + if pattern.matches(url): + return self._transport if transport is None else transport + + return self._transport + + async def request( + self, + method: str, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Build and send a request. + + Equivalent to: + + ```python + request = client.build_request(...) + response = await client.send(request, ...) + ``` + + See `AsyncClient.build_request()`, `AsyncClient.send()` + and [Merging of configuration][0] for how the various parameters + are merged with client-level configuration. + + [0]: /advanced/clients/#merging-of-configuration + """ + + if cookies is not None: # pragma: no cover + message = ( + "Setting per-request cookies=<...> is being deprecated, because " + "the expected behaviour on cookie persistence is ambiguous. Set " + "cookies directly on the client instance instead." + ) + warnings.warn(message, DeprecationWarning, stacklevel=2) + + request = self.build_request( + method=method, + url=url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + extensions=extensions, + ) + return await self.send(request, auth=auth, follow_redirects=follow_redirects) + + @asynccontextmanager + async def stream( + self, + method: str, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> typing.AsyncIterator[Response]: + """ + Alternative to `httpx.request()` that streams the response body + instead of loading it into memory at once. + + **Parameters**: See `httpx.request`. + + See also: [Streaming Responses][0] + + [0]: /quickstart#streaming-responses + """ + request = self.build_request( + method=method, + url=url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + timeout=timeout, + extensions=extensions, + ) + response = await self.send( + request=request, + auth=auth, + follow_redirects=follow_redirects, + stream=True, + ) + try: + yield response + finally: + await response.aclose() + + async def send( + self, + request: Request, + *, + stream: bool = False, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + ) -> Response: + """ + Send a request. + + The request is sent as-is, unmodified. + + Typically you'll want to build one with `AsyncClient.build_request()` + so that any client-level configuration is merged into the request, + but passing an explicit `httpx.Request()` is supported as well. + + See also: [Request instances][0] + + [0]: /advanced/clients/#request-instances + """ + if self._state == ClientState.CLOSED: + raise RuntimeError("Cannot send a request, as the client has been closed.") + + self._state = ClientState.OPENED + follow_redirects = ( + self.follow_redirects + if isinstance(follow_redirects, UseClientDefault) + else follow_redirects + ) + + self._set_timeout(request) + + auth = self._build_request_auth(request, auth) + + response = await self._send_handling_auth( + request, + auth=auth, + follow_redirects=follow_redirects, + history=[], + ) + try: + if not stream: + await response.aread() + + return response + + except BaseException as exc: + await response.aclose() + raise exc + + async def _send_handling_auth( + self, + request: Request, + auth: Auth, + follow_redirects: bool, + history: list[Response], + ) -> Response: + auth_flow = auth.async_auth_flow(request) + try: + request = await auth_flow.__anext__() + + while True: + response = await self._send_handling_redirects( + request, + follow_redirects=follow_redirects, + history=history, + ) + try: + try: + next_request = await auth_flow.asend(response) + except StopAsyncIteration: + return response + + response.history = list(history) + await response.aread() + request = next_request + history.append(response) + + except BaseException as exc: + await response.aclose() + raise exc + finally: + await auth_flow.aclose() + + async def _send_handling_redirects( + self, + request: Request, + follow_redirects: bool, + history: list[Response], + ) -> Response: + while True: + if len(history) > self.max_redirects: + raise TooManyRedirects( + "Exceeded maximum allowed redirects.", request=request + ) + + for hook in self._event_hooks["request"]: + await hook(request) + + response = await self._send_single_request(request) + try: + for hook in self._event_hooks["response"]: + await hook(response) + + response.history = list(history) + + if not response.has_redirect_location: + return response + + request = self._build_redirect_request(request, response) + history = history + [response] + + if follow_redirects: + await response.aread() + else: + response.next_request = request + return response + + except BaseException as exc: + await response.aclose() + raise exc + + async def _send_single_request(self, request: Request) -> Response: + """ + Sends a single request, without handling any redirections. + """ + transport = self._transport_for_url(request.url) + start = time.perf_counter() + + if not isinstance(request.stream, AsyncByteStream): + raise RuntimeError( + "Attempted to send an sync request with an AsyncClient instance." + ) + + with request_context(request=request): + response = await transport.handle_async_request(request) + + assert isinstance(response.stream, AsyncByteStream) + response.request = request + response.stream = BoundAsyncStream( + response.stream, response=response, start=start + ) + self.cookies.extract_cookies(response) + response.default_encoding = self._default_encoding + + logger.info( + 'HTTP Request: %s %s "%s %d %s"', + request.method, + request.url, + response.http_version, + response.status_code, + response.reason_phrase, + ) + + return response + + async def get( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault | None = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `GET` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "GET", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def options( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send an `OPTIONS` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "OPTIONS", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def head( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `HEAD` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "HEAD", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def post( + self, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `POST` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "POST", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def put( + self, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `PUT` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "PUT", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def patch( + self, + url: URL | str, + *, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `PATCH` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "PATCH", + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def delete( + self, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + auth: AuthTypes | UseClientDefault = USE_CLIENT_DEFAULT, + follow_redirects: bool | UseClientDefault = USE_CLIENT_DEFAULT, + timeout: TimeoutTypes | UseClientDefault = USE_CLIENT_DEFAULT, + extensions: RequestExtensions | None = None, + ) -> Response: + """ + Send a `DELETE` request. + + **Parameters**: See `httpx.request`. + """ + return await self.request( + "DELETE", + url, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + async def aclose(self) -> None: + """ + Close transport and proxies. + """ + if self._state != ClientState.CLOSED: + self._state = ClientState.CLOSED + + await self._transport.aclose() + for proxy in self._mounts.values(): + if proxy is not None: + await proxy.aclose() + + async def __aenter__(self: U) -> U: + if self._state != ClientState.UNOPENED: + msg = { + ClientState.OPENED: "Cannot open a client instance more than once.", + ClientState.CLOSED: ( + "Cannot reopen a client instance, once it has been closed." + ), + }[self._state] + raise RuntimeError(msg) + + self._state = ClientState.OPENED + + await self._transport.__aenter__() + for proxy in self._mounts.values(): + if proxy is not None: + await proxy.__aenter__() + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, + ) -> None: + self._state = ClientState.CLOSED + + await self._transport.__aexit__(exc_type, exc_value, traceback) + for proxy in self._mounts.values(): + if proxy is not None: + await proxy.__aexit__(exc_type, exc_value, traceback) diff --git a/source/target-vendors/cp312/httpx/_config.py b/source/target-vendors/cp312/httpx/_config.py new file mode 100644 index 0000000..467a6c9 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_config.py @@ -0,0 +1,248 @@ +from __future__ import annotations + +import os +import typing + +from ._models import Headers +from ._types import CertTypes, HeaderTypes, TimeoutTypes +from ._urls import URL + +if typing.TYPE_CHECKING: + import ssl # pragma: no cover + +__all__ = ["Limits", "Proxy", "Timeout", "create_ssl_context"] + + +class UnsetType: + pass # pragma: no cover + + +UNSET = UnsetType() + + +def create_ssl_context( + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, +) -> ssl.SSLContext: + import ssl + import warnings + + import certifi + + if verify is True: + if trust_env and os.environ.get("SSL_CERT_FILE"): # pragma: nocover + ctx = ssl.create_default_context(cafile=os.environ["SSL_CERT_FILE"]) + elif trust_env and os.environ.get("SSL_CERT_DIR"): # pragma: nocover + ctx = ssl.create_default_context(capath=os.environ["SSL_CERT_DIR"]) + else: + # Default case... + ctx = ssl.create_default_context(cafile=certifi.where()) + elif verify is False: + ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + elif isinstance(verify, str): # pragma: nocover + message = ( + "`verify=` is deprecated. " + "Use `verify=ssl.create_default_context(cafile=...)` " + "or `verify=ssl.create_default_context(capath=...)` instead." + ) + warnings.warn(message, DeprecationWarning) + if os.path.isdir(verify): + return ssl.create_default_context(capath=verify) + return ssl.create_default_context(cafile=verify) + else: + ctx = verify + + if cert: # pragma: nocover + message = ( + "`cert=...` is deprecated. Use `verify=` instead," + "with `.load_cert_chain()` to configure the certificate chain." + ) + warnings.warn(message, DeprecationWarning) + if isinstance(cert, str): + ctx.load_cert_chain(cert) + else: + ctx.load_cert_chain(*cert) + + return ctx + + +class Timeout: + """ + Timeout configuration. + + **Usage**: + + Timeout(None) # No timeouts. + Timeout(5.0) # 5s timeout on all operations. + Timeout(None, connect=5.0) # 5s timeout on connect, no other timeouts. + Timeout(5.0, connect=10.0) # 10s timeout on connect. 5s timeout elsewhere. + Timeout(5.0, pool=None) # No timeout on acquiring connection from pool. + # 5s timeout elsewhere. + """ + + def __init__( + self, + timeout: TimeoutTypes | UnsetType = UNSET, + *, + connect: None | float | UnsetType = UNSET, + read: None | float | UnsetType = UNSET, + write: None | float | UnsetType = UNSET, + pool: None | float | UnsetType = UNSET, + ) -> None: + if isinstance(timeout, Timeout): + # Passed as a single explicit Timeout. + assert connect is UNSET + assert read is UNSET + assert write is UNSET + assert pool is UNSET + self.connect = timeout.connect # type: typing.Optional[float] + self.read = timeout.read # type: typing.Optional[float] + self.write = timeout.write # type: typing.Optional[float] + self.pool = timeout.pool # type: typing.Optional[float] + elif isinstance(timeout, tuple): + # Passed as a tuple. + self.connect = timeout[0] + self.read = timeout[1] + self.write = None if len(timeout) < 3 else timeout[2] + self.pool = None if len(timeout) < 4 else timeout[3] + elif not ( + isinstance(connect, UnsetType) + or isinstance(read, UnsetType) + or isinstance(write, UnsetType) + or isinstance(pool, UnsetType) + ): + self.connect = connect + self.read = read + self.write = write + self.pool = pool + else: + if isinstance(timeout, UnsetType): + raise ValueError( + "httpx.Timeout must either include a default, or set all " + "four parameters explicitly." + ) + self.connect = timeout if isinstance(connect, UnsetType) else connect + self.read = timeout if isinstance(read, UnsetType) else read + self.write = timeout if isinstance(write, UnsetType) else write + self.pool = timeout if isinstance(pool, UnsetType) else pool + + def as_dict(self) -> dict[str, float | None]: + return { + "connect": self.connect, + "read": self.read, + "write": self.write, + "pool": self.pool, + } + + def __eq__(self, other: typing.Any) -> bool: + return ( + isinstance(other, self.__class__) + and self.connect == other.connect + and self.read == other.read + and self.write == other.write + and self.pool == other.pool + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + if len({self.connect, self.read, self.write, self.pool}) == 1: + return f"{class_name}(timeout={self.connect})" + return ( + f"{class_name}(connect={self.connect}, " + f"read={self.read}, write={self.write}, pool={self.pool})" + ) + + +class Limits: + """ + Configuration for limits to various client behaviors. + + **Parameters:** + + * **max_connections** - The maximum number of concurrent connections that may be + established. + * **max_keepalive_connections** - Allow the connection pool to maintain + keep-alive connections below this point. Should be less than or equal + to `max_connections`. + * **keepalive_expiry** - Time limit on idle keep-alive connections in seconds. + """ + + def __init__( + self, + *, + max_connections: int | None = None, + max_keepalive_connections: int | None = None, + keepalive_expiry: float | None = 5.0, + ) -> None: + self.max_connections = max_connections + self.max_keepalive_connections = max_keepalive_connections + self.keepalive_expiry = keepalive_expiry + + def __eq__(self, other: typing.Any) -> bool: + return ( + isinstance(other, self.__class__) + and self.max_connections == other.max_connections + and self.max_keepalive_connections == other.max_keepalive_connections + and self.keepalive_expiry == other.keepalive_expiry + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + return ( + f"{class_name}(max_connections={self.max_connections}, " + f"max_keepalive_connections={self.max_keepalive_connections}, " + f"keepalive_expiry={self.keepalive_expiry})" + ) + + +class Proxy: + def __init__( + self, + url: URL | str, + *, + ssl_context: ssl.SSLContext | None = None, + auth: tuple[str, str] | None = None, + headers: HeaderTypes | None = None, + ) -> None: + url = URL(url) + headers = Headers(headers) + + if url.scheme not in ("http", "https", "socks5", "socks5h"): + raise ValueError(f"Unknown scheme for proxy URL {url!r}") + + if url.username or url.password: + # Remove any auth credentials from the URL. + auth = (url.username, url.password) + url = url.copy_with(username=None, password=None) + + self.url = url + self.auth = auth + self.headers = headers + self.ssl_context = ssl_context + + @property + def raw_auth(self) -> tuple[bytes, bytes] | None: + # The proxy authentication as raw bytes. + return ( + None + if self.auth is None + else (self.auth[0].encode("utf-8"), self.auth[1].encode("utf-8")) + ) + + def __repr__(self) -> str: + # The authentication is represented with the password component masked. + auth = (self.auth[0], "********") if self.auth else None + + # Build a nice concise representation. + url_str = f"{str(self.url)!r}" + auth_str = f", auth={auth!r}" if auth else "" + headers_str = f", headers={dict(self.headers)!r}" if self.headers else "" + return f"Proxy({url_str}{auth_str}{headers_str})" + + +DEFAULT_TIMEOUT_CONFIG = Timeout(timeout=5.0) +DEFAULT_LIMITS = Limits(max_connections=100, max_keepalive_connections=20) +DEFAULT_MAX_REDIRECTS = 20 diff --git a/source/target-vendors/cp312/httpx/_content.py b/source/target-vendors/cp312/httpx/_content.py new file mode 100644 index 0000000..6f479a0 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_content.py @@ -0,0 +1,240 @@ +from __future__ import annotations + +import inspect +import warnings +from json import dumps as json_dumps +from typing import ( + Any, + AsyncIterable, + AsyncIterator, + Iterable, + Iterator, + Mapping, +) +from urllib.parse import urlencode + +from ._exceptions import StreamClosed, StreamConsumed +from ._multipart import MultipartStream +from ._types import ( + AsyncByteStream, + RequestContent, + RequestData, + RequestFiles, + ResponseContent, + SyncByteStream, +) +from ._utils import peek_filelike_length, primitive_value_to_str + +__all__ = ["ByteStream"] + + +class ByteStream(AsyncByteStream, SyncByteStream): + def __init__(self, stream: bytes) -> None: + self._stream = stream + + def __iter__(self) -> Iterator[bytes]: + yield self._stream + + async def __aiter__(self) -> AsyncIterator[bytes]: + yield self._stream + + +class IteratorByteStream(SyncByteStream): + CHUNK_SIZE = 65_536 + + def __init__(self, stream: Iterable[bytes]) -> None: + self._stream = stream + self._is_stream_consumed = False + self._is_generator = inspect.isgenerator(stream) + + def __iter__(self) -> Iterator[bytes]: + if self._is_stream_consumed and self._is_generator: + raise StreamConsumed() + + self._is_stream_consumed = True + if hasattr(self._stream, "read"): + # File-like interfaces should use 'read' directly. + chunk = self._stream.read(self.CHUNK_SIZE) + while chunk: + yield chunk + chunk = self._stream.read(self.CHUNK_SIZE) + else: + # Otherwise iterate. + for part in self._stream: + yield part + + +class AsyncIteratorByteStream(AsyncByteStream): + CHUNK_SIZE = 65_536 + + def __init__(self, stream: AsyncIterable[bytes]) -> None: + self._stream = stream + self._is_stream_consumed = False + self._is_generator = inspect.isasyncgen(stream) + + async def __aiter__(self) -> AsyncIterator[bytes]: + if self._is_stream_consumed and self._is_generator: + raise StreamConsumed() + + self._is_stream_consumed = True + if hasattr(self._stream, "aread"): + # File-like interfaces should use 'aread' directly. + chunk = await self._stream.aread(self.CHUNK_SIZE) + while chunk: + yield chunk + chunk = await self._stream.aread(self.CHUNK_SIZE) + else: + # Otherwise iterate. + async for part in self._stream: + yield part + + +class UnattachedStream(AsyncByteStream, SyncByteStream): + """ + If a request or response is serialized using pickle, then it is no longer + attached to a stream for I/O purposes. Any stream operations should result + in `httpx.StreamClosed`. + """ + + def __iter__(self) -> Iterator[bytes]: + raise StreamClosed() + + async def __aiter__(self) -> AsyncIterator[bytes]: + raise StreamClosed() + yield b"" # pragma: no cover + + +def encode_content( + content: str | bytes | Iterable[bytes] | AsyncIterable[bytes], +) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: + if isinstance(content, (bytes, str)): + body = content.encode("utf-8") if isinstance(content, str) else content + content_length = len(body) + headers = {"Content-Length": str(content_length)} if body else {} + return headers, ByteStream(body) + + elif isinstance(content, Iterable) and not isinstance(content, dict): + # `not isinstance(content, dict)` is a bit oddly specific, but it + # catches a case that's easy for users to make in error, and would + # otherwise pass through here, like any other bytes-iterable, + # because `dict` happens to be iterable. See issue #2491. + content_length_or_none = peek_filelike_length(content) + + if content_length_or_none is None: + headers = {"Transfer-Encoding": "chunked"} + else: + headers = {"Content-Length": str(content_length_or_none)} + return headers, IteratorByteStream(content) # type: ignore + + elif isinstance(content, AsyncIterable): + headers = {"Transfer-Encoding": "chunked"} + return headers, AsyncIteratorByteStream(content) + + raise TypeError(f"Unexpected type for 'content', {type(content)!r}") + + +def encode_urlencoded_data( + data: RequestData, +) -> tuple[dict[str, str], ByteStream]: + plain_data = [] + for key, value in data.items(): + if isinstance(value, (list, tuple)): + plain_data.extend([(key, primitive_value_to_str(item)) for item in value]) + else: + plain_data.append((key, primitive_value_to_str(value))) + body = urlencode(plain_data, doseq=True).encode("utf-8") + content_length = str(len(body)) + content_type = "application/x-www-form-urlencoded" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, ByteStream(body) + + +def encode_multipart_data( + data: RequestData, files: RequestFiles, boundary: bytes | None +) -> tuple[dict[str, str], MultipartStream]: + multipart = MultipartStream(data=data, files=files, boundary=boundary) + headers = multipart.get_headers() + return headers, multipart + + +def encode_text(text: str) -> tuple[dict[str, str], ByteStream]: + body = text.encode("utf-8") + content_length = str(len(body)) + content_type = "text/plain; charset=utf-8" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, ByteStream(body) + + +def encode_html(html: str) -> tuple[dict[str, str], ByteStream]: + body = html.encode("utf-8") + content_length = str(len(body)) + content_type = "text/html; charset=utf-8" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, ByteStream(body) + + +def encode_json(json: Any) -> tuple[dict[str, str], ByteStream]: + body = json_dumps( + json, ensure_ascii=False, separators=(",", ":"), allow_nan=False + ).encode("utf-8") + content_length = str(len(body)) + content_type = "application/json" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, ByteStream(body) + + +def encode_request( + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: Any | None = None, + boundary: bytes | None = None, +) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: + """ + Handles encoding the given `content`, `data`, `files`, and `json`, + returning a two-tuple of (, ). + """ + if data is not None and not isinstance(data, Mapping): + # We prefer to separate `content=` + # for raw request content, and `data=
      ` for url encoded or + # multipart form content. + # + # However for compat with requests, we *do* still support + # `data=` usages. We deal with that case here, treating it + # as if `content=<...>` had been supplied instead. + message = "Use 'content=<...>' to upload raw bytes/text content." + warnings.warn(message, DeprecationWarning, stacklevel=2) + return encode_content(data) + + if content is not None: + return encode_content(content) + elif files: + return encode_multipart_data(data or {}, files, boundary) + elif data: + return encode_urlencoded_data(data) + elif json is not None: + return encode_json(json) + + return {}, ByteStream(b"") + + +def encode_response( + content: ResponseContent | None = None, + text: str | None = None, + html: str | None = None, + json: Any | None = None, +) -> tuple[dict[str, str], SyncByteStream | AsyncByteStream]: + """ + Handles encoding the given `content`, returning a two-tuple of + (, ). + """ + if content is not None: + return encode_content(content) + elif text is not None: + return encode_text(text) + elif html is not None: + return encode_html(html) + elif json is not None: + return encode_json(json) + + return {}, ByteStream(b"") diff --git a/source/target-vendors/cp312/httpx/_decoders.py b/source/target-vendors/cp312/httpx/_decoders.py new file mode 100644 index 0000000..899dfad --- /dev/null +++ b/source/target-vendors/cp312/httpx/_decoders.py @@ -0,0 +1,393 @@ +""" +Handlers for Content-Encoding. + +See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding +""" + +from __future__ import annotations + +import codecs +import io +import typing +import zlib + +from ._exceptions import DecodingError + +# Brotli support is optional +try: + # The C bindings in `brotli` are recommended for CPython. + import brotli +except ImportError: # pragma: no cover + try: + # The CFFI bindings in `brotlicffi` are recommended for PyPy + # and other environments. + import brotlicffi as brotli + except ImportError: + brotli = None + + +# Zstandard support is optional +try: + import zstandard +except ImportError: # pragma: no cover + zstandard = None # type: ignore + + +class ContentDecoder: + def decode(self, data: bytes) -> bytes: + raise NotImplementedError() # pragma: no cover + + def flush(self) -> bytes: + raise NotImplementedError() # pragma: no cover + + +class IdentityDecoder(ContentDecoder): + """ + Handle unencoded data. + """ + + def decode(self, data: bytes) -> bytes: + return data + + def flush(self) -> bytes: + return b"" + + +class DeflateDecoder(ContentDecoder): + """ + Handle 'deflate' decoding. + + See: https://stackoverflow.com/questions/1838699 + """ + + def __init__(self) -> None: + self.first_attempt = True + self.decompressor = zlib.decompressobj() + + def decode(self, data: bytes) -> bytes: + was_first_attempt = self.first_attempt + self.first_attempt = False + try: + return self.decompressor.decompress(data) + except zlib.error as exc: + if was_first_attempt: + self.decompressor = zlib.decompressobj(-zlib.MAX_WBITS) + return self.decode(data) + raise DecodingError(str(exc)) from exc + + def flush(self) -> bytes: + try: + return self.decompressor.flush() + except zlib.error as exc: # pragma: no cover + raise DecodingError(str(exc)) from exc + + +class GZipDecoder(ContentDecoder): + """ + Handle 'gzip' decoding. + + See: https://stackoverflow.com/questions/1838699 + """ + + def __init__(self) -> None: + self.decompressor = zlib.decompressobj(zlib.MAX_WBITS | 16) + + def decode(self, data: bytes) -> bytes: + try: + return self.decompressor.decompress(data) + except zlib.error as exc: + raise DecodingError(str(exc)) from exc + + def flush(self) -> bytes: + try: + return self.decompressor.flush() + except zlib.error as exc: # pragma: no cover + raise DecodingError(str(exc)) from exc + + +class BrotliDecoder(ContentDecoder): + """ + Handle 'brotli' decoding. + + Requires `pip install brotlipy`. See: https://brotlipy.readthedocs.io/ + or `pip install brotli`. See https://github.com/google/brotli + Supports both 'brotlipy' and 'Brotli' packages since they share an import + name. The top branches are for 'brotlipy' and bottom branches for 'Brotli' + """ + + def __init__(self) -> None: + if brotli is None: # pragma: no cover + raise ImportError( + "Using 'BrotliDecoder', but neither of the 'brotlicffi' or 'brotli' " + "packages have been installed. " + "Make sure to install httpx using `pip install httpx[brotli]`." + ) from None + + self.decompressor = brotli.Decompressor() + self.seen_data = False + self._decompress: typing.Callable[[bytes], bytes] + if hasattr(self.decompressor, "decompress"): + # The 'brotlicffi' package. + self._decompress = self.decompressor.decompress # pragma: no cover + else: + # The 'brotli' package. + self._decompress = self.decompressor.process # pragma: no cover + + def decode(self, data: bytes) -> bytes: + if not data: + return b"" + self.seen_data = True + try: + return self._decompress(data) + except brotli.error as exc: + raise DecodingError(str(exc)) from exc + + def flush(self) -> bytes: + if not self.seen_data: + return b"" + try: + if hasattr(self.decompressor, "finish"): + # Only available in the 'brotlicffi' package. + + # As the decompressor decompresses eagerly, this + # will never actually emit any data. However, it will potentially throw + # errors if a truncated or damaged data stream has been used. + self.decompressor.finish() # pragma: no cover + return b"" + except brotli.error as exc: # pragma: no cover + raise DecodingError(str(exc)) from exc + + +class ZStandardDecoder(ContentDecoder): + """ + Handle 'zstd' RFC 8878 decoding. + + Requires `pip install zstandard`. + Can be installed as a dependency of httpx using `pip install httpx[zstd]`. + """ + + # inspired by the ZstdDecoder implementation in urllib3 + def __init__(self) -> None: + if zstandard is None: # pragma: no cover + raise ImportError( + "Using 'ZStandardDecoder', ..." + "Make sure to install httpx using `pip install httpx[zstd]`." + ) from None + + self.decompressor = zstandard.ZstdDecompressor().decompressobj() + self.seen_data = False + + def decode(self, data: bytes) -> bytes: + assert zstandard is not None + self.seen_data = True + output = io.BytesIO() + try: + output.write(self.decompressor.decompress(data)) + while self.decompressor.eof and self.decompressor.unused_data: + unused_data = self.decompressor.unused_data + self.decompressor = zstandard.ZstdDecompressor().decompressobj() + output.write(self.decompressor.decompress(unused_data)) + except zstandard.ZstdError as exc: + raise DecodingError(str(exc)) from exc + return output.getvalue() + + def flush(self) -> bytes: + if not self.seen_data: + return b"" + ret = self.decompressor.flush() # note: this is a no-op + if not self.decompressor.eof: + raise DecodingError("Zstandard data is incomplete") # pragma: no cover + return bytes(ret) + + +class MultiDecoder(ContentDecoder): + """ + Handle the case where multiple encodings have been applied. + """ + + def __init__(self, children: typing.Sequence[ContentDecoder]) -> None: + """ + 'children' should be a sequence of decoders in the order in which + each was applied. + """ + # Note that we reverse the order for decoding. + self.children = list(reversed(children)) + + def decode(self, data: bytes) -> bytes: + for child in self.children: + data = child.decode(data) + return data + + def flush(self) -> bytes: + data = b"" + for child in self.children: + data = child.decode(data) + child.flush() + return data + + +class ByteChunker: + """ + Handles returning byte content in fixed-size chunks. + """ + + def __init__(self, chunk_size: int | None = None) -> None: + self._buffer = io.BytesIO() + self._chunk_size = chunk_size + + def decode(self, content: bytes) -> list[bytes]: + if self._chunk_size is None: + return [content] if content else [] + + self._buffer.write(content) + if self._buffer.tell() >= self._chunk_size: + value = self._buffer.getvalue() + chunks = [ + value[i : i + self._chunk_size] + for i in range(0, len(value), self._chunk_size) + ] + if len(chunks[-1]) == self._chunk_size: + self._buffer.seek(0) + self._buffer.truncate() + return chunks + else: + self._buffer.seek(0) + self._buffer.write(chunks[-1]) + self._buffer.truncate() + return chunks[:-1] + else: + return [] + + def flush(self) -> list[bytes]: + value = self._buffer.getvalue() + self._buffer.seek(0) + self._buffer.truncate() + return [value] if value else [] + + +class TextChunker: + """ + Handles returning text content in fixed-size chunks. + """ + + def __init__(self, chunk_size: int | None = None) -> None: + self._buffer = io.StringIO() + self._chunk_size = chunk_size + + def decode(self, content: str) -> list[str]: + if self._chunk_size is None: + return [content] if content else [] + + self._buffer.write(content) + if self._buffer.tell() >= self._chunk_size: + value = self._buffer.getvalue() + chunks = [ + value[i : i + self._chunk_size] + for i in range(0, len(value), self._chunk_size) + ] + if len(chunks[-1]) == self._chunk_size: + self._buffer.seek(0) + self._buffer.truncate() + return chunks + else: + self._buffer.seek(0) + self._buffer.write(chunks[-1]) + self._buffer.truncate() + return chunks[:-1] + else: + return [] + + def flush(self) -> list[str]: + value = self._buffer.getvalue() + self._buffer.seek(0) + self._buffer.truncate() + return [value] if value else [] + + +class TextDecoder: + """ + Handles incrementally decoding bytes into text + """ + + def __init__(self, encoding: str = "utf-8") -> None: + self.decoder = codecs.getincrementaldecoder(encoding)(errors="replace") + + def decode(self, data: bytes) -> str: + return self.decoder.decode(data) + + def flush(self) -> str: + return self.decoder.decode(b"", True) + + +class LineDecoder: + """ + Handles incrementally reading lines from text. + + Has the same behaviour as the stdllib splitlines, + but handling the input iteratively. + """ + + def __init__(self) -> None: + self.buffer: list[str] = [] + self.trailing_cr: bool = False + + def decode(self, text: str) -> list[str]: + # See https://docs.python.org/3/library/stdtypes.html#str.splitlines + NEWLINE_CHARS = "\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029" + + # We always push a trailing `\r` into the next decode iteration. + if self.trailing_cr: + text = "\r" + text + self.trailing_cr = False + if text.endswith("\r"): + self.trailing_cr = True + text = text[:-1] + + if not text: + # NOTE: the edge case input of empty text doesn't occur in practice, + # because other httpx internals filter out this value + return [] # pragma: no cover + + trailing_newline = text[-1] in NEWLINE_CHARS + lines = text.splitlines() + + if len(lines) == 1 and not trailing_newline: + # No new lines, buffer the input and continue. + self.buffer.append(lines[0]) + return [] + + if self.buffer: + # Include any existing buffer in the first portion of the + # splitlines result. + lines = ["".join(self.buffer) + lines[0]] + lines[1:] + self.buffer = [] + + if not trailing_newline: + # If the last segment of splitlines is not newline terminated, + # then drop it from our output and start a new buffer. + self.buffer = [lines.pop()] + + return lines + + def flush(self) -> list[str]: + if not self.buffer and not self.trailing_cr: + return [] + + lines = ["".join(self.buffer)] + self.buffer = [] + self.trailing_cr = False + return lines + + +SUPPORTED_DECODERS = { + "identity": IdentityDecoder, + "gzip": GZipDecoder, + "deflate": DeflateDecoder, + "br": BrotliDecoder, + "zstd": ZStandardDecoder, +} + + +if brotli is None: + SUPPORTED_DECODERS.pop("br") # pragma: no cover +if zstandard is None: + SUPPORTED_DECODERS.pop("zstd") # pragma: no cover diff --git a/source/target-vendors/cp312/httpx/_exceptions.py b/source/target-vendors/cp312/httpx/_exceptions.py new file mode 100644 index 0000000..77f45a6 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_exceptions.py @@ -0,0 +1,379 @@ +""" +Our exception hierarchy: + +* HTTPError + x RequestError + + TransportError + - TimeoutException + · ConnectTimeout + · ReadTimeout + · WriteTimeout + · PoolTimeout + - NetworkError + · ConnectError + · ReadError + · WriteError + · CloseError + - ProtocolError + · LocalProtocolError + · RemoteProtocolError + - ProxyError + - UnsupportedProtocol + + DecodingError + + TooManyRedirects + x HTTPStatusError +* InvalidURL +* CookieConflict +* StreamError + x StreamConsumed + x StreamClosed + x ResponseNotRead + x RequestNotRead +""" + +from __future__ import annotations + +import contextlib +import typing + +if typing.TYPE_CHECKING: + from ._models import Request, Response # pragma: no cover + +__all__ = [ + "CloseError", + "ConnectError", + "ConnectTimeout", + "CookieConflict", + "DecodingError", + "HTTPError", + "HTTPStatusError", + "InvalidURL", + "LocalProtocolError", + "NetworkError", + "PoolTimeout", + "ProtocolError", + "ProxyError", + "ReadError", + "ReadTimeout", + "RemoteProtocolError", + "RequestError", + "RequestNotRead", + "ResponseNotRead", + "StreamClosed", + "StreamConsumed", + "StreamError", + "TimeoutException", + "TooManyRedirects", + "TransportError", + "UnsupportedProtocol", + "WriteError", + "WriteTimeout", +] + + +class HTTPError(Exception): + """ + Base class for `RequestError` and `HTTPStatusError`. + + Useful for `try...except` blocks when issuing a request, + and then calling `.raise_for_status()`. + + For example: + + ``` + try: + response = httpx.get("https://www.example.com") + response.raise_for_status() + except httpx.HTTPError as exc: + print(f"HTTP Exception for {exc.request.url} - {exc}") + ``` + """ + + def __init__(self, message: str) -> None: + super().__init__(message) + self._request: Request | None = None + + @property + def request(self) -> Request: + if self._request is None: + raise RuntimeError("The .request property has not been set.") + return self._request + + @request.setter + def request(self, request: Request) -> None: + self._request = request + + +class RequestError(HTTPError): + """ + Base class for all exceptions that may occur when issuing a `.request()`. + """ + + def __init__(self, message: str, *, request: Request | None = None) -> None: + super().__init__(message) + # At the point an exception is raised we won't typically have a request + # instance to associate it with. + # + # The 'request_context' context manager is used within the Client and + # Response methods in order to ensure that any raised exceptions + # have a `.request` property set on them. + self._request = request + + +class TransportError(RequestError): + """ + Base class for all exceptions that occur at the level of the Transport API. + """ + + +# Timeout exceptions... + + +class TimeoutException(TransportError): + """ + The base class for timeout errors. + + An operation has timed out. + """ + + +class ConnectTimeout(TimeoutException): + """ + Timed out while connecting to the host. + """ + + +class ReadTimeout(TimeoutException): + """ + Timed out while receiving data from the host. + """ + + +class WriteTimeout(TimeoutException): + """ + Timed out while sending data to the host. + """ + + +class PoolTimeout(TimeoutException): + """ + Timed out waiting to acquire a connection from the pool. + """ + + +# Core networking exceptions... + + +class NetworkError(TransportError): + """ + The base class for network-related errors. + + An error occurred while interacting with the network. + """ + + +class ReadError(NetworkError): + """ + Failed to receive data from the network. + """ + + +class WriteError(NetworkError): + """ + Failed to send data through the network. + """ + + +class ConnectError(NetworkError): + """ + Failed to establish a connection. + """ + + +class CloseError(NetworkError): + """ + Failed to close a connection. + """ + + +# Other transport exceptions... + + +class ProxyError(TransportError): + """ + An error occurred while establishing a proxy connection. + """ + + +class UnsupportedProtocol(TransportError): + """ + Attempted to make a request to an unsupported protocol. + + For example issuing a request to `ftp://www.example.com`. + """ + + +class ProtocolError(TransportError): + """ + The protocol was violated. + """ + + +class LocalProtocolError(ProtocolError): + """ + A protocol was violated by the client. + + For example if the user instantiated a `Request` instance explicitly, + failed to include the mandatory `Host:` header, and then issued it directly + using `client.send()`. + """ + + +class RemoteProtocolError(ProtocolError): + """ + The protocol was violated by the server. + + For example, returning malformed HTTP. + """ + + +# Other request exceptions... + + +class DecodingError(RequestError): + """ + Decoding of the response failed, due to a malformed encoding. + """ + + +class TooManyRedirects(RequestError): + """ + Too many redirects. + """ + + +# Client errors + + +class HTTPStatusError(HTTPError): + """ + The response had an error HTTP status of 4xx or 5xx. + + May be raised when calling `response.raise_for_status()` + """ + + def __init__(self, message: str, *, request: Request, response: Response) -> None: + super().__init__(message) + self.request = request + self.response = response + + +class InvalidURL(Exception): + """ + URL is improperly formed or cannot be parsed. + """ + + def __init__(self, message: str) -> None: + super().__init__(message) + + +class CookieConflict(Exception): + """ + Attempted to lookup a cookie by name, but multiple cookies existed. + + Can occur when calling `response.cookies.get(...)`. + """ + + def __init__(self, message: str) -> None: + super().__init__(message) + + +# Stream exceptions... + +# These may occur as the result of a programming error, by accessing +# the request/response stream in an invalid manner. + + +class StreamError(RuntimeError): + """ + The base class for stream exceptions. + + The developer made an error in accessing the request stream in + an invalid way. + """ + + def __init__(self, message: str) -> None: + super().__init__(message) + + +class StreamConsumed(StreamError): + """ + Attempted to read or stream content, but the content has already + been streamed. + """ + + def __init__(self) -> None: + message = ( + "Attempted to read or stream some content, but the content has " + "already been streamed. For requests, this could be due to passing " + "a generator as request content, and then receiving a redirect " + "response or a secondary request as part of an authentication flow." + "For responses, this could be due to attempting to stream the response " + "content more than once." + ) + super().__init__(message) + + +class StreamClosed(StreamError): + """ + Attempted to read or stream response content, but the request has been + closed. + """ + + def __init__(self) -> None: + message = ( + "Attempted to read or stream content, but the stream has " "been closed." + ) + super().__init__(message) + + +class ResponseNotRead(StreamError): + """ + Attempted to access streaming response content, without having called `read()`. + """ + + def __init__(self) -> None: + message = ( + "Attempted to access streaming response content," + " without having called `read()`." + ) + super().__init__(message) + + +class RequestNotRead(StreamError): + """ + Attempted to access streaming request content, without having called `read()`. + """ + + def __init__(self) -> None: + message = ( + "Attempted to access streaming request content," + " without having called `read()`." + ) + super().__init__(message) + + +@contextlib.contextmanager +def request_context( + request: Request | None = None, +) -> typing.Iterator[None]: + """ + A context manager that can be used to attach the given request context + to any `RequestError` exceptions that are raised within the block. + """ + try: + yield + except RequestError as exc: + if request is not None: + exc.request = request + raise exc diff --git a/source/target-vendors/cp312/httpx/_main.py b/source/target-vendors/cp312/httpx/_main.py new file mode 100644 index 0000000..cffa4bb --- /dev/null +++ b/source/target-vendors/cp312/httpx/_main.py @@ -0,0 +1,506 @@ +from __future__ import annotations + +import functools +import json +import sys +import typing + +import click +import pygments.lexers +import pygments.util +import rich.console +import rich.markup +import rich.progress +import rich.syntax +import rich.table + +from ._client import Client +from ._exceptions import RequestError +from ._models import Response +from ._status_codes import codes + +if typing.TYPE_CHECKING: + import httpcore # pragma: no cover + + +def print_help() -> None: + console = rich.console.Console() + + console.print("[bold]HTTPX :butterfly:", justify="center") + console.print() + console.print("A next generation HTTP client.", justify="center") + console.print() + console.print( + "Usage: [bold]httpx[/bold] [cyan] [OPTIONS][/cyan] ", justify="left" + ) + console.print() + + table = rich.table.Table.grid(padding=1, pad_edge=True) + table.add_column("Parameter", no_wrap=True, justify="left", style="bold") + table.add_column("Description") + table.add_row( + "-m, --method [cyan]METHOD", + "Request method, such as GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD.\n" + "[Default: GET, or POST if a request body is included]", + ) + table.add_row( + "-p, --params [cyan] ...", + "Query parameters to include in the request URL.", + ) + table.add_row( + "-c, --content [cyan]TEXT", "Byte content to include in the request body." + ) + table.add_row( + "-d, --data [cyan] ...", "Form data to include in the request body." + ) + table.add_row( + "-f, --files [cyan] ...", + "Form files to include in the request body.", + ) + table.add_row("-j, --json [cyan]TEXT", "JSON data to include in the request body.") + table.add_row( + "-h, --headers [cyan] ...", + "Include additional HTTP headers in the request.", + ) + table.add_row( + "--cookies [cyan] ...", "Cookies to include in the request." + ) + table.add_row( + "--auth [cyan]", + "Username and password to include in the request. Specify '-' for the password" + " to use a password prompt. Note that using --verbose/-v will expose" + " the Authorization header, including the password encoding" + " in a trivially reversible format.", + ) + + table.add_row( + "--proxy [cyan]URL", + "Send the request via a proxy. Should be the URL giving the proxy address.", + ) + + table.add_row( + "--timeout [cyan]FLOAT", + "Timeout value to use for network operations, such as establishing the" + " connection, reading some data, etc... [Default: 5.0]", + ) + + table.add_row("--follow-redirects", "Automatically follow redirects.") + table.add_row("--no-verify", "Disable SSL verification.") + table.add_row( + "--http2", "Send the request using HTTP/2, if the remote server supports it." + ) + + table.add_row( + "--download [cyan]FILE", + "Save the response content as a file, rather than displaying it.", + ) + + table.add_row("-v, --verbose", "Verbose output. Show request as well as response.") + table.add_row("--help", "Show this message and exit.") + console.print(table) + + +def get_lexer_for_response(response: Response) -> str: + content_type = response.headers.get("Content-Type") + if content_type is not None: + mime_type, _, _ = content_type.partition(";") + try: + return typing.cast( + str, pygments.lexers.get_lexer_for_mimetype(mime_type.strip()).name + ) + except pygments.util.ClassNotFound: # pragma: no cover + pass + return "" # pragma: no cover + + +def format_request_headers(request: httpcore.Request, http2: bool = False) -> str: + version = "HTTP/2" if http2 else "HTTP/1.1" + headers = [ + (name.lower() if http2 else name, value) for name, value in request.headers + ] + method = request.method.decode("ascii") + target = request.url.target.decode("ascii") + lines = [f"{method} {target} {version}"] + [ + f"{name.decode('ascii')}: {value.decode('ascii')}" for name, value in headers + ] + return "\n".join(lines) + + +def format_response_headers( + http_version: bytes, + status: int, + reason_phrase: bytes | None, + headers: list[tuple[bytes, bytes]], +) -> str: + version = http_version.decode("ascii") + reason = ( + codes.get_reason_phrase(status) + if reason_phrase is None + else reason_phrase.decode("ascii") + ) + lines = [f"{version} {status} {reason}"] + [ + f"{name.decode('ascii')}: {value.decode('ascii')}" for name, value in headers + ] + return "\n".join(lines) + + +def print_request_headers(request: httpcore.Request, http2: bool = False) -> None: + console = rich.console.Console() + http_text = format_request_headers(request, http2=http2) + syntax = rich.syntax.Syntax(http_text, "http", theme="ansi_dark", word_wrap=True) + console.print(syntax) + syntax = rich.syntax.Syntax("", "http", theme="ansi_dark", word_wrap=True) + console.print(syntax) + + +def print_response_headers( + http_version: bytes, + status: int, + reason_phrase: bytes | None, + headers: list[tuple[bytes, bytes]], +) -> None: + console = rich.console.Console() + http_text = format_response_headers(http_version, status, reason_phrase, headers) + syntax = rich.syntax.Syntax(http_text, "http", theme="ansi_dark", word_wrap=True) + console.print(syntax) + syntax = rich.syntax.Syntax("", "http", theme="ansi_dark", word_wrap=True) + console.print(syntax) + + +def print_response(response: Response) -> None: + console = rich.console.Console() + lexer_name = get_lexer_for_response(response) + if lexer_name: + if lexer_name.lower() == "json": + try: + data = response.json() + text = json.dumps(data, indent=4) + except ValueError: # pragma: no cover + text = response.text + else: + text = response.text + + syntax = rich.syntax.Syntax(text, lexer_name, theme="ansi_dark", word_wrap=True) + console.print(syntax) + else: + console.print(f"<{len(response.content)} bytes of binary data>") + + +_PCTRTT = typing.Tuple[typing.Tuple[str, str], ...] +_PCTRTTT = typing.Tuple[_PCTRTT, ...] +_PeerCertRetDictType = typing.Dict[str, typing.Union[str, _PCTRTTT, _PCTRTT]] + + +def format_certificate(cert: _PeerCertRetDictType) -> str: # pragma: no cover + lines = [] + for key, value in cert.items(): + if isinstance(value, (list, tuple)): + lines.append(f"* {key}:") + for item in value: + if key in ("subject", "issuer"): + for sub_item in item: + lines.append(f"* {sub_item[0]}: {sub_item[1]!r}") + elif isinstance(item, tuple) and len(item) == 2: + lines.append(f"* {item[0]}: {item[1]!r}") + else: + lines.append(f"* {item!r}") + else: + lines.append(f"* {key}: {value!r}") + return "\n".join(lines) + + +def trace( + name: str, info: typing.Mapping[str, typing.Any], verbose: bool = False +) -> None: + console = rich.console.Console() + if name == "connection.connect_tcp.started" and verbose: + host = info["host"] + console.print(f"* Connecting to {host!r}") + elif name == "connection.connect_tcp.complete" and verbose: + stream = info["return_value"] + server_addr = stream.get_extra_info("server_addr") + console.print(f"* Connected to {server_addr[0]!r} on port {server_addr[1]}") + elif name == "connection.start_tls.complete" and verbose: # pragma: no cover + stream = info["return_value"] + ssl_object = stream.get_extra_info("ssl_object") + version = ssl_object.version() + cipher = ssl_object.cipher() + server_cert = ssl_object.getpeercert() + alpn = ssl_object.selected_alpn_protocol() + console.print(f"* SSL established using {version!r} / {cipher[0]!r}") + console.print(f"* Selected ALPN protocol: {alpn!r}") + if server_cert: + console.print("* Server certificate:") + console.print(format_certificate(server_cert)) + elif name == "http11.send_request_headers.started" and verbose: + request = info["request"] + print_request_headers(request, http2=False) + elif name == "http2.send_request_headers.started" and verbose: # pragma: no cover + request = info["request"] + print_request_headers(request, http2=True) + elif name == "http11.receive_response_headers.complete": + http_version, status, reason_phrase, headers = info["return_value"] + print_response_headers(http_version, status, reason_phrase, headers) + elif name == "http2.receive_response_headers.complete": # pragma: no cover + status, headers = info["return_value"] + http_version = b"HTTP/2" + reason_phrase = None + print_response_headers(http_version, status, reason_phrase, headers) + + +def download_response(response: Response, download: typing.BinaryIO) -> None: + console = rich.console.Console() + console.print() + content_length = response.headers.get("Content-Length") + with rich.progress.Progress( + "[progress.description]{task.description}", + "[progress.percentage]{task.percentage:>3.0f}%", + rich.progress.BarColumn(bar_width=None), + rich.progress.DownloadColumn(), + rich.progress.TransferSpeedColumn(), + ) as progress: + description = f"Downloading [bold]{rich.markup.escape(download.name)}" + download_task = progress.add_task( + description, + total=int(content_length or 0), + start=content_length is not None, + ) + for chunk in response.iter_bytes(): + download.write(chunk) + progress.update(download_task, completed=response.num_bytes_downloaded) + + +def validate_json( + ctx: click.Context, + param: click.Option | click.Parameter, + value: typing.Any, +) -> typing.Any: + if value is None: + return None + + try: + return json.loads(value) + except json.JSONDecodeError: # pragma: no cover + raise click.BadParameter("Not valid JSON") + + +def validate_auth( + ctx: click.Context, + param: click.Option | click.Parameter, + value: typing.Any, +) -> typing.Any: + if value == (None, None): + return None + + username, password = value + if password == "-": # pragma: no cover + password = click.prompt("Password", hide_input=True) + return (username, password) + + +def handle_help( + ctx: click.Context, + param: click.Option | click.Parameter, + value: typing.Any, +) -> None: + if not value or ctx.resilient_parsing: + return + + print_help() + ctx.exit() + + +@click.command(add_help_option=False) +@click.argument("url", type=str) +@click.option( + "--method", + "-m", + "method", + type=str, + help=( + "Request method, such as GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD. " + "[Default: GET, or POST if a request body is included]" + ), +) +@click.option( + "--params", + "-p", + "params", + type=(str, str), + multiple=True, + help="Query parameters to include in the request URL.", +) +@click.option( + "--content", + "-c", + "content", + type=str, + help="Byte content to include in the request body.", +) +@click.option( + "--data", + "-d", + "data", + type=(str, str), + multiple=True, + help="Form data to include in the request body.", +) +@click.option( + "--files", + "-f", + "files", + type=(str, click.File(mode="rb")), + multiple=True, + help="Form files to include in the request body.", +) +@click.option( + "--json", + "-j", + "json", + type=str, + callback=validate_json, + help="JSON data to include in the request body.", +) +@click.option( + "--headers", + "-h", + "headers", + type=(str, str), + multiple=True, + help="Include additional HTTP headers in the request.", +) +@click.option( + "--cookies", + "cookies", + type=(str, str), + multiple=True, + help="Cookies to include in the request.", +) +@click.option( + "--auth", + "auth", + type=(str, str), + default=(None, None), + callback=validate_auth, + help=( + "Username and password to include in the request. " + "Specify '-' for the password to use a password prompt. " + "Note that using --verbose/-v will expose the Authorization header, " + "including the password encoding in a trivially reversible format." + ), +) +@click.option( + "--proxy", + "proxy", + type=str, + default=None, + help="Send the request via a proxy. Should be the URL giving the proxy address.", +) +@click.option( + "--timeout", + "timeout", + type=float, + default=5.0, + help=( + "Timeout value to use for network operations, such as establishing the " + "connection, reading some data, etc... [Default: 5.0]" + ), +) +@click.option( + "--follow-redirects", + "follow_redirects", + is_flag=True, + default=False, + help="Automatically follow redirects.", +) +@click.option( + "--no-verify", + "verify", + is_flag=True, + default=True, + help="Disable SSL verification.", +) +@click.option( + "--http2", + "http2", + type=bool, + is_flag=True, + default=False, + help="Send the request using HTTP/2, if the remote server supports it.", +) +@click.option( + "--download", + type=click.File("wb"), + help="Save the response content as a file, rather than displaying it.", +) +@click.option( + "--verbose", + "-v", + type=bool, + is_flag=True, + default=False, + help="Verbose. Show request as well as response.", +) +@click.option( + "--help", + is_flag=True, + is_eager=True, + expose_value=False, + callback=handle_help, + help="Show this message and exit.", +) +def main( + url: str, + method: str, + params: list[tuple[str, str]], + content: str, + data: list[tuple[str, str]], + files: list[tuple[str, click.File]], + json: str, + headers: list[tuple[str, str]], + cookies: list[tuple[str, str]], + auth: tuple[str, str] | None, + proxy: str, + timeout: float, + follow_redirects: bool, + verify: bool, + http2: bool, + download: typing.BinaryIO | None, + verbose: bool, +) -> None: + """ + An HTTP command line client. + Sends a request and displays the response. + """ + if not method: + method = "POST" if content or data or files or json else "GET" + + try: + with Client(proxy=proxy, timeout=timeout, http2=http2, verify=verify) as client: + with client.stream( + method, + url, + params=list(params), + content=content, + data=dict(data), + files=files, # type: ignore + json=json, + headers=headers, + cookies=dict(cookies), + auth=auth, + follow_redirects=follow_redirects, + extensions={"trace": functools.partial(trace, verbose=verbose)}, + ) as response: + if download is not None: + download_response(response, download) + else: + response.read() + if response.content: + print_response(response) + + except RequestError as exc: + console = rich.console.Console() + console.print(f"[red]{type(exc).__name__}[/red]: {exc}") + sys.exit(1) + + sys.exit(0 if response.is_success else 1) diff --git a/source/target-vendors/cp312/httpx/_models.py b/source/target-vendors/cp312/httpx/_models.py new file mode 100644 index 0000000..67d74bf --- /dev/null +++ b/source/target-vendors/cp312/httpx/_models.py @@ -0,0 +1,1277 @@ +from __future__ import annotations + +import codecs +import datetime +import email.message +import json as jsonlib +import re +import typing +import urllib.request +from collections.abc import Mapping +from http.cookiejar import Cookie, CookieJar + +from ._content import ByteStream, UnattachedStream, encode_request, encode_response +from ._decoders import ( + SUPPORTED_DECODERS, + ByteChunker, + ContentDecoder, + IdentityDecoder, + LineDecoder, + MultiDecoder, + TextChunker, + TextDecoder, +) +from ._exceptions import ( + CookieConflict, + HTTPStatusError, + RequestNotRead, + ResponseNotRead, + StreamClosed, + StreamConsumed, + request_context, +) +from ._multipart import get_multipart_boundary_from_content_type +from ._status_codes import codes +from ._types import ( + AsyncByteStream, + CookieTypes, + HeaderTypes, + QueryParamTypes, + RequestContent, + RequestData, + RequestExtensions, + RequestFiles, + ResponseContent, + ResponseExtensions, + SyncByteStream, +) +from ._urls import URL +from ._utils import to_bytes_or_str, to_str + +__all__ = ["Cookies", "Headers", "Request", "Response"] + +SENSITIVE_HEADERS = {"authorization", "proxy-authorization"} + + +def _is_known_encoding(encoding: str) -> bool: + """ + Return `True` if `encoding` is a known codec. + """ + try: + codecs.lookup(encoding) + except LookupError: + return False + return True + + +def _normalize_header_key(key: str | bytes, encoding: str | None = None) -> bytes: + """ + Coerce str/bytes into a strictly byte-wise HTTP header key. + """ + return key if isinstance(key, bytes) else key.encode(encoding or "ascii") + + +def _normalize_header_value(value: str | bytes, encoding: str | None = None) -> bytes: + """ + Coerce str/bytes into a strictly byte-wise HTTP header value. + """ + if isinstance(value, bytes): + return value + if not isinstance(value, str): + raise TypeError(f"Header value must be str or bytes, not {type(value)}") + return value.encode(encoding or "ascii") + + +def _parse_content_type_charset(content_type: str) -> str | None: + # We used to use `cgi.parse_header()` here, but `cgi` became a dead battery. + # See: https://peps.python.org/pep-0594/#cgi + msg = email.message.Message() + msg["content-type"] = content_type + return msg.get_content_charset(failobj=None) + + +def _parse_header_links(value: str) -> list[dict[str, str]]: + """ + Returns a list of parsed link headers, for more info see: + https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link + The generic syntax of those is: + Link: < uri-reference >; param1=value1; param2="value2" + So for instance: + Link; '; type="image/jpeg",;' + would return + [ + {"url": "http:/.../front.jpeg", "type": "image/jpeg"}, + {"url": "http://.../back.jpeg"}, + ] + :param value: HTTP Link entity-header field + :return: list of parsed link headers + """ + links: list[dict[str, str]] = [] + replace_chars = " '\"" + value = value.strip(replace_chars) + if not value: + return links + for val in re.split(", *<", value): + try: + url, params = val.split(";", 1) + except ValueError: + url, params = val, "" + link = {"url": url.strip("<> '\"")} + for param in params.split(";"): + try: + key, value = param.split("=") + except ValueError: + break + link[key.strip(replace_chars)] = value.strip(replace_chars) + links.append(link) + return links + + +def _obfuscate_sensitive_headers( + items: typing.Iterable[tuple[typing.AnyStr, typing.AnyStr]], +) -> typing.Iterator[tuple[typing.AnyStr, typing.AnyStr]]: + for k, v in items: + if to_str(k.lower()) in SENSITIVE_HEADERS: + v = to_bytes_or_str("[secure]", match_type_of=v) + yield k, v + + +class Headers(typing.MutableMapping[str, str]): + """ + HTTP headers, as a case-insensitive multi-dict. + """ + + def __init__( + self, + headers: HeaderTypes | None = None, + encoding: str | None = None, + ) -> None: + self._list = [] # type: typing.List[typing.Tuple[bytes, bytes, bytes]] + + if isinstance(headers, Headers): + self._list = list(headers._list) + elif isinstance(headers, Mapping): + for k, v in headers.items(): + bytes_key = _normalize_header_key(k, encoding) + bytes_value = _normalize_header_value(v, encoding) + self._list.append((bytes_key, bytes_key.lower(), bytes_value)) + elif headers is not None: + for k, v in headers: + bytes_key = _normalize_header_key(k, encoding) + bytes_value = _normalize_header_value(v, encoding) + self._list.append((bytes_key, bytes_key.lower(), bytes_value)) + + self._encoding = encoding + + @property + def encoding(self) -> str: + """ + Header encoding is mandated as ascii, but we allow fallbacks to utf-8 + or iso-8859-1. + """ + if self._encoding is None: + for encoding in ["ascii", "utf-8"]: + for key, value in self.raw: + try: + key.decode(encoding) + value.decode(encoding) + except UnicodeDecodeError: + break + else: + # The else block runs if 'break' did not occur, meaning + # all values fitted the encoding. + self._encoding = encoding + break + else: + # The ISO-8859-1 encoding covers all 256 code points in a byte, + # so will never raise decode errors. + self._encoding = "iso-8859-1" + return self._encoding + + @encoding.setter + def encoding(self, value: str) -> None: + self._encoding = value + + @property + def raw(self) -> list[tuple[bytes, bytes]]: + """ + Returns a list of the raw header items, as byte pairs. + """ + return [(raw_key, value) for raw_key, _, value in self._list] + + def keys(self) -> typing.KeysView[str]: + return {key.decode(self.encoding): None for _, key, value in self._list}.keys() + + def values(self) -> typing.ValuesView[str]: + values_dict: dict[str, str] = {} + for _, key, value in self._list: + str_key = key.decode(self.encoding) + str_value = value.decode(self.encoding) + if str_key in values_dict: + values_dict[str_key] += f", {str_value}" + else: + values_dict[str_key] = str_value + return values_dict.values() + + def items(self) -> typing.ItemsView[str, str]: + """ + Return `(key, value)` items of headers. Concatenate headers + into a single comma separated value when a key occurs multiple times. + """ + values_dict: dict[str, str] = {} + for _, key, value in self._list: + str_key = key.decode(self.encoding) + str_value = value.decode(self.encoding) + if str_key in values_dict: + values_dict[str_key] += f", {str_value}" + else: + values_dict[str_key] = str_value + return values_dict.items() + + def multi_items(self) -> list[tuple[str, str]]: + """ + Return a list of `(key, value)` pairs of headers. Allow multiple + occurrences of the same key without concatenating into a single + comma separated value. + """ + return [ + (key.decode(self.encoding), value.decode(self.encoding)) + for _, key, value in self._list + ] + + def get(self, key: str, default: typing.Any = None) -> typing.Any: + """ + Return a header value. If multiple occurrences of the header occur + then concatenate them together with commas. + """ + try: + return self[key] + except KeyError: + return default + + def get_list(self, key: str, split_commas: bool = False) -> list[str]: + """ + Return a list of all header values for a given key. + If `split_commas=True` is passed, then any comma separated header + values are split into multiple return strings. + """ + get_header_key = key.lower().encode(self.encoding) + + values = [ + item_value.decode(self.encoding) + for _, item_key, item_value in self._list + if item_key.lower() == get_header_key + ] + + if not split_commas: + return values + + split_values = [] + for value in values: + split_values.extend([item.strip() for item in value.split(",")]) + return split_values + + def update(self, headers: HeaderTypes | None = None) -> None: # type: ignore + headers = Headers(headers) + for key in headers.keys(): + if key in self: + self.pop(key) + self._list.extend(headers._list) + + def copy(self) -> Headers: + return Headers(self, encoding=self.encoding) + + def __getitem__(self, key: str) -> str: + """ + Return a single header value. + + If there are multiple headers with the same key, then we concatenate + them with commas. See: https://tools.ietf.org/html/rfc7230#section-3.2.2 + """ + normalized_key = key.lower().encode(self.encoding) + + items = [ + header_value.decode(self.encoding) + for _, header_key, header_value in self._list + if header_key == normalized_key + ] + + if items: + return ", ".join(items) + + raise KeyError(key) + + def __setitem__(self, key: str, value: str) -> None: + """ + Set the header `key` to `value`, removing any duplicate entries. + Retains insertion order. + """ + set_key = key.encode(self._encoding or "utf-8") + set_value = value.encode(self._encoding or "utf-8") + lookup_key = set_key.lower() + + found_indexes = [ + idx + for idx, (_, item_key, _) in enumerate(self._list) + if item_key == lookup_key + ] + + for idx in reversed(found_indexes[1:]): + del self._list[idx] + + if found_indexes: + idx = found_indexes[0] + self._list[idx] = (set_key, lookup_key, set_value) + else: + self._list.append((set_key, lookup_key, set_value)) + + def __delitem__(self, key: str) -> None: + """ + Remove the header `key`. + """ + del_key = key.lower().encode(self.encoding) + + pop_indexes = [ + idx + for idx, (_, item_key, _) in enumerate(self._list) + if item_key.lower() == del_key + ] + + if not pop_indexes: + raise KeyError(key) + + for idx in reversed(pop_indexes): + del self._list[idx] + + def __contains__(self, key: typing.Any) -> bool: + header_key = key.lower().encode(self.encoding) + return header_key in [key for _, key, _ in self._list] + + def __iter__(self) -> typing.Iterator[typing.Any]: + return iter(self.keys()) + + def __len__(self) -> int: + return len(self._list) + + def __eq__(self, other: typing.Any) -> bool: + try: + other_headers = Headers(other) + except ValueError: + return False + + self_list = [(key, value) for _, key, value in self._list] + other_list = [(key, value) for _, key, value in other_headers._list] + return sorted(self_list) == sorted(other_list) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + + encoding_str = "" + if self.encoding != "ascii": + encoding_str = f", encoding={self.encoding!r}" + + as_list = list(_obfuscate_sensitive_headers(self.multi_items())) + as_dict = dict(as_list) + + no_duplicate_keys = len(as_dict) == len(as_list) + if no_duplicate_keys: + return f"{class_name}({as_dict!r}{encoding_str})" + return f"{class_name}({as_list!r}{encoding_str})" + + +class Request: + def __init__( + self, + method: str, + url: URL | str, + *, + params: QueryParamTypes | None = None, + headers: HeaderTypes | None = None, + cookies: CookieTypes | None = None, + content: RequestContent | None = None, + data: RequestData | None = None, + files: RequestFiles | None = None, + json: typing.Any | None = None, + stream: SyncByteStream | AsyncByteStream | None = None, + extensions: RequestExtensions | None = None, + ) -> None: + self.method = method.upper() + self.url = URL(url) if params is None else URL(url, params=params) + self.headers = Headers(headers) + self.extensions = {} if extensions is None else dict(extensions) + + if cookies: + Cookies(cookies).set_cookie_header(self) + + if stream is None: + content_type: str | None = self.headers.get("content-type") + headers, stream = encode_request( + content=content, + data=data, + files=files, + json=json, + boundary=get_multipart_boundary_from_content_type( + content_type=content_type.encode(self.headers.encoding) + if content_type + else None + ), + ) + self._prepare(headers) + self.stream = stream + # Load the request body, except for streaming content. + if isinstance(stream, ByteStream): + self.read() + else: + # There's an important distinction between `Request(content=...)`, + # and `Request(stream=...)`. + # + # Using `content=...` implies automatically populated `Host` and content + # headers, of either `Content-Length: ...` or `Transfer-Encoding: chunked`. + # + # Using `stream=...` will not automatically include *any* + # auto-populated headers. + # + # As an end-user you don't really need `stream=...`. It's only + # useful when: + # + # * Preserving the request stream when copying requests, eg for redirects. + # * Creating request instances on the *server-side* of the transport API. + self.stream = stream + + def _prepare(self, default_headers: dict[str, str]) -> None: + for key, value in default_headers.items(): + # Ignore Transfer-Encoding if the Content-Length has been set explicitly. + if key.lower() == "transfer-encoding" and "Content-Length" in self.headers: + continue + self.headers.setdefault(key, value) + + auto_headers: list[tuple[bytes, bytes]] = [] + + has_host = "Host" in self.headers + has_content_length = ( + "Content-Length" in self.headers or "Transfer-Encoding" in self.headers + ) + + if not has_host and self.url.host: + auto_headers.append((b"Host", self.url.netloc)) + if not has_content_length and self.method in ("POST", "PUT", "PATCH"): + auto_headers.append((b"Content-Length", b"0")) + + self.headers = Headers(auto_headers + self.headers.raw) + + @property + def content(self) -> bytes: + if not hasattr(self, "_content"): + raise RequestNotRead() + return self._content + + def read(self) -> bytes: + """ + Read and return the request content. + """ + if not hasattr(self, "_content"): + assert isinstance(self.stream, typing.Iterable) + self._content = b"".join(self.stream) + if not isinstance(self.stream, ByteStream): + # If a streaming request has been read entirely into memory, then + # we can replace the stream with a raw bytes implementation, + # to ensure that any non-replayable streams can still be used. + self.stream = ByteStream(self._content) + return self._content + + async def aread(self) -> bytes: + """ + Read and return the request content. + """ + if not hasattr(self, "_content"): + assert isinstance(self.stream, typing.AsyncIterable) + self._content = b"".join([part async for part in self.stream]) + if not isinstance(self.stream, ByteStream): + # If a streaming request has been read entirely into memory, then + # we can replace the stream with a raw bytes implementation, + # to ensure that any non-replayable streams can still be used. + self.stream = ByteStream(self._content) + return self._content + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + url = str(self.url) + return f"<{class_name}({self.method!r}, {url!r})>" + + def __getstate__(self) -> dict[str, typing.Any]: + return { + name: value + for name, value in self.__dict__.items() + if name not in ["extensions", "stream"] + } + + def __setstate__(self, state: dict[str, typing.Any]) -> None: + for name, value in state.items(): + setattr(self, name, value) + self.extensions = {} + self.stream = UnattachedStream() + + +class Response: + def __init__( + self, + status_code: int, + *, + headers: HeaderTypes | None = None, + content: ResponseContent | None = None, + text: str | None = None, + html: str | None = None, + json: typing.Any = None, + stream: SyncByteStream | AsyncByteStream | None = None, + request: Request | None = None, + extensions: ResponseExtensions | None = None, + history: list[Response] | None = None, + default_encoding: str | typing.Callable[[bytes], str] = "utf-8", + ) -> None: + self.status_code = status_code + self.headers = Headers(headers) + + self._request: Request | None = request + + # When follow_redirects=False and a redirect is received, + # the client will set `response.next_request`. + self.next_request: Request | None = None + + self.extensions = {} if extensions is None else dict(extensions) + self.history = [] if history is None else list(history) + + self.is_closed = False + self.is_stream_consumed = False + + self.default_encoding = default_encoding + + if stream is None: + headers, stream = encode_response(content, text, html, json) + self._prepare(headers) + self.stream = stream + if isinstance(stream, ByteStream): + # Load the response body, except for streaming content. + self.read() + else: + # There's an important distinction between `Response(content=...)`, + # and `Response(stream=...)`. + # + # Using `content=...` implies automatically populated content headers, + # of either `Content-Length: ...` or `Transfer-Encoding: chunked`. + # + # Using `stream=...` will not automatically include any content headers. + # + # As an end-user you don't really need `stream=...`. It's only + # useful when creating response instances having received a stream + # from the transport API. + self.stream = stream + + self._num_bytes_downloaded = 0 + + def _prepare(self, default_headers: dict[str, str]) -> None: + for key, value in default_headers.items(): + # Ignore Transfer-Encoding if the Content-Length has been set explicitly. + if key.lower() == "transfer-encoding" and "content-length" in self.headers: + continue + self.headers.setdefault(key, value) + + @property + def elapsed(self) -> datetime.timedelta: + """ + Returns the time taken for the complete request/response + cycle to complete. + """ + if not hasattr(self, "_elapsed"): + raise RuntimeError( + "'.elapsed' may only be accessed after the response " + "has been read or closed." + ) + return self._elapsed + + @elapsed.setter + def elapsed(self, elapsed: datetime.timedelta) -> None: + self._elapsed = elapsed + + @property + def request(self) -> Request: + """ + Returns the request instance associated to the current response. + """ + if self._request is None: + raise RuntimeError( + "The request instance has not been set on this response." + ) + return self._request + + @request.setter + def request(self, value: Request) -> None: + self._request = value + + @property + def http_version(self) -> str: + try: + http_version: bytes = self.extensions["http_version"] + except KeyError: + return "HTTP/1.1" + else: + return http_version.decode("ascii", errors="ignore") + + @property + def reason_phrase(self) -> str: + try: + reason_phrase: bytes = self.extensions["reason_phrase"] + except KeyError: + return codes.get_reason_phrase(self.status_code) + else: + return reason_phrase.decode("ascii", errors="ignore") + + @property + def url(self) -> URL: + """ + Returns the URL for which the request was made. + """ + return self.request.url + + @property + def content(self) -> bytes: + if not hasattr(self, "_content"): + raise ResponseNotRead() + return self._content + + @property + def text(self) -> str: + if not hasattr(self, "_text"): + content = self.content + if not content: + self._text = "" + else: + decoder = TextDecoder(encoding=self.encoding or "utf-8") + self._text = "".join([decoder.decode(self.content), decoder.flush()]) + return self._text + + @property + def encoding(self) -> str | None: + """ + Return an encoding to use for decoding the byte content into text. + The priority for determining this is given by... + + * `.encoding = <>` has been set explicitly. + * The encoding as specified by the charset parameter in the Content-Type header. + * The encoding as determined by `default_encoding`, which may either be + a string like "utf-8" indicating the encoding to use, or may be a callable + which enables charset autodetection. + """ + if not hasattr(self, "_encoding"): + encoding = self.charset_encoding + if encoding is None or not _is_known_encoding(encoding): + if isinstance(self.default_encoding, str): + encoding = self.default_encoding + elif hasattr(self, "_content"): + encoding = self.default_encoding(self._content) + self._encoding = encoding or "utf-8" + return self._encoding + + @encoding.setter + def encoding(self, value: str) -> None: + """ + Set the encoding to use for decoding the byte content into text. + + If the `text` attribute has been accessed, attempting to set the + encoding will throw a ValueError. + """ + if hasattr(self, "_text"): + raise ValueError( + "Setting encoding after `text` has been accessed is not allowed." + ) + self._encoding = value + + @property + def charset_encoding(self) -> str | None: + """ + Return the encoding, as specified by the Content-Type header. + """ + content_type = self.headers.get("Content-Type") + if content_type is None: + return None + + return _parse_content_type_charset(content_type) + + def _get_content_decoder(self) -> ContentDecoder: + """ + Returns a decoder instance which can be used to decode the raw byte + content, depending on the Content-Encoding used in the response. + """ + if not hasattr(self, "_decoder"): + decoders: list[ContentDecoder] = [] + values = self.headers.get_list("content-encoding", split_commas=True) + for value in values: + value = value.strip().lower() + try: + decoder_cls = SUPPORTED_DECODERS[value] + decoders.append(decoder_cls()) + except KeyError: + continue + + if len(decoders) == 1: + self._decoder = decoders[0] + elif len(decoders) > 1: + self._decoder = MultiDecoder(children=decoders) + else: + self._decoder = IdentityDecoder() + + return self._decoder + + @property + def is_informational(self) -> bool: + """ + A property which is `True` for 1xx status codes, `False` otherwise. + """ + return codes.is_informational(self.status_code) + + @property + def is_success(self) -> bool: + """ + A property which is `True` for 2xx status codes, `False` otherwise. + """ + return codes.is_success(self.status_code) + + @property + def is_redirect(self) -> bool: + """ + A property which is `True` for 3xx status codes, `False` otherwise. + + Note that not all responses with a 3xx status code indicate a URL redirect. + + Use `response.has_redirect_location` to determine responses with a properly + formed URL redirection. + """ + return codes.is_redirect(self.status_code) + + @property + def is_client_error(self) -> bool: + """ + A property which is `True` for 4xx status codes, `False` otherwise. + """ + return codes.is_client_error(self.status_code) + + @property + def is_server_error(self) -> bool: + """ + A property which is `True` for 5xx status codes, `False` otherwise. + """ + return codes.is_server_error(self.status_code) + + @property + def is_error(self) -> bool: + """ + A property which is `True` for 4xx and 5xx status codes, `False` otherwise. + """ + return codes.is_error(self.status_code) + + @property + def has_redirect_location(self) -> bool: + """ + Returns True for 3xx responses with a properly formed URL redirection, + `False` otherwise. + """ + return ( + self.status_code + in ( + # 301 (Cacheable redirect. Method may change to GET.) + codes.MOVED_PERMANENTLY, + # 302 (Uncacheable redirect. Method may change to GET.) + codes.FOUND, + # 303 (Client should make a GET or HEAD request.) + codes.SEE_OTHER, + # 307 (Equiv. 302, but retain method) + codes.TEMPORARY_REDIRECT, + # 308 (Equiv. 301, but retain method) + codes.PERMANENT_REDIRECT, + ) + and "Location" in self.headers + ) + + def raise_for_status(self) -> Response: + """ + Raise the `HTTPStatusError` if one occurred. + """ + request = self._request + if request is None: + raise RuntimeError( + "Cannot call `raise_for_status` as the request " + "instance has not been set on this response." + ) + + if self.is_success: + return self + + if self.has_redirect_location: + message = ( + "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" + "Redirect location: '{0.headers[location]}'\n" + "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}" + ) + else: + message = ( + "{error_type} '{0.status_code} {0.reason_phrase}' for url '{0.url}'\n" + "For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/{0.status_code}" + ) + + status_class = self.status_code // 100 + error_types = { + 1: "Informational response", + 3: "Redirect response", + 4: "Client error", + 5: "Server error", + } + error_type = error_types.get(status_class, "Invalid status code") + message = message.format(self, error_type=error_type) + raise HTTPStatusError(message, request=request, response=self) + + def json(self, **kwargs: typing.Any) -> typing.Any: + return jsonlib.loads(self.content, **kwargs) + + @property + def cookies(self) -> Cookies: + if not hasattr(self, "_cookies"): + self._cookies = Cookies() + self._cookies.extract_cookies(self) + return self._cookies + + @property + def links(self) -> dict[str | None, dict[str, str]]: + """ + Returns the parsed header links of the response, if any + """ + header = self.headers.get("link") + if header is None: + return {} + + return { + (link.get("rel") or link.get("url")): link + for link in _parse_header_links(header) + } + + @property + def num_bytes_downloaded(self) -> int: + return self._num_bytes_downloaded + + def __repr__(self) -> str: + return f"" + + def __getstate__(self) -> dict[str, typing.Any]: + return { + name: value + for name, value in self.__dict__.items() + if name not in ["extensions", "stream", "is_closed", "_decoder"] + } + + def __setstate__(self, state: dict[str, typing.Any]) -> None: + for name, value in state.items(): + setattr(self, name, value) + self.is_closed = True + self.extensions = {} + self.stream = UnattachedStream() + + def read(self) -> bytes: + """ + Read and return the response content. + """ + if not hasattr(self, "_content"): + self._content = b"".join(self.iter_bytes()) + return self._content + + def iter_bytes(self, chunk_size: int | None = None) -> typing.Iterator[bytes]: + """ + A byte-iterator over the decoded response content. + This allows us to handle gzip, deflate, brotli, and zstd encoded responses. + """ + if hasattr(self, "_content"): + chunk_size = len(self._content) if chunk_size is None else chunk_size + for i in range(0, len(self._content), max(chunk_size, 1)): + yield self._content[i : i + chunk_size] + else: + decoder = self._get_content_decoder() + chunker = ByteChunker(chunk_size=chunk_size) + with request_context(request=self._request): + for raw_bytes in self.iter_raw(): + decoded = decoder.decode(raw_bytes) + for chunk in chunker.decode(decoded): + yield chunk + decoded = decoder.flush() + for chunk in chunker.decode(decoded): + yield chunk # pragma: no cover + for chunk in chunker.flush(): + yield chunk + + def iter_text(self, chunk_size: int | None = None) -> typing.Iterator[str]: + """ + A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + decoder = TextDecoder(encoding=self.encoding or "utf-8") + chunker = TextChunker(chunk_size=chunk_size) + with request_context(request=self._request): + for byte_content in self.iter_bytes(): + text_content = decoder.decode(byte_content) + for chunk in chunker.decode(text_content): + yield chunk + text_content = decoder.flush() + for chunk in chunker.decode(text_content): + yield chunk # pragma: no cover + for chunk in chunker.flush(): + yield chunk + + def iter_lines(self) -> typing.Iterator[str]: + decoder = LineDecoder() + with request_context(request=self._request): + for text in self.iter_text(): + for line in decoder.decode(text): + yield line + for line in decoder.flush(): + yield line + + def iter_raw(self, chunk_size: int | None = None) -> typing.Iterator[bytes]: + """ + A byte-iterator over the raw response content. + """ + if self.is_stream_consumed: + raise StreamConsumed() + if self.is_closed: + raise StreamClosed() + if not isinstance(self.stream, SyncByteStream): + raise RuntimeError("Attempted to call a sync iterator on an async stream.") + + self.is_stream_consumed = True + self._num_bytes_downloaded = 0 + chunker = ByteChunker(chunk_size=chunk_size) + + with request_context(request=self._request): + for raw_stream_bytes in self.stream: + self._num_bytes_downloaded += len(raw_stream_bytes) + for chunk in chunker.decode(raw_stream_bytes): + yield chunk + + for chunk in chunker.flush(): + yield chunk + + self.close() + + def close(self) -> None: + """ + Close the response and release the connection. + Automatically called if the response body is read to completion. + """ + if not isinstance(self.stream, SyncByteStream): + raise RuntimeError("Attempted to call an sync close on an async stream.") + + if not self.is_closed: + self.is_closed = True + with request_context(request=self._request): + self.stream.close() + + async def aread(self) -> bytes: + """ + Read and return the response content. + """ + if not hasattr(self, "_content"): + self._content = b"".join([part async for part in self.aiter_bytes()]) + return self._content + + async def aiter_bytes( + self, chunk_size: int | None = None + ) -> typing.AsyncIterator[bytes]: + """ + A byte-iterator over the decoded response content. + This allows us to handle gzip, deflate, brotli, and zstd encoded responses. + """ + if hasattr(self, "_content"): + chunk_size = len(self._content) if chunk_size is None else chunk_size + for i in range(0, len(self._content), max(chunk_size, 1)): + yield self._content[i : i + chunk_size] + else: + decoder = self._get_content_decoder() + chunker = ByteChunker(chunk_size=chunk_size) + with request_context(request=self._request): + async for raw_bytes in self.aiter_raw(): + decoded = decoder.decode(raw_bytes) + for chunk in chunker.decode(decoded): + yield chunk + decoded = decoder.flush() + for chunk in chunker.decode(decoded): + yield chunk # pragma: no cover + for chunk in chunker.flush(): + yield chunk + + async def aiter_text( + self, chunk_size: int | None = None + ) -> typing.AsyncIterator[str]: + """ + A str-iterator over the decoded response content + that handles both gzip, deflate, etc but also detects the content's + string encoding. + """ + decoder = TextDecoder(encoding=self.encoding or "utf-8") + chunker = TextChunker(chunk_size=chunk_size) + with request_context(request=self._request): + async for byte_content in self.aiter_bytes(): + text_content = decoder.decode(byte_content) + for chunk in chunker.decode(text_content): + yield chunk + text_content = decoder.flush() + for chunk in chunker.decode(text_content): + yield chunk # pragma: no cover + for chunk in chunker.flush(): + yield chunk + + async def aiter_lines(self) -> typing.AsyncIterator[str]: + decoder = LineDecoder() + with request_context(request=self._request): + async for text in self.aiter_text(): + for line in decoder.decode(text): + yield line + for line in decoder.flush(): + yield line + + async def aiter_raw( + self, chunk_size: int | None = None + ) -> typing.AsyncIterator[bytes]: + """ + A byte-iterator over the raw response content. + """ + if self.is_stream_consumed: + raise StreamConsumed() + if self.is_closed: + raise StreamClosed() + if not isinstance(self.stream, AsyncByteStream): + raise RuntimeError("Attempted to call an async iterator on an sync stream.") + + self.is_stream_consumed = True + self._num_bytes_downloaded = 0 + chunker = ByteChunker(chunk_size=chunk_size) + + with request_context(request=self._request): + async for raw_stream_bytes in self.stream: + self._num_bytes_downloaded += len(raw_stream_bytes) + for chunk in chunker.decode(raw_stream_bytes): + yield chunk + + for chunk in chunker.flush(): + yield chunk + + await self.aclose() + + async def aclose(self) -> None: + """ + Close the response and release the connection. + Automatically called if the response body is read to completion. + """ + if not isinstance(self.stream, AsyncByteStream): + raise RuntimeError("Attempted to call an async close on an sync stream.") + + if not self.is_closed: + self.is_closed = True + with request_context(request=self._request): + await self.stream.aclose() + + +class Cookies(typing.MutableMapping[str, str]): + """ + HTTP Cookies, as a mutable mapping. + """ + + def __init__(self, cookies: CookieTypes | None = None) -> None: + if cookies is None or isinstance(cookies, dict): + self.jar = CookieJar() + if isinstance(cookies, dict): + for key, value in cookies.items(): + self.set(key, value) + elif isinstance(cookies, list): + self.jar = CookieJar() + for key, value in cookies: + self.set(key, value) + elif isinstance(cookies, Cookies): + self.jar = CookieJar() + for cookie in cookies.jar: + self.jar.set_cookie(cookie) + else: + self.jar = cookies + + def extract_cookies(self, response: Response) -> None: + """ + Loads any cookies based on the response `Set-Cookie` headers. + """ + urllib_response = self._CookieCompatResponse(response) + urllib_request = self._CookieCompatRequest(response.request) + + self.jar.extract_cookies(urllib_response, urllib_request) # type: ignore + + def set_cookie_header(self, request: Request) -> None: + """ + Sets an appropriate 'Cookie:' HTTP header on the `Request`. + """ + urllib_request = self._CookieCompatRequest(request) + self.jar.add_cookie_header(urllib_request) + + def set(self, name: str, value: str, domain: str = "", path: str = "/") -> None: + """ + Set a cookie value by name. May optionally include domain and path. + """ + kwargs = { + "version": 0, + "name": name, + "value": value, + "port": None, + "port_specified": False, + "domain": domain, + "domain_specified": bool(domain), + "domain_initial_dot": domain.startswith("."), + "path": path, + "path_specified": bool(path), + "secure": False, + "expires": None, + "discard": True, + "comment": None, + "comment_url": None, + "rest": {"HttpOnly": None}, + "rfc2109": False, + } + cookie = Cookie(**kwargs) # type: ignore + self.jar.set_cookie(cookie) + + def get( # type: ignore + self, + name: str, + default: str | None = None, + domain: str | None = None, + path: str | None = None, + ) -> str | None: + """ + Get a cookie by name. May optionally include domain and path + in order to specify exactly which cookie to retrieve. + """ + value = None + for cookie in self.jar: + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + if value is not None: + message = f"Multiple cookies exist with name={name}" + raise CookieConflict(message) + value = cookie.value + + if value is None: + return default + return value + + def delete( + self, + name: str, + domain: str | None = None, + path: str | None = None, + ) -> None: + """ + Delete a cookie by name. May optionally include domain and path + in order to specify exactly which cookie to delete. + """ + if domain is not None and path is not None: + return self.jar.clear(domain, path, name) + + remove = [ + cookie + for cookie in self.jar + if cookie.name == name + and (domain is None or cookie.domain == domain) + and (path is None or cookie.path == path) + ] + + for cookie in remove: + self.jar.clear(cookie.domain, cookie.path, cookie.name) + + def clear(self, domain: str | None = None, path: str | None = None) -> None: + """ + Delete all cookies. Optionally include a domain and path in + order to only delete a subset of all the cookies. + """ + args = [] + if domain is not None: + args.append(domain) + if path is not None: + assert domain is not None + args.append(path) + self.jar.clear(*args) + + def update(self, cookies: CookieTypes | None = None) -> None: # type: ignore + cookies = Cookies(cookies) + for cookie in cookies.jar: + self.jar.set_cookie(cookie) + + def __setitem__(self, name: str, value: str) -> None: + return self.set(name, value) + + def __getitem__(self, name: str) -> str: + value = self.get(name) + if value is None: + raise KeyError(name) + return value + + def __delitem__(self, name: str) -> None: + return self.delete(name) + + def __len__(self) -> int: + return len(self.jar) + + def __iter__(self) -> typing.Iterator[str]: + return (cookie.name for cookie in self.jar) + + def __bool__(self) -> bool: + for _ in self.jar: + return True + return False + + def __repr__(self) -> str: + cookies_repr = ", ".join( + [ + f"" + for cookie in self.jar + ] + ) + + return f"" + + class _CookieCompatRequest(urllib.request.Request): + """ + Wraps a `Request` instance up in a compatibility interface suitable + for use with `CookieJar` operations. + """ + + def __init__(self, request: Request) -> None: + super().__init__( + url=str(request.url), + headers=dict(request.headers), + method=request.method, + ) + self.request = request + + def add_unredirected_header(self, key: str, value: str) -> None: + super().add_unredirected_header(key, value) + self.request.headers[key] = value + + class _CookieCompatResponse: + """ + Wraps a `Request` instance up in a compatibility interface suitable + for use with `CookieJar` operations. + """ + + def __init__(self, response: Response) -> None: + self.response = response + + def info(self) -> email.message.Message: + info = email.message.Message() + for key, value in self.response.headers.multi_items(): + # Note that setting `info[key]` here is an "append" operation, + # not a "replace" operation. + # https://docs.python.org/3/library/email.compat32-message.html#email.message.Message.__setitem__ + info[key] = value + return info diff --git a/source/target-vendors/cp312/httpx/_multipart.py b/source/target-vendors/cp312/httpx/_multipart.py new file mode 100644 index 0000000..b4761af --- /dev/null +++ b/source/target-vendors/cp312/httpx/_multipart.py @@ -0,0 +1,300 @@ +from __future__ import annotations + +import io +import mimetypes +import os +import re +import typing +from pathlib import Path + +from ._types import ( + AsyncByteStream, + FileContent, + FileTypes, + RequestData, + RequestFiles, + SyncByteStream, +) +from ._utils import ( + peek_filelike_length, + primitive_value_to_str, + to_bytes, +) + +_HTML5_FORM_ENCODING_REPLACEMENTS = {'"': "%22", "\\": "\\\\"} +_HTML5_FORM_ENCODING_REPLACEMENTS.update( + {chr(c): "%{:02X}".format(c) for c in range(0x1F + 1) if c != 0x1B} +) +_HTML5_FORM_ENCODING_RE = re.compile( + r"|".join([re.escape(c) for c in _HTML5_FORM_ENCODING_REPLACEMENTS.keys()]) +) + + +def _format_form_param(name: str, value: str) -> bytes: + """ + Encode a name/value pair within a multipart form. + """ + + def replacer(match: typing.Match[str]) -> str: + return _HTML5_FORM_ENCODING_REPLACEMENTS[match.group(0)] + + value = _HTML5_FORM_ENCODING_RE.sub(replacer, value) + return f'{name}="{value}"'.encode() + + +def _guess_content_type(filename: str | None) -> str | None: + """ + Guesses the mimetype based on a filename. Defaults to `application/octet-stream`. + + Returns `None` if `filename` is `None` or empty. + """ + if filename: + return mimetypes.guess_type(filename)[0] or "application/octet-stream" + return None + + +def get_multipart_boundary_from_content_type( + content_type: bytes | None, +) -> bytes | None: + if not content_type or not content_type.startswith(b"multipart/form-data"): + return None + # parse boundary according to + # https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1 + if b";" in content_type: + for section in content_type.split(b";"): + if section.strip().lower().startswith(b"boundary="): + return section.strip()[len(b"boundary=") :].strip(b'"') + return None + + +class DataField: + """ + A single form field item, within a multipart form field. + """ + + def __init__(self, name: str, value: str | bytes | int | float | None) -> None: + if not isinstance(name, str): + raise TypeError( + f"Invalid type for name. Expected str, got {type(name)}: {name!r}" + ) + if value is not None and not isinstance(value, (str, bytes, int, float)): + raise TypeError( + "Invalid type for value. Expected primitive type," + f" got {type(value)}: {value!r}" + ) + self.name = name + self.value: str | bytes = ( + value if isinstance(value, bytes) else primitive_value_to_str(value) + ) + + def render_headers(self) -> bytes: + if not hasattr(self, "_headers"): + name = _format_form_param("name", self.name) + self._headers = b"".join( + [b"Content-Disposition: form-data; ", name, b"\r\n\r\n"] + ) + + return self._headers + + def render_data(self) -> bytes: + if not hasattr(self, "_data"): + self._data = to_bytes(self.value) + + return self._data + + def get_length(self) -> int: + headers = self.render_headers() + data = self.render_data() + return len(headers) + len(data) + + def render(self) -> typing.Iterator[bytes]: + yield self.render_headers() + yield self.render_data() + + +class FileField: + """ + A single file field item, within a multipart form field. + """ + + CHUNK_SIZE = 64 * 1024 + + def __init__(self, name: str, value: FileTypes) -> None: + self.name = name + + fileobj: FileContent + + headers: dict[str, str] = {} + content_type: str | None = None + + # This large tuple based API largely mirror's requests' API + # It would be good to think of better APIs for this that we could + # include in httpx 2.0 since variable length tuples(especially of 4 elements) + # are quite unwieldly + if isinstance(value, tuple): + if len(value) == 2: + # neither the 3rd parameter (content_type) nor the 4th (headers) + # was included + filename, fileobj = value + elif len(value) == 3: + filename, fileobj, content_type = value + else: + # all 4 parameters included + filename, fileobj, content_type, headers = value # type: ignore + else: + filename = Path(str(getattr(value, "name", "upload"))).name + fileobj = value + + if content_type is None: + content_type = _guess_content_type(filename) + + has_content_type_header = any("content-type" in key.lower() for key in headers) + if content_type is not None and not has_content_type_header: + # note that unlike requests, we ignore the content_type provided in the 3rd + # tuple element if it is also included in the headers requests does + # the opposite (it overwrites the headerwith the 3rd tuple element) + headers["Content-Type"] = content_type + + if isinstance(fileobj, io.StringIO): + raise TypeError( + "Multipart file uploads require 'io.BytesIO', not 'io.StringIO'." + ) + if isinstance(fileobj, io.TextIOBase): + raise TypeError( + "Multipart file uploads must be opened in binary mode, not text mode." + ) + + self.filename = filename + self.file = fileobj + self.headers = headers + + def get_length(self) -> int | None: + headers = self.render_headers() + + if isinstance(self.file, (str, bytes)): + return len(headers) + len(to_bytes(self.file)) + + file_length = peek_filelike_length(self.file) + + # If we can't determine the filesize without reading it into memory, + # then return `None` here, to indicate an unknown file length. + if file_length is None: + return None + + return len(headers) + file_length + + def render_headers(self) -> bytes: + if not hasattr(self, "_headers"): + parts = [ + b"Content-Disposition: form-data; ", + _format_form_param("name", self.name), + ] + if self.filename: + filename = _format_form_param("filename", self.filename) + parts.extend([b"; ", filename]) + for header_name, header_value in self.headers.items(): + key, val = f"\r\n{header_name}: ".encode(), header_value.encode() + parts.extend([key, val]) + parts.append(b"\r\n\r\n") + self._headers = b"".join(parts) + + return self._headers + + def render_data(self) -> typing.Iterator[bytes]: + if isinstance(self.file, (str, bytes)): + yield to_bytes(self.file) + return + + if hasattr(self.file, "seek"): + try: + self.file.seek(0) + except io.UnsupportedOperation: + pass + + chunk = self.file.read(self.CHUNK_SIZE) + while chunk: + yield to_bytes(chunk) + chunk = self.file.read(self.CHUNK_SIZE) + + def render(self) -> typing.Iterator[bytes]: + yield self.render_headers() + yield from self.render_data() + + +class MultipartStream(SyncByteStream, AsyncByteStream): + """ + Request content as streaming multipart encoded form data. + """ + + def __init__( + self, + data: RequestData, + files: RequestFiles, + boundary: bytes | None = None, + ) -> None: + if boundary is None: + boundary = os.urandom(16).hex().encode("ascii") + + self.boundary = boundary + self.content_type = "multipart/form-data; boundary=%s" % boundary.decode( + "ascii" + ) + self.fields = list(self._iter_fields(data, files)) + + def _iter_fields( + self, data: RequestData, files: RequestFiles + ) -> typing.Iterator[FileField | DataField]: + for name, value in data.items(): + if isinstance(value, (tuple, list)): + for item in value: + yield DataField(name=name, value=item) + else: + yield DataField(name=name, value=value) + + file_items = files.items() if isinstance(files, typing.Mapping) else files + for name, value in file_items: + yield FileField(name=name, value=value) + + def iter_chunks(self) -> typing.Iterator[bytes]: + for field in self.fields: + yield b"--%s\r\n" % self.boundary + yield from field.render() + yield b"\r\n" + yield b"--%s--\r\n" % self.boundary + + def get_content_length(self) -> int | None: + """ + Return the length of the multipart encoded content, or `None` if + any of the files have a length that cannot be determined upfront. + """ + boundary_length = len(self.boundary) + length = 0 + + for field in self.fields: + field_length = field.get_length() + if field_length is None: + return None + + length += 2 + boundary_length + 2 # b"--{boundary}\r\n" + length += field_length + length += 2 # b"\r\n" + + length += 2 + boundary_length + 4 # b"--{boundary}--\r\n" + return length + + # Content stream interface. + + def get_headers(self) -> dict[str, str]: + content_length = self.get_content_length() + content_type = self.content_type + if content_length is None: + return {"Transfer-Encoding": "chunked", "Content-Type": content_type} + return {"Content-Length": str(content_length), "Content-Type": content_type} + + def __iter__(self) -> typing.Iterator[bytes]: + for chunk in self.iter_chunks(): + yield chunk + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + for chunk in self.iter_chunks(): + yield chunk diff --git a/source/target-vendors/cp312/httpx/_status_codes.py b/source/target-vendors/cp312/httpx/_status_codes.py new file mode 100644 index 0000000..133a623 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_status_codes.py @@ -0,0 +1,162 @@ +from __future__ import annotations + +from enum import IntEnum + +__all__ = ["codes"] + + +class codes(IntEnum): + """HTTP status codes and reason phrases + + Status codes from the following RFCs are all observed: + + * RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616 + * RFC 6585: Additional HTTP Status Codes + * RFC 3229: Delta encoding in HTTP + * RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518 + * RFC 5842: Binding Extensions to WebDAV + * RFC 7238: Permanent Redirect + * RFC 2295: Transparent Content Negotiation in HTTP + * RFC 2774: An HTTP Extension Framework + * RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2) + * RFC 2324: Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0) + * RFC 7725: An HTTP Status Code to Report Legal Obstacles + * RFC 8297: An HTTP Status Code for Indicating Hints + * RFC 8470: Using Early Data in HTTP + """ + + def __new__(cls, value: int, phrase: str = "") -> codes: + obj = int.__new__(cls, value) + obj._value_ = value + + obj.phrase = phrase # type: ignore[attr-defined] + return obj + + def __str__(self) -> str: + return str(self.value) + + @classmethod + def get_reason_phrase(cls, value: int) -> str: + try: + return codes(value).phrase # type: ignore + except ValueError: + return "" + + @classmethod + def is_informational(cls, value: int) -> bool: + """ + Returns `True` for 1xx status codes, `False` otherwise. + """ + return 100 <= value <= 199 + + @classmethod + def is_success(cls, value: int) -> bool: + """ + Returns `True` for 2xx status codes, `False` otherwise. + """ + return 200 <= value <= 299 + + @classmethod + def is_redirect(cls, value: int) -> bool: + """ + Returns `True` for 3xx status codes, `False` otherwise. + """ + return 300 <= value <= 399 + + @classmethod + def is_client_error(cls, value: int) -> bool: + """ + Returns `True` for 4xx status codes, `False` otherwise. + """ + return 400 <= value <= 499 + + @classmethod + def is_server_error(cls, value: int) -> bool: + """ + Returns `True` for 5xx status codes, `False` otherwise. + """ + return 500 <= value <= 599 + + @classmethod + def is_error(cls, value: int) -> bool: + """ + Returns `True` for 4xx or 5xx status codes, `False` otherwise. + """ + return 400 <= value <= 599 + + # informational + CONTINUE = 100, "Continue" + SWITCHING_PROTOCOLS = 101, "Switching Protocols" + PROCESSING = 102, "Processing" + EARLY_HINTS = 103, "Early Hints" + + # success + OK = 200, "OK" + CREATED = 201, "Created" + ACCEPTED = 202, "Accepted" + NON_AUTHORITATIVE_INFORMATION = 203, "Non-Authoritative Information" + NO_CONTENT = 204, "No Content" + RESET_CONTENT = 205, "Reset Content" + PARTIAL_CONTENT = 206, "Partial Content" + MULTI_STATUS = 207, "Multi-Status" + ALREADY_REPORTED = 208, "Already Reported" + IM_USED = 226, "IM Used" + + # redirection + MULTIPLE_CHOICES = 300, "Multiple Choices" + MOVED_PERMANENTLY = 301, "Moved Permanently" + FOUND = 302, "Found" + SEE_OTHER = 303, "See Other" + NOT_MODIFIED = 304, "Not Modified" + USE_PROXY = 305, "Use Proxy" + TEMPORARY_REDIRECT = 307, "Temporary Redirect" + PERMANENT_REDIRECT = 308, "Permanent Redirect" + + # client error + BAD_REQUEST = 400, "Bad Request" + UNAUTHORIZED = 401, "Unauthorized" + PAYMENT_REQUIRED = 402, "Payment Required" + FORBIDDEN = 403, "Forbidden" + NOT_FOUND = 404, "Not Found" + METHOD_NOT_ALLOWED = 405, "Method Not Allowed" + NOT_ACCEPTABLE = 406, "Not Acceptable" + PROXY_AUTHENTICATION_REQUIRED = 407, "Proxy Authentication Required" + REQUEST_TIMEOUT = 408, "Request Timeout" + CONFLICT = 409, "Conflict" + GONE = 410, "Gone" + LENGTH_REQUIRED = 411, "Length Required" + PRECONDITION_FAILED = 412, "Precondition Failed" + REQUEST_ENTITY_TOO_LARGE = 413, "Request Entity Too Large" + REQUEST_URI_TOO_LONG = 414, "Request-URI Too Long" + UNSUPPORTED_MEDIA_TYPE = 415, "Unsupported Media Type" + REQUESTED_RANGE_NOT_SATISFIABLE = 416, "Requested Range Not Satisfiable" + EXPECTATION_FAILED = 417, "Expectation Failed" + IM_A_TEAPOT = 418, "I'm a teapot" + MISDIRECTED_REQUEST = 421, "Misdirected Request" + UNPROCESSABLE_ENTITY = 422, "Unprocessable Entity" + LOCKED = 423, "Locked" + FAILED_DEPENDENCY = 424, "Failed Dependency" + TOO_EARLY = 425, "Too Early" + UPGRADE_REQUIRED = 426, "Upgrade Required" + PRECONDITION_REQUIRED = 428, "Precondition Required" + TOO_MANY_REQUESTS = 429, "Too Many Requests" + REQUEST_HEADER_FIELDS_TOO_LARGE = 431, "Request Header Fields Too Large" + UNAVAILABLE_FOR_LEGAL_REASONS = 451, "Unavailable For Legal Reasons" + + # server errors + INTERNAL_SERVER_ERROR = 500, "Internal Server Error" + NOT_IMPLEMENTED = 501, "Not Implemented" + BAD_GATEWAY = 502, "Bad Gateway" + SERVICE_UNAVAILABLE = 503, "Service Unavailable" + GATEWAY_TIMEOUT = 504, "Gateway Timeout" + HTTP_VERSION_NOT_SUPPORTED = 505, "HTTP Version Not Supported" + VARIANT_ALSO_NEGOTIATES = 506, "Variant Also Negotiates" + INSUFFICIENT_STORAGE = 507, "Insufficient Storage" + LOOP_DETECTED = 508, "Loop Detected" + NOT_EXTENDED = 510, "Not Extended" + NETWORK_AUTHENTICATION_REQUIRED = 511, "Network Authentication Required" + + +# Include lower-case styles for `requests` compatibility. +for code in codes: + setattr(codes, code._name_.lower(), int(code)) diff --git a/source/target-vendors/cp312/httpx/_transports/__init__.py b/source/target-vendors/cp312/httpx/_transports/__init__.py new file mode 100644 index 0000000..7a32105 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_transports/__init__.py @@ -0,0 +1,15 @@ +from .asgi import * +from .base import * +from .default import * +from .mock import * +from .wsgi import * + +__all__ = [ + "ASGITransport", + "AsyncBaseTransport", + "BaseTransport", + "AsyncHTTPTransport", + "HTTPTransport", + "MockTransport", + "WSGITransport", +] diff --git a/source/target-vendors/cp312/httpx/_transports/asgi.py b/source/target-vendors/cp312/httpx/_transports/asgi.py new file mode 100644 index 0000000..2bc4efa --- /dev/null +++ b/source/target-vendors/cp312/httpx/_transports/asgi.py @@ -0,0 +1,187 @@ +from __future__ import annotations + +import typing + +from .._models import Request, Response +from .._types import AsyncByteStream +from .base import AsyncBaseTransport + +if typing.TYPE_CHECKING: # pragma: no cover + import asyncio + + import trio + + Event = typing.Union[asyncio.Event, trio.Event] + + +_Message = typing.MutableMapping[str, typing.Any] +_Receive = typing.Callable[[], typing.Awaitable[_Message]] +_Send = typing.Callable[ + [typing.MutableMapping[str, typing.Any]], typing.Awaitable[None] +] +_ASGIApp = typing.Callable[ + [typing.MutableMapping[str, typing.Any], _Receive, _Send], typing.Awaitable[None] +] + +__all__ = ["ASGITransport"] + + +def is_running_trio() -> bool: + try: + # sniffio is a dependency of trio. + + # See https://github.com/python-trio/trio/issues/2802 + import sniffio + + if sniffio.current_async_library() == "trio": + return True + except ImportError: # pragma: nocover + pass + + return False + + +def create_event() -> Event: + if is_running_trio(): + import trio + + return trio.Event() + + import asyncio + + return asyncio.Event() + + +class ASGIResponseStream(AsyncByteStream): + def __init__(self, body: list[bytes]) -> None: + self._body = body + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + yield b"".join(self._body) + + +class ASGITransport(AsyncBaseTransport): + """ + A custom AsyncTransport that handles sending requests directly to an ASGI app. + + ```python + transport = httpx.ASGITransport( + app=app, + root_path="/submount", + client=("1.2.3.4", 123) + ) + client = httpx.AsyncClient(transport=transport) + ``` + + Arguments: + + * `app` - The ASGI application. + * `raise_app_exceptions` - Boolean indicating if exceptions in the application + should be raised. Default to `True`. Can be set to `False` for use cases + such as testing the content of a client 500 response. + * `root_path` - The root path on which the ASGI application should be mounted. + * `client` - A two-tuple indicating the client IP and port of incoming requests. + ``` + """ + + def __init__( + self, + app: _ASGIApp, + raise_app_exceptions: bool = True, + root_path: str = "", + client: tuple[str, int] = ("127.0.0.1", 123), + ) -> None: + self.app = app + self.raise_app_exceptions = raise_app_exceptions + self.root_path = root_path + self.client = client + + async def handle_async_request( + self, + request: Request, + ) -> Response: + assert isinstance(request.stream, AsyncByteStream) + + # ASGI scope. + scope = { + "type": "http", + "asgi": {"version": "3.0"}, + "http_version": "1.1", + "method": request.method, + "headers": [(k.lower(), v) for (k, v) in request.headers.raw], + "scheme": request.url.scheme, + "path": request.url.path, + "raw_path": request.url.raw_path.split(b"?")[0], + "query_string": request.url.query, + "server": (request.url.host, request.url.port), + "client": self.client, + "root_path": self.root_path, + } + + # Request. + request_body_chunks = request.stream.__aiter__() + request_complete = False + + # Response. + status_code = None + response_headers = None + body_parts = [] + response_started = False + response_complete = create_event() + + # ASGI callables. + + async def receive() -> dict[str, typing.Any]: + nonlocal request_complete + + if request_complete: + await response_complete.wait() + return {"type": "http.disconnect"} + + try: + body = await request_body_chunks.__anext__() + except StopAsyncIteration: + request_complete = True + return {"type": "http.request", "body": b"", "more_body": False} + return {"type": "http.request", "body": body, "more_body": True} + + async def send(message: typing.MutableMapping[str, typing.Any]) -> None: + nonlocal status_code, response_headers, response_started + + if message["type"] == "http.response.start": + assert not response_started + + status_code = message["status"] + response_headers = message.get("headers", []) + response_started = True + + elif message["type"] == "http.response.body": + assert not response_complete.is_set() + body = message.get("body", b"") + more_body = message.get("more_body", False) + + if body and request.method != "HEAD": + body_parts.append(body) + + if not more_body: + response_complete.set() + + try: + await self.app(scope, receive, send) + except Exception: # noqa: PIE-786 + if self.raise_app_exceptions: + raise + + response_complete.set() + if status_code is None: + status_code = 500 + if response_headers is None: + response_headers = {} + + assert response_complete.is_set() + assert status_code is not None + assert response_headers is not None + + stream = ASGIResponseStream(body_parts) + + return Response(status_code, headers=response_headers, stream=stream) diff --git a/source/target-vendors/cp312/httpx/_transports/base.py b/source/target-vendors/cp312/httpx/_transports/base.py new file mode 100644 index 0000000..66fd99d --- /dev/null +++ b/source/target-vendors/cp312/httpx/_transports/base.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import typing +from types import TracebackType + +from .._models import Request, Response + +T = typing.TypeVar("T", bound="BaseTransport") +A = typing.TypeVar("A", bound="AsyncBaseTransport") + +__all__ = ["AsyncBaseTransport", "BaseTransport"] + + +class BaseTransport: + def __enter__(self: T) -> T: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, + ) -> None: + self.close() + + def handle_request(self, request: Request) -> Response: + """ + Send a single HTTP request and return a response. + + Developers shouldn't typically ever need to call into this API directly, + since the Client class provides all the higher level user-facing API + niceties. + + In order to properly release any network resources, the response + stream should *either* be consumed immediately, with a call to + `response.stream.read()`, or else the `handle_request` call should + be followed with a try/finally block to ensuring the stream is + always closed. + + Example usage: + + with httpx.HTTPTransport() as transport: + req = httpx.Request( + method=b"GET", + url=(b"https", b"www.example.com", 443, b"/"), + headers=[(b"Host", b"www.example.com")], + ) + resp = transport.handle_request(req) + body = resp.stream.read() + print(resp.status_code, resp.headers, body) + + + Takes a `Request` instance as the only argument. + + Returns a `Response` instance. + """ + raise NotImplementedError( + "The 'handle_request' method must be implemented." + ) # pragma: no cover + + def close(self) -> None: + pass + + +class AsyncBaseTransport: + async def __aenter__(self: A) -> A: + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, + ) -> None: + await self.aclose() + + async def handle_async_request( + self, + request: Request, + ) -> Response: + raise NotImplementedError( + "The 'handle_async_request' method must be implemented." + ) # pragma: no cover + + async def aclose(self) -> None: + pass diff --git a/source/target-vendors/cp312/httpx/_transports/default.py b/source/target-vendors/cp312/httpx/_transports/default.py new file mode 100644 index 0000000..d5aa05f --- /dev/null +++ b/source/target-vendors/cp312/httpx/_transports/default.py @@ -0,0 +1,406 @@ +""" +Custom transports, with nicely configured defaults. + +The following additional keyword arguments are currently supported by httpcore... + +* uds: str +* local_address: str +* retries: int + +Example usages... + +# Disable HTTP/2 on a single specific domain. +mounts = { + "all://": httpx.HTTPTransport(http2=True), + "all://*example.org": httpx.HTTPTransport() +} + +# Using advanced httpcore configuration, with connection retries. +transport = httpx.HTTPTransport(retries=1) +client = httpx.Client(transport=transport) + +# Using advanced httpcore configuration, with unix domain sockets. +transport = httpx.HTTPTransport(uds="socket.uds") +client = httpx.Client(transport=transport) +""" + +from __future__ import annotations + +import contextlib +import typing +from types import TracebackType + +if typing.TYPE_CHECKING: + import ssl # pragma: no cover + + import httpx # pragma: no cover + +from .._config import DEFAULT_LIMITS, Limits, Proxy, create_ssl_context +from .._exceptions import ( + ConnectError, + ConnectTimeout, + LocalProtocolError, + NetworkError, + PoolTimeout, + ProtocolError, + ProxyError, + ReadError, + ReadTimeout, + RemoteProtocolError, + TimeoutException, + UnsupportedProtocol, + WriteError, + WriteTimeout, +) +from .._models import Request, Response +from .._types import AsyncByteStream, CertTypes, ProxyTypes, SyncByteStream +from .._urls import URL +from .base import AsyncBaseTransport, BaseTransport + +T = typing.TypeVar("T", bound="HTTPTransport") +A = typing.TypeVar("A", bound="AsyncHTTPTransport") + +SOCKET_OPTION = typing.Union[ + typing.Tuple[int, int, int], + typing.Tuple[int, int, typing.Union[bytes, bytearray]], + typing.Tuple[int, int, None, int], +] + +__all__ = ["AsyncHTTPTransport", "HTTPTransport"] + +HTTPCORE_EXC_MAP: dict[type[Exception], type[httpx.HTTPError]] = {} + + +def _load_httpcore_exceptions() -> dict[type[Exception], type[httpx.HTTPError]]: + import httpcore + + return { + httpcore.TimeoutException: TimeoutException, + httpcore.ConnectTimeout: ConnectTimeout, + httpcore.ReadTimeout: ReadTimeout, + httpcore.WriteTimeout: WriteTimeout, + httpcore.PoolTimeout: PoolTimeout, + httpcore.NetworkError: NetworkError, + httpcore.ConnectError: ConnectError, + httpcore.ReadError: ReadError, + httpcore.WriteError: WriteError, + httpcore.ProxyError: ProxyError, + httpcore.UnsupportedProtocol: UnsupportedProtocol, + httpcore.ProtocolError: ProtocolError, + httpcore.LocalProtocolError: LocalProtocolError, + httpcore.RemoteProtocolError: RemoteProtocolError, + } + + +@contextlib.contextmanager +def map_httpcore_exceptions() -> typing.Iterator[None]: + global HTTPCORE_EXC_MAP + if len(HTTPCORE_EXC_MAP) == 0: + HTTPCORE_EXC_MAP = _load_httpcore_exceptions() + try: + yield + except Exception as exc: + mapped_exc = None + + for from_exc, to_exc in HTTPCORE_EXC_MAP.items(): + if not isinstance(exc, from_exc): + continue + # We want to map to the most specific exception we can find. + # Eg if `exc` is an `httpcore.ReadTimeout`, we want to map to + # `httpx.ReadTimeout`, not just `httpx.TimeoutException`. + if mapped_exc is None or issubclass(to_exc, mapped_exc): + mapped_exc = to_exc + + if mapped_exc is None: # pragma: no cover + raise + + message = str(exc) + raise mapped_exc(message) from exc + + +class ResponseStream(SyncByteStream): + def __init__(self, httpcore_stream: typing.Iterable[bytes]) -> None: + self._httpcore_stream = httpcore_stream + + def __iter__(self) -> typing.Iterator[bytes]: + with map_httpcore_exceptions(): + for part in self._httpcore_stream: + yield part + + def close(self) -> None: + if hasattr(self._httpcore_stream, "close"): + self._httpcore_stream.close() + + +class HTTPTransport(BaseTransport): + def __init__( + self, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + limits: Limits = DEFAULT_LIMITS, + proxy: ProxyTypes | None = None, + uds: str | None = None, + local_address: str | None = None, + retries: int = 0, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + import httpcore + + proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy + ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env) + + if proxy is None: + self._pool = httpcore.ConnectionPool( + ssl_context=ssl_context, + max_connections=limits.max_connections, + max_keepalive_connections=limits.max_keepalive_connections, + keepalive_expiry=limits.keepalive_expiry, + http1=http1, + http2=http2, + uds=uds, + local_address=local_address, + retries=retries, + socket_options=socket_options, + ) + elif proxy.url.scheme in ("http", "https"): + self._pool = httpcore.HTTPProxy( + proxy_url=httpcore.URL( + scheme=proxy.url.raw_scheme, + host=proxy.url.raw_host, + port=proxy.url.port, + target=proxy.url.raw_path, + ), + proxy_auth=proxy.raw_auth, + proxy_headers=proxy.headers.raw, + ssl_context=ssl_context, + proxy_ssl_context=proxy.ssl_context, + max_connections=limits.max_connections, + max_keepalive_connections=limits.max_keepalive_connections, + keepalive_expiry=limits.keepalive_expiry, + http1=http1, + http2=http2, + socket_options=socket_options, + ) + elif proxy.url.scheme in ("socks5", "socks5h"): + try: + import socksio # noqa + except ImportError: # pragma: no cover + raise ImportError( + "Using SOCKS proxy, but the 'socksio' package is not installed. " + "Make sure to install httpx using `pip install httpx[socks]`." + ) from None + + self._pool = httpcore.SOCKSProxy( + proxy_url=httpcore.URL( + scheme=proxy.url.raw_scheme, + host=proxy.url.raw_host, + port=proxy.url.port, + target=proxy.url.raw_path, + ), + proxy_auth=proxy.raw_auth, + ssl_context=ssl_context, + max_connections=limits.max_connections, + max_keepalive_connections=limits.max_keepalive_connections, + keepalive_expiry=limits.keepalive_expiry, + http1=http1, + http2=http2, + ) + else: # pragma: no cover + raise ValueError( + "Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h'," + f" but got {proxy.url.scheme!r}." + ) + + def __enter__(self: T) -> T: # Use generics for subclass support. + self._pool.__enter__() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, + ) -> None: + with map_httpcore_exceptions(): + self._pool.__exit__(exc_type, exc_value, traceback) + + def handle_request( + self, + request: Request, + ) -> Response: + assert isinstance(request.stream, SyncByteStream) + import httpcore + + req = httpcore.Request( + method=request.method, + url=httpcore.URL( + scheme=request.url.raw_scheme, + host=request.url.raw_host, + port=request.url.port, + target=request.url.raw_path, + ), + headers=request.headers.raw, + content=request.stream, + extensions=request.extensions, + ) + with map_httpcore_exceptions(): + resp = self._pool.handle_request(req) + + assert isinstance(resp.stream, typing.Iterable) + + return Response( + status_code=resp.status, + headers=resp.headers, + stream=ResponseStream(resp.stream), + extensions=resp.extensions, + ) + + def close(self) -> None: + self._pool.close() + + +class AsyncResponseStream(AsyncByteStream): + def __init__(self, httpcore_stream: typing.AsyncIterable[bytes]) -> None: + self._httpcore_stream = httpcore_stream + + async def __aiter__(self) -> typing.AsyncIterator[bytes]: + with map_httpcore_exceptions(): + async for part in self._httpcore_stream: + yield part + + async def aclose(self) -> None: + if hasattr(self._httpcore_stream, "aclose"): + await self._httpcore_stream.aclose() + + +class AsyncHTTPTransport(AsyncBaseTransport): + def __init__( + self, + verify: ssl.SSLContext | str | bool = True, + cert: CertTypes | None = None, + trust_env: bool = True, + http1: bool = True, + http2: bool = False, + limits: Limits = DEFAULT_LIMITS, + proxy: ProxyTypes | None = None, + uds: str | None = None, + local_address: str | None = None, + retries: int = 0, + socket_options: typing.Iterable[SOCKET_OPTION] | None = None, + ) -> None: + import httpcore + + proxy = Proxy(url=proxy) if isinstance(proxy, (str, URL)) else proxy + ssl_context = create_ssl_context(verify=verify, cert=cert, trust_env=trust_env) + + if proxy is None: + self._pool = httpcore.AsyncConnectionPool( + ssl_context=ssl_context, + max_connections=limits.max_connections, + max_keepalive_connections=limits.max_keepalive_connections, + keepalive_expiry=limits.keepalive_expiry, + http1=http1, + http2=http2, + uds=uds, + local_address=local_address, + retries=retries, + socket_options=socket_options, + ) + elif proxy.url.scheme in ("http", "https"): + self._pool = httpcore.AsyncHTTPProxy( + proxy_url=httpcore.URL( + scheme=proxy.url.raw_scheme, + host=proxy.url.raw_host, + port=proxy.url.port, + target=proxy.url.raw_path, + ), + proxy_auth=proxy.raw_auth, + proxy_headers=proxy.headers.raw, + proxy_ssl_context=proxy.ssl_context, + ssl_context=ssl_context, + max_connections=limits.max_connections, + max_keepalive_connections=limits.max_keepalive_connections, + keepalive_expiry=limits.keepalive_expiry, + http1=http1, + http2=http2, + socket_options=socket_options, + ) + elif proxy.url.scheme in ("socks5", "socks5h"): + try: + import socksio # noqa + except ImportError: # pragma: no cover + raise ImportError( + "Using SOCKS proxy, but the 'socksio' package is not installed. " + "Make sure to install httpx using `pip install httpx[socks]`." + ) from None + + self._pool = httpcore.AsyncSOCKSProxy( + proxy_url=httpcore.URL( + scheme=proxy.url.raw_scheme, + host=proxy.url.raw_host, + port=proxy.url.port, + target=proxy.url.raw_path, + ), + proxy_auth=proxy.raw_auth, + ssl_context=ssl_context, + max_connections=limits.max_connections, + max_keepalive_connections=limits.max_keepalive_connections, + keepalive_expiry=limits.keepalive_expiry, + http1=http1, + http2=http2, + ) + else: # pragma: no cover + raise ValueError( + "Proxy protocol must be either 'http', 'https', 'socks5', or 'socks5h'," + " but got {proxy.url.scheme!r}." + ) + + async def __aenter__(self: A) -> A: # Use generics for subclass support. + await self._pool.__aenter__() + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None = None, + exc_value: BaseException | None = None, + traceback: TracebackType | None = None, + ) -> None: + with map_httpcore_exceptions(): + await self._pool.__aexit__(exc_type, exc_value, traceback) + + async def handle_async_request( + self, + request: Request, + ) -> Response: + assert isinstance(request.stream, AsyncByteStream) + import httpcore + + req = httpcore.Request( + method=request.method, + url=httpcore.URL( + scheme=request.url.raw_scheme, + host=request.url.raw_host, + port=request.url.port, + target=request.url.raw_path, + ), + headers=request.headers.raw, + content=request.stream, + extensions=request.extensions, + ) + with map_httpcore_exceptions(): + resp = await self._pool.handle_async_request(req) + + assert isinstance(resp.stream, typing.AsyncIterable) + + return Response( + status_code=resp.status, + headers=resp.headers, + stream=AsyncResponseStream(resp.stream), + extensions=resp.extensions, + ) + + async def aclose(self) -> None: + await self._pool.aclose() diff --git a/source/target-vendors/cp312/httpx/_transports/mock.py b/source/target-vendors/cp312/httpx/_transports/mock.py new file mode 100644 index 0000000..8c418f5 --- /dev/null +++ b/source/target-vendors/cp312/httpx/_transports/mock.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +import typing + +from .._models import Request, Response +from .base import AsyncBaseTransport, BaseTransport + +SyncHandler = typing.Callable[[Request], Response] +AsyncHandler = typing.Callable[[Request], typing.Coroutine[None, None, Response]] + + +__all__ = ["MockTransport"] + + +class MockTransport(AsyncBaseTransport, BaseTransport): + def __init__(self, handler: SyncHandler | AsyncHandler) -> None: + self.handler = handler + + def handle_request( + self, + request: Request, + ) -> Response: + request.read() + response = self.handler(request) + if not isinstance(response, Response): # pragma: no cover + raise TypeError("Cannot use an async handler in a sync Client") + return response + + async def handle_async_request( + self, + request: Request, + ) -> Response: + await request.aread() + response = self.handler(request) + + # Allow handler to *optionally* be an `async` function. + # If it is, then the `response` variable need to be awaited to actually + # return the result. + + if not isinstance(response, Response): + response = await response + + return response diff --git a/source/target-vendors/cp312/httpx/_transports/wsgi.py b/source/target-vendors/cp312/httpx/_transports/wsgi.py new file mode 100644 index 0000000..8592ffe --- /dev/null +++ b/source/target-vendors/cp312/httpx/_transports/wsgi.py @@ -0,0 +1,149 @@ +from __future__ import annotations + +import io +import itertools +import sys +import typing + +from .._models import Request, Response +from .._types import SyncByteStream +from .base import BaseTransport + +if typing.TYPE_CHECKING: + from _typeshed import OptExcInfo # pragma: no cover + from _typeshed.wsgi import WSGIApplication # pragma: no cover + +_T = typing.TypeVar("_T") + + +__all__ = ["WSGITransport"] + + +def _skip_leading_empty_chunks(body: typing.Iterable[_T]) -> typing.Iterable[_T]: + body = iter(body) + for chunk in body: + if chunk: + return itertools.chain([chunk], body) + return [] + + +class WSGIByteStream(SyncByteStream): + def __init__(self, result: typing.Iterable[bytes]) -> None: + self._close = getattr(result, "close", None) + self._result = _skip_leading_empty_chunks(result) + + def __iter__(self) -> typing.Iterator[bytes]: + for part in self._result: + yield part + + def close(self) -> None: + if self._close is not None: + self._close() + + +class WSGITransport(BaseTransport): + """ + A custom transport that handles sending requests directly to an WSGI app. + The simplest way to use this functionality is to use the `app` argument. + + ``` + client = httpx.Client(app=app) + ``` + + Alternatively, you can setup the transport instance explicitly. + This allows you to include any additional configuration arguments specific + to the WSGITransport class: + + ``` + transport = httpx.WSGITransport( + app=app, + script_name="/submount", + remote_addr="1.2.3.4" + ) + client = httpx.Client(transport=transport) + ``` + + Arguments: + + * `app` - The WSGI application. + * `raise_app_exceptions` - Boolean indicating if exceptions in the application + should be raised. Default to `True`. Can be set to `False` for use cases + such as testing the content of a client 500 response. + * `script_name` - The root path on which the WSGI application should be mounted. + * `remote_addr` - A string indicating the client IP of incoming requests. + ``` + """ + + def __init__( + self, + app: WSGIApplication, + raise_app_exceptions: bool = True, + script_name: str = "", + remote_addr: str = "127.0.0.1", + wsgi_errors: typing.TextIO | None = None, + ) -> None: + self.app = app + self.raise_app_exceptions = raise_app_exceptions + self.script_name = script_name + self.remote_addr = remote_addr + self.wsgi_errors = wsgi_errors + + def handle_request(self, request: Request) -> Response: + request.read() + wsgi_input = io.BytesIO(request.content) + + port = request.url.port or {"http": 80, "https": 443}[request.url.scheme] + environ = { + "wsgi.version": (1, 0), + "wsgi.url_scheme": request.url.scheme, + "wsgi.input": wsgi_input, + "wsgi.errors": self.wsgi_errors or sys.stderr, + "wsgi.multithread": True, + "wsgi.multiprocess": False, + "wsgi.run_once": False, + "REQUEST_METHOD": request.method, + "SCRIPT_NAME": self.script_name, + "PATH_INFO": request.url.path, + "QUERY_STRING": request.url.query.decode("ascii"), + "SERVER_NAME": request.url.host, + "SERVER_PORT": str(port), + "SERVER_PROTOCOL": "HTTP/1.1", + "REMOTE_ADDR": self.remote_addr, + } + for header_key, header_value in request.headers.raw: + key = header_key.decode("ascii").upper().replace("-", "_") + if key not in ("CONTENT_TYPE", "CONTENT_LENGTH"): + key = "HTTP_" + key + environ[key] = header_value.decode("ascii") + + seen_status = None + seen_response_headers = None + seen_exc_info = None + + def start_response( + status: str, + response_headers: list[tuple[str, str]], + exc_info: OptExcInfo | None = None, + ) -> typing.Callable[[bytes], typing.Any]: + nonlocal seen_status, seen_response_headers, seen_exc_info + seen_status = status + seen_response_headers = response_headers + seen_exc_info = exc_info + return lambda _: None + + result = self.app(environ, start_response) + + stream = WSGIByteStream(result) + + assert seen_status is not None + assert seen_response_headers is not None + if seen_exc_info and seen_exc_info[0] and self.raise_app_exceptions: + raise seen_exc_info[1] + + status_code = int(seen_status.split()[0]) + headers = [ + (key.encode("ascii"), value.encode("ascii")) + for key, value in seen_response_headers + ] + + return Response(status_code, headers=headers, stream=stream) diff --git a/source/target-vendors/cp312/httpx/_types.py b/source/target-vendors/cp312/httpx/_types.py new file mode 100644 index 0000000..704dfdf --- /dev/null +++ b/source/target-vendors/cp312/httpx/_types.py @@ -0,0 +1,114 @@ +""" +Type definitions for type checking purposes. +""" + +from http.cookiejar import CookieJar +from typing import ( + IO, + TYPE_CHECKING, + Any, + AsyncIterable, + AsyncIterator, + Callable, + Dict, + Iterable, + Iterator, + List, + Mapping, + Optional, + Sequence, + Tuple, + Union, +) + +if TYPE_CHECKING: # pragma: no cover + from ._auth import Auth # noqa: F401 + from ._config import Proxy, Timeout # noqa: F401 + from ._models import Cookies, Headers, Request # noqa: F401 + from ._urls import URL, QueryParams # noqa: F401 + + +PrimitiveData = Optional[Union[str, int, float, bool]] + +URLTypes = Union["URL", str] + +QueryParamTypes = Union[ + "QueryParams", + Mapping[str, Union[PrimitiveData, Sequence[PrimitiveData]]], + List[Tuple[str, PrimitiveData]], + Tuple[Tuple[str, PrimitiveData], ...], + str, + bytes, +] + +HeaderTypes = Union[ + "Headers", + Mapping[str, str], + Mapping[bytes, bytes], + Sequence[Tuple[str, str]], + Sequence[Tuple[bytes, bytes]], +] + +CookieTypes = Union["Cookies", CookieJar, Dict[str, str], List[Tuple[str, str]]] + +TimeoutTypes = Union[ + Optional[float], + Tuple[Optional[float], Optional[float], Optional[float], Optional[float]], + "Timeout", +] +ProxyTypes = Union["URL", str, "Proxy"] +CertTypes = Union[str, Tuple[str, str], Tuple[str, str, str]] + +AuthTypes = Union[ + Tuple[Union[str, bytes], Union[str, bytes]], + Callable[["Request"], "Request"], + "Auth", +] + +RequestContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] +ResponseContent = Union[str, bytes, Iterable[bytes], AsyncIterable[bytes]] +ResponseExtensions = Mapping[str, Any] + +RequestData = Mapping[str, Any] + +FileContent = Union[IO[bytes], bytes, str] +FileTypes = Union[ + # file (or bytes) + FileContent, + # (filename, file (or bytes)) + Tuple[Optional[str], FileContent], + # (filename, file (or bytes), content_type) + Tuple[Optional[str], FileContent, Optional[str]], + # (filename, file (or bytes), content_type, headers) + Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], +] +RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] + +RequestExtensions = Mapping[str, Any] + +__all__ = ["AsyncByteStream", "SyncByteStream"] + + +class SyncByteStream: + def __iter__(self) -> Iterator[bytes]: + raise NotImplementedError( + "The '__iter__' method must be implemented." + ) # pragma: no cover + yield b"" # pragma: no cover + + def close(self) -> None: + """ + Subclasses can override this method to release any network resources + after a request/response cycle is complete. + """ + + +class AsyncByteStream: + async def __aiter__(self) -> AsyncIterator[bytes]: + raise NotImplementedError( + "The '__aiter__' method must be implemented." + ) # pragma: no cover + yield b"" # pragma: no cover + + async def aclose(self) -> None: + pass diff --git a/source/target-vendors/cp312/httpx/_urlparse.py b/source/target-vendors/cp312/httpx/_urlparse.py new file mode 100644 index 0000000..bf190fd --- /dev/null +++ b/source/target-vendors/cp312/httpx/_urlparse.py @@ -0,0 +1,527 @@ +""" +An implementation of `urlparse` that provides URL validation and normalization +as described by RFC3986. + +We rely on this implementation rather than the one in Python's stdlib, because: + +* It provides more complete URL validation. +* It properly differentiates between an empty querystring and an absent querystring, + to distinguish URLs with a trailing '?'. +* It handles scheme, hostname, port, and path normalization. +* It supports IDNA hostnames, normalizing them to their encoded form. +* The API supports passing individual components, as well as the complete URL string. + +Previously we relied on the excellent `rfc3986` package to handle URL parsing and +validation, but this module provides a simpler alternative, with less indirection +required. +""" + +from __future__ import annotations + +import ipaddress +import re +import typing + +import idna + +from ._exceptions import InvalidURL + +MAX_URL_LENGTH = 65536 + +# https://datatracker.ietf.org/doc/html/rfc3986.html#section-2.3 +UNRESERVED_CHARACTERS = ( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" +) +SUB_DELIMS = "!$&'()*+,;=" + +PERCENT_ENCODED_REGEX = re.compile("%[A-Fa-f0-9]{2}") + +# https://url.spec.whatwg.org/#percent-encoded-bytes + +# The fragment percent-encode set is the C0 control percent-encode set +# and U+0020 SPACE, U+0022 ("), U+003C (<), U+003E (>), and U+0060 (`). +FRAG_SAFE = "".join( + [chr(i) for i in range(0x20, 0x7F) if i not in (0x20, 0x22, 0x3C, 0x3E, 0x60)] +) + +# The query percent-encode set is the C0 control percent-encode set +# and U+0020 SPACE, U+0022 ("), U+0023 (#), U+003C (<), and U+003E (>). +QUERY_SAFE = "".join( + [chr(i) for i in range(0x20, 0x7F) if i not in (0x20, 0x22, 0x23, 0x3C, 0x3E)] +) + +# The path percent-encode set is the query percent-encode set +# and U+003F (?), U+0060 (`), U+007B ({), and U+007D (}). +PATH_SAFE = "".join( + [ + chr(i) + for i in range(0x20, 0x7F) + if i not in (0x20, 0x22, 0x23, 0x3C, 0x3E) + (0x3F, 0x60, 0x7B, 0x7D) + ] +) + +# The userinfo percent-encode set is the path percent-encode set +# and U+002F (/), U+003A (:), U+003B (;), U+003D (=), U+0040 (@), +# U+005B ([) to U+005E (^), inclusive, and U+007C (|). +USERNAME_SAFE = "".join( + [ + chr(i) + for i in range(0x20, 0x7F) + if i + not in (0x20, 0x22, 0x23, 0x3C, 0x3E) + + (0x3F, 0x60, 0x7B, 0x7D) + + (0x2F, 0x3A, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) + ] +) +PASSWORD_SAFE = "".join( + [ + chr(i) + for i in range(0x20, 0x7F) + if i + not in (0x20, 0x22, 0x23, 0x3C, 0x3E) + + (0x3F, 0x60, 0x7B, 0x7D) + + (0x2F, 0x3A, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) + ] +) +# Note... The terminology 'userinfo' percent-encode set in the WHATWG document +# is used for the username and password quoting. For the joint userinfo component +# we remove U+003A (:) from the safe set. +USERINFO_SAFE = "".join( + [ + chr(i) + for i in range(0x20, 0x7F) + if i + not in (0x20, 0x22, 0x23, 0x3C, 0x3E) + + (0x3F, 0x60, 0x7B, 0x7D) + + (0x2F, 0x3B, 0x3D, 0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x7C) + ] +) + + +# {scheme}: (optional) +# //{authority} (optional) +# {path} +# ?{query} (optional) +# #{fragment} (optional) +URL_REGEX = re.compile( + ( + r"(?:(?P{scheme}):)?" + r"(?://(?P{authority}))?" + r"(?P{path})" + r"(?:\?(?P{query}))?" + r"(?:#(?P{fragment}))?" + ).format( + scheme="([a-zA-Z][a-zA-Z0-9+.-]*)?", + authority="[^/?#]*", + path="[^?#]*", + query="[^#]*", + fragment=".*", + ) +) + +# {userinfo}@ (optional) +# {host} +# :{port} (optional) +AUTHORITY_REGEX = re.compile( + ( + r"(?:(?P{userinfo})@)?" r"(?P{host})" r":?(?P{port})?" + ).format( + userinfo=".*", # Any character sequence. + host="(\\[.*\\]|[^:@]*)", # Either any character sequence excluding ':' or '@', + # or an IPv6 address enclosed within square brackets. + port=".*", # Any character sequence. + ) +) + + +# If we call urlparse with an individual component, then we need to regex +# validate that component individually. +# Note that we're duplicating the same strings as above. Shock! Horror!! +COMPONENT_REGEX = { + "scheme": re.compile("([a-zA-Z][a-zA-Z0-9+.-]*)?"), + "authority": re.compile("[^/?#]*"), + "path": re.compile("[^?#]*"), + "query": re.compile("[^#]*"), + "fragment": re.compile(".*"), + "userinfo": re.compile("[^@]*"), + "host": re.compile("(\\[.*\\]|[^:]*)"), + "port": re.compile(".*"), +} + + +# We use these simple regexs as a first pass before handing off to +# the stdlib 'ipaddress' module for IP address validation. +IPv4_STYLE_HOSTNAME = re.compile(r"^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") +IPv6_STYLE_HOSTNAME = re.compile(r"^\[.*\]$") + + +class ParseResult(typing.NamedTuple): + scheme: str + userinfo: str + host: str + port: int | None + path: str + query: str | None + fragment: str | None + + @property + def authority(self) -> str: + return "".join( + [ + f"{self.userinfo}@" if self.userinfo else "", + f"[{self.host}]" if ":" in self.host else self.host, + f":{self.port}" if self.port is not None else "", + ] + ) + + @property + def netloc(self) -> str: + return "".join( + [ + f"[{self.host}]" if ":" in self.host else self.host, + f":{self.port}" if self.port is not None else "", + ] + ) + + def copy_with(self, **kwargs: str | None) -> ParseResult: + if not kwargs: + return self + + defaults = { + "scheme": self.scheme, + "authority": self.authority, + "path": self.path, + "query": self.query, + "fragment": self.fragment, + } + defaults.update(kwargs) + return urlparse("", **defaults) + + def __str__(self) -> str: + authority = self.authority + return "".join( + [ + f"{self.scheme}:" if self.scheme else "", + f"//{authority}" if authority else "", + self.path, + f"?{self.query}" if self.query is not None else "", + f"#{self.fragment}" if self.fragment is not None else "", + ] + ) + + +def urlparse(url: str = "", **kwargs: str | None) -> ParseResult: + # Initial basic checks on allowable URLs. + # --------------------------------------- + + # Hard limit the maximum allowable URL length. + if len(url) > MAX_URL_LENGTH: + raise InvalidURL("URL too long") + + # If a URL includes any ASCII control characters including \t, \r, \n, + # then treat it as invalid. + if any(char.isascii() and not char.isprintable() for char in url): + char = next(char for char in url if char.isascii() and not char.isprintable()) + idx = url.find(char) + error = ( + f"Invalid non-printable ASCII character in URL, {char!r} at position {idx}." + ) + raise InvalidURL(error) + + # Some keyword arguments require special handling. + # ------------------------------------------------ + + # Coerce "port" to a string, if it is provided as an integer. + if "port" in kwargs: + port = kwargs["port"] + kwargs["port"] = str(port) if isinstance(port, int) else port + + # Replace "netloc" with "host and "port". + if "netloc" in kwargs: + netloc = kwargs.pop("netloc") or "" + kwargs["host"], _, kwargs["port"] = netloc.partition(":") + + # Replace "username" and/or "password" with "userinfo". + if "username" in kwargs or "password" in kwargs: + username = quote(kwargs.pop("username", "") or "", safe=USERNAME_SAFE) + password = quote(kwargs.pop("password", "") or "", safe=PASSWORD_SAFE) + kwargs["userinfo"] = f"{username}:{password}" if password else username + + # Replace "raw_path" with "path" and "query". + if "raw_path" in kwargs: + raw_path = kwargs.pop("raw_path") or "" + kwargs["path"], seperator, kwargs["query"] = raw_path.partition("?") + if not seperator: + kwargs["query"] = None + + # Ensure that IPv6 "host" addresses are always escaped with "[...]". + if "host" in kwargs: + host = kwargs.get("host") or "" + if ":" in host and not (host.startswith("[") and host.endswith("]")): + kwargs["host"] = f"[{host}]" + + # If any keyword arguments are provided, ensure they are valid. + # ------------------------------------------------------------- + + for key, value in kwargs.items(): + if value is not None: + if len(value) > MAX_URL_LENGTH: + raise InvalidURL(f"URL component '{key}' too long") + + # If a component includes any ASCII control characters including \t, \r, \n, + # then treat it as invalid. + if any(char.isascii() and not char.isprintable() for char in value): + char = next( + char for char in value if char.isascii() and not char.isprintable() + ) + idx = value.find(char) + error = ( + f"Invalid non-printable ASCII character in URL {key} component, " + f"{char!r} at position {idx}." + ) + raise InvalidURL(error) + + # Ensure that keyword arguments match as a valid regex. + if not COMPONENT_REGEX[key].fullmatch(value): + raise InvalidURL(f"Invalid URL component '{key}'") + + # The URL_REGEX will always match, but may have empty components. + url_match = URL_REGEX.match(url) + assert url_match is not None + url_dict = url_match.groupdict() + + # * 'scheme', 'authority', and 'path' may be empty strings. + # * 'query' may be 'None', indicating no trailing "?" portion. + # Any string including the empty string, indicates a trailing "?". + # * 'fragment' may be 'None', indicating no trailing "#" portion. + # Any string including the empty string, indicates a trailing "#". + scheme = kwargs.get("scheme", url_dict["scheme"]) or "" + authority = kwargs.get("authority", url_dict["authority"]) or "" + path = kwargs.get("path", url_dict["path"]) or "" + query = kwargs.get("query", url_dict["query"]) + frag = kwargs.get("fragment", url_dict["fragment"]) + + # The AUTHORITY_REGEX will always match, but may have empty components. + authority_match = AUTHORITY_REGEX.match(authority) + assert authority_match is not None + authority_dict = authority_match.groupdict() + + # * 'userinfo' and 'host' may be empty strings. + # * 'port' may be 'None'. + userinfo = kwargs.get("userinfo", authority_dict["userinfo"]) or "" + host = kwargs.get("host", authority_dict["host"]) or "" + port = kwargs.get("port", authority_dict["port"]) + + # Normalize and validate each component. + # We end up with a parsed representation of the URL, + # with components that are plain ASCII bytestrings. + parsed_scheme: str = scheme.lower() + parsed_userinfo: str = quote(userinfo, safe=USERINFO_SAFE) + parsed_host: str = encode_host(host) + parsed_port: int | None = normalize_port(port, scheme) + + has_scheme = parsed_scheme != "" + has_authority = ( + parsed_userinfo != "" or parsed_host != "" or parsed_port is not None + ) + validate_path(path, has_scheme=has_scheme, has_authority=has_authority) + if has_scheme or has_authority: + path = normalize_path(path) + + parsed_path: str = quote(path, safe=PATH_SAFE) + parsed_query: str | None = None if query is None else quote(query, safe=QUERY_SAFE) + parsed_frag: str | None = None if frag is None else quote(frag, safe=FRAG_SAFE) + + # The parsed ASCII bytestrings are our canonical form. + # All properties of the URL are derived from these. + return ParseResult( + parsed_scheme, + parsed_userinfo, + parsed_host, + parsed_port, + parsed_path, + parsed_query, + parsed_frag, + ) + + +def encode_host(host: str) -> str: + if not host: + return "" + + elif IPv4_STYLE_HOSTNAME.match(host): + # Validate IPv4 hostnames like #.#.#.# + # + # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 + # + # IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + try: + ipaddress.IPv4Address(host) + except ipaddress.AddressValueError: + raise InvalidURL(f"Invalid IPv4 address: {host!r}") + return host + + elif IPv6_STYLE_HOSTNAME.match(host): + # Validate IPv6 hostnames like [...] + # + # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 + # + # "A host identified by an Internet Protocol literal address, version 6 + # [RFC3513] or later, is distinguished by enclosing the IP literal + # within square brackets ("[" and "]"). This is the only place where + # square bracket characters are allowed in the URI syntax." + try: + ipaddress.IPv6Address(host[1:-1]) + except ipaddress.AddressValueError: + raise InvalidURL(f"Invalid IPv6 address: {host!r}") + return host[1:-1] + + elif host.isascii(): + # Regular ASCII hostnames + # + # From https://datatracker.ietf.org/doc/html/rfc3986/#section-3.2.2 + # + # reg-name = *( unreserved / pct-encoded / sub-delims ) + WHATWG_SAFE = '"`{}%|\\' + return quote(host.lower(), safe=SUB_DELIMS + WHATWG_SAFE) + + # IDNA hostnames + try: + return idna.encode(host.lower()).decode("ascii") + except idna.IDNAError: + raise InvalidURL(f"Invalid IDNA hostname: {host!r}") + + +def normalize_port(port: str | int | None, scheme: str) -> int | None: + # From https://tools.ietf.org/html/rfc3986#section-3.2.3 + # + # "A scheme may define a default port. For example, the "http" scheme + # defines a default port of "80", corresponding to its reserved TCP + # port number. The type of port designated by the port number (e.g., + # TCP, UDP, SCTP) is defined by the URI scheme. URI producers and + # normalizers should omit the port component and its ":" delimiter if + # port is empty or if its value would be the same as that of the + # scheme's default." + if port is None or port == "": + return None + + try: + port_as_int = int(port) + except ValueError: + raise InvalidURL(f"Invalid port: {port!r}") + + # See https://url.spec.whatwg.org/#url-miscellaneous + default_port = {"ftp": 21, "http": 80, "https": 443, "ws": 80, "wss": 443}.get( + scheme + ) + if port_as_int == default_port: + return None + return port_as_int + + +def validate_path(path: str, has_scheme: bool, has_authority: bool) -> None: + """ + Path validation rules that depend on if the URL contains + a scheme or authority component. + + See https://datatracker.ietf.org/doc/html/rfc3986.html#section-3.3 + """ + if has_authority: + # If a URI contains an authority component, then the path component + # must either be empty or begin with a slash ("/") character." + if path and not path.startswith("/"): + raise InvalidURL("For absolute URLs, path must be empty or begin with '/'") + + if not has_scheme and not has_authority: + # If a URI does not contain an authority component, then the path cannot begin + # with two slash characters ("//"). + if path.startswith("//"): + raise InvalidURL("Relative URLs cannot have a path starting with '//'") + + # In addition, a URI reference (Section 4.1) may be a relative-path reference, + # in which case the first path segment cannot contain a colon (":") character. + if path.startswith(":"): + raise InvalidURL("Relative URLs cannot have a path starting with ':'") + + +def normalize_path(path: str) -> str: + """ + Drop "." and ".." segments from a URL path. + + For example: + + normalize_path("/path/./to/somewhere/..") == "/path/to" + """ + # Fast return when no '.' characters in the path. + if "." not in path: + return path + + components = path.split("/") + + # Fast return when no '.' or '..' components in the path. + if "." not in components and ".." not in components: + return path + + # https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4 + output: list[str] = [] + for component in components: + if component == ".": + pass + elif component == "..": + if output and output != [""]: + output.pop() + else: + output.append(component) + return "/".join(output) + + +def PERCENT(string: str) -> str: + return "".join([f"%{byte:02X}" for byte in string.encode("utf-8")]) + + +def percent_encoded(string: str, safe: str) -> str: + """ + Use percent-encoding to quote a string. + """ + NON_ESCAPED_CHARS = UNRESERVED_CHARACTERS + safe + + # Fast path for strings that don't need escaping. + if not string.rstrip(NON_ESCAPED_CHARS): + return string + + return "".join( + [char if char in NON_ESCAPED_CHARS else PERCENT(char) for char in string] + ) + + +def quote(string: str, safe: str) -> str: + """ + Use percent-encoding to quote a string, omitting existing '%xx' escape sequences. + + See: https://www.rfc-editor.org/rfc/rfc3986#section-2.1 + + * `string`: The string to be percent-escaped. + * `safe`: A string containing characters that may be treated as safe, and do not + need to be escaped. Unreserved characters are always treated as safe. + See: https://www.rfc-editor.org/rfc/rfc3986#section-2.3 + """ + parts = [] + current_position = 0 + for match in re.finditer(PERCENT_ENCODED_REGEX, string): + start_position, end_position = match.start(), match.end() + matched_text = match.group(0) + # Add any text up to the '%xx' escape sequence. + if start_position != current_position: + leading_text = string[current_position:start_position] + parts.append(percent_encoded(leading_text, safe=safe)) + + # Add the '%xx' escape sequence. + parts.append(matched_text) + current_position = end_position + + # Add any text after the final '%xx' escape sequence. + if current_position != len(string): + trailing_text = string[current_position:] + parts.append(percent_encoded(trailing_text, safe=safe)) + + return "".join(parts) diff --git a/source/target-vendors/cp312/httpx/_urls.py b/source/target-vendors/cp312/httpx/_urls.py new file mode 100644 index 0000000..147a8fa --- /dev/null +++ b/source/target-vendors/cp312/httpx/_urls.py @@ -0,0 +1,641 @@ +from __future__ import annotations + +import typing +from urllib.parse import parse_qs, unquote, urlencode + +import idna + +from ._types import QueryParamTypes +from ._urlparse import urlparse +from ._utils import primitive_value_to_str + +__all__ = ["URL", "QueryParams"] + + +class URL: + """ + url = httpx.URL("HTTPS://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink") + + assert url.scheme == "https" + assert url.username == "jo@email.com" + assert url.password == "a secret" + assert url.userinfo == b"jo%40email.com:a%20secret" + assert url.host == "müller.de" + assert url.raw_host == b"xn--mller-kva.de" + assert url.port == 1234 + assert url.netloc == b"xn--mller-kva.de:1234" + assert url.path == "/pa th" + assert url.query == b"?search=ab" + assert url.raw_path == b"/pa%20th?search=ab" + assert url.fragment == "anchorlink" + + The components of a URL are broken down like this: + + https://jo%40email.com:a%20secret@müller.de:1234/pa%20th?search=ab#anchorlink + [scheme] [ username ] [password] [ host ][port][ path ] [ query ] [fragment] + [ userinfo ] [ netloc ][ raw_path ] + + Note that: + + * `url.scheme` is normalized to always be lowercased. + + * `url.host` is normalized to always be lowercased. Internationalized domain + names are represented in unicode, without IDNA encoding applied. For instance: + + url = httpx.URL("http://中国.icom.museum") + assert url.host == "中国.icom.museum" + url = httpx.URL("http://xn--fiqs8s.icom.museum") + assert url.host == "中国.icom.museum" + + * `url.raw_host` is normalized to always be lowercased, and is IDNA encoded. + + url = httpx.URL("http://中国.icom.museum") + assert url.raw_host == b"xn--fiqs8s.icom.museum" + url = httpx.URL("http://xn--fiqs8s.icom.museum") + assert url.raw_host == b"xn--fiqs8s.icom.museum" + + * `url.port` is either None or an integer. URLs that include the default port for + "http", "https", "ws", "wss", and "ftp" schemes have their port + normalized to `None`. + + assert httpx.URL("http://example.com") == httpx.URL("http://example.com:80") + assert httpx.URL("http://example.com").port is None + assert httpx.URL("http://example.com:80").port is None + + * `url.userinfo` is raw bytes, without URL escaping. Usually you'll want to work + with `url.username` and `url.password` instead, which handle the URL escaping. + + * `url.raw_path` is raw bytes of both the path and query, without URL escaping. + This portion is used as the target when constructing HTTP requests. Usually you'll + want to work with `url.path` instead. + + * `url.query` is raw bytes, without URL escaping. A URL query string portion can + only be properly URL escaped when decoding the parameter names and values + themselves. + """ + + def __init__(self, url: URL | str = "", **kwargs: typing.Any) -> None: + if kwargs: + allowed = { + "scheme": str, + "username": str, + "password": str, + "userinfo": bytes, + "host": str, + "port": int, + "netloc": bytes, + "path": str, + "query": bytes, + "raw_path": bytes, + "fragment": str, + "params": object, + } + + # Perform type checking for all supported keyword arguments. + for key, value in kwargs.items(): + if key not in allowed: + message = f"{key!r} is an invalid keyword argument for URL()" + raise TypeError(message) + if value is not None and not isinstance(value, allowed[key]): + expected = allowed[key].__name__ + seen = type(value).__name__ + message = f"Argument {key!r} must be {expected} but got {seen}" + raise TypeError(message) + if isinstance(value, bytes): + kwargs[key] = value.decode("ascii") + + if "params" in kwargs: + # Replace any "params" keyword with the raw "query" instead. + # + # Ensure that empty params use `kwargs["query"] = None` rather + # than `kwargs["query"] = ""`, so that generated URLs do not + # include an empty trailing "?". + params = kwargs.pop("params") + kwargs["query"] = None if not params else str(QueryParams(params)) + + if isinstance(url, str): + self._uri_reference = urlparse(url, **kwargs) + elif isinstance(url, URL): + self._uri_reference = url._uri_reference.copy_with(**kwargs) + else: + raise TypeError( + "Invalid type for url. Expected str or httpx.URL," + f" got {type(url)}: {url!r}" + ) + + @property + def scheme(self) -> str: + """ + The URL scheme, such as "http", "https". + Always normalised to lowercase. + """ + return self._uri_reference.scheme + + @property + def raw_scheme(self) -> bytes: + """ + The raw bytes representation of the URL scheme, such as b"http", b"https". + Always normalised to lowercase. + """ + return self._uri_reference.scheme.encode("ascii") + + @property + def userinfo(self) -> bytes: + """ + The URL userinfo as a raw bytestring. + For example: b"jo%40email.com:a%20secret". + """ + return self._uri_reference.userinfo.encode("ascii") + + @property + def username(self) -> str: + """ + The URL username as a string, with URL decoding applied. + For example: "jo@email.com" + """ + userinfo = self._uri_reference.userinfo + return unquote(userinfo.partition(":")[0]) + + @property + def password(self) -> str: + """ + The URL password as a string, with URL decoding applied. + For example: "a secret" + """ + userinfo = self._uri_reference.userinfo + return unquote(userinfo.partition(":")[2]) + + @property + def host(self) -> str: + """ + The URL host as a string. + Always normalized to lowercase, with IDNA hosts decoded into unicode. + + Examples: + + url = httpx.URL("http://www.EXAMPLE.org") + assert url.host == "www.example.org" + + url = httpx.URL("http://中国.icom.museum") + assert url.host == "中国.icom.museum" + + url = httpx.URL("http://xn--fiqs8s.icom.museum") + assert url.host == "中国.icom.museum" + + url = httpx.URL("https://[::ffff:192.168.0.1]") + assert url.host == "::ffff:192.168.0.1" + """ + host: str = self._uri_reference.host + + if host.startswith("xn--"): + host = idna.decode(host) + + return host + + @property + def raw_host(self) -> bytes: + """ + The raw bytes representation of the URL host. + Always normalized to lowercase, and IDNA encoded. + + Examples: + + url = httpx.URL("http://www.EXAMPLE.org") + assert url.raw_host == b"www.example.org" + + url = httpx.URL("http://中国.icom.museum") + assert url.raw_host == b"xn--fiqs8s.icom.museum" + + url = httpx.URL("http://xn--fiqs8s.icom.museum") + assert url.raw_host == b"xn--fiqs8s.icom.museum" + + url = httpx.URL("https://[::ffff:192.168.0.1]") + assert url.raw_host == b"::ffff:192.168.0.1" + """ + return self._uri_reference.host.encode("ascii") + + @property + def port(self) -> int | None: + """ + The URL port as an integer. + + Note that the URL class performs port normalization as per the WHATWG spec. + Default ports for "http", "https", "ws", "wss", and "ftp" schemes are always + treated as `None`. + + For example: + + assert httpx.URL("http://www.example.com") == httpx.URL("http://www.example.com:80") + assert httpx.URL("http://www.example.com:80").port is None + """ + return self._uri_reference.port + + @property + def netloc(self) -> bytes: + """ + Either `` or `:` as bytes. + Always normalized to lowercase, and IDNA encoded. + + This property may be used for generating the value of a request + "Host" header. + """ + return self._uri_reference.netloc.encode("ascii") + + @property + def path(self) -> str: + """ + The URL path as a string. Excluding the query string, and URL decoded. + + For example: + + url = httpx.URL("https://example.com/pa%20th") + assert url.path == "/pa th" + """ + path = self._uri_reference.path or "/" + return unquote(path) + + @property + def query(self) -> bytes: + """ + The URL query string, as raw bytes, excluding the leading b"?". + + This is necessarily a bytewise interface, because we cannot + perform URL decoding of this representation until we've parsed + the keys and values into a QueryParams instance. + + For example: + + url = httpx.URL("https://example.com/?filter=some%20search%20terms") + assert url.query == b"filter=some%20search%20terms" + """ + query = self._uri_reference.query or "" + return query.encode("ascii") + + @property + def params(self) -> QueryParams: + """ + The URL query parameters, neatly parsed and packaged into an immutable + multidict representation. + """ + return QueryParams(self._uri_reference.query) + + @property + def raw_path(self) -> bytes: + """ + The complete URL path and query string as raw bytes. + Used as the target when constructing HTTP requests. + + For example: + + GET /users?search=some%20text HTTP/1.1 + Host: www.example.org + Connection: close + """ + path = self._uri_reference.path or "/" + if self._uri_reference.query is not None: + path += "?" + self._uri_reference.query + return path.encode("ascii") + + @property + def fragment(self) -> str: + """ + The URL fragments, as used in HTML anchors. + As a string, without the leading '#'. + """ + return unquote(self._uri_reference.fragment or "") + + @property + def is_absolute_url(self) -> bool: + """ + Return `True` for absolute URLs such as 'http://example.com/path', + and `False` for relative URLs such as '/path'. + """ + # We don't use `.is_absolute` from `rfc3986` because it treats + # URLs with a fragment portion as not absolute. + # What we actually care about is if the URL provides + # a scheme and hostname to which connections should be made. + return bool(self._uri_reference.scheme and self._uri_reference.host) + + @property + def is_relative_url(self) -> bool: + """ + Return `False` for absolute URLs such as 'http://example.com/path', + and `True` for relative URLs such as '/path'. + """ + return not self.is_absolute_url + + def copy_with(self, **kwargs: typing.Any) -> URL: + """ + Copy this URL, returning a new URL with some components altered. + Accepts the same set of parameters as the components that are made + available via properties on the `URL` class. + + For example: + + url = httpx.URL("https://www.example.com").copy_with( + username="jo@gmail.com", password="a secret" + ) + assert url == "https://jo%40email.com:a%20secret@www.example.com" + """ + return URL(self, **kwargs) + + def copy_set_param(self, key: str, value: typing.Any = None) -> URL: + return self.copy_with(params=self.params.set(key, value)) + + def copy_add_param(self, key: str, value: typing.Any = None) -> URL: + return self.copy_with(params=self.params.add(key, value)) + + def copy_remove_param(self, key: str) -> URL: + return self.copy_with(params=self.params.remove(key)) + + def copy_merge_params(self, params: QueryParamTypes) -> URL: + return self.copy_with(params=self.params.merge(params)) + + def join(self, url: URL | str) -> URL: + """ + Return an absolute URL, using this URL as the base. + + Eg. + + url = httpx.URL("https://www.example.com/test") + url = url.join("/new/path") + assert url == "https://www.example.com/new/path" + """ + from urllib.parse import urljoin + + return URL(urljoin(str(self), str(URL(url)))) + + def __hash__(self) -> int: + return hash(str(self)) + + def __eq__(self, other: typing.Any) -> bool: + return isinstance(other, (URL, str)) and str(self) == str(URL(other)) + + def __str__(self) -> str: + return str(self._uri_reference) + + def __repr__(self) -> str: + scheme, userinfo, host, port, path, query, fragment = self._uri_reference + + if ":" in userinfo: + # Mask any password component. + userinfo = f'{userinfo.split(":")[0]}:[secure]' + + authority = "".join( + [ + f"{userinfo}@" if userinfo else "", + f"[{host}]" if ":" in host else host, + f":{port}" if port is not None else "", + ] + ) + url = "".join( + [ + f"{self.scheme}:" if scheme else "", + f"//{authority}" if authority else "", + path, + f"?{query}" if query is not None else "", + f"#{fragment}" if fragment is not None else "", + ] + ) + + return f"{self.__class__.__name__}({url!r})" + + @property + def raw(self) -> tuple[bytes, bytes, int, bytes]: # pragma: nocover + import collections + import warnings + + warnings.warn("URL.raw is deprecated.") + RawURL = collections.namedtuple( + "RawURL", ["raw_scheme", "raw_host", "port", "raw_path"] + ) + return RawURL( + raw_scheme=self.raw_scheme, + raw_host=self.raw_host, + port=self.port, + raw_path=self.raw_path, + ) + + +class QueryParams(typing.Mapping[str, str]): + """ + URL query parameters, as a multi-dict. + """ + + def __init__(self, *args: QueryParamTypes | None, **kwargs: typing.Any) -> None: + assert len(args) < 2, "Too many arguments." + assert not (args and kwargs), "Cannot mix named and unnamed arguments." + + value = args[0] if args else kwargs + + if value is None or isinstance(value, (str, bytes)): + value = value.decode("ascii") if isinstance(value, bytes) else value + self._dict = parse_qs(value, keep_blank_values=True) + elif isinstance(value, QueryParams): + self._dict = {k: list(v) for k, v in value._dict.items()} + else: + dict_value: dict[typing.Any, list[typing.Any]] = {} + if isinstance(value, (list, tuple)): + # Convert list inputs like: + # [("a", "123"), ("a", "456"), ("b", "789")] + # To a dict representation, like: + # {"a": ["123", "456"], "b": ["789"]} + for item in value: + dict_value.setdefault(item[0], []).append(item[1]) + else: + # Convert dict inputs like: + # {"a": "123", "b": ["456", "789"]} + # To dict inputs where values are always lists, like: + # {"a": ["123"], "b": ["456", "789"]} + dict_value = { + k: list(v) if isinstance(v, (list, tuple)) else [v] + for k, v in value.items() + } + + # Ensure that keys and values are neatly coerced to strings. + # We coerce values `True` and `False` to JSON-like "true" and "false" + # representations, and coerce `None` values to the empty string. + self._dict = { + str(k): [primitive_value_to_str(item) for item in v] + for k, v in dict_value.items() + } + + def keys(self) -> typing.KeysView[str]: + """ + Return all the keys in the query params. + + Usage: + + q = httpx.QueryParams("a=123&a=456&b=789") + assert list(q.keys()) == ["a", "b"] + """ + return self._dict.keys() + + def values(self) -> typing.ValuesView[str]: + """ + Return all the values in the query params. If a key occurs more than once + only the first item for that key is returned. + + Usage: + + q = httpx.QueryParams("a=123&a=456&b=789") + assert list(q.values()) == ["123", "789"] + """ + return {k: v[0] for k, v in self._dict.items()}.values() + + def items(self) -> typing.ItemsView[str, str]: + """ + Return all items in the query params. If a key occurs more than once + only the first item for that key is returned. + + Usage: + + q = httpx.QueryParams("a=123&a=456&b=789") + assert list(q.items()) == [("a", "123"), ("b", "789")] + """ + return {k: v[0] for k, v in self._dict.items()}.items() + + def multi_items(self) -> list[tuple[str, str]]: + """ + Return all items in the query params. Allow duplicate keys to occur. + + Usage: + + q = httpx.QueryParams("a=123&a=456&b=789") + assert list(q.multi_items()) == [("a", "123"), ("a", "456"), ("b", "789")] + """ + multi_items: list[tuple[str, str]] = [] + for k, v in self._dict.items(): + multi_items.extend([(k, i) for i in v]) + return multi_items + + def get(self, key: typing.Any, default: typing.Any = None) -> typing.Any: + """ + Get a value from the query param for a given key. If the key occurs + more than once, then only the first value is returned. + + Usage: + + q = httpx.QueryParams("a=123&a=456&b=789") + assert q.get("a") == "123" + """ + if key in self._dict: + return self._dict[str(key)][0] + return default + + def get_list(self, key: str) -> list[str]: + """ + Get all values from the query param for a given key. + + Usage: + + q = httpx.QueryParams("a=123&a=456&b=789") + assert q.get_list("a") == ["123", "456"] + """ + return list(self._dict.get(str(key), [])) + + def set(self, key: str, value: typing.Any = None) -> QueryParams: + """ + Return a new QueryParams instance, setting the value of a key. + + Usage: + + q = httpx.QueryParams("a=123") + q = q.set("a", "456") + assert q == httpx.QueryParams("a=456") + """ + q = QueryParams() + q._dict = dict(self._dict) + q._dict[str(key)] = [primitive_value_to_str(value)] + return q + + def add(self, key: str, value: typing.Any = None) -> QueryParams: + """ + Return a new QueryParams instance, setting or appending the value of a key. + + Usage: + + q = httpx.QueryParams("a=123") + q = q.add("a", "456") + assert q == httpx.QueryParams("a=123&a=456") + """ + q = QueryParams() + q._dict = dict(self._dict) + q._dict[str(key)] = q.get_list(key) + [primitive_value_to_str(value)] + return q + + def remove(self, key: str) -> QueryParams: + """ + Return a new QueryParams instance, removing the value of a key. + + Usage: + + q = httpx.QueryParams("a=123") + q = q.remove("a") + assert q == httpx.QueryParams("") + """ + q = QueryParams() + q._dict = dict(self._dict) + q._dict.pop(str(key), None) + return q + + def merge(self, params: QueryParamTypes | None = None) -> QueryParams: + """ + Return a new QueryParams instance, updated with. + + Usage: + + q = httpx.QueryParams("a=123") + q = q.merge({"b": "456"}) + assert q == httpx.QueryParams("a=123&b=456") + + q = httpx.QueryParams("a=123") + q = q.merge({"a": "456", "b": "789"}) + assert q == httpx.QueryParams("a=456&b=789") + """ + q = QueryParams(params) + q._dict = {**self._dict, **q._dict} + return q + + def __getitem__(self, key: typing.Any) -> str: + return self._dict[key][0] + + def __contains__(self, key: typing.Any) -> bool: + return key in self._dict + + def __iter__(self) -> typing.Iterator[typing.Any]: + return iter(self.keys()) + + def __len__(self) -> int: + return len(self._dict) + + def __bool__(self) -> bool: + return bool(self._dict) + + def __hash__(self) -> int: + return hash(str(self)) + + def __eq__(self, other: typing.Any) -> bool: + if not isinstance(other, self.__class__): + return False + return sorted(self.multi_items()) == sorted(other.multi_items()) + + def __str__(self) -> str: + return urlencode(self.multi_items()) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + query_string = str(self) + return f"{class_name}({query_string!r})" + + def update(self, params: QueryParamTypes | None = None) -> None: + raise RuntimeError( + "QueryParams are immutable since 0.18.0. " + "Use `q = q.merge(...)` to create an updated copy." + ) + + def __setitem__(self, key: str, value: str) -> None: + raise RuntimeError( + "QueryParams are immutable since 0.18.0. " + "Use `q = q.set(key, value)` to create an updated copy." + ) diff --git a/source/target-vendors/cp312/httpx/_utils.py b/source/target-vendors/cp312/httpx/_utils.py new file mode 100644 index 0000000..7fe827d --- /dev/null +++ b/source/target-vendors/cp312/httpx/_utils.py @@ -0,0 +1,242 @@ +from __future__ import annotations + +import ipaddress +import os +import re +import typing +from urllib.request import getproxies + +from ._types import PrimitiveData + +if typing.TYPE_CHECKING: # pragma: no cover + from ._urls import URL + + +def primitive_value_to_str(value: PrimitiveData) -> str: + """ + Coerce a primitive data type into a string value. + + Note that we prefer JSON-style 'true'/'false' for boolean values here. + """ + if value is True: + return "true" + elif value is False: + return "false" + elif value is None: + return "" + return str(value) + + +def get_environment_proxies() -> dict[str, str | None]: + """Gets proxy information from the environment""" + + # urllib.request.getproxies() falls back on System + # Registry and Config for proxies on Windows and macOS. + # We don't want to propagate non-HTTP proxies into + # our configuration such as 'TRAVIS_APT_PROXY'. + proxy_info = getproxies() + mounts: dict[str, str | None] = {} + + for scheme in ("http", "https", "all"): + if proxy_info.get(scheme): + hostname = proxy_info[scheme] + mounts[f"{scheme}://"] = ( + hostname if "://" in hostname else f"http://{hostname}" + ) + + no_proxy_hosts = [host.strip() for host in proxy_info.get("no", "").split(",")] + for hostname in no_proxy_hosts: + # See https://curl.haxx.se/libcurl/c/CURLOPT_NOPROXY.html for details + # on how names in `NO_PROXY` are handled. + if hostname == "*": + # If NO_PROXY=* is used or if "*" occurs as any one of the comma + # separated hostnames, then we should just bypass any information + # from HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, and always ignore + # proxies. + return {} + elif hostname: + # NO_PROXY=.google.com is marked as "all://*.google.com, + # which disables "www.google.com" but not "google.com" + # NO_PROXY=google.com is marked as "all://*google.com, + # which disables "www.google.com" and "google.com". + # (But not "wwwgoogle.com") + # NO_PROXY can include domains, IPv6, IPv4 addresses and "localhost" + # NO_PROXY=example.com,::1,localhost,192.168.0.0/16 + if "://" in hostname: + mounts[hostname] = None + elif is_ipv4_hostname(hostname): + mounts[f"all://{hostname}"] = None + elif is_ipv6_hostname(hostname): + mounts[f"all://[{hostname}]"] = None + elif hostname.lower() == "localhost": + mounts[f"all://{hostname}"] = None + else: + mounts[f"all://*{hostname}"] = None + + return mounts + + +def to_bytes(value: str | bytes, encoding: str = "utf-8") -> bytes: + return value.encode(encoding) if isinstance(value, str) else value + + +def to_str(value: str | bytes, encoding: str = "utf-8") -> str: + return value if isinstance(value, str) else value.decode(encoding) + + +def to_bytes_or_str(value: str, match_type_of: typing.AnyStr) -> typing.AnyStr: + return value if isinstance(match_type_of, str) else value.encode() + + +def unquote(value: str) -> str: + return value[1:-1] if value[0] == value[-1] == '"' else value + + +def peek_filelike_length(stream: typing.Any) -> int | None: + """ + Given a file-like stream object, return its length in number of bytes + without reading it into memory. + """ + try: + # Is it an actual file? + fd = stream.fileno() + # Yup, seems to be an actual file. + length = os.fstat(fd).st_size + except (AttributeError, OSError): + # No... Maybe it's something that supports random access, like `io.BytesIO`? + try: + # Assuming so, go to end of stream to figure out its length, + # then put it back in place. + offset = stream.tell() + length = stream.seek(0, os.SEEK_END) + stream.seek(offset) + except (AttributeError, OSError): + # Not even that? Sorry, we're doomed... + return None + + return length + + +class URLPattern: + """ + A utility class currently used for making lookups against proxy keys... + + # Wildcard matching... + >>> pattern = URLPattern("all://") + >>> pattern.matches(httpx.URL("http://example.com")) + True + + # Witch scheme matching... + >>> pattern = URLPattern("https://") + >>> pattern.matches(httpx.URL("https://example.com")) + True + >>> pattern.matches(httpx.URL("http://example.com")) + False + + # With domain matching... + >>> pattern = URLPattern("https://example.com") + >>> pattern.matches(httpx.URL("https://example.com")) + True + >>> pattern.matches(httpx.URL("http://example.com")) + False + >>> pattern.matches(httpx.URL("https://other.com")) + False + + # Wildcard scheme, with domain matching... + >>> pattern = URLPattern("all://example.com") + >>> pattern.matches(httpx.URL("https://example.com")) + True + >>> pattern.matches(httpx.URL("http://example.com")) + True + >>> pattern.matches(httpx.URL("https://other.com")) + False + + # With port matching... + >>> pattern = URLPattern("https://example.com:1234") + >>> pattern.matches(httpx.URL("https://example.com:1234")) + True + >>> pattern.matches(httpx.URL("https://example.com")) + False + """ + + def __init__(self, pattern: str) -> None: + from ._urls import URL + + if pattern and ":" not in pattern: + raise ValueError( + f"Proxy keys should use proper URL forms rather " + f"than plain scheme strings. " + f'Instead of "{pattern}", use "{pattern}://"' + ) + + url = URL(pattern) + self.pattern = pattern + self.scheme = "" if url.scheme == "all" else url.scheme + self.host = "" if url.host == "*" else url.host + self.port = url.port + if not url.host or url.host == "*": + self.host_regex: typing.Pattern[str] | None = None + elif url.host.startswith("*."): + # *.example.com should match "www.example.com", but not "example.com" + domain = re.escape(url.host[2:]) + self.host_regex = re.compile(f"^.+\\.{domain}$") + elif url.host.startswith("*"): + # *example.com should match "www.example.com" and "example.com" + domain = re.escape(url.host[1:]) + self.host_regex = re.compile(f"^(.+\\.)?{domain}$") + else: + # example.com should match "example.com" but not "www.example.com" + domain = re.escape(url.host) + self.host_regex = re.compile(f"^{domain}$") + + def matches(self, other: URL) -> bool: + if self.scheme and self.scheme != other.scheme: + return False + if ( + self.host + and self.host_regex is not None + and not self.host_regex.match(other.host) + ): + return False + if self.port is not None and self.port != other.port: + return False + return True + + @property + def priority(self) -> tuple[int, int, int]: + """ + The priority allows URLPattern instances to be sortable, so that + we can match from most specific to least specific. + """ + # URLs with a port should take priority over URLs without a port. + port_priority = 0 if self.port is not None else 1 + # Longer hostnames should match first. + host_priority = -len(self.host) + # Longer schemes should match first. + scheme_priority = -len(self.scheme) + return (port_priority, host_priority, scheme_priority) + + def __hash__(self) -> int: + return hash(self.pattern) + + def __lt__(self, other: URLPattern) -> bool: + return self.priority < other.priority + + def __eq__(self, other: typing.Any) -> bool: + return isinstance(other, URLPattern) and self.pattern == other.pattern + + +def is_ipv4_hostname(hostname: str) -> bool: + try: + ipaddress.IPv4Address(hostname.split("/")[0]) + except Exception: + return False + return True + + +def is_ipv6_hostname(hostname: str) -> bool: + try: + ipaddress.IPv6Address(hostname.split("/")[0]) + except Exception: + return False + return True diff --git a/source/target-vendors/cp312/httpx/py.typed b/source/target-vendors/cp312/httpx/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/METADATA b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/METADATA new file mode 100644 index 0000000..41f3bf1 --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/METADATA @@ -0,0 +1,351 @@ +Metadata-Version: 2.4 +Name: httpx-sse +Version: 0.4.3 +Summary: Consume Server-Sent Event (SSE) messages with HTTPX. +Author-email: Florimond Manca +License: MIT +Project-URL: Homepage, https://github.com/florimondmanca/httpx-sse +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-File: LICENSE +Dynamic: license-file + +# httpx-sse + +[![Build Status](https://dev.azure.com/florimondmanca/public/_apis/build/status/florimondmanca.httpx-sse?branchName=master)](https://dev.azure.com/florimondmanca/public/_build?definitionId=19) +[![Coverage](https://codecov.io/gh/florimondmanca/httpx-sse/branch/master/graph/badge.svg)](https://codecov.io/gh/florimondmanca/httpx-sse) +[![Package version](https://badge.fury.io/py/httpx-sse.svg)](https://pypi.org/project/httpx-sse) + +Consume [Server-Sent Event (SSE)](https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events) messages with [HTTPX](https://www.python-httpx.org). + +**Table of contents** + +- [Installation](#installation) +- [Quickstart](#quickstart) +- [How-To](#how-to) +- [API Reference](#api-reference) + +## Installation + +**NOTE**: This is beta software. Please be sure to pin your dependencies. + +```bash +pip install httpx-sse=="0.4.*" +``` + +## Quickstart + +`httpx-sse` provides the [`connect_sse`](#connect_sse) and [`aconnect_sse`](#aconnect_sse) helpers for connecting to an SSE endpoint. The resulting [`EventSource`](#eventsource) object exposes the [`.iter_sse()`](#iter_sse) and [`.aiter_sse()`](#aiter_sse) methods to iterate over the server-sent events. + +Example usage: + +```python +import httpx +from httpx_sse import connect_sse + +with httpx.Client() as client: + with connect_sse(client, "GET", "http://localhost:8000/sse") as event_source: + for sse in event_source.iter_sse(): + print(sse.event, sse.data, sse.id, sse.retry) +``` + +You can try this against this example Starlette server ([credit](https://sysid.github.io/sse/)): + +```python +# Requirements: pip install uvicorn starlette sse-starlette +import asyncio +import uvicorn +from starlette.applications import Starlette +from starlette.routing import Route +from sse_starlette.sse import EventSourceResponse + +async def numbers(minimum, maximum): + for i in range(minimum, maximum + 1): + await asyncio.sleep(0.9) + yield {"data": i} + +async def sse(request): + generator = numbers(1, 5) + return EventSourceResponse(generator) + +routes = [ + Route("/sse", endpoint=sse) +] + +app = Starlette(routes=routes) + +if __name__ == "__main__": + uvicorn.run(app) +``` + +## How-To + +### Calling into Python web apps + +You can [call into Python web apps](https://www.python-httpx.org/async/#calling-into-python-web-apps) with HTTPX and `httpx-sse` to test SSE endpoints directly. + +Here's an example of calling into a Starlette ASGI app... + +```python +import asyncio + +import httpx +from httpx_sse import aconnect_sse +from sse_starlette.sse import EventSourceResponse +from starlette.applications import Starlette +from starlette.routing import Route + +async def auth_events(request): + async def events(): + yield { + "event": "login", + "data": '{"user_id": "4135"}', + } + + return EventSourceResponse(events()) + +app = Starlette(routes=[Route("/sse/auth/", endpoint=auth_events)]) + +async def main(): + async with httpx.AsyncClient(transport=httpx.ASGITransport(app)) as client: + async with aconnect_sse( + client, "GET", "http://localhost:8000/sse/auth/" + ) as event_source: + events = [sse async for sse in event_source.aiter_sse()] + (sse,) = events + assert sse.event == "login" + assert sse.json() == {"user_id": "4135"} + +asyncio.run(main()) +``` + +### Handling reconnections + +_(Advanced)_ + +`SSETransport` and `AsyncSSETransport` don't have reconnection built-in. This is because how to perform retries is generally dependent on your use case. As a result, if the connection breaks while attempting to read from the server, you will get an `httpx.ReadError` from `iter_sse()` (or `aiter_sse()`). + +However, `httpx-sse` does allow implementing reconnection by using the `Last-Event-ID` and reconnection time (in milliseconds), exposed as `sse.id` and `sse.retry` respectively. + +Here's how you might achieve this using [`stamina`](https://github.com/hynek/stamina)... + +```python +import time +from typing import Iterator + +import httpx +from httpx_sse import connect_sse, ServerSentEvent +from stamina import retry + +def iter_sse_retrying(client, method, url): + last_event_id = "" + reconnection_delay = 0.0 + + # `stamina` will apply jitter and exponential backoff on top of + # the `retry` reconnection delay sent by the server. + @retry(on=httpx.ReadError) + def _iter_sse(): + nonlocal last_event_id, reconnection_delay + + time.sleep(reconnection_delay) + + headers = {"Accept": "text/event-stream"} + + if last_event_id: + headers["Last-Event-ID"] = last_event_id + + with connect_sse(client, method, url, headers=headers) as event_source: + for sse in event_source.iter_sse(): + last_event_id = sse.id + + if sse.retry is not None: + reconnection_delay = sse.retry / 1000 + + yield sse + + return _iter_sse() +``` + +Usage: + +```python +with httpx.Client() as client: + for sse in iter_sse_retrying(client, "GET", "http://localhost:8000/sse"): + print(sse.event, sse.data) +``` + +## API Reference + +### `connect_sse` + +```python +def connect_sse( + client: httpx.Client, + method: str, + url: Union[str, httpx.URL], + **kwargs, +) -> ContextManager[EventSource] +``` + +Connect to an SSE endpoint and return an [`EventSource`](#eventsource) context manager. + +This sets `Cache-Control: no-store` on the request, as per the SSE spec, as well as `Accept: text/event-stream`. + +If the response `Content-Type` is not `text/event-stream`, this will raise an [`SSEError`](#sseerror). + +### `aconnect_sse` + +```python +async def aconnect_sse( + client: httpx.AsyncClient, + method: str, + url: Union[str, httpx.URL], + **kwargs, +) -> AsyncContextManager[EventSource] +``` + +An async equivalent to [`connect_sse`](#connect_sse). + +### `EventSource` + +```python +def __init__(response: httpx.Response) +``` + +Helper for working with an SSE response. + +#### `response` + +The underlying [`httpx.Response`](https://www.python-httpx.org/api/#response). + +You may use this to perform more operations and checks on the response, such as checking for HTTP status errors: + +```python +with connect_sse(...) as event_source: + event_source.response.raise_for_status() + + for sse in event_source.iter_sse(): + ... +``` + +#### `iter_sse` + +```python +def iter_sse() -> Iterator[ServerSentEvent] +``` + +Decode the response content and yield corresponding [`ServerSentEvent`](#serversentevent). + +Example usage: + +```python +for sse in event_source.iter_sse(): + ... +``` + +#### `aiter_sse` + +```python +async def iter_sse() -> AsyncIterator[ServerSentEvent] +``` + +An async equivalent to `iter_sse`. + +### `ServerSentEvent` + +Represents a server-sent event. + +* `event: str` - Defaults to `"message"`. +* `data: str` - Defaults to `""`. +* `id: str` - Defaults to `""`. +* `retry: str | None` - Defaults to `None`. + +Methods: + +* `json() -> Any` - Returns `sse.data` decoded as JSON. + +### `SSEError` + +An error that occurred while making a request to an SSE endpoint. + +Parents: + +* `httpx.TransportError` + +## License + +MIT + +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## 0.4.3 - 2025-10-10 + +### Fixed + +* Fix performance issue introduced by the improved line parsing from release 0.4.2. (Pull #40) + +## 0.4.2 - 2025-10-07 + +### Fixed + +* Fix incorrect newline parsing that was not compliant with SSE spec. (Pull #37) + +## 0.4.1 - 2025-06-24 + +### Fixed + +* Always close the response async generator in `aiter_sse()`. (Pull #30) + +## 0.4.0 - 2023-12-22 + +### Removed + +* Dropped Python 3.7 support, as it has reached EOL. (Pull #21) + +### Added + +* Add official support for Python 3.12. (Pull #21) + +### Fixed + +* Allow `Content-Type` that contain but are not strictly `text/event-stream`. (Pull #22 by @dbuades) +* Improve error message when `Content-Type` is missing. (Pull #20 by @jamesbraza) + +## 0.3.1 - 2023-06-01 + +### Added + +* Add `__repr__()` for `ServerSentEvent` model, which may help with debugging and other tasks. (Pull #16) + +## 0.3.0 - 2023-04-27 + +### Changed + +* Raising an `SSEError` if the response content type is not `text/event-stream` is now performed as part of `iter_sse()` / `aiter_sse()`, instead of `connect_sse()` / `aconnect_sse()`. This allows inspecting the response before iterating on server-sent events, such as checking for error responses. (Pull #12) + +## 0.2.0 - 2023-03-27 + +### Changed + +* `connect_sse()` and `aconnect_sse()` now require a `method` argument: `connect_sse(client, "GET", "https://example.org")`. This provides support for SSE requests with HTTP verbs other than `GET`. (Pull #7) + +## 0.1.0 - 2023-02-05 + +_Initial release_ + +### Added + +* Add `connect_sse`, `aconnect_sse()`, `ServerSentEvent` and `SSEError`. diff --git a/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/RECORD b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/RECORD new file mode 100644 index 0000000..dc042e8 --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/RECORD @@ -0,0 +1,11 @@ +httpx_sse/__init__.py,sha256=G-F8jpJLo4eJwKvKt6ejTQYPhBHgmksZTNuaQySRAjc,282 +httpx_sse/_api.py,sha256=D7pfkajmdHlms75OV8HpdOrOEr5NbWQlDwMfSFcJ8FU,2919 +httpx_sse/_decoders.py,sha256=na1XyVBiCLbRE8tg0o713U5Gz-m9fBxYPfSMmu_xns8,4005 +httpx_sse/_exceptions.py,sha256=sFZBUT1xIM1DvYQ6ckpzrhBG9d8VffFSZFMIEhv1N58,62 +httpx_sse/_models.py,sha256=4WwGeBEGMR2nbROTZ7PyVlu7chmWg7tbkJyXyd5DTx0,1221 +httpx_sse/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +httpx_sse-0.4.3.dist-info/licenses/LICENSE,sha256=vuxn5O6Dp68m8kK-2Zh6qGPW0t-3dhBqojYMQYfzGQE,1072 +httpx_sse-0.4.3.dist-info/METADATA,sha256=1MbYBO5axG6bO2WVwnq4riunz7X2kseLFv9GPkvRqB4,9671 +httpx_sse-0.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 +httpx_sse-0.4.3.dist-info/top_level.txt,sha256=hbK3kwBH9d-rEZQvJ6yBawdDylIKfJ8fh0CM4EVNs04,10 +httpx_sse-0.4.3.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/WHEEL b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/WHEEL new file mode 100644 index 0000000..e7fa31b --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/licenses/LICENSE b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/licenses/LICENSE new file mode 100644 index 0000000..36600eb --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Florimond Manca + +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/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/top_level.txt b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/top_level.txt new file mode 100644 index 0000000..a5e926f --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse-0.4.3.dist-info/top_level.txt @@ -0,0 +1 @@ +httpx_sse diff --git a/source/target-vendors/cp312/httpx_sse/__init__.py b/source/target-vendors/cp312/httpx_sse/__init__.py new file mode 100644 index 0000000..b83cf09 --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse/__init__.py @@ -0,0 +1,14 @@ +from ._api import EventSource, aconnect_sse, connect_sse +from ._exceptions import SSEError +from ._models import ServerSentEvent + +__version__ = "0.4.3" + +__all__ = [ + "__version__", + "EventSource", + "connect_sse", + "aconnect_sse", + "ServerSentEvent", + "SSEError", +] diff --git a/source/target-vendors/cp312/httpx_sse/_api.py b/source/target-vendors/cp312/httpx_sse/_api.py new file mode 100644 index 0000000..017ed5e --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse/_api.py @@ -0,0 +1,93 @@ +from collections.abc import AsyncGenerator +from contextlib import asynccontextmanager, contextmanager +from typing import Any, AsyncIterator, Iterator, cast + +import httpx + +from ._decoders import SSEDecoder, SSELineDecoder +from ._exceptions import SSEError +from ._models import ServerSentEvent + + +class EventSource: + def __init__(self, response: httpx.Response) -> None: + self._response = response + + def _check_content_type(self) -> None: + content_type = self._response.headers.get("content-type", "").partition(";")[0] + if "text/event-stream" not in content_type: + raise SSEError( + "Expected response header Content-Type to contain 'text/event-stream', " + f"got {content_type!r}" + ) + + @property + def response(self) -> httpx.Response: + return self._response + + def iter_sse(self) -> Iterator[ServerSentEvent]: + self._check_content_type() + decoder = SSEDecoder() + for line in _iter_sse_lines(self._response): + line = line.rstrip("\n") + sse = decoder.decode(line) + if sse is not None: + yield sse + + async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]: + self._check_content_type() + decoder = SSEDecoder() + lines = cast(AsyncGenerator[str, None], _aiter_sse_lines(self._response)) + try: + async for line in lines: + line = line.rstrip("\n") + sse = decoder.decode(line) + if sse is not None: + yield sse + finally: + await lines.aclose() + + +@contextmanager +def connect_sse( + client: httpx.Client, method: str, url: str, **kwargs: Any +) -> Iterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) + + +@asynccontextmanager +async def aconnect_sse( + client: httpx.AsyncClient, + method: str, + url: str, + **kwargs: Any, +) -> AsyncIterator[EventSource]: + headers = kwargs.pop("headers", {}) + headers["Accept"] = "text/event-stream" + headers["Cache-Control"] = "no-store" + + async with client.stream(method, url, headers=headers, **kwargs) as response: + yield EventSource(response) + + +async def _aiter_sse_lines(response: httpx.Response) -> AsyncIterator[str]: + decoder = SSELineDecoder() + async for text in response.aiter_text(): + for line in decoder.decode(text): + yield line + for line in decoder.flush(): + yield line + + +def _iter_sse_lines(response: httpx.Response) -> Iterator[str]: + decoder = SSELineDecoder() + for text in response.iter_text(): + for line in decoder.decode(text): + yield line + for line in decoder.flush(): + yield line diff --git a/source/target-vendors/cp312/httpx_sse/_decoders.py b/source/target-vendors/cp312/httpx_sse/_decoders.py new file mode 100644 index 0000000..287e384 --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse/_decoders.py @@ -0,0 +1,139 @@ +from typing import List, Optional + +from ._models import ServerSentEvent + + +def _splitlines_sse(text: str) -> List[str]: + """Split text on \r\n, \r, or \n only.""" + if not text: + return [] + + if "\r" not in text: + lines = text.split("\n") + else: + normalized = text.replace("\r\n", "\n").replace("\r", "\n") + lines = normalized.split("\n") + + if text[-1] in "\r\n": + lines.pop() + + return lines + + +class SSELineDecoder: + """ + Handles incrementally reading lines from text. + + Mostly a copy of httpx._decoders.LineDecoder, but as per SSE spec, only \r\n, \r, + and \n are treated as newlines, which differs from the behavior of splitlines() + used by httpx._decoders.LineDecoder. + """ + + def __init__(self) -> None: + self.buffer: list[str] = [] + self.trailing_cr: bool = False + + def decode(self, text: str) -> list[str]: + # We always push a trailing `\r` into the next decode iteration. + if self.trailing_cr: + text = "\r" + text + self.trailing_cr = False + if text.endswith("\r"): + self.trailing_cr = True + text = text[:-1] + + if not text: + # NOTE: the edge case input of empty text doesn't occur in practice, + # because other httpx internals filter out this value + return [] # pragma: no cover + + trailing_newline = text[-1] in "\n\r" + lines = _splitlines_sse(text) + + if len(lines) == 1 and not trailing_newline: + # No new lines, buffer the input and continue. + self.buffer.append(lines[0]) + return [] + + if self.buffer: + # Include any existing buffer in the first portion of the + # splitlines result. + lines = ["".join(self.buffer) + lines[0]] + lines[1:] + self.buffer = [] + + if not trailing_newline: + # If the last segment of splitlines is not newline terminated, + # then drop it from our output and start a new buffer. + self.buffer = [lines.pop()] + + return lines + + def flush(self) -> list[str]: + if not self.buffer and not self.trailing_cr: + return [] + + lines = ["".join(self.buffer)] + self.buffer = [] + self.trailing_cr = False + return lines + + +class SSEDecoder: + def __init__(self) -> None: + self._event = "" + self._data: List[str] = [] + self._last_event_id = "" + self._retry: Optional[int] = None + + def decode(self, line: str) -> Optional[ServerSentEvent]: + # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 + + if not line: + if ( + not self._event + and not self._data + and not self._last_event_id + and self._retry is None + ): + return None + + sse = ServerSentEvent( + event=self._event, + data="\n".join(self._data), + id=self._last_event_id, + retry=self._retry, + ) + + # NOTE: as per the SSE spec, do not reset last_event_id. + self._event = "" + self._data = [] + self._retry = None + + return sse + + if line.startswith(":"): + return None + + fieldname, _, value = line.partition(":") + + if value.startswith(" "): + value = value[1:] + + if fieldname == "event": + self._event = value + elif fieldname == "data": + self._data.append(value) + elif fieldname == "id": + if "\0" in value: + pass + else: + self._last_event_id = value + elif fieldname == "retry": + try: + self._retry = int(value) + except (TypeError, ValueError): + pass + else: + pass # Field is ignored. + + return None diff --git a/source/target-vendors/cp312/httpx_sse/_exceptions.py b/source/target-vendors/cp312/httpx_sse/_exceptions.py new file mode 100644 index 0000000..cd2c4d2 --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse/_exceptions.py @@ -0,0 +1,5 @@ +import httpx + + +class SSEError(httpx.TransportError): + pass diff --git a/source/target-vendors/cp312/httpx_sse/_models.py b/source/target-vendors/cp312/httpx_sse/_models.py new file mode 100644 index 0000000..d4dc119 --- /dev/null +++ b/source/target-vendors/cp312/httpx_sse/_models.py @@ -0,0 +1,54 @@ +import json +from typing import Any, Optional + + +class ServerSentEvent: + def __init__( + self, + event: Optional[str] = None, + data: Optional[str] = None, + id: Optional[str] = None, + retry: Optional[int] = None, + ) -> None: + if not event: + event = "message" + + if data is None: + data = "" + + if id is None: + id = "" + + self._event = event + self._data = data + self._id = id + self._retry = retry + + @property + def event(self) -> str: + return self._event + + @property + def data(self) -> str: + return self._data + + @property + def id(self) -> str: + return self._id + + @property + def retry(self) -> Optional[int]: + return self._retry + + def json(self) -> Any: + return json.loads(self.data) + + def __repr__(self) -> str: + pieces = [f"event={self.event!r}"] + if self.data != "": + pieces.append(f"data={self.data!r}") + if self.id != "": + pieces.append(f"id={self.id!r}") + if self.retry is not None: + pieces.append(f"retry={self.retry!r}") + return f"ServerSentEvent({', '.join(pieces)})" diff --git a/source/target-vendors/cp312/httpx_sse/py.typed b/source/target-vendors/cp312/httpx_sse/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/idna-3.20.dist-info/METADATA b/source/target-vendors/cp312/idna-3.20.dist-info/METADATA new file mode 100644 index 0000000..edbc446 --- /dev/null +++ b/source/target-vendors/cp312/idna-3.20.dist-info/METADATA @@ -0,0 +1,176 @@ +Metadata-Version: 2.5 +Name: idna +Version: 3.20 +Summary: Internationalized Domain Names in Applications (IDNA) +Author-email: Kim Davies +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: Name Service (DNS) +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Utilities +License-File: LICENSE.md +Requires-Dist: ruff >= 0.16.0 ; extra == "all" +Requires-Dist: mypy >= 1.11.2 ; extra == "all" +Requires-Dist: ty >= 0.0.37 ; extra == "all" +Requires-Dist: pytest >= 8.3.2 ; extra == "all" +Requires-Dist: hypothesis >= 6.141.1 ; extra == "all" +Requires-Dist: coverage >= 7.10.0 ; extra == "all" +Project-URL: Changelog, https://github.com/kjd/idna/blob/master/HISTORY.md +Project-URL: Issue tracker, https://github.com/kjd/idna/issues +Project-URL: Source, https://github.com/kjd/idna +Provides-Extra: all +Import-Name: idna + +# Internationalized Domain Names in Applications (IDNA) + +Support for [Internationalized Domain Names in Applications +(IDNA)](https://tools.ietf.org/html/rfc5891) and [Unicode IDNA +Compatibility Processing](https://unicode.org/reports/tr46/). It +supersedes the standard library's `encodings.idna`, which only +implements the 2003 specification, offering broader script coverage and +limiting domains with known security vulnerabilities. + +## Usage + +Package may be installed from [PyPI](https://pypi.org/project/idna/) via +the typical methods (e.g. `python3 -m pip install idna`) + +For typical usage, the `encode` and `decode` functions will take a +domain name argument and perform a conversion to ASCII-compatible encoding +(known as A-labels), or to Unicode strings (known as U-labels) +respectively. + +```pycon +>>> import idna +>>> idna.encode('ドメイン.テスト') +b'xn--eckwd4c7c.xn--zckzah' +>>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) +ドメイン.テスト +``` + +Conversions can be applied at a per-label basis using the `ulabel` or +`alabel` functions for specialized use cases. + + +### Compatibility Mapping (UTS #46) + +This library provides support for [Unicode IDNA Compatibility +Processing](https://unicode.org/reports/tr46/) which normalizes input from +different potential ways a user may input a domain prior to performing the IDNA +conversion operations. This functionality, known as a +[mapping](https://tools.ietf.org/html/rfc5895), is considered by the +specification to be a local user-interface issue distinct from IDNA +conversion functionality. + +For example, "Königsgäßchen" is not a permissible label as capital letters +are not allowed. UTS #46 will convert this into lower case prior to applying +the IDNA conversion. + +```pycon +>>> import idna +>>> idna.encode('Königsgäßchen') +... +idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed +>>> idna.encode('Königsgäßchen', uts46=True) +b'xn--knigsgchen-b4a3dun' +>>> idna.decode('xn--knigsgchen-b4a3dun') +'königsgäßchen' +``` + +When performing a decode operation for display purposes, `decode()` +accepts a `display=True` argument that leaves any `xn--` label that +fails to decode unchanged. This is useful for user interface display +where a domain is in use, the A-label form can be presented when it +is not a valid IDN. + + +## Exceptions + +All errors raised during conversion derive from the `idna.IDNAError` +base class. The more specific exceptions are: + +* `idna.IDNABidiError` — raised when a label contains an illegal + combination of left-to-right and right-to-left characters. +* `idna.InvalidCodepoint` — raised when a label contains a codepoint + that is INVALID for IDNA. +* `idna.InvalidCodepointContext` — raised when a CONTEXTO or CONTEXTJ + codepoint appears in a position whose contextual requirements are + not satisfied. + +Exceptions carry machine-readable attributes so that applications do +not need to parse the message: `code` is a short, stable identifier +for the rule that failed (such as `disallowed_codepoint` or +`label_too_long`); and, when the failure can be attributed to a +particular character, `text` (the label or domain being validated), +`codepoint` (the offending codepoint as an integer) and `position` +are set. + + +## Command-line tool + +The package supports command-line usage to convert domain names +between their Unicode and ASCII-compatible forms. It can be run either +as a module (`python3 -m idna`) or, once installed (such as with `uv +tool` or `pipx`), via the `idna` script: + +```bash +$ uv tool install idna +$ idna xn--e1afmkfd.xn--p1ai +пример.рф +$ idna пример.рф +xn--e1afmkfd.xn--p1ai +``` + +Mode can be specified with `-e`/`--encode` or `-d`/`--decode`, otherwise +it will be chosen automatically based on the first input. Multiple +domains can be supplied either as arguments or through standard input. +UTS #46 mapping is applied by default, which lets the tool accept +inputs that aren't strictly valid IDNA 2008 by normalising them first, +pass `--strict` to disable UTS #46. + +Conversion failures are reported on stderr together with the +offending input; processing continues with the remaining domains and +the tool exits with a non-zero status if any conversion failed. + + +## Additional Notes + +* **Python version support**. This library supports Python 3.9 and higher. + As this library serves as a low-level toolkit for a variety of + applications, we strive to support all versions of Python that are + not beyond end-of-life. Free-threaded Python is also supported, + as the library holds no mutable global state the functions can be + called concurrently from multiple threads. + +* **Unicode version**. The IDNA and UTS #46 lookup tables are generated + from a specific Unicode release. Some Unicode data depends on the + running Python's `unicodedata` module, so on an older Python a + character new to Unicode may be rejected as unknown even if this + library knows about it. + +* **Emoji**. It is an occasional request to support emoji domains in + this library. Encoding of symbols like emoji is expressly prohibited by + the IDNA technical standard, and emoji domains are broadly phased + out across the domain industry due to associated security risks. + +* **Regenerating lookup tables**. The IDNA and UTS #46 functionality + relies upon pre-calculated lookup tables, generated using the + `idna-data` script in [`tools/`](tools/README.md). + diff --git a/source/target-vendors/cp312/idna-3.20.dist-info/RECORD b/source/target-vendors/cp312/idna-3.20.dist-info/RECORD new file mode 100644 index 0000000..1e93cc6 --- /dev/null +++ b/source/target-vendors/cp312/idna-3.20.dist-info/RECORD @@ -0,0 +1,16 @@ +idna/__init__.py,sha256=hRTD7VMTajWW699RL6SHu919pama3K7YLgNj0sMG068,944 +idna/__main__.py,sha256=4JMK66Wj4uLZTKbF-sT3LAxOsr6buig77PmOkJCRRxw,83 +idna/cli.py,sha256=LgGXKiXmev37pdgkATwB6AiJORZTnA2zP3LzfEK4iWo,4245 +idna/codec.py,sha256=ff9CR9debiZcvqEmHxDRIrqSmaNxQpz6AY4JHsC3YC0,8002 +idna/compat.py,sha256=T_eZXOUt0b5Tga56cPybQu9CCYK0FTK1mdiPb96na8A,1376 +idna/core.py,sha256=PdTD_-5P8iMgf6xl84EqHmiVrorR56btYBFXaPNVFSA,32580 +idna/idnadata.py,sha256=I6mowdFd6cY00L8hPXeYEPSFCD_hsPfgkEStBKacx-s,45763 +idna/intranges.py,sha256=g49scLSkqJtAhLmOODa7hVHriSjmb60tiTsEoocJdBI,1851 +idna/package_data.py,sha256=rnWVNKPFgqAKyFbPykZKOe6CUdOTII2K8GtgW8IOAqk,21 +idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +idna/uts46data.py,sha256=dw6Em_oVbHGCiolEClf-mupwc18QOuRhbuT2guE9bAA,237174 +idna-3.20.dist-info/entry_points.txt,sha256=7H3nGOHap3jnLE5e7q7Ywr9Vq8axB7WIj5-C_4N2vhw,38 +idna-3.20.dist-info/licenses/LICENSE.md,sha256=GppPDj1HmickDd1ZqRN6ZqtKD539yMphiMwL_YUYfwQ,1541 +idna-3.20.dist-info/WHEEL,sha256=lqN8jXt_QloFOGcx9kStvWbryhfEXoI2F2z-YURm350,81 +idna-3.20.dist-info/METADATA,sha256=29jBTB5MoeDJgkptvHy794iE8461LZEUjNMCX2ceS4U,7207 +idna-3.20.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/idna-3.20.dist-info/WHEEL b/source/target-vendors/cp312/idna-3.20.dist-info/WHEEL new file mode 100644 index 0000000..1ab9a08 --- /dev/null +++ b/source/target-vendors/cp312/idna-3.20.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 4.1.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/idna-3.20.dist-info/entry_points.txt b/source/target-vendors/cp312/idna-3.20.dist-info/entry_points.txt new file mode 100644 index 0000000..59ca7ac --- /dev/null +++ b/source/target-vendors/cp312/idna-3.20.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +idna=idna.cli:main + diff --git a/source/target-vendors/cp312/idna-3.20.dist-info/licenses/LICENSE.md b/source/target-vendors/cp312/idna-3.20.dist-info/licenses/LICENSE.md new file mode 100644 index 0000000..f706835 --- /dev/null +++ b/source/target-vendors/cp312/idna-3.20.dist-info/licenses/LICENSE.md @@ -0,0 +1,31 @@ +BSD 3-Clause License + +Copyright (c) 2013-2026, Kim Davies and contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/idna/__init__.py b/source/target-vendors/cp312/idna/__init__.py new file mode 100644 index 0000000..d6c890a --- /dev/null +++ b/source/target-vendors/cp312/idna/__init__.py @@ -0,0 +1,47 @@ +from .core import ( + IDNABidiError, + IDNAError, + InvalidCodepoint, + InvalidCodepointContext, + alabel, + check_bidi, + check_hyphen_ok, + check_initial_combiner, + check_label, + check_nfc, + decode, + encode, + ulabel, + uts46_remap, + valid_contextj, + valid_contexto, + valid_label_length, + valid_string_length, +) +from .idnadata import __version__ as unicode_version +from .intranges import intranges_contain +from .package_data import __version__ + +__all__ = [ + "__version__", + "unicode_version", + "IDNABidiError", + "IDNAError", + "InvalidCodepoint", + "InvalidCodepointContext", + "alabel", + "check_bidi", + "check_hyphen_ok", + "check_initial_combiner", + "check_label", + "check_nfc", + "decode", + "encode", + "intranges_contain", + "ulabel", + "uts46_remap", + "valid_contextj", + "valid_contexto", + "valid_label_length", + "valid_string_length", +] diff --git a/source/target-vendors/cp312/idna/__main__.py b/source/target-vendors/cp312/idna/__main__.py new file mode 100644 index 0000000..dbdd066 --- /dev/null +++ b/source/target-vendors/cp312/idna/__main__.py @@ -0,0 +1,6 @@ +import sys + +from .cli import main + +if __name__ == "__main__": + sys.exit(main()) diff --git a/source/target-vendors/cp312/idna/cli.py b/source/target-vendors/cp312/idna/cli.py new file mode 100644 index 0000000..894d8a0 --- /dev/null +++ b/source/target-vendors/cp312/idna/cli.py @@ -0,0 +1,132 @@ +"""Command-line interface for the :mod:`idna` package. + +Invoked via ``python -m idna``. See :func:`main` for the entry point. +""" + +from __future__ import annotations + +import argparse +import sys +from itertools import chain +from typing import IO, TYPE_CHECKING + +from . import IDNAError, decode, encode, unicode_version +from .core import _alabel_prefix, _unicode_dots_re +from .package_data import __version__ + +if TYPE_CHECKING: + from collections.abc import Iterable + + +def _looks_like_alabel(s: str) -> bool: + """Return True if any label in ``s`` carries the ``xn--`` ACE prefix.""" + prefix = _alabel_prefix.decode("ascii") + return any(label.lower().startswith(prefix) for label in _unicode_dots_re.split(s)) + + +def _build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + prog="python -m idna", + description=( + "Convert a domain name between its Unicode (U-label) and " + "ASCII-compatible (A-label) forms. With no mode flag, the " + "direction is chosen from the first input — if it contains " + "an xn-- label the stream is decoded, otherwise it is " + "encoded — and the same mode is applied to every remaining " + "input. UTS #46 mapping is applied by default; pass " + "--strict to disable it. When no domains are given on the " + "command line and stdin is piped, one domain per line is " + "read from stdin." + ), + ) + mode = parser.add_mutually_exclusive_group() + mode.add_argument( + "-e", + "--encode", + dest="mode", + action="store_const", + const="encode", + help="Encode the input to its ASCII A-label form.", + ) + mode.add_argument( + "-d", + "--decode", + dest="mode", + action="store_const", + const="decode", + help="Decode the input from its ASCII A-label form.", + ) + parser.add_argument( + "--strict", + action="store_true", + help="Disable the default UTS #46 mapping and apply IDNA 2008 rules verbatim.", + ) + parser.add_argument( + "--version", + action="version", + version=f"idna {__version__} (Unicode {unicode_version})", + ) + parser.add_argument( + "domain", + nargs="*", + help="One or more domain names to convert. Omit to read from stdin.", + ) + return parser + + +def _iter_stdin(stream: IO[str]) -> Iterable[str]: + """Yield non-empty stripped lines from ``stream``, ignoring blanks.""" + for line in stream: + stripped = line.strip() + if stripped: + yield stripped + + +def _convert_one(domain: str, mode: str, uts46: bool) -> bool: + """Convert ``domain`` and write the result; return ``False`` on failure.""" + try: + if mode == "decode": + print(decode(domain, uts46=uts46)) + else: + print(encode(domain, uts46=uts46).decode("ascii")) + except IDNAError as err: + print(f"idna: {mode} failed for {domain!r}: {err}", file=sys.stderr) + return False + return True + + +def main(argv: list[str] | None = None) -> int: + """Entry point for ``python -m idna``. + + When more than one domain is supplied (via positional arguments or + piped stdin) and no mode flag is given, the first input determines + the direction and that mode is applied uniformly to the rest. + + :param argv: Argument list excluding the program name. Defaults to + :data:`sys.argv` when ``None``. + :returns: ``0`` on success, ``1`` if any conversion fails. + """ + parser = _build_parser() + args = parser.parse_args(argv) + uts46 = not args.strict + + if args.domain: + domains: Iterable[str] = args.domain + elif not sys.stdin.isatty(): + domains = _iter_stdin(sys.stdin) + else: + parser.error("a domain argument is required when stdin is a terminal") + + iterator = iter(domains) + first = next(iterator, None) + if first is None: + return 0 + + mode = args.mode or ("decode" if _looks_like_alabel(first) else "encode") + + results = [_convert_one(domain, mode, uts46) for domain in chain([first], iterator)] + return 0 if all(results) else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/source/target-vendors/cp312/idna/codec.py b/source/target-vendors/cp312/idna/codec.py new file mode 100644 index 0000000..8efc1ee --- /dev/null +++ b/source/target-vendors/cp312/idna/codec.py @@ -0,0 +1,225 @@ +from __future__ import annotations + +import codecs +from typing import Any + +from .core import IDNAError, _max_domain_length, _unicode_dots_re, alabel, decode, encode, ulabel + + +class Codec(codecs.Codec): + """Stateless IDNA 2008 codec. + + Implements the :class:`codecs.Codec` protocol so that the whole-domain + encoder (:func:`idna.encode`) and decoder (:func:`idna.decode`) are + accessible through the standard codec machinery as ``"idna2008"``. + + Only the ``"strict"`` error handler is supported; any other handler + raises :exc:`~idna.IDNAError`. + """ + + def encode(self, data: str, errors: str = "strict") -> tuple[bytes, int]: # ty: ignore[invalid-method-override] + if errors != "strict": + raise IDNAError(f'Unsupported error handling "{errors}"', code="unsupported_errors") + + if not data: + return b"", 0 + + return encode(data), len(data) + + def decode(self, data: bytes, errors: str = "strict") -> tuple[str, int]: # ty: ignore[invalid-method-override] + if errors != "strict": + raise IDNAError(f'Unsupported error handling "{errors}"', code="unsupported_errors") + + if not data: + return "", 0 + + return decode(data), len(data) + + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + """Incremental IDNA 2008 encoder. + + Buffers a partial trailing label across calls until either the next + label separator is seen or ``final=True``, so that streamed input is + encoded one whole label at a time. Any of the four Unicode label + separators (``U+002E``, ``U+3002``, ``U+FF0E``, ``U+FF61``) ends a + label; the result always uses ``U+002E`` as the separator. + + The 253-octet domain length limit (254 with a trailing dot) that + :func:`idna.encode` enforces is applied to the accumulated output, so + that streaming a name and encoding it in one shot either both succeed + with the same result or both raise :exc:`~idna.IDNAError`. + + Only the ``"strict"`` error handler is supported. + """ + + def __init__(self, errors: str = "strict") -> None: + super().__init__(errors) + self._emitted = 0 # octets returned so far + self._trailing_dot = False # whether the output so far ends with "." + + def reset(self) -> None: + super().reset() + self._emitted = 0 + self._trailing_dot = False + + def getstate(self) -> Any: + if not self.buffer and not self._emitted: + return 0 + return (self.buffer, self._emitted, self._trailing_dot) + + def setstate(self, state: Any) -> None: + if state: + self.buffer, self._emitted, self._trailing_dot = state + else: + self.reset() + + def _buffer_encode(self, data: str, errors: str, final: bool) -> tuple[bytes, int]: # ty: ignore[invalid-method-override] + if errors != "strict": + raise IDNAError(f'Unsupported error handling "{errors}"', code="unsupported_errors") + + result_bytes = b"" + size = 0 + if data: + labels = _unicode_dots_re.split(data) + trailing_dot = b"" + if labels: + if not labels[-1]: + trailing_dot = b"." + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = b"." + + result = [] + for label in labels: + result.append(alabel(label)) + if size: + size += 1 + size += len(label) + + result_bytes = b".".join(result) + trailing_dot + size += len(trailing_dot) + + # Mirror encode(): the whole name may not exceed 253 octets, or 254 + # when it ends with a dot. Until the input is final a trailing dot + # may still arrive, so only the 254-octet ceiling applies before then. + self._emitted += len(result_bytes) + if result_bytes: + self._trailing_dot = result_bytes.endswith(b".") + may_end_with_dot = self._trailing_dot or not final + if self._emitted > _max_domain_length + may_end_with_dot: + raise IDNAError("Domain too long", code="domain_too_long") + return result_bytes, size + + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + """Incremental IDNA 2008 decoder. + + Buffers a partial trailing label across calls until either the next + label separator is seen or ``final=True``, so that streamed input is + decoded one whole label at a time. + + The 254-octet input length limit that :func:`idna.decode` enforces is + applied to the accumulated input, so that streaming a name and decoding + it in one shot either both succeed with the same result or both raise + :exc:`~idna.IDNAError`. + + Only the ``"strict"`` error handler is supported. + """ + + def __init__(self, errors: str = "strict") -> None: + super().__init__(errors) + self._consumed = 0 # input octets consumed so far + + def reset(self) -> None: + super().reset() + self._consumed = 0 + + def getstate(self) -> tuple[bytes, int]: + return (self.buffer, self._consumed) + + def setstate(self, state: tuple[bytes, int]) -> None: + self.buffer, self._consumed = state + + def _buffer_decode(self, data: Any, errors: str, final: bool) -> tuple[str, int]: # ty: ignore[invalid-method-override] + if errors != "strict": + raise IDNAError(f'Unsupported error handling "{errors}"', code="unsupported_errors") + + if not data: + return ("", 0) + + if not isinstance(data, str): + try: + data = str(data, "ascii") + except UnicodeDecodeError as err: + raise IDNAError("Invalid ASCII in A-label", code="invalid_ascii") from err + + # Mirror decode(), which rejects input longer than 254 characters + # (253 plus a possible trailing dot) before looking at any label. + # ``data`` is the unconsumed buffer plus the new input, so this is + # the total seen so far. + if self._consumed + len(data) > _max_domain_length + 1: + raise IDNAError("Domain too long", code="domain_too_long") + + labels = _unicode_dots_re.split(data) + trailing_dot = "" + if labels: + if not labels[-1]: + trailing_dot = "." + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = "." + + result = [] + size = 0 + for label in labels: + result.append(ulabel(label)) + if size: + size += 1 + size += len(label) + + result_str = ".".join(result) + trailing_dot + size += len(trailing_dot) + self._consumed += size + return (result_str, size) + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + + +class StreamReader(Codec, codecs.StreamReader): + pass + + +def search_function(name: str) -> codecs.CodecInfo | None: + """Codec search function registered with :mod:`codecs`. + + Returns a :class:`codecs.CodecInfo` for the ``"idna2008"`` codec name + so that ``str.encode("idna2008")`` and ``bytes.decode("idna2008")`` + invoke the IDNA 2008 codec defined in this module. + + :param name: The codec name being looked up. + :returns: A :class:`codecs.CodecInfo` instance if ``name`` is + ``"idna2008"``, otherwise ``None``. + """ + if name != "idna2008": + return None + return codecs.CodecInfo( + name=name, + encode=Codec().encode, + decode=Codec().decode, # type: ignore + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamwriter=StreamWriter, + streamreader=StreamReader, + ) + + +codecs.register(search_function) diff --git a/source/target-vendors/cp312/idna/compat.py b/source/target-vendors/cp312/idna/compat.py new file mode 100644 index 0000000..5bedee9 --- /dev/null +++ b/source/target-vendors/cp312/idna/compat.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from typing import Any + +from .core import decode, encode + + +def ToASCII(label: str) -> bytes: + """Compatibility shim for :rfc:`3490` ``ToASCII``. + + Delegates to :func:`idna.encode` (IDNA 2008). Provided to ease porting + of code written against the legacy :mod:`encodings.idna` API; new code + should call :func:`idna.encode` directly. + + :param label: The label or domain to encode. + :returns: The encoded form as ASCII :class:`bytes`. + """ + return encode(label) + + +def ToUnicode(label: bytes | bytearray) -> str: + """Compatibility shim for :rfc:`3490` ``ToUnicode``. + + Delegates to :func:`idna.decode` (IDNA 2008). Provided to ease porting + of code written against the legacy :mod:`encodings.idna` API; new code + should call :func:`idna.decode` directly. + + :param label: The label or domain to decode. + :returns: The decoded Unicode form. + """ + return decode(label) + + +def nameprep(s: Any) -> None: + """Stub for :rfc:`3491` Nameprep, which is not used by IDNA 2008. + + IDNA 2008 (:rfc:`5891`) replaces Nameprep with the per-codepoint + validity classes from :rfc:`5892`; this function exists only to + return a clear error if legacy code attempts to call it. + + :raises NotImplementedError: Always. + """ + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") diff --git a/source/target-vendors/cp312/idna/core.py b/source/target-vendors/cp312/idna/core.py new file mode 100644 index 0000000..d4a6f0e --- /dev/null +++ b/source/target-vendors/cp312/idna/core.py @@ -0,0 +1,863 @@ +from __future__ import annotations + +import bisect +import re +import unicodedata +import warnings +from typing import Literal + +from . import idnadata +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b"xn--" +_max_input_length = 1024 +_max_domain_length = 253 # RFC 1035 octets, excluding any trailing dot +_STATUS_VALID, _STATUS_MAPPED, _STATUS_DEVIATION, _STATUS_IGNORED = b"VMDI" +_unicode_dots_re = re.compile("[\u002e\u3002\uff0e\uff61]") +_std3_disallowed_re = re.compile("[\x00-\x2c\x2f\x3a-\x40A-Z\x5b-\x60\x7b-\x7f]") +_bidi_rtl_first = frozenset({"R", "AL"}) +_bidi_rtl_categories = frozenset({"R", "AL", "AN"}) +_bidi_rtl_allowed = frozenset({"R", "AL", "AN", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"}) +_bidi_rtl_valid_ending = frozenset({"R", "AL", "EN", "AN"}) +_bidi_rtl_numeric = frozenset({"AN", "EN"}) +_bidi_ltr_allowed = frozenset({"L", "EN", "ES", "CS", "ET", "ON", "BN", "NSM"}) +_bidi_ltr_valid_ending = frozenset({"L", "EN"}) +_bidi_joiner_l_or_d = frozenset({"L", "D"}) +_bidi_joiner_r_or_d = frozenset({"R", "D"}) + + +def _joining_type(cp: int) -> str | None: + for jt, ranges in idnadata.joining_types.items(): + if intranges_contain(cp, ranges): + return jt + return None + + +# Machine-readable identifiers for the rule an :class:`IDNAError` reports. +# These strings are stable and documented; exception message wording is not. +_ErrorCode = Literal[ + "input_too_long", + "label_too_long", + "domain_too_long", + "empty_label", + "empty_domain", + "not_nfc", + "hyphen_3_4", + "hyphen_start_end", + "leading_combiner", + "disallowed_codepoint", + "contextj", + "contexto", + "unknown_codepoint", + "bidi_rule_1", + "bidi_rule_2", + "bidi_rule_3", + "bidi_rule_4", + "bidi_rule_5", + "bidi_rule_6", + "bidi_unknown_direction", + "invalid_alabel", + "non_canonical_alabel", + "invalid_ascii", + "invalid_utf8", + "uts46_disallowed", + "uts46_std3", + "unsupported_errors", +] + + +class IDNAError(UnicodeError): + """Base exception for all IDNA-encoding related problems. + + ``str(err)`` is a human-readable description of the failure. The + exception also carries machine-readable attributes so callers do not + need to parse the message: + + * ``code`` -- a short, stable identifier for the rule that failed, such + as ``"disallowed_codepoint"`` or ``"bidi_rule_2"``; the full list is + documented in the README. Message wording, by contrast, may change + between releases. + * ``text`` -- the label (or, for UTS #46 processing, the domain) that + was being validated; + * ``codepoint`` -- the offending codepoint, as an ``int``; + * ``position`` -- the 1-based index of the offending character within + ``text``, matching the position quoted in the message. + + Each is ``None`` when it does not apply. + """ + + code: str | None + text: str | None + codepoint: int | None + position: int | None + + def __init__( + self, + *args: object, + code: _ErrorCode | None = None, + text: str | None = None, + codepoint: int | None = None, + position: int | None = None, + ) -> None: + super().__init__(*args) + self.code = code + self.text = text + self.codepoint = codepoint + self.position = position + + +class IDNABidiError(IDNAError): + """Exception when bidirectional requirements are not satisfied""" + + +class InvalidCodepoint(IDNAError): + """Exception when a disallowed or unallocated codepoint is used""" + + +class InvalidCodepointContext(IDNAError): + """Exception when the codepoint is not valid in the context it is used""" + + +def _combining_class(cp: int) -> int: + v = unicodedata.combining(chr(cp)) + if v == 0 and not unicodedata.name(chr(cp)): + raise ValueError("Unknown character in unicodedata") + return v + + +def _is_script(cp: str, script: str) -> bool: + return intranges_contain(ord(cp), idnadata.scripts[script]) + + +def _punycode(s: str) -> bytes: + return s.encode("punycode") + + +def _unot(s: int) -> str: + return f"U+{s:04X}" + + +def valid_label_length(label: bytes | str) -> bool: + """Check that a label does not exceed the maximum permitted length. + + Per :rfc:`1035` (and :rfc:`5891` §4.2.4) a DNS label must not exceed + 63 octets. The argument may be either a :class:`str` (a U-label, where + length is measured in characters) or :class:`bytes` (an A-label, where + length is measured in octets). + + :param label: The label to check. + :returns: ``True`` if the label is within the length limit, otherwise + ``False``. + """ + return len(label) <= 63 + + +def valid_string_length(domain: bytes | str, trailing_dot: bool) -> bool: + """Check that a full domain name does not exceed the maximum length. + + Per :rfc:`1035`, a domain name is limited to 253 octets when no trailing + dot is present, or 254 octets when one is included. + + :param domain: The full (possibly multi-label) domain name. + :param trailing_dot: ``True`` if ``domain`` includes a trailing ``.``. + :returns: ``True`` if the domain is within the length limit, otherwise + ``False``. + """ + return len(domain) <= _max_domain_length + trailing_dot + + +def check_bidi(label: str, check_ltr: bool = False) -> bool: + """Validate the Bidi Rule from :rfc:`5893` for a single label. + + The Bidi Rule constrains how bidirectional characters (Hebrew, Arabic, + etc.) may appear within a label. By default the check is only applied + when the label contains at least one right-to-left character (Unicode + bidirectional categories ``R``, ``AL``, or ``AN``); set ``check_ltr`` + to ``True`` to apply it to LTR-only labels as well. + + :param label: The label to validate, as a Unicode string. + :param check_ltr: If ``True``, apply the rules even when the label + contains no RTL characters. + :returns: ``True`` if the label satisfies the Bidi Rule. + :raises IDNABidiError: If any of Bidi Rule conditions 1-6 are violated, + or if the directional category of a codepoint cannot be determined. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == "": + # String likely comes from a newer version of Unicode + raise IDNABidiError( + f"Unknown directionality in label {label!r} at position {idx}", + code="bidi_unknown_direction", + text=label, + codepoint=ord(cp), + position=idx, + ) + if direction in _bidi_rtl_categories: + bidi_label = True + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in _bidi_rtl_first: + rtl = True + elif direction == "L": + rtl = False + else: + raise IDNABidiError( + f"First codepoint in label {label!r} must be directionality L, R or AL", + code="bidi_rule_1", + text=label, + codepoint=ord(label[0]), + position=1, + ) + + valid_ending = False + ending_idx = 1 + number_type: str | None = None + for idx, cp in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if direction not in _bidi_rtl_allowed: + raise IDNABidiError( + f"Invalid direction for codepoint at position {idx} in a right-to-left label", + code="bidi_rule_2", + text=label, + codepoint=ord(cp), + position=idx, + ) + # Bidi rule 3 + if direction in _bidi_rtl_valid_ending: + valid_ending = True + ending_idx = idx + elif direction != "NSM": + valid_ending = False + ending_idx = idx + # Bidi rule 4 + if direction in _bidi_rtl_numeric: + if not number_type: + number_type = direction + elif number_type != direction: + raise IDNABidiError( + "Can not mix numeral types in a right-to-left label", + code="bidi_rule_4", + text=label, + codepoint=ord(cp), + position=idx, + ) + else: + # Bidi rule 5 + if direction not in _bidi_ltr_allowed: + raise IDNABidiError( + f"Invalid direction for codepoint at position {idx} in a left-to-right label", + code="bidi_rule_5", + text=label, + codepoint=ord(cp), + position=idx, + ) + # Bidi rule 6 + if direction in _bidi_ltr_valid_ending: + valid_ending = True + ending_idx = idx + elif direction != "NSM": + valid_ending = False + ending_idx = idx + + if not valid_ending: + # Rules 3 and 6 concern the last character that is not a + # non-spacing mark, which is what ``ending_idx`` tracks. + raise IDNABidiError( + "Label ends with illegal codepoint directionality", + code="bidi_rule_3" if rtl else "bidi_rule_6", + text=label, + codepoint=ord(label[ending_idx - 1]), + position=ending_idx, + ) + + return True + + +def check_initial_combiner(label: str) -> bool: + """Reject labels that begin with a combining mark. + + Per :rfc:`5891` §4.2.3.2 a label must not start with a character of + Unicode general category ``M`` (Mark). + + :param label: The label to check. + :returns: ``True`` if the first character is not a combining mark. + :raises IDNAError: If the label begins with a combining character. + """ + if label and unicodedata.category(label[0])[0] == "M": + raise IDNAError( + "Label begins with an illegal combining character", + code="leading_combiner", + text=label, + codepoint=ord(label[0]), + position=1, + ) + return True + + +def check_hyphen_ok(label: str) -> bool: + """Validate the hyphen restrictions for a label. + + Per :rfc:`5891` §4.2.3.1 a label must not start or end with a hyphen + (``U+002D``), and must not have hyphens in both the third and fourth + positions (the prefix reserved for A-labels). + + :param label: The label to check. + :returns: ``True`` if the hyphen restrictions are satisfied. + :raises IDNAError: If any of the hyphen restrictions are violated. + """ + if label[2:4] == "--": + raise IDNAError("Label has disallowed hyphens in 3rd and 4th position", code="hyphen_3_4") + if label.startswith("-") or label.endswith("-"): + raise IDNAError("Label must not start or end with a hyphen", code="hyphen_start_end") + return True + + +def check_nfc(label: str) -> None: + """Require that a label is in Unicode Normalization Form C. + + :param label: The label to check. + :raises IDNAError: If ``label`` differs from its NFC normalisation. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + if unicodedata.normalize("NFC", label) != label: + raise IDNAError("Label must be in Normalization Form C", code="not_nfc") + + +def valid_contextj(label: str, pos: int) -> bool: + """Validate the CONTEXTJ rules from :rfc:`5892` Appendix A. + + These rules govern the contextual use of the joiner codepoints + ``U+200C`` (ZERO WIDTH NON-JOINER, Appendix A.1) and ``U+200D`` + (ZERO WIDTH JOINER, Appendix A.2) within a label. + + :param label: The label containing the codepoint. + :param pos: Index of the joiner codepoint within ``label``. + :returns: ``True`` if the codepoint at ``pos`` satisfies its CONTEXTJ + rule, ``False`` otherwise (including when the codepoint at + ``pos`` is not a recognised joiner). + :raises ValueError: If an adjacent codepoint has no Unicode name when + determining its combining class. + :raises IDNAError: If ``label`` exceeds the defensive input length limit. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + cp_value = ord(label[pos]) + + if cp_value == 0x200C: + if pos > 0 and _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos - 1, -1, -1): + joining_type = _joining_type(ord(label[i])) + if joining_type == "T": + continue + if joining_type in _bidi_joiner_l_or_d: + ok = True + break + break + + if not ok: + return False + + ok = False + for i in range(pos + 1, len(label)): + joining_type = _joining_type(ord(label[i])) + if joining_type == "T": + continue + if joining_type in _bidi_joiner_r_or_d: + ok = True + break + break + return ok + + if cp_value == 0x200D: + return pos > 0 and _combining_class(ord(label[pos - 1])) == _virama_combining_class + + return False + + +def valid_contexto(label: str, pos: int, exception: bool = False) -> bool: + """Validate the CONTEXTO rules from :rfc:`5892` Appendix A. + + Covers the contextual rules for codepoints such as MIDDLE DOT + (``U+00B7``), Greek lower numeral sign, Hebrew punctuation, Katakana + middle dot, and the Arabic-Indic / Extended Arabic-Indic digit ranges. + + :param label: The label containing the codepoint. + :param pos: Index of the codepoint within ``label``. + :param exception: Reserved for forward compatibility; currently unused. + :returns: ``True`` if the codepoint at ``pos`` satisfies its CONTEXTO + rule, ``False`` otherwise (including when the codepoint is not a + recognised CONTEXTO codepoint). + :raises IDNAError: If ``label`` exceeds the defensive input length limit. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + cp_value = ord(label[pos]) + + if cp_value == 0x00B7: + return 0 < pos < len(label) - 1 and ord(label[pos - 1]) == 0x006C and ord(label[pos + 1]) == 0x006C + + if cp_value == 0x0375: + if pos < len(label) - 1 and len(label) > 1: + return _is_script(label[pos + 1], "Greek") + return False + + if cp_value in {0x05F3, 0x05F4}: + if pos > 0: + return _is_script(label[pos - 1], "Hebrew") + return False + + if cp_value == 0x30FB: + for cp in label: + if cp == "\u30fb": + continue + if _is_script(cp, "Hiragana") or _is_script(cp, "Katakana") or _is_script(cp, "Han"): + return True + return False + + if 0x660 <= cp_value <= 0x669: + return not any(0x6F0 <= ord(cp) <= 0x06F9 for cp in label) + + if 0x6F0 <= cp_value <= 0x6F9: + return not any(0x660 <= ord(cp) <= 0x0669 for cp in label) + + return False + + +def check_label(label: str | bytes | bytearray) -> None: + """Run the full set of IDNA 2008 validity checks on a single label. + + Applies, in order: NFC normalisation (:func:`check_nfc`), hyphen + restrictions (:func:`check_hyphen_ok`), the no-leading-combiner rule + (:func:`check_initial_combiner`), per-codepoint validity (PVALID, + CONTEXTJ, CONTEXTO classes from :rfc:`5892`), and the Bidi Rule + (:func:`check_bidi`). + + :param label: The label to validate. ``bytes`` or ``bytearray`` input + is decoded as UTF-8 first. + :raises IDNAError: If the label is empty or fails a structural rule. + :raises InvalidCodepoint: If the label contains a DISALLOWED or + UNASSIGNED codepoint. + :raises InvalidCodepointContext: If a CONTEXTJ or CONTEXTO codepoint + is not valid in its context. + :raises IDNABidiError: If the Bidi Rule is violated. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + if isinstance(label, (bytes, bytearray)): + try: + label = label.decode("utf-8") + except UnicodeDecodeError as err: + raise IDNAError("Invalid UTF-8 in label", code="invalid_utf8") from err + if len(label) == 0: + raise IDNAError("Empty Label", code="empty_label") + + # Check against the domain length rather than the label length to + # support some UTS #46 use cases, while still bounding the work done + # by the label contextual rules below. + if not valid_string_length(label, trailing_dot=True): + raise IDNAError("Label too long", code="label_too_long") + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for pos, cp in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes["PVALID"]): + continue + if intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTJ"]): + try: + contextj_ok = valid_contextj(label, pos) + except ValueError as err: + raise IDNAError( + f"Unknown codepoint adjacent to joiner {_unot(cp_value)} at position {pos + 1} in {label!r}", + code="unknown_codepoint", + text=label, + codepoint=cp_value, + position=pos + 1, + ) from err + if not contextj_ok: + raise InvalidCodepointContext( + f"Joiner {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}", + code="contextj", + text=label, + codepoint=cp_value, + position=pos + 1, + ) + elif intranges_contain(cp_value, idnadata.codepoint_classes["CONTEXTO"]): + if not valid_contexto(label, pos): + raise InvalidCodepointContext( + f"Codepoint {_unot(cp_value)} not allowed at position {pos + 1} in {label!r}", + code="contexto", + text=label, + codepoint=cp_value, + position=pos + 1, + ) + else: + raise InvalidCodepoint( + f"Codepoint {_unot(cp_value)} at position {pos + 1} of {label!r} not allowed", + code="disallowed_codepoint", + text=label, + codepoint=cp_value, + position=pos + 1, + ) + + check_bidi(label) + + +def alabel(label: str) -> bytes: + """Convert a single U-label into its A-label form. + + The result is the ASCII-Compatible Encoding (ACE) form per :rfc:`5891` + §4: the label is validated, Punycode-encoded, and prefixed with + ``xn--``. Pure ASCII labels that are already valid IDNA labels are + returned unchanged (as :class:`bytes`). + + :param label: The label to convert, as a Unicode string. + :returns: The A-label as ASCII-encoded :class:`bytes`. + :raises IDNAError: If the label is invalid or the resulting A-label + exceeds 63 octets. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + try: + label_bytes = label.encode("ascii") + except UnicodeEncodeError: + pass + else: + ulabel(label_bytes) + if not valid_label_length(label_bytes): + raise IDNAError("Label too long", code="label_too_long") + return label_bytes + + check_label(label) + label_bytes = _alabel_prefix + _punycode(label) + + if not valid_label_length(label_bytes): + raise IDNAError("Label too long", code="label_too_long") + + return label_bytes + + +def ulabel(label: str | bytes | bytearray) -> str: + """Convert a single A-label into its U-label form. + + Performs the inverse of :func:`alabel`: an ``xn--``-prefixed label is + Punycode-decoded and validated, and is rejected unless it is the + canonical A-label for the decoded U-label (:rfc:`5891` §5.3). Labels + that are already Unicode (or plain ASCII without the ACE prefix) are + validated and returned as a Unicode string. + + :param label: The label to convert. ``bytes`` or ``bytearray`` input + is treated as ASCII. + :returns: The U-label as a Unicode string. + :raises IDNAError: If the label is malformed or fails validation. + """ + if len(label) > _max_input_length: + raise IDNAError("Label too long", code="input_too_long") + if not isinstance(label, (bytes, bytearray)): + try: + label_bytes = label.encode("ascii") + except UnicodeEncodeError: + check_label(label) + return label + else: + label_bytes = bytes(label) + if not label_bytes.isascii(): + raise IDNAError("Invalid ASCII in A-label", code="invalid_ascii") + + label_bytes = label_bytes.lower() + if label_bytes.startswith(_alabel_prefix): + label_bytes = label_bytes[len(_alabel_prefix) :] + if not label_bytes: + raise IDNAError("Malformed A-label, no Punycode eligible content found", code="invalid_alabel") + if label_bytes.endswith(b"-"): + raise IDNAError("A-label must not end with a hyphen", code="invalid_alabel") + else: + check_label(label_bytes) + return label_bytes.decode("ascii") + + try: + label = label_bytes.decode("punycode") + except UnicodeError as err: + raise IDNAError("Invalid A-label", code="invalid_alabel") from err + # RFC 5891 §5.3: the label is rejected unless re-encoding the decoded + # form reproduces the (lowercased) input. This catches "fake A-labels" + # (RFC 5890 §2.3.2.1) such as ``xn---bbk``, a non-canonical Punycode + # spelling of ``xn--bbk`` that would otherwise decode to the same + # U-label and so display identically to a different wire-format name. + if _punycode(label) != label_bytes: + raise IDNAError("A-label is not the canonical Punycode encoding of its U-label", code="non_canonical_alabel") + check_label(label) + return label + + +def _check_std3(text: str, domain: str, offset: int) -> None: + """Raise if ``text``, a slice of ``domain`` starting at ``offset`` that + UTS #46 mapping left unchanged, contains an ASCII character disallowed + under ``UseSTD3ASCIIRules``.""" + match = _std3_disallowed_re.search(text) + if match: + codepoint = ord(match.group()) + position = offset + match.start() + 1 + raise InvalidCodepoint( + f"Codepoint {_unot(codepoint)} not allowed at position {position} in {domain!r}", + code="uts46_std3", + text=domain, + codepoint=codepoint, + position=position, + ) + + +def _warn_transitional() -> None: + warnings.warn( + "Transitional processing is deprecated in UTS #46 and has no effect. " + "The transitional argument will be removed in a future version.", + DeprecationWarning, + stacklevel=3, + ) + + +def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str: + """Apply the UTS #46 character mapping to a domain string. + + Implements the mapping table from `UTS #46 §4 + `_: each character is kept, + replaced, or rejected based on its status (``V``, ``M``, ``D``, + ``I``, ``X``). The result is returned in Normalisation Form C. + + :param domain: The full domain name to remap. + :param std3_rules: If ``True``, apply UTS #46's ``UseSTD3ASCIIRules``: + after mapping, any ASCII character other than a lowercase letter, + digit, hyphen or the label separator ``.`` is rejected, whether it + appeared in the input or was produced by a mapping (e.g. U+FF01 + FULLWIDTH EXCLAMATION MARK maps to ``!``). If ``False``, such + characters are passed through. + :param transitional: Deprecated and ignored. UTS #46 deprecated + transitional processing in Unicode 15.1 and deviation (status + ``D``) codepoints are now always kept, so this has no effect + beyond emitting a :class:`DeprecationWarning`. It will be removed + in a future version. + :returns: The remapped domain, in Normalisation Form C. + :raises InvalidCodepoint: If the domain contains a disallowed + codepoint under the chosen rules. + :raises IDNAError: If ``domain`` exceeds the defensive input length limit. + """ + if transitional: + _warn_transitional() + if len(domain) > _max_input_length: + raise IDNAError("Domain too long", code="input_too_long") + if domain.isascii(): + # The only ASCII mapping in UTS #46 is upper- to lowercase, and + # ASCII is invariant under NFC, so lowercasing is the whole job. + result = domain.lower() + if std3_rules: + _check_std3(result, domain, 0) + return result + + from .uts46data import uts46_replacements, uts46_starts, uts46_statuses + + # ``start`` marks the run of unchanged input not yet copied; a run is + # only sliced out when a character must be replaced or dropped, so the + # common no-change case makes no copy. STD3 is checked per output piece + # to report a violation at its input position. + output: list[str] = [] + start = 0 + for pos, char in enumerate(domain): + code_point = ord(char) + i = code_point if code_point < 256 else bisect.bisect_right(uts46_starts, code_point) - 1 + status = uts46_statuses[i] + # UTS #46 §4: V valid, D deviation (kept), M mapped, I ignored, + # anything else disallowed. + if status == _STATUS_VALID: + continue + if status == _STATUS_MAPPED: + replacement = uts46_replacements[i] + elif status == _STATUS_DEVIATION: + continue + elif status == _STATUS_IGNORED: + replacement = None + else: + raise InvalidCodepoint( + f"Codepoint {_unot(code_point)} not allowed at position {pos + 1} in {domain!r}", + code="uts46_disallowed", + text=domain, + codepoint=code_point, + position=pos + 1, + ) + if start < pos: + run = domain[start:pos] + if std3_rules: + _check_std3(run, domain, start) + output.append(run) + if replacement: + if std3_rules and _std3_disallowed_re.search(replacement): + raise InvalidCodepoint( + f"Codepoint {_unot(code_point)} not allowed at position {pos + 1} in {domain!r}", + code="uts46_std3", + text=domain, + codepoint=code_point, + position=pos + 1, + ) + output.append(replacement) + start = pos + 1 + + if start == 0: + if std3_rules: + _check_std3(domain, domain, 0) + return unicodedata.normalize("NFC", domain) + tail = domain[start:] + if std3_rules: + _check_std3(tail, domain, start) + output.append(tail) + return unicodedata.normalize("NFC", "".join(output)) + + +def encode( + s: str | bytes | bytearray, + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, + transitional: bool = False, +) -> bytes: + """Encode a Unicode domain name into its ASCII (A-label) form. + + Splits the input on label separators (only ``U+002E`` if ``strict`` is + set; otherwise also IDEOGRAPHIC FULL STOP ``U+3002``, FULLWIDTH FULL + STOP ``U+FF0E``, and HALFWIDTH IDEOGRAPHIC FULL STOP ``U+FF61``), + encodes each label with :func:`alabel`, and rejoins them with ``.``. + Optionally pre-processes the input through :func:`uts46_remap`. + + :param s: The domain name to encode. + :param strict: If ``True``, only ``U+002E`` is recognised as a label + separator. + :param uts46: If ``True``, apply UTS #46 mapping before encoding. + :param std3_rules: Forwarded to :func:`uts46_remap` when ``uts46`` is + ``True``. + :param transitional: Deprecated and ignored (see :func:`uts46_remap`): + emits a :class:`DeprecationWarning` and will be removed in a + future version. + :returns: The encoded domain as ASCII :class:`bytes`. + :raises IDNAError: If the domain is empty, contains an invalid label, + or exceeds the maximum domain length. + """ + if transitional: + _warn_transitional() + if not isinstance(s, str): + try: + s = str(s, "ascii") + except (UnicodeDecodeError, TypeError) as err: + raise IDNAError( + "should pass a unicode string to the function rather than a byte string.", code="invalid_ascii" + ) from err + if len(s) > _max_input_length: + raise IDNAError("Domain too long", code="input_too_long") + if uts46: + s = uts46_remap(s, std3_rules) + + if not valid_string_length(s, trailing_dot=True): + raise IDNAError("Domain too long", code="domain_too_long") + + trailing_dot = False + result = [] + labels = s.split(".") if strict else _unicode_dots_re.split(s) + if not labels or labels == [""]: + raise IDNAError("Empty domain", code="empty_domain") + if labels[-1] == "": + del labels[-1] + trailing_dot = True + for label in labels: + s = alabel(label) + if s: + result.append(s) + else: + raise IDNAError("Empty label", code="empty_label") + if trailing_dot: + result.append(b"") + s = b".".join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError("Domain too long", code="domain_too_long") + return s + + +def decode( + s: str | bytes | bytearray, + strict: bool = False, + uts46: bool = False, + std3_rules: bool = False, + display: bool = False, +) -> str: + """Decode an A-label-encoded domain name back to Unicode. + + Splits the input on label separators (see :func:`encode` for the + rules), decodes each label with :func:`ulabel`, and rejoins them + with ``.``. Optionally pre-processes the input through + :func:`uts46_remap`. + + :param s: The domain name to decode. + :param strict: If ``True``, only ``U+002E`` is recognised as a label + separator. + :param uts46: If ``True``, apply UTS #46 mapping before decoding. + :param std3_rules: Forwarded to :func:`uts46_remap` when ``uts46`` is + ``True``. + :param display: If ``True``, any ``xn--`` label that fails IDNA + validation is passed through unchanged (lowercased) rather than + aborting the whole call. Intended for "decode for display" + consumers (e.g. URL libraries, HTTP clients) that want to show + the user the label as it appears on the wire when it cannot be + rendered as Unicode. Matches the per-label recovery prescribed + by UTS #46 §4 and the WHATWG URL "domain to Unicode" algorithm. + :returns: The decoded domain as a Unicode string. + :raises IDNAError: If the input is not valid ASCII, contains an + invalid label, or is empty. + """ + if not isinstance(s, str): + try: + s = str(s, "ascii") + except (UnicodeDecodeError, TypeError) as err: + raise IDNAError("Invalid ASCII in A-label", code="invalid_ascii") from err + if len(s) > _max_input_length: + raise IDNAError("Domain too long", code="input_too_long") + if uts46: + s = uts46_remap(s, std3_rules, False) + if not valid_string_length(s, trailing_dot=True): + raise IDNAError("Domain too long", code="domain_too_long") + trailing_dot = False + result = [] + labels = s.split(".") if strict else _unicode_dots_re.split(s) + if not labels or labels == [""]: + raise IDNAError("Empty domain", code="empty_domain") + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + try: + u = ulabel(label) + except IDNAError: + if display and label[:4].lower() == "xn--": + u = label.lower() + else: + raise + if u: + result.append(u) + else: + raise IDNAError("Empty label", code="empty_label") + if trailing_dot: + result.append("") + return ".".join(result) diff --git a/source/target-vendors/cp312/idna/idnadata.py b/source/target-vendors/cp312/idna/idnadata.py new file mode 100644 index 0000000..471c047 --- /dev/null +++ b/source/target-vendors/cp312/idna/idnadata.py @@ -0,0 +1,1933 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "18.0.0" + +scripts = { + "Greek": ( + 0x37000000374, + 0x37500000378, + 0x37A0000037E, + 0x37F00000380, + 0x38400000385, + 0x38600000387, + 0x3880000038B, + 0x38C0000038D, + 0x38E000003A2, + 0x3A3000003E2, + 0x3F000000400, + 0x1D2600001D2B, + 0x1D5D00001D62, + 0x1D6600001D6B, + 0x1DBF00001DC0, + 0x1F0000001F16, + 0x1F1800001F1E, + 0x1F2000001F46, + 0x1F4800001F4E, + 0x1F5000001F58, + 0x1F5900001F5A, + 0x1F5B00001F5C, + 0x1F5D00001F5E, + 0x1F5F00001F7E, + 0x1F8000001FB5, + 0x1FB600001FC5, + 0x1FC600001FD4, + 0x1FD600001FDC, + 0x1FDD00001FF0, + 0x1FF200001FF5, + 0x1FF600001FFF, + 0x212600002127, + 0xAB650000AB66, + 0x101400001018F, + 0x101A0000101A1, + 0x1D2000001D246, + 0x1DFF30001DFF5, + ), + "Han": ( + 0x2E8000002E9A, + 0x2E9B00002EF4, + 0x2F0000002FD6, + 0x300500003006, + 0x300700003008, + 0x30210000302A, + 0x30380000303C, + 0x340000004DC0, + 0x4E000000A000, + 0xF9000000FA6E, + 0xFA700000FADA, + 0x16FE200016FE4, + 0x16FF000016FF7, + 0x200000002A6E0, + 0x2A7000002B81F, + 0x2B8200002CEAE, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x2F8000002FA1E, + 0x300000003134B, + 0x313500003347A, + ), + "Hebrew": ( + 0x591000005CA, + 0x5D0000005EB, + 0x5EF000005F5, + 0xFB1D0000FB37, + 0xFB380000FB3D, + 0xFB3E0000FB3F, + 0xFB400000FB42, + 0xFB430000FB45, + 0xFB460000FB50, + ), + "Hiragana": ( + 0x304100003097, + 0x309D000030A0, + 0x1B0010001B120, + 0x1B1230001B124, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1F2000001F201, + ), + "Katakana": ( + 0x30A1000030FB, + 0x30FD00003100, + 0x31F000003200, + 0x32D0000032FF, + 0x330000003358, + 0xFF660000FF70, + 0xFF710000FF9E, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B001, + 0x1B1200001B123, + 0x1B1240001B129, + 0x1B1550001B156, + 0x1B1640001B169, + ), +} + + +joining_types = { + "C": ( + 0x64000000641, + 0x7FA000007FB, + 0x88300000886, + 0x180A0000180B, + 0x200D0000200E, + ), + "D": ( + 0x62000000621, + 0x62600000627, + 0x62800000629, + 0x62A0000062F, + 0x63300000640, + 0x64100000648, + 0x6490000064B, + 0x66E00000670, + 0x67800000688, + 0x69A000006C0, + 0x6C1000006C3, + 0x6CC000006CD, + 0x6CE000006CF, + 0x6D0000006D2, + 0x6FA000006FD, + 0x6FF00000700, + 0x71200000715, + 0x71A0000071E, + 0x71F00000728, + 0x7290000072A, + 0x72B0000072C, + 0x72D0000072F, + 0x74E00000759, + 0x75C0000076B, + 0x76D00000771, + 0x77200000773, + 0x77500000778, + 0x77A00000780, + 0x7CA000007EB, + 0x84100000846, + 0x84800000849, + 0x84A00000854, + 0x85500000856, + 0x86000000861, + 0x86200000866, + 0x86800000869, + 0x88600000887, + 0x8890000088E, + 0x88F00000890, + 0x8A0000008AA, + 0x8AF000008B1, + 0x8B3000008B9, + 0x8BA000008C9, + 0x180700001808, + 0x182000001879, + 0x1887000018A9, + 0x18AA000018AB, + 0xA8400000A872, + 0x10AC000010AC5, + 0x10AD300010AD7, + 0x10AD800010ADD, + 0x10ADE00010AE1, + 0x10AEB00010AEF, + 0x10B8000010B81, + 0x10B8200010B83, + 0x10B8600010B89, + 0x10B8A00010B8C, + 0x10B8D00010B8E, + 0x10B9000010B91, + 0x10BAD00010BAF, + 0x10D0100010D22, + 0x10D2300010D24, + 0x10EC300010EC5, + 0x10EC600010EC8, + 0x10F3000010F33, + 0x10F3400010F45, + 0x10F5100010F54, + 0x10F7000010F74, + 0x10F7600010F82, + 0x10FB000010FB1, + 0x10FB200010FB4, + 0x10FB800010FB9, + 0x10FBB00010FBD, + 0x10FBE00010FC0, + 0x10FC100010FC2, + 0x10FC400010FC5, + 0x10FCA00010FCB, + 0x1E9000001E944, + ), + "L": ( + 0xA8720000A873, + 0x10ACD00010ACE, + 0x10AD700010AD8, + 0x10D0000010D01, + 0x10ED900010EEF, + 0x10FCB00010FCC, + ), + "R": ( + 0x62200000626, + 0x62700000628, + 0x6290000062A, + 0x62F00000633, + 0x64800000649, + 0x67100000674, + 0x67500000678, + 0x6880000069A, + 0x6C0000006C1, + 0x6C3000006CC, + 0x6CD000006CE, + 0x6CF000006D0, + 0x6D2000006D4, + 0x6D5000006D6, + 0x6EE000006F0, + 0x71000000711, + 0x7150000071A, + 0x71E0000071F, + 0x72800000729, + 0x72A0000072B, + 0x72C0000072D, + 0x72F00000730, + 0x74D0000074E, + 0x7590000075C, + 0x76B0000076D, + 0x77100000772, + 0x77300000775, + 0x7780000077A, + 0x84000000841, + 0x84600000848, + 0x8490000084A, + 0x85400000855, + 0x85600000859, + 0x86700000868, + 0x8690000086B, + 0x87000000883, + 0x88E0000088F, + 0x8AA000008AD, + 0x8AE000008AF, + 0x8B1000008B3, + 0x8B9000008BA, + 0x10AC500010AC6, + 0x10AC700010AC8, + 0x10AC900010ACB, + 0x10ACE00010AD3, + 0x10ADD00010ADE, + 0x10AE100010AE2, + 0x10AE400010AE5, + 0x10AEF00010AF0, + 0x10B8100010B82, + 0x10B8300010B86, + 0x10B8900010B8A, + 0x10B8C00010B8D, + 0x10B8E00010B90, + 0x10B9100010B92, + 0x10BA900010BAD, + 0x10D2200010D23, + 0x10EC200010EC3, + 0x10F3300010F34, + 0x10F5400010F55, + 0x10F7400010F76, + 0x10FB400010FB7, + 0x10FB900010FBB, + 0x10FBD00010FBE, + 0x10FC200010FC4, + 0x10FC900010FCA, + ), + "T": ( + 0xAD000000AE, + 0x30000000370, + 0x4830000048A, + 0x591000005BE, + 0x5BF000005C0, + 0x5C1000005C3, + 0x5C4000005C6, + 0x5C7000005CA, + 0x6100000061B, + 0x61C0000061D, + 0x64B00000660, + 0x67000000671, + 0x6D6000006DD, + 0x6DF000006E5, + 0x6E7000006E9, + 0x6EA000006EE, + 0x70F00000710, + 0x71100000712, + 0x7300000074B, + 0x7A6000007B1, + 0x7EB000007F4, + 0x7FD000007FE, + 0x8160000081A, + 0x81B00000824, + 0x82500000828, + 0x8290000082E, + 0x8590000085C, + 0x897000008A0, + 0x8CA000008E2, + 0x8E300000903, + 0x93A0000093B, + 0x93C0000093D, + 0x94100000949, + 0x94D0000094E, + 0x95100000958, + 0x96200000964, + 0x98100000982, + 0x9BC000009BD, + 0x9C1000009C5, + 0x9CD000009CE, + 0x9E2000009E4, + 0x9FE000009FF, + 0xA0100000A03, + 0xA3C00000A3D, + 0xA4100000A43, + 0xA4700000A49, + 0xA4B00000A4E, + 0xA5100000A52, + 0xA7000000A72, + 0xA7500000A76, + 0xA8100000A83, + 0xABC00000ABD, + 0xAC100000AC6, + 0xAC700000AC9, + 0xACD00000ACE, + 0xAE200000AE4, + 0xAFA00000B00, + 0xB0100000B02, + 0xB3C00000B3D, + 0xB3F00000B40, + 0xB4100000B45, + 0xB4D00000B4E, + 0xB5300000B57, + 0xB6200000B64, + 0xB8200000B83, + 0xBC000000BC1, + 0xBCD00000BCE, + 0xC0000000C01, + 0xC0400000C05, + 0xC3C00000C3D, + 0xC3E00000C41, + 0xC4600000C49, + 0xC4A00000C4E, + 0xC5500000C57, + 0xC6200000C64, + 0xC8100000C82, + 0xCBC00000CBD, + 0xCBF00000CC0, + 0xCC600000CC7, + 0xCCC00000CCE, + 0xCE200000CE4, + 0xD0000000D02, + 0xD3B00000D3D, + 0xD4100000D45, + 0xD4D00000D4E, + 0xD6200000D64, + 0xD8100000D82, + 0xDCA00000DCB, + 0xDD200000DD5, + 0xDD600000DD7, + 0xE3100000E32, + 0xE3400000E3B, + 0xE4700000E4F, + 0xEB100000EB2, + 0xEB400000EBD, + 0xEC800000ECF, + 0xF1800000F1A, + 0xF3500000F36, + 0xF3700000F38, + 0xF3900000F3A, + 0xF7100000F7F, + 0xF8000000F85, + 0xF8600000F88, + 0xF8D00000F98, + 0xF9900000FBD, + 0xFC600000FC7, + 0x102D00001031, + 0x103200001038, + 0x10390000103B, + 0x103D0000103F, + 0x10580000105A, + 0x105E00001061, + 0x107100001075, + 0x108200001083, + 0x108500001087, + 0x108D0000108E, + 0x109D0000109E, + 0x135D00001360, + 0x171200001715, + 0x173200001734, + 0x175200001754, + 0x177200001774, + 0x17B4000017B6, + 0x17B7000017BE, + 0x17C6000017C7, + 0x17C9000017D4, + 0x17DD000017DE, + 0x180B0000180E, + 0x180F00001810, + 0x188500001887, + 0x18A9000018AA, + 0x192000001923, + 0x192700001929, + 0x193200001933, + 0x19390000193C, + 0x1A1700001A19, + 0x1A1B00001A1C, + 0x1A5600001A57, + 0x1A5800001A5F, + 0x1A6000001A61, + 0x1A6200001A63, + 0x1A6500001A6D, + 0x1A7300001A7D, + 0x1A7F00001A80, + 0x1AB000001AF1, + 0x1B0000001B04, + 0x1B3400001B35, + 0x1B3600001B3B, + 0x1B3C00001B3D, + 0x1B4200001B43, + 0x1B6B00001B74, + 0x1B8000001B82, + 0x1BA200001BA6, + 0x1BA800001BAA, + 0x1BAB00001BAE, + 0x1BE600001BE7, + 0x1BE800001BEA, + 0x1BED00001BEE, + 0x1BEF00001BF2, + 0x1C2C00001C34, + 0x1C3600001C38, + 0x1CD000001CD3, + 0x1CD400001CE1, + 0x1CE200001CE9, + 0x1CED00001CEE, + 0x1CF400001CF5, + 0x1CF800001CFA, + 0x1DC000001E00, + 0x200B0000200C, + 0x200E00002010, + 0x202A0000202F, + 0x206000002065, + 0x206A00002070, + 0x20D0000020F1, + 0x2CEF00002CF2, + 0x2D7F00002D80, + 0x2DE000002E00, + 0x302A0000302E, + 0x30990000309B, + 0xA66F0000A673, + 0xA6740000A67E, + 0xA69E0000A6A0, + 0xA6F00000A6F2, + 0xA8020000A803, + 0xA8060000A807, + 0xA80B0000A80C, + 0xA8250000A827, + 0xA82C0000A82D, + 0xA8C40000A8C6, + 0xA8E00000A8F2, + 0xA8FF0000A900, + 0xA9260000A92E, + 0xA9470000A952, + 0xA9800000A983, + 0xA9B30000A9B4, + 0xA9B60000A9BA, + 0xA9BC0000A9BE, + 0xA9E50000A9E6, + 0xAA290000AA2F, + 0xAA310000AA33, + 0xAA350000AA37, + 0xAA430000AA44, + 0xAA4C0000AA4D, + 0xAA7C0000AA7D, + 0xAAB00000AAB1, + 0xAAB20000AAB5, + 0xAAB70000AAB9, + 0xAABE0000AAC0, + 0xAAC10000AAC2, + 0xAAEC0000AAEE, + 0xAAF60000AAF7, + 0xABE50000ABE6, + 0xABE80000ABE9, + 0xABED0000ABEE, + 0xFB1E0000FB1F, + 0xFE000000FE10, + 0xFE200000FE30, + 0xFEFF0000FF00, + 0xFFF90000FFFC, + 0x101FD000101FE, + 0x102E0000102E1, + 0x103760001037B, + 0x10A0100010A04, + 0x10A0500010A07, + 0x10A0C00010A10, + 0x10A3800010A3B, + 0x10A3F00010A40, + 0x10AE500010AE7, + 0x10D2400010D28, + 0x10D6900010D6E, + 0x10EAB00010EAD, + 0x10ECB00010ED0, + 0x10EF000010F00, + 0x10F4600010F51, + 0x10F8200010F86, + 0x1100100011002, + 0x1103800011047, + 0x1107000011071, + 0x1107300011075, + 0x1107F00011082, + 0x110B3000110B7, + 0x110B9000110BB, + 0x110C2000110C3, + 0x1110000011103, + 0x111270001112C, + 0x1112D00011135, + 0x1117300011174, + 0x1118000011182, + 0x111B6000111BF, + 0x111C9000111CD, + 0x111CF000111D0, + 0x1122F00011232, + 0x1123400011235, + 0x1123600011238, + 0x1123E0001123F, + 0x1124100011242, + 0x112DF000112E0, + 0x112E3000112EB, + 0x1130000011302, + 0x1133B0001133D, + 0x1134000011341, + 0x113660001136D, + 0x1137000011375, + 0x113BB000113C1, + 0x113CE000113CF, + 0x113D0000113D1, + 0x113D2000113D3, + 0x113E1000113E3, + 0x1143800011440, + 0x1144200011445, + 0x1144600011447, + 0x1145E0001145F, + 0x114B3000114B9, + 0x114BA000114BB, + 0x114BF000114C1, + 0x114C2000114C4, + 0x115B2000115B6, + 0x115BC000115BE, + 0x115BF000115C1, + 0x115DC000115DE, + 0x116330001163B, + 0x1163D0001163E, + 0x1163F00011641, + 0x116AB000116AC, + 0x116AD000116AE, + 0x116B0000116B6, + 0x116B7000116B8, + 0x1171D0001171E, + 0x1171F00011720, + 0x1172200011726, + 0x117270001172C, + 0x1182F00011838, + 0x118390001183B, + 0x1193B0001193D, + 0x1193E0001193F, + 0x1194300011944, + 0x119D4000119D8, + 0x119DA000119DC, + 0x119E0000119E1, + 0x11A0100011A0B, + 0x11A3300011A39, + 0x11A3B00011A3F, + 0x11A4700011A48, + 0x11A5100011A57, + 0x11A5900011A5C, + 0x11A8A00011A97, + 0x11A9800011A9A, + 0x11B6000011B61, + 0x11B6200011B65, + 0x11B6600011B67, + 0x11C3000011C37, + 0x11C3800011C3E, + 0x11C3F00011C40, + 0x11C9200011CA8, + 0x11CAA00011CB1, + 0x11CB200011CB4, + 0x11CB500011CB7, + 0x11D3100011D37, + 0x11D3A00011D3B, + 0x11D3C00011D3E, + 0x11D3F00011D46, + 0x11D4700011D48, + 0x11D9000011D92, + 0x11D9500011D96, + 0x11D9700011D98, + 0x11DF000011DF1, + 0x11EF300011EF5, + 0x11F0000011F02, + 0x11F3600011F3B, + 0x11F4000011F41, + 0x11F4200011F43, + 0x11F5A00011F5B, + 0x1343000013441, + 0x1344700013456, + 0x1611E0001612A, + 0x1612D00016130, + 0x16AF000016AF5, + 0x16B3000016B37, + 0x16F4F00016F50, + 0x16F8F00016F93, + 0x16FE400016FE5, + 0x1BC9D0001BC9F, + 0x1BCA00001BCA4, + 0x1CF000001CF2E, + 0x1CF300001CF47, + 0x1D1270001D129, + 0x1D1670001D16A, + 0x1D1730001D183, + 0x1D1850001D18C, + 0x1D1AA0001D1AE, + 0x1D2420001D245, + 0x1D25B0001D25D, + 0x1DA000001DA37, + 0x1DA3B0001DA6D, + 0x1DA750001DA76, + 0x1DA840001DA85, + 0x1DA9B0001DAA0, + 0x1DAA10001DAB0, + 0x1E0000001E007, + 0x1E0080001E019, + 0x1E01B0001E022, + 0x1E0230001E025, + 0x1E0260001E02B, + 0x1E08F0001E090, + 0x1E1300001E137, + 0x1E2AE0001E2AF, + 0x1E2EC0001E2F0, + 0x1E4EC0001E4F0, + 0x1E5EE0001E5F0, + 0x1E6E30001E6E4, + 0x1E6E60001E6E7, + 0x1E6EE0001E6F0, + 0x1E6F50001E6F6, + 0x1E8D00001E8D7, + 0x1E9440001E94C, + 0xE0001000E0002, + 0xE0020000E0080, + 0xE0100000E01F0, + ), +} + + +codepoint_classes = { + "PVALID": ( + 0x2D0000002E, + 0x300000003A, + 0x610000007B, + 0xDF000000F7, + 0xF800000100, + 0x10100000102, + 0x10300000104, + 0x10500000106, + 0x10700000108, + 0x1090000010A, + 0x10B0000010C, + 0x10D0000010E, + 0x10F00000110, + 0x11100000112, + 0x11300000114, + 0x11500000116, + 0x11700000118, + 0x1190000011A, + 0x11B0000011C, + 0x11D0000011E, + 0x11F00000120, + 0x12100000122, + 0x12300000124, + 0x12500000126, + 0x12700000128, + 0x1290000012A, + 0x12B0000012C, + 0x12D0000012E, + 0x12F00000130, + 0x13100000132, + 0x13500000136, + 0x13700000139, + 0x13A0000013B, + 0x13C0000013D, + 0x13E0000013F, + 0x14200000143, + 0x14400000145, + 0x14600000147, + 0x14800000149, + 0x14B0000014C, + 0x14D0000014E, + 0x14F00000150, + 0x15100000152, + 0x15300000154, + 0x15500000156, + 0x15700000158, + 0x1590000015A, + 0x15B0000015C, + 0x15D0000015E, + 0x15F00000160, + 0x16100000162, + 0x16300000164, + 0x16500000166, + 0x16700000168, + 0x1690000016A, + 0x16B0000016C, + 0x16D0000016E, + 0x16F00000170, + 0x17100000172, + 0x17300000174, + 0x17500000176, + 0x17700000178, + 0x17A0000017B, + 0x17C0000017D, + 0x17E0000017F, + 0x18000000181, + 0x18300000184, + 0x18500000186, + 0x18800000189, + 0x18C0000018E, + 0x19200000193, + 0x19500000196, + 0x1990000019C, + 0x19E0000019F, + 0x1A1000001A2, + 0x1A3000001A4, + 0x1A5000001A6, + 0x1A8000001A9, + 0x1AA000001AC, + 0x1AD000001AE, + 0x1B0000001B1, + 0x1B4000001B5, + 0x1B6000001B7, + 0x1B9000001BC, + 0x1BD000001C4, + 0x1CE000001CF, + 0x1D0000001D1, + 0x1D2000001D3, + 0x1D4000001D5, + 0x1D6000001D7, + 0x1D8000001D9, + 0x1DA000001DB, + 0x1DC000001DE, + 0x1DF000001E0, + 0x1E1000001E2, + 0x1E3000001E4, + 0x1E5000001E6, + 0x1E7000001E8, + 0x1E9000001EA, + 0x1EB000001EC, + 0x1ED000001EE, + 0x1EF000001F1, + 0x1F5000001F6, + 0x1F9000001FA, + 0x1FB000001FC, + 0x1FD000001FE, + 0x1FF00000200, + 0x20100000202, + 0x20300000204, + 0x20500000206, + 0x20700000208, + 0x2090000020A, + 0x20B0000020C, + 0x20D0000020E, + 0x20F00000210, + 0x21100000212, + 0x21300000214, + 0x21500000216, + 0x21700000218, + 0x2190000021A, + 0x21B0000021C, + 0x21D0000021E, + 0x21F00000220, + 0x22100000222, + 0x22300000224, + 0x22500000226, + 0x22700000228, + 0x2290000022A, + 0x22B0000022C, + 0x22D0000022E, + 0x22F00000230, + 0x23100000232, + 0x2330000023A, + 0x23C0000023D, + 0x23F00000241, + 0x24200000243, + 0x24700000248, + 0x2490000024A, + 0x24B0000024C, + 0x24D0000024E, + 0x24F000002B0, + 0x2B9000002C2, + 0x2C6000002D2, + 0x2EC000002ED, + 0x2EE000002EF, + 0x30000000340, + 0x34200000343, + 0x3460000034F, + 0x35000000370, + 0x37100000372, + 0x37300000374, + 0x37700000378, + 0x37B0000037E, + 0x39000000391, + 0x3AC000003CF, + 0x3D7000003D8, + 0x3D9000003DA, + 0x3DB000003DC, + 0x3DD000003DE, + 0x3DF000003E0, + 0x3E1000003E2, + 0x3E3000003E4, + 0x3E5000003E6, + 0x3E7000003E8, + 0x3E9000003EA, + 0x3EB000003EC, + 0x3ED000003EE, + 0x3EF000003F0, + 0x3F3000003F4, + 0x3F8000003F9, + 0x3FB000003FD, + 0x43000000460, + 0x46100000462, + 0x46300000464, + 0x46500000466, + 0x46700000468, + 0x4690000046A, + 0x46B0000046C, + 0x46D0000046E, + 0x46F00000470, + 0x47100000472, + 0x47300000474, + 0x47500000476, + 0x47700000478, + 0x4790000047A, + 0x47B0000047C, + 0x47D0000047E, + 0x47F00000480, + 0x48100000482, + 0x48300000488, + 0x48B0000048C, + 0x48D0000048E, + 0x48F00000490, + 0x49100000492, + 0x49300000494, + 0x49500000496, + 0x49700000498, + 0x4990000049A, + 0x49B0000049C, + 0x49D0000049E, + 0x49F000004A0, + 0x4A1000004A2, + 0x4A3000004A4, + 0x4A5000004A6, + 0x4A7000004A8, + 0x4A9000004AA, + 0x4AB000004AC, + 0x4AD000004AE, + 0x4AF000004B0, + 0x4B1000004B2, + 0x4B3000004B4, + 0x4B5000004B6, + 0x4B7000004B8, + 0x4B9000004BA, + 0x4BB000004BC, + 0x4BD000004BE, + 0x4BF000004C0, + 0x4C2000004C3, + 0x4C4000004C5, + 0x4C6000004C7, + 0x4C8000004C9, + 0x4CA000004CB, + 0x4CC000004CD, + 0x4CE000004D0, + 0x4D1000004D2, + 0x4D3000004D4, + 0x4D5000004D6, + 0x4D7000004D8, + 0x4D9000004DA, + 0x4DB000004DC, + 0x4DD000004DE, + 0x4DF000004E0, + 0x4E1000004E2, + 0x4E3000004E4, + 0x4E5000004E6, + 0x4E7000004E8, + 0x4E9000004EA, + 0x4EB000004EC, + 0x4ED000004EE, + 0x4EF000004F0, + 0x4F1000004F2, + 0x4F3000004F4, + 0x4F5000004F6, + 0x4F7000004F8, + 0x4F9000004FA, + 0x4FB000004FC, + 0x4FD000004FE, + 0x4FF00000500, + 0x50100000502, + 0x50300000504, + 0x50500000506, + 0x50700000508, + 0x5090000050A, + 0x50B0000050C, + 0x50D0000050E, + 0x50F00000510, + 0x51100000512, + 0x51300000514, + 0x51500000516, + 0x51700000518, + 0x5190000051A, + 0x51B0000051C, + 0x51D0000051E, + 0x51F00000520, + 0x52100000522, + 0x52300000524, + 0x52500000526, + 0x52700000528, + 0x5290000052A, + 0x52B0000052C, + 0x52D0000052E, + 0x52F00000530, + 0x5590000055A, + 0x56000000587, + 0x58800000589, + 0x591000005BE, + 0x5BF000005C0, + 0x5C1000005C3, + 0x5C4000005C6, + 0x5C7000005CA, + 0x5D0000005EB, + 0x5EF000005F3, + 0x6100000061B, + 0x62000000640, + 0x64100000660, + 0x66E00000675, + 0x679000006D4, + 0x6D5000006DD, + 0x6DF000006E9, + 0x6EA000006F0, + 0x6FA00000700, + 0x7100000074B, + 0x74D000007B2, + 0x7C0000007F6, + 0x7FD000007FE, + 0x8000000082E, + 0x8400000085C, + 0x8600000086B, + 0x87000000888, + 0x88900000890, + 0x897000008E2, + 0x8E300000958, + 0x96000000964, + 0x96600000970, + 0x97100000984, + 0x9850000098D, + 0x98F00000991, + 0x993000009A9, + 0x9AA000009B1, + 0x9B2000009B3, + 0x9B6000009BA, + 0x9BC000009C5, + 0x9C7000009C9, + 0x9CB000009CF, + 0x9D7000009D8, + 0x9E0000009E4, + 0x9E6000009F2, + 0x9FC000009FD, + 0x9FE000009FF, + 0xA0100000A04, + 0xA0500000A0B, + 0xA0F00000A11, + 0xA1300000A29, + 0xA2A00000A31, + 0xA3200000A33, + 0xA3500000A36, + 0xA3800000A3A, + 0xA3C00000A3D, + 0xA3E00000A43, + 0xA4700000A49, + 0xA4B00000A4E, + 0xA5100000A52, + 0xA5C00000A5D, + 0xA6600000A76, + 0xA8100000A84, + 0xA8500000A8E, + 0xA8F00000A92, + 0xA9300000AA9, + 0xAAA00000AB1, + 0xAB200000AB4, + 0xAB500000ABA, + 0xABC00000AC6, + 0xAC700000ACA, + 0xACB00000ACE, + 0xAD000000AD1, + 0xAE000000AE4, + 0xAE600000AF0, + 0xAF900000B00, + 0xB0100000B04, + 0xB0500000B0D, + 0xB0F00000B11, + 0xB1300000B29, + 0xB2A00000B31, + 0xB3200000B34, + 0xB3500000B3A, + 0xB3C00000B45, + 0xB4700000B49, + 0xB4B00000B4E, + 0xB5300000B58, + 0xB5F00000B64, + 0xB6600000B70, + 0xB7100000B72, + 0xB8200000B84, + 0xB8500000B8B, + 0xB8E00000B91, + 0xB9200000B96, + 0xB9900000B9B, + 0xB9C00000B9D, + 0xB9E00000BA0, + 0xBA300000BA5, + 0xBA800000BAB, + 0xBAE00000BBA, + 0xBBE00000BC3, + 0xBC600000BC9, + 0xBCA00000BCE, + 0xBD000000BD1, + 0xBD700000BD8, + 0xBE600000BF0, + 0xC0000000C0D, + 0xC0E00000C11, + 0xC1200000C29, + 0xC2A00000C3A, + 0xC3C00000C45, + 0xC4600000C49, + 0xC4A00000C4E, + 0xC5500000C57, + 0xC5800000C5B, + 0xC5C00000C5E, + 0xC6000000C64, + 0xC6600000C70, + 0xC8000000C84, + 0xC8500000C8D, + 0xC8E00000C91, + 0xC9200000CA9, + 0xCAA00000CB4, + 0xCB500000CBA, + 0xCBC00000CC5, + 0xCC600000CC9, + 0xCCA00000CCE, + 0xCD500000CD7, + 0xCDC00000CDF, + 0xCE000000CE4, + 0xCE600000CF0, + 0xCF100000CF4, + 0xD0000000D0D, + 0xD0E00000D11, + 0xD1200000D45, + 0xD4600000D49, + 0xD4A00000D4F, + 0xD5400000D58, + 0xD5F00000D64, + 0xD6600000D70, + 0xD7A00000D80, + 0xD8100000D84, + 0xD8500000D97, + 0xD9A00000DB2, + 0xDB300000DBC, + 0xDBD00000DBE, + 0xDC000000DC7, + 0xDCA00000DCB, + 0xDCF00000DD5, + 0xDD600000DD7, + 0xDD800000DE0, + 0xDE600000DF0, + 0xDF200000DF4, + 0xE0100000E33, + 0xE3400000E3B, + 0xE4000000E4F, + 0xE5000000E5A, + 0xE8100000E83, + 0xE8400000E85, + 0xE8600000E8B, + 0xE8C00000EA4, + 0xEA500000EA6, + 0xEA700000EB3, + 0xEB400000EBE, + 0xEC000000EC5, + 0xEC600000EC7, + 0xEC800000ECF, + 0xED000000EDA, + 0xEDE00000EE0, + 0xF0000000F01, + 0xF0B00000F0C, + 0xF1800000F1A, + 0xF2000000F2A, + 0xF3500000F36, + 0xF3700000F38, + 0xF3900000F3A, + 0xF3E00000F43, + 0xF4400000F48, + 0xF4900000F4D, + 0xF4E00000F52, + 0xF5300000F57, + 0xF5800000F5C, + 0xF5D00000F69, + 0xF6A00000F6D, + 0xF7100000F73, + 0xF7400000F75, + 0xF7A00000F81, + 0xF8200000F85, + 0xF8600000F93, + 0xF9400000F98, + 0xF9900000F9D, + 0xF9E00000FA2, + 0xFA300000FA7, + 0xFA800000FAC, + 0xFAD00000FB9, + 0xFBA00000FBD, + 0xFC600000FC7, + 0x10000000104A, + 0x10500000109E, + 0x10D0000010FB, + 0x10FD00001100, + 0x120000001249, + 0x124A0000124E, + 0x125000001257, + 0x125800001259, + 0x125A0000125E, + 0x126000001289, + 0x128A0000128E, + 0x1290000012B1, + 0x12B2000012B6, + 0x12B8000012BF, + 0x12C0000012C1, + 0x12C2000012C6, + 0x12C8000012D7, + 0x12D800001311, + 0x131200001316, + 0x13180000135B, + 0x135D00001360, + 0x138000001390, + 0x13A0000013F6, + 0x14010000166D, + 0x166F00001680, + 0x16810000169B, + 0x16A0000016EB, + 0x16F1000016F9, + 0x170000001716, + 0x171F00001735, + 0x174000001754, + 0x17600000176D, + 0x176E00001771, + 0x177200001774, + 0x1780000017B4, + 0x17B6000017D4, + 0x17D7000017D8, + 0x17DC000017DE, + 0x17E0000017EA, + 0x18100000181A, + 0x182000001879, + 0x1880000018AB, + 0x18B0000018F6, + 0x19000000191F, + 0x19200000192C, + 0x19300000193C, + 0x19460000196E, + 0x197000001975, + 0x1980000019AC, + 0x19B0000019CA, + 0x19D0000019DA, + 0x1A0000001A1C, + 0x1A2000001A5F, + 0x1A6000001A7D, + 0x1A7F00001A8A, + 0x1A9000001A9A, + 0x1AA700001AA8, + 0x1AB000001ABE, + 0x1ABF00001AF1, + 0x1B0000001B4D, + 0x1B5000001B5A, + 0x1B6B00001B74, + 0x1B8000001BF4, + 0x1C0000001C38, + 0x1C4000001C4A, + 0x1C4D00001C7E, + 0x1C8A00001C8B, + 0x1CD000001CD3, + 0x1CD400001CFB, + 0x1D0000001D2C, + 0x1D2F00001D30, + 0x1D3B00001D3C, + 0x1D4E00001D4F, + 0x1D6B00001D78, + 0x1D7900001D9B, + 0x1DC000001E00, + 0x1E0100001E02, + 0x1E0300001E04, + 0x1E0500001E06, + 0x1E0700001E08, + 0x1E0900001E0A, + 0x1E0B00001E0C, + 0x1E0D00001E0E, + 0x1E0F00001E10, + 0x1E1100001E12, + 0x1E1300001E14, + 0x1E1500001E16, + 0x1E1700001E18, + 0x1E1900001E1A, + 0x1E1B00001E1C, + 0x1E1D00001E1E, + 0x1E1F00001E20, + 0x1E2100001E22, + 0x1E2300001E24, + 0x1E2500001E26, + 0x1E2700001E28, + 0x1E2900001E2A, + 0x1E2B00001E2C, + 0x1E2D00001E2E, + 0x1E2F00001E30, + 0x1E3100001E32, + 0x1E3300001E34, + 0x1E3500001E36, + 0x1E3700001E38, + 0x1E3900001E3A, + 0x1E3B00001E3C, + 0x1E3D00001E3E, + 0x1E3F00001E40, + 0x1E4100001E42, + 0x1E4300001E44, + 0x1E4500001E46, + 0x1E4700001E48, + 0x1E4900001E4A, + 0x1E4B00001E4C, + 0x1E4D00001E4E, + 0x1E4F00001E50, + 0x1E5100001E52, + 0x1E5300001E54, + 0x1E5500001E56, + 0x1E5700001E58, + 0x1E5900001E5A, + 0x1E5B00001E5C, + 0x1E5D00001E5E, + 0x1E5F00001E60, + 0x1E6100001E62, + 0x1E6300001E64, + 0x1E6500001E66, + 0x1E6700001E68, + 0x1E6900001E6A, + 0x1E6B00001E6C, + 0x1E6D00001E6E, + 0x1E6F00001E70, + 0x1E7100001E72, + 0x1E7300001E74, + 0x1E7500001E76, + 0x1E7700001E78, + 0x1E7900001E7A, + 0x1E7B00001E7C, + 0x1E7D00001E7E, + 0x1E7F00001E80, + 0x1E8100001E82, + 0x1E8300001E84, + 0x1E8500001E86, + 0x1E8700001E88, + 0x1E8900001E8A, + 0x1E8B00001E8C, + 0x1E8D00001E8E, + 0x1E8F00001E90, + 0x1E9100001E92, + 0x1E9300001E94, + 0x1E9500001E9A, + 0x1E9C00001E9E, + 0x1E9F00001EA0, + 0x1EA100001EA2, + 0x1EA300001EA4, + 0x1EA500001EA6, + 0x1EA700001EA8, + 0x1EA900001EAA, + 0x1EAB00001EAC, + 0x1EAD00001EAE, + 0x1EAF00001EB0, + 0x1EB100001EB2, + 0x1EB300001EB4, + 0x1EB500001EB6, + 0x1EB700001EB8, + 0x1EB900001EBA, + 0x1EBB00001EBC, + 0x1EBD00001EBE, + 0x1EBF00001EC0, + 0x1EC100001EC2, + 0x1EC300001EC4, + 0x1EC500001EC6, + 0x1EC700001EC8, + 0x1EC900001ECA, + 0x1ECB00001ECC, + 0x1ECD00001ECE, + 0x1ECF00001ED0, + 0x1ED100001ED2, + 0x1ED300001ED4, + 0x1ED500001ED6, + 0x1ED700001ED8, + 0x1ED900001EDA, + 0x1EDB00001EDC, + 0x1EDD00001EDE, + 0x1EDF00001EE0, + 0x1EE100001EE2, + 0x1EE300001EE4, + 0x1EE500001EE6, + 0x1EE700001EE8, + 0x1EE900001EEA, + 0x1EEB00001EEC, + 0x1EED00001EEE, + 0x1EEF00001EF0, + 0x1EF100001EF2, + 0x1EF300001EF4, + 0x1EF500001EF6, + 0x1EF700001EF8, + 0x1EF900001EFA, + 0x1EFB00001EFC, + 0x1EFD00001EFE, + 0x1EFF00001F08, + 0x1F1000001F16, + 0x1F2000001F28, + 0x1F3000001F38, + 0x1F4000001F46, + 0x1F5000001F58, + 0x1F6000001F68, + 0x1F7000001F71, + 0x1F7200001F73, + 0x1F7400001F75, + 0x1F7600001F77, + 0x1F7800001F79, + 0x1F7A00001F7B, + 0x1F7C00001F7D, + 0x1FB000001FB2, + 0x1FB600001FB7, + 0x1FC600001FC7, + 0x1FD000001FD3, + 0x1FD600001FD8, + 0x1FE000001FE3, + 0x1FE400001FE8, + 0x1FF600001FF7, + 0x208F00002090, + 0x214E0000214F, + 0x218400002185, + 0x2C3000002C60, + 0x2C6100002C62, + 0x2C6500002C67, + 0x2C6800002C69, + 0x2C6A00002C6B, + 0x2C6C00002C6D, + 0x2C7100002C72, + 0x2C7300002C75, + 0x2C7600002C7C, + 0x2C8100002C82, + 0x2C8300002C84, + 0x2C8500002C86, + 0x2C8700002C88, + 0x2C8900002C8A, + 0x2C8B00002C8C, + 0x2C8D00002C8E, + 0x2C8F00002C90, + 0x2C9100002C92, + 0x2C9300002C94, + 0x2C9500002C96, + 0x2C9700002C98, + 0x2C9900002C9A, + 0x2C9B00002C9C, + 0x2C9D00002C9E, + 0x2C9F00002CA0, + 0x2CA100002CA2, + 0x2CA300002CA4, + 0x2CA500002CA6, + 0x2CA700002CA8, + 0x2CA900002CAA, + 0x2CAB00002CAC, + 0x2CAD00002CAE, + 0x2CAF00002CB0, + 0x2CB100002CB2, + 0x2CB300002CB4, + 0x2CB500002CB6, + 0x2CB700002CB8, + 0x2CB900002CBA, + 0x2CBB00002CBC, + 0x2CBD00002CBE, + 0x2CBF00002CC0, + 0x2CC100002CC2, + 0x2CC300002CC4, + 0x2CC500002CC6, + 0x2CC700002CC8, + 0x2CC900002CCA, + 0x2CCB00002CCC, + 0x2CCD00002CCE, + 0x2CCF00002CD0, + 0x2CD100002CD2, + 0x2CD300002CD4, + 0x2CD500002CD6, + 0x2CD700002CD8, + 0x2CD900002CDA, + 0x2CDB00002CDC, + 0x2CDD00002CDE, + 0x2CDF00002CE0, + 0x2CE100002CE2, + 0x2CE300002CE5, + 0x2CEC00002CED, + 0x2CEE00002CF2, + 0x2CF300002CF4, + 0x2D0000002D26, + 0x2D2700002D28, + 0x2D2D00002D2E, + 0x2D3000002D68, + 0x2D7F00002D97, + 0x2DA000002DA7, + 0x2DA800002DAF, + 0x2DB000002DB7, + 0x2DB800002DBF, + 0x2DC000002DC7, + 0x2DC800002DCF, + 0x2DD000002DD7, + 0x2DD800002DDF, + 0x2DE000002E00, + 0x2E2F00002E30, + 0x300500003008, + 0x302A0000302E, + 0x303C0000303D, + 0x304100003097, + 0x30990000309B, + 0x309D0000309F, + 0x30A1000030FB, + 0x30FC000030FF, + 0x310500003130, + 0x31A0000031C0, + 0x31F000003200, + 0x340000004DC0, + 0x4E000000A48D, + 0xA4D00000A4FE, + 0xA5000000A60D, + 0xA6100000A62C, + 0xA6410000A642, + 0xA6430000A644, + 0xA6450000A646, + 0xA6470000A648, + 0xA6490000A64A, + 0xA64B0000A64C, + 0xA64D0000A64E, + 0xA64F0000A650, + 0xA6510000A652, + 0xA6530000A654, + 0xA6550000A656, + 0xA6570000A658, + 0xA6590000A65A, + 0xA65B0000A65C, + 0xA65D0000A65E, + 0xA65F0000A660, + 0xA6610000A662, + 0xA6630000A664, + 0xA6650000A666, + 0xA6670000A668, + 0xA6690000A66A, + 0xA66B0000A66C, + 0xA66D0000A670, + 0xA6740000A67E, + 0xA67F0000A680, + 0xA6810000A682, + 0xA6830000A684, + 0xA6850000A686, + 0xA6870000A688, + 0xA6890000A68A, + 0xA68B0000A68C, + 0xA68D0000A68E, + 0xA68F0000A690, + 0xA6910000A692, + 0xA6930000A694, + 0xA6950000A696, + 0xA6970000A698, + 0xA6990000A69A, + 0xA69B0000A69C, + 0xA69E0000A6E6, + 0xA6F00000A6F2, + 0xA7170000A720, + 0xA7230000A724, + 0xA7250000A726, + 0xA7270000A728, + 0xA7290000A72A, + 0xA72B0000A72C, + 0xA72D0000A72E, + 0xA72F0000A732, + 0xA7330000A734, + 0xA7350000A736, + 0xA7370000A738, + 0xA7390000A73A, + 0xA73B0000A73C, + 0xA73D0000A73E, + 0xA73F0000A740, + 0xA7410000A742, + 0xA7430000A744, + 0xA7450000A746, + 0xA7470000A748, + 0xA7490000A74A, + 0xA74B0000A74C, + 0xA74D0000A74E, + 0xA74F0000A750, + 0xA7510000A752, + 0xA7530000A754, + 0xA7550000A756, + 0xA7570000A758, + 0xA7590000A75A, + 0xA75B0000A75C, + 0xA75D0000A75E, + 0xA75F0000A760, + 0xA7610000A762, + 0xA7630000A764, + 0xA7650000A766, + 0xA7670000A768, + 0xA7690000A76A, + 0xA76B0000A76C, + 0xA76D0000A76E, + 0xA76F0000A770, + 0xA7710000A779, + 0xA77A0000A77B, + 0xA77C0000A77D, + 0xA77F0000A780, + 0xA7810000A782, + 0xA7830000A784, + 0xA7850000A786, + 0xA7870000A789, + 0xA78C0000A78D, + 0xA78E0000A790, + 0xA7910000A792, + 0xA7930000A796, + 0xA7970000A798, + 0xA7990000A79A, + 0xA79B0000A79C, + 0xA79D0000A79E, + 0xA79F0000A7A0, + 0xA7A10000A7A2, + 0xA7A30000A7A4, + 0xA7A50000A7A6, + 0xA7A70000A7A8, + 0xA7A90000A7AA, + 0xA7AF0000A7B0, + 0xA7B50000A7B6, + 0xA7B70000A7B8, + 0xA7B90000A7BA, + 0xA7BB0000A7BC, + 0xA7BD0000A7BE, + 0xA7BF0000A7C0, + 0xA7C10000A7C2, + 0xA7C30000A7C4, + 0xA7C80000A7C9, + 0xA7CA0000A7CB, + 0xA7CD0000A7CE, + 0xA7CF0000A7D0, + 0xA7D10000A7D2, + 0xA7D30000A7D4, + 0xA7D50000A7D6, + 0xA7D70000A7D8, + 0xA7D90000A7DA, + 0xA7DB0000A7DC, + 0xA7F60000A7F8, + 0xA7FA0000A828, + 0xA82C0000A82D, + 0xA8400000A874, + 0xA8800000A8C6, + 0xA8D00000A8DA, + 0xA8E00000A8F8, + 0xA8FB0000A8FC, + 0xA8FD0000A92E, + 0xA9300000A954, + 0xA9800000A9C1, + 0xA9CF0000A9DA, + 0xA9E00000A9FF, + 0xAA000000AA37, + 0xAA400000AA4E, + 0xAA500000AA5A, + 0xAA600000AA77, + 0xAA7A0000AAC3, + 0xAADB0000AADE, + 0xAAE00000AAF0, + 0xAAF20000AAF7, + 0xAB010000AB07, + 0xAB090000AB0F, + 0xAB110000AB17, + 0xAB200000AB27, + 0xAB280000AB2F, + 0xAB300000AB5B, + 0xAB600000AB69, + 0xABC00000ABEB, + 0xABEC0000ABEE, + 0xABF00000ABFA, + 0xAC000000D7A4, + 0xFA0E0000FA10, + 0xFA110000FA12, + 0xFA130000FA15, + 0xFA1F0000FA20, + 0xFA210000FA22, + 0xFA230000FA25, + 0xFA270000FA2A, + 0xFB1E0000FB1F, + 0xFE200000FE30, + 0xFE730000FE74, + 0x100000001000C, + 0x1000D00010027, + 0x100280001003B, + 0x1003C0001003E, + 0x1003F0001004E, + 0x100500001005E, + 0x10080000100FB, + 0x101FD000101FE, + 0x102800001029D, + 0x102A0000102D1, + 0x102E0000102E1, + 0x1030000010320, + 0x1032D00010341, + 0x103420001034A, + 0x103500001037B, + 0x103800001039E, + 0x103A0000103C4, + 0x103C8000103D0, + 0x104280001049E, + 0x104A0000104AA, + 0x104D8000104FC, + 0x1050000010528, + 0x1053000010564, + 0x10597000105A2, + 0x105A3000105B2, + 0x105B3000105BA, + 0x105BB000105BD, + 0x105C0000105F4, + 0x1060000010737, + 0x1074000010756, + 0x1076000010768, + 0x1078000010781, + 0x1080000010806, + 0x1080800010809, + 0x1080A00010836, + 0x1083700010839, + 0x1083C0001083D, + 0x1083F00010856, + 0x1086000010877, + 0x108800001089F, + 0x108E0000108F3, + 0x108F4000108F6, + 0x1090000010916, + 0x109200001093A, + 0x109400001095A, + 0x10980000109B8, + 0x109BE000109C0, + 0x10A0000010A04, + 0x10A0500010A07, + 0x10A0C00010A14, + 0x10A1500010A18, + 0x10A1900010A36, + 0x10A3800010A3B, + 0x10A3F00010A40, + 0x10A6000010A7D, + 0x10A8000010A9D, + 0x10AC000010AC8, + 0x10AC900010AE7, + 0x10B0000010B36, + 0x10B4000010B56, + 0x10B6000010B73, + 0x10B8000010B92, + 0x10C0000010C49, + 0x10CC000010CF3, + 0x10D0000010D28, + 0x10D3000010D3A, + 0x10D4000010D50, + 0x10D6900010D6E, + 0x10D6F00010D86, + 0x10E8000010EAA, + 0x10EAB00010EAD, + 0x10EB000010EB2, + 0x10EC200010EC8, + 0x10ECB00010ED0, + 0x10ED900010EEF, + 0x10EF000010F1D, + 0x10F2700010F28, + 0x10F3000010F51, + 0x10F7000010F86, + 0x10FB000010FC5, + 0x10FE000010FF7, + 0x1100000011047, + 0x1106600011076, + 0x1107F000110BB, + 0x110C2000110C3, + 0x110D0000110E9, + 0x110F0000110FA, + 0x1110000011135, + 0x1113600011140, + 0x1114400011148, + 0x1115000011174, + 0x1117600011177, + 0x11180000111C5, + 0x111C9000111CD, + 0x111CE000111DB, + 0x111DC000111DD, + 0x1120000011212, + 0x1121300011238, + 0x1123E00011242, + 0x1128000011287, + 0x1128800011289, + 0x1128A0001128E, + 0x1128F0001129E, + 0x1129F000112A9, + 0x112B0000112EB, + 0x112F0000112FA, + 0x1130000011304, + 0x113050001130D, + 0x1130F00011311, + 0x1131300011329, + 0x1132A00011331, + 0x1133200011334, + 0x113350001133A, + 0x1133B00011345, + 0x1134700011349, + 0x1134B0001134E, + 0x1135000011351, + 0x1135700011358, + 0x1135D00011364, + 0x113660001136D, + 0x1137000011375, + 0x113800001138A, + 0x1138B0001138C, + 0x1138E0001138F, + 0x11390000113B6, + 0x113B7000113C1, + 0x113C2000113C3, + 0x113C5000113C6, + 0x113C7000113CB, + 0x113CC000113D4, + 0x113E1000113E3, + 0x114000001144B, + 0x114500001145A, + 0x1145E00011462, + 0x11480000114C6, + 0x114C7000114C8, + 0x114D0000114DA, + 0x11580000115B6, + 0x115B8000115C1, + 0x115D8000115DE, + 0x1160000011641, + 0x1164400011645, + 0x116500001165A, + 0x11680000116B9, + 0x116C0000116CA, + 0x116D0000116E4, + 0x117000001171B, + 0x1171D0001172C, + 0x117300001173A, + 0x1174000011747, + 0x118000001183B, + 0x118C0000118EA, + 0x118FF00011907, + 0x119090001190A, + 0x1190C00011914, + 0x1191500011917, + 0x1191800011936, + 0x1193700011939, + 0x1193B00011944, + 0x119500001195A, + 0x119A0000119A8, + 0x119AA000119D8, + 0x119DA000119E2, + 0x119E3000119E5, + 0x11A0000011A3F, + 0x11A4700011A48, + 0x11A5000011A9A, + 0x11A9D00011A9E, + 0x11AB000011AF9, + 0x11B0A00011B0B, + 0x11B6000011B68, + 0x11BC000011BE1, + 0x11BF000011BFA, + 0x11C0000011C09, + 0x11C0A00011C37, + 0x11C3800011C41, + 0x11C5000011C5A, + 0x11C7200011C90, + 0x11C9200011CA8, + 0x11CA900011CB7, + 0x11D0000011D07, + 0x11D0800011D0A, + 0x11D0B00011D37, + 0x11D3A00011D3B, + 0x11D3C00011D3E, + 0x11D3F00011D48, + 0x11D5000011D5A, + 0x11D6000011D66, + 0x11D6700011D69, + 0x11D6A00011D8F, + 0x11D9000011D92, + 0x11D9300011D99, + 0x11DA000011DAA, + 0x11DB000011DDC, + 0x11DE000011DEA, + 0x11DF000011DF2, + 0x11EE000011EF7, + 0x11F0000011F11, + 0x11F1200011F3B, + 0x11F3E00011F43, + 0x11F5000011F5B, + 0x11FB000011FB1, + 0x120000001239A, + 0x1248000012544, + 0x12F9000012FF1, + 0x1300000013430, + 0x1344000013456, + 0x13460000143FB, + 0x1440000014647, + 0x161000001613A, + 0x1680000016A39, + 0x16A4000016A5F, + 0x16A6000016A6A, + 0x16A7000016ABF, + 0x16AC000016ACA, + 0x16AD000016AEE, + 0x16AF000016AF5, + 0x16B0000016B37, + 0x16B4000016B44, + 0x16B5000016B5A, + 0x16B6300016B78, + 0x16B7D00016B90, + 0x16D4000016D6D, + 0x16D7000016D7A, + 0x16E6000016E80, + 0x16EBB00016ED4, + 0x16F0000016F4B, + 0x16F4F00016F88, + 0x16F8F00016FA0, + 0x16FE000016FE2, + 0x16FE300016FE5, + 0x16FF000016FF4, + 0x1700000018CDB, + 0x18CFF00018D21, + 0x18D8000018DF3, + 0x18E0000019192, + 0x191A0000191D3, + 0x1AFF00001AFF4, + 0x1AFF50001AFFC, + 0x1AFFD0001AFFF, + 0x1B0000001B123, + 0x1B1270001B129, + 0x1B1320001B133, + 0x1B1500001B153, + 0x1B1550001B156, + 0x1B1640001B169, + 0x1B1700001B2FC, + 0x1BC000001BC6B, + 0x1BC700001BC7D, + 0x1BC800001BC89, + 0x1BC900001BC9A, + 0x1BC9D0001BC9F, + 0x1CF000001CF2E, + 0x1CF300001CF47, + 0x1D2500001D253, + 0x1D25B0001D25D, + 0x1D25F0001D260, + 0x1D2800001D282, + 0x1DA000001DA37, + 0x1DA3B0001DA6D, + 0x1DA750001DA76, + 0x1DA840001DA85, + 0x1DA9B0001DAA0, + 0x1DAA10001DAB0, + 0x1DF000001DF40, + 0x1DF410001DF48, + 0x1DF490001DF4A, + 0x1DF4B0001DF4D, + 0x1DF4E0001DF51, + 0x1DF520001DF68, + 0x1DF690001DF6A, + 0x1DF6B0001DF6C, + 0x1DF6D0001DF6E, + 0x1DF6F0001DF72, + 0x1DF730001DF74, + 0x1DF750001DF76, + 0x1DF770001DF78, + 0x1DF790001DF7A, + 0x1DF7B0001DF7C, + 0x1DF7D0001DF7E, + 0x1DF7F0001DF82, + 0x1DF900001DF95, + 0x1DF960001DF97, + 0x1E0000001E007, + 0x1E0080001E019, + 0x1E01B0001E022, + 0x1E0230001E025, + 0x1E0260001E02B, + 0x1E08F0001E090, + 0x1E1000001E12D, + 0x1E1300001E13E, + 0x1E1400001E14A, + 0x1E14E0001E14F, + 0x1E2900001E2AF, + 0x1E2C00001E2FA, + 0x1E4D00001E4FA, + 0x1E5D00001E5FB, + 0x1E6C00001E6DF, + 0x1E6E00001E6F6, + 0x1E6FE0001E700, + 0x1E7E00001E7E7, + 0x1E7E80001E7EC, + 0x1E7ED0001E7EF, + 0x1E7F00001E7FF, + 0x1E8000001E8C5, + 0x1E8D00001E8D7, + 0x1E9220001E94C, + 0x1E9500001E95A, + 0x200000002A6E0, + 0x2A7000002B81F, + 0x2B8200002CEAE, + 0x2CEB00002EBE1, + 0x2EBF00002EE5E, + 0x300000003134B, + 0x313500003347A, + 0x3D0000003FC40, + ), + "CONTEXTJ": (0x200C0000200E,), + "CONTEXTO": ( + 0xB7000000B8, + 0x37500000376, + 0x5F3000005F5, + 0x6600000066A, + 0x6F0000006FA, + 0x30FB000030FC, + ), +} diff --git a/source/target-vendors/cp312/idna/intranges.py b/source/target-vendors/cp312/idna/intranges.py new file mode 100644 index 0000000..19d7781 --- /dev/null +++ b/source/target-vendors/cp312/idna/intranges.py @@ -0,0 +1,55 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect + + +def intranges_from_list(list_: list[int]) -> tuple[int, ...]: + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + + Ranges are encoded as single integers (start << 32 | end), not as tuples. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i + 1 < len(sorted_list) and sorted_list[i] == sorted_list[i + 1] - 1: + continue + current_range = sorted_list[last_write + 1 : i + 1] + ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) + last_write = i + + return tuple(ranges) + + +def _encode_range(start: int, end: int) -> int: + return (start << 32) | end + + +def _decode_range(r: int) -> tuple[int, int]: + return (r >> 32), (r & ((1 << 32) - 1)) + + +def intranges_contain(int_: int, ranges: tuple[int, ...]) -> bool: + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = _encode_range(int_, 0) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = _decode_range(ranges[pos - 1]) + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = _decode_range(ranges[pos]) + if left == int_: + return True + return False diff --git a/source/target-vendors/cp312/idna/package_data.py b/source/target-vendors/cp312/idna/package_data.py new file mode 100644 index 0000000..2f9ff7e --- /dev/null +++ b/source/target-vendors/cp312/idna/package_data.py @@ -0,0 +1 @@ +__version__ = "3.20" diff --git a/source/target-vendors/cp312/idna/py.typed b/source/target-vendors/cp312/idna/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/idna/uts46data.py b/source/target-vendors/cp312/idna/uts46data.py new file mode 100644 index 0000000..dbfb60f --- /dev/null +++ b/source/target-vendors/cp312/idna/uts46data.py @@ -0,0 +1,17117 @@ +# This file is automatically generated by tools/idna-data + +from __future__ import annotations + +from array import array + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "18.0.0" + +uts46_starts: array[int] = array( + "I", + ( + 0x0, + 0x1, + 0x2, + 0x3, + 0x4, + 0x5, + 0x6, + 0x7, + 0x8, + 0x9, + 0xA, + 0xB, + 0xC, + 0xD, + 0xE, + 0xF, + 0x10, + 0x11, + 0x12, + 0x13, + 0x14, + 0x15, + 0x16, + 0x17, + 0x18, + 0x19, + 0x1A, + 0x1B, + 0x1C, + 0x1D, + 0x1E, + 0x1F, + 0x20, + 0x21, + 0x22, + 0x23, + 0x24, + 0x25, + 0x26, + 0x27, + 0x28, + 0x29, + 0x2A, + 0x2B, + 0x2C, + 0x2D, + 0x2E, + 0x2F, + 0x30, + 0x31, + 0x32, + 0x33, + 0x34, + 0x35, + 0x36, + 0x37, + 0x38, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D, + 0x3E, + 0x3F, + 0x40, + 0x41, + 0x42, + 0x43, + 0x44, + 0x45, + 0x46, + 0x47, + 0x48, + 0x49, + 0x4A, + 0x4B, + 0x4C, + 0x4D, + 0x4E, + 0x4F, + 0x50, + 0x51, + 0x52, + 0x53, + 0x54, + 0x55, + 0x56, + 0x57, + 0x58, + 0x59, + 0x5A, + 0x5B, + 0x5C, + 0x5D, + 0x5E, + 0x5F, + 0x60, + 0x61, + 0x62, + 0x63, + 0x64, + 0x65, + 0x66, + 0x67, + 0x68, + 0x69, + 0x6A, + 0x6B, + 0x6C, + 0x6D, + 0x6E, + 0x6F, + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x77, + 0x78, + 0x79, + 0x7A, + 0x7B, + 0x7C, + 0x7D, + 0x7E, + 0x7F, + 0x80, + 0x81, + 0x82, + 0x83, + 0x84, + 0x85, + 0x86, + 0x87, + 0x88, + 0x89, + 0x8A, + 0x8B, + 0x8C, + 0x8D, + 0x8E, + 0x8F, + 0x90, + 0x91, + 0x92, + 0x93, + 0x94, + 0x95, + 0x96, + 0x97, + 0x98, + 0x99, + 0x9A, + 0x9B, + 0x9C, + 0x9D, + 0x9E, + 0x9F, + 0xA0, + 0xA1, + 0xA2, + 0xA3, + 0xA4, + 0xA5, + 0xA6, + 0xA7, + 0xA8, + 0xA9, + 0xAA, + 0xAB, + 0xAC, + 0xAD, + 0xAE, + 0xAF, + 0xB0, + 0xB1, + 0xB2, + 0xB3, + 0xB4, + 0xB5, + 0xB6, + 0xB7, + 0xB8, + 0xB9, + 0xBA, + 0xBB, + 0xBC, + 0xBD, + 0xBE, + 0xBF, + 0xC0, + 0xC1, + 0xC2, + 0xC3, + 0xC4, + 0xC5, + 0xC6, + 0xC7, + 0xC8, + 0xC9, + 0xCA, + 0xCB, + 0xCC, + 0xCD, + 0xCE, + 0xCF, + 0xD0, + 0xD1, + 0xD2, + 0xD3, + 0xD4, + 0xD5, + 0xD6, + 0xD7, + 0xD8, + 0xD9, + 0xDA, + 0xDB, + 0xDC, + 0xDD, + 0xDE, + 0xDF, + 0xE0, + 0xE1, + 0xE2, + 0xE3, + 0xE4, + 0xE5, + 0xE6, + 0xE7, + 0xE8, + 0xE9, + 0xEA, + 0xEB, + 0xEC, + 0xED, + 0xEE, + 0xEF, + 0xF0, + 0xF1, + 0xF2, + 0xF3, + 0xF4, + 0xF5, + 0xF6, + 0xF7, + 0xF8, + 0xF9, + 0xFA, + 0xFB, + 0xFC, + 0xFD, + 0xFE, + 0xFF, + 0x100, + 0x101, + 0x102, + 0x103, + 0x104, + 0x105, + 0x106, + 0x107, + 0x108, + 0x109, + 0x10A, + 0x10B, + 0x10C, + 0x10D, + 0x10E, + 0x10F, + 0x110, + 0x111, + 0x112, + 0x113, + 0x114, + 0x115, + 0x116, + 0x117, + 0x118, + 0x119, + 0x11A, + 0x11B, + 0x11C, + 0x11D, + 0x11E, + 0x11F, + 0x120, + 0x121, + 0x122, + 0x123, + 0x124, + 0x125, + 0x126, + 0x127, + 0x128, + 0x129, + 0x12A, + 0x12B, + 0x12C, + 0x12D, + 0x12E, + 0x12F, + 0x130, + 0x131, + 0x132, + 0x134, + 0x135, + 0x136, + 0x137, + 0x139, + 0x13A, + 0x13B, + 0x13C, + 0x13D, + 0x13E, + 0x13F, + 0x141, + 0x142, + 0x143, + 0x144, + 0x145, + 0x146, + 0x147, + 0x148, + 0x149, + 0x14A, + 0x14B, + 0x14C, + 0x14D, + 0x14E, + 0x14F, + 0x150, + 0x151, + 0x152, + 0x153, + 0x154, + 0x155, + 0x156, + 0x157, + 0x158, + 0x159, + 0x15A, + 0x15B, + 0x15C, + 0x15D, + 0x15E, + 0x15F, + 0x160, + 0x161, + 0x162, + 0x163, + 0x164, + 0x165, + 0x166, + 0x167, + 0x168, + 0x169, + 0x16A, + 0x16B, + 0x16C, + 0x16D, + 0x16E, + 0x16F, + 0x170, + 0x171, + 0x172, + 0x173, + 0x174, + 0x175, + 0x176, + 0x177, + 0x178, + 0x179, + 0x17A, + 0x17B, + 0x17C, + 0x17D, + 0x17E, + 0x17F, + 0x180, + 0x181, + 0x182, + 0x183, + 0x184, + 0x185, + 0x186, + 0x187, + 0x188, + 0x189, + 0x18A, + 0x18B, + 0x18C, + 0x18E, + 0x18F, + 0x190, + 0x191, + 0x192, + 0x193, + 0x194, + 0x195, + 0x196, + 0x197, + 0x198, + 0x199, + 0x19C, + 0x19D, + 0x19E, + 0x19F, + 0x1A0, + 0x1A1, + 0x1A2, + 0x1A3, + 0x1A4, + 0x1A5, + 0x1A6, + 0x1A7, + 0x1A8, + 0x1A9, + 0x1AA, + 0x1AC, + 0x1AD, + 0x1AE, + 0x1AF, + 0x1B0, + 0x1B1, + 0x1B2, + 0x1B3, + 0x1B4, + 0x1B5, + 0x1B6, + 0x1B7, + 0x1B8, + 0x1B9, + 0x1BC, + 0x1BD, + 0x1C4, + 0x1C7, + 0x1CA, + 0x1CD, + 0x1CE, + 0x1CF, + 0x1D0, + 0x1D1, + 0x1D2, + 0x1D3, + 0x1D4, + 0x1D5, + 0x1D6, + 0x1D7, + 0x1D8, + 0x1D9, + 0x1DA, + 0x1DB, + 0x1DC, + 0x1DE, + 0x1DF, + 0x1E0, + 0x1E1, + 0x1E2, + 0x1E3, + 0x1E4, + 0x1E5, + 0x1E6, + 0x1E7, + 0x1E8, + 0x1E9, + 0x1EA, + 0x1EB, + 0x1EC, + 0x1ED, + 0x1EE, + 0x1EF, + 0x1F1, + 0x1F4, + 0x1F5, + 0x1F6, + 0x1F7, + 0x1F8, + 0x1F9, + 0x1FA, + 0x1FB, + 0x1FC, + 0x1FD, + 0x1FE, + 0x1FF, + 0x200, + 0x201, + 0x202, + 0x203, + 0x204, + 0x205, + 0x206, + 0x207, + 0x208, + 0x209, + 0x20A, + 0x20B, + 0x20C, + 0x20D, + 0x20E, + 0x20F, + 0x210, + 0x211, + 0x212, + 0x213, + 0x214, + 0x215, + 0x216, + 0x217, + 0x218, + 0x219, + 0x21A, + 0x21B, + 0x21C, + 0x21D, + 0x21E, + 0x21F, + 0x220, + 0x221, + 0x222, + 0x223, + 0x224, + 0x225, + 0x226, + 0x227, + 0x228, + 0x229, + 0x22A, + 0x22B, + 0x22C, + 0x22D, + 0x22E, + 0x22F, + 0x230, + 0x231, + 0x232, + 0x233, + 0x23A, + 0x23B, + 0x23C, + 0x23D, + 0x23E, + 0x23F, + 0x241, + 0x242, + 0x243, + 0x244, + 0x245, + 0x246, + 0x247, + 0x248, + 0x249, + 0x24A, + 0x24B, + 0x24C, + 0x24D, + 0x24E, + 0x24F, + 0x2B0, + 0x2B1, + 0x2B2, + 0x2B3, + 0x2B4, + 0x2B5, + 0x2B6, + 0x2B7, + 0x2B8, + 0x2B9, + 0x2D8, + 0x2D9, + 0x2DA, + 0x2DB, + 0x2DC, + 0x2DD, + 0x2DE, + 0x2E0, + 0x2E1, + 0x2E2, + 0x2E3, + 0x2E4, + 0x2E5, + 0x340, + 0x341, + 0x342, + 0x343, + 0x344, + 0x345, + 0x346, + 0x34F, + 0x350, + 0x370, + 0x371, + 0x372, + 0x373, + 0x374, + 0x375, + 0x376, + 0x377, + 0x378, + 0x37A, + 0x37B, + 0x37E, + 0x37F, + 0x380, + 0x384, + 0x385, + 0x386, + 0x387, + 0x388, + 0x389, + 0x38A, + 0x38B, + 0x38C, + 0x38D, + 0x38E, + 0x38F, + 0x390, + 0x391, + 0x392, + 0x393, + 0x394, + 0x395, + 0x396, + 0x397, + 0x398, + 0x399, + 0x39A, + 0x39B, + 0x39C, + 0x39D, + 0x39E, + 0x39F, + 0x3A0, + 0x3A1, + 0x3A2, + 0x3A3, + 0x3A4, + 0x3A5, + 0x3A6, + 0x3A7, + 0x3A8, + 0x3A9, + 0x3AA, + 0x3AB, + 0x3AC, + 0x3C2, + 0x3C3, + 0x3CF, + 0x3D0, + 0x3D1, + 0x3D2, + 0x3D3, + 0x3D4, + 0x3D5, + 0x3D6, + 0x3D7, + 0x3D8, + 0x3D9, + 0x3DA, + 0x3DB, + 0x3DC, + 0x3DD, + 0x3DE, + 0x3DF, + 0x3E0, + 0x3E1, + 0x3E2, + 0x3E3, + 0x3E4, + 0x3E5, + 0x3E6, + 0x3E7, + 0x3E8, + 0x3E9, + 0x3EA, + 0x3EB, + 0x3EC, + 0x3ED, + 0x3EE, + 0x3EF, + 0x3F0, + 0x3F1, + 0x3F2, + 0x3F3, + 0x3F4, + 0x3F5, + 0x3F6, + 0x3F7, + 0x3F8, + 0x3F9, + 0x3FA, + 0x3FB, + 0x3FD, + 0x3FE, + 0x3FF, + 0x400, + 0x401, + 0x402, + 0x403, + 0x404, + 0x405, + 0x406, + 0x407, + 0x408, + 0x409, + 0x40A, + 0x40B, + 0x40C, + 0x40D, + 0x40E, + 0x40F, + 0x410, + 0x411, + 0x412, + 0x413, + 0x414, + 0x415, + 0x416, + 0x417, + 0x418, + 0x419, + 0x41A, + 0x41B, + 0x41C, + 0x41D, + 0x41E, + 0x41F, + 0x420, + 0x421, + 0x422, + 0x423, + 0x424, + 0x425, + 0x426, + 0x427, + 0x428, + 0x429, + 0x42A, + 0x42B, + 0x42C, + 0x42D, + 0x42E, + 0x42F, + 0x430, + 0x460, + 0x461, + 0x462, + 0x463, + 0x464, + 0x465, + 0x466, + 0x467, + 0x468, + 0x469, + 0x46A, + 0x46B, + 0x46C, + 0x46D, + 0x46E, + 0x46F, + 0x470, + 0x471, + 0x472, + 0x473, + 0x474, + 0x475, + 0x476, + 0x477, + 0x478, + 0x479, + 0x47A, + 0x47B, + 0x47C, + 0x47D, + 0x47E, + 0x47F, + 0x480, + 0x481, + 0x48A, + 0x48B, + 0x48C, + 0x48D, + 0x48E, + 0x48F, + 0x490, + 0x491, + 0x492, + 0x493, + 0x494, + 0x495, + 0x496, + 0x497, + 0x498, + 0x499, + 0x49A, + 0x49B, + 0x49C, + 0x49D, + 0x49E, + 0x49F, + 0x4A0, + 0x4A1, + 0x4A2, + 0x4A3, + 0x4A4, + 0x4A5, + 0x4A6, + 0x4A7, + 0x4A8, + 0x4A9, + 0x4AA, + 0x4AB, + 0x4AC, + 0x4AD, + 0x4AE, + 0x4AF, + 0x4B0, + 0x4B1, + 0x4B2, + 0x4B3, + 0x4B4, + 0x4B5, + 0x4B6, + 0x4B7, + 0x4B8, + 0x4B9, + 0x4BA, + 0x4BB, + 0x4BC, + 0x4BD, + 0x4BE, + 0x4BF, + 0x4C0, + 0x4C1, + 0x4C2, + 0x4C3, + 0x4C4, + 0x4C5, + 0x4C6, + 0x4C7, + 0x4C8, + 0x4C9, + 0x4CA, + 0x4CB, + 0x4CC, + 0x4CD, + 0x4CE, + 0x4D0, + 0x4D1, + 0x4D2, + 0x4D3, + 0x4D4, + 0x4D5, + 0x4D6, + 0x4D7, + 0x4D8, + 0x4D9, + 0x4DA, + 0x4DB, + 0x4DC, + 0x4DD, + 0x4DE, + 0x4DF, + 0x4E0, + 0x4E1, + 0x4E2, + 0x4E3, + 0x4E4, + 0x4E5, + 0x4E6, + 0x4E7, + 0x4E8, + 0x4E9, + 0x4EA, + 0x4EB, + 0x4EC, + 0x4ED, + 0x4EE, + 0x4EF, + 0x4F0, + 0x4F1, + 0x4F2, + 0x4F3, + 0x4F4, + 0x4F5, + 0x4F6, + 0x4F7, + 0x4F8, + 0x4F9, + 0x4FA, + 0x4FB, + 0x4FC, + 0x4FD, + 0x4FE, + 0x4FF, + 0x500, + 0x501, + 0x502, + 0x503, + 0x504, + 0x505, + 0x506, + 0x507, + 0x508, + 0x509, + 0x50A, + 0x50B, + 0x50C, + 0x50D, + 0x50E, + 0x50F, + 0x510, + 0x511, + 0x512, + 0x513, + 0x514, + 0x515, + 0x516, + 0x517, + 0x518, + 0x519, + 0x51A, + 0x51B, + 0x51C, + 0x51D, + 0x51E, + 0x51F, + 0x520, + 0x521, + 0x522, + 0x523, + 0x524, + 0x525, + 0x526, + 0x527, + 0x528, + 0x529, + 0x52A, + 0x52B, + 0x52C, + 0x52D, + 0x52E, + 0x52F, + 0x530, + 0x531, + 0x532, + 0x533, + 0x534, + 0x535, + 0x536, + 0x537, + 0x538, + 0x539, + 0x53A, + 0x53B, + 0x53C, + 0x53D, + 0x53E, + 0x53F, + 0x540, + 0x541, + 0x542, + 0x543, + 0x544, + 0x545, + 0x546, + 0x547, + 0x548, + 0x549, + 0x54A, + 0x54B, + 0x54C, + 0x54D, + 0x54E, + 0x54F, + 0x550, + 0x551, + 0x552, + 0x553, + 0x554, + 0x555, + 0x556, + 0x557, + 0x558, + 0x559, + 0x587, + 0x588, + 0x58B, + 0x58C, + 0x58D, + 0x590, + 0x591, + 0x5CA, + 0x5D0, + 0x5EB, + 0x5EF, + 0x5F5, + 0x606, + 0x61C, + 0x61D, + 0x675, + 0x676, + 0x677, + 0x678, + 0x679, + 0x6DD, + 0x6DE, + 0x70E, + 0x710, + 0x74B, + 0x74D, + 0x7B2, + 0x7C0, + 0x7FB, + 0x7FD, + 0x82E, + 0x830, + 0x83F, + 0x840, + 0x85C, + 0x85E, + 0x85F, + 0x860, + 0x86B, + 0x870, + 0x890, + 0x897, + 0x8E2, + 0x8E3, + 0x958, + 0x959, + 0x95A, + 0x95B, + 0x95C, + 0x95D, + 0x95E, + 0x95F, + 0x960, + 0x984, + 0x985, + 0x98D, + 0x98F, + 0x991, + 0x993, + 0x9A9, + 0x9AA, + 0x9B1, + 0x9B2, + 0x9B3, + 0x9B6, + 0x9BA, + 0x9BC, + 0x9C5, + 0x9C7, + 0x9C9, + 0x9CB, + 0x9CF, + 0x9D7, + 0x9D8, + 0x9DC, + 0x9DD, + 0x9DE, + 0x9DF, + 0x9E0, + 0x9E4, + 0x9E6, + 0x9FF, + 0xA01, + 0xA04, + 0xA05, + 0xA0B, + 0xA0F, + 0xA11, + 0xA13, + 0xA29, + 0xA2A, + 0xA31, + 0xA32, + 0xA33, + 0xA34, + 0xA35, + 0xA36, + 0xA37, + 0xA38, + 0xA3A, + 0xA3C, + 0xA3D, + 0xA3E, + 0xA43, + 0xA47, + 0xA49, + 0xA4B, + 0xA4E, + 0xA51, + 0xA52, + 0xA59, + 0xA5A, + 0xA5B, + 0xA5C, + 0xA5D, + 0xA5E, + 0xA5F, + 0xA66, + 0xA77, + 0xA81, + 0xA84, + 0xA85, + 0xA8E, + 0xA8F, + 0xA92, + 0xA93, + 0xAA9, + 0xAAA, + 0xAB1, + 0xAB2, + 0xAB4, + 0xAB5, + 0xABA, + 0xABC, + 0xAC6, + 0xAC7, + 0xACA, + 0xACB, + 0xACE, + 0xAD0, + 0xAD1, + 0xAE0, + 0xAE4, + 0xAE6, + 0xAF2, + 0xAF9, + 0xB00, + 0xB01, + 0xB04, + 0xB05, + 0xB0D, + 0xB0F, + 0xB11, + 0xB13, + 0xB29, + 0xB2A, + 0xB31, + 0xB32, + 0xB34, + 0xB35, + 0xB3A, + 0xB3C, + 0xB45, + 0xB47, + 0xB49, + 0xB4B, + 0xB4E, + 0xB53, + 0xB58, + 0xB5C, + 0xB5D, + 0xB5E, + 0xB5F, + 0xB64, + 0xB66, + 0xB78, + 0xB82, + 0xB84, + 0xB85, + 0xB8B, + 0xB8E, + 0xB91, + 0xB92, + 0xB96, + 0xB99, + 0xB9B, + 0xB9C, + 0xB9D, + 0xB9E, + 0xBA0, + 0xBA3, + 0xBA5, + 0xBA8, + 0xBAB, + 0xBAE, + 0xBBA, + 0xBBE, + 0xBC3, + 0xBC6, + 0xBC9, + 0xBCA, + 0xBCE, + 0xBD0, + 0xBD1, + 0xBD7, + 0xBD8, + 0xBE6, + 0xBFB, + 0xC00, + 0xC0D, + 0xC0E, + 0xC11, + 0xC12, + 0xC29, + 0xC2A, + 0xC3A, + 0xC3C, + 0xC45, + 0xC46, + 0xC49, + 0xC4A, + 0xC4E, + 0xC55, + 0xC57, + 0xC58, + 0xC5B, + 0xC5C, + 0xC5E, + 0xC60, + 0xC64, + 0xC66, + 0xC70, + 0xC77, + 0xC8D, + 0xC8E, + 0xC91, + 0xC92, + 0xCA9, + 0xCAA, + 0xCB4, + 0xCB5, + 0xCBA, + 0xCBC, + 0xCC5, + 0xCC6, + 0xCC9, + 0xCCA, + 0xCCE, + 0xCD5, + 0xCD7, + 0xCDC, + 0xCDF, + 0xCE0, + 0xCE4, + 0xCE6, + 0xCF0, + 0xCF1, + 0xCF4, + 0xD00, + 0xD0D, + 0xD0E, + 0xD11, + 0xD12, + 0xD45, + 0xD46, + 0xD49, + 0xD4A, + 0xD50, + 0xD54, + 0xD64, + 0xD66, + 0xD80, + 0xD81, + 0xD84, + 0xD85, + 0xD97, + 0xD9A, + 0xDB2, + 0xDB3, + 0xDBC, + 0xDBD, + 0xDBE, + 0xDC0, + 0xDC7, + 0xDCA, + 0xDCB, + 0xDCF, + 0xDD5, + 0xDD6, + 0xDD7, + 0xDD8, + 0xDE0, + 0xDE6, + 0xDF0, + 0xDF2, + 0xDF5, + 0xE01, + 0xE33, + 0xE34, + 0xE3B, + 0xE3F, + 0xE5C, + 0xE81, + 0xE83, + 0xE84, + 0xE85, + 0xE86, + 0xE8B, + 0xE8C, + 0xEA4, + 0xEA5, + 0xEA6, + 0xEA7, + 0xEB3, + 0xEB4, + 0xEBE, + 0xEC0, + 0xEC5, + 0xEC6, + 0xEC7, + 0xEC8, + 0xECF, + 0xED0, + 0xEDA, + 0xEDC, + 0xEDD, + 0xEDE, + 0xEE0, + 0xF00, + 0xF0C, + 0xF0D, + 0xF43, + 0xF44, + 0xF48, + 0xF49, + 0xF4D, + 0xF4E, + 0xF52, + 0xF53, + 0xF57, + 0xF58, + 0xF5C, + 0xF5D, + 0xF69, + 0xF6A, + 0xF6D, + 0xF71, + 0xF73, + 0xF74, + 0xF75, + 0xF76, + 0xF77, + 0xF78, + 0xF79, + 0xF7A, + 0xF81, + 0xF82, + 0xF93, + 0xF94, + 0xF98, + 0xF99, + 0xF9D, + 0xF9E, + 0xFA2, + 0xFA3, + 0xFA7, + 0xFA8, + 0xFAC, + 0xFAD, + 0xFB9, + 0xFBA, + 0xFBD, + 0xFBE, + 0xFCD, + 0xFCE, + 0xFDB, + 0x1000, + 0x10A0, + 0x10A1, + 0x10A2, + 0x10A3, + 0x10A4, + 0x10A5, + 0x10A6, + 0x10A7, + 0x10A8, + 0x10A9, + 0x10AA, + 0x10AB, + 0x10AC, + 0x10AD, + 0x10AE, + 0x10AF, + 0x10B0, + 0x10B1, + 0x10B2, + 0x10B3, + 0x10B4, + 0x10B5, + 0x10B6, + 0x10B7, + 0x10B8, + 0x10B9, + 0x10BA, + 0x10BB, + 0x10BC, + 0x10BD, + 0x10BE, + 0x10BF, + 0x10C0, + 0x10C1, + 0x10C2, + 0x10C3, + 0x10C4, + 0x10C5, + 0x10C6, + 0x10C7, + 0x10C8, + 0x10CD, + 0x10CE, + 0x10D0, + 0x10FC, + 0x10FD, + 0x115F, + 0x1161, + 0x1249, + 0x124A, + 0x124E, + 0x1250, + 0x1257, + 0x1258, + 0x1259, + 0x125A, + 0x125E, + 0x1260, + 0x1289, + 0x128A, + 0x128E, + 0x1290, + 0x12B1, + 0x12B2, + 0x12B6, + 0x12B8, + 0x12BF, + 0x12C0, + 0x12C1, + 0x12C2, + 0x12C6, + 0x12C8, + 0x12D7, + 0x12D8, + 0x1311, + 0x1312, + 0x1316, + 0x1318, + 0x135B, + 0x135D, + 0x137D, + 0x1380, + 0x139A, + 0x13A0, + 0x13F6, + 0x13F8, + 0x13F9, + 0x13FA, + 0x13FB, + 0x13FC, + 0x13FD, + 0x13FE, + 0x1400, + 0x1680, + 0x1681, + 0x169D, + 0x16A0, + 0x16F9, + 0x1700, + 0x1716, + 0x171F, + 0x1737, + 0x1740, + 0x1754, + 0x1760, + 0x176D, + 0x176E, + 0x1771, + 0x1772, + 0x1774, + 0x1780, + 0x17B4, + 0x17B6, + 0x17DE, + 0x17E0, + 0x17EA, + 0x17F0, + 0x17FA, + 0x1800, + 0x180B, + 0x1810, + 0x181A, + 0x1820, + 0x1879, + 0x1880, + 0x18AB, + 0x18B0, + 0x18F6, + 0x1900, + 0x191F, + 0x1920, + 0x192C, + 0x1930, + 0x193C, + 0x1940, + 0x1941, + 0x1944, + 0x196E, + 0x1970, + 0x1975, + 0x1980, + 0x19AC, + 0x19B0, + 0x19CA, + 0x19D0, + 0x19DB, + 0x19DE, + 0x1A1C, + 0x1A1E, + 0x1A5F, + 0x1A60, + 0x1A7D, + 0x1A7F, + 0x1A8A, + 0x1A90, + 0x1A9A, + 0x1AA0, + 0x1AAE, + 0x1AB0, + 0x1AF1, + 0x1B00, + 0x1B4D, + 0x1B4E, + 0x1BF4, + 0x1BFC, + 0x1C38, + 0x1C3B, + 0x1C4A, + 0x1C4D, + 0x1C80, + 0x1C81, + 0x1C82, + 0x1C83, + 0x1C84, + 0x1C86, + 0x1C87, + 0x1C88, + 0x1C89, + 0x1C8A, + 0x1C8B, + 0x1C90, + 0x1C91, + 0x1C92, + 0x1C93, + 0x1C94, + 0x1C95, + 0x1C96, + 0x1C97, + 0x1C98, + 0x1C99, + 0x1C9A, + 0x1C9B, + 0x1C9C, + 0x1C9D, + 0x1C9E, + 0x1C9F, + 0x1CA0, + 0x1CA1, + 0x1CA2, + 0x1CA3, + 0x1CA4, + 0x1CA5, + 0x1CA6, + 0x1CA7, + 0x1CA8, + 0x1CA9, + 0x1CAA, + 0x1CAB, + 0x1CAC, + 0x1CAD, + 0x1CAE, + 0x1CAF, + 0x1CB0, + 0x1CB1, + 0x1CB2, + 0x1CB3, + 0x1CB4, + 0x1CB5, + 0x1CB6, + 0x1CB7, + 0x1CB8, + 0x1CB9, + 0x1CBA, + 0x1CBB, + 0x1CBD, + 0x1CBE, + 0x1CBF, + 0x1CC0, + 0x1CC8, + 0x1CD0, + 0x1CFB, + 0x1D00, + 0x1D2C, + 0x1D2D, + 0x1D2E, + 0x1D2F, + 0x1D30, + 0x1D31, + 0x1D32, + 0x1D33, + 0x1D34, + 0x1D35, + 0x1D36, + 0x1D37, + 0x1D38, + 0x1D39, + 0x1D3A, + 0x1D3B, + 0x1D3C, + 0x1D3D, + 0x1D3E, + 0x1D3F, + 0x1D40, + 0x1D41, + 0x1D42, + 0x1D43, + 0x1D44, + 0x1D45, + 0x1D46, + 0x1D47, + 0x1D48, + 0x1D49, + 0x1D4A, + 0x1D4B, + 0x1D4C, + 0x1D4D, + 0x1D4E, + 0x1D4F, + 0x1D50, + 0x1D51, + 0x1D52, + 0x1D53, + 0x1D54, + 0x1D55, + 0x1D56, + 0x1D57, + 0x1D58, + 0x1D59, + 0x1D5A, + 0x1D5B, + 0x1D5C, + 0x1D5D, + 0x1D5E, + 0x1D5F, + 0x1D60, + 0x1D61, + 0x1D62, + 0x1D63, + 0x1D64, + 0x1D65, + 0x1D66, + 0x1D67, + 0x1D68, + 0x1D69, + 0x1D6A, + 0x1D6B, + 0x1D78, + 0x1D79, + 0x1D9B, + 0x1D9C, + 0x1D9D, + 0x1D9E, + 0x1D9F, + 0x1DA0, + 0x1DA1, + 0x1DA2, + 0x1DA3, + 0x1DA4, + 0x1DA5, + 0x1DA6, + 0x1DA7, + 0x1DA8, + 0x1DA9, + 0x1DAA, + 0x1DAB, + 0x1DAC, + 0x1DAD, + 0x1DAE, + 0x1DAF, + 0x1DB0, + 0x1DB1, + 0x1DB2, + 0x1DB3, + 0x1DB4, + 0x1DB5, + 0x1DB6, + 0x1DB7, + 0x1DB8, + 0x1DB9, + 0x1DBA, + 0x1DBB, + 0x1DBC, + 0x1DBD, + 0x1DBE, + 0x1DBF, + 0x1DC0, + 0x1E00, + 0x1E01, + 0x1E02, + 0x1E03, + 0x1E04, + 0x1E05, + 0x1E06, + 0x1E07, + 0x1E08, + 0x1E09, + 0x1E0A, + 0x1E0B, + 0x1E0C, + 0x1E0D, + 0x1E0E, + 0x1E0F, + 0x1E10, + 0x1E11, + 0x1E12, + 0x1E13, + 0x1E14, + 0x1E15, + 0x1E16, + 0x1E17, + 0x1E18, + 0x1E19, + 0x1E1A, + 0x1E1B, + 0x1E1C, + 0x1E1D, + 0x1E1E, + 0x1E1F, + 0x1E20, + 0x1E21, + 0x1E22, + 0x1E23, + 0x1E24, + 0x1E25, + 0x1E26, + 0x1E27, + 0x1E28, + 0x1E29, + 0x1E2A, + 0x1E2B, + 0x1E2C, + 0x1E2D, + 0x1E2E, + 0x1E2F, + 0x1E30, + 0x1E31, + 0x1E32, + 0x1E33, + 0x1E34, + 0x1E35, + 0x1E36, + 0x1E37, + 0x1E38, + 0x1E39, + 0x1E3A, + 0x1E3B, + 0x1E3C, + 0x1E3D, + 0x1E3E, + 0x1E3F, + 0x1E40, + 0x1E41, + 0x1E42, + 0x1E43, + 0x1E44, + 0x1E45, + 0x1E46, + 0x1E47, + 0x1E48, + 0x1E49, + 0x1E4A, + 0x1E4B, + 0x1E4C, + 0x1E4D, + 0x1E4E, + 0x1E4F, + 0x1E50, + 0x1E51, + 0x1E52, + 0x1E53, + 0x1E54, + 0x1E55, + 0x1E56, + 0x1E57, + 0x1E58, + 0x1E59, + 0x1E5A, + 0x1E5B, + 0x1E5C, + 0x1E5D, + 0x1E5E, + 0x1E5F, + 0x1E60, + 0x1E61, + 0x1E62, + 0x1E63, + 0x1E64, + 0x1E65, + 0x1E66, + 0x1E67, + 0x1E68, + 0x1E69, + 0x1E6A, + 0x1E6B, + 0x1E6C, + 0x1E6D, + 0x1E6E, + 0x1E6F, + 0x1E70, + 0x1E71, + 0x1E72, + 0x1E73, + 0x1E74, + 0x1E75, + 0x1E76, + 0x1E77, + 0x1E78, + 0x1E79, + 0x1E7A, + 0x1E7B, + 0x1E7C, + 0x1E7D, + 0x1E7E, + 0x1E7F, + 0x1E80, + 0x1E81, + 0x1E82, + 0x1E83, + 0x1E84, + 0x1E85, + 0x1E86, + 0x1E87, + 0x1E88, + 0x1E89, + 0x1E8A, + 0x1E8B, + 0x1E8C, + 0x1E8D, + 0x1E8E, + 0x1E8F, + 0x1E90, + 0x1E91, + 0x1E92, + 0x1E93, + 0x1E94, + 0x1E95, + 0x1E9A, + 0x1E9B, + 0x1E9C, + 0x1E9E, + 0x1E9F, + 0x1EA0, + 0x1EA1, + 0x1EA2, + 0x1EA3, + 0x1EA4, + 0x1EA5, + 0x1EA6, + 0x1EA7, + 0x1EA8, + 0x1EA9, + 0x1EAA, + 0x1EAB, + 0x1EAC, + 0x1EAD, + 0x1EAE, + 0x1EAF, + 0x1EB0, + 0x1EB1, + 0x1EB2, + 0x1EB3, + 0x1EB4, + 0x1EB5, + 0x1EB6, + 0x1EB7, + 0x1EB8, + 0x1EB9, + 0x1EBA, + 0x1EBB, + 0x1EBC, + 0x1EBD, + 0x1EBE, + 0x1EBF, + 0x1EC0, + 0x1EC1, + 0x1EC2, + 0x1EC3, + 0x1EC4, + 0x1EC5, + 0x1EC6, + 0x1EC7, + 0x1EC8, + 0x1EC9, + 0x1ECA, + 0x1ECB, + 0x1ECC, + 0x1ECD, + 0x1ECE, + 0x1ECF, + 0x1ED0, + 0x1ED1, + 0x1ED2, + 0x1ED3, + 0x1ED4, + 0x1ED5, + 0x1ED6, + 0x1ED7, + 0x1ED8, + 0x1ED9, + 0x1EDA, + 0x1EDB, + 0x1EDC, + 0x1EDD, + 0x1EDE, + 0x1EDF, + 0x1EE0, + 0x1EE1, + 0x1EE2, + 0x1EE3, + 0x1EE4, + 0x1EE5, + 0x1EE6, + 0x1EE7, + 0x1EE8, + 0x1EE9, + 0x1EEA, + 0x1EEB, + 0x1EEC, + 0x1EED, + 0x1EEE, + 0x1EEF, + 0x1EF0, + 0x1EF1, + 0x1EF2, + 0x1EF3, + 0x1EF4, + 0x1EF5, + 0x1EF6, + 0x1EF7, + 0x1EF8, + 0x1EF9, + 0x1EFA, + 0x1EFB, + 0x1EFC, + 0x1EFD, + 0x1EFE, + 0x1EFF, + 0x1F08, + 0x1F09, + 0x1F0A, + 0x1F0B, + 0x1F0C, + 0x1F0D, + 0x1F0E, + 0x1F0F, + 0x1F10, + 0x1F16, + 0x1F18, + 0x1F19, + 0x1F1A, + 0x1F1B, + 0x1F1C, + 0x1F1D, + 0x1F1E, + 0x1F20, + 0x1F28, + 0x1F29, + 0x1F2A, + 0x1F2B, + 0x1F2C, + 0x1F2D, + 0x1F2E, + 0x1F2F, + 0x1F30, + 0x1F38, + 0x1F39, + 0x1F3A, + 0x1F3B, + 0x1F3C, + 0x1F3D, + 0x1F3E, + 0x1F3F, + 0x1F40, + 0x1F46, + 0x1F48, + 0x1F49, + 0x1F4A, + 0x1F4B, + 0x1F4C, + 0x1F4D, + 0x1F4E, + 0x1F50, + 0x1F58, + 0x1F59, + 0x1F5A, + 0x1F5B, + 0x1F5C, + 0x1F5D, + 0x1F5E, + 0x1F5F, + 0x1F60, + 0x1F68, + 0x1F69, + 0x1F6A, + 0x1F6B, + 0x1F6C, + 0x1F6D, + 0x1F6E, + 0x1F6F, + 0x1F70, + 0x1F71, + 0x1F72, + 0x1F73, + 0x1F74, + 0x1F75, + 0x1F76, + 0x1F77, + 0x1F78, + 0x1F79, + 0x1F7A, + 0x1F7B, + 0x1F7C, + 0x1F7D, + 0x1F7E, + 0x1F80, + 0x1F81, + 0x1F82, + 0x1F83, + 0x1F84, + 0x1F85, + 0x1F86, + 0x1F87, + 0x1F88, + 0x1F89, + 0x1F8A, + 0x1F8B, + 0x1F8C, + 0x1F8D, + 0x1F8E, + 0x1F8F, + 0x1F90, + 0x1F91, + 0x1F92, + 0x1F93, + 0x1F94, + 0x1F95, + 0x1F96, + 0x1F97, + 0x1F98, + 0x1F99, + 0x1F9A, + 0x1F9B, + 0x1F9C, + 0x1F9D, + 0x1F9E, + 0x1F9F, + 0x1FA0, + 0x1FA1, + 0x1FA2, + 0x1FA3, + 0x1FA4, + 0x1FA5, + 0x1FA6, + 0x1FA7, + 0x1FA8, + 0x1FA9, + 0x1FAA, + 0x1FAB, + 0x1FAC, + 0x1FAD, + 0x1FAE, + 0x1FAF, + 0x1FB0, + 0x1FB2, + 0x1FB3, + 0x1FB4, + 0x1FB5, + 0x1FB6, + 0x1FB7, + 0x1FB8, + 0x1FB9, + 0x1FBA, + 0x1FBB, + 0x1FBC, + 0x1FBD, + 0x1FBE, + 0x1FBF, + 0x1FC0, + 0x1FC1, + 0x1FC2, + 0x1FC3, + 0x1FC4, + 0x1FC5, + 0x1FC6, + 0x1FC7, + 0x1FC8, + 0x1FC9, + 0x1FCA, + 0x1FCB, + 0x1FCC, + 0x1FCD, + 0x1FCE, + 0x1FCF, + 0x1FD0, + 0x1FD3, + 0x1FD4, + 0x1FD6, + 0x1FD8, + 0x1FD9, + 0x1FDA, + 0x1FDB, + 0x1FDC, + 0x1FDD, + 0x1FDE, + 0x1FDF, + 0x1FE0, + 0x1FE3, + 0x1FE4, + 0x1FE8, + 0x1FE9, + 0x1FEA, + 0x1FEB, + 0x1FEC, + 0x1FED, + 0x1FEE, + 0x1FEF, + 0x1FF0, + 0x1FF2, + 0x1FF3, + 0x1FF4, + 0x1FF5, + 0x1FF6, + 0x1FF7, + 0x1FF8, + 0x1FF9, + 0x1FFA, + 0x1FFB, + 0x1FFC, + 0x1FFD, + 0x1FFE, + 0x1FFF, + 0x2000, + 0x200B, + 0x200C, + 0x200E, + 0x2010, + 0x2011, + 0x2012, + 0x2017, + 0x2018, + 0x2024, + 0x2027, + 0x2028, + 0x202F, + 0x2030, + 0x2033, + 0x2034, + 0x2035, + 0x2036, + 0x2037, + 0x2038, + 0x203C, + 0x203D, + 0x203E, + 0x203F, + 0x2047, + 0x2048, + 0x2049, + 0x204A, + 0x2057, + 0x2058, + 0x205F, + 0x2060, + 0x2065, + 0x206A, + 0x2070, + 0x2071, + 0x2072, + 0x2074, + 0x2075, + 0x2076, + 0x2077, + 0x2078, + 0x2079, + 0x207A, + 0x207B, + 0x207C, + 0x207D, + 0x207E, + 0x207F, + 0x2080, + 0x2081, + 0x2082, + 0x2083, + 0x2084, + 0x2085, + 0x2086, + 0x2087, + 0x2088, + 0x2089, + 0x208A, + 0x208B, + 0x208C, + 0x208D, + 0x208E, + 0x208F, + 0x2090, + 0x2091, + 0x2092, + 0x2093, + 0x2094, + 0x2095, + 0x2096, + 0x2097, + 0x2098, + 0x2099, + 0x209A, + 0x209B, + 0x209C, + 0x209D, + 0x209E, + 0x209F, + 0x20A0, + 0x20A8, + 0x20A9, + 0x20C5, + 0x20D0, + 0x20F1, + 0x2100, + 0x2101, + 0x2102, + 0x2103, + 0x2104, + 0x2105, + 0x2106, + 0x2107, + 0x2108, + 0x2109, + 0x210A, + 0x210B, + 0x210F, + 0x2110, + 0x2112, + 0x2114, + 0x2115, + 0x2116, + 0x2117, + 0x2119, + 0x211A, + 0x211B, + 0x211E, + 0x2120, + 0x2121, + 0x2122, + 0x2123, + 0x2124, + 0x2125, + 0x2126, + 0x2127, + 0x2128, + 0x2129, + 0x212A, + 0x212B, + 0x212C, + 0x212D, + 0x212E, + 0x212F, + 0x2131, + 0x2132, + 0x2133, + 0x2134, + 0x2135, + 0x2136, + 0x2137, + 0x2138, + 0x2139, + 0x213A, + 0x213B, + 0x213C, + 0x213D, + 0x213F, + 0x2140, + 0x2141, + 0x2145, + 0x2147, + 0x2148, + 0x2149, + 0x214A, + 0x2150, + 0x2151, + 0x2152, + 0x2153, + 0x2154, + 0x2155, + 0x2156, + 0x2157, + 0x2158, + 0x2159, + 0x215A, + 0x215B, + 0x215C, + 0x215D, + 0x215E, + 0x215F, + 0x2160, + 0x2161, + 0x2162, + 0x2163, + 0x2164, + 0x2165, + 0x2166, + 0x2167, + 0x2168, + 0x2169, + 0x216A, + 0x216B, + 0x216C, + 0x216D, + 0x216E, + 0x216F, + 0x2170, + 0x2171, + 0x2172, + 0x2173, + 0x2174, + 0x2175, + 0x2176, + 0x2177, + 0x2178, + 0x2179, + 0x217A, + 0x217B, + 0x217C, + 0x217D, + 0x217E, + 0x217F, + 0x2180, + 0x2183, + 0x2184, + 0x2189, + 0x218A, + 0x218C, + 0x2190, + 0x222C, + 0x222D, + 0x222E, + 0x222F, + 0x2230, + 0x2231, + 0x2329, + 0x232A, + 0x232B, + 0x242A, + 0x2440, + 0x244B, + 0x2460, + 0x2461, + 0x2462, + 0x2463, + 0x2464, + 0x2465, + 0x2466, + 0x2467, + 0x2468, + 0x2469, + 0x246A, + 0x246B, + 0x246C, + 0x246D, + 0x246E, + 0x246F, + 0x2470, + 0x2471, + 0x2472, + 0x2473, + 0x2474, + 0x2475, + 0x2476, + 0x2477, + 0x2478, + 0x2479, + 0x247A, + 0x247B, + 0x247C, + 0x247D, + 0x247E, + 0x247F, + 0x2480, + 0x2481, + 0x2482, + 0x2483, + 0x2484, + 0x2485, + 0x2486, + 0x2487, + 0x2488, + 0x249C, + 0x249D, + 0x249E, + 0x249F, + 0x24A0, + 0x24A1, + 0x24A2, + 0x24A3, + 0x24A4, + 0x24A5, + 0x24A6, + 0x24A7, + 0x24A8, + 0x24A9, + 0x24AA, + 0x24AB, + 0x24AC, + 0x24AD, + 0x24AE, + 0x24AF, + 0x24B0, + 0x24B1, + 0x24B2, + 0x24B3, + 0x24B4, + 0x24B5, + 0x24B6, + 0x24B7, + 0x24B8, + 0x24B9, + 0x24BA, + 0x24BB, + 0x24BC, + 0x24BD, + 0x24BE, + 0x24BF, + 0x24C0, + 0x24C1, + 0x24C2, + 0x24C3, + 0x24C4, + 0x24C5, + 0x24C6, + 0x24C7, + 0x24C8, + 0x24C9, + 0x24CA, + 0x24CB, + 0x24CC, + 0x24CD, + 0x24CE, + 0x24CF, + 0x24D0, + 0x24D1, + 0x24D2, + 0x24D3, + 0x24D4, + 0x24D5, + 0x24D6, + 0x24D7, + 0x24D8, + 0x24D9, + 0x24DA, + 0x24DB, + 0x24DC, + 0x24DD, + 0x24DE, + 0x24DF, + 0x24E0, + 0x24E1, + 0x24E2, + 0x24E3, + 0x24E4, + 0x24E5, + 0x24E6, + 0x24E7, + 0x24E8, + 0x24E9, + 0x24EA, + 0x24EB, + 0x2A0C, + 0x2A0D, + 0x2A74, + 0x2A75, + 0x2A76, + 0x2A77, + 0x2ADC, + 0x2ADD, + 0x2B74, + 0x2B76, + 0x2C00, + 0x2C01, + 0x2C02, + 0x2C03, + 0x2C04, + 0x2C05, + 0x2C06, + 0x2C07, + 0x2C08, + 0x2C09, + 0x2C0A, + 0x2C0B, + 0x2C0C, + 0x2C0D, + 0x2C0E, + 0x2C0F, + 0x2C10, + 0x2C11, + 0x2C12, + 0x2C13, + 0x2C14, + 0x2C15, + 0x2C16, + 0x2C17, + 0x2C18, + 0x2C19, + 0x2C1A, + 0x2C1B, + 0x2C1C, + 0x2C1D, + 0x2C1E, + 0x2C1F, + 0x2C20, + 0x2C21, + 0x2C22, + 0x2C23, + 0x2C24, + 0x2C25, + 0x2C26, + 0x2C27, + 0x2C28, + 0x2C29, + 0x2C2A, + 0x2C2B, + 0x2C2C, + 0x2C2D, + 0x2C2E, + 0x2C2F, + 0x2C30, + 0x2C60, + 0x2C61, + 0x2C62, + 0x2C63, + 0x2C64, + 0x2C65, + 0x2C67, + 0x2C68, + 0x2C69, + 0x2C6A, + 0x2C6B, + 0x2C6C, + 0x2C6D, + 0x2C6E, + 0x2C6F, + 0x2C70, + 0x2C71, + 0x2C72, + 0x2C73, + 0x2C75, + 0x2C76, + 0x2C7C, + 0x2C7D, + 0x2C7E, + 0x2C7F, + 0x2C80, + 0x2C81, + 0x2C82, + 0x2C83, + 0x2C84, + 0x2C85, + 0x2C86, + 0x2C87, + 0x2C88, + 0x2C89, + 0x2C8A, + 0x2C8B, + 0x2C8C, + 0x2C8D, + 0x2C8E, + 0x2C8F, + 0x2C90, + 0x2C91, + 0x2C92, + 0x2C93, + 0x2C94, + 0x2C95, + 0x2C96, + 0x2C97, + 0x2C98, + 0x2C99, + 0x2C9A, + 0x2C9B, + 0x2C9C, + 0x2C9D, + 0x2C9E, + 0x2C9F, + 0x2CA0, + 0x2CA1, + 0x2CA2, + 0x2CA3, + 0x2CA4, + 0x2CA5, + 0x2CA6, + 0x2CA7, + 0x2CA8, + 0x2CA9, + 0x2CAA, + 0x2CAB, + 0x2CAC, + 0x2CAD, + 0x2CAE, + 0x2CAF, + 0x2CB0, + 0x2CB1, + 0x2CB2, + 0x2CB3, + 0x2CB4, + 0x2CB5, + 0x2CB6, + 0x2CB7, + 0x2CB8, + 0x2CB9, + 0x2CBA, + 0x2CBB, + 0x2CBC, + 0x2CBD, + 0x2CBE, + 0x2CBF, + 0x2CC0, + 0x2CC1, + 0x2CC2, + 0x2CC3, + 0x2CC4, + 0x2CC5, + 0x2CC6, + 0x2CC7, + 0x2CC8, + 0x2CC9, + 0x2CCA, + 0x2CCB, + 0x2CCC, + 0x2CCD, + 0x2CCE, + 0x2CCF, + 0x2CD0, + 0x2CD1, + 0x2CD2, + 0x2CD3, + 0x2CD4, + 0x2CD5, + 0x2CD6, + 0x2CD7, + 0x2CD8, + 0x2CD9, + 0x2CDA, + 0x2CDB, + 0x2CDC, + 0x2CDD, + 0x2CDE, + 0x2CDF, + 0x2CE0, + 0x2CE1, + 0x2CE2, + 0x2CE3, + 0x2CEB, + 0x2CEC, + 0x2CED, + 0x2CEE, + 0x2CF2, + 0x2CF3, + 0x2CF4, + 0x2CF9, + 0x2D26, + 0x2D27, + 0x2D28, + 0x2D2D, + 0x2D2E, + 0x2D30, + 0x2D68, + 0x2D6F, + 0x2D70, + 0x2D71, + 0x2D7F, + 0x2D97, + 0x2DA0, + 0x2DA7, + 0x2DA8, + 0x2DAF, + 0x2DB0, + 0x2DB7, + 0x2DB8, + 0x2DBF, + 0x2DC0, + 0x2DC7, + 0x2DC8, + 0x2DCF, + 0x2DD0, + 0x2DD7, + 0x2DD8, + 0x2DDF, + 0x2DE0, + 0x2E5E, + 0x2E60, + 0x2E64, + 0x2E80, + 0x2E9A, + 0x2E9B, + 0x2E9F, + 0x2EA0, + 0x2EF3, + 0x2EF4, + 0x2F00, + 0x2F01, + 0x2F02, + 0x2F03, + 0x2F04, + 0x2F05, + 0x2F06, + 0x2F07, + 0x2F08, + 0x2F09, + 0x2F0A, + 0x2F0B, + 0x2F0C, + 0x2F0D, + 0x2F0E, + 0x2F0F, + 0x2F10, + 0x2F11, + 0x2F12, + 0x2F13, + 0x2F14, + 0x2F15, + 0x2F16, + 0x2F17, + 0x2F18, + 0x2F19, + 0x2F1A, + 0x2F1B, + 0x2F1C, + 0x2F1D, + 0x2F1E, + 0x2F1F, + 0x2F20, + 0x2F21, + 0x2F22, + 0x2F23, + 0x2F24, + 0x2F25, + 0x2F26, + 0x2F27, + 0x2F28, + 0x2F29, + 0x2F2A, + 0x2F2B, + 0x2F2C, + 0x2F2D, + 0x2F2E, + 0x2F2F, + 0x2F30, + 0x2F31, + 0x2F32, + 0x2F33, + 0x2F34, + 0x2F35, + 0x2F36, + 0x2F37, + 0x2F38, + 0x2F39, + 0x2F3A, + 0x2F3B, + 0x2F3C, + 0x2F3D, + 0x2F3E, + 0x2F3F, + 0x2F40, + 0x2F41, + 0x2F42, + 0x2F43, + 0x2F44, + 0x2F45, + 0x2F46, + 0x2F47, + 0x2F48, + 0x2F49, + 0x2F4A, + 0x2F4B, + 0x2F4C, + 0x2F4D, + 0x2F4E, + 0x2F4F, + 0x2F50, + 0x2F51, + 0x2F52, + 0x2F53, + 0x2F54, + 0x2F55, + 0x2F56, + 0x2F57, + 0x2F58, + 0x2F59, + 0x2F5A, + 0x2F5B, + 0x2F5C, + 0x2F5D, + 0x2F5E, + 0x2F5F, + 0x2F60, + 0x2F61, + 0x2F62, + 0x2F63, + 0x2F64, + 0x2F65, + 0x2F66, + 0x2F67, + 0x2F68, + 0x2F69, + 0x2F6A, + 0x2F6B, + 0x2F6C, + 0x2F6D, + 0x2F6E, + 0x2F6F, + 0x2F70, + 0x2F71, + 0x2F72, + 0x2F73, + 0x2F74, + 0x2F75, + 0x2F76, + 0x2F77, + 0x2F78, + 0x2F79, + 0x2F7A, + 0x2F7B, + 0x2F7C, + 0x2F7D, + 0x2F7E, + 0x2F7F, + 0x2F80, + 0x2F81, + 0x2F82, + 0x2F83, + 0x2F84, + 0x2F85, + 0x2F86, + 0x2F87, + 0x2F88, + 0x2F89, + 0x2F8A, + 0x2F8B, + 0x2F8C, + 0x2F8D, + 0x2F8E, + 0x2F8F, + 0x2F90, + 0x2F91, + 0x2F92, + 0x2F93, + 0x2F94, + 0x2F95, + 0x2F96, + 0x2F97, + 0x2F98, + 0x2F99, + 0x2F9A, + 0x2F9B, + 0x2F9C, + 0x2F9D, + 0x2F9E, + 0x2F9F, + 0x2FA0, + 0x2FA1, + 0x2FA2, + 0x2FA3, + 0x2FA4, + 0x2FA5, + 0x2FA6, + 0x2FA7, + 0x2FA8, + 0x2FA9, + 0x2FAA, + 0x2FAB, + 0x2FAC, + 0x2FAD, + 0x2FAE, + 0x2FAF, + 0x2FB0, + 0x2FB1, + 0x2FB2, + 0x2FB3, + 0x2FB4, + 0x2FB5, + 0x2FB6, + 0x2FB7, + 0x2FB8, + 0x2FB9, + 0x2FBA, + 0x2FBB, + 0x2FBC, + 0x2FBD, + 0x2FBE, + 0x2FBF, + 0x2FC0, + 0x2FC1, + 0x2FC2, + 0x2FC3, + 0x2FC4, + 0x2FC5, + 0x2FC6, + 0x2FC7, + 0x2FC8, + 0x2FC9, + 0x2FCA, + 0x2FCB, + 0x2FCC, + 0x2FCD, + 0x2FCE, + 0x2FCF, + 0x2FD0, + 0x2FD1, + 0x2FD2, + 0x2FD3, + 0x2FD4, + 0x2FD5, + 0x2FD6, + 0x3000, + 0x3001, + 0x3002, + 0x3003, + 0x3036, + 0x3037, + 0x3038, + 0x3039, + 0x303A, + 0x303B, + 0x3040, + 0x3041, + 0x3097, + 0x3099, + 0x309B, + 0x309C, + 0x309D, + 0x309F, + 0x30A0, + 0x30FF, + 0x3100, + 0x3105, + 0x3130, + 0x3131, + 0x3132, + 0x3133, + 0x3134, + 0x3135, + 0x3136, + 0x3137, + 0x3138, + 0x3139, + 0x313A, + 0x313B, + 0x313C, + 0x313D, + 0x313E, + 0x313F, + 0x3140, + 0x3141, + 0x3142, + 0x3143, + 0x3144, + 0x3145, + 0x3146, + 0x3147, + 0x3148, + 0x3149, + 0x314A, + 0x314B, + 0x314C, + 0x314D, + 0x314E, + 0x314F, + 0x3150, + 0x3151, + 0x3152, + 0x3153, + 0x3154, + 0x3155, + 0x3156, + 0x3157, + 0x3158, + 0x3159, + 0x315A, + 0x315B, + 0x315C, + 0x315D, + 0x315E, + 0x315F, + 0x3160, + 0x3161, + 0x3162, + 0x3163, + 0x3164, + 0x3165, + 0x3166, + 0x3167, + 0x3168, + 0x3169, + 0x316A, + 0x316B, + 0x316C, + 0x316D, + 0x316E, + 0x316F, + 0x3170, + 0x3171, + 0x3172, + 0x3173, + 0x3174, + 0x3175, + 0x3176, + 0x3177, + 0x3178, + 0x3179, + 0x317A, + 0x317B, + 0x317C, + 0x317D, + 0x317E, + 0x317F, + 0x3180, + 0x3181, + 0x3182, + 0x3183, + 0x3184, + 0x3185, + 0x3186, + 0x3187, + 0x3188, + 0x3189, + 0x318A, + 0x318B, + 0x318C, + 0x318D, + 0x318E, + 0x318F, + 0x3190, + 0x3192, + 0x3193, + 0x3194, + 0x3195, + 0x3196, + 0x3197, + 0x3198, + 0x3199, + 0x319A, + 0x319B, + 0x319C, + 0x319D, + 0x319E, + 0x319F, + 0x31A0, + 0x31E6, + 0x31F0, + 0x3200, + 0x3201, + 0x3202, + 0x3203, + 0x3204, + 0x3205, + 0x3206, + 0x3207, + 0x3208, + 0x3209, + 0x320A, + 0x320B, + 0x320C, + 0x320D, + 0x320E, + 0x320F, + 0x3210, + 0x3211, + 0x3212, + 0x3213, + 0x3214, + 0x3215, + 0x3216, + 0x3217, + 0x3218, + 0x3219, + 0x321A, + 0x321B, + 0x321C, + 0x321D, + 0x321E, + 0x321F, + 0x3220, + 0x3221, + 0x3222, + 0x3223, + 0x3224, + 0x3225, + 0x3226, + 0x3227, + 0x3228, + 0x3229, + 0x322A, + 0x322B, + 0x322C, + 0x322D, + 0x322E, + 0x322F, + 0x3230, + 0x3231, + 0x3232, + 0x3233, + 0x3234, + 0x3235, + 0x3236, + 0x3237, + 0x3238, + 0x3239, + 0x323A, + 0x323B, + 0x323C, + 0x323D, + 0x323E, + 0x323F, + 0x3240, + 0x3241, + 0x3242, + 0x3243, + 0x3244, + 0x3245, + 0x3246, + 0x3247, + 0x3248, + 0x3250, + 0x3251, + 0x3252, + 0x3253, + 0x3254, + 0x3255, + 0x3256, + 0x3257, + 0x3258, + 0x3259, + 0x325A, + 0x325B, + 0x325C, + 0x325D, + 0x325E, + 0x325F, + 0x3260, + 0x3261, + 0x3262, + 0x3263, + 0x3264, + 0x3265, + 0x3266, + 0x3267, + 0x3268, + 0x3269, + 0x326A, + 0x326B, + 0x326C, + 0x326D, + 0x326E, + 0x326F, + 0x3270, + 0x3271, + 0x3272, + 0x3273, + 0x3274, + 0x3275, + 0x3276, + 0x3277, + 0x3278, + 0x3279, + 0x327A, + 0x327B, + 0x327C, + 0x327D, + 0x327E, + 0x327F, + 0x3280, + 0x3281, + 0x3282, + 0x3283, + 0x3284, + 0x3285, + 0x3286, + 0x3287, + 0x3288, + 0x3289, + 0x328A, + 0x328B, + 0x328C, + 0x328D, + 0x328E, + 0x328F, + 0x3290, + 0x3291, + 0x3292, + 0x3293, + 0x3294, + 0x3295, + 0x3296, + 0x3297, + 0x3298, + 0x3299, + 0x329A, + 0x329B, + 0x329C, + 0x329D, + 0x329E, + 0x329F, + 0x32A0, + 0x32A1, + 0x32A2, + 0x32A3, + 0x32A4, + 0x32A5, + 0x32A6, + 0x32A7, + 0x32A8, + 0x32A9, + 0x32AA, + 0x32AB, + 0x32AC, + 0x32AD, + 0x32AE, + 0x32AF, + 0x32B0, + 0x32B1, + 0x32B2, + 0x32B3, + 0x32B4, + 0x32B5, + 0x32B6, + 0x32B7, + 0x32B8, + 0x32B9, + 0x32BA, + 0x32BB, + 0x32BC, + 0x32BD, + 0x32BE, + 0x32BF, + 0x32C0, + 0x32C1, + 0x32C2, + 0x32C3, + 0x32C4, + 0x32C5, + 0x32C6, + 0x32C7, + 0x32C8, + 0x32C9, + 0x32CA, + 0x32CB, + 0x32CC, + 0x32CD, + 0x32CE, + 0x32CF, + 0x32D0, + 0x32D1, + 0x32D2, + 0x32D3, + 0x32D4, + 0x32D5, + 0x32D6, + 0x32D7, + 0x32D8, + 0x32D9, + 0x32DA, + 0x32DB, + 0x32DC, + 0x32DD, + 0x32DE, + 0x32DF, + 0x32E0, + 0x32E1, + 0x32E2, + 0x32E3, + 0x32E4, + 0x32E5, + 0x32E6, + 0x32E7, + 0x32E8, + 0x32E9, + 0x32EA, + 0x32EB, + 0x32EC, + 0x32ED, + 0x32EE, + 0x32EF, + 0x32F0, + 0x32F1, + 0x32F2, + 0x32F3, + 0x32F4, + 0x32F5, + 0x32F6, + 0x32F7, + 0x32F8, + 0x32F9, + 0x32FA, + 0x32FB, + 0x32FC, + 0x32FD, + 0x32FE, + 0x32FF, + 0x3300, + 0x3301, + 0x3302, + 0x3303, + 0x3304, + 0x3305, + 0x3306, + 0x3307, + 0x3308, + 0x3309, + 0x330A, + 0x330B, + 0x330C, + 0x330D, + 0x330E, + 0x330F, + 0x3310, + 0x3311, + 0x3312, + 0x3313, + 0x3314, + 0x3315, + 0x3316, + 0x3317, + 0x3318, + 0x3319, + 0x331A, + 0x331B, + 0x331C, + 0x331D, + 0x331E, + 0x331F, + 0x3320, + 0x3321, + 0x3322, + 0x3323, + 0x3324, + 0x3325, + 0x3326, + 0x3327, + 0x3328, + 0x3329, + 0x332A, + 0x332B, + 0x332C, + 0x332D, + 0x332E, + 0x332F, + 0x3330, + 0x3331, + 0x3332, + 0x3333, + 0x3334, + 0x3335, + 0x3336, + 0x3337, + 0x3338, + 0x3339, + 0x333A, + 0x333B, + 0x333C, + 0x333D, + 0x333E, + 0x333F, + 0x3340, + 0x3341, + 0x3342, + 0x3343, + 0x3344, + 0x3345, + 0x3346, + 0x3347, + 0x3348, + 0x3349, + 0x334A, + 0x334B, + 0x334C, + 0x334D, + 0x334E, + 0x334F, + 0x3350, + 0x3351, + 0x3352, + 0x3353, + 0x3354, + 0x3355, + 0x3356, + 0x3357, + 0x3358, + 0x3359, + 0x335A, + 0x335B, + 0x335C, + 0x335D, + 0x335E, + 0x335F, + 0x3360, + 0x3361, + 0x3362, + 0x3363, + 0x3364, + 0x3365, + 0x3366, + 0x3367, + 0x3368, + 0x3369, + 0x336A, + 0x336B, + 0x336C, + 0x336D, + 0x336E, + 0x336F, + 0x3370, + 0x3371, + 0x3372, + 0x3373, + 0x3374, + 0x3375, + 0x3376, + 0x3377, + 0x3378, + 0x3379, + 0x337A, + 0x337B, + 0x337C, + 0x337D, + 0x337E, + 0x337F, + 0x3380, + 0x3381, + 0x3382, + 0x3383, + 0x3384, + 0x3385, + 0x3386, + 0x3387, + 0x3388, + 0x3389, + 0x338A, + 0x338B, + 0x338C, + 0x338D, + 0x338E, + 0x338F, + 0x3390, + 0x3391, + 0x3392, + 0x3393, + 0x3394, + 0x3395, + 0x3396, + 0x3397, + 0x3398, + 0x3399, + 0x339A, + 0x339B, + 0x339C, + 0x339D, + 0x339E, + 0x339F, + 0x33A0, + 0x33A1, + 0x33A2, + 0x33A3, + 0x33A4, + 0x33A5, + 0x33A6, + 0x33A7, + 0x33A8, + 0x33A9, + 0x33AA, + 0x33AB, + 0x33AC, + 0x33AD, + 0x33AE, + 0x33AF, + 0x33B0, + 0x33B1, + 0x33B2, + 0x33B3, + 0x33B4, + 0x33B5, + 0x33B6, + 0x33B7, + 0x33B8, + 0x33B9, + 0x33BA, + 0x33BB, + 0x33BC, + 0x33BD, + 0x33BE, + 0x33BF, + 0x33C0, + 0x33C1, + 0x33C2, + 0x33C3, + 0x33C4, + 0x33C5, + 0x33C6, + 0x33C7, + 0x33C8, + 0x33C9, + 0x33CA, + 0x33CB, + 0x33CC, + 0x33CD, + 0x33CE, + 0x33CF, + 0x33D0, + 0x33D1, + 0x33D2, + 0x33D3, + 0x33D4, + 0x33D5, + 0x33D6, + 0x33D7, + 0x33D8, + 0x33D9, + 0x33DA, + 0x33DB, + 0x33DC, + 0x33DD, + 0x33DE, + 0x33DF, + 0x33E0, + 0x33E1, + 0x33E2, + 0x33E3, + 0x33E4, + 0x33E5, + 0x33E6, + 0x33E7, + 0x33E8, + 0x33E9, + 0x33EA, + 0x33EB, + 0x33EC, + 0x33ED, + 0x33EE, + 0x33EF, + 0x33F0, + 0x33F1, + 0x33F2, + 0x33F3, + 0x33F4, + 0x33F5, + 0x33F6, + 0x33F7, + 0x33F8, + 0x33F9, + 0x33FA, + 0x33FB, + 0x33FC, + 0x33FD, + 0x33FE, + 0x33FF, + 0x3400, + 0xA48D, + 0xA490, + 0xA4C7, + 0xA4D0, + 0xA62C, + 0xA640, + 0xA641, + 0xA642, + 0xA643, + 0xA644, + 0xA645, + 0xA646, + 0xA647, + 0xA648, + 0xA649, + 0xA64A, + 0xA64B, + 0xA64C, + 0xA64D, + 0xA64E, + 0xA64F, + 0xA650, + 0xA651, + 0xA652, + 0xA653, + 0xA654, + 0xA655, + 0xA656, + 0xA657, + 0xA658, + 0xA659, + 0xA65A, + 0xA65B, + 0xA65C, + 0xA65D, + 0xA65E, + 0xA65F, + 0xA660, + 0xA661, + 0xA662, + 0xA663, + 0xA664, + 0xA665, + 0xA666, + 0xA667, + 0xA668, + 0xA669, + 0xA66A, + 0xA66B, + 0xA66C, + 0xA66D, + 0xA680, + 0xA681, + 0xA682, + 0xA683, + 0xA684, + 0xA685, + 0xA686, + 0xA687, + 0xA688, + 0xA689, + 0xA68A, + 0xA68B, + 0xA68C, + 0xA68D, + 0xA68E, + 0xA68F, + 0xA690, + 0xA691, + 0xA692, + 0xA693, + 0xA694, + 0xA695, + 0xA696, + 0xA697, + 0xA698, + 0xA699, + 0xA69A, + 0xA69B, + 0xA69C, + 0xA69D, + 0xA69E, + 0xA6F8, + 0xA700, + 0xA722, + 0xA723, + 0xA724, + 0xA725, + 0xA726, + 0xA727, + 0xA728, + 0xA729, + 0xA72A, + 0xA72B, + 0xA72C, + 0xA72D, + 0xA72E, + 0xA72F, + 0xA732, + 0xA733, + 0xA734, + 0xA735, + 0xA736, + 0xA737, + 0xA738, + 0xA739, + 0xA73A, + 0xA73B, + 0xA73C, + 0xA73D, + 0xA73E, + 0xA73F, + 0xA740, + 0xA741, + 0xA742, + 0xA743, + 0xA744, + 0xA745, + 0xA746, + 0xA747, + 0xA748, + 0xA749, + 0xA74A, + 0xA74B, + 0xA74C, + 0xA74D, + 0xA74E, + 0xA74F, + 0xA750, + 0xA751, + 0xA752, + 0xA753, + 0xA754, + 0xA755, + 0xA756, + 0xA757, + 0xA758, + 0xA759, + 0xA75A, + 0xA75B, + 0xA75C, + 0xA75D, + 0xA75E, + 0xA75F, + 0xA760, + 0xA761, + 0xA762, + 0xA763, + 0xA764, + 0xA765, + 0xA766, + 0xA767, + 0xA768, + 0xA769, + 0xA76A, + 0xA76B, + 0xA76C, + 0xA76D, + 0xA76E, + 0xA76F, + 0xA770, + 0xA771, + 0xA779, + 0xA77A, + 0xA77B, + 0xA77C, + 0xA77D, + 0xA77E, + 0xA77F, + 0xA780, + 0xA781, + 0xA782, + 0xA783, + 0xA784, + 0xA785, + 0xA786, + 0xA787, + 0xA78B, + 0xA78C, + 0xA78D, + 0xA78E, + 0xA790, + 0xA791, + 0xA792, + 0xA793, + 0xA796, + 0xA797, + 0xA798, + 0xA799, + 0xA79A, + 0xA79B, + 0xA79C, + 0xA79D, + 0xA79E, + 0xA79F, + 0xA7A0, + 0xA7A1, + 0xA7A2, + 0xA7A3, + 0xA7A4, + 0xA7A5, + 0xA7A6, + 0xA7A7, + 0xA7A8, + 0xA7A9, + 0xA7AA, + 0xA7AB, + 0xA7AC, + 0xA7AD, + 0xA7AE, + 0xA7AF, + 0xA7B0, + 0xA7B1, + 0xA7B2, + 0xA7B3, + 0xA7B4, + 0xA7B5, + 0xA7B6, + 0xA7B7, + 0xA7B8, + 0xA7B9, + 0xA7BA, + 0xA7BB, + 0xA7BC, + 0xA7BD, + 0xA7BE, + 0xA7BF, + 0xA7C0, + 0xA7C1, + 0xA7C2, + 0xA7C3, + 0xA7C4, + 0xA7C5, + 0xA7C6, + 0xA7C7, + 0xA7C8, + 0xA7C9, + 0xA7CA, + 0xA7CB, + 0xA7CC, + 0xA7CD, + 0xA7CE, + 0xA7CF, + 0xA7D0, + 0xA7D1, + 0xA7D2, + 0xA7D3, + 0xA7D4, + 0xA7D5, + 0xA7D6, + 0xA7D7, + 0xA7D8, + 0xA7D9, + 0xA7DA, + 0xA7DB, + 0xA7DC, + 0xA7DD, + 0xA7DE, + 0xA7E2, + 0xA7E3, + 0xA7F1, + 0xA7F2, + 0xA7F3, + 0xA7F4, + 0xA7F5, + 0xA7F6, + 0xA7F8, + 0xA7F9, + 0xA7FA, + 0xA82D, + 0xA830, + 0xA83A, + 0xA840, + 0xA878, + 0xA880, + 0xA8C6, + 0xA8CE, + 0xA8DA, + 0xA8E0, + 0xA954, + 0xA95F, + 0xA97D, + 0xA980, + 0xA9CE, + 0xA9CF, + 0xA9DA, + 0xA9DE, + 0xA9FF, + 0xAA00, + 0xAA37, + 0xAA40, + 0xAA4E, + 0xAA50, + 0xAA5A, + 0xAA5C, + 0xAAC3, + 0xAADB, + 0xAAF7, + 0xAB01, + 0xAB07, + 0xAB09, + 0xAB0F, + 0xAB11, + 0xAB17, + 0xAB20, + 0xAB27, + 0xAB28, + 0xAB2F, + 0xAB30, + 0xAB5C, + 0xAB5D, + 0xAB5E, + 0xAB5F, + 0xAB60, + 0xAB69, + 0xAB6A, + 0xAB6C, + 0xAB6D, + 0xAB6E, + 0xAB70, + 0xAB71, + 0xAB72, + 0xAB73, + 0xAB74, + 0xAB75, + 0xAB76, + 0xAB77, + 0xAB78, + 0xAB79, + 0xAB7A, + 0xAB7B, + 0xAB7C, + 0xAB7D, + 0xAB7E, + 0xAB7F, + 0xAB80, + 0xAB81, + 0xAB82, + 0xAB83, + 0xAB84, + 0xAB85, + 0xAB86, + 0xAB87, + 0xAB88, + 0xAB89, + 0xAB8A, + 0xAB8B, + 0xAB8C, + 0xAB8D, + 0xAB8E, + 0xAB8F, + 0xAB90, + 0xAB91, + 0xAB92, + 0xAB93, + 0xAB94, + 0xAB95, + 0xAB96, + 0xAB97, + 0xAB98, + 0xAB99, + 0xAB9A, + 0xAB9B, + 0xAB9C, + 0xAB9D, + 0xAB9E, + 0xAB9F, + 0xABA0, + 0xABA1, + 0xABA2, + 0xABA3, + 0xABA4, + 0xABA5, + 0xABA6, + 0xABA7, + 0xABA8, + 0xABA9, + 0xABAA, + 0xABAB, + 0xABAC, + 0xABAD, + 0xABAE, + 0xABAF, + 0xABB0, + 0xABB1, + 0xABB2, + 0xABB3, + 0xABB4, + 0xABB5, + 0xABB6, + 0xABB7, + 0xABB8, + 0xABB9, + 0xABBA, + 0xABBB, + 0xABBC, + 0xABBD, + 0xABBE, + 0xABBF, + 0xABC0, + 0xABEE, + 0xABF0, + 0xABFA, + 0xAC00, + 0xD7A4, + 0xD7B0, + 0xD7C7, + 0xD7CB, + 0xD7FC, + 0xF900, + 0xF901, + 0xF902, + 0xF903, + 0xF904, + 0xF905, + 0xF906, + 0xF907, + 0xF909, + 0xF90A, + 0xF90B, + 0xF90C, + 0xF90D, + 0xF90E, + 0xF90F, + 0xF910, + 0xF911, + 0xF912, + 0xF913, + 0xF914, + 0xF915, + 0xF916, + 0xF917, + 0xF918, + 0xF919, + 0xF91A, + 0xF91B, + 0xF91C, + 0xF91D, + 0xF91E, + 0xF91F, + 0xF920, + 0xF921, + 0xF922, + 0xF923, + 0xF924, + 0xF925, + 0xF926, + 0xF927, + 0xF928, + 0xF929, + 0xF92A, + 0xF92B, + 0xF92C, + 0xF92D, + 0xF92E, + 0xF92F, + 0xF930, + 0xF931, + 0xF932, + 0xF933, + 0xF934, + 0xF935, + 0xF936, + 0xF937, + 0xF938, + 0xF939, + 0xF93A, + 0xF93B, + 0xF93C, + 0xF93D, + 0xF93E, + 0xF93F, + 0xF940, + 0xF941, + 0xF942, + 0xF943, + 0xF944, + 0xF945, + 0xF946, + 0xF947, + 0xF948, + 0xF949, + 0xF94A, + 0xF94B, + 0xF94C, + 0xF94D, + 0xF94E, + 0xF94F, + 0xF950, + 0xF951, + 0xF952, + 0xF953, + 0xF954, + 0xF955, + 0xF956, + 0xF957, + 0xF958, + 0xF959, + 0xF95A, + 0xF95B, + 0xF95C, + 0xF95D, + 0xF95E, + 0xF95F, + 0xF960, + 0xF961, + 0xF962, + 0xF963, + 0xF964, + 0xF965, + 0xF966, + 0xF967, + 0xF968, + 0xF969, + 0xF96A, + 0xF96B, + 0xF96C, + 0xF96D, + 0xF96E, + 0xF96F, + 0xF970, + 0xF971, + 0xF972, + 0xF973, + 0xF974, + 0xF975, + 0xF976, + 0xF977, + 0xF978, + 0xF979, + 0xF97A, + 0xF97B, + 0xF97C, + 0xF97D, + 0xF97E, + 0xF97F, + 0xF980, + 0xF981, + 0xF982, + 0xF983, + 0xF984, + 0xF985, + 0xF986, + 0xF987, + 0xF988, + 0xF989, + 0xF98A, + 0xF98B, + 0xF98C, + 0xF98D, + 0xF98E, + 0xF98F, + 0xF990, + 0xF991, + 0xF992, + 0xF993, + 0xF994, + 0xF995, + 0xF996, + 0xF997, + 0xF998, + 0xF999, + 0xF99A, + 0xF99B, + 0xF99C, + 0xF99D, + 0xF99E, + 0xF99F, + 0xF9A0, + 0xF9A1, + 0xF9A2, + 0xF9A3, + 0xF9A4, + 0xF9A5, + 0xF9A6, + 0xF9A7, + 0xF9A8, + 0xF9A9, + 0xF9AA, + 0xF9AB, + 0xF9AC, + 0xF9AD, + 0xF9AE, + 0xF9AF, + 0xF9B0, + 0xF9B1, + 0xF9B2, + 0xF9B3, + 0xF9B4, + 0xF9B5, + 0xF9B6, + 0xF9B7, + 0xF9B8, + 0xF9B9, + 0xF9BA, + 0xF9BB, + 0xF9BC, + 0xF9BD, + 0xF9BE, + 0xF9BF, + 0xF9C0, + 0xF9C1, + 0xF9C2, + 0xF9C3, + 0xF9C4, + 0xF9C5, + 0xF9C6, + 0xF9C7, + 0xF9C8, + 0xF9C9, + 0xF9CA, + 0xF9CB, + 0xF9CC, + 0xF9CD, + 0xF9CE, + 0xF9CF, + 0xF9D0, + 0xF9D1, + 0xF9D2, + 0xF9D3, + 0xF9D4, + 0xF9D5, + 0xF9D6, + 0xF9D7, + 0xF9D8, + 0xF9D9, + 0xF9DA, + 0xF9DB, + 0xF9DC, + 0xF9DD, + 0xF9DE, + 0xF9DF, + 0xF9E0, + 0xF9E1, + 0xF9E2, + 0xF9E3, + 0xF9E4, + 0xF9E5, + 0xF9E6, + 0xF9E7, + 0xF9E8, + 0xF9E9, + 0xF9EA, + 0xF9EB, + 0xF9EC, + 0xF9ED, + 0xF9EE, + 0xF9EF, + 0xF9F0, + 0xF9F1, + 0xF9F2, + 0xF9F3, + 0xF9F4, + 0xF9F5, + 0xF9F6, + 0xF9F7, + 0xF9F8, + 0xF9F9, + 0xF9FA, + 0xF9FB, + 0xF9FC, + 0xF9FD, + 0xF9FE, + 0xF9FF, + 0xFA00, + 0xFA01, + 0xFA02, + 0xFA03, + 0xFA04, + 0xFA05, + 0xFA06, + 0xFA07, + 0xFA08, + 0xFA09, + 0xFA0A, + 0xFA0B, + 0xFA0C, + 0xFA0D, + 0xFA0E, + 0xFA10, + 0xFA11, + 0xFA12, + 0xFA13, + 0xFA15, + 0xFA16, + 0xFA17, + 0xFA18, + 0xFA19, + 0xFA1A, + 0xFA1B, + 0xFA1C, + 0xFA1D, + 0xFA1E, + 0xFA1F, + 0xFA20, + 0xFA21, + 0xFA22, + 0xFA23, + 0xFA25, + 0xFA26, + 0xFA27, + 0xFA2A, + 0xFA2B, + 0xFA2C, + 0xFA2D, + 0xFA2E, + 0xFA2F, + 0xFA30, + 0xFA31, + 0xFA32, + 0xFA33, + 0xFA34, + 0xFA35, + 0xFA36, + 0xFA37, + 0xFA38, + 0xFA39, + 0xFA3A, + 0xFA3B, + 0xFA3C, + 0xFA3D, + 0xFA3E, + 0xFA3F, + 0xFA40, + 0xFA41, + 0xFA42, + 0xFA43, + 0xFA44, + 0xFA45, + 0xFA46, + 0xFA47, + 0xFA48, + 0xFA49, + 0xFA4A, + 0xFA4B, + 0xFA4C, + 0xFA4D, + 0xFA4E, + 0xFA4F, + 0xFA50, + 0xFA51, + 0xFA52, + 0xFA53, + 0xFA54, + 0xFA55, + 0xFA56, + 0xFA57, + 0xFA58, + 0xFA59, + 0xFA5A, + 0xFA5B, + 0xFA5C, + 0xFA5D, + 0xFA5F, + 0xFA60, + 0xFA61, + 0xFA62, + 0xFA63, + 0xFA64, + 0xFA65, + 0xFA66, + 0xFA67, + 0xFA68, + 0xFA69, + 0xFA6A, + 0xFA6B, + 0xFA6C, + 0xFA6D, + 0xFA6E, + 0xFA70, + 0xFA71, + 0xFA72, + 0xFA73, + 0xFA74, + 0xFA75, + 0xFA76, + 0xFA77, + 0xFA78, + 0xFA79, + 0xFA7A, + 0xFA7B, + 0xFA7C, + 0xFA7D, + 0xFA7E, + 0xFA7F, + 0xFA80, + 0xFA81, + 0xFA82, + 0xFA83, + 0xFA84, + 0xFA85, + 0xFA86, + 0xFA87, + 0xFA88, + 0xFA89, + 0xFA8A, + 0xFA8B, + 0xFA8C, + 0xFA8D, + 0xFA8E, + 0xFA8F, + 0xFA90, + 0xFA91, + 0xFA92, + 0xFA93, + 0xFA94, + 0xFA95, + 0xFA96, + 0xFA97, + 0xFA98, + 0xFA99, + 0xFA9A, + 0xFA9B, + 0xFA9C, + 0xFA9D, + 0xFA9E, + 0xFA9F, + 0xFAA0, + 0xFAA1, + 0xFAA2, + 0xFAA3, + 0xFAA4, + 0xFAA5, + 0xFAA6, + 0xFAA7, + 0xFAA8, + 0xFAA9, + 0xFAAA, + 0xFAAB, + 0xFAAC, + 0xFAAD, + 0xFAAE, + 0xFAAF, + 0xFAB0, + 0xFAB1, + 0xFAB2, + 0xFAB3, + 0xFAB4, + 0xFAB5, + 0xFAB6, + 0xFAB7, + 0xFAB8, + 0xFAB9, + 0xFABA, + 0xFABB, + 0xFABC, + 0xFABD, + 0xFABE, + 0xFABF, + 0xFAC0, + 0xFAC1, + 0xFAC2, + 0xFAC3, + 0xFAC4, + 0xFAC5, + 0xFAC6, + 0xFAC7, + 0xFAC8, + 0xFAC9, + 0xFACA, + 0xFACB, + 0xFACC, + 0xFACD, + 0xFACE, + 0xFACF, + 0xFAD0, + 0xFAD1, + 0xFAD2, + 0xFAD3, + 0xFAD4, + 0xFAD5, + 0xFAD6, + 0xFAD7, + 0xFAD8, + 0xFAD9, + 0xFADA, + 0xFB00, + 0xFB01, + 0xFB02, + 0xFB03, + 0xFB04, + 0xFB05, + 0xFB07, + 0xFB13, + 0xFB14, + 0xFB15, + 0xFB16, + 0xFB17, + 0xFB18, + 0xFB1D, + 0xFB1E, + 0xFB1F, + 0xFB20, + 0xFB21, + 0xFB22, + 0xFB23, + 0xFB24, + 0xFB25, + 0xFB26, + 0xFB27, + 0xFB28, + 0xFB29, + 0xFB2A, + 0xFB2B, + 0xFB2C, + 0xFB2D, + 0xFB2E, + 0xFB2F, + 0xFB30, + 0xFB31, + 0xFB32, + 0xFB33, + 0xFB34, + 0xFB35, + 0xFB36, + 0xFB37, + 0xFB38, + 0xFB39, + 0xFB3A, + 0xFB3B, + 0xFB3C, + 0xFB3D, + 0xFB3E, + 0xFB3F, + 0xFB40, + 0xFB41, + 0xFB42, + 0xFB43, + 0xFB44, + 0xFB45, + 0xFB46, + 0xFB47, + 0xFB48, + 0xFB49, + 0xFB4A, + 0xFB4B, + 0xFB4C, + 0xFB4D, + 0xFB4E, + 0xFB4F, + 0xFB50, + 0xFB52, + 0xFB56, + 0xFB5A, + 0xFB5E, + 0xFB62, + 0xFB66, + 0xFB6A, + 0xFB6E, + 0xFB72, + 0xFB76, + 0xFB7A, + 0xFB7E, + 0xFB82, + 0xFB84, + 0xFB86, + 0xFB88, + 0xFB8A, + 0xFB8C, + 0xFB8E, + 0xFB92, + 0xFB96, + 0xFB9A, + 0xFB9E, + 0xFBA0, + 0xFBA4, + 0xFBA6, + 0xFBAA, + 0xFBAE, + 0xFBB0, + 0xFBB2, + 0xFBD3, + 0xFBD7, + 0xFBD9, + 0xFBDB, + 0xFBDD, + 0xFBDE, + 0xFBE0, + 0xFBE2, + 0xFBE4, + 0xFBE8, + 0xFBEA, + 0xFBEC, + 0xFBEE, + 0xFBF0, + 0xFBF2, + 0xFBF4, + 0xFBF6, + 0xFBF9, + 0xFBFC, + 0xFC00, + 0xFC01, + 0xFC02, + 0xFC03, + 0xFC04, + 0xFC05, + 0xFC06, + 0xFC07, + 0xFC08, + 0xFC09, + 0xFC0A, + 0xFC0B, + 0xFC0C, + 0xFC0D, + 0xFC0E, + 0xFC0F, + 0xFC10, + 0xFC11, + 0xFC12, + 0xFC13, + 0xFC14, + 0xFC15, + 0xFC16, + 0xFC17, + 0xFC18, + 0xFC19, + 0xFC1A, + 0xFC1B, + 0xFC1C, + 0xFC1D, + 0xFC1E, + 0xFC1F, + 0xFC20, + 0xFC21, + 0xFC22, + 0xFC23, + 0xFC24, + 0xFC25, + 0xFC26, + 0xFC27, + 0xFC28, + 0xFC29, + 0xFC2A, + 0xFC2B, + 0xFC2C, + 0xFC2D, + 0xFC2E, + 0xFC2F, + 0xFC30, + 0xFC31, + 0xFC32, + 0xFC33, + 0xFC34, + 0xFC35, + 0xFC36, + 0xFC37, + 0xFC38, + 0xFC39, + 0xFC3A, + 0xFC3B, + 0xFC3C, + 0xFC3D, + 0xFC3E, + 0xFC3F, + 0xFC40, + 0xFC41, + 0xFC42, + 0xFC43, + 0xFC44, + 0xFC45, + 0xFC46, + 0xFC47, + 0xFC48, + 0xFC49, + 0xFC4A, + 0xFC4B, + 0xFC4C, + 0xFC4D, + 0xFC4E, + 0xFC4F, + 0xFC50, + 0xFC51, + 0xFC52, + 0xFC53, + 0xFC54, + 0xFC55, + 0xFC56, + 0xFC57, + 0xFC58, + 0xFC59, + 0xFC5A, + 0xFC5B, + 0xFC5C, + 0xFC5D, + 0xFC5E, + 0xFC5F, + 0xFC60, + 0xFC61, + 0xFC62, + 0xFC63, + 0xFC64, + 0xFC65, + 0xFC66, + 0xFC67, + 0xFC68, + 0xFC69, + 0xFC6A, + 0xFC6B, + 0xFC6C, + 0xFC6D, + 0xFC6E, + 0xFC6F, + 0xFC70, + 0xFC71, + 0xFC72, + 0xFC73, + 0xFC74, + 0xFC75, + 0xFC76, + 0xFC77, + 0xFC78, + 0xFC79, + 0xFC7A, + 0xFC7B, + 0xFC7C, + 0xFC7D, + 0xFC7E, + 0xFC7F, + 0xFC80, + 0xFC81, + 0xFC82, + 0xFC83, + 0xFC84, + 0xFC85, + 0xFC86, + 0xFC87, + 0xFC88, + 0xFC89, + 0xFC8A, + 0xFC8B, + 0xFC8C, + 0xFC8D, + 0xFC8E, + 0xFC8F, + 0xFC90, + 0xFC91, + 0xFC92, + 0xFC93, + 0xFC94, + 0xFC95, + 0xFC96, + 0xFC97, + 0xFC98, + 0xFC99, + 0xFC9A, + 0xFC9B, + 0xFC9C, + 0xFC9D, + 0xFC9E, + 0xFC9F, + 0xFCA0, + 0xFCA1, + 0xFCA2, + 0xFCA3, + 0xFCA4, + 0xFCA5, + 0xFCA6, + 0xFCA7, + 0xFCA8, + 0xFCA9, + 0xFCAA, + 0xFCAB, + 0xFCAC, + 0xFCAD, + 0xFCAE, + 0xFCAF, + 0xFCB0, + 0xFCB1, + 0xFCB2, + 0xFCB3, + 0xFCB4, + 0xFCB5, + 0xFCB6, + 0xFCB7, + 0xFCB8, + 0xFCB9, + 0xFCBA, + 0xFCBB, + 0xFCBC, + 0xFCBD, + 0xFCBE, + 0xFCBF, + 0xFCC0, + 0xFCC1, + 0xFCC2, + 0xFCC3, + 0xFCC4, + 0xFCC5, + 0xFCC6, + 0xFCC7, + 0xFCC8, + 0xFCC9, + 0xFCCA, + 0xFCCB, + 0xFCCC, + 0xFCCD, + 0xFCCE, + 0xFCCF, + 0xFCD0, + 0xFCD1, + 0xFCD2, + 0xFCD3, + 0xFCD4, + 0xFCD5, + 0xFCD6, + 0xFCD7, + 0xFCD8, + 0xFCD9, + 0xFCDA, + 0xFCDB, + 0xFCDC, + 0xFCDD, + 0xFCDE, + 0xFCDF, + 0xFCE0, + 0xFCE1, + 0xFCE2, + 0xFCE3, + 0xFCE4, + 0xFCE5, + 0xFCE6, + 0xFCE7, + 0xFCE8, + 0xFCE9, + 0xFCEA, + 0xFCEB, + 0xFCEC, + 0xFCED, + 0xFCEE, + 0xFCEF, + 0xFCF0, + 0xFCF1, + 0xFCF2, + 0xFCF3, + 0xFCF4, + 0xFCF5, + 0xFCF6, + 0xFCF7, + 0xFCF8, + 0xFCF9, + 0xFCFA, + 0xFCFB, + 0xFCFC, + 0xFCFD, + 0xFCFE, + 0xFCFF, + 0xFD00, + 0xFD01, + 0xFD02, + 0xFD03, + 0xFD04, + 0xFD05, + 0xFD06, + 0xFD07, + 0xFD08, + 0xFD09, + 0xFD0A, + 0xFD0B, + 0xFD0C, + 0xFD0D, + 0xFD0E, + 0xFD0F, + 0xFD10, + 0xFD11, + 0xFD12, + 0xFD13, + 0xFD14, + 0xFD15, + 0xFD16, + 0xFD17, + 0xFD18, + 0xFD19, + 0xFD1A, + 0xFD1B, + 0xFD1C, + 0xFD1D, + 0xFD1E, + 0xFD1F, + 0xFD20, + 0xFD21, + 0xFD22, + 0xFD23, + 0xFD24, + 0xFD25, + 0xFD26, + 0xFD27, + 0xFD28, + 0xFD29, + 0xFD2A, + 0xFD2B, + 0xFD2C, + 0xFD2D, + 0xFD2E, + 0xFD2F, + 0xFD30, + 0xFD31, + 0xFD32, + 0xFD33, + 0xFD34, + 0xFD35, + 0xFD36, + 0xFD37, + 0xFD38, + 0xFD39, + 0xFD3A, + 0xFD3B, + 0xFD3C, + 0xFD3E, + 0xFD50, + 0xFD51, + 0xFD53, + 0xFD54, + 0xFD55, + 0xFD56, + 0xFD57, + 0xFD58, + 0xFD5A, + 0xFD5B, + 0xFD5C, + 0xFD5D, + 0xFD5E, + 0xFD5F, + 0xFD61, + 0xFD62, + 0xFD64, + 0xFD66, + 0xFD67, + 0xFD69, + 0xFD6A, + 0xFD6C, + 0xFD6E, + 0xFD6F, + 0xFD71, + 0xFD73, + 0xFD74, + 0xFD75, + 0xFD76, + 0xFD78, + 0xFD79, + 0xFD7A, + 0xFD7B, + 0xFD7C, + 0xFD7E, + 0xFD7F, + 0xFD80, + 0xFD81, + 0xFD82, + 0xFD83, + 0xFD85, + 0xFD87, + 0xFD89, + 0xFD8A, + 0xFD8B, + 0xFD8C, + 0xFD8D, + 0xFD8E, + 0xFD8F, + 0xFD90, + 0xFD92, + 0xFD93, + 0xFD94, + 0xFD95, + 0xFD96, + 0xFD97, + 0xFD99, + 0xFD9A, + 0xFD9B, + 0xFD9C, + 0xFD9E, + 0xFD9F, + 0xFDA0, + 0xFDA1, + 0xFDA2, + 0xFDA3, + 0xFDA4, + 0xFDA5, + 0xFDA6, + 0xFDA7, + 0xFDA8, + 0xFDA9, + 0xFDAA, + 0xFDAB, + 0xFDAC, + 0xFDAD, + 0xFDAE, + 0xFDAF, + 0xFDB0, + 0xFDB1, + 0xFDB2, + 0xFDB3, + 0xFDB4, + 0xFDB5, + 0xFDB6, + 0xFDB7, + 0xFDB8, + 0xFDB9, + 0xFDBA, + 0xFDBB, + 0xFDBC, + 0xFDBD, + 0xFDBE, + 0xFDBF, + 0xFDC0, + 0xFDC1, + 0xFDC2, + 0xFDC3, + 0xFDC4, + 0xFDC5, + 0xFDC6, + 0xFDC7, + 0xFDC8, + 0xFDD0, + 0xFDF0, + 0xFDF1, + 0xFDF2, + 0xFDF3, + 0xFDF4, + 0xFDF5, + 0xFDF6, + 0xFDF7, + 0xFDF8, + 0xFDF9, + 0xFDFA, + 0xFDFB, + 0xFDFC, + 0xFDFD, + 0xFE00, + 0xFE10, + 0xFE11, + 0xFE12, + 0xFE13, + 0xFE14, + 0xFE15, + 0xFE16, + 0xFE17, + 0xFE18, + 0xFE19, + 0xFE20, + 0xFE30, + 0xFE31, + 0xFE32, + 0xFE33, + 0xFE35, + 0xFE36, + 0xFE37, + 0xFE38, + 0xFE39, + 0xFE3A, + 0xFE3B, + 0xFE3C, + 0xFE3D, + 0xFE3E, + 0xFE3F, + 0xFE40, + 0xFE41, + 0xFE42, + 0xFE43, + 0xFE44, + 0xFE45, + 0xFE47, + 0xFE48, + 0xFE49, + 0xFE4D, + 0xFE50, + 0xFE51, + 0xFE52, + 0xFE54, + 0xFE55, + 0xFE56, + 0xFE57, + 0xFE58, + 0xFE59, + 0xFE5A, + 0xFE5B, + 0xFE5C, + 0xFE5D, + 0xFE5E, + 0xFE5F, + 0xFE60, + 0xFE61, + 0xFE62, + 0xFE63, + 0xFE64, + 0xFE65, + 0xFE66, + 0xFE67, + 0xFE68, + 0xFE69, + 0xFE6A, + 0xFE6B, + 0xFE6C, + 0xFE70, + 0xFE71, + 0xFE72, + 0xFE73, + 0xFE74, + 0xFE75, + 0xFE76, + 0xFE77, + 0xFE78, + 0xFE79, + 0xFE7A, + 0xFE7B, + 0xFE7C, + 0xFE7D, + 0xFE7E, + 0xFE7F, + 0xFE80, + 0xFE81, + 0xFE83, + 0xFE85, + 0xFE87, + 0xFE89, + 0xFE8D, + 0xFE8F, + 0xFE93, + 0xFE95, + 0xFE99, + 0xFE9D, + 0xFEA1, + 0xFEA5, + 0xFEA9, + 0xFEAB, + 0xFEAD, + 0xFEAF, + 0xFEB1, + 0xFEB5, + 0xFEB9, + 0xFEBD, + 0xFEC1, + 0xFEC5, + 0xFEC9, + 0xFECD, + 0xFED1, + 0xFED5, + 0xFED9, + 0xFEDD, + 0xFEE1, + 0xFEE5, + 0xFEE9, + 0xFEED, + 0xFEEF, + 0xFEF1, + 0xFEF5, + 0xFEF7, + 0xFEF9, + 0xFEFB, + 0xFEFD, + 0xFEFF, + 0xFF00, + 0xFF01, + 0xFF02, + 0xFF03, + 0xFF04, + 0xFF05, + 0xFF06, + 0xFF07, + 0xFF08, + 0xFF09, + 0xFF0A, + 0xFF0B, + 0xFF0C, + 0xFF0D, + 0xFF0E, + 0xFF0F, + 0xFF10, + 0xFF11, + 0xFF12, + 0xFF13, + 0xFF14, + 0xFF15, + 0xFF16, + 0xFF17, + 0xFF18, + 0xFF19, + 0xFF1A, + 0xFF1B, + 0xFF1C, + 0xFF1D, + 0xFF1E, + 0xFF1F, + 0xFF20, + 0xFF21, + 0xFF22, + 0xFF23, + 0xFF24, + 0xFF25, + 0xFF26, + 0xFF27, + 0xFF28, + 0xFF29, + 0xFF2A, + 0xFF2B, + 0xFF2C, + 0xFF2D, + 0xFF2E, + 0xFF2F, + 0xFF30, + 0xFF31, + 0xFF32, + 0xFF33, + 0xFF34, + 0xFF35, + 0xFF36, + 0xFF37, + 0xFF38, + 0xFF39, + 0xFF3A, + 0xFF3B, + 0xFF3C, + 0xFF3D, + 0xFF3E, + 0xFF3F, + 0xFF40, + 0xFF41, + 0xFF42, + 0xFF43, + 0xFF44, + 0xFF45, + 0xFF46, + 0xFF47, + 0xFF48, + 0xFF49, + 0xFF4A, + 0xFF4B, + 0xFF4C, + 0xFF4D, + 0xFF4E, + 0xFF4F, + 0xFF50, + 0xFF51, + 0xFF52, + 0xFF53, + 0xFF54, + 0xFF55, + 0xFF56, + 0xFF57, + 0xFF58, + 0xFF59, + 0xFF5A, + 0xFF5B, + 0xFF5C, + 0xFF5D, + 0xFF5E, + 0xFF5F, + 0xFF60, + 0xFF61, + 0xFF62, + 0xFF63, + 0xFF64, + 0xFF65, + 0xFF66, + 0xFF67, + 0xFF68, + 0xFF69, + 0xFF6A, + 0xFF6B, + 0xFF6C, + 0xFF6D, + 0xFF6E, + 0xFF6F, + 0xFF70, + 0xFF71, + 0xFF72, + 0xFF73, + 0xFF74, + 0xFF75, + 0xFF76, + 0xFF77, + 0xFF78, + 0xFF79, + 0xFF7A, + 0xFF7B, + 0xFF7C, + 0xFF7D, + 0xFF7E, + 0xFF7F, + 0xFF80, + 0xFF81, + 0xFF82, + 0xFF83, + 0xFF84, + 0xFF85, + 0xFF86, + 0xFF87, + 0xFF88, + 0xFF89, + 0xFF8A, + 0xFF8B, + 0xFF8C, + 0xFF8D, + 0xFF8E, + 0xFF8F, + 0xFF90, + 0xFF91, + 0xFF92, + 0xFF93, + 0xFF94, + 0xFF95, + 0xFF96, + 0xFF97, + 0xFF98, + 0xFF99, + 0xFF9A, + 0xFF9B, + 0xFF9C, + 0xFF9D, + 0xFF9E, + 0xFF9F, + 0xFFA0, + 0xFFA1, + 0xFFA2, + 0xFFA3, + 0xFFA4, + 0xFFA5, + 0xFFA6, + 0xFFA7, + 0xFFA8, + 0xFFA9, + 0xFFAA, + 0xFFAB, + 0xFFAC, + 0xFFAD, + 0xFFAE, + 0xFFAF, + 0xFFB0, + 0xFFB1, + 0xFFB2, + 0xFFB3, + 0xFFB4, + 0xFFB5, + 0xFFB6, + 0xFFB7, + 0xFFB8, + 0xFFB9, + 0xFFBA, + 0xFFBB, + 0xFFBC, + 0xFFBD, + 0xFFBE, + 0xFFBF, + 0xFFC2, + 0xFFC3, + 0xFFC4, + 0xFFC5, + 0xFFC6, + 0xFFC7, + 0xFFC8, + 0xFFCA, + 0xFFCB, + 0xFFCC, + 0xFFCD, + 0xFFCE, + 0xFFCF, + 0xFFD0, + 0xFFD2, + 0xFFD3, + 0xFFD4, + 0xFFD5, + 0xFFD6, + 0xFFD7, + 0xFFD8, + 0xFFDA, + 0xFFDB, + 0xFFDC, + 0xFFDD, + 0xFFE0, + 0xFFE1, + 0xFFE2, + 0xFFE3, + 0xFFE4, + 0xFFE5, + 0xFFE6, + 0xFFE7, + 0xFFE8, + 0xFFE9, + 0xFFEA, + 0xFFEB, + 0xFFEC, + 0xFFED, + 0xFFEE, + 0xFFEF, + 0x10000, + 0x1000C, + 0x1000D, + 0x10027, + 0x10028, + 0x1003B, + 0x1003C, + 0x1003E, + 0x1003F, + 0x1004E, + 0x10050, + 0x1005E, + 0x10080, + 0x100FB, + 0x10100, + 0x10103, + 0x10107, + 0x10134, + 0x10137, + 0x1018F, + 0x10190, + 0x1019D, + 0x101A0, + 0x101A1, + 0x101D0, + 0x101FE, + 0x10280, + 0x1029D, + 0x102A0, + 0x102D1, + 0x102E0, + 0x102FC, + 0x10300, + 0x10324, + 0x1032D, + 0x1034B, + 0x10350, + 0x1037B, + 0x10380, + 0x1039E, + 0x1039F, + 0x103C4, + 0x103C8, + 0x103D6, + 0x10400, + 0x10401, + 0x10402, + 0x10403, + 0x10404, + 0x10405, + 0x10406, + 0x10407, + 0x10408, + 0x10409, + 0x1040A, + 0x1040B, + 0x1040C, + 0x1040D, + 0x1040E, + 0x1040F, + 0x10410, + 0x10411, + 0x10412, + 0x10413, + 0x10414, + 0x10415, + 0x10416, + 0x10417, + 0x10418, + 0x10419, + 0x1041A, + 0x1041B, + 0x1041C, + 0x1041D, + 0x1041E, + 0x1041F, + 0x10420, + 0x10421, + 0x10422, + 0x10423, + 0x10424, + 0x10425, + 0x10426, + 0x10427, + 0x10428, + 0x1049E, + 0x104A0, + 0x104AA, + 0x104B0, + 0x104B1, + 0x104B2, + 0x104B3, + 0x104B4, + 0x104B5, + 0x104B6, + 0x104B7, + 0x104B8, + 0x104B9, + 0x104BA, + 0x104BB, + 0x104BC, + 0x104BD, + 0x104BE, + 0x104BF, + 0x104C0, + 0x104C1, + 0x104C2, + 0x104C3, + 0x104C4, + 0x104C5, + 0x104C6, + 0x104C7, + 0x104C8, + 0x104C9, + 0x104CA, + 0x104CB, + 0x104CC, + 0x104CD, + 0x104CE, + 0x104CF, + 0x104D0, + 0x104D1, + 0x104D2, + 0x104D3, + 0x104D4, + 0x104D8, + 0x104FC, + 0x10500, + 0x10528, + 0x10530, + 0x10564, + 0x1056F, + 0x10570, + 0x10571, + 0x10572, + 0x10573, + 0x10574, + 0x10575, + 0x10576, + 0x10577, + 0x10578, + 0x10579, + 0x1057A, + 0x1057B, + 0x1057C, + 0x1057D, + 0x1057E, + 0x1057F, + 0x10580, + 0x10581, + 0x10582, + 0x10583, + 0x10584, + 0x10585, + 0x10586, + 0x10587, + 0x10588, + 0x10589, + 0x1058A, + 0x1058B, + 0x1058C, + 0x1058D, + 0x1058E, + 0x1058F, + 0x10590, + 0x10591, + 0x10592, + 0x10593, + 0x10594, + 0x10595, + 0x10596, + 0x10597, + 0x105A2, + 0x105A3, + 0x105B2, + 0x105B3, + 0x105BA, + 0x105BB, + 0x105BD, + 0x105C0, + 0x105F4, + 0x10600, + 0x10737, + 0x10740, + 0x10756, + 0x10760, + 0x10768, + 0x10780, + 0x10781, + 0x10782, + 0x10783, + 0x10784, + 0x10785, + 0x10786, + 0x10787, + 0x10788, + 0x10789, + 0x1078A, + 0x1078B, + 0x1078C, + 0x1078D, + 0x1078E, + 0x1078F, + 0x10790, + 0x10791, + 0x10792, + 0x10793, + 0x10794, + 0x10795, + 0x10796, + 0x10797, + 0x10798, + 0x10799, + 0x1079A, + 0x1079B, + 0x1079C, + 0x1079D, + 0x1079E, + 0x1079F, + 0x107A0, + 0x107A1, + 0x107A2, + 0x107A3, + 0x107A4, + 0x107A5, + 0x107A6, + 0x107A7, + 0x107A8, + 0x107A9, + 0x107AA, + 0x107AB, + 0x107AC, + 0x107AD, + 0x107AE, + 0x107AF, + 0x107B0, + 0x107B1, + 0x107B2, + 0x107B3, + 0x107B4, + 0x107B5, + 0x107B6, + 0x107B7, + 0x107B8, + 0x107B9, + 0x107BA, + 0x107BB, + 0x107BC, + 0x107BD, + 0x107BE, + 0x107BF, + 0x107C0, + 0x10800, + 0x10806, + 0x10808, + 0x10809, + 0x1080A, + 0x10836, + 0x10837, + 0x10839, + 0x1083C, + 0x1083D, + 0x1083F, + 0x10856, + 0x10857, + 0x1089F, + 0x108A7, + 0x108B0, + 0x108E0, + 0x108F3, + 0x108F4, + 0x108F6, + 0x108FB, + 0x1091C, + 0x1091F, + 0x1093A, + 0x1093F, + 0x1095A, + 0x10980, + 0x109B8, + 0x109BC, + 0x109D0, + 0x109D2, + 0x10A04, + 0x10A05, + 0x10A07, + 0x10A0C, + 0x10A14, + 0x10A15, + 0x10A18, + 0x10A19, + 0x10A36, + 0x10A38, + 0x10A3B, + 0x10A3F, + 0x10A49, + 0x10A50, + 0x10A59, + 0x10A60, + 0x10AA0, + 0x10AC0, + 0x10AE7, + 0x10AEB, + 0x10AF7, + 0x10B00, + 0x10B36, + 0x10B39, + 0x10B56, + 0x10B58, + 0x10B73, + 0x10B78, + 0x10B92, + 0x10B99, + 0x10B9D, + 0x10BA9, + 0x10BB0, + 0x10C00, + 0x10C49, + 0x10C80, + 0x10C81, + 0x10C82, + 0x10C83, + 0x10C84, + 0x10C85, + 0x10C86, + 0x10C87, + 0x10C88, + 0x10C89, + 0x10C8A, + 0x10C8B, + 0x10C8C, + 0x10C8D, + 0x10C8E, + 0x10C8F, + 0x10C90, + 0x10C91, + 0x10C92, + 0x10C93, + 0x10C94, + 0x10C95, + 0x10C96, + 0x10C97, + 0x10C98, + 0x10C99, + 0x10C9A, + 0x10C9B, + 0x10C9C, + 0x10C9D, + 0x10C9E, + 0x10C9F, + 0x10CA0, + 0x10CA1, + 0x10CA2, + 0x10CA3, + 0x10CA4, + 0x10CA5, + 0x10CA6, + 0x10CA7, + 0x10CA8, + 0x10CA9, + 0x10CAA, + 0x10CAB, + 0x10CAC, + 0x10CAD, + 0x10CAE, + 0x10CAF, + 0x10CB0, + 0x10CB1, + 0x10CB2, + 0x10CB3, + 0x10CC0, + 0x10CF3, + 0x10CFA, + 0x10D28, + 0x10D30, + 0x10D3A, + 0x10D40, + 0x10D50, + 0x10D51, + 0x10D52, + 0x10D53, + 0x10D54, + 0x10D55, + 0x10D56, + 0x10D57, + 0x10D58, + 0x10D59, + 0x10D5A, + 0x10D5B, + 0x10D5C, + 0x10D5D, + 0x10D5E, + 0x10D5F, + 0x10D60, + 0x10D61, + 0x10D62, + 0x10D63, + 0x10D64, + 0x10D65, + 0x10D66, + 0x10D69, + 0x10D86, + 0x10D8E, + 0x10D90, + 0x10E60, + 0x10E7F, + 0x10E80, + 0x10EAA, + 0x10EAB, + 0x10EAE, + 0x10EB0, + 0x10EB2, + 0x10EC2, + 0x10EC8, + 0x10EC9, + 0x10EEF, + 0x10EF0, + 0x10F28, + 0x10F30, + 0x10F5A, + 0x10F70, + 0x10F8A, + 0x10FB0, + 0x10FCC, + 0x10FE0, + 0x10FF7, + 0x11000, + 0x1104E, + 0x11052, + 0x11076, + 0x1107F, + 0x110BD, + 0x110BE, + 0x110C3, + 0x110D0, + 0x110E9, + 0x110F0, + 0x110FA, + 0x11100, + 0x11135, + 0x11136, + 0x11148, + 0x11150, + 0x11177, + 0x11180, + 0x111E0, + 0x111E1, + 0x111F5, + 0x11200, + 0x11212, + 0x11213, + 0x11242, + 0x11280, + 0x11287, + 0x11288, + 0x11289, + 0x1128A, + 0x1128E, + 0x1128F, + 0x1129E, + 0x1129F, + 0x112AA, + 0x112B0, + 0x112EB, + 0x112F0, + 0x112FA, + 0x11300, + 0x11304, + 0x11305, + 0x1130D, + 0x1130F, + 0x11311, + 0x11313, + 0x11329, + 0x1132A, + 0x11331, + 0x11332, + 0x11334, + 0x11335, + 0x1133A, + 0x1133B, + 0x11345, + 0x11347, + 0x11349, + 0x1134B, + 0x1134E, + 0x11350, + 0x11351, + 0x11357, + 0x11358, + 0x1135D, + 0x11364, + 0x11366, + 0x1136D, + 0x11370, + 0x11375, + 0x11380, + 0x1138A, + 0x1138B, + 0x1138C, + 0x1138E, + 0x1138F, + 0x11390, + 0x113B6, + 0x113B7, + 0x113C1, + 0x113C2, + 0x113C3, + 0x113C5, + 0x113C6, + 0x113C7, + 0x113CB, + 0x113CC, + 0x113D6, + 0x113D7, + 0x113D9, + 0x113E1, + 0x113E3, + 0x11400, + 0x1145C, + 0x1145D, + 0x11462, + 0x11480, + 0x114C8, + 0x114D0, + 0x114DA, + 0x11580, + 0x115B6, + 0x115B8, + 0x115DE, + 0x11600, + 0x11645, + 0x11650, + 0x1165A, + 0x11660, + 0x1166D, + 0x11680, + 0x116BA, + 0x116C0, + 0x116CA, + 0x116D0, + 0x116E4, + 0x11700, + 0x1171B, + 0x1171D, + 0x1172C, + 0x11730, + 0x11747, + 0x11800, + 0x1183C, + 0x118A0, + 0x118A1, + 0x118A2, + 0x118A3, + 0x118A4, + 0x118A5, + 0x118A6, + 0x118A7, + 0x118A8, + 0x118A9, + 0x118AA, + 0x118AB, + 0x118AC, + 0x118AD, + 0x118AE, + 0x118AF, + 0x118B0, + 0x118B1, + 0x118B2, + 0x118B3, + 0x118B4, + 0x118B5, + 0x118B6, + 0x118B7, + 0x118B8, + 0x118B9, + 0x118BA, + 0x118BB, + 0x118BC, + 0x118BD, + 0x118BE, + 0x118BF, + 0x118C0, + 0x118F3, + 0x118FF, + 0x11907, + 0x11909, + 0x1190A, + 0x1190C, + 0x11914, + 0x11915, + 0x11917, + 0x11918, + 0x11936, + 0x11937, + 0x11939, + 0x1193B, + 0x11947, + 0x11950, + 0x1195A, + 0x119A0, + 0x119A8, + 0x119AA, + 0x119D8, + 0x119DA, + 0x119E5, + 0x11A00, + 0x11A48, + 0x11A50, + 0x11AA3, + 0x11AB0, + 0x11AF9, + 0x11B00, + 0x11B0B, + 0x11B60, + 0x11B68, + 0x11BC0, + 0x11BE2, + 0x11BF0, + 0x11BFA, + 0x11C00, + 0x11C09, + 0x11C0A, + 0x11C37, + 0x11C38, + 0x11C46, + 0x11C50, + 0x11C6D, + 0x11C70, + 0x11C90, + 0x11C92, + 0x11CA8, + 0x11CA9, + 0x11CB7, + 0x11D00, + 0x11D07, + 0x11D08, + 0x11D0A, + 0x11D0B, + 0x11D37, + 0x11D3A, + 0x11D3B, + 0x11D3C, + 0x11D3E, + 0x11D3F, + 0x11D48, + 0x11D50, + 0x11D5A, + 0x11D60, + 0x11D66, + 0x11D67, + 0x11D69, + 0x11D6A, + 0x11D8F, + 0x11D90, + 0x11D92, + 0x11D93, + 0x11D99, + 0x11DA0, + 0x11DAA, + 0x11DB0, + 0x11DDC, + 0x11DE0, + 0x11DEA, + 0x11DF0, + 0x11DF2, + 0x11EE0, + 0x11EF9, + 0x11F00, + 0x11F11, + 0x11F12, + 0x11F3B, + 0x11F3E, + 0x11F5B, + 0x11FB0, + 0x11FB1, + 0x11FC0, + 0x11FF2, + 0x11FFF, + 0x1239A, + 0x12400, + 0x12544, + 0x12550, + 0x12687, + 0x12F90, + 0x12FF3, + 0x13000, + 0x13430, + 0x13440, + 0x13456, + 0x13460, + 0x143FB, + 0x14400, + 0x14647, + 0x16100, + 0x1613A, + 0x16800, + 0x16A39, + 0x16A40, + 0x16A5F, + 0x16A60, + 0x16A6A, + 0x16A6E, + 0x16ABF, + 0x16AC0, + 0x16ACA, + 0x16AD0, + 0x16AEE, + 0x16AF0, + 0x16AF6, + 0x16B00, + 0x16B46, + 0x16B50, + 0x16B5A, + 0x16B5B, + 0x16B62, + 0x16B63, + 0x16B78, + 0x16B7D, + 0x16B90, + 0x16D40, + 0x16D7A, + 0x16E40, + 0x16E41, + 0x16E42, + 0x16E43, + 0x16E44, + 0x16E45, + 0x16E46, + 0x16E47, + 0x16E48, + 0x16E49, + 0x16E4A, + 0x16E4B, + 0x16E4C, + 0x16E4D, + 0x16E4E, + 0x16E4F, + 0x16E50, + 0x16E51, + 0x16E52, + 0x16E53, + 0x16E54, + 0x16E55, + 0x16E56, + 0x16E57, + 0x16E58, + 0x16E59, + 0x16E5A, + 0x16E5B, + 0x16E5C, + 0x16E5D, + 0x16E5E, + 0x16E5F, + 0x16E60, + 0x16E9B, + 0x16EA0, + 0x16EA1, + 0x16EA2, + 0x16EA3, + 0x16EA4, + 0x16EA5, + 0x16EA6, + 0x16EA7, + 0x16EA8, + 0x16EA9, + 0x16EAA, + 0x16EAB, + 0x16EAC, + 0x16EAD, + 0x16EAE, + 0x16EAF, + 0x16EB0, + 0x16EB1, + 0x16EB2, + 0x16EB3, + 0x16EB4, + 0x16EB5, + 0x16EB6, + 0x16EB7, + 0x16EB8, + 0x16EB9, + 0x16EBB, + 0x16ED4, + 0x16F00, + 0x16F4B, + 0x16F4F, + 0x16F88, + 0x16F8F, + 0x16FA0, + 0x16FE0, + 0x16FE5, + 0x16FF0, + 0x16FF7, + 0x17000, + 0x18CDB, + 0x18CFF, + 0x18D21, + 0x18D80, + 0x18DF3, + 0x18E00, + 0x19192, + 0x191A0, + 0x191D3, + 0x1AFF0, + 0x1AFF4, + 0x1AFF5, + 0x1AFFC, + 0x1AFFD, + 0x1AFFF, + 0x1B000, + 0x1B123, + 0x1B124, + 0x1B125, + 0x1B126, + 0x1B127, + 0x1B129, + 0x1B132, + 0x1B133, + 0x1B150, + 0x1B153, + 0x1B155, + 0x1B156, + 0x1B164, + 0x1B169, + 0x1B170, + 0x1B2FC, + 0x1BC00, + 0x1BC6B, + 0x1BC70, + 0x1BC7D, + 0x1BC80, + 0x1BC89, + 0x1BC90, + 0x1BC9A, + 0x1BC9C, + 0x1BCA0, + 0x1BCA4, + 0x1CC00, + 0x1CCD6, + 0x1CCD7, + 0x1CCD8, + 0x1CCD9, + 0x1CCDA, + 0x1CCDB, + 0x1CCDC, + 0x1CCDD, + 0x1CCDE, + 0x1CCDF, + 0x1CCE0, + 0x1CCE1, + 0x1CCE2, + 0x1CCE3, + 0x1CCE4, + 0x1CCE5, + 0x1CCE6, + 0x1CCE7, + 0x1CCE8, + 0x1CCE9, + 0x1CCEA, + 0x1CCEB, + 0x1CCEC, + 0x1CCED, + 0x1CCEE, + 0x1CCEF, + 0x1CCF0, + 0x1CCF1, + 0x1CCF2, + 0x1CCF3, + 0x1CCF4, + 0x1CCF5, + 0x1CCF6, + 0x1CCF7, + 0x1CCF8, + 0x1CCF9, + 0x1CCFA, + 0x1CCFD, + 0x1CD00, + 0x1CEB4, + 0x1CEBA, + 0x1CED1, + 0x1CED2, + 0x1CED5, + 0x1CEDD, + 0x1CEFE, + 0x1CF00, + 0x1CF2E, + 0x1CF30, + 0x1CF47, + 0x1CF50, + 0x1CFC4, + 0x1D000, + 0x1D0F6, + 0x1D100, + 0x1D15E, + 0x1D15F, + 0x1D160, + 0x1D161, + 0x1D162, + 0x1D163, + 0x1D164, + 0x1D165, + 0x1D173, + 0x1D17B, + 0x1D1BB, + 0x1D1BC, + 0x1D1BD, + 0x1D1BE, + 0x1D1BF, + 0x1D1C0, + 0x1D1C1, + 0x1D246, + 0x1D250, + 0x1D282, + 0x1D2C0, + 0x1D2D4, + 0x1D2E0, + 0x1D2F4, + 0x1D300, + 0x1D357, + 0x1D360, + 0x1D379, + 0x1D400, + 0x1D401, + 0x1D402, + 0x1D403, + 0x1D404, + 0x1D405, + 0x1D406, + 0x1D407, + 0x1D408, + 0x1D409, + 0x1D40A, + 0x1D40B, + 0x1D40C, + 0x1D40D, + 0x1D40E, + 0x1D40F, + 0x1D410, + 0x1D411, + 0x1D412, + 0x1D413, + 0x1D414, + 0x1D415, + 0x1D416, + 0x1D417, + 0x1D418, + 0x1D419, + 0x1D41A, + 0x1D41B, + 0x1D41C, + 0x1D41D, + 0x1D41E, + 0x1D41F, + 0x1D420, + 0x1D421, + 0x1D422, + 0x1D423, + 0x1D424, + 0x1D425, + 0x1D426, + 0x1D427, + 0x1D428, + 0x1D429, + 0x1D42A, + 0x1D42B, + 0x1D42C, + 0x1D42D, + 0x1D42E, + 0x1D42F, + 0x1D430, + 0x1D431, + 0x1D432, + 0x1D433, + 0x1D434, + 0x1D435, + 0x1D436, + 0x1D437, + 0x1D438, + 0x1D439, + 0x1D43A, + 0x1D43B, + 0x1D43C, + 0x1D43D, + 0x1D43E, + 0x1D43F, + 0x1D440, + 0x1D441, + 0x1D442, + 0x1D443, + 0x1D444, + 0x1D445, + 0x1D446, + 0x1D447, + 0x1D448, + 0x1D449, + 0x1D44A, + 0x1D44B, + 0x1D44C, + 0x1D44D, + 0x1D44E, + 0x1D44F, + 0x1D450, + 0x1D451, + 0x1D452, + 0x1D453, + 0x1D454, + 0x1D455, + 0x1D456, + 0x1D457, + 0x1D458, + 0x1D459, + 0x1D45A, + 0x1D45B, + 0x1D45C, + 0x1D45D, + 0x1D45E, + 0x1D45F, + 0x1D460, + 0x1D461, + 0x1D462, + 0x1D463, + 0x1D464, + 0x1D465, + 0x1D466, + 0x1D467, + 0x1D468, + 0x1D469, + 0x1D46A, + 0x1D46B, + 0x1D46C, + 0x1D46D, + 0x1D46E, + 0x1D46F, + 0x1D470, + 0x1D471, + 0x1D472, + 0x1D473, + 0x1D474, + 0x1D475, + 0x1D476, + 0x1D477, + 0x1D478, + 0x1D479, + 0x1D47A, + 0x1D47B, + 0x1D47C, + 0x1D47D, + 0x1D47E, + 0x1D47F, + 0x1D480, + 0x1D481, + 0x1D482, + 0x1D483, + 0x1D484, + 0x1D485, + 0x1D486, + 0x1D487, + 0x1D488, + 0x1D489, + 0x1D48A, + 0x1D48B, + 0x1D48C, + 0x1D48D, + 0x1D48E, + 0x1D48F, + 0x1D490, + 0x1D491, + 0x1D492, + 0x1D493, + 0x1D494, + 0x1D495, + 0x1D496, + 0x1D497, + 0x1D498, + 0x1D499, + 0x1D49A, + 0x1D49B, + 0x1D49C, + 0x1D49D, + 0x1D49E, + 0x1D49F, + 0x1D4A0, + 0x1D4A2, + 0x1D4A3, + 0x1D4A5, + 0x1D4A6, + 0x1D4A7, + 0x1D4A9, + 0x1D4AA, + 0x1D4AB, + 0x1D4AC, + 0x1D4AD, + 0x1D4AE, + 0x1D4AF, + 0x1D4B0, + 0x1D4B1, + 0x1D4B2, + 0x1D4B3, + 0x1D4B4, + 0x1D4B5, + 0x1D4B6, + 0x1D4B7, + 0x1D4B8, + 0x1D4B9, + 0x1D4BA, + 0x1D4BB, + 0x1D4BC, + 0x1D4BD, + 0x1D4BE, + 0x1D4BF, + 0x1D4C0, + 0x1D4C1, + 0x1D4C2, + 0x1D4C3, + 0x1D4C4, + 0x1D4C5, + 0x1D4C6, + 0x1D4C7, + 0x1D4C8, + 0x1D4C9, + 0x1D4CA, + 0x1D4CB, + 0x1D4CC, + 0x1D4CD, + 0x1D4CE, + 0x1D4CF, + 0x1D4D0, + 0x1D4D1, + 0x1D4D2, + 0x1D4D3, + 0x1D4D4, + 0x1D4D5, + 0x1D4D6, + 0x1D4D7, + 0x1D4D8, + 0x1D4D9, + 0x1D4DA, + 0x1D4DB, + 0x1D4DC, + 0x1D4DD, + 0x1D4DE, + 0x1D4DF, + 0x1D4E0, + 0x1D4E1, + 0x1D4E2, + 0x1D4E3, + 0x1D4E4, + 0x1D4E5, + 0x1D4E6, + 0x1D4E7, + 0x1D4E8, + 0x1D4E9, + 0x1D4EA, + 0x1D4EB, + 0x1D4EC, + 0x1D4ED, + 0x1D4EE, + 0x1D4EF, + 0x1D4F0, + 0x1D4F1, + 0x1D4F2, + 0x1D4F3, + 0x1D4F4, + 0x1D4F5, + 0x1D4F6, + 0x1D4F7, + 0x1D4F8, + 0x1D4F9, + 0x1D4FA, + 0x1D4FB, + 0x1D4FC, + 0x1D4FD, + 0x1D4FE, + 0x1D4FF, + 0x1D500, + 0x1D501, + 0x1D502, + 0x1D503, + 0x1D504, + 0x1D505, + 0x1D506, + 0x1D507, + 0x1D508, + 0x1D509, + 0x1D50A, + 0x1D50B, + 0x1D50D, + 0x1D50E, + 0x1D50F, + 0x1D510, + 0x1D511, + 0x1D512, + 0x1D513, + 0x1D514, + 0x1D515, + 0x1D516, + 0x1D517, + 0x1D518, + 0x1D519, + 0x1D51A, + 0x1D51B, + 0x1D51C, + 0x1D51D, + 0x1D51E, + 0x1D51F, + 0x1D520, + 0x1D521, + 0x1D522, + 0x1D523, + 0x1D524, + 0x1D525, + 0x1D526, + 0x1D527, + 0x1D528, + 0x1D529, + 0x1D52A, + 0x1D52B, + 0x1D52C, + 0x1D52D, + 0x1D52E, + 0x1D52F, + 0x1D530, + 0x1D531, + 0x1D532, + 0x1D533, + 0x1D534, + 0x1D535, + 0x1D536, + 0x1D537, + 0x1D538, + 0x1D539, + 0x1D53A, + 0x1D53B, + 0x1D53C, + 0x1D53D, + 0x1D53E, + 0x1D53F, + 0x1D540, + 0x1D541, + 0x1D542, + 0x1D543, + 0x1D544, + 0x1D545, + 0x1D546, + 0x1D547, + 0x1D54A, + 0x1D54B, + 0x1D54C, + 0x1D54D, + 0x1D54E, + 0x1D54F, + 0x1D550, + 0x1D551, + 0x1D552, + 0x1D553, + 0x1D554, + 0x1D555, + 0x1D556, + 0x1D557, + 0x1D558, + 0x1D559, + 0x1D55A, + 0x1D55B, + 0x1D55C, + 0x1D55D, + 0x1D55E, + 0x1D55F, + 0x1D560, + 0x1D561, + 0x1D562, + 0x1D563, + 0x1D564, + 0x1D565, + 0x1D566, + 0x1D567, + 0x1D568, + 0x1D569, + 0x1D56A, + 0x1D56B, + 0x1D56C, + 0x1D56D, + 0x1D56E, + 0x1D56F, + 0x1D570, + 0x1D571, + 0x1D572, + 0x1D573, + 0x1D574, + 0x1D575, + 0x1D576, + 0x1D577, + 0x1D578, + 0x1D579, + 0x1D57A, + 0x1D57B, + 0x1D57C, + 0x1D57D, + 0x1D57E, + 0x1D57F, + 0x1D580, + 0x1D581, + 0x1D582, + 0x1D583, + 0x1D584, + 0x1D585, + 0x1D586, + 0x1D587, + 0x1D588, + 0x1D589, + 0x1D58A, + 0x1D58B, + 0x1D58C, + 0x1D58D, + 0x1D58E, + 0x1D58F, + 0x1D590, + 0x1D591, + 0x1D592, + 0x1D593, + 0x1D594, + 0x1D595, + 0x1D596, + 0x1D597, + 0x1D598, + 0x1D599, + 0x1D59A, + 0x1D59B, + 0x1D59C, + 0x1D59D, + 0x1D59E, + 0x1D59F, + 0x1D5A0, + 0x1D5A1, + 0x1D5A2, + 0x1D5A3, + 0x1D5A4, + 0x1D5A5, + 0x1D5A6, + 0x1D5A7, + 0x1D5A8, + 0x1D5A9, + 0x1D5AA, + 0x1D5AB, + 0x1D5AC, + 0x1D5AD, + 0x1D5AE, + 0x1D5AF, + 0x1D5B0, + 0x1D5B1, + 0x1D5B2, + 0x1D5B3, + 0x1D5B4, + 0x1D5B5, + 0x1D5B6, + 0x1D5B7, + 0x1D5B8, + 0x1D5B9, + 0x1D5BA, + 0x1D5BB, + 0x1D5BC, + 0x1D5BD, + 0x1D5BE, + 0x1D5BF, + 0x1D5C0, + 0x1D5C1, + 0x1D5C2, + 0x1D5C3, + 0x1D5C4, + 0x1D5C5, + 0x1D5C6, + 0x1D5C7, + 0x1D5C8, + 0x1D5C9, + 0x1D5CA, + 0x1D5CB, + 0x1D5CC, + 0x1D5CD, + 0x1D5CE, + 0x1D5CF, + 0x1D5D0, + 0x1D5D1, + 0x1D5D2, + 0x1D5D3, + 0x1D5D4, + 0x1D5D5, + 0x1D5D6, + 0x1D5D7, + 0x1D5D8, + 0x1D5D9, + 0x1D5DA, + 0x1D5DB, + 0x1D5DC, + 0x1D5DD, + 0x1D5DE, + 0x1D5DF, + 0x1D5E0, + 0x1D5E1, + 0x1D5E2, + 0x1D5E3, + 0x1D5E4, + 0x1D5E5, + 0x1D5E6, + 0x1D5E7, + 0x1D5E8, + 0x1D5E9, + 0x1D5EA, + 0x1D5EB, + 0x1D5EC, + 0x1D5ED, + 0x1D5EE, + 0x1D5EF, + 0x1D5F0, + 0x1D5F1, + 0x1D5F2, + 0x1D5F3, + 0x1D5F4, + 0x1D5F5, + 0x1D5F6, + 0x1D5F7, + 0x1D5F8, + 0x1D5F9, + 0x1D5FA, + 0x1D5FB, + 0x1D5FC, + 0x1D5FD, + 0x1D5FE, + 0x1D5FF, + 0x1D600, + 0x1D601, + 0x1D602, + 0x1D603, + 0x1D604, + 0x1D605, + 0x1D606, + 0x1D607, + 0x1D608, + 0x1D609, + 0x1D60A, + 0x1D60B, + 0x1D60C, + 0x1D60D, + 0x1D60E, + 0x1D60F, + 0x1D610, + 0x1D611, + 0x1D612, + 0x1D613, + 0x1D614, + 0x1D615, + 0x1D616, + 0x1D617, + 0x1D618, + 0x1D619, + 0x1D61A, + 0x1D61B, + 0x1D61C, + 0x1D61D, + 0x1D61E, + 0x1D61F, + 0x1D620, + 0x1D621, + 0x1D622, + 0x1D623, + 0x1D624, + 0x1D625, + 0x1D626, + 0x1D627, + 0x1D628, + 0x1D629, + 0x1D62A, + 0x1D62B, + 0x1D62C, + 0x1D62D, + 0x1D62E, + 0x1D62F, + 0x1D630, + 0x1D631, + 0x1D632, + 0x1D633, + 0x1D634, + 0x1D635, + 0x1D636, + 0x1D637, + 0x1D638, + 0x1D639, + 0x1D63A, + 0x1D63B, + 0x1D63C, + 0x1D63D, + 0x1D63E, + 0x1D63F, + 0x1D640, + 0x1D641, + 0x1D642, + 0x1D643, + 0x1D644, + 0x1D645, + 0x1D646, + 0x1D647, + 0x1D648, + 0x1D649, + 0x1D64A, + 0x1D64B, + 0x1D64C, + 0x1D64D, + 0x1D64E, + 0x1D64F, + 0x1D650, + 0x1D651, + 0x1D652, + 0x1D653, + 0x1D654, + 0x1D655, + 0x1D656, + 0x1D657, + 0x1D658, + 0x1D659, + 0x1D65A, + 0x1D65B, + 0x1D65C, + 0x1D65D, + 0x1D65E, + 0x1D65F, + 0x1D660, + 0x1D661, + 0x1D662, + 0x1D663, + 0x1D664, + 0x1D665, + 0x1D666, + 0x1D667, + 0x1D668, + 0x1D669, + 0x1D66A, + 0x1D66B, + 0x1D66C, + 0x1D66D, + 0x1D66E, + 0x1D66F, + 0x1D670, + 0x1D671, + 0x1D672, + 0x1D673, + 0x1D674, + 0x1D675, + 0x1D676, + 0x1D677, + 0x1D678, + 0x1D679, + 0x1D67A, + 0x1D67B, + 0x1D67C, + 0x1D67D, + 0x1D67E, + 0x1D67F, + 0x1D680, + 0x1D681, + 0x1D682, + 0x1D683, + 0x1D684, + 0x1D685, + 0x1D686, + 0x1D687, + 0x1D688, + 0x1D689, + 0x1D68A, + 0x1D68B, + 0x1D68C, + 0x1D68D, + 0x1D68E, + 0x1D68F, + 0x1D690, + 0x1D691, + 0x1D692, + 0x1D693, + 0x1D694, + 0x1D695, + 0x1D696, + 0x1D697, + 0x1D698, + 0x1D699, + 0x1D69A, + 0x1D69B, + 0x1D69C, + 0x1D69D, + 0x1D69E, + 0x1D69F, + 0x1D6A0, + 0x1D6A1, + 0x1D6A2, + 0x1D6A3, + 0x1D6A4, + 0x1D6A5, + 0x1D6A6, + 0x1D6A7, + 0x1D6A8, + 0x1D6A9, + 0x1D6AA, + 0x1D6AB, + 0x1D6AC, + 0x1D6AD, + 0x1D6AE, + 0x1D6AF, + 0x1D6B0, + 0x1D6B1, + 0x1D6B2, + 0x1D6B3, + 0x1D6B4, + 0x1D6B5, + 0x1D6B6, + 0x1D6B7, + 0x1D6B8, + 0x1D6B9, + 0x1D6BA, + 0x1D6BB, + 0x1D6BC, + 0x1D6BD, + 0x1D6BE, + 0x1D6BF, + 0x1D6C0, + 0x1D6C1, + 0x1D6C2, + 0x1D6C3, + 0x1D6C4, + 0x1D6C5, + 0x1D6C6, + 0x1D6C7, + 0x1D6C8, + 0x1D6C9, + 0x1D6CA, + 0x1D6CB, + 0x1D6CC, + 0x1D6CD, + 0x1D6CE, + 0x1D6CF, + 0x1D6D0, + 0x1D6D1, + 0x1D6D2, + 0x1D6D3, + 0x1D6D5, + 0x1D6D6, + 0x1D6D7, + 0x1D6D8, + 0x1D6D9, + 0x1D6DA, + 0x1D6DB, + 0x1D6DC, + 0x1D6DD, + 0x1D6DE, + 0x1D6DF, + 0x1D6E0, + 0x1D6E1, + 0x1D6E2, + 0x1D6E3, + 0x1D6E4, + 0x1D6E5, + 0x1D6E6, + 0x1D6E7, + 0x1D6E8, + 0x1D6E9, + 0x1D6EA, + 0x1D6EB, + 0x1D6EC, + 0x1D6ED, + 0x1D6EE, + 0x1D6EF, + 0x1D6F0, + 0x1D6F1, + 0x1D6F2, + 0x1D6F3, + 0x1D6F4, + 0x1D6F5, + 0x1D6F6, + 0x1D6F7, + 0x1D6F8, + 0x1D6F9, + 0x1D6FA, + 0x1D6FB, + 0x1D6FC, + 0x1D6FD, + 0x1D6FE, + 0x1D6FF, + 0x1D700, + 0x1D701, + 0x1D702, + 0x1D703, + 0x1D704, + 0x1D705, + 0x1D706, + 0x1D707, + 0x1D708, + 0x1D709, + 0x1D70A, + 0x1D70B, + 0x1D70C, + 0x1D70D, + 0x1D70F, + 0x1D710, + 0x1D711, + 0x1D712, + 0x1D713, + 0x1D714, + 0x1D715, + 0x1D716, + 0x1D717, + 0x1D718, + 0x1D719, + 0x1D71A, + 0x1D71B, + 0x1D71C, + 0x1D71D, + 0x1D71E, + 0x1D71F, + 0x1D720, + 0x1D721, + 0x1D722, + 0x1D723, + 0x1D724, + 0x1D725, + 0x1D726, + 0x1D727, + 0x1D728, + 0x1D729, + 0x1D72A, + 0x1D72B, + 0x1D72C, + 0x1D72D, + 0x1D72E, + 0x1D72F, + 0x1D730, + 0x1D731, + 0x1D732, + 0x1D733, + 0x1D734, + 0x1D735, + 0x1D736, + 0x1D737, + 0x1D738, + 0x1D739, + 0x1D73A, + 0x1D73B, + 0x1D73C, + 0x1D73D, + 0x1D73E, + 0x1D73F, + 0x1D740, + 0x1D741, + 0x1D742, + 0x1D743, + 0x1D744, + 0x1D745, + 0x1D746, + 0x1D747, + 0x1D749, + 0x1D74A, + 0x1D74B, + 0x1D74C, + 0x1D74D, + 0x1D74E, + 0x1D74F, + 0x1D750, + 0x1D751, + 0x1D752, + 0x1D753, + 0x1D754, + 0x1D755, + 0x1D756, + 0x1D757, + 0x1D758, + 0x1D759, + 0x1D75A, + 0x1D75B, + 0x1D75C, + 0x1D75D, + 0x1D75E, + 0x1D75F, + 0x1D760, + 0x1D761, + 0x1D762, + 0x1D763, + 0x1D764, + 0x1D765, + 0x1D766, + 0x1D767, + 0x1D768, + 0x1D769, + 0x1D76A, + 0x1D76B, + 0x1D76C, + 0x1D76D, + 0x1D76E, + 0x1D76F, + 0x1D770, + 0x1D771, + 0x1D772, + 0x1D773, + 0x1D774, + 0x1D775, + 0x1D776, + 0x1D777, + 0x1D778, + 0x1D779, + 0x1D77A, + 0x1D77B, + 0x1D77C, + 0x1D77D, + 0x1D77E, + 0x1D77F, + 0x1D780, + 0x1D781, + 0x1D783, + 0x1D784, + 0x1D785, + 0x1D786, + 0x1D787, + 0x1D788, + 0x1D789, + 0x1D78A, + 0x1D78B, + 0x1D78C, + 0x1D78D, + 0x1D78E, + 0x1D78F, + 0x1D790, + 0x1D791, + 0x1D792, + 0x1D793, + 0x1D794, + 0x1D795, + 0x1D796, + 0x1D797, + 0x1D798, + 0x1D799, + 0x1D79A, + 0x1D79B, + 0x1D79C, + 0x1D79D, + 0x1D79E, + 0x1D79F, + 0x1D7A0, + 0x1D7A1, + 0x1D7A2, + 0x1D7A3, + 0x1D7A4, + 0x1D7A5, + 0x1D7A6, + 0x1D7A7, + 0x1D7A8, + 0x1D7A9, + 0x1D7AA, + 0x1D7AB, + 0x1D7AC, + 0x1D7AD, + 0x1D7AE, + 0x1D7AF, + 0x1D7B0, + 0x1D7B1, + 0x1D7B2, + 0x1D7B3, + 0x1D7B4, + 0x1D7B5, + 0x1D7B6, + 0x1D7B7, + 0x1D7B8, + 0x1D7B9, + 0x1D7BA, + 0x1D7BB, + 0x1D7BD, + 0x1D7BE, + 0x1D7BF, + 0x1D7C0, + 0x1D7C1, + 0x1D7C2, + 0x1D7C3, + 0x1D7C4, + 0x1D7C5, + 0x1D7C6, + 0x1D7C7, + 0x1D7C8, + 0x1D7C9, + 0x1D7CA, + 0x1D7CC, + 0x1D7CE, + 0x1D7CF, + 0x1D7D0, + 0x1D7D1, + 0x1D7D2, + 0x1D7D3, + 0x1D7D4, + 0x1D7D5, + 0x1D7D6, + 0x1D7D7, + 0x1D7D8, + 0x1D7D9, + 0x1D7DA, + 0x1D7DB, + 0x1D7DC, + 0x1D7DD, + 0x1D7DE, + 0x1D7DF, + 0x1D7E0, + 0x1D7E1, + 0x1D7E2, + 0x1D7E3, + 0x1D7E4, + 0x1D7E5, + 0x1D7E6, + 0x1D7E7, + 0x1D7E8, + 0x1D7E9, + 0x1D7EA, + 0x1D7EB, + 0x1D7EC, + 0x1D7ED, + 0x1D7EE, + 0x1D7EF, + 0x1D7F0, + 0x1D7F1, + 0x1D7F2, + 0x1D7F3, + 0x1D7F4, + 0x1D7F5, + 0x1D7F6, + 0x1D7F7, + 0x1D7F8, + 0x1D7F9, + 0x1D7FA, + 0x1D7FB, + 0x1D7FC, + 0x1D7FD, + 0x1D7FE, + 0x1D7FF, + 0x1D800, + 0x1DA8C, + 0x1DA9B, + 0x1DAA0, + 0x1DAA1, + 0x1DAB0, + 0x1DB00, + 0x1DB1D, + 0x1DF00, + 0x1DF40, + 0x1DF41, + 0x1DF48, + 0x1DF49, + 0x1DF4A, + 0x1DF4B, + 0x1DF4D, + 0x1DF4E, + 0x1DF51, + 0x1DF52, + 0x1DF68, + 0x1DF69, + 0x1DF6A, + 0x1DF6B, + 0x1DF6C, + 0x1DF6D, + 0x1DF6E, + 0x1DF6F, + 0x1DF72, + 0x1DF73, + 0x1DF74, + 0x1DF75, + 0x1DF76, + 0x1DF77, + 0x1DF78, + 0x1DF79, + 0x1DF7A, + 0x1DF7B, + 0x1DF7C, + 0x1DF7D, + 0x1DF7E, + 0x1DF7F, + 0x1DF82, + 0x1DF90, + 0x1DF95, + 0x1DF96, + 0x1DF97, + 0x1DFCD, + 0x1DFCE, + 0x1DFCF, + 0x1DFD0, + 0x1DFD1, + 0x1DFD2, + 0x1DFD3, + 0x1DFD4, + 0x1DFD5, + 0x1DFD6, + 0x1DFD7, + 0x1DFD8, + 0x1DFD9, + 0x1DFDA, + 0x1DFDB, + 0x1DFDC, + 0x1DFDD, + 0x1DFDE, + 0x1DFDF, + 0x1DFE0, + 0x1DFE1, + 0x1DFE2, + 0x1DFE3, + 0x1DFE4, + 0x1DFE5, + 0x1DFE6, + 0x1DFE7, + 0x1DFE8, + 0x1DFE9, + 0x1DFEA, + 0x1DFEB, + 0x1DFEC, + 0x1DFED, + 0x1DFEE, + 0x1DFEF, + 0x1DFF0, + 0x1DFF1, + 0x1DFF2, + 0x1DFF3, + 0x1DFF4, + 0x1DFF5, + 0x1DFF6, + 0x1DFF7, + 0x1DFF8, + 0x1DFF9, + 0x1DFFA, + 0x1DFFB, + 0x1DFFC, + 0x1DFFD, + 0x1DFFE, + 0x1DFFF, + 0x1E000, + 0x1E007, + 0x1E008, + 0x1E019, + 0x1E01B, + 0x1E022, + 0x1E023, + 0x1E025, + 0x1E026, + 0x1E02B, + 0x1E030, + 0x1E031, + 0x1E032, + 0x1E033, + 0x1E034, + 0x1E035, + 0x1E036, + 0x1E037, + 0x1E038, + 0x1E039, + 0x1E03A, + 0x1E03B, + 0x1E03C, + 0x1E03D, + 0x1E03E, + 0x1E03F, + 0x1E040, + 0x1E041, + 0x1E042, + 0x1E043, + 0x1E044, + 0x1E045, + 0x1E046, + 0x1E047, + 0x1E048, + 0x1E049, + 0x1E04A, + 0x1E04B, + 0x1E04C, + 0x1E04D, + 0x1E04E, + 0x1E04F, + 0x1E050, + 0x1E051, + 0x1E052, + 0x1E053, + 0x1E054, + 0x1E055, + 0x1E056, + 0x1E057, + 0x1E058, + 0x1E059, + 0x1E05A, + 0x1E05B, + 0x1E05C, + 0x1E05D, + 0x1E05E, + 0x1E05F, + 0x1E060, + 0x1E061, + 0x1E062, + 0x1E063, + 0x1E064, + 0x1E065, + 0x1E066, + 0x1E067, + 0x1E068, + 0x1E069, + 0x1E06A, + 0x1E06B, + 0x1E06C, + 0x1E06D, + 0x1E06E, + 0x1E08F, + 0x1E090, + 0x1E100, + 0x1E12D, + 0x1E130, + 0x1E13E, + 0x1E140, + 0x1E14A, + 0x1E14E, + 0x1E150, + 0x1E290, + 0x1E2AF, + 0x1E2C0, + 0x1E2FA, + 0x1E2FF, + 0x1E300, + 0x1E4D0, + 0x1E4FA, + 0x1E5D0, + 0x1E5FB, + 0x1E5FF, + 0x1E600, + 0x1E6C0, + 0x1E6DF, + 0x1E6E0, + 0x1E6F6, + 0x1E6FE, + 0x1E700, + 0x1E7E0, + 0x1E7E7, + 0x1E7E8, + 0x1E7EC, + 0x1E7ED, + 0x1E7EF, + 0x1E7F0, + 0x1E7FF, + 0x1E800, + 0x1E8C5, + 0x1E8C7, + 0x1E8D7, + 0x1E900, + 0x1E901, + 0x1E902, + 0x1E903, + 0x1E904, + 0x1E905, + 0x1E906, + 0x1E907, + 0x1E908, + 0x1E909, + 0x1E90A, + 0x1E90B, + 0x1E90C, + 0x1E90D, + 0x1E90E, + 0x1E90F, + 0x1E910, + 0x1E911, + 0x1E912, + 0x1E913, + 0x1E914, + 0x1E915, + 0x1E916, + 0x1E917, + 0x1E918, + 0x1E919, + 0x1E91A, + 0x1E91B, + 0x1E91C, + 0x1E91D, + 0x1E91E, + 0x1E91F, + 0x1E920, + 0x1E921, + 0x1E922, + 0x1E94C, + 0x1E950, + 0x1E95A, + 0x1E95E, + 0x1E960, + 0x1EC71, + 0x1ECB5, + 0x1ED01, + 0x1ED3E, + 0x1EE00, + 0x1EE01, + 0x1EE02, + 0x1EE03, + 0x1EE04, + 0x1EE05, + 0x1EE06, + 0x1EE07, + 0x1EE08, + 0x1EE09, + 0x1EE0A, + 0x1EE0B, + 0x1EE0C, + 0x1EE0D, + 0x1EE0E, + 0x1EE0F, + 0x1EE10, + 0x1EE11, + 0x1EE12, + 0x1EE13, + 0x1EE14, + 0x1EE15, + 0x1EE16, + 0x1EE17, + 0x1EE18, + 0x1EE19, + 0x1EE1A, + 0x1EE1B, + 0x1EE1C, + 0x1EE1D, + 0x1EE1E, + 0x1EE1F, + 0x1EE20, + 0x1EE21, + 0x1EE22, + 0x1EE23, + 0x1EE24, + 0x1EE25, + 0x1EE27, + 0x1EE28, + 0x1EE29, + 0x1EE2A, + 0x1EE2B, + 0x1EE2C, + 0x1EE2D, + 0x1EE2E, + 0x1EE2F, + 0x1EE30, + 0x1EE31, + 0x1EE32, + 0x1EE33, + 0x1EE34, + 0x1EE35, + 0x1EE36, + 0x1EE37, + 0x1EE38, + 0x1EE39, + 0x1EE3A, + 0x1EE3B, + 0x1EE3C, + 0x1EE42, + 0x1EE43, + 0x1EE47, + 0x1EE48, + 0x1EE49, + 0x1EE4A, + 0x1EE4B, + 0x1EE4C, + 0x1EE4D, + 0x1EE4E, + 0x1EE4F, + 0x1EE50, + 0x1EE51, + 0x1EE52, + 0x1EE53, + 0x1EE54, + 0x1EE55, + 0x1EE57, + 0x1EE58, + 0x1EE59, + 0x1EE5A, + 0x1EE5B, + 0x1EE5C, + 0x1EE5D, + 0x1EE5E, + 0x1EE5F, + 0x1EE60, + 0x1EE61, + 0x1EE62, + 0x1EE63, + 0x1EE64, + 0x1EE65, + 0x1EE67, + 0x1EE68, + 0x1EE69, + 0x1EE6A, + 0x1EE6B, + 0x1EE6C, + 0x1EE6D, + 0x1EE6E, + 0x1EE6F, + 0x1EE70, + 0x1EE71, + 0x1EE72, + 0x1EE73, + 0x1EE74, + 0x1EE75, + 0x1EE76, + 0x1EE77, + 0x1EE78, + 0x1EE79, + 0x1EE7A, + 0x1EE7B, + 0x1EE7C, + 0x1EE7D, + 0x1EE7E, + 0x1EE7F, + 0x1EE80, + 0x1EE81, + 0x1EE82, + 0x1EE83, + 0x1EE84, + 0x1EE85, + 0x1EE86, + 0x1EE87, + 0x1EE88, + 0x1EE89, + 0x1EE8A, + 0x1EE8B, + 0x1EE8C, + 0x1EE8D, + 0x1EE8E, + 0x1EE8F, + 0x1EE90, + 0x1EE91, + 0x1EE92, + 0x1EE93, + 0x1EE94, + 0x1EE95, + 0x1EE96, + 0x1EE97, + 0x1EE98, + 0x1EE99, + 0x1EE9A, + 0x1EE9B, + 0x1EE9C, + 0x1EEA1, + 0x1EEA2, + 0x1EEA3, + 0x1EEA4, + 0x1EEA5, + 0x1EEA6, + 0x1EEA7, + 0x1EEA8, + 0x1EEA9, + 0x1EEAA, + 0x1EEAB, + 0x1EEAC, + 0x1EEAD, + 0x1EEAE, + 0x1EEAF, + 0x1EEB0, + 0x1EEB1, + 0x1EEB2, + 0x1EEB3, + 0x1EEB4, + 0x1EEB5, + 0x1EEB6, + 0x1EEB7, + 0x1EEB8, + 0x1EEB9, + 0x1EEBA, + 0x1EEBB, + 0x1EEBC, + 0x1EEF0, + 0x1EEF2, + 0x1F000, + 0x1F02C, + 0x1F030, + 0x1F094, + 0x1F0A0, + 0x1F0AF, + 0x1F0B1, + 0x1F0C0, + 0x1F0C1, + 0x1F0D0, + 0x1F0D1, + 0x1F0F6, + 0x1F101, + 0x1F102, + 0x1F103, + 0x1F104, + 0x1F105, + 0x1F106, + 0x1F107, + 0x1F108, + 0x1F109, + 0x1F10A, + 0x1F10B, + 0x1F110, + 0x1F111, + 0x1F112, + 0x1F113, + 0x1F114, + 0x1F115, + 0x1F116, + 0x1F117, + 0x1F118, + 0x1F119, + 0x1F11A, + 0x1F11B, + 0x1F11C, + 0x1F11D, + 0x1F11E, + 0x1F11F, + 0x1F120, + 0x1F121, + 0x1F122, + 0x1F123, + 0x1F124, + 0x1F125, + 0x1F126, + 0x1F127, + 0x1F128, + 0x1F129, + 0x1F12A, + 0x1F12B, + 0x1F12C, + 0x1F12D, + 0x1F12E, + 0x1F12F, + 0x1F130, + 0x1F131, + 0x1F132, + 0x1F133, + 0x1F134, + 0x1F135, + 0x1F136, + 0x1F137, + 0x1F138, + 0x1F139, + 0x1F13A, + 0x1F13B, + 0x1F13C, + 0x1F13D, + 0x1F13E, + 0x1F13F, + 0x1F140, + 0x1F141, + 0x1F142, + 0x1F143, + 0x1F144, + 0x1F145, + 0x1F146, + 0x1F147, + 0x1F148, + 0x1F149, + 0x1F14A, + 0x1F14B, + 0x1F14C, + 0x1F14D, + 0x1F14E, + 0x1F14F, + 0x1F150, + 0x1F16A, + 0x1F16B, + 0x1F16C, + 0x1F16D, + 0x1F190, + 0x1F191, + 0x1F1AF, + 0x1F1E6, + 0x1F200, + 0x1F201, + 0x1F202, + 0x1F203, + 0x1F210, + 0x1F211, + 0x1F212, + 0x1F213, + 0x1F214, + 0x1F215, + 0x1F216, + 0x1F217, + 0x1F218, + 0x1F219, + 0x1F21A, + 0x1F21B, + 0x1F21C, + 0x1F21D, + 0x1F21E, + 0x1F21F, + 0x1F220, + 0x1F221, + 0x1F222, + 0x1F223, + 0x1F224, + 0x1F225, + 0x1F226, + 0x1F227, + 0x1F228, + 0x1F229, + 0x1F22A, + 0x1F22B, + 0x1F22C, + 0x1F22D, + 0x1F22E, + 0x1F22F, + 0x1F230, + 0x1F231, + 0x1F232, + 0x1F233, + 0x1F234, + 0x1F235, + 0x1F236, + 0x1F237, + 0x1F238, + 0x1F239, + 0x1F23A, + 0x1F23B, + 0x1F23C, + 0x1F240, + 0x1F241, + 0x1F242, + 0x1F243, + 0x1F244, + 0x1F245, + 0x1F246, + 0x1F247, + 0x1F248, + 0x1F249, + 0x1F250, + 0x1F251, + 0x1F252, + 0x1F260, + 0x1F266, + 0x1F300, + 0x1F6DA, + 0x1F6DC, + 0x1F6ED, + 0x1F6F0, + 0x1F6FD, + 0x1F700, + 0x1F7DC, + 0x1F7E0, + 0x1F7EC, + 0x1F7F0, + 0x1F80C, + 0x1F810, + 0x1F848, + 0x1F850, + 0x1F85A, + 0x1F860, + 0x1F888, + 0x1F890, + 0x1F8AE, + 0x1F8B0, + 0x1F8BC, + 0x1F8C0, + 0x1F8C2, + 0x1F8D0, + 0x1F8D9, + 0x1F900, + 0x1FA58, + 0x1FA60, + 0x1FA6E, + 0x1FA70, + 0x1FA7D, + 0x1FA80, + 0x1FAC7, + 0x1FAC8, + 0x1FAC9, + 0x1FACC, + 0x1FADE, + 0x1FADF, + 0x1FAEC, + 0x1FAEF, + 0x1FAFB, + 0x1FB00, + 0x1FB93, + 0x1FB94, + 0x1FBF0, + 0x1FBF1, + 0x1FBF2, + 0x1FBF3, + 0x1FBF4, + 0x1FBF5, + 0x1FBF6, + 0x1FBF7, + 0x1FBF8, + 0x1FBF9, + 0x1FBFA, + 0x1FBFB, + 0x20000, + 0x2A6E0, + 0x2A700, + 0x2B81F, + 0x2B820, + 0x2CEAE, + 0x2CEB0, + 0x2EBE1, + 0x2EBF0, + 0x2EE5E, + 0x2F800, + 0x2F801, + 0x2F802, + 0x2F803, + 0x2F804, + 0x2F805, + 0x2F806, + 0x2F807, + 0x2F808, + 0x2F809, + 0x2F80A, + 0x2F80B, + 0x2F80C, + 0x2F80D, + 0x2F80E, + 0x2F80F, + 0x2F810, + 0x2F811, + 0x2F812, + 0x2F813, + 0x2F814, + 0x2F815, + 0x2F816, + 0x2F817, + 0x2F818, + 0x2F819, + 0x2F81A, + 0x2F81B, + 0x2F81C, + 0x2F81D, + 0x2F81E, + 0x2F81F, + 0x2F820, + 0x2F821, + 0x2F822, + 0x2F823, + 0x2F824, + 0x2F825, + 0x2F826, + 0x2F827, + 0x2F828, + 0x2F829, + 0x2F82A, + 0x2F82B, + 0x2F82C, + 0x2F82D, + 0x2F82E, + 0x2F82F, + 0x2F830, + 0x2F831, + 0x2F834, + 0x2F835, + 0x2F836, + 0x2F837, + 0x2F838, + 0x2F839, + 0x2F83A, + 0x2F83B, + 0x2F83C, + 0x2F83D, + 0x2F83E, + 0x2F83F, + 0x2F840, + 0x2F841, + 0x2F842, + 0x2F843, + 0x2F844, + 0x2F845, + 0x2F847, + 0x2F848, + 0x2F849, + 0x2F84A, + 0x2F84B, + 0x2F84C, + 0x2F84D, + 0x2F84E, + 0x2F84F, + 0x2F850, + 0x2F851, + 0x2F852, + 0x2F853, + 0x2F854, + 0x2F855, + 0x2F856, + 0x2F857, + 0x2F858, + 0x2F859, + 0x2F85A, + 0x2F85B, + 0x2F85C, + 0x2F85D, + 0x2F85E, + 0x2F85F, + 0x2F860, + 0x2F861, + 0x2F862, + 0x2F863, + 0x2F864, + 0x2F865, + 0x2F866, + 0x2F867, + 0x2F868, + 0x2F869, + 0x2F86A, + 0x2F86C, + 0x2F86D, + 0x2F86E, + 0x2F86F, + 0x2F870, + 0x2F871, + 0x2F872, + 0x2F873, + 0x2F874, + 0x2F875, + 0x2F876, + 0x2F877, + 0x2F878, + 0x2F879, + 0x2F87A, + 0x2F87B, + 0x2F87C, + 0x2F87D, + 0x2F87E, + 0x2F87F, + 0x2F880, + 0x2F881, + 0x2F882, + 0x2F883, + 0x2F884, + 0x2F885, + 0x2F886, + 0x2F887, + 0x2F888, + 0x2F889, + 0x2F88A, + 0x2F88B, + 0x2F88C, + 0x2F88D, + 0x2F88E, + 0x2F88F, + 0x2F890, + 0x2F891, + 0x2F893, + 0x2F894, + 0x2F896, + 0x2F897, + 0x2F898, + 0x2F899, + 0x2F89A, + 0x2F89B, + 0x2F89C, + 0x2F89D, + 0x2F89E, + 0x2F89F, + 0x2F8A0, + 0x2F8A1, + 0x2F8A2, + 0x2F8A3, + 0x2F8A4, + 0x2F8A5, + 0x2F8A6, + 0x2F8A7, + 0x2F8A8, + 0x2F8A9, + 0x2F8AA, + 0x2F8AB, + 0x2F8AC, + 0x2F8AD, + 0x2F8AE, + 0x2F8AF, + 0x2F8B0, + 0x2F8B1, + 0x2F8B2, + 0x2F8B3, + 0x2F8B4, + 0x2F8B5, + 0x2F8B6, + 0x2F8B7, + 0x2F8B8, + 0x2F8B9, + 0x2F8BA, + 0x2F8BB, + 0x2F8BC, + 0x2F8BD, + 0x2F8BE, + 0x2F8BF, + 0x2F8C0, + 0x2F8C1, + 0x2F8C2, + 0x2F8C3, + 0x2F8C4, + 0x2F8C5, + 0x2F8C6, + 0x2F8C7, + 0x2F8C8, + 0x2F8C9, + 0x2F8CA, + 0x2F8CB, + 0x2F8CC, + 0x2F8CD, + 0x2F8CE, + 0x2F8CF, + 0x2F8D0, + 0x2F8D1, + 0x2F8D2, + 0x2F8D3, + 0x2F8D4, + 0x2F8D5, + 0x2F8D6, + 0x2F8D7, + 0x2F8D8, + 0x2F8D9, + 0x2F8DA, + 0x2F8DB, + 0x2F8DC, + 0x2F8DD, + 0x2F8DE, + 0x2F8DF, + 0x2F8E0, + 0x2F8E1, + 0x2F8E2, + 0x2F8E3, + 0x2F8E4, + 0x2F8E5, + 0x2F8E6, + 0x2F8E7, + 0x2F8E8, + 0x2F8E9, + 0x2F8EA, + 0x2F8EB, + 0x2F8EC, + 0x2F8ED, + 0x2F8EE, + 0x2F8EF, + 0x2F8F0, + 0x2F8F1, + 0x2F8F2, + 0x2F8F3, + 0x2F8F4, + 0x2F8F5, + 0x2F8F6, + 0x2F8F7, + 0x2F8F8, + 0x2F8F9, + 0x2F8FA, + 0x2F8FB, + 0x2F8FC, + 0x2F8FD, + 0x2F8FE, + 0x2F8FF, + 0x2F900, + 0x2F901, + 0x2F902, + 0x2F903, + 0x2F904, + 0x2F905, + 0x2F906, + 0x2F907, + 0x2F908, + 0x2F909, + 0x2F90A, + 0x2F90B, + 0x2F90C, + 0x2F90D, + 0x2F90E, + 0x2F90F, + 0x2F910, + 0x2F911, + 0x2F912, + 0x2F913, + 0x2F914, + 0x2F915, + 0x2F916, + 0x2F917, + 0x2F918, + 0x2F919, + 0x2F91A, + 0x2F91B, + 0x2F91C, + 0x2F91D, + 0x2F91E, + 0x2F91F, + 0x2F920, + 0x2F921, + 0x2F922, + 0x2F923, + 0x2F924, + 0x2F925, + 0x2F926, + 0x2F927, + 0x2F928, + 0x2F929, + 0x2F92A, + 0x2F92B, + 0x2F92C, + 0x2F92E, + 0x2F92F, + 0x2F930, + 0x2F931, + 0x2F932, + 0x2F933, + 0x2F934, + 0x2F935, + 0x2F936, + 0x2F937, + 0x2F938, + 0x2F939, + 0x2F93A, + 0x2F93B, + 0x2F93C, + 0x2F93D, + 0x2F93E, + 0x2F93F, + 0x2F940, + 0x2F941, + 0x2F942, + 0x2F943, + 0x2F944, + 0x2F945, + 0x2F946, + 0x2F948, + 0x2F949, + 0x2F94A, + 0x2F94B, + 0x2F94C, + 0x2F94D, + 0x2F94E, + 0x2F94F, + 0x2F950, + 0x2F951, + 0x2F952, + 0x2F953, + 0x2F954, + 0x2F955, + 0x2F956, + 0x2F957, + 0x2F958, + 0x2F959, + 0x2F95A, + 0x2F95B, + 0x2F95C, + 0x2F95D, + 0x2F95F, + 0x2F960, + 0x2F961, + 0x2F962, + 0x2F963, + 0x2F964, + 0x2F965, + 0x2F966, + 0x2F967, + 0x2F968, + 0x2F969, + 0x2F96A, + 0x2F96B, + 0x2F96C, + 0x2F96D, + 0x2F96E, + 0x2F96F, + 0x2F970, + 0x2F971, + 0x2F972, + 0x2F973, + 0x2F974, + 0x2F975, + 0x2F976, + 0x2F977, + 0x2F978, + 0x2F979, + 0x2F97A, + 0x2F97B, + 0x2F97C, + 0x2F97D, + 0x2F97E, + 0x2F97F, + 0x2F980, + 0x2F981, + 0x2F982, + 0x2F983, + 0x2F984, + 0x2F985, + 0x2F986, + 0x2F987, + 0x2F988, + 0x2F989, + 0x2F98A, + 0x2F98B, + 0x2F98C, + 0x2F98D, + 0x2F98E, + 0x2F98F, + 0x2F990, + 0x2F991, + 0x2F992, + 0x2F993, + 0x2F994, + 0x2F995, + 0x2F996, + 0x2F997, + 0x2F998, + 0x2F999, + 0x2F99A, + 0x2F99B, + 0x2F99C, + 0x2F99D, + 0x2F99E, + 0x2F99F, + 0x2F9A0, + 0x2F9A1, + 0x2F9A2, + 0x2F9A3, + 0x2F9A4, + 0x2F9A5, + 0x2F9A6, + 0x2F9A7, + 0x2F9A8, + 0x2F9A9, + 0x2F9AA, + 0x2F9AB, + 0x2F9AC, + 0x2F9AD, + 0x2F9AE, + 0x2F9AF, + 0x2F9B0, + 0x2F9B1, + 0x2F9B2, + 0x2F9B3, + 0x2F9B4, + 0x2F9B5, + 0x2F9B6, + 0x2F9B7, + 0x2F9B8, + 0x2F9B9, + 0x2F9BA, + 0x2F9BB, + 0x2F9BC, + 0x2F9BD, + 0x2F9BE, + 0x2F9BF, + 0x2F9C0, + 0x2F9C1, + 0x2F9C2, + 0x2F9C3, + 0x2F9C4, + 0x2F9C5, + 0x2F9C6, + 0x2F9C7, + 0x2F9C8, + 0x2F9C9, + 0x2F9CA, + 0x2F9CB, + 0x2F9CC, + 0x2F9CD, + 0x2F9CE, + 0x2F9CF, + 0x2F9D0, + 0x2F9D1, + 0x2F9D2, + 0x2F9D3, + 0x2F9D4, + 0x2F9D5, + 0x2F9D6, + 0x2F9D7, + 0x2F9D8, + 0x2F9D9, + 0x2F9DA, + 0x2F9DB, + 0x2F9DC, + 0x2F9DD, + 0x2F9DE, + 0x2F9DF, + 0x2F9E0, + 0x2F9E1, + 0x2F9E2, + 0x2F9E3, + 0x2F9E4, + 0x2F9E5, + 0x2F9E6, + 0x2F9E7, + 0x2F9E8, + 0x2F9E9, + 0x2F9EA, + 0x2F9EB, + 0x2F9EC, + 0x2F9ED, + 0x2F9EE, + 0x2F9EF, + 0x2F9F0, + 0x2F9F1, + 0x2F9F2, + 0x2F9F3, + 0x2F9F4, + 0x2F9F5, + 0x2F9F6, + 0x2F9F7, + 0x2F9F8, + 0x2F9F9, + 0x2F9FA, + 0x2F9FB, + 0x2F9FC, + 0x2F9FD, + 0x2F9FE, + 0x2FA00, + 0x2FA01, + 0x2FA02, + 0x2FA03, + 0x2FA04, + 0x2FA05, + 0x2FA06, + 0x2FA07, + 0x2FA08, + 0x2FA09, + 0x2FA0A, + 0x2FA0B, + 0x2FA0C, + 0x2FA0D, + 0x2FA0E, + 0x2FA0F, + 0x2FA10, + 0x2FA11, + 0x2FA12, + 0x2FA13, + 0x2FA14, + 0x2FA15, + 0x2FA16, + 0x2FA17, + 0x2FA18, + 0x2FA19, + 0x2FA1A, + 0x2FA1B, + 0x2FA1C, + 0x2FA1D, + 0x2FA1E, + 0x30000, + 0x3134B, + 0x31350, + 0x3347A, + 0x3D000, + 0x3FC40, + 0xE0100, + 0xE01F0, + ), +) + +uts46_statuses: bytes = ( + b"VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV" + b"VMMMMMMMMMMMMMMMMMMMMMMMMMMVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV" + b"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXMVVVVVVVMVMVVIVMVVMMMMVVMMMVMMMV" + b"MMMMMMMMMMMMMMMMMMMMMMMVMMMMMMMDVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMMVMVMVMVMVMMV" + b"MVMVMVMMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMMVMVMVMVMM" + b"VMVMMVMMMVMMMMVMMVMMMVMMVMMVMVMVMMVMVMVMMVMMMVMVMMVMVMMMMVMVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMMVMMMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVM" + b"VMVMVMVMVMVMVMVMVMVMVMVMVMVMMVMMVMVMMMMVMVMVMVMVMMMMMMMMMVMMMMMM" + b"VMMMMMVMMVMMMVIVMVMVMVMVXMVMMXMMMMMMMXMXMMVMMMMMMMMMMMMMMMMMXMMM" + b"MMMMMMVDVMMMMMMMMVMVMVMVMVMVMVMVMVMVMVMVMVMMMVMMVMVMMVMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMVMVMVMVMVMVMVMVMVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMV" + b"MVMMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVM" + b"VMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVXMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMXMVMVMMVXVXVXVXVXVMMMMVXVXVXVXVXVXVXVXVX" + b"VXVXVXVMMMMMMMMVXVXVXVXVXVXVXVXVXVXVXMMXMVXVXVXVXVXVXVXVMXVMXVXV" + b"XVXVXVXVXMMMVXMXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVX" + b"VXVXMMXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXV" + b"XVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXV" + b"XVXVMVXVXVXVXVXVXVXVMVXVXVXVXVXMMVXVMVMVXVMVMVMVMVMVXVMVMMMMMVMV" + b"MVXVMVMVMVMVMVXVXVXVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMXMXV" + b"MVIVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXMMMMMMXVXVXVXVXVXVXVXVX" + b"VXVIVXVXVXVIVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVMMM" + b"MMMMMMVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMVXVXVMMMV" + b"MMMMMMMMMMMVMMMMMMMMMMMMMMMMMMVMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMVMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMVMVMVMVMVMVMVMVMVMVMVMVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMMVMVM" + b"VMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVM" + b"VMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMMMMMMMMVXMMMMMMXVMMMMMMMMVMMMMMM" + b"MMVXMMMMMMXVXMXMXMXMVMMMMMMMMVMVMVMVMVMVMVMXMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMVMMMXVMMMMMMMMMMMMMMXVMMMMMMMMMVMXVM" + b"MMMXMMMVMVMMMMMMMMXMMMXVMMMMMMMMXMIDXVMVMVXVXMVMMVMMVMVMVMMMVMVM" + b"IXIMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMVMMMMMMMMMMMMMMMMVMVXVXMMMMVMMM" + b"VMMMMMMVMMVMMMVMMMVMVMVMVMMMMVMMMMMMMMMMVMMMMMVMMMMVMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMVMVXVMMVMMVMMVXVXMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMVMMMVMVXVMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMVMMMVMVMVMVMMMMVMVMV" + b"MMMMMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVXVXVXVXVXMVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXVMVMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMVMVMVMMMVXVXVMMVM" + b"VMXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMIMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXVMMMMMMMMMMMMMMVXVMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMXMMMMMMMMM" + b"MMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVXVXVXMVMVMVMVMVM" + b"VMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVM" + b"MVXVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMVMMM" + b"MMVMMMMMVMVMVMVMVMVMVMVMMMMVMVMMVMVMVMVMVMVMVMVMMXMXMMMMMVMMVXVX" + b"VXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVMMMMVMVMMXMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMV" + b"XVXVXVXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMVMVMVMMMMMMMMMMVMVMVMMVMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMMMXMMMMMXMVMMMMMMMMMMMMMMMMMMMMM" + b"MMMXMMMMMXMXMMXMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVXMMMMMMMMMMMM" + b"MVIMMXMMMMMMXVXMMMMMMMMMMMMMMMMMMMVMMMMMMXMMMMMMMMMMMMMMMMMMMXMM" + b"MMXMMMVMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXIXMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMIMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMM" + b"MMMXMMMMMMXMMMMMMXMMMXMMMMMMMXMMMMMMMXVXVXVXVXVXVXVXVXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVXVXMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXVXVXVXVMMMMMMMMMMMXMMMMMMMMMM" + b"MMMMMXMMMMMMMXMMXVXVXVXVXVXVXVXVXVMMMMMXMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMXMMMMMMMMMMMMMMXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMXVXVXVXVMMMMMMMMMMMMMMMMMMMMMMXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVX" + b"VXVXVXVXVXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVXVXVXVXVXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMVXMMMMMMMMMMMMMMMMMMMMMMMMMXVXVXVXVXVXVX" + b"VXVXVXVXVXVXVXVXVMMMMVXVXVXVXVXVXVXVXVXVXVIXVMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMVXVXVXVXVXVXVXVXVXVMMMMMMMVIVMMMMMMVXVXVXVXVXVX" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMXMXMMXMMMMXMMMMMMMMMMMMXMXMMMMMM" + b"MXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMXMMMMXMMMMMMMMXMMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMXMMMM" + b"MXMXMMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVXVXVXVXVMVMV" + b"MVMVMVMVMVMVMVMVMVMVMVMVMVMVXVMVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMVXVXVXVXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXV" + b"XVXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVXVXVXVXVXMMMMXMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMXMMXMXMXMMMMMMMMMMXMMMMXMXMXMXMXMXMXMMMXMMXMXMX" + b"MXMXMXMXMMXMXMMMMXMMMMMMMXMMMMXMMMMXMXMMMMMMMMMMXMMMMMMMMMMMMMMM" + b"MMXMMMXMMMMMXMMMMMMMMMMMMMMMMMXVXVXVXVXVXVXVXMMMMMMMMMMVMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMVMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMVMMMVMVX" + b"VMMMXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXMMMMMMMMMXMMXV" + b"XVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVXVMMMMMMMMMMVXVXVXVX" + b"VXVXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM" + b"MMMMMMMMMMMMMMMMMMMMMMMMXVXVXVXIX" +) + +uts46_replacements: tuple[str | None, ...] = ( + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + " ", + None, + None, + None, + None, + None, + None, + None, + " ̈", + None, + "a", + None, + None, + None, + None, + " ̄", + None, + None, + "2", + "3", + " ́", + "μ", + None, + None, + " ̧", + "1", + "o", + None, + "1⁄4", + "1⁄2", + "3⁄4", + None, + "à", + "á", + "â", + "ã", + "ä", + "å", + "æ", + "ç", + "è", + "é", + "ê", + "ë", + "ì", + "í", + "î", + "ï", + "ð", + "ñ", + "ò", + "ó", + "ô", + "õ", + "ö", + None, + "ø", + "ù", + "ú", + "û", + "ü", + "ý", + "þ", + "ss", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ā", + None, + "ă", + None, + "ą", + None, + "ć", + None, + "ĉ", + None, + "ċ", + None, + "č", + None, + "ď", + None, + "đ", + None, + "ē", + None, + "ĕ", + None, + "ė", + None, + "ę", + None, + "ě", + None, + "ĝ", + None, + "ğ", + None, + "ġ", + None, + "ģ", + None, + "ĥ", + None, + "ħ", + None, + "ĩ", + None, + "ī", + None, + "ĭ", + None, + "į", + None, + "i̇", + None, + "ij", + "ĵ", + None, + "ķ", + None, + "ĺ", + None, + "ļ", + None, + "ľ", + None, + "l·", + "ł", + None, + "ń", + None, + "ņ", + None, + "ň", + None, + "ʼn", + "ŋ", + None, + "ō", + None, + "ŏ", + None, + "ő", + None, + "œ", + None, + "ŕ", + None, + "ŗ", + None, + "ř", + None, + "ś", + None, + "ŝ", + None, + "ş", + None, + "š", + None, + "ţ", + None, + "ť", + None, + "ŧ", + None, + "ũ", + None, + "ū", + None, + "ŭ", + None, + "ů", + None, + "ű", + None, + "ų", + None, + "ŵ", + None, + "ŷ", + None, + "ÿ", + "ź", + None, + "ż", + None, + "ž", + None, + "s", + None, + "ɓ", + "ƃ", + None, + "ƅ", + None, + "ɔ", + "ƈ", + None, + "ɖ", + "ɗ", + "ƌ", + None, + "ǝ", + "ə", + "ɛ", + "ƒ", + None, + "ɠ", + "ɣ", + None, + "ɩ", + "ɨ", + "ƙ", + None, + "ɯ", + "ɲ", + None, + "ɵ", + "ơ", + None, + "ƣ", + None, + "ƥ", + None, + "ʀ", + "ƨ", + None, + "ʃ", + None, + "ƭ", + None, + "ʈ", + "ư", + None, + "ʊ", + "ʋ", + "ƴ", + None, + "ƶ", + None, + "ʒ", + "ƹ", + None, + "ƽ", + None, + "dž", + "lj", + "nj", + "ǎ", + None, + "ǐ", + None, + "ǒ", + None, + "ǔ", + None, + "ǖ", + None, + "ǘ", + None, + "ǚ", + None, + "ǜ", + None, + "ǟ", + None, + "ǡ", + None, + "ǣ", + None, + "ǥ", + None, + "ǧ", + None, + "ǩ", + None, + "ǫ", + None, + "ǭ", + None, + "ǯ", + None, + "dz", + "ǵ", + None, + "ƕ", + "ƿ", + "ǹ", + None, + "ǻ", + None, + "ǽ", + None, + "ǿ", + None, + "ȁ", + None, + "ȃ", + None, + "ȅ", + None, + "ȇ", + None, + "ȉ", + None, + "ȋ", + None, + "ȍ", + None, + "ȏ", + None, + "ȑ", + None, + "ȓ", + None, + "ȕ", + None, + "ȗ", + None, + "ș", + None, + "ț", + None, + "ȝ", + None, + "ȟ", + None, + "ƞ", + None, + "ȣ", + None, + "ȥ", + None, + "ȧ", + None, + "ȩ", + None, + "ȫ", + None, + "ȭ", + None, + "ȯ", + None, + "ȱ", + None, + "ȳ", + None, + "ⱥ", + "ȼ", + None, + "ƚ", + "ⱦ", + None, + "ɂ", + None, + "ƀ", + "ʉ", + "ʌ", + "ɇ", + None, + "ɉ", + None, + "ɋ", + None, + "ɍ", + None, + "ɏ", + None, + "h", + "ɦ", + "j", + "r", + "ɹ", + "ɻ", + "ʁ", + "w", + "y", + None, + " ̆", + " ̇", + " ̊", + " ̨", + " ̃", + " ̋", + None, + "ɣ", + "l", + "s", + "x", + "ʕ", + None, + "̀", + "́", + None, + "̓", + "̈́", + "ι", + None, + None, + None, + "ͱ", + None, + "ͳ", + None, + "ʹ", + None, + "ͷ", + None, + None, + " ι", + None, + ";", + "ϳ", + None, + " ́", + " ̈́", + "ά", + "·", + "έ", + "ή", + "ί", + None, + "ό", + None, + "ύ", + "ώ", + None, + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + None, + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "ϊ", + "ϋ", + None, + "σ", + None, + "ϗ", + "β", + "θ", + "υ", + "ύ", + "ϋ", + "φ", + "π", + None, + "ϙ", + None, + "ϛ", + None, + "ϝ", + None, + "ϟ", + None, + "ϡ", + None, + "ϣ", + None, + "ϥ", + None, + "ϧ", + None, + "ϩ", + None, + "ϫ", + None, + "ϭ", + None, + "ϯ", + None, + "κ", + "ρ", + "σ", + None, + "θ", + "ε", + None, + "ϸ", + None, + "σ", + "ϻ", + None, + "ͻ", + "ͼ", + "ͽ", + "ѐ", + "ё", + "ђ", + "ѓ", + "є", + "ѕ", + "і", + "ї", + "ј", + "љ", + "њ", + "ћ", + "ќ", + "ѝ", + "ў", + "џ", + "а", + "б", + "в", + "г", + "д", + "е", + "ж", + "з", + "и", + "й", + "к", + "л", + "м", + "н", + "о", + "п", + "р", + "с", + "т", + "у", + "ф", + "х", + "ц", + "ч", + "ш", + "щ", + "ъ", + "ы", + "ь", + "э", + "ю", + "я", + None, + "ѡ", + None, + "ѣ", + None, + "ѥ", + None, + "ѧ", + None, + "ѩ", + None, + "ѫ", + None, + "ѭ", + None, + "ѯ", + None, + "ѱ", + None, + "ѳ", + None, + "ѵ", + None, + "ѷ", + None, + "ѹ", + None, + "ѻ", + None, + "ѽ", + None, + "ѿ", + None, + "ҁ", + None, + "ҋ", + None, + "ҍ", + None, + "ҏ", + None, + "ґ", + None, + "ғ", + None, + "ҕ", + None, + "җ", + None, + "ҙ", + None, + "қ", + None, + "ҝ", + None, + "ҟ", + None, + "ҡ", + None, + "ң", + None, + "ҥ", + None, + "ҧ", + None, + "ҩ", + None, + "ҫ", + None, + "ҭ", + None, + "ү", + None, + "ұ", + None, + "ҳ", + None, + "ҵ", + None, + "ҷ", + None, + "ҹ", + None, + "һ", + None, + "ҽ", + None, + "ҿ", + None, + "ӏ", + "ӂ", + None, + "ӄ", + None, + "ӆ", + None, + "ӈ", + None, + "ӊ", + None, + "ӌ", + None, + "ӎ", + None, + "ӑ", + None, + "ӓ", + None, + "ӕ", + None, + "ӗ", + None, + "ә", + None, + "ӛ", + None, + "ӝ", + None, + "ӟ", + None, + "ӡ", + None, + "ӣ", + None, + "ӥ", + None, + "ӧ", + None, + "ө", + None, + "ӫ", + None, + "ӭ", + None, + "ӯ", + None, + "ӱ", + None, + "ӳ", + None, + "ӵ", + None, + "ӷ", + None, + "ӹ", + None, + "ӻ", + None, + "ӽ", + None, + "ӿ", + None, + "ԁ", + None, + "ԃ", + None, + "ԅ", + None, + "ԇ", + None, + "ԉ", + None, + "ԋ", + None, + "ԍ", + None, + "ԏ", + None, + "ԑ", + None, + "ԓ", + None, + "ԕ", + None, + "ԗ", + None, + "ԙ", + None, + "ԛ", + None, + "ԝ", + None, + "ԟ", + None, + "ԡ", + None, + "ԣ", + None, + "ԥ", + None, + "ԧ", + None, + "ԩ", + None, + "ԫ", + None, + "ԭ", + None, + "ԯ", + None, + None, + "ա", + "բ", + "գ", + "դ", + "ե", + "զ", + "է", + "ը", + "թ", + "ժ", + "ի", + "լ", + "խ", + "ծ", + "կ", + "հ", + "ձ", + "ղ", + "ճ", + "մ", + "յ", + "ն", + "շ", + "ո", + "չ", + "պ", + "ջ", + "ռ", + "ս", + "վ", + "տ", + "ր", + "ց", + "ւ", + "փ", + "ք", + "օ", + "ֆ", + None, + "է", + None, + "եւ", + None, + "ի", + "յ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "اٴ", + "وٴ", + "ۇٴ", + "يٴ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "क़", + "ख़", + "ग़", + "ज़", + "ड़", + "ढ़", + "फ़", + "य़", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ড়", + "ঢ়", + None, + "য়", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ਲ਼", + None, + None, + "ਸ਼", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ਖ਼", + "ਗ਼", + "ਜ਼", + None, + None, + "ਫ਼", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ଡ଼", + "ଢ଼", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ํา", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ໍາ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ຫນ", + "ຫມ", + None, + None, + None, + "་", + None, + "གྷ", + None, + None, + None, + "ཌྷ", + None, + "དྷ", + None, + "བྷ", + None, + "ཛྷ", + None, + "ཀྵ", + None, + None, + None, + "ཱི", + None, + "ཱུ", + "ྲྀ", + "ྲཱྀ", + "ླྀ", + "ླཱྀ", + None, + "ཱྀ", + None, + "ྒྷ", + None, + None, + None, + "ྜྷ", + None, + "ྡྷ", + None, + "ྦྷ", + None, + "ྫྷ", + None, + "ྐྵ", + None, + None, + None, + None, + None, + None, + None, + "ⴀ", + "ⴁ", + "ⴂ", + "ⴃ", + "ⴄ", + "ⴅ", + "ⴆ", + "ⴇ", + "ⴈ", + "ⴉ", + "ⴊ", + "ⴋ", + "ⴌ", + "ⴍ", + "ⴎ", + "ⴏ", + "ⴐ", + "ⴑ", + "ⴒ", + "ⴓ", + "ⴔ", + "ⴕ", + "ⴖ", + "ⴗ", + "ⴘ", + "ⴙ", + "ⴚ", + "ⴛ", + "ⴜ", + "ⴝ", + "ⴞ", + "ⴟ", + "ⴠ", + "ⴡ", + "ⴢ", + "ⴣ", + "ⴤ", + "ⴥ", + None, + "ⴧ", + None, + "ⴭ", + None, + None, + "ნ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "Ᏸ", + "Ᏹ", + "Ᏺ", + "Ᏻ", + "Ᏼ", + "Ᏽ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "в", + "д", + "о", + "с", + "т", + "ъ", + "ѣ", + "ꙋ", + "ᲊ", + None, + None, + "ა", + "ბ", + "გ", + "დ", + "ე", + "ვ", + "ზ", + "თ", + "ი", + "კ", + "ლ", + "მ", + "ნ", + "ო", + "პ", + "ჟ", + "რ", + "ს", + "ტ", + "უ", + "ფ", + "ქ", + "ღ", + "ყ", + "შ", + "ჩ", + "ც", + "ძ", + "წ", + "ჭ", + "ხ", + "ჯ", + "ჰ", + "ჱ", + "ჲ", + "ჳ", + "ჴ", + "ჵ", + "ჶ", + "ჷ", + "ჸ", + "ჹ", + "ჺ", + None, + "ჽ", + "ჾ", + "ჿ", + None, + None, + None, + None, + None, + "a", + "æ", + "b", + None, + "d", + "e", + "ǝ", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + None, + "o", + "ȣ", + "p", + "r", + "t", + "u", + "w", + "a", + "ɐ", + "ɑ", + "ᴂ", + "b", + "d", + "e", + "ə", + "ɛ", + "ɜ", + "g", + None, + "k", + "m", + "ŋ", + "o", + "ɔ", + "ᴖ", + "ᴗ", + "p", + "t", + "u", + "ᴝ", + "ɯ", + "v", + "ᴥ", + "β", + "γ", + "δ", + "φ", + "χ", + "i", + "r", + "u", + "v", + "β", + "γ", + "ρ", + "φ", + "χ", + None, + "н", + None, + "ɒ", + "c", + "ɕ", + "ð", + "ɜ", + "f", + "ɟ", + "ɡ", + "ɥ", + "ɨ", + "ɩ", + "ɪ", + "ᵻ", + "ʝ", + "ɭ", + "ᶅ", + "ʟ", + "ɱ", + "ɰ", + "ɲ", + "ɳ", + "ɴ", + "ɵ", + "ɸ", + "ʂ", + "ʃ", + "ƫ", + "ʉ", + "ʊ", + "ᴜ", + "ʋ", + "ʌ", + "z", + "ʐ", + "ʑ", + "ʒ", + "θ", + None, + "ḁ", + None, + "ḃ", + None, + "ḅ", + None, + "ḇ", + None, + "ḉ", + None, + "ḋ", + None, + "ḍ", + None, + "ḏ", + None, + "ḑ", + None, + "ḓ", + None, + "ḕ", + None, + "ḗ", + None, + "ḙ", + None, + "ḛ", + None, + "ḝ", + None, + "ḟ", + None, + "ḡ", + None, + "ḣ", + None, + "ḥ", + None, + "ḧ", + None, + "ḩ", + None, + "ḫ", + None, + "ḭ", + None, + "ḯ", + None, + "ḱ", + None, + "ḳ", + None, + "ḵ", + None, + "ḷ", + None, + "ḹ", + None, + "ḻ", + None, + "ḽ", + None, + "ḿ", + None, + "ṁ", + None, + "ṃ", + None, + "ṅ", + None, + "ṇ", + None, + "ṉ", + None, + "ṋ", + None, + "ṍ", + None, + "ṏ", + None, + "ṑ", + None, + "ṓ", + None, + "ṕ", + None, + "ṗ", + None, + "ṙ", + None, + "ṛ", + None, + "ṝ", + None, + "ṟ", + None, + "ṡ", + None, + "ṣ", + None, + "ṥ", + None, + "ṧ", + None, + "ṩ", + None, + "ṫ", + None, + "ṭ", + None, + "ṯ", + None, + "ṱ", + None, + "ṳ", + None, + "ṵ", + None, + "ṷ", + None, + "ṹ", + None, + "ṻ", + None, + "ṽ", + None, + "ṿ", + None, + "ẁ", + None, + "ẃ", + None, + "ẅ", + None, + "ẇ", + None, + "ẉ", + None, + "ẋ", + None, + "ẍ", + None, + "ẏ", + None, + "ẑ", + None, + "ẓ", + None, + "ẕ", + None, + "aʾ", + "ṡ", + None, + "ß", + None, + "ạ", + None, + "ả", + None, + "ấ", + None, + "ầ", + None, + "ẩ", + None, + "ẫ", + None, + "ậ", + None, + "ắ", + None, + "ằ", + None, + "ẳ", + None, + "ẵ", + None, + "ặ", + None, + "ẹ", + None, + "ẻ", + None, + "ẽ", + None, + "ế", + None, + "ề", + None, + "ể", + None, + "ễ", + None, + "ệ", + None, + "ỉ", + None, + "ị", + None, + "ọ", + None, + "ỏ", + None, + "ố", + None, + "ồ", + None, + "ổ", + None, + "ỗ", + None, + "ộ", + None, + "ớ", + None, + "ờ", + None, + "ở", + None, + "ỡ", + None, + "ợ", + None, + "ụ", + None, + "ủ", + None, + "ứ", + None, + "ừ", + None, + "ử", + None, + "ữ", + None, + "ự", + None, + "ỳ", + None, + "ỵ", + None, + "ỷ", + None, + "ỹ", + None, + "ỻ", + None, + "ỽ", + None, + "ỿ", + None, + "ἀ", + "ἁ", + "ἂ", + "ἃ", + "ἄ", + "ἅ", + "ἆ", + "ἇ", + None, + None, + "ἐ", + "ἑ", + "ἒ", + "ἓ", + "ἔ", + "ἕ", + None, + None, + "ἠ", + "ἡ", + "ἢ", + "ἣ", + "ἤ", + "ἥ", + "ἦ", + "ἧ", + None, + "ἰ", + "ἱ", + "ἲ", + "ἳ", + "ἴ", + "ἵ", + "ἶ", + "ἷ", + None, + None, + "ὀ", + "ὁ", + "ὂ", + "ὃ", + "ὄ", + "ὅ", + None, + None, + None, + "ὑ", + None, + "ὓ", + None, + "ὕ", + None, + "ὗ", + None, + "ὠ", + "ὡ", + "ὢ", + "ὣ", + "ὤ", + "ὥ", + "ὦ", + "ὧ", + None, + "ά", + None, + "έ", + None, + "ή", + None, + "ί", + None, + "ό", + None, + "ύ", + None, + "ώ", + None, + "ἀι", + "ἁι", + "ἂι", + "ἃι", + "ἄι", + "ἅι", + "ἆι", + "ἇι", + "ἀι", + "ἁι", + "ἂι", + "ἃι", + "ἄι", + "ἅι", + "ἆι", + "ἇι", + "ἠι", + "ἡι", + "ἢι", + "ἣι", + "ἤι", + "ἥι", + "ἦι", + "ἧι", + "ἠι", + "ἡι", + "ἢι", + "ἣι", + "ἤι", + "ἥι", + "ἦι", + "ἧι", + "ὠι", + "ὡι", + "ὢι", + "ὣι", + "ὤι", + "ὥι", + "ὦι", + "ὧι", + "ὠι", + "ὡι", + "ὢι", + "ὣι", + "ὤι", + "ὥι", + "ὦι", + "ὧι", + None, + "ὰι", + "αι", + "άι", + None, + None, + "ᾶι", + "ᾰ", + "ᾱ", + "ὰ", + "ά", + "αι", + " ̓", + "ι", + " ̓", + " ͂", + " ̈͂", + "ὴι", + "ηι", + "ήι", + None, + None, + "ῆι", + "ὲ", + "έ", + "ὴ", + "ή", + "ηι", + " ̓̀", + " ̓́", + " ̓͂", + None, + "ΐ", + None, + None, + "ῐ", + "ῑ", + "ὶ", + "ί", + None, + " ̔̀", + " ̔́", + " ̔͂", + None, + "ΰ", + None, + "ῠ", + "ῡ", + "ὺ", + "ύ", + "ῥ", + " ̈̀", + " ̈́", + "`", + None, + "ὼι", + "ωι", + "ώι", + None, + None, + "ῶι", + "ὸ", + "ό", + "ὼ", + "ώ", + "ωι", + " ́", + " ̔", + None, + " ", + None, + "", + None, + None, + "‐", + None, + " ̳", + None, + None, + None, + None, + " ", + None, + "′′", + "′′′", + None, + "‵‵", + "‵‵‵", + None, + "!!", + None, + " ̅", + None, + "??", + "?!", + "!?", + None, + "′′′′", + None, + " ", + None, + None, + None, + "0", + "i", + None, + "4", + "5", + "6", + "7", + "8", + "9", + "+", + "−", + "=", + "(", + ")", + "n", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "+", + "−", + "=", + "(", + ")", + None, + "a", + "e", + "o", + "x", + "ə", + "h", + "k", + "l", + "m", + "n", + "p", + "s", + "t", + "w", + "y", + "z", + None, + "rs", + None, + None, + None, + None, + "a/c", + "a/s", + "c", + "°c", + None, + "c/o", + "c/u", + "ɛ", + None, + "°f", + "g", + "h", + "ħ", + "i", + "l", + None, + "n", + "no", + None, + "p", + "q", + "r", + None, + "sm", + "tel", + "tm", + None, + "z", + None, + "ω", + None, + "z", + None, + "k", + "å", + "b", + "c", + None, + "e", + "f", + "ⅎ", + "m", + "o", + "א", + "ב", + "ג", + "ד", + "i", + None, + "fax", + "π", + "γ", + "π", + "∑", + None, + "d", + "e", + "i", + "j", + None, + "1⁄7", + "1⁄9", + "1⁄10", + "1⁄3", + "2⁄3", + "1⁄5", + "2⁄5", + "3⁄5", + "4⁄5", + "1⁄6", + "5⁄6", + "1⁄8", + "3⁄8", + "5⁄8", + "7⁄8", + "1⁄", + "i", + "ii", + "iii", + "iv", + "v", + "vi", + "vii", + "viii", + "ix", + "x", + "xi", + "xii", + "l", + "c", + "d", + "m", + "i", + "ii", + "iii", + "iv", + "v", + "vi", + "vii", + "viii", + "ix", + "x", + "xi", + "xii", + "l", + "c", + "d", + "m", + None, + "ↄ", + None, + "0⁄3", + None, + None, + None, + "∫∫", + "∫∫∫", + None, + "∮∮", + "∮∮∮", + None, + "〈", + "〉", + None, + None, + None, + None, + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "(1)", + "(2)", + "(3)", + "(4)", + "(5)", + "(6)", + "(7)", + "(8)", + "(9)", + "(10)", + "(11)", + "(12)", + "(13)", + "(14)", + "(15)", + "(16)", + "(17)", + "(18)", + "(19)", + "(20)", + None, + "(a)", + "(b)", + "(c)", + "(d)", + "(e)", + "(f)", + "(g)", + "(h)", + "(i)", + "(j)", + "(k)", + "(l)", + "(m)", + "(n)", + "(o)", + "(p)", + "(q)", + "(r)", + "(s)", + "(t)", + "(u)", + "(v)", + "(w)", + "(x)", + "(y)", + "(z)", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "0", + None, + "∫∫∫∫", + None, + "::=", + "==", + "===", + None, + "⫝̸", + None, + None, + None, + "ⰰ", + "ⰱ", + "ⰲ", + "ⰳ", + "ⰴ", + "ⰵ", + "ⰶ", + "ⰷ", + "ⰸ", + "ⰹ", + "ⰺ", + "ⰻ", + "ⰼ", + "ⰽ", + "ⰾ", + "ⰿ", + "ⱀ", + "ⱁ", + "ⱂ", + "ⱃ", + "ⱄ", + "ⱅ", + "ⱆ", + "ⱇ", + "ⱈ", + "ⱉ", + "ⱊ", + "ⱋ", + "ⱌ", + "ⱍ", + "ⱎ", + "ⱏ", + "ⱐ", + "ⱑ", + "ⱒ", + "ⱓ", + "ⱔ", + "ⱕ", + "ⱖ", + "ⱗ", + "ⱘ", + "ⱙ", + "ⱚ", + "ⱛ", + "ⱜ", + "ⱝ", + "ⱞ", + "ⱟ", + None, + "ⱡ", + None, + "ɫ", + "ᵽ", + "ɽ", + None, + "ⱨ", + None, + "ⱪ", + None, + "ⱬ", + None, + "ɑ", + "ɱ", + "ɐ", + "ɒ", + None, + "ⱳ", + None, + "ⱶ", + None, + "j", + "v", + "ȿ", + "ɀ", + "ⲁ", + None, + "ⲃ", + None, + "ⲅ", + None, + "ⲇ", + None, + "ⲉ", + None, + "ⲋ", + None, + "ⲍ", + None, + "ⲏ", + None, + "ⲑ", + None, + "ⲓ", + None, + "ⲕ", + None, + "ⲗ", + None, + "ⲙ", + None, + "ⲛ", + None, + "ⲝ", + None, + "ⲟ", + None, + "ⲡ", + None, + "ⲣ", + None, + "ⲥ", + None, + "ⲧ", + None, + "ⲩ", + None, + "ⲫ", + None, + "ⲭ", + None, + "ⲯ", + None, + "ⲱ", + None, + "ⲳ", + None, + "ⲵ", + None, + "ⲷ", + None, + "ⲹ", + None, + "ⲻ", + None, + "ⲽ", + None, + "ⲿ", + None, + "ⳁ", + None, + "ⳃ", + None, + "ⳅ", + None, + "ⳇ", + None, + "ⳉ", + None, + "ⳋ", + None, + "ⳍ", + None, + "ⳏ", + None, + "ⳑ", + None, + "ⳓ", + None, + "ⳕ", + None, + "ⳗ", + None, + "ⳙ", + None, + "ⳛ", + None, + "ⳝ", + None, + "ⳟ", + None, + "ⳡ", + None, + "ⳣ", + None, + "ⳬ", + None, + "ⳮ", + None, + "ⳳ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ⵡ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "母", + None, + "龟", + None, + "一", + "丨", + "丶", + "丿", + "乙", + "亅", + "二", + "亠", + "人", + "儿", + "入", + "八", + "冂", + "冖", + "冫", + "几", + "凵", + "刀", + "力", + "勹", + "匕", + "匚", + "匸", + "十", + "卜", + "卩", + "厂", + "厶", + "又", + "口", + "囗", + "土", + "士", + "夂", + "夊", + "夕", + "大", + "女", + "子", + "宀", + "寸", + "小", + "尢", + "尸", + "屮", + "山", + "巛", + "工", + "己", + "巾", + "干", + "幺", + "广", + "廴", + "廾", + "弋", + "弓", + "彐", + "彡", + "彳", + "心", + "戈", + "戶", + "手", + "支", + "攴", + "文", + "斗", + "斤", + "方", + "无", + "日", + "曰", + "月", + "木", + "欠", + "止", + "歹", + "殳", + "毋", + "比", + "毛", + "氏", + "气", + "水", + "火", + "爪", + "父", + "爻", + "爿", + "片", + "牙", + "牛", + "犬", + "玄", + "玉", + "瓜", + "瓦", + "甘", + "生", + "用", + "田", + "疋", + "疒", + "癶", + "白", + "皮", + "皿", + "目", + "矛", + "矢", + "石", + "示", + "禸", + "禾", + "穴", + "立", + "竹", + "米", + "糸", + "缶", + "网", + "羊", + "羽", + "老", + "而", + "耒", + "耳", + "聿", + "肉", + "臣", + "自", + "至", + "臼", + "舌", + "舛", + "舟", + "艮", + "色", + "艸", + "虍", + "虫", + "血", + "行", + "衣", + "襾", + "見", + "角", + "言", + "谷", + "豆", + "豕", + "豸", + "貝", + "赤", + "走", + "足", + "身", + "車", + "辛", + "辰", + "辵", + "邑", + "酉", + "釆", + "里", + "金", + "長", + "門", + "阜", + "隶", + "隹", + "雨", + "靑", + "非", + "面", + "革", + "韋", + "韭", + "音", + "頁", + "風", + "飛", + "食", + "首", + "香", + "馬", + "骨", + "高", + "髟", + "鬥", + "鬯", + "鬲", + "鬼", + "魚", + "鳥", + "鹵", + "鹿", + "麥", + "麻", + "黃", + "黍", + "黑", + "黹", + "黽", + "鼎", + "鼓", + "鼠", + "鼻", + "齊", + "齒", + "龍", + "龜", + "龠", + None, + " ", + None, + ".", + None, + "〒", + None, + "十", + "卄", + "卅", + None, + None, + None, + None, + None, + " ゙", + " ゚", + None, + "より", + None, + "コト", + None, + None, + None, + "ᄀ", + "ᄁ", + "ᆪ", + "ᄂ", + "ᆬ", + "ᆭ", + "ᄃ", + "ᄄ", + "ᄅ", + "ᆰ", + "ᆱ", + "ᆲ", + "ᆳ", + "ᆴ", + "ᆵ", + "ᄚ", + "ᄆ", + "ᄇ", + "ᄈ", + "ᄡ", + "ᄉ", + "ᄊ", + "ᄋ", + "ᄌ", + "ᄍ", + "ᄎ", + "ᄏ", + "ᄐ", + "ᄑ", + "ᄒ", + "ᅡ", + "ᅢ", + "ᅣ", + "ᅤ", + "ᅥ", + "ᅦ", + "ᅧ", + "ᅨ", + "ᅩ", + "ᅪ", + "ᅫ", + "ᅬ", + "ᅭ", + "ᅮ", + "ᅯ", + "ᅰ", + "ᅱ", + "ᅲ", + "ᅳ", + "ᅴ", + "ᅵ", + None, + "ᄔ", + "ᄕ", + "ᇇ", + "ᇈ", + "ᇌ", + "ᇎ", + "ᇓ", + "ᇗ", + "ᇙ", + "ᄜ", + "ᇝ", + "ᇟ", + "ᄝ", + "ᄞ", + "ᄠ", + "ᄢ", + "ᄣ", + "ᄧ", + "ᄩ", + "ᄫ", + "ᄬ", + "ᄭ", + "ᄮ", + "ᄯ", + "ᄲ", + "ᄶ", + "ᅀ", + "ᅇ", + "ᅌ", + "ᇱ", + "ᇲ", + "ᅗ", + "ᅘ", + "ᅙ", + "ᆄ", + "ᆅ", + "ᆈ", + "ᆑ", + "ᆒ", + "ᆔ", + "ᆞ", + "ᆡ", + None, + None, + "一", + "二", + "三", + "四", + "上", + "中", + "下", + "甲", + "乙", + "丙", + "丁", + "天", + "地", + "人", + None, + None, + None, + "(ᄀ)", + "(ᄂ)", + "(ᄃ)", + "(ᄅ)", + "(ᄆ)", + "(ᄇ)", + "(ᄉ)", + "(ᄋ)", + "(ᄌ)", + "(ᄎ)", + "(ᄏ)", + "(ᄐ)", + "(ᄑ)", + "(ᄒ)", + "(가)", + "(나)", + "(다)", + "(라)", + "(마)", + "(바)", + "(사)", + "(아)", + "(자)", + "(차)", + "(카)", + "(타)", + "(파)", + "(하)", + "(주)", + "(오전)", + "(오후)", + None, + "(一)", + "(二)", + "(三)", + "(四)", + "(五)", + "(六)", + "(七)", + "(八)", + "(九)", + "(十)", + "(月)", + "(火)", + "(水)", + "(木)", + "(金)", + "(土)", + "(日)", + "(株)", + "(有)", + "(社)", + "(名)", + "(特)", + "(財)", + "(祝)", + "(労)", + "(代)", + "(呼)", + "(学)", + "(監)", + "(企)", + "(資)", + "(協)", + "(祭)", + "(休)", + "(自)", + "(至)", + "問", + "幼", + "文", + "箏", + None, + "pte", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "ᄀ", + "ᄂ", + "ᄃ", + "ᄅ", + "ᄆ", + "ᄇ", + "ᄉ", + "ᄋ", + "ᄌ", + "ᄎ", + "ᄏ", + "ᄐ", + "ᄑ", + "ᄒ", + "가", + "나", + "다", + "라", + "마", + "바", + "사", + "아", + "자", + "차", + "카", + "타", + "파", + "하", + "참고", + "주의", + "우", + None, + "一", + "二", + "三", + "四", + "五", + "六", + "七", + "八", + "九", + "十", + "月", + "火", + "水", + "木", + "金", + "土", + "日", + "株", + "有", + "社", + "名", + "特", + "財", + "祝", + "労", + "秘", + "男", + "女", + "適", + "優", + "印", + "注", + "項", + "休", + "写", + "正", + "上", + "中", + "下", + "左", + "右", + "医", + "宗", + "学", + "監", + "企", + "資", + "協", + "夜", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "50", + "1月", + "2月", + "3月", + "4月", + "5月", + "6月", + "7月", + "8月", + "9月", + "10月", + "11月", + "12月", + "hg", + "erg", + "ev", + "ltd", + "ア", + "イ", + "ウ", + "エ", + "オ", + "カ", + "キ", + "ク", + "ケ", + "コ", + "サ", + "シ", + "ス", + "セ", + "ソ", + "タ", + "チ", + "ツ", + "テ", + "ト", + "ナ", + "ニ", + "ヌ", + "ネ", + "ノ", + "ハ", + "ヒ", + "フ", + "ヘ", + "ホ", + "マ", + "ミ", + "ム", + "メ", + "モ", + "ヤ", + "ユ", + "ヨ", + "ラ", + "リ", + "ル", + "レ", + "ロ", + "ワ", + "ヰ", + "ヱ", + "ヲ", + "令和", + "アパート", + "アルファ", + "アンペア", + "アール", + "イニング", + "インチ", + "ウォン", + "エスクード", + "エーカー", + "オンス", + "オーム", + "カイリ", + "カラット", + "カロリー", + "ガロン", + "ガンマ", + "ギガ", + "ギニー", + "キュリー", + "ギルダー", + "キロ", + "キログラム", + "キロメートル", + "キロワット", + "グラム", + "グラムトン", + "クルゼイロ", + "クローネ", + "ケース", + "コルナ", + "コーポ", + "サイクル", + "サンチーム", + "シリング", + "センチ", + "セント", + "ダース", + "デシ", + "ドル", + "トン", + "ナノ", + "ノット", + "ハイツ", + "パーセント", + "パーツ", + "バーレル", + "ピアストル", + "ピクル", + "ピコ", + "ビル", + "ファラッド", + "フィート", + "ブッシェル", + "フラン", + "ヘクタール", + "ペソ", + "ペニヒ", + "ヘルツ", + "ペンス", + "ページ", + "ベータ", + "ポイント", + "ボルト", + "ホン", + "ポンド", + "ホール", + "ホーン", + "マイクロ", + "マイル", + "マッハ", + "マルク", + "マンション", + "ミクロン", + "ミリ", + "ミリバール", + "メガ", + "メガトン", + "メートル", + "ヤード", + "ヤール", + "ユアン", + "リットル", + "リラ", + "ルピー", + "ルーブル", + "レム", + "レントゲン", + "ワット", + "0点", + "1点", + "2点", + "3点", + "4点", + "5点", + "6点", + "7点", + "8点", + "9点", + "10点", + "11点", + "12点", + "13点", + "14点", + "15点", + "16点", + "17点", + "18点", + "19点", + "20点", + "21点", + "22点", + "23点", + "24点", + "hpa", + "da", + "au", + "bar", + "ov", + "pc", + "dm", + "dm2", + "dm3", + "iu", + "平成", + "昭和", + "大正", + "明治", + "株式会社", + "pa", + "na", + "μa", + "ma", + "ka", + "kb", + "mb", + "gb", + "cal", + "kcal", + "pf", + "nf", + "μf", + "μg", + "mg", + "kg", + "hz", + "khz", + "mhz", + "ghz", + "thz", + "μl", + "ml", + "dl", + "kl", + "fm", + "nm", + "μm", + "mm", + "cm", + "km", + "mm2", + "cm2", + "m2", + "km2", + "mm3", + "cm3", + "m3", + "km3", + "m∕s", + "m∕s2", + "pa", + "kpa", + "mpa", + "gpa", + "rad", + "rad∕s", + "rad∕s2", + "ps", + "ns", + "μs", + "ms", + "pv", + "nv", + "μv", + "mv", + "kv", + "mv", + "pw", + "nw", + "μw", + "mw", + "kw", + "mw", + "kω", + "mω", + None, + "bq", + "cc", + "cd", + "c∕kg", + None, + "db", + "gy", + "ha", + "hp", + "in", + "kk", + "km", + "kt", + "lm", + "ln", + "log", + "lx", + "mb", + "mil", + "mol", + "ph", + None, + "ppm", + "pr", + "sr", + "sv", + "wb", + "v∕m", + "a∕m", + "1日", + "2日", + "3日", + "4日", + "5日", + "6日", + "7日", + "8日", + "9日", + "10日", + "11日", + "12日", + "13日", + "14日", + "15日", + "16日", + "17日", + "18日", + "19日", + "20日", + "21日", + "22日", + "23日", + "24日", + "25日", + "26日", + "27日", + "28日", + "29日", + "30日", + "31日", + "gal", + None, + None, + None, + None, + None, + None, + "ꙁ", + None, + "ꙃ", + None, + "ꙅ", + None, + "ꙇ", + None, + "ꙉ", + None, + "ꙋ", + None, + "ꙍ", + None, + "ꙏ", + None, + "ꙑ", + None, + "ꙓ", + None, + "ꙕ", + None, + "ꙗ", + None, + "ꙙ", + None, + "ꙛ", + None, + "ꙝ", + None, + "ꙟ", + None, + "ꙡ", + None, + "ꙣ", + None, + "ꙥ", + None, + "ꙧ", + None, + "ꙩ", + None, + "ꙫ", + None, + "ꙭ", + None, + "ꚁ", + None, + "ꚃ", + None, + "ꚅ", + None, + "ꚇ", + None, + "ꚉ", + None, + "ꚋ", + None, + "ꚍ", + None, + "ꚏ", + None, + "ꚑ", + None, + "ꚓ", + None, + "ꚕ", + None, + "ꚗ", + None, + "ꚙ", + None, + "ꚛ", + None, + "ъ", + "ь", + None, + None, + None, + "ꜣ", + None, + "ꜥ", + None, + "ꜧ", + None, + "ꜩ", + None, + "ꜫ", + None, + "ꜭ", + None, + "ꜯ", + None, + "ꜳ", + None, + "ꜵ", + None, + "ꜷ", + None, + "ꜹ", + None, + "ꜻ", + None, + "ꜽ", + None, + "ꜿ", + None, + "ꝁ", + None, + "ꝃ", + None, + "ꝅ", + None, + "ꝇ", + None, + "ꝉ", + None, + "ꝋ", + None, + "ꝍ", + None, + "ꝏ", + None, + "ꝑ", + None, + "ꝓ", + None, + "ꝕ", + None, + "ꝗ", + None, + "ꝙ", + None, + "ꝛ", + None, + "ꝝ", + None, + "ꝟ", + None, + "ꝡ", + None, + "ꝣ", + None, + "ꝥ", + None, + "ꝧ", + None, + "ꝩ", + None, + "ꝫ", + None, + "ꝭ", + None, + "ꝯ", + None, + "ꝯ", + None, + "ꝺ", + None, + "ꝼ", + None, + "ᵹ", + "ꝿ", + None, + "ꞁ", + None, + "ꞃ", + None, + "ꞅ", + None, + "ꞇ", + None, + "ꞌ", + None, + "ɥ", + None, + "ꞑ", + None, + "ꞓ", + None, + "ꞗ", + None, + "ꞙ", + None, + "ꞛ", + None, + "ꞝ", + None, + "ꞟ", + None, + "ꞡ", + None, + "ꞣ", + None, + "ꞥ", + None, + "ꞧ", + None, + "ꞩ", + None, + "ɦ", + "ɜ", + "ɡ", + "ɬ", + "ɪ", + None, + "ʞ", + "ʇ", + "ʝ", + "ꭓ", + "ꞵ", + None, + "ꞷ", + None, + "ꞹ", + None, + "ꞻ", + None, + "ꞽ", + None, + "ꞿ", + None, + "ꟁ", + None, + "ꟃ", + None, + "ꞔ", + "ʂ", + "ᶎ", + "ꟈ", + None, + "ꟊ", + None, + "ɤ", + "ꟍ", + None, + "꟏", + None, + "ꟑ", + None, + "ꟓ", + None, + "ꟕ", + None, + "ꟗ", + None, + "ꟙ", + None, + "ꟛ", + None, + "ƛ", + "ɷ", + None, + "ɼ", + None, + "s", + "c", + "f", + "q", + "ꟶ", + None, + "ħ", + "œ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ꜧ", + "ꬷ", + "ɫ", + "ꭒ", + None, + "ʍ", + None, + "ꭋ", + "ꭌ", + None, + "Ꭰ", + "Ꭱ", + "Ꭲ", + "Ꭳ", + "Ꭴ", + "Ꭵ", + "Ꭶ", + "Ꭷ", + "Ꭸ", + "Ꭹ", + "Ꭺ", + "Ꭻ", + "Ꭼ", + "Ꭽ", + "Ꭾ", + "Ꭿ", + "Ꮀ", + "Ꮁ", + "Ꮂ", + "Ꮃ", + "Ꮄ", + "Ꮅ", + "Ꮆ", + "Ꮇ", + "Ꮈ", + "Ꮉ", + "Ꮊ", + "Ꮋ", + "Ꮌ", + "Ꮍ", + "Ꮎ", + "Ꮏ", + "Ꮐ", + "Ꮑ", + "Ꮒ", + "Ꮓ", + "Ꮔ", + "Ꮕ", + "Ꮖ", + "Ꮗ", + "Ꮘ", + "Ꮙ", + "Ꮚ", + "Ꮛ", + "Ꮜ", + "Ꮝ", + "Ꮞ", + "Ꮟ", + "Ꮠ", + "Ꮡ", + "Ꮢ", + "Ꮣ", + "Ꮤ", + "Ꮥ", + "Ꮦ", + "Ꮧ", + "Ꮨ", + "Ꮩ", + "Ꮪ", + "Ꮫ", + "Ꮬ", + "Ꮭ", + "Ꮮ", + "Ꮯ", + "Ꮰ", + "Ꮱ", + "Ꮲ", + "Ꮳ", + "Ꮴ", + "Ꮵ", + "Ꮶ", + "Ꮷ", + "Ꮸ", + "Ꮹ", + "Ꮺ", + "Ꮻ", + "Ꮼ", + "Ꮽ", + "Ꮾ", + "Ꮿ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "豈", + "更", + "車", + "賈", + "滑", + "串", + "句", + "龜", + "契", + "金", + "喇", + "奈", + "懶", + "癩", + "羅", + "蘿", + "螺", + "裸", + "邏", + "樂", + "洛", + "烙", + "珞", + "落", + "酪", + "駱", + "亂", + "卵", + "欄", + "爛", + "蘭", + "鸞", + "嵐", + "濫", + "藍", + "襤", + "拉", + "臘", + "蠟", + "廊", + "朗", + "浪", + "狼", + "郎", + "來", + "冷", + "勞", + "擄", + "櫓", + "爐", + "盧", + "老", + "蘆", + "虜", + "路", + "露", + "魯", + "鷺", + "碌", + "祿", + "綠", + "菉", + "錄", + "鹿", + "論", + "壟", + "弄", + "籠", + "聾", + "牢", + "磊", + "賂", + "雷", + "壘", + "屢", + "樓", + "淚", + "漏", + "累", + "縷", + "陋", + "勒", + "肋", + "凜", + "凌", + "稜", + "綾", + "菱", + "陵", + "讀", + "拏", + "樂", + "諾", + "丹", + "寧", + "怒", + "率", + "異", + "北", + "磻", + "便", + "復", + "不", + "泌", + "數", + "索", + "參", + "塞", + "省", + "葉", + "說", + "殺", + "辰", + "沈", + "拾", + "若", + "掠", + "略", + "亮", + "兩", + "凉", + "梁", + "糧", + "良", + "諒", + "量", + "勵", + "呂", + "女", + "廬", + "旅", + "濾", + "礪", + "閭", + "驪", + "麗", + "黎", + "力", + "曆", + "歷", + "轢", + "年", + "憐", + "戀", + "撚", + "漣", + "煉", + "璉", + "秊", + "練", + "聯", + "輦", + "蓮", + "連", + "鍊", + "列", + "劣", + "咽", + "烈", + "裂", + "說", + "廉", + "念", + "捻", + "殮", + "簾", + "獵", + "令", + "囹", + "寧", + "嶺", + "怜", + "玲", + "瑩", + "羚", + "聆", + "鈴", + "零", + "靈", + "領", + "例", + "禮", + "醴", + "隸", + "惡", + "了", + "僚", + "寮", + "尿", + "料", + "樂", + "燎", + "療", + "蓼", + "遼", + "龍", + "暈", + "阮", + "劉", + "杻", + "柳", + "流", + "溜", + "琉", + "留", + "硫", + "紐", + "類", + "六", + "戮", + "陸", + "倫", + "崙", + "淪", + "輪", + "律", + "慄", + "栗", + "率", + "隆", + "利", + "吏", + "履", + "易", + "李", + "梨", + "泥", + "理", + "痢", + "罹", + "裏", + "裡", + "里", + "離", + "匿", + "溺", + "吝", + "燐", + "璘", + "藺", + "隣", + "鱗", + "麟", + "林", + "淋", + "臨", + "立", + "笠", + "粒", + "狀", + "炙", + "識", + "什", + "茶", + "刺", + "切", + "度", + "拓", + "糖", + "宅", + "洞", + "暴", + "輻", + "行", + "降", + "見", + "廓", + "兀", + "嗀", + None, + "塚", + None, + "晴", + None, + "凞", + "猪", + "益", + "礼", + "神", + "祥", + "福", + "靖", + "精", + "羽", + None, + "蘒", + None, + "諸", + None, + "逸", + "都", + None, + "飯", + "飼", + "館", + "鶴", + "郞", + "隷", + "侮", + "僧", + "免", + "勉", + "勤", + "卑", + "喝", + "嘆", + "器", + "塀", + "墨", + "層", + "屮", + "悔", + "慨", + "憎", + "懲", + "敏", + "既", + "暑", + "梅", + "海", + "渚", + "漢", + "煮", + "爫", + "琢", + "碑", + "社", + "祉", + "祈", + "祐", + "祖", + "祝", + "禍", + "禎", + "穀", + "突", + "節", + "練", + "縉", + "繁", + "署", + "者", + "臭", + "艹", + "著", + "褐", + "視", + "謁", + "謹", + "賓", + "贈", + "辶", + "逸", + "難", + "響", + "頻", + "恵", + "𤋮", + "舘", + None, + "並", + "况", + "全", + "侀", + "充", + "冀", + "勇", + "勺", + "喝", + "啕", + "喙", + "嗢", + "塚", + "墳", + "奄", + "奔", + "婢", + "嬨", + "廒", + "廙", + "彩", + "徭", + "惘", + "慎", + "愈", + "憎", + "慠", + "懲", + "戴", + "揄", + "搜", + "摒", + "敖", + "晴", + "朗", + "望", + "杖", + "歹", + "殺", + "流", + "滛", + "滋", + "漢", + "瀞", + "煮", + "瞧", + "爵", + "犯", + "猪", + "瑱", + "甆", + "画", + "瘝", + "瘟", + "益", + "盛", + "直", + "睊", + "着", + "磌", + "窱", + "節", + "类", + "絛", + "練", + "缾", + "者", + "荒", + "華", + "蝹", + "襁", + "覆", + "視", + "調", + "諸", + "請", + "謁", + "諾", + "諭", + "謹", + "變", + "贈", + "輸", + "遲", + "醙", + "鉶", + "陼", + "難", + "靖", + "韛", + "響", + "頋", + "頻", + "鬒", + "龜", + "𢡊", + "𢡄", + "𣏕", + "㮝", + "䀘", + "䀹", + "𥉉", + "𥳐", + "𧻓", + "齃", + "龎", + None, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "st", + None, + "մն", + "մե", + "մի", + "վն", + "մխ", + None, + "יִ", + None, + "ײַ", + "ע", + "א", + "ד", + "ה", + "כ", + "ל", + "ם", + "ר", + "ת", + "+", + "שׁ", + "שׂ", + "שּׁ", + "שּׂ", + "אַ", + "אָ", + "אּ", + "בּ", + "גּ", + "דּ", + "הּ", + "וּ", + "זּ", + None, + "טּ", + "יּ", + "ךּ", + "כּ", + "לּ", + None, + "מּ", + None, + "נּ", + "סּ", + None, + "ףּ", + "פּ", + None, + "צּ", + "קּ", + "רּ", + "שּ", + "תּ", + "וֹ", + "בֿ", + "כֿ", + "פֿ", + "אל", + "ٱ", + "ٻ", + "پ", + "ڀ", + "ٺ", + "ٿ", + "ٹ", + "ڤ", + "ڦ", + "ڄ", + "ڃ", + "چ", + "ڇ", + "ڍ", + "ڌ", + "ڎ", + "ڈ", + "ژ", + "ڑ", + "ک", + "گ", + "ڳ", + "ڱ", + "ں", + "ڻ", + "ۀ", + "ہ", + "ھ", + "ے", + "ۓ", + None, + "ڭ", + "ۇ", + "ۆ", + "ۈ", + "ۇٴ", + "ۋ", + "ۅ", + "ۉ", + "ې", + "ى", + "ئا", + "ئە", + "ئو", + "ئۇ", + "ئۆ", + "ئۈ", + "ئې", + "ئى", + "ی", + "ئج", + "ئح", + "ئم", + "ئى", + "ئي", + "بج", + "بح", + "بخ", + "بم", + "بى", + "بي", + "تج", + "تح", + "تخ", + "تم", + "تى", + "تي", + "ثج", + "ثم", + "ثى", + "ثي", + "جح", + "جم", + "حج", + "حم", + "خج", + "خح", + "خم", + "سج", + "سح", + "سخ", + "سم", + "صح", + "صم", + "ضج", + "ضح", + "ضخ", + "ضم", + "طح", + "طم", + "ظم", + "عج", + "عم", + "غج", + "غم", + "فج", + "فح", + "فخ", + "فم", + "فى", + "في", + "قح", + "قم", + "قى", + "قي", + "كا", + "كج", + "كح", + "كخ", + "كل", + "كم", + "كى", + "كي", + "لج", + "لح", + "لخ", + "لم", + "لى", + "لي", + "مج", + "مح", + "مخ", + "مم", + "مى", + "مي", + "نج", + "نح", + "نخ", + "نم", + "نى", + "ني", + "هج", + "هم", + "هى", + "هي", + "يج", + "يح", + "يخ", + "يم", + "يى", + "يي", + "ذٰ", + "رٰ", + "ىٰ", + " ٌّ", + " ٍّ", + " َّ", + " ُّ", + " ِّ", + " ّٰ", + "ئر", + "ئز", + "ئم", + "ئن", + "ئى", + "ئي", + "بر", + "بز", + "بم", + "بن", + "بى", + "بي", + "تر", + "تز", + "تم", + "تن", + "تى", + "تي", + "ثر", + "ثز", + "ثم", + "ثن", + "ثى", + "ثي", + "فى", + "في", + "قى", + "قي", + "كا", + "كل", + "كم", + "كى", + "كي", + "لم", + "لى", + "لي", + "ما", + "مم", + "نر", + "نز", + "نم", + "نن", + "نى", + "ني", + "ىٰ", + "ير", + "يز", + "يم", + "ين", + "يى", + "يي", + "ئج", + "ئح", + "ئخ", + "ئم", + "ئه", + "بج", + "بح", + "بخ", + "بم", + "به", + "تج", + "تح", + "تخ", + "تم", + "ته", + "ثم", + "جح", + "جم", + "حج", + "حم", + "خج", + "خم", + "سج", + "سح", + "سخ", + "سم", + "صح", + "صخ", + "صم", + "ضج", + "ضح", + "ضخ", + "ضم", + "طح", + "ظم", + "عج", + "عم", + "غج", + "غم", + "فج", + "فح", + "فخ", + "فم", + "قح", + "قم", + "كج", + "كح", + "كخ", + "كل", + "كم", + "لج", + "لح", + "لخ", + "لم", + "له", + "مج", + "مح", + "مخ", + "مم", + "نج", + "نح", + "نخ", + "نم", + "نه", + "هج", + "هم", + "هٰ", + "يج", + "يح", + "يخ", + "يم", + "يه", + "ئم", + "ئه", + "بم", + "به", + "تم", + "ته", + "ثم", + "ثه", + "سم", + "سه", + "شم", + "شه", + "كل", + "كم", + "لم", + "نم", + "نه", + "يم", + "يه", + "ـَّ", + "ـُّ", + "ـِّ", + "طى", + "طي", + "عى", + "عي", + "غى", + "غي", + "سى", + "سي", + "شى", + "شي", + "حى", + "حي", + "جى", + "جي", + "خى", + "خي", + "صى", + "صي", + "ضى", + "ضي", + "شج", + "شح", + "شخ", + "شم", + "شر", + "سر", + "صر", + "ضر", + "طى", + "طي", + "عى", + "عي", + "غى", + "غي", + "سى", + "سي", + "شى", + "شي", + "حى", + "حي", + "جى", + "جي", + "خى", + "خي", + "صى", + "صي", + "ضى", + "ضي", + "شج", + "شح", + "شخ", + "شم", + "شر", + "سر", + "صر", + "ضر", + "شج", + "شح", + "شخ", + "شم", + "سه", + "شه", + "طم", + "سج", + "سح", + "سخ", + "شج", + "شح", + "شخ", + "طم", + "ظم", + "اً", + None, + "تجم", + "تحج", + "تحم", + "تخم", + "تمج", + "تمح", + "تمخ", + "جمح", + "حمي", + "حمى", + "سحج", + "سجح", + "سجى", + "سمح", + "سمج", + "سمم", + "صحح", + "صمم", + "شحم", + "شجي", + "شمخ", + "شمم", + "ضحى", + "ضخم", + "طمح", + "طمم", + "طمي", + "عجم", + "عمم", + "عمى", + "غمم", + "غمي", + "غمى", + "فخم", + "قمح", + "قمم", + "لحم", + "لحي", + "لحى", + "لجج", + "لخم", + "لمح", + "محج", + "محم", + "محي", + "مجح", + "مجم", + "مخج", + "مخم", + None, + "مجخ", + "همج", + "همم", + "نحم", + "نحى", + "نجم", + "نجى", + "نمي", + "نمى", + "يمم", + "بخي", + "تجي", + "تجى", + "تخي", + "تخى", + "تمي", + "تمى", + "جمي", + "جحى", + "جمى", + "سخى", + "صحي", + "شحي", + "ضحي", + "لجي", + "لمي", + "يحي", + "يجي", + "يمي", + "ممي", + "قمي", + "نحي", + "قمح", + "لحم", + "عمي", + "كمي", + "نجح", + "مخي", + "لجم", + "كمم", + "لجم", + "نجح", + "جحي", + "حجي", + "مجي", + "فمي", + "بحي", + "كمم", + "عجم", + "صمم", + "سخي", + "نجي", + None, + None, + "صلے", + "قلے", + "الله", + "اكبر", + "محمد", + "صلعم", + "رسول", + "عليه", + "وسلم", + "صلى", + "صلى الله عليه وسلم", + "جل جلاله", + "ریال", + None, + None, + ",", + "、", + None, + ":", + ";", + "!", + "?", + "〖", + "〗", + None, + None, + None, + "—", + "–", + "_", + "(", + ")", + "{", + "}", + "〔", + "〕", + "【", + "】", + "《", + "》", + "〈", + "〉", + "「", + "」", + "『", + "』", + None, + "[", + "]", + " ̅", + "_", + ",", + "、", + None, + ";", + ":", + "?", + "!", + "—", + "(", + ")", + "{", + "}", + "〔", + "〕", + "#", + "&", + "*", + "+", + "-", + "<", + ">", + "=", + None, + "\\", + "$", + "%", + "@", + None, + " ً", + "ـً", + " ٌ", + None, + " ٍ", + None, + " َ", + "ـَ", + " ُ", + "ـُ", + " ِ", + "ـِ", + " ّ", + "ـّ", + " ْ", + "ـْ", + "ء", + "آ", + "أ", + "ؤ", + "إ", + "ئ", + "ا", + "ب", + "ة", + "ت", + "ث", + "ج", + "ح", + "خ", + "د", + "ذ", + "ر", + "ز", + "س", + "ش", + "ص", + "ض", + "ط", + "ظ", + "ع", + "غ", + "ف", + "ق", + "ك", + "ل", + "م", + "ن", + "ه", + "و", + "ى", + "ي", + "لآ", + "لأ", + "لإ", + "لا", + None, + None, + None, + "!", + '"', + "#", + "$", + "%", + "&", + "'", + "(", + ")", + "*", + "+", + ",", + "-", + ".", + "/", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ":", + ";", + "<", + "=", + ">", + "?", + "@", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "[", + "\\", + "]", + "^", + "_", + "`", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "{", + "|", + "}", + "~", + "⦅", + "⦆", + ".", + "「", + "」", + "、", + "・", + "ヲ", + "ァ", + "ィ", + "ゥ", + "ェ", + "ォ", + "ャ", + "ュ", + "ョ", + "ッ", + "ー", + "ア", + "イ", + "ウ", + "エ", + "オ", + "カ", + "キ", + "ク", + "ケ", + "コ", + "サ", + "シ", + "ス", + "セ", + "ソ", + "タ", + "チ", + "ツ", + "テ", + "ト", + "ナ", + "ニ", + "ヌ", + "ネ", + "ノ", + "ハ", + "ヒ", + "フ", + "ヘ", + "ホ", + "マ", + "ミ", + "ム", + "メ", + "モ", + "ヤ", + "ユ", + "ヨ", + "ラ", + "リ", + "ル", + "レ", + "ロ", + "ワ", + "ン", + "゙", + "゚", + None, + "ᄀ", + "ᄁ", + "ᆪ", + "ᄂ", + "ᆬ", + "ᆭ", + "ᄃ", + "ᄄ", + "ᄅ", + "ᆰ", + "ᆱ", + "ᆲ", + "ᆳ", + "ᆴ", + "ᆵ", + "ᄚ", + "ᄆ", + "ᄇ", + "ᄈ", + "ᄡ", + "ᄉ", + "ᄊ", + "ᄋ", + "ᄌ", + "ᄍ", + "ᄎ", + "ᄏ", + "ᄐ", + "ᄑ", + "ᄒ", + None, + "ᅡ", + "ᅢ", + "ᅣ", + "ᅤ", + "ᅥ", + "ᅦ", + None, + "ᅧ", + "ᅨ", + "ᅩ", + "ᅪ", + "ᅫ", + "ᅬ", + None, + "ᅭ", + "ᅮ", + "ᅯ", + "ᅰ", + "ᅱ", + "ᅲ", + None, + "ᅳ", + "ᅴ", + "ᅵ", + None, + "¢", + "£", + "¬", + " ̄", + "¦", + "¥", + "₩", + None, + "│", + "←", + "↑", + "→", + "↓", + "■", + "○", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𐐨", + "𐐩", + "𐐪", + "𐐫", + "𐐬", + "𐐭", + "𐐮", + "𐐯", + "𐐰", + "𐐱", + "𐐲", + "𐐳", + "𐐴", + "𐐵", + "𐐶", + "𐐷", + "𐐸", + "𐐹", + "𐐺", + "𐐻", + "𐐼", + "𐐽", + "𐐾", + "𐐿", + "𐑀", + "𐑁", + "𐑂", + "𐑃", + "𐑄", + "𐑅", + "𐑆", + "𐑇", + "𐑈", + "𐑉", + "𐑊", + "𐑋", + "𐑌", + "𐑍", + "𐑎", + "𐑏", + None, + None, + None, + None, + "𐓘", + "𐓙", + "𐓚", + "𐓛", + "𐓜", + "𐓝", + "𐓞", + "𐓟", + "𐓠", + "𐓡", + "𐓢", + "𐓣", + "𐓤", + "𐓥", + "𐓦", + "𐓧", + "𐓨", + "𐓩", + "𐓪", + "𐓫", + "𐓬", + "𐓭", + "𐓮", + "𐓯", + "𐓰", + "𐓱", + "𐓲", + "𐓳", + "𐓴", + "𐓵", + "𐓶", + "𐓷", + "𐓸", + "𐓹", + "𐓺", + "𐓻", + None, + None, + None, + None, + None, + None, + None, + None, + "𐖗", + "𐖘", + "𐖙", + "𐖚", + "𐖛", + "𐖜", + "𐖝", + "𐖞", + "𐖟", + "𐖠", + "𐖡", + None, + "𐖣", + "𐖤", + "𐖥", + "𐖦", + "𐖧", + "𐖨", + "𐖩", + "𐖪", + "𐖫", + "𐖬", + "𐖭", + "𐖮", + "𐖯", + "𐖰", + "𐖱", + None, + "𐖳", + "𐖴", + "𐖵", + "𐖶", + "𐖷", + "𐖸", + "𐖹", + None, + "𐖻", + "𐖼", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ː", + "ˑ", + "æ", + "ʙ", + "ɓ", + None, + "ʣ", + "ꭦ", + "ʥ", + "ʤ", + "ɖ", + "ɗ", + "ᶑ", + "ɘ", + "ɞ", + "ʩ", + "ɤ", + "ɢ", + "ɠ", + "ʛ", + "ħ", + "ʜ", + "ɧ", + "ʄ", + "ʪ", + "ʫ", + "ɬ", + "𝼄", + "ꞎ", + "ɮ", + "𝼅", + "ʎ", + "𝼆", + "ø", + "ɶ", + "ɷ", + "q", + "ɺ", + "𝼈", + "ɽ", + "ɾ", + "ʀ", + "ʨ", + "ʦ", + "ꭧ", + "ʧ", + "ʈ", + "ⱱ", + None, + "ʏ", + "ʡ", + "ʢ", + "ʘ", + "ǀ", + "ǁ", + "ǂ", + "𝼊", + "𝼞", + "ʇ", + "ʖ", + "ʗ", + "ʞ", + "𝼋", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𐳀", + "𐳁", + "𐳂", + "𐳃", + "𐳄", + "𐳅", + "𐳆", + "𐳇", + "𐳈", + "𐳉", + "𐳊", + "𐳋", + "𐳌", + "𐳍", + "𐳎", + "𐳏", + "𐳐", + "𐳑", + "𐳒", + "𐳓", + "𐳔", + "𐳕", + "𐳖", + "𐳗", + "𐳘", + "𐳙", + "𐳚", + "𐳛", + "𐳜", + "𐳝", + "𐳞", + "𐳟", + "𐳠", + "𐳡", + "𐳢", + "𐳣", + "𐳤", + "𐳥", + "𐳦", + "𐳧", + "𐳨", + "𐳩", + "𐳪", + "𐳫", + "𐳬", + "𐳭", + "𐳮", + "𐳯", + "𐳰", + "𐳱", + "𐳲", + None, + None, + None, + None, + None, + None, + None, + None, + "𐵰", + "𐵱", + "𐵲", + "𐵳", + "𐵴", + "𐵵", + "𐵶", + "𐵷", + "𐵸", + "𐵹", + "𐵺", + "𐵻", + "𐵼", + "𐵽", + "𐵾", + "𐵿", + "𐶀", + "𐶁", + "𐶂", + "𐶃", + "𐶄", + "𐶅", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𑣀", + "𑣁", + "𑣂", + "𑣃", + "𑣄", + "𑣅", + "𑣆", + "𑣇", + "𑣈", + "𑣉", + "𑣊", + "𑣋", + "𑣌", + "𑣍", + "𑣎", + "𑣏", + "𑣐", + "𑣑", + "𑣒", + "𑣓", + "𑣔", + "𑣕", + "𑣖", + "𑣗", + "𑣘", + "𑣙", + "𑣚", + "𑣛", + "𑣜", + "𑣝", + "𑣞", + "𑣟", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𖹠", + "𖹡", + "𖹢", + "𖹣", + "𖹤", + "𖹥", + "𖹦", + "𖹧", + "𖹨", + "𖹩", + "𖹪", + "𖹫", + "𖹬", + "𖹭", + "𖹮", + "𖹯", + "𖹰", + "𖹱", + "𖹲", + "𖹳", + "𖹴", + "𖹵", + "𖹶", + "𖹷", + "𖹸", + "𖹹", + "𖹺", + "𖹻", + "𖹼", + "𖹽", + "𖹾", + "𖹿", + None, + None, + "𖺻", + "𖺼", + "𖺽", + "𖺾", + "𖺿", + "𖻀", + "𖻁", + "𖻂", + "𖻃", + "𖻄", + "𖻅", + "𖻆", + "𖻇", + "𖻈", + "𖻉", + "𖻊", + "𖻋", + "𖻌", + "𖻍", + "𖻎", + "𖻏", + "𖻐", + "𖻑", + "𖻒", + "𖻓", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "こと", + "トキ", + "トテ", + "ヨリ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𝅗𝅥", + "𝅘𝅥", + "𝅘𝅥𝅮", + "𝅘𝅥𝅯", + "𝅘𝅥𝅰", + "𝅘𝅥𝅱", + "𝅘𝅥𝅲", + None, + None, + None, + "𝆹𝅥", + "𝆺𝅥", + "𝆹𝅥𝅮", + "𝆺𝅥𝅮", + "𝆹𝅥𝅯", + "𝆺𝅥𝅯", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + None, + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + None, + "c", + "d", + None, + "g", + None, + "j", + "k", + None, + "n", + "o", + "p", + "q", + None, + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + None, + "f", + None, + "h", + "i", + "j", + "k", + "l", + "m", + "n", + None, + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + None, + "d", + "e", + "f", + "g", + None, + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + None, + "s", + "t", + "u", + "v", + "w", + "x", + "y", + None, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + None, + "d", + "e", + "f", + "g", + None, + "i", + "j", + "k", + "l", + "m", + None, + "o", + None, + "s", + "t", + "u", + "v", + "w", + "x", + "y", + None, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "ı", + "ȷ", + "ss", + None, + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "θ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∇", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∂", + "ε", + "θ", + "κ", + "φ", + "ρ", + "π", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "θ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∇", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∂", + "ε", + "θ", + "κ", + "φ", + "ρ", + "π", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "θ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∇", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∂", + "ε", + "θ", + "κ", + "φ", + "ρ", + "π", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "θ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∇", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∂", + "ε", + "θ", + "κ", + "φ", + "ρ", + "π", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "θ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∇", + "α", + "β", + "γ", + "δ", + "ε", + "ζ", + "η", + "θ", + "ι", + "κ", + "λ", + "μ", + "ν", + "ξ", + "ο", + "π", + "ρ", + "σ", + "τ", + "υ", + "φ", + "χ", + "ψ", + "ω", + "∂", + "ε", + "θ", + "κ", + "φ", + "ρ", + "π", + "ϝ", + None, + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𝽁", + None, + "𝽉", + None, + "𝽋", + None, + "𝽎", + None, + "𝽒", + None, + "𝽩", + None, + "𝽫", + None, + "𝽭", + None, + "𝽯", + None, + "𝽳", + None, + "𝽵", + None, + "𝽷", + None, + "𝽹", + None, + "𝽻", + None, + "𝽽", + None, + "𝽿", + None, + None, + None, + "ss", + None, + None, + "𝽗", + "𝽘", + "𝽙", + "ɣ", + "ᴘ", + "ƀ", + "đ", + "ǥ", + "ł", + "ƚ", + "𝽐", + "𝼾", + "ɉ", + "ᵿ", + "𝼿", + "ƞ", + "ɼ", + "ȸ", + "ȹ", + "𝼫", + "𝼙", + "ʆ", + "ᶘ", + "𝼬", + "𝼜", + "ʓ", + "ᶚ", + "ᴅ", + "ᴀ", + "ᴇ", + "ɿ", + "ʅ", + "ʮ", + "ʯ", + "ȡ", + "ȴ", + "ȵ", + "ȶ", + "ψ", + "ω", + "ᶁ", + "ꞕ", + "ᶇ", + "ᶊ", + "ᶎ", + "ƈ", + "ƙ", + "ƥ", + "ʠ", + "ƭ", + "𝼉", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "а", + "б", + "в", + "г", + "д", + "е", + "ж", + "з", + "и", + "к", + "л", + "м", + "о", + "п", + "р", + "с", + "т", + "у", + "ф", + "х", + "ц", + "ч", + "ш", + "ы", + "э", + "ю", + "ꚉ", + "ә", + "і", + "ј", + "ө", + "ү", + "ӏ", + "а", + "б", + "в", + "г", + "д", + "е", + "ж", + "з", + "и", + "к", + "л", + "о", + "п", + "с", + "у", + "ф", + "х", + "ц", + "ч", + "ш", + "ъ", + "ы", + "ґ", + "і", + "ѕ", + "џ", + "ҫ", + "ꙑ", + "ұ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "𞤢", + "𞤣", + "𞤤", + "𞤥", + "𞤦", + "𞤧", + "𞤨", + "𞤩", + "𞤪", + "𞤫", + "𞤬", + "𞤭", + "𞤮", + "𞤯", + "𞤰", + "𞤱", + "𞤲", + "𞤳", + "𞤴", + "𞤵", + "𞤶", + "𞤷", + "𞤸", + "𞤹", + "𞤺", + "𞤻", + "𞤼", + "𞤽", + "𞤾", + "𞤿", + "𞥀", + "𞥁", + "𞥂", + "𞥃", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "ا", + "ب", + "ج", + "د", + None, + "و", + "ز", + "ح", + "ط", + "ي", + "ك", + "ل", + "م", + "ن", + "س", + "ع", + "ف", + "ص", + "ق", + "ر", + "ش", + "ت", + "ث", + "خ", + "ذ", + "ض", + "ظ", + "غ", + "ٮ", + "ں", + "ڡ", + "ٯ", + None, + "ب", + "ج", + None, + "ه", + None, + "ح", + None, + "ي", + "ك", + "ل", + "م", + "ن", + "س", + "ع", + "ف", + "ص", + "ق", + None, + "ش", + "ت", + "ث", + "خ", + None, + "ض", + None, + "غ", + None, + "ج", + None, + "ح", + None, + "ي", + None, + "ل", + None, + "ن", + "س", + "ع", + None, + "ص", + "ق", + None, + "ش", + None, + "خ", + None, + "ض", + None, + "غ", + None, + "ں", + None, + "ٯ", + None, + "ب", + "ج", + None, + "ه", + None, + "ح", + "ط", + "ي", + "ك", + None, + "م", + "ن", + "س", + "ع", + "ف", + "ص", + "ق", + None, + "ش", + "ت", + "ث", + "خ", + None, + "ض", + "ظ", + "غ", + "ٮ", + None, + "ڡ", + None, + "ا", + "ب", + "ج", + "د", + "ه", + "و", + "ز", + "ح", + "ط", + "ي", + None, + "ل", + "م", + "ن", + "س", + "ع", + "ف", + "ص", + "ق", + "ر", + "ش", + "ت", + "ث", + "خ", + "ذ", + "ض", + "ظ", + "غ", + None, + "ب", + "ج", + "د", + None, + "و", + "ز", + "ح", + "ط", + "ي", + None, + "ل", + "م", + "ن", + "س", + "ع", + "ف", + "ص", + "ق", + "ر", + "ش", + "ت", + "ث", + "خ", + "ذ", + "ض", + "ظ", + "غ", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "0,", + "1,", + "2,", + "3,", + "4,", + "5,", + "6,", + "7,", + "8,", + "9,", + None, + "(a)", + "(b)", + "(c)", + "(d)", + "(e)", + "(f)", + "(g)", + "(h)", + "(i)", + "(j)", + "(k)", + "(l)", + "(m)", + "(n)", + "(o)", + "(p)", + "(q)", + "(r)", + "(s)", + "(t)", + "(u)", + "(v)", + "(w)", + "(x)", + "(y)", + "(z)", + "〔s〕", + "c", + "r", + "cd", + "wz", + None, + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "hv", + "mv", + "sd", + "ss", + "ppv", + "wc", + None, + "mc", + "md", + "mr", + None, + "dj", + None, + None, + None, + "ほか", + "ココ", + "サ", + None, + "手", + "字", + "双", + "デ", + "二", + "多", + "解", + "天", + "交", + "映", + "無", + "料", + "前", + "後", + "再", + "新", + "初", + "終", + "生", + "販", + "声", + "吹", + "演", + "投", + "捕", + "一", + "三", + "遊", + "左", + "中", + "右", + "指", + "走", + "打", + "禁", + "空", + "合", + "満", + "有", + "月", + "申", + "割", + "営", + "配", + None, + "〔本〕", + "〔三〕", + "〔二〕", + "〔安〕", + "〔点〕", + "〔打〕", + "〔盗〕", + "〔勝〕", + "〔敗〕", + None, + "得", + "可", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + None, + "丽", + "丸", + "乁", + "𠄢", + "你", + "侮", + "侻", + "倂", + "偺", + "備", + "僧", + "像", + "㒞", + "𠘺", + "免", + "兔", + "兤", + "具", + "𠔜", + "㒹", + "內", + "再", + "𠕋", + "冗", + "冤", + "仌", + "冬", + "况", + "𩇟", + "凵", + "刃", + "㓟", + "刻", + "剆", + "割", + "剷", + "㔕", + "勇", + "勉", + "勤", + "勺", + "包", + "匆", + "北", + "卉", + "卑", + "博", + "即", + "卽", + "卿", + "𠨬", + "灰", + "及", + "叟", + "𠭣", + "叫", + "叱", + "吆", + "咞", + "吸", + "呈", + "周", + "咢", + "哶", + "唐", + "啓", + "啣", + "善", + "喙", + "喫", + "喳", + "嗂", + "圖", + "嘆", + "圗", + "噑", + "噴", + "切", + "壮", + "城", + "埴", + "堍", + "型", + "堲", + "報", + "墬", + "𡓤", + "売", + "壷", + "夆", + "多", + "夢", + "奢", + "𡚨", + "𡛪", + "姬", + "娛", + "娧", + "姘", + "婦", + "㛮", + "㛼", + "嬈", + "嬾", + "𡧈", + "寃", + "寘", + "寧", + "寳", + "𡬘", + "寿", + "将", + "当", + "尢", + "㞁", + "屠", + "屮", + "峀", + "岍", + "𡷤", + "嵃", + "𡷦", + "嵮", + "嵫", + "嵼", + "巡", + "巢", + "㠯", + "巽", + "帨", + "帽", + "幩", + "㡢", + "𢆃", + "㡼", + "庰", + "庳", + "庶", + "廊", + "𪎒", + "廾", + "𢌱", + "舁", + "弢", + "㣇", + "𣊸", + "𦇚", + "形", + "彫", + "㣣", + "徚", + "忍", + "志", + "忹", + "悁", + "㤺", + "㤜", + "悔", + "𢛔", + "惇", + "慈", + "慌", + "慎", + "慌", + "慺", + "憎", + "憲", + "憤", + "憯", + "懞", + "懲", + "懶", + "成", + "戛", + "扝", + "抱", + "拔", + "捐", + "𢬌", + "挽", + "拼", + "捨", + "掃", + "揤", + "𢯱", + "搢", + "揅", + "掩", + "㨮", + "摩", + "摾", + "撝", + "摷", + "㩬", + "敏", + "敬", + "𣀊", + "旣", + "書", + "晉", + "㬙", + "暑", + "㬈", + "㫤", + "冒", + "冕", + "最", + "暜", + "肭", + "䏙", + "朗", + "望", + "朡", + "杞", + "杓", + "𣏃", + "㭉", + "柺", + "枅", + "桒", + "梅", + "𣑭", + "梎", + "栟", + "椔", + "㮝", + "楂", + "榣", + "槪", + "檨", + "𣚣", + "櫛", + "㰘", + "次", + "𣢧", + "歔", + "㱎", + "歲", + "殟", + "殺", + "殻", + "𣪍", + "𡴋", + "𣫺", + "汎", + "𣲼", + "沿", + "泍", + "汧", + "洖", + "派", + "海", + "流", + "浩", + "浸", + "涅", + "𣴞", + "洴", + "港", + "湮", + "㴳", + "滋", + "滇", + "𣻑", + "淹", + "潮", + "𣽞", + "𣾎", + "濆", + "瀹", + "瀞", + "瀛", + "㶖", + "灊", + "災", + "灷", + "炭", + "𠔥", + "煅", + "𤉣", + "熜", + "𤎫", + "爨", + "爵", + "牐", + "𤘈", + "犀", + "犕", + "𤜵", + "𤠔", + "獺", + "王", + "㺬", + "玥", + "㺸", + "瑇", + "瑜", + "瑱", + "璅", + "瓊", + "㼛", + "甤", + "𤰶", + "甾", + "𤲒", + "異", + "𢆟", + "瘐", + "𤾡", + "𤾸", + "𥁄", + "㿼", + "䀈", + "直", + "𥃳", + "𥃲", + "𥄙", + "𥄳", + "眞", + "真", + "睊", + "䀹", + "瞋", + "䁆", + "䂖", + "𥐝", + "硎", + "碌", + "磌", + "䃣", + "𥘦", + "祖", + "𥚚", + "𥛅", + "福", + "秫", + "䄯", + "穀", + "穊", + "穏", + "𥥼", + "𥪧", + "竮", + "䈂", + "𥮫", + "篆", + "築", + "䈧", + "𥲀", + "糒", + "䊠", + "糨", + "糣", + "紀", + "𥾆", + "絣", + "䌁", + "緇", + "縂", + "繅", + "䌴", + "𦈨", + "𦉇", + "䍙", + "𦋙", + "罺", + "𦌾", + "羕", + "翺", + "者", + "𦓚", + "𦔣", + "聠", + "𦖨", + "聰", + "𣍟", + "䏕", + "育", + "脃", + "䐋", + "脾", + "媵", + "𦞧", + "𦞵", + "𣎓", + "𣎜", + "舁", + "舄", + "辞", + "䑫", + "芑", + "芋", + "芝", + "劳", + "花", + "芳", + "芽", + "苦", + "𦬼", + "若", + "茝", + "荣", + "莭", + "茣", + "莽", + "菧", + "著", + "荓", + "菊", + "菌", + "菜", + "𦰶", + "𦵫", + "𦳕", + "䔫", + "蓱", + "蓳", + "蔖", + "𧏊", + "蕤", + "𦼬", + "䕝", + "䕡", + "𦾱", + "𧃒", + "䕫", + "虐", + "虜", + "虧", + "虩", + "蚩", + "蚈", + "蜎", + "蛢", + "蝹", + "蜨", + "蝫", + "螆", + "䗗", + "蟡", + "蠁", + "䗹", + "衠", + "衣", + "𧙧", + "裗", + "裞", + "䘵", + "裺", + "㒻", + "𧢮", + "𧥦", + "䚾", + "䛇", + "誠", + "諭", + "變", + "豕", + "𧲨", + "貫", + "賁", + "贛", + "起", + "𧼯", + "𠠄", + "跋", + "趼", + "跰", + "𠣞", + "軔", + "輸", + "𨗒", + "𨗭", + "邔", + "郱", + "鄑", + "𨜮", + "鄛", + "鈸", + "鋗", + "鋘", + "鉼", + "鏹", + "鐕", + "𨯺", + "開", + "䦕", + "閷", + "𨵷", + "䧦", + "雃", + "嶲", + "霣", + "𩅅", + "𩈚", + "䩮", + "䩶", + "韠", + "𩐊", + "䪲", + "𩒖", + "頋", + "頩", + "𩖶", + "飢", + "䬳", + "餩", + "馧", + "駂", + "駾", + "䯎", + "𩬰", + "鬒", + "鱀", + "鳽", + "䳎", + "䳭", + "鵧", + "𪃎", + "䳸", + "𪄅", + "𪈎", + "𪊑", + "麻", + "䵖", + "黹", + "黾", + "鼅", + "鼏", + "鼖", + "鼻", + "𪘀", + None, + None, + None, + None, + None, + None, + None, + None, + None, +) diff --git a/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/METADATA b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/METADATA new file mode 100644 index 0000000..ba828d2 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/METADATA @@ -0,0 +1,170 @@ +Metadata-Version: 2.4 +Name: jsonschema +Version: 4.26.0 +Summary: An implementation of JSON Schema validation for Python +Project-URL: Homepage, https://github.com/python-jsonschema/jsonschema +Project-URL: Documentation, https://python-jsonschema.readthedocs.io/ +Project-URL: Issues, https://github.com/python-jsonschema/jsonschema/issues/ +Project-URL: Funding, https://github.com/sponsors/Julian +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema?utm_source=pypi-jsonschema&utm_medium=referral&utm_campaign=pypi-link +Project-URL: Changelog, https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst +Project-URL: Source, https://github.com/python-jsonschema/jsonschema +Author-email: Julian Berman +License-Expression: MIT +License-File: COPYING +Keywords: data validation,json,json schema,jsonschema,validation +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: File Formats :: JSON +Classifier: Topic :: File Formats :: JSON :: JSON Schema +Requires-Python: >=3.10 +Requires-Dist: attrs>=22.2.0 +Requires-Dist: jsonschema-specifications>=2023.03.6 +Requires-Dist: referencing>=0.28.4 +Requires-Dist: rpds-py>=0.25.0 +Provides-Extra: format +Requires-Dist: fqdn; extra == 'format' +Requires-Dist: idna; extra == 'format' +Requires-Dist: isoduration; extra == 'format' +Requires-Dist: jsonpointer>1.13; extra == 'format' +Requires-Dist: rfc3339-validator; extra == 'format' +Requires-Dist: rfc3987; extra == 'format' +Requires-Dist: uri-template; extra == 'format' +Requires-Dist: webcolors>=1.11; extra == 'format' +Provides-Extra: format-nongpl +Requires-Dist: fqdn; extra == 'format-nongpl' +Requires-Dist: idna; extra == 'format-nongpl' +Requires-Dist: isoduration; extra == 'format-nongpl' +Requires-Dist: jsonpointer>1.13; extra == 'format-nongpl' +Requires-Dist: rfc3339-validator; extra == 'format-nongpl' +Requires-Dist: rfc3986-validator>0.1.0; extra == 'format-nongpl' +Requires-Dist: rfc3987-syntax>=1.1.0; extra == 'format-nongpl' +Requires-Dist: uri-template; extra == 'format-nongpl' +Requires-Dist: webcolors>=24.6.0; extra == 'format-nongpl' +Description-Content-Type: text/x-rst + +========== +jsonschema +========== + +|PyPI| |Pythons| |CI| |ReadTheDocs| |Precommit| |Zenodo| + +.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema.svg + :alt: PyPI version + :target: https://pypi.org/project/jsonschema/ + +.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema.svg + :alt: Supported Python versions + :target: https://pypi.org/project/jsonschema/ + +.. |CI| image:: https://github.com/python-jsonschema/jsonschema/workflows/CI/badge.svg + :alt: Build status + :target: https://github.com/python-jsonschema/jsonschema/actions?query=workflow%3ACI + +.. |ReadTheDocs| image:: https://readthedocs.org/projects/python-jsonschema/badge/?version=stable&style=flat + :alt: ReadTheDocs status + :target: https://python-jsonschema.readthedocs.io/en/stable/ + +.. |Precommit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/jsonschema/main.svg + :alt: pre-commit.ci status + :target: https://results.pre-commit.ci/latest/github/python-jsonschema/jsonschema/main + +.. |Zenodo| image:: https://zenodo.org/badge/3072629.svg + :alt: Zenodo DOI + :target: https://zenodo.org/badge/latestdoi/3072629 + + +``jsonschema`` is an implementation of the `JSON Schema `_ specification for Python. + +.. code:: python + + >>> from jsonschema import validate + + >>> # A sample schema, like what we'd get from json.load() + >>> schema = { + ... "type" : "object", + ... "properties" : { + ... "price" : {"type" : "number"}, + ... "name" : {"type" : "string"}, + ... }, + ... } + + >>> # If no exception is raised by validate(), the instance is valid. + >>> validate(instance={"name" : "Eggs", "price" : 34.99}, schema=schema) + + >>> validate( + ... instance={"name" : "Eggs", "price" : "Invalid"}, schema=schema, + ... ) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + ValidationError: 'Invalid' is not of type 'number' + +It can also be used from the command line by installing `check-jsonschema `_. + +Features +-------- + +* Full support for `Draft 2020-12 `_, `Draft 2019-09 `_, `Draft 7 `_, `Draft 6 `_, `Draft 4 `_ and `Draft 3 `_ + +* `Lazy validation `_ that can iteratively report *all* validation errors. + +* `Programmatic querying `_ of which properties or items failed validation. + + +Installation +------------ + +``jsonschema`` is available on `PyPI `_. You can install using `pip `_: + +.. code:: bash + + $ pip install jsonschema + + +Extras +====== + +Two extras are available when installing the package, both currently related to ``format`` validation: + + * ``format`` + * ``format-nongpl`` + +They can be used when installing in order to include additional dependencies, e.g.: + +.. code:: bash + + $ pip install jsonschema'[format]' + +Be aware that the mere presence of these dependencies – or even the specification of ``format`` checks in a schema – do *not* activate format checks (as per the specification). +Please read the `format validation documentation `_ for further details. + +About +----- + +I'm Julian Berman. + +``jsonschema`` is on `GitHub `_. + +Get in touch, via GitHub or otherwise, if you've got something to contribute, it'd be most welcome! + +If you feel overwhelmingly grateful, you can also `sponsor me `_. + +And for companies who appreciate ``jsonschema`` and its continued support and growth, ``jsonschema`` is also now supportable via `TideLift `_. + + +Release Information +------------------- + +v4.26.0 +======= + +* Decrease import time by delaying importing of ``urllib.request`` (#1416). diff --git a/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/RECORD b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/RECORD new file mode 100644 index 0000000..aa5b1a8 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/RECORD @@ -0,0 +1,43 @@ +jsonschema/__init__.py,sha256=p-Rw4TS_0OPHZIJyImDWsdWgmd6CPWHMXLq7BuQxTGc,3941 +jsonschema/__main__.py,sha256=iLsZf2upUB3ilBKTlMnyK-HHt2Cnnfkwwxi_c6gLvSA,115 +jsonschema/_format.py,sha256=lrs1U7iSB2ZX9Z2EalsROYeQm1d9kefw2CLo08G8P4s,15568 +jsonschema/_keywords.py,sha256=r8_DrqAfn6QLwQnmXEggveiSU-UaIL2p2nuPINelfFc,14949 +jsonschema/_legacy_keywords.py,sha256=2tWuwRPWbYS7EAl8wBIC_rabGuv1J4dfYLqNEPpShhA,15191 +jsonschema/_types.py,sha256=f_nkTDbrja3E3fsINTC73y_gMXTU210I_H7qK0NN30c,5456 +jsonschema/_typing.py,sha256=pXLnGy3jNtIUTq037kUfq0we17085eHtJwDJ2t--mQE,617 +jsonschema/_utils.py,sha256=Xv6_wKKslBJlwyj9-j2c8JDFw-4z4aWFnVe2pX8h7U4,10659 +jsonschema/cli.py,sha256=av90OtpSxuiko3FAyEHtxpI-NSuX3WMtoQpIx09obJY,8445 +jsonschema/exceptions.py,sha256=b42hUDOfPFcprI4ZlNpjDeLKv8k9vOhgWct2jyDlxzk,15256 +jsonschema/protocols.py,sha256=lgyryVHqFijSFRAz95ch3VN2Fz-oTFyhj9Obcy5P_CI,7198 +jsonschema/validators.py,sha256=l_FxuZW0sMoFUwqTZqElL7F1P5nzy3sQaLbZqrEJb6U,47159 +jsonschema/benchmarks/__init__.py,sha256=A0sQrxDBVHSyQ-8ru3L11hMXf3q9gVuB9x_YgHb4R9M,70 +jsonschema/benchmarks/const_vs_enum.py,sha256=DVFi3WDqBalZFOibnjpX1uTSr3Rxa2cPgFcowd7Ukrs,830 +jsonschema/benchmarks/contains.py,sha256=gexQoUrCOwECofbt19BeosQZ7WFL6PDdkX49DWwBlOg,786 +jsonschema/benchmarks/import_benchmark.py,sha256=2DRIOVS6p-bqLn_822B_X5FkIRvsJ2V1CYnV2druzDs,779 +jsonschema/benchmarks/issue232.py,sha256=3LLYLIlBGQnVuyyo2iAv-xky5P6PRFHANx4-zIIQOoE,521 +jsonschema/benchmarks/json_schema_test_suite.py,sha256=PvfabpUYcF4_7csYDTcTauED8rnFEGYbdY5RqTXD08s,320 +jsonschema/benchmarks/nested_schemas.py,sha256=mo07dx-CIgmSOI62CNs4g5xu1FzHklLBpkQoDxWYcKs,1892 +jsonschema/benchmarks/subcomponents.py,sha256=fEyiMzsWeK2pd7DEGCuuY-vzGunwhHczRBWEnBRLKIo,1113 +jsonschema/benchmarks/unused_registry.py,sha256=hwRwONc9cefPtYzkoX_TYRO3GyUojriv0-YQaK3vnj0,940 +jsonschema/benchmarks/useless_applicator_schemas.py,sha256=EVm5-EtOEFoLP_Vt2j4SrCwlx05NhPqNuZQ6LIMP1Dc,3342 +jsonschema/benchmarks/useless_keywords.py,sha256=bj_zKr1oVctFlqyZaObCsYTgFjiiNgPzC0hr1Y868mE,867 +jsonschema/benchmarks/validator_creation.py,sha256=UkUQlLAnussnr_KdCIdad6xx2pXxQLmYtsXoiirKeWQ,285 +jsonschema/benchmarks/issue232/issue.json,sha256=eaPOZjMRu5u8RpKrsA9uk7ucPZS5tkKG4D_hkOTQ3Hk,117105 +jsonschema/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jsonschema/tests/_suite.py,sha256=2k0X91N7dOHhQc5mrYv40OKf1weioj6RMBqWgLT6-PI,8374 +jsonschema/tests/fuzz_validate.py,sha256=fUA7yTJIihaCwJplkUehZeyB84HcXEcqtY5oPJXIO7I,1114 +jsonschema/tests/test_cli.py,sha256=A89r5LOHy-peLPZA5YDkOaMTWqzQO_w2Tu8WFz_vphM,28544 +jsonschema/tests/test_deprecations.py,sha256=yG6mkRJHpTHbWoxpLC5y5H7fk8erGOs8f_9V4tCBEh8,15754 +jsonschema/tests/test_exceptions.py,sha256=rsEqdjknUz3dEyJb6_DiModPHXsJTEWzDrxUscg8G5o,24301 +jsonschema/tests/test_format.py,sha256=eVm5SMaWF2lOPO28bPAwNvkiQvHCQKy-MnuAgEchfEc,3188 +jsonschema/tests/test_jsonschema_test_suite.py,sha256=tAfxknM65OR9LyDPHu1pkEaombLgjRLnJ6FPiWPdxjg,8461 +jsonschema/tests/test_types.py,sha256=cF51KTDmdsx06MrIc4fXKt0X9fIsVgw5uhT8CamVa8U,6977 +jsonschema/tests/test_utils.py,sha256=sao74o1PyYMxBfqweokQN48CFSS6yhJk5FkCfMJ5PsI,4163 +jsonschema/tests/test_validators.py,sha256=uzl-agyLoZPTufouIHSxFPfPYrdIdjNwjHcD_5NyU4E,87949 +jsonschema/tests/typing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jsonschema/tests/typing/test_all_concrete_validators_match_protocol.py,sha256=I5XUl5ZYUSZo3APkF10l8Mnfk09oXKqvXWttGGd3sDk,1238 +jsonschema-4.26.0.dist-info/METADATA,sha256=BbGJhmypipbaOTS_a4NofO0_-FMlJzt34WtwX22LJtI,7592 +jsonschema-4.26.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87 +jsonschema-4.26.0.dist-info/entry_points.txt,sha256=vO7rX4Fs_xIVJy2pnAtKgTSxfpnozAVQ0DjCmpMxnWE,51 +jsonschema-4.26.0.dist-info/licenses/COPYING,sha256=T5KgFaE8TRoEC-8BiqE0MLTxvHO0Gxa7hGw0Z2bedDk,1057 +jsonschema-4.26.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/WHEEL b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/WHEEL new file mode 100644 index 0000000..ae8ec1b --- /dev/null +++ b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.28.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/entry_points.txt b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/entry_points.txt new file mode 100644 index 0000000..eecef9d --- /dev/null +++ b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +jsonschema = jsonschema.cli:main diff --git a/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/licenses/COPYING b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/licenses/COPYING new file mode 100644 index 0000000..af9cfbd --- /dev/null +++ b/source/target-vendors/cp312/jsonschema-4.26.0.dist-info/licenses/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2013 Julian Berman + +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/source/target-vendors/cp312/jsonschema/__init__.py b/source/target-vendors/cp312/jsonschema/__init__.py new file mode 100644 index 0000000..d8dec8c --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/__init__.py @@ -0,0 +1,120 @@ +""" +An implementation of JSON Schema for Python. + +The main functionality is provided by the validator classes for each of the +supported JSON Schema versions. + +Most commonly, `jsonschema.validators.validate` is the quickest way to simply +validate a given instance under a schema, and will create a validator +for you. +""" +import warnings + +from jsonschema._format import FormatChecker +from jsonschema._types import TypeChecker +from jsonschema.exceptions import SchemaError, ValidationError +from jsonschema.validators import ( + Draft3Validator, + Draft4Validator, + Draft6Validator, + Draft7Validator, + Draft201909Validator, + Draft202012Validator, + validate, +) + + +def __getattr__(name): + if name == "__version__": + warnings.warn( + "Accessing jsonschema.__version__ is deprecated and will be " + "removed in a future release. Use importlib.metadata directly " + "to query for jsonschema's version.", + DeprecationWarning, + stacklevel=2, + ) + + from importlib import metadata + return metadata.version("jsonschema") + elif name == "RefResolver": + from jsonschema.validators import _RefResolver + warnings.warn( + _RefResolver._DEPRECATION_MESSAGE, + DeprecationWarning, + stacklevel=2, + ) + return _RefResolver + elif name == "ErrorTree": + warnings.warn( + "Importing ErrorTree directly from the jsonschema package " + "is deprecated and will become an ImportError. Import it from " + "jsonschema.exceptions instead.", + DeprecationWarning, + stacklevel=2, + ) + from jsonschema.exceptions import ErrorTree + return ErrorTree + elif name == "FormatError": + warnings.warn( + "Importing FormatError directly from the jsonschema package " + "is deprecated and will become an ImportError. Import it from " + "jsonschema.exceptions instead.", + DeprecationWarning, + stacklevel=2, + ) + from jsonschema.exceptions import FormatError + return FormatError + elif name == "Validator": + warnings.warn( + "Importing Validator directly from the jsonschema package " + "is deprecated and will become an ImportError. Import it from " + "jsonschema.protocols instead.", + DeprecationWarning, + stacklevel=2, + ) + from jsonschema.protocols import Validator + return Validator + elif name == "RefResolutionError": + from jsonschema.exceptions import _RefResolutionError + warnings.warn( + _RefResolutionError._DEPRECATION_MESSAGE, + DeprecationWarning, + stacklevel=2, + ) + return _RefResolutionError + + format_checkers = { + "draft3_format_checker": Draft3Validator, + "draft4_format_checker": Draft4Validator, + "draft6_format_checker": Draft6Validator, + "draft7_format_checker": Draft7Validator, + "draft201909_format_checker": Draft201909Validator, + "draft202012_format_checker": Draft202012Validator, + } + ValidatorForFormat = format_checkers.get(name) + if ValidatorForFormat is not None: + warnings.warn( + f"Accessing jsonschema.{name} is deprecated and will be " + "removed in a future release. Instead, use the FORMAT_CHECKER " + "attribute on the corresponding Validator.", + DeprecationWarning, + stacklevel=2, + ) + return ValidatorForFormat.FORMAT_CHECKER + + raise AttributeError(f"module {__name__} has no attribute {name}") + + +__all__ = [ + "Draft3Validator", + "Draft4Validator", + "Draft6Validator", + "Draft7Validator", + "Draft201909Validator", + "Draft202012Validator", + "FormatChecker", + "SchemaError", + "TypeChecker", + "ValidationError", + "validate", +] diff --git a/source/target-vendors/cp312/jsonschema/__main__.py b/source/target-vendors/cp312/jsonschema/__main__.py new file mode 100644 index 0000000..fb260ae --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/__main__.py @@ -0,0 +1,6 @@ +""" +The jsonschema CLI is now deprecated in favor of check-jsonschema. +""" +from jsonschema.cli import main + +main() diff --git a/source/target-vendors/cp312/jsonschema/_format.py b/source/target-vendors/cp312/jsonschema/_format.py new file mode 100644 index 0000000..5efda86 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/_format.py @@ -0,0 +1,546 @@ +from __future__ import annotations + +from contextlib import suppress +from datetime import date, datetime +from uuid import UUID +import ipaddress +import re +import typing +import warnings + +from jsonschema.exceptions import FormatError + +_FormatCheckCallable = typing.Callable[[object], bool] +#: A format checker callable. +_F = typing.TypeVar("_F", bound=_FormatCheckCallable) +_RaisesType = type[Exception] | tuple[type[Exception], ...] + +_RE_DATE = re.compile(r"^\d{4}-\d{2}-\d{2}$", re.ASCII) + + +class FormatChecker: + """ + A ``format`` property checker. + + JSON Schema does not mandate that the ``format`` property actually do any + validation. If validation is desired however, instances of this class can + be hooked into validators to enable format validation. + + `FormatChecker` objects always return ``True`` when asked about + formats that they do not know how to validate. + + To add a check for a custom format use the `FormatChecker.checks` + decorator. + + Arguments: + + formats: + + The known formats to validate. This argument can be used to + limit which formats will be used during validation. + + """ + + checkers: dict[ + str, + tuple[_FormatCheckCallable, _RaisesType], + ] = {} # noqa: RUF012 + + def __init__(self, formats: typing.Iterable[str] | None = None): + if formats is None: + formats = self.checkers.keys() + self.checkers = {k: self.checkers[k] for k in formats} + + def __repr__(self): + return f"" + + def checks( + self, format: str, raises: _RaisesType = (), + ) -> typing.Callable[[_F], _F]: + """ + Register a decorated function as validating a new format. + + Arguments: + + format: + + The format that the decorated function will check. + + raises: + + The exception(s) raised by the decorated function when an + invalid instance is found. + + The exception object will be accessible as the + `jsonschema.exceptions.ValidationError.cause` attribute of the + resulting validation error. + + """ + + def _checks(func: _F) -> _F: + self.checkers[format] = (func, raises) + return func + + return _checks + + @classmethod + def cls_checks( + cls, format: str, raises: _RaisesType = (), + ) -> typing.Callable[[_F], _F]: + warnings.warn( + ( + "FormatChecker.cls_checks is deprecated. Call " + "FormatChecker.checks on a specific FormatChecker instance " + "instead." + ), + DeprecationWarning, + stacklevel=2, + ) + return cls._cls_checks(format=format, raises=raises) + + @classmethod + def _cls_checks( + cls, format: str, raises: _RaisesType = (), + ) -> typing.Callable[[_F], _F]: + def _checks(func: _F) -> _F: + cls.checkers[format] = (func, raises) + return func + + return _checks + + def check(self, instance: object, format: str) -> None: + """ + Check whether the instance conforms to the given format. + + Arguments: + + instance (*any primitive type*, i.e. str, number, bool): + + The instance to check + + format: + + The format that instance should conform to + + Raises: + + FormatError: + + if the instance does not conform to ``format`` + + """ + if format not in self.checkers: + return + + func, raises = self.checkers[format] + result, cause = None, None + try: + result = func(instance) + except raises as e: + cause = e + if not result: + raise FormatError(f"{instance!r} is not a {format!r}", cause=cause) + + def conforms(self, instance: object, format: str) -> bool: + """ + Check whether the instance conforms to the given format. + + Arguments: + + instance (*any primitive type*, i.e. str, number, bool): + + The instance to check + + format: + + The format that instance should conform to + + Returns: + + bool: whether it conformed + + """ + try: + self.check(instance, format) + except FormatError: + return False + else: + return True + + +draft3_format_checker = FormatChecker() +draft4_format_checker = FormatChecker() +draft6_format_checker = FormatChecker() +draft7_format_checker = FormatChecker() +draft201909_format_checker = FormatChecker() +draft202012_format_checker = FormatChecker() + +_draft_checkers: dict[str, FormatChecker] = dict( + draft3=draft3_format_checker, + draft4=draft4_format_checker, + draft6=draft6_format_checker, + draft7=draft7_format_checker, + draft201909=draft201909_format_checker, + draft202012=draft202012_format_checker, +) + + +def _checks_drafts( + name=None, + draft3=None, + draft4=None, + draft6=None, + draft7=None, + draft201909=None, + draft202012=None, + raises=(), +) -> typing.Callable[[_F], _F]: + draft3 = draft3 or name + draft4 = draft4 or name + draft6 = draft6 or name + draft7 = draft7 or name + draft201909 = draft201909 or name + draft202012 = draft202012 or name + + def wrap(func: _F) -> _F: + if draft3: + func = _draft_checkers["draft3"].checks(draft3, raises)(func) + if draft4: + func = _draft_checkers["draft4"].checks(draft4, raises)(func) + if draft6: + func = _draft_checkers["draft6"].checks(draft6, raises)(func) + if draft7: + func = _draft_checkers["draft7"].checks(draft7, raises)(func) + if draft201909: + func = _draft_checkers["draft201909"].checks(draft201909, raises)( + func, + ) + if draft202012: + func = _draft_checkers["draft202012"].checks(draft202012, raises)( + func, + ) + + # Oy. This is bad global state, but relied upon for now, until + # deprecation. See #519 and test_format_checkers_come_with_defaults + FormatChecker._cls_checks( + draft202012 or draft201909 or draft7 or draft6 or draft4 or draft3, + raises, + )(func) + return func + + return wrap + + +@_checks_drafts(name="idn-email") +@_checks_drafts(name="email") +def is_email(instance: object) -> bool: + if not isinstance(instance, str): + return True + return "@" in instance + + +@_checks_drafts( + draft3="ip-address", + draft4="ipv4", + draft6="ipv4", + draft7="ipv4", + draft201909="ipv4", + draft202012="ipv4", + raises=ipaddress.AddressValueError, +) +def is_ipv4(instance: object) -> bool: + if not isinstance(instance, str): + return True + return bool(ipaddress.IPv4Address(instance)) + + +@_checks_drafts(name="ipv6", raises=ipaddress.AddressValueError) +def is_ipv6(instance: object) -> bool: + if not isinstance(instance, str): + return True + address = ipaddress.IPv6Address(instance) + return not getattr(address, "scope_id", "") + + +with suppress(ImportError): + from fqdn import FQDN + + @_checks_drafts( + draft3="host-name", + draft4="hostname", + draft6="hostname", + draft7="hostname", + draft201909="hostname", + draft202012="hostname", + # fqdn.FQDN("") raises a ValueError due to a bug + # however, it's not clear when or if that will be fixed, so catch it + # here for now + raises=ValueError, + ) + def is_host_name(instance: object) -> bool: + if not isinstance(instance, str): + return True + return FQDN(instance, min_labels=1).is_valid + + +with suppress(ImportError): + # The built-in `idna` codec only implements RFC 3890, so we go elsewhere. + import idna + + @_checks_drafts( + draft7="idn-hostname", + draft201909="idn-hostname", + draft202012="idn-hostname", + raises=(idna.IDNAError, UnicodeError), + ) + def is_idn_host_name(instance: object) -> bool: + if not isinstance(instance, str): + return True + idna.encode(instance) + return True + + +try: + import rfc3987 +except ImportError: + with suppress(ImportError): + from rfc3986_validator import validate_rfc3986 + + @_checks_drafts(name="uri") + def is_uri(instance: object) -> bool: + if not isinstance(instance, str): + return True + return validate_rfc3986(instance, rule="URI") + + @_checks_drafts( + draft6="uri-reference", + draft7="uri-reference", + draft201909="uri-reference", + draft202012="uri-reference", + raises=ValueError, + ) + def is_uri_reference(instance: object) -> bool: + if not isinstance(instance, str): + return True + return validate_rfc3986(instance, rule="URI_reference") + + with suppress(ImportError): + from rfc3987_syntax import is_valid_syntax as _rfc3987_is_valid_syntax + + @_checks_drafts( + draft7="iri", + draft201909="iri", + draft202012="iri", + raises=ValueError, + ) + def is_iri(instance: object) -> bool: + if not isinstance(instance, str): + return True + return _rfc3987_is_valid_syntax("iri", instance) + + @_checks_drafts( + draft7="iri-reference", + draft201909="iri-reference", + draft202012="iri-reference", + raises=ValueError, + ) + def is_iri_reference(instance: object) -> bool: + if not isinstance(instance, str): + return True + return _rfc3987_is_valid_syntax("iri_reference", instance) + +else: + + @_checks_drafts( + draft7="iri", + draft201909="iri", + draft202012="iri", + raises=ValueError, + ) + def is_iri(instance: object) -> bool: + if not isinstance(instance, str): + return True + return rfc3987.parse(instance, rule="IRI") + + @_checks_drafts( + draft7="iri-reference", + draft201909="iri-reference", + draft202012="iri-reference", + raises=ValueError, + ) + def is_iri_reference(instance: object) -> bool: + if not isinstance(instance, str): + return True + return rfc3987.parse(instance, rule="IRI_reference") + + @_checks_drafts(name="uri", raises=ValueError) + def is_uri(instance: object) -> bool: + if not isinstance(instance, str): + return True + return rfc3987.parse(instance, rule="URI") + + @_checks_drafts( + draft6="uri-reference", + draft7="uri-reference", + draft201909="uri-reference", + draft202012="uri-reference", + raises=ValueError, + ) + def is_uri_reference(instance: object) -> bool: + if not isinstance(instance, str): + return True + return rfc3987.parse(instance, rule="URI_reference") + + +with suppress(ImportError): + from rfc3339_validator import validate_rfc3339 + + @_checks_drafts(name="date-time") + def is_datetime(instance: object) -> bool: + if not isinstance(instance, str): + return True + return validate_rfc3339(instance.upper()) + + @_checks_drafts( + draft7="time", + draft201909="time", + draft202012="time", + ) + def is_time(instance: object) -> bool: + if not isinstance(instance, str): + return True + return is_datetime("1970-01-01T" + instance) + + +@_checks_drafts(name="regex", raises=re.error) +def is_regex(instance: object) -> bool: + if not isinstance(instance, str): + return True + return bool(re.compile(instance)) + + +@_checks_drafts( + draft3="date", + draft7="date", + draft201909="date", + draft202012="date", + raises=ValueError, +) +def is_date(instance: object) -> bool: + if not isinstance(instance, str): + return True + return bool(_RE_DATE.fullmatch(instance) and date.fromisoformat(instance)) + + +@_checks_drafts(draft3="time", raises=ValueError) +def is_draft3_time(instance: object) -> bool: + if not isinstance(instance, str): + return True + return bool(datetime.strptime(instance, "%H:%M:%S")) # noqa: DTZ007 + + +with suppress(ImportError): + import webcolors + + @_checks_drafts(draft3="color", raises=(ValueError, TypeError)) + def is_css21_color(instance: object) -> bool: + if isinstance(instance, str): + try: + webcolors.name_to_hex(instance) + except ValueError: + webcolors.normalize_hex(instance.lower()) + return True + + +with suppress(ImportError): + import jsonpointer + + @_checks_drafts( + draft6="json-pointer", + draft7="json-pointer", + draft201909="json-pointer", + draft202012="json-pointer", + raises=jsonpointer.JsonPointerException, + ) + def is_json_pointer(instance: object) -> bool: + if not isinstance(instance, str): + return True + return bool(jsonpointer.JsonPointer(instance)) + + # TODO: I don't want to maintain this, so it + # needs to go either into jsonpointer (pending + # https://github.com/stefankoegl/python-json-pointer/issues/34) or + # into a new external library. + @_checks_drafts( + draft7="relative-json-pointer", + draft201909="relative-json-pointer", + draft202012="relative-json-pointer", + raises=jsonpointer.JsonPointerException, + ) + def is_relative_json_pointer(instance: object) -> bool: + # Definition taken from: + # https://tools.ietf.org/html/draft-handrews-relative-json-pointer-01#section-3 + if not isinstance(instance, str): + return True + if not instance: + return False + + non_negative_integer, rest = [], "" + for i, character in enumerate(instance): + if character.isdigit(): + # digits with a leading "0" are not allowed + if i > 0 and int(instance[i - 1]) == 0: + return False + + non_negative_integer.append(character) + continue + + if not non_negative_integer: + return False + + rest = instance[i:] + break + return (rest == "#") or bool(jsonpointer.JsonPointer(rest)) + + +with suppress(ImportError): + import uri_template + + @_checks_drafts( + draft6="uri-template", + draft7="uri-template", + draft201909="uri-template", + draft202012="uri-template", + ) + def is_uri_template(instance: object) -> bool: + if not isinstance(instance, str): + return True + return uri_template.validate(instance) + + +with suppress(ImportError): + import isoduration + + @_checks_drafts( + draft201909="duration", + draft202012="duration", + raises=isoduration.DurationParsingException, + ) + def is_duration(instance: object) -> bool: + if not isinstance(instance, str): + return True + isoduration.parse_duration(instance) + # FIXME: See bolsote/isoduration#25 and bolsote/isoduration#21 + return instance.endswith(tuple("DMYWHMS")) + + +@_checks_drafts( + draft201909="uuid", + draft202012="uuid", + raises=ValueError, +) +def is_uuid(instance: object) -> bool: + if not isinstance(instance, str): + return True + UUID(instance) + return all(instance[position] == "-" for position in (8, 13, 18, 23)) diff --git a/source/target-vendors/cp312/jsonschema/_keywords.py b/source/target-vendors/cp312/jsonschema/_keywords.py new file mode 100644 index 0000000..f30f954 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/_keywords.py @@ -0,0 +1,449 @@ +from fractions import Fraction +import re + +from jsonschema._utils import ( + ensure_list, + equal, + extras_msg, + find_additional_properties, + find_evaluated_item_indexes_by_schema, + find_evaluated_property_keys_by_schema, + uniq, +) +from jsonschema.exceptions import FormatError, ValidationError + + +def patternProperties(validator, patternProperties, instance, schema): + if not validator.is_type(instance, "object"): + return + + for pattern, subschema in patternProperties.items(): + for k, v in instance.items(): + if re.search(pattern, k): + yield from validator.descend( + v, subschema, path=k, schema_path=pattern, + ) + + +def propertyNames(validator, propertyNames, instance, schema): + if not validator.is_type(instance, "object"): + return + + for property in instance: + yield from validator.descend(instance=property, schema=propertyNames) + + +def additionalProperties(validator, aP, instance, schema): + if not validator.is_type(instance, "object"): + return + + extras = set(find_additional_properties(instance, schema)) + + if validator.is_type(aP, "object"): + for extra in extras: + yield from validator.descend(instance[extra], aP, path=extra) + elif not aP and extras: + if "patternProperties" in schema: + verb = "does" if len(extras) == 1 else "do" + joined = ", ".join(repr(each) for each in sorted(extras)) + patterns = ", ".join( + repr(each) for each in sorted(schema["patternProperties"]) + ) + error = f"{joined} {verb} not match any of the regexes: {patterns}" + yield ValidationError(error) + else: + error = "Additional properties are not allowed (%s %s unexpected)" + yield ValidationError(error % extras_msg(sorted(extras, key=str))) + + +def items(validator, items, instance, schema): + if not validator.is_type(instance, "array"): + return + + prefix = len(schema.get("prefixItems", [])) + total = len(instance) + extra = total - prefix + if extra <= 0: + return + + if items is False: + rest = instance[prefix:] if extra != 1 else instance[prefix] + item = "items" if prefix != 1 else "item" + yield ValidationError( + f"Expected at most {prefix} {item} but found {extra} " + f"extra: {rest!r}", + ) + else: + for index in range(prefix, total): + yield from validator.descend( + instance=instance[index], + schema=items, + path=index, + ) + + +def const(validator, const, instance, schema): + if not equal(instance, const): + yield ValidationError(f"{const!r} was expected") + + +def contains(validator, contains, instance, schema): + if not validator.is_type(instance, "array"): + return + + matches = 0 + min_contains = schema.get("minContains", 1) + max_contains = schema.get("maxContains", len(instance)) + + contains_validator = validator.evolve(schema=contains) + + for each in instance: + if contains_validator.is_valid(each): + matches += 1 + if matches > max_contains: + yield ValidationError( + "Too many items match the given schema " + f"(expected at most {max_contains})", + validator="maxContains", + validator_value=max_contains, + ) + return + + if matches < min_contains: + if not matches: + yield ValidationError( + f"{instance!r} does not contain items " + "matching the given schema", + ) + else: + yield ValidationError( + "Too few items match the given schema (expected at least " + f"{min_contains} but only {matches} matched)", + validator="minContains", + validator_value=min_contains, + ) + + +def exclusiveMinimum(validator, minimum, instance, schema): + if not validator.is_type(instance, "number"): + return + + if instance <= minimum: + yield ValidationError( + f"{instance!r} is less than or equal to " + f"the minimum of {minimum!r}", + ) + + +def exclusiveMaximum(validator, maximum, instance, schema): + if not validator.is_type(instance, "number"): + return + + if instance >= maximum: + yield ValidationError( + f"{instance!r} is greater than or equal " + f"to the maximum of {maximum!r}", + ) + + +def minimum(validator, minimum, instance, schema): + if not validator.is_type(instance, "number"): + return + + if instance < minimum: + message = f"{instance!r} is less than the minimum of {minimum!r}" + yield ValidationError(message) + + +def maximum(validator, maximum, instance, schema): + if not validator.is_type(instance, "number"): + return + + if instance > maximum: + message = f"{instance!r} is greater than the maximum of {maximum!r}" + yield ValidationError(message) + + +def multipleOf(validator, dB, instance, schema): + if not validator.is_type(instance, "number"): + return + + if isinstance(dB, float): + quotient = instance / dB + try: + failed = int(quotient) != quotient + except OverflowError: + # When `instance` is large and `dB` is less than one, + # quotient can overflow to infinity; and then casting to int + # raises an error. + # + # In this case we fall back to Fraction logic, which is + # exact and cannot overflow. The performance is also + # acceptable: we try the fast all-float option first, and + # we know that fraction(dB) can have at most a few hundred + # digits in each part. The worst-case slowdown is therefore + # for already-slow enormous integers or Decimals. + failed = (Fraction(instance) / Fraction(dB)).denominator != 1 + else: + failed = instance % dB + + if failed: + yield ValidationError(f"{instance!r} is not a multiple of {dB}") + + +def minItems(validator, mI, instance, schema): + if validator.is_type(instance, "array") and len(instance) < mI: + message = "should be non-empty" if mI == 1 else "is too short" + yield ValidationError(f"{instance!r} {message}") + + +def maxItems(validator, mI, instance, schema): + if validator.is_type(instance, "array") and len(instance) > mI: + message = "is expected to be empty" if mI == 0 else "is too long" + yield ValidationError(f"{instance!r} {message}") + + +def uniqueItems(validator, uI, instance, schema): + if ( + uI + and validator.is_type(instance, "array") + and not uniq(instance) + ): + yield ValidationError(f"{instance!r} has non-unique elements") + + +def pattern(validator, patrn, instance, schema): + if ( + validator.is_type(instance, "string") + and not re.search(patrn, instance) + ): + yield ValidationError(f"{instance!r} does not match {patrn!r}") + + +def format(validator, format, instance, schema): + if validator.format_checker is not None: + try: + validator.format_checker.check(instance, format) + except FormatError as error: + yield ValidationError(error.message, cause=error.cause) + + +def minLength(validator, mL, instance, schema): + if validator.is_type(instance, "string") and len(instance) < mL: + message = "should be non-empty" if mL == 1 else "is too short" + yield ValidationError(f"{instance!r} {message}") + + +def maxLength(validator, mL, instance, schema): + if validator.is_type(instance, "string") and len(instance) > mL: + message = "is expected to be empty" if mL == 0 else "is too long" + yield ValidationError(f"{instance!r} {message}") + + +def dependentRequired(validator, dependentRequired, instance, schema): + if not validator.is_type(instance, "object"): + return + + for property, dependency in dependentRequired.items(): + if property not in instance: + continue + + for each in dependency: + if each not in instance: + message = f"{each!r} is a dependency of {property!r}" + yield ValidationError(message) + + +def dependentSchemas(validator, dependentSchemas, instance, schema): + if not validator.is_type(instance, "object"): + return + + for property, dependency in dependentSchemas.items(): + if property not in instance: + continue + yield from validator.descend( + instance, dependency, schema_path=property, + ) + + +def enum(validator, enums, instance, schema): + if all(not equal(each, instance) for each in enums): + yield ValidationError(f"{instance!r} is not one of {enums!r}") + + +def ref(validator, ref, instance, schema): + yield from validator._validate_reference(ref=ref, instance=instance) + + +def dynamicRef(validator, dynamicRef, instance, schema): + yield from validator._validate_reference(ref=dynamicRef, instance=instance) + + +def type(validator, types, instance, schema): + types = ensure_list(types) + + if not any(validator.is_type(instance, type) for type in types): + reprs = ", ".join(repr(type) for type in types) + yield ValidationError(f"{instance!r} is not of type {reprs}") + + +def properties(validator, properties, instance, schema): + if not validator.is_type(instance, "object"): + return + + for property, subschema in properties.items(): + if property in instance: + yield from validator.descend( + instance[property], + subschema, + path=property, + schema_path=property, + ) + + +def required(validator, required, instance, schema): + if not validator.is_type(instance, "object"): + return + for property in required: + if property not in instance: + yield ValidationError(f"{property!r} is a required property") + + +def minProperties(validator, mP, instance, schema): + if validator.is_type(instance, "object") and len(instance) < mP: + message = ( + "should be non-empty" if mP == 1 + else "does not have enough properties" + ) + yield ValidationError(f"{instance!r} {message}") + + +def maxProperties(validator, mP, instance, schema): + if not validator.is_type(instance, "object"): + return + if validator.is_type(instance, "object") and len(instance) > mP: + message = ( + "is expected to be empty" if mP == 0 + else "has too many properties" + ) + yield ValidationError(f"{instance!r} {message}") + + +def allOf(validator, allOf, instance, schema): + for index, subschema in enumerate(allOf): + yield from validator.descend(instance, subschema, schema_path=index) + + +def anyOf(validator, anyOf, instance, schema): + all_errors = [] + for index, subschema in enumerate(anyOf): + errs = list(validator.descend(instance, subschema, schema_path=index)) + if not errs: + break + all_errors.extend(errs) + else: + yield ValidationError( + f"{instance!r} is not valid under any of the given schemas", + context=all_errors, + ) + + +def oneOf(validator, oneOf, instance, schema): + subschemas = enumerate(oneOf) + all_errors = [] + for index, subschema in subschemas: + errs = list(validator.descend(instance, subschema, schema_path=index)) + if not errs: + first_valid = subschema + break + all_errors.extend(errs) + else: + yield ValidationError( + f"{instance!r} is not valid under any of the given schemas", + context=all_errors, + ) + + more_valid = [ + each for _, each in subschemas + if validator.evolve(schema=each).is_valid(instance) + ] + if more_valid: + more_valid.append(first_valid) + reprs = ", ".join(repr(schema) for schema in more_valid) + yield ValidationError(f"{instance!r} is valid under each of {reprs}") + + +def not_(validator, not_schema, instance, schema): + if validator.evolve(schema=not_schema).is_valid(instance): + message = f"{instance!r} should not be valid under {not_schema!r}" + yield ValidationError(message) + + +def if_(validator, if_schema, instance, schema): + if validator.evolve(schema=if_schema).is_valid(instance): + if "then" in schema: + then = schema["then"] + yield from validator.descend(instance, then, schema_path="then") + elif "else" in schema: + else_ = schema["else"] + yield from validator.descend(instance, else_, schema_path="else") + + +def unevaluatedItems(validator, unevaluatedItems, instance, schema): + if not validator.is_type(instance, "array"): + return + evaluated_item_indexes = find_evaluated_item_indexes_by_schema( + validator, instance, schema, + ) + unevaluated_items = [ + item for index, item in enumerate(instance) + if index not in evaluated_item_indexes + ] + if unevaluated_items: + error = "Unevaluated items are not allowed (%s %s unexpected)" + yield ValidationError(error % extras_msg(unevaluated_items)) + + +def unevaluatedProperties(validator, unevaluatedProperties, instance, schema): + if not validator.is_type(instance, "object"): + return + evaluated_keys = find_evaluated_property_keys_by_schema( + validator, instance, schema, + ) + unevaluated_keys = [] + for property in instance: + if property not in evaluated_keys: + for _ in validator.descend( + instance[property], + unevaluatedProperties, + path=property, + schema_path=property, + ): + # FIXME: Include context for each unevaluated property + # indicating why it's invalid under the subschema. + unevaluated_keys.append(property) # noqa: PERF401 + + if unevaluated_keys: + if unevaluatedProperties is False: + error = "Unevaluated properties are not allowed (%s %s unexpected)" + extras = sorted(unevaluated_keys, key=str) + yield ValidationError(error % extras_msg(extras)) + else: + error = ( + "Unevaluated properties are not valid under " + "the given schema (%s %s unevaluated and invalid)" + ) + yield ValidationError(error % extras_msg(unevaluated_keys)) + + +def prefixItems(validator, prefixItems, instance, schema): + if not validator.is_type(instance, "array"): + return + + for (index, item), subschema in zip(enumerate(instance), prefixItems): + yield from validator.descend( + instance=item, + schema=subschema, + schema_path=index, + path=index, + ) diff --git a/source/target-vendors/cp312/jsonschema/_legacy_keywords.py b/source/target-vendors/cp312/jsonschema/_legacy_keywords.py new file mode 100644 index 0000000..c691589 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/_legacy_keywords.py @@ -0,0 +1,449 @@ +import re + +from referencing.jsonschema import lookup_recursive_ref + +from jsonschema import _utils +from jsonschema.exceptions import ValidationError + + +def ignore_ref_siblings(schema): + """ + Ignore siblings of ``$ref`` if it is present. + + Otherwise, return all keywords. + + Suitable for use with `create`'s ``applicable_validators`` argument. + """ + ref = schema.get("$ref") + if ref is not None: + return [("$ref", ref)] + else: + return schema.items() + + +def dependencies_draft3(validator, dependencies, instance, schema): + if not validator.is_type(instance, "object"): + return + + for property, dependency in dependencies.items(): + if property not in instance: + continue + + if validator.is_type(dependency, "object"): + yield from validator.descend( + instance, dependency, schema_path=property, + ) + elif validator.is_type(dependency, "string"): + if dependency not in instance: + message = f"{dependency!r} is a dependency of {property!r}" + yield ValidationError(message) + else: + for each in dependency: + if each not in instance: + message = f"{each!r} is a dependency of {property!r}" + yield ValidationError(message) + + +def dependencies_draft4_draft6_draft7( + validator, + dependencies, + instance, + schema, +): + """ + Support for the ``dependencies`` keyword from pre-draft 2019-09. + + In later drafts, the keyword was split into separate + ``dependentRequired`` and ``dependentSchemas`` validators. + """ + if not validator.is_type(instance, "object"): + return + + for property, dependency in dependencies.items(): + if property not in instance: + continue + + if validator.is_type(dependency, "array"): + for each in dependency: + if each not in instance: + message = f"{each!r} is a dependency of {property!r}" + yield ValidationError(message) + else: + yield from validator.descend( + instance, dependency, schema_path=property, + ) + + +def disallow_draft3(validator, disallow, instance, schema): + for disallowed in _utils.ensure_list(disallow): + if validator.evolve(schema={"type": [disallowed]}).is_valid(instance): + message = f"{disallowed!r} is disallowed for {instance!r}" + yield ValidationError(message) + + +def extends_draft3(validator, extends, instance, schema): + if validator.is_type(extends, "object"): + yield from validator.descend(instance, extends) + return + for index, subschema in enumerate(extends): + yield from validator.descend(instance, subschema, schema_path=index) + + +def items_draft3_draft4(validator, items, instance, schema): + if not validator.is_type(instance, "array"): + return + + if validator.is_type(items, "object"): + for index, item in enumerate(instance): + yield from validator.descend(item, items, path=index) + else: + for (index, item), subschema in zip(enumerate(instance), items): + yield from validator.descend( + item, subschema, path=index, schema_path=index, + ) + + +def additionalItems(validator, aI, instance, schema): + if ( + not validator.is_type(instance, "array") + or validator.is_type(schema.get("items", {}), "object") + ): + return + + len_items = len(schema.get("items", [])) + if validator.is_type(aI, "object"): + for index, item in enumerate(instance[len_items:], start=len_items): + yield from validator.descend(item, aI, path=index) + elif not aI and len(instance) > len(schema.get("items", [])): + error = "Additional items are not allowed (%s %s unexpected)" + yield ValidationError( + error % _utils.extras_msg(instance[len(schema.get("items", [])):]), + ) + + +def items_draft6_draft7_draft201909(validator, items, instance, schema): + if not validator.is_type(instance, "array"): + return + + if validator.is_type(items, "array"): + for (index, item), subschema in zip(enumerate(instance), items): + yield from validator.descend( + item, subschema, path=index, schema_path=index, + ) + else: + for index, item in enumerate(instance): + yield from validator.descend(item, items, path=index) + + +def minimum_draft3_draft4(validator, minimum, instance, schema): + if not validator.is_type(instance, "number"): + return + + if schema.get("exclusiveMinimum", False): + failed = instance <= minimum + cmp = "less than or equal to" + else: + failed = instance < minimum + cmp = "less than" + + if failed: + message = f"{instance!r} is {cmp} the minimum of {minimum!r}" + yield ValidationError(message) + + +def maximum_draft3_draft4(validator, maximum, instance, schema): + if not validator.is_type(instance, "number"): + return + + if schema.get("exclusiveMaximum", False): + failed = instance >= maximum + cmp = "greater than or equal to" + else: + failed = instance > maximum + cmp = "greater than" + + if failed: + message = f"{instance!r} is {cmp} the maximum of {maximum!r}" + yield ValidationError(message) + + +def properties_draft3(validator, properties, instance, schema): + if not validator.is_type(instance, "object"): + return + + for property, subschema in properties.items(): + if property in instance: + yield from validator.descend( + instance[property], + subschema, + path=property, + schema_path=property, + ) + elif subschema.get("required", False): + error = ValidationError(f"{property!r} is a required property") + error._set( + validator="required", + validator_value=subschema["required"], + instance=instance, + schema=schema, + ) + error.path.appendleft(property) + error.schema_path.extend([property, "required"]) + yield error + + +def type_draft3(validator, types, instance, schema): + types = _utils.ensure_list(types) + + all_errors = [] + for index, type in enumerate(types): + if validator.is_type(type, "object"): + errors = list(validator.descend(instance, type, schema_path=index)) + if not errors: + return + all_errors.extend(errors) + elif validator.is_type(instance, type): + return + + reprs = [] + for type in types: + try: + reprs.append(repr(type["name"])) + except Exception: # noqa: BLE001 + reprs.append(repr(type)) + yield ValidationError( + f"{instance!r} is not of type {', '.join(reprs)}", + context=all_errors, + ) + + +def contains_draft6_draft7(validator, contains, instance, schema): + if not validator.is_type(instance, "array"): + return + + if not any( + validator.evolve(schema=contains).is_valid(element) + for element in instance + ): + yield ValidationError( + f"None of {instance!r} are valid under the given schema", + ) + + +def recursiveRef(validator, recursiveRef, instance, schema): + resolved = lookup_recursive_ref(validator._resolver) + yield from validator.descend( + instance, + resolved.contents, + resolver=resolved.resolver, + ) + + +def find_evaluated_item_indexes_by_schema(validator, instance, schema): + """ + Get all indexes of items that get evaluated under the current schema. + + Covers all keywords related to unevaluatedItems: items, prefixItems, if, + then, else, contains, unevaluatedItems, allOf, oneOf, anyOf + """ + if validator.is_type(schema, "boolean"): + return [] + evaluated_indexes = [] + + ref = schema.get("$ref") + if ref is not None: + resolved = validator._resolver.lookup(ref) + evaluated_indexes.extend( + find_evaluated_item_indexes_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + if "$recursiveRef" in schema: + resolved = lookup_recursive_ref(validator._resolver) + evaluated_indexes.extend( + find_evaluated_item_indexes_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + if "items" in schema: + if "additionalItems" in schema: + return list(range(len(instance))) + + if validator.is_type(schema["items"], "object"): + return list(range(len(instance))) + evaluated_indexes += list(range(len(schema["items"]))) + + if "if" in schema: + if validator.evolve(schema=schema["if"]).is_valid(instance): + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, schema["if"], + ) + if "then" in schema: + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, schema["then"], + ) + elif "else" in schema: + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, schema["else"], + ) + + for keyword in ["contains", "unevaluatedItems"]: + if keyword in schema: + for k, v in enumerate(instance): + if validator.evolve(schema=schema[keyword]).is_valid(v): + evaluated_indexes.append(k) + + for keyword in ["allOf", "oneOf", "anyOf"]: + if keyword in schema: + for subschema in schema[keyword]: + errs = next(validator.descend(instance, subschema), None) + if errs is None: + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, subschema, + ) + + return evaluated_indexes + + +def unevaluatedItems_draft2019(validator, unevaluatedItems, instance, schema): + if not validator.is_type(instance, "array"): + return + evaluated_item_indexes = find_evaluated_item_indexes_by_schema( + validator, instance, schema, + ) + unevaluated_items = [ + item for index, item in enumerate(instance) + if index not in evaluated_item_indexes + ] + if unevaluated_items: + error = "Unevaluated items are not allowed (%s %s unexpected)" + yield ValidationError(error % _utils.extras_msg(unevaluated_items)) + + +def find_evaluated_property_keys_by_schema(validator, instance, schema): + if validator.is_type(schema, "boolean"): + return [] + evaluated_keys = [] + + ref = schema.get("$ref") + if ref is not None: + resolved = validator._resolver.lookup(ref) + evaluated_keys.extend( + find_evaluated_property_keys_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + if "$recursiveRef" in schema: + resolved = lookup_recursive_ref(validator._resolver) + evaluated_keys.extend( + find_evaluated_property_keys_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + for keyword in [ + "properties", "additionalProperties", "unevaluatedProperties", + ]: + if keyword in schema: + schema_value = schema[keyword] + if validator.is_type(schema_value, "boolean") and schema_value: + evaluated_keys += instance.keys() + + elif validator.is_type(schema_value, "object"): + for property in schema_value: + if property in instance: + evaluated_keys.append(property) + + if "patternProperties" in schema: + for property in instance: + for pattern in schema["patternProperties"]: + if re.search(pattern, property): + evaluated_keys.append(property) + + if "dependentSchemas" in schema: + for property, subschema in schema["dependentSchemas"].items(): + if property not in instance: + continue + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, subschema, + ) + + for keyword in ["allOf", "oneOf", "anyOf"]: + if keyword in schema: + for subschema in schema[keyword]: + errs = next(validator.descend(instance, subschema), None) + if errs is None: + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, subschema, + ) + + if "if" in schema: + if validator.evolve(schema=schema["if"]).is_valid(instance): + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, schema["if"], + ) + if "then" in schema: + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, schema["then"], + ) + elif "else" in schema: + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, schema["else"], + ) + + return evaluated_keys + + +def unevaluatedProperties_draft2019(validator, uP, instance, schema): + if not validator.is_type(instance, "object"): + return + evaluated_keys = find_evaluated_property_keys_by_schema( + validator, instance, schema, + ) + unevaluated_keys = [] + for property in instance: + if property not in evaluated_keys: + for _ in validator.descend( + instance[property], + uP, + path=property, + schema_path=property, + ): + # FIXME: Include context for each unevaluated property + # indicating why it's invalid under the subschema. + unevaluated_keys.append(property) # noqa: PERF401 + + if unevaluated_keys: + if uP is False: + error = "Unevaluated properties are not allowed (%s %s unexpected)" + extras = sorted(unevaluated_keys, key=str) + yield ValidationError(error % _utils.extras_msg(extras)) + else: + error = ( + "Unevaluated properties are not valid under " + "the given schema (%s %s unevaluated and invalid)" + ) + yield ValidationError(error % _utils.extras_msg(unevaluated_keys)) diff --git a/source/target-vendors/cp312/jsonschema/_types.py b/source/target-vendors/cp312/jsonschema/_types.py new file mode 100644 index 0000000..fcfe3f0 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/_types.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING +import numbers + +from attrs import evolve, field, frozen +from rpds import HashTrieMap + +from jsonschema.exceptions import UndefinedTypeCheck + +if TYPE_CHECKING: + from collections.abc import Callable, Mapping + from typing import Any + + +# unfortunately, the type of HashTrieMap is generic, and if used as an attrs +# converter, the generic type is presented to mypy, which then fails to match +# the concrete type of a type checker mapping +# this "do nothing" wrapper presents the correct information to mypy +def _typed_map_converter( + init_val: Mapping[str, Callable[[TypeChecker, Any], bool]], +) -> HashTrieMap[str, Callable[[TypeChecker, Any], bool]]: + return HashTrieMap.convert(init_val) + + +def is_array(checker, instance): + return isinstance(instance, list) + + +def is_bool(checker, instance): + return isinstance(instance, bool) + + +def is_integer(checker, instance): + # bool inherits from int, so ensure bools aren't reported as ints + if isinstance(instance, bool): + return False + return isinstance(instance, int) + + +def is_null(checker, instance): + return instance is None + + +def is_number(checker, instance): + # bool inherits from int, so ensure bools aren't reported as ints + if isinstance(instance, bool): + return False + return isinstance(instance, numbers.Number) + + +def is_object(checker, instance): + return isinstance(instance, dict) + + +def is_string(checker, instance): + return isinstance(instance, str) + + +def is_any(checker, instance): + return True + + +@frozen(repr=False) +class TypeChecker: + """ + A :kw:`type` property checker. + + A `TypeChecker` performs type checking for a `Validator`, converting + between the defined JSON Schema types and some associated Python types or + objects. + + Modifying the behavior just mentioned by redefining which Python objects + are considered to be of which JSON Schema types can be done using + `TypeChecker.redefine` or `TypeChecker.redefine_many`, and types can be + removed via `TypeChecker.remove`. Each of these return a new `TypeChecker`. + + Arguments: + + type_checkers: + + The initial mapping of types to their checking functions. + + """ + + _type_checkers: HashTrieMap[ + str, Callable[[TypeChecker, Any], bool], + ] = field(default=HashTrieMap(), converter=_typed_map_converter) + + def __repr__(self): + types = ", ".join(repr(k) for k in sorted(self._type_checkers)) + return f"<{self.__class__.__name__} types={{{types}}}>" + + def is_type(self, instance, type: str) -> bool: + """ + Check if the instance is of the appropriate type. + + Arguments: + + instance: + + The instance to check + + type: + + The name of the type that is expected. + + Raises: + + `jsonschema.exceptions.UndefinedTypeCheck`: + + if ``type`` is unknown to this object. + + """ + try: + fn = self._type_checkers[type] + except KeyError: + raise UndefinedTypeCheck(type) from None + + return fn(self, instance) + + def redefine(self, type: str, fn) -> TypeChecker: + """ + Produce a new checker with the given type redefined. + + Arguments: + + type: + + The name of the type to check. + + fn (collections.abc.Callable): + + A callable taking exactly two parameters - the type + checker calling the function and the instance to check. + The function should return true if instance is of this + type and false otherwise. + + """ + return self.redefine_many({type: fn}) + + def redefine_many(self, definitions=()) -> TypeChecker: + """ + Produce a new checker with the given types redefined. + + Arguments: + + definitions (dict): + + A dictionary mapping types to their checking functions. + + """ + type_checkers = self._type_checkers.update(definitions) + return evolve(self, type_checkers=type_checkers) + + def remove(self, *types) -> TypeChecker: + """ + Produce a new checker with the given types forgotten. + + Arguments: + + types: + + the names of the types to remove. + + Raises: + + `jsonschema.exceptions.UndefinedTypeCheck`: + + if any given type is unknown to this object + + """ + type_checkers = self._type_checkers + for each in types: + try: + type_checkers = type_checkers.remove(each) + except KeyError: + raise UndefinedTypeCheck(each) from None + return evolve(self, type_checkers=type_checkers) + + +draft3_type_checker = TypeChecker( + { + "any": is_any, + "array": is_array, + "boolean": is_bool, + "integer": is_integer, + "object": is_object, + "null": is_null, + "number": is_number, + "string": is_string, + }, +) +draft4_type_checker = draft3_type_checker.remove("any") +draft6_type_checker = draft4_type_checker.redefine( + "integer", + lambda checker, instance: ( + is_integer(checker, instance) + or (isinstance(instance, float) and instance.is_integer()) + ), +) +draft7_type_checker = draft6_type_checker +draft201909_type_checker = draft7_type_checker +draft202012_type_checker = draft201909_type_checker diff --git a/source/target-vendors/cp312/jsonschema/_typing.py b/source/target-vendors/cp312/jsonschema/_typing.py new file mode 100644 index 0000000..f8dda63 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/_typing.py @@ -0,0 +1,29 @@ +""" +Some (initially private) typing helpers for jsonschema's types. +""" +from collections.abc import Callable, Iterable +from typing import Any, Protocol + +import referencing.jsonschema + +from jsonschema.protocols import Validator + + +class SchemaKeywordValidator(Protocol): + def __call__( + self, + validator: Validator, + value: Any, + instance: Any, + schema: referencing.jsonschema.Schema, + ) -> None: + ... + + +id_of = Callable[[referencing.jsonschema.Schema], str | None] + + +ApplicableValidators = Callable[ + [referencing.jsonschema.Schema], + Iterable[tuple[str, Any]], +] diff --git a/source/target-vendors/cp312/jsonschema/_utils.py b/source/target-vendors/cp312/jsonschema/_utils.py new file mode 100644 index 0000000..84a0965 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/_utils.py @@ -0,0 +1,355 @@ +from collections.abc import Mapping, MutableMapping, Sequence +from urllib.parse import urlsplit +import itertools +import re + + +class URIDict(MutableMapping): + """ + Dictionary which uses normalized URIs as keys. + """ + + def normalize(self, uri): + return urlsplit(uri).geturl() + + def __init__(self, *args, **kwargs): + self.store = dict() + self.store.update(*args, **kwargs) + + def __getitem__(self, uri): + return self.store[self.normalize(uri)] + + def __setitem__(self, uri, value): + self.store[self.normalize(uri)] = value + + def __delitem__(self, uri): + del self.store[self.normalize(uri)] + + def __iter__(self): + return iter(self.store) + + def __len__(self): # pragma: no cover -- untested, but to be removed + return len(self.store) + + def __repr__(self): # pragma: no cover -- untested, but to be removed + return repr(self.store) + + +class Unset: + """ + An as-of-yet unset attribute or unprovided default parameter. + """ + + def __repr__(self): # pragma: no cover + return "" + + +def format_as_index(container, indices): + """ + Construct a single string containing indexing operations for the indices. + + For example for a container ``bar``, [1, 2, "foo"] -> bar[1][2]["foo"] + + Arguments: + + container (str): + + A word to use for the thing being indexed + + indices (sequence): + + The indices to format. + + """ + if not indices: + return container + return f"{container}[{']['.join(repr(index) for index in indices)}]" + + +def find_additional_properties(instance, schema): + """ + Return the set of additional properties for the given ``instance``. + + Weeds out properties that should have been validated by ``properties`` and + / or ``patternProperties``. + + Assumes ``instance`` is dict-like already. + """ + properties = schema.get("properties", {}) + patterns = "|".join(schema.get("patternProperties", {})) + for property in instance: + if property not in properties: + if patterns and re.search(patterns, property): + continue + yield property + + +def extras_msg(extras): + """ + Create an error message for extra items or properties. + """ + verb = "was" if len(extras) == 1 else "were" + return ", ".join(repr(extra) for extra in extras), verb + + +def ensure_list(thing): + """ + Wrap ``thing`` in a list if it's a single str. + + Otherwise, return it unchanged. + """ + if isinstance(thing, str): + return [thing] + return thing + + +def _mapping_equal(one, two): + """ + Check if two mappings are equal using the semantics of `equal`. + """ + if len(one) != len(two): + return False + return all( + key in two and equal(value, two[key]) + for key, value in one.items() + ) + + +def _sequence_equal(one, two): + """ + Check if two sequences are equal using the semantics of `equal`. + """ + if len(one) != len(two): + return False + return all(equal(i, j) for i, j in zip(one, two)) + + +def equal(one, two): + """ + Check if two things are equal evading some Python type hierarchy semantics. + + Specifically in JSON Schema, evade `bool` inheriting from `int`, + recursing into sequences to do the same. + """ + if one is two: + return True + if isinstance(one, str) or isinstance(two, str): + return one == two + if isinstance(one, Sequence) and isinstance(two, Sequence): + return _sequence_equal(one, two) + if isinstance(one, Mapping) and isinstance(two, Mapping): + return _mapping_equal(one, two) + return unbool(one) == unbool(two) + + +def unbool(element, true=object(), false=object()): + """ + A hack to make True and 1 and False and 0 unique for ``uniq``. + """ + if element is True: + return true + elif element is False: + return false + return element + + +def uniq(container): + """ + Check if all of a container's elements are unique. + + Tries to rely on the container being recursively sortable, or otherwise + falls back on (slow) brute force. + """ + try: + sort = sorted(unbool(i) for i in container) + sliced = itertools.islice(sort, 1, None) + + for i, j in zip(sort, sliced): + if equal(i, j): + return False + + except (NotImplementedError, TypeError): + seen = [] + for e in container: + e = unbool(e) + + for i in seen: + if equal(i, e): + return False + + seen.append(e) + return True + + +def find_evaluated_item_indexes_by_schema(validator, instance, schema): + """ + Get all indexes of items that get evaluated under the current schema. + + Covers all keywords related to unevaluatedItems: items, prefixItems, if, + then, else, contains, unevaluatedItems, allOf, oneOf, anyOf + """ + if validator.is_type(schema, "boolean"): + return [] + evaluated_indexes = [] + + if "items" in schema: + return list(range(len(instance))) + + ref = schema.get("$ref") + if ref is not None: + resolved = validator._resolver.lookup(ref) + evaluated_indexes.extend( + find_evaluated_item_indexes_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + dynamicRef = schema.get("$dynamicRef") + if dynamicRef is not None: + resolved = validator._resolver.lookup(dynamicRef) + evaluated_indexes.extend( + find_evaluated_item_indexes_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + if "prefixItems" in schema: + evaluated_indexes += list(range(len(schema["prefixItems"]))) + + if "if" in schema: + if validator.evolve(schema=schema["if"]).is_valid(instance): + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, schema["if"], + ) + if "then" in schema: + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, schema["then"], + ) + elif "else" in schema: + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, schema["else"], + ) + + for keyword in ["contains", "unevaluatedItems"]: + if keyword in schema: + for k, v in enumerate(instance): + if validator.evolve(schema=schema[keyword]).is_valid(v): + evaluated_indexes.append(k) + + for keyword in ["allOf", "oneOf", "anyOf"]: + if keyword in schema: + for subschema in schema[keyword]: + errs = next(validator.descend(instance, subschema), None) + if errs is None: + evaluated_indexes += find_evaluated_item_indexes_by_schema( + validator, instance, subschema, + ) + + return evaluated_indexes + + +def find_evaluated_property_keys_by_schema(validator, instance, schema): + """ + Get all keys of items that get evaluated under the current schema. + + Covers all keywords related to unevaluatedProperties: properties, + additionalProperties, unevaluatedProperties, patternProperties, + dependentSchemas, allOf, oneOf, anyOf, if, then, else + """ + if validator.is_type(schema, "boolean"): + return [] + evaluated_keys = [] + + ref = schema.get("$ref") + if ref is not None: + resolved = validator._resolver.lookup(ref) + evaluated_keys.extend( + find_evaluated_property_keys_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + dynamicRef = schema.get("$dynamicRef") + if dynamicRef is not None: + resolved = validator._resolver.lookup(dynamicRef) + evaluated_keys.extend( + find_evaluated_property_keys_by_schema( + validator.evolve( + schema=resolved.contents, + _resolver=resolved.resolver, + ), + instance, + resolved.contents, + ), + ) + + properties = schema.get("properties") + if validator.is_type(properties, "object"): + evaluated_keys += properties.keys() & instance.keys() + + for keyword in ["additionalProperties", "unevaluatedProperties"]: + if (subschema := schema.get(keyword)) is None: + continue + evaluated_keys += ( + key + for key, value in instance.items() + if is_valid(validator.descend(value, subschema)) + ) + + if "patternProperties" in schema: + for property in instance: + for pattern in schema["patternProperties"]: + if re.search(pattern, property): + evaluated_keys.append(property) + + if "dependentSchemas" in schema: + for property, subschema in schema["dependentSchemas"].items(): + if property not in instance: + continue + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, subschema, + ) + + for keyword in ["allOf", "oneOf", "anyOf"]: + for subschema in schema.get(keyword, []): + if not is_valid(validator.descend(instance, subschema)): + continue + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, subschema, + ) + + if "if" in schema: + if validator.evolve(schema=schema["if"]).is_valid(instance): + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, schema["if"], + ) + if "then" in schema: + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, schema["then"], + ) + elif "else" in schema: + evaluated_keys += find_evaluated_property_keys_by_schema( + validator, instance, schema["else"], + ) + + return evaluated_keys + + +def is_valid(errs_it): + """Whether there are no errors in the given iterator.""" + return next(errs_it, None) is None diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/__init__.py b/source/target-vendors/cp312/jsonschema/benchmarks/__init__.py new file mode 100644 index 0000000..e3dcc68 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/__init__.py @@ -0,0 +1,5 @@ +""" +Benchmarks for validation. + +This package is *not* public API. +""" diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/const_vs_enum.py b/source/target-vendors/cp312/jsonschema/benchmarks/const_vs_enum.py new file mode 100644 index 0000000..c6fecd1 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/const_vs_enum.py @@ -0,0 +1,30 @@ +""" +A benchmark for comparing equivalent validation of `const` and `enum`. +""" + +from pyperf import Runner + +from jsonschema import Draft202012Validator + +value = [37] * 100 +const_schema = {"const": list(value)} +enum_schema = {"enum": [list(value)]} + +valid = list(value) +invalid = [*valid, 73] + +const = Draft202012Validator(const_schema) +enum = Draft202012Validator(enum_schema) + +assert const.is_valid(valid) +assert enum.is_valid(valid) +assert not const.is_valid(invalid) +assert not enum.is_valid(invalid) + + +if __name__ == "__main__": + runner = Runner() + runner.bench_func("const valid", lambda: const.is_valid(valid)) + runner.bench_func("const invalid", lambda: const.is_valid(invalid)) + runner.bench_func("enum valid", lambda: enum.is_valid(valid)) + runner.bench_func("enum invalid", lambda: enum.is_valid(invalid)) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/contains.py b/source/target-vendors/cp312/jsonschema/benchmarks/contains.py new file mode 100644 index 0000000..739cd04 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/contains.py @@ -0,0 +1,28 @@ +""" +A benchmark for validation of the `contains` keyword. +""" + +from pyperf import Runner + +from jsonschema import Draft202012Validator + +schema = { + "type": "array", + "contains": {"const": 37}, +} +validator = Draft202012Validator(schema) + +size = 1000 +beginning = [37] + [0] * (size - 1) +middle = [0] * (size // 2) + [37] + [0] * (size // 2) +end = [0] * (size - 1) + [37] +invalid = [0] * size + + +if __name__ == "__main__": + runner = Runner() + runner.bench_func("baseline", lambda: validator.is_valid([])) + runner.bench_func("beginning", lambda: validator.is_valid(beginning)) + runner.bench_func("middle", lambda: validator.is_valid(middle)) + runner.bench_func("end", lambda: validator.is_valid(end)) + runner.bench_func("invalid", lambda: validator.is_valid(invalid)) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/import_benchmark.py b/source/target-vendors/cp312/jsonschema/benchmarks/import_benchmark.py new file mode 100644 index 0000000..59fa921 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/import_benchmark.py @@ -0,0 +1,31 @@ +""" +A benchmark which measures the import time of jsonschema +""" + +import subprocess +import sys + + +def import_time(loops): + total_us = 0 + for _ in range(loops): + p = subprocess.run( # noqa: S603 (arguments are static) + [sys.executable, "-X", "importtime", "-c", "import jsonschema"], + stderr=subprocess.PIPE, + stdout=subprocess.DEVNULL, + check=True, + ) + + line = p.stderr.splitlines()[-1] + field = line.split(b"|")[-2].strip() + us = int(field) # microseconds + total_us += us + + # pyperf expects seconds + return total_us / 1_000_000.0 + +if __name__ == "__main__": + from pyperf import Runner + runner = Runner() + + runner.bench_time_func("Import time (cumulative)", import_time) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/issue232.py b/source/target-vendors/cp312/jsonschema/benchmarks/issue232.py new file mode 100644 index 0000000..efd0715 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/issue232.py @@ -0,0 +1,25 @@ +""" +A performance benchmark using the example from issue #232. + +See https://github.com/python-jsonschema/jsonschema/pull/232. +""" +from pathlib import Path + +from pyperf import Runner +from referencing import Registry + +from jsonschema.tests._suite import Version +import jsonschema + +issue232 = Version( + path=Path(__file__).parent / "issue232", + remotes=Registry(), + name="issue232", +) + + +if __name__ == "__main__": + issue232.benchmark( + runner=Runner(), + Validator=jsonschema.Draft4Validator, + ) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/issue232/issue.json b/source/target-vendors/cp312/jsonschema/benchmarks/issue232/issue.json new file mode 100644 index 0000000..804c340 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/issue232/issue.json @@ -0,0 +1,2653 @@ +[ + { + "description": "Petstore", + "schema": { + "title": "A JSON Schema for Swagger 2.0 API.", + "id": "http://swagger.io/v2/schema.json#", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "required": [ + "swagger", + "info", + "paths" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "swagger": { + "type": "string", + "enum": [ + "2.0" + ], + "description": "The Swagger version of this document." + }, + "info": { + "$ref": "#/definitions/info" + }, + "host": { + "type": "string", + "pattern": "^[^{}/ :\\\\]+(?::\\d+)?$", + "description": "The host (name or ip) of the API. Example: 'swagger.io'" + }, + "basePath": { + "type": "string", + "pattern": "^/", + "description": "The base path to the API. Example: '/api'." + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "consumes": { + "description": "A list of MIME types accepted by the API.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "paths": { + "$ref": "#/definitions/paths" + }, + "definitions": { + "$ref": "#/definitions/definitions" + }, + "parameters": { + "$ref": "#/definitions/parameterDefinitions" + }, + "responses": { + "$ref": "#/definitions/responseDefinitions" + }, + "security": { + "$ref": "#/definitions/security" + }, + "securityDefinitions": { + "$ref": "#/definitions/securityDefinitions" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "definitions": { + "info": { + "type": "object", + "description": "General information about the API.", + "required": [ + "version", + "title" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "title": { + "type": "string", + "description": "A unique and precise title of the API." + }, + "version": { + "type": "string", + "description": "A semantic version number of the API." + }, + "description": { + "type": "string", + "description": "A longer description of the API. Should be different from the title. GitHub Flavored Markdown is allowed." + }, + "termsOfService": { + "type": "string", + "description": "The terms of service for the API." + }, + "contact": { + "$ref": "#/definitions/contact" + }, + "license": { + "$ref": "#/definitions/license" + } + } + }, + "contact": { + "type": "object", + "description": "Contact information for the owners of the API.", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The identifying name of the contact person/organization." + }, + "url": { + "type": "string", + "description": "The URL pointing to the contact information.", + "format": "uri" + }, + "email": { + "type": "string", + "description": "The email address of the contact person/organization.", + "format": "email" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "license": { + "type": "object", + "required": [ + "name" + ], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the license type. It's encouraged to use an OSI compatible license." + }, + "url": { + "type": "string", + "description": "The URL pointing to the license.", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "paths": { + "type": "object", + "description": "Relative paths to the individual endpoints. They must be relative to the 'basePath'.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + }, + "^/": { + "$ref": "#/definitions/pathItem" + } + }, + "additionalProperties": false + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "description": "One or more JSON objects describing the schemas being consumed and produced by the API." + }, + "parameterDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/parameter" + }, + "description": "One or more JSON representations for parameters" + }, + "responseDefinitions": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/response" + }, + "description": "One or more JSON representations for parameters" + }, + "externalDocs": { + "type": "object", + "additionalProperties": false, + "description": "information about external documentation", + "required": [ + "url" + ], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "examples": { + "type": "object", + "additionalProperties": true + }, + "mimeType": { + "type": "string", + "description": "The MIME type of the HTTP message." + }, + "operation": { + "type": "object", + "required": [ + "responses" + ], + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the operation." + }, + "description": { + "type": "string", + "description": "A longer description of the operation, GitHub Flavored Markdown is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string", + "description": "A unique identifier of the operation." + }, + "produces": { + "description": "A list of MIME types the API can produce.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "consumes": { + "description": "A list of MIME types the API can consume.", + "allOf": [ + { + "$ref": "#/definitions/mediaTypeList" + } + ] + }, + "parameters": { + "$ref": "#/definitions/parametersList" + }, + "responses": { + "$ref": "#/definitions/responses" + }, + "schemes": { + "$ref": "#/definitions/schemesList" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "$ref": "#/definitions/security" + } + } + }, + "pathItem": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "get": { + "$ref": "#/definitions/operation" + }, + "put": { + "$ref": "#/definitions/operation" + }, + "post": { + "$ref": "#/definitions/operation" + }, + "delete": { + "$ref": "#/definitions/operation" + }, + "options": { + "$ref": "#/definitions/operation" + }, + "head": { + "$ref": "#/definitions/operation" + }, + "patch": { + "$ref": "#/definitions/operation" + }, + "parameters": { + "$ref": "#/definitions/parametersList" + } + } + }, + "responses": { + "type": "object", + "description": "Response objects names can either be any valid HTTP status code or 'default'.", + "minProperties": 1, + "additionalProperties": false, + "patternProperties": { + "^([0-9]{3})$|^(default)$": { + "$ref": "#/definitions/responseValue" + }, + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "not": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + } + }, + "responseValue": { + "oneOf": [ + { + "$ref": "#/definitions/response" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "response": { + "type": "object", + "required": [ + "description" + ], + "properties": { + "description": { + "type": "string" + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "$ref": "#/definitions/fileSchema" + } + ] + }, + "headers": { + "$ref": "#/definitions/headers" + }, + "examples": { + "$ref": "#/definitions/examples" + } + }, + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/header" + } + }, + "header": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "vendorExtension": { + "description": "Any property starting with x- is valid.", + "additionalProperties": true, + "additionalItems": true + }, + "bodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "schema" + ], + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "body" + ] + }, + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "schema": { + "$ref": "#/definitions/schema" + } + }, + "additionalProperties": false + }, + "headerParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "header" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "queryParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "query" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "formDataParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "required": { + "type": "boolean", + "description": "Determines whether or not this parameter is required or optional.", + "default": false + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "formData" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "allowEmptyValue": { + "type": "boolean", + "default": false, + "description": "allows sending a parameter by name only or with an empty value." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array", + "file" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormatWithMulti" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "pathParameterSubSchema": { + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "required" + ], + "properties": { + "required": { + "type": "boolean", + "enum": [ + true + ], + "description": "Determines whether or not this parameter is required or optional." + }, + "in": { + "type": "string", + "description": "Determines the location of the parameter.", + "enum": [ + "path" + ] + }, + "description": { + "type": "string", + "description": "A brief description of the parameter. This could contain examples of use. GitHub Flavored Markdown is allowed." + }, + "name": { + "type": "string", + "description": "The name of the parameter." + }, + "type": { + "type": "string", + "enum": [ + "string", + "number", + "boolean", + "integer", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + } + }, + "nonBodyParameter": { + "type": "object", + "required": [ + "name", + "in", + "type" + ], + "oneOf": [ + { + "$ref": "#/definitions/headerParameterSubSchema" + }, + { + "$ref": "#/definitions/formDataParameterSubSchema" + }, + { + "$ref": "#/definitions/queryParameterSubSchema" + }, + { + "$ref": "#/definitions/pathParameterSubSchema" + } + ] + }, + "parameter": { + "oneOf": [ + { + "$ref": "#/definitions/bodyParameter" + }, + { + "$ref": "#/definitions/nonBodyParameter" + } + ] + }, + "schema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "$ref": { + "type": "string" + }, + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "maxProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minProperties": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "additionalProperties": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "boolean" + } + ], + "default": {} + }, + "type": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/type" + }, + "items": { + "anyOf": [ + { + "$ref": "#/definitions/schema" + }, + { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + } + ], + "default": {} + }, + "allOf": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/schema" + } + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/schema" + }, + "default": {} + }, + "discriminator": { + "type": "string" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/xml" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "fileSchema": { + "type": "object", + "description": "A deterministic version of a JSON Schema object.", + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "required": [ + "type" + ], + "properties": { + "format": { + "type": "string" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "required": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/stringArray" + }, + "type": { + "type": "string", + "enum": [ + "file" + ] + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "example": {} + }, + "additionalProperties": false + }, + "primitivesItems": { + "type": "object", + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "enum": [ + "string", + "number", + "integer", + "boolean", + "array" + ] + }, + "format": { + "type": "string" + }, + "items": { + "$ref": "#/definitions/primitivesItems" + }, + "collectionFormat": { + "$ref": "#/definitions/collectionFormat" + }, + "default": { + "$ref": "#/definitions/default" + }, + "maximum": { + "$ref": "#/definitions/maximum" + }, + "exclusiveMaximum": { + "$ref": "#/definitions/exclusiveMaximum" + }, + "minimum": { + "$ref": "#/definitions/minimum" + }, + "exclusiveMinimum": { + "$ref": "#/definitions/exclusiveMinimum" + }, + "maxLength": { + "$ref": "#/definitions/maxLength" + }, + "minLength": { + "$ref": "#/definitions/minLength" + }, + "pattern": { + "$ref": "#/definitions/pattern" + }, + "maxItems": { + "$ref": "#/definitions/maxItems" + }, + "minItems": { + "$ref": "#/definitions/minItems" + }, + "uniqueItems": { + "$ref": "#/definitions/uniqueItems" + }, + "enum": { + "$ref": "#/definitions/enum" + }, + "multipleOf": { + "$ref": "#/definitions/multipleOf" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/securityRequirement" + }, + "uniqueItems": true + }, + "securityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true + } + }, + "xml": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "tag": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "securityDefinitions": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/basicAuthenticationSecurity" + }, + { + "$ref": "#/definitions/apiKeySecurity" + }, + { + "$ref": "#/definitions/oauth2ImplicitSecurity" + }, + { + "$ref": "#/definitions/oauth2PasswordSecurity" + }, + { + "$ref": "#/definitions/oauth2ApplicationSecurity" + }, + { + "$ref": "#/definitions/oauth2AccessCodeSecurity" + } + ] + } + }, + "basicAuthenticationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "basic" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "apiKeySecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "name", + "in" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "apiKey" + ] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": [ + "header", + "query" + ] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ImplicitSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "implicit" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2PasswordSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "password" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2ApplicationSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "application" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2AccessCodeSecurity": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "flow", + "authorizationUrl", + "tokenUrl" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "oauth2" + ] + }, + "flow": { + "type": "string", + "enum": [ + "accessCode" + ] + }, + "scopes": { + "$ref": "#/definitions/oauth2Scopes" + }, + "authorizationUrl": { + "type": "string", + "format": "uri" + }, + "tokenUrl": { + "type": "string", + "format": "uri" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + } + }, + "oauth2Scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "mediaTypeList": { + "type": "array", + "items": { + "$ref": "#/definitions/mimeType" + }, + "uniqueItems": true + }, + "parametersList": { + "type": "array", + "description": "The parameters needed to send a valid API call.", + "additionalItems": false, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/parameter" + }, + { + "$ref": "#/definitions/jsonReference" + } + ] + }, + "uniqueItems": true + }, + "schemesList": { + "type": "array", + "description": "The transfer protocol of the API.", + "items": { + "type": "string", + "enum": [ + "http", + "https", + "ws", + "wss" + ] + }, + "uniqueItems": true + }, + "collectionFormat": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes" + ], + "default": "csv" + }, + "collectionFormatWithMulti": { + "type": "string", + "enum": [ + "csv", + "ssv", + "tsv", + "pipes", + "multi" + ], + "default": "csv" + }, + "title": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/title" + }, + "description": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/description" + }, + "default": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/default" + }, + "multipleOf": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/multipleOf" + }, + "maximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/maximum" + }, + "exclusiveMaximum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMaximum" + }, + "minimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/minimum" + }, + "exclusiveMinimum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/exclusiveMinimum" + }, + "maxLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minLength": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "pattern": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/pattern" + }, + "maxItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveInteger" + }, + "minItems": { + "$ref": "http://json-schema.org/draft-04/schema#/definitions/positiveIntegerDefault0" + }, + "uniqueItems": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/uniqueItems" + }, + "enum": { + "$ref": "http://json-schema.org/draft-04/schema#/properties/enum" + }, + "jsonReference": { + "type": "object", + "required": [ + "$ref" + ], + "additionalProperties": false, + "properties": { + "$ref": { + "type": "string" + } + } + } + } + }, + "tests": [ + { + "description": "Example petsore", + "data": { + "swagger": "2.0", + "info": { + "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.", + "version": "1.0.0", + "title": "Swagger Petstore", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "email": "apiteam@swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "petstore.swagger.io", + "basePath": "/v2", + "tags": [ + { + "name": "pet", + "description": "Everything about your Pets", + "externalDocs": { + "description": "Find out more", + "url": "http://swagger.io" + } + }, + { + "name": "store", + "description": "Access to Petstore orders" + }, + { + "name": "user", + "description": "Operations about user", + "externalDocs": { + "description": "Find out more about our store", + "url": "http://swagger.io" + } + } + ], + "schemes": [ + "http" + ], + "paths": { + "/pet": { + "post": { + "tags": [ + "pet" + ], + "summary": "Add a new pet to the store", + "description": "", + "operationId": "addPet", + "consumes": [ + "application/json", + "application/xml" + ], + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Pet object that needs to be added to the store", + "required": true, + "schema": { + "$ref": "#/definitions/Pet" + } + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + }, + "put": { + "tags": [ + "pet" + ], + "summary": "Update an existing pet", + "description": "", + "operationId": "updatePet", + "consumes": [ + "application/json", + "application/xml" + ], + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Pet object that needs to be added to the store", + "required": true, + "schema": { + "$ref": "#/definitions/Pet" + } + } + ], + "responses": { + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + }, + "405": { + "description": "Validation exception" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/findByStatus": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by status", + "description": "Multiple status values can be provided with comma separated strings", + "operationId": "findPetsByStatus", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "status", + "in": "query", + "description": "Status values that need to be considered for filter", + "required": true, + "type": "array", + "items": { + "type": "string", + "enum": [ + "available", + "pending", + "sold" + ], + "default": "available" + }, + "collectionFormat": "multi" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + }, + "400": { + "description": "Invalid status value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/findByTags": { + "get": { + "tags": [ + "pet" + ], + "summary": "Finds Pets by tags", + "description": "Muliple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.", + "operationId": "findPetsByTags", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "tags", + "in": "query", + "description": "Tags to filter by", + "required": true, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + }, + "400": { + "description": "Invalid tag value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ], + "deprecated": true + } + }, + "/pet/{petId}": { + "get": { + "tags": [ + "pet" + ], + "summary": "Find pet by ID", + "description": "Returns a single pet", + "operationId": "getPetById", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "petId", + "in": "path", + "description": "ID of pet to return", + "required": true, + "type": "integer", + "format": "int64" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/Pet" + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + }, + "security": [ + { + "api_key": [] + } + ] + }, + "post": { + "tags": [ + "pet" + ], + "summary": "Updates a pet in the store with form data", + "description": "", + "operationId": "updatePetWithForm", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "petId", + "in": "path", + "description": "ID of pet that needs to be updated", + "required": true, + "type": "integer", + "format": "int64" + }, + { + "name": "name", + "in": "formData", + "description": "Updated name of the pet", + "required": false, + "type": "string" + }, + { + "name": "status", + "in": "formData", + "description": "Updated status of the pet", + "required": false, + "type": "string" + } + ], + "responses": { + "405": { + "description": "Invalid input" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + }, + "delete": { + "tags": [ + "pet" + ], + "summary": "Deletes a pet", + "description": "", + "operationId": "deletePet", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "api_key", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "petId", + "in": "path", + "description": "Pet id to delete", + "required": true, + "type": "integer", + "format": "int64" + } + ], + "responses": { + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Pet not found" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/pet/{petId}/uploadImage": { + "post": { + "tags": [ + "pet" + ], + "summary": "uploads an image", + "description": "", + "operationId": "uploadFile", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "petId", + "in": "path", + "description": "ID of pet to update", + "required": true, + "type": "integer", + "format": "int64" + }, + { + "name": "additionalMetadata", + "in": "formData", + "description": "Additional data to pass to server", + "required": false, + "type": "string" + }, + { + "name": "file", + "in": "formData", + "description": "file to upload", + "required": false, + "type": "file" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/ApiResponse" + } + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ] + } + }, + "/store/inventory": { + "get": { + "tags": [ + "store" + ], + "summary": "Returns pet inventories by status", + "description": "Returns a map of status codes to quantities", + "operationId": "getInventory", + "produces": [ + "application/json" + ], + "parameters": [], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + }, + "security": [ + { + "api_key": [] + } + ] + } + }, + "/store/order": { + "post": { + "tags": [ + "store" + ], + "summary": "Place an order for a pet", + "description": "", + "operationId": "placeOrder", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "order placed for purchasing the pet", + "required": true, + "schema": { + "$ref": "#/definitions/Order" + } + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/Order" + } + }, + "400": { + "description": "Invalid Order" + } + } + } + }, + "/store/order/{orderId}": { + "get": { + "tags": [ + "store" + ], + "summary": "Find purchase order by ID", + "description": "For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions", + "operationId": "getOrderById", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "orderId", + "in": "path", + "description": "ID of pet that needs to be fetched", + "required": true, + "type": "integer", + "maximum": 10.0, + "minimum": 1.0, + "format": "int64" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/Order" + } + }, + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + }, + "delete": { + "tags": [ + "store" + ], + "summary": "Delete purchase order by ID", + "description": "For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors", + "operationId": "deleteOrder", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "orderId", + "in": "path", + "description": "ID of the order that needs to be deleted", + "required": true, + "type": "integer", + "minimum": 1.0, + "format": "int64" + } + ], + "responses": { + "400": { + "description": "Invalid ID supplied" + }, + "404": { + "description": "Order not found" + } + } + } + }, + "/user": { + "post": { + "tags": [ + "user" + ], + "summary": "Create user", + "description": "This can only be done by the logged in user.", + "operationId": "createUser", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Created user object", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/createWithArray": { + "post": { + "tags": [ + "user" + ], + "summary": "Creates list of users with given input array", + "description": "", + "operationId": "createUsersWithArrayInput", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "List of user object", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + } + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/createWithList": { + "post": { + "tags": [ + "user" + ], + "summary": "Creates list of users with given input array", + "description": "", + "operationId": "createUsersWithListInput", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "in": "body", + "name": "body", + "description": "List of user object", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + } + ], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/login": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs user into the system", + "description": "", + "operationId": "loginUser", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "username", + "in": "query", + "description": "The user name for login", + "required": true, + "type": "string" + }, + { + "name": "password", + "in": "query", + "description": "The password for login in clear text", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "string" + }, + "headers": { + "X-Rate-Limit": { + "type": "integer", + "format": "int32", + "description": "calls per hour allowed by the user" + }, + "X-Expires-After": { + "type": "string", + "format": "date-time", + "description": "date in UTC when token expires" + } + } + }, + "400": { + "description": "Invalid username/password supplied" + } + } + } + }, + "/user/logout": { + "get": { + "tags": [ + "user" + ], + "summary": "Logs out current logged in user session", + "description": "", + "operationId": "logoutUser", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [], + "responses": { + "default": { + "description": "successful operation" + } + } + } + }, + "/user/{username}": { + "get": { + "tags": [ + "user" + ], + "summary": "Get user by user name", + "description": "", + "operationId": "getUserByName", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "username", + "in": "path", + "description": "The name that needs to be fetched. Use user1 for testing. ", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "$ref": "#/definitions/User" + } + }, + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + }, + "put": { + "tags": [ + "user" + ], + "summary": "Updated user", + "description": "This can only be done by the logged in user.", + "operationId": "updateUser", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "username", + "in": "path", + "description": "name that need to be updated", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "Updated user object", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "400": { + "description": "Invalid user supplied" + }, + "404": { + "description": "User not found" + } + } + }, + "delete": { + "tags": [ + "user" + ], + "summary": "Delete user", + "description": "This can only be done by the logged in user.", + "operationId": "deleteUser", + "produces": [ + "application/xml", + "application/json" + ], + "parameters": [ + { + "name": "username", + "in": "path", + "description": "The name that needs to be deleted", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid username supplied" + }, + "404": { + "description": "User not found" + } + } + } + } + }, + "securityDefinitions": { + "petstore_auth": { + "type": "oauth2", + "authorizationUrl": "http://petstore.swagger.io/oauth/dialog", + "flow": "implicit", + "scopes": { + "write:pets": "modify pets in your account", + "read:pets": "read your pets" + } + }, + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "header" + } + }, + "definitions": { + "Order": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "petId": { + "type": "integer", + "format": "int64" + }, + "quantity": { + "type": "integer", + "format": "int32" + }, + "shipDate": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "Order Status", + "enum": [ + "placed", + "approved", + "delivered" + ] + }, + "complete": { + "type": "boolean", + "default": false + } + }, + "xml": { + "name": "Order" + } + }, + "Category": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "Category" + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "username": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "password": { + "type": "string" + }, + "phone": { + "type": "string" + }, + "userStatus": { + "type": "integer", + "format": "int32", + "description": "User Status" + } + }, + "xml": { + "name": "User" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "Tag" + } + }, + "Pet": { + "type": "object", + "required": [ + "name", + "photoUrls" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "category": { + "$ref": "#/definitions/Category" + }, + "name": { + "type": "string", + "example": "doggie" + }, + "photoUrls": { + "type": "array", + "xml": { + "name": "photoUrl", + "wrapped": true + }, + "items": { + "type": "string" + } + }, + "tags": { + "type": "array", + "xml": { + "name": "tag", + "wrapped": true + }, + "items": { + "$ref": "#/definitions/Tag" + } + }, + "status": { + "type": "string", + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ] + } + }, + "xml": { + "name": "Pet" + } + }, + "ApiResponse": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "type": { + "type": "string" + }, + "message": { + "type": "string" + } + } + } + }, + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } + }, + "valid": true + } + ] + } +] diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/json_schema_test_suite.py b/source/target-vendors/cp312/jsonschema/benchmarks/json_schema_test_suite.py new file mode 100644 index 0000000..905fb6a --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/json_schema_test_suite.py @@ -0,0 +1,12 @@ +""" +A performance benchmark using the official test suite. + +This benchmarks jsonschema using every valid example in the +JSON-Schema-Test-Suite. It will take some time to complete. +""" +from pyperf import Runner + +from jsonschema.tests._suite import Suite + +if __name__ == "__main__": + Suite().benchmark(runner=Runner()) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/nested_schemas.py b/source/target-vendors/cp312/jsonschema/benchmarks/nested_schemas.py new file mode 100644 index 0000000..b025c47 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/nested_schemas.py @@ -0,0 +1,56 @@ +""" +Validating highly nested schemas shouldn't cause exponential time blowups. + +See https://github.com/python-jsonschema/jsonschema/issues/1097. +""" +from itertools import cycle + +from jsonschema.validators import validator_for + +metaschemaish = { + "$id": "https://example.com/draft/2020-12/schema/strict", + "$schema": "https://json-schema.org/draft/2020-12/schema", + + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": True, + "https://json-schema.org/draft/2020-12/vocab/applicator": True, + "https://json-schema.org/draft/2020-12/vocab/unevaluated": True, + "https://json-schema.org/draft/2020-12/vocab/validation": True, + "https://json-schema.org/draft/2020-12/vocab/meta-data": True, + "https://json-schema.org/draft/2020-12/vocab/format-annotation": True, + "https://json-schema.org/draft/2020-12/vocab/content": True, + }, + "$dynamicAnchor": "meta", + + "$ref": "https://json-schema.org/draft/2020-12/schema", + "unevaluatedProperties": False, +} + + +def nested_schema(levels): + """ + Produce a schema which validates deeply nested objects and arrays. + """ + + names = cycle(["foo", "bar", "baz", "quux", "spam", "eggs"]) + schema = {"type": "object", "properties": {"ham": {"type": "string"}}} + for _, name in zip(range(levels - 1), names): + schema = {"type": "object", "properties": {name: schema}} + return schema + + +validator = validator_for(metaschemaish)(metaschemaish) + +if __name__ == "__main__": + from pyperf import Runner + runner = Runner() + + not_nested = nested_schema(levels=1) + runner.bench_func("not nested", lambda: validator.is_valid(not_nested)) + + for levels in range(1, 11, 3): + schema = nested_schema(levels=levels) + runner.bench_func( + f"nested * {levels}", + lambda schema=schema: validator.is_valid(schema), + ) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/subcomponents.py b/source/target-vendors/cp312/jsonschema/benchmarks/subcomponents.py new file mode 100644 index 0000000..6d78c7b --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/subcomponents.py @@ -0,0 +1,42 @@ +""" +A benchmark which tries to compare the possible slow subparts of validation. +""" +from referencing import Registry +from referencing.jsonschema import DRAFT202012 +from rpds import HashTrieMap, HashTrieSet + +from jsonschema import Draft202012Validator + +schema = { + "type": "array", + "minLength": 1, + "maxLength": 1, + "items": {"type": "integer"}, +} + +hmap = HashTrieMap() +hset = HashTrieSet() + +registry = Registry() + +v = Draft202012Validator(schema) + + +def registry_data_structures(): + return hmap.insert("foo", "bar"), hset.insert("foo") + + +def registry_add(): + resource = DRAFT202012.create_resource(schema) + return registry.with_resource(uri="urn:example", resource=resource) + + +if __name__ == "__main__": + from pyperf import Runner + runner = Runner() + + runner.bench_func("HashMap/HashSet insertion", registry_data_structures) + runner.bench_func("Registry insertion", registry_add) + runner.bench_func("Success", lambda: v.is_valid([1])) + runner.bench_func("Failure", lambda: v.is_valid(["foo"])) + runner.bench_func("Metaschema validation", lambda: v.check_schema(schema)) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/unused_registry.py b/source/target-vendors/cp312/jsonschema/benchmarks/unused_registry.py new file mode 100644 index 0000000..7b272c2 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/unused_registry.py @@ -0,0 +1,35 @@ +""" +An unused schema registry should not cause slower validation. + +"Unused" here means one where no reference resolution is occurring anyhow. + +See https://github.com/python-jsonschema/jsonschema/issues/1088. +""" +from pyperf import Runner +from referencing import Registry +from referencing.jsonschema import DRAFT201909 + +from jsonschema import Draft201909Validator + +registry = Registry().with_resource( + "urn:example:foo", + DRAFT201909.create_resource({}), +) + +schema = {"$ref": "https://json-schema.org/draft/2019-09/schema"} +instance = {"maxLength": 4} + +no_registry = Draft201909Validator(schema) +with_useless_registry = Draft201909Validator(schema, registry=registry) + +if __name__ == "__main__": + runner = Runner() + + runner.bench_func( + "no registry", + lambda: no_registry.is_valid(instance), + ) + runner.bench_func( + "useless registry", + lambda: with_useless_registry.is_valid(instance), + ) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/useless_applicator_schemas.py b/source/target-vendors/cp312/jsonschema/benchmarks/useless_applicator_schemas.py new file mode 100644 index 0000000..f3229c0 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/useless_applicator_schemas.py @@ -0,0 +1,106 @@ + +""" +A benchmark for validation of applicators containing lots of useless schemas. + +Signals a small possible optimization to remove all such schemas ahead of time. +""" + +from pyperf import Runner + +from jsonschema import Draft202012Validator as Validator + +NUM_USELESS = 100000 + +subschema = {"const": 37} + +valid = 37 +invalid = 12 + +baseline = Validator(subschema) + + +# These should be indistinguishable from just `subschema` +by_name = { + "single subschema": { + "anyOf": Validator({"anyOf": [subschema]}), + "allOf": Validator({"allOf": [subschema]}), + "oneOf": Validator({"oneOf": [subschema]}), + }, + "redundant subschemas": { + "anyOf": Validator({"anyOf": [subschema] * NUM_USELESS}), + "allOf": Validator({"allOf": [subschema] * NUM_USELESS}), + }, + "useless successful subschemas (beginning)": { + "anyOf": Validator({"anyOf": [subschema, *[True] * NUM_USELESS]}), + "allOf": Validator({"allOf": [subschema, *[True] * NUM_USELESS]}), + }, + "useless successful subschemas (middle)": { + "anyOf": Validator( + { + "anyOf": [ + *[True] * (NUM_USELESS // 2), + subschema, + *[True] * (NUM_USELESS // 2), + ], + }, + ), + "allOf": Validator( + { + "allOf": [ + *[True] * (NUM_USELESS // 2), + subschema, + *[True] * (NUM_USELESS // 2), + ], + }, + ), + }, + "useless successful subschemas (end)": { + "anyOf": Validator({"anyOf": [*[True] * NUM_USELESS, subschema]}), + "allOf": Validator({"allOf": [*[True] * NUM_USELESS, subschema]}), + }, + "useless failing subschemas (beginning)": { + "anyOf": Validator({"anyOf": [subschema, *[False] * NUM_USELESS]}), + "oneOf": Validator({"oneOf": [subschema, *[False] * NUM_USELESS]}), + }, + "useless failing subschemas (middle)": { + "anyOf": Validator( + { + "anyOf": [ + *[False] * (NUM_USELESS // 2), + subschema, + *[False] * (NUM_USELESS // 2), + ], + }, + ), + "oneOf": Validator( + { + "oneOf": [ + *[False] * (NUM_USELESS // 2), + subschema, + *[False] * (NUM_USELESS // 2), + ], + }, + ), + }, + "useless failing subschemas (end)": { + "anyOf": Validator({"anyOf": [*[False] * NUM_USELESS, subschema]}), + "oneOf": Validator({"oneOf": [*[False] * NUM_USELESS, subschema]}), + }, +} + +if __name__ == "__main__": + runner = Runner() + + runner.bench_func("baseline valid", lambda: baseline.is_valid(valid)) + runner.bench_func("baseline invalid", lambda: baseline.is_valid(invalid)) + + for group, applicators in by_name.items(): + for applicator, validator in applicators.items(): + runner.bench_func( + f"{group}: {applicator} valid", + lambda validator=validator: validator.is_valid(valid), + ) + runner.bench_func( + f"{group}: {applicator} invalid", + lambda validator=validator: validator.is_valid(invalid), + ) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/useless_keywords.py b/source/target-vendors/cp312/jsonschema/benchmarks/useless_keywords.py new file mode 100644 index 0000000..50f4359 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/useless_keywords.py @@ -0,0 +1,32 @@ +""" +A benchmark for validation of schemas containing lots of useless keywords. + +Checks we filter them out once, ahead of time. +""" + +from pyperf import Runner + +from jsonschema import Draft202012Validator + +NUM_USELESS = 100000 +schema = dict( + [ + ("not", {"const": 42}), + *((str(i), i) for i in range(NUM_USELESS)), + ("type", "integer"), + *((str(i), i) for i in range(NUM_USELESS, NUM_USELESS)), + ("minimum", 37), + ], +) +validator = Draft202012Validator(schema) + +valid = 3737 +invalid = 12 + + +if __name__ == "__main__": + runner = Runner() + runner.bench_func("beginning of schema", lambda: validator.is_valid(42)) + runner.bench_func("middle of schema", lambda: validator.is_valid("foo")) + runner.bench_func("end of schema", lambda: validator.is_valid(12)) + runner.bench_func("valid", lambda: validator.is_valid(3737)) diff --git a/source/target-vendors/cp312/jsonschema/benchmarks/validator_creation.py b/source/target-vendors/cp312/jsonschema/benchmarks/validator_creation.py new file mode 100644 index 0000000..4baeb3a --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/benchmarks/validator_creation.py @@ -0,0 +1,14 @@ +from pyperf import Runner + +from jsonschema import Draft202012Validator + +schema = { + "type": "array", + "minLength": 1, + "maxLength": 1, + "items": {"type": "integer"}, +} + + +if __name__ == "__main__": + Runner().bench_func("validator creation", Draft202012Validator, schema) diff --git a/source/target-vendors/cp312/jsonschema/cli.py b/source/target-vendors/cp312/jsonschema/cli.py new file mode 100644 index 0000000..f3ca4d6 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/cli.py @@ -0,0 +1,292 @@ +""" +The ``jsonschema`` command line. +""" + +from importlib import metadata +from json import JSONDecodeError +from pkgutil import resolve_name +from textwrap import dedent +import argparse +import json +import sys +import traceback +import warnings + +from attrs import define, field + +from jsonschema.exceptions import SchemaError +from jsonschema.validators import _RefResolver, validator_for + +warnings.warn( + ( + "The jsonschema CLI is deprecated and will be removed in a future " + "version. Please use check-jsonschema instead, which can be installed " + "from https://pypi.org/project/check-jsonschema/" + ), + DeprecationWarning, + stacklevel=2, +) + + +class _CannotLoadFile(Exception): + pass + + +@define +class _Outputter: + + _formatter = field() + _stdout = field() + _stderr = field() + + @classmethod + def from_arguments(cls, arguments, stdout, stderr): + if arguments["output"] == "plain": + formatter = _PlainFormatter(arguments["error_format"]) + elif arguments["output"] == "pretty": + formatter = _PrettyFormatter() + return cls(formatter=formatter, stdout=stdout, stderr=stderr) + + def load(self, path): + try: + file = open(path) # noqa: SIM115, PTH123 + except FileNotFoundError as error: + self.filenotfound_error(path=path, exc_info=sys.exc_info()) + raise _CannotLoadFile() from error + + with file: + try: + return json.load(file) + except JSONDecodeError as error: + self.parsing_error(path=path, exc_info=sys.exc_info()) + raise _CannotLoadFile() from error + + def filenotfound_error(self, **kwargs): + self._stderr.write(self._formatter.filenotfound_error(**kwargs)) + + def parsing_error(self, **kwargs): + self._stderr.write(self._formatter.parsing_error(**kwargs)) + + def validation_error(self, **kwargs): + self._stderr.write(self._formatter.validation_error(**kwargs)) + + def validation_success(self, **kwargs): + self._stdout.write(self._formatter.validation_success(**kwargs)) + + +@define +class _PrettyFormatter: + + _ERROR_MSG = dedent( + """\ + ===[{type}]===({path})=== + + {body} + ----------------------------- + """, + ) + _SUCCESS_MSG = "===[SUCCESS]===({path})===\n" + + def filenotfound_error(self, path, exc_info): + return self._ERROR_MSG.format( + path=path, + type="FileNotFoundError", + body=f"{path!r} does not exist.", + ) + + def parsing_error(self, path, exc_info): + exc_type, exc_value, exc_traceback = exc_info + exc_lines = "".join( + traceback.format_exception(exc_type, exc_value, exc_traceback), + ) + return self._ERROR_MSG.format( + path=path, + type=exc_type.__name__, + body=exc_lines, + ) + + def validation_error(self, instance_path, error): + return self._ERROR_MSG.format( + path=instance_path, + type=error.__class__.__name__, + body=error, + ) + + def validation_success(self, instance_path): + return self._SUCCESS_MSG.format(path=instance_path) + + +@define +class _PlainFormatter: + + _error_format = field() + + def filenotfound_error(self, path, exc_info): + return f"{path!r} does not exist.\n" + + def parsing_error(self, path, exc_info): + return "Failed to parse {}: {}\n".format( + "" if path == "" else repr(path), + exc_info[1], + ) + + def validation_error(self, instance_path, error): + return self._error_format.format(file_name=instance_path, error=error) + + def validation_success(self, instance_path): + return "" + + +def _resolve_name_with_default(name): + if "." not in name: + name = "jsonschema." + name + return resolve_name(name) + + +parser = argparse.ArgumentParser( + description="JSON Schema Validation CLI", +) +parser.add_argument( + "-i", "--instance", + action="append", + dest="instances", + help=""" + a path to a JSON instance (i.e. filename.json) to validate (may + be specified multiple times). If no instances are provided via this + option, one will be expected on standard input. + """, +) +parser.add_argument( + "-F", "--error-format", + help=""" + the format to use for each validation error message, specified + in a form suitable for str.format. This string will be passed + one formatted object named 'error' for each ValidationError. + Only provide this option when using --output=plain, which is the + default. If this argument is unprovided and --output=plain is + used, a simple default representation will be used. + """, +) +parser.add_argument( + "-o", "--output", + choices=["plain", "pretty"], + default="plain", + help=""" + an output format to use. 'plain' (default) will produce minimal + text with one line for each error, while 'pretty' will produce + more detailed human-readable output on multiple lines. + """, +) +parser.add_argument( + "-V", "--validator", + type=_resolve_name_with_default, + help=""" + the fully qualified object name of a validator to use, or, for + validators that are registered with jsonschema, simply the name + of the class. + """, +) +parser.add_argument( + "--base-uri", + help=""" + a base URI to assign to the provided schema, even if it does not + declare one (via e.g. $id). This option can be used if you wish to + resolve relative references to a particular URI (or local path) + """, +) +parser.add_argument( + "--version", + action="version", + version=metadata.version("jsonschema"), +) +parser.add_argument( + "schema", + help="the path to a JSON Schema to validate with (i.e. schema.json)", +) + + +def parse_args(args): # noqa: D103 + arguments = vars(parser.parse_args(args=args or ["--help"])) + if arguments["output"] != "plain" and arguments["error_format"]: + raise parser.error( + "--error-format can only be used with --output plain", + ) + if arguments["output"] == "plain" and arguments["error_format"] is None: + arguments["error_format"] = "{error.instance}: {error.message}\n" + return arguments + + +def _validate_instance(instance_path, instance, validator, outputter): + invalid = False + for error in validator.iter_errors(instance): + invalid = True + outputter.validation_error(instance_path=instance_path, error=error) + + if not invalid: + outputter.validation_success(instance_path=instance_path) + return invalid + + +def main(args=sys.argv[1:]): # noqa: D103 + sys.exit(run(arguments=parse_args(args=args))) + + +def run(arguments, stdout=sys.stdout, stderr=sys.stderr, stdin=sys.stdin): # noqa: D103 + outputter = _Outputter.from_arguments( + arguments=arguments, + stdout=stdout, + stderr=stderr, + ) + + try: + schema = outputter.load(arguments["schema"]) + except _CannotLoadFile: + return 1 + + Validator = arguments["validator"] + if Validator is None: + Validator = validator_for(schema) + + try: + Validator.check_schema(schema) + except SchemaError as error: + outputter.validation_error( + instance_path=arguments["schema"], + error=error, + ) + return 1 + + if arguments["instances"]: + load, instances = outputter.load, arguments["instances"] + else: + def load(_): + try: + return json.load(stdin) + except JSONDecodeError as error: + outputter.parsing_error( + path="", exc_info=sys.exc_info(), + ) + raise _CannotLoadFile() from error + instances = [""] + + resolver = _RefResolver( + base_uri=arguments["base_uri"], + referrer=schema, + ) if arguments["base_uri"] is not None else None + + validator = Validator(schema, resolver=resolver) + exit_code = 0 + for each in instances: + try: + instance = load(each) + except _CannotLoadFile: + exit_code = 1 + else: + exit_code |= _validate_instance( + instance_path=each, + instance=instance, + validator=validator, + outputter=outputter, + ) + + return exit_code diff --git a/source/target-vendors/cp312/jsonschema/exceptions.py b/source/target-vendors/cp312/jsonschema/exceptions.py new file mode 100644 index 0000000..d955e35 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/exceptions.py @@ -0,0 +1,490 @@ +""" +Validation errors, and some surrounding helpers. +""" +from __future__ import annotations + +from collections import defaultdict, deque +from pprint import pformat +from textwrap import dedent, indent +from typing import TYPE_CHECKING, Any, ClassVar +import heapq +import re +import warnings + +from attrs import define +from referencing.exceptions import Unresolvable as _Unresolvable + +from jsonschema import _utils + +if TYPE_CHECKING: + from collections.abc import Iterable, Mapping, MutableMapping, Sequence + + from jsonschema import _types + +WEAK_MATCHES: frozenset[str] = frozenset(["anyOf", "oneOf"]) +STRONG_MATCHES: frozenset[str] = frozenset() + +_JSON_PATH_COMPATIBLE_PROPERTY_PATTERN = re.compile("^[a-zA-Z][a-zA-Z0-9_]*$") + +_unset = _utils.Unset() + + +def _pretty(thing: Any, prefix: str): + """ + Format something for an error message as prettily as we currently can. + """ + return indent(pformat(thing, width=72, sort_dicts=False), prefix).lstrip() + + +def __getattr__(name): + if name == "RefResolutionError": + warnings.warn( + _RefResolutionError._DEPRECATION_MESSAGE, + DeprecationWarning, + stacklevel=2, + ) + return _RefResolutionError + raise AttributeError(f"module {__name__} has no attribute {name}") + + +class _Error(Exception): + + _word_for_schema_in_error_message: ClassVar[str] + _word_for_instance_in_error_message: ClassVar[str] + + def __init__( + self, + message: str, + validator: str = _unset, # type: ignore[assignment] + path: Iterable[str | int] = (), + cause: Exception | None = None, + context=(), + validator_value: Any = _unset, + instance: Any = _unset, + schema: Mapping[str, Any] | bool = _unset, # type: ignore[assignment] + schema_path: Iterable[str | int] = (), + parent: _Error | None = None, + type_checker: _types.TypeChecker = _unset, # type: ignore[assignment] + ) -> None: + super().__init__( + message, + validator, + path, + cause, + context, + validator_value, + instance, + schema, + schema_path, + parent, + ) + self.message = message + self.path = self.relative_path = deque(path) + self.schema_path = self.relative_schema_path = deque(schema_path) + self.context = list(context) + self.cause = self.__cause__ = cause + self.validator = validator + self.validator_value = validator_value + self.instance = instance + self.schema = schema + self.parent = parent + self._type_checker = type_checker + + for error in context: + error.parent = self + + def __repr__(self) -> str: + return f"<{self.__class__.__name__}: {self.message!r}>" + + def __str__(self) -> str: + essential_for_verbose = ( + self.validator, self.validator_value, self.instance, self.schema, + ) + if any(m is _unset for m in essential_for_verbose): + return self.message + + schema_path = _utils.format_as_index( + container=self._word_for_schema_in_error_message, + indices=list(self.relative_schema_path)[:-1], + ) + instance_path = _utils.format_as_index( + container=self._word_for_instance_in_error_message, + indices=self.relative_path, + ) + prefix = 16 * " " + + return dedent( + f"""\ + {self.message} + + Failed validating {self.validator!r} in {schema_path}: + {_pretty(self.schema, prefix=prefix)} + + On {instance_path}: + {_pretty(self.instance, prefix=prefix)} + """.rstrip(), + ) + + @classmethod + def create_from(cls, other: _Error): + return cls(**other._contents()) + + @property + def absolute_path(self) -> Sequence[str | int]: + parent = self.parent + if parent is None: + return self.relative_path + + path = deque(self.relative_path) + path.extendleft(reversed(parent.absolute_path)) + return path + + @property + def absolute_schema_path(self) -> Sequence[str | int]: + parent = self.parent + if parent is None: + return self.relative_schema_path + + path = deque(self.relative_schema_path) + path.extendleft(reversed(parent.absolute_schema_path)) + return path + + @property + def json_path(self) -> str: + path = "$" + for elem in self.absolute_path: + if isinstance(elem, int): + path += "[" + str(elem) + "]" + elif _JSON_PATH_COMPATIBLE_PROPERTY_PATTERN.match(elem): + path += "." + elem + else: + escaped_elem = elem.replace("\\", "\\\\").replace("'", r"\'") + path += "['" + escaped_elem + "']" + return path + + def _set( + self, + type_checker: _types.TypeChecker | None = None, + **kwargs: Any, + ) -> None: + if type_checker is not None and self._type_checker is _unset: + self._type_checker = type_checker + + for k, v in kwargs.items(): + if getattr(self, k) is _unset: + setattr(self, k, v) + + def _contents(self): + attrs = ( + "message", "cause", "context", "validator", "validator_value", + "path", "schema_path", "instance", "schema", "parent", + ) + return {attr: getattr(self, attr) for attr in attrs} + + def _matches_type(self) -> bool: + try: + # We ignore this as we want to simply crash if this happens + expected = self.schema["type"] # type: ignore[index] + except (KeyError, TypeError): + return False + + if isinstance(expected, str): + return self._type_checker.is_type(self.instance, expected) + + return any( + self._type_checker.is_type(self.instance, expected_type) + for expected_type in expected + ) + + +class ValidationError(_Error): + """ + An instance was invalid under a provided schema. + """ + + _word_for_schema_in_error_message = "schema" + _word_for_instance_in_error_message = "instance" + + +class SchemaError(_Error): + """ + A schema was invalid under its corresponding metaschema. + """ + + _word_for_schema_in_error_message = "metaschema" + _word_for_instance_in_error_message = "schema" + + +@define(slots=False) +class _RefResolutionError(Exception): # noqa: PLW1641 + """ + A ref could not be resolved. + """ + + _DEPRECATION_MESSAGE = ( + "jsonschema.exceptions.RefResolutionError is deprecated as of version " + "4.18.0. If you wish to catch potential reference resolution errors, " + "directly catch referencing.exceptions.Unresolvable." + ) + + _cause: Exception + + def __eq__(self, other): + if self.__class__ is not other.__class__: + return NotImplemented # pragma: no cover -- uncovered but deprecated # noqa: E501 + return self._cause == other._cause + + def __str__(self) -> str: + return str(self._cause) + + +class _WrappedReferencingError(_RefResolutionError, _Unresolvable): # pragma: no cover -- partially uncovered but to be removed # noqa: E501 + def __init__(self, cause: _Unresolvable): + object.__setattr__(self, "_wrapped", cause) + + def __eq__(self, other): + if other.__class__ is self.__class__: + return self._wrapped == other._wrapped + elif other.__class__ is self._wrapped.__class__: + return self._wrapped == other + return NotImplemented + + def __getattr__(self, attr): + return getattr(self._wrapped, attr) + + def __hash__(self): + return hash(self._wrapped) + + def __repr__(self): + return f"" + + def __str__(self): + return f"{self._wrapped.__class__.__name__}: {self._wrapped}" + + +class UndefinedTypeCheck(Exception): + """ + A type checker was asked to check a type it did not have registered. + """ + + def __init__(self, type: str) -> None: + self.type = type + + def __str__(self) -> str: + return f"Type {self.type!r} is unknown to this type checker" + + +class UnknownType(Exception): + """ + A validator was asked to validate an instance against an unknown type. + """ + + def __init__(self, type, instance, schema): + self.type = type + self.instance = instance + self.schema = schema + + def __str__(self): + prefix = 16 * " " + + return dedent( + f"""\ + Unknown type {self.type!r} for validator with schema: + {_pretty(self.schema, prefix=prefix)} + + While checking instance: + {_pretty(self.instance, prefix=prefix)} + """.rstrip(), + ) + + +class FormatError(Exception): + """ + Validating a format failed. + """ + + def __init__(self, message, cause=None): + super().__init__(message, cause) + self.message = message + self.cause = self.__cause__ = cause + + def __str__(self): + return self.message + + +class ErrorTree: + """ + ErrorTrees make it easier to check which validations failed. + """ + + _instance = _unset + + def __init__(self, errors: Iterable[ValidationError] = ()): + self.errors: MutableMapping[str, ValidationError] = {} + self._contents: Mapping[str, ErrorTree] = defaultdict(self.__class__) + + for error in errors: + container = self + for element in error.path: + container = container[element] + container.errors[error.validator] = error + + container._instance = error.instance + + def __contains__(self, index: str | int): + """ + Check whether ``instance[index]`` has any errors. + """ + return index in self._contents + + def __getitem__(self, index): + """ + Retrieve the child tree one level down at the given ``index``. + + If the index is not in the instance that this tree corresponds + to and is not known by this tree, whatever error would be raised + by ``instance.__getitem__`` will be propagated (usually this is + some subclass of `LookupError`. + """ + if self._instance is not _unset and index not in self: + self._instance[index] + return self._contents[index] + + def __setitem__(self, index: str | int, value: ErrorTree): + """ + Add an error to the tree at the given ``index``. + + .. deprecated:: v4.20.0 + + Setting items on an `ErrorTree` is deprecated without replacement. + To populate a tree, provide all of its sub-errors when you + construct the tree. + """ + warnings.warn( + "ErrorTree.__setitem__ is deprecated without replacement.", + DeprecationWarning, + stacklevel=2, + ) + self._contents[index] = value # type: ignore[index] + + def __iter__(self): + """ + Iterate (non-recursively) over the indices in the instance with errors. + """ + return iter(self._contents) + + def __len__(self): + """ + Return the `total_errors`. + """ + return self.total_errors + + def __repr__(self): + total = len(self) + errors = "error" if total == 1 else "errors" + return f"<{self.__class__.__name__} ({total} total {errors})>" + + @property + def total_errors(self): + """ + The total number of errors in the entire tree, including children. + """ + child_errors = sum(len(tree) for _, tree in self._contents.items()) + return len(self.errors) + child_errors + + +def by_relevance(weak=WEAK_MATCHES, strong=STRONG_MATCHES): + """ + Create a key function that can be used to sort errors by relevance. + + Arguments: + weak (set): + a collection of validation keywords to consider to be + "weak". If there are two errors at the same level of the + instance and one is in the set of weak validation keywords, + the other error will take priority. By default, :kw:`anyOf` + and :kw:`oneOf` are considered weak keywords and will be + superseded by other same-level validation errors. + + strong (set): + a collection of validation keywords to consider to be + "strong" + + """ + + def relevance(error): + validator = error.validator + return ( # prefer errors which are ... + -len(error.path), # 'deeper' and thereby more specific + error.path, # earlier (for sibling errors) + validator not in weak, # for a non-low-priority keyword + validator in strong, # for a high priority keyword + not error._matches_type(), # at least match the instance's type + ) # otherwise we'll treat them the same + + return relevance + + +relevance = by_relevance() +""" +A key function (e.g. to use with `sorted`) which sorts errors by relevance. + +Example: + +.. code:: python + + sorted(validator.iter_errors(12), key=jsonschema.exceptions.relevance) +""" + + +def best_match(errors, key=relevance): + """ + Try to find an error that appears to be the best match among given errors. + + In general, errors that are higher up in the instance (i.e. for which + `ValidationError.path` is shorter) are considered better matches, + since they indicate "more" is wrong with the instance. + + If the resulting match is either :kw:`oneOf` or :kw:`anyOf`, the + *opposite* assumption is made -- i.e. the deepest error is picked, + since these keywords only need to match once, and any other errors + may not be relevant. + + Arguments: + errors (collections.abc.Iterable): + + the errors to select from. Do not provide a mixture of + errors from different validation attempts (i.e. from + different instances or schemas), since it won't produce + sensical output. + + key (collections.abc.Callable): + + the key to use when sorting errors. See `relevance` and + transitively `by_relevance` for more details (the default is + to sort with the defaults of that function). Changing the + default is only useful if you want to change the function + that rates errors but still want the error context descent + done by this function. + + Returns: + the best matching error, or ``None`` if the iterable was empty + + .. note:: + + This function is a heuristic. Its return value may change for a given + set of inputs from version to version if better heuristics are added. + + """ + best = max(errors, key=key, default=None) + if best is None: + return + + while best.context: + # Calculate the minimum via nsmallest, because we don't recurse if + # all nested errors have the same relevance (i.e. if min == max == all) + smallest = heapq.nsmallest(2, best.context, key=key) + if len(smallest) == 2 and key(smallest[0]) == key(smallest[1]): # noqa: PLR2004 + return best + best = smallest[0] + return best diff --git a/source/target-vendors/cp312/jsonschema/protocols.py b/source/target-vendors/cp312/jsonschema/protocols.py new file mode 100644 index 0000000..b6288dc --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/protocols.py @@ -0,0 +1,230 @@ +""" +typing.Protocol classes for jsonschema interfaces. +""" + +# for reference material on Protocols, see +# https://www.python.org/dev/peps/pep-0544/ + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, ClassVar, Protocol, runtime_checkable + +# in order for Sphinx to resolve references accurately from type annotations, +# it needs to see names like `jsonschema.TypeChecker` +# therefore, only import at type-checking time (to avoid circular references), +# but use `jsonschema` for any types which will otherwise not be resolvable +if TYPE_CHECKING: + from collections.abc import Iterable, Mapping + + import referencing.jsonschema + + from jsonschema import _typing + from jsonschema.exceptions import ValidationError + import jsonschema + import jsonschema.validators + +# For code authors working on the validator protocol, these are the three +# use-cases which should be kept in mind: +# +# 1. As a protocol class, it can be used in type annotations to describe the +# available methods and attributes of a validator +# 2. It is the source of autodoc for the validator documentation +# 3. It is runtime_checkable, meaning that it can be used in isinstance() +# checks. +# +# Since protocols are not base classes, isinstance() checking is limited in +# its capabilities. See docs on runtime_checkable for detail + + +@runtime_checkable +class Validator(Protocol): + """ + The protocol to which all validator classes adhere. + + Arguments: + + schema: + + The schema that the validator object will validate with. + It is assumed to be valid, and providing + an invalid schema can lead to undefined behavior. See + `Validator.check_schema` to validate a schema first. + + registry: + + a schema registry that will be used for looking up JSON references + + resolver: + + a resolver that will be used to resolve :kw:`$ref` + properties (JSON references). If unprovided, one will be created. + + .. deprecated:: v4.18.0 + + `RefResolver <_RefResolver>` has been deprecated in favor of + `referencing`, and with it, this argument. + + format_checker: + + if provided, a checker which will be used to assert about + :kw:`format` properties present in the schema. If unprovided, + *no* format validation is done, and the presence of format + within schemas is strictly informational. Certain formats + require additional packages to be installed in order to assert + against instances. Ensure you've installed `jsonschema` with + its `extra (optional) dependencies ` when + invoking ``pip``. + + .. deprecated:: v4.12.0 + + Subclassing validator classes now explicitly warns this is not part of + their public API. + + """ + + #: An object representing the validator's meta schema (the schema that + #: describes valid schemas in the given version). + META_SCHEMA: ClassVar[Mapping] + + #: A mapping of validation keywords (`str`\s) to functions that + #: validate the keyword with that name. For more information see + #: `creating-validators`. + VALIDATORS: ClassVar[Mapping] + + #: A `jsonschema.TypeChecker` that will be used when validating + #: :kw:`type` keywords in JSON schemas. + TYPE_CHECKER: ClassVar[jsonschema.TypeChecker] + + #: A `jsonschema.FormatChecker` that will be used when validating + #: :kw:`format` keywords in JSON schemas. + FORMAT_CHECKER: ClassVar[jsonschema.FormatChecker] + + #: A function which given a schema returns its ID. + ID_OF: _typing.id_of + + #: The schema that will be used to validate instances + schema: Mapping | bool + + def __init__( + self, + schema: Mapping | bool, + resolver: Any = None, # deprecated + format_checker: jsonschema.FormatChecker | None = None, + *, + registry: referencing.jsonschema.SchemaRegistry = ..., + ) -> None: ... + + @classmethod + def check_schema(cls, schema: Mapping | bool) -> None: + """ + Validate the given schema against the validator's `META_SCHEMA`. + + Raises: + + `jsonschema.exceptions.SchemaError`: + + if the schema is invalid + + """ + + def is_type(self, instance: Any, type: str) -> bool: + """ + Check if the instance is of the given (JSON Schema) type. + + Arguments: + + instance: + + the value to check + + type: + + the name of a known (JSON Schema) type + + Returns: + + whether the instance is of the given type + + Raises: + + `jsonschema.exceptions.UnknownType`: + + if ``type`` is not a known type + + """ + + def is_valid(self, instance: Any) -> bool: + """ + Check if the instance is valid under the current `schema`. + + Returns: + + whether the instance is valid or not + + >>> schema = {"maxItems" : 2} + >>> Draft202012Validator(schema).is_valid([2, 3, 4]) + False + + """ + + def iter_errors(self, instance: Any) -> Iterable[ValidationError]: + r""" + Lazily yield each of the validation errors in the given instance. + + >>> schema = { + ... "type" : "array", + ... "items" : {"enum" : [1, 2, 3]}, + ... "maxItems" : 2, + ... } + >>> v = Draft202012Validator(schema) + >>> for error in sorted(v.iter_errors([2, 3, 4]), key=str): + ... print(error.message) + 4 is not one of [1, 2, 3] + [2, 3, 4] is too long + + .. deprecated:: v4.0.0 + + Calling this function with a second schema argument is deprecated. + Use `Validator.evolve` instead. + """ + + def validate(self, instance: Any) -> None: + """ + Check if the instance is valid under the current `schema`. + + Raises: + + `jsonschema.exceptions.ValidationError`: + + if the instance is invalid + + >>> schema = {"maxItems" : 2} + >>> Draft202012Validator(schema).validate([2, 3, 4]) + Traceback (most recent call last): + ... + ValidationError: [2, 3, 4] is too long + + """ + + def evolve(self, **kwargs) -> Validator: + """ + Create a new validator like this one, but with given changes. + + Preserves all other attributes, so can be used to e.g. create a + validator with a different schema but with the same :kw:`$ref` + resolution behavior. + + >>> validator = Draft202012Validator({}) + >>> validator.evolve(schema={"type": "number"}) + Draft202012Validator(schema={'type': 'number'}, format_checker=None) + + The returned object satisfies the validator protocol, but may not + be of the same concrete class! In particular this occurs + when a :kw:`$ref` occurs to a schema with a different + :kw:`$schema` than this one (i.e. for a different draft). + + >>> validator.evolve( + ... schema={"$schema": Draft7Validator.META_SCHEMA["$id"]} + ... ) + Draft7Validator(schema=..., format_checker=None) + """ diff --git a/source/target-vendors/cp312/jsonschema/tests/__init__.py b/source/target-vendors/cp312/jsonschema/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/jsonschema/tests/_suite.py b/source/target-vendors/cp312/jsonschema/tests/_suite.py new file mode 100644 index 0000000..d61d382 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/_suite.py @@ -0,0 +1,285 @@ +""" +Python representations of the JSON Schema Test Suite tests. +""" +from __future__ import annotations + +from contextlib import suppress +from functools import partial +from pathlib import Path +from typing import TYPE_CHECKING, Any +import json +import os +import re +import sys +import unittest + +from attrs import field, frozen +from referencing import Registry +import referencing.jsonschema + +if TYPE_CHECKING: + from collections.abc import Iterable, Mapping, Sequence + + from referencing.jsonschema import Schema + import pyperf + +from jsonschema.validators import _VALIDATORS +import jsonschema + +MAGIC_REMOTE_URL = "http://localhost:1234" + +_DELIMITERS = re.compile(r"[\W\- ]+") + + +def _find_suite(): + root = os.environ.get("JSON_SCHEMA_TEST_SUITE") + if root is not None: + return Path(root) + + root = Path(jsonschema.__file__).parent.parent / "json" + if not root.is_dir(): # pragma: no cover + raise ValueError( + ( + "Can't find the JSON-Schema-Test-Suite directory. " + "Set the 'JSON_SCHEMA_TEST_SUITE' environment " + "variable or run the tests from alongside a checkout " + "of the suite." + ), + ) + return root + + +@frozen +class Suite: + + _root: Path = field(factory=_find_suite) + + + def benchmark(self, runner: pyperf.Runner): # pragma: no cover + for name, Validator in _VALIDATORS.items(): + self.version(name=name).benchmark( + runner=runner, + Validator=Validator, + ) + + def version(self, name) -> Version: + Validator = _VALIDATORS[name] + uri: str = Validator.ID_OF(Validator.META_SCHEMA) # type: ignore[assignment] + specification = referencing.jsonschema.specification_with(uri) + + registry = Registry().with_contents( + remotes_in(root=self._root / "remotes", name=name, uri=uri), + default_specification=specification, + ) + return Version( + name=name, + path=self._root / "tests" / name, + remotes=registry, + ) + + +@frozen +class Version: + + _path: Path + _remotes: referencing.jsonschema.SchemaRegistry + + name: str + + def benchmark(self, **kwargs): # pragma: no cover + for case in self.cases(): + case.benchmark(**kwargs) + + def cases(self) -> Iterable[_Case]: + return self._cases_in(paths=self._path.glob("*.json")) + + def format_cases(self) -> Iterable[_Case]: + return self._cases_in(paths=self._path.glob("optional/format/*.json")) + + def optional_cases_of(self, name: str) -> Iterable[_Case]: + return self._cases_in(paths=[self._path / "optional" / f"{name}.json"]) + + def to_unittest_testcase(self, *groups, **kwargs): + name = kwargs.pop("name", "Test" + self.name.title().replace("-", "")) + methods = { + method.__name__: method + for method in ( + test.to_unittest_method(**kwargs) + for group in groups + for case in group + for test in case.tests + ) + } + cls = type(name, (unittest.TestCase,), methods) + + # We're doing crazy things, so if they go wrong, like a function + # behaving differently on some other interpreter, just make them + # not happen. + with suppress(Exception): + cls.__module__ = _someone_save_us_the_module_of_the_caller() + + return cls + + def _cases_in(self, paths: Iterable[Path]) -> Iterable[_Case]: + for path in paths: + for case in json.loads(path.read_text(encoding="utf-8")): + yield _Case.from_dict( + case, + version=self, + subject=path.stem, + remotes=self._remotes, + ) + + +@frozen +class _Case: + + version: Version + + subject: str + description: str + schema: Mapping[str, Any] | bool + tests: list[_Test] + comment: str | None = None + specification: Sequence[dict[str, str]] = () + + @classmethod + def from_dict(cls, data, remotes, **kwargs): + data.update(kwargs) + tests = [ + _Test( + version=data["version"], + subject=data["subject"], + case_description=data["description"], + schema=data["schema"], + remotes=remotes, + **test, + ) for test in data.pop("tests") + ] + return cls(tests=tests, **data) + + def benchmark(self, runner: pyperf.Runner, **kwargs): # pragma: no cover + for test in self.tests: + runner.bench_func( + test.fully_qualified_name, + partial(test.validate_ignoring_errors, **kwargs), + ) + + +def remotes_in( + root: Path, + name: str, + uri: str, +) -> Iterable[tuple[str, Schema]]: + # This messy logic is because the test suite is terrible at indicating + # what remotes are needed for what drafts, and mixes in schemas which + # have no $schema and which are invalid under earlier versions, in with + # other schemas which are needed for tests. + + for each in root.rglob("*.json"): + schema = json.loads(each.read_text()) + + relative = str(each.relative_to(root)).replace("\\", "/") + + if ( + ( # invalid boolean schema + name in {"draft3", "draft4"} + and each.stem == "tree" + ) or + ( # draft/*.json + "$schema" not in schema + and relative.startswith("draft") + and not relative.startswith(name) + ) + ): + continue + yield f"{MAGIC_REMOTE_URL}/{relative}", schema + + +@frozen(repr=False) +class _Test: + + version: Version + + subject: str + case_description: str + description: str + + data: Any + schema: Mapping[str, Any] | bool + + valid: bool + + _remotes: referencing.jsonschema.SchemaRegistry + + comment: str | None = None + + def __repr__(self): # pragma: no cover + return f"" + + @property + def fully_qualified_name(self): # pragma: no cover + return " > ".join( # noqa: FLY002 + [ + self.version.name, + self.subject, + self.case_description, + self.description, + ], + ) + + def to_unittest_method(self, skip=lambda test: None, **kwargs): + if self.valid: + def fn(this): + self.validate(**kwargs) + else: + def fn(this): + with this.assertRaises(jsonschema.ValidationError): + self.validate(**kwargs) + + fn.__name__ = "_".join( + [ + "test", + _DELIMITERS.sub("_", self.subject), + _DELIMITERS.sub("_", self.case_description), + _DELIMITERS.sub("_", self.description), + ], + ) + reason = skip(self) + if reason is None or os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0": + return fn + elif os.environ.get("JSON_SCHEMA_EXPECTED_FAILURES", "0") != "0": # pragma: no cover # noqa: E501 + return unittest.expectedFailure(fn) + else: + return unittest.skip(reason)(fn) + + def validate(self, Validator, **kwargs): + Validator.check_schema(self.schema) + validator = Validator( + schema=self.schema, + registry=self._remotes, + **kwargs, + ) + if os.environ.get("JSON_SCHEMA_DEBUG", "0") != "0": # pragma: no cover + breakpoint() # noqa: T100 + validator.validate(instance=self.data) + + def validate_ignoring_errors(self, Validator): # pragma: no cover + with suppress(jsonschema.ValidationError): + self.validate(Validator=Validator) + + +def _someone_save_us_the_module_of_the_caller(): + """ + The FQON of the module 2nd stack frames up from here. + + This is intended to allow us to dynamically return test case classes that + are indistinguishable from being defined in the module that wants them. + + Otherwise, trial will mis-print the FQON, and copy pasting it won't re-run + the class that really is running. + + Save us all, this is all so so so so so terrible. + """ + + return sys._getframe(2).f_globals["__name__"] diff --git a/source/target-vendors/cp312/jsonschema/tests/fuzz_validate.py b/source/target-vendors/cp312/jsonschema/tests/fuzz_validate.py new file mode 100644 index 0000000..c12e88b --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/fuzz_validate.py @@ -0,0 +1,50 @@ +""" +Fuzzing setup for OSS-Fuzz. + +See https://github.com/google/oss-fuzz/tree/master/projects/jsonschema for the +other half of the setup here. +""" +import sys + +from hypothesis import given, strategies + +import jsonschema + +PRIM = strategies.one_of( + strategies.booleans(), + strategies.integers(), + strategies.floats(allow_nan=False, allow_infinity=False), + strategies.text(), +) +DICT = strategies.recursive( + base=strategies.one_of( + strategies.booleans(), + strategies.dictionaries(strategies.text(), PRIM), + ), + extend=lambda inner: strategies.dictionaries(strategies.text(), inner), +) + + +@given(obj1=DICT, obj2=DICT) +def test_schemas(obj1, obj2): + try: + jsonschema.validate(instance=obj1, schema=obj2) + except jsonschema.exceptions.ValidationError: + pass + except jsonschema.exceptions.SchemaError: + pass + + +def main(): + atheris.instrument_all() + atheris.Setup( + sys.argv, + test_schemas.hypothesis.fuzz_one_input, + enable_python_coverage=True, + ) + atheris.Fuzz() + + +if __name__ == "__main__": + import atheris + main() diff --git a/source/target-vendors/cp312/jsonschema/tests/test_cli.py b/source/target-vendors/cp312/jsonschema/tests/test_cli.py new file mode 100644 index 0000000..bed9f3e --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_cli.py @@ -0,0 +1,904 @@ +from contextlib import redirect_stderr, redirect_stdout +from importlib import metadata +from io import StringIO +from json import JSONDecodeError +from pathlib import Path +from textwrap import dedent +from unittest import TestCase +import json +import os +import subprocess +import sys +import tempfile +import warnings + +from jsonschema import Draft4Validator, Draft202012Validator +from jsonschema.exceptions import ( + SchemaError, + ValidationError, + _RefResolutionError, +) +from jsonschema.validators import _LATEST_VERSION, validate + +with warnings.catch_warnings(): + warnings.simplefilter("ignore") + from jsonschema import cli + + +def fake_validator(*errors): + errors = list(reversed(errors)) + + class FakeValidator: + def __init__(self, *args, **kwargs): + pass + + def iter_errors(self, instance): + if errors: + return errors.pop() + return [] # pragma: no cover + + @classmethod + def check_schema(self, schema): + pass + + return FakeValidator + + +def fake_open(all_contents): + def open(path): + contents = all_contents.get(path) + if contents is None: + raise FileNotFoundError(path) + return StringIO(contents) + return open + + +def _message_for(non_json): + try: + json.loads(non_json) + except JSONDecodeError as error: + return str(error) + else: # pragma: no cover + raise RuntimeError("Tried and failed to capture a JSON dump error.") + + +class TestCLI(TestCase): + def run_cli( + self, argv, files=None, stdin=StringIO(), exit_code=0, **override, + ): + arguments = cli.parse_args(argv) + arguments.update(override) + + self.assertFalse(hasattr(cli, "open")) + cli.open = fake_open(files or {}) + try: + stdout, stderr = StringIO(), StringIO() + actual_exit_code = cli.run( + arguments, + stdin=stdin, + stdout=stdout, + stderr=stderr, + ) + finally: + del cli.open + + self.assertEqual( + actual_exit_code, exit_code, msg=dedent( + f""" + Expected an exit code of {exit_code} != {actual_exit_code}. + + stdout: {stdout.getvalue()} + + stderr: {stderr.getvalue()} + """, + ), + ) + return stdout.getvalue(), stderr.getvalue() + + def assertOutputs(self, stdout="", stderr="", **kwargs): + self.assertEqual( + self.run_cli(**kwargs), + (dedent(stdout), dedent(stderr)), + ) + + def test_invalid_instance(self): + error = ValidationError("I am an error!", instance=12) + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_instance=json.dumps(error.instance), + ), + validator=fake_validator([error]), + + argv=["-i", "some_instance", "some_schema"], + + exit_code=1, + stderr="12: I am an error!\n", + ) + + def test_invalid_instance_pretty_output(self): + error = ValidationError("I am an error!", instance=12) + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_instance=json.dumps(error.instance), + ), + validator=fake_validator([error]), + + argv=["-i", "some_instance", "--output", "pretty", "some_schema"], + + exit_code=1, + stderr="""\ + ===[ValidationError]===(some_instance)=== + + I am an error! + ----------------------------- + """, + ) + + def test_invalid_instance_explicit_plain_output(self): + error = ValidationError("I am an error!", instance=12) + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_instance=json.dumps(error.instance), + ), + validator=fake_validator([error]), + + argv=["--output", "plain", "-i", "some_instance", "some_schema"], + + exit_code=1, + stderr="12: I am an error!\n", + ) + + def test_invalid_instance_multiple_errors(self): + instance = 12 + first = ValidationError("First error", instance=instance) + second = ValidationError("Second error", instance=instance) + + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_instance=json.dumps(instance), + ), + validator=fake_validator([first, second]), + + argv=["-i", "some_instance", "some_schema"], + + exit_code=1, + stderr="""\ + 12: First error + 12: Second error + """, + ) + + def test_invalid_instance_multiple_errors_pretty_output(self): + instance = 12 + first = ValidationError("First error", instance=instance) + second = ValidationError("Second error", instance=instance) + + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_instance=json.dumps(instance), + ), + validator=fake_validator([first, second]), + + argv=["-i", "some_instance", "--output", "pretty", "some_schema"], + + exit_code=1, + stderr="""\ + ===[ValidationError]===(some_instance)=== + + First error + ----------------------------- + ===[ValidationError]===(some_instance)=== + + Second error + ----------------------------- + """, + ) + + def test_multiple_invalid_instances(self): + first_instance = 12 + first_errors = [ + ValidationError("An error", instance=first_instance), + ValidationError("Another error", instance=first_instance), + ] + second_instance = "foo" + second_errors = [ValidationError("BOOM", instance=second_instance)] + + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_first_instance=json.dumps(first_instance), + some_second_instance=json.dumps(second_instance), + ), + validator=fake_validator(first_errors, second_errors), + + argv=[ + "-i", "some_first_instance", + "-i", "some_second_instance", + "some_schema", + ], + + exit_code=1, + stderr="""\ + 12: An error + 12: Another error + foo: BOOM + """, + ) + + def test_multiple_invalid_instances_pretty_output(self): + first_instance = 12 + first_errors = [ + ValidationError("An error", instance=first_instance), + ValidationError("Another error", instance=first_instance), + ] + second_instance = "foo" + second_errors = [ValidationError("BOOM", instance=second_instance)] + + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_first_instance=json.dumps(first_instance), + some_second_instance=json.dumps(second_instance), + ), + validator=fake_validator(first_errors, second_errors), + + argv=[ + "--output", "pretty", + "-i", "some_first_instance", + "-i", "some_second_instance", + "some_schema", + ], + + exit_code=1, + stderr="""\ + ===[ValidationError]===(some_first_instance)=== + + An error + ----------------------------- + ===[ValidationError]===(some_first_instance)=== + + Another error + ----------------------------- + ===[ValidationError]===(some_second_instance)=== + + BOOM + ----------------------------- + """, + ) + + def test_custom_error_format(self): + first_instance = 12 + first_errors = [ + ValidationError("An error", instance=first_instance), + ValidationError("Another error", instance=first_instance), + ] + second_instance = "foo" + second_errors = [ValidationError("BOOM", instance=second_instance)] + + self.assertOutputs( + files=dict( + some_schema='{"does not": "matter since it is stubbed"}', + some_first_instance=json.dumps(first_instance), + some_second_instance=json.dumps(second_instance), + ), + validator=fake_validator(first_errors, second_errors), + + argv=[ + "--error-format", ":{error.message}._-_.{error.instance}:", + "-i", "some_first_instance", + "-i", "some_second_instance", + "some_schema", + ], + + exit_code=1, + stderr=":An error._-_.12::Another error._-_.12::BOOM._-_.foo:", + ) + + def test_invalid_schema(self): + self.assertOutputs( + files=dict(some_schema='{"type": 12}'), + argv=["some_schema"], + + exit_code=1, + stderr="""\ + 12: 12 is not valid under any of the given schemas + """, + ) + + def test_invalid_schema_pretty_output(self): + schema = {"type": 12} + + with self.assertRaises(SchemaError) as e: + validate(schema=schema, instance="") + error = str(e.exception) + + self.assertOutputs( + files=dict(some_schema=json.dumps(schema)), + argv=["--output", "pretty", "some_schema"], + + exit_code=1, + stderr=( + "===[SchemaError]===(some_schema)===\n\n" + + str(error) + + "\n-----------------------------\n" + ), + ) + + def test_invalid_schema_multiple_errors(self): + self.assertOutputs( + files=dict(some_schema='{"type": 12, "items": 57}'), + argv=["some_schema"], + + exit_code=1, + stderr="""\ + 57: 57 is not of type 'object', 'boolean' + """, + ) + + def test_invalid_schema_multiple_errors_pretty_output(self): + schema = {"type": 12, "items": 57} + + with self.assertRaises(SchemaError) as e: + validate(schema=schema, instance="") + error = str(e.exception) + + self.assertOutputs( + files=dict(some_schema=json.dumps(schema)), + argv=["--output", "pretty", "some_schema"], + + exit_code=1, + stderr=( + "===[SchemaError]===(some_schema)===\n\n" + + str(error) + + "\n-----------------------------\n" + ), + ) + + def test_invalid_schema_with_invalid_instance(self): + """ + "Validating" an instance that's invalid under an invalid schema + just shows the schema error. + """ + self.assertOutputs( + files=dict( + some_schema='{"type": 12, "minimum": 30}', + some_instance="13", + ), + argv=["-i", "some_instance", "some_schema"], + + exit_code=1, + stderr="""\ + 12: 12 is not valid under any of the given schemas + """, + ) + + def test_invalid_schema_with_invalid_instance_pretty_output(self): + instance, schema = 13, {"type": 12, "minimum": 30} + + with self.assertRaises(SchemaError) as e: + validate(schema=schema, instance=instance) + error = str(e.exception) + + self.assertOutputs( + files=dict( + some_schema=json.dumps(schema), + some_instance=json.dumps(instance), + ), + argv=["--output", "pretty", "-i", "some_instance", "some_schema"], + + exit_code=1, + stderr=( + "===[SchemaError]===(some_schema)===\n\n" + + str(error) + + "\n-----------------------------\n" + ), + ) + + def test_invalid_instance_continues_with_the_rest(self): + self.assertOutputs( + files=dict( + some_schema='{"minimum": 30}', + first_instance="not valid JSON!", + second_instance="12", + ), + argv=[ + "-i", "first_instance", + "-i", "second_instance", + "some_schema", + ], + + exit_code=1, + stderr="""\ + Failed to parse 'first_instance': {} + 12: 12 is less than the minimum of 30 + """.format(_message_for("not valid JSON!")), + ) + + def test_custom_error_format_applies_to_schema_errors(self): + instance, schema = 13, {"type": 12, "minimum": 30} + + with self.assertRaises(SchemaError): + validate(schema=schema, instance=instance) + + self.assertOutputs( + files=dict(some_schema=json.dumps(schema)), + + argv=[ + "--error-format", ":{error.message}._-_.{error.instance}:", + "some_schema", + ], + + exit_code=1, + stderr=":12 is not valid under any of the given schemas._-_.12:", + ) + + def test_instance_is_invalid_JSON(self): + instance = "not valid JSON!" + + self.assertOutputs( + files=dict(some_schema="{}", some_instance=instance), + argv=["-i", "some_instance", "some_schema"], + + exit_code=1, + stderr=f"""\ + Failed to parse 'some_instance': {_message_for(instance)} + """, + ) + + def test_instance_is_invalid_JSON_pretty_output(self): + stdout, stderr = self.run_cli( + files=dict( + some_schema="{}", + some_instance="not valid JSON!", + ), + + argv=["--output", "pretty", "-i", "some_instance", "some_schema"], + + exit_code=1, + ) + self.assertFalse(stdout) + self.assertIn( + "(some_instance)===\n\nTraceback (most recent call last):\n", + stderr, + ) + self.assertNotIn("some_schema", stderr) + + def test_instance_is_invalid_JSON_on_stdin(self): + instance = "not valid JSON!" + + self.assertOutputs( + files=dict(some_schema="{}"), + stdin=StringIO(instance), + + argv=["some_schema"], + + exit_code=1, + stderr=f"""\ + Failed to parse : {_message_for(instance)} + """, + ) + + def test_instance_is_invalid_JSON_on_stdin_pretty_output(self): + stdout, stderr = self.run_cli( + files=dict(some_schema="{}"), + stdin=StringIO("not valid JSON!"), + + argv=["--output", "pretty", "some_schema"], + + exit_code=1, + ) + self.assertFalse(stdout) + self.assertIn( + "()===\n\nTraceback (most recent call last):\n", + stderr, + ) + self.assertNotIn("some_schema", stderr) + + def test_schema_is_invalid_JSON(self): + schema = "not valid JSON!" + + self.assertOutputs( + files=dict(some_schema=schema), + + argv=["some_schema"], + + exit_code=1, + stderr=f"""\ + Failed to parse 'some_schema': {_message_for(schema)} + """, + ) + + def test_schema_is_invalid_JSON_pretty_output(self): + stdout, stderr = self.run_cli( + files=dict(some_schema="not valid JSON!"), + + argv=["--output", "pretty", "some_schema"], + + exit_code=1, + ) + self.assertFalse(stdout) + self.assertIn( + "(some_schema)===\n\nTraceback (most recent call last):\n", + stderr, + ) + + def test_schema_and_instance_are_both_invalid_JSON(self): + """ + Only the schema error is reported, as we abort immediately. + """ + schema, instance = "not valid JSON!", "also not valid JSON!" + self.assertOutputs( + files=dict(some_schema=schema, some_instance=instance), + + argv=["some_schema"], + + exit_code=1, + stderr=f"""\ + Failed to parse 'some_schema': {_message_for(schema)} + """, + ) + + def test_schema_and_instance_are_both_invalid_JSON_pretty_output(self): + """ + Only the schema error is reported, as we abort immediately. + """ + stdout, stderr = self.run_cli( + files=dict( + some_schema="not valid JSON!", + some_instance="also not valid JSON!", + ), + + argv=["--output", "pretty", "-i", "some_instance", "some_schema"], + + exit_code=1, + ) + self.assertFalse(stdout) + self.assertIn( + "(some_schema)===\n\nTraceback (most recent call last):\n", + stderr, + ) + self.assertNotIn("some_instance", stderr) + + def test_instance_does_not_exist(self): + self.assertOutputs( + files=dict(some_schema="{}"), + argv=["-i", "nonexisting_instance", "some_schema"], + + exit_code=1, + stderr="""\ + 'nonexisting_instance' does not exist. + """, + ) + + def test_instance_does_not_exist_pretty_output(self): + self.assertOutputs( + files=dict(some_schema="{}"), + argv=[ + "--output", "pretty", + "-i", "nonexisting_instance", + "some_schema", + ], + + exit_code=1, + stderr="""\ + ===[FileNotFoundError]===(nonexisting_instance)=== + + 'nonexisting_instance' does not exist. + ----------------------------- + """, + ) + + def test_schema_does_not_exist(self): + self.assertOutputs( + argv=["nonexisting_schema"], + + exit_code=1, + stderr="'nonexisting_schema' does not exist.\n", + ) + + def test_schema_does_not_exist_pretty_output(self): + self.assertOutputs( + argv=["--output", "pretty", "nonexisting_schema"], + + exit_code=1, + stderr="""\ + ===[FileNotFoundError]===(nonexisting_schema)=== + + 'nonexisting_schema' does not exist. + ----------------------------- + """, + ) + + def test_neither_instance_nor_schema_exist(self): + self.assertOutputs( + argv=["-i", "nonexisting_instance", "nonexisting_schema"], + + exit_code=1, + stderr="'nonexisting_schema' does not exist.\n", + ) + + def test_neither_instance_nor_schema_exist_pretty_output(self): + self.assertOutputs( + argv=[ + "--output", "pretty", + "-i", "nonexisting_instance", + "nonexisting_schema", + ], + + exit_code=1, + stderr="""\ + ===[FileNotFoundError]===(nonexisting_schema)=== + + 'nonexisting_schema' does not exist. + ----------------------------- + """, + ) + + def test_successful_validation(self): + self.assertOutputs( + files=dict(some_schema="{}", some_instance="{}"), + argv=["-i", "some_instance", "some_schema"], + stdout="", + stderr="", + ) + + def test_successful_validation_pretty_output(self): + self.assertOutputs( + files=dict(some_schema="{}", some_instance="{}"), + argv=["--output", "pretty", "-i", "some_instance", "some_schema"], + stdout="===[SUCCESS]===(some_instance)===\n", + stderr="", + ) + + def test_successful_validation_of_stdin(self): + self.assertOutputs( + files=dict(some_schema="{}"), + stdin=StringIO("{}"), + argv=["some_schema"], + stdout="", + stderr="", + ) + + def test_successful_validation_of_stdin_pretty_output(self): + self.assertOutputs( + files=dict(some_schema="{}"), + stdin=StringIO("{}"), + argv=["--output", "pretty", "some_schema"], + stdout="===[SUCCESS]===()===\n", + stderr="", + ) + + def test_successful_validation_of_just_the_schema(self): + self.assertOutputs( + files=dict(some_schema="{}", some_instance="{}"), + argv=["-i", "some_instance", "some_schema"], + stdout="", + stderr="", + ) + + def test_successful_validation_of_just_the_schema_pretty_output(self): + self.assertOutputs( + files=dict(some_schema="{}", some_instance="{}"), + argv=["--output", "pretty", "-i", "some_instance", "some_schema"], + stdout="===[SUCCESS]===(some_instance)===\n", + stderr="", + ) + + def test_successful_validation_via_explicit_base_uri(self): + ref_schema_file = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115 + ref_schema_file.close() + self.addCleanup(os.remove, ref_schema_file.name) + + ref_path = Path(ref_schema_file.name) + ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}') + + schema = f'{{"$ref": "{ref_path.name}#/definitions/num"}}' + + self.assertOutputs( + files=dict(some_schema=schema, some_instance="1"), + argv=[ + "-i", "some_instance", + "--base-uri", ref_path.parent.as_uri() + "/", + "some_schema", + ], + stdout="", + stderr="", + ) + + def test_unsuccessful_validation_via_explicit_base_uri(self): + ref_schema_file = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115 + ref_schema_file.close() + self.addCleanup(os.remove, ref_schema_file.name) + + ref_path = Path(ref_schema_file.name) + ref_path.write_text('{"definitions": {"num": {"type": "integer"}}}') + + schema = f'{{"$ref": "{ref_path.name}#/definitions/num"}}' + + self.assertOutputs( + files=dict(some_schema=schema, some_instance='"1"'), + argv=[ + "-i", "some_instance", + "--base-uri", ref_path.parent.as_uri() + "/", + "some_schema", + ], + exit_code=1, + stdout="", + stderr="1: '1' is not of type 'integer'\n", + ) + + def test_nonexistent_file_with_explicit_base_uri(self): + schema = '{"$ref": "someNonexistentFile.json#definitions/num"}' + instance = "1" + + with self.assertRaises(_RefResolutionError) as e: + self.assertOutputs( + files=dict( + some_schema=schema, + some_instance=instance, + ), + argv=[ + "-i", "some_instance", + "--base-uri", Path.cwd().as_uri(), + "some_schema", + ], + ) + error = str(e.exception) + self.assertIn(f"{os.sep}someNonexistentFile.json'", error) + + def test_invalid_explicit_base_uri(self): + schema = '{"$ref": "foo.json#definitions/num"}' + instance = "1" + + with self.assertRaises(_RefResolutionError) as e: + self.assertOutputs( + files=dict( + some_schema=schema, + some_instance=instance, + ), + argv=[ + "-i", "some_instance", + "--base-uri", "not@UR1", + "some_schema", + ], + ) + error = str(e.exception) + self.assertEqual( + error, "unknown url type: 'foo.json'", + ) + + def test_it_validates_using_the_latest_validator_when_unspecified(self): + # There isn't a better way now I can think of to ensure that the + # latest version was used, given that the call to validator_for + # is hidden inside the CLI, so guard that that's the case, and + # this test will have to be updated when versions change until + # we can think of a better way to ensure this behavior. + self.assertIs(Draft202012Validator, _LATEST_VERSION) + + self.assertOutputs( + files=dict(some_schema='{"const": "check"}', some_instance='"a"'), + argv=["-i", "some_instance", "some_schema"], + exit_code=1, + stdout="", + stderr="a: 'check' was expected\n", + ) + + def test_it_validates_using_draft7_when_specified(self): + """ + Specifically, `const` validation applies for Draft 7. + """ + schema = """ + { + "$schema": "http://json-schema.org/draft-07/schema#", + "const": "check" + } + """ + instance = '"foo"' + self.assertOutputs( + files=dict(some_schema=schema, some_instance=instance), + argv=["-i", "some_instance", "some_schema"], + exit_code=1, + stdout="", + stderr="foo: 'check' was expected\n", + ) + + def test_it_validates_using_draft4_when_specified(self): + """ + Specifically, `const` validation *does not* apply for Draft 4. + """ + schema = """ + { + "$schema": "http://json-schema.org/draft-04/schema#", + "const": "check" + } + """ + instance = '"foo"' + self.assertOutputs( + files=dict(some_schema=schema, some_instance=instance), + argv=["-i", "some_instance", "some_schema"], + stdout="", + stderr="", + ) + + +class TestParser(TestCase): + + FakeValidator = fake_validator() + + def test_find_validator_by_fully_qualified_object_name(self): + arguments = cli.parse_args( + [ + "--validator", + "jsonschema.tests.test_cli.TestParser.FakeValidator", + "--instance", "mem://some/instance", + "mem://some/schema", + ], + ) + self.assertIs(arguments["validator"], self.FakeValidator) + + def test_find_validator_in_jsonschema(self): + arguments = cli.parse_args( + [ + "--validator", "Draft4Validator", + "--instance", "mem://some/instance", + "mem://some/schema", + ], + ) + self.assertIs(arguments["validator"], Draft4Validator) + + def cli_output_for(self, *argv): + stdout, stderr = StringIO(), StringIO() + with redirect_stdout(stdout), redirect_stderr(stderr): # noqa: SIM117 + with self.assertRaises(SystemExit): + cli.parse_args(argv) + return stdout.getvalue(), stderr.getvalue() + + def test_unknown_output(self): + stdout, stderr = self.cli_output_for( + "--output", "foo", + "mem://some/schema", + ) + self.assertIn("invalid choice: 'foo'", stderr) + self.assertFalse(stdout) + + def test_useless_error_format(self): + stdout, stderr = self.cli_output_for( + "--output", "pretty", + "--error-format", "foo", + "mem://some/schema", + ) + self.assertIn( + "--error-format can only be used with --output plain", + stderr, + ) + self.assertFalse(stdout) + + +class TestCLIIntegration(TestCase): + def test_license(self): + our_metadata = metadata.metadata("jsonschema") + self.assertEqual(our_metadata.get("License-Expression"), "MIT") + + def test_version(self): + version = subprocess.check_output( + [sys.executable, "-W", "ignore", "-m", "jsonschema", "--version"], + stderr=subprocess.STDOUT, + ) + version = version.decode("utf-8").strip() + self.assertEqual(version, metadata.version("jsonschema")) + + def test_no_arguments_shows_usage_notes(self): + output = subprocess.check_output( + [sys.executable, "-m", "jsonschema"], + stderr=subprocess.STDOUT, + ) + output_for_help = subprocess.check_output( + [sys.executable, "-m", "jsonschema", "--help"], + stderr=subprocess.STDOUT, + ) + self.assertEqual(output, output_for_help) diff --git a/source/target-vendors/cp312/jsonschema/tests/test_deprecations.py b/source/target-vendors/cp312/jsonschema/tests/test_deprecations.py new file mode 100644 index 0000000..a54b02f --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_deprecations.py @@ -0,0 +1,432 @@ +from contextlib import contextmanager +from io import BytesIO +from unittest import TestCase, mock +import importlib.metadata +import json +import subprocess +import sys +import urllib.request + +import referencing.exceptions + +from jsonschema import FormatChecker, exceptions, protocols, validators + + +class TestDeprecations(TestCase): + def test_version(self): + """ + As of v4.0.0, __version__ is deprecated in favor of importlib.metadata. + """ + + message = "Accessing jsonschema.__version__ is deprecated" + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import __version__ + + self.assertEqual(__version__, importlib.metadata.version("jsonschema")) + self.assertEqual(w.filename, __file__) + + def test_validators_ErrorTree(self): + """ + As of v4.0.0, importing ErrorTree from jsonschema.validators is + deprecated in favor of doing so from jsonschema.exceptions. + """ + + message = "Importing ErrorTree from jsonschema.validators is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema.validators import ErrorTree + + self.assertEqual(ErrorTree, exceptions.ErrorTree) + self.assertEqual(w.filename, __file__) + + def test_import_ErrorTree(self): + """ + As of v4.18.0, importing ErrorTree from the package root is + deprecated in favor of doing so from jsonschema.exceptions. + """ + + message = "Importing ErrorTree directly from the jsonschema package " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import ErrorTree + + self.assertEqual(ErrorTree, exceptions.ErrorTree) + self.assertEqual(w.filename, __file__) + + def test_ErrorTree_setitem(self): + """ + As of v4.20.0, setting items on an ErrorTree is deprecated. + """ + + e = exceptions.ValidationError("some error", path=["foo"]) + tree = exceptions.ErrorTree() + subtree = exceptions.ErrorTree(errors=[e]) + + message = "ErrorTree.__setitem__ is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + tree["foo"] = subtree + + self.assertEqual(tree["foo"], subtree) + self.assertEqual(w.filename, __file__) + + def test_import_FormatError(self): + """ + As of v4.18.0, importing FormatError from the package root is + deprecated in favor of doing so from jsonschema.exceptions. + """ + + message = "Importing FormatError directly from the jsonschema package " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import FormatError + + self.assertEqual(FormatError, exceptions.FormatError) + self.assertEqual(w.filename, __file__) + + def test_import_Validator(self): + """ + As of v4.19.0, importing Validator from the package root is + deprecated in favor of doing so from jsonschema.protocols. + """ + + message = "Importing Validator directly from the jsonschema package " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import Validator + + self.assertEqual(Validator, protocols.Validator) + self.assertEqual(w.filename, __file__) + + def test_validators_validators(self): + """ + As of v4.0.0, accessing jsonschema.validators.validators is + deprecated. + """ + + message = "Accessing jsonschema.validators.validators is deprecated" + with self.assertWarnsRegex(DeprecationWarning, message) as w: + value = validators.validators + + self.assertEqual(value, validators._VALIDATORS) + self.assertEqual(w.filename, __file__) + + def test_validators_meta_schemas(self): + """ + As of v4.0.0, accessing jsonschema.validators.meta_schemas is + deprecated. + """ + + message = "Accessing jsonschema.validators.meta_schemas is deprecated" + with self.assertWarnsRegex(DeprecationWarning, message) as w: + value = validators.meta_schemas + + self.assertEqual(value, validators._META_SCHEMAS) + self.assertEqual(w.filename, __file__) + + def test_RefResolver_in_scope(self): + """ + As of v4.0.0, RefResolver.in_scope is deprecated. + """ + + resolver = validators._RefResolver.from_schema({}) + message = "jsonschema.RefResolver.in_scope is deprecated " + with self.assertWarnsRegex(DeprecationWarning, message) as w: # noqa: SIM117 + with resolver.in_scope("foo"): + pass + + self.assertEqual(w.filename, __file__) + + def test_Validator_is_valid_two_arguments(self): + """ + As of v4.0.0, calling is_valid with two arguments (to provide a + different schema) is deprecated. + """ + + validator = validators.Draft7Validator({}) + message = "Passing a schema to Validator.is_valid is deprecated " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + result = validator.is_valid("foo", {"type": "number"}) + + self.assertFalse(result) + self.assertEqual(w.filename, __file__) + + def test_Validator_iter_errors_two_arguments(self): + """ + As of v4.0.0, calling iter_errors with two arguments (to provide a + different schema) is deprecated. + """ + + validator = validators.Draft7Validator({}) + message = "Passing a schema to Validator.iter_errors is deprecated " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + error, = validator.iter_errors("foo", {"type": "number"}) + + self.assertEqual(error.validator, "type") + self.assertEqual(w.filename, __file__) + + def test_Validator_resolver(self): + """ + As of v4.18.0, accessing Validator.resolver is deprecated. + """ + + validator = validators.Draft7Validator({}) + message = "Accessing Draft7Validator.resolver is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + self.assertIsInstance(validator.resolver, validators._RefResolver) + + self.assertEqual(w.filename, __file__) + + def test_RefResolver(self): + """ + As of v4.18.0, RefResolver is fully deprecated. + """ + + message = "jsonschema.RefResolver is deprecated" + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import RefResolver + self.assertEqual(w.filename, __file__) + + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema.validators import RefResolver # noqa: F401 + self.assertEqual(w.filename, __file__) + + def test_RefResolutionError(self): + """ + As of v4.18.0, RefResolutionError is deprecated in favor of directly + catching errors from the referencing library. + """ + + message = "jsonschema.exceptions.RefResolutionError is deprecated" + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import RefResolutionError + + self.assertEqual(RefResolutionError, exceptions._RefResolutionError) + self.assertEqual(w.filename, __file__) + + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema.exceptions import RefResolutionError + + self.assertEqual(RefResolutionError, exceptions._RefResolutionError) + self.assertEqual(w.filename, __file__) + + def test_catching_Unresolvable_directly(self): + """ + This behavior is the intended behavior (i.e. it's not deprecated), but + given we do "tricksy" things in the iterim to wrap exceptions in a + multiple inheritance subclass, we need to be extra sure it works and + stays working. + """ + validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) + + with self.assertRaises(referencing.exceptions.Unresolvable) as e: + validator.validate(12) + + expected = referencing.exceptions.Unresolvable(ref="urn:nothing") + self.assertEqual( + (e.exception, str(e.exception)), + (expected, "Unresolvable: urn:nothing"), + ) + + def test_catching_Unresolvable_via_RefResolutionError(self): + """ + Until RefResolutionError is removed, it is still possible to catch + exceptions from reference resolution using it, even though they may + have been raised by referencing. + """ + with self.assertWarns(DeprecationWarning): + from jsonschema import RefResolutionError + + validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) + + with self.assertRaises(referencing.exceptions.Unresolvable) as u: + validator.validate(12) + + with self.assertRaises(RefResolutionError) as e: + validator.validate(12) + + self.assertEqual( + (e.exception, str(e.exception)), + (u.exception, "Unresolvable: urn:nothing"), + ) + + def test_WrappedReferencingError_hashability(self): + """ + Ensure the wrapped referencing errors are hashable when possible. + """ + with self.assertWarns(DeprecationWarning): + from jsonschema import RefResolutionError + + validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) + + with self.assertRaises(referencing.exceptions.Unresolvable) as u: + validator.validate(12) + + with self.assertRaises(RefResolutionError) as e: + validator.validate(12) + + self.assertIn(e.exception, {u.exception}) + self.assertIn(u.exception, {e.exception}) + + def test_Validator_subclassing(self): + """ + As of v4.12.0, subclassing a validator class produces an explicit + deprecation warning. + + This was never intended to be public API (and some comments over the + years in issues said so, but obviously that's not a great way to make + sure it's followed). + + A future version will explicitly raise an error. + """ + + message = "Subclassing validator classes is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + class Subclass(validators.Draft202012Validator): + pass + + self.assertEqual(w.filename, __file__) + + with self.assertWarnsRegex(DeprecationWarning, message) as w: + class AnotherSubclass(validators.create(meta_schema={})): + pass + + def test_FormatChecker_cls_checks(self): + """ + As of v4.14.0, FormatChecker.cls_checks is deprecated without + replacement. + """ + + self.addCleanup(FormatChecker.checkers.pop, "boom", None) + + message = "FormatChecker.cls_checks " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + FormatChecker.cls_checks("boom") + + self.assertEqual(w.filename, __file__) + + def test_draftN_format_checker(self): + """ + As of v4.16.0, accessing jsonschema.draftn_format_checker is deprecated + in favor of Validator.FORMAT_CHECKER. + """ + + message = "Accessing jsonschema.draft202012_format_checker is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import draft202012_format_checker + + self.assertIs( + draft202012_format_checker, + validators.Draft202012Validator.FORMAT_CHECKER, + ) + self.assertEqual(w.filename, __file__) + + message = "Accessing jsonschema.draft201909_format_checker is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import draft201909_format_checker + + self.assertIs( + draft201909_format_checker, + validators.Draft201909Validator.FORMAT_CHECKER, + ) + self.assertEqual(w.filename, __file__) + + message = "Accessing jsonschema.draft7_format_checker is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import draft7_format_checker + + self.assertIs( + draft7_format_checker, + validators.Draft7Validator.FORMAT_CHECKER, + ) + self.assertEqual(w.filename, __file__) + + message = "Accessing jsonschema.draft6_format_checker is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import draft6_format_checker + + self.assertIs( + draft6_format_checker, + validators.Draft6Validator.FORMAT_CHECKER, + ) + self.assertEqual(w.filename, __file__) + + message = "Accessing jsonschema.draft4_format_checker is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import draft4_format_checker + + self.assertIs( + draft4_format_checker, + validators.Draft4Validator.FORMAT_CHECKER, + ) + self.assertEqual(w.filename, __file__) + + message = "Accessing jsonschema.draft3_format_checker is " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + from jsonschema import draft3_format_checker + + self.assertIs( + draft3_format_checker, + validators.Draft3Validator.FORMAT_CHECKER, + ) + self.assertEqual(w.filename, __file__) + + with self.assertRaises(ImportError): + from jsonschema import draft1234_format_checker # noqa: F401 + + def test_import_cli(self): + """ + As of v4.17.0, importing jsonschema.cli is deprecated. + """ + + message = "The jsonschema CLI is deprecated and will be removed " + with self.assertWarnsRegex(DeprecationWarning, message) as w: + import jsonschema.cli + importlib.reload(jsonschema.cli) + + self.assertEqual(w.filename, importlib.__file__) + + def test_cli(self): + """ + As of v4.17.0, the jsonschema CLI is deprecated. + """ + + process = subprocess.run( + [sys.executable, "-m", "jsonschema"], + capture_output=True, + check=True, + ) + self.assertIn(b"The jsonschema CLI is deprecated ", process.stderr) + + def test_automatic_remote_retrieval(self): + """ + Automatic retrieval of remote references is deprecated as of v4.18.0. + """ + ref = "http://bar#/$defs/baz" + schema = {"$defs": {"baz": {"type": "integer"}}} + + if "requests" in sys.modules: # pragma: no cover + self.addCleanup( + sys.modules.__setitem__, "requests", sys.modules["requests"], + ) + sys.modules["requests"] = None + + @contextmanager + def fake_urlopen(request): + self.assertIsInstance(request, urllib.request.Request) + self.assertEqual(request.full_url, "http://bar") + + # Ha ha urllib.request.Request "normalizes" header names and + # Request.get_header does not also normalize them... + (header, value), = request.header_items() + self.assertEqual(header.lower(), "user-agent") + self.assertEqual( + value, "python-jsonschema (deprecated $ref resolution)", + ) + yield BytesIO(json.dumps(schema).encode("utf8")) + + validator = validators.Draft202012Validator({"$ref": ref}) + + message = "Automatically retrieving remote references " + patch = mock.patch.object(urllib.request, "urlopen", new=fake_urlopen) + + with patch, self.assertWarnsRegex(DeprecationWarning, message): + self.assertEqual( + (validator.is_valid({}), validator.is_valid(37)), + (False, True), + ) diff --git a/source/target-vendors/cp312/jsonschema/tests/test_exceptions.py b/source/target-vendors/cp312/jsonschema/tests/test_exceptions.py new file mode 100644 index 0000000..358b924 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_exceptions.py @@ -0,0 +1,759 @@ +from unittest import TestCase +import textwrap + +import jsonpath_ng + +from jsonschema import exceptions +from jsonschema.validators import _LATEST_VERSION + + +class TestBestMatch(TestCase): + def best_match_of(self, instance, schema): + errors = list(_LATEST_VERSION(schema).iter_errors(instance)) + msg = f"No errors found for {instance} under {schema!r}!" + self.assertTrue(errors, msg=msg) + + best = exceptions.best_match(iter(errors)) + reversed_best = exceptions.best_match(reversed(errors)) + + self.assertEqual( + best._contents(), + reversed_best._contents(), + f"No consistent best match!\nGot: {best}\n\nThen: {reversed_best}", + ) + return best + + def test_shallower_errors_are_better_matches(self): + schema = { + "properties": { + "foo": { + "minProperties": 2, + "properties": {"bar": {"type": "object"}}, + }, + }, + } + best = self.best_match_of(instance={"foo": {"bar": []}}, schema=schema) + self.assertEqual(best.validator, "minProperties") + + def test_oneOf_and_anyOf_are_weak_matches(self): + """ + A property you *must* match is probably better than one you have to + match a part of. + """ + + schema = { + "minProperties": 2, + "anyOf": [{"type": "string"}, {"type": "number"}], + "oneOf": [{"type": "string"}, {"type": "number"}], + } + best = self.best_match_of(instance={}, schema=schema) + self.assertEqual(best.validator, "minProperties") + + def test_if_the_most_relevant_error_is_anyOf_it_is_traversed(self): + """ + If the most relevant error is an anyOf, then we traverse its context + and select the otherwise *least* relevant error, since in this case + that means the most specific, deep, error inside the instance. + + I.e. since only one of the schemas must match, we look for the most + relevant one. + """ + + schema = { + "properties": { + "foo": { + "anyOf": [ + {"type": "string"}, + {"properties": {"bar": {"type": "array"}}}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) + self.assertEqual(best.validator_value, "array") + + def test_no_anyOf_traversal_for_equally_relevant_errors(self): + """ + We don't traverse into an anyOf (as above) if all of its context errors + seem to be equally "wrong" against the instance. + """ + + schema = { + "anyOf": [ + {"type": "string"}, + {"type": "integer"}, + {"type": "object"}, + ], + } + best = self.best_match_of(instance=[], schema=schema) + self.assertEqual(best.validator, "anyOf") + + def test_anyOf_traversal_for_single_equally_relevant_error(self): + """ + We *do* traverse anyOf with a single nested error, even though it is + vacuously equally relevant to itself. + """ + + schema = { + "anyOf": [ + {"type": "string"}, + ], + } + best = self.best_match_of(instance=[], schema=schema) + self.assertEqual(best.validator, "type") + + def test_anyOf_traversal_for_single_sibling_errors(self): + """ + We *do* traverse anyOf with a single subschema that fails multiple + times (e.g. on multiple items). + """ + + schema = { + "anyOf": [ + {"items": {"const": 37}}, + ], + } + best = self.best_match_of(instance=[12, 12], schema=schema) + self.assertEqual(best.validator, "const") + + def test_anyOf_traversal_for_non_type_matching_sibling_errors(self): + """ + We *do* traverse anyOf with multiple subschemas when one does not type + match. + """ + + schema = { + "anyOf": [ + {"type": "object"}, + {"items": {"const": 37}}, + ], + } + best = self.best_match_of(instance=[12, 12], schema=schema) + self.assertEqual(best.validator, "const") + + def test_if_the_most_relevant_error_is_oneOf_it_is_traversed(self): + """ + If the most relevant error is an oneOf, then we traverse its context + and select the otherwise *least* relevant error, since in this case + that means the most specific, deep, error inside the instance. + + I.e. since only one of the schemas must match, we look for the most + relevant one. + """ + + schema = { + "properties": { + "foo": { + "oneOf": [ + {"type": "string"}, + {"properties": {"bar": {"type": "array"}}}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) + self.assertEqual(best.validator_value, "array") + + def test_no_oneOf_traversal_for_equally_relevant_errors(self): + """ + We don't traverse into an oneOf (as above) if all of its context errors + seem to be equally "wrong" against the instance. + """ + + schema = { + "oneOf": [ + {"type": "string"}, + {"type": "integer"}, + {"type": "object"}, + ], + } + best = self.best_match_of(instance=[], schema=schema) + self.assertEqual(best.validator, "oneOf") + + def test_oneOf_traversal_for_single_equally_relevant_error(self): + """ + We *do* traverse oneOf with a single nested error, even though it is + vacuously equally relevant to itself. + """ + + schema = { + "oneOf": [ + {"type": "string"}, + ], + } + best = self.best_match_of(instance=[], schema=schema) + self.assertEqual(best.validator, "type") + + def test_oneOf_traversal_for_single_sibling_errors(self): + """ + We *do* traverse oneOf with a single subschema that fails multiple + times (e.g. on multiple items). + """ + + schema = { + "oneOf": [ + {"items": {"const": 37}}, + ], + } + best = self.best_match_of(instance=[12, 12], schema=schema) + self.assertEqual(best.validator, "const") + + def test_oneOf_traversal_for_non_type_matching_sibling_errors(self): + """ + We *do* traverse oneOf with multiple subschemas when one does not type + match. + """ + + schema = { + "oneOf": [ + {"type": "object"}, + {"items": {"const": 37}}, + ], + } + best = self.best_match_of(instance=[12, 12], schema=schema) + self.assertEqual(best.validator, "const") + + def test_if_the_most_relevant_error_is_allOf_it_is_traversed(self): + """ + Now, if the error is allOf, we traverse but select the *most* relevant + error from the context, because all schemas here must match anyways. + """ + + schema = { + "properties": { + "foo": { + "allOf": [ + {"type": "string"}, + {"properties": {"bar": {"type": "array"}}}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) + self.assertEqual(best.validator_value, "string") + + def test_nested_context_for_oneOf(self): + """ + We traverse into nested contexts (a oneOf containing an error in a + nested oneOf here). + """ + + schema = { + "properties": { + "foo": { + "oneOf": [ + {"type": "string"}, + { + "oneOf": [ + {"type": "string"}, + { + "properties": { + "bar": {"type": "array"}, + }, + }, + ], + }, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": {"bar": 12}}, schema=schema) + self.assertEqual(best.validator_value, "array") + + def test_it_prioritizes_matching_types(self): + schema = { + "properties": { + "foo": { + "anyOf": [ + {"type": "array", "minItems": 2}, + {"type": "string", "minLength": 10}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": "bar"}, schema=schema) + self.assertEqual(best.validator, "minLength") + + reordered = { + "properties": { + "foo": { + "anyOf": [ + {"type": "string", "minLength": 10}, + {"type": "array", "minItems": 2}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": "bar"}, schema=reordered) + self.assertEqual(best.validator, "minLength") + + def test_it_prioritizes_matching_union_types(self): + schema = { + "properties": { + "foo": { + "anyOf": [ + {"type": ["array", "object"], "minItems": 2}, + {"type": ["integer", "string"], "minLength": 10}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": "bar"}, schema=schema) + self.assertEqual(best.validator, "minLength") + + reordered = { + "properties": { + "foo": { + "anyOf": [ + {"type": "string", "minLength": 10}, + {"type": "array", "minItems": 2}, + ], + }, + }, + } + best = self.best_match_of(instance={"foo": "bar"}, schema=reordered) + self.assertEqual(best.validator, "minLength") + + def test_boolean_schemas(self): + schema = {"properties": {"foo": False}} + best = self.best_match_of(instance={"foo": "bar"}, schema=schema) + self.assertIsNone(best.validator) + + def test_one_error(self): + validator = _LATEST_VERSION({"minProperties": 2}) + validator.iter_errors({}) + self.assertEqual( + exceptions.best_match(validator.iter_errors({})).validator, + "minProperties", + ) + + def test_no_errors(self): + validator = _LATEST_VERSION({}) + self.assertIsNone(exceptions.best_match(validator.iter_errors({}))) + + +class TestByRelevance(TestCase): + def test_short_paths_are_better_matches(self): + shallow = exceptions.ValidationError("Oh no!", path=["baz"]) + deep = exceptions.ValidationError("Oh yes!", path=["foo", "bar"]) + match = max([shallow, deep], key=exceptions.relevance) + self.assertIs(match, shallow) + + match = max([deep, shallow], key=exceptions.relevance) + self.assertIs(match, shallow) + + def test_global_errors_are_even_better_matches(self): + shallow = exceptions.ValidationError("Oh no!", path=[]) + deep = exceptions.ValidationError("Oh yes!", path=["foo"]) + + errors = sorted([shallow, deep], key=exceptions.relevance) + self.assertEqual( + [list(error.path) for error in errors], + [["foo"], []], + ) + + errors = sorted([deep, shallow], key=exceptions.relevance) + self.assertEqual( + [list(error.path) for error in errors], + [["foo"], []], + ) + + def test_weak_keywords_are_lower_priority(self): + weak = exceptions.ValidationError("Oh no!", path=[], validator="a") + normal = exceptions.ValidationError("Oh yes!", path=[], validator="b") + + best_match = exceptions.by_relevance(weak="a") + + match = max([weak, normal], key=best_match) + self.assertIs(match, normal) + + match = max([normal, weak], key=best_match) + self.assertIs(match, normal) + + def test_strong_keywords_are_higher_priority(self): + weak = exceptions.ValidationError("Oh no!", path=[], validator="a") + normal = exceptions.ValidationError("Oh yes!", path=[], validator="b") + strong = exceptions.ValidationError("Oh fine!", path=[], validator="c") + + best_match = exceptions.by_relevance(weak="a", strong="c") + + match = max([weak, normal, strong], key=best_match) + self.assertIs(match, strong) + + match = max([strong, normal, weak], key=best_match) + self.assertIs(match, strong) + + +class TestErrorTree(TestCase): + def test_it_knows_how_many_total_errors_it_contains(self): + # FIXME: #442 + errors = [ + exceptions.ValidationError("Something", validator=i) + for i in range(8) + ] + tree = exceptions.ErrorTree(errors) + self.assertEqual(tree.total_errors, 8) + + def test_it_contains_an_item_if_the_item_had_an_error(self): + errors = [exceptions.ValidationError("a message", path=["bar"])] + tree = exceptions.ErrorTree(errors) + self.assertIn("bar", tree) + + def test_it_does_not_contain_an_item_if_the_item_had_no_error(self): + errors = [exceptions.ValidationError("a message", path=["bar"])] + tree = exceptions.ErrorTree(errors) + self.assertNotIn("foo", tree) + + def test_keywords_that_failed_appear_in_errors_dict(self): + error = exceptions.ValidationError("a message", validator="foo") + tree = exceptions.ErrorTree([error]) + self.assertEqual(tree.errors, {"foo": error}) + + def test_it_creates_a_child_tree_for_each_nested_path(self): + errors = [ + exceptions.ValidationError("a bar message", path=["bar"]), + exceptions.ValidationError("a bar -> 0 message", path=["bar", 0]), + ] + tree = exceptions.ErrorTree(errors) + self.assertIn(0, tree["bar"]) + self.assertNotIn(1, tree["bar"]) + + def test_children_have_their_errors_dicts_built(self): + e1, e2 = ( + exceptions.ValidationError("1", validator="foo", path=["bar", 0]), + exceptions.ValidationError("2", validator="quux", path=["bar", 0]), + ) + tree = exceptions.ErrorTree([e1, e2]) + self.assertEqual(tree["bar"][0].errors, {"foo": e1, "quux": e2}) + + def test_multiple_errors_with_instance(self): + e1, e2 = ( + exceptions.ValidationError( + "1", + validator="foo", + path=["bar", "bar2"], + instance="i1"), + exceptions.ValidationError( + "2", + validator="quux", + path=["foobar", 2], + instance="i2"), + ) + exceptions.ErrorTree([e1, e2]) + + def test_it_does_not_contain_subtrees_that_are_not_in_the_instance(self): + error = exceptions.ValidationError("123", validator="foo", instance=[]) + tree = exceptions.ErrorTree([error]) + + with self.assertRaises(IndexError): + tree[0] + + def test_if_its_in_the_tree_anyhow_it_does_not_raise_an_error(self): + """ + If a keyword refers to a path that isn't in the instance, the + tree still properly returns a subtree for that path. + """ + + error = exceptions.ValidationError( + "a message", validator="foo", instance={}, path=["foo"], + ) + tree = exceptions.ErrorTree([error]) + self.assertIsInstance(tree["foo"], exceptions.ErrorTree) + + def test_iter(self): + e1, e2 = ( + exceptions.ValidationError( + "1", + validator="foo", + path=["bar", "bar2"], + instance="i1"), + exceptions.ValidationError( + "2", + validator="quux", + path=["foobar", 2], + instance="i2"), + ) + tree = exceptions.ErrorTree([e1, e2]) + self.assertEqual(set(tree), {"bar", "foobar"}) + + def test_repr_single(self): + error = exceptions.ValidationError( + "1", + validator="foo", + path=["bar", "bar2"], + instance="i1", + ) + tree = exceptions.ErrorTree([error]) + self.assertEqual(repr(tree), "") + + def test_repr_multiple(self): + e1, e2 = ( + exceptions.ValidationError( + "1", + validator="foo", + path=["bar", "bar2"], + instance="i1"), + exceptions.ValidationError( + "2", + validator="quux", + path=["foobar", 2], + instance="i2"), + ) + tree = exceptions.ErrorTree([e1, e2]) + self.assertEqual(repr(tree), "") + + def test_repr_empty(self): + tree = exceptions.ErrorTree([]) + self.assertEqual(repr(tree), "") + + +class TestErrorInitReprStr(TestCase): + def make_error(self, **kwargs): + defaults = dict( + message="hello", + validator="type", + validator_value="string", + instance=5, + schema={"type": "string"}, + ) + defaults.update(kwargs) + return exceptions.ValidationError(**defaults) + + def assertShows(self, expected, **kwargs): + expected = textwrap.dedent(expected).rstrip("\n") + + error = self.make_error(**kwargs) + message_line, _, rest = str(error).partition("\n") + self.assertEqual(message_line, error.message) + self.assertEqual(rest, expected) + + def test_it_calls_super_and_sets_args(self): + error = self.make_error() + self.assertGreater(len(error.args), 1) + + def test_repr(self): + self.assertEqual( + repr(exceptions.ValidationError(message="Hello!")), + "", + ) + + def test_unset_error(self): + error = exceptions.ValidationError("message") + self.assertEqual(str(error), "message") + + kwargs = { + "validator": "type", + "validator_value": "string", + "instance": 5, + "schema": {"type": "string"}, + } + # Just the message should show if any of the attributes are unset + for attr in kwargs: + k = dict(kwargs) + del k[attr] + error = exceptions.ValidationError("message", **k) + self.assertEqual(str(error), "message") + + def test_empty_paths(self): + self.assertShows( + """ + Failed validating 'type' in schema: + {'type': 'string'} + + On instance: + 5 + """, + path=[], + schema_path=[], + ) + + def test_one_item_paths(self): + self.assertShows( + """ + Failed validating 'type' in schema: + {'type': 'string'} + + On instance[0]: + 5 + """, + path=[0], + schema_path=["items"], + ) + + def test_multiple_item_paths(self): + self.assertShows( + """ + Failed validating 'type' in schema['items'][0]: + {'type': 'string'} + + On instance[0]['a']: + 5 + """, + path=[0, "a"], + schema_path=["items", 0, 1], + ) + + def test_uses_pprint(self): + self.assertShows( + """ + Failed validating 'maxLength' in schema: + {0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9, + 10: 10, + 11: 11, + 12: 12, + 13: 13, + 14: 14, + 15: 15, + 16: 16, + 17: 17, + 18: 18, + 19: 19} + + On instance: + [0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24] + """, + instance=list(range(25)), + schema=dict(zip(range(20), range(20))), + validator="maxLength", + ) + + def test_does_not_reorder_dicts(self): + self.assertShows( + """ + Failed validating 'type' in schema: + {'do': 3, 'not': 7, 'sort': 37, 'me': 73} + + On instance: + {'here': 73, 'too': 37, 'no': 7, 'sorting': 3} + """, + schema={ + "do": 3, + "not": 7, + "sort": 37, + "me": 73, + }, + instance={ + "here": 73, + "too": 37, + "no": 7, + "sorting": 3, + }, + ) + + def test_str_works_with_instances_having_overriden_eq_operator(self): + """ + Check for #164 which rendered exceptions unusable when a + `ValidationError` involved instances with an `__eq__` method + that returned truthy values. + """ + + class DontEQMeBro: + def __eq__(this, other): # pragma: no cover + self.fail("Don't!") + + def __ne__(this, other): # pragma: no cover + self.fail("Don't!") + + instance = DontEQMeBro() + error = exceptions.ValidationError( + "a message", + validator="foo", + instance=instance, + validator_value="some", + schema="schema", + ) + self.assertIn(repr(instance), str(error)) + + +class TestHashable(TestCase): + def test_hashable(self): + {exceptions.ValidationError("")} + {exceptions.SchemaError("")} + + +class TestJsonPathRendering(TestCase): + def validate_json_path_rendering(self, property_name, expected_path): + error = exceptions.ValidationError( + path=[property_name], + message="1", + validator="foo", + instance="i1", + ) + + rendered_json_path = error.json_path + self.assertEqual(rendered_json_path, expected_path) + + re_parsed_name = jsonpath_ng.parse(rendered_json_path).right.fields[0] + self.assertEqual(re_parsed_name, property_name) + + def test_basic(self): + self.validate_json_path_rendering("x", "$.x") + + def test_empty(self): + self.validate_json_path_rendering("", "$['']") + + def test_number(self): + self.validate_json_path_rendering("1", "$['1']") + + def test_period(self): + self.validate_json_path_rendering(".", "$['.']") + + def test_single_quote(self): + self.validate_json_path_rendering("'", r"$['\'']") + + def test_space(self): + self.validate_json_path_rendering(" ", "$[' ']") + + def test_backslash(self): + self.validate_json_path_rendering("\\", r"$['\\']") + + def test_backslash_single_quote(self): + self.validate_json_path_rendering(r"\'", r"$['\\\'']") + + def test_underscore(self): + self.validate_json_path_rendering("_", r"$['_']") + + def test_double_quote(self): + self.validate_json_path_rendering('"', """$['"']""") + + def test_hyphen(self): + self.validate_json_path_rendering("-", "$['-']") + + def test_json_path_injection(self): + self.validate_json_path_rendering("a[0]", "$['a[0]']") + + def test_open_bracket(self): + self.validate_json_path_rendering("[", "$['[']") diff --git a/source/target-vendors/cp312/jsonschema/tests/test_format.py b/source/target-vendors/cp312/jsonschema/tests/test_format.py new file mode 100644 index 0000000..d829f98 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_format.py @@ -0,0 +1,91 @@ +""" +Tests for the parts of jsonschema related to the :kw:`format` keyword. +""" + +from unittest import TestCase + +from jsonschema import FormatChecker, ValidationError +from jsonschema.exceptions import FormatError +from jsonschema.validators import Draft4Validator + +BOOM = ValueError("Boom!") +BANG = ZeroDivisionError("Bang!") + + +def boom(thing): + if thing == "bang": + raise BANG + raise BOOM + + +class TestFormatChecker(TestCase): + def test_it_can_validate_no_formats(self): + checker = FormatChecker(formats=()) + self.assertFalse(checker.checkers) + + def test_it_raises_a_key_error_for_unknown_formats(self): + with self.assertRaises(KeyError): + FormatChecker(formats=["o noes"]) + + def test_it_can_register_cls_checkers(self): + original = dict(FormatChecker.checkers) + self.addCleanup(FormatChecker.checkers.pop, "boom") + with self.assertWarns(DeprecationWarning): + FormatChecker.cls_checks("boom")(boom) + self.assertEqual( + FormatChecker.checkers, + dict(original, boom=(boom, ())), + ) + + def test_it_can_register_checkers(self): + checker = FormatChecker() + checker.checks("boom")(boom) + self.assertEqual( + checker.checkers, + dict(FormatChecker.checkers, boom=(boom, ())), + ) + + def test_it_catches_registered_errors(self): + checker = FormatChecker() + checker.checks("boom", raises=type(BOOM))(boom) + + with self.assertRaises(FormatError) as cm: + checker.check(instance=12, format="boom") + + self.assertIs(cm.exception.cause, BOOM) + self.assertIs(cm.exception.__cause__, BOOM) + self.assertEqual(str(cm.exception), "12 is not a 'boom'") + + # Unregistered errors should not be caught + with self.assertRaises(type(BANG)): + checker.check(instance="bang", format="boom") + + def test_format_error_causes_become_validation_error_causes(self): + checker = FormatChecker() + checker.checks("boom", raises=ValueError)(boom) + validator = Draft4Validator({"format": "boom"}, format_checker=checker) + + with self.assertRaises(ValidationError) as cm: + validator.validate("BOOM") + + self.assertIs(cm.exception.cause, BOOM) + self.assertIs(cm.exception.__cause__, BOOM) + + def test_format_checkers_come_with_defaults(self): + # This is bad :/ but relied upon. + # The docs for quite awhile recommended people do things like + # validate(..., format_checker=FormatChecker()) + # We should change that, but we can't without deprecation... + checker = FormatChecker() + with self.assertRaises(FormatError): + checker.check(instance="not-an-ipv4", format="ipv4") + + def test_repr(self): + checker = FormatChecker(formats=()) + checker.checks("foo")(lambda thing: True) # pragma: no cover + checker.checks("bar")(lambda thing: True) # pragma: no cover + checker.checks("baz")(lambda thing: True) # pragma: no cover + self.assertEqual( + repr(checker), + "", + ) diff --git a/source/target-vendors/cp312/jsonschema/tests/test_jsonschema_test_suite.py b/source/target-vendors/cp312/jsonschema/tests/test_jsonschema_test_suite.py new file mode 100644 index 0000000..41c9825 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_jsonschema_test_suite.py @@ -0,0 +1,262 @@ +""" +Test runner for the JSON Schema official test suite + +Tests comprehensive correctness of each draft's validator. + +See https://github.com/json-schema-org/JSON-Schema-Test-Suite for details. +""" + + +from jsonschema.tests._suite import Suite +import jsonschema + +SUITE = Suite() +DRAFT3 = SUITE.version(name="draft3") +DRAFT4 = SUITE.version(name="draft4") +DRAFT6 = SUITE.version(name="draft6") +DRAFT7 = SUITE.version(name="draft7") +DRAFT201909 = SUITE.version(name="draft2019-09") +DRAFT202012 = SUITE.version(name="draft2020-12") + + +def skip(message, **kwargs): + def skipper(test): + if all(value == getattr(test, attr) for attr, value in kwargs.items()): + return message + return skipper + + +def ecmascript_regex(test): + if test.subject == "ecmascript-regex": + return "ECMA regex support will be added in #1142." + + +def missing_format(Validator): + def missing_format(test): # pragma: no cover + schema = test.schema + if ( + schema is True + or schema is False + or "format" not in schema + or schema["format"] in Validator.FORMAT_CHECKER.checkers + or test.valid + ): + return + + return f"Format checker {schema['format']!r} not found." + return missing_format + + +def complex_email_validation(test): + if test.subject != "email": + return + + message = "Complex email validation is (intentionally) unsupported." + return skip( + message=message, + description="an invalid domain", + )(test) or skip( + message=message, + description="an invalid IPv4-address-literal", + )(test) or skip( + message=message, + description="dot after local part is not valid", + )(test) or skip( + message=message, + description="dot before local part is not valid", + )(test) or skip( + message=message, + description="two subsequent dots inside local part are not valid", + )(test) + + +def leap_second(test): + message = "Leap seconds are unsupported." + return skip( + message=message, + subject="time", + description="a valid time string with leap second", + )(test) or skip( + message=message, + subject="time", + description="a valid time string with leap second, Zulu", + )(test) or skip( + message=message, + subject="time", + description="a valid time string with leap second with offset", + )(test) or skip( + message=message, + subject="time", + description="valid leap second, positive time-offset", + )(test) or skip( + message=message, + subject="time", + description="valid leap second, negative time-offset", + )(test) or skip( + message=message, + subject="time", + description="valid leap second, large positive time-offset", + )(test) or skip( + message=message, + subject="time", + description="valid leap second, large negative time-offset", + )(test) or skip( + message=message, + subject="time", + description="valid leap second, zero time-offset", + )(test) or skip( + message=message, + subject="date-time", + description="a valid date-time with a leap second, UTC", + )(test) or skip( + message=message, + subject="date-time", + description="a valid date-time with a leap second, with minus offset", + )(test) + + +TestDraft3 = DRAFT3.to_unittest_testcase( + DRAFT3.cases(), + DRAFT3.format_cases(), + DRAFT3.optional_cases_of(name="bignum"), + DRAFT3.optional_cases_of(name="non-bmp-regex"), + DRAFT3.optional_cases_of(name="zeroTerminatedFloats"), + Validator=jsonschema.Draft3Validator, + format_checker=jsonschema.Draft3Validator.FORMAT_CHECKER, + skip=lambda test: ( + ecmascript_regex(test) + or missing_format(jsonschema.Draft3Validator)(test) + or complex_email_validation(test) + ), +) + + +TestDraft4 = DRAFT4.to_unittest_testcase( + DRAFT4.cases(), + DRAFT4.format_cases(), + DRAFT4.optional_cases_of(name="bignum"), + DRAFT4.optional_cases_of(name="float-overflow"), + DRAFT4.optional_cases_of(name="id"), + DRAFT4.optional_cases_of(name="non-bmp-regex"), + DRAFT4.optional_cases_of(name="zeroTerminatedFloats"), + Validator=jsonschema.Draft4Validator, + format_checker=jsonschema.Draft4Validator.FORMAT_CHECKER, + skip=lambda test: ( + ecmascript_regex(test) + or leap_second(test) + or missing_format(jsonschema.Draft4Validator)(test) + or complex_email_validation(test) + ), +) + + +TestDraft6 = DRAFT6.to_unittest_testcase( + DRAFT6.cases(), + DRAFT6.format_cases(), + DRAFT6.optional_cases_of(name="bignum"), + DRAFT6.optional_cases_of(name="float-overflow"), + DRAFT6.optional_cases_of(name="id"), + DRAFT6.optional_cases_of(name="non-bmp-regex"), + Validator=jsonschema.Draft6Validator, + format_checker=jsonschema.Draft6Validator.FORMAT_CHECKER, + skip=lambda test: ( + ecmascript_regex(test) + or leap_second(test) + or missing_format(jsonschema.Draft6Validator)(test) + or complex_email_validation(test) + ), +) + + +TestDraft7 = DRAFT7.to_unittest_testcase( + DRAFT7.cases(), + DRAFT7.format_cases(), + DRAFT7.optional_cases_of(name="bignum"), + DRAFT7.optional_cases_of(name="cross-draft"), + DRAFT7.optional_cases_of(name="float-overflow"), + DRAFT6.optional_cases_of(name="id"), + DRAFT7.optional_cases_of(name="non-bmp-regex"), + DRAFT7.optional_cases_of(name="unknownKeyword"), + Validator=jsonschema.Draft7Validator, + format_checker=jsonschema.Draft7Validator.FORMAT_CHECKER, + skip=lambda test: ( + ecmascript_regex(test) + or leap_second(test) + or missing_format(jsonschema.Draft7Validator)(test) + or complex_email_validation(test) + ), +) + + +TestDraft201909 = DRAFT201909.to_unittest_testcase( + DRAFT201909.cases(), + DRAFT201909.optional_cases_of(name="anchor"), + DRAFT201909.optional_cases_of(name="bignum"), + DRAFT201909.optional_cases_of(name="cross-draft"), + DRAFT201909.optional_cases_of(name="float-overflow"), + DRAFT201909.optional_cases_of(name="id"), + DRAFT201909.optional_cases_of(name="no-schema"), + DRAFT201909.optional_cases_of(name="non-bmp-regex"), + DRAFT201909.optional_cases_of(name="refOfUnknownKeyword"), + DRAFT201909.optional_cases_of(name="unknownKeyword"), + Validator=jsonschema.Draft201909Validator, + skip=skip( + message="Vocabulary support is still in-progress.", + subject="vocabulary", + description=( + "no validation: invalid number, but it still validates" + ), + ), +) + + +TestDraft201909Format = DRAFT201909.to_unittest_testcase( + DRAFT201909.format_cases(), + name="TestDraft201909Format", + Validator=jsonschema.Draft201909Validator, + format_checker=jsonschema.Draft201909Validator.FORMAT_CHECKER, + skip=lambda test: ( + complex_email_validation(test) + or ecmascript_regex(test) + or leap_second(test) + or missing_format(jsonschema.Draft201909Validator)(test) + or complex_email_validation(test) + ), +) + + +TestDraft202012 = DRAFT202012.to_unittest_testcase( + DRAFT202012.cases(), + DRAFT201909.optional_cases_of(name="anchor"), + DRAFT202012.optional_cases_of(name="bignum"), + DRAFT202012.optional_cases_of(name="cross-draft"), + DRAFT202012.optional_cases_of(name="float-overflow"), + DRAFT202012.optional_cases_of(name="id"), + DRAFT202012.optional_cases_of(name="no-schema"), + DRAFT202012.optional_cases_of(name="non-bmp-regex"), + DRAFT202012.optional_cases_of(name="refOfUnknownKeyword"), + DRAFT202012.optional_cases_of(name="unknownKeyword"), + Validator=jsonschema.Draft202012Validator, + skip=skip( + message="Vocabulary support is still in-progress.", + subject="vocabulary", + description=( + "no validation: invalid number, but it still validates" + ), + ), +) + + +TestDraft202012Format = DRAFT202012.to_unittest_testcase( + DRAFT202012.format_cases(), + name="TestDraft202012Format", + Validator=jsonschema.Draft202012Validator, + format_checker=jsonschema.Draft202012Validator.FORMAT_CHECKER, + skip=lambda test: ( + complex_email_validation(test) + or ecmascript_regex(test) + or leap_second(test) + or missing_format(jsonschema.Draft202012Validator)(test) + or complex_email_validation(test) + ), +) diff --git a/source/target-vendors/cp312/jsonschema/tests/test_types.py b/source/target-vendors/cp312/jsonschema/tests/test_types.py new file mode 100644 index 0000000..bd97b18 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_types.py @@ -0,0 +1,221 @@ +""" +Tests for the `TypeChecker`-based type interface. + +The actual correctness of the type checking is handled in +`test_jsonschema_test_suite`; these tests check that TypeChecker +functions correctly at a more granular level. +""" +from collections import namedtuple +from unittest import TestCase + +from jsonschema import ValidationError, _keywords +from jsonschema._types import TypeChecker +from jsonschema.exceptions import UndefinedTypeCheck, UnknownType +from jsonschema.validators import Draft202012Validator, extend + + +def equals_2(checker, instance): + return instance == 2 + + +def is_namedtuple(instance): + return isinstance(instance, tuple) and getattr(instance, "_fields", None) + + +def is_object_or_named_tuple(checker, instance): + if Draft202012Validator.TYPE_CHECKER.is_type(instance, "object"): + return True + return is_namedtuple(instance) + + +class TestTypeChecker(TestCase): + def test_is_type(self): + checker = TypeChecker({"two": equals_2}) + self.assertEqual( + ( + checker.is_type(instance=2, type="two"), + checker.is_type(instance="bar", type="two"), + ), + (True, False), + ) + + def test_is_unknown_type(self): + with self.assertRaises(UndefinedTypeCheck) as e: + TypeChecker().is_type(4, "foobar") + self.assertIn( + "'foobar' is unknown to this type checker", + str(e.exception), + ) + self.assertTrue( + e.exception.__suppress_context__, + msg="Expected the internal KeyError to be hidden.", + ) + + def test_checks_can_be_added_at_init(self): + checker = TypeChecker({"two": equals_2}) + self.assertEqual(checker, TypeChecker().redefine("two", equals_2)) + + def test_redefine_existing_type(self): + self.assertEqual( + TypeChecker().redefine("two", object()).redefine("two", equals_2), + TypeChecker().redefine("two", equals_2), + ) + + def test_remove(self): + self.assertEqual( + TypeChecker({"two": equals_2}).remove("two"), + TypeChecker(), + ) + + def test_remove_unknown_type(self): + with self.assertRaises(UndefinedTypeCheck) as context: + TypeChecker().remove("foobar") + self.assertIn("foobar", str(context.exception)) + + def test_redefine_many(self): + self.assertEqual( + TypeChecker().redefine_many({"foo": int, "bar": str}), + TypeChecker().redefine("foo", int).redefine("bar", str), + ) + + def test_remove_multiple(self): + self.assertEqual( + TypeChecker({"foo": int, "bar": str}).remove("foo", "bar"), + TypeChecker(), + ) + + def test_type_check_can_raise_key_error(self): + """ + Make sure no one writes: + + try: + self._type_checkers[type](...) + except KeyError: + + ignoring the fact that the function itself can raise that. + """ + + error = KeyError("Stuff") + + def raises_keyerror(checker, instance): + raise error + + with self.assertRaises(KeyError) as context: + TypeChecker({"foo": raises_keyerror}).is_type(4, "foo") + + self.assertIs(context.exception, error) + + def test_repr(self): + checker = TypeChecker({"foo": is_namedtuple, "bar": is_namedtuple}) + self.assertEqual(repr(checker), "") + + +class TestCustomTypes(TestCase): + def test_simple_type_can_be_extended(self): + def int_or_str_int(checker, instance): + if not isinstance(instance, (int, str)): + return False + try: + int(instance) + except ValueError: + return False + return True + + CustomValidator = extend( + Draft202012Validator, + type_checker=Draft202012Validator.TYPE_CHECKER.redefine( + "integer", int_or_str_int, + ), + ) + validator = CustomValidator({"type": "integer"}) + + validator.validate(4) + validator.validate("4") + + with self.assertRaises(ValidationError): + validator.validate(4.4) + + with self.assertRaises(ValidationError): + validator.validate("foo") + + def test_object_can_be_extended(self): + schema = {"type": "object"} + + Point = namedtuple("Point", ["x", "y"]) + + type_checker = Draft202012Validator.TYPE_CHECKER.redefine( + "object", is_object_or_named_tuple, + ) + + CustomValidator = extend( + Draft202012Validator, + type_checker=type_checker, + ) + validator = CustomValidator(schema) + + validator.validate(Point(x=4, y=5)) + + def test_object_extensions_require_custom_validators(self): + schema = {"type": "object", "required": ["x"]} + + type_checker = Draft202012Validator.TYPE_CHECKER.redefine( + "object", is_object_or_named_tuple, + ) + + CustomValidator = extend( + Draft202012Validator, + type_checker=type_checker, + ) + validator = CustomValidator(schema) + + Point = namedtuple("Point", ["x", "y"]) + # Cannot handle required + with self.assertRaises(ValidationError): + validator.validate(Point(x=4, y=5)) + + def test_object_extensions_can_handle_custom_validators(self): + schema = { + "type": "object", + "required": ["x"], + "properties": {"x": {"type": "integer"}}, + } + + type_checker = Draft202012Validator.TYPE_CHECKER.redefine( + "object", is_object_or_named_tuple, + ) + + def coerce_named_tuple(fn): + def coerced(validator, value, instance, schema): + if is_namedtuple(instance): + instance = instance._asdict() + return fn(validator, value, instance, schema) + return coerced + + required = coerce_named_tuple(_keywords.required) + properties = coerce_named_tuple(_keywords.properties) + + CustomValidator = extend( + Draft202012Validator, + type_checker=type_checker, + validators={"required": required, "properties": properties}, + ) + + validator = CustomValidator(schema) + + Point = namedtuple("Point", ["x", "y"]) + # Can now process required and properties + validator.validate(Point(x=4, y=5)) + + with self.assertRaises(ValidationError): + validator.validate(Point(x="not an integer", y=5)) + + # As well as still handle objects. + validator.validate({"x": 4, "y": 5}) + + with self.assertRaises(ValidationError): + validator.validate({"x": "not an integer", "y": 5}) + + def test_unknown_type(self): + with self.assertRaises(UnknownType) as e: + Draft202012Validator({}).is_type(12, "some unknown type") + self.assertIn("'some unknown type'", str(e.exception)) diff --git a/source/target-vendors/cp312/jsonschema/tests/test_utils.py b/source/target-vendors/cp312/jsonschema/tests/test_utils.py new file mode 100644 index 0000000..d9764b0 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_utils.py @@ -0,0 +1,138 @@ +from math import nan +from unittest import TestCase + +from jsonschema._utils import equal + + +class TestEqual(TestCase): + def test_none(self): + self.assertTrue(equal(None, None)) + + def test_nan(self): + self.assertTrue(equal(nan, nan)) + + +class TestDictEqual(TestCase): + def test_equal_dictionaries(self): + dict_1 = {"a": "b", "c": "d"} + dict_2 = {"c": "d", "a": "b"} + self.assertTrue(equal(dict_1, dict_2)) + + def test_equal_dictionaries_with_nan(self): + dict_1 = {"a": nan, "c": "d"} + dict_2 = {"c": "d", "a": nan} + self.assertTrue(equal(dict_1, dict_2)) + + def test_missing_key(self): + dict_1 = {"a": "b", "c": "d"} + dict_2 = {"c": "d", "x": "b"} + self.assertFalse(equal(dict_1, dict_2)) + + def test_additional_key(self): + dict_1 = {"a": "b", "c": "d"} + dict_2 = {"c": "d", "a": "b", "x": "x"} + self.assertFalse(equal(dict_1, dict_2)) + + def test_missing_value(self): + dict_1 = {"a": "b", "c": "d"} + dict_2 = {"c": "d", "a": "x"} + self.assertFalse(equal(dict_1, dict_2)) + + def test_empty_dictionaries(self): + dict_1 = {} + dict_2 = {} + self.assertTrue(equal(dict_1, dict_2)) + + def test_one_none(self): + dict_1 = None + dict_2 = {"a": "b", "c": "d"} + self.assertFalse(equal(dict_1, dict_2)) + + def test_same_item(self): + dict_1 = {"a": "b", "c": "d"} + self.assertTrue(equal(dict_1, dict_1)) + + def test_nested_equal(self): + dict_1 = {"a": {"a": "b", "c": "d"}, "c": "d"} + dict_2 = {"c": "d", "a": {"a": "b", "c": "d"}} + self.assertTrue(equal(dict_1, dict_2)) + + def test_nested_dict_unequal(self): + dict_1 = {"a": {"a": "b", "c": "d"}, "c": "d"} + dict_2 = {"c": "d", "a": {"a": "b", "c": "x"}} + self.assertFalse(equal(dict_1, dict_2)) + + def test_mixed_nested_equal(self): + dict_1 = {"a": ["a", "b", "c", "d"], "c": "d"} + dict_2 = {"c": "d", "a": ["a", "b", "c", "d"]} + self.assertTrue(equal(dict_1, dict_2)) + + def test_nested_list_unequal(self): + dict_1 = {"a": ["a", "b", "c", "d"], "c": "d"} + dict_2 = {"c": "d", "a": ["b", "c", "d", "a"]} + self.assertFalse(equal(dict_1, dict_2)) + + +class TestListEqual(TestCase): + def test_equal_lists(self): + list_1 = ["a", "b", "c"] + list_2 = ["a", "b", "c"] + self.assertTrue(equal(list_1, list_2)) + + def test_equal_lists_with_nan(self): + list_1 = ["a", nan, "c"] + list_2 = ["a", nan, "c"] + self.assertTrue(equal(list_1, list_2)) + + def test_unsorted_lists(self): + list_1 = ["a", "b", "c"] + list_2 = ["b", "b", "a"] + self.assertFalse(equal(list_1, list_2)) + + def test_first_list_larger(self): + list_1 = ["a", "b", "c"] + list_2 = ["a", "b"] + self.assertFalse(equal(list_1, list_2)) + + def test_second_list_larger(self): + list_1 = ["a", "b"] + list_2 = ["a", "b", "c"] + self.assertFalse(equal(list_1, list_2)) + + def test_list_with_none_unequal(self): + list_1 = ["a", "b", None] + list_2 = ["a", "b", "c"] + self.assertFalse(equal(list_1, list_2)) + + list_1 = ["a", "b", None] + list_2 = [None, "b", "c"] + self.assertFalse(equal(list_1, list_2)) + + def test_list_with_none_equal(self): + list_1 = ["a", None, "c"] + list_2 = ["a", None, "c"] + self.assertTrue(equal(list_1, list_2)) + + def test_empty_list(self): + list_1 = [] + list_2 = [] + self.assertTrue(equal(list_1, list_2)) + + def test_one_none(self): + list_1 = None + list_2 = [] + self.assertFalse(equal(list_1, list_2)) + + def test_same_list(self): + list_1 = ["a", "b", "c"] + self.assertTrue(equal(list_1, list_1)) + + def test_equal_nested_lists(self): + list_1 = ["a", ["b", "c"], "d"] + list_2 = ["a", ["b", "c"], "d"] + self.assertTrue(equal(list_1, list_2)) + + def test_unequal_nested_lists(self): + list_1 = ["a", ["b", "c"], "d"] + list_2 = ["a", [], "c"] + self.assertFalse(equal(list_1, list_2)) diff --git a/source/target-vendors/cp312/jsonschema/tests/test_validators.py b/source/target-vendors/cp312/jsonschema/tests/test_validators.py new file mode 100644 index 0000000..d419ddf --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/test_validators.py @@ -0,0 +1,2573 @@ +from __future__ import annotations + +from collections import deque, namedtuple +from contextlib import contextmanager +from decimal import Decimal +from io import BytesIO +from typing import Any +from unittest import TestCase, mock +from urllib.request import pathname2url +import json +import os +import sys +import tempfile +import warnings + +from attrs import define, field +from referencing.jsonschema import DRAFT202012 +import referencing.exceptions + +from jsonschema import ( + FormatChecker, + TypeChecker, + exceptions, + protocols, + validators, +) + + +def fail(validator, errors, instance, schema): + for each in errors: + each.setdefault("message", "You told me to fail!") + yield exceptions.ValidationError(**each) + + +class TestCreateAndExtend(TestCase): + def setUp(self): + self.addCleanup( + self.assertEqual, + validators._META_SCHEMAS, + dict(validators._META_SCHEMAS), + ) + self.addCleanup( + self.assertEqual, + validators._VALIDATORS, + dict(validators._VALIDATORS), + ) + + self.meta_schema = {"$id": "some://meta/schema"} + self.validators = {"fail": fail} + self.type_checker = TypeChecker() + self.Validator = validators.create( + meta_schema=self.meta_schema, + validators=self.validators, + type_checker=self.type_checker, + ) + + def test_attrs(self): + self.assertEqual( + ( + self.Validator.VALIDATORS, + self.Validator.META_SCHEMA, + self.Validator.TYPE_CHECKER, + ), ( + self.validators, + self.meta_schema, + self.type_checker, + ), + ) + + def test_init(self): + schema = {"fail": []} + self.assertEqual(self.Validator(schema).schema, schema) + + def test_iter_errors_successful(self): + schema = {"fail": []} + validator = self.Validator(schema) + + errors = list(validator.iter_errors("hello")) + self.assertEqual(errors, []) + + def test_iter_errors_one_error(self): + schema = {"fail": [{"message": "Whoops!"}]} + validator = self.Validator(schema) + + expected_error = exceptions.ValidationError( + "Whoops!", + instance="goodbye", + schema=schema, + validator="fail", + validator_value=[{"message": "Whoops!"}], + schema_path=deque(["fail"]), + ) + + errors = list(validator.iter_errors("goodbye")) + self.assertEqual(len(errors), 1) + self.assertEqual(errors[0]._contents(), expected_error._contents()) + + def test_iter_errors_multiple_errors(self): + schema = { + "fail": [ + {"message": "First"}, + {"message": "Second!", "validator": "asdf"}, + {"message": "Third"}, + ], + } + validator = self.Validator(schema) + + errors = list(validator.iter_errors("goodbye")) + self.assertEqual(len(errors), 3) + + def test_if_a_version_is_provided_it_is_registered(self): + Validator = validators.create( + meta_schema={"$id": "something"}, + version="my version", + ) + self.addCleanup(validators._META_SCHEMAS.pop, "something") + self.addCleanup(validators._VALIDATORS.pop, "my version") + self.assertEqual(Validator.__name__, "MyVersionValidator") + self.assertEqual(Validator.__qualname__, "MyVersionValidator") + + def test_repr(self): + Validator = validators.create( + meta_schema={"$id": "something"}, + version="my version", + ) + self.addCleanup(validators._META_SCHEMAS.pop, "something") + self.addCleanup(validators._VALIDATORS.pop, "my version") + self.assertEqual( + repr(Validator({})), + "MyVersionValidator(schema={}, format_checker=None)", + ) + + def test_long_repr(self): + Validator = validators.create( + meta_schema={"$id": "something"}, + version="my version", + ) + self.addCleanup(validators._META_SCHEMAS.pop, "something") + self.addCleanup(validators._VALIDATORS.pop, "my version") + self.assertEqual( + repr(Validator({"a": list(range(1000))})), ( + "MyVersionValidator(schema={'a': [0, 1, 2, 3, 4, 5, ...]}, " + "format_checker=None)" + ), + ) + + def test_repr_no_version(self): + Validator = validators.create(meta_schema={}) + self.assertEqual( + repr(Validator({})), + "Validator(schema={}, format_checker=None)", + ) + + def test_dashes_are_stripped_from_validator_names(self): + Validator = validators.create( + meta_schema={"$id": "something"}, + version="foo-bar", + ) + self.addCleanup(validators._META_SCHEMAS.pop, "something") + self.addCleanup(validators._VALIDATORS.pop, "foo-bar") + self.assertEqual(Validator.__qualname__, "FooBarValidator") + + def test_if_a_version_is_not_provided_it_is_not_registered(self): + original = dict(validators._META_SCHEMAS) + validators.create(meta_schema={"id": "id"}) + self.assertEqual(validators._META_SCHEMAS, original) + + def test_validates_registers_meta_schema_id(self): + meta_schema_key = "meta schema id" + my_meta_schema = {"id": meta_schema_key} + + validators.create( + meta_schema=my_meta_schema, + version="my version", + id_of=lambda s: s.get("id", ""), + ) + self.addCleanup(validators._META_SCHEMAS.pop, meta_schema_key) + self.addCleanup(validators._VALIDATORS.pop, "my version") + + self.assertIn(meta_schema_key, validators._META_SCHEMAS) + + def test_validates_registers_meta_schema_draft6_id(self): + meta_schema_key = "meta schema $id" + my_meta_schema = {"$id": meta_schema_key} + + validators.create( + meta_schema=my_meta_schema, + version="my version", + ) + self.addCleanup(validators._META_SCHEMAS.pop, meta_schema_key) + self.addCleanup(validators._VALIDATORS.pop, "my version") + + self.assertIn(meta_schema_key, validators._META_SCHEMAS) + + def test_create_default_types(self): + Validator = validators.create(meta_schema={}, validators=()) + self.assertTrue( + all( + Validator({}).is_type(instance=instance, type=type) + for type, instance in [ + ("array", []), + ("boolean", True), + ("integer", 12), + ("null", None), + ("number", 12.0), + ("object", {}), + ("string", "foo"), + ] + ), + ) + + def test_check_schema_with_different_metaschema(self): + """ + One can create a validator class whose metaschema uses a different + dialect than itself. + """ + + NoEmptySchemasValidator = validators.create( + meta_schema={ + "$schema": validators.Draft202012Validator.META_SCHEMA["$id"], + "not": {"const": {}}, + }, + ) + NoEmptySchemasValidator.check_schema({"foo": "bar"}) + + with self.assertRaises(exceptions.SchemaError): + NoEmptySchemasValidator.check_schema({}) + + NoEmptySchemasValidator({"foo": "bar"}).validate("foo") + + def test_check_schema_with_different_metaschema_defaults_to_self(self): + """ + A validator whose metaschema doesn't declare $schema defaults to its + own validation behavior, not the latest "normal" specification. + """ + + NoEmptySchemasValidator = validators.create( + meta_schema={"fail": [{"message": "Meta schema whoops!"}]}, + validators={"fail": fail}, + ) + with self.assertRaises(exceptions.SchemaError): + NoEmptySchemasValidator.check_schema({}) + + def test_extend(self): + original = dict(self.Validator.VALIDATORS) + new = object() + + Extended = validators.extend( + self.Validator, + validators={"new": new}, + ) + self.assertEqual( + ( + Extended.VALIDATORS, + Extended.META_SCHEMA, + Extended.TYPE_CHECKER, + self.Validator.VALIDATORS, + ), ( + dict(original, new=new), + self.Validator.META_SCHEMA, + self.Validator.TYPE_CHECKER, + original, + ), + ) + + def test_extend_idof(self): + """ + Extending a validator preserves its notion of schema IDs. + """ + def id_of(schema): + return schema.get("__test__", self.Validator.ID_OF(schema)) + correct_id = "the://correct/id/" + meta_schema = { + "$id": "the://wrong/id/", + "__test__": correct_id, + } + Original = validators.create( + meta_schema=meta_schema, + validators=self.validators, + type_checker=self.type_checker, + id_of=id_of, + ) + self.assertEqual(Original.ID_OF(Original.META_SCHEMA), correct_id) + + Derived = validators.extend(Original) + self.assertEqual(Derived.ID_OF(Derived.META_SCHEMA), correct_id) + + def test_extend_applicable_validators(self): + """ + Extending a validator preserves its notion of applicable validators. + """ + + schema = { + "$defs": {"test": {"type": "number"}}, + "$ref": "#/$defs/test", + "maximum": 1, + } + + draft4 = validators.Draft4Validator(schema) + self.assertTrue(draft4.is_valid(37)) # as $ref ignores siblings + + Derived = validators.extend(validators.Draft4Validator) + self.assertTrue(Derived(schema).is_valid(37)) + + +class TestValidationErrorMessages(TestCase): + def message_for(self, instance, schema, *args, **kwargs): + cls = kwargs.pop("cls", validators._LATEST_VERSION) + cls.check_schema(schema) + validator = cls(schema, *args, **kwargs) + errors = list(validator.iter_errors(instance)) + self.assertTrue(errors, msg=f"No errors were raised for {instance!r}") + self.assertEqual( + len(errors), + 1, + msg=f"Expected exactly one error, found {errors!r}", + ) + return errors[0].message + + def test_single_type_failure(self): + message = self.message_for(instance=1, schema={"type": "string"}) + self.assertEqual(message, "1 is not of type 'string'") + + def test_single_type_list_failure(self): + message = self.message_for(instance=1, schema={"type": ["string"]}) + self.assertEqual(message, "1 is not of type 'string'") + + def test_multiple_type_failure(self): + types = "string", "object" + message = self.message_for(instance=1, schema={"type": list(types)}) + self.assertEqual(message, "1 is not of type 'string', 'object'") + + def test_object_with_named_type_failure(self): + schema = {"type": [{"name": "Foo", "minimum": 3}]} + message = self.message_for( + instance=1, + schema=schema, + cls=validators.Draft3Validator, + ) + self.assertEqual(message, "1 is not of type 'Foo'") + + def test_minimum(self): + message = self.message_for(instance=1, schema={"minimum": 2}) + self.assertEqual(message, "1 is less than the minimum of 2") + + def test_maximum(self): + message = self.message_for(instance=1, schema={"maximum": 0}) + self.assertEqual(message, "1 is greater than the maximum of 0") + + def test_dependencies_single_element(self): + depend, on = "bar", "foo" + schema = {"dependencies": {depend: on}} + message = self.message_for( + instance={"bar": 2}, + schema=schema, + cls=validators.Draft3Validator, + ) + self.assertEqual(message, "'foo' is a dependency of 'bar'") + + def test_object_without_title_type_failure_draft3(self): + type = {"type": [{"minimum": 3}]} + message = self.message_for( + instance=1, + schema={"type": [type]}, + cls=validators.Draft3Validator, + ) + self.assertEqual( + message, + "1 is not of type {'type': [{'minimum': 3}]}", + ) + + def test_dependencies_list_draft3(self): + depend, on = "bar", "foo" + schema = {"dependencies": {depend: [on]}} + message = self.message_for( + instance={"bar": 2}, + schema=schema, + cls=validators.Draft3Validator, + ) + self.assertEqual(message, "'foo' is a dependency of 'bar'") + + def test_dependencies_list_draft7(self): + depend, on = "bar", "foo" + schema = {"dependencies": {depend: [on]}} + message = self.message_for( + instance={"bar": 2}, + schema=schema, + cls=validators.Draft7Validator, + ) + self.assertEqual(message, "'foo' is a dependency of 'bar'") + + def test_additionalItems_single_failure(self): + message = self.message_for( + instance=[2], + schema={"items": [], "additionalItems": False}, + cls=validators.Draft3Validator, + ) + self.assertIn("(2 was unexpected)", message) + + def test_additionalItems_multiple_failures(self): + message = self.message_for( + instance=[1, 2, 3], + schema={"items": [], "additionalItems": False}, + cls=validators.Draft3Validator, + ) + self.assertIn("(1, 2, 3 were unexpected)", message) + + def test_additionalProperties_single_failure(self): + additional = "foo" + schema = {"additionalProperties": False} + message = self.message_for(instance={additional: 2}, schema=schema) + self.assertIn("('foo' was unexpected)", message) + + def test_additionalProperties_multiple_failures(self): + schema = {"additionalProperties": False} + message = self.message_for( + instance=dict.fromkeys(["foo", "bar"]), + schema=schema, + ) + + self.assertIn(repr("foo"), message) + self.assertIn(repr("bar"), message) + self.assertIn("were unexpected)", message) + + def test_const(self): + schema = {"const": 12} + message = self.message_for( + instance={"foo": "bar"}, + schema=schema, + ) + self.assertIn("12 was expected", message) + + def test_contains_draft_6(self): + schema = {"contains": {"const": 12}} + message = self.message_for( + instance=[2, {}, []], + schema=schema, + cls=validators.Draft6Validator, + ) + self.assertEqual( + message, + "None of [2, {}, []] are valid under the given schema", + ) + + def test_invalid_format_default_message(self): + checker = FormatChecker(formats=()) + checker.checks("thing")(lambda value: False) + + schema = {"format": "thing"} + message = self.message_for( + instance="bla", + schema=schema, + format_checker=checker, + ) + + self.assertIn(repr("bla"), message) + self.assertIn(repr("thing"), message) + self.assertIn("is not a", message) + + def test_additionalProperties_false_patternProperties(self): + schema = {"type": "object", + "additionalProperties": False, + "patternProperties": { + "^abc$": {"type": "string"}, + "^def$": {"type": "string"}, + }} + message = self.message_for( + instance={"zebra": 123}, + schema=schema, + cls=validators.Draft4Validator, + ) + self.assertEqual( + message, + "{} does not match any of the regexes: {}, {}".format( + repr("zebra"), repr("^abc$"), repr("^def$"), + ), + ) + message = self.message_for( + instance={"zebra": 123, "fish": 456}, + schema=schema, + cls=validators.Draft4Validator, + ) + self.assertEqual( + message, + "{}, {} do not match any of the regexes: {}, {}".format( + repr("fish"), repr("zebra"), repr("^abc$"), repr("^def$"), + ), + ) + + def test_False_schema(self): + message = self.message_for( + instance="something", + schema=False, + ) + self.assertEqual(message, "False schema does not allow 'something'") + + def test_multipleOf(self): + message = self.message_for( + instance=3, + schema={"multipleOf": 2}, + ) + self.assertEqual(message, "3 is not a multiple of 2") + + def test_minItems(self): + message = self.message_for(instance=[], schema={"minItems": 2}) + self.assertEqual(message, "[] is too short") + + def test_maxItems(self): + message = self.message_for(instance=[1, 2, 3], schema={"maxItems": 2}) + self.assertEqual(message, "[1, 2, 3] is too long") + + def test_minItems_1(self): + message = self.message_for(instance=[], schema={"minItems": 1}) + self.assertEqual(message, "[] should be non-empty") + + def test_maxItems_0(self): + message = self.message_for(instance=[1, 2, 3], schema={"maxItems": 0}) + self.assertEqual(message, "[1, 2, 3] is expected to be empty") + + def test_minLength(self): + message = self.message_for( + instance="", + schema={"minLength": 2}, + ) + self.assertEqual(message, "'' is too short") + + def test_maxLength(self): + message = self.message_for( + instance="abc", + schema={"maxLength": 2}, + ) + self.assertEqual(message, "'abc' is too long") + + def test_minLength_1(self): + message = self.message_for(instance="", schema={"minLength": 1}) + self.assertEqual(message, "'' should be non-empty") + + def test_maxLength_0(self): + message = self.message_for(instance="abc", schema={"maxLength": 0}) + self.assertEqual(message, "'abc' is expected to be empty") + + def test_minProperties(self): + message = self.message_for(instance={}, schema={"minProperties": 2}) + self.assertEqual(message, "{} does not have enough properties") + + def test_maxProperties(self): + message = self.message_for( + instance={"a": {}, "b": {}, "c": {}}, + schema={"maxProperties": 2}, + ) + self.assertEqual( + message, + "{'a': {}, 'b': {}, 'c': {}} has too many properties", + ) + + def test_minProperties_1(self): + message = self.message_for(instance={}, schema={"minProperties": 1}) + self.assertEqual(message, "{} should be non-empty") + + def test_maxProperties_0(self): + message = self.message_for( + instance={1: 2}, + schema={"maxProperties": 0}, + ) + self.assertEqual(message, "{1: 2} is expected to be empty") + + def test_prefixItems_with_items(self): + message = self.message_for( + instance=[1, 2, "foo"], + schema={"items": False, "prefixItems": [{}, {}]}, + ) + self.assertEqual( + message, + "Expected at most 2 items but found 1 extra: 'foo'", + ) + + def test_prefixItems_with_multiple_extra_items(self): + message = self.message_for( + instance=[1, 2, "foo", 5], + schema={"items": False, "prefixItems": [{}, {}]}, + ) + self.assertEqual( + message, + "Expected at most 2 items but found 2 extra: ['foo', 5]", + ) + + def test_pattern(self): + message = self.message_for( + instance="bbb", + schema={"pattern": "^a*$"}, + ) + self.assertEqual(message, "'bbb' does not match '^a*$'") + + def test_does_not_contain(self): + message = self.message_for( + instance=[], + schema={"contains": {"type": "string"}}, + ) + self.assertEqual( + message, + "[] does not contain items matching the given schema", + ) + + def test_contains_too_few(self): + message = self.message_for( + instance=["foo", 1], + schema={"contains": {"type": "string"}, "minContains": 2}, + ) + self.assertEqual( + message, + "Too few items match the given schema " + "(expected at least 2 but only 1 matched)", + ) + + def test_contains_too_few_both_constrained(self): + message = self.message_for( + instance=["foo", 1], + schema={ + "contains": {"type": "string"}, + "minContains": 2, + "maxContains": 4, + }, + ) + self.assertEqual( + message, + "Too few items match the given schema (expected at least 2 but " + "only 1 matched)", + ) + + def test_contains_too_many(self): + message = self.message_for( + instance=["foo", "bar", "baz"], + schema={"contains": {"type": "string"}, "maxContains": 2}, + ) + self.assertEqual( + message, + "Too many items match the given schema (expected at most 2)", + ) + + def test_contains_too_many_both_constrained(self): + message = self.message_for( + instance=["foo"] * 5, + schema={ + "contains": {"type": "string"}, + "minContains": 2, + "maxContains": 4, + }, + ) + self.assertEqual( + message, + "Too many items match the given schema (expected at most 4)", + ) + + def test_exclusiveMinimum(self): + message = self.message_for( + instance=3, + schema={"exclusiveMinimum": 5}, + ) + self.assertEqual( + message, + "3 is less than or equal to the minimum of 5", + ) + + def test_exclusiveMaximum(self): + message = self.message_for(instance=3, schema={"exclusiveMaximum": 2}) + self.assertEqual( + message, + "3 is greater than or equal to the maximum of 2", + ) + + def test_required(self): + message = self.message_for(instance={}, schema={"required": ["foo"]}) + self.assertEqual(message, "'foo' is a required property") + + def test_dependentRequired(self): + message = self.message_for( + instance={"foo": {}}, + schema={"dependentRequired": {"foo": ["bar"]}}, + ) + self.assertEqual(message, "'bar' is a dependency of 'foo'") + + def test_oneOf_matches_none(self): + message = self.message_for(instance={}, schema={"oneOf": [False]}) + self.assertEqual( + message, + "{} is not valid under any of the given schemas", + ) + + def test_oneOf_matches_too_many(self): + message = self.message_for(instance={}, schema={"oneOf": [True, True]}) + self.assertEqual(message, "{} is valid under each of True, True") + + def test_unevaluated_items(self): + schema = {"type": "array", "unevaluatedItems": False} + message = self.message_for(instance=["foo", "bar"], schema=schema) + self.assertIn( + message, + "Unevaluated items are not allowed ('foo', 'bar' were unexpected)", + ) + + def test_unevaluated_items_on_invalid_type(self): + schema = {"type": "array", "unevaluatedItems": False} + message = self.message_for(instance="foo", schema=schema) + self.assertEqual(message, "'foo' is not of type 'array'") + + def test_unevaluated_properties_invalid_against_subschema(self): + schema = { + "properties": {"foo": {"type": "string"}}, + "unevaluatedProperties": {"const": 12}, + } + message = self.message_for( + instance={ + "foo": "foo", + "bar": "bar", + "baz": 12, + }, + schema=schema, + ) + self.assertEqual( + message, + "Unevaluated properties are not valid under the given schema " + "('bar' was unevaluated and invalid)", + ) + + def test_unevaluated_properties_disallowed(self): + schema = {"type": "object", "unevaluatedProperties": False} + message = self.message_for( + instance={ + "foo": "foo", + "bar": "bar", + }, + schema=schema, + ) + self.assertEqual( + message, + "Unevaluated properties are not allowed " + "('bar', 'foo' were unexpected)", + ) + + def test_unevaluated_properties_on_invalid_type(self): + schema = {"type": "object", "unevaluatedProperties": False} + message = self.message_for(instance="foo", schema=schema) + self.assertEqual(message, "'foo' is not of type 'object'") + + def test_single_item(self): + schema = {"prefixItems": [{}], "items": False} + message = self.message_for( + instance=["foo", "bar", "baz"], + schema=schema, + ) + self.assertEqual( + message, + "Expected at most 1 item but found 2 extra: ['bar', 'baz']", + ) + + def test_heterogeneous_additionalItems_with_Items(self): + schema = {"items": [{}], "additionalItems": False} + message = self.message_for( + instance=["foo", "bar", 37], + schema=schema, + cls=validators.Draft7Validator, + ) + self.assertEqual( + message, + "Additional items are not allowed ('bar', 37 were unexpected)", + ) + + def test_heterogeneous_items_prefixItems(self): + schema = {"prefixItems": [{}], "items": False} + message = self.message_for( + instance=["foo", "bar", 37], + schema=schema, + ) + self.assertEqual( + message, + "Expected at most 1 item but found 2 extra: ['bar', 37]", + ) + + def test_heterogeneous_unevaluatedItems_prefixItems(self): + schema = {"prefixItems": [{}], "unevaluatedItems": False} + message = self.message_for( + instance=["foo", "bar", 37], + schema=schema, + ) + self.assertEqual( + message, + "Unevaluated items are not allowed ('bar', 37 were unexpected)", + ) + + def test_heterogeneous_properties_additionalProperties(self): + """ + Not valid deserialized JSON, but this should not blow up. + """ + schema = {"properties": {"foo": {}}, "additionalProperties": False} + message = self.message_for( + instance={"foo": {}, "a": "baz", 37: 12}, + schema=schema, + ) + self.assertEqual( + message, + "Additional properties are not allowed (37, 'a' were unexpected)", + ) + + def test_heterogeneous_properties_unevaluatedProperties(self): + """ + Not valid deserialized JSON, but this should not blow up. + """ + schema = {"properties": {"foo": {}}, "unevaluatedProperties": False} + message = self.message_for( + instance={"foo": {}, "a": "baz", 37: 12}, + schema=schema, + ) + self.assertEqual( + message, + "Unevaluated properties are not allowed (37, 'a' were unexpected)", + ) + + +class TestValidationErrorDetails(TestCase): + # TODO: These really need unit tests for each individual keyword, rather + # than just these higher level tests. + def test_anyOf(self): + instance = 5 + schema = { + "anyOf": [ + {"minimum": 20}, + {"type": "string"}, + ], + } + + validator = validators.Draft4Validator(schema) + errors = list(validator.iter_errors(instance)) + self.assertEqual(len(errors), 1) + e = errors[0] + + self.assertEqual(e.validator, "anyOf") + self.assertEqual(e.validator_value, schema["anyOf"]) + self.assertEqual(e.instance, instance) + self.assertEqual(e.schema, schema) + self.assertIsNone(e.parent) + + self.assertEqual(e.path, deque([])) + self.assertEqual(e.relative_path, deque([])) + self.assertEqual(e.absolute_path, deque([])) + self.assertEqual(e.json_path, "$") + + self.assertEqual(e.schema_path, deque(["anyOf"])) + self.assertEqual(e.relative_schema_path, deque(["anyOf"])) + self.assertEqual(e.absolute_schema_path, deque(["anyOf"])) + + self.assertEqual(len(e.context), 2) + + e1, e2 = sorted_errors(e.context) + + self.assertEqual(e1.validator, "minimum") + self.assertEqual(e1.validator_value, schema["anyOf"][0]["minimum"]) + self.assertEqual(e1.instance, instance) + self.assertEqual(e1.schema, schema["anyOf"][0]) + self.assertIs(e1.parent, e) + + self.assertEqual(e1.path, deque([])) + self.assertEqual(e1.absolute_path, deque([])) + self.assertEqual(e1.relative_path, deque([])) + self.assertEqual(e1.json_path, "$") + + self.assertEqual(e1.schema_path, deque([0, "minimum"])) + self.assertEqual(e1.relative_schema_path, deque([0, "minimum"])) + self.assertEqual( + e1.absolute_schema_path, deque(["anyOf", 0, "minimum"]), + ) + + self.assertFalse(e1.context) + + self.assertEqual(e2.validator, "type") + self.assertEqual(e2.validator_value, schema["anyOf"][1]["type"]) + self.assertEqual(e2.instance, instance) + self.assertEqual(e2.schema, schema["anyOf"][1]) + self.assertIs(e2.parent, e) + + self.assertEqual(e2.path, deque([])) + self.assertEqual(e2.relative_path, deque([])) + self.assertEqual(e2.absolute_path, deque([])) + self.assertEqual(e2.json_path, "$") + + self.assertEqual(e2.schema_path, deque([1, "type"])) + self.assertEqual(e2.relative_schema_path, deque([1, "type"])) + self.assertEqual(e2.absolute_schema_path, deque(["anyOf", 1, "type"])) + + self.assertEqual(len(e2.context), 0) + + def test_type(self): + instance = {"foo": 1} + schema = { + "type": [ + {"type": "integer"}, + { + "type": "object", + "properties": {"foo": {"enum": [2]}}, + }, + ], + } + + validator = validators.Draft3Validator(schema) + errors = list(validator.iter_errors(instance)) + self.assertEqual(len(errors), 1) + e = errors[0] + + self.assertEqual(e.validator, "type") + self.assertEqual(e.validator_value, schema["type"]) + self.assertEqual(e.instance, instance) + self.assertEqual(e.schema, schema) + self.assertIsNone(e.parent) + + self.assertEqual(e.path, deque([])) + self.assertEqual(e.relative_path, deque([])) + self.assertEqual(e.absolute_path, deque([])) + self.assertEqual(e.json_path, "$") + + self.assertEqual(e.schema_path, deque(["type"])) + self.assertEqual(e.relative_schema_path, deque(["type"])) + self.assertEqual(e.absolute_schema_path, deque(["type"])) + + self.assertEqual(len(e.context), 2) + + e1, e2 = sorted_errors(e.context) + + self.assertEqual(e1.validator, "type") + self.assertEqual(e1.validator_value, schema["type"][0]["type"]) + self.assertEqual(e1.instance, instance) + self.assertEqual(e1.schema, schema["type"][0]) + self.assertIs(e1.parent, e) + + self.assertEqual(e1.path, deque([])) + self.assertEqual(e1.relative_path, deque([])) + self.assertEqual(e1.absolute_path, deque([])) + self.assertEqual(e1.json_path, "$") + + self.assertEqual(e1.schema_path, deque([0, "type"])) + self.assertEqual(e1.relative_schema_path, deque([0, "type"])) + self.assertEqual(e1.absolute_schema_path, deque(["type", 0, "type"])) + + self.assertFalse(e1.context) + + self.assertEqual(e2.validator, "enum") + self.assertEqual(e2.validator_value, [2]) + self.assertEqual(e2.instance, 1) + self.assertEqual(e2.schema, {"enum": [2]}) + self.assertIs(e2.parent, e) + + self.assertEqual(e2.path, deque(["foo"])) + self.assertEqual(e2.relative_path, deque(["foo"])) + self.assertEqual(e2.absolute_path, deque(["foo"])) + self.assertEqual(e2.json_path, "$.foo") + + self.assertEqual( + e2.schema_path, deque([1, "properties", "foo", "enum"]), + ) + self.assertEqual( + e2.relative_schema_path, deque([1, "properties", "foo", "enum"]), + ) + self.assertEqual( + e2.absolute_schema_path, + deque(["type", 1, "properties", "foo", "enum"]), + ) + + self.assertFalse(e2.context) + + def test_single_nesting(self): + instance = {"foo": 2, "bar": [1], "baz": 15, "quux": "spam"} + schema = { + "properties": { + "foo": {"type": "string"}, + "bar": {"minItems": 2}, + "baz": {"maximum": 10, "enum": [2, 4, 6, 8]}, + }, + } + + validator = validators.Draft3Validator(schema) + errors = validator.iter_errors(instance) + e1, e2, e3, e4 = sorted_errors(errors) + + self.assertEqual(e1.path, deque(["bar"])) + self.assertEqual(e2.path, deque(["baz"])) + self.assertEqual(e3.path, deque(["baz"])) + self.assertEqual(e4.path, deque(["foo"])) + + self.assertEqual(e1.relative_path, deque(["bar"])) + self.assertEqual(e2.relative_path, deque(["baz"])) + self.assertEqual(e3.relative_path, deque(["baz"])) + self.assertEqual(e4.relative_path, deque(["foo"])) + + self.assertEqual(e1.absolute_path, deque(["bar"])) + self.assertEqual(e2.absolute_path, deque(["baz"])) + self.assertEqual(e3.absolute_path, deque(["baz"])) + self.assertEqual(e4.absolute_path, deque(["foo"])) + + self.assertEqual(e1.json_path, "$.bar") + self.assertEqual(e2.json_path, "$.baz") + self.assertEqual(e3.json_path, "$.baz") + self.assertEqual(e4.json_path, "$.foo") + + self.assertEqual(e1.validator, "minItems") + self.assertEqual(e2.validator, "enum") + self.assertEqual(e3.validator, "maximum") + self.assertEqual(e4.validator, "type") + + def test_multiple_nesting(self): + instance = [1, {"foo": 2, "bar": {"baz": [1]}}, "quux"] + schema = { + "type": "string", + "items": { + "type": ["string", "object"], + "properties": { + "foo": {"enum": [1, 3]}, + "bar": { + "type": "array", + "properties": { + "bar": {"required": True}, + "baz": {"minItems": 2}, + }, + }, + }, + }, + } + + validator = validators.Draft3Validator(schema) + errors = validator.iter_errors(instance) + e1, e2, e3, e4, e5, e6 = sorted_errors(errors) + + self.assertEqual(e1.path, deque([])) + self.assertEqual(e2.path, deque([0])) + self.assertEqual(e3.path, deque([1, "bar"])) + self.assertEqual(e4.path, deque([1, "bar", "bar"])) + self.assertEqual(e5.path, deque([1, "bar", "baz"])) + self.assertEqual(e6.path, deque([1, "foo"])) + + self.assertEqual(e1.json_path, "$") + self.assertEqual(e2.json_path, "$[0]") + self.assertEqual(e3.json_path, "$[1].bar") + self.assertEqual(e4.json_path, "$[1].bar.bar") + self.assertEqual(e5.json_path, "$[1].bar.baz") + self.assertEqual(e6.json_path, "$[1].foo") + + self.assertEqual(e1.schema_path, deque(["type"])) + self.assertEqual(e2.schema_path, deque(["items", "type"])) + self.assertEqual( + list(e3.schema_path), ["items", "properties", "bar", "type"], + ) + self.assertEqual( + list(e4.schema_path), + ["items", "properties", "bar", "properties", "bar", "required"], + ) + self.assertEqual( + list(e5.schema_path), + ["items", "properties", "bar", "properties", "baz", "minItems"], + ) + self.assertEqual( + list(e6.schema_path), ["items", "properties", "foo", "enum"], + ) + + self.assertEqual(e1.validator, "type") + self.assertEqual(e2.validator, "type") + self.assertEqual(e3.validator, "type") + self.assertEqual(e4.validator, "required") + self.assertEqual(e5.validator, "minItems") + self.assertEqual(e6.validator, "enum") + + def test_recursive(self): + schema = { + "definitions": { + "node": { + "anyOf": [{ + "type": "object", + "required": ["name", "children"], + "properties": { + "name": { + "type": "string", + }, + "children": { + "type": "object", + "patternProperties": { + "^.*$": { + "$ref": "#/definitions/node", + }, + }, + }, + }, + }], + }, + }, + "type": "object", + "required": ["root"], + "properties": {"root": {"$ref": "#/definitions/node"}}, + } + + instance = { + "root": { + "name": "root", + "children": { + "a": { + "name": "a", + "children": { + "ab": { + "name": "ab", + # missing "children" + }, + }, + }, + }, + }, + } + validator = validators.Draft4Validator(schema) + + e, = validator.iter_errors(instance) + self.assertEqual(e.absolute_path, deque(["root"])) + self.assertEqual( + e.absolute_schema_path, deque(["properties", "root", "anyOf"]), + ) + self.assertEqual(e.json_path, "$.root") + + e1, = e.context + self.assertEqual(e1.absolute_path, deque(["root", "children", "a"])) + self.assertEqual( + e1.absolute_schema_path, deque( + [ + "properties", + "root", + "anyOf", + 0, + "properties", + "children", + "patternProperties", + "^.*$", + "anyOf", + ], + ), + ) + self.assertEqual(e1.json_path, "$.root.children.a") + + e2, = e1.context + self.assertEqual( + e2.absolute_path, deque( + ["root", "children", "a", "children", "ab"], + ), + ) + self.assertEqual( + e2.absolute_schema_path, deque( + [ + "properties", + "root", + "anyOf", + 0, + "properties", + "children", + "patternProperties", + "^.*$", + "anyOf", + 0, + "properties", + "children", + "patternProperties", + "^.*$", + "anyOf", + ], + ), + ) + self.assertEqual(e2.json_path, "$.root.children.a.children.ab") + + def test_additionalProperties(self): + instance = {"bar": "bar", "foo": 2} + schema = {"additionalProperties": {"type": "integer", "minimum": 5}} + + validator = validators.Draft3Validator(schema) + errors = validator.iter_errors(instance) + e1, e2 = sorted_errors(errors) + + self.assertEqual(e1.path, deque(["bar"])) + self.assertEqual(e2.path, deque(["foo"])) + + self.assertEqual(e1.json_path, "$.bar") + self.assertEqual(e2.json_path, "$.foo") + + self.assertEqual(e1.validator, "type") + self.assertEqual(e2.validator, "minimum") + + def test_patternProperties(self): + instance = {"bar": 1, "foo": 2} + schema = { + "patternProperties": { + "bar": {"type": "string"}, + "foo": {"minimum": 5}, + }, + } + + validator = validators.Draft3Validator(schema) + errors = validator.iter_errors(instance) + e1, e2 = sorted_errors(errors) + + self.assertEqual(e1.path, deque(["bar"])) + self.assertEqual(e2.path, deque(["foo"])) + + self.assertEqual(e1.json_path, "$.bar") + self.assertEqual(e2.json_path, "$.foo") + + self.assertEqual(e1.validator, "type") + self.assertEqual(e2.validator, "minimum") + + def test_additionalItems(self): + instance = ["foo", 1] + schema = { + "items": [], + "additionalItems": {"type": "integer", "minimum": 5}, + } + + validator = validators.Draft3Validator(schema) + errors = validator.iter_errors(instance) + e1, e2 = sorted_errors(errors) + + self.assertEqual(e1.path, deque([0])) + self.assertEqual(e2.path, deque([1])) + + self.assertEqual(e1.json_path, "$[0]") + self.assertEqual(e2.json_path, "$[1]") + + self.assertEqual(e1.validator, "type") + self.assertEqual(e2.validator, "minimum") + + def test_additionalItems_with_items(self): + instance = ["foo", "bar", 1] + schema = { + "items": [{}], + "additionalItems": {"type": "integer", "minimum": 5}, + } + + validator = validators.Draft3Validator(schema) + errors = validator.iter_errors(instance) + e1, e2 = sorted_errors(errors) + + self.assertEqual(e1.path, deque([1])) + self.assertEqual(e2.path, deque([2])) + + self.assertEqual(e1.json_path, "$[1]") + self.assertEqual(e2.json_path, "$[2]") + + self.assertEqual(e1.validator, "type") + self.assertEqual(e2.validator, "minimum") + + def test_propertyNames(self): + instance = {"foo": 12} + schema = {"propertyNames": {"not": {"const": "foo"}}} + + validator = validators.Draft7Validator(schema) + error, = validator.iter_errors(instance) + + self.assertEqual(error.validator, "not") + self.assertEqual( + error.message, + "'foo' should not be valid under {'const': 'foo'}", + ) + self.assertEqual(error.path, deque([])) + self.assertEqual(error.json_path, "$") + self.assertEqual(error.schema_path, deque(["propertyNames", "not"])) + + def test_if_then(self): + schema = { + "if": {"const": 12}, + "then": {"const": 13}, + } + + validator = validators.Draft7Validator(schema) + error, = validator.iter_errors(12) + + self.assertEqual(error.validator, "const") + self.assertEqual(error.message, "13 was expected") + self.assertEqual(error.path, deque([])) + self.assertEqual(error.json_path, "$") + self.assertEqual(error.schema_path, deque(["then", "const"])) + + def test_if_else(self): + schema = { + "if": {"const": 12}, + "else": {"const": 13}, + } + + validator = validators.Draft7Validator(schema) + error, = validator.iter_errors(15) + + self.assertEqual(error.validator, "const") + self.assertEqual(error.message, "13 was expected") + self.assertEqual(error.path, deque([])) + self.assertEqual(error.json_path, "$") + self.assertEqual(error.schema_path, deque(["else", "const"])) + + def test_boolean_schema_False(self): + validator = validators.Draft7Validator(False) + error, = validator.iter_errors(12) + + self.assertEqual( + ( + error.message, + error.validator, + error.validator_value, + error.instance, + error.schema, + error.schema_path, + error.json_path, + ), + ( + "False schema does not allow 12", + None, + None, + 12, + False, + deque([]), + "$", + ), + ) + + def test_ref(self): + ref, schema = "someRef", {"additionalProperties": {"type": "integer"}} + validator = validators.Draft7Validator( + {"$ref": ref}, + resolver=validators._RefResolver("", {}, store={ref: schema}), + ) + error, = validator.iter_errors({"foo": "notAnInteger"}) + + self.assertEqual( + ( + error.message, + error.validator, + error.validator_value, + error.instance, + error.absolute_path, + error.schema, + error.schema_path, + error.json_path, + ), + ( + "'notAnInteger' is not of type 'integer'", + "type", + "integer", + "notAnInteger", + deque(["foo"]), + {"type": "integer"}, + deque(["additionalProperties", "type"]), + "$.foo", + ), + ) + + def test_prefixItems(self): + schema = {"prefixItems": [{"type": "string"}, {}, {}, {"maximum": 3}]} + validator = validators.Draft202012Validator(schema) + type_error, min_error = validator.iter_errors([1, 2, "foo", 5]) + self.assertEqual( + ( + type_error.message, + type_error.validator, + type_error.validator_value, + type_error.instance, + type_error.absolute_path, + type_error.schema, + type_error.schema_path, + type_error.json_path, + ), + ( + "1 is not of type 'string'", + "type", + "string", + 1, + deque([0]), + {"type": "string"}, + deque(["prefixItems", 0, "type"]), + "$[0]", + ), + ) + self.assertEqual( + ( + min_error.message, + min_error.validator, + min_error.validator_value, + min_error.instance, + min_error.absolute_path, + min_error.schema, + min_error.schema_path, + min_error.json_path, + ), + ( + "5 is greater than the maximum of 3", + "maximum", + 3, + 5, + deque([3]), + {"maximum": 3}, + deque(["prefixItems", 3, "maximum"]), + "$[3]", + ), + ) + + def test_prefixItems_with_items(self): + schema = { + "items": {"type": "string"}, + "prefixItems": [{}], + } + validator = validators.Draft202012Validator(schema) + e1, e2 = validator.iter_errors(["foo", 2, "bar", 4, "baz"]) + self.assertEqual( + ( + e1.message, + e1.validator, + e1.validator_value, + e1.instance, + e1.absolute_path, + e1.schema, + e1.schema_path, + e1.json_path, + ), + ( + "2 is not of type 'string'", + "type", + "string", + 2, + deque([1]), + {"type": "string"}, + deque(["items", "type"]), + "$[1]", + ), + ) + self.assertEqual( + ( + e2.message, + e2.validator, + e2.validator_value, + e2.instance, + e2.absolute_path, + e2.schema, + e2.schema_path, + e2.json_path, + ), + ( + "4 is not of type 'string'", + "type", + "string", + 4, + deque([3]), + {"type": "string"}, + deque(["items", "type"]), + "$[3]", + ), + ) + + def test_contains_too_many(self): + """ + `contains` + `maxContains` produces only one error, even if there are + many more incorrectly matching elements. + """ + schema = {"contains": {"type": "string"}, "maxContains": 2} + validator = validators.Draft202012Validator(schema) + error, = validator.iter_errors(["foo", 2, "bar", 4, "baz", "quux"]) + self.assertEqual( + ( + error.message, + error.validator, + error.validator_value, + error.instance, + error.absolute_path, + error.schema, + error.schema_path, + error.json_path, + ), + ( + "Too many items match the given schema (expected at most 2)", + "maxContains", + 2, + ["foo", 2, "bar", 4, "baz", "quux"], + deque([]), + {"contains": {"type": "string"}, "maxContains": 2}, + deque(["contains"]), + "$", + ), + ) + + def test_contains_too_few(self): + schema = {"contains": {"type": "string"}, "minContains": 2} + validator = validators.Draft202012Validator(schema) + error, = validator.iter_errors(["foo", 2, 4]) + self.assertEqual( + ( + error.message, + error.validator, + error.validator_value, + error.instance, + error.absolute_path, + error.schema, + error.schema_path, + error.json_path, + ), + ( + ( + "Too few items match the given schema " + "(expected at least 2 but only 1 matched)" + ), + "minContains", + 2, + ["foo", 2, 4], + deque([]), + {"contains": {"type": "string"}, "minContains": 2}, + deque(["contains"]), + "$", + ), + ) + + def test_contains_none(self): + schema = {"contains": {"type": "string"}, "minContains": 2} + validator = validators.Draft202012Validator(schema) + error, = validator.iter_errors([2, 4]) + self.assertEqual( + ( + error.message, + error.validator, + error.validator_value, + error.instance, + error.absolute_path, + error.schema, + error.schema_path, + error.json_path, + ), + ( + "[2, 4] does not contain items matching the given schema", + "contains", + {"type": "string"}, + [2, 4], + deque([]), + {"contains": {"type": "string"}, "minContains": 2}, + deque(["contains"]), + "$", + ), + ) + + def test_ref_sibling(self): + schema = { + "$defs": {"foo": {"required": ["bar"]}}, + "properties": { + "aprop": { + "$ref": "#/$defs/foo", + "required": ["baz"], + }, + }, + } + + validator = validators.Draft202012Validator(schema) + e1, e2 = validator.iter_errors({"aprop": {}}) + self.assertEqual( + ( + e1.message, + e1.validator, + e1.validator_value, + e1.instance, + e1.absolute_path, + e1.schema, + e1.schema_path, + e1.relative_schema_path, + e1.json_path, + ), + ( + "'bar' is a required property", + "required", + ["bar"], + {}, + deque(["aprop"]), + {"required": ["bar"]}, + deque(["properties", "aprop", "required"]), + deque(["properties", "aprop", "required"]), + "$.aprop", + ), + ) + self.assertEqual( + ( + e2.message, + e2.validator, + e2.validator_value, + e2.instance, + e2.absolute_path, + e2.schema, + e2.schema_path, + e2.relative_schema_path, + e2.json_path, + ), + ( + "'baz' is a required property", + "required", + ["baz"], + {}, + deque(["aprop"]), + {"$ref": "#/$defs/foo", "required": ["baz"]}, + deque(["properties", "aprop", "required"]), + deque(["properties", "aprop", "required"]), + "$.aprop", + ), + ) + + +class MetaSchemaTestsMixin: + # TODO: These all belong upstream + def test_invalid_properties(self): + with self.assertRaises(exceptions.SchemaError): + self.Validator.check_schema({"properties": 12}) + + def test_minItems_invalid_string(self): + with self.assertRaises(exceptions.SchemaError): + # needs to be an integer + self.Validator.check_schema({"minItems": "1"}) + + def test_enum_allows_empty_arrays(self): + """ + Technically, all the spec says is they SHOULD have elements, not MUST. + + (As of Draft 6. Previous drafts do say MUST). + + See #529. + """ + if self.Validator in { + validators.Draft3Validator, + validators.Draft4Validator, + }: + with self.assertRaises(exceptions.SchemaError): + self.Validator.check_schema({"enum": []}) + else: + self.Validator.check_schema({"enum": []}) + + def test_enum_allows_non_unique_items(self): + """ + Technically, all the spec says is they SHOULD be unique, not MUST. + + (As of Draft 6. Previous drafts do say MUST). + + See #529. + """ + if self.Validator in { + validators.Draft3Validator, + validators.Draft4Validator, + }: + with self.assertRaises(exceptions.SchemaError): + self.Validator.check_schema({"enum": [12, 12]}) + else: + self.Validator.check_schema({"enum": [12, 12]}) + + def test_schema_with_invalid_regex(self): + with self.assertRaises(exceptions.SchemaError): + self.Validator.check_schema({"pattern": "*notaregex"}) + + def test_schema_with_invalid_regex_with_disabled_format_validation(self): + self.Validator.check_schema( + {"pattern": "*notaregex"}, + format_checker=None, + ) + + +class ValidatorTestMixin(MetaSchemaTestsMixin): + def test_it_implements_the_validator_protocol(self): + self.assertIsInstance(self.Validator({}), protocols.Validator) + + def test_valid_instances_are_valid(self): + schema, instance = self.valid + self.assertTrue(self.Validator(schema).is_valid(instance)) + + def test_invalid_instances_are_not_valid(self): + schema, instance = self.invalid + self.assertFalse(self.Validator(schema).is_valid(instance)) + + def test_non_existent_properties_are_ignored(self): + self.Validator({object(): object()}).validate(instance=object()) + + def test_evolve(self): + schema, format_checker = {"type": "integer"}, FormatChecker() + original = self.Validator( + schema, + format_checker=format_checker, + ) + new = original.evolve( + schema={"type": "string"}, + format_checker=self.Validator.FORMAT_CHECKER, + ) + + expected = self.Validator( + {"type": "string"}, + format_checker=self.Validator.FORMAT_CHECKER, + _resolver=new._resolver, + ) + + self.assertEqual(new, expected) + self.assertNotEqual(new, original) + + def test_evolve_with_subclass(self): + """ + Subclassing validators isn't supported public API, but some users have + done it, because we don't actually error entirely when it's done :/ + + We need to deprecate doing so first to help as many of these users + ensure they can move to supported APIs, but this test ensures that in + the interim, we haven't broken those users. + """ + + with self.assertWarns(DeprecationWarning): + @define + class OhNo(self.Validator): + foo = field(factory=lambda: [1, 2, 3]) + _bar = field(default=37) + + validator = OhNo({}, bar=12) + self.assertEqual(validator.foo, [1, 2, 3]) + + new = validator.evolve(schema={"type": "integer"}) + self.assertEqual(new.foo, [1, 2, 3]) + self.assertEqual(new._bar, 12) + + def test_is_type_is_true_for_valid_type(self): + self.assertTrue(self.Validator({}).is_type("foo", "string")) + + def test_is_type_is_false_for_invalid_type(self): + self.assertFalse(self.Validator({}).is_type("foo", "array")) + + def test_is_type_evades_bool_inheriting_from_int(self): + self.assertFalse(self.Validator({}).is_type(True, "integer")) + self.assertFalse(self.Validator({}).is_type(True, "number")) + + def test_it_can_validate_with_decimals(self): + schema = {"items": {"type": "number"}} + Validator = validators.extend( + self.Validator, + type_checker=self.Validator.TYPE_CHECKER.redefine( + "number", + lambda checker, thing: isinstance( + thing, (int, float, Decimal), + ) and not isinstance(thing, bool), + ), + ) + + validator = Validator(schema) + validator.validate([1, 1.1, Decimal(1) / Decimal(8)]) + + invalid = ["foo", {}, [], True, None] + self.assertEqual( + [error.instance for error in validator.iter_errors(invalid)], + invalid, + ) + + def test_it_returns_true_for_formats_it_does_not_know_about(self): + validator = self.Validator( + {"format": "carrot"}, format_checker=FormatChecker(), + ) + validator.validate("bugs") + + def test_it_does_not_validate_formats_by_default(self): + validator = self.Validator({}) + self.assertIsNone(validator.format_checker) + + def test_it_validates_formats_if_a_checker_is_provided(self): + checker = FormatChecker() + bad = ValueError("Bad!") + + @checker.checks("foo", raises=ValueError) + def check(value): + if value == "good": + return True + elif value == "bad": + raise bad + else: # pragma: no cover + self.fail(f"What is {value}? [Baby Don't Hurt Me]") + + validator = self.Validator( + {"format": "foo"}, format_checker=checker, + ) + + validator.validate("good") + with self.assertRaises(exceptions.ValidationError) as cm: + validator.validate("bad") + + # Make sure original cause is attached + self.assertIs(cm.exception.cause, bad) + + def test_non_string_custom_type(self): + non_string_type = object() + schema = {"type": [non_string_type]} + Crazy = validators.extend( + self.Validator, + type_checker=self.Validator.TYPE_CHECKER.redefine( + non_string_type, + lambda checker, thing: isinstance(thing, int), + ), + ) + Crazy(schema).validate(15) + + def test_it_properly_formats_tuples_in_errors(self): + """ + A tuple instance properly formats validation errors for uniqueItems. + + See #224 + """ + TupleValidator = validators.extend( + self.Validator, + type_checker=self.Validator.TYPE_CHECKER.redefine( + "array", + lambda checker, thing: isinstance(thing, tuple), + ), + ) + with self.assertRaises(exceptions.ValidationError) as e: + TupleValidator({"uniqueItems": True}).validate((1, 1)) + self.assertIn("(1, 1) has non-unique elements", str(e.exception)) + + def test_check_redefined_sequence(self): + """ + Allow array to validate against another defined sequence type + """ + schema = {"type": "array", "uniqueItems": True} + MyMapping = namedtuple("MyMapping", "a, b") + Validator = validators.extend( + self.Validator, + type_checker=self.Validator.TYPE_CHECKER.redefine_many( + { + "array": lambda checker, thing: isinstance( + thing, (list, deque), + ), + "object": lambda checker, thing: isinstance( + thing, (dict, MyMapping), + ), + }, + ), + ) + validator = Validator(schema) + + valid_instances = [ + deque(["a", None, "1", "", True]), + deque([[False], [0]]), + [deque([False]), deque([0])], + [[deque([False])], [deque([0])]], + [[[[[deque([False])]]]], [[[[deque([0])]]]]], + [deque([deque([False])]), deque([deque([0])])], + [MyMapping("a", 0), MyMapping("a", False)], + [ + MyMapping("a", [deque([0])]), + MyMapping("a", [deque([False])]), + ], + [ + MyMapping("a", [MyMapping("a", deque([0]))]), + MyMapping("a", [MyMapping("a", deque([False]))]), + ], + [deque(deque(deque([False]))), deque(deque(deque([0])))], + ] + + for instance in valid_instances: + validator.validate(instance) + + invalid_instances = [ + deque(["a", "b", "a"]), + deque([[False], [False]]), + [deque([False]), deque([False])], + [[deque([False])], [deque([False])]], + [[[[[deque([False])]]]], [[[[deque([False])]]]]], + [deque([deque([False])]), deque([deque([False])])], + [MyMapping("a", False), MyMapping("a", False)], + [ + MyMapping("a", [deque([False])]), + MyMapping("a", [deque([False])]), + ], + [ + MyMapping("a", [MyMapping("a", deque([False]))]), + MyMapping("a", [MyMapping("a", deque([False]))]), + ], + [deque(deque(deque([False]))), deque(deque(deque([False])))], + ] + + for instance in invalid_instances: + with self.assertRaises(exceptions.ValidationError): + validator.validate(instance) + + def test_it_creates_a_ref_resolver_if_not_provided(self): + with self.assertWarns(DeprecationWarning): + resolver = self.Validator({}).resolver + self.assertIsInstance(resolver, validators._RefResolver) + + def test_it_upconverts_from_deprecated_RefResolvers(self): + ref, schema = "someCoolRef", {"type": "integer"} + resolver = validators._RefResolver("", {}, store={ref: schema}) + validator = self.Validator({"$ref": ref}, resolver=resolver) + + with self.assertRaises(exceptions.ValidationError): + validator.validate(None) + + def test_it_upconverts_from_yet_older_deprecated_legacy_RefResolvers(self): + """ + Legacy RefResolvers support only the context manager form of + resolution. + """ + + class LegacyRefResolver: + @contextmanager + def resolving(this, ref): + self.assertEqual(ref, "the ref") + yield {"type": "integer"} + + resolver = LegacyRefResolver() + schema = {"$ref": "the ref"} + + with self.assertRaises(exceptions.ValidationError): + self.Validator(schema, resolver=resolver).validate(None) + + +class AntiDraft6LeakMixin: + """ + Make sure functionality from draft 6 doesn't leak backwards in time. + """ + + def test_True_is_not_a_schema(self): + with self.assertRaises(exceptions.SchemaError) as e: + self.Validator.check_schema(True) + self.assertIn("True is not of type", str(e.exception)) + + def test_False_is_not_a_schema(self): + with self.assertRaises(exceptions.SchemaError) as e: + self.Validator.check_schema(False) + self.assertIn("False is not of type", str(e.exception)) + + def test_True_is_not_a_schema_even_if_you_forget_to_check(self): + with self.assertRaises(Exception) as e: + self.Validator(True).validate(12) + self.assertNotIsInstance(e.exception, exceptions.ValidationError) + + def test_False_is_not_a_schema_even_if_you_forget_to_check(self): + with self.assertRaises(Exception) as e: + self.Validator(False).validate(12) + self.assertNotIsInstance(e.exception, exceptions.ValidationError) + + +class TestDraft3Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase): + Validator = validators.Draft3Validator + valid: tuple[dict, dict] = ({}, {}) + invalid = {"type": "integer"}, "foo" + + def test_any_type_is_valid_for_type_any(self): + validator = self.Validator({"type": "any"}) + validator.validate(object()) + + def test_any_type_is_redefinable(self): + """ + Sigh, because why not. + """ + Crazy = validators.extend( + self.Validator, + type_checker=self.Validator.TYPE_CHECKER.redefine( + "any", lambda checker, thing: isinstance(thing, int), + ), + ) + validator = Crazy({"type": "any"}) + validator.validate(12) + with self.assertRaises(exceptions.ValidationError): + validator.validate("foo") + + def test_is_type_is_true_for_any_type(self): + self.assertTrue(self.Validator({"type": "any"}).is_valid(object())) + + def test_is_type_does_not_evade_bool_if_it_is_being_tested(self): + self.assertTrue(self.Validator({}).is_type(True, "boolean")) + self.assertTrue(self.Validator({"type": "any"}).is_valid(True)) + + +class TestDraft4Validator(AntiDraft6LeakMixin, ValidatorTestMixin, TestCase): + Validator = validators.Draft4Validator + valid: tuple[dict, dict] = ({}, {}) + invalid = {"type": "integer"}, "foo" + + +class TestDraft6Validator(ValidatorTestMixin, TestCase): + Validator = validators.Draft6Validator + valid: tuple[dict, dict] = ({}, {}) + invalid = {"type": "integer"}, "foo" + + +class TestDraft7Validator(ValidatorTestMixin, TestCase): + Validator = validators.Draft7Validator + valid: tuple[dict, dict] = ({}, {}) + invalid = {"type": "integer"}, "foo" + + +class TestDraft201909Validator(ValidatorTestMixin, TestCase): + Validator = validators.Draft201909Validator + valid: tuple[dict, dict] = ({}, {}) + invalid = {"type": "integer"}, "foo" + + +class TestDraft202012Validator(ValidatorTestMixin, TestCase): + Validator = validators.Draft202012Validator + valid: tuple[dict, dict] = ({}, {}) + invalid = {"type": "integer"}, "foo" + + +class TestLatestValidator(TestCase): + """ + These really apply to multiple versions but are easiest to test on one. + """ + + def test_ref_resolvers_may_have_boolean_schemas_stored(self): + ref = "someCoolRef" + schema = {"$ref": ref} + resolver = validators._RefResolver("", {}, store={ref: False}) + validator = validators._LATEST_VERSION(schema, resolver=resolver) + + with self.assertRaises(exceptions.ValidationError): + validator.validate(None) + + +class TestValidatorFor(TestCase): + def test_draft_3(self): + schema = {"$schema": "http://json-schema.org/draft-03/schema"} + self.assertIs( + validators.validator_for(schema), + validators.Draft3Validator, + ) + + schema = {"$schema": "http://json-schema.org/draft-03/schema#"} + self.assertIs( + validators.validator_for(schema), + validators.Draft3Validator, + ) + + def test_draft_4(self): + schema = {"$schema": "http://json-schema.org/draft-04/schema"} + self.assertIs( + validators.validator_for(schema), + validators.Draft4Validator, + ) + + schema = {"$schema": "http://json-schema.org/draft-04/schema#"} + self.assertIs( + validators.validator_for(schema), + validators.Draft4Validator, + ) + + def test_draft_6(self): + schema = {"$schema": "http://json-schema.org/draft-06/schema"} + self.assertIs( + validators.validator_for(schema), + validators.Draft6Validator, + ) + + schema = {"$schema": "http://json-schema.org/draft-06/schema#"} + self.assertIs( + validators.validator_for(schema), + validators.Draft6Validator, + ) + + def test_draft_7(self): + schema = {"$schema": "http://json-schema.org/draft-07/schema"} + self.assertIs( + validators.validator_for(schema), + validators.Draft7Validator, + ) + + schema = {"$schema": "http://json-schema.org/draft-07/schema#"} + self.assertIs( + validators.validator_for(schema), + validators.Draft7Validator, + ) + + def test_draft_201909(self): + schema = {"$schema": "https://json-schema.org/draft/2019-09/schema"} + self.assertIs( + validators.validator_for(schema), + validators.Draft201909Validator, + ) + + schema = {"$schema": "https://json-schema.org/draft/2019-09/schema#"} + self.assertIs( + validators.validator_for(schema), + validators.Draft201909Validator, + ) + + def test_draft_202012(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + self.assertIs( + validators.validator_for(schema), + validators.Draft202012Validator, + ) + + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema#"} + self.assertIs( + validators.validator_for(schema), + validators.Draft202012Validator, + ) + + def test_True(self): + self.assertIs( + validators.validator_for(True), + validators._LATEST_VERSION, + ) + + def test_False(self): + self.assertIs( + validators.validator_for(False), + validators._LATEST_VERSION, + ) + + def test_custom_validator(self): + Validator = validators.create( + meta_schema={"id": "meta schema id"}, + version="12", + id_of=lambda s: s.get("id", ""), + ) + schema = {"$schema": "meta schema id"} + self.assertIs( + validators.validator_for(schema), + Validator, + ) + + def test_custom_validator_draft6(self): + Validator = validators.create( + meta_schema={"$id": "meta schema $id"}, + version="13", + ) + schema = {"$schema": "meta schema $id"} + self.assertIs( + validators.validator_for(schema), + Validator, + ) + + def test_validator_for_jsonschema_default(self): + self.assertIs(validators.validator_for({}), validators._LATEST_VERSION) + + def test_validator_for_custom_default(self): + self.assertIs(validators.validator_for({}, default=None), None) + + def test_warns_if_meta_schema_specified_was_not_found(self): + with self.assertWarns(DeprecationWarning) as cm: + validators.validator_for(schema={"$schema": "unknownSchema"}) + + self.assertEqual(cm.filename, __file__) + self.assertEqual( + str(cm.warning), + "The metaschema specified by $schema was not found. " + "Using the latest draft to validate, but this will raise " + "an error in the future.", + ) + + def test_does_not_warn_if_meta_schema_is_unspecified(self): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + validators.validator_for(schema={}, default={}) + self.assertFalse(w) + + def test_validator_for_custom_default_with_schema(self): + schema, default = {"$schema": "mailto:foo@example.com"}, object() + self.assertIs(validators.validator_for(schema, default), default) + + +class TestValidate(TestCase): + def assertUses(self, schema, Validator): + result = [] + with mock.patch.object(Validator, "check_schema", result.append): + validators.validate({}, schema) + self.assertEqual(result, [schema]) + + def test_draft3_validator_is_chosen(self): + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-03/schema#"}, + Validator=validators.Draft3Validator, + ) + # Make sure it works without the empty fragment + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-03/schema"}, + Validator=validators.Draft3Validator, + ) + + def test_draft4_validator_is_chosen(self): + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-04/schema#"}, + Validator=validators.Draft4Validator, + ) + # Make sure it works without the empty fragment + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-04/schema"}, + Validator=validators.Draft4Validator, + ) + + def test_draft6_validator_is_chosen(self): + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-06/schema#"}, + Validator=validators.Draft6Validator, + ) + # Make sure it works without the empty fragment + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-06/schema"}, + Validator=validators.Draft6Validator, + ) + + def test_draft7_validator_is_chosen(self): + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-07/schema#"}, + Validator=validators.Draft7Validator, + ) + # Make sure it works without the empty fragment + self.assertUses( + schema={"$schema": "http://json-schema.org/draft-07/schema"}, + Validator=validators.Draft7Validator, + ) + + def test_draft202012_validator_is_chosen(self): + self.assertUses( + schema={ + "$schema": "https://json-schema.org/draft/2020-12/schema#", + }, + Validator=validators.Draft202012Validator, + ) + # Make sure it works without the empty fragment + self.assertUses( + schema={ + "$schema": "https://json-schema.org/draft/2020-12/schema", + }, + Validator=validators.Draft202012Validator, + ) + + def test_draft202012_validator_is_the_default(self): + self.assertUses(schema={}, Validator=validators.Draft202012Validator) + + def test_validation_error_message(self): + with self.assertRaises(exceptions.ValidationError) as e: + validators.validate(12, {"type": "string"}) + self.assertRegex( + str(e.exception), + "(?s)Failed validating '.*' in schema.*On instance", + ) + + def test_schema_error_message(self): + with self.assertRaises(exceptions.SchemaError) as e: + validators.validate(12, {"type": 12}) + self.assertRegex( + str(e.exception), + "(?s)Failed validating '.*' in metaschema.*On schema", + ) + + def test_it_uses_best_match(self): + schema = { + "oneOf": [ + {"type": "number", "minimum": 20}, + {"type": "array"}, + ], + } + with self.assertRaises(exceptions.ValidationError) as e: + validators.validate(12, schema) + self.assertIn("12 is less than the minimum of 20", str(e.exception)) + + +class TestThreading(TestCase): + """ + Threading-related functionality tests. + + jsonschema doesn't promise thread safety, and its validation behavior + across multiple threads may change at any time, but that means it isn't + safe to share *validators* across threads, not that anytime one has + multiple threads that jsonschema won't work (it certainly is intended to). + + These tests ensure that this minimal level of functionality continues to + work. + """ + + def test_validation_across_a_second_thread(self): + failed = [] + + def validate(): + try: + validators.validate(instance=37, schema=True) + except: # pragma: no cover # noqa: E722 + failed.append(sys.exc_info()) + + validate() # just verify it succeeds + + from threading import Thread + thread = Thread(target=validate) + thread.start() + thread.join() + self.assertEqual((thread.is_alive(), failed), (False, [])) + + +class TestReferencing(TestCase): + def test_registry_with_retrieve(self): + def retrieve(uri): + return DRAFT202012.create_resource({"type": "integer"}) + + registry = referencing.Registry(retrieve=retrieve) + schema = {"$ref": "https://example.com/"} + validator = validators.Draft202012Validator(schema, registry=registry) + + self.assertEqual( + (validator.is_valid(12), validator.is_valid("foo")), + (True, False), + ) + + def test_custom_registries_do_not_autoretrieve_remote_resources(self): + registry = referencing.Registry() + schema = {"$ref": "https://example.com/"} + validator = validators.Draft202012Validator(schema, registry=registry) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + with self.assertRaises(referencing.exceptions.Unresolvable): + validator.validate(12) + self.assertFalse(w) + + +class TestRefResolver(TestCase): + + base_uri = "" + stored_uri = "foo://stored" + stored_schema = {"stored": "schema"} + + def setUp(self): + self.referrer = {} + self.store = {self.stored_uri: self.stored_schema} + self.resolver = validators._RefResolver( + self.base_uri, self.referrer, self.store, + ) + + def test_it_does_not_retrieve_schema_urls_from_the_network(self): + ref = validators.Draft3Validator.META_SCHEMA["id"] + with mock.patch.object(self.resolver, "resolve_remote") as patched: # noqa: SIM117 + with self.resolver.resolving(ref) as resolved: + pass + self.assertEqual(resolved, validators.Draft3Validator.META_SCHEMA) + self.assertFalse(patched.called) + + def test_it_resolves_local_refs(self): + ref = "#/properties/foo" + self.referrer["properties"] = {"foo": object()} + with self.resolver.resolving(ref) as resolved: + self.assertEqual(resolved, self.referrer["properties"]["foo"]) + + def test_it_resolves_local_refs_with_id(self): + schema = {"id": "http://bar/schema#", "a": {"foo": "bar"}} + resolver = validators._RefResolver.from_schema( + schema, + id_of=lambda schema: schema.get("id", ""), + ) + with resolver.resolving("#/a") as resolved: + self.assertEqual(resolved, schema["a"]) + with resolver.resolving("http://bar/schema#/a") as resolved: + self.assertEqual(resolved, schema["a"]) + + def test_it_retrieves_stored_refs(self): + with self.resolver.resolving(self.stored_uri) as resolved: + self.assertIs(resolved, self.stored_schema) + + self.resolver.store["cached_ref"] = {"foo": 12} + with self.resolver.resolving("cached_ref#/foo") as resolved: + self.assertEqual(resolved, 12) + + def test_it_retrieves_unstored_refs_via_requests(self): + ref = "http://bar#baz" + schema = {"baz": 12} + + if "requests" in sys.modules: # pragma: no cover + self.addCleanup( + sys.modules.__setitem__, "requests", sys.modules["requests"], + ) + sys.modules["requests"] = ReallyFakeRequests({"http://bar": schema}) + + with self.resolver.resolving(ref) as resolved: + self.assertEqual(resolved, 12) + + def test_it_retrieves_unstored_refs_via_urlopen(self): + ref = "http://bar#baz" + schema = {"baz": 12} + + if "requests" in sys.modules: # pragma: no cover + self.addCleanup( + sys.modules.__setitem__, "requests", sys.modules["requests"], + ) + sys.modules["requests"] = None + + @contextmanager + def fake_urlopen(url): + self.assertEqual(url, "http://bar") + yield BytesIO(json.dumps(schema).encode("utf8")) + + with mock.patch("urllib.request.urlopen", new=fake_urlopen): # noqa: SIM117 + with self.resolver.resolving(ref) as resolved: + pass + self.assertEqual(resolved, 12) + + def test_it_retrieves_local_refs_via_urlopen(self): + with tempfile.NamedTemporaryFile(delete=False, mode="wt") as tempf: + self.addCleanup(os.remove, tempf.name) + json.dump({"foo": "bar"}, tempf) + + ref = f"file://{pathname2url(tempf.name)}#foo" + with self.resolver.resolving(ref) as resolved: + self.assertEqual(resolved, "bar") + + def test_it_can_construct_a_base_uri_from_a_schema(self): + schema = {"id": "foo"} + resolver = validators._RefResolver.from_schema( + schema, + id_of=lambda schema: schema.get("id", ""), + ) + self.assertEqual(resolver.base_uri, "foo") + self.assertEqual(resolver.resolution_scope, "foo") + with resolver.resolving("") as resolved: + self.assertEqual(resolved, schema) + with resolver.resolving("#") as resolved: + self.assertEqual(resolved, schema) + with resolver.resolving("foo") as resolved: + self.assertEqual(resolved, schema) + with resolver.resolving("foo#") as resolved: + self.assertEqual(resolved, schema) + + def test_it_can_construct_a_base_uri_from_a_schema_without_id(self): + schema = {} + resolver = validators._RefResolver.from_schema(schema) + self.assertEqual(resolver.base_uri, "") + self.assertEqual(resolver.resolution_scope, "") + with resolver.resolving("") as resolved: + self.assertEqual(resolved, schema) + with resolver.resolving("#") as resolved: + self.assertEqual(resolved, schema) + + def test_custom_uri_scheme_handlers(self): + def handler(url): + self.assertEqual(url, ref) + return schema + + schema = {"foo": "bar"} + ref = "foo://bar" + resolver = validators._RefResolver("", {}, handlers={"foo": handler}) + with resolver.resolving(ref) as resolved: + self.assertEqual(resolved, schema) + + def test_cache_remote_on(self): + response = [object()] + + def handler(url): + try: + return response.pop() + except IndexError: # pragma: no cover + self.fail("Response must not have been cached!") + + ref = "foo://bar" + resolver = validators._RefResolver( + "", {}, cache_remote=True, handlers={"foo": handler}, + ) + with resolver.resolving(ref): + pass + with resolver.resolving(ref): + pass + + def test_cache_remote_off(self): + response = [object()] + + def handler(url): + try: + return response.pop() + except IndexError: # pragma: no cover + self.fail("Handler called twice!") + + ref = "foo://bar" + resolver = validators._RefResolver( + "", {}, cache_remote=False, handlers={"foo": handler}, + ) + with resolver.resolving(ref): + pass + + def test_if_you_give_it_junk_you_get_a_resolution_error(self): + error = ValueError("Oh no! What's this?") + + def handler(url): + raise error + + ref = "foo://bar" + resolver = validators._RefResolver("", {}, handlers={"foo": handler}) + with self.assertRaises(exceptions._RefResolutionError) as err: # noqa: SIM117 + with resolver.resolving(ref): + self.fail("Shouldn't get this far!") # pragma: no cover + self.assertEqual(err.exception, exceptions._RefResolutionError(error)) + + def test_helpful_error_message_on_failed_pop_scope(self): + resolver = validators._RefResolver("", {}) + resolver.pop_scope() + with self.assertRaises(exceptions._RefResolutionError) as exc: + resolver.pop_scope() + self.assertIn("Failed to pop the scope", str(exc.exception)) + + def test_pointer_within_schema_with_different_id(self): + """ + See #1085. + """ + schema = validators.Draft7Validator.META_SCHEMA + one = validators._RefResolver("", schema) + validator = validators.Draft7Validator(schema, resolver=one) + self.assertFalse(validator.is_valid({"maxLength": "foo"})) + + another = { + "allOf": [{"$ref": validators.Draft7Validator.META_SCHEMA["$id"]}], + } + two = validators._RefResolver("", another) + validator = validators.Draft7Validator(another, resolver=two) + self.assertFalse(validator.is_valid({"maxLength": "foo"})) + + def test_newly_created_validator_with_ref_resolver(self): + """ + See https://github.com/python-jsonschema/jsonschema/issues/1061#issuecomment-1624266555. + """ + + def handle(uri): + self.assertEqual(uri, "http://example.com/foo") + return {"type": "integer"} + + resolver = validators._RefResolver("", {}, handlers={"http": handle}) + Validator = validators.create( + meta_schema={}, + validators=validators.Draft4Validator.VALIDATORS, + ) + schema = {"$id": "http://example.com/bar", "$ref": "foo"} + validator = Validator(schema, resolver=resolver) + self.assertEqual( + (validator.is_valid({}), validator.is_valid(37)), + (False, True), + ) + + def test_refresolver_with_pointer_in_schema_with_no_id(self): + """ + See https://github.com/python-jsonschema/jsonschema/issues/1124#issuecomment-1632574249. + """ + + schema = { + "properties": {"x": {"$ref": "#/definitions/x"}}, + "definitions": {"x": {"type": "integer"}}, + } + + validator = validators.Draft202012Validator( + schema, + resolver=validators._RefResolver("", schema), + ) + self.assertEqual( + (validator.is_valid({"x": "y"}), validator.is_valid({"x": 37})), + (False, True), + ) + + + +def sorted_errors(errors): + def key(error): + return ( + [str(e) for e in error.path], + [str(e) for e in error.schema_path], + ) + return sorted(errors, key=key) + + +@define +class ReallyFakeRequests: + + _responses: dict[str, Any] + + def get(self, url): + response = self._responses.get(url) + if url is None: # pragma: no cover + raise ValueError("Unknown URL: " + repr(url)) + return _ReallyFakeJSONResponse(json.dumps(response)) + + +@define +class _ReallyFakeJSONResponse: + + _response: str + + def json(self): + return json.loads(self._response) diff --git a/source/target-vendors/cp312/jsonschema/tests/typing/__init__.py b/source/target-vendors/cp312/jsonschema/tests/typing/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/jsonschema/tests/typing/test_all_concrete_validators_match_protocol.py b/source/target-vendors/cp312/jsonschema/tests/typing/test_all_concrete_validators_match_protocol.py new file mode 100644 index 0000000..63e8bd4 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/tests/typing/test_all_concrete_validators_match_protocol.py @@ -0,0 +1,38 @@ +""" +This module acts as a test that type checkers will allow each validator +class to be assigned to a variable of type `type[Validator]` + +The assignation is only valid if type checkers recognize each Validator +implementation as a valid implementer of the protocol. +""" +from jsonschema.protocols import Validator +from jsonschema.validators import ( + Draft3Validator, + Draft4Validator, + Draft6Validator, + Draft7Validator, + Draft201909Validator, + Draft202012Validator, +) + +my_validator: type[Validator] + +my_validator = Draft3Validator +my_validator = Draft4Validator +my_validator = Draft6Validator +my_validator = Draft7Validator +my_validator = Draft201909Validator +my_validator = Draft202012Validator + + +# in order to confirm that none of the above were incorrectly typed as 'Any' +# ensure that each of these assignments to a non-validator variable requires an +# ignore +none_var: None + +none_var = Draft3Validator # type: ignore[assignment] +none_var = Draft4Validator # type: ignore[assignment] +none_var = Draft6Validator # type: ignore[assignment] +none_var = Draft7Validator # type: ignore[assignment] +none_var = Draft201909Validator # type: ignore[assignment] +none_var = Draft202012Validator # type: ignore[assignment] diff --git a/source/target-vendors/cp312/jsonschema/validators.py b/source/target-vendors/cp312/jsonschema/validators.py new file mode 100644 index 0000000..98ddf6b --- /dev/null +++ b/source/target-vendors/cp312/jsonschema/validators.py @@ -0,0 +1,1410 @@ +""" +Creation and extension of validators, with implementations for existing drafts. +""" +from __future__ import annotations + +from collections import deque +from collections.abc import Iterable, Mapping, Sequence +from functools import lru_cache +from operator import methodcaller +from typing import TYPE_CHECKING +from urllib.parse import unquote, urldefrag, urljoin, urlsplit +from warnings import warn +import contextlib +import json +import reprlib +import warnings + +from attrs import define, field, fields +from jsonschema_specifications import REGISTRY as SPECIFICATIONS +from rpds import HashTrieMap +import referencing.exceptions +import referencing.jsonschema + +from jsonschema import ( + _format, + _keywords, + _legacy_keywords, + _types, + _typing, + _utils, + exceptions, +) + +if TYPE_CHECKING: + from jsonschema.protocols import Validator + +_UNSET = _utils.Unset() + +_VALIDATORS: dict[str, Validator] = {} +_META_SCHEMAS = _utils.URIDict() + + +def __getattr__(name): + if name == "ErrorTree": + warnings.warn( + "Importing ErrorTree from jsonschema.validators is deprecated. " + "Instead import it from jsonschema.exceptions.", + DeprecationWarning, + stacklevel=2, + ) + from jsonschema.exceptions import ErrorTree + return ErrorTree + elif name == "validators": + warnings.warn( + "Accessing jsonschema.validators.validators is deprecated. " + "Use jsonschema.validators.validator_for with a given schema.", + DeprecationWarning, + stacklevel=2, + ) + return _VALIDATORS + elif name == "meta_schemas": + warnings.warn( + "Accessing jsonschema.validators.meta_schemas is deprecated. " + "Use jsonschema.validators.validator_for with a given schema.", + DeprecationWarning, + stacklevel=2, + ) + return _META_SCHEMAS + elif name == "RefResolver": + warnings.warn( + _RefResolver._DEPRECATION_MESSAGE, + DeprecationWarning, + stacklevel=2, + ) + return _RefResolver + raise AttributeError(f"module {__name__} has no attribute {name}") + + +def validates(version): + """ + Register the decorated validator for a ``version`` of the specification. + + Registered validators and their meta schemas will be considered when + parsing :kw:`$schema` keywords' URIs. + + Arguments: + + version (str): + + An identifier to use as the version's name + + Returns: + + collections.abc.Callable: + + a class decorator to decorate the validator with the version + + """ + + def _validates(cls): + _VALIDATORS[version] = cls + meta_schema_id = cls.ID_OF(cls.META_SCHEMA) + _META_SCHEMAS[meta_schema_id] = cls + return cls + return _validates + + +def _warn_for_remote_retrieve(uri: str): + from urllib.request import Request, urlopen + headers = {"User-Agent": "python-jsonschema (deprecated $ref resolution)"} + request = Request(uri, headers=headers) # noqa: S310 + with urlopen(request) as response: # noqa: S310 + warnings.warn( + "Automatically retrieving remote references can be a security " + "vulnerability and is discouraged by the JSON Schema " + "specifications. Relying on this behavior is deprecated " + "and will shortly become an error. If you are sure you want to " + "remotely retrieve your reference and that it is safe to do so, " + "you can find instructions for doing so via referencing.Registry " + "in the referencing documentation " + "(https://referencing.readthedocs.org).", + DeprecationWarning, + stacklevel=9, # Ha ha ha ha magic numbers :/ + ) + return referencing.Resource.from_contents( + json.load(response), + default_specification=referencing.jsonschema.DRAFT202012, + ) + + +_REMOTE_WARNING_REGISTRY = SPECIFICATIONS.combine( + referencing.Registry(retrieve=_warn_for_remote_retrieve), # type: ignore[call-arg] +) + + +def create( + meta_schema: referencing.jsonschema.ObjectSchema, + validators: ( + Mapping[str, _typing.SchemaKeywordValidator] + | Iterable[tuple[str, _typing.SchemaKeywordValidator]] + ) = (), + version: str | None = None, + type_checker: _types.TypeChecker = _types.draft202012_type_checker, + format_checker: _format.FormatChecker = _format.draft202012_format_checker, + id_of: _typing.id_of = referencing.jsonschema.DRAFT202012.id_of, + applicable_validators: _typing.ApplicableValidators = methodcaller( + "items", + ), +) -> type[Validator]: + """ + Create a new validator class. + + Arguments: + + meta_schema: + + the meta schema for the new validator class + + validators: + + a mapping from names to callables, where each callable will + validate the schema property with the given name. + + Each callable should take 4 arguments: + + 1. a validator instance, + 2. the value of the property being validated within the + instance + 3. the instance + 4. the schema + + version: + + an identifier for the version that this validator class will + validate. If provided, the returned validator class will + have its ``__name__`` set to include the version, and also + will have `jsonschema.validators.validates` automatically + called for the given version. + + type_checker: + + a type checker, used when applying the :kw:`type` keyword. + + If unprovided, a `jsonschema.TypeChecker` will be created + with a set of default types typical of JSON Schema drafts. + + format_checker: + + a format checker, used when applying the :kw:`format` keyword. + + If unprovided, a `jsonschema.FormatChecker` will be created + with a set of default formats typical of JSON Schema drafts. + + id_of: + + A function that given a schema, returns its ID. + + applicable_validators: + + A function that, given a schema, returns the list of + applicable schema keywords and associated values + which will be used to validate the instance. + This is mostly used to support pre-draft 7 versions of JSON Schema + which specified behavior around ignoring keywords if they were + siblings of a ``$ref`` keyword. If you're not attempting to + implement similar behavior, you can typically ignore this argument + and leave it at its default. + + Returns: + + a new `jsonschema.protocols.Validator` class + + """ + # preemptively don't shadow the `Validator.format_checker` local + format_checker_arg = format_checker + + specification = referencing.jsonschema.specification_with( + dialect_id=id_of(meta_schema) or "urn:unknown-dialect", + default=referencing.Specification.OPAQUE, + ) + + @define + class Validator: + + VALIDATORS = dict(validators) # noqa: RUF012 + META_SCHEMA = dict(meta_schema) # noqa: RUF012 + TYPE_CHECKER = type_checker + FORMAT_CHECKER = format_checker_arg + ID_OF = staticmethod(id_of) + + _APPLICABLE_VALIDATORS = applicable_validators + _validators = field(init=False, repr=False, eq=False) + + schema: referencing.jsonschema.Schema = field(repr=reprlib.repr) + _ref_resolver = field(default=None, repr=False, alias="resolver") + format_checker: _format.FormatChecker | None = field(default=None) + # TODO: include new meta-schemas added at runtime + _registry: referencing.jsonschema.SchemaRegistry = field( + default=_REMOTE_WARNING_REGISTRY, + kw_only=True, + repr=False, + ) + _resolver = field( + alias="_resolver", + default=None, + kw_only=True, + repr=False, + ) + + def __init_subclass__(cls): + warnings.warn( + ( + "Subclassing validator classes is not intended to " + "be part of their public API. A future version " + "will make doing so an error, as the behavior of " + "subclasses isn't guaranteed to stay the same " + "between releases of jsonschema. Instead, prefer " + "composition of validators, wrapping them in an object " + "owned entirely by the downstream library." + ), + DeprecationWarning, + stacklevel=2, + ) + + def evolve(self, **changes): + cls = self.__class__ + schema = changes.setdefault("schema", self.schema) + NewValidator = validator_for(schema, default=cls) + + for field in fields(cls): # noqa: F402 + if not field.init: + continue + attr_name = field.name + init_name = field.alias + if init_name not in changes: + changes[init_name] = getattr(self, attr_name) + + return NewValidator(**changes) + + cls.evolve = evolve + + def __attrs_post_init__(self): + if self._resolver is None: + registry = self._registry + if registry is not _REMOTE_WARNING_REGISTRY: + registry = SPECIFICATIONS.combine(registry) + resource = specification.create_resource(self.schema) + self._resolver = registry.resolver_with_root(resource) + + if self.schema is True or self.schema is False: + self._validators = [] + else: + self._validators = [ + (self.VALIDATORS[k], k, v) + for k, v in applicable_validators(self.schema) + if k in self.VALIDATORS + ] + + # REMOVEME: Legacy ref resolution state management. + push_scope = getattr(self._ref_resolver, "push_scope", None) + if push_scope is not None: + id = id_of(self.schema) + if id is not None: + push_scope(id) + + @classmethod + def check_schema(cls, schema, format_checker=_UNSET): + Validator = validator_for(cls.META_SCHEMA, default=cls) + if format_checker is _UNSET: + format_checker = Validator.FORMAT_CHECKER + validator = Validator( + schema=cls.META_SCHEMA, + format_checker=format_checker, + ) + for error in validator.iter_errors(schema): + raise exceptions.SchemaError.create_from(error) + + @property + def resolver(self): + warnings.warn( + ( + f"Accessing {self.__class__.__name__}.resolver is " + "deprecated as of v4.18.0, in favor of the " + "https://github.com/python-jsonschema/referencing " + "library, which provides more compliant referencing " + "behavior as well as more flexible APIs for " + "customization." + ), + DeprecationWarning, + stacklevel=2, + ) + if self._ref_resolver is None: + self._ref_resolver = _RefResolver.from_schema( + self.schema, + id_of=id_of, + ) + return self._ref_resolver + + def evolve(self, **changes): + schema = changes.setdefault("schema", self.schema) + NewValidator = validator_for(schema, default=self.__class__) + + for (attr_name, init_name) in evolve_fields: + if init_name not in changes: + changes[init_name] = getattr(self, attr_name) + + return NewValidator(**changes) + + def iter_errors(self, instance, _schema=None): + if _schema is not None: + warnings.warn( + ( + "Passing a schema to Validator.iter_errors " + "is deprecated and will be removed in a future " + "release. Call validator.evolve(schema=new_schema)." + "iter_errors(...) instead." + ), + DeprecationWarning, + stacklevel=2, + ) + validators = [ + (self.VALIDATORS[k], k, v) + for k, v in applicable_validators(_schema) + if k in self.VALIDATORS + ] + else: + _schema, validators = self.schema, self._validators + + if _schema is True: + return + elif _schema is False: + yield exceptions.ValidationError( + f"False schema does not allow {instance!r}", + validator=None, + validator_value=None, + instance=instance, + schema=_schema, + ) + return + + for validator, k, v in validators: + errors = validator(self, v, instance, _schema) or () + for error in errors: + # set details if not already set by the called fn + error._set( + validator=k, + validator_value=v, + instance=instance, + schema=_schema, + type_checker=self.TYPE_CHECKER, + ) + if k not in {"if", "$ref"}: + error.schema_path.appendleft(k) + yield error + + def descend( + self, + instance, + schema, + path=None, + schema_path=None, + resolver=None, + ): + if schema is True: + return + elif schema is False: + yield exceptions.ValidationError( + f"False schema does not allow {instance!r}", + validator=None, + validator_value=None, + instance=instance, + schema=schema, + ) + return + + if self._ref_resolver is not None: + evolved = self.evolve(schema=schema) + else: + if resolver is None: + resolver = self._resolver.in_subresource( + specification.create_resource(schema), + ) + evolved = self.evolve(schema=schema, _resolver=resolver) + + for k, v in applicable_validators(schema): + validator = evolved.VALIDATORS.get(k) + if validator is None: + continue + + errors = validator(evolved, v, instance, schema) or () + for error in errors: + # set details if not already set by the called fn + error._set( + validator=k, + validator_value=v, + instance=instance, + schema=schema, + type_checker=evolved.TYPE_CHECKER, + ) + if k not in {"if", "$ref"}: + error.schema_path.appendleft(k) + if path is not None: + error.path.appendleft(path) + if schema_path is not None: + error.schema_path.appendleft(schema_path) + yield error + + def validate(self, *args, **kwargs): + for error in self.iter_errors(*args, **kwargs): + raise error + + def is_type(self, instance, type): + try: + return self.TYPE_CHECKER.is_type(instance, type) + except exceptions.UndefinedTypeCheck: + exc = exceptions.UnknownType(type, instance, self.schema) + raise exc from None + + def _validate_reference(self, ref, instance): + if self._ref_resolver is None: + try: + resolved = self._resolver.lookup(ref) + except referencing.exceptions.Unresolvable as err: + raise exceptions._WrappedReferencingError(err) from err + + return self.descend( + instance, + resolved.contents, + resolver=resolved.resolver, + ) + else: + resolve = getattr(self._ref_resolver, "resolve", None) + if resolve is None: + with self._ref_resolver.resolving(ref) as resolved: + return self.descend(instance, resolved) + else: + scope, resolved = resolve(ref) + self._ref_resolver.push_scope(scope) + + try: + return list(self.descend(instance, resolved)) + finally: + self._ref_resolver.pop_scope() + + def is_valid(self, instance, _schema=None): + if _schema is not None: + warnings.warn( + ( + "Passing a schema to Validator.is_valid is deprecated " + "and will be removed in a future release. Call " + "validator.evolve(schema=new_schema).is_valid(...) " + "instead." + ), + DeprecationWarning, + stacklevel=2, + ) + self = self.evolve(schema=_schema) + + error = next(self.iter_errors(instance), None) + return error is None + + evolve_fields = [ + (field.name, field.alias) + for field in fields(Validator) + if field.init + ] + + if version is not None: + safe = version.title().replace(" ", "").replace("-", "") + Validator.__name__ = Validator.__qualname__ = f"{safe}Validator" + Validator = validates(version)(Validator) # type: ignore[misc] + + return Validator # type: ignore[return-value] + + +def extend( + validator, + validators=(), + version=None, + type_checker=None, + format_checker=None, +): + """ + Create a new validator class by extending an existing one. + + Arguments: + + validator (jsonschema.protocols.Validator): + + an existing validator class + + validators (collections.abc.Mapping): + + a mapping of new validator callables to extend with, whose + structure is as in `create`. + + .. note:: + + Any validator callables with the same name as an + existing one will (silently) replace the old validator + callable entirely, effectively overriding any validation + done in the "parent" validator class. + + If you wish to instead extend the behavior of a parent's + validator callable, delegate and call it directly in + the new validator function by retrieving it using + ``OldValidator.VALIDATORS["validation_keyword_name"]``. + + version (str): + + a version for the new validator class + + type_checker (jsonschema.TypeChecker): + + a type checker, used when applying the :kw:`type` keyword. + + If unprovided, the type checker of the extended + `jsonschema.protocols.Validator` will be carried along. + + format_checker (jsonschema.FormatChecker): + + a format checker, used when applying the :kw:`format` keyword. + + If unprovided, the format checker of the extended + `jsonschema.protocols.Validator` will be carried along. + + Returns: + + a new `jsonschema.protocols.Validator` class extending the one + provided + + .. note:: Meta Schemas + + The new validator class will have its parent's meta schema. + + If you wish to change or extend the meta schema in the new + validator class, modify ``META_SCHEMA`` directly on the returned + class. Note that no implicit copying is done, so a copy should + likely be made before modifying it, in order to not affect the + old validator. + + """ + all_validators = dict(validator.VALIDATORS) + all_validators.update(validators) + + if type_checker is None: + type_checker = validator.TYPE_CHECKER + if format_checker is None: + format_checker = validator.FORMAT_CHECKER + return create( + meta_schema=validator.META_SCHEMA, + validators=all_validators, + version=version, + type_checker=type_checker, + format_checker=format_checker, + id_of=validator.ID_OF, + applicable_validators=validator._APPLICABLE_VALIDATORS, + ) + + +Draft3Validator = create( + meta_schema=SPECIFICATIONS.contents( + "http://json-schema.org/draft-03/schema#", + ), + validators={ + "$ref": _keywords.ref, + "additionalItems": _legacy_keywords.additionalItems, + "additionalProperties": _keywords.additionalProperties, + "dependencies": _legacy_keywords.dependencies_draft3, + "disallow": _legacy_keywords.disallow_draft3, + "divisibleBy": _keywords.multipleOf, + "enum": _keywords.enum, + "extends": _legacy_keywords.extends_draft3, + "format": _keywords.format, + "items": _legacy_keywords.items_draft3_draft4, + "maxItems": _keywords.maxItems, + "maxLength": _keywords.maxLength, + "maximum": _legacy_keywords.maximum_draft3_draft4, + "minItems": _keywords.minItems, + "minLength": _keywords.minLength, + "minimum": _legacy_keywords.minimum_draft3_draft4, + "pattern": _keywords.pattern, + "patternProperties": _keywords.patternProperties, + "properties": _legacy_keywords.properties_draft3, + "type": _legacy_keywords.type_draft3, + "uniqueItems": _keywords.uniqueItems, + }, + type_checker=_types.draft3_type_checker, + format_checker=_format.draft3_format_checker, + version="draft3", + id_of=referencing.jsonschema.DRAFT3.id_of, + applicable_validators=_legacy_keywords.ignore_ref_siblings, +) + +Draft4Validator = create( + meta_schema=SPECIFICATIONS.contents( + "http://json-schema.org/draft-04/schema#", + ), + validators={ + "$ref": _keywords.ref, + "additionalItems": _legacy_keywords.additionalItems, + "additionalProperties": _keywords.additionalProperties, + "allOf": _keywords.allOf, + "anyOf": _keywords.anyOf, + "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7, + "enum": _keywords.enum, + "format": _keywords.format, + "items": _legacy_keywords.items_draft3_draft4, + "maxItems": _keywords.maxItems, + "maxLength": _keywords.maxLength, + "maxProperties": _keywords.maxProperties, + "maximum": _legacy_keywords.maximum_draft3_draft4, + "minItems": _keywords.minItems, + "minLength": _keywords.minLength, + "minProperties": _keywords.minProperties, + "minimum": _legacy_keywords.minimum_draft3_draft4, + "multipleOf": _keywords.multipleOf, + "not": _keywords.not_, + "oneOf": _keywords.oneOf, + "pattern": _keywords.pattern, + "patternProperties": _keywords.patternProperties, + "properties": _keywords.properties, + "required": _keywords.required, + "type": _keywords.type, + "uniqueItems": _keywords.uniqueItems, + }, + type_checker=_types.draft4_type_checker, + format_checker=_format.draft4_format_checker, + version="draft4", + id_of=referencing.jsonschema.DRAFT4.id_of, + applicable_validators=_legacy_keywords.ignore_ref_siblings, +) + +Draft6Validator = create( + meta_schema=SPECIFICATIONS.contents( + "http://json-schema.org/draft-06/schema#", + ), + validators={ + "$ref": _keywords.ref, + "additionalItems": _legacy_keywords.additionalItems, + "additionalProperties": _keywords.additionalProperties, + "allOf": _keywords.allOf, + "anyOf": _keywords.anyOf, + "const": _keywords.const, + "contains": _legacy_keywords.contains_draft6_draft7, + "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7, + "enum": _keywords.enum, + "exclusiveMaximum": _keywords.exclusiveMaximum, + "exclusiveMinimum": _keywords.exclusiveMinimum, + "format": _keywords.format, + "items": _legacy_keywords.items_draft6_draft7_draft201909, + "maxItems": _keywords.maxItems, + "maxLength": _keywords.maxLength, + "maxProperties": _keywords.maxProperties, + "maximum": _keywords.maximum, + "minItems": _keywords.minItems, + "minLength": _keywords.minLength, + "minProperties": _keywords.minProperties, + "minimum": _keywords.minimum, + "multipleOf": _keywords.multipleOf, + "not": _keywords.not_, + "oneOf": _keywords.oneOf, + "pattern": _keywords.pattern, + "patternProperties": _keywords.patternProperties, + "properties": _keywords.properties, + "propertyNames": _keywords.propertyNames, + "required": _keywords.required, + "type": _keywords.type, + "uniqueItems": _keywords.uniqueItems, + }, + type_checker=_types.draft6_type_checker, + format_checker=_format.draft6_format_checker, + version="draft6", + id_of=referencing.jsonschema.DRAFT6.id_of, + applicable_validators=_legacy_keywords.ignore_ref_siblings, +) + +Draft7Validator = create( + meta_schema=SPECIFICATIONS.contents( + "http://json-schema.org/draft-07/schema#", + ), + validators={ + "$ref": _keywords.ref, + "additionalItems": _legacy_keywords.additionalItems, + "additionalProperties": _keywords.additionalProperties, + "allOf": _keywords.allOf, + "anyOf": _keywords.anyOf, + "const": _keywords.const, + "contains": _legacy_keywords.contains_draft6_draft7, + "dependencies": _legacy_keywords.dependencies_draft4_draft6_draft7, + "enum": _keywords.enum, + "exclusiveMaximum": _keywords.exclusiveMaximum, + "exclusiveMinimum": _keywords.exclusiveMinimum, + "format": _keywords.format, + "if": _keywords.if_, + "items": _legacy_keywords.items_draft6_draft7_draft201909, + "maxItems": _keywords.maxItems, + "maxLength": _keywords.maxLength, + "maxProperties": _keywords.maxProperties, + "maximum": _keywords.maximum, + "minItems": _keywords.minItems, + "minLength": _keywords.minLength, + "minProperties": _keywords.minProperties, + "minimum": _keywords.minimum, + "multipleOf": _keywords.multipleOf, + "not": _keywords.not_, + "oneOf": _keywords.oneOf, + "pattern": _keywords.pattern, + "patternProperties": _keywords.patternProperties, + "properties": _keywords.properties, + "propertyNames": _keywords.propertyNames, + "required": _keywords.required, + "type": _keywords.type, + "uniqueItems": _keywords.uniqueItems, + }, + type_checker=_types.draft7_type_checker, + format_checker=_format.draft7_format_checker, + version="draft7", + id_of=referencing.jsonschema.DRAFT7.id_of, + applicable_validators=_legacy_keywords.ignore_ref_siblings, +) + +Draft201909Validator = create( + meta_schema=SPECIFICATIONS.contents( + "https://json-schema.org/draft/2019-09/schema", + ), + validators={ + "$recursiveRef": _legacy_keywords.recursiveRef, + "$ref": _keywords.ref, + "additionalItems": _legacy_keywords.additionalItems, + "additionalProperties": _keywords.additionalProperties, + "allOf": _keywords.allOf, + "anyOf": _keywords.anyOf, + "const": _keywords.const, + "contains": _keywords.contains, + "dependentRequired": _keywords.dependentRequired, + "dependentSchemas": _keywords.dependentSchemas, + "enum": _keywords.enum, + "exclusiveMaximum": _keywords.exclusiveMaximum, + "exclusiveMinimum": _keywords.exclusiveMinimum, + "format": _keywords.format, + "if": _keywords.if_, + "items": _legacy_keywords.items_draft6_draft7_draft201909, + "maxItems": _keywords.maxItems, + "maxLength": _keywords.maxLength, + "maxProperties": _keywords.maxProperties, + "maximum": _keywords.maximum, + "minItems": _keywords.minItems, + "minLength": _keywords.minLength, + "minProperties": _keywords.minProperties, + "minimum": _keywords.minimum, + "multipleOf": _keywords.multipleOf, + "not": _keywords.not_, + "oneOf": _keywords.oneOf, + "pattern": _keywords.pattern, + "patternProperties": _keywords.patternProperties, + "properties": _keywords.properties, + "propertyNames": _keywords.propertyNames, + "required": _keywords.required, + "type": _keywords.type, + "unevaluatedItems": _legacy_keywords.unevaluatedItems_draft2019, + "unevaluatedProperties": ( + _legacy_keywords.unevaluatedProperties_draft2019 + ), + "uniqueItems": _keywords.uniqueItems, + }, + type_checker=_types.draft201909_type_checker, + format_checker=_format.draft201909_format_checker, + version="draft2019-09", +) + +Draft202012Validator = create( + meta_schema=SPECIFICATIONS.contents( + "https://json-schema.org/draft/2020-12/schema", + ), + validators={ + "$dynamicRef": _keywords.dynamicRef, + "$ref": _keywords.ref, + "additionalProperties": _keywords.additionalProperties, + "allOf": _keywords.allOf, + "anyOf": _keywords.anyOf, + "const": _keywords.const, + "contains": _keywords.contains, + "dependentRequired": _keywords.dependentRequired, + "dependentSchemas": _keywords.dependentSchemas, + "enum": _keywords.enum, + "exclusiveMaximum": _keywords.exclusiveMaximum, + "exclusiveMinimum": _keywords.exclusiveMinimum, + "format": _keywords.format, + "if": _keywords.if_, + "items": _keywords.items, + "maxItems": _keywords.maxItems, + "maxLength": _keywords.maxLength, + "maxProperties": _keywords.maxProperties, + "maximum": _keywords.maximum, + "minItems": _keywords.minItems, + "minLength": _keywords.minLength, + "minProperties": _keywords.minProperties, + "minimum": _keywords.minimum, + "multipleOf": _keywords.multipleOf, + "not": _keywords.not_, + "oneOf": _keywords.oneOf, + "pattern": _keywords.pattern, + "patternProperties": _keywords.patternProperties, + "prefixItems": _keywords.prefixItems, + "properties": _keywords.properties, + "propertyNames": _keywords.propertyNames, + "required": _keywords.required, + "type": _keywords.type, + "unevaluatedItems": _keywords.unevaluatedItems, + "unevaluatedProperties": _keywords.unevaluatedProperties, + "uniqueItems": _keywords.uniqueItems, + }, + type_checker=_types.draft202012_type_checker, + format_checker=_format.draft202012_format_checker, + version="draft2020-12", +) + +_LATEST_VERSION: type[Validator] = Draft202012Validator + + +class _RefResolver: + """ + Resolve JSON References. + + Arguments: + + base_uri (str): + + The URI of the referring document + + referrer: + + The actual referring document + + store (dict): + + A mapping from URIs to documents to cache + + cache_remote (bool): + + Whether remote refs should be cached after first resolution + + handlers (dict): + + A mapping from URI schemes to functions that should be used + to retrieve them + + urljoin_cache (:func:`functools.lru_cache`): + + A cache that will be used for caching the results of joining + the resolution scope to subscopes. + + remote_cache (:func:`functools.lru_cache`): + + A cache that will be used for caching the results of + resolved remote URLs. + + Attributes: + + cache_remote (bool): + + Whether remote refs should be cached after first resolution + + .. deprecated:: v4.18.0 + + ``RefResolver`` has been deprecated in favor of `referencing`. + + """ + + _DEPRECATION_MESSAGE = ( + "jsonschema.RefResolver is deprecated as of v4.18.0, in favor of the " + "https://github.com/python-jsonschema/referencing library, which " + "provides more compliant referencing behavior as well as more " + "flexible APIs for customization. A future release will remove " + "RefResolver. Please file a feature request (on referencing) if you " + "are missing an API for the kind of customization you need." + ) + + def __init__( + self, + base_uri, + referrer, + store=HashTrieMap(), + cache_remote=True, + handlers=(), + urljoin_cache=None, + remote_cache=None, + ): + if urljoin_cache is None: + urljoin_cache = lru_cache(1024)(urljoin) + if remote_cache is None: + remote_cache = lru_cache(1024)(self.resolve_from_url) + + self.referrer = referrer + self.cache_remote = cache_remote + self.handlers = dict(handlers) + + self._scopes_stack = [base_uri] + + self.store = _utils.URIDict( + (uri, each.contents) for uri, each in SPECIFICATIONS.items() + ) + self.store.update( + (id, each.META_SCHEMA) for id, each in _META_SCHEMAS.items() + ) + self.store.update(store) + self.store.update( + (schema["$id"], schema) + for schema in store.values() + if isinstance(schema, Mapping) and "$id" in schema + ) + self.store[base_uri] = referrer + + self._urljoin_cache = urljoin_cache + self._remote_cache = remote_cache + + @classmethod + def from_schema( # noqa: D417 + cls, + schema, + id_of=referencing.jsonschema.DRAFT202012.id_of, + *args, + **kwargs, + ): + """ + Construct a resolver from a JSON schema object. + + Arguments: + + schema: + + the referring schema + + Returns: + + `_RefResolver` + + """ + return cls(base_uri=id_of(schema) or "", referrer=schema, *args, **kwargs) # noqa: B026, E501 + + def push_scope(self, scope): + """ + Enter a given sub-scope. + + Treats further dereferences as being performed underneath the + given scope. + """ + self._scopes_stack.append( + self._urljoin_cache(self.resolution_scope, scope), + ) + + def pop_scope(self): + """ + Exit the most recent entered scope. + + Treats further dereferences as being performed underneath the + original scope. + + Don't call this method more times than `push_scope` has been + called. + """ + try: + self._scopes_stack.pop() + except IndexError: + raise exceptions._RefResolutionError( + "Failed to pop the scope from an empty stack. " + "`pop_scope()` should only be called once for every " + "`push_scope()`", + ) from None + + @property + def resolution_scope(self): + """ + Retrieve the current resolution scope. + """ + return self._scopes_stack[-1] + + @property + def base_uri(self): + """ + Retrieve the current base URI, not including any fragment. + """ + uri, _ = urldefrag(self.resolution_scope) + return uri + + @contextlib.contextmanager + def in_scope(self, scope): + """ + Temporarily enter the given scope for the duration of the context. + + .. deprecated:: v4.0.0 + """ + warnings.warn( + "jsonschema.RefResolver.in_scope is deprecated and will be " + "removed in a future release.", + DeprecationWarning, + stacklevel=3, + ) + self.push_scope(scope) + try: + yield + finally: + self.pop_scope() + + @contextlib.contextmanager + def resolving(self, ref): + """ + Resolve the given ``ref`` and enter its resolution scope. + + Exits the scope on exit of this context manager. + + Arguments: + + ref (str): + + The reference to resolve + + """ + url, resolved = self.resolve(ref) + self.push_scope(url) + try: + yield resolved + finally: + self.pop_scope() + + def _find_in_referrer(self, key): + return self._get_subschemas_cache()[key] + + @lru_cache # noqa: B019 + def _get_subschemas_cache(self): + cache = {key: [] for key in _SUBSCHEMAS_KEYWORDS} + for keyword, subschema in _search_schema( + self.referrer, _match_subschema_keywords, + ): + cache[keyword].append(subschema) + return cache + + @lru_cache # noqa: B019 + def _find_in_subschemas(self, url): + subschemas = self._get_subschemas_cache()["$id"] + if not subschemas: + return None + uri, fragment = urldefrag(url) + for subschema in subschemas: + id = subschema["$id"] + if not isinstance(id, str): + continue + target_uri = self._urljoin_cache(self.resolution_scope, id) + if target_uri.rstrip("/") == uri.rstrip("/"): + if fragment: + subschema = self.resolve_fragment(subschema, fragment) + self.store[url] = subschema + return url, subschema + return None + + def resolve(self, ref): + """ + Resolve the given reference. + """ + url = self._urljoin_cache(self.resolution_scope, ref).rstrip("/") + + match = self._find_in_subschemas(url) + if match is not None: + return match + + return url, self._remote_cache(url) + + def resolve_from_url(self, url): + """ + Resolve the given URL. + """ + url, fragment = urldefrag(url) + if not url: + url = self.base_uri + + try: + document = self.store[url] + except KeyError: + try: + document = self.resolve_remote(url) + except Exception as exc: + raise exceptions._RefResolutionError(exc) from exc + + return self.resolve_fragment(document, fragment) + + def resolve_fragment(self, document, fragment): + """ + Resolve a ``fragment`` within the referenced ``document``. + + Arguments: + + document: + + The referent document + + fragment (str): + + a URI fragment to resolve within it + + """ + fragment = fragment.lstrip("/") + + if not fragment: + return document + + if document is self.referrer: + find = self._find_in_referrer + else: + + def find(key): + yield from _search_schema(document, _match_keyword(key)) + + for keyword in ["$anchor", "$dynamicAnchor"]: + for subschema in find(keyword): + if fragment == subschema[keyword]: + return subschema + for keyword in ["id", "$id"]: + for subschema in find(keyword): + if "#" + fragment == subschema[keyword]: + return subschema + + # Resolve via path + parts = unquote(fragment).split("/") if fragment else [] + for part in parts: + part = part.replace("~1", "/").replace("~0", "~") + + if isinstance(document, Sequence): + try: # noqa: SIM105 + part = int(part) + except ValueError: + pass + try: + document = document[part] + except (TypeError, LookupError) as err: + raise exceptions._RefResolutionError( + f"Unresolvable JSON pointer: {fragment!r}", + ) from err + + return document + + def resolve_remote(self, uri): + """ + Resolve a remote ``uri``. + + If called directly, does not check the store first, but after + retrieving the document at the specified URI it will be saved in + the store if :attr:`cache_remote` is True. + + .. note:: + + If the requests_ library is present, ``jsonschema`` will use it to + request the remote ``uri``, so that the correct encoding is + detected and used. + + If it isn't, or if the scheme of the ``uri`` is not ``http`` or + ``https``, UTF-8 is assumed. + + Arguments: + + uri (str): + + The URI to resolve + + Returns: + + The retrieved document + + .. _requests: https://pypi.org/project/requests/ + + """ + try: + import requests + except ImportError: + requests = None + + scheme = urlsplit(uri).scheme + + if scheme in self.handlers: + result = self.handlers[scheme](uri) + elif scheme in ["http", "https"] and requests: + # Requests has support for detecting the correct encoding of + # json over http + result = requests.get(uri).json() + else: + # Otherwise, pass off to urllib and assume utf-8 + from urllib.request import urlopen + with urlopen(uri) as url: # noqa: S310 + result = json.loads(url.read().decode("utf-8")) + + if self.cache_remote: + self.store[uri] = result + return result + + +_SUBSCHEMAS_KEYWORDS = ("$id", "id", "$anchor", "$dynamicAnchor") + + +def _match_keyword(keyword): + + def matcher(value): + if keyword in value: + yield value + + return matcher + + +def _match_subschema_keywords(value): + for keyword in _SUBSCHEMAS_KEYWORDS: + if keyword in value: + yield keyword, value + + +def _search_schema(schema, matcher): + """Breadth-first search routine.""" + values = deque([schema]) + while values: + value = values.pop() + if not isinstance(value, dict): + continue + yield from matcher(value) + values.extendleft(value.values()) + + +def validate(instance, schema, cls=None, *args, **kwargs): # noqa: D417 + """ + Validate an instance under the given schema. + + >>> validate([2, 3, 4], {"maxItems": 2}) + Traceback (most recent call last): + ... + ValidationError: [2, 3, 4] is too long + + :func:`~jsonschema.validators.validate` will first verify that the + provided schema is itself valid, since not doing so can lead to less + obvious error messages and fail in less obvious or consistent ways. + + If you know you have a valid schema already, especially + if you intend to validate multiple instances with + the same schema, you likely would prefer using the + `jsonschema.protocols.Validator.validate` method directly on a + specific validator (e.g. ``Draft202012Validator.validate``). + + + Arguments: + + instance: + + The instance to validate + + schema: + + The schema to validate with + + cls (jsonschema.protocols.Validator): + + The class that will be used to validate the instance. + + If the ``cls`` argument is not provided, two things will happen + in accordance with the specification. First, if the schema has a + :kw:`$schema` keyword containing a known meta-schema [#]_ then the + proper validator will be used. The specification recommends that + all schemas contain :kw:`$schema` properties for this reason. If no + :kw:`$schema` property is found, the default validator class is the + latest released draft. + + Any other provided positional and keyword arguments will be passed + on when instantiating the ``cls``. + + Raises: + + `jsonschema.exceptions.ValidationError`: + + if the instance is invalid + + `jsonschema.exceptions.SchemaError`: + + if the schema itself is invalid + + .. rubric:: Footnotes + .. [#] known by a validator registered with + `jsonschema.validators.validates` + + """ + if cls is None: + cls = validator_for(schema) + + cls.check_schema(schema) + validator = cls(schema, *args, **kwargs) + error = exceptions.best_match(validator.iter_errors(instance)) + if error is not None: + raise error + + +def validator_for( + schema, + default: type[Validator] | _utils.Unset = _UNSET, +) -> type[Validator]: + """ + Retrieve the validator class appropriate for validating the given schema. + + Uses the :kw:`$schema` keyword that should be present in the given + schema to look up the appropriate validator class. + + Arguments: + + schema (collections.abc.Mapping or bool): + + the schema to look at + + default: + + the default to return if the appropriate validator class + cannot be determined. + + If unprovided, the default is to return the latest supported + draft. + + Examples: + + The :kw:`$schema` JSON Schema keyword will control which validator + class is returned: + + >>> schema = { + ... "$schema": "https://json-schema.org/draft/2020-12/schema", + ... "type": "integer", + ... } + >>> jsonschema.validators.validator_for(schema) + + + + Here, a draft 7 schema instead will return the draft 7 validator: + + >>> schema = { + ... "$schema": "http://json-schema.org/draft-07/schema#", + ... "type": "integer", + ... } + >>> jsonschema.validators.validator_for(schema) + + + + Schemas with no ``$schema`` keyword will fallback to the default + argument: + + >>> schema = {"type": "integer"} + >>> jsonschema.validators.validator_for( + ... schema, default=Draft7Validator, + ... ) + + + or if none is provided, to the latest version supported. + Always including the keyword when authoring schemas is highly + recommended. + + """ + DefaultValidator = _LATEST_VERSION if default is _UNSET else default + + if schema is True or schema is False or "$schema" not in schema: + return DefaultValidator # type: ignore[return-value] + if schema["$schema"] not in _META_SCHEMAS and default is _UNSET: + warn( + ( + "The metaschema specified by $schema was not found. " + "Using the latest draft to validate, but this will raise " + "an error in the future." + ), + DeprecationWarning, + stacklevel=2, + ) + return _META_SCHEMAS.get(schema["$schema"], DefaultValidator) diff --git a/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/METADATA b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/METADATA new file mode 100644 index 0000000..ff5daef --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/METADATA @@ -0,0 +1,54 @@ +Metadata-Version: 2.4 +Name: jsonschema-specifications +Version: 2025.9.1 +Summary: The JSON Schema meta-schemas and vocabularies, exposed as a Registry +Project-URL: Documentation, https://jsonschema-specifications.readthedocs.io/ +Project-URL: Homepage, https://github.com/python-jsonschema/jsonschema-specifications +Project-URL: Issues, https://github.com/python-jsonschema/jsonschema-specifications/issues/ +Project-URL: Funding, https://github.com/sponsors/Julian +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema-specifications?utm_source=pypi-jsonschema-specifications&utm_medium=referral&utm_campaign=pypi-link +Project-URL: Source, https://github.com/python-jsonschema/jsonschema-specifications +Author-email: Julian Berman +License-Expression: MIT +License-File: COPYING +Keywords: data validation,json,json schema,jsonschema,validation +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: File Formats :: JSON +Classifier: Topic :: File Formats :: JSON :: JSON Schema +Requires-Python: >=3.9 +Requires-Dist: referencing>=0.31.0 +Description-Content-Type: text/x-rst + +============================= +``jsonschema-specifications`` +============================= + +|PyPI| |Pythons| |CI| |ReadTheDocs| + +JSON support files from the `JSON Schema Specifications `_ (metaschemas, vocabularies, etc.), packaged for runtime access from Python as a `referencing-based Schema Registry `_. + +.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema-specifications.svg + :alt: PyPI version + :target: https://pypi.org/project/jsonschema-specifications/ + +.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema-specifications.svg + :alt: Supported Python versions + :target: https://pypi.org/project/jsonschema-specifications/ + +.. |CI| image:: https://github.com/python-jsonschema/jsonschema-specifications/workflows/CI/badge.svg + :alt: Build status + :target: https://github.com/python-jsonschema/jsonschema-specifications/actions?query=workflow%3ACI + +.. |ReadTheDocs| image:: https://readthedocs.org/projects/jsonschema-specifications/badge/?version=stable&style=flat + :alt: ReadTheDocs status + :target: https://jsonschema-specifications.readthedocs.io/en/stable/ diff --git a/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/RECORD b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/RECORD new file mode 100644 index 0000000..11399af --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/RECORD @@ -0,0 +1,28 @@ +jsonschema_specifications/__init__.py,sha256=qoTB2DKY7qvNrGhMPH6gtmAJRLilmVQ-fFZwT6ryqw0,386 +jsonschema_specifications/_core.py,sha256=tFhc1CMleJ3AJOK_bjxOpFQTdrsUClFGfFxPBU_CebM,1140 +jsonschema_specifications/schemas/draft201909/metaschema.json,sha256=e3YbPhIfCgyh6ioLjizIVrz4AWBLgmjXG6yqICvAwTs,1785 +jsonschema_specifications/schemas/draft201909/vocabularies/applicator,sha256=aJUQDplyb7sQcFhRK77D7P1LJOj9L6zuPlBe5ysNTDE,1860 +jsonschema_specifications/schemas/draft201909/vocabularies/content,sha256=m31PVaTi_bAsQwBo_f-rxzKt3OI42j8d8mkCScM1MnQ,517 +jsonschema_specifications/schemas/draft201909/vocabularies/core,sha256=taLElX9kldClCB8ECevooU5BOayyA_x0hHH47eKvWyw,1531 +jsonschema_specifications/schemas/draft201909/vocabularies/format,sha256=UOu_55BhGoSbjMQAoJwdDg-2q1wNQ6DyIgH9NiUFa_Q,403 +jsonschema_specifications/schemas/draft201909/vocabularies/meta-data,sha256=1H4kRd1qgicaKY2DzGxsuNSuHhXg3Fa-zTehY-zwEoY,892 +jsonschema_specifications/schemas/draft201909/vocabularies/validation,sha256=HlJsHTNac0gF_ILPV5jBK5YK19olF8Zs2lobCTWcPBw,2834 +jsonschema_specifications/schemas/draft202012/metaschema.json,sha256=Qdp29a-3zgYtJI92JGOpL3ykfk4PkFsiS6av7vkd7Q8,2452 +jsonschema_specifications/schemas/draft202012/vocabularies/applicator,sha256=xKbkFHuR_vf-ptwFjLG_k0AvdBS3ZXiosWqvHa1qrO8,1659 +jsonschema_specifications/schemas/draft202012/vocabularies/content,sha256=CDQ3R3ZOSlgUJieTz01lIFenkThjxZUNQyl-jh_axbY,519 +jsonschema_specifications/schemas/draft202012/vocabularies/core,sha256=wtEqjk3RHTNt_IOj9mOqTGnwtJs76wlP_rJbUxb0gD0,1564 +jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation,sha256=q8d1rf79idIjWBcNm_k_Tr0jSVY7u-3WDwK-98gSvMA,448 +jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion,sha256=xSJCuaG7eGsmw-gset1CjDH5yW5XXc6Z5W6l_qptogw,445 +jsonschema_specifications/schemas/draft202012/vocabularies/meta-data,sha256=j3bW4U9Bubku-TO3CM3FFEyLUmhlGtEZGEhfsXVPHHY,892 +jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated,sha256=Lb-8tzmUtnCwl2SSre4f_7RsIWgnhNL1pMpWH54tDLQ,506 +jsonschema_specifications/schemas/draft202012/vocabularies/validation,sha256=cBCjHlQfMtK-ch4t40jfdcmzaHaj7TBId_wKvaHTelg,2834 +jsonschema_specifications/schemas/draft3/metaschema.json,sha256=LPdfZENvtb43Si6qJ6uLfh_WUcm0ba6mxnsC_WTiRYs,2600 +jsonschema_specifications/schemas/draft4/metaschema.json,sha256=4UidC0dV8CeTMCWR0_y48Htok6gqlPJIlfjk7fEbguI,4357 +jsonschema_specifications/schemas/draft6/metaschema.json,sha256=wp386fVINcOgbAOzxdXsDtp3cGVo-cTffPvHVmpRAG0,4437 +jsonschema_specifications/schemas/draft7/metaschema.json,sha256=PVOSCIJhYGxVm2A_OFMpyfGrRbXWZ-uZBodFOwVdQF4,4819 +jsonschema_specifications/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jsonschema_specifications/tests/test_jsonschema_specifications.py,sha256=WkbYRW6A6FoZ0rivShfqVLSCsAiHJ2x8TxqECJTXPTY,1106 +jsonschema_specifications-2025.9.1.dist-info/METADATA,sha256=NavUF1fzK06iR1aSDe1HtwFz13y8BSpabTq1g7Lo2J0,2907 +jsonschema_specifications-2025.9.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 +jsonschema_specifications-2025.9.1.dist-info/licenses/COPYING,sha256=QtzWNJX4e063x3V6-jebtVpT-Ur9el9lfZrfVyNuUVw,1057 +jsonschema_specifications-2025.9.1.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/WHEEL b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/WHEEL new file mode 100644 index 0000000..12228d4 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.27.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/licenses/COPYING b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/licenses/COPYING new file mode 100644 index 0000000..a9f853e --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications-2025.9.1.dist-info/licenses/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2022 Julian Berman + +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/source/target-vendors/cp312/jsonschema_specifications/__init__.py b/source/target-vendors/cp312/jsonschema_specifications/__init__.py new file mode 100644 index 0000000..a423574 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/__init__.py @@ -0,0 +1,12 @@ +""" +The JSON Schema meta-schemas and vocabularies, exposed as a Registry. +""" + +from referencing.jsonschema import EMPTY_REGISTRY as _EMPTY_REGISTRY + +from jsonschema_specifications._core import _schemas + +#: A `referencing.jsonschema.SchemaRegistry` containing all of the official +#: meta-schemas and vocabularies. +REGISTRY = (_schemas() @ _EMPTY_REGISTRY).crawl() +__all__ = ["REGISTRY"] diff --git a/source/target-vendors/cp312/jsonschema_specifications/_core.py b/source/target-vendors/cp312/jsonschema_specifications/_core.py new file mode 100644 index 0000000..e67bd71 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/_core.py @@ -0,0 +1,38 @@ +""" +Load all the JSON Schema specification's official schemas. +""" + +import json + +try: + from importlib.resources import files +except ImportError: + from importlib_resources import ( # type: ignore[import-not-found, no-redef] + files, + ) + +from referencing import Resource + + +def _schemas(): + """ + All schemas we ship. + """ + # importlib.resources.abc.Traversal doesn't have nice ways to do this that + # I'm aware of... + # + # It can't recurse arbitrarily, e.g. no ``.glob()``. + # + # So this takes some liberties given the real layout of what we ship + # (only 2 levels of nesting, no directories within the second level). + + for version in files(__package__).joinpath("schemas").iterdir(): + if version.name.startswith("."): + continue + for child in version.iterdir(): + children = [child] if child.is_file() else child.iterdir() + for path in children: + if path.name.startswith("."): + continue + contents = json.loads(path.read_text(encoding="utf-8")) + yield Resource.from_contents(contents) diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/metaschema.json b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/metaschema.json new file mode 100644 index 0000000..2248a0c --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/metaschema.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/schema", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/core": true, + "https://json-schema.org/draft/2019-09/vocab/applicator": true, + "https://json-schema.org/draft/2019-09/vocab/validation": true, + "https://json-schema.org/draft/2019-09/vocab/meta-data": true, + "https://json-schema.org/draft/2019-09/vocab/format": false, + "https://json-schema.org/draft/2019-09/vocab/content": true + }, + "$recursiveAnchor": true, + + "title": "Core and Validation specifications meta-schema", + "allOf": [ + {"$ref": "meta/core"}, + {"$ref": "meta/applicator"}, + {"$ref": "meta/validation"}, + {"$ref": "meta/meta-data"}, + {"$ref": "meta/format"}, + {"$ref": "meta/content"} + ], + "type": ["object", "boolean"], + "properties": { + "definitions": { + "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.", + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + }, + "dependencies": { + "$comment": "\"dependencies\" is no longer a keyword, but schema authors should avoid redefining it to facilitate a smooth transition to \"dependentSchemas\" and \"dependentRequired\"", + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$recursiveRef": "#" }, + { "$ref": "meta/validation#/$defs/stringArray" } + ] + } + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/applicator b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/applicator new file mode 100644 index 0000000..24a1cc4 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/applicator @@ -0,0 +1,56 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/applicator", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/applicator": true + }, + "$recursiveAnchor": true, + + "title": "Applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "additionalItems": { "$recursiveRef": "#" }, + "unevaluatedItems": { "$recursiveRef": "#" }, + "items": { + "anyOf": [ + { "$recursiveRef": "#" }, + { "$ref": "#/$defs/schemaArray" } + ] + }, + "contains": { "$recursiveRef": "#" }, + "additionalProperties": { "$recursiveRef": "#" }, + "unevaluatedProperties": { "$recursiveRef": "#" }, + "properties": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependentSchemas": { + "type": "object", + "additionalProperties": { + "$recursiveRef": "#" + } + }, + "propertyNames": { "$recursiveRef": "#" }, + "if": { "$recursiveRef": "#" }, + "then": { "$recursiveRef": "#" }, + "else": { "$recursiveRef": "#" }, + "allOf": { "$ref": "#/$defs/schemaArray" }, + "anyOf": { "$ref": "#/$defs/schemaArray" }, + "oneOf": { "$ref": "#/$defs/schemaArray" }, + "not": { "$recursiveRef": "#" } + }, + "$defs": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$recursiveRef": "#" } + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/content b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/content new file mode 100644 index 0000000..f6752a8 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/content @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/content", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/content": true + }, + "$recursiveAnchor": true, + + "title": "Content vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "contentMediaType": { "type": "string" }, + "contentEncoding": { "type": "string" }, + "contentSchema": { "$recursiveRef": "#" } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/core b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/core new file mode 100644 index 0000000..eb708a5 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/core @@ -0,0 +1,57 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/core", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/core": true + }, + "$recursiveAnchor": true, + + "title": "Core vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference", + "$comment": "Non-empty fragments not allowed.", + "pattern": "^[^#]*#?$" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$anchor": { + "type": "string", + "pattern": "^[A-Za-z][-A-Za-z0-9.:_]*$" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$recursiveRef": { + "type": "string", + "format": "uri-reference" + }, + "$recursiveAnchor": { + "type": "boolean", + "default": false + }, + "$vocabulary": { + "type": "object", + "propertyNames": { + "type": "string", + "format": "uri" + }, + "additionalProperties": { + "type": "boolean" + } + }, + "$comment": { + "type": "string" + }, + "$defs": { + "type": "object", + "additionalProperties": { "$recursiveRef": "#" }, + "default": {} + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/format b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/format new file mode 100644 index 0000000..09bbfdd --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/format @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/format", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/format": true + }, + "$recursiveAnchor": true, + + "title": "Format vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data new file mode 100644 index 0000000..da04cff --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/meta-data", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/meta-data": true + }, + "$recursiveAnchor": true, + + "title": "Meta-data vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "deprecated": { + "type": "boolean", + "default": false + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/validation b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/validation new file mode 100644 index 0000000..9f59677 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft201909/vocabularies/validation @@ -0,0 +1,98 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://json-schema.org/draft/2019-09/meta/validation", + "$vocabulary": { + "https://json-schema.org/draft/2019-09/vocab/validation": true + }, + "$recursiveAnchor": true, + + "title": "Validation vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + } + }, + "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/metaschema.json b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/metaschema.json new file mode 100644 index 0000000..d5e2d31 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/metaschema.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/schema", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true, + "https://json-schema.org/draft/2020-12/vocab/applicator": true, + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true, + "https://json-schema.org/draft/2020-12/vocab/validation": true, + "https://json-schema.org/draft/2020-12/vocab/meta-data": true, + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true, + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "$dynamicAnchor": "meta", + + "title": "Core and Validation specifications meta-schema", + "allOf": [ + {"$ref": "meta/core"}, + {"$ref": "meta/applicator"}, + {"$ref": "meta/unevaluated"}, + {"$ref": "meta/validation"}, + {"$ref": "meta/meta-data"}, + {"$ref": "meta/format-annotation"}, + {"$ref": "meta/content"} + ], + "type": ["object", "boolean"], + "$comment": "This meta-schema also defines keywords that have appeared in previous drafts in order to prevent incompatible extensions as they remain in common use.", + "properties": { + "definitions": { + "$comment": "\"definitions\" has been replaced by \"$defs\".", + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "deprecated": true, + "default": {} + }, + "dependencies": { + "$comment": "\"dependencies\" has been split and replaced by \"dependentSchemas\" and \"dependentRequired\" in order to serve their differing semantics.", + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$dynamicRef": "#meta" }, + { "$ref": "meta/validation#/$defs/stringArray" } + ] + }, + "deprecated": true, + "default": {} + }, + "$recursiveAnchor": { + "$comment": "\"$recursiveAnchor\" has been replaced by \"$dynamicAnchor\".", + "$ref": "meta/core#/$defs/anchorString", + "deprecated": true + }, + "$recursiveRef": { + "$comment": "\"$recursiveRef\" has been replaced by \"$dynamicRef\".", + "$ref": "meta/core#/$defs/uriReferenceString", + "deprecated": true + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/applicator b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/applicator new file mode 100644 index 0000000..ca69923 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/applicator @@ -0,0 +1,48 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/applicator", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/applicator": true + }, + "$dynamicAnchor": "meta", + + "title": "Applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "prefixItems": { "$ref": "#/$defs/schemaArray" }, + "items": { "$dynamicRef": "#meta" }, + "contains": { "$dynamicRef": "#meta" }, + "additionalProperties": { "$dynamicRef": "#meta" }, + "properties": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependentSchemas": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" }, + "default": {} + }, + "propertyNames": { "$dynamicRef": "#meta" }, + "if": { "$dynamicRef": "#meta" }, + "then": { "$dynamicRef": "#meta" }, + "else": { "$dynamicRef": "#meta" }, + "allOf": { "$ref": "#/$defs/schemaArray" }, + "anyOf": { "$ref": "#/$defs/schemaArray" }, + "oneOf": { "$ref": "#/$defs/schemaArray" }, + "not": { "$dynamicRef": "#meta" } + }, + "$defs": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$dynamicRef": "#meta" } + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/content b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/content new file mode 100644 index 0000000..2f6e056 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/content @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/content", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/content": true + }, + "$dynamicAnchor": "meta", + + "title": "Content vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "contentEncoding": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentSchema": { "$dynamicRef": "#meta" } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/core b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/core new file mode 100644 index 0000000..dfc092d --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/core @@ -0,0 +1,51 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/core", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/core": true + }, + "$dynamicAnchor": "meta", + + "title": "Core vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "$id": { + "$ref": "#/$defs/uriReferenceString", + "$comment": "Non-empty fragments not allowed.", + "pattern": "^[^#]*#?$" + }, + "$schema": { "$ref": "#/$defs/uriString" }, + "$ref": { "$ref": "#/$defs/uriReferenceString" }, + "$anchor": { "$ref": "#/$defs/anchorString" }, + "$dynamicRef": { "$ref": "#/$defs/uriReferenceString" }, + "$dynamicAnchor": { "$ref": "#/$defs/anchorString" }, + "$vocabulary": { + "type": "object", + "propertyNames": { "$ref": "#/$defs/uriString" }, + "additionalProperties": { + "type": "boolean" + } + }, + "$comment": { + "type": "string" + }, + "$defs": { + "type": "object", + "additionalProperties": { "$dynamicRef": "#meta" } + } + }, + "$defs": { + "anchorString": { + "type": "string", + "pattern": "^[A-Za-z_][-A-Za-z0-9._]*$" + }, + "uriString": { + "type": "string", + "format": "uri" + }, + "uriReferenceString": { + "type": "string", + "format": "uri-reference" + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation new file mode 100644 index 0000000..51ef7ea --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/format-annotation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/format-annotation": true + }, + "$dynamicAnchor": "meta", + + "title": "Format vocabulary meta-schema for annotation results", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion new file mode 100644 index 0000000..5e73fd7 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/format-assertion", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/format-assertion": true + }, + "$dynamicAnchor": "meta", + + "title": "Format vocabulary meta-schema for assertion results", + "type": ["object", "boolean"], + "properties": { + "format": { "type": "string" } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data new file mode 100644 index 0000000..05cbc22 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/meta-data", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/meta-data": true + }, + "$dynamicAnchor": "meta", + + "title": "Meta-data vocabulary meta-schema", + + "type": ["object", "boolean"], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "deprecated": { + "type": "boolean", + "default": false + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated new file mode 100644 index 0000000..5f62a3f --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated @@ -0,0 +1,15 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/unevaluated", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/unevaluated": true + }, + "$dynamicAnchor": "meta", + + "title": "Unevaluated applicator vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "unevaluatedItems": { "$dynamicRef": "#meta" }, + "unevaluatedProperties": { "$dynamicRef": "#meta" } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/validation b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/validation new file mode 100644 index 0000000..606b87b --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft202012/vocabularies/validation @@ -0,0 +1,98 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://json-schema.org/draft/2020-12/meta/validation", + "$vocabulary": { + "https://json-schema.org/draft/2020-12/vocab/validation": true + }, + "$dynamicAnchor": "meta", + + "title": "Validation vocabulary meta-schema", + "type": ["object", "boolean"], + "properties": { + "type": { + "anyOf": [ + { "$ref": "#/$defs/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/$defs/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/$defs/nonNegativeInteger" }, + "minLength": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { "$ref": "#/$defs/nonNegativeInteger" }, + "minItems": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, + "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, + "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/$defs/stringArray" }, + "dependentRequired": { + "type": "object", + "additionalProperties": { + "$ref": "#/$defs/stringArray" + } + } + }, + "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 0 + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + } +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft3/metaschema.json b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft3/metaschema.json new file mode 100644 index 0000000..8b26b1f --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft3/metaschema.json @@ -0,0 +1,172 @@ +{ + "$schema" : "http://json-schema.org/draft-03/schema#", + "id" : "http://json-schema.org/draft-03/schema#", + "type" : "object", + + "properties" : { + "type" : { + "type" : ["string", "array"], + "items" : { + "type" : ["string", {"$ref" : "#"}] + }, + "uniqueItems" : true, + "default" : "any" + }, + + "properties" : { + "type" : "object", + "additionalProperties" : {"$ref" : "#"}, + "default" : {} + }, + + "patternProperties" : { + "type" : "object", + "additionalProperties" : {"$ref" : "#"}, + "default" : {} + }, + + "additionalProperties" : { + "type" : [{"$ref" : "#"}, "boolean"], + "default" : {} + }, + + "items" : { + "type" : [{"$ref" : "#"}, "array"], + "items" : {"$ref" : "#"}, + "default" : {} + }, + + "additionalItems" : { + "type" : [{"$ref" : "#"}, "boolean"], + "default" : {} + }, + + "required" : { + "type" : "boolean", + "default" : false + }, + + "dependencies" : { + "type" : "object", + "additionalProperties" : { + "type" : ["string", "array", {"$ref" : "#"}], + "items" : { + "type" : "string" + } + }, + "default" : {} + }, + + "minimum" : { + "type" : "number" + }, + + "maximum" : { + "type" : "number" + }, + + "exclusiveMinimum" : { + "type" : "boolean", + "default" : false + }, + + "exclusiveMaximum" : { + "type" : "boolean", + "default" : false + }, + + "minItems" : { + "type" : "integer", + "minimum" : 0, + "default" : 0 + }, + + "maxItems" : { + "type" : "integer", + "minimum" : 0 + }, + + "uniqueItems" : { + "type" : "boolean", + "default" : false + }, + + "pattern" : { + "type" : "string", + "format" : "regex" + }, + + "minLength" : { + "type" : "integer", + "minimum" : 0, + "default" : 0 + }, + + "maxLength" : { + "type" : "integer" + }, + + "enum" : { + "type" : "array", + "minItems" : 1, + "uniqueItems" : true + }, + + "default" : { + "type" : "any" + }, + + "title" : { + "type" : "string" + }, + + "description" : { + "type" : "string" + }, + + "format" : { + "type" : "string" + }, + + "divisibleBy" : { + "type" : "number", + "minimum" : 0, + "exclusiveMinimum" : true, + "default" : 1 + }, + + "disallow" : { + "type" : ["string", "array"], + "items" : { + "type" : ["string", {"$ref" : "#"}] + }, + "uniqueItems" : true + }, + + "extends" : { + "type" : [{"$ref" : "#"}, "array"], + "items" : {"$ref" : "#"}, + "default" : {} + }, + + "id" : { + "type" : "string" + }, + + "$ref" : { + "type" : "string" + }, + + "$schema" : { + "type" : "string", + "format" : "uri" + } + }, + + "dependencies" : { + "exclusiveMinimum" : "minimum", + "exclusiveMaximum" : "maximum" + }, + + "default" : {} +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft4/metaschema.json b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft4/metaschema.json new file mode 100644 index 0000000..bcbb847 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft4/metaschema.json @@ -0,0 +1,149 @@ +{ + "id": "http://json-schema.org/draft-04/schema#", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "positiveInteger": { + "type": "integer", + "minimum": 0 + }, + "positiveIntegerDefault0": { + "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] + }, + "simpleTypes": { + "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true + } + }, + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "$schema": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { "$ref": "#/definitions/positiveInteger" }, + "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/positiveInteger" }, + "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { "$ref": "#/definitions/positiveInteger" }, + "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { + "anyOf": [ + { "type": "boolean" }, + { "$ref": "#" } + ], + "default": {} + }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "enum": { + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "dependencies": { + "exclusiveMaximum": [ "maximum" ], + "exclusiveMinimum": [ "minimum" ] + }, + "default": {} +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft6/metaschema.json b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft6/metaschema.json new file mode 100644 index 0000000..a0d2bf7 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft6/metaschema.json @@ -0,0 +1,153 @@ +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "http://json-schema.org/draft-06/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": {}, + "examples": { + "type": "array", + "items": {} + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": {} + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": {}, + "enum": { + "type": "array" + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": {} +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/schemas/draft7/metaschema.json b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft7/metaschema.json new file mode 100644 index 0000000..746cde9 --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/schemas/draft7/metaschema.json @@ -0,0 +1,166 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$comment": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "readOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": true + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": true, + "enum": { + "type": "array", + "items": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentEncoding": { "type": "string" }, + "if": {"$ref": "#"}, + "then": {"$ref": "#"}, + "else": {"$ref": "#"}, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": true +} diff --git a/source/target-vendors/cp312/jsonschema_specifications/tests/__init__.py b/source/target-vendors/cp312/jsonschema_specifications/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/jsonschema_specifications/tests/test_jsonschema_specifications.py b/source/target-vendors/cp312/jsonschema_specifications/tests/test_jsonschema_specifications.py new file mode 100644 index 0000000..fd2927e --- /dev/null +++ b/source/target-vendors/cp312/jsonschema_specifications/tests/test_jsonschema_specifications.py @@ -0,0 +1,41 @@ +from collections.abc import Mapping +from pathlib import Path + +import pytest + +from jsonschema_specifications import REGISTRY + + +def test_it_contains_metaschemas(): + schema = REGISTRY.contents("http://json-schema.org/draft-07/schema#") + assert isinstance(schema, Mapping) + assert schema["$id"] == "http://json-schema.org/draft-07/schema#" + assert schema["title"] == "Core schema meta-schema" + + +def test_it_is_crawled(): + assert REGISTRY.crawl() == REGISTRY + + +@pytest.mark.parametrize( + "ignored_relative_path", + ["schemas/.DS_Store", "schemas/draft7/.DS_Store"], +) +def test_it_copes_with_dotfiles(ignored_relative_path): + """ + Ignore files like .DS_Store if someone has actually caused one to exist. + + We test here through the private interface as of course the global has + already loaded our schemas. + """ + + import jsonschema_specifications + + package = Path(jsonschema_specifications.__file__).parent + + ignored = package / ignored_relative_path + ignored.touch() + try: + list(jsonschema_specifications._schemas()) + finally: + ignored.unlink() diff --git a/source/target-vendors/cp312/jwt/__init__.py b/source/target-vendors/cp312/jwt/__init__.py new file mode 100644 index 0000000..4f9b685 --- /dev/null +++ b/source/target-vendors/cp312/jwt/__init__.py @@ -0,0 +1,78 @@ +from .api_jwk import PyJWK, PyJWKSet +from .api_jws import ( + PyJWS, + get_algorithm_by_name, + get_unverified_header, + register_algorithm, + unregister_algorithm, +) +from .api_jwt import PyJWT, decode, decode_complete, encode +from .exceptions import ( + DecodeError, + ExpiredSignatureError, + ImmatureSignatureError, + InvalidAlgorithmError, + InvalidAudienceError, + InvalidIssuedAtError, + InvalidIssuerError, + InvalidKeyError, + InvalidSignatureError, + InvalidTokenError, + MissingRequiredClaimError, + PyJWKClientConnectionError, + PyJWKClientError, + PyJWKError, + PyJWKSetError, + PyJWTError, +) +from .jwks_client import PyJWKClient +from .warnings import InsecureKeyLengthWarning + +__version__ = "2.14.0" + +__title__ = "PyJWT" +__description__ = "JSON Web Token implementation in Python" +__url__ = "https://pyjwt.readthedocs.io" +__uri__ = __url__ +__doc__ = f"{__description__} <{__uri__}>" + +__author__ = "José Padilla" +__email__ = "hello@jpadilla.com" + +__license__ = "MIT" +__copyright__ = "Copyright 2015-2026 José Padilla" + + +__all__ = [ + "PyJWS", + "PyJWT", + "PyJWKClient", + "PyJWK", + "PyJWKSet", + "decode", + "decode_complete", + "encode", + "get_unverified_header", + "register_algorithm", + "unregister_algorithm", + "get_algorithm_by_name", + # Warnings + "InsecureKeyLengthWarning", + # Exceptions + "DecodeError", + "ExpiredSignatureError", + "ImmatureSignatureError", + "InvalidAlgorithmError", + "InvalidAudienceError", + "InvalidIssuedAtError", + "InvalidIssuerError", + "InvalidKeyError", + "InvalidSignatureError", + "InvalidTokenError", + "MissingRequiredClaimError", + "PyJWKClientConnectionError", + "PyJWKClientError", + "PyJWKError", + "PyJWKSetError", + "PyJWTError", +] diff --git a/source/target-vendors/cp312/jwt/algorithms.py b/source/target-vendors/cp312/jwt/algorithms.py new file mode 100644 index 0000000..3f350e3 --- /dev/null +++ b/source/target-vendors/cp312/jwt/algorithms.py @@ -0,0 +1,1111 @@ +from __future__ import annotations + +import hashlib +import hmac +import json +import os +import sys +from abc import ABC, abstractmethod +from typing import ( + TYPE_CHECKING, + Any, + ClassVar, + Literal, + NoReturn, + Union, + cast, + get_args, + overload, +) + +from .exceptions import InvalidKeyError +from .types import HashlibHash, JWKDict +from .utils import ( + base64url_decode, + base64url_encode, + der_to_raw_signature, + force_bytes, + from_base64url_uint, + is_pem_format, + is_ssh_key, + raw_to_der_signature, + to_base64url_uint, +) + +try: + from cryptography import x509 + from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import padding + from cryptography.hazmat.primitives.asymmetric.ec import ( + ECDSA, + SECP256K1, + SECP256R1, + SECP384R1, + SECP521R1, + EllipticCurve, + EllipticCurvePrivateKey, + EllipticCurvePrivateNumbers, + EllipticCurvePublicKey, + EllipticCurvePublicNumbers, + ) + from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, + Ed448PublicKey, + ) + from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, + Ed25519PublicKey, + ) + from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKey, + RSAPrivateNumbers, + RSAPublicKey, + RSAPublicNumbers, + rsa_crt_dmp1, + rsa_crt_dmq1, + rsa_crt_iqmp, + rsa_recover_prime_factors, + ) + from cryptography.hazmat.primitives.serialization import ( + Encoding, + NoEncryption, + PrivateFormat, + PublicFormat, + load_der_public_key, + load_pem_private_key, + load_pem_public_key, + load_ssh_public_key, + ) + + if sys.version_info >= (3, 10): + from typing import TypeAlias + else: + # Python 3.9 and lower + from typing_extensions import TypeAlias + + # Type aliases for convenience in algorithms method signatures + AllowedRSAKeys: TypeAlias = Union[RSAPrivateKey, RSAPublicKey] + AllowedECKeys: TypeAlias = Union[EllipticCurvePrivateKey, EllipticCurvePublicKey] + AllowedOKPKeys: TypeAlias = Union[ + Ed25519PrivateKey, Ed25519PublicKey, Ed448PrivateKey, Ed448PublicKey + ] + AllowedKeys: TypeAlias = Union[AllowedRSAKeys, AllowedECKeys, AllowedOKPKeys] + #: Type alias for allowed ``cryptography`` private keys (requires ``cryptography`` to be installed) + AllowedPrivateKeys: TypeAlias = Union[ + RSAPrivateKey, EllipticCurvePrivateKey, Ed25519PrivateKey, Ed448PrivateKey + ] + #: Type alias for allowed ``cryptography`` public keys (requires ``cryptography`` to be installed) + AllowedPublicKeys: TypeAlias = Union[ + RSAPublicKey, EllipticCurvePublicKey, Ed25519PublicKey, Ed448PublicKey + ] + + if TYPE_CHECKING or bool(os.getenv("SPHINX_BUILD", "")): + from cryptography.hazmat.primitives.asymmetric.types import ( + PrivateKeyTypes, + PublicKeyTypes, + ) + + has_crypto = True +except ModuleNotFoundError: + if sys.version_info >= (3, 11): + from typing import Never + else: + from typing_extensions import Never + + AllowedRSAKeys = Never # type: ignore[misc] + AllowedECKeys = Never # type: ignore[misc] + AllowedOKPKeys = Never # type: ignore[misc] + AllowedKeys = Never # type: ignore[misc] + AllowedPrivateKeys = Never # type: ignore[misc] + AllowedPublicKeys = Never # type: ignore[misc] + has_crypto = False + + +requires_cryptography = { + "RS256", + "RS384", + "RS512", + "ES256", + "ES256K", + "ES384", + "ES521", + "ES512", + "PS256", + "PS384", + "PS512", + "EdDSA", +} + + +def get_default_algorithms() -> dict[str, Algorithm]: + """ + Returns the algorithms that are implemented by the library. + """ + default_algorithms: dict[str, Algorithm] = { + "none": NoneAlgorithm(), + "HS256": HMACAlgorithm(HMACAlgorithm.SHA256), + "HS384": HMACAlgorithm(HMACAlgorithm.SHA384), + "HS512": HMACAlgorithm(HMACAlgorithm.SHA512), + } + + if has_crypto: + default_algorithms.update( + { + "RS256": RSAAlgorithm(RSAAlgorithm.SHA256), + "RS384": RSAAlgorithm(RSAAlgorithm.SHA384), + "RS512": RSAAlgorithm(RSAAlgorithm.SHA512), + "ES256": ECAlgorithm(ECAlgorithm.SHA256, SECP256R1), + "ES256K": ECAlgorithm(ECAlgorithm.SHA256, SECP256K1), + "ES384": ECAlgorithm(ECAlgorithm.SHA384, SECP384R1), + "ES521": ECAlgorithm(ECAlgorithm.SHA512, SECP521R1), + "ES512": ECAlgorithm( + ECAlgorithm.SHA512, SECP521R1 + ), # Backward compat for #219 fix + "PS256": RSAPSSAlgorithm(RSAPSSAlgorithm.SHA256), + "PS384": RSAPSSAlgorithm(RSAPSSAlgorithm.SHA384), + "PS512": RSAPSSAlgorithm(RSAPSSAlgorithm.SHA512), + "EdDSA": OKPAlgorithm(), + } + ) + + return default_algorithms + + +class Algorithm(ABC): + """ + The interface for an algorithm used to sign and verify tokens. + """ + + # pyjwt-964: Validate to ensure the key passed in was decoded to the correct cryptography key family + _crypto_key_types: tuple[type[AllowedKeys], ...] | None = None + + def compute_hash_digest(self, bytestr: bytes) -> bytes: + """ + Compute a hash digest using the specified algorithm's hash algorithm. + + If there is no hash algorithm, raises a NotImplementedError. + """ + # lookup self.hash_alg if defined in a way that mypy can understand + hash_alg = getattr(self, "hash_alg", None) + if hash_alg is None: + raise NotImplementedError + + if ( + has_crypto + and isinstance(hash_alg, type) + and issubclass(hash_alg, hashes.HashAlgorithm) + ): + digest = hashes.Hash(hash_alg(), backend=default_backend()) + digest.update(bytestr) + return bytes(digest.finalize()) + else: + return bytes(hash_alg(bytestr).digest()) + + def check_crypto_key_type(self, key: PublicKeyTypes | PrivateKeyTypes) -> None: + """Check that the key belongs to the right cryptographic family. + + Note that this method only works when ``cryptography`` is installed. + + :param key: Potentially a cryptography key + :type key: :py:data:`PublicKeyTypes ` | :py:data:`PrivateKeyTypes ` + :raises ValueError: if ``cryptography`` is not installed, or this method is called by a non-cryptography algorithm + :raises InvalidKeyError: if the key doesn't match the expected key classes + """ + if not has_crypto or self._crypto_key_types is None: + raise ValueError( + "This method requires the cryptography library, and should only be used by cryptography-based algorithms." + ) + + if not isinstance(key, self._crypto_key_types): + valid_classes = (cls.__name__ for cls in self._crypto_key_types) + actual_class = key.__class__.__name__ + self_class = self.__class__.__name__ + raise InvalidKeyError( + f"Expected one of {valid_classes}, got: {actual_class}. Invalid Key type for {self_class}" + ) + + @abstractmethod + def prepare_key(self, key: Any) -> Any: + """ + Performs necessary validation and conversions on the key and returns + the key value in the proper format for sign() and verify(). + """ + + @abstractmethod + def sign(self, msg: bytes, key: Any) -> bytes: + """ + Returns a digital signature for the specified message + using the specified key value. + """ + + @abstractmethod + def verify(self, msg: bytes, key: Any, sig: bytes) -> bool: + """ + Verifies that the specified digital signature is valid + for the specified message and key values. + """ + + @overload + @staticmethod + @abstractmethod + def to_jwk(key_obj: Any, as_dict: Literal[True]) -> JWKDict: ... # pragma: no cover + + @overload + @staticmethod + @abstractmethod + def to_jwk( + key_obj: Any, as_dict: Literal[False] = False + ) -> str: ... # pragma: no cover + + @staticmethod + @abstractmethod + def to_jwk(key_obj: Any, as_dict: bool = False) -> JWKDict | str: + """ + Serializes a given key into a JWK + """ + + @staticmethod + @abstractmethod + def from_jwk(jwk: str | JWKDict) -> Any: + """ + Deserializes a given key from JWK back into a key object + """ + + def check_key_length(self, key: Any) -> str | None: + """ + Return a warning message if the key is below the minimum + recommended length for this algorithm, or None if adequate. + """ + return None + + +class NoneAlgorithm(Algorithm): + """ + Placeholder for use when no signing or verification + operations are required. + """ + + def prepare_key(self, key: str | None) -> None: + if key == "": + key = None + + if key is not None: + raise InvalidKeyError('When alg = "none", key value must be None.') + + return key + + def sign(self, msg: bytes, key: None) -> bytes: + return b"" + + def verify(self, msg: bytes, key: None, sig: bytes) -> bool: + return False + + @staticmethod + def to_jwk(key_obj: Any, as_dict: bool = False) -> NoReturn: + raise NotImplementedError() + + @staticmethod + def from_jwk(jwk: str | JWKDict) -> NoReturn: + raise NotImplementedError() + + +class HMACAlgorithm(Algorithm): + """ + Performs signing and verification operations using HMAC + and the specified hash function. + """ + + SHA256: ClassVar[HashlibHash] = hashlib.sha256 + SHA384: ClassVar[HashlibHash] = hashlib.sha384 + SHA512: ClassVar[HashlibHash] = hashlib.sha512 + + def __init__(self, hash_alg: HashlibHash) -> None: + self.hash_alg = hash_alg + + @staticmethod + def _is_der_key(key_bytes: bytes) -> bool: + if not has_crypto: + return False + + try: + load_der_public_key(key_bytes) + except (TypeError, ValueError, UnsupportedAlgorithm): + pass + else: + return True + + try: + x509.load_der_x509_certificate(key_bytes) + except (TypeError, ValueError, UnsupportedAlgorithm): + return False + else: + return True + + def prepare_key(self, key: str | bytes) -> bytes: + key_bytes = force_bytes(key) + + if len(key_bytes) == 0: + raise InvalidKeyError("HMAC key must not be empty.") + + if ( + is_pem_format(key_bytes) + or is_ssh_key(key_bytes) + or self._is_der_key(key_bytes) + ): + raise InvalidKeyError( + "The specified key is an asymmetric key or x509 certificate and" + " should not be used as an HMAC secret." + ) + + # Defense against algorithm-confusion attacks: an attacker with + # control over the token header can force this code path by setting + # alg=HS*, and HMACAlgorithm is the only algorithm that accepts + # arbitrary bytes as a valid secret. Other algorithms reject + # non-key-shaped input naturally. Even a symmetric (kty=oct) JWK + # should be loaded via PyJWK / from_jwk rather than fed as raw JSON + # bytes (whose contents are not the secret material). + try: + jwk_obj = json.loads(key_bytes, parse_int=lambda _: 0) + except RecursionError: + try: + decoded_key = key_bytes.decode( + json.detect_encoding(key_bytes), errors="surrogatepass" + ) + except UnicodeError: + decoded_key = "" + stripped_key = decoded_key.lstrip("\ufeff \t\r\n") + has_jwk_member = False + index = 0 + while index < len(decoded_key): + if decoded_key[index] != '"': + index += 1 + continue + end = index + 1 + while end < len(decoded_key): + if decoded_key[end] == "\\": + end += 2 + elif decoded_key[end] == '"': + break + else: + end += 1 + if end >= len(decoded_key): + break + next_index = end + 1 + while ( + next_index < len(decoded_key) + and decoded_key[next_index] in " \t\r\n" + ): + next_index += 1 + if next_index < len(decoded_key) and decoded_key[next_index] == ":": + try: + has_jwk_member = ( + json.loads(decoded_key[index : end + 1]) == "kty" + ) + except ValueError: + pass + if has_jwk_member: + break + index = end + 1 + if stripped_key.startswith("{") or ( + stripped_key.startswith("[") and has_jwk_member + ): + raise InvalidKeyError( + "The specified key looks like a JWK and should not be " + "used directly as an HMAC secret. Load it via " + "PyJWK / HMACAlgorithm.from_jwk first." + ) from None + jwk_obj = None + except ValueError: + jwk_obj = None + contains_jwk_member = False + objects_to_check = [jwk_obj] + while objects_to_check: + obj = objects_to_check.pop() + if isinstance(obj, dict): + if "kty" in obj: + contains_jwk_member = True + break + objects_to_check.extend(obj.values()) + elif isinstance(obj, list): + objects_to_check.extend(obj) + if contains_jwk_member: + raise InvalidKeyError( + "The specified key looks like a JWK and should not be " + "used directly as an HMAC secret. Load it via " + "PyJWK / HMACAlgorithm.from_jwk first." + ) + + return key_bytes + + @overload + @staticmethod + def to_jwk(key_obj: str | bytes, as_dict: Literal[True]) -> JWKDict: ... + + @overload + @staticmethod + def to_jwk(key_obj: str | bytes, as_dict: Literal[False] = False) -> str: ... + + @staticmethod + def to_jwk(key_obj: str | bytes, as_dict: bool = False) -> JWKDict | str: + jwk = { + "k": base64url_encode(force_bytes(key_obj)).decode(), + "kty": "oct", + } + + if as_dict: + return jwk + else: + return json.dumps(jwk) + + @staticmethod + def from_jwk(jwk: str | JWKDict) -> bytes: + try: + if isinstance(jwk, str): + obj: JWKDict = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") from None + + if obj.get("kty") != "oct": + raise InvalidKeyError("Not an HMAC key") + + key_bytes = base64url_decode(obj["k"]) + if len(key_bytes) == 0: + raise InvalidKeyError("HMAC key must not be empty.") + return key_bytes + + def check_key_length(self, key: bytes) -> str | None: + min_length = self.hash_alg().digest_size + if len(key) < min_length: + return ( + f"The HMAC key is {len(key)} bytes long, which is below " + f"the minimum recommended length of {min_length} bytes for " + f"{self.hash_alg().name.upper()}. " + f"See RFC 7518 Section 3.2." + ) + return None + + def sign(self, msg: bytes, key: bytes) -> bytes: + return hmac.new(key, msg, self.hash_alg).digest() + + def verify(self, msg: bytes, key: bytes, sig: bytes) -> bool: + return hmac.compare_digest(sig, self.sign(msg, key)) + + +if has_crypto: + + class RSAAlgorithm(Algorithm): + """ + Performs signing and verification operations using + RSASSA-PKCS-v1_5 and the specified hash function. + """ + + SHA256: ClassVar[type[hashes.HashAlgorithm]] = hashes.SHA256 + SHA384: ClassVar[type[hashes.HashAlgorithm]] = hashes.SHA384 + SHA512: ClassVar[type[hashes.HashAlgorithm]] = hashes.SHA512 + + _crypto_key_types = cast( + tuple[type[AllowedKeys], ...], + get_args(Union[RSAPrivateKey, RSAPublicKey]), + ) + _MIN_KEY_SIZE: ClassVar[int] = 2048 + + def __init__(self, hash_alg: type[hashes.HashAlgorithm]) -> None: + self.hash_alg = hash_alg + + def check_key_length(self, key: AllowedRSAKeys) -> str | None: + if key.key_size < self._MIN_KEY_SIZE: + return ( + f"The RSA key is {key.key_size} bits long, which is below " + f"the minimum recommended size of {self._MIN_KEY_SIZE} bits. " + f"See NIST SP 800-131A." + ) + return None + + def prepare_key(self, key: AllowedRSAKeys | str | bytes) -> AllowedRSAKeys: + if isinstance(key, self._crypto_key_types): + # Cast is required for type narrowing on Python 3.9's mypy + # but redundant on newer mypy versions; suppress both + # diagnostics so the line works across all supported envs. + return cast(AllowedRSAKeys, key) # type: ignore[redundant-cast,unused-ignore] + + if not isinstance(key, (bytes, str)): + raise TypeError("Expecting a PEM-formatted key.") + + key_bytes = force_bytes(key) + + try: + if key_bytes.startswith(b"ssh-rsa"): + public_key: PublicKeyTypes = load_ssh_public_key(key_bytes) + self.check_crypto_key_type(public_key) + return cast(RSAPublicKey, public_key) + else: + private_key: PrivateKeyTypes = load_pem_private_key( + key_bytes, password=None + ) + self.check_crypto_key_type(private_key) + return cast(RSAPrivateKey, private_key) + except ValueError: + try: + public_key = load_pem_public_key(key_bytes) + self.check_crypto_key_type(public_key) + return cast(RSAPublicKey, public_key) + except (ValueError, UnsupportedAlgorithm): + raise InvalidKeyError( + "Could not parse the provided public key." + ) from None + + @overload + @staticmethod + def to_jwk(key_obj: AllowedRSAKeys, as_dict: Literal[True]) -> JWKDict: ... + + @overload + @staticmethod + def to_jwk(key_obj: AllowedRSAKeys, as_dict: Literal[False] = False) -> str: ... + + @staticmethod + def to_jwk(key_obj: AllowedRSAKeys, as_dict: bool = False) -> JWKDict | str: + obj: dict[str, Any] | None = None + + if hasattr(key_obj, "private_numbers"): + # Private key + numbers = key_obj.private_numbers() + + obj = { + "kty": "RSA", + "key_ops": ["sign"], + "n": to_base64url_uint(numbers.public_numbers.n).decode(), + "e": to_base64url_uint(numbers.public_numbers.e).decode(), + "d": to_base64url_uint(numbers.d).decode(), + "p": to_base64url_uint(numbers.p).decode(), + "q": to_base64url_uint(numbers.q).decode(), + "dp": to_base64url_uint(numbers.dmp1).decode(), + "dq": to_base64url_uint(numbers.dmq1).decode(), + "qi": to_base64url_uint(numbers.iqmp).decode(), + } + + elif hasattr(key_obj, "verify"): + # Public key + numbers = key_obj.public_numbers() + + obj = { + "kty": "RSA", + "key_ops": ["verify"], + "n": to_base64url_uint(numbers.n).decode(), + "e": to_base64url_uint(numbers.e).decode(), + } + else: + raise InvalidKeyError("Not a public or private key") + + if as_dict: + return obj + else: + return json.dumps(obj) + + @staticmethod + def from_jwk(jwk: str | JWKDict) -> AllowedRSAKeys: + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") from None + + if obj.get("kty") != "RSA": + raise InvalidKeyError("Not an RSA key") from None + + if "d" in obj and "e" in obj and "n" in obj: + # Private key + if "oth" in obj: + raise InvalidKeyError( + "Unsupported RSA private key: > 2 primes not supported" + ) + + other_props = ["p", "q", "dp", "dq", "qi"] + props_found = [prop in obj for prop in other_props] + any_props_found = any(props_found) + + if any_props_found and not all(props_found): + raise InvalidKeyError( + "RSA key must include all parameters if any are present besides d" + ) from None + + public_numbers = RSAPublicNumbers( + from_base64url_uint(obj["e"]), + from_base64url_uint(obj["n"]), + ) + + if any_props_found: + numbers = RSAPrivateNumbers( + d=from_base64url_uint(obj["d"]), + p=from_base64url_uint(obj["p"]), + q=from_base64url_uint(obj["q"]), + dmp1=from_base64url_uint(obj["dp"]), + dmq1=from_base64url_uint(obj["dq"]), + iqmp=from_base64url_uint(obj["qi"]), + public_numbers=public_numbers, + ) + else: + d = from_base64url_uint(obj["d"]) + p, q = rsa_recover_prime_factors( + public_numbers.n, d, public_numbers.e + ) + + numbers = RSAPrivateNumbers( + d=d, + p=p, + q=q, + dmp1=rsa_crt_dmp1(d, p), + dmq1=rsa_crt_dmq1(d, q), + iqmp=rsa_crt_iqmp(p, q), + public_numbers=public_numbers, + ) + + return numbers.private_key() + elif "n" in obj and "e" in obj: + # Public key + return RSAPublicNumbers( + from_base64url_uint(obj["e"]), + from_base64url_uint(obj["n"]), + ).public_key() + else: + raise InvalidKeyError("Not a public or private key") + + def sign(self, msg: bytes, key: RSAPrivateKey) -> bytes: + signature: bytes = key.sign(msg, padding.PKCS1v15(), self.hash_alg()) + return signature + + def verify(self, msg: bytes, key: RSAPublicKey, sig: bytes) -> bool: + try: + key.verify(sig, msg, padding.PKCS1v15(), self.hash_alg()) + return True + except InvalidSignature: + return False + + class ECAlgorithm(Algorithm): + """ + Performs signing and verification operations using + ECDSA and the specified hash function + """ + + SHA256: ClassVar[type[hashes.HashAlgorithm]] = hashes.SHA256 + SHA384: ClassVar[type[hashes.HashAlgorithm]] = hashes.SHA384 + SHA512: ClassVar[type[hashes.HashAlgorithm]] = hashes.SHA512 + + _crypto_key_types = cast( + tuple[type[AllowedKeys], ...], + get_args(Union[EllipticCurvePrivateKey, EllipticCurvePublicKey]), + ) + + def __init__( + self, + hash_alg: type[hashes.HashAlgorithm], + expected_curve: type[EllipticCurve] | None = None, + ) -> None: + self.hash_alg = hash_alg + self.expected_curve = expected_curve + + def _validate_curve(self, key: AllowedECKeys) -> None: + """Validate that the key's curve matches the expected curve.""" + if self.expected_curve is None: + return + + if not isinstance(key.curve, self.expected_curve): + raise InvalidKeyError( + f"The key's curve '{key.curve.name}' does not match the expected " + f"curve '{self.expected_curve.name}' for this algorithm" + ) + + def prepare_key(self, key: AllowedECKeys | str | bytes) -> AllowedECKeys: + if isinstance(key, self._crypto_key_types): + # See note in RSAAlgorithm.prepare_key. + ec_key = cast(AllowedECKeys, key) # type: ignore[redundant-cast,unused-ignore] + self._validate_curve(ec_key) + return ec_key + + if not isinstance(key, (bytes, str)): + raise TypeError("Expecting a PEM-formatted key.") + + key_bytes = force_bytes(key) + + # Attempt to load key. We don't know if it's + # a Signing Key or a Verifying Key, so we try + # the Verifying Key first. + try: + if key_bytes.startswith(b"ecdsa-sha2-"): + public_key: PublicKeyTypes = load_ssh_public_key(key_bytes) + else: + public_key = load_pem_public_key(key_bytes) + + # Explicit check the key to prevent confusing errors from cryptography + self.check_crypto_key_type(public_key) + ec_public_key = cast(EllipticCurvePublicKey, public_key) + self._validate_curve(ec_public_key) + return ec_public_key + except ValueError: + private_key = load_pem_private_key(key_bytes, password=None) + self.check_crypto_key_type(private_key) + ec_private_key = cast(EllipticCurvePrivateKey, private_key) + self._validate_curve(ec_private_key) + return ec_private_key + + def sign(self, msg: bytes, key: EllipticCurvePrivateKey) -> bytes: + der_sig = key.sign(msg, ECDSA(self.hash_alg())) + + return der_to_raw_signature(der_sig, key.curve) + + def verify(self, msg: bytes, key: AllowedECKeys, sig: bytes) -> bool: + try: + der_sig = raw_to_der_signature(sig, key.curve) + except ValueError: + return False + + try: + public_key = ( + key.public_key() + if isinstance(key, EllipticCurvePrivateKey) + else key + ) + public_key.verify(der_sig, msg, ECDSA(self.hash_alg())) + return True + except InvalidSignature: + return False + + @overload + @staticmethod + def to_jwk(key_obj: AllowedECKeys, as_dict: Literal[True]) -> JWKDict: ... + + @overload + @staticmethod + def to_jwk(key_obj: AllowedECKeys, as_dict: Literal[False] = False) -> str: ... + + @staticmethod + def to_jwk(key_obj: AllowedECKeys, as_dict: bool = False) -> JWKDict | str: + if isinstance(key_obj, EllipticCurvePrivateKey): + public_numbers = key_obj.public_key().public_numbers() + elif isinstance(key_obj, EllipticCurvePublicKey): + public_numbers = key_obj.public_numbers() + else: + raise InvalidKeyError("Not a public or private key") + + if isinstance(key_obj.curve, SECP256R1): + crv = "P-256" + elif isinstance(key_obj.curve, SECP384R1): + crv = "P-384" + elif isinstance(key_obj.curve, SECP521R1): + crv = "P-521" + elif isinstance(key_obj.curve, SECP256K1): + crv = "secp256k1" + else: + raise InvalidKeyError(f"Invalid curve: {key_obj.curve}") + + obj: dict[str, Any] = { + "kty": "EC", + "crv": crv, + "x": to_base64url_uint( + public_numbers.x, + bit_length=key_obj.curve.key_size, + ).decode(), + "y": to_base64url_uint( + public_numbers.y, + bit_length=key_obj.curve.key_size, + ).decode(), + } + + if isinstance(key_obj, EllipticCurvePrivateKey): + obj["d"] = to_base64url_uint( + key_obj.private_numbers().private_value, + bit_length=key_obj.curve.key_size, + ).decode() + + if as_dict: + return obj + else: + return json.dumps(obj) + + @staticmethod + def from_jwk(jwk: str | JWKDict) -> AllowedECKeys: + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") from None + + if obj.get("kty") != "EC": + raise InvalidKeyError("Not an Elliptic curve key") from None + + if "x" not in obj or "y" not in obj: + raise InvalidKeyError("Not an Elliptic curve key") from None + + x = base64url_decode(obj.get("x")) + y = base64url_decode(obj.get("y")) + + curve = obj.get("crv") + curve_obj: EllipticCurve + + if curve == "P-256": + if len(x) == len(y) == 32: + curve_obj = SECP256R1() + else: + raise InvalidKeyError( + "Coords should be 32 bytes for curve P-256" + ) from None + elif curve == "P-384": + if len(x) == len(y) == 48: + curve_obj = SECP384R1() + else: + raise InvalidKeyError( + "Coords should be 48 bytes for curve P-384" + ) from None + elif curve == "P-521": + if len(x) == len(y) == 66: + curve_obj = SECP521R1() + else: + raise InvalidKeyError( + "Coords should be 66 bytes for curve P-521" + ) from None + elif curve == "secp256k1": + if len(x) == len(y) == 32: + curve_obj = SECP256K1() + else: + raise InvalidKeyError( + "Coords should be 32 bytes for curve secp256k1" + ) + else: + raise InvalidKeyError(f"Invalid curve: {curve}") + + public_numbers = EllipticCurvePublicNumbers( + x=int.from_bytes(x, byteorder="big"), + y=int.from_bytes(y, byteorder="big"), + curve=curve_obj, + ) + + if "d" not in obj: + return public_numbers.public_key() + + d = base64url_decode(obj.get("d")) + if len(d) != len(x): + raise InvalidKeyError( + "D should be {} bytes for curve {}", len(x), curve + ) + + return EllipticCurvePrivateNumbers( + int.from_bytes(d, byteorder="big"), public_numbers + ).private_key() + + class RSAPSSAlgorithm(RSAAlgorithm): + """ + Performs a signature using RSASSA-PSS with MGF1 + """ + + def sign(self, msg: bytes, key: RSAPrivateKey) -> bytes: + signature: bytes = key.sign( + msg, + padding.PSS( + mgf=padding.MGF1(self.hash_alg()), + salt_length=self.hash_alg().digest_size, + ), + self.hash_alg(), + ) + return signature + + def verify(self, msg: bytes, key: RSAPublicKey, sig: bytes) -> bool: + try: + key.verify( + sig, + msg, + padding.PSS( + mgf=padding.MGF1(self.hash_alg()), + salt_length=self.hash_alg().digest_size, + ), + self.hash_alg(), + ) + return True + except InvalidSignature: + return False + + class OKPAlgorithm(Algorithm): + """ + Performs signing and verification operations using EdDSA + + This class requires ``cryptography>=2.6`` to be installed. + """ + + _crypto_key_types = cast( + tuple[type[AllowedKeys], ...], + get_args( + Union[ + Ed25519PrivateKey, + Ed25519PublicKey, + Ed448PrivateKey, + Ed448PublicKey, + ] + ), + ) + + def __init__(self, **kwargs: Any) -> None: + pass + + def prepare_key(self, key: AllowedOKPKeys | str | bytes) -> AllowedOKPKeys: + if not isinstance(key, (str, bytes)): + self.check_crypto_key_type(key) + return key + + key_str = key.decode("utf-8") if isinstance(key, bytes) else key + key_bytes = key.encode("utf-8") if isinstance(key, str) else key + + loaded_key: PublicKeyTypes | PrivateKeyTypes + if "-----BEGIN PUBLIC" in key_str: + loaded_key = load_pem_public_key(key_bytes) + elif "-----BEGIN PRIVATE" in key_str: + loaded_key = load_pem_private_key(key_bytes, password=None) + elif key_str[0:4] == "ssh-": + loaded_key = load_ssh_public_key(key_bytes) + else: + raise InvalidKeyError("Not a public or private key") + + # Explicit check the key to prevent confusing errors from cryptography + self.check_crypto_key_type(loaded_key) + return cast("AllowedOKPKeys", loaded_key) + + def sign( + self, msg: str | bytes, key: Ed25519PrivateKey | Ed448PrivateKey + ) -> bytes: + """ + Sign a message ``msg`` using the EdDSA private key ``key`` + :param str|bytes msg: Message to sign + :param Ed25519PrivateKey}Ed448PrivateKey key: A :class:`.Ed25519PrivateKey` + or :class:`.Ed448PrivateKey` isinstance + :return bytes signature: The signature, as bytes + """ + msg_bytes = msg.encode("utf-8") if isinstance(msg, str) else msg + signature: bytes = key.sign(msg_bytes) + return signature + + def verify( + self, msg: str | bytes, key: AllowedOKPKeys, sig: str | bytes + ) -> bool: + """ + Verify a given ``msg`` against a signature ``sig`` using the EdDSA key ``key`` + + :param str|bytes sig: EdDSA signature to check ``msg`` against + :param str|bytes msg: Message to sign + :param Ed25519PrivateKey|Ed25519PublicKey|Ed448PrivateKey|Ed448PublicKey key: + A private or public EdDSA key instance + :return bool verified: True if signature is valid, False if not. + """ + try: + msg_bytes = msg.encode("utf-8") if isinstance(msg, str) else msg + sig_bytes = sig.encode("utf-8") if isinstance(sig, str) else sig + + public_key = ( + key.public_key() + if isinstance(key, (Ed25519PrivateKey, Ed448PrivateKey)) + else key + ) + public_key.verify(sig_bytes, msg_bytes) + return True # If no exception was raised, the signature is valid. + except InvalidSignature: + return False + + @overload + @staticmethod + def to_jwk(key: AllowedOKPKeys, as_dict: Literal[True]) -> JWKDict: ... + + @overload + @staticmethod + def to_jwk(key: AllowedOKPKeys, as_dict: Literal[False] = False) -> str: ... + + @staticmethod + def to_jwk(key: AllowedOKPKeys, as_dict: bool = False) -> JWKDict | str: + if isinstance(key, (Ed25519PublicKey, Ed448PublicKey)): + x = key.public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw, + ) + crv = "Ed25519" if isinstance(key, Ed25519PublicKey) else "Ed448" + + obj = { + "x": base64url_encode(force_bytes(x)).decode(), + "kty": "OKP", + "crv": crv, + } + + if as_dict: + return obj + else: + return json.dumps(obj) + + if isinstance(key, (Ed25519PrivateKey, Ed448PrivateKey)): + d = key.private_bytes( + encoding=Encoding.Raw, + format=PrivateFormat.Raw, + encryption_algorithm=NoEncryption(), + ) + + x = key.public_key().public_bytes( + encoding=Encoding.Raw, + format=PublicFormat.Raw, + ) + + crv = "Ed25519" if isinstance(key, Ed25519PrivateKey) else "Ed448" + obj = { + "x": base64url_encode(force_bytes(x)).decode(), + "d": base64url_encode(force_bytes(d)).decode(), + "kty": "OKP", + "crv": crv, + } + + if as_dict: + return obj + else: + return json.dumps(obj) + + raise InvalidKeyError("Not a public or private key") + + @staticmethod + def from_jwk(jwk: str | JWKDict) -> AllowedOKPKeys: + try: + if isinstance(jwk, str): + obj = json.loads(jwk) + elif isinstance(jwk, dict): + obj = jwk + else: + raise ValueError + except ValueError: + raise InvalidKeyError("Key is not valid JSON") from None + + if obj.get("kty") != "OKP": + raise InvalidKeyError("Not an Octet Key Pair") + + curve = obj.get("crv") + if curve != "Ed25519" and curve != "Ed448": + raise InvalidKeyError(f"Invalid curve: {curve}") + + if "x" not in obj: + raise InvalidKeyError('OKP should have "x" parameter') + x = base64url_decode(obj.get("x")) + + try: + if "d" not in obj: + if curve == "Ed25519": + return Ed25519PublicKey.from_public_bytes(x) + return Ed448PublicKey.from_public_bytes(x) + d = base64url_decode(obj.get("d")) + if curve == "Ed25519": + return Ed25519PrivateKey.from_private_bytes(d) + return Ed448PrivateKey.from_private_bytes(d) + except ValueError as err: + raise InvalidKeyError("Invalid key parameter") from err diff --git a/source/target-vendors/cp312/jwt/api_jwk.py b/source/target-vendors/cp312/jwt/api_jwk.py new file mode 100644 index 0000000..5ee26b4 --- /dev/null +++ b/source/target-vendors/cp312/jwt/api_jwk.py @@ -0,0 +1,193 @@ +from __future__ import annotations + +import json +import time +from collections.abc import Iterator +from typing import Any + +from .algorithms import get_default_algorithms, has_crypto, requires_cryptography +from .exceptions import ( + InvalidKeyError, + MissingCryptographyError, + PyJWKError, + PyJWKSetError, + PyJWTError, +) +from .types import JWKDict + + +class PyJWK: + def __init__(self, jwk_data: JWKDict, algorithm: str | None = None) -> None: + """A class that represents a `JSON Web Key `_. + + :param jwk_data: The decoded JWK data. + :type jwk_data: dict[str, typing.Any] + :param algorithm: The key algorithm. If not specified, the key's ``alg`` will be used. + :type algorithm: str or None + :raises InvalidKeyError: If the key type (``kty``) is not found or unsupported, or if the curve (``crv``) is not found or unsupported. + :raises MissingCryptographyError: If the algorithm requires ``cryptography`` to be installed and it is not available. + :raises PyJWKError: If unable to find an algorithm for the key. + """ + self._jwk_data = jwk_data + + kty = self._jwk_data.get("kty", None) + if not kty: + raise InvalidKeyError(f"kty is not found: {self._jwk_data}") + + if not algorithm and isinstance(self._jwk_data, dict): + algorithm = self._jwk_data.get("alg", None) + + if not algorithm: + # Determine alg with kty (and crv). + crv = self._jwk_data.get("crv", None) + if kty == "EC": + if crv == "P-256" or not crv: + algorithm = "ES256" + elif crv == "P-384": + algorithm = "ES384" + elif crv == "P-521": + algorithm = "ES512" + elif crv == "secp256k1": + algorithm = "ES256K" + else: + raise InvalidKeyError(f"Unsupported crv: {crv}") + elif kty == "RSA": + algorithm = "RS256" + elif kty == "oct": + algorithm = "HS256" + elif kty == "OKP": + if not crv: + raise InvalidKeyError(f"crv is not found: {self._jwk_data}") + if crv == "Ed25519": + algorithm = "EdDSA" + else: + raise InvalidKeyError(f"Unsupported crv: {crv}") + else: + raise InvalidKeyError(f"Unsupported kty: {kty}") + + if not has_crypto and algorithm in requires_cryptography: + raise MissingCryptographyError( + f"{algorithm} requires 'cryptography' to be installed." + ) + + self.algorithm_name = algorithm + + try: + self.Algorithm = get_default_algorithms()[algorithm] + except KeyError: + raise PyJWKError( + f"Unable to find an algorithm for key: {self._jwk_data}", + ) from None + + try: + self.key = self.Algorithm.from_jwk(self._jwk_data) + except ValueError as error: + raise InvalidKeyError( + f"Unable to construct key from JWK: {error}" + ) from error + + @staticmethod + def from_dict(obj: JWKDict, algorithm: str | None = None) -> PyJWK: + """Creates a :class:`PyJWK` object from a JSON-like dictionary. + + :param obj: The JWK data, as a dictionary + :type obj: dict[str, typing.Any] + :param algorithm: The key algorithm. If not specified, the key's ``alg`` will be used. + :type algorithm: str or None + :rtype: PyJWK + """ + return PyJWK(obj, algorithm) + + @staticmethod + def from_json(data: str, algorithm: None = None) -> PyJWK: + """Create a :class:`PyJWK` object from a JSON string. + Implicitly calls :meth:`PyJWK.from_dict()`. + + :param str data: The JWK data, as a JSON string. + :param algorithm: The key algorithm. If not specific, the key's ``alg`` will be used. + :type algorithm: str or None + + :rtype: PyJWK + """ + obj = json.loads(data) + return PyJWK.from_dict(obj, algorithm) + + @property + def key_type(self) -> str | None: + """The `kty` property from the JWK. + + :rtype: str or None + """ + return self._jwk_data.get("kty", None) + + @property + def key_id(self) -> str | None: + """The `kid` property from the JWK. + + :rtype: str or None + """ + return self._jwk_data.get("kid", None) + + @property + def public_key_use(self) -> str | None: + """The `use` property from the JWK. + + :rtype: str or None + """ + return self._jwk_data.get("use", None) + + +class PyJWKSet: + def __init__(self, keys: list[JWKDict]) -> None: + self.keys: list[PyJWK] = [] + + if not keys: + raise PyJWKSetError("The JWK Set did not contain any keys") + + if not isinstance(keys, list): + raise PyJWKSetError("Invalid JWK Set value") + + for key in keys: + try: + self.keys.append(PyJWK(key)) + except PyJWTError as error: + if isinstance(error, MissingCryptographyError): + raise error + # skip unusable keys + continue + + if len(self.keys) == 0: + raise PyJWKSetError( + "The JWK Set did not contain any usable keys. Perhaps 'cryptography' is not installed?" + ) + + @staticmethod + def from_dict(obj: dict[str, Any]) -> PyJWKSet: + keys = obj.get("keys", []) + return PyJWKSet(keys) + + @staticmethod + def from_json(data: str) -> PyJWKSet: + obj = json.loads(data) + return PyJWKSet.from_dict(obj) + + def __getitem__(self, kid: str) -> PyJWK: + for key in self.keys: + if key.key_id == kid: + return key + raise KeyError(f"keyset has no key for kid: {kid}") + + def __iter__(self) -> Iterator[PyJWK]: + return iter(self.keys) + + +class PyJWTSetWithTimestamp: + def __init__(self, jwk_set: PyJWKSet): + self.jwk_set = jwk_set + self.timestamp = time.monotonic() + + def get_jwk_set(self) -> PyJWKSet: + return self.jwk_set + + def get_timestamp(self) -> float: + return self.timestamp diff --git a/source/target-vendors/cp312/jwt/api_jws.py b/source/target-vendors/cp312/jwt/api_jws.py new file mode 100644 index 0000000..81a2ccb --- /dev/null +++ b/source/target-vendors/cp312/jwt/api_jws.py @@ -0,0 +1,472 @@ +from __future__ import annotations + +import binascii +import json +import warnings +from collections.abc import Sequence +from typing import TYPE_CHECKING, Any + +from .algorithms import ( + Algorithm, + get_default_algorithms, + has_crypto, + requires_cryptography, +) +from .api_jwk import PyJWK +from .exceptions import ( + DecodeError, + InvalidAlgorithmError, + InvalidKeyError, + InvalidSignatureError, + InvalidTokenError, +) +from .utils import base64url_decode, base64url_encode +from .warnings import InsecureKeyLengthWarning, RemovedInPyjwt3Warning + +if TYPE_CHECKING: + from .algorithms import AllowedPrivateKeys, AllowedPublicKeys + from .types import SigOptions + +_ALGORITHM_UNSET = object() +_BASE64URL_ALPHABET = ( + b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" +) + + +class PyJWS: + header_typ = "JWT" + + def __init__( + self, + algorithms: Sequence[str] | None = None, + options: SigOptions | None = None, + ) -> None: + self._algorithms = get_default_algorithms() + self._valid_algs = ( + set(algorithms) if algorithms is not None else set(self._algorithms) + ) + + # Remove algorithms that aren't on the whitelist + for key in list(self._algorithms.keys()): + if key not in self._valid_algs: + del self._algorithms[key] + + self.options: SigOptions = self._get_default_options() + if options is not None: + self.options = {**self.options, **options} + + @staticmethod + def _get_default_options() -> SigOptions: + return {"verify_signature": True, "enforce_minimum_key_length": False} + + def register_algorithm(self, alg_id: str, alg_obj: Algorithm) -> None: + """ + Registers a new Algorithm for use when creating and verifying tokens. + + :param str alg_id: the ID of the Algorithm + :param alg_obj: the Algorithm object + :type alg_obj: Algorithm + """ + if alg_id in self._algorithms: + raise ValueError("Algorithm already has a handler.") + + if not isinstance(alg_obj, Algorithm): + raise TypeError("Object is not of type `Algorithm`") + + self._algorithms[alg_id] = alg_obj + self._valid_algs.add(alg_id) + + def unregister_algorithm(self, alg_id: str) -> None: + """ + Unregisters an Algorithm for use when creating and verifying tokens + :param str alg_id: the ID of the Algorithm + :raises KeyError: if algorithm is not registered. + """ + if alg_id not in self._algorithms: + raise KeyError( + "The specified algorithm could not be removed" + " because it is not registered." + ) + + del self._algorithms[alg_id] + self._valid_algs.remove(alg_id) + + def get_algorithms(self) -> list[str]: + """ + Returns a list of supported values for the `alg` parameter. + + :rtype: list[str] + """ + return list(self._valid_algs) + + def get_algorithm_by_name(self, alg_name: str) -> Algorithm: + """ + For a given string name, return the matching Algorithm object. + + Example usage: + >>> jws_obj = PyJWS() + >>> jws_obj.get_algorithm_by_name("RS256") + + :param alg_name: The name of the algorithm to retrieve + :type alg_name: str + :rtype: Algorithm + """ + try: + return self._algorithms[alg_name] + except KeyError as e: + if not has_crypto and alg_name in requires_cryptography: + raise NotImplementedError( + f"Algorithm '{alg_name}' could not be found. Do you have cryptography installed?" + ) from e + raise NotImplementedError("Algorithm not supported") from e + + def encode( + self, + payload: bytes, + key: AllowedPrivateKeys | PyJWK | str | bytes, + algorithm: str | None = _ALGORITHM_UNSET, # type: ignore[assignment] + headers: dict[str, Any] | None = None, + json_encoder: type[json.JSONEncoder] | None = None, + is_payload_detached: bool = False, + sort_headers: bool = True, + ) -> str: + segments: list[bytes] = [] + + # declare a new var to narrow the type for type checkers + if algorithm is _ALGORITHM_UNSET: + if isinstance(key, PyJWK): + algorithm_ = key.algorithm_name + else: + algorithm_ = "HS256" + elif algorithm is None: + if isinstance(key, PyJWK): + algorithm_ = key.algorithm_name + else: + algorithm_ = "none" + else: + algorithm_ = algorithm + + # Prefer headers values if present to function parameters. + if headers: + headers_alg = headers.get("alg") + if headers_alg: + algorithm_ = headers["alg"] + + headers_b64 = headers.get("b64") + if headers_b64 is False: + is_payload_detached = True + + # Header + header: dict[str, Any] = {"typ": self.header_typ, "alg": algorithm_} + + if headers: + self._validate_headers(headers, encoding=True) + header.update(headers) + + if not header["typ"]: + del header["typ"] + + if is_payload_detached: + header["b64"] = False + # RFC 7797 §3: producers MUST list "b64" in "crit" whenever + # "b64" appears in the protected header, so b64-unaware + # verifiers don't silently treat an unencoded payload as + # base64-encoded. + existing_crit = header.get("crit", []) + if not isinstance(existing_crit, list): + raise InvalidTokenError("Invalid 'crit' header: must be a list") + if "b64" not in existing_crit: + header["crit"] = [*existing_crit, "b64"] + elif "b64" in header: + # True is the standard value for b64, so no need for it + del header["b64"] + + json_header = json.dumps( + header, separators=(",", ":"), cls=json_encoder, sort_keys=sort_headers + ).encode() + + segments.append(base64url_encode(json_header)) + + if is_payload_detached: + msg_payload = payload + else: + msg_payload = base64url_encode(payload) + segments.append(msg_payload) + + # Segments + signing_input = b".".join(segments) + + alg_obj = self.get_algorithm_by_name(algorithm_) + if isinstance(key, PyJWK): + key = key.key + key = alg_obj.prepare_key(key) + + key_length_msg = alg_obj.check_key_length(key) + if key_length_msg: + if self.options.get("enforce_minimum_key_length", False): + raise InvalidKeyError(key_length_msg) + else: + warnings.warn(key_length_msg, InsecureKeyLengthWarning, stacklevel=2) + + signature = alg_obj.sign(signing_input, key) + + segments.append(base64url_encode(signature)) + + # Don't put the payload content inside the encoded token when detached + if is_payload_detached: + segments[1] = b"" + encoded_string = b".".join(segments) + + return encoded_string.decode("utf-8") + + def decode_complete( + self, + jwt: str | bytes, + key: AllowedPublicKeys | PyJWK | str | bytes = "", + algorithms: Sequence[str] | None = None, + options: SigOptions | None = None, + detached_payload: bytes | None = None, + **kwargs: dict[str, Any], + ) -> dict[str, Any]: + if kwargs: + warnings.warn( + "passing additional kwargs to decode_complete() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + stacklevel=2, + ) + merged_options: SigOptions + if options is None: + merged_options = self.options + else: + merged_options = {**self.options, **options} + + verify_signature = merged_options["verify_signature"] + + if verify_signature and not algorithms and not isinstance(key, PyJWK): + raise DecodeError( + 'It is required that you pass in a value for the "algorithms" argument when calling decode().' + ) + + payload, signing_input, header, signature = self._load(jwt) + + self._validate_headers(header) + + if detached_payload is not None and header.get("b64", True) is not False: + raise DecodeError( + 'It is only valid to pass "detached_payload" when the protected header has "b64" set to false.' + ) + + if header.get("b64", True) is False: + # RFC 7797 §3: when "b64" is present in the protected header, + # it MUST also appear in "crit". A token that sets b64=false + # without declaring it critical is malformed. + crit = header.get("crit") or [] + if not isinstance(crit, list) or "b64" not in crit: + raise InvalidTokenError( + "The 'b64' header parameter requires 'b64' to be listed in 'crit'." + ) + if detached_payload is None: + raise DecodeError( + 'It is required that you pass in a value for the "detached_payload" argument to decode a message having the b64 header set to false.' + ) + payload = detached_payload + signing_input = b".".join([signing_input.rsplit(b".", 1)[0], payload]) + + if verify_signature: + self._verify_signature( + signing_input, + header, + signature, + key, + algorithms, + options=merged_options, + ) + + return { + "payload": payload, + "header": header, + "signature": signature, + } + + def decode( + self, + jwt: str | bytes, + key: AllowedPublicKeys | PyJWK | str | bytes = "", + algorithms: Sequence[str] | None = None, + options: SigOptions | None = None, + detached_payload: bytes | None = None, + **kwargs: dict[str, Any], + ) -> Any: + if kwargs: + warnings.warn( + "passing additional kwargs to decode() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + stacklevel=2, + ) + decoded = self.decode_complete( + jwt, key, algorithms, options, detached_payload=detached_payload + ) + return decoded["payload"] + + def get_unverified_header(self, jwt: str | bytes) -> dict[str, Any]: + """Returns back the JWT header parameters as a `dict` + + Note: The signature is not verified so the header parameters + should not be fully trusted until signature verification is complete + """ + headers = self._load(jwt)[2] + self._validate_headers(headers) + + return headers + + @staticmethod + def _decode_base64url_segment(segment: bytes, name: str) -> bytes: + if len(segment) % 4 == 1 or any( + character not in _BASE64URL_ALPHABET for character in segment + ): + raise DecodeError(f"Invalid {name} padding") + + try: + decoded = base64url_decode(segment) + except (TypeError, binascii.Error) as err: + raise DecodeError(f"Invalid {name} padding") from err + + if base64url_encode(decoded) != segment: + raise DecodeError(f"Invalid {name} padding") + + return decoded + + def _load(self, jwt: str | bytes) -> tuple[bytes, bytes, dict[str, Any], bytes]: + if isinstance(jwt, str): + jwt = jwt.encode("utf-8") + + if not isinstance(jwt, bytes): + raise DecodeError(f"Invalid token type. Token must be a {bytes}") + + try: + signing_input, crypto_segment = jwt.rsplit(b".", 1) + header_segment, payload_segment = signing_input.split(b".", 1) + except ValueError as err: + raise DecodeError("Not enough segments") from err + + header_data = self._decode_base64url_segment(header_segment, "header") + + try: + header: dict[str, Any] = json.loads(header_data) + except (ValueError, RecursionError) as e: + raise DecodeError(f"Invalid header string: {e}") from e + + if not isinstance(header, dict): + raise DecodeError("Invalid header string: must be a json object") + + if header.get("b64", True) is False: + # Detached payload form (RFC 7515 Appendix F): the compact-form + # payload segment must be empty; the caller supplies the actual + # payload via the `detached_payload` argument in decode_complete. + # Skipping the base64 decode here removes an unauthenticated work + # amplifier — otherwise an attacker can inflate the unused + # segment to force CPU + memory cost before the signature is + # even checked. + if payload_segment: + raise DecodeError("Payload segment must be empty when 'b64' is false.") + payload = b"" + else: + payload = self._decode_base64url_segment(payload_segment, "payload") + + signature = self._decode_base64url_segment(crypto_segment, "crypto") + + return (payload, signing_input, header, signature) + + def _verify_signature( + self, + signing_input: bytes, + header: dict[str, Any], + signature: bytes, + key: AllowedPublicKeys | PyJWK | str | bytes = "", + algorithms: Sequence[str] | None = None, + options: SigOptions | None = None, + ) -> None: + effective_options = options if options is not None else self.options + + if algorithms is None and isinstance(key, PyJWK): + algorithms = [key.algorithm_name] + try: + alg = header["alg"] + except KeyError: + raise InvalidAlgorithmError("Algorithm not specified") from None + + if not alg or (algorithms is not None and alg not in algorithms): + raise InvalidAlgorithmError("The specified alg value is not allowed") + + if isinstance(key, PyJWK): + # The PyJWK has a fixed algorithm bound at construction time. + # Verification must use that algorithm, not whatever the token + # header advertises, otherwise the caller's allow-list check + # above degenerates into a string compare with no behavioural + # effect on which algorithm actually verifies the signature. + if alg != key.algorithm_name: + raise InvalidAlgorithmError( + f"Token algorithm {alg!r} does not match the key's " + f"algorithm {key.algorithm_name!r}" + ) + alg_obj = key.Algorithm + prepared_key = alg_obj.prepare_key(key.key) + else: + try: + alg_obj = self.get_algorithm_by_name(alg) + except NotImplementedError as e: + raise InvalidAlgorithmError("Algorithm not supported") from e + prepared_key = alg_obj.prepare_key(key) + + key_length_msg = alg_obj.check_key_length(prepared_key) + if key_length_msg: + if effective_options.get("enforce_minimum_key_length", False): + raise InvalidKeyError(key_length_msg) + else: + warnings.warn(key_length_msg, InsecureKeyLengthWarning, stacklevel=4) + + if not alg_obj.verify(signing_input, prepared_key, signature): + raise InvalidSignatureError("Signature verification failed") + + # Extensions that PyJWT actually understands and supports + _supported_crit: set[str] = {"b64"} + + def _validate_headers( + self, headers: dict[str, Any], *, encoding: bool = False + ) -> None: + if "kid" in headers: + self._validate_kid(headers["kid"]) + if not encoding and "crit" in headers: + self._validate_crit(headers) + + def _validate_kid(self, kid: Any) -> None: + if not isinstance(kid, str): + raise InvalidTokenError("Key ID header parameter must be a string") + + def _validate_crit(self, headers: dict[str, Any]) -> None: + crit = headers["crit"] + if not isinstance(crit, list) or len(crit) == 0: + raise InvalidTokenError("Invalid 'crit' header: must be a non-empty list") + for ext in crit: + if not isinstance(ext, str): + raise InvalidTokenError("Invalid 'crit' header: values must be strings") + if ext not in self._supported_crit: + raise InvalidTokenError(f"Unsupported critical extension: {ext}") + if ext not in headers: + raise InvalidTokenError( + f"Critical extension '{ext}' is missing from headers" + ) + + +_jws_global_obj = PyJWS() +encode = _jws_global_obj.encode +decode_complete = _jws_global_obj.decode_complete +decode = _jws_global_obj.decode +register_algorithm = _jws_global_obj.register_algorithm +unregister_algorithm = _jws_global_obj.unregister_algorithm +get_algorithm_by_name = _jws_global_obj.get_algorithm_by_name +get_unverified_header = _jws_global_obj.get_unverified_header diff --git a/source/target-vendors/cp312/jwt/api_jwt.py b/source/target-vendors/cp312/jwt/api_jwt.py new file mode 100644 index 0000000..051ed34 --- /dev/null +++ b/source/target-vendors/cp312/jwt/api_jwt.py @@ -0,0 +1,595 @@ +from __future__ import annotations + +import json +import os +import warnings +from calendar import timegm +from collections.abc import Container, Iterable, Sequence +from datetime import datetime, timedelta, timezone +from typing import TYPE_CHECKING, Any, Union, cast + +from .api_jws import PyJWS, _ALGORITHM_UNSET, _jws_global_obj +from .exceptions import ( + DecodeError, + ExpiredSignatureError, + ImmatureSignatureError, + InvalidAudienceError, + InvalidIssuedAtError, + InvalidIssuerError, + InvalidJTIError, + InvalidSubjectError, + MissingRequiredClaimError, +) +from .warnings import RemovedInPyjwt3Warning + +if TYPE_CHECKING or bool(os.getenv("SPHINX_BUILD", "")): + import sys + + if sys.version_info >= (3, 10): + from typing import TypeAlias + else: + # Python 3.9 and lower + from typing_extensions import TypeAlias + + from .algorithms import AllowedPrivateKeys, AllowedPublicKeys + from .api_jwk import PyJWK + from .types import FullOptions, Options, SigOptions + + AllowedPrivateKeyTypes: TypeAlias = Union[AllowedPrivateKeys, PyJWK, str, bytes] + AllowedPublicKeyTypes: TypeAlias = Union[AllowedPublicKeys, PyJWK, str, bytes] + + +class PyJWT: + def __init__(self, options: Options | None = None) -> None: + self.options: FullOptions + self.options = self._get_default_options() + if options is not None: + self.options = self._merge_options(options) + + self._jws = PyJWS(options=self._get_sig_options()) + + @staticmethod + def _get_default_options() -> FullOptions: + return { + "verify_signature": True, + "verify_exp": True, + "verify_nbf": True, + "verify_iat": True, + "verify_aud": True, + "verify_iss": True, + "verify_sub": True, + "verify_jti": True, + "require": [], + "strict_aud": False, + "enforce_minimum_key_length": False, + } + + def _get_sig_options(self) -> SigOptions: + return { + "verify_signature": self.options["verify_signature"], + "enforce_minimum_key_length": self.options.get( + "enforce_minimum_key_length", False + ), + } + + def _merge_options(self, options: Options | None = None) -> FullOptions: + if options is None: + return self.options + + merged_options = cast("Options", dict(options)) + + # (defensive) set defaults for verify_x to False if verify_signature is False + if not merged_options.get("verify_signature", True): + merged_options["verify_exp"] = merged_options.get("verify_exp", False) + merged_options["verify_nbf"] = merged_options.get("verify_nbf", False) + merged_options["verify_iat"] = merged_options.get("verify_iat", False) + merged_options["verify_aud"] = merged_options.get("verify_aud", False) + merged_options["verify_iss"] = merged_options.get("verify_iss", False) + merged_options["verify_sub"] = merged_options.get("verify_sub", False) + merged_options["verify_jti"] = merged_options.get("verify_jti", False) + return {**self.options, **merged_options} + + def encode( + self, + payload: dict[str, Any], + key: AllowedPrivateKeyTypes, + algorithm: str | None = _ALGORITHM_UNSET, # type: ignore[assignment] + headers: dict[str, Any] | None = None, + json_encoder: type[json.JSONEncoder] | None = None, + sort_headers: bool = True, + ) -> str: + """Encode the ``payload`` as JSON Web Token. + + :param payload: JWT claims, e.g. ``dict(iss=..., aud=..., sub=...)`` + :type payload: dict[str, typing.Any] + :param key: a key suitable for the chosen algorithm: + + * for **asymmetric algorithms**: PEM-formatted private key, a multiline string + * for **symmetric algorithms**: plain string, sufficiently long for security + + :type key: str or bytes or PyJWK or :py:class:`jwt.algorithms.AllowedPrivateKeys` + :param algorithm: algorithm to sign the token with, e.g. ``"ES256"``. + If ``headers`` includes ``alg``, it will be preferred to this parameter. + If ``key`` is a :class:`PyJWK` object, by default the key algorithm will be used. + :type algorithm: str or None + :param headers: additional JWT header fields, e.g. ``dict(kid="my-key-id")``. + :type headers: dict[str, typing.Any] or None + :param json_encoder: custom JSON encoder for ``payload`` and ``headers`` + :type json_encoder: json.JSONEncoder or None + + :rtype: str + :returns: a JSON Web Token + + :raises TypeError: if ``payload`` is not a ``dict`` + """ + # Check that we get a dict + if not isinstance(payload, dict): + raise TypeError( + "Expecting a dict object, as JWT only supports " + "JSON objects as payloads." + ) + + # Payload + payload = payload.copy() + for time_claim in ["exp", "iat", "nbf"]: + # Convert datetime to a intDate value in known time-format claims + if isinstance(payload.get(time_claim), datetime): + payload[time_claim] = timegm(payload[time_claim].utctimetuple()) + + # Issue #1039, iss being set to non-string + if "iss" in payload and not isinstance(payload["iss"], str): + raise TypeError("Issuer (iss) must be a string.") + + json_payload = self._encode_payload( + payload, + headers=headers, + json_encoder=json_encoder, + ) + + return self._jws.encode( + json_payload, + key, + algorithm, + headers, + json_encoder, + sort_headers=sort_headers, + ) + + def _encode_payload( + self, + payload: dict[str, Any], + headers: dict[str, Any] | None = None, + json_encoder: type[json.JSONEncoder] | None = None, + ) -> bytes: + """ + Encode a given payload to the bytes to be signed. + + This method is intended to be overridden by subclasses that need to + encode the payload in a different way, e.g. compress the payload. + """ + return json.dumps( + payload, + separators=(",", ":"), + cls=json_encoder, + ).encode("utf-8") + + def decode_complete( + self, + jwt: str | bytes, + key: AllowedPublicKeyTypes = "", + algorithms: Sequence[str] | None = None, + options: Options | None = None, + # deprecated arg, remove in pyjwt3 + verify: bool | None = None, + # could be used as passthrough to api_jws, consider removal in pyjwt3 + detached_payload: bytes | None = None, + # passthrough arguments to _validate_claims + # consider putting in options + audience: str | Iterable[str] | None = None, + issuer: str | Container[str] | None = None, + subject: str | None = None, + leeway: float | timedelta = 0, + # kwargs + **kwargs: Any, + ) -> dict[str, Any]: + """Identical to ``jwt.decode`` except for return value which is a dictionary containing the token header (JOSE Header), + the token payload (JWT Payload), and token signature (JWT Signature) on the keys "header", "payload", + and "signature" respectively. + + :param jwt: the token to be decoded + :type jwt: str or bytes + :param key: the key suitable for the allowed algorithm + :type key: str or bytes or PyJWK or :py:class:`jwt.algorithms.AllowedPublicKeys` + + :param algorithms: allowed algorithms, e.g. ``["ES256"]`` + + .. warning:: + + Do **not** compute the ``algorithms`` parameter based on + the ``alg`` from the token itself, or on any other data + that an attacker may be able to influence, as that might + expose you to various vulnerabilities (see `RFC 8725 §2.1 + `_). Instead, + either hard-code a fixed value for ``algorithms``, or + configure it in the same place you configure the + ``key``. Make sure not to mix symmetric and asymmetric + algorithms that interpret the ``key`` in different ways + (e.g. HS\\* and RS\\*). + :type algorithms: typing.Sequence[str] or None + + :param jwt.types.Options options: extended decoding and validation options + Refer to :py:class:`jwt.types.Options` for more information. + + :param audience: optional, the value for ``verify_aud`` check + :type audience: str or typing.Iterable[str] or None + :param issuer: optional, the value for ``verify_iss`` check + :type issuer: str or typing.Container[str] or None + :param leeway: a time margin in seconds for the expiration check + :type leeway: float or datetime.timedelta + :rtype: dict[str, typing.Any] + :returns: Decoded JWT with the JOSE Header on the key ``header``, the JWS + Payload on the key ``payload``, and the JWS Signature on the key ``signature``. + """ + if kwargs: + warnings.warn( + "passing additional kwargs to decode_complete() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + stacklevel=2, + ) + + if options is None: + verify_signature = True + else: + verify_signature = options.get("verify_signature", True) + + # If the user has set the legacy `verify` argument, and it doesn't match + # what the relevant `options` entry for the argument is, inform the user + # that they're likely making a mistake. + if verify is not None and verify != verify_signature: + warnings.warn( + "The `verify` argument to `decode` does nothing in PyJWT 2.0 and newer. " + "The equivalent is setting `verify_signature` to False in the `options` dictionary. " + "This invocation has a mismatch between the kwarg and the option entry.", + category=DeprecationWarning, + stacklevel=2, + ) + + merged_options = self._merge_options(options) + + sig_options: SigOptions = { + "verify_signature": verify_signature, + "enforce_minimum_key_length": merged_options.get( + "enforce_minimum_key_length", False + ), + } + decoded = self._jws.decode_complete( + jwt, + key=key, + algorithms=algorithms, + options=sig_options, + detached_payload=detached_payload, + ) + + payload = self._decode_payload(decoded) + + self._validate_claims( + payload, + merged_options, + audience=audience, + issuer=issuer, + leeway=leeway, + subject=subject, + ) + + decoded["payload"] = payload + return decoded + + def _decode_payload(self, decoded: dict[str, Any]) -> dict[str, Any]: + """ + Decode the payload from a JWS dictionary (payload, signature, header). + + This method is intended to be overridden by subclasses that need to + decode the payload in a different way, e.g. decompress compressed + payloads. + """ + try: + payload: dict[str, Any] = json.loads(decoded["payload"]) + except ValueError as e: + raise DecodeError(f"Invalid payload string: {e}") from e + if not isinstance(payload, dict): + raise DecodeError("Invalid payload string: must be a json object") + return payload + + def decode( + self, + jwt: str | bytes, + key: AllowedPublicKeys | PyJWK | str | bytes = "", + algorithms: Sequence[str] | None = None, + options: Options | None = None, + # deprecated arg, remove in pyjwt3 + verify: bool | None = None, + # could be used as passthrough to api_jws, consider removal in pyjwt3 + detached_payload: bytes | None = None, + # passthrough arguments to _validate_claims + # consider putting in options + audience: str | Iterable[str] | None = None, + subject: str | None = None, + issuer: str | Container[str] | None = None, + leeway: float | timedelta = 0, + # kwargs + **kwargs: Any, + ) -> dict[str, Any]: + """Verify the ``jwt`` token signature and return the token claims. + + :param jwt: the token to be decoded + :type jwt: str or bytes + :param key: the key suitable for the allowed algorithm + :type key: str or bytes or PyJWK or :py:class:`jwt.algorithms.AllowedPublicKeys` + + :param algorithms: allowed algorithms, e.g. ``["ES256"]`` + If ``key`` is a :class:`PyJWK` object, allowed algorithms will default to the key algorithm. + + .. warning:: + + Do **not** compute the ``algorithms`` parameter based on + the ``alg`` from the token itself, or on any other data + that an attacker may be able to influence, as that might + expose you to various vulnerabilities (see `RFC 8725 §2.1 + `_). Instead, + either hard-code a fixed value for ``algorithms``, or + configure it in the same place you configure the + ``key``. Make sure not to mix symmetric and asymmetric + algorithms that interpret the ``key`` in different ways + (e.g. HS\\* and RS\\*). + :type algorithms: typing.Sequence[str] or None + + :param jwt.types.Options options: extended decoding and validation options + Refer to :py:class:`jwt.types.Options` for more information. + + :param audience: optional, the value for ``verify_aud`` check + :type audience: str or typing.Iterable[str] or None + :param subject: optional, the value for ``verify_sub`` check + :type subject: str or None + :param issuer: optional, the value for ``verify_iss`` check + :type issuer: str or typing.Container[str] or None + :param leeway: a time margin in seconds for the expiration check + :type leeway: float or datetime.timedelta + :rtype: dict[str, typing.Any] + :returns: the JWT claims + """ + if kwargs: + warnings.warn( + "passing additional kwargs to decode() is deprecated " + "and will be removed in pyjwt version 3. " + f"Unsupported kwargs: {tuple(kwargs.keys())}", + RemovedInPyjwt3Warning, + stacklevel=2, + ) + decoded = self.decode_complete( + jwt, + key, + algorithms, + options, + verify=verify, + detached_payload=detached_payload, + audience=audience, + subject=subject, + issuer=issuer, + leeway=leeway, + ) + return cast(dict[str, Any], decoded["payload"]) + + def _validate_claims( + self, + payload: dict[str, Any], + options: FullOptions, + audience: Iterable[str] | str | None = None, + issuer: Container[str] | str | None = None, + subject: str | None = None, + leeway: float | timedelta = 0, + ) -> None: + if isinstance(leeway, timedelta): + leeway = leeway.total_seconds() + + if audience is not None and not isinstance(audience, (str, Iterable)): + raise TypeError("audience must be a string, iterable or None") + + self._validate_required_claims(payload, options["require"]) + + now = datetime.now(tz=timezone.utc).timestamp() + + if "iat" in payload and options["verify_iat"]: + self._validate_iat(payload, now, leeway) + + if "nbf" in payload and options["verify_nbf"]: + self._validate_nbf(payload, now, leeway) + + if "exp" in payload and options["verify_exp"]: + self._validate_exp(payload, now, leeway) + + if options["verify_iss"]: + self._validate_iss(payload, issuer) + + if options["verify_aud"]: + self._validate_aud( + payload, audience, strict=options.get("strict_aud", False) + ) + + if options["verify_sub"]: + self._validate_sub(payload, subject) + + if options["verify_jti"]: + self._validate_jti(payload) + + def _validate_required_claims( + self, + payload: dict[str, Any], + claims: Iterable[str], + ) -> None: + for claim in claims: + if payload.get(claim) is None: + raise MissingRequiredClaimError(claim) + + def _validate_sub( + self, payload: dict[str, Any], subject: str | None = None + ) -> None: + """ + Checks whether "sub" if in the payload is valid or not. + This is an Optional claim + + :param payload(dict): The payload which needs to be validated + :param subject(str): The subject of the token + """ + + if "sub" not in payload: + return + + if not isinstance(payload["sub"], str): + raise InvalidSubjectError("Subject must be a string") + + if subject is not None: + if payload.get("sub") != subject: + raise InvalidSubjectError("Invalid subject") + + def _validate_jti(self, payload: dict[str, Any]) -> None: + """ + Checks whether "jti" if in the payload is valid or not + This is an Optional claim + + :param payload(dict): The payload which needs to be validated + """ + + if "jti" not in payload: + return + + if not isinstance(payload.get("jti"), str): + raise InvalidJTIError("JWT ID must be a string") + + def _validate_iat( + self, + payload: dict[str, Any], + now: float, + leeway: float, + ) -> None: + try: + iat = int(payload["iat"]) + except ValueError: + raise InvalidIssuedAtError( + "Issued At claim (iat) must be an integer." + ) from None + if iat > (now + leeway): + raise ImmatureSignatureError("The token is not yet valid (iat)") + + def _validate_nbf( + self, + payload: dict[str, Any], + now: float, + leeway: float, + ) -> None: + try: + nbf = int(payload["nbf"]) + except ValueError: + raise DecodeError("Not Before claim (nbf) must be an integer.") from None + + if nbf > (now + leeway): + raise ImmatureSignatureError("The token is not yet valid (nbf)") + + def _validate_exp( + self, + payload: dict[str, Any], + now: float, + leeway: float, + ) -> None: + try: + exp = int(payload["exp"]) + except ValueError: + raise DecodeError( + "Expiration Time claim (exp) must be an integer." + ) from None + + if exp <= (now - leeway): + raise ExpiredSignatureError("Signature has expired") + + def _validate_aud( + self, + payload: dict[str, Any], + audience: str | Iterable[str] | None, + *, + strict: bool = False, + ) -> None: + if audience is None: + if "aud" not in payload or not payload["aud"]: + return + # Application did not specify an audience, but + # the token has the 'aud' claim + raise InvalidAudienceError("Invalid audience") + + if "aud" not in payload or not payload["aud"]: + # Application specified an audience, but it could not be + # verified since the token does not contain a claim. + raise MissingRequiredClaimError("aud") + + audience_claims = payload["aud"] + + # In strict mode, we forbid list matching: the supplied audience + # must be a string, and it must exactly match the audience claim. + if strict: + # Only a single audience is allowed in strict mode. + if not isinstance(audience, str): + raise InvalidAudienceError("Invalid audience (strict)") + + # Only a single audience claim is allowed in strict mode. + if not isinstance(audience_claims, str): + raise InvalidAudienceError("Invalid claim format in token (strict)") + + if audience != audience_claims: + raise InvalidAudienceError("Audience doesn't match (strict)") + + return + + if isinstance(audience_claims, str): + audience_claims = [audience_claims] + if not isinstance(audience_claims, list): + raise InvalidAudienceError("Invalid claim format in token") + if any(not isinstance(c, str) for c in audience_claims): + raise InvalidAudienceError("Invalid claim format in token") + + if isinstance(audience, str): + audience = [audience] + + if all(aud not in audience_claims for aud in audience): + raise InvalidAudienceError("Audience doesn't match") + + def _validate_iss( + self, payload: dict[str, Any], issuer: Container[str] | str | None + ) -> None: + if issuer is None: + return + + if "iss" not in payload: + raise MissingRequiredClaimError("iss") + + iss = payload["iss"] + if not isinstance(iss, str): + raise InvalidIssuerError("Payload Issuer (iss) must be a string") + + if isinstance(issuer, str): + if iss != issuer: + raise InvalidIssuerError("Invalid issuer") + else: + try: + if iss not in issuer: + raise InvalidIssuerError("Invalid issuer") + except TypeError: + raise InvalidIssuerError( + 'Issuer param must be "str" or "Container[str]"' + ) from None + + +_jwt_global_obj = PyJWT() +_jwt_global_obj._jws = _jws_global_obj +encode = _jwt_global_obj.encode +decode_complete = _jwt_global_obj.decode_complete +decode = _jwt_global_obj.decode diff --git a/source/target-vendors/cp312/jwt/exceptions.py b/source/target-vendors/cp312/jwt/exceptions.py new file mode 100644 index 0000000..57559fc --- /dev/null +++ b/source/target-vendors/cp312/jwt/exceptions.py @@ -0,0 +1,113 @@ +class PyJWTError(Exception): + """ + Base class for all exceptions + """ + + pass + + +class InvalidTokenError(PyJWTError): + """Base exception when ``decode()`` fails on a token""" + + pass + + +class DecodeError(InvalidTokenError): + """Raised when a token cannot be decoded because it failed validation""" + + pass + + +class InvalidSignatureError(DecodeError): + """Raised when a token's signature doesn't match the one provided as part of + the token.""" + + pass + + +class ExpiredSignatureError(InvalidTokenError): + """Raised when a token's ``exp`` claim indicates that it has expired""" + + pass + + +class InvalidAudienceError(InvalidTokenError): + """Raised when a token's ``aud`` claim does not match one of the expected + audience values""" + + pass + + +class InvalidIssuerError(InvalidTokenError): + """Raised when a token's ``iss`` claim does not match the expected issuer""" + + pass + + +class InvalidIssuedAtError(InvalidTokenError): + """Raised when a token's ``iat`` claim is non-numeric""" + + pass + + +class ImmatureSignatureError(InvalidTokenError): + """Raised when a token's ``nbf`` or ``iat`` claims represent a time in the future""" + + pass + + +class InvalidKeyError(PyJWTError): + """Raised when the specified key is not in the proper format""" + + pass + + +class InvalidAlgorithmError(InvalidTokenError): + """Raised when the specified algorithm is not recognized by PyJWT""" + + pass + + +class MissingRequiredClaimError(InvalidTokenError): + """Raised when a claim that is required to be present is not contained + in the claimset""" + + def __init__(self, claim: str) -> None: + self.claim = claim + + def __str__(self) -> str: + return f'Token is missing the "{self.claim}" claim' + + +class PyJWKError(PyJWTError): + pass + + +class MissingCryptographyError(PyJWKError): + """Raised if the algorithm requires ``cryptography`` to be installed and it is not available.""" + + pass + + +class PyJWKSetError(PyJWTError): + pass + + +class PyJWKClientError(PyJWTError): + pass + + +class PyJWKClientConnectionError(PyJWKClientError): + pass + + +class InvalidSubjectError(InvalidTokenError): + """Raised when a token's ``sub`` claim is not a string or doesn't match the expected ``subject``""" + + pass + + +class InvalidJTIError(InvalidTokenError): + """Raised when a token's ``jti`` claim is not a string""" + + pass diff --git a/source/target-vendors/cp312/jwt/help.py b/source/target-vendors/cp312/jwt/help.py new file mode 100644 index 0000000..2f42b5d --- /dev/null +++ b/source/target-vendors/cp312/jwt/help.py @@ -0,0 +1,66 @@ +import json +import platform +import sys + +from . import __version__ as pyjwt_version + +try: + import cryptography + + cryptography_version = cryptography.__version__ +except ModuleNotFoundError: + cryptography_version = "" + + +def info() -> dict[str, dict[str, str]]: + """ + Generate information for a bug report. + Based on the requests package help utility module. + """ + try: + platform_info = { + "system": platform.system(), + "release": platform.release(), + } + except OSError: + platform_info = {"system": "Unknown", "release": "Unknown"} + + implementation = platform.python_implementation() + + if implementation == "CPython": + implementation_version = platform.python_version() + elif implementation == "PyPy": + pypy_version_info = sys.pypy_version_info # type: ignore[attr-defined] + implementation_version = ( + f"{pypy_version_info.major}." + f"{pypy_version_info.minor}." + f"{pypy_version_info.micro}" + ) + if pypy_version_info.releaselevel != "final": + implementation_version = "".join( + [ + implementation_version, + pypy_version_info.releaselevel, + ] + ) + else: + implementation_version = "Unknown" + + return { + "platform": platform_info, + "implementation": { + "name": implementation, + "version": implementation_version, + }, + "cryptography": {"version": cryptography_version}, + "pyjwt": {"version": pyjwt_version}, + } + + +def main() -> None: + """Pretty-print the bug information as JSON.""" + print(json.dumps(info(), sort_keys=True, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/source/target-vendors/cp312/jwt/jwk_set_cache.py b/source/target-vendors/cp312/jwt/jwk_set_cache.py new file mode 100644 index 0000000..f3f3ca5 --- /dev/null +++ b/source/target-vendors/cp312/jwt/jwk_set_cache.py @@ -0,0 +1,31 @@ +import time +from typing import Optional + +from .api_jwk import PyJWKSet, PyJWTSetWithTimestamp + + +class JWKSetCache: + def __init__(self, lifespan: float) -> None: + self.jwk_set_with_timestamp: Optional[PyJWTSetWithTimestamp] = None + self.lifespan = lifespan + + def put(self, jwk_set: PyJWKSet) -> None: + if jwk_set is not None: + self.jwk_set_with_timestamp = PyJWTSetWithTimestamp(jwk_set) + else: + # clear cache + self.jwk_set_with_timestamp = None + + def get(self) -> Optional[PyJWKSet]: + if self.jwk_set_with_timestamp is None or self.is_expired(): + return None + + return self.jwk_set_with_timestamp.get_jwk_set() + + def is_expired(self) -> bool: + return ( + self.jwk_set_with_timestamp is not None + and self.lifespan > -1 + and time.monotonic() + > self.jwk_set_with_timestamp.get_timestamp() + self.lifespan + ) diff --git a/source/target-vendors/cp312/jwt/jwks_client.py b/source/target-vendors/cp312/jwt/jwks_client.py new file mode 100644 index 0000000..4ef34ce --- /dev/null +++ b/source/target-vendors/cp312/jwt/jwks_client.py @@ -0,0 +1,302 @@ +from __future__ import annotations + +import json +import math +import threading +import time +import urllib.request +from functools import lru_cache +from ssl import SSLContext +from typing import Any +from urllib.error import HTTPError, URLError +from urllib.parse import urlparse + +from .api_jwk import PyJWK, PyJWKSet +from .api_jwt import decode_complete as decode_token +from .exceptions import PyJWKClientConnectionError, PyJWKClientError +from .jwk_set_cache import JWKSetCache + + +class _NoRedirectHandler(urllib.request.HTTPRedirectHandler): + def redirect_request( + self, + req: urllib.request.Request, + fp: Any, + code: int, + msg: str, + headers: Any, + newurl: str, + ) -> urllib.request.Request | None: + return None + + +class PyJWKClient: + def __init__( + self, + uri: str, + cache_keys: bool = False, + max_cached_keys: int = 16, + cache_jwk_set: bool = True, + lifespan: float = 300, + headers: dict[str, Any] | None = None, + timeout: float = 30, + ssl_context: SSLContext | None = None, + cooldown_duration: float = 30, + ): + """A client for retrieving signing keys from a JWKS endpoint. + + ``PyJWKClient`` uses a two-tier caching system to avoid unnecessary + network requests: + + **Tier 1 — JWK Set cache** (enabled by default): + Caches the entire JSON Web Key Set response from the endpoint. + Controlled by: + + - ``cache_jwk_set``: Set to ``True`` (the default) to enable this + cache. When enabled, the JWK Set is fetched from the network only + when the cache is empty or expired. + - ``lifespan``: Time in seconds before the cached JWK Set expires. + Defaults to ``300`` (5 minutes). Must be greater than 0. + + Unknown key IDs can trigger one forced refresh after the cooldown + period configured by ``cooldown_duration``. Every successful fetch + starts this cooldown, including the initial fetch and cache-expiry + fetches. A newly rotated key may therefore wait for the cooldown + period before it is fetched; set ``cooldown_duration`` to ``0`` to + disable this behavior. The cooldown is bypassed when + ``cache_jwk_set`` is ``False``. + + **Tier 2 — Signing key cache** (disabled by default): + Caches individual signing keys (looked up by ``kid``) using an LRU + cache with **no time-based expiration**. Keys are evicted only when + the cache reaches its maximum size. Controlled by: + + - ``cache_keys``: Set to ``True`` to enable this cache. + Defaults to ``False``. + - ``max_cached_keys``: Maximum number of signing keys to keep in + the LRU cache. Defaults to ``16``. + + :param uri: The URL of the JWKS endpoint. + :type uri: str + :param cache_keys: Enable the per-key LRU cache (Tier 2). + :type cache_keys: bool + :param max_cached_keys: Max entries in the signing key LRU cache. + :type max_cached_keys: int + :param cache_jwk_set: Enable the JWK Set response cache (Tier 1). + :type cache_jwk_set: bool + :param lifespan: TTL in seconds for the JWK Set cache. + :type lifespan: float + :param headers: Optional HTTP headers to include in requests. + :type headers: dict or None + :param timeout: HTTP request timeout in seconds. + :type timeout: float + :param ssl_context: Optional SSL context for the request. + :type ssl_context: ssl.SSLContext or None + :param cooldown_duration: Minimum time in seconds between forced + refreshes after an unknown key ID. Defaults to ``30``. + :type cooldown_duration: float + """ + if headers is None: + headers = {} + # urllib's default OpenerDirector also handles file://, ftp://, and + # data: URIs. Reject anything that isn't http(s) eagerly so a caller + # passing an attacker-influenced URL (e.g. taken from a `jku` token + # header) can't read local files or reach other unintended schemes. + scheme = urlparse(uri).scheme.lower() + if scheme not in ("http", "https"): + raise PyJWKClientError( + f"Invalid JWKS URI scheme {scheme!r}: only 'http' and 'https' " + f"are supported." + ) + self.uri = uri + self.jwk_set_cache: JWKSetCache | None = None + self.headers = headers + self.timeout = timeout + self.ssl_context = ssl_context + if cooldown_duration < 0: + raise PyJWKClientError( + "Cooldown duration must be greater than or equal to 0, " + f'the input is "{cooldown_duration}"' + ) + if not math.isfinite(cooldown_duration): + raise PyJWKClientError( + f'Cooldown duration must be finite, the input is "{cooldown_duration}"' + ) + self.cooldown_duration = cooldown_duration + self._last_successful_fetch: float | None = None + self._client_lock = threading.RLock() + + if cache_jwk_set: + # Init jwt set cache with default or given lifespan. + # Default lifespan is 300 seconds (5 minutes). + if lifespan <= 0: + raise PyJWKClientError( + f'Lifespan must be greater than 0, the input is "{lifespan}"' + ) + self.jwk_set_cache = JWKSetCache(lifespan) + else: + self.jwk_set_cache = None + + if cache_keys: + # Cache signing keys + get_signing_key = lru_cache(maxsize=max_cached_keys)(self.get_signing_key) + # Ignore mypy (https://github.com/python/mypy/issues/2427) + self.get_signing_key = get_signing_key # type: ignore[method-assign] + + def fetch_data(self) -> Any: + """Fetch the JWK Set from the JWKS endpoint. + + Makes an HTTP request to the configured ``uri`` and returns the + parsed JSON response. If the JWK Set cache is enabled, the + response is stored in the cache. + + :returns: The parsed JWK Set as a dictionary. + :raises PyJWKClientConnectionError: If the HTTP request fails. + """ + try: + r = urllib.request.Request(url=self.uri, headers=self.headers) + handlers: list[Any] = [_NoRedirectHandler()] + if self.ssl_context is not None: + handlers.append(urllib.request.HTTPSHandler(context=self.ssl_context)) + opener = urllib.request.build_opener(*handlers) + with opener.open(r, timeout=self.timeout) as response: + jwk_set = json.load(response) + except (URLError, TimeoutError) as e: + if isinstance(e, HTTPError): + e.close() + raise PyJWKClientConnectionError( + f'Fail to fetch data from the url, err: "{e}"' + ) from e + + # Only update the cache on a successful fetch. Writing in a + # `finally` block with `jwk_set=None` on error clears any + # previously-cached JWKS, turning a transient outage into a cache + # wipe that breaks legitimate auth. + if self.jwk_set_cache is not None: + self.jwk_set_cache.put(jwk_set) + self._last_successful_fetch = time.monotonic() + return jwk_set + + def get_jwk_set(self, refresh: bool = False) -> PyJWKSet: + """Return the JWK Set, using the cache when available. + + :param refresh: Force a fresh fetch from the endpoint, bypassing + the cache. + :type refresh: bool + :returns: The JWK Set. + :rtype: PyJWKSet + :raises PyJWKClientError: If the endpoint does not return a JSON + object. + """ + data = None + if self.jwk_set_cache is not None and not refresh: + data = self.jwk_set_cache.get() + + if data is None: + data = self.fetch_data() + + if not isinstance(data, dict): + raise PyJWKClientError("The JWKS endpoint did not return a JSON object") + + return PyJWKSet.from_dict(data) + + def get_signing_keys(self, refresh: bool = False) -> list[PyJWK]: + """Return all signing keys from the JWK Set. + + Filters the JWK Set to keys whose ``use`` is ``"sig"`` (or + unspecified) and that have a ``kid``. + + :param refresh: Force a fresh fetch from the endpoint, bypassing + the cache. + :type refresh: bool + :returns: A list of signing keys. + :rtype: list[PyJWK] + :raises PyJWKClientError: If no signing keys are found. + """ + jwk_set = self.get_jwk_set(refresh) + return self._get_signing_keys_from_jwk_set(jwk_set) + + @staticmethod + def _get_signing_keys_from_jwk_set(jwk_set: PyJWKSet) -> list[PyJWK]: + signing_keys = [ + jwk_set_key + for jwk_set_key in jwk_set.keys + if jwk_set_key.public_key_use in ["sig", None] and jwk_set_key.key_id + ] + + if not signing_keys: + raise PyJWKClientError("The JWKS endpoint did not contain any signing keys") + + return signing_keys + + def get_signing_key(self, kid: str) -> PyJWK: + """Return the signing key matching the given ``kid``. + + If no match is found in the current JWK Set, the set is refreshed + from the endpoint and the lookup is retried once when the refresh + cooldown permits it. + + :param kid: The key ID to look up. + :type kid: str + :returns: The matching signing key. + :rtype: PyJWK + :raises PyJWKClientError: If no matching key is found after + refreshing. + """ + with self._client_lock: + signing_keys = self.get_signing_keys() + signing_key = self.match_kid(signing_keys, kid) + + if not signing_key: + cooling_down = ( + self.jwk_set_cache is not None + and self._last_successful_fetch is not None + and time.monotonic() - self._last_successful_fetch + < self.cooldown_duration + ) + if not cooling_down: + signing_keys = self.get_signing_keys(refresh=True) + self._last_successful_fetch = time.monotonic() + signing_key = self.match_kid(signing_keys, kid) + + if not signing_key: + raise PyJWKClientError( + f'Unable to find a signing key that matches: "{kid}"' + ) + + return signing_key + + def get_signing_key_from_jwt(self, token: str | bytes) -> PyJWK: + """Return the signing key for a JWT by reading its ``kid`` header. + + Extracts the ``kid`` from the token's unverified header and + delegates to :meth:`get_signing_key`. + + :param token: The encoded JWT. + :type token: str or bytes + :returns: The matching signing key. + :rtype: PyJWK + """ + unverified = decode_token(token, options={"verify_signature": False}) + header = unverified["header"] + return self.get_signing_key(header.get("kid")) + + @staticmethod + def match_kid(signing_keys: list[PyJWK], kid: str) -> PyJWK | None: + """Find a key in *signing_keys* that matches *kid*. + + :param signing_keys: The list of keys to search. + :type signing_keys: list[PyJWK] + :param kid: The key ID to match. + :type kid: str + :returns: The matching key, or ``None`` if not found. + :rtype: PyJWK or None + """ + signing_key = None + + for key in signing_keys: + if key.key_id == kid: + signing_key = key + break + + return signing_key diff --git a/source/target-vendors/cp312/jwt/py.typed b/source/target-vendors/cp312/jwt/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/jwt/types.py b/source/target-vendors/cp312/jwt/types.py new file mode 100644 index 0000000..61bfdf0 --- /dev/null +++ b/source/target-vendors/cp312/jwt/types.py @@ -0,0 +1,69 @@ +from typing import Any, Callable, TypedDict + +JWKDict = dict[str, Any] + +HashlibHash = Callable[..., Any] + + +class SigOptions(TypedDict, total=False): + """Options for PyJWS class (TypedDict). Note that this is a smaller set of options than + for :py:func:`jwt.decode()`.""" + + verify_signature: bool + """verify the JWT cryptographic signature""" + enforce_minimum_key_length: bool + """Default: ``False``. Raise :py:class:`jwt.exceptions.InvalidKeyError` instead of warning when keys are below minimum recommended length.""" + + +class Options(TypedDict, total=False): + """Options for :py:func:`jwt.decode()` and :py:func:`jwt.decode_complete()` (TypedDict). + + .. warning:: + + Some claims, such as ``exp``, ``iat``, ``jti``, ``nbf``, and ``sub``, + will only be verified if present. Please refer to the documentation below + for which ones, and make sure to include them in the ``require`` param + if you want to make sure that they are always present (and therefore always verified + if ``verify_{claim} = True`` for that claim). + """ + + verify_signature: bool + """Default: ``True``. Verify the JWT cryptographic signature.""" + require: list[str] + """Default: ``[]``. List of claims that must be present. + Example: ``require=["exp", "iat", "nbf"]``. + **Only verifies that the claims exists**. Does not verify that the claims are valid.""" + strict_aud: bool + """Default: ``False``. (requires ``verify_aud=True``) Check that the ``aud`` claim is a single value (not a list), and matches ``audience`` exactly.""" + verify_aud: bool + """Default: ``verify_signature``. Check that ``aud`` (audience) claim matches ``audience``.""" + verify_exp: bool + """Default: ``verify_signature``. Check that ``exp`` (expiration) claim value is in the future (if present in payload). """ + verify_iat: bool + """Default: ``verify_signature``. Check that ``iat`` (issued at) claim value is an integer (if present in payload). """ + verify_iss: bool + """Default: ``verify_signature``. Check that ``iss`` (issuer) claim matches ``issuer``. """ + verify_jti: bool + """Default: ``verify_signature``. Check that ``jti`` (JWT ID) claim is a string (if present in payload). """ + verify_nbf: bool + """Default: ``verify_signature``. Check that ``nbf`` (not before) claim value is in the past (if present in payload). """ + verify_sub: bool + """Default: ``verify_signature``. Check that ``sub`` (subject) claim is a string and matches ``subject`` (if present in payload). """ + enforce_minimum_key_length: bool + """Default: ``False``. Raise :py:class:`jwt.exceptions.InvalidKeyError` instead of warning when keys are below minimum recommended length.""" + + +# The only difference between Options and FullOptions is that FullOptions +# required _every_ value to be there; Options doesn't require any +class FullOptions(TypedDict): + verify_signature: bool + require: list[str] + strict_aud: bool + verify_aud: bool + verify_exp: bool + verify_iat: bool + verify_iss: bool + verify_jti: bool + verify_nbf: bool + verify_sub: bool + enforce_minimum_key_length: bool diff --git a/source/target-vendors/cp312/jwt/utils.py b/source/target-vendors/cp312/jwt/utils.py new file mode 100644 index 0000000..914cb50 --- /dev/null +++ b/source/target-vendors/cp312/jwt/utils.py @@ -0,0 +1,146 @@ +import base64 +import binascii +import re +from typing import Optional, Union + +try: + from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurve + from cryptography.hazmat.primitives.asymmetric.utils import ( + decode_dss_signature, + encode_dss_signature, + ) +except ModuleNotFoundError: + pass + + +def force_bytes(value: Union[bytes, str]) -> bytes: + if isinstance(value, str): + return value.encode("utf-8") + elif isinstance(value, bytes): + return value + else: + raise TypeError("Expected a string value") + + +def base64url_decode(input: Union[bytes, str]) -> bytes: + input_bytes = force_bytes(input) + + rem = len(input_bytes) % 4 + + if rem > 0: + input_bytes += b"=" * (4 - rem) + + return base64.urlsafe_b64decode(input_bytes) + + +def base64url_encode(input: bytes) -> bytes: + return base64.urlsafe_b64encode(input).replace(b"=", b"") + + +def to_base64url_uint(val: int, *, bit_length: Optional[int] = None) -> bytes: + if val < 0: + raise ValueError("Must be a positive integer") + + int_bytes = bytes_from_int(val, bit_length=bit_length) + + if len(int_bytes) == 0: + int_bytes = b"\x00" + + return base64url_encode(int_bytes) + + +def from_base64url_uint(val: Union[bytes, str]) -> int: + data = base64url_decode(force_bytes(val)) + return int.from_bytes(data, byteorder="big") + + +def number_to_bytes(num: int, num_bytes: int) -> bytes: + padded_hex = "%0*x" % (2 * num_bytes, num) + return binascii.a2b_hex(padded_hex.encode("ascii")) + + +def bytes_to_number(string: bytes) -> int: + return int(binascii.b2a_hex(string), 16) + + +def bytes_from_int(val: int, *, bit_length: Optional[int] = None) -> bytes: + if bit_length is None: + bit_length = val.bit_length() + byte_length = (bit_length + 7) // 8 + + return val.to_bytes(byte_length, "big", signed=False) + + +def der_to_raw_signature(der_sig: bytes, curve: "EllipticCurve") -> bytes: + num_bits = curve.key_size + num_bytes = (num_bits + 7) // 8 + + r, s = decode_dss_signature(der_sig) + + return number_to_bytes(r, num_bytes) + number_to_bytes(s, num_bytes) + + +def raw_to_der_signature(raw_sig: bytes, curve: "EllipticCurve") -> bytes: + num_bits = curve.key_size + num_bytes = (num_bits + 7) // 8 + + if len(raw_sig) != 2 * num_bytes: + raise ValueError("Invalid signature") + + r = bytes_to_number(raw_sig[:num_bytes]) + s = bytes_to_number(raw_sig[num_bytes:]) + + return bytes(encode_dss_signature(r, s)) + + +# Based on https://github.com/hynek/pem/blob/7ad94db26b0bc21d10953f5dbad3acfdfacf57aa/src/pem/_core.py#L224-L252 +_PEMS = { + b"CERTIFICATE", + b"TRUSTED CERTIFICATE", + b"PRIVATE KEY", + b"PUBLIC KEY", + b"ENCRYPTED PRIVATE KEY", + b"OPENSSH PRIVATE KEY", + b"DSA PRIVATE KEY", + b"RSA PRIVATE KEY", + b"RSA PUBLIC KEY", + b"EC PRIVATE KEY", + b"DH PARAMETERS", + b"NEW CERTIFICATE REQUEST", + b"CERTIFICATE REQUEST", + b"SSH2 PUBLIC KEY", + b"SSH2 ENCRYPTED PRIVATE KEY", + b"X509 CRL", +} + +# Accept PEM formatting variants that the cryptography loader accepts, while +# retaining the explicit asymmetric-key marker check. +_PEM_MARKER_RE = re.compile( + b"(?=(----[- ](BEGIN|END) (" + b"|".join(_PEMS) + b")[- ]----))" +) + + +def is_pem_format(key: bytes) -> bool: + begin_markers: dict[bytes, int] = {} + for marker in _PEM_MARKER_RE.finditer(key): + marker_type, label = marker.group(2), marker.group(3) + if marker_type == b"BEGIN": + begin_markers[label] = marker.start(1) + len(marker.group(1)) + elif label in begin_markers and begin_markers[label] < marker.start(1): + return True + return False + + +# Based on https://github.com/pyca/cryptography/blob/bcb70852d577b3f490f015378c75cba74986297b/src/cryptography/hazmat/primitives/serialization/ssh.py#L40-L46 +_SSH_KEY_FORMATS = ( + b"ssh-ed25519", + b"ssh-rsa", + b"ssh-dss", + b"ecdsa-sha2-nistp256", + b"ecdsa-sha2-nistp384", + b"ecdsa-sha2-nistp521", +) + + +def is_ssh_key(key: bytes) -> bool: + return key.startswith(_SSH_KEY_FORMATS) diff --git a/source/target-vendors/cp312/jwt/warnings.py b/source/target-vendors/cp312/jwt/warnings.py new file mode 100644 index 0000000..8a41a36 --- /dev/null +++ b/source/target-vendors/cp312/jwt/warnings.py @@ -0,0 +1,11 @@ +class RemovedInPyjwt3Warning(DeprecationWarning): + """Warning for features that will be removed in PyJWT 3.""" + + pass + + +class InsecureKeyLengthWarning(UserWarning): + """Warning emitted when a cryptographic key is shorter than the minimum + recommended length. See :ref:`key-length-validation` for details.""" + + pass diff --git a/source/target-vendors/cp312/mcp-1.26.0.dist-info/METADATA b/source/target-vendors/cp312/mcp-1.26.0.dist-info/METADATA new file mode 100644 index 0000000..19afdb6 --- /dev/null +++ b/source/target-vendors/cp312/mcp-1.26.0.dist-info/METADATA @@ -0,0 +1,2606 @@ +Metadata-Version: 2.4 +Name: mcp +Version: 1.26.0 +Summary: Model Context Protocol SDK +Project-URL: Homepage, https://modelcontextprotocol.io +Project-URL: Repository, https://github.com/modelcontextprotocol/python-sdk +Project-URL: Issues, https://github.com/modelcontextprotocol/python-sdk/issues +Author: Anthropic, PBC. +Maintainer-email: David Soria Parra , Justin Spahr-Summers +License: MIT +License-File: LICENSE +Keywords: automation,git,llm,mcp +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Requires-Python: >=3.10 +Requires-Dist: anyio>=4.5 +Requires-Dist: httpx-sse>=0.4 +Requires-Dist: httpx>=0.27.1 +Requires-Dist: jsonschema>=4.20.0 +Requires-Dist: pydantic-settings>=2.5.2 +Requires-Dist: pydantic<3.0.0,>=2.11.0 +Requires-Dist: pyjwt[crypto]>=2.10.1 +Requires-Dist: python-multipart>=0.0.9 +Requires-Dist: pywin32>=310; sys_platform == 'win32' +Requires-Dist: sse-starlette>=1.6.1 +Requires-Dist: starlette>=0.27 +Requires-Dist: typing-extensions>=4.9.0 +Requires-Dist: typing-inspection>=0.4.1 +Requires-Dist: uvicorn>=0.31.1; sys_platform != 'emscripten' +Provides-Extra: cli +Requires-Dist: python-dotenv>=1.0.0; extra == 'cli' +Requires-Dist: typer>=0.16.0; extra == 'cli' +Provides-Extra: rich +Requires-Dist: rich>=13.9.4; extra == 'rich' +Provides-Extra: ws +Requires-Dist: websockets>=15.0.1; extra == 'ws' +Description-Content-Type: text/markdown + +# MCP Python SDK + +
      + +Python implementation of the Model Context Protocol (MCP) + +[![PyPI][pypi-badge]][pypi-url] +[![MIT licensed][mit-badge]][mit-url] +[![Python Version][python-badge]][python-url] +[![Documentation][docs-badge]][docs-url] +[![Protocol][protocol-badge]][protocol-url] +[![Specification][spec-badge]][spec-url] + +
      + + +## Table of Contents + +- [MCP Python SDK](#mcp-python-sdk) + - [Overview](#overview) + - [Installation](#installation) + - [Adding MCP to your python project](#adding-mcp-to-your-python-project) + - [Running the standalone MCP development tools](#running-the-standalone-mcp-development-tools) + - [Quickstart](#quickstart) + - [What is MCP?](#what-is-mcp) + - [Core Concepts](#core-concepts) + - [Server](#server) + - [Resources](#resources) + - [Tools](#tools) + - [Structured Output](#structured-output) + - [Prompts](#prompts) + - [Images](#images) + - [Context](#context) + - [Getting Context in Functions](#getting-context-in-functions) + - [Context Properties and Methods](#context-properties-and-methods) + - [Completions](#completions) + - [Elicitation](#elicitation) + - [Sampling](#sampling) + - [Logging and Notifications](#logging-and-notifications) + - [Authentication](#authentication) + - [FastMCP Properties](#fastmcp-properties) + - [Session Properties and Methods](#session-properties-and-methods) + - [Request Context Properties](#request-context-properties) + - [Running Your Server](#running-your-server) + - [Development Mode](#development-mode) + - [Claude Desktop Integration](#claude-desktop-integration) + - [Direct Execution](#direct-execution) + - [Streamable HTTP Transport](#streamable-http-transport) + - [CORS Configuration for Browser-Based Clients](#cors-configuration-for-browser-based-clients) + - [Mounting to an Existing ASGI Server](#mounting-to-an-existing-asgi-server) + - [StreamableHTTP servers](#streamablehttp-servers) + - [Basic mounting](#basic-mounting) + - [Host-based routing](#host-based-routing) + - [Multiple servers with path configuration](#multiple-servers-with-path-configuration) + - [Path configuration at initialization](#path-configuration-at-initialization) + - [SSE servers](#sse-servers) + - [Advanced Usage](#advanced-usage) + - [Low-Level Server](#low-level-server) + - [Structured Output Support](#structured-output-support) + - [Pagination (Advanced)](#pagination-advanced) + - [Writing MCP Clients](#writing-mcp-clients) + - [Client Display Utilities](#client-display-utilities) + - [OAuth Authentication for Clients](#oauth-authentication-for-clients) + - [Parsing Tool Results](#parsing-tool-results) + - [MCP Primitives](#mcp-primitives) + - [Server Capabilities](#server-capabilities) + - [Documentation](#documentation) + - [Contributing](#contributing) + - [License](#license) + +[pypi-badge]: https://img.shields.io/pypi/v/mcp.svg +[pypi-url]: https://pypi.org/project/mcp/ +[mit-badge]: https://img.shields.io/pypi/l/mcp.svg +[mit-url]: https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE +[python-badge]: https://img.shields.io/pypi/pyversions/mcp.svg +[python-url]: https://www.python.org/downloads/ +[docs-badge]: https://img.shields.io/badge/docs-python--sdk-blue.svg +[docs-url]: https://modelcontextprotocol.github.io/python-sdk/ +[protocol-badge]: https://img.shields.io/badge/protocol-modelcontextprotocol.io-blue.svg +[protocol-url]: https://modelcontextprotocol.io +[spec-badge]: https://img.shields.io/badge/spec-spec.modelcontextprotocol.io-blue.svg +[spec-url]: https://modelcontextprotocol.io/specification/latest + +## Overview + +The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This Python SDK implements the full MCP specification, making it easy to: + +- Build MCP clients that can connect to any MCP server +- Create MCP servers that expose resources, prompts and tools +- Use standard transports like stdio, SSE, and Streamable HTTP +- Handle all MCP protocol messages and lifecycle events + +## Installation + +### Adding MCP to your python project + +We recommend using [uv](https://docs.astral.sh/uv/) to manage your Python projects. + +If you haven't created a uv-managed project yet, create one: + + ```bash + uv init mcp-server-demo + cd mcp-server-demo + ``` + + Then add MCP to your project dependencies: + + ```bash + uv add "mcp[cli]" + ``` + +Alternatively, for projects using pip for dependencies: + +```bash +pip install "mcp[cli]" +``` + +### Running the standalone MCP development tools + +To run the mcp command with uv: + +```bash +uv run mcp +``` + +## Quickstart + +Let's create a simple MCP server that exposes a calculator tool and some data: + + +```python +""" +FastMCP quickstart example. + +Run from the repository root: + uv run examples/snippets/servers/fastmcp_quickstart.py +""" + +from mcp.server.fastmcp import FastMCP + +# Create an MCP server +mcp = FastMCP("Demo", json_response=True) + + +# Add an addition tool +@mcp.tool() +def add(a: int, b: int) -> int: + """Add two numbers""" + return a + b + + +# Add a dynamic greeting resource +@mcp.resource("greeting://{name}") +def get_greeting(name: str) -> str: + """Get a personalized greeting""" + return f"Hello, {name}!" + + +# Add a prompt +@mcp.prompt() +def greet_user(name: str, style: str = "friendly") -> str: + """Generate a greeting prompt""" + styles = { + "friendly": "Please write a warm, friendly greeting", + "formal": "Please write a formal, professional greeting", + "casual": "Please write a casual, relaxed greeting", + } + + return f"{styles.get(style, styles['friendly'])} for someone named {name}." + + +# Run with streamable HTTP transport +if __name__ == "__main__": + mcp.run(transport="streamable-http") +``` + +_Full example: [examples/snippets/servers/fastmcp_quickstart.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/fastmcp_quickstart.py)_ + + +You can install this server in [Claude Code](https://docs.claude.com/en/docs/claude-code/mcp) and interact with it right away. First, run the server: + +```bash +uv run --with mcp examples/snippets/servers/fastmcp_quickstart.py +``` + +Then add it to Claude Code: + +```bash +claude mcp add --transport http my-server http://localhost:8000/mcp +``` + +Alternatively, you can test it with the MCP Inspector. Start the server as above, then in a separate terminal: + +```bash +npx -y @modelcontextprotocol/inspector +``` + +In the inspector UI, connect to `http://localhost:8000/mcp`. + +## What is MCP? + +The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can: + +- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context) +- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) +- Define interaction patterns through **Prompts** (reusable templates for LLM interactions) +- And more! + +## Core Concepts + +### Server + +The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing: + + +```python +"""Example showing lifespan support for startup/shutdown with strong typing.""" + +from collections.abc import AsyncIterator +from contextlib import asynccontextmanager +from dataclasses import dataclass + +from mcp.server.fastmcp import Context, FastMCP +from mcp.server.session import ServerSession + + +# Mock database class for example +class Database: + """Mock database class for example.""" + + @classmethod + async def connect(cls) -> "Database": + """Connect to database.""" + return cls() + + async def disconnect(self) -> None: + """Disconnect from database.""" + pass + + def query(self) -> str: + """Execute a query.""" + return "Query result" + + +@dataclass +class AppContext: + """Application context with typed dependencies.""" + + db: Database + + +@asynccontextmanager +async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]: + """Manage application lifecycle with type-safe context.""" + # Initialize on startup + db = await Database.connect() + try: + yield AppContext(db=db) + finally: + # Cleanup on shutdown + await db.disconnect() + + +# Pass lifespan to server +mcp = FastMCP("My App", lifespan=app_lifespan) + + +# Access type-safe lifespan context in tools +@mcp.tool() +def query_db(ctx: Context[ServerSession, AppContext]) -> str: + """Tool that uses initialized resources.""" + db = ctx.request_context.lifespan_context.db + return db.query() +``` + +_Full example: [examples/snippets/servers/lifespan_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py)_ + + +### Resources + +Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects: + + +```python +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP(name="Resource Example") + + +@mcp.resource("file://documents/{name}") +def read_document(name: str) -> str: + """Read a document by name.""" + # This would normally read from disk + return f"Content of {name}" + + +@mcp.resource("config://settings") +def get_settings() -> str: + """Get application settings.""" + return """{ + "theme": "dark", + "language": "en", + "debug": false +}""" +``` + +_Full example: [examples/snippets/servers/basic_resource.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_resource.py)_ + + +### Tools + +Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects: + + +```python +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP(name="Tool Example") + + +@mcp.tool() +def sum(a: int, b: int) -> int: + """Add two numbers together.""" + return a + b + + +@mcp.tool() +def get_weather(city: str, unit: str = "celsius") -> str: + """Get weather for a city.""" + # This would normally call a weather API + return f"Weather in {city}: 22degrees{unit[0].upper()}" +``` + +_Full example: [examples/snippets/servers/basic_tool.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_tool.py)_ + + +Tools can optionally receive a Context object by including a parameter with the `Context` type annotation. This context is automatically injected by the FastMCP framework and provides access to MCP capabilities: + + +```python +from mcp.server.fastmcp import Context, FastMCP +from mcp.server.session import ServerSession + +mcp = FastMCP(name="Progress Example") + + +@mcp.tool() +async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str: + """Execute a task with progress updates.""" + await ctx.info(f"Starting: {task_name}") + + for i in range(steps): + progress = (i + 1) / steps + await ctx.report_progress( + progress=progress, + total=1.0, + message=f"Step {i + 1}/{steps}", + ) + await ctx.debug(f"Completed step {i + 1}") + + return f"Task '{task_name}' completed" +``` + +_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_ + + +#### Structured Output + +Tools will return structured results by default, if their return type +annotation is compatible. Otherwise, they will return unstructured results. + +Structured output supports these return types: + +- Pydantic models (BaseModel subclasses) +- TypedDicts +- Dataclasses and other classes with type hints +- `dict[str, T]` (where T is any JSON-serializable type) +- Primitive types (str, int, float, bool, bytes, None) - wrapped in `{"result": value}` +- Generic types (list, tuple, Union, Optional, etc.) - wrapped in `{"result": value}` + +Classes without type hints cannot be serialized for structured output. Only +classes with properly annotated attributes will be converted to Pydantic models +for schema generation and validation. + +Structured results are automatically validated against the output schema +generated from the annotation. This ensures the tool returns well-typed, +validated data that clients can easily process. + +**Note:** For backward compatibility, unstructured results are also +returned. Unstructured results are provided for backward compatibility +with previous versions of the MCP specification, and are quirks-compatible +with previous versions of FastMCP in the current version of the SDK. + +**Note:** In cases where a tool function's return type annotation +causes the tool to be classified as structured _and this is undesirable_, +the classification can be suppressed by passing `structured_output=False` +to the `@tool` decorator. + +##### Advanced: Direct CallToolResult + +For full control over tool responses including the `_meta` field (for passing data to client applications without exposing it to the model), you can return `CallToolResult` directly: + + +```python +"""Example showing direct CallToolResult return for advanced control.""" + +from typing import Annotated + +from pydantic import BaseModel + +from mcp.server.fastmcp import FastMCP +from mcp.types import CallToolResult, TextContent + +mcp = FastMCP("CallToolResult Example") + + +class ValidationModel(BaseModel): + """Model for validating structured output.""" + + status: str + data: dict[str, int] + + +@mcp.tool() +def advanced_tool() -> CallToolResult: + """Return CallToolResult directly for full control including _meta field.""" + return CallToolResult( + content=[TextContent(type="text", text="Response visible to the model")], + _meta={"hidden": "data for client applications only"}, + ) + + +@mcp.tool() +def validated_tool() -> Annotated[CallToolResult, ValidationModel]: + """Return CallToolResult with structured output validation.""" + return CallToolResult( + content=[TextContent(type="text", text="Validated response")], + structuredContent={"status": "success", "data": {"result": 42}}, + _meta={"internal": "metadata"}, + ) + + +@mcp.tool() +def empty_result_tool() -> CallToolResult: + """For empty results, return CallToolResult with empty content.""" + return CallToolResult(content=[]) +``` + +_Full example: [examples/snippets/servers/direct_call_tool_result.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_call_tool_result.py)_ + + +**Important:** `CallToolResult` must always be returned (no `Optional` or `Union`). For empty results, use `CallToolResult(content=[])`. For optional simple types, use `str | None` without `CallToolResult`. + + +```python +"""Example showing structured output with tools.""" + +from typing import TypedDict + +from pydantic import BaseModel, Field + +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP("Structured Output Example") + + +# Using Pydantic models for rich structured data +class WeatherData(BaseModel): + """Weather information structure.""" + + temperature: float = Field(description="Temperature in Celsius") + humidity: float = Field(description="Humidity percentage") + condition: str + wind_speed: float + + +@mcp.tool() +def get_weather(city: str) -> WeatherData: + """Get weather for a city - returns structured data.""" + # Simulated weather data + return WeatherData( + temperature=22.5, + humidity=45.0, + condition="sunny", + wind_speed=5.2, + ) + + +# Using TypedDict for simpler structures +class LocationInfo(TypedDict): + latitude: float + longitude: float + name: str + + +@mcp.tool() +def get_location(address: str) -> LocationInfo: + """Get location coordinates""" + return LocationInfo(latitude=51.5074, longitude=-0.1278, name="London, UK") + + +# Using dict[str, Any] for flexible schemas +@mcp.tool() +def get_statistics(data_type: str) -> dict[str, float]: + """Get various statistics""" + return {"mean": 42.5, "median": 40.0, "std_dev": 5.2} + + +# Ordinary classes with type hints work for structured output +class UserProfile: + name: str + age: int + email: str | None = None + + def __init__(self, name: str, age: int, email: str | None = None): + self.name = name + self.age = age + self.email = email + + +@mcp.tool() +def get_user(user_id: str) -> UserProfile: + """Get user profile - returns structured data""" + return UserProfile(name="Alice", age=30, email="alice@example.com") + + +# Classes WITHOUT type hints cannot be used for structured output +class UntypedConfig: + def __init__(self, setting1, setting2): # type: ignore[reportMissingParameterType] + self.setting1 = setting1 + self.setting2 = setting2 + + +@mcp.tool() +def get_config() -> UntypedConfig: + """This returns unstructured output - no schema generated""" + return UntypedConfig("value1", "value2") + + +# Lists and other types are wrapped automatically +@mcp.tool() +def list_cities() -> list[str]: + """Get a list of cities""" + return ["London", "Paris", "Tokyo"] + # Returns: {"result": ["London", "Paris", "Tokyo"]} + + +@mcp.tool() +def get_temperature(city: str) -> float: + """Get temperature as a simple float""" + return 22.5 + # Returns: {"result": 22.5} +``` + +_Full example: [examples/snippets/servers/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/structured_output.py)_ + + +### Prompts + +Prompts are reusable templates that help LLMs interact with your server effectively: + + +```python +from mcp.server.fastmcp import FastMCP +from mcp.server.fastmcp.prompts import base + +mcp = FastMCP(name="Prompt Example") + + +@mcp.prompt(title="Code Review") +def review_code(code: str) -> str: + return f"Please review this code:\n\n{code}" + + +@mcp.prompt(title="Debug Assistant") +def debug_error(error: str) -> list[base.Message]: + return [ + base.UserMessage("I'm seeing this error:"), + base.UserMessage(error), + base.AssistantMessage("I'll help debug that. What have you tried so far?"), + ] +``` + +_Full example: [examples/snippets/servers/basic_prompt.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/basic_prompt.py)_ + + +### Icons + +MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts: + +```python +from mcp.server.fastmcp import FastMCP, Icon + +# Create an icon from a file path or URL +icon = Icon( + src="icon.png", + mimeType="image/png", + sizes="64x64" +) + +# Add icons to server +mcp = FastMCP( + "My Server", + website_url="https://example.com", + icons=[icon] +) + +# Add icons to tools, resources, and prompts +@mcp.tool(icons=[icon]) +def my_tool(): + """Tool with an icon.""" + return "result" + +@mcp.resource("demo://resource", icons=[icon]) +def my_resource(): + """Resource with an icon.""" + return "content" +``` + +_Full example: [examples/fastmcp/icons_demo.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/fastmcp/icons_demo.py)_ + +### Images + +FastMCP provides an `Image` class that automatically handles image data: + + +```python +"""Example showing image handling with FastMCP.""" + +from PIL import Image as PILImage + +from mcp.server.fastmcp import FastMCP, Image + +mcp = FastMCP("Image Example") + + +@mcp.tool() +def create_thumbnail(image_path: str) -> Image: + """Create a thumbnail from an image""" + img = PILImage.open(image_path) + img.thumbnail((100, 100)) + return Image(data=img.tobytes(), format="png") +``` + +_Full example: [examples/snippets/servers/images.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/images.py)_ + + +### Context + +The Context object is automatically injected into tool and resource functions that request it via type hints. It provides access to MCP capabilities like logging, progress reporting, resource reading, user interaction, and request metadata. + +#### Getting Context in Functions + +To use context in a tool or resource function, add a parameter with the `Context` type annotation: + +```python +from mcp.server.fastmcp import Context, FastMCP + +mcp = FastMCP(name="Context Example") + + +@mcp.tool() +async def my_tool(x: int, ctx: Context) -> str: + """Tool that uses context capabilities.""" + # The context parameter can have any name as long as it's type-annotated + return await process_with_context(x, ctx) +``` + +#### Context Properties and Methods + +The Context object provides the following capabilities: + +- `ctx.request_id` - Unique ID for the current request +- `ctx.client_id` - Client ID if available +- `ctx.fastmcp` - Access to the FastMCP server instance (see [FastMCP Properties](#fastmcp-properties)) +- `ctx.session` - Access to the underlying session for advanced communication (see [Session Properties and Methods](#session-properties-and-methods)) +- `ctx.request_context` - Access to request-specific data and lifespan resources (see [Request Context Properties](#request-context-properties)) +- `await ctx.debug(message)` - Send debug log message +- `await ctx.info(message)` - Send info log message +- `await ctx.warning(message)` - Send warning log message +- `await ctx.error(message)` - Send error log message +- `await ctx.log(level, message, logger_name=None)` - Send log with custom level +- `await ctx.report_progress(progress, total=None, message=None)` - Report operation progress +- `await ctx.read_resource(uri)` - Read a resource by URI +- `await ctx.elicit(message, schema)` - Request additional information from user with validation + + +```python +from mcp.server.fastmcp import Context, FastMCP +from mcp.server.session import ServerSession + +mcp = FastMCP(name="Progress Example") + + +@mcp.tool() +async def long_running_task(task_name: str, ctx: Context[ServerSession, None], steps: int = 5) -> str: + """Execute a task with progress updates.""" + await ctx.info(f"Starting: {task_name}") + + for i in range(steps): + progress = (i + 1) / steps + await ctx.report_progress( + progress=progress, + total=1.0, + message=f"Step {i + 1}/{steps}", + ) + await ctx.debug(f"Completed step {i + 1}") + + return f"Task '{task_name}' completed" +``` + +_Full example: [examples/snippets/servers/tool_progress.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/tool_progress.py)_ + + +### Completions + +MCP supports providing completion suggestions for prompt arguments and resource template parameters. With the context parameter, servers can provide completions based on previously resolved values: + +Client usage: + + +```python +""" +cd to the `examples/snippets` directory and run: + uv run completion-client +""" + +import asyncio +import os + +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client +from mcp.types import PromptReference, ResourceTemplateReference + +# Create server parameters for stdio connection +server_params = StdioServerParameters( + command="uv", # Using uv to run the server + args=["run", "server", "completion", "stdio"], # Server with completion support + env={"UV_INDEX": os.environ.get("UV_INDEX", "")}, +) + + +async def run(): + """Run the completion client example.""" + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + # Initialize the connection + await session.initialize() + + # List available resource templates + templates = await session.list_resource_templates() + print("Available resource templates:") + for template in templates.resourceTemplates: + print(f" - {template.uriTemplate}") + + # List available prompts + prompts = await session.list_prompts() + print("\nAvailable prompts:") + for prompt in prompts.prompts: + print(f" - {prompt.name}") + + # Complete resource template arguments + if templates.resourceTemplates: + template = templates.resourceTemplates[0] + print(f"\nCompleting arguments for resource template: {template.uriTemplate}") + + # Complete without context + result = await session.complete( + ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate), + argument={"name": "owner", "value": "model"}, + ) + print(f"Completions for 'owner' starting with 'model': {result.completion.values}") + + # Complete with context - repo suggestions based on owner + result = await session.complete( + ref=ResourceTemplateReference(type="ref/resource", uri=template.uriTemplate), + argument={"name": "repo", "value": ""}, + context_arguments={"owner": "modelcontextprotocol"}, + ) + print(f"Completions for 'repo' with owner='modelcontextprotocol': {result.completion.values}") + + # Complete prompt arguments + if prompts.prompts: + prompt_name = prompts.prompts[0].name + print(f"\nCompleting arguments for prompt: {prompt_name}") + + result = await session.complete( + ref=PromptReference(type="ref/prompt", name=prompt_name), + argument={"name": "style", "value": ""}, + ) + print(f"Completions for 'style' argument: {result.completion.values}") + + +def main(): + """Entry point for the completion client.""" + asyncio.run(run()) + + +if __name__ == "__main__": + main() +``` + +_Full example: [examples/snippets/clients/completion_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/completion_client.py)_ + +### Elicitation + +Request additional information from users. This example shows an Elicitation during a Tool Call: + + +```python +"""Elicitation examples demonstrating form and URL mode elicitation. + +Form mode elicitation collects structured, non-sensitive data through a schema. +URL mode elicitation directs users to external URLs for sensitive operations +like OAuth flows, credential collection, or payment processing. +""" + +import uuid + +from pydantic import BaseModel, Field + +from mcp.server.fastmcp import Context, FastMCP +from mcp.server.session import ServerSession +from mcp.shared.exceptions import UrlElicitationRequiredError +from mcp.types import ElicitRequestURLParams + +mcp = FastMCP(name="Elicitation Example") + + +class BookingPreferences(BaseModel): + """Schema for collecting user preferences.""" + + checkAlternative: bool = Field(description="Would you like to check another date?") + alternativeDate: str = Field( + default="2024-12-26", + description="Alternative date (YYYY-MM-DD)", + ) + + +@mcp.tool() +async def book_table(date: str, time: str, party_size: int, ctx: Context[ServerSession, None]) -> str: + """Book a table with date availability check. + + This demonstrates form mode elicitation for collecting non-sensitive user input. + """ + # Check if date is available + if date == "2024-12-25": + # Date unavailable - ask user for alternative + result = await ctx.elicit( + message=(f"No tables available for {party_size} on {date}. Would you like to try another date?"), + schema=BookingPreferences, + ) + + if result.action == "accept" and result.data: + if result.data.checkAlternative: + return f"[SUCCESS] Booked for {result.data.alternativeDate}" + return "[CANCELLED] No booking made" + return "[CANCELLED] Booking cancelled" + + # Date available + return f"[SUCCESS] Booked for {date} at {time}" + + +@mcp.tool() +async def secure_payment(amount: float, ctx: Context[ServerSession, None]) -> str: + """Process a secure payment requiring URL confirmation. + + This demonstrates URL mode elicitation using ctx.elicit_url() for + operations that require out-of-band user interaction. + """ + elicitation_id = str(uuid.uuid4()) + + result = await ctx.elicit_url( + message=f"Please confirm payment of ${amount:.2f}", + url=f"https://payments.example.com/confirm?amount={amount}&id={elicitation_id}", + elicitation_id=elicitation_id, + ) + + if result.action == "accept": + # In a real app, the payment confirmation would happen out-of-band + # and you'd verify the payment status from your backend + return f"Payment of ${amount:.2f} initiated - check your browser to complete" + elif result.action == "decline": + return "Payment declined by user" + return "Payment cancelled" + + +@mcp.tool() +async def connect_service(service_name: str, ctx: Context[ServerSession, None]) -> str: + """Connect to a third-party service requiring OAuth authorization. + + This demonstrates the "throw error" pattern using UrlElicitationRequiredError. + Use this pattern when the tool cannot proceed without user authorization. + """ + elicitation_id = str(uuid.uuid4()) + + # Raise UrlElicitationRequiredError to signal that the client must complete + # a URL elicitation before this request can be processed. + # The MCP framework will convert this to a -32042 error response. + raise UrlElicitationRequiredError( + [ + ElicitRequestURLParams( + mode="url", + message=f"Authorization required to connect to {service_name}", + url=f"https://{service_name}.example.com/oauth/authorize?elicit={elicitation_id}", + elicitationId=elicitation_id, + ) + ] + ) +``` + +_Full example: [examples/snippets/servers/elicitation.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/elicitation.py)_ + + +Elicitation schemas support default values for all field types. Default values are automatically included in the JSON schema sent to clients, allowing them to pre-populate forms. + +The `elicit()` method returns an `ElicitationResult` with: + +- `action`: "accept", "decline", or "cancel" +- `data`: The validated response (only when accepted) +- `validation_error`: Any validation error message + +### Sampling + +Tools can interact with LLMs through sampling (generating text): + + +```python +from mcp.server.fastmcp import Context, FastMCP +from mcp.server.session import ServerSession +from mcp.types import SamplingMessage, TextContent + +mcp = FastMCP(name="Sampling Example") + + +@mcp.tool() +async def generate_poem(topic: str, ctx: Context[ServerSession, None]) -> str: + """Generate a poem using LLM sampling.""" + prompt = f"Write a short poem about {topic}" + + result = await ctx.session.create_message( + messages=[ + SamplingMessage( + role="user", + content=TextContent(type="text", text=prompt), + ) + ], + max_tokens=100, + ) + + # Since we're not passing tools param, result.content is single content + if result.content.type == "text": + return result.content.text + return str(result.content) +``` + +_Full example: [examples/snippets/servers/sampling.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/sampling.py)_ + + +### Logging and Notifications + +Tools can send logs and notifications through the context: + + +```python +from mcp.server.fastmcp import Context, FastMCP +from mcp.server.session import ServerSession + +mcp = FastMCP(name="Notifications Example") + + +@mcp.tool() +async def process_data(data: str, ctx: Context[ServerSession, None]) -> str: + """Process data with logging.""" + # Different log levels + await ctx.debug(f"Debug: Processing '{data}'") + await ctx.info("Info: Starting processing") + await ctx.warning("Warning: This is experimental") + await ctx.error("Error: (This is just a demo)") + + # Notify about resource changes + await ctx.session.send_resource_list_changed() + + return f"Processed: {data}" +``` + +_Full example: [examples/snippets/servers/notifications.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/notifications.py)_ + + +### Authentication + +Authentication can be used by servers that want to expose tools accessing protected resources. + +`mcp.server.auth` implements OAuth 2.1 resource server functionality, where MCP servers act as Resource Servers (RS) that validate tokens issued by separate Authorization Servers (AS). This follows the [MCP authorization specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization) and implements RFC 9728 (Protected Resource Metadata) for AS discovery. + +MCP servers can use authentication by providing an implementation of the `TokenVerifier` protocol: + + +```python +""" +Run from the repository root: + uv run examples/snippets/servers/oauth_server.py +""" + +from pydantic import AnyHttpUrl + +from mcp.server.auth.provider import AccessToken, TokenVerifier +from mcp.server.auth.settings import AuthSettings +from mcp.server.fastmcp import FastMCP + + +class SimpleTokenVerifier(TokenVerifier): + """Simple token verifier for demonstration.""" + + async def verify_token(self, token: str) -> AccessToken | None: + pass # This is where you would implement actual token validation + + +# Create FastMCP instance as a Resource Server +mcp = FastMCP( + "Weather Service", + json_response=True, + # Token verifier for authentication + token_verifier=SimpleTokenVerifier(), + # Auth settings for RFC 9728 Protected Resource Metadata + auth=AuthSettings( + issuer_url=AnyHttpUrl("https://auth.example.com"), # Authorization Server URL + resource_server_url=AnyHttpUrl("http://localhost:3001"), # This server's URL + required_scopes=["user"], + ), +) + + +@mcp.tool() +async def get_weather(city: str = "London") -> dict[str, str]: + """Get weather data for a city""" + return { + "city": city, + "temperature": "22", + "condition": "Partly cloudy", + "humidity": "65%", + } + + +if __name__ == "__main__": + mcp.run(transport="streamable-http") +``` + +_Full example: [examples/snippets/servers/oauth_server.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/oauth_server.py)_ + + +For a complete example with separate Authorization Server and Resource Server implementations, see [`examples/servers/simple-auth/`](examples/servers/simple-auth/). + +**Architecture:** + +- **Authorization Server (AS)**: Handles OAuth flows, user authentication, and token issuance +- **Resource Server (RS)**: Your MCP server that validates tokens and serves protected resources +- **Client**: Discovers AS through RFC 9728, obtains tokens, and uses them with the MCP server + +See [TokenVerifier](src/mcp/server/auth/provider.py) for more details on implementing token validation. + +### FastMCP Properties + +The FastMCP server instance accessible via `ctx.fastmcp` provides access to server configuration and metadata: + +- `ctx.fastmcp.name` - The server's name as defined during initialization +- `ctx.fastmcp.instructions` - Server instructions/description provided to clients +- `ctx.fastmcp.website_url` - Optional website URL for the server +- `ctx.fastmcp.icons` - Optional list of icons for UI display +- `ctx.fastmcp.settings` - Complete server configuration object containing: + - `debug` - Debug mode flag + - `log_level` - Current logging level + - `host` and `port` - Server network configuration + - `mount_path`, `sse_path`, `streamable_http_path` - Transport paths + - `stateless_http` - Whether the server operates in stateless mode + - And other configuration options + +```python +@mcp.tool() +def server_info(ctx: Context) -> dict: + """Get information about the current server.""" + return { + "name": ctx.fastmcp.name, + "instructions": ctx.fastmcp.instructions, + "debug_mode": ctx.fastmcp.settings.debug, + "log_level": ctx.fastmcp.settings.log_level, + "host": ctx.fastmcp.settings.host, + "port": ctx.fastmcp.settings.port, + } +``` + +### Session Properties and Methods + +The session object accessible via `ctx.session` provides advanced control over client communication: + +- `ctx.session.client_params` - Client initialization parameters and declared capabilities +- `await ctx.session.send_log_message(level, data, logger)` - Send log messages with full control +- `await ctx.session.create_message(messages, max_tokens)` - Request LLM sampling/completion +- `await ctx.session.send_progress_notification(token, progress, total, message)` - Direct progress updates +- `await ctx.session.send_resource_updated(uri)` - Notify clients that a specific resource changed +- `await ctx.session.send_resource_list_changed()` - Notify clients that the resource list changed +- `await ctx.session.send_tool_list_changed()` - Notify clients that the tool list changed +- `await ctx.session.send_prompt_list_changed()` - Notify clients that the prompt list changed + +```python +@mcp.tool() +async def notify_data_update(resource_uri: str, ctx: Context) -> str: + """Update data and notify clients of the change.""" + # Perform data update logic here + + # Notify clients that this specific resource changed + await ctx.session.send_resource_updated(AnyUrl(resource_uri)) + + # If this affects the overall resource list, notify about that too + await ctx.session.send_resource_list_changed() + + return f"Updated {resource_uri} and notified clients" +``` + +### Request Context Properties + +The request context accessible via `ctx.request_context` contains request-specific information and resources: + +- `ctx.request_context.lifespan_context` - Access to resources initialized during server startup + - Database connections, configuration objects, shared services + - Type-safe access to resources defined in your server's lifespan function +- `ctx.request_context.meta` - Request metadata from the client including: + - `progressToken` - Token for progress notifications + - Other client-provided metadata +- `ctx.request_context.request` - The original MCP request object for advanced processing +- `ctx.request_context.request_id` - Unique identifier for this request + +```python +# Example with typed lifespan context +@dataclass +class AppContext: + db: Database + config: AppConfig + +@mcp.tool() +def query_with_config(query: str, ctx: Context) -> str: + """Execute a query using shared database and configuration.""" + # Access typed lifespan context + app_ctx: AppContext = ctx.request_context.lifespan_context + + # Use shared resources + connection = app_ctx.db + settings = app_ctx.config + + # Execute query with configuration + result = connection.execute(query, timeout=settings.query_timeout) + return str(result) +``` + +_Full lifespan example: [examples/snippets/servers/lifespan_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lifespan_example.py)_ + +## Running Your Server + +### Development Mode + +The fastest way to test and debug your server is with the MCP Inspector: + +```bash +uv run mcp dev server.py + +# Add dependencies +uv run mcp dev server.py --with pandas --with numpy + +# Mount local code +uv run mcp dev server.py --with-editable . +``` + +### Claude Desktop Integration + +Once your server is ready, install it in Claude Desktop: + +```bash +uv run mcp install server.py + +# Custom name +uv run mcp install server.py --name "My Analytics Server" + +# Environment variables +uv run mcp install server.py -v API_KEY=abc123 -v DB_URL=postgres://... +uv run mcp install server.py -f .env +``` + +### Direct Execution + +For advanced scenarios like custom deployments: + + +```python +"""Example showing direct execution of an MCP server. + +This is the simplest way to run an MCP server directly. +cd to the `examples/snippets` directory and run: + uv run direct-execution-server + or + python servers/direct_execution.py +""" + +from mcp.server.fastmcp import FastMCP + +mcp = FastMCP("My App") + + +@mcp.tool() +def hello(name: str = "World") -> str: + """Say hello to someone.""" + return f"Hello, {name}!" + + +def main(): + """Entry point for the direct execution server.""" + mcp.run() + + +if __name__ == "__main__": + main() +``` + +_Full example: [examples/snippets/servers/direct_execution.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/direct_execution.py)_ + + +Run it with: + +```bash +python servers/direct_execution.py +# or +uv run mcp run servers/direct_execution.py +``` + +Note that `uv run mcp run` or `uv run mcp dev` only supports server using FastMCP and not the low-level server variant. + +### Streamable HTTP Transport + +> **Note**: Streamable HTTP transport is the recommended transport for production deployments. Use `stateless_http=True` and `json_response=True` for optimal scalability. + + +```python +""" +Run from the repository root: + uv run examples/snippets/servers/streamable_config.py +""" + +from mcp.server.fastmcp import FastMCP + +# Stateless server with JSON responses (recommended) +mcp = FastMCP("StatelessServer", stateless_http=True, json_response=True) + +# Other configuration options: +# Stateless server with SSE streaming responses +# mcp = FastMCP("StatelessServer", stateless_http=True) + +# Stateful server with session persistence +# mcp = FastMCP("StatefulServer") + + +# Add a simple tool to demonstrate the server +@mcp.tool() +def greet(name: str = "World") -> str: + """Greet someone by name.""" + return f"Hello, {name}!" + + +# Run server with streamable_http transport +if __name__ == "__main__": + mcp.run(transport="streamable-http") +``` + +_Full example: [examples/snippets/servers/streamable_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_config.py)_ + + +You can mount multiple FastMCP servers in a Starlette application: + + +```python +""" +Run from the repository root: + uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload +""" + +import contextlib + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create the Echo server +echo_mcp = FastMCP(name="EchoServer", stateless_http=True, json_response=True) + + +@echo_mcp.tool() +def echo(message: str) -> str: + """A simple echo tool""" + return f"Echo: {message}" + + +# Create the Math server +math_mcp = FastMCP(name="MathServer", stateless_http=True, json_response=True) + + +@math_mcp.tool() +def add_two(n: int) -> int: + """Tool to add two to the input""" + return n + 2 + + +# Create a combined lifespan to manage both session managers +@contextlib.asynccontextmanager +async def lifespan(app: Starlette): + async with contextlib.AsyncExitStack() as stack: + await stack.enter_async_context(echo_mcp.session_manager.run()) + await stack.enter_async_context(math_mcp.session_manager.run()) + yield + + +# Create the Starlette app and mount the MCP servers +app = Starlette( + routes=[ + Mount("/echo", echo_mcp.streamable_http_app()), + Mount("/math", math_mcp.streamable_http_app()), + ], + lifespan=lifespan, +) + +# Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp +# To mount at the root of each path (e.g., /echo instead of /echo/mcp): +# echo_mcp.settings.streamable_http_path = "/" +# math_mcp.settings.streamable_http_path = "/" +``` + +_Full example: [examples/snippets/servers/streamable_starlette_mount.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_starlette_mount.py)_ + + +For low level server with Streamable HTTP implementations, see: + +- Stateful server: [`examples/servers/simple-streamablehttp/`](examples/servers/simple-streamablehttp/) +- Stateless server: [`examples/servers/simple-streamablehttp-stateless/`](examples/servers/simple-streamablehttp-stateless/) + +The streamable HTTP transport supports: + +- Stateful and stateless operation modes +- Resumability with event stores +- JSON or SSE response formats +- Better scalability for multi-node deployments + +#### CORS Configuration for Browser-Based Clients + +If you'd like your server to be accessible by browser-based MCP clients, you'll need to configure CORS headers. The `Mcp-Session-Id` header must be exposed for browser clients to access it: + +```python +from starlette.applications import Starlette +from starlette.middleware.cors import CORSMiddleware + +# Create your Starlette app first +starlette_app = Starlette(routes=[...]) + +# Then wrap it with CORS middleware +starlette_app = CORSMiddleware( + starlette_app, + allow_origins=["*"], # Configure appropriately for production + allow_methods=["GET", "POST", "DELETE"], # MCP streamable HTTP methods + expose_headers=["Mcp-Session-Id"], +) +``` + +This configuration is necessary because: + +- The MCP streamable HTTP transport uses the `Mcp-Session-Id` header for session management +- Browsers restrict access to response headers unless explicitly exposed via CORS +- Without this configuration, browser-based clients won't be able to read the session ID from initialization responses + +### Mounting to an Existing ASGI Server + +By default, SSE servers are mounted at `/sse` and Streamable HTTP servers are mounted at `/mcp`. You can customize these paths using the methods described below. + +For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes). + +#### StreamableHTTP servers + +You can mount the StreamableHTTP server to an existing ASGI server using the `streamable_http_app` method. This allows you to integrate the StreamableHTTP server with other ASGI applications. + +##### Basic mounting + + +```python +""" +Basic example showing how to mount StreamableHTTP server in Starlette. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload +""" + +import contextlib + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create MCP server +mcp = FastMCP("My App", json_response=True) + + +@mcp.tool() +def hello() -> str: + """A simple hello tool""" + return "Hello from MCP!" + + +# Create a lifespan context manager to run the session manager +@contextlib.asynccontextmanager +async def lifespan(app: Starlette): + async with mcp.session_manager.run(): + yield + + +# Mount the StreamableHTTP server to the existing ASGI server +app = Starlette( + routes=[ + Mount("/", app=mcp.streamable_http_app()), + ], + lifespan=lifespan, +) +``` + +_Full example: [examples/snippets/servers/streamable_http_basic_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_basic_mounting.py)_ + + +##### Host-based routing + + +```python +""" +Example showing how to mount StreamableHTTP server using Host-based routing. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload +""" + +import contextlib + +from starlette.applications import Starlette +from starlette.routing import Host + +from mcp.server.fastmcp import FastMCP + +# Create MCP server +mcp = FastMCP("MCP Host App", json_response=True) + + +@mcp.tool() +def domain_info() -> str: + """Get domain-specific information""" + return "This is served from mcp.acme.corp" + + +# Create a lifespan context manager to run the session manager +@contextlib.asynccontextmanager +async def lifespan(app: Starlette): + async with mcp.session_manager.run(): + yield + + +# Mount using Host-based routing +app = Starlette( + routes=[ + Host("mcp.acme.corp", app=mcp.streamable_http_app()), + ], + lifespan=lifespan, +) +``` + +_Full example: [examples/snippets/servers/streamable_http_host_mounting.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_host_mounting.py)_ + + +##### Multiple servers with path configuration + + +```python +""" +Example showing how to mount multiple StreamableHTTP servers with path configuration. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload +""" + +import contextlib + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Create multiple MCP servers +api_mcp = FastMCP("API Server", json_response=True) +chat_mcp = FastMCP("Chat Server", json_response=True) + + +@api_mcp.tool() +def api_status() -> str: + """Get API status""" + return "API is running" + + +@chat_mcp.tool() +def send_message(message: str) -> str: + """Send a chat message""" + return f"Message sent: {message}" + + +# Configure servers to mount at the root of each path +# This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp +api_mcp.settings.streamable_http_path = "/" +chat_mcp.settings.streamable_http_path = "/" + + +# Create a combined lifespan to manage both session managers +@contextlib.asynccontextmanager +async def lifespan(app: Starlette): + async with contextlib.AsyncExitStack() as stack: + await stack.enter_async_context(api_mcp.session_manager.run()) + await stack.enter_async_context(chat_mcp.session_manager.run()) + yield + + +# Mount the servers +app = Starlette( + routes=[ + Mount("/api", app=api_mcp.streamable_http_app()), + Mount("/chat", app=chat_mcp.streamable_http_app()), + ], + lifespan=lifespan, +) +``` + +_Full example: [examples/snippets/servers/streamable_http_multiple_servers.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_multiple_servers.py)_ + + +##### Path configuration at initialization + + +```python +""" +Example showing path configuration during FastMCP initialization. + +Run from the repository root: + uvicorn examples.snippets.servers.streamable_http_path_config:app --reload +""" + +from starlette.applications import Starlette +from starlette.routing import Mount + +from mcp.server.fastmcp import FastMCP + +# Configure streamable_http_path during initialization +# This server will mount at the root of wherever it's mounted +mcp_at_root = FastMCP( + "My Server", + json_response=True, + streamable_http_path="/", +) + + +@mcp_at_root.tool() +def process_data(data: str) -> str: + """Process some data""" + return f"Processed: {data}" + + +# Mount at /process - endpoints will be at /process instead of /process/mcp +app = Starlette( + routes=[ + Mount("/process", app=mcp_at_root.streamable_http_app()), + ] +) +``` + +_Full example: [examples/snippets/servers/streamable_http_path_config.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/streamable_http_path_config.py)_ + + +#### SSE servers + +> **Note**: SSE transport is being superseded by [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http). + +You can mount the SSE server to an existing ASGI server using the `sse_app` method. This allows you to integrate the SSE server with other ASGI applications. + +```python +from starlette.applications import Starlette +from starlette.routing import Mount, Host +from mcp.server.fastmcp import FastMCP + + +mcp = FastMCP("My App") + +# Mount the SSE server to the existing ASGI server +app = Starlette( + routes=[ + Mount('/', app=mcp.sse_app()), + ] +) + +# or dynamically mount as host +app.router.routes.append(Host('mcp.acme.corp', app=mcp.sse_app())) +``` + +When mounting multiple MCP servers under different paths, you can configure the mount path in several ways: + +```python +from starlette.applications import Starlette +from starlette.routing import Mount +from mcp.server.fastmcp import FastMCP + +# Create multiple MCP servers +github_mcp = FastMCP("GitHub API") +browser_mcp = FastMCP("Browser") +curl_mcp = FastMCP("Curl") +search_mcp = FastMCP("Search") + +# Method 1: Configure mount paths via settings (recommended for persistent configuration) +github_mcp.settings.mount_path = "/github" +browser_mcp.settings.mount_path = "/browser" + +# Method 2: Pass mount path directly to sse_app (preferred for ad-hoc mounting) +# This approach doesn't modify the server's settings permanently + +# Create Starlette app with multiple mounted servers +app = Starlette( + routes=[ + # Using settings-based configuration + Mount("/github", app=github_mcp.sse_app()), + Mount("/browser", app=browser_mcp.sse_app()), + # Using direct mount path parameter + Mount("/curl", app=curl_mcp.sse_app("/curl")), + Mount("/search", app=search_mcp.sse_app("/search")), + ] +) + +# Method 3: For direct execution, you can also pass the mount path to run() +if __name__ == "__main__": + search_mcp.run(transport="sse", mount_path="/search") +``` + +For more information on mounting applications in Starlette, see the [Starlette documentation](https://www.starlette.io/routing/#submounting-routes). + +## Advanced Usage + +### Low-Level Server + +For more control, you can use the low-level server implementation directly. This gives you full access to the protocol and allows you to customize every aspect of your server, including lifecycle management through the lifespan API: + + +```python +""" +Run from the repository root: + uv run examples/snippets/servers/lowlevel/lifespan.py +""" + +from collections.abc import AsyncIterator +from contextlib import asynccontextmanager +from typing import Any + +import mcp.server.stdio +import mcp.types as types +from mcp.server.lowlevel import NotificationOptions, Server +from mcp.server.models import InitializationOptions + + +# Mock database class for example +class Database: + """Mock database class for example.""" + + @classmethod + async def connect(cls) -> "Database": + """Connect to database.""" + print("Database connected") + return cls() + + async def disconnect(self) -> None: + """Disconnect from database.""" + print("Database disconnected") + + async def query(self, query_str: str) -> list[dict[str, str]]: + """Execute a query.""" + # Simulate database query + return [{"id": "1", "name": "Example", "query": query_str}] + + +@asynccontextmanager +async def server_lifespan(_server: Server) -> AsyncIterator[dict[str, Any]]: + """Manage server startup and shutdown lifecycle.""" + # Initialize resources on startup + db = await Database.connect() + try: + yield {"db": db} + finally: + # Clean up on shutdown + await db.disconnect() + + +# Pass lifespan to server +server = Server("example-server", lifespan=server_lifespan) + + +@server.list_tools() +async def handle_list_tools() -> list[types.Tool]: + """List available tools.""" + return [ + types.Tool( + name="query_db", + description="Query the database", + inputSchema={ + "type": "object", + "properties": {"query": {"type": "string", "description": "SQL query to execute"}}, + "required": ["query"], + }, + ) + ] + + +@server.call_tool() +async def query_db(name: str, arguments: dict[str, Any]) -> list[types.TextContent]: + """Handle database query tool call.""" + if name != "query_db": + raise ValueError(f"Unknown tool: {name}") + + # Access lifespan context + ctx = server.request_context + db = ctx.lifespan_context["db"] + + # Execute query + results = await db.query(arguments["query"]) + + return [types.TextContent(type="text", text=f"Query results: {results}")] + + +async def run(): + """Run the server with lifespan management.""" + async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="example-server", + server_version="0.1.0", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), + ), + ) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(run()) +``` + +_Full example: [examples/snippets/servers/lowlevel/lifespan.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/lifespan.py)_ + + +The lifespan API provides: + +- A way to initialize resources when the server starts and clean them up when it stops +- Access to initialized resources through the request context in handlers +- Type-safe context passing between lifespan and request handlers + + +```python +""" +Run from the repository root: +uv run examples/snippets/servers/lowlevel/basic.py +""" + +import asyncio + +import mcp.server.stdio +import mcp.types as types +from mcp.server.lowlevel import NotificationOptions, Server +from mcp.server.models import InitializationOptions + +# Create a server instance +server = Server("example-server") + + +@server.list_prompts() +async def handle_list_prompts() -> list[types.Prompt]: + """List available prompts.""" + return [ + types.Prompt( + name="example-prompt", + description="An example prompt template", + arguments=[types.PromptArgument(name="arg1", description="Example argument", required=True)], + ) + ] + + +@server.get_prompt() +async def handle_get_prompt(name: str, arguments: dict[str, str] | None) -> types.GetPromptResult: + """Get a specific prompt by name.""" + if name != "example-prompt": + raise ValueError(f"Unknown prompt: {name}") + + arg1_value = (arguments or {}).get("arg1", "default") + + return types.GetPromptResult( + description="Example prompt", + messages=[ + types.PromptMessage( + role="user", + content=types.TextContent(type="text", text=f"Example prompt text with argument: {arg1_value}"), + ) + ], + ) + + +async def run(): + """Run the basic low-level server.""" + async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="example", + server_version="0.1.0", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), + ), + ) + + +if __name__ == "__main__": + asyncio.run(run()) +``` + +_Full example: [examples/snippets/servers/lowlevel/basic.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/basic.py)_ + + +Caution: The `uv run mcp run` and `uv run mcp dev` tool doesn't support low-level server. + +#### Structured Output Support + +The low-level server supports structured output for tools, allowing you to return both human-readable content and machine-readable structured data. Tools can define an `outputSchema` to validate their structured output: + + +```python +""" +Run from the repository root: + uv run examples/snippets/servers/lowlevel/structured_output.py +""" + +import asyncio +from typing import Any + +import mcp.server.stdio +import mcp.types as types +from mcp.server.lowlevel import NotificationOptions, Server +from mcp.server.models import InitializationOptions + +server = Server("example-server") + + +@server.list_tools() +async def list_tools() -> list[types.Tool]: + """List available tools with structured output schemas.""" + return [ + types.Tool( + name="get_weather", + description="Get current weather for a city", + inputSchema={ + "type": "object", + "properties": {"city": {"type": "string", "description": "City name"}}, + "required": ["city"], + }, + outputSchema={ + "type": "object", + "properties": { + "temperature": {"type": "number", "description": "Temperature in Celsius"}, + "condition": {"type": "string", "description": "Weather condition"}, + "humidity": {"type": "number", "description": "Humidity percentage"}, + "city": {"type": "string", "description": "City name"}, + }, + "required": ["temperature", "condition", "humidity", "city"], + }, + ) + ] + + +@server.call_tool() +async def call_tool(name: str, arguments: dict[str, Any]) -> dict[str, Any]: + """Handle tool calls with structured output.""" + if name == "get_weather": + city = arguments["city"] + + # Simulated weather data - in production, call a weather API + weather_data = { + "temperature": 22.5, + "condition": "partly cloudy", + "humidity": 65, + "city": city, # Include the requested city + } + + # low-level server will validate structured output against the tool's + # output schema, and additionally serialize it into a TextContent block + # for backwards compatibility with pre-2025-06-18 clients. + return weather_data + else: + raise ValueError(f"Unknown tool: {name}") + + +async def run(): + """Run the structured output server.""" + async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="structured-output-example", + server_version="0.1.0", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), + ), + ) + + +if __name__ == "__main__": + asyncio.run(run()) +``` + +_Full example: [examples/snippets/servers/lowlevel/structured_output.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/structured_output.py)_ + + +Tools can return data in four ways: + +1. **Content only**: Return a list of content blocks (default behavior before spec revision 2025-06-18) +2. **Structured data only**: Return a dictionary that will be serialized to JSON (Introduced in spec revision 2025-06-18) +3. **Both**: Return a tuple of (content, structured_data) preferred option to use for backwards compatibility +4. **Direct CallToolResult**: Return `CallToolResult` directly for full control (including `_meta` field) + +When an `outputSchema` is defined, the server automatically validates the structured output against the schema. This ensures type safety and helps catch errors early. + +##### Returning CallToolResult Directly + +For full control over the response including the `_meta` field (for passing data to client applications without exposing it to the model), return `CallToolResult` directly: + + +```python +""" +Run from the repository root: + uv run examples/snippets/servers/lowlevel/direct_call_tool_result.py +""" + +import asyncio +from typing import Any + +import mcp.server.stdio +import mcp.types as types +from mcp.server.lowlevel import NotificationOptions, Server +from mcp.server.models import InitializationOptions + +server = Server("example-server") + + +@server.list_tools() +async def list_tools() -> list[types.Tool]: + """List available tools.""" + return [ + types.Tool( + name="advanced_tool", + description="Tool with full control including _meta field", + inputSchema={ + "type": "object", + "properties": {"message": {"type": "string"}}, + "required": ["message"], + }, + ) + ] + + +@server.call_tool() +async def handle_call_tool(name: str, arguments: dict[str, Any]) -> types.CallToolResult: + """Handle tool calls by returning CallToolResult directly.""" + if name == "advanced_tool": + message = str(arguments.get("message", "")) + return types.CallToolResult( + content=[types.TextContent(type="text", text=f"Processed: {message}")], + structuredContent={"result": "success", "message": message}, + _meta={"hidden": "data for client applications only"}, + ) + + raise ValueError(f"Unknown tool: {name}") + + +async def run(): + """Run the server.""" + async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="example", + server_version="0.1.0", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), + ), + ) + + +if __name__ == "__main__": + asyncio.run(run()) +``` + +_Full example: [examples/snippets/servers/lowlevel/direct_call_tool_result.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/lowlevel/direct_call_tool_result.py)_ + + +**Note:** When returning `CallToolResult`, you bypass the automatic content/structured conversion. You must construct the complete response yourself. + +### Pagination (Advanced) + +For servers that need to handle large datasets, the low-level server provides paginated versions of list operations. This is an optional optimization - most servers won't need pagination unless they're dealing with hundreds or thousands of items. + +#### Server-side Implementation + + +```python +""" +Example of implementing pagination with MCP server decorators. +""" + +from pydantic import AnyUrl + +import mcp.types as types +from mcp.server.lowlevel import Server + +# Initialize the server +server = Server("paginated-server") + +# Sample data to paginate +ITEMS = [f"Item {i}" for i in range(1, 101)] # 100 items + + +@server.list_resources() +async def list_resources_paginated(request: types.ListResourcesRequest) -> types.ListResourcesResult: + """List resources with pagination support.""" + page_size = 10 + + # Extract cursor from request params + cursor = request.params.cursor if request.params is not None else None + + # Parse cursor to get offset + start = 0 if cursor is None else int(cursor) + end = start + page_size + + # Get page of resources + page_items = [ + types.Resource(uri=AnyUrl(f"resource://items/{item}"), name=item, description=f"Description for {item}") + for item in ITEMS[start:end] + ] + + # Determine next cursor + next_cursor = str(end) if end < len(ITEMS) else None + + return types.ListResourcesResult(resources=page_items, nextCursor=next_cursor) +``` + +_Full example: [examples/snippets/servers/pagination_example.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/servers/pagination_example.py)_ + + +#### Client-side Consumption + + +```python +""" +Example of consuming paginated MCP endpoints from a client. +""" + +import asyncio + +from mcp.client.session import ClientSession +from mcp.client.stdio import StdioServerParameters, stdio_client +from mcp.types import PaginatedRequestParams, Resource + + +async def list_all_resources() -> None: + """Fetch all resources using pagination.""" + async with stdio_client(StdioServerParameters(command="uv", args=["run", "mcp-simple-pagination"])) as ( + read, + write, + ): + async with ClientSession(read, write) as session: + await session.initialize() + + all_resources: list[Resource] = [] + cursor = None + + while True: + # Fetch a page of resources + result = await session.list_resources(params=PaginatedRequestParams(cursor=cursor)) + all_resources.extend(result.resources) + + print(f"Fetched {len(result.resources)} resources") + + # Check if there are more pages + if result.nextCursor: + cursor = result.nextCursor + else: + break + + print(f"Total resources: {len(all_resources)}") + + +if __name__ == "__main__": + asyncio.run(list_all_resources()) +``` + +_Full example: [examples/snippets/clients/pagination_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/pagination_client.py)_ + + +#### Key Points + +- **Cursors are opaque strings** - the server defines the format (numeric offsets, timestamps, etc.) +- **Return `nextCursor=None`** when there are no more pages +- **Backward compatible** - clients that don't support pagination will still work (they'll just get the first page) +- **Flexible page sizes** - Each endpoint can define its own page size based on data characteristics + +See the [simple-pagination example](examples/servers/simple-pagination) for a complete implementation. + +### Writing MCP Clients + +The SDK provides a high-level client interface for connecting to MCP servers using various [transports](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports): + + +```python +""" +cd to the `examples/snippets/clients` directory and run: + uv run client +""" + +import asyncio +import os + +from pydantic import AnyUrl + +from mcp import ClientSession, StdioServerParameters, types +from mcp.client.stdio import stdio_client +from mcp.shared.context import RequestContext + +# Create server parameters for stdio connection +server_params = StdioServerParameters( + command="uv", # Using uv to run the server + args=["run", "server", "fastmcp_quickstart", "stdio"], # We're already in snippets dir + env={"UV_INDEX": os.environ.get("UV_INDEX", "")}, +) + + +# Optional: create a sampling callback +async def handle_sampling_message( + context: RequestContext[ClientSession, None], params: types.CreateMessageRequestParams +) -> types.CreateMessageResult: + print(f"Sampling request: {params.messages}") + return types.CreateMessageResult( + role="assistant", + content=types.TextContent( + type="text", + text="Hello, world! from model", + ), + model="gpt-3.5-turbo", + stopReason="endTurn", + ) + + +async def run(): + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write, sampling_callback=handle_sampling_message) as session: + # Initialize the connection + await session.initialize() + + # List available prompts + prompts = await session.list_prompts() + print(f"Available prompts: {[p.name for p in prompts.prompts]}") + + # Get a prompt (greet_user prompt from fastmcp_quickstart) + if prompts.prompts: + prompt = await session.get_prompt("greet_user", arguments={"name": "Alice", "style": "friendly"}) + print(f"Prompt result: {prompt.messages[0].content}") + + # List available resources + resources = await session.list_resources() + print(f"Available resources: {[r.uri for r in resources.resources]}") + + # List available tools + tools = await session.list_tools() + print(f"Available tools: {[t.name for t in tools.tools]}") + + # Read a resource (greeting resource from fastmcp_quickstart) + resource_content = await session.read_resource(AnyUrl("greeting://World")) + content_block = resource_content.contents[0] + if isinstance(content_block, types.TextContent): + print(f"Resource content: {content_block.text}") + + # Call a tool (add tool from fastmcp_quickstart) + result = await session.call_tool("add", arguments={"a": 5, "b": 3}) + result_unstructured = result.content[0] + if isinstance(result_unstructured, types.TextContent): + print(f"Tool result: {result_unstructured.text}") + result_structured = result.structuredContent + print(f"Structured tool result: {result_structured}") + + +def main(): + """Entry point for the client script.""" + asyncio.run(run()) + + +if __name__ == "__main__": + main() +``` + +_Full example: [examples/snippets/clients/stdio_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/stdio_client.py)_ + + +Clients can also connect using [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http): + + +```python +""" +Run from the repository root: + uv run examples/snippets/clients/streamable_basic.py +""" + +import asyncio + +from mcp import ClientSession +from mcp.client.streamable_http import streamable_http_client + + +async def main(): + # Connect to a streamable HTTP server + async with streamable_http_client("http://localhost:8000/mcp") as ( + read_stream, + write_stream, + _, + ): + # Create a session using the client streams + async with ClientSession(read_stream, write_stream) as session: + # Initialize the connection + await session.initialize() + # List available tools + tools = await session.list_tools() + print(f"Available tools: {[tool.name for tool in tools.tools]}") + + +if __name__ == "__main__": + asyncio.run(main()) +``` + +_Full example: [examples/snippets/clients/streamable_basic.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/streamable_basic.py)_ + + +### Client Display Utilities + +When building MCP clients, the SDK provides utilities to help display human-readable names for tools, resources, and prompts: + + +```python +""" +cd to the `examples/snippets` directory and run: + uv run display-utilities-client +""" + +import asyncio +import os + +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client +from mcp.shared.metadata_utils import get_display_name + +# Create server parameters for stdio connection +server_params = StdioServerParameters( + command="uv", # Using uv to run the server + args=["run", "server", "fastmcp_quickstart", "stdio"], + env={"UV_INDEX": os.environ.get("UV_INDEX", "")}, +) + + +async def display_tools(session: ClientSession): + """Display available tools with human-readable names""" + tools_response = await session.list_tools() + + for tool in tools_response.tools: + # get_display_name() returns the title if available, otherwise the name + display_name = get_display_name(tool) + print(f"Tool: {display_name}") + if tool.description: + print(f" {tool.description}") + + +async def display_resources(session: ClientSession): + """Display available resources with human-readable names""" + resources_response = await session.list_resources() + + for resource in resources_response.resources: + display_name = get_display_name(resource) + print(f"Resource: {display_name} ({resource.uri})") + + templates_response = await session.list_resource_templates() + for template in templates_response.resourceTemplates: + display_name = get_display_name(template) + print(f"Resource Template: {display_name}") + + +async def run(): + """Run the display utilities example.""" + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + # Initialize the connection + await session.initialize() + + print("=== Available Tools ===") + await display_tools(session) + + print("\n=== Available Resources ===") + await display_resources(session) + + +def main(): + """Entry point for the display utilities client.""" + asyncio.run(run()) + + +if __name__ == "__main__": + main() +``` + +_Full example: [examples/snippets/clients/display_utilities.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/display_utilities.py)_ + + +The `get_display_name()` function implements the proper precedence rules for displaying names: + +- For tools: `title` > `annotations.title` > `name` +- For other objects: `title` > `name` + +This ensures your client UI shows the most user-friendly names that servers provide. + +### OAuth Authentication for Clients + +The SDK includes [authorization support](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization) for connecting to protected MCP servers: + + +```python +""" +Before running, specify running MCP RS server URL. +To spin up RS server locally, see + examples/servers/simple-auth/README.md + +cd to the `examples/snippets` directory and run: + uv run oauth-client +""" + +import asyncio +from urllib.parse import parse_qs, urlparse + +import httpx +from pydantic import AnyUrl + +from mcp import ClientSession +from mcp.client.auth import OAuthClientProvider, TokenStorage +from mcp.client.streamable_http import streamable_http_client +from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken + + +class InMemoryTokenStorage(TokenStorage): + """Demo In-memory token storage implementation.""" + + def __init__(self): + self.tokens: OAuthToken | None = None + self.client_info: OAuthClientInformationFull | None = None + + async def get_tokens(self) -> OAuthToken | None: + """Get stored tokens.""" + return self.tokens + + async def set_tokens(self, tokens: OAuthToken) -> None: + """Store tokens.""" + self.tokens = tokens + + async def get_client_info(self) -> OAuthClientInformationFull | None: + """Get stored client information.""" + return self.client_info + + async def set_client_info(self, client_info: OAuthClientInformationFull) -> None: + """Store client information.""" + self.client_info = client_info + + +async def handle_redirect(auth_url: str) -> None: + print(f"Visit: {auth_url}") + + +async def handle_callback() -> tuple[str, str | None]: + callback_url = input("Paste callback URL: ") + params = parse_qs(urlparse(callback_url).query) + return params["code"][0], params.get("state", [None])[0] + + +async def main(): + """Run the OAuth client example.""" + oauth_auth = OAuthClientProvider( + server_url="http://localhost:8001", + client_metadata=OAuthClientMetadata( + client_name="Example MCP Client", + redirect_uris=[AnyUrl("http://localhost:3000/callback")], + grant_types=["authorization_code", "refresh_token"], + response_types=["code"], + scope="user", + ), + storage=InMemoryTokenStorage(), + redirect_handler=handle_redirect, + callback_handler=handle_callback, + ) + + async with httpx.AsyncClient(auth=oauth_auth, follow_redirects=True) as custom_client: + async with streamable_http_client("http://localhost:8001/mcp", http_client=custom_client) as (read, write, _): + async with ClientSession(read, write) as session: + await session.initialize() + + tools = await session.list_tools() + print(f"Available tools: {[tool.name for tool in tools.tools]}") + + resources = await session.list_resources() + print(f"Available resources: {[r.uri for r in resources.resources]}") + + +def run(): + asyncio.run(main()) + + +if __name__ == "__main__": + run() +``` + +_Full example: [examples/snippets/clients/oauth_client.py](https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/snippets/clients/oauth_client.py)_ + + +For a complete working example, see [`examples/clients/simple-auth-client/`](examples/clients/simple-auth-client/). + +### Parsing Tool Results + +When calling tools through MCP, the `CallToolResult` object contains the tool's response in a structured format. Understanding how to parse this result is essential for properly handling tool outputs. + +```python +"""examples/snippets/clients/parsing_tool_results.py""" + +import asyncio + +from mcp import ClientSession, StdioServerParameters, types +from mcp.client.stdio import stdio_client + + +async def parse_tool_results(): + """Demonstrates how to parse different types of content in CallToolResult.""" + server_params = StdioServerParameters( + command="python", args=["path/to/mcp_server.py"] + ) + + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + await session.initialize() + + # Example 1: Parsing text content + result = await session.call_tool("get_data", {"format": "text"}) + for content in result.content: + if isinstance(content, types.TextContent): + print(f"Text: {content.text}") + + # Example 2: Parsing structured content from JSON tools + result = await session.call_tool("get_user", {"id": "123"}) + if hasattr(result, "structuredContent") and result.structuredContent: + # Access structured data directly + user_data = result.structuredContent + print(f"User: {user_data.get('name')}, Age: {user_data.get('age')}") + + # Example 3: Parsing embedded resources + result = await session.call_tool("read_config", {}) + for content in result.content: + if isinstance(content, types.EmbeddedResource): + resource = content.resource + if isinstance(resource, types.TextResourceContents): + print(f"Config from {resource.uri}: {resource.text}") + elif isinstance(resource, types.BlobResourceContents): + print(f"Binary data from {resource.uri}") + + # Example 4: Parsing image content + result = await session.call_tool("generate_chart", {"data": [1, 2, 3]}) + for content in result.content: + if isinstance(content, types.ImageContent): + print(f"Image ({content.mimeType}): {len(content.data)} bytes") + + # Example 5: Handling errors + result = await session.call_tool("failing_tool", {}) + if result.isError: + print("Tool execution failed!") + for content in result.content: + if isinstance(content, types.TextContent): + print(f"Error: {content.text}") + + +async def main(): + await parse_tool_results() + + +if __name__ == "__main__": + asyncio.run(main()) +``` + +### MCP Primitives + +The MCP protocol defines three core primitives that servers can implement: + +| Primitive | Control | Description | Example Use | +|-----------|-----------------------|-----------------------------------------------------|------------------------------| +| Prompts | User-controlled | Interactive templates invoked by user choice | Slash commands, menu options | +| Resources | Application-controlled| Contextual data managed by the client application | File contents, API responses | +| Tools | Model-controlled | Functions exposed to the LLM to take actions | API calls, data updates | + +### Server Capabilities + +MCP servers declare capabilities during initialization: + +| Capability | Feature Flag | Description | +|--------------|------------------------------|------------------------------------| +| `prompts` | `listChanged` | Prompt template management | +| `resources` | `subscribe`
      `listChanged`| Resource exposure and updates | +| `tools` | `listChanged` | Tool discovery and execution | +| `logging` | - | Server logging configuration | +| `completions`| - | Argument completion suggestions | + +## Documentation + +- [API Reference](https://modelcontextprotocol.github.io/python-sdk/api/) +- [Experimental Features (Tasks)](https://modelcontextprotocol.github.io/python-sdk/experimental/tasks/) +- [Model Context Protocol documentation](https://modelcontextprotocol.io) +- [Model Context Protocol specification](https://modelcontextprotocol.io/specification/latest) +- [Officially supported servers](https://github.com/modelcontextprotocol/servers) + +## Contributing + +We are passionate about supporting contributors of all levels of experience and would love to see you get involved in the project. See the [contributing guide](CONTRIBUTING.md) to get started. + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/source/target-vendors/cp312/mcp-1.26.0.dist-info/RECORD b/source/target-vendors/cp312/mcp-1.26.0.dist-info/RECORD new file mode 100644 index 0000000..66e4ac7 --- /dev/null +++ b/source/target-vendors/cp312/mcp-1.26.0.dist-info/RECORD @@ -0,0 +1,115 @@ +mcp/__init__.py,sha256=9mrheVmhQg7bZ2JNzXnaIIYFQ-HVE7fVyG7AJQz4r3I,3224 +mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mcp/types.py,sha256=aCQQnNHquvQ8XauCmoMBWxuI7JrhSXZeaBSvryP5veU,64908 +mcp/cli/__init__.py,sha256=NJrJIUQmjc6FtSxvGNt1zeXnSLj8-Mli86laODTtQzE,107 +mcp/cli/claude.py,sha256=MKUuZGrBmMSslD2weLIxU7RdQXZl2OvuMMq-_-EAlgY,5086 +mcp/cli/cli.py,sha256=w6mWBmcy4y7nxLQDa4qSbxKV0BWeJqU_SFZf3qdOubs,15179 +mcp/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mcp/client/__main__.py,sha256=_aXYJ3xJiQGURxEEfvV-4MAqxRJwIFptFaLHyJgfvRU,2588 +mcp/client/session.py,sha256=A31De5OwhsBRD-iF32lraArJQ_vYHJYkYYrI_XudAX8,23495 +mcp/client/session_group.py,sha256=wXt4sZI-WRXdy5PPv-hNwRhMuzEhKMkQf3bFvaOITEc,17423 +mcp/client/sse.py,sha256=foXGvt297jQOFV0AnFVfQhqRZVlnp1REjW7R1Bl1FFc,8257 +mcp/client/streamable_http.py,sha256=jrAcPU2onG5z1JSpYCnbzy_gXQv__nYHGx5Amv22L1s,28324 +mcp/client/websocket.py,sha256=mH6zD_nRnMr11uSFdDTy2TZ2YeS9S18v-JJ2rQ7tXck,3486 +mcp/client/auth/__init__.py,sha256=hvlPclaDk3EkHr_nrt6tx37iv_rQ8SQgosM0OhJSeQ4,488 +mcp/client/auth/exceptions.py,sha256=uUDHX_P0S3R_tt7oAS8ALQrUgOiV2Dgc0QQAdaaBcW8,264 +mcp/client/auth/oauth2.py,sha256=4n8H8M5-2rCXH9kBX81ZDkKW4XEhY5N8U3B018cIYuk,27638 +mcp/client/auth/utils.py,sha256=Mm443kj9pHY09mUYflmr89W8jexZalvDS96b_31tUIE,12069 +mcp/client/auth/extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mcp/client/auth/extensions/client_credentials.py,sha256=XvCarBQnB4DREuYEVygZbe0P9Wj7z8dSx_3SqajMKzQ,20897 +mcp/client/experimental/__init__.py,sha256=r923QPMrHQbLQYA_F48MLy2Y8ODdPWJhx8SuzhXcaEA,219 +mcp/client/experimental/task_handlers.py,sha256=yDrCoiCha5iBBVpjqZ66uk3ZoDiQznqU29xKGY4Dh_Q,10791 +mcp/client/experimental/tasks.py,sha256=LLEbfmIwCNk0PCpPSnhK6U0dcaqxENbdzLQXeGsqVjI,7055 +mcp/client/stdio/__init__.py,sha256=ojInz-HjRW8Wq0ExFIajmc9Uf8xrZFOZv5vzptxs9lQ,9403 +mcp/os/__init__.py,sha256=uqaGIfCF4I0IPeSsEEZMNwZuDF91U0WKAIbDcKzPRLo,43 +mcp/os/posix/__init__.py,sha256=l_2j8jhhgw69s_-eH4dCDk4QYxNlxKGIpaOCvcbv1Qk,40 +mcp/os/posix/utilities.py,sha256=mTEYV74M9z9s2deXWctpUGTS1MNtkOr7IYCXU3mxlNI,1930 +mcp/os/win32/__init__.py,sha256=7xyI7KWpZhDS3omGEBcu3200Q-DjIsS7c-a-vrn28Y4,42 +mcp/os/win32/utilities.py,sha256=M5j9NF9QhgCHqQeHYpc9z0ksFsNy1F43vYqQl3LXq-Y,10808 +mcp/server/__init__.py,sha256=jeMjAkvChhKLEy1fpeKJ4d_bT1vnnmuGm11otQ7ncBg,202 +mcp/server/__main__.py,sha256=KakUSquF7R44Ugwg3N5VQCJsPnsEVrbwk-UnRHerVww,1328 +mcp/server/elicitation.py,sha256=euqjotipBszsirdZurr2fbKemRYwR7-zlZlijwMdSNY,6917 +mcp/server/models.py,sha256=w-xEPy_qGds2_bEpejN6iaWeh0UvMtKqwlXzPN_ChZ0,422 +mcp/server/session.py,sha256=A0pB1LsQnWgJUowQDhUy45BZHY2_qi29fuJ26jLPc0k,27555 +mcp/server/sse.py,sha256=QqzE9gWpG35HfQo6gbsCmZPV4ud02EtZcewNGTwKvF8,10826 +mcp/server/stdio.py,sha256=LkFigRZC4uIDUA2JjnsKlgOuLh9IWFBNVgHcs97JsM8,3358 +mcp/server/streamable_http.py,sha256=75k3sVYmcBe6t0zmk0XgiOuAq3RSMCr50j8248Wy7W0,46836 +mcp/server/streamable_http_manager.py,sha256=OoFoMo4CUKCVbRgVzsI5-MsLS4qj7rWSMBdrkem8uu4,12183 +mcp/server/transport_security.py,sha256=T8oLE1lh2WXW6cVvPiNUSmG5WmxMvdCCXkm7JdSvmIs,4938 +mcp/server/validation.py,sha256=owYWMCEg5KLesnXmNbyaTifJyJKJYp79FszXgLPsG7c,3633 +mcp/server/websocket.py,sha256=sw9aSmyhOZlqK-jPQd9RS03zn9XaLR4D6HL6vi8DtBY,2352 +mcp/server/auth/__init__.py,sha256=xmxBzGAYvejOEzxqvZxiRkootIdlpp5WrCNiPKvuKdk,51 +mcp/server/auth/errors.py,sha256=8YjlejJPl-qMjZrbJTDzMPBOAOITn0Da0pC5QWn9QdE,224 +mcp/server/auth/json_response.py,sha256=EMv3qAH62vRuw8XBHdFU3kYp0S8Jd6DjRGfwc7Jc9XU,377 +mcp/server/auth/provider.py,sha256=itp10kM6TGcQGL_zMUVpQ28FK3p-q_zFK5V3CJNoHBE,9846 +mcp/server/auth/routes.py,sha256=j4B5b2Pw2VJnCOq3bW2t3mRvgxJ3oI5wzQn0z3AlZ50,9131 +mcp/server/auth/settings.py,sha256=Nj8tNCXANHMCmX6nxCa-GUrA9knJ9f8zCuMxMDFN4D4,1031 +mcp/server/auth/handlers/__init__.py,sha256=T2ueQWVpLDbMIAiOcROyumxRwqa8Po5lA9zd_Cbt2Uc,58 +mcp/server/auth/handlers/authorize.py,sha256=fAz-L-5Qv6KeHjpoBOAUE6sYgTuG0ydPA7y2xjb4pIM,9728 +mcp/server/auth/handlers/metadata.py,sha256=mWPkrs1DfG-Qzq1nZU2HzwxSwk8K_vXe-ZpEDZ0k_QA,853 +mcp/server/auth/handlers/register.py,sha256=CtH9c03oZtJgUoBVr-VgrAoJ6WXBw2RGNk5n70eBlPc,5928 +mcp/server/auth/handlers/revoke.py,sha256=DIVjn09k7qTkAXrkTsRBVlR-XM9rsmTJzKlXyNdJqDE,3113 +mcp/server/auth/handlers/token.py,sha256=yt5kUvB8zhBgONpYZJOQTFyoJZBhC0UKPUE3GQMkots,10223 +mcp/server/auth/middleware/__init__.py,sha256=XhRUi_w-ie_QG7XT5EfqNG-NPZvXtJtgHSB_tPVYNIw,42 +mcp/server/auth/middleware/auth_context.py,sha256=0hYDUr2GL0VqTVQtCCZCDop2JwGox_IuD0XBZQbtpT0,1696 +mcp/server/auth/middleware/bearer_auth.py,sha256=-t3Ar5bNuIJtYSlF2CsvmAozEX2uySo4chp2Rzgbw4s,4423 +mcp/server/auth/middleware/client_auth.py,sha256=lIIGufkj8rwkNVjh63tPH1UOY5h4Bc08zuvGmubUz40,4723 +mcp/server/experimental/__init__.py,sha256=DtyLxeneqNnUc4ZDKeD9KBFEX9ku2iRwOqsME9k5Gvc,373 +mcp/server/experimental/request_context.py,sha256=MAH7Z-Xoe0vENzcPtu4_lVGywDZHp-7FaUJ8bYDt8Jo,8448 +mcp/server/experimental/session_features.py,sha256=fwwIb-Uj2hhjnrE2ZOfEL5Y5UgNa8gg8SiIl5QpN8YA,7870 +mcp/server/experimental/task_context.py,sha256=M970tK_ZM_mle0gRfgSTvd5NztUMW5Wx3yCYExRfo8I,23021 +mcp/server/experimental/task_result_handler.py,sha256=EyTcsYcdwzK49_z8RnBfRX1WQKaFcEzKF3tnpEIUcvg,8379 +mcp/server/experimental/task_support.py,sha256=gP2NiEIaycpRsLa0ThQG8VFOoMGUaoh0mrn4BNfQChQ,3691 +mcp/server/fastmcp/__init__.py,sha256=4EnleAYdPF_hgPexfq2zxGRtU_Fd3ZrjXegKckuj-K8,297 +mcp/server/fastmcp/exceptions.py,sha256=q9djUDmpwmGEWcHI8q4UzJBtf7s7UtgL--OB7OaGzyQ,435 +mcp/server/fastmcp/server.py,sha256=q9Jb2B34oDCO66kM3htygwfYUsfv4Ku54KXGrPW3ubc,52706 +mcp/server/fastmcp/prompts/__init__.py,sha256=4BsMxoYolpoxg74xkkkzCFL8vvdkLVJ5cIPNs1ND1Jo,99 +mcp/server/fastmcp/prompts/base.py,sha256=s5-zpCjfd-LLbqMoa2oJnzUoVUGW4EVhi8ufvWSjHns,7088 +mcp/server/fastmcp/prompts/manager.py,sha256=IXIv__muOQhXgipCmKWJ4cyPjjawWkjmeahe6G29oyU,1835 +mcp/server/fastmcp/resources/__init__.py,sha256=e4S369jBoJt07ez9_ZaJefzGfz4kr9nGwG4KPMzMHc8,464 +mcp/server/fastmcp/resources/base.py,sha256=aw7d46dfMGCz9fYNtShxCJ9PlnNGmoev4JfPpstC8xI,1852 +mcp/server/fastmcp/resources/resource_manager.py,sha256=f_yS7f4-hs-RryiLHlxXmf68bHd4cZnIPkmXbwzhaVg,4007 +mcp/server/fastmcp/resources/templates.py,sha256=dLcTfoEV6nu8CkDq7WsNI1qmwGFan4mMewvYUroLPPA,4947 +mcp/server/fastmcp/resources/types.py,sha256=g6bfXFNGGfoOGiq37TMvG87kxXrgjSgV6UzLS4M6Lz4,7214 +mcp/server/fastmcp/tools/__init__.py,sha256=ZboxhyMJDl87Svjov8YwNYwNZi55P9VhmpTjBZLesnk,96 +mcp/server/fastmcp/tools/base.py,sha256=h2JrpiTTMhj_t1QhQNyIhFPjMTD97-rciQnUe8YAylQ,4740 +mcp/server/fastmcp/tools/tool_manager.py,sha256=rNjJ6_ug6HZEJuYIaN7qqTGgEqiCTha6T0eeSZG9KnY,2972 +mcp/server/fastmcp/utilities/__init__.py,sha256=-imJ8S-rXmbXMWeDamldP-dHDqAPg_wwmPVz-LNX14E,31 +mcp/server/fastmcp/utilities/context_injection.py,sha256=BVm4Svi5RK-nlscwYZT75WuLPccRAJ_INdZxxVSM-lg,2028 +mcp/server/fastmcp/utilities/func_metadata.py,sha256=unwzYeTu8JRVxqYZe-jiCEdtia2KpOnKHWiTEXugBjc,22121 +mcp/server/fastmcp/utilities/logging.py,sha256=e8kBHAYHB00gntMTaWMN6uT4kwiiOdL14qDXEZU0x-k,1063 +mcp/server/fastmcp/utilities/types.py,sha256=xXRshurGRIjVnr1lVPwcZomSSN4_wvxpNb2jS6RUCw4,3546 +mcp/server/lowlevel/__init__.py,sha256=mS7slrVoWzHMYqDHDIJ7oRZxwPZG_I63UVQiJN311YY,93 +mcp/server/lowlevel/experimental.py,sha256=s0BoxBuMKXXmINiShqBOo456PWyKF4Juf9PG8ydE4V0,10545 +mcp/server/lowlevel/func_inspection.py,sha256=uLEpY5IHgWicIfbYbaI4aDYfUgMRxuFdTu20duvH2pw,2466 +mcp/server/lowlevel/helper_types.py,sha256=LVC0N6JMPynVs4fMJSfBmqKIigHNLsRNhBvbU06rg6A,251 +mcp/server/lowlevel/server.py,sha256=kQiQVVOV3oMD3q72SWOwVkQ_DgvdHSL2GlFIHXDDvao,33499 +mcp/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +mcp/shared/_httpx_utils.py,sha256=bfvypq5zsbvL4dgtNfX-lp8R_FqmzDtWEK61K7Y-Sos,2906 +mcp/shared/auth.py,sha256=KndMQ-tXUUGZzXw4fx_2QFLhcGBzQCQi9w8MF6eNSVU,6446 +mcp/shared/auth_utils.py,sha256=urxND9gJd48mHI0XgwjLx5Eq2GlMBrs4y9HebSQtyY4,3006 +mcp/shared/context.py,sha256=QMRHwXCIJsvf4U3vcgqSAXaaUEMKhfj_9XlCI-kUknE,1188 +mcp/shared/exceptions.py,sha256=glHYWFVmdInhHRnlwrpr5w_iALLM0OlNZAM3djNBDXg,2433 +mcp/shared/memory.py,sha256=DtPFbfalB14Nm5hZS5zZLAwrIkqwZFVcBUwFcBAU1TM,3951 +mcp/shared/message.py,sha256=K7wy_fCaPo7p0r8_2Pd223Ab0Q9DMABuCitK3xq0cQI,1550 +mcp/shared/metadata_utils.py,sha256=9Tp9b0PkfjBhm2SlwHnod1W4Bf6vZB0p5J2E7Sv25U4,1712 +mcp/shared/progress.py,sha256=Ys4V_DTQhYsug6KS6Bb3E4T0CDyOOaIecIXAIMFs1tU,1756 +mcp/shared/response_router.py,sha256=en9M764wGHNkWl6dn9Ki7amIRCclHaKsfbnTfpL9KR0,2043 +mcp/shared/session.py,sha256=N5J5m4Y2mnYy1ujy7-yxGLu8fNaau1S7FPawecsJ1_Q,24086 +mcp/shared/tool_name_validation.py,sha256=mTEvgzsMskayyilLaIkP7lIaA4je8cnkj9xYIc6htgo,4531 +mcp/shared/version.py,sha256=GKwM5WHAwd2Dmrq7TyrAHEGWhTO_9UKJJUmC791JcMk,156 +mcp/shared/experimental/__init__.py,sha256=BhhD176Lv_NmLZ3nK6n3zVyCbCxEj5VMwPuqjm3fqcs,209 +mcp/shared/experimental/tasks/__init__.py,sha256=jYCm-mbvvEblzcSWEvQMTlbRD3iUJss-PGF4sMI9OMc,433 +mcp/shared/experimental/tasks/capabilities.py,sha256=wkO_u4698o5yYtV8RPCRj0oaKWfQLMk7l05-ICdjGmo,3571 +mcp/shared/experimental/tasks/context.py,sha256=an3XBnocKUwdlKX8hR71wowzDixBKwsUe9uCBXrsq1w,2875 +mcp/shared/experimental/tasks/helpers.py,sha256=OF7obHXpVoQmrqft-ZcEXOA9bY8xHvnMfd2YGz3xeLo,5517 +mcp/shared/experimental/tasks/in_memory_task_store.py,sha256=cmCPo59XOQPe-kF5uG1Yd-6nHZDaOhrEZJZc35v3I8U,7558 +mcp/shared/experimental/tasks/message_queue.py,sha256=vf5Dmwb-XkpytbK6TixouFWj8ci0wxeN2STpj7IUoiw,7436 +mcp/shared/experimental/tasks/polling.py,sha256=6BCbo7hYGG19bG_RJUYvnYLJ65WHWbWJ9gwri7Aiw80,1369 +mcp/shared/experimental/tasks/resolver.py,sha256=5VvPexlwcL1TZq2j_7fAdMziYlbHDNHk1UW4l1hVH1M,1801 +mcp/shared/experimental/tasks/store.py,sha256=552Kbp7UqLoIruPZnrIkZFu5m0iiQz0quNuHOKI-Yts,3808 +mcp-1.26.0.dist-info/METADATA,sha256=faPMQb0c9UArFqMQZ9WdGFxZdVjfGHy2I71OQ-hBlws,89485 +mcp-1.26.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87 +mcp-1.26.0.dist-info/entry_points.txt,sha256=gnGBbo3yGF0YJNXfZpgkAg1-CQtKxnzxrlA53c8viYA,42 +mcp-1.26.0.dist-info/licenses/LICENSE,sha256=XhPbvB0SD8KgPOzefJFCSuLX3hG2PVje0vRDHiYe5Q0,1071 +mcp-1.26.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/mcp-1.26.0.dist-info/WHEEL b/source/target-vendors/cp312/mcp-1.26.0.dist-info/WHEEL new file mode 100644 index 0000000..ae8ec1b --- /dev/null +++ b/source/target-vendors/cp312/mcp-1.26.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.28.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/mcp-1.26.0.dist-info/entry_points.txt b/source/target-vendors/cp312/mcp-1.26.0.dist-info/entry_points.txt new file mode 100644 index 0000000..df7969b --- /dev/null +++ b/source/target-vendors/cp312/mcp-1.26.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +mcp = mcp.cli:app [cli] diff --git a/source/target-vendors/cp312/mcp-1.26.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/mcp-1.26.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..3d48435 --- /dev/null +++ b/source/target-vendors/cp312/mcp-1.26.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Anthropic, PBC + +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/source/target-vendors/cp312/mcp/__init__.py b/source/target-vendors/cp312/mcp/__init__.py new file mode 100644 index 0000000..fbec40d --- /dev/null +++ b/source/target-vendors/cp312/mcp/__init__.py @@ -0,0 +1,135 @@ +from .client.session import ClientSession +from .client.session_group import ClientSessionGroup +from .client.stdio import StdioServerParameters, stdio_client +from .server.session import ServerSession +from .server.stdio import stdio_server +from .shared.exceptions import McpError, UrlElicitationRequiredError +from .types import ( + CallToolRequest, + ClientCapabilities, + ClientNotification, + ClientRequest, + ClientResult, + CompleteRequest, + CreateMessageRequest, + CreateMessageResult, + CreateMessageResultWithTools, + ErrorData, + GetPromptRequest, + GetPromptResult, + Implementation, + IncludeContext, + InitializedNotification, + InitializeRequest, + InitializeResult, + JSONRPCError, + JSONRPCRequest, + JSONRPCResponse, + ListPromptsRequest, + ListPromptsResult, + ListResourcesRequest, + ListResourcesResult, + ListToolsResult, + LoggingLevel, + LoggingMessageNotification, + Notification, + PingRequest, + ProgressNotification, + PromptsCapability, + ReadResourceRequest, + ReadResourceResult, + Resource, + ResourcesCapability, + ResourceUpdatedNotification, + RootsCapability, + SamplingCapability, + SamplingContent, + SamplingContextCapability, + SamplingMessage, + SamplingMessageContentBlock, + SamplingToolsCapability, + ServerCapabilities, + ServerNotification, + ServerRequest, + ServerResult, + SetLevelRequest, + StopReason, + SubscribeRequest, + Tool, + ToolChoice, + ToolResultContent, + ToolsCapability, + ToolUseContent, + UnsubscribeRequest, +) +from .types import ( + Role as SamplingRole, +) + +__all__ = [ + "CallToolRequest", + "ClientCapabilities", + "ClientNotification", + "ClientRequest", + "ClientResult", + "ClientSession", + "ClientSessionGroup", + "CompleteRequest", + "CreateMessageRequest", + "CreateMessageResult", + "CreateMessageResultWithTools", + "ErrorData", + "GetPromptRequest", + "GetPromptResult", + "Implementation", + "IncludeContext", + "InitializeRequest", + "InitializeResult", + "InitializedNotification", + "JSONRPCError", + "JSONRPCRequest", + "JSONRPCResponse", + "ListPromptsRequest", + "ListPromptsResult", + "ListResourcesRequest", + "ListResourcesResult", + "ListToolsResult", + "LoggingLevel", + "LoggingMessageNotification", + "McpError", + "Notification", + "PingRequest", + "ProgressNotification", + "PromptsCapability", + "ReadResourceRequest", + "ReadResourceResult", + "Resource", + "ResourcesCapability", + "ResourceUpdatedNotification", + "RootsCapability", + "SamplingCapability", + "SamplingContent", + "SamplingContextCapability", + "SamplingMessage", + "SamplingMessageContentBlock", + "SamplingRole", + "SamplingToolsCapability", + "ServerCapabilities", + "ServerNotification", + "ServerRequest", + "ServerResult", + "ServerSession", + "SetLevelRequest", + "StdioServerParameters", + "StopReason", + "SubscribeRequest", + "Tool", + "ToolChoice", + "ToolResultContent", + "ToolsCapability", + "ToolUseContent", + "UnsubscribeRequest", + "UrlElicitationRequiredError", + "stdio_client", + "stdio_server", +] diff --git a/source/target-vendors/cp312/mcp/cli/__init__.py b/source/target-vendors/cp312/mcp/cli/__init__.py new file mode 100644 index 0000000..b29bce8 --- /dev/null +++ b/source/target-vendors/cp312/mcp/cli/__init__.py @@ -0,0 +1,6 @@ +"""FastMCP CLI package.""" + +from .cli import app + +if __name__ == "__main__": # pragma: no cover + app() diff --git a/source/target-vendors/cp312/mcp/cli/claude.py b/source/target-vendors/cp312/mcp/cli/claude.py new file mode 100644 index 0000000..f2dc688 --- /dev/null +++ b/source/target-vendors/cp312/mcp/cli/claude.py @@ -0,0 +1,148 @@ +"""Claude app integration utilities.""" + +import json +import os +import shutil +import sys +from pathlib import Path +from typing import Any + +from mcp.server.fastmcp.utilities.logging import get_logger + +logger = get_logger(__name__) + +MCP_PACKAGE = "mcp[cli]" + + +def get_claude_config_path() -> Path | None: # pragma: no cover + """Get the Claude config directory based on platform.""" + if sys.platform == "win32": + path = Path(Path.home(), "AppData", "Roaming", "Claude") + elif sys.platform == "darwin": + path = Path(Path.home(), "Library", "Application Support", "Claude") + elif sys.platform.startswith("linux"): + path = Path(os.environ.get("XDG_CONFIG_HOME", Path.home() / ".config"), "Claude") + else: + return None + + if path.exists(): + return path + return None + + +def get_uv_path() -> str: + """Get the full path to the uv executable.""" + uv_path = shutil.which("uv") + if not uv_path: # pragma: no cover + logger.error( + "uv executable not found in PATH, falling back to 'uv'. Please ensure uv is installed and in your PATH" + ) + return "uv" # Fall back to just "uv" if not found + return uv_path + + +def update_claude_config( + file_spec: str, + server_name: str, + *, + with_editable: Path | None = None, + with_packages: list[str] | None = None, + env_vars: dict[str, str] | None = None, +) -> bool: + """Add or update a FastMCP server in Claude's configuration. + + Args: + file_spec: Path to the server file, optionally with :object suffix + server_name: Name for the server in Claude's config + with_editable: Optional directory to install in editable mode + with_packages: Optional list of additional packages to install + env_vars: Optional dictionary of environment variables. These are merged with + any existing variables, with new values taking precedence. + + Raises: + RuntimeError: If Claude Desktop's config directory is not found, indicating + Claude Desktop may not be installed or properly set up. + """ + config_dir = get_claude_config_path() + uv_path = get_uv_path() + if not config_dir: # pragma: no cover + raise RuntimeError( + "Claude Desktop config directory not found. Please ensure Claude Desktop" + " is installed and has been run at least once to initialize its config." + ) + + config_file = config_dir / "claude_desktop_config.json" + if not config_file.exists(): # pragma: no cover + try: + config_file.write_text("{}") + except Exception: + logger.exception( + "Failed to create Claude config file", + extra={ + "config_file": str(config_file), + }, + ) + return False + + try: + config = json.loads(config_file.read_text()) + if "mcpServers" not in config: + config["mcpServers"] = {} + + # Always preserve existing env vars and merge with new ones + if server_name in config["mcpServers"] and "env" in config["mcpServers"][server_name]: # pragma: no cover + existing_env = config["mcpServers"][server_name]["env"] + if env_vars: + # New vars take precedence over existing ones + env_vars = {**existing_env, **env_vars} + else: + env_vars = existing_env + + # Build uv run command + args = ["run", "--frozen"] + + # Collect all packages in a set to deduplicate + packages = {MCP_PACKAGE} + if with_packages: # pragma: no cover + packages.update(pkg for pkg in with_packages if pkg) + + # Add all packages with --with + for pkg in sorted(packages): + args.extend(["--with", pkg]) + + if with_editable: # pragma: no cover + args.extend(["--with-editable", str(with_editable)]) + + # Convert file path to absolute before adding to command + # Split off any :object suffix first + if ":" in file_spec: + file_path, server_object = file_spec.rsplit(":", 1) + file_spec = f"{Path(file_path).resolve()}:{server_object}" + else: # pragma: no cover + file_spec = str(Path(file_spec).resolve()) + + # Add fastmcp run command + args.extend(["mcp", "run", file_spec]) + + server_config: dict[str, Any] = {"command": uv_path, "args": args} + + # Add environment variables if specified + if env_vars: # pragma: no cover + server_config["env"] = env_vars + + config["mcpServers"][server_name] = server_config + + config_file.write_text(json.dumps(config, indent=2)) + logger.info( + f"Added server '{server_name}' to Claude config", + extra={"config_file": str(config_file)}, + ) + return True + except Exception: # pragma: no cover + logger.exception( + "Failed to update Claude config", + extra={ + "config_file": str(config_file), + }, + ) + return False diff --git a/source/target-vendors/cp312/mcp/cli/cli.py b/source/target-vendors/cp312/mcp/cli/cli.py new file mode 100644 index 0000000..c4cae0d --- /dev/null +++ b/source/target-vendors/cp312/mcp/cli/cli.py @@ -0,0 +1,488 @@ +"""MCP CLI tools.""" + +import importlib.metadata +import importlib.util +import os +import subprocess +import sys +from pathlib import Path +from typing import Annotated, Any + +from mcp.server import FastMCP +from mcp.server import Server as LowLevelServer + +try: + import typer +except ImportError: # pragma: no cover + print("Error: typer is required. Install with 'pip install mcp[cli]'") + sys.exit(1) + +try: + from mcp.cli import claude + from mcp.server.fastmcp.utilities.logging import get_logger +except ImportError: # pragma: no cover + print("Error: mcp.server.fastmcp is not installed or not in PYTHONPATH") + sys.exit(1) + +try: + import dotenv +except ImportError: # pragma: no cover + dotenv = None + +logger = get_logger("cli") + +app = typer.Typer( + name="mcp", + help="MCP development tools", + add_completion=False, + no_args_is_help=True, # Show help if no args provided +) + + +def _get_npx_command(): + """Get the correct npx command for the current platform.""" + if sys.platform == "win32": + # Try both npx.cmd and npx.exe on Windows + for cmd in ["npx.cmd", "npx.exe", "npx"]: + try: + subprocess.run([cmd, "--version"], check=True, capture_output=True, shell=True) + return cmd + except subprocess.CalledProcessError: + continue + return None + return "npx" # On Unix-like systems, just use npx + + +def _parse_env_var(env_var: str) -> tuple[str, str]: # pragma: no cover + """Parse environment variable string in format KEY=VALUE.""" + if "=" not in env_var: + logger.error(f"Invalid environment variable format: {env_var}. Must be KEY=VALUE") + sys.exit(1) + key, value = env_var.split("=", 1) + return key.strip(), value.strip() + + +def _build_uv_command( + file_spec: str, + with_editable: Path | None = None, + with_packages: list[str] | None = None, +) -> list[str]: + """Build the uv run command that runs an MCP server through mcp run.""" + cmd = ["uv"] + + cmd.extend(["run", "--with", "mcp"]) + + if with_editable: + cmd.extend(["--with-editable", str(with_editable)]) + + if with_packages: + for pkg in with_packages: + if pkg: # pragma: no cover + cmd.extend(["--with", pkg]) + + # Add mcp run command + cmd.extend(["mcp", "run", file_spec]) + return cmd + + +def _parse_file_path(file_spec: str) -> tuple[Path, str | None]: + """Parse a file path that may include a server object specification. + + Args: + file_spec: Path to file, optionally with :object suffix + + Returns: + Tuple of (file_path, server_object) + """ + # First check if we have a Windows path (e.g., C:\...) + has_windows_drive = len(file_spec) > 1 and file_spec[1] == ":" + + # Split on the last colon, but only if it's not part of the Windows drive letter + # and there's actually another colon in the string after the drive letter + if ":" in (file_spec[2:] if has_windows_drive else file_spec): + file_str, server_object = file_spec.rsplit(":", 1) + else: + file_str, server_object = file_spec, None + + # Resolve the file path + file_path = Path(file_str).expanduser().resolve() + if not file_path.exists(): + logger.error(f"File not found: {file_path}") + sys.exit(1) + if not file_path.is_file(): + logger.error(f"Not a file: {file_path}") + sys.exit(1) + + return file_path, server_object + + +def _import_server(file: Path, server_object: str | None = None): # pragma: no cover + """Import an MCP server from a file. + + Args: + file: Path to the file + server_object: Optional object name in format "module:object" or just "object" + + Returns: + The server object + """ + # Add parent directory to Python path so imports can be resolved + file_dir = str(file.parent) + if file_dir not in sys.path: + sys.path.insert(0, file_dir) + + # Import the module + spec = importlib.util.spec_from_file_location("server_module", file) + if not spec or not spec.loader: + logger.error("Could not load module", extra={"file": str(file)}) + sys.exit(1) + + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + def _check_server_object(server_object: Any, object_name: str): + """Helper function to check that the server object is supported + + Args: + server_object: The server object to check. + + Returns: + True if it's supported. + """ + if not isinstance(server_object, FastMCP): + logger.error(f"The server object {object_name} is of type {type(server_object)} (expecting {FastMCP}).") + if isinstance(server_object, LowLevelServer): + logger.warning( + "Note that only FastMCP server is supported. Low level Server class is not yet supported." + ) + return False + return True + + # If no object specified, try common server names + if not server_object: + # Look for the most common server object names + for name in ["mcp", "server", "app"]: + if hasattr(module, name): + if not _check_server_object(getattr(module, name), f"{file}:{name}"): + logger.error(f"Ignoring object '{file}:{name}' as it's not a valid server object") + continue + return getattr(module, name) + + logger.error( + f"No server object found in {file}. Please either:\n" + "1. Use a standard variable name (mcp, server, or app)\n" + "2. Specify the object name with file:object syntax" + "3. If the server creates the FastMCP object within main() " + " or another function, refactor the FastMCP object to be a " + " global variable named mcp, server, or app.", + extra={"file": str(file)}, + ) + sys.exit(1) + + # Handle module:object syntax + if ":" in server_object: + module_name, object_name = server_object.split(":", 1) + try: + server_module = importlib.import_module(module_name) + server = getattr(server_module, object_name, None) + except ImportError: + logger.error( + f"Could not import module '{module_name}'", + extra={"file": str(file)}, + ) + sys.exit(1) + else: + # Just object name + server = getattr(module, server_object, None) + + if server is None: + logger.error( + f"Server object '{server_object}' not found", + extra={"file": str(file)}, + ) + sys.exit(1) + + if not _check_server_object(server, server_object): + sys.exit(1) + + return server + + +@app.command() +def version() -> None: # pragma: no cover + """Show the MCP version.""" + try: + version = importlib.metadata.version("mcp") + print(f"MCP version {version}") + except importlib.metadata.PackageNotFoundError: + print("MCP version unknown (package not installed)") + sys.exit(1) + + +@app.command() +def dev( + file_spec: str = typer.Argument( + ..., + help="Python file to run, optionally with :object suffix", + ), + with_editable: Annotated[ + Path | None, + typer.Option( + "--with-editable", + "-e", + help="Directory containing pyproject.toml to install in editable mode", + exists=True, + file_okay=False, + resolve_path=True, + ), + ] = None, + with_packages: Annotated[ + list[str], + typer.Option( + "--with", + help="Additional packages to install", + ), + ] = [], +) -> None: # pragma: no cover + """Run an MCP server with the MCP Inspector.""" + file, server_object = _parse_file_path(file_spec) + + logger.debug( + "Starting dev server", + extra={ + "file": str(file), + "server_object": server_object, + "with_editable": str(with_editable) if with_editable else None, + "with_packages": with_packages, + }, + ) + + try: + # Import server to get dependencies + server = _import_server(file, server_object) + if hasattr(server, "dependencies"): + with_packages = list(set(with_packages + server.dependencies)) + + uv_cmd = _build_uv_command(file_spec, with_editable, with_packages) + + # Get the correct npx command + npx_cmd = _get_npx_command() + if not npx_cmd: + logger.error( + "npx not found. Please ensure Node.js and npm are properly installed and added to your system PATH." + ) + sys.exit(1) + + # Run the MCP Inspector command with shell=True on Windows + shell = sys.platform == "win32" + process = subprocess.run( + [npx_cmd, "@modelcontextprotocol/inspector"] + uv_cmd, + check=True, + shell=shell, + env=dict(os.environ.items()), # Convert to list of tuples for env update + ) + sys.exit(process.returncode) + except subprocess.CalledProcessError as e: + logger.error( + "Dev server failed", + extra={ + "file": str(file), + "error": str(e), + "returncode": e.returncode, + }, + ) + sys.exit(e.returncode) + except FileNotFoundError: + logger.error( + "npx not found. Please ensure Node.js and npm are properly installed " + "and added to your system PATH. You may need to restart your terminal " + "after installation.", + extra={"file": str(file)}, + ) + sys.exit(1) + + +@app.command() +def run( + file_spec: str = typer.Argument( + ..., + help="Python file to run, optionally with :object suffix", + ), + transport: Annotated[ + str | None, + typer.Option( + "--transport", + "-t", + help="Transport protocol to use (stdio or sse)", + ), + ] = None, +) -> None: # pragma: no cover + """Run an MCP server. + + The server can be specified in two ways:\n + 1. Module approach: server.py - runs the module directly, expecting a server.run() call.\n + 2. Import approach: server.py:app - imports and runs the specified server object.\n\n + + Note: This command runs the server directly. You are responsible for ensuring + all dependencies are available.\n + For dependency management, use `mcp install` or `mcp dev` instead. + """ # noqa: E501 + file, server_object = _parse_file_path(file_spec) + + logger.debug( + "Running server", + extra={ + "file": str(file), + "server_object": server_object, + "transport": transport, + }, + ) + + try: + # Import and get server object + server = _import_server(file, server_object) + + # Run the server + kwargs = {} + if transport: + kwargs["transport"] = transport + + server.run(**kwargs) + + except Exception: + logger.exception( + "Failed to run server", + extra={ + "file": str(file), + }, + ) + sys.exit(1) + + +@app.command() +def install( + file_spec: str = typer.Argument( + ..., + help="Python file to run, optionally with :object suffix", + ), + server_name: Annotated[ + str | None, + typer.Option( + "--name", + "-n", + help="Custom name for the server (defaults to server's name attribute or file name)", + ), + ] = None, + with_editable: Annotated[ + Path | None, + typer.Option( + "--with-editable", + "-e", + help="Directory containing pyproject.toml to install in editable mode", + exists=True, + file_okay=False, + resolve_path=True, + ), + ] = None, + with_packages: Annotated[ + list[str], + typer.Option( + "--with", + help="Additional packages to install", + ), + ] = [], + env_vars: Annotated[ + list[str], + typer.Option( + "--env-var", + "-v", + help="Environment variables in KEY=VALUE format", + ), + ] = [], + env_file: Annotated[ + Path | None, + typer.Option( + "--env-file", + "-f", + help="Load environment variables from a .env file", + exists=True, + file_okay=True, + dir_okay=False, + resolve_path=True, + ), + ] = None, +) -> None: # pragma: no cover + """Install an MCP server in the Claude desktop app. + + Environment variables are preserved once added and only updated if new values + are explicitly provided. + """ + file, server_object = _parse_file_path(file_spec) + + logger.debug( + "Installing server", + extra={ + "file": str(file), + "server_name": server_name, + "server_object": server_object, + "with_editable": str(with_editable) if with_editable else None, + "with_packages": with_packages, + }, + ) + + if not claude.get_claude_config_path(): + logger.error("Claude app not found") + sys.exit(1) + + # Try to import server to get its name, but fall back to file name if dependencies + # missing + name = server_name + server = None + if not name: + try: + server = _import_server(file, server_object) + name = server.name + except (ImportError, ModuleNotFoundError) as e: + logger.debug( + "Could not import server (likely missing dependencies), using file name", + extra={"error": str(e)}, + ) + name = file.stem + + # Get server dependencies if available + server_dependencies = getattr(server, "dependencies", []) if server else [] + if server_dependencies: + with_packages = list(set(with_packages + server_dependencies)) + + # Process environment variables if provided + env_dict: dict[str, str] | None = None + if env_file or env_vars: + env_dict = {} + # Load from .env file if specified + if env_file: + if dotenv: + try: + env_dict |= {k: v for k, v in dotenv.dotenv_values(env_file).items() if v is not None} + except (OSError, ValueError): + logger.exception("Failed to load .env file") + sys.exit(1) + else: + logger.error("python-dotenv is not installed. Cannot load .env file.") + sys.exit(1) + + # Add command line environment variables + for env_var in env_vars: + key, value = _parse_env_var(env_var) + env_dict[key] = value + + if claude.update_claude_config( + file_spec, + name, + with_editable=with_editable, + with_packages=with_packages, + env_vars=env_dict, + ): + logger.info(f"Successfully installed {name} in Claude app") + else: + logger.error(f"Failed to install {name} in Claude app") + sys.exit(1) diff --git a/source/target-vendors/cp312/mcp/client/__init__.py b/source/target-vendors/cp312/mcp/client/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/mcp/client/__main__.py b/source/target-vendors/cp312/mcp/client/__main__.py new file mode 100644 index 0000000..2efe05d --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/__main__.py @@ -0,0 +1,85 @@ +import argparse +import logging +import sys +from functools import partial +from urllib.parse import urlparse + +import anyio +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream + +import mcp.types as types +from mcp.client.session import ClientSession +from mcp.client.sse import sse_client +from mcp.client.stdio import StdioServerParameters, stdio_client +from mcp.shared.message import SessionMessage +from mcp.shared.session import RequestResponder + +if not sys.warnoptions: + import warnings + + warnings.simplefilter("ignore") + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger("client") + + +async def message_handler( + message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception, +) -> None: + if isinstance(message, Exception): + logger.error("Error: %s", message) + return + + logger.info("Received message from server: %s", message) + + +async def run_session( + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], + write_stream: MemoryObjectSendStream[SessionMessage], + client_info: types.Implementation | None = None, +): + async with ClientSession( + read_stream, + write_stream, + message_handler=message_handler, + client_info=client_info, + ) as session: + logger.info("Initializing session") + await session.initialize() + logger.info("Initialized") + + +async def main(command_or_url: str, args: list[str], env: list[tuple[str, str]]): + env_dict = dict(env) + + if urlparse(command_or_url).scheme in ("http", "https"): + # Use SSE client for HTTP(S) URLs + async with sse_client(command_or_url) as streams: + await run_session(*streams) + else: + # Use stdio client for commands + server_parameters = StdioServerParameters(command=command_or_url, args=args, env=env_dict) + async with stdio_client(server_parameters) as streams: + await run_session(*streams) + + +def cli(): + parser = argparse.ArgumentParser() + parser.add_argument("command_or_url", help="Command or URL to connect to") + parser.add_argument("args", nargs="*", help="Additional arguments") + parser.add_argument( + "-e", + "--env", + nargs=2, + action="append", + metavar=("KEY", "VALUE"), + help="Environment variables to set. Can be used multiple times.", + default=[], + ) + + args = parser.parse_args() + anyio.run(partial(main, args.command_or_url, args.args, args.env), backend="trio") + + +if __name__ == "__main__": + cli() diff --git a/source/target-vendors/cp312/mcp/client/auth/__init__.py b/source/target-vendors/cp312/mcp/client/auth/__init__.py new file mode 100644 index 0000000..252dfd9 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/auth/__init__.py @@ -0,0 +1,21 @@ +""" +OAuth2 Authentication implementation for HTTPX. + +Implements authorization code flow with PKCE and automatic token refresh. +""" + +from mcp.client.auth.exceptions import OAuthFlowError, OAuthRegistrationError, OAuthTokenError +from mcp.client.auth.oauth2 import ( + OAuthClientProvider, + PKCEParameters, + TokenStorage, +) + +__all__ = [ + "OAuthClientProvider", + "OAuthFlowError", + "OAuthRegistrationError", + "OAuthTokenError", + "PKCEParameters", + "TokenStorage", +] diff --git a/source/target-vendors/cp312/mcp/client/auth/exceptions.py b/source/target-vendors/cp312/mcp/client/auth/exceptions.py new file mode 100644 index 0000000..5ce8777 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/auth/exceptions.py @@ -0,0 +1,10 @@ +class OAuthFlowError(Exception): + """Base exception for OAuth flow errors.""" + + +class OAuthTokenError(OAuthFlowError): + """Raised when token operations fail.""" + + +class OAuthRegistrationError(OAuthFlowError): + """Raised when client registration fails.""" diff --git a/source/target-vendors/cp312/mcp/client/auth/extensions/__init__.py b/source/target-vendors/cp312/mcp/client/auth/extensions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/mcp/client/auth/extensions/client_credentials.py b/source/target-vendors/cp312/mcp/client/auth/extensions/client_credentials.py new file mode 100644 index 0000000..e2f3f08 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/auth/extensions/client_credentials.py @@ -0,0 +1,487 @@ +""" +OAuth client credential extensions for MCP. + +Provides OAuth providers for machine-to-machine authentication flows: +- ClientCredentialsOAuthProvider: For client_credentials with client_id + client_secret +- PrivateKeyJWTOAuthProvider: For client_credentials with private_key_jwt authentication + (typically using a pre-built JWT from workload identity federation) +- RFC7523OAuthClientProvider: For jwt-bearer grant (RFC 7523 Section 2.1) +""" + +import time +from collections.abc import Awaitable, Callable +from typing import Any, Literal +from uuid import uuid4 + +import httpx +import jwt +from pydantic import BaseModel, Field + +from mcp.client.auth import OAuthClientProvider, OAuthFlowError, OAuthTokenError, TokenStorage +from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata + + +class ClientCredentialsOAuthProvider(OAuthClientProvider): + """OAuth provider for client_credentials grant with client_id + client_secret. + + This provider sets client_info directly, bypassing dynamic client registration. + Use this when you already have client credentials (client_id and client_secret). + + Example: + ```python + provider = ClientCredentialsOAuthProvider( + server_url="https://api.example.com", + storage=my_token_storage, + client_id="my-client-id", + client_secret="my-client-secret", + ) + ``` + """ + + def __init__( + self, + server_url: str, + storage: TokenStorage, + client_id: str, + client_secret: str, + token_endpoint_auth_method: Literal["client_secret_basic", "client_secret_post"] = "client_secret_basic", + scopes: str | None = None, + ) -> None: + """Initialize client_credentials OAuth provider. + + Args: + server_url: The MCP server URL. + storage: Token storage implementation. + client_id: The OAuth client ID. + client_secret: The OAuth client secret. + token_endpoint_auth_method: Authentication method for token endpoint. + Either "client_secret_basic" (default) or "client_secret_post". + scopes: Optional space-separated list of scopes to request. + """ + # Build minimal client_metadata for the base class + client_metadata = OAuthClientMetadata( + redirect_uris=None, + grant_types=["client_credentials"], + token_endpoint_auth_method=token_endpoint_auth_method, + scope=scopes, + ) + super().__init__(server_url, client_metadata, storage, None, None, 300.0) + # Store client_info to be set during _initialize - no dynamic registration needed + self._fixed_client_info = OAuthClientInformationFull( + redirect_uris=None, + client_id=client_id, + client_secret=client_secret, + grant_types=["client_credentials"], + token_endpoint_auth_method=token_endpoint_auth_method, + scope=scopes, + ) + + async def _initialize(self) -> None: + """Load stored tokens and set pre-configured client_info.""" + self.context.current_tokens = await self.context.storage.get_tokens() + self.context.client_info = self._fixed_client_info + self._initialized = True + + async def _perform_authorization(self) -> httpx.Request: + """Perform client_credentials authorization.""" + return await self._exchange_token_client_credentials() + + async def _exchange_token_client_credentials(self) -> httpx.Request: + """Build token exchange request for client_credentials grant.""" + token_data: dict[str, Any] = { + "grant_type": "client_credentials", + } + + headers: dict[str, str] = {"Content-Type": "application/x-www-form-urlencoded"} + + # Use standard auth methods (client_secret_basic, client_secret_post, none) + token_data, headers = self.context.prepare_token_auth(token_data, headers) + + if self.context.should_include_resource_param(self.context.protocol_version): + token_data["resource"] = self.context.get_resource_url() + + if self.context.client_metadata.scope: + token_data["scope"] = self.context.client_metadata.scope + + token_url = self._get_token_endpoint() + return httpx.Request("POST", token_url, data=token_data, headers=headers) + + +def static_assertion_provider(token: str) -> Callable[[str], Awaitable[str]]: + """Create an assertion provider that returns a static JWT token. + + Use this when you have a pre-built JWT (e.g., from workload identity federation) + that doesn't need the audience parameter. + + Example: + ```python + provider = PrivateKeyJWTOAuthProvider( + server_url="https://api.example.com", + storage=my_token_storage, + client_id="my-client-id", + assertion_provider=static_assertion_provider(my_prebuilt_jwt), + ) + ``` + + Args: + token: The pre-built JWT assertion string. + + Returns: + An async callback suitable for use as an assertion_provider. + """ + + async def provider(audience: str) -> str: + return token + + return provider + + +class SignedJWTParameters(BaseModel): + """Parameters for creating SDK-signed JWT assertions. + + Use `create_assertion_provider()` to create an assertion provider callback + for use with `PrivateKeyJWTOAuthProvider`. + + Example: + ```python + jwt_params = SignedJWTParameters( + issuer="my-client-id", + subject="my-client-id", + signing_key=private_key_pem, + ) + provider = PrivateKeyJWTOAuthProvider( + server_url="https://api.example.com", + storage=my_token_storage, + client_id="my-client-id", + assertion_provider=jwt_params.create_assertion_provider(), + ) + ``` + """ + + issuer: str = Field(description="Issuer for JWT assertions (typically client_id).") + subject: str = Field(description="Subject identifier for JWT assertions (typically client_id).") + signing_key: str = Field(description="Private key for JWT signing (PEM format).") + signing_algorithm: str = Field(default="RS256", description="Algorithm for signing JWT assertions.") + lifetime_seconds: int = Field(default=300, description="Lifetime of generated JWT in seconds.") + additional_claims: dict[str, Any] | None = Field(default=None, description="Additional claims.") + + def create_assertion_provider(self) -> Callable[[str], Awaitable[str]]: + """Create an assertion provider callback for use with PrivateKeyJWTOAuthProvider. + + Returns: + An async callback that takes the audience (authorization server issuer URL) + and returns a signed JWT assertion. + """ + + async def provider(audience: str) -> str: + now = int(time.time()) + claims: dict[str, Any] = { + "iss": self.issuer, + "sub": self.subject, + "aud": audience, + "exp": now + self.lifetime_seconds, + "iat": now, + "jti": str(uuid4()), + } + if self.additional_claims: + claims.update(self.additional_claims) + + return jwt.encode(claims, self.signing_key, algorithm=self.signing_algorithm) + + return provider + + +class PrivateKeyJWTOAuthProvider(OAuthClientProvider): + """OAuth provider for client_credentials grant with private_key_jwt authentication. + + Uses RFC 7523 Section 2.2 for client authentication via JWT assertion. + + The JWT assertion's audience MUST be the authorization server's issuer identifier + (per RFC 7523bis security updates). The `assertion_provider` callback receives + this audience value and must return a JWT with that audience. + + **Option 1: Pre-built JWT via Workload Identity Federation** + + In production scenarios, the JWT assertion is typically obtained from a workload + identity provider (e.g., GCP, AWS IAM, Azure AD): + + ```python + async def get_workload_identity_token(audience: str) -> str: + # Fetch JWT from your identity provider + # The JWT's audience must match the provided audience parameter + return await fetch_token_from_identity_provider(audience=audience) + + provider = PrivateKeyJWTOAuthProvider( + server_url="https://api.example.com", + storage=my_token_storage, + client_id="my-client-id", + assertion_provider=get_workload_identity_token, + ) + ``` + + **Option 2: Static pre-built JWT** + + If you have a static JWT that doesn't need the audience parameter: + + ```python + provider = PrivateKeyJWTOAuthProvider( + server_url="https://api.example.com", + storage=my_token_storage, + client_id="my-client-id", + assertion_provider=static_assertion_provider(my_prebuilt_jwt), + ) + ``` + + **Option 3: SDK-signed JWT (for testing/simple setups)** + + For testing or simple deployments, use `SignedJWTParameters.create_assertion_provider()`: + + ```python + jwt_params = SignedJWTParameters( + issuer="my-client-id", + subject="my-client-id", + signing_key=private_key_pem, + ) + provider = PrivateKeyJWTOAuthProvider( + server_url="https://api.example.com", + storage=my_token_storage, + client_id="my-client-id", + assertion_provider=jwt_params.create_assertion_provider(), + ) + ``` + """ + + def __init__( + self, + server_url: str, + storage: TokenStorage, + client_id: str, + assertion_provider: Callable[[str], Awaitable[str]], + scopes: str | None = None, + ) -> None: + """Initialize private_key_jwt OAuth provider. + + Args: + server_url: The MCP server URL. + storage: Token storage implementation. + client_id: The OAuth client ID. + assertion_provider: Async callback that takes the audience (authorization + server's issuer identifier) and returns a JWT assertion. Use + `SignedJWTParameters.create_assertion_provider()` for SDK-signed JWTs, + `static_assertion_provider()` for pre-built JWTs, or provide your own + callback for workload identity federation. + scopes: Optional space-separated list of scopes to request. + """ + # Build minimal client_metadata for the base class + client_metadata = OAuthClientMetadata( + redirect_uris=None, + grant_types=["client_credentials"], + token_endpoint_auth_method="private_key_jwt", + scope=scopes, + ) + super().__init__(server_url, client_metadata, storage, None, None, 300.0) + self._assertion_provider = assertion_provider + # Store client_info to be set during _initialize - no dynamic registration needed + self._fixed_client_info = OAuthClientInformationFull( + redirect_uris=None, + client_id=client_id, + grant_types=["client_credentials"], + token_endpoint_auth_method="private_key_jwt", + scope=scopes, + ) + + async def _initialize(self) -> None: + """Load stored tokens and set pre-configured client_info.""" + self.context.current_tokens = await self.context.storage.get_tokens() + self.context.client_info = self._fixed_client_info + self._initialized = True + + async def _perform_authorization(self) -> httpx.Request: + """Perform client_credentials authorization with private_key_jwt.""" + return await self._exchange_token_client_credentials() + + async def _add_client_authentication_jwt(self, *, token_data: dict[str, Any]) -> None: + """Add JWT assertion for client authentication to token endpoint parameters.""" + if not self.context.oauth_metadata: + raise OAuthFlowError("Missing OAuth metadata for private_key_jwt flow") # pragma: no cover + + # Audience MUST be the issuer identifier of the authorization server + # https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rfc7523bis-01 + audience = str(self.context.oauth_metadata.issuer) + assertion = await self._assertion_provider(audience) + + # RFC 7523 Section 2.2: client authentication via JWT + token_data["client_assertion"] = assertion + token_data["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" + + async def _exchange_token_client_credentials(self) -> httpx.Request: + """Build token exchange request for client_credentials grant with private_key_jwt.""" + token_data: dict[str, Any] = { + "grant_type": "client_credentials", + } + + headers: dict[str, str] = {"Content-Type": "application/x-www-form-urlencoded"} + + # Add JWT client authentication (RFC 7523 Section 2.2) + await self._add_client_authentication_jwt(token_data=token_data) + + if self.context.should_include_resource_param(self.context.protocol_version): + token_data["resource"] = self.context.get_resource_url() + + if self.context.client_metadata.scope: + token_data["scope"] = self.context.client_metadata.scope + + token_url = self._get_token_endpoint() + return httpx.Request("POST", token_url, data=token_data, headers=headers) + + +class JWTParameters(BaseModel): + """JWT parameters.""" + + assertion: str | None = Field( + default=None, + description="JWT assertion for JWT authentication. " + "Will be used instead of generating a new assertion if provided.", + ) + + issuer: str | None = Field(default=None, description="Issuer for JWT assertions.") + subject: str | None = Field(default=None, description="Subject identifier for JWT assertions.") + audience: str | None = Field(default=None, description="Audience for JWT assertions.") + claims: dict[str, Any] | None = Field(default=None, description="Additional claims for JWT assertions.") + jwt_signing_algorithm: str | None = Field(default="RS256", description="Algorithm for signing JWT assertions.") + jwt_signing_key: str | None = Field(default=None, description="Private key for JWT signing.") + jwt_lifetime_seconds: int = Field(default=300, description="Lifetime of generated JWT in seconds.") + + def to_assertion(self, with_audience_fallback: str | None = None) -> str: + if self.assertion is not None: + # Prebuilt JWT (e.g. acquired out-of-band) + assertion = self.assertion + else: + if not self.jwt_signing_key: + raise OAuthFlowError("Missing signing key for JWT bearer grant") # pragma: no cover + if not self.issuer: + raise OAuthFlowError("Missing issuer for JWT bearer grant") # pragma: no cover + if not self.subject: + raise OAuthFlowError("Missing subject for JWT bearer grant") # pragma: no cover + + audience = self.audience if self.audience else with_audience_fallback + if not audience: + raise OAuthFlowError("Missing audience for JWT bearer grant") # pragma: no cover + + now = int(time.time()) + claims: dict[str, Any] = { + "iss": self.issuer, + "sub": self.subject, + "aud": audience, + "exp": now + self.jwt_lifetime_seconds, + "iat": now, + "jti": str(uuid4()), + } + claims.update(self.claims or {}) + + assertion = jwt.encode( + claims, + self.jwt_signing_key, + algorithm=self.jwt_signing_algorithm or "RS256", + ) + return assertion + + +class RFC7523OAuthClientProvider(OAuthClientProvider): + """OAuth client provider for RFC 7523 jwt-bearer grant. + + .. deprecated:: + Use :class:`ClientCredentialsOAuthProvider` for client_credentials with + client_id + client_secret, or :class:`PrivateKeyJWTOAuthProvider` for + client_credentials with private_key_jwt authentication instead. + + This provider supports the jwt-bearer authorization grant (RFC 7523 Section 2.1) + where the JWT itself is the authorization grant. + """ + + def __init__( + self, + server_url: str, + client_metadata: OAuthClientMetadata, + storage: TokenStorage, + redirect_handler: Callable[[str], Awaitable[None]] | None = None, + callback_handler: Callable[[], Awaitable[tuple[str, str | None]]] | None = None, + timeout: float = 300.0, + jwt_parameters: JWTParameters | None = None, + ) -> None: + import warnings + + warnings.warn( + "RFC7523OAuthClientProvider is deprecated. Use ClientCredentialsOAuthProvider " + "or PrivateKeyJWTOAuthProvider instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__(server_url, client_metadata, storage, redirect_handler, callback_handler, timeout) + self.jwt_parameters = jwt_parameters + + async def _exchange_token_authorization_code( + self, auth_code: str, code_verifier: str, *, token_data: dict[str, Any] | None = None + ) -> httpx.Request: # pragma: no cover + """Build token exchange request for authorization_code flow.""" + token_data = token_data or {} + if self.context.client_metadata.token_endpoint_auth_method == "private_key_jwt": + self._add_client_authentication_jwt(token_data=token_data) + return await super()._exchange_token_authorization_code(auth_code, code_verifier, token_data=token_data) + + async def _perform_authorization(self) -> httpx.Request: # pragma: no cover + """Perform the authorization flow.""" + if "urn:ietf:params:oauth:grant-type:jwt-bearer" in self.context.client_metadata.grant_types: + token_request = await self._exchange_token_jwt_bearer() + return token_request + else: + return await super()._perform_authorization() + + def _add_client_authentication_jwt(self, *, token_data: dict[str, Any]): # pragma: no cover + """Add JWT assertion for client authentication to token endpoint parameters.""" + if not self.jwt_parameters: + raise OAuthTokenError("Missing JWT parameters for private_key_jwt flow") + if not self.context.oauth_metadata: + raise OAuthTokenError("Missing OAuth metadata for private_key_jwt flow") + + # We need to set the audience to the issuer identifier of the authorization server + # https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rfc7523bis-01#name-updates-to-rfc-7523 + issuer = str(self.context.oauth_metadata.issuer) + assertion = self.jwt_parameters.to_assertion(with_audience_fallback=issuer) + + # When using private_key_jwt, in a client_credentials flow, we use RFC 7523 Section 2.2 + token_data["client_assertion"] = assertion + token_data["client_assertion_type"] = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" + # We need to set the audience to the resource server, the audience is difference from the one in claims + # it represents the resource server that will validate the token + token_data["audience"] = self.context.get_resource_url() + + async def _exchange_token_jwt_bearer(self) -> httpx.Request: + """Build token exchange request for JWT bearer grant.""" + if not self.context.client_info: + raise OAuthFlowError("Missing client info") # pragma: no cover + if not self.jwt_parameters: + raise OAuthFlowError("Missing JWT parameters") # pragma: no cover + if not self.context.oauth_metadata: + raise OAuthTokenError("Missing OAuth metadata") # pragma: no cover + + # We need to set the audience to the issuer identifier of the authorization server + # https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rfc7523bis-01#name-updates-to-rfc-7523 + issuer = str(self.context.oauth_metadata.issuer) + assertion = self.jwt_parameters.to_assertion(with_audience_fallback=issuer) + + token_data = { + "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", + "assertion": assertion, + } + + if self.context.should_include_resource_param(self.context.protocol_version): # pragma: no branch + token_data["resource"] = self.context.get_resource_url() + + if self.context.client_metadata.scope: # pragma: no branch + token_data["scope"] = self.context.client_metadata.scope + + token_url = self._get_token_endpoint() + return httpx.Request( + "POST", token_url, data=token_data, headers={"Content-Type": "application/x-www-form-urlencoded"} + ) diff --git a/source/target-vendors/cp312/mcp/client/auth/oauth2.py b/source/target-vendors/cp312/mcp/client/auth/oauth2.py new file mode 100644 index 0000000..cd96a75 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/auth/oauth2.py @@ -0,0 +1,616 @@ +""" +OAuth2 Authentication implementation for HTTPX. + +Implements authorization code flow with PKCE and automatic token refresh. +""" + +import base64 +import hashlib +import logging +import secrets +import string +import time +from collections.abc import AsyncGenerator, Awaitable, Callable +from dataclasses import dataclass, field +from typing import Any, Protocol +from urllib.parse import quote, urlencode, urljoin, urlparse + +import anyio +import httpx +from pydantic import BaseModel, Field, ValidationError + +from mcp.client.auth.exceptions import OAuthFlowError, OAuthTokenError +from mcp.client.auth.utils import ( + build_oauth_authorization_server_metadata_discovery_urls, + build_protected_resource_metadata_discovery_urls, + create_client_info_from_metadata_url, + create_client_registration_request, + create_oauth_metadata_request, + extract_field_from_www_auth, + extract_resource_metadata_from_www_auth, + extract_scope_from_www_auth, + get_client_metadata_scopes, + handle_auth_metadata_response, + handle_protected_resource_response, + handle_registration_response, + handle_token_response_scopes, + is_valid_client_metadata_url, + should_use_client_metadata_url, +) +from mcp.client.streamable_http import MCP_PROTOCOL_VERSION +from mcp.shared.auth import ( + OAuthClientInformationFull, + OAuthClientMetadata, + OAuthMetadata, + OAuthToken, + ProtectedResourceMetadata, +) +from mcp.shared.auth_utils import ( + calculate_token_expiry, + check_resource_allowed, + resource_url_from_server_url, +) + +logger = logging.getLogger(__name__) + + +class PKCEParameters(BaseModel): + """PKCE (Proof Key for Code Exchange) parameters.""" + + code_verifier: str = Field(..., min_length=43, max_length=128) + code_challenge: str = Field(..., min_length=43, max_length=128) + + @classmethod + def generate(cls) -> "PKCEParameters": + """Generate new PKCE parameters.""" + code_verifier = "".join(secrets.choice(string.ascii_letters + string.digits + "-._~") for _ in range(128)) + digest = hashlib.sha256(code_verifier.encode()).digest() + code_challenge = base64.urlsafe_b64encode(digest).decode().rstrip("=") + return cls(code_verifier=code_verifier, code_challenge=code_challenge) + + +class TokenStorage(Protocol): + """Protocol for token storage implementations.""" + + async def get_tokens(self) -> OAuthToken | None: + """Get stored tokens.""" + ... + + async def set_tokens(self, tokens: OAuthToken) -> None: + """Store tokens.""" + ... + + async def get_client_info(self) -> OAuthClientInformationFull | None: + """Get stored client information.""" + ... + + async def set_client_info(self, client_info: OAuthClientInformationFull) -> None: + """Store client information.""" + ... + + +@dataclass +class OAuthContext: + """OAuth flow context.""" + + server_url: str + client_metadata: OAuthClientMetadata + storage: TokenStorage + redirect_handler: Callable[[str], Awaitable[None]] | None + callback_handler: Callable[[], Awaitable[tuple[str, str | None]]] | None + timeout: float = 300.0 + client_metadata_url: str | None = None + + # Discovered metadata + protected_resource_metadata: ProtectedResourceMetadata | None = None + oauth_metadata: OAuthMetadata | None = None + auth_server_url: str | None = None + protocol_version: str | None = None + + # Client registration + client_info: OAuthClientInformationFull | None = None + + # Token management + current_tokens: OAuthToken | None = None + token_expiry_time: float | None = None + + # State + lock: anyio.Lock = field(default_factory=anyio.Lock) + + def get_authorization_base_url(self, server_url: str) -> str: + """Extract base URL by removing path component.""" + parsed = urlparse(server_url) + return f"{parsed.scheme}://{parsed.netloc}" + + def update_token_expiry(self, token: OAuthToken) -> None: + """Update token expiry time using shared util function.""" + self.token_expiry_time = calculate_token_expiry(token.expires_in) + + def is_token_valid(self) -> bool: + """Check if current token is valid.""" + return bool( + self.current_tokens + and self.current_tokens.access_token + and (not self.token_expiry_time or time.time() <= self.token_expiry_time) + ) + + def can_refresh_token(self) -> bool: + """Check if token can be refreshed.""" + return bool(self.current_tokens and self.current_tokens.refresh_token and self.client_info) + + def clear_tokens(self) -> None: + """Clear current tokens.""" + self.current_tokens = None + self.token_expiry_time = None + + def get_resource_url(self) -> str: + """Get resource URL for RFC 8707. + + Uses PRM resource if it's a valid parent, otherwise uses canonical server URL. + """ + resource = resource_url_from_server_url(self.server_url) + + # If PRM provides a resource that's a valid parent, use it + if self.protected_resource_metadata and self.protected_resource_metadata.resource: + prm_resource = str(self.protected_resource_metadata.resource) + if check_resource_allowed(requested_resource=resource, configured_resource=prm_resource): + resource = prm_resource + + return resource + + def should_include_resource_param(self, protocol_version: str | None = None) -> bool: + """Determine if the resource parameter should be included in OAuth requests. + + Returns True if: + - Protected resource metadata is available, OR + - MCP-Protocol-Version header is 2025-06-18 or later + """ + # If we have protected resource metadata, include the resource param + if self.protected_resource_metadata is not None: + return True + + # If no protocol version provided, don't include resource param + if not protocol_version: + return False + + # Check if protocol version is 2025-06-18 or later + # Version format is YYYY-MM-DD, so string comparison works + return protocol_version >= "2025-06-18" + + def prepare_token_auth( + self, data: dict[str, str], headers: dict[str, str] | None = None + ) -> tuple[dict[str, str], dict[str, str]]: + """Prepare authentication for token requests. + + Args: + data: The form data to send + headers: Optional headers dict to update + + Returns: + Tuple of (updated_data, updated_headers) + """ + if headers is None: + headers = {} # pragma: no cover + + if not self.client_info: + return data, headers # pragma: no cover + + auth_method = self.client_info.token_endpoint_auth_method + + if auth_method == "client_secret_basic" and self.client_info.client_id and self.client_info.client_secret: + # URL-encode client ID and secret per RFC 6749 Section 2.3.1 + encoded_id = quote(self.client_info.client_id, safe="") + encoded_secret = quote(self.client_info.client_secret, safe="") + credentials = f"{encoded_id}:{encoded_secret}" + encoded_credentials = base64.b64encode(credentials.encode()).decode() + headers["Authorization"] = f"Basic {encoded_credentials}" + # Don't include client_secret in body for basic auth + data = {k: v for k, v in data.items() if k != "client_secret"} + elif auth_method == "client_secret_post" and self.client_info.client_secret: + # Include client_secret in request body + data["client_secret"] = self.client_info.client_secret + # For auth_method == "none", don't add any client_secret + + return data, headers + + +class OAuthClientProvider(httpx.Auth): + """ + OAuth2 authentication for httpx. + Handles OAuth flow with automatic client registration and token storage. + """ + + requires_response_body = True + + def __init__( + self, + server_url: str, + client_metadata: OAuthClientMetadata, + storage: TokenStorage, + redirect_handler: Callable[[str], Awaitable[None]] | None = None, + callback_handler: Callable[[], Awaitable[tuple[str, str | None]]] | None = None, + timeout: float = 300.0, + client_metadata_url: str | None = None, + ): + """Initialize OAuth2 authentication. + + Args: + server_url: The MCP server URL. + client_metadata: OAuth client metadata for registration. + storage: Token storage implementation. + redirect_handler: Handler for authorization redirects. + callback_handler: Handler for authorization callbacks. + timeout: Timeout for the OAuth flow. + client_metadata_url: URL-based client ID. When provided and the server + advertises client_id_metadata_document_supported=true, this URL will be + used as the client_id instead of performing dynamic client registration. + Must be a valid HTTPS URL with a non-root pathname. + + Raises: + ValueError: If client_metadata_url is provided but not a valid HTTPS URL + with a non-root pathname. + """ + # Validate client_metadata_url if provided + if client_metadata_url is not None and not is_valid_client_metadata_url(client_metadata_url): + raise ValueError( + f"client_metadata_url must be a valid HTTPS URL with a non-root pathname, got: {client_metadata_url}" + ) + + self.context = OAuthContext( + server_url=server_url, + client_metadata=client_metadata, + storage=storage, + redirect_handler=redirect_handler, + callback_handler=callback_handler, + timeout=timeout, + client_metadata_url=client_metadata_url, + ) + self._initialized = False + + async def _handle_protected_resource_response(self, response: httpx.Response) -> bool: + """ + Handle protected resource metadata discovery response. + + Per SEP-985, supports fallback when discovery fails at one URL. + + Returns: + True if metadata was successfully discovered, False if we should try next URL + """ + if response.status_code == 200: + try: + content = await response.aread() + metadata = ProtectedResourceMetadata.model_validate_json(content) + self.context.protected_resource_metadata = metadata + if metadata.authorization_servers: # pragma: no branch + self.context.auth_server_url = str(metadata.authorization_servers[0]) + return True + + except ValidationError: # pragma: no cover + # Invalid metadata - try next URL + logger.warning(f"Invalid protected resource metadata at {response.request.url}") + return False + elif response.status_code == 404: # pragma: no cover + # Not found - try next URL in fallback chain + logger.debug(f"Protected resource metadata not found at {response.request.url}, trying next URL") + return False + else: + # Other error - fail immediately + raise OAuthFlowError( + f"Protected Resource Metadata request failed: {response.status_code}" + ) # pragma: no cover + + async def _perform_authorization(self) -> httpx.Request: + """Perform the authorization flow.""" + auth_code, code_verifier = await self._perform_authorization_code_grant() + token_request = await self._exchange_token_authorization_code(auth_code, code_verifier) + return token_request + + async def _perform_authorization_code_grant(self) -> tuple[str, str]: + """Perform the authorization redirect and get auth code.""" + if self.context.client_metadata.redirect_uris is None: + raise OAuthFlowError("No redirect URIs provided for authorization code grant") # pragma: no cover + if not self.context.redirect_handler: + raise OAuthFlowError("No redirect handler provided for authorization code grant") # pragma: no cover + if not self.context.callback_handler: + raise OAuthFlowError("No callback handler provided for authorization code grant") # pragma: no cover + + if self.context.oauth_metadata and self.context.oauth_metadata.authorization_endpoint: + auth_endpoint = str(self.context.oauth_metadata.authorization_endpoint) # pragma: no cover + else: + auth_base_url = self.context.get_authorization_base_url(self.context.server_url) + auth_endpoint = urljoin(auth_base_url, "/authorize") + + if not self.context.client_info: + raise OAuthFlowError("No client info available for authorization") # pragma: no cover + + # Generate PKCE parameters + pkce_params = PKCEParameters.generate() + state = secrets.token_urlsafe(32) + + auth_params = { + "response_type": "code", + "client_id": self.context.client_info.client_id, + "redirect_uri": str(self.context.client_metadata.redirect_uris[0]), + "state": state, + "code_challenge": pkce_params.code_challenge, + "code_challenge_method": "S256", + } + + # Only include resource param if conditions are met + if self.context.should_include_resource_param(self.context.protocol_version): + auth_params["resource"] = self.context.get_resource_url() # RFC 8707 # pragma: no cover + + if self.context.client_metadata.scope: # pragma: no branch + auth_params["scope"] = self.context.client_metadata.scope + + authorization_url = f"{auth_endpoint}?{urlencode(auth_params)}" + await self.context.redirect_handler(authorization_url) + + # Wait for callback + auth_code, returned_state = await self.context.callback_handler() + + if returned_state is None or not secrets.compare_digest(returned_state, state): + raise OAuthFlowError(f"State parameter mismatch: {returned_state} != {state}") # pragma: no cover + + if not auth_code: + raise OAuthFlowError("No authorization code received") # pragma: no cover + + # Return auth code and code verifier for token exchange + return auth_code, pkce_params.code_verifier + + def _get_token_endpoint(self) -> str: + if self.context.oauth_metadata and self.context.oauth_metadata.token_endpoint: + token_url = str(self.context.oauth_metadata.token_endpoint) + else: + auth_base_url = self.context.get_authorization_base_url(self.context.server_url) + token_url = urljoin(auth_base_url, "/token") + return token_url + + async def _exchange_token_authorization_code( + self, auth_code: str, code_verifier: str, *, token_data: dict[str, Any] | None = {} + ) -> httpx.Request: + """Build token exchange request for authorization_code flow.""" + if self.context.client_metadata.redirect_uris is None: + raise OAuthFlowError("No redirect URIs provided for authorization code grant") # pragma: no cover + if not self.context.client_info: + raise OAuthFlowError("Missing client info") # pragma: no cover + + token_url = self._get_token_endpoint() + token_data = token_data or {} + token_data.update( + { + "grant_type": "authorization_code", + "code": auth_code, + "redirect_uri": str(self.context.client_metadata.redirect_uris[0]), + "client_id": self.context.client_info.client_id, + "code_verifier": code_verifier, + } + ) + + # Only include resource param if conditions are met + if self.context.should_include_resource_param(self.context.protocol_version): + token_data["resource"] = self.context.get_resource_url() # RFC 8707 + + # Prepare authentication based on preferred method + headers = {"Content-Type": "application/x-www-form-urlencoded"} + token_data, headers = self.context.prepare_token_auth(token_data, headers) + + return httpx.Request("POST", token_url, data=token_data, headers=headers) + + async def _handle_token_response(self, response: httpx.Response) -> None: + """Handle token exchange response.""" + if response.status_code != 200: + body = await response.aread() # pragma: no cover + body_text = body.decode("utf-8") # pragma: no cover + raise OAuthTokenError(f"Token exchange failed ({response.status_code}): {body_text}") # pragma: no cover + + # Parse and validate response with scope validation + token_response = await handle_token_response_scopes(response) + + # Store tokens in context + self.context.current_tokens = token_response + self.context.update_token_expiry(token_response) + await self.context.storage.set_tokens(token_response) + + async def _refresh_token(self) -> httpx.Request: + """Build token refresh request.""" + if not self.context.current_tokens or not self.context.current_tokens.refresh_token: + raise OAuthTokenError("No refresh token available") # pragma: no cover + + if not self.context.client_info or not self.context.client_info.client_id: + raise OAuthTokenError("No client info available") # pragma: no cover + + if self.context.oauth_metadata and self.context.oauth_metadata.token_endpoint: + token_url = str(self.context.oauth_metadata.token_endpoint) # pragma: no cover + else: + auth_base_url = self.context.get_authorization_base_url(self.context.server_url) + token_url = urljoin(auth_base_url, "/token") + + refresh_data: dict[str, str] = { + "grant_type": "refresh_token", + "refresh_token": self.context.current_tokens.refresh_token, + "client_id": self.context.client_info.client_id, + } + + # Only include resource param if conditions are met + if self.context.should_include_resource_param(self.context.protocol_version): + refresh_data["resource"] = self.context.get_resource_url() # RFC 8707 + + # Prepare authentication based on preferred method + headers = {"Content-Type": "application/x-www-form-urlencoded"} + refresh_data, headers = self.context.prepare_token_auth(refresh_data, headers) + + return httpx.Request("POST", token_url, data=refresh_data, headers=headers) + + async def _handle_refresh_response(self, response: httpx.Response) -> bool: # pragma: no cover + """Handle token refresh response. Returns True if successful.""" + if response.status_code != 200: + logger.warning(f"Token refresh failed: {response.status_code}") + self.context.clear_tokens() + return False + + try: + content = await response.aread() + token_response = OAuthToken.model_validate_json(content) + + self.context.current_tokens = token_response + self.context.update_token_expiry(token_response) + await self.context.storage.set_tokens(token_response) + + return True + except ValidationError: + logger.exception("Invalid refresh response") + self.context.clear_tokens() + return False + + async def _initialize(self) -> None: # pragma: no cover + """Load stored tokens and client info.""" + self.context.current_tokens = await self.context.storage.get_tokens() + self.context.client_info = await self.context.storage.get_client_info() + self._initialized = True + + def _add_auth_header(self, request: httpx.Request) -> None: + """Add authorization header to request if we have valid tokens.""" + if self.context.current_tokens and self.context.current_tokens.access_token: # pragma: no branch + request.headers["Authorization"] = f"Bearer {self.context.current_tokens.access_token}" + + async def _handle_oauth_metadata_response(self, response: httpx.Response) -> None: + content = await response.aread() + metadata = OAuthMetadata.model_validate_json(content) + self.context.oauth_metadata = metadata + + async def async_auth_flow(self, request: httpx.Request) -> AsyncGenerator[httpx.Request, httpx.Response]: + """HTTPX auth flow integration.""" + async with self.context.lock: + if not self._initialized: + await self._initialize() # pragma: no cover + + # Capture protocol version from request headers + self.context.protocol_version = request.headers.get(MCP_PROTOCOL_VERSION) + + if not self.context.is_token_valid() and self.context.can_refresh_token(): + # Try to refresh token + refresh_request = await self._refresh_token() # pragma: no cover + refresh_response = yield refresh_request # pragma: no cover + + if not await self._handle_refresh_response(refresh_response): # pragma: no cover + # Refresh failed, need full re-authentication + self._initialized = False + + if self.context.is_token_valid(): + self._add_auth_header(request) + + response = yield request + + if response.status_code == 401: + # Perform full OAuth flow + try: + # OAuth flow must be inline due to generator constraints + www_auth_resource_metadata_url = extract_resource_metadata_from_www_auth(response) + + # Step 1: Discover protected resource metadata (SEP-985 with fallback support) + prm_discovery_urls = build_protected_resource_metadata_discovery_urls( + www_auth_resource_metadata_url, self.context.server_url + ) + + for url in prm_discovery_urls: # pragma: no branch + discovery_request = create_oauth_metadata_request(url) + + discovery_response = yield discovery_request # sending request + + prm = await handle_protected_resource_response(discovery_response) + if prm: + self.context.protected_resource_metadata = prm + + # todo: try all authorization_servers to find the OASM + assert ( + len(prm.authorization_servers) > 0 + ) # this is always true as authorization_servers has a min length of 1 + + self.context.auth_server_url = str(prm.authorization_servers[0]) + break + else: + logger.debug(f"Protected resource metadata discovery failed: {url}") + + asm_discovery_urls = build_oauth_authorization_server_metadata_discovery_urls( + self.context.auth_server_url, self.context.server_url + ) + + # Step 2: Discover OAuth Authorization Server Metadata (OASM) (with fallback for legacy servers) + for url in asm_discovery_urls: # pragma: no cover + oauth_metadata_request = create_oauth_metadata_request(url) + oauth_metadata_response = yield oauth_metadata_request + + ok, asm = await handle_auth_metadata_response(oauth_metadata_response) + if not ok: + break + if ok and asm: + self.context.oauth_metadata = asm + break + else: + logger.debug(f"OAuth metadata discovery failed: {url}") + + # Step 3: Apply scope selection strategy + self.context.client_metadata.scope = get_client_metadata_scopes( + extract_scope_from_www_auth(response), + self.context.protected_resource_metadata, + self.context.oauth_metadata, + ) + + # Step 4: Register client or use URL-based client ID (CIMD) + if not self.context.client_info: + if should_use_client_metadata_url( + self.context.oauth_metadata, self.context.client_metadata_url + ): + # Use URL-based client ID (CIMD) + logger.debug(f"Using URL-based client ID (CIMD): {self.context.client_metadata_url}") + client_information = create_client_info_from_metadata_url( + self.context.client_metadata_url, # type: ignore[arg-type] + redirect_uris=self.context.client_metadata.redirect_uris, + ) + self.context.client_info = client_information + await self.context.storage.set_client_info(client_information) + else: + # Fallback to Dynamic Client Registration + registration_request = create_client_registration_request( + self.context.oauth_metadata, + self.context.client_metadata, + self.context.get_authorization_base_url(self.context.server_url), + ) + registration_response = yield registration_request + client_information = await handle_registration_response(registration_response) + self.context.client_info = client_information + await self.context.storage.set_client_info(client_information) + + # Step 5: Perform authorization and complete token exchange + token_response = yield await self._perform_authorization() + await self._handle_token_response(token_response) + except Exception: # pragma: no cover + logger.exception("OAuth flow error") + raise + + # Retry with new tokens + self._add_auth_header(request) + yield request + elif response.status_code == 403: + # Step 1: Extract error field from WWW-Authenticate header + error = extract_field_from_www_auth(response, "error") + + # Step 2: Check if we need to step-up authorization + if error == "insufficient_scope": # pragma: no branch + try: + # Step 2a: Update the required scopes + self.context.client_metadata.scope = get_client_metadata_scopes( + extract_scope_from_www_auth(response), self.context.protected_resource_metadata + ) + + # Step 2b: Perform (re-)authorization and token exchange + token_response = yield await self._perform_authorization() + await self._handle_token_response(token_response) + except Exception: # pragma: no cover + logger.exception("OAuth flow error") + raise + + # Retry with new tokens + self._add_auth_header(request) + yield request diff --git a/source/target-vendors/cp312/mcp/client/auth/utils.py b/source/target-vendors/cp312/mcp/client/auth/utils.py new file mode 100644 index 0000000..b4426be --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/auth/utils.py @@ -0,0 +1,336 @@ +import logging +import re +from urllib.parse import urljoin, urlparse + +from httpx import Request, Response +from pydantic import AnyUrl, ValidationError + +from mcp.client.auth import OAuthRegistrationError, OAuthTokenError +from mcp.client.streamable_http import MCP_PROTOCOL_VERSION +from mcp.shared.auth import ( + OAuthClientInformationFull, + OAuthClientMetadata, + OAuthMetadata, + OAuthToken, + ProtectedResourceMetadata, +) +from mcp.types import LATEST_PROTOCOL_VERSION + +logger = logging.getLogger(__name__) + + +def extract_field_from_www_auth(response: Response, field_name: str) -> str | None: + """ + Extract field from WWW-Authenticate header. + + Returns: + Field value if found in WWW-Authenticate header, None otherwise + """ + www_auth_header = response.headers.get("WWW-Authenticate") + if not www_auth_header: + return None + + # Pattern matches: field_name="value" or field_name=value (unquoted) + pattern = rf'{field_name}=(?:"([^"]+)"|([^\s,]+))' + match = re.search(pattern, www_auth_header) + + if match: + # Return quoted value if present, otherwise unquoted value + return match.group(1) or match.group(2) + + return None + + +def extract_scope_from_www_auth(response: Response) -> str | None: + """ + Extract scope parameter from WWW-Authenticate header as per RFC6750. + + Returns: + Scope string if found in WWW-Authenticate header, None otherwise + """ + return extract_field_from_www_auth(response, "scope") + + +def extract_resource_metadata_from_www_auth(response: Response) -> str | None: + """ + Extract protected resource metadata URL from WWW-Authenticate header as per RFC9728. + + Returns: + Resource metadata URL if found in WWW-Authenticate header, None otherwise + """ + if not response or response.status_code != 401: + return None # pragma: no cover + + return extract_field_from_www_auth(response, "resource_metadata") + + +def build_protected_resource_metadata_discovery_urls(www_auth_url: str | None, server_url: str) -> list[str]: + """ + Build ordered list of URLs to try for protected resource metadata discovery. + + Per SEP-985, the client MUST: + 1. Try resource_metadata from WWW-Authenticate header (if present) + 2. Fall back to path-based well-known URI: /.well-known/oauth-protected-resource/{path} + 3. Fall back to root-based well-known URI: /.well-known/oauth-protected-resource + + Args: + www_auth_url: optional resource_metadata url extracted from the WWW-Authenticate header + server_url: server url + + Returns: + Ordered list of URLs to try for discovery + """ + urls: list[str] = [] + + # Priority 1: WWW-Authenticate header with resource_metadata parameter + if www_auth_url: + urls.append(www_auth_url) + + # Priority 2-3: Well-known URIs (RFC 9728) + parsed = urlparse(server_url) + base_url = f"{parsed.scheme}://{parsed.netloc}" + + # Priority 2: Path-based well-known URI (if server has a path component) + if parsed.path and parsed.path != "/": + path_based_url = urljoin(base_url, f"/.well-known/oauth-protected-resource{parsed.path}") + urls.append(path_based_url) + + # Priority 3: Root-based well-known URI + root_based_url = urljoin(base_url, "/.well-known/oauth-protected-resource") + urls.append(root_based_url) + + return urls + + +def get_client_metadata_scopes( + www_authenticate_scope: str | None, + protected_resource_metadata: ProtectedResourceMetadata | None, + authorization_server_metadata: OAuthMetadata | None = None, +) -> str | None: + """Select scopes as outlined in the 'Scope Selection Strategy' in the MCP spec.""" + # Per MCP spec, scope selection priority order: + # 1. Use scope from WWW-Authenticate header (if provided) + # 2. Use all scopes from PRM scopes_supported (if available) + # 3. Omit scope parameter if neither is available + + if www_authenticate_scope is not None: + # Priority 1: WWW-Authenticate header scope + return www_authenticate_scope + elif protected_resource_metadata is not None and protected_resource_metadata.scopes_supported is not None: + # Priority 2: PRM scopes_supported + return " ".join(protected_resource_metadata.scopes_supported) + elif authorization_server_metadata is not None and authorization_server_metadata.scopes_supported is not None: + return " ".join(authorization_server_metadata.scopes_supported) # pragma: no cover + else: + # Priority 3: Omit scope parameter + return None + + +def build_oauth_authorization_server_metadata_discovery_urls(auth_server_url: str | None, server_url: str) -> list[str]: + """ + Generate ordered list of (url, type) tuples for discovery attempts. + + Args: + auth_server_url: URL for the OAuth Authorization Metadata URL if found, otherwise None + server_url: URL for the MCP server, used as a fallback if auth_server_url is None + """ + + if not auth_server_url: + # Legacy path using the 2025-03-26 spec: + # link: https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization + parsed = urlparse(server_url) + return [f"{parsed.scheme}://{parsed.netloc}/.well-known/oauth-authorization-server"] + + urls: list[str] = [] + parsed = urlparse(auth_server_url) + base_url = f"{parsed.scheme}://{parsed.netloc}" + + # RFC 8414: Path-aware OAuth discovery + if parsed.path and parsed.path != "/": + oauth_path = f"/.well-known/oauth-authorization-server{parsed.path.rstrip('/')}" + urls.append(urljoin(base_url, oauth_path)) + + # RFC 8414 section 5: Path-aware OIDC discovery + # See https://www.rfc-editor.org/rfc/rfc8414.html#section-5 + oidc_path = f"/.well-known/openid-configuration{parsed.path.rstrip('/')}" + urls.append(urljoin(base_url, oidc_path)) + + # https://openid.net/specs/openid-connect-discovery-1_0.html + oidc_path = f"{parsed.path.rstrip('/')}/.well-known/openid-configuration" + urls.append(urljoin(base_url, oidc_path)) + return urls + + # OAuth root + urls.append(urljoin(base_url, "/.well-known/oauth-authorization-server")) + + # OIDC 1.0 fallback (appends to full URL per OIDC spec) + # https://openid.net/specs/openid-connect-discovery-1_0.html + urls.append(urljoin(base_url, "/.well-known/openid-configuration")) + + return urls + + +async def handle_protected_resource_response( + response: Response, +) -> ProtectedResourceMetadata | None: + """ + Handle protected resource metadata discovery response. + + Per SEP-985, supports fallback when discovery fails at one URL. + + Returns: + True if metadata was successfully discovered, False if we should try next URL + """ + if response.status_code == 200: + try: + content = await response.aread() + metadata = ProtectedResourceMetadata.model_validate_json(content) + return metadata + + except ValidationError: # pragma: no cover + # Invalid metadata - try next URL + return None + else: + # Not found - try next URL in fallback chain + return None + + +async def handle_auth_metadata_response(response: Response) -> tuple[bool, OAuthMetadata | None]: + if response.status_code == 200: + try: + content = await response.aread() + asm = OAuthMetadata.model_validate_json(content) + return True, asm + except ValidationError: # pragma: no cover + return True, None + elif response.status_code < 400 or response.status_code >= 500: + return False, None # Non-4XX error, stop trying + return True, None + + +def create_oauth_metadata_request(url: str) -> Request: + return Request("GET", url, headers={MCP_PROTOCOL_VERSION: LATEST_PROTOCOL_VERSION}) + + +def create_client_registration_request( + auth_server_metadata: OAuthMetadata | None, client_metadata: OAuthClientMetadata, auth_base_url: str +) -> Request: + """Build registration request or skip if already registered.""" + + if auth_server_metadata and auth_server_metadata.registration_endpoint: + registration_url = str(auth_server_metadata.registration_endpoint) + else: + registration_url = urljoin(auth_base_url, "/register") + + registration_data = client_metadata.model_dump(by_alias=True, mode="json", exclude_none=True) + + return Request("POST", registration_url, json=registration_data, headers={"Content-Type": "application/json"}) + + +async def handle_registration_response(response: Response) -> OAuthClientInformationFull: + """Handle registration response.""" + if response.status_code not in (200, 201): + await response.aread() + raise OAuthRegistrationError(f"Registration failed: {response.status_code} {response.text}") + + try: + content = await response.aread() + client_info = OAuthClientInformationFull.model_validate_json(content) + return client_info + # self.context.client_info = client_info + # await self.context.storage.set_client_info(client_info) + except ValidationError as e: # pragma: no cover + raise OAuthRegistrationError(f"Invalid registration response: {e}") + + +def is_valid_client_metadata_url(url: str | None) -> bool: + """Validate that a URL is suitable for use as a client_id (CIMD). + + The URL must be HTTPS with a non-root pathname. + + Args: + url: The URL to validate + + Returns: + True if the URL is a valid HTTPS URL with a non-root pathname + """ + if not url: + return False + try: + parsed = urlparse(url) + return parsed.scheme == "https" and parsed.path not in ("", "/") + except Exception: + return False + + +def should_use_client_metadata_url( + oauth_metadata: OAuthMetadata | None, + client_metadata_url: str | None, +) -> bool: + """Determine if URL-based client ID (CIMD) should be used instead of DCR. + + URL-based client IDs should be used when: + 1. The server advertises client_id_metadata_document_supported=true + 2. The client has a valid client_metadata_url configured + + Args: + oauth_metadata: OAuth authorization server metadata + client_metadata_url: URL-based client ID (already validated) + + Returns: + True if CIMD should be used, False if DCR should be used + """ + if not client_metadata_url: + return False + + if not oauth_metadata: + return False + + return oauth_metadata.client_id_metadata_document_supported is True + + +def create_client_info_from_metadata_url( + client_metadata_url: str, redirect_uris: list[AnyUrl] | None = None +) -> OAuthClientInformationFull: + """Create client information using a URL-based client ID (CIMD). + + When using URL-based client IDs, the URL itself becomes the client_id + and no client_secret is used (token_endpoint_auth_method="none"). + + Args: + client_metadata_url: The URL to use as the client_id + redirect_uris: The redirect URIs from the client metadata (passed through for + compatibility with OAuthClientInformationFull which inherits from OAuthClientMetadata) + + Returns: + OAuthClientInformationFull with the URL as client_id + """ + return OAuthClientInformationFull( + client_id=client_metadata_url, + token_endpoint_auth_method="none", + redirect_uris=redirect_uris, + ) + + +async def handle_token_response_scopes( + response: Response, +) -> OAuthToken: + """Parse and validate token response with optional scope validation. + + Parses token response JSON. Callers should check response.status_code before calling. + + Args: + response: HTTP response from token endpoint (status already checked by caller) + + Returns: + Validated OAuthToken model + + Raises: + OAuthTokenError: If response JSON is invalid + """ + try: + content = await response.aread() + token_response = OAuthToken.model_validate_json(content) + return token_response + except ValidationError as e: # pragma: no cover + raise OAuthTokenError(f"Invalid token response: {e}") diff --git a/source/target-vendors/cp312/mcp/client/experimental/__init__.py b/source/target-vendors/cp312/mcp/client/experimental/__init__.py new file mode 100644 index 0000000..b6579b1 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/experimental/__init__.py @@ -0,0 +1,9 @@ +""" +Experimental client features. + +WARNING: These APIs are experimental and may change without notice. +""" + +from mcp.client.experimental.tasks import ExperimentalClientFeatures + +__all__ = ["ExperimentalClientFeatures"] diff --git a/source/target-vendors/cp312/mcp/client/experimental/task_handlers.py b/source/target-vendors/cp312/mcp/client/experimental/task_handlers.py new file mode 100644 index 0000000..a475086 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/experimental/task_handlers.py @@ -0,0 +1,290 @@ +""" +Experimental task handler protocols for server -> client requests. + +This module provides Protocol types and default handlers for when servers +send task-related requests to clients (the reverse of normal client -> server flow). + +WARNING: These APIs are experimental and may change without notice. + +Use cases: +- Server sends task-augmented sampling/elicitation request to client +- Client creates a local task, spawns background work, returns CreateTaskResult +- Server polls client's task status via tasks/get, tasks/result, etc. +""" + +from dataclasses import dataclass, field +from typing import TYPE_CHECKING, Any, Protocol + +from pydantic import TypeAdapter + +import mcp.types as types +from mcp.shared.context import RequestContext +from mcp.shared.session import RequestResponder + +if TYPE_CHECKING: + from mcp.client.session import ClientSession + + +class GetTaskHandlerFnT(Protocol): + """Handler for tasks/get requests from server. + + WARNING: This is experimental and may change without notice. + """ + + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.GetTaskRequestParams, + ) -> types.GetTaskResult | types.ErrorData: ... # pragma: no branch + + +class GetTaskResultHandlerFnT(Protocol): + """Handler for tasks/result requests from server. + + WARNING: This is experimental and may change without notice. + """ + + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.GetTaskPayloadRequestParams, + ) -> types.GetTaskPayloadResult | types.ErrorData: ... # pragma: no branch + + +class ListTasksHandlerFnT(Protocol): + """Handler for tasks/list requests from server. + + WARNING: This is experimental and may change without notice. + """ + + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.PaginatedRequestParams | None, + ) -> types.ListTasksResult | types.ErrorData: ... # pragma: no branch + + +class CancelTaskHandlerFnT(Protocol): + """Handler for tasks/cancel requests from server. + + WARNING: This is experimental and may change without notice. + """ + + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.CancelTaskRequestParams, + ) -> types.CancelTaskResult | types.ErrorData: ... # pragma: no branch + + +class TaskAugmentedSamplingFnT(Protocol): + """Handler for task-augmented sampling/createMessage requests from server. + + When server sends a CreateMessageRequest with task field, this callback + is invoked. The callback should create a task, spawn background work, + and return CreateTaskResult immediately. + + WARNING: This is experimental and may change without notice. + """ + + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.CreateMessageRequestParams, + task_metadata: types.TaskMetadata, + ) -> types.CreateTaskResult | types.ErrorData: ... # pragma: no branch + + +class TaskAugmentedElicitationFnT(Protocol): + """Handler for task-augmented elicitation/create requests from server. + + When server sends an ElicitRequest with task field, this callback + is invoked. The callback should create a task, spawn background work, + and return CreateTaskResult immediately. + + WARNING: This is experimental and may change without notice. + """ + + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.ElicitRequestParams, + task_metadata: types.TaskMetadata, + ) -> types.CreateTaskResult | types.ErrorData: ... # pragma: no branch + + +async def default_get_task_handler( + context: RequestContext["ClientSession", Any], + params: types.GetTaskRequestParams, +) -> types.GetTaskResult | types.ErrorData: + return types.ErrorData( + code=types.METHOD_NOT_FOUND, + message="tasks/get not supported", + ) + + +async def default_get_task_result_handler( + context: RequestContext["ClientSession", Any], + params: types.GetTaskPayloadRequestParams, +) -> types.GetTaskPayloadResult | types.ErrorData: + return types.ErrorData( + code=types.METHOD_NOT_FOUND, + message="tasks/result not supported", + ) + + +async def default_list_tasks_handler( + context: RequestContext["ClientSession", Any], + params: types.PaginatedRequestParams | None, +) -> types.ListTasksResult | types.ErrorData: + return types.ErrorData( + code=types.METHOD_NOT_FOUND, + message="tasks/list not supported", + ) + + +async def default_cancel_task_handler( + context: RequestContext["ClientSession", Any], + params: types.CancelTaskRequestParams, +) -> types.CancelTaskResult | types.ErrorData: + return types.ErrorData( + code=types.METHOD_NOT_FOUND, + message="tasks/cancel not supported", + ) + + +async def default_task_augmented_sampling( + context: RequestContext["ClientSession", Any], + params: types.CreateMessageRequestParams, + task_metadata: types.TaskMetadata, +) -> types.CreateTaskResult | types.ErrorData: + return types.ErrorData( + code=types.INVALID_REQUEST, + message="Task-augmented sampling not supported", + ) + + +async def default_task_augmented_elicitation( + context: RequestContext["ClientSession", Any], + params: types.ElicitRequestParams, + task_metadata: types.TaskMetadata, +) -> types.CreateTaskResult | types.ErrorData: + return types.ErrorData( + code=types.INVALID_REQUEST, + message="Task-augmented elicitation not supported", + ) + + +@dataclass +class ExperimentalTaskHandlers: + """Container for experimental task handlers. + + Groups all task-related handlers that handle server -> client requests. + This includes both pure task requests (get, list, cancel, result) and + task-augmented request handlers (sampling, elicitation with task field). + + WARNING: These APIs are experimental and may change without notice. + + Example: + handlers = ExperimentalTaskHandlers( + get_task=my_get_task_handler, + list_tasks=my_list_tasks_handler, + ) + session = ClientSession(..., experimental_task_handlers=handlers) + """ + + # Pure task request handlers + get_task: GetTaskHandlerFnT = field(default=default_get_task_handler) + get_task_result: GetTaskResultHandlerFnT = field(default=default_get_task_result_handler) + list_tasks: ListTasksHandlerFnT = field(default=default_list_tasks_handler) + cancel_task: CancelTaskHandlerFnT = field(default=default_cancel_task_handler) + + # Task-augmented request handlers + augmented_sampling: TaskAugmentedSamplingFnT = field(default=default_task_augmented_sampling) + augmented_elicitation: TaskAugmentedElicitationFnT = field(default=default_task_augmented_elicitation) + + def build_capability(self) -> types.ClientTasksCapability | None: + """Build ClientTasksCapability from the configured handlers. + + Returns a capability object that reflects which handlers are configured + (i.e., not using the default "not supported" handlers). + + Returns: + ClientTasksCapability if any handlers are provided, None otherwise + """ + has_list = self.list_tasks is not default_list_tasks_handler + has_cancel = self.cancel_task is not default_cancel_task_handler + has_sampling = self.augmented_sampling is not default_task_augmented_sampling + has_elicitation = self.augmented_elicitation is not default_task_augmented_elicitation + + # If no handlers are provided, return None + if not any([has_list, has_cancel, has_sampling, has_elicitation]): + return None + + # Build requests capability if any request handlers are provided + requests_capability: types.ClientTasksRequestsCapability | None = None + if has_sampling or has_elicitation: + requests_capability = types.ClientTasksRequestsCapability( + sampling=types.TasksSamplingCapability(createMessage=types.TasksCreateMessageCapability()) + if has_sampling + else None, + elicitation=types.TasksElicitationCapability(create=types.TasksCreateElicitationCapability()) + if has_elicitation + else None, + ) + + return types.ClientTasksCapability( + list=types.TasksListCapability() if has_list else None, + cancel=types.TasksCancelCapability() if has_cancel else None, + requests=requests_capability, + ) + + @staticmethod + def handles_request(request: types.ServerRequest) -> bool: + """Check if this handler handles the given request type.""" + return isinstance( + request.root, + types.GetTaskRequest | types.GetTaskPayloadRequest | types.ListTasksRequest | types.CancelTaskRequest, + ) + + async def handle_request( + self, + ctx: RequestContext["ClientSession", Any], + responder: RequestResponder[types.ServerRequest, types.ClientResult], + ) -> None: + """Handle a task-related request from the server. + + Call handles_request() first to check if this handler can handle the request. + """ + client_response_type: TypeAdapter[types.ClientResult | types.ErrorData] = TypeAdapter( + types.ClientResult | types.ErrorData + ) + + match responder.request.root: + case types.GetTaskRequest(params=params): + response = await self.get_task(ctx, params) + client_response = client_response_type.validate_python(response) + await responder.respond(client_response) + + case types.GetTaskPayloadRequest(params=params): + response = await self.get_task_result(ctx, params) + client_response = client_response_type.validate_python(response) + await responder.respond(client_response) + + case types.ListTasksRequest(params=params): + response = await self.list_tasks(ctx, params) + client_response = client_response_type.validate_python(response) + await responder.respond(client_response) + + case types.CancelTaskRequest(params=params): + response = await self.cancel_task(ctx, params) + client_response = client_response_type.validate_python(response) + await responder.respond(client_response) + + case _: # pragma: no cover + raise ValueError(f"Unhandled request type: {type(responder.request.root)}") + + +# Backwards compatibility aliases +default_task_augmented_sampling_callback = default_task_augmented_sampling +default_task_augmented_elicitation_callback = default_task_augmented_elicitation diff --git a/source/target-vendors/cp312/mcp/client/experimental/tasks.py b/source/target-vendors/cp312/mcp/client/experimental/tasks.py new file mode 100644 index 0000000..ce9c387 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/experimental/tasks.py @@ -0,0 +1,224 @@ +""" +Experimental client-side task support. + +This module provides client methods for interacting with MCP tasks. + +WARNING: These APIs are experimental and may change without notice. + +Example: + # Call a tool as a task + result = await session.experimental.call_tool_as_task("tool_name", {"arg": "value"}) + task_id = result.task.taskId + + # Get task status + status = await session.experimental.get_task(task_id) + + # Get task result when complete + if status.status == "completed": + result = await session.experimental.get_task_result(task_id, CallToolResult) + + # List all tasks + tasks = await session.experimental.list_tasks() + + # Cancel a task + await session.experimental.cancel_task(task_id) +""" + +from collections.abc import AsyncIterator +from typing import TYPE_CHECKING, Any, TypeVar + +import mcp.types as types +from mcp.shared.experimental.tasks.polling import poll_until_terminal + +if TYPE_CHECKING: + from mcp.client.session import ClientSession + +ResultT = TypeVar("ResultT", bound=types.Result) + + +class ExperimentalClientFeatures: + """ + Experimental client features for tasks and other experimental APIs. + + WARNING: These APIs are experimental and may change without notice. + + Access via session.experimental: + status = await session.experimental.get_task(task_id) + """ + + def __init__(self, session: "ClientSession") -> None: + self._session = session + + async def call_tool_as_task( + self, + name: str, + arguments: dict[str, Any] | None = None, + *, + ttl: int = 60000, + meta: dict[str, Any] | None = None, + ) -> types.CreateTaskResult: + """Call a tool as a task, returning a CreateTaskResult for polling. + + This is a convenience method for calling tools that support task execution. + The server will return a task reference instead of the immediate result, + which can then be polled via `get_task()` and retrieved via `get_task_result()`. + + Args: + name: The tool name + arguments: Tool arguments + ttl: Task time-to-live in milliseconds (default: 60000 = 1 minute) + meta: Optional metadata to include in the request + + Returns: + CreateTaskResult containing the task reference + + Example: + # Create task + result = await session.experimental.call_tool_as_task( + "long_running_tool", {"input": "data"} + ) + task_id = result.task.taskId + + # Poll for completion + while True: + status = await session.experimental.get_task(task_id) + if status.status == "completed": + break + await asyncio.sleep(0.5) + + # Get result + final = await session.experimental.get_task_result(task_id, CallToolResult) + """ + _meta: types.RequestParams.Meta | None = None + if meta is not None: + _meta = types.RequestParams.Meta(**meta) + + return await self._session.send_request( + types.ClientRequest( + types.CallToolRequest( + params=types.CallToolRequestParams( + name=name, + arguments=arguments, + task=types.TaskMetadata(ttl=ttl), + _meta=_meta, + ), + ) + ), + types.CreateTaskResult, + ) + + async def get_task(self, task_id: str) -> types.GetTaskResult: + """ + Get the current status of a task. + + Args: + task_id: The task identifier + + Returns: + GetTaskResult containing the task status and metadata + """ + return await self._session.send_request( + types.ClientRequest( + types.GetTaskRequest( + params=types.GetTaskRequestParams(taskId=task_id), + ) + ), + types.GetTaskResult, + ) + + async def get_task_result( + self, + task_id: str, + result_type: type[ResultT], + ) -> ResultT: + """ + Get the result of a completed task. + + The result type depends on the original request type: + - tools/call tasks return CallToolResult + - Other request types return their corresponding result type + + Args: + task_id: The task identifier + result_type: The expected result type (e.g., CallToolResult) + + Returns: + The task result, validated against result_type + """ + return await self._session.send_request( + types.ClientRequest( + types.GetTaskPayloadRequest( + params=types.GetTaskPayloadRequestParams(taskId=task_id), + ) + ), + result_type, + ) + + async def list_tasks( + self, + cursor: str | None = None, + ) -> types.ListTasksResult: + """ + List all tasks. + + Args: + cursor: Optional pagination cursor + + Returns: + ListTasksResult containing tasks and optional next cursor + """ + params = types.PaginatedRequestParams(cursor=cursor) if cursor else None + return await self._session.send_request( + types.ClientRequest( + types.ListTasksRequest(params=params), + ), + types.ListTasksResult, + ) + + async def cancel_task(self, task_id: str) -> types.CancelTaskResult: + """ + Cancel a running task. + + Args: + task_id: The task identifier + + Returns: + CancelTaskResult with the updated task state + """ + return await self._session.send_request( + types.ClientRequest( + types.CancelTaskRequest( + params=types.CancelTaskRequestParams(taskId=task_id), + ) + ), + types.CancelTaskResult, + ) + + async def poll_task(self, task_id: str) -> AsyncIterator[types.GetTaskResult]: + """ + Poll a task until it reaches a terminal status. + + Yields GetTaskResult for each poll, allowing the caller to react to + status changes (e.g., handle input_required). Exits when task reaches + a terminal status (completed, failed, cancelled). + + Respects the pollInterval hint from the server. + + Args: + task_id: The task identifier + + Yields: + GetTaskResult for each poll + + Example: + async for status in session.experimental.poll_task(task_id): + print(f"Status: {status.status}") + if status.status == "input_required": + # Handle elicitation request via tasks/result + pass + + # Task is now terminal, get the result + result = await session.experimental.get_task_result(task_id, CallToolResult) + """ + async for status in poll_until_terminal(self.get_task, task_id): + yield status diff --git a/source/target-vendors/cp312/mcp/client/session.py b/source/target-vendors/cp312/mcp/client/session.py new file mode 100644 index 0000000..8519f15 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/session.py @@ -0,0 +1,615 @@ +import logging +from datetime import timedelta +from typing import Any, Protocol, overload + +import anyio.lowlevel +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import AnyUrl, TypeAdapter +from typing_extensions import deprecated + +import mcp.types as types +from mcp.client.experimental import ExperimentalClientFeatures +from mcp.client.experimental.task_handlers import ExperimentalTaskHandlers +from mcp.shared.context import RequestContext +from mcp.shared.message import SessionMessage +from mcp.shared.session import BaseSession, ProgressFnT, RequestResponder +from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS + +DEFAULT_CLIENT_INFO = types.Implementation(name="mcp", version="0.1.0") + +logger = logging.getLogger("client") + + +class SamplingFnT(Protocol): + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.CreateMessageRequestParams, + ) -> types.CreateMessageResult | types.CreateMessageResultWithTools | types.ErrorData: ... # pragma: no branch + + +class ElicitationFnT(Protocol): + async def __call__( + self, + context: RequestContext["ClientSession", Any], + params: types.ElicitRequestParams, + ) -> types.ElicitResult | types.ErrorData: ... # pragma: no branch + + +class ListRootsFnT(Protocol): + async def __call__( + self, context: RequestContext["ClientSession", Any] + ) -> types.ListRootsResult | types.ErrorData: ... # pragma: no branch + + +class LoggingFnT(Protocol): + async def __call__( + self, + params: types.LoggingMessageNotificationParams, + ) -> None: ... # pragma: no branch + + +class MessageHandlerFnT(Protocol): + async def __call__( + self, + message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception, + ) -> None: ... # pragma: no branch + + +async def _default_message_handler( + message: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception, +) -> None: + await anyio.lowlevel.checkpoint() + + +async def _default_sampling_callback( + context: RequestContext["ClientSession", Any], + params: types.CreateMessageRequestParams, +) -> types.CreateMessageResult | types.CreateMessageResultWithTools | types.ErrorData: + return types.ErrorData( + code=types.INVALID_REQUEST, + message="Sampling not supported", + ) + + +async def _default_elicitation_callback( + context: RequestContext["ClientSession", Any], + params: types.ElicitRequestParams, +) -> types.ElicitResult | types.ErrorData: + return types.ErrorData( # pragma: no cover + code=types.INVALID_REQUEST, + message="Elicitation not supported", + ) + + +async def _default_list_roots_callback( + context: RequestContext["ClientSession", Any], +) -> types.ListRootsResult | types.ErrorData: + return types.ErrorData( + code=types.INVALID_REQUEST, + message="List roots not supported", + ) + + +async def _default_logging_callback( + params: types.LoggingMessageNotificationParams, +) -> None: + pass + + +ClientResponse: TypeAdapter[types.ClientResult | types.ErrorData] = TypeAdapter(types.ClientResult | types.ErrorData) + + +class ClientSession( + BaseSession[ + types.ClientRequest, + types.ClientNotification, + types.ClientResult, + types.ServerRequest, + types.ServerNotification, + ] +): + def __init__( + self, + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], + write_stream: MemoryObjectSendStream[SessionMessage], + read_timeout_seconds: timedelta | None = None, + sampling_callback: SamplingFnT | None = None, + elicitation_callback: ElicitationFnT | None = None, + list_roots_callback: ListRootsFnT | None = None, + logging_callback: LoggingFnT | None = None, + message_handler: MessageHandlerFnT | None = None, + client_info: types.Implementation | None = None, + *, + sampling_capabilities: types.SamplingCapability | None = None, + experimental_task_handlers: ExperimentalTaskHandlers | None = None, + ) -> None: + super().__init__( + read_stream, + write_stream, + types.ServerRequest, + types.ServerNotification, + read_timeout_seconds=read_timeout_seconds, + ) + self._client_info = client_info or DEFAULT_CLIENT_INFO + self._sampling_callback = sampling_callback or _default_sampling_callback + self._sampling_capabilities = sampling_capabilities + self._elicitation_callback = elicitation_callback or _default_elicitation_callback + self._list_roots_callback = list_roots_callback or _default_list_roots_callback + self._logging_callback = logging_callback or _default_logging_callback + self._message_handler = message_handler or _default_message_handler + self._tool_output_schemas: dict[str, dict[str, Any] | None] = {} + self._server_capabilities: types.ServerCapabilities | None = None + self._experimental_features: ExperimentalClientFeatures | None = None + + # Experimental: Task handlers (use defaults if not provided) + self._task_handlers = experimental_task_handlers or ExperimentalTaskHandlers() + + async def initialize(self) -> types.InitializeResult: + sampling = ( + (self._sampling_capabilities or types.SamplingCapability()) + if self._sampling_callback is not _default_sampling_callback + else None + ) + elicitation = ( + types.ElicitationCapability( + form=types.FormElicitationCapability(), + url=types.UrlElicitationCapability(), + ) + if self._elicitation_callback is not _default_elicitation_callback + else None + ) + roots = ( + # TODO: Should this be based on whether we + # _will_ send notifications, or only whether + # they're supported? + types.RootsCapability(listChanged=True) + if self._list_roots_callback is not _default_list_roots_callback + else None + ) + + result = await self.send_request( + types.ClientRequest( + types.InitializeRequest( + params=types.InitializeRequestParams( + protocolVersion=types.LATEST_PROTOCOL_VERSION, + capabilities=types.ClientCapabilities( + sampling=sampling, + elicitation=elicitation, + experimental=None, + roots=roots, + tasks=self._task_handlers.build_capability(), + ), + clientInfo=self._client_info, + ), + ) + ), + types.InitializeResult, + ) + + if result.protocolVersion not in SUPPORTED_PROTOCOL_VERSIONS: + raise RuntimeError(f"Unsupported protocol version from the server: {result.protocolVersion}") + + self._server_capabilities = result.capabilities + + await self.send_notification(types.ClientNotification(types.InitializedNotification())) + + return result + + def get_server_capabilities(self) -> types.ServerCapabilities | None: + """Return the server capabilities received during initialization. + + Returns None if the session has not been initialized yet. + """ + return self._server_capabilities + + @property + def experimental(self) -> ExperimentalClientFeatures: + """Experimental APIs for tasks and other features. + + WARNING: These APIs are experimental and may change without notice. + + Example: + status = await session.experimental.get_task(task_id) + result = await session.experimental.get_task_result(task_id, CallToolResult) + """ + if self._experimental_features is None: + self._experimental_features = ExperimentalClientFeatures(self) + return self._experimental_features + + async def send_ping(self) -> types.EmptyResult: + """Send a ping request.""" + return await self.send_request( + types.ClientRequest(types.PingRequest()), + types.EmptyResult, + ) + + async def send_progress_notification( + self, + progress_token: str | int, + progress: float, + total: float | None = None, + message: str | None = None, + ) -> None: + """Send a progress notification.""" + await self.send_notification( + types.ClientNotification( + types.ProgressNotification( + params=types.ProgressNotificationParams( + progressToken=progress_token, + progress=progress, + total=total, + message=message, + ), + ), + ) + ) + + async def set_logging_level(self, level: types.LoggingLevel) -> types.EmptyResult: + """Send a logging/setLevel request.""" + return await self.send_request( # pragma: no cover + types.ClientRequest( + types.SetLevelRequest( + params=types.SetLevelRequestParams(level=level), + ) + ), + types.EmptyResult, + ) + + @overload + @deprecated("Use list_resources(params=PaginatedRequestParams(...)) instead") + async def list_resources(self, cursor: str | None) -> types.ListResourcesResult: ... + + @overload + async def list_resources(self, *, params: types.PaginatedRequestParams | None) -> types.ListResourcesResult: ... + + @overload + async def list_resources(self) -> types.ListResourcesResult: ... + + async def list_resources( + self, + cursor: str | None = None, + *, + params: types.PaginatedRequestParams | None = None, + ) -> types.ListResourcesResult: + """Send a resources/list request. + + Args: + cursor: Simple cursor string for pagination (deprecated, use params instead) + params: Full pagination parameters including cursor and any future fields + """ + if params is not None and cursor is not None: + raise ValueError("Cannot specify both cursor and params") + + if params is not None: + request_params = params + elif cursor is not None: + request_params = types.PaginatedRequestParams(cursor=cursor) + else: + request_params = None + + return await self.send_request( + types.ClientRequest(types.ListResourcesRequest(params=request_params)), + types.ListResourcesResult, + ) + + @overload + @deprecated("Use list_resource_templates(params=PaginatedRequestParams(...)) instead") + async def list_resource_templates(self, cursor: str | None) -> types.ListResourceTemplatesResult: ... + + @overload + async def list_resource_templates( + self, *, params: types.PaginatedRequestParams | None + ) -> types.ListResourceTemplatesResult: ... + + @overload + async def list_resource_templates(self) -> types.ListResourceTemplatesResult: ... + + async def list_resource_templates( + self, + cursor: str | None = None, + *, + params: types.PaginatedRequestParams | None = None, + ) -> types.ListResourceTemplatesResult: + """Send a resources/templates/list request. + + Args: + cursor: Simple cursor string for pagination (deprecated, use params instead) + params: Full pagination parameters including cursor and any future fields + """ + if params is not None and cursor is not None: + raise ValueError("Cannot specify both cursor and params") + + if params is not None: + request_params = params + elif cursor is not None: + request_params = types.PaginatedRequestParams(cursor=cursor) + else: + request_params = None + + return await self.send_request( + types.ClientRequest(types.ListResourceTemplatesRequest(params=request_params)), + types.ListResourceTemplatesResult, + ) + + async def read_resource(self, uri: AnyUrl) -> types.ReadResourceResult: + """Send a resources/read request.""" + return await self.send_request( + types.ClientRequest( + types.ReadResourceRequest( + params=types.ReadResourceRequestParams(uri=uri), + ) + ), + types.ReadResourceResult, + ) + + async def subscribe_resource(self, uri: AnyUrl) -> types.EmptyResult: + """Send a resources/subscribe request.""" + return await self.send_request( # pragma: no cover + types.ClientRequest( + types.SubscribeRequest( + params=types.SubscribeRequestParams(uri=uri), + ) + ), + types.EmptyResult, + ) + + async def unsubscribe_resource(self, uri: AnyUrl) -> types.EmptyResult: + """Send a resources/unsubscribe request.""" + return await self.send_request( # pragma: no cover + types.ClientRequest( + types.UnsubscribeRequest( + params=types.UnsubscribeRequestParams(uri=uri), + ) + ), + types.EmptyResult, + ) + + async def call_tool( + self, + name: str, + arguments: dict[str, Any] | None = None, + read_timeout_seconds: timedelta | None = None, + progress_callback: ProgressFnT | None = None, + *, + meta: dict[str, Any] | None = None, + ) -> types.CallToolResult: + """Send a tools/call request with optional progress callback support.""" + + _meta: types.RequestParams.Meta | None = None + if meta is not None: + _meta = types.RequestParams.Meta(**meta) + + result = await self.send_request( + types.ClientRequest( + types.CallToolRequest( + params=types.CallToolRequestParams(name=name, arguments=arguments, _meta=_meta), + ) + ), + types.CallToolResult, + request_read_timeout_seconds=read_timeout_seconds, + progress_callback=progress_callback, + ) + + if not result.isError: + await self._validate_tool_result(name, result) + + return result + + async def _validate_tool_result(self, name: str, result: types.CallToolResult) -> None: + """Validate the structured content of a tool result against its output schema.""" + if name not in self._tool_output_schemas: + # refresh output schema cache + await self.list_tools() + + output_schema = None + if name in self._tool_output_schemas: + output_schema = self._tool_output_schemas.get(name) + else: + logger.warning(f"Tool {name} not listed by server, cannot validate any structured content") + + if output_schema is not None: + from jsonschema import SchemaError, ValidationError, validate + + if result.structuredContent is None: + raise RuntimeError( + f"Tool {name} has an output schema but did not return structured content" + ) # pragma: no cover + try: + validate(result.structuredContent, output_schema) + except ValidationError as e: + raise RuntimeError(f"Invalid structured content returned by tool {name}: {e}") # pragma: no cover + except SchemaError as e: # pragma: no cover + raise RuntimeError(f"Invalid schema for tool {name}: {e}") # pragma: no cover + + @overload + @deprecated("Use list_prompts(params=PaginatedRequestParams(...)) instead") + async def list_prompts(self, cursor: str | None) -> types.ListPromptsResult: ... + + @overload + async def list_prompts(self, *, params: types.PaginatedRequestParams | None) -> types.ListPromptsResult: ... + + @overload + async def list_prompts(self) -> types.ListPromptsResult: ... + + async def list_prompts( + self, + cursor: str | None = None, + *, + params: types.PaginatedRequestParams | None = None, + ) -> types.ListPromptsResult: + """Send a prompts/list request. + + Args: + cursor: Simple cursor string for pagination (deprecated, use params instead) + params: Full pagination parameters including cursor and any future fields + """ + if params is not None and cursor is not None: + raise ValueError("Cannot specify both cursor and params") + + if params is not None: + request_params = params + elif cursor is not None: + request_params = types.PaginatedRequestParams(cursor=cursor) + else: + request_params = None + + return await self.send_request( + types.ClientRequest(types.ListPromptsRequest(params=request_params)), + types.ListPromptsResult, + ) + + async def get_prompt(self, name: str, arguments: dict[str, str] | None = None) -> types.GetPromptResult: + """Send a prompts/get request.""" + return await self.send_request( + types.ClientRequest( + types.GetPromptRequest( + params=types.GetPromptRequestParams(name=name, arguments=arguments), + ) + ), + types.GetPromptResult, + ) + + async def complete( + self, + ref: types.ResourceTemplateReference | types.PromptReference, + argument: dict[str, str], + context_arguments: dict[str, str] | None = None, + ) -> types.CompleteResult: + """Send a completion/complete request.""" + context = None + if context_arguments is not None: + context = types.CompletionContext(arguments=context_arguments) + + return await self.send_request( + types.ClientRequest( + types.CompleteRequest( + params=types.CompleteRequestParams( + ref=ref, + argument=types.CompletionArgument(**argument), + context=context, + ), + ) + ), + types.CompleteResult, + ) + + @overload + @deprecated("Use list_tools(params=PaginatedRequestParams(...)) instead") + async def list_tools(self, cursor: str | None) -> types.ListToolsResult: ... + + @overload + async def list_tools(self, *, params: types.PaginatedRequestParams | None) -> types.ListToolsResult: ... + + @overload + async def list_tools(self) -> types.ListToolsResult: ... + + async def list_tools( + self, + cursor: str | None = None, + *, + params: types.PaginatedRequestParams | None = None, + ) -> types.ListToolsResult: + """Send a tools/list request. + + Args: + cursor: Simple cursor string for pagination (deprecated, use params instead) + params: Full pagination parameters including cursor and any future fields + """ + if params is not None and cursor is not None: + raise ValueError("Cannot specify both cursor and params") + + if params is not None: + request_params = params + elif cursor is not None: + request_params = types.PaginatedRequestParams(cursor=cursor) + else: + request_params = None + + result = await self.send_request( + types.ClientRequest(types.ListToolsRequest(params=request_params)), + types.ListToolsResult, + ) + + # Cache tool output schemas for future validation + # Note: don't clear the cache, as we may be using a cursor + for tool in result.tools: + self._tool_output_schemas[tool.name] = tool.outputSchema + + return result + + async def send_roots_list_changed(self) -> None: # pragma: no cover + """Send a roots/list_changed notification.""" + await self.send_notification(types.ClientNotification(types.RootsListChangedNotification())) + + async def _received_request(self, responder: RequestResponder[types.ServerRequest, types.ClientResult]) -> None: + ctx = RequestContext[ClientSession, Any]( + request_id=responder.request_id, + meta=responder.request_meta, + session=self, + lifespan_context=None, + ) + + # Delegate to experimental task handler if applicable + if self._task_handlers.handles_request(responder.request): + with responder: + await self._task_handlers.handle_request(ctx, responder) + return None + + # Core request handling + match responder.request.root: + case types.CreateMessageRequest(params=params): + with responder: + # Check if this is a task-augmented request + if params.task is not None: + response = await self._task_handlers.augmented_sampling(ctx, params, params.task) + else: + response = await self._sampling_callback(ctx, params) + client_response = ClientResponse.validate_python(response) + await responder.respond(client_response) + + case types.ElicitRequest(params=params): + with responder: + # Check if this is a task-augmented request + if params.task is not None: + response = await self._task_handlers.augmented_elicitation(ctx, params, params.task) + else: + response = await self._elicitation_callback(ctx, params) + client_response = ClientResponse.validate_python(response) + await responder.respond(client_response) + + case types.ListRootsRequest(): + with responder: + response = await self._list_roots_callback(ctx) + client_response = ClientResponse.validate_python(response) + await responder.respond(client_response) + + case types.PingRequest(): # pragma: no cover + with responder: + return await responder.respond(types.ClientResult(root=types.EmptyResult())) + + case _: # pragma: no cover + pass # Task requests handled above by _task_handlers + + return None + + async def _handle_incoming( + self, + req: RequestResponder[types.ServerRequest, types.ClientResult] | types.ServerNotification | Exception, + ) -> None: + """Handle incoming messages by forwarding to the message handler.""" + await self._message_handler(req) + + async def _received_notification(self, notification: types.ServerNotification) -> None: + """Handle notifications from the server.""" + # Process specific notification types + match notification.root: + case types.LoggingMessageNotification(params=params): + await self._logging_callback(params) + case types.ElicitCompleteNotification(params=params): + # Handle elicitation completion notification + # Clients MAY use this to retry requests or update UI + # The notification contains the elicitationId of the completed elicitation + pass + case _: + pass diff --git a/source/target-vendors/cp312/mcp/client/session_group.py b/source/target-vendors/cp312/mcp/client/session_group.py new file mode 100644 index 0000000..f82677d --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/session_group.py @@ -0,0 +1,447 @@ +""" +SessionGroup concurrently manages multiple MCP session connections. + +Tools, resources, and prompts are aggregated across servers. Servers may +be connected to or disconnected from at any point after initialization. + +This abstractions can handle naming collisions using a custom user-provided +hook. +""" + +import contextlib +import logging +from collections.abc import Callable +from dataclasses import dataclass +from datetime import timedelta +from types import TracebackType +from typing import Any, TypeAlias, overload + +import anyio +import httpx +from pydantic import BaseModel +from typing_extensions import Self, deprecated + +import mcp +from mcp import types +from mcp.client.session import ElicitationFnT, ListRootsFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT +from mcp.client.sse import sse_client +from mcp.client.stdio import StdioServerParameters +from mcp.client.streamable_http import streamable_http_client +from mcp.shared._httpx_utils import create_mcp_http_client +from mcp.shared.exceptions import McpError +from mcp.shared.session import ProgressFnT + + +class SseServerParameters(BaseModel): + """Parameters for intializing a sse_client.""" + + # The endpoint URL. + url: str + + # Optional headers to include in requests. + headers: dict[str, Any] | None = None + + # HTTP timeout for regular operations. + timeout: float = 5 + + # Timeout for SSE read operations. + sse_read_timeout: float = 60 * 5 + + +class StreamableHttpParameters(BaseModel): + """Parameters for intializing a streamable_http_client.""" + + # The endpoint URL. + url: str + + # Optional headers to include in requests. + headers: dict[str, Any] | None = None + + # HTTP timeout for regular operations. + timeout: timedelta = timedelta(seconds=30) + + # Timeout for SSE read operations. + sse_read_timeout: timedelta = timedelta(seconds=60 * 5) + + # Close the client session when the transport closes. + terminate_on_close: bool = True + + +ServerParameters: TypeAlias = StdioServerParameters | SseServerParameters | StreamableHttpParameters + + +# Use dataclass instead of pydantic BaseModel +# because pydantic BaseModel cannot handle Protocol fields. +@dataclass +class ClientSessionParameters: + """Parameters for establishing a client session to an MCP server.""" + + read_timeout_seconds: timedelta | None = None + sampling_callback: SamplingFnT | None = None + elicitation_callback: ElicitationFnT | None = None + list_roots_callback: ListRootsFnT | None = None + logging_callback: LoggingFnT | None = None + message_handler: MessageHandlerFnT | None = None + client_info: types.Implementation | None = None + + +class ClientSessionGroup: + """Client for managing connections to multiple MCP servers. + + This class is responsible for encapsulating management of server connections. + It aggregates tools, resources, and prompts from all connected servers. + + For auxiliary handlers, such as resource subscription, this is delegated to + the client and can be accessed via the session. + + Example Usage: + name_fn = lambda name, server_info: f"{(server_info.name)}_{name}" + async with ClientSessionGroup(component_name_hook=name_fn) as group: + for server_param in server_params: + await group.connect_to_server(server_param) + ... + + """ + + class _ComponentNames(BaseModel): + """Used for reverse index to find components.""" + + prompts: set[str] = set() + resources: set[str] = set() + tools: set[str] = set() + + # Standard MCP components. + _prompts: dict[str, types.Prompt] + _resources: dict[str, types.Resource] + _tools: dict[str, types.Tool] + + # Client-server connection management. + _sessions: dict[mcp.ClientSession, _ComponentNames] + _tool_to_session: dict[str, mcp.ClientSession] + _exit_stack: contextlib.AsyncExitStack + _session_exit_stacks: dict[mcp.ClientSession, contextlib.AsyncExitStack] + + # Optional fn consuming (component_name, serverInfo) for custom names. + # This is provide a means to mitigate naming conflicts across servers. + # Example: (tool_name, serverInfo) => "{result.serverInfo.name}.{tool_name}" + _ComponentNameHook: TypeAlias = Callable[[str, types.Implementation], str] + _component_name_hook: _ComponentNameHook | None + + def __init__( + self, + exit_stack: contextlib.AsyncExitStack | None = None, + component_name_hook: _ComponentNameHook | None = None, + ) -> None: + """Initializes the MCP client.""" + + self._tools = {} + self._resources = {} + self._prompts = {} + + self._sessions = {} + self._tool_to_session = {} + if exit_stack is None: + self._exit_stack = contextlib.AsyncExitStack() + self._owns_exit_stack = True + else: + self._exit_stack = exit_stack + self._owns_exit_stack = False + self._session_exit_stacks = {} + self._component_name_hook = component_name_hook + + async def __aenter__(self) -> Self: # pragma: no cover + # Enter the exit stack only if we created it ourselves + if self._owns_exit_stack: + await self._exit_stack.__aenter__() + return self + + async def __aexit__( + self, + _exc_type: type[BaseException] | None, + _exc_val: BaseException | None, + _exc_tb: TracebackType | None, + ) -> bool | None: # pragma: no cover + """Closes session exit stacks and main exit stack upon completion.""" + + # Only close the main exit stack if we created it + if self._owns_exit_stack: + await self._exit_stack.aclose() + + # Concurrently close session stacks. + async with anyio.create_task_group() as tg: + for exit_stack in self._session_exit_stacks.values(): + tg.start_soon(exit_stack.aclose) + + @property + def sessions(self) -> list[mcp.ClientSession]: + """Returns the list of sessions being managed.""" + return list(self._sessions.keys()) # pragma: no cover + + @property + def prompts(self) -> dict[str, types.Prompt]: + """Returns the prompts as a dictionary of names to prompts.""" + return self._prompts + + @property + def resources(self) -> dict[str, types.Resource]: + """Returns the resources as a dictionary of names to resources.""" + return self._resources + + @property + def tools(self) -> dict[str, types.Tool]: + """Returns the tools as a dictionary of names to tools.""" + return self._tools + + @overload + async def call_tool( + self, + name: str, + arguments: dict[str, Any], + read_timeout_seconds: timedelta | None = None, + progress_callback: ProgressFnT | None = None, + *, + meta: dict[str, Any] | None = None, + ) -> types.CallToolResult: ... + + @overload + @deprecated("The 'args' parameter is deprecated. Use 'arguments' instead.") + async def call_tool( + self, + name: str, + *, + args: dict[str, Any], + read_timeout_seconds: timedelta | None = None, + progress_callback: ProgressFnT | None = None, + meta: dict[str, Any] | None = None, + ) -> types.CallToolResult: ... + + async def call_tool( + self, + name: str, + arguments: dict[str, Any] | None = None, + read_timeout_seconds: timedelta | None = None, + progress_callback: ProgressFnT | None = None, + *, + meta: dict[str, Any] | None = None, + args: dict[str, Any] | None = None, + ) -> types.CallToolResult: + """Executes a tool given its name and arguments.""" + session = self._tool_to_session[name] + session_tool_name = self.tools[name].name + return await session.call_tool( + session_tool_name, + arguments if args is None else args, + read_timeout_seconds=read_timeout_seconds, + progress_callback=progress_callback, + meta=meta, + ) + + async def disconnect_from_server(self, session: mcp.ClientSession) -> None: + """Disconnects from a single MCP server.""" + + session_known_for_components = session in self._sessions + session_known_for_stack = session in self._session_exit_stacks + + if not session_known_for_components and not session_known_for_stack: + raise McpError( + types.ErrorData( + code=types.INVALID_PARAMS, + message="Provided session is not managed or already disconnected.", + ) + ) + + if session_known_for_components: # pragma: no cover + component_names = self._sessions.pop(session) # Pop from _sessions tracking + + # Remove prompts associated with the session. + for name in component_names.prompts: + if name in self._prompts: + del self._prompts[name] + # Remove resources associated with the session. + for name in component_names.resources: + if name in self._resources: + del self._resources[name] + # Remove tools associated with the session. + for name in component_names.tools: + if name in self._tools: + del self._tools[name] + if name in self._tool_to_session: + del self._tool_to_session[name] + + # Clean up the session's resources via its dedicated exit stack + if session_known_for_stack: + session_stack_to_close = self._session_exit_stacks.pop(session) # pragma: no cover + await session_stack_to_close.aclose() # pragma: no cover + + async def connect_with_session( + self, server_info: types.Implementation, session: mcp.ClientSession + ) -> mcp.ClientSession: + """Connects to a single MCP server.""" + await self._aggregate_components(server_info, session) + return session + + async def connect_to_server( + self, + server_params: ServerParameters, + session_params: ClientSessionParameters | None = None, + ) -> mcp.ClientSession: + """Connects to a single MCP server.""" + server_info, session = await self._establish_session(server_params, session_params or ClientSessionParameters()) + return await self.connect_with_session(server_info, session) + + async def _establish_session( + self, + server_params: ServerParameters, + session_params: ClientSessionParameters, + ) -> tuple[types.Implementation, mcp.ClientSession]: + """Establish a client session to an MCP server.""" + + session_stack = contextlib.AsyncExitStack() + try: + # Create read and write streams that facilitate io with the server. + if isinstance(server_params, StdioServerParameters): + client = mcp.stdio_client(server_params) + read, write = await session_stack.enter_async_context(client) + elif isinstance(server_params, SseServerParameters): + client = sse_client( + url=server_params.url, + headers=server_params.headers, + timeout=server_params.timeout, + sse_read_timeout=server_params.sse_read_timeout, + ) + read, write = await session_stack.enter_async_context(client) + else: + httpx_client = create_mcp_http_client( + headers=server_params.headers, + timeout=httpx.Timeout( + server_params.timeout.total_seconds(), + read=server_params.sse_read_timeout.total_seconds(), + ), + ) + await session_stack.enter_async_context(httpx_client) + + client = streamable_http_client( + url=server_params.url, + http_client=httpx_client, + terminate_on_close=server_params.terminate_on_close, + ) + read, write, _ = await session_stack.enter_async_context(client) + + session = await session_stack.enter_async_context( + mcp.ClientSession( + read, + write, + read_timeout_seconds=session_params.read_timeout_seconds, + sampling_callback=session_params.sampling_callback, + elicitation_callback=session_params.elicitation_callback, + list_roots_callback=session_params.list_roots_callback, + logging_callback=session_params.logging_callback, + message_handler=session_params.message_handler, + client_info=session_params.client_info, + ) + ) + + result = await session.initialize() + + # Session successfully initialized. + # Store its stack and register the stack with the main group stack. + self._session_exit_stacks[session] = session_stack + # session_stack itself becomes a resource managed by the + # main _exit_stack. + await self._exit_stack.enter_async_context(session_stack) + + return result.serverInfo, session + except Exception: # pragma: no cover + # If anything during this setup fails, ensure the session-specific + # stack is closed. + await session_stack.aclose() + raise + + async def _aggregate_components(self, server_info: types.Implementation, session: mcp.ClientSession) -> None: + """Aggregates prompts, resources, and tools from a given session.""" + + # Create a reverse index so we can find all prompts, resources, and + # tools belonging to this session. Used for removing components from + # the session group via self.disconnect_from_server. + component_names = self._ComponentNames() + + # Temporary components dicts. We do not want to modify the aggregate + # lists in case of an intermediate failure. + prompts_temp: dict[str, types.Prompt] = {} + resources_temp: dict[str, types.Resource] = {} + tools_temp: dict[str, types.Tool] = {} + tool_to_session_temp: dict[str, mcp.ClientSession] = {} + + # Query the server for its prompts and aggregate to list. + try: + prompts = (await session.list_prompts()).prompts + for prompt in prompts: + name = self._component_name(prompt.name, server_info) + prompts_temp[name] = prompt + component_names.prompts.add(name) + except McpError as err: # pragma: no cover + logging.warning(f"Could not fetch prompts: {err}") + + # Query the server for its resources and aggregate to list. + try: + resources = (await session.list_resources()).resources + for resource in resources: + name = self._component_name(resource.name, server_info) + resources_temp[name] = resource + component_names.resources.add(name) + except McpError as err: # pragma: no cover + logging.warning(f"Could not fetch resources: {err}") + + # Query the server for its tools and aggregate to list. + try: + tools = (await session.list_tools()).tools + for tool in tools: + name = self._component_name(tool.name, server_info) + tools_temp[name] = tool + tool_to_session_temp[name] = session + component_names.tools.add(name) + except McpError as err: # pragma: no cover + logging.warning(f"Could not fetch tools: {err}") + + # Clean up exit stack for session if we couldn't retrieve anything + # from the server. + if not any((prompts_temp, resources_temp, tools_temp)): + del self._session_exit_stacks[session] # pragma: no cover + + # Check for duplicates. + matching_prompts = prompts_temp.keys() & self._prompts.keys() + if matching_prompts: + raise McpError( # pragma: no cover + types.ErrorData( + code=types.INVALID_PARAMS, + message=f"{matching_prompts} already exist in group prompts.", + ) + ) + matching_resources = resources_temp.keys() & self._resources.keys() + if matching_resources: + raise McpError( # pragma: no cover + types.ErrorData( + code=types.INVALID_PARAMS, + message=f"{matching_resources} already exist in group resources.", + ) + ) + matching_tools = tools_temp.keys() & self._tools.keys() + if matching_tools: + raise McpError( + types.ErrorData( + code=types.INVALID_PARAMS, + message=f"{matching_tools} already exist in group tools.", + ) + ) + + # Aggregate components. + self._sessions[session] = component_names + self._prompts.update(prompts_temp) + self._resources.update(resources_temp) + self._tools.update(tools_temp) + self._tool_to_session.update(tool_to_session_temp) + + def _component_name(self, name: str, server_info: types.Implementation) -> str: + if self._component_name_hook: + return self._component_name_hook(name, server_info) + return name diff --git a/source/target-vendors/cp312/mcp/client/sse.py b/source/target-vendors/cp312/mcp/client/sse.py new file mode 100644 index 0000000..b2ac677 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/sse.py @@ -0,0 +1,164 @@ +import logging +from collections.abc import Callable +from contextlib import asynccontextmanager +from typing import Any +from urllib.parse import parse_qs, urljoin, urlparse + +import anyio +import httpx +from anyio.abc import TaskStatus +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from httpx_sse import aconnect_sse +from httpx_sse._exceptions import SSEError + +import mcp.types as types +from mcp.shared._httpx_utils import McpHttpClientFactory, create_mcp_http_client +from mcp.shared.message import SessionMessage + +logger = logging.getLogger(__name__) + + +def remove_request_params(url: str) -> str: + return urljoin(url, urlparse(url).path) + + +def _extract_session_id_from_endpoint(endpoint_url: str) -> str | None: + query_params = parse_qs(urlparse(endpoint_url).query) + return query_params.get("sessionId", [None])[0] or query_params.get("session_id", [None])[0] + + +@asynccontextmanager +async def sse_client( + url: str, + headers: dict[str, Any] | None = None, + timeout: float = 5, + sse_read_timeout: float = 60 * 5, + httpx_client_factory: McpHttpClientFactory = create_mcp_http_client, + auth: httpx.Auth | None = None, + on_session_created: Callable[[str], None] | None = None, +): + """ + Client transport for SSE. + + `sse_read_timeout` determines how long (in seconds) the client will wait for a new + event before disconnecting. All other HTTP operations are controlled by `timeout`. + + Args: + url: The SSE endpoint URL. + headers: Optional headers to include in requests. + timeout: HTTP timeout for regular operations. + sse_read_timeout: Timeout for SSE read operations. + auth: Optional HTTPX authentication handler. + on_session_created: Optional callback invoked with the session ID when received. + """ + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] + read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] + + write_stream: MemoryObjectSendStream[SessionMessage] + write_stream_reader: MemoryObjectReceiveStream[SessionMessage] + + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + async with anyio.create_task_group() as tg: + try: + logger.debug(f"Connecting to SSE endpoint: {remove_request_params(url)}") + async with httpx_client_factory( + headers=headers, auth=auth, timeout=httpx.Timeout(timeout, read=sse_read_timeout) + ) as client: + async with aconnect_sse( + client, + "GET", + url, + ) as event_source: + event_source.response.raise_for_status() + logger.debug("SSE connection established") + + async def sse_reader( + task_status: TaskStatus[str] = anyio.TASK_STATUS_IGNORED, + ): + try: + async for sse in event_source.aiter_sse(): # pragma: no branch + logger.debug(f"Received SSE event: {sse.event}") + match sse.event: + case "endpoint": + endpoint_url = urljoin(url, sse.data) + logger.debug(f"Received endpoint URL: {endpoint_url}") + + url_parsed = urlparse(url) + endpoint_parsed = urlparse(endpoint_url) + if ( # pragma: no cover + url_parsed.netloc != endpoint_parsed.netloc + or url_parsed.scheme != endpoint_parsed.scheme + ): + error_msg = ( # pragma: no cover + f"Endpoint origin does not match connection origin: {endpoint_url}" + ) + logger.error(error_msg) # pragma: no cover + raise ValueError(error_msg) # pragma: no cover + + if on_session_created: + session_id = _extract_session_id_from_endpoint(endpoint_url) + if session_id: + on_session_created(session_id) + + task_status.started(endpoint_url) + + case "message": + # Skip empty data (keep-alive pings) + if not sse.data: + continue + try: + message = types.JSONRPCMessage.model_validate_json( # noqa: E501 + sse.data + ) + logger.debug(f"Received server message: {message}") + except Exception as exc: # pragma: no cover + logger.exception("Error parsing server message") # pragma: no cover + await read_stream_writer.send(exc) # pragma: no cover + continue # pragma: no cover + + session_message = SessionMessage(message) + await read_stream_writer.send(session_message) + case _: # pragma: no cover + logger.warning(f"Unknown SSE event: {sse.event}") # pragma: no cover + except SSEError as sse_exc: # pragma: no cover + logger.exception("Encountered SSE exception") # pragma: no cover + raise sse_exc # pragma: no cover + except Exception as exc: # pragma: no cover + logger.exception("Error in sse_reader") # pragma: no cover + await read_stream_writer.send(exc) # pragma: no cover + finally: + await read_stream_writer.aclose() + + async def post_writer(endpoint_url: str): + try: + async with write_stream_reader: + async for session_message in write_stream_reader: + logger.debug(f"Sending client message: {session_message}") + response = await client.post( + endpoint_url, + json=session_message.message.model_dump( + by_alias=True, + mode="json", + exclude_none=True, + ), + ) + response.raise_for_status() + logger.debug(f"Client message sent successfully: {response.status_code}") + except Exception: # pragma: no cover + logger.exception("Error in post_writer") # pragma: no cover + finally: + await write_stream.aclose() + + endpoint_url = await tg.start(sse_reader) + logger.debug(f"Starting post writer with endpoint URL: {endpoint_url}") + tg.start_soon(post_writer, endpoint_url) + + try: + yield read_stream, write_stream + finally: + tg.cancel_scope.cancel() + finally: + await read_stream_writer.aclose() + await write_stream.aclose() diff --git a/source/target-vendors/cp312/mcp/client/stdio/__init__.py b/source/target-vendors/cp312/mcp/client/stdio/__init__.py new file mode 100644 index 0000000..0d76bb9 --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/stdio/__init__.py @@ -0,0 +1,278 @@ +import logging +import os +import sys +from contextlib import asynccontextmanager +from pathlib import Path +from typing import Literal, TextIO + +import anyio +import anyio.lowlevel +from anyio.abc import Process +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from anyio.streams.text import TextReceiveStream +from pydantic import BaseModel, Field + +import mcp.types as types +from mcp.os.posix.utilities import terminate_posix_process_tree +from mcp.os.win32.utilities import ( + FallbackProcess, + create_windows_process, + get_windows_executable_command, + terminate_windows_process_tree, +) +from mcp.shared.message import SessionMessage + +logger = logging.getLogger(__name__) + +# Environment variables to inherit by default +DEFAULT_INHERITED_ENV_VARS = ( + [ + "APPDATA", + "HOMEDRIVE", + "HOMEPATH", + "LOCALAPPDATA", + "PATH", + "PATHEXT", + "PROCESSOR_ARCHITECTURE", + "SYSTEMDRIVE", + "SYSTEMROOT", + "TEMP", + "USERNAME", + "USERPROFILE", + ] + if sys.platform == "win32" + else ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"] +) + +# Timeout for process termination before falling back to force kill +PROCESS_TERMINATION_TIMEOUT = 2.0 + + +def get_default_environment() -> dict[str, str]: + """ + Returns a default environment object including only environment variables deemed + safe to inherit. + """ + env: dict[str, str] = {} + + for key in DEFAULT_INHERITED_ENV_VARS: + value = os.environ.get(key) + if value is None: + continue # pragma: no cover + + if value.startswith("()"): # pragma: no cover + # Skip functions, which are a security risk + continue # pragma: no cover + + env[key] = value + + return env + + +class StdioServerParameters(BaseModel): + command: str + """The executable to run to start the server.""" + + args: list[str] = Field(default_factory=list) + """Command line arguments to pass to the executable.""" + + env: dict[str, str] | None = None + """ + The environment to use when spawning the process. + + If not specified, the result of get_default_environment() will be used. + """ + + cwd: str | Path | None = None + """The working directory to use when spawning the process.""" + + encoding: str = "utf-8" + """ + The text encoding used when sending/receiving messages to the server + + defaults to utf-8 + """ + + encoding_error_handler: Literal["strict", "ignore", "replace"] = "strict" + """ + The text encoding error handler. + + See https://docs.python.org/3/library/codecs.html#codec-base-classes for + explanations of possible values + """ + + +@asynccontextmanager +async def stdio_client(server: StdioServerParameters, errlog: TextIO = sys.stderr): + """ + Client transport for stdio: this will connect to a server by spawning a + process and communicating with it over stdin/stdout. + """ + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] + read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] + + write_stream: MemoryObjectSendStream[SessionMessage] + write_stream_reader: MemoryObjectReceiveStream[SessionMessage] + + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + try: + command = _get_executable_command(server.command) + + # Open process with stderr piped for capture + process = await _create_platform_compatible_process( + command=command, + args=server.args, + env=({**get_default_environment(), **server.env} if server.env is not None else get_default_environment()), + errlog=errlog, + cwd=server.cwd, + ) + except OSError: + # Clean up streams if process creation fails + await read_stream.aclose() + await write_stream.aclose() + await read_stream_writer.aclose() + await write_stream_reader.aclose() + raise + + async def stdout_reader(): + assert process.stdout, "Opened process is missing stdout" + + try: + async with read_stream_writer: + buffer = "" + async for chunk in TextReceiveStream( + process.stdout, + encoding=server.encoding, + errors=server.encoding_error_handler, + ): + lines = (buffer + chunk).split("\n") + buffer = lines.pop() + + for line in lines: + try: + message = types.JSONRPCMessage.model_validate_json(line) + except Exception as exc: # pragma: no cover + logger.exception("Failed to parse JSONRPC message from server") + await read_stream_writer.send(exc) + continue + + session_message = SessionMessage(message) + await read_stream_writer.send(session_message) + except anyio.ClosedResourceError: # pragma: no cover + await anyio.lowlevel.checkpoint() + + async def stdin_writer(): + assert process.stdin, "Opened process is missing stdin" + + try: + async with write_stream_reader: + async for session_message in write_stream_reader: + json = session_message.message.model_dump_json(by_alias=True, exclude_none=True) + await process.stdin.send( + (json + "\n").encode( + encoding=server.encoding, + errors=server.encoding_error_handler, + ) + ) + except anyio.ClosedResourceError: # pragma: no cover + await anyio.lowlevel.checkpoint() + + async with ( + anyio.create_task_group() as tg, + process, + ): + tg.start_soon(stdout_reader) + tg.start_soon(stdin_writer) + try: + yield read_stream, write_stream + finally: + # MCP spec: stdio shutdown sequence + # 1. Close input stream to server + # 2. Wait for server to exit, or send SIGTERM if it doesn't exit in time + # 3. Send SIGKILL if still not exited + if process.stdin: # pragma: no branch + try: + await process.stdin.aclose() + except Exception: # pragma: no cover + # stdin might already be closed, which is fine + pass + + try: + # Give the process time to exit gracefully after stdin closes + with anyio.fail_after(PROCESS_TERMINATION_TIMEOUT): + await process.wait() + except TimeoutError: + # Process didn't exit from stdin closure, use platform-specific termination + # which handles SIGTERM -> SIGKILL escalation + await _terminate_process_tree(process) + except ProcessLookupError: # pragma: no cover + # Process already exited, which is fine + pass + await read_stream.aclose() + await write_stream.aclose() + await read_stream_writer.aclose() + await write_stream_reader.aclose() + + +def _get_executable_command(command: str) -> str: + """ + Get the correct executable command normalized for the current platform. + + Args: + command: Base command (e.g., 'uvx', 'npx') + + Returns: + str: Platform-appropriate command + """ + if sys.platform == "win32": # pragma: no cover + return get_windows_executable_command(command) + else: + return command # pragma: no cover + + +async def _create_platform_compatible_process( + command: str, + args: list[str], + env: dict[str, str] | None = None, + errlog: TextIO = sys.stderr, + cwd: Path | str | None = None, +): + """ + Creates a subprocess in a platform-compatible way. + + Unix: Creates process in a new session/process group for killpg support + Windows: Creates process in a Job Object for reliable child termination + """ + if sys.platform == "win32": # pragma: no cover + process = await create_windows_process(command, args, env, errlog, cwd) + else: + process = await anyio.open_process( + [command, *args], + env=env, + stderr=errlog, + cwd=cwd, + start_new_session=True, + ) # pragma: no cover + + return process + + +async def _terminate_process_tree(process: Process | FallbackProcess, timeout_seconds: float = 2.0) -> None: + """ + Terminate a process and all its children using platform-specific methods. + + Unix: Uses os.killpg() for atomic process group termination + Windows: Uses Job Objects via pywin32 for reliable child process cleanup + + Args: + process: The process to terminate + timeout_seconds: Timeout in seconds before force killing (default: 2.0) + """ + if sys.platform == "win32": # pragma: no cover + await terminate_windows_process_tree(process, timeout_seconds) + else: # pragma: no cover + # FallbackProcess should only be used for Windows compatibility + assert isinstance(process, Process) + await terminate_posix_process_tree(process, timeout_seconds) diff --git a/source/target-vendors/cp312/mcp/client/streamable_http.py b/source/target-vendors/cp312/mcp/client/streamable_http.py new file mode 100644 index 0000000..ed28fcc --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/streamable_http.py @@ -0,0 +1,722 @@ +""" +StreamableHTTP Client Transport Module + +This module implements the StreamableHTTP transport for MCP clients, +providing support for HTTP POST requests with optional SSE streaming responses +and session management. +""" + +import contextlib +import logging +from collections.abc import AsyncGenerator, Awaitable, Callable +from contextlib import asynccontextmanager +from dataclasses import dataclass +from datetime import timedelta +from typing import Any, overload +from warnings import warn + +import anyio +import httpx +from anyio.abc import TaskGroup +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from httpx_sse import EventSource, ServerSentEvent, aconnect_sse +from typing_extensions import deprecated + +from mcp.shared._httpx_utils import ( + McpHttpClientFactory, + create_mcp_http_client, +) +from mcp.shared.message import ClientMessageMetadata, SessionMessage +from mcp.types import ( + ErrorData, + InitializeResult, + JSONRPCError, + JSONRPCMessage, + JSONRPCNotification, + JSONRPCRequest, + JSONRPCResponse, + RequestId, +) + +logger = logging.getLogger(__name__) + + +SessionMessageOrError = SessionMessage | Exception +StreamWriter = MemoryObjectSendStream[SessionMessageOrError] +StreamReader = MemoryObjectReceiveStream[SessionMessage] +GetSessionIdCallback = Callable[[], str | None] + +MCP_SESSION_ID = "mcp-session-id" +MCP_PROTOCOL_VERSION = "mcp-protocol-version" +LAST_EVENT_ID = "last-event-id" + +# Reconnection defaults +DEFAULT_RECONNECTION_DELAY_MS = 1000 # 1 second fallback when server doesn't provide retry +MAX_RECONNECTION_ATTEMPTS = 2 # Max retry attempts before giving up +CONTENT_TYPE = "content-type" +ACCEPT = "accept" + + +JSON = "application/json" +SSE = "text/event-stream" + +# Sentinel value for detecting unset optional parameters +_UNSET = object() + + +class StreamableHTTPError(Exception): + """Base exception for StreamableHTTP transport errors.""" + + +class ResumptionError(StreamableHTTPError): + """Raised when resumption request is invalid.""" + + +@dataclass +class RequestContext: + """Context for a request operation.""" + + client: httpx.AsyncClient + session_id: str | None + session_message: SessionMessage + metadata: ClientMessageMetadata | None + read_stream_writer: StreamWriter + headers: dict[str, str] | None = None # Deprecated - no longer used + sse_read_timeout: float | None = None # Deprecated - no longer used + + +class StreamableHTTPTransport: + """StreamableHTTP client transport implementation.""" + + @overload + def __init__(self, url: str) -> None: ... + + @overload + @deprecated( + "Parameters headers, timeout, sse_read_timeout, and auth are deprecated. " + "Configure these on the httpx.AsyncClient instead." + ) + def __init__( + self, + url: str, + headers: dict[str, str] | None = None, + timeout: float | timedelta = 30, + sse_read_timeout: float | timedelta = 60 * 5, + auth: httpx.Auth | None = None, + ) -> None: ... + + def __init__( + self, + url: str, + headers: Any = _UNSET, + timeout: Any = _UNSET, + sse_read_timeout: Any = _UNSET, + auth: Any = _UNSET, + ) -> None: + """Initialize the StreamableHTTP transport. + + Args: + url: The endpoint URL. + headers: Optional headers to include in requests. + timeout: HTTP timeout for regular operations. + sse_read_timeout: Timeout for SSE read operations. + auth: Optional HTTPX authentication handler. + """ + # Check for deprecated parameters and issue runtime warning + deprecated_params: list[str] = [] + if headers is not _UNSET: + deprecated_params.append("headers") + if timeout is not _UNSET: + deprecated_params.append("timeout") + if sse_read_timeout is not _UNSET: + deprecated_params.append("sse_read_timeout") + if auth is not _UNSET: + deprecated_params.append("auth") + + if deprecated_params: + warn( + f"Parameters {', '.join(deprecated_params)} are deprecated and will be ignored. " + "Configure these on the httpx.AsyncClient instead.", + DeprecationWarning, + stacklevel=2, + ) + + self.url = url + self.session_id = None + self.protocol_version = None + + def _prepare_headers(self) -> dict[str, str]: + """Build MCP-specific request headers. + + These headers will be merged with the httpx.AsyncClient's default headers, + with these MCP-specific headers taking precedence. + """ + headers: dict[str, str] = {} + # Add MCP protocol headers + headers[ACCEPT] = f"{JSON}, {SSE}" + headers[CONTENT_TYPE] = JSON + # Add session headers if available + if self.session_id: + headers[MCP_SESSION_ID] = self.session_id + if self.protocol_version: + headers[MCP_PROTOCOL_VERSION] = self.protocol_version + return headers + + def _is_initialization_request(self, message: JSONRPCMessage) -> bool: + """Check if the message is an initialization request.""" + return isinstance(message.root, JSONRPCRequest) and message.root.method == "initialize" + + def _is_initialized_notification(self, message: JSONRPCMessage) -> bool: + """Check if the message is an initialized notification.""" + return isinstance(message.root, JSONRPCNotification) and message.root.method == "notifications/initialized" + + def _maybe_extract_session_id_from_response( + self, + response: httpx.Response, + ) -> None: + """Extract and store session ID from response headers.""" + new_session_id = response.headers.get(MCP_SESSION_ID) + if new_session_id: + self.session_id = new_session_id + logger.info(f"Received session ID: {self.session_id}") + + def _maybe_extract_protocol_version_from_message( + self, + message: JSONRPCMessage, + ) -> None: + """Extract protocol version from initialization response message.""" + if isinstance(message.root, JSONRPCResponse) and message.root.result: # pragma: no branch + try: + # Parse the result as InitializeResult for type safety + init_result = InitializeResult.model_validate(message.root.result) + self.protocol_version = str(init_result.protocolVersion) + logger.info(f"Negotiated protocol version: {self.protocol_version}") + except Exception as exc: # pragma: no cover + logger.warning( + f"Failed to parse initialization response as InitializeResult: {exc}" + ) # pragma: no cover + logger.warning(f"Raw result: {message.root.result}") + + async def _handle_sse_event( + self, + sse: ServerSentEvent, + read_stream_writer: StreamWriter, + original_request_id: RequestId | None = None, + resumption_callback: Callable[[str], Awaitable[None]] | None = None, + is_initialization: bool = False, + ) -> bool: + """Handle an SSE event, returning True if the response is complete.""" + if sse.event == "message": + # Handle priming events (empty data with ID) for resumability + if not sse.data: + # Call resumption callback for priming events that have an ID + if sse.id and resumption_callback: + await resumption_callback(sse.id) + return False + try: + message = JSONRPCMessage.model_validate_json(sse.data) + logger.debug(f"SSE message: {message}") + + # Extract protocol version from initialization response + if is_initialization: + self._maybe_extract_protocol_version_from_message(message) + + # If this is a response and we have original_request_id, replace it + if original_request_id is not None and isinstance(message.root, JSONRPCResponse | JSONRPCError): + message.root.id = original_request_id + + session_message = SessionMessage(message) + await read_stream_writer.send(session_message) + + # Call resumption token callback if we have an ID + if sse.id and resumption_callback: + await resumption_callback(sse.id) + + # If this is a response or error return True indicating completion + # Otherwise, return False to continue listening + return isinstance(message.root, JSONRPCResponse | JSONRPCError) + + except Exception as exc: # pragma: no cover + logger.exception("Error parsing SSE message") + await read_stream_writer.send(exc) + return False + else: # pragma: no cover + logger.warning(f"Unknown SSE event: {sse.event}") + return False + + async def handle_get_stream( + self, + client: httpx.AsyncClient, + read_stream_writer: StreamWriter, + ) -> None: + """Handle GET stream for server-initiated messages with auto-reconnect.""" + last_event_id: str | None = None + retry_interval_ms: int | None = None + attempt: int = 0 + + while attempt < MAX_RECONNECTION_ATTEMPTS: # pragma: no branch + try: + if not self.session_id: + return + + headers = self._prepare_headers() + if last_event_id: + headers[LAST_EVENT_ID] = last_event_id # pragma: no cover + + async with aconnect_sse( + client, + "GET", + self.url, + headers=headers, + ) as event_source: + event_source.response.raise_for_status() + logger.debug("GET SSE connection established") + + async for sse in event_source.aiter_sse(): + # Track last event ID for reconnection + if sse.id: + last_event_id = sse.id # pragma: no cover + # Track retry interval from server + if sse.retry is not None: + retry_interval_ms = sse.retry # pragma: no cover + + await self._handle_sse_event(sse, read_stream_writer) + + # Stream ended normally (server closed) - reset attempt counter + attempt = 0 + + except Exception as exc: # pragma: no cover + logger.debug(f"GET stream error: {exc}") + attempt += 1 + + if attempt >= MAX_RECONNECTION_ATTEMPTS: # pragma: no cover + logger.debug(f"GET stream max reconnection attempts ({MAX_RECONNECTION_ATTEMPTS}) exceeded") + return + + # Wait before reconnecting + delay_ms = retry_interval_ms if retry_interval_ms is not None else DEFAULT_RECONNECTION_DELAY_MS + logger.info(f"GET stream disconnected, reconnecting in {delay_ms}ms...") + await anyio.sleep(delay_ms / 1000.0) + + async def _handle_resumption_request(self, ctx: RequestContext) -> None: + """Handle a resumption request using GET with SSE.""" + headers = self._prepare_headers() + if ctx.metadata and ctx.metadata.resumption_token: + headers[LAST_EVENT_ID] = ctx.metadata.resumption_token + else: + raise ResumptionError("Resumption request requires a resumption token") # pragma: no cover + + # Extract original request ID to map responses + original_request_id = None + if isinstance(ctx.session_message.message.root, JSONRPCRequest): # pragma: no branch + original_request_id = ctx.session_message.message.root.id + + async with aconnect_sse( + ctx.client, + "GET", + self.url, + headers=headers, + ) as event_source: + event_source.response.raise_for_status() + logger.debug("Resumption GET SSE connection established") + + async for sse in event_source.aiter_sse(): # pragma: no branch + is_complete = await self._handle_sse_event( + sse, + ctx.read_stream_writer, + original_request_id, + ctx.metadata.on_resumption_token_update if ctx.metadata else None, + ) + if is_complete: + await event_source.response.aclose() + break + + async def _handle_post_request(self, ctx: RequestContext) -> None: + """Handle a POST request with response processing.""" + headers = self._prepare_headers() + message = ctx.session_message.message + is_initialization = self._is_initialization_request(message) + + async with ctx.client.stream( + "POST", + self.url, + json=message.model_dump(by_alias=True, mode="json", exclude_none=True), + headers=headers, + ) as response: + if response.status_code == 202: + logger.debug("Received 202 Accepted") + return + + if response.status_code == 404: # pragma: no branch + if isinstance(message.root, JSONRPCRequest): + await self._send_session_terminated_error( # pragma: no cover + ctx.read_stream_writer, # pragma: no cover + message.root.id, # pragma: no cover + ) # pragma: no cover + return # pragma: no cover + + response.raise_for_status() + if is_initialization: + self._maybe_extract_session_id_from_response(response) + + # Per https://modelcontextprotocol.io/specification/2025-06-18/basic#notifications: + # The server MUST NOT send a response to notifications. + if isinstance(message.root, JSONRPCRequest): + content_type = response.headers.get(CONTENT_TYPE, "").lower() + if content_type.startswith(JSON): + await self._handle_json_response(response, ctx.read_stream_writer, is_initialization) + elif content_type.startswith(SSE): + await self._handle_sse_response(response, ctx, is_initialization) + else: + await self._handle_unexpected_content_type( # pragma: no cover + content_type, # pragma: no cover + ctx.read_stream_writer, # pragma: no cover + ) # pragma: no cover + + async def _handle_json_response( + self, + response: httpx.Response, + read_stream_writer: StreamWriter, + is_initialization: bool = False, + ) -> None: + """Handle JSON response from the server.""" + try: + content = await response.aread() + message = JSONRPCMessage.model_validate_json(content) + + # Extract protocol version from initialization response + if is_initialization: + self._maybe_extract_protocol_version_from_message(message) + + session_message = SessionMessage(message) + await read_stream_writer.send(session_message) + except Exception as exc: # pragma: no cover + logger.exception("Error parsing JSON response") + await read_stream_writer.send(exc) + + async def _handle_sse_response( + self, + response: httpx.Response, + ctx: RequestContext, + is_initialization: bool = False, + ) -> None: + """Handle SSE response from the server.""" + last_event_id: str | None = None + retry_interval_ms: int | None = None + + try: + event_source = EventSource(response) + async for sse in event_source.aiter_sse(): # pragma: no branch + # Track last event ID for potential reconnection + if sse.id: + last_event_id = sse.id + + # Track retry interval from server + if sse.retry is not None: + retry_interval_ms = sse.retry + + is_complete = await self._handle_sse_event( + sse, + ctx.read_stream_writer, + resumption_callback=(ctx.metadata.on_resumption_token_update if ctx.metadata else None), + is_initialization=is_initialization, + ) + # If the SSE event indicates completion, like returning respose/error + # break the loop + if is_complete: + await response.aclose() + return # Normal completion, no reconnect needed + except Exception as e: # pragma: no cover + logger.debug(f"SSE stream ended: {e}") + + # Stream ended without response - reconnect if we received an event with ID + if last_event_id is not None: # pragma: no branch + logger.info("SSE stream disconnected, reconnecting...") + await self._handle_reconnection(ctx, last_event_id, retry_interval_ms) + + async def _handle_reconnection( + self, + ctx: RequestContext, + last_event_id: str, + retry_interval_ms: int | None = None, + attempt: int = 0, + ) -> None: + """Reconnect with Last-Event-ID to resume stream after server disconnect.""" + # Bail if max retries exceeded + if attempt >= MAX_RECONNECTION_ATTEMPTS: # pragma: no cover + logger.debug(f"Max reconnection attempts ({MAX_RECONNECTION_ATTEMPTS}) exceeded") + return + + # Always wait - use server value or default + delay_ms = retry_interval_ms if retry_interval_ms is not None else DEFAULT_RECONNECTION_DELAY_MS + await anyio.sleep(delay_ms / 1000.0) + + headers = self._prepare_headers() + headers[LAST_EVENT_ID] = last_event_id + + # Extract original request ID to map responses + original_request_id = None + if isinstance(ctx.session_message.message.root, JSONRPCRequest): # pragma: no branch + original_request_id = ctx.session_message.message.root.id + + try: + async with aconnect_sse( + ctx.client, + "GET", + self.url, + headers=headers, + ) as event_source: + event_source.response.raise_for_status() + logger.info("Reconnected to SSE stream") + + # Track for potential further reconnection + reconnect_last_event_id: str = last_event_id + reconnect_retry_ms = retry_interval_ms + + async for sse in event_source.aiter_sse(): + if sse.id: # pragma: no branch + reconnect_last_event_id = sse.id + if sse.retry is not None: + reconnect_retry_ms = sse.retry + + is_complete = await self._handle_sse_event( + sse, + ctx.read_stream_writer, + original_request_id, + ctx.metadata.on_resumption_token_update if ctx.metadata else None, + ) + if is_complete: + await event_source.response.aclose() + return + + # Stream ended again without response - reconnect again (reset attempt counter) + logger.info("SSE stream disconnected, reconnecting...") + await self._handle_reconnection(ctx, reconnect_last_event_id, reconnect_retry_ms, 0) + except Exception as e: # pragma: no cover + logger.debug(f"Reconnection failed: {e}") + # Try to reconnect again if we still have an event ID + await self._handle_reconnection(ctx, last_event_id, retry_interval_ms, attempt + 1) + + async def _handle_unexpected_content_type( + self, + content_type: str, + read_stream_writer: StreamWriter, + ) -> None: # pragma: no cover + """Handle unexpected content type in response.""" + error_msg = f"Unexpected content type: {content_type}" # pragma: no cover + logger.error(error_msg) # pragma: no cover + await read_stream_writer.send(ValueError(error_msg)) # pragma: no cover + + async def _send_session_terminated_error( + self, + read_stream_writer: StreamWriter, + request_id: RequestId, + ) -> None: + """Send a session terminated error response.""" + jsonrpc_error = JSONRPCError( + jsonrpc="2.0", + id=request_id, + error=ErrorData(code=32600, message="Session terminated"), + ) + session_message = SessionMessage(JSONRPCMessage(jsonrpc_error)) + await read_stream_writer.send(session_message) + + async def post_writer( + self, + client: httpx.AsyncClient, + write_stream_reader: StreamReader, + read_stream_writer: StreamWriter, + write_stream: MemoryObjectSendStream[SessionMessage], + start_get_stream: Callable[[], None], + tg: TaskGroup, + ) -> None: + """Handle writing requests to the server.""" + try: + async with write_stream_reader: + async for session_message in write_stream_reader: + message = session_message.message + metadata = ( + session_message.metadata + if isinstance(session_message.metadata, ClientMessageMetadata) + else None + ) + + # Check if this is a resumption request + is_resumption = bool(metadata and metadata.resumption_token) + + logger.debug(f"Sending client message: {message}") + + # Handle initialized notification + if self._is_initialized_notification(message): + start_get_stream() + + ctx = RequestContext( + client=client, + session_id=self.session_id, + session_message=session_message, + metadata=metadata, + read_stream_writer=read_stream_writer, + ) + + async def handle_request_async(): + if is_resumption: + await self._handle_resumption_request(ctx) + else: + await self._handle_post_request(ctx) + + # If this is a request, start a new task to handle it + if isinstance(message.root, JSONRPCRequest): + tg.start_soon(handle_request_async) + else: + await handle_request_async() + + except Exception: + logger.exception("Error in post_writer") # pragma: no cover + finally: + await read_stream_writer.aclose() + await write_stream.aclose() + + async def terminate_session(self, client: httpx.AsyncClient) -> None: # pragma: no cover + """Terminate the session by sending a DELETE request.""" + if not self.session_id: + return + + try: + headers = self._prepare_headers() + response = await client.delete(self.url, headers=headers) + + if response.status_code == 405: + logger.debug("Server does not allow session termination") + elif response.status_code not in (200, 204): + logger.warning(f"Session termination failed: {response.status_code}") + except Exception as exc: + logger.warning(f"Session termination failed: {exc}") + + def get_session_id(self) -> str | None: + """Get the current session ID.""" + return self.session_id + + +@asynccontextmanager +async def streamable_http_client( + url: str, + *, + http_client: httpx.AsyncClient | None = None, + terminate_on_close: bool = True, +) -> AsyncGenerator[ + tuple[ + MemoryObjectReceiveStream[SessionMessage | Exception], + MemoryObjectSendStream[SessionMessage], + GetSessionIdCallback, + ], + None, +]: + """ + Client transport for StreamableHTTP. + + Args: + url: The MCP server endpoint URL. + http_client: Optional pre-configured httpx.AsyncClient. If None, a default + client with recommended MCP timeouts will be created. To configure headers, + authentication, or other HTTP settings, create an httpx.AsyncClient and pass it here. + terminate_on_close: If True, send a DELETE request to terminate the session + when the context exits. + + Yields: + Tuple containing: + - read_stream: Stream for reading messages from the server + - write_stream: Stream for sending messages to the server + - get_session_id_callback: Function to retrieve the current session ID + + Example: + See examples/snippets/clients/ for usage patterns. + """ + read_stream_writer, read_stream = anyio.create_memory_object_stream[SessionMessage | Exception](0) + write_stream, write_stream_reader = anyio.create_memory_object_stream[SessionMessage](0) + + # Determine if we need to create and manage the client + client_provided = http_client is not None + client = http_client + + if client is None: + # Create default client with recommended MCP timeouts + client = create_mcp_http_client() + + transport = StreamableHTTPTransport(url) + + async with anyio.create_task_group() as tg: + try: + logger.debug(f"Connecting to StreamableHTTP endpoint: {url}") + + async with contextlib.AsyncExitStack() as stack: + # Only manage client lifecycle if we created it + if not client_provided: + await stack.enter_async_context(client) + + def start_get_stream() -> None: + tg.start_soon(transport.handle_get_stream, client, read_stream_writer) + + tg.start_soon( + transport.post_writer, + client, + write_stream_reader, + read_stream_writer, + write_stream, + start_get_stream, + tg, + ) + + try: + yield ( + read_stream, + write_stream, + transport.get_session_id, + ) + finally: + if transport.session_id and terminate_on_close: + await transport.terminate_session(client) + tg.cancel_scope.cancel() + finally: + await read_stream_writer.aclose() + await write_stream.aclose() + + +@asynccontextmanager +@deprecated("Use `streamable_http_client` instead.") +async def streamablehttp_client( + url: str, + headers: dict[str, str] | None = None, + timeout: float | timedelta = 30, + sse_read_timeout: float | timedelta = 60 * 5, + terminate_on_close: bool = True, + httpx_client_factory: McpHttpClientFactory = create_mcp_http_client, + auth: httpx.Auth | None = None, +) -> AsyncGenerator[ + tuple[ + MemoryObjectReceiveStream[SessionMessage | Exception], + MemoryObjectSendStream[SessionMessage], + GetSessionIdCallback, + ], + None, +]: + # Convert timeout parameters + timeout_seconds = timeout.total_seconds() if isinstance(timeout, timedelta) else timeout + sse_read_timeout_seconds = ( + sse_read_timeout.total_seconds() if isinstance(sse_read_timeout, timedelta) else sse_read_timeout + ) + + # Create httpx client using the factory with old-style parameters + client = httpx_client_factory( + headers=headers, + timeout=httpx.Timeout(timeout_seconds, read=sse_read_timeout_seconds), + auth=auth, + ) + + # Manage client lifecycle since we created it + async with client: + async with streamable_http_client( + url, + http_client=client, + terminate_on_close=terminate_on_close, + ) as streams: + yield streams diff --git a/source/target-vendors/cp312/mcp/client/websocket.py b/source/target-vendors/cp312/mcp/client/websocket.py new file mode 100644 index 0000000..e8c8d9a --- /dev/null +++ b/source/target-vendors/cp312/mcp/client/websocket.py @@ -0,0 +1,86 @@ +import json +import logging +from collections.abc import AsyncGenerator +from contextlib import asynccontextmanager + +import anyio +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import ValidationError +from websockets.asyncio.client import connect as ws_connect +from websockets.typing import Subprotocol + +import mcp.types as types +from mcp.shared.message import SessionMessage + +logger = logging.getLogger(__name__) + + +@asynccontextmanager +async def websocket_client( + url: str, +) -> AsyncGenerator[ + tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]], + None, +]: + """ + WebSocket client transport for MCP, symmetrical to the server version. + + Connects to 'url' using the 'mcp' subprotocol, then yields: + (read_stream, write_stream) + + - read_stream: As you read from this stream, you'll receive either valid + JSONRPCMessage objects or Exception objects (when validation fails). + - write_stream: Write JSONRPCMessage objects to this stream to send them + over the WebSocket to the server. + """ + + # Create two in-memory streams: + # - One for incoming messages (read_stream, written by ws_reader) + # - One for outgoing messages (write_stream, read by ws_writer) + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] + read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] + write_stream: MemoryObjectSendStream[SessionMessage] + write_stream_reader: MemoryObjectReceiveStream[SessionMessage] + + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + # Connect using websockets, requesting the "mcp" subprotocol + async with ws_connect(url, subprotocols=[Subprotocol("mcp")]) as ws: + + async def ws_reader(): + """ + Reads text messages from the WebSocket, parses them as JSON-RPC messages, + and sends them into read_stream_writer. + """ + async with read_stream_writer: + async for raw_text in ws: + try: + message = types.JSONRPCMessage.model_validate_json(raw_text) + session_message = SessionMessage(message) + await read_stream_writer.send(session_message) + except ValidationError as exc: # pragma: no cover + # If JSON parse or model validation fails, send the exception + await read_stream_writer.send(exc) + + async def ws_writer(): + """ + Reads JSON-RPC messages from write_stream_reader and + sends them to the server. + """ + async with write_stream_reader: + async for session_message in write_stream_reader: + # Convert to a dict, then to JSON + msg_dict = session_message.message.model_dump(by_alias=True, mode="json", exclude_none=True) + await ws.send(json.dumps(msg_dict)) + + async with anyio.create_task_group() as tg: + # Start reader and writer tasks + tg.start_soon(ws_reader) + tg.start_soon(ws_writer) + + # Yield the receive/send streams + yield (read_stream, write_stream) + + # Once the caller's 'async with' block exits, we shut down + tg.cancel_scope.cancel() diff --git a/source/target-vendors/cp312/mcp/os/__init__.py b/source/target-vendors/cp312/mcp/os/__init__.py new file mode 100644 index 0000000..fa5dbc8 --- /dev/null +++ b/source/target-vendors/cp312/mcp/os/__init__.py @@ -0,0 +1 @@ +"""Platform-specific utilities for MCP.""" diff --git a/source/target-vendors/cp312/mcp/os/posix/__init__.py b/source/target-vendors/cp312/mcp/os/posix/__init__.py new file mode 100644 index 0000000..23aff8b --- /dev/null +++ b/source/target-vendors/cp312/mcp/os/posix/__init__.py @@ -0,0 +1 @@ +"""POSIX-specific utilities for MCP.""" diff --git a/source/target-vendors/cp312/mcp/os/posix/utilities.py b/source/target-vendors/cp312/mcp/os/posix/utilities.py new file mode 100644 index 0000000..dd1aea3 --- /dev/null +++ b/source/target-vendors/cp312/mcp/os/posix/utilities.py @@ -0,0 +1,60 @@ +""" +POSIX-specific functionality for stdio client operations. +""" + +import logging +import os +import signal + +import anyio +from anyio.abc import Process + +logger = logging.getLogger(__name__) + + +async def terminate_posix_process_tree(process: Process, timeout_seconds: float = 2.0) -> None: + """ + Terminate a process and all its children on POSIX systems. + + Uses os.killpg() for atomic process group termination. + + Args: + process: The process to terminate + timeout_seconds: Timeout in seconds before force killing (default: 2.0) + """ + pid = getattr(process, "pid", None) or getattr(getattr(process, "popen", None), "pid", None) + if not pid: + # No PID means there's no process to terminate - it either never started, + # already exited, or we have an invalid process object + return + + try: + pgid = os.getpgid(pid) + os.killpg(pgid, signal.SIGTERM) + + with anyio.move_on_after(timeout_seconds): + while True: + try: + # Check if process group still exists (signal 0 = check only) + os.killpg(pgid, 0) + await anyio.sleep(0.1) + except ProcessLookupError: + return + + try: + os.killpg(pgid, signal.SIGKILL) + except ProcessLookupError: + pass + + except (ProcessLookupError, PermissionError, OSError) as e: + logger.warning(f"Process group termination failed for PID {pid}: {e}, falling back to simple terminate") + try: + process.terminate() + with anyio.fail_after(timeout_seconds): + await process.wait() + except Exception: + logger.warning(f"Process termination failed for PID {pid}, attempting force kill") + try: + process.kill() + except Exception: + logger.exception(f"Failed to kill process {pid}") diff --git a/source/target-vendors/cp312/mcp/os/win32/__init__.py b/source/target-vendors/cp312/mcp/os/win32/__init__.py new file mode 100644 index 0000000..f1ebab9 --- /dev/null +++ b/source/target-vendors/cp312/mcp/os/win32/__init__.py @@ -0,0 +1 @@ +"""Windows-specific utilities for MCP.""" diff --git a/source/target-vendors/cp312/mcp/os/win32/utilities.py b/source/target-vendors/cp312/mcp/os/win32/utilities.py new file mode 100644 index 0000000..962be02 --- /dev/null +++ b/source/target-vendors/cp312/mcp/os/win32/utilities.py @@ -0,0 +1,338 @@ +""" +Windows-specific functionality for stdio client operations. +""" + +import logging +import shutil +import subprocess +import sys +from pathlib import Path +from typing import BinaryIO, TextIO, cast + +import anyio +from anyio import to_thread +from anyio.abc import Process +from anyio.streams.file import FileReadStream, FileWriteStream +from typing_extensions import deprecated + +logger = logging.getLogger("client.stdio.win32") + +# Windows-specific imports for Job Objects +if sys.platform == "win32": + import pywintypes + import win32api + import win32con + import win32job +else: + # Type stubs for non-Windows platforms + win32api = None + win32con = None + win32job = None + pywintypes = None + +JobHandle = int + + +def get_windows_executable_command(command: str) -> str: + """ + Get the correct executable command normalized for Windows. + + On Windows, commands might exist with specific extensions (.exe, .cmd, etc.) + that need to be located for proper execution. + + Args: + command: Base command (e.g., 'uvx', 'npx') + + Returns: + str: Windows-appropriate command path + """ + try: + # First check if command exists in PATH as-is + if command_path := shutil.which(command): + return command_path + + # Check for Windows-specific extensions + for ext in [".cmd", ".bat", ".exe", ".ps1"]: + ext_version = f"{command}{ext}" + if ext_path := shutil.which(ext_version): + return ext_path + + # For regular commands or if we couldn't find special versions + return command + except OSError: + # Handle file system errors during path resolution + # (permissions, broken symlinks, etc.) + return command + + +class FallbackProcess: + """ + A fallback process wrapper for Windows to handle async I/O + when using subprocess.Popen, which provides sync-only FileIO objects. + + This wraps stdin and stdout into async-compatible + streams (FileReadStream, FileWriteStream), + so that MCP clients expecting async streams can work properly. + """ + + def __init__(self, popen_obj: subprocess.Popen[bytes]): + self.popen: subprocess.Popen[bytes] = popen_obj + self.stdin_raw = popen_obj.stdin # type: ignore[assignment] + self.stdout_raw = popen_obj.stdout # type: ignore[assignment] + self.stderr = popen_obj.stderr # type: ignore[assignment] + + self.stdin = FileWriteStream(cast(BinaryIO, self.stdin_raw)) if self.stdin_raw else None + self.stdout = FileReadStream(cast(BinaryIO, self.stdout_raw)) if self.stdout_raw else None + + async def __aenter__(self): + """Support async context manager entry.""" + return self + + async def __aexit__( + self, + exc_type: BaseException | None, + exc_val: BaseException | None, + exc_tb: object | None, + ) -> None: + """Terminate and wait on process exit inside a thread.""" + self.popen.terminate() + await to_thread.run_sync(self.popen.wait) + + # Close the file handles to prevent ResourceWarning + if self.stdin: + await self.stdin.aclose() + if self.stdout: + await self.stdout.aclose() + if self.stdin_raw: + self.stdin_raw.close() + if self.stdout_raw: + self.stdout_raw.close() + if self.stderr: + self.stderr.close() + + async def wait(self): + """Async wait for process completion.""" + return await to_thread.run_sync(self.popen.wait) + + def terminate(self): + """Terminate the subprocess immediately.""" + return self.popen.terminate() + + def kill(self) -> None: + """Kill the subprocess immediately (alias for terminate).""" + self.terminate() + + @property + def pid(self) -> int: + """Return the process ID.""" + return self.popen.pid + + +# ------------------------ +# Updated function +# ------------------------ + + +async def create_windows_process( + command: str, + args: list[str], + env: dict[str, str] | None = None, + errlog: TextIO | None = sys.stderr, + cwd: Path | str | None = None, +) -> Process | FallbackProcess: + """ + Creates a subprocess in a Windows-compatible way with Job Object support. + + Attempt to use anyio's open_process for async subprocess creation. + In some cases this will throw NotImplementedError on Windows, e.g. + when using the SelectorEventLoop which does not support async subprocesses. + In that case, we fall back to using subprocess.Popen. + + The process is automatically added to a Job Object to ensure all child + processes are terminated when the parent is terminated. + + Args: + command (str): The executable to run + args (list[str]): List of command line arguments + env (dict[str, str] | None): Environment variables + errlog (TextIO | None): Where to send stderr output (defaults to sys.stderr) + cwd (Path | str | None): Working directory for the subprocess + + Returns: + Process | FallbackProcess: Async-compatible subprocess with stdin and stdout streams + """ + job = _create_job_object() + process = None + + try: + # First try using anyio with Windows-specific flags to hide console window + process = await anyio.open_process( + [command, *args], + env=env, + # Ensure we don't create console windows for each process + creationflags=subprocess.CREATE_NO_WINDOW # type: ignore + if hasattr(subprocess, "CREATE_NO_WINDOW") + else 0, + stderr=errlog, + cwd=cwd, + ) + except NotImplementedError: + # If Windows doesn't support async subprocess creation, use fallback + process = await _create_windows_fallback_process(command, args, env, errlog, cwd) + except Exception: + # Try again without creation flags + process = await anyio.open_process( + [command, *args], + env=env, + stderr=errlog, + cwd=cwd, + ) + + _maybe_assign_process_to_job(process, job) + return process + + +async def _create_windows_fallback_process( + command: str, + args: list[str], + env: dict[str, str] | None = None, + errlog: TextIO | None = sys.stderr, + cwd: Path | str | None = None, +) -> FallbackProcess: + """ + Create a subprocess using subprocess.Popen as a fallback when anyio fails. + + This function wraps the sync subprocess.Popen in an async-compatible interface. + """ + try: + # Try launching with creationflags to avoid opening a new console window + popen_obj = subprocess.Popen( + [command, *args], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=errlog, + env=env, + cwd=cwd, + bufsize=0, # Unbuffered output + creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), + ) + except Exception: + # If creationflags failed, fallback without them + popen_obj = subprocess.Popen( + [command, *args], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=errlog, + env=env, + cwd=cwd, + bufsize=0, + ) + return FallbackProcess(popen_obj) + + +def _create_job_object() -> int | None: + """ + Create a Windows Job Object configured to terminate all processes when closed. + """ + if sys.platform != "win32" or not win32job: + return None + + try: + job = win32job.CreateJobObject(None, "") + extended_info = win32job.QueryInformationJobObject(job, win32job.JobObjectExtendedLimitInformation) + + extended_info["BasicLimitInformation"]["LimitFlags"] |= win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE + win32job.SetInformationJobObject(job, win32job.JobObjectExtendedLimitInformation, extended_info) + return job + except Exception as e: + logger.warning(f"Failed to create Job Object for process tree management: {e}") + return None + + +def _maybe_assign_process_to_job(process: Process | FallbackProcess, job: JobHandle | None) -> None: + """ + Try to assign a process to a job object. If assignment fails + for any reason, the job handle is closed. + """ + if not job: + return + + if sys.platform != "win32" or not win32api or not win32con or not win32job: + return + + try: + process_handle = win32api.OpenProcess( + win32con.PROCESS_SET_QUOTA | win32con.PROCESS_TERMINATE, False, process.pid + ) + if not process_handle: + raise Exception("Failed to open process handle") + + try: + win32job.AssignProcessToJobObject(job, process_handle) + process._job_object = job + finally: + win32api.CloseHandle(process_handle) + except Exception as e: + logger.warning(f"Failed to assign process {process.pid} to Job Object: {e}") + if win32api: + win32api.CloseHandle(job) + + +async def terminate_windows_process_tree(process: Process | FallbackProcess, timeout_seconds: float = 2.0) -> None: + """ + Terminate a process and all its children on Windows. + + If the process has an associated job object, it will be terminated. + Otherwise, falls back to basic process termination. + + Args: + process: The process to terminate + timeout_seconds: Timeout in seconds before force killing (default: 2.0) + """ + if sys.platform != "win32": + return + + job = getattr(process, "_job_object", None) + if job and win32job: + try: + win32job.TerminateJobObject(job, 1) + except Exception: + # Job might already be terminated + pass + finally: + if win32api: + try: + win32api.CloseHandle(job) + except Exception: + pass + + # Always try to terminate the process itself as well + try: + process.terminate() + except Exception: + pass + + +@deprecated( + "terminate_windows_process is deprecated and will be removed in a future version. " + "Process termination is now handled internally by the stdio_client context manager." +) +async def terminate_windows_process(process: Process | FallbackProcess): + """ + Terminate a Windows process. + + Note: On Windows, terminating a process with process.terminate() doesn't + always guarantee immediate process termination. + So we give it 2s to exit, or we call process.kill() + which sends a SIGKILL equivalent signal. + + Args: + process: The process to terminate + """ + try: + process.terminate() + with anyio.fail_after(2.0): + await process.wait() + except TimeoutError: + # Force kill if it doesn't terminate + process.kill() diff --git a/source/target-vendors/cp312/mcp/py.typed b/source/target-vendors/cp312/mcp/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/mcp/server/__init__.py b/source/target-vendors/cp312/mcp/server/__init__.py new file mode 100644 index 0000000..0feed36 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/__init__.py @@ -0,0 +1,5 @@ +from .fastmcp import FastMCP +from .lowlevel import NotificationOptions, Server +from .models import InitializationOptions + +__all__ = ["Server", "FastMCP", "NotificationOptions", "InitializationOptions"] diff --git a/source/target-vendors/cp312/mcp/server/__main__.py b/source/target-vendors/cp312/mcp/server/__main__.py new file mode 100644 index 0000000..1970eca --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/__main__.py @@ -0,0 +1,50 @@ +import importlib.metadata +import logging +import sys + +import anyio + +from mcp.server.models import InitializationOptions +from mcp.server.session import ServerSession +from mcp.server.stdio import stdio_server +from mcp.types import ServerCapabilities + +if not sys.warnoptions: + import warnings + + warnings.simplefilter("ignore") + +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger("server") + + +async def receive_loop(session: ServerSession): + logger.info("Starting receive loop") + async for message in session.incoming_messages: + if isinstance(message, Exception): + logger.error("Error: %s", message) + continue + + logger.info("Received message from client: %s", message) + + +async def main(): + version = importlib.metadata.version("mcp") + async with stdio_server() as (read_stream, write_stream): + async with ( + ServerSession( + read_stream, + write_stream, + InitializationOptions( + server_name="mcp", + server_version=version, + capabilities=ServerCapabilities(), + ), + ) as session, + write_stream, + ): + await receive_loop(session) + + +if __name__ == "__main__": + anyio.run(main, backend="trio") diff --git a/source/target-vendors/cp312/mcp/server/auth/__init__.py b/source/target-vendors/cp312/mcp/server/auth/__init__.py new file mode 100644 index 0000000..6888ffe --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/__init__.py @@ -0,0 +1,3 @@ +""" +MCP OAuth server authorization components. +""" diff --git a/source/target-vendors/cp312/mcp/server/auth/errors.py b/source/target-vendors/cp312/mcp/server/auth/errors.py new file mode 100644 index 0000000..117deea --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/errors.py @@ -0,0 +1,5 @@ +from pydantic import ValidationError + + +def stringify_pydantic_error(validation_error: ValidationError) -> str: + return "\n".join(f"{'.'.join(str(loc) for loc in e['loc'])}: {e['msg']}" for e in validation_error.errors()) diff --git a/source/target-vendors/cp312/mcp/server/auth/handlers/__init__.py b/source/target-vendors/cp312/mcp/server/auth/handlers/__init__.py new file mode 100644 index 0000000..e99a62d --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/handlers/__init__.py @@ -0,0 +1,3 @@ +""" +Request handlers for MCP authorization endpoints. +""" diff --git a/source/target-vendors/cp312/mcp/server/auth/handlers/authorize.py b/source/target-vendors/cp312/mcp/server/auth/handlers/authorize.py new file mode 100644 index 0000000..3570d28 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/handlers/authorize.py @@ -0,0 +1,224 @@ +import logging +from dataclasses import dataclass +from typing import Any, Literal + +from pydantic import AnyUrl, BaseModel, Field, RootModel, ValidationError +from starlette.datastructures import FormData, QueryParams +from starlette.requests import Request +from starlette.responses import RedirectResponse, Response + +from mcp.server.auth.errors import stringify_pydantic_error +from mcp.server.auth.json_response import PydanticJSONResponse +from mcp.server.auth.provider import ( + AuthorizationErrorCode, + AuthorizationParams, + AuthorizeError, + OAuthAuthorizationServerProvider, + construct_redirect_uri, +) +from mcp.shared.auth import InvalidRedirectUriError, InvalidScopeError + +logger = logging.getLogger(__name__) + + +class AuthorizationRequest(BaseModel): + # See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1 + client_id: str = Field(..., description="The client ID") + redirect_uri: AnyUrl | None = Field(None, description="URL to redirect to after authorization") + + # see OAuthClientMetadata; we only support `code` + response_type: Literal["code"] = Field(..., description="Must be 'code' for authorization code flow") + code_challenge: str = Field(..., description="PKCE code challenge") + code_challenge_method: Literal["S256"] = Field("S256", description="PKCE code challenge method, must be S256") + state: str | None = Field(None, description="Optional state parameter") + scope: str | None = Field( + None, + description="Optional scope; if specified, should be a space-separated list of scope strings", + ) + resource: str | None = Field( + None, + description="RFC 8707 resource indicator - the MCP server this token will be used with", + ) + + +class AuthorizationErrorResponse(BaseModel): + error: AuthorizationErrorCode + error_description: str | None + error_uri: AnyUrl | None = None + # must be set if provided in the request + state: str | None = None + + +def best_effort_extract_string(key: str, params: None | FormData | QueryParams) -> str | None: + if params is None: # pragma: no cover + return None + value = params.get(key) + if isinstance(value, str): + return value + return None + + +class AnyUrlModel(RootModel[AnyUrl]): + root: AnyUrl + + +@dataclass +class AuthorizationHandler: + provider: OAuthAuthorizationServerProvider[Any, Any, Any] + + async def handle(self, request: Request) -> Response: + # implements authorization requests for grant_type=code; + # see https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1 + + state = None + redirect_uri = None + client = None + params = None + + async def error_response( + error: AuthorizationErrorCode, + error_description: str | None, + attempt_load_client: bool = True, + ): + # Error responses take two different formats: + # 1. The request has a valid client ID & redirect_uri: we issue a redirect + # back to the redirect_uri with the error response fields as query + # parameters. This allows the client to be notified of the error. + # 2. Otherwise, we return an error response directly to the end user; + # we choose to do so in JSON, but this is left undefined in the + # specification. + # See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2.1 + # + # This logic is a bit awkward to handle, because the error might be thrown + # very early in request validation, before we've done the usual Pydantic + # validation, loaded the client, etc. To handle this, error_response() + # contains fallback logic which attempts to load the parameters directly + # from the request. + + nonlocal client, redirect_uri, state + if client is None and attempt_load_client: + # make last-ditch attempt to load the client + client_id = best_effort_extract_string("client_id", params) + client = await self.provider.get_client(client_id) if client_id else None + if redirect_uri is None and client: + # make last-ditch effort to load the redirect uri + try: + if params is not None and "redirect_uri" not in params: + raw_redirect_uri = None + else: + raw_redirect_uri = AnyUrlModel.model_validate( + best_effort_extract_string("redirect_uri", params) + ).root + redirect_uri = client.validate_redirect_uri(raw_redirect_uri) + except (ValidationError, InvalidRedirectUriError): + # if the redirect URI is invalid, ignore it & just return the + # initial error + pass + + # the error response MUST contain the state specified by the client, if any + if state is None: # pragma: no cover + # make last-ditch effort to load state + state = best_effort_extract_string("state", params) + + error_resp = AuthorizationErrorResponse( + error=error, + error_description=error_description, + state=state, + ) + + if redirect_uri and client: + return RedirectResponse( + url=construct_redirect_uri(str(redirect_uri), **error_resp.model_dump(exclude_none=True)), + status_code=302, + headers={"Cache-Control": "no-store"}, + ) + else: + return PydanticJSONResponse( + status_code=400, + content=error_resp, + headers={"Cache-Control": "no-store"}, + ) + + try: + # Parse request parameters + if request.method == "GET": + # Convert query_params to dict for pydantic validation + params = request.query_params + else: + # Parse form data for POST requests + params = await request.form() + + # Save state if it exists, even before validation + state = best_effort_extract_string("state", params) + + try: + auth_request = AuthorizationRequest.model_validate(params) + state = auth_request.state # Update with validated state + except ValidationError as validation_error: + error: AuthorizationErrorCode = "invalid_request" + for e in validation_error.errors(): + if e["loc"] == ("response_type",) and e["type"] == "literal_error": + error = "unsupported_response_type" + break + return await error_response(error, stringify_pydantic_error(validation_error)) + + # Get client information + client = await self.provider.get_client( + auth_request.client_id, + ) + if not client: + # For client_id validation errors, return direct error (no redirect) + return await error_response( + error="invalid_request", + error_description=f"Client ID '{auth_request.client_id}' not found", + attempt_load_client=False, + ) + + # Validate redirect_uri against client's registered URIs + try: + redirect_uri = client.validate_redirect_uri(auth_request.redirect_uri) + except InvalidRedirectUriError as validation_error: + # For redirect_uri validation errors, return direct error (no redirect) + return await error_response( + error="invalid_request", + error_description=validation_error.message, + ) + + # Validate scope - for scope errors, we can redirect + try: + scopes = client.validate_scope(auth_request.scope) + except InvalidScopeError as validation_error: + # For scope errors, redirect with error parameters + return await error_response( + error="invalid_scope", + error_description=validation_error.message, + ) + + # Setup authorization parameters + auth_params = AuthorizationParams( + state=state, + scopes=scopes, + code_challenge=auth_request.code_challenge, + redirect_uri=redirect_uri, + redirect_uri_provided_explicitly=auth_request.redirect_uri is not None, + resource=auth_request.resource, # RFC 8707 + ) + + try: + # Let the provider pick the next URI to redirect to + return RedirectResponse( + url=await self.provider.authorize( + client, + auth_params, + ), + status_code=302, + headers={"Cache-Control": "no-store"}, + ) + except AuthorizeError as e: + # Handle authorization errors as defined in RFC 6749 Section 4.1.2.1 + return await error_response(error=e.error, error_description=e.error_description) + + except Exception as validation_error: # pragma: no cover + # Catch-all for unexpected errors + logger.exception("Unexpected error in authorization_handler", exc_info=validation_error) + return await error_response(error="server_error", error_description="An unexpected error occurred") diff --git a/source/target-vendors/cp312/mcp/server/auth/handlers/metadata.py b/source/target-vendors/cp312/mcp/server/auth/handlers/metadata.py new file mode 100644 index 0000000..f126442 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/handlers/metadata.py @@ -0,0 +1,29 @@ +from dataclasses import dataclass + +from starlette.requests import Request +from starlette.responses import Response + +from mcp.server.auth.json_response import PydanticJSONResponse +from mcp.shared.auth import OAuthMetadata, ProtectedResourceMetadata + + +@dataclass +class MetadataHandler: + metadata: OAuthMetadata + + async def handle(self, request: Request) -> Response: + return PydanticJSONResponse( + content=self.metadata, + headers={"Cache-Control": "public, max-age=3600"}, # Cache for 1 hour + ) + + +@dataclass +class ProtectedResourceMetadataHandler: + metadata: ProtectedResourceMetadata + + async def handle(self, request: Request) -> Response: + return PydanticJSONResponse( + content=self.metadata, + headers={"Cache-Control": "public, max-age=3600"}, # Cache for 1 hour + ) diff --git a/source/target-vendors/cp312/mcp/server/auth/handlers/register.py b/source/target-vendors/cp312/mcp/server/auth/handlers/register.py new file mode 100644 index 0000000..c65473d --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/handlers/register.py @@ -0,0 +1,136 @@ +import secrets +import time +from dataclasses import dataclass +from typing import Any +from uuid import uuid4 + +from pydantic import BaseModel, RootModel, ValidationError +from starlette.requests import Request +from starlette.responses import Response + +from mcp.server.auth.errors import stringify_pydantic_error +from mcp.server.auth.json_response import PydanticJSONResponse +from mcp.server.auth.provider import OAuthAuthorizationServerProvider, RegistrationError, RegistrationErrorCode +from mcp.server.auth.settings import ClientRegistrationOptions +from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata + + +class RegistrationRequest(RootModel[OAuthClientMetadata]): + # this wrapper is a no-op; it's just to separate out the types exposed to the + # provider from what we use in the HTTP handler + root: OAuthClientMetadata + + +class RegistrationErrorResponse(BaseModel): + error: RegistrationErrorCode + error_description: str | None + + +@dataclass +class RegistrationHandler: + provider: OAuthAuthorizationServerProvider[Any, Any, Any] + options: ClientRegistrationOptions + + async def handle(self, request: Request) -> Response: + # Implements dynamic client registration as defined in https://datatracker.ietf.org/doc/html/rfc7591#section-3.1 + try: + # Parse request body as JSON + body = await request.json() + client_metadata = OAuthClientMetadata.model_validate(body) + + # Scope validation is handled below + except ValidationError as validation_error: + return PydanticJSONResponse( + content=RegistrationErrorResponse( + error="invalid_client_metadata", + error_description=stringify_pydantic_error(validation_error), + ), + status_code=400, + ) + + client_id = str(uuid4()) + + # If auth method is None, default to client_secret_post + if client_metadata.token_endpoint_auth_method is None: + client_metadata.token_endpoint_auth_method = "client_secret_post" + + client_secret = None + if client_metadata.token_endpoint_auth_method != "none": # pragma: no branch + # cryptographically secure random 32-byte hex string + client_secret = secrets.token_hex(32) + + if client_metadata.scope is None and self.options.default_scopes is not None: + client_metadata.scope = " ".join(self.options.default_scopes) + elif client_metadata.scope is not None and self.options.valid_scopes is not None: + requested_scopes = set(client_metadata.scope.split()) + valid_scopes = set(self.options.valid_scopes) + if not requested_scopes.issubset(valid_scopes): # pragma: no branch + return PydanticJSONResponse( + content=RegistrationErrorResponse( + error="invalid_client_metadata", + error_description="Requested scopes are not valid: " + f"{', '.join(requested_scopes - valid_scopes)}", + ), + status_code=400, + ) + if not {"authorization_code", "refresh_token"}.issubset(set(client_metadata.grant_types)): + return PydanticJSONResponse( + content=RegistrationErrorResponse( + error="invalid_client_metadata", + error_description="grant_types must be authorization_code and refresh_token", + ), + status_code=400, + ) + + # The MCP spec requires servers to use the authorization `code` flow + # with PKCE + if "code" not in client_metadata.response_types: + return PydanticJSONResponse( + content=RegistrationErrorResponse( + error="invalid_client_metadata", + error_description="response_types must include 'code' for authorization_code grant", + ), + status_code=400, + ) + + client_id_issued_at = int(time.time()) + client_secret_expires_at = ( + client_id_issued_at + self.options.client_secret_expiry_seconds + if self.options.client_secret_expiry_seconds is not None + else None + ) + + client_info = OAuthClientInformationFull( + client_id=client_id, + client_id_issued_at=client_id_issued_at, + client_secret=client_secret, + client_secret_expires_at=client_secret_expires_at, + # passthrough information from the client request + redirect_uris=client_metadata.redirect_uris, + token_endpoint_auth_method=client_metadata.token_endpoint_auth_method, + grant_types=client_metadata.grant_types, + response_types=client_metadata.response_types, + client_name=client_metadata.client_name, + client_uri=client_metadata.client_uri, + logo_uri=client_metadata.logo_uri, + scope=client_metadata.scope, + contacts=client_metadata.contacts, + tos_uri=client_metadata.tos_uri, + policy_uri=client_metadata.policy_uri, + jwks_uri=client_metadata.jwks_uri, + jwks=client_metadata.jwks, + software_id=client_metadata.software_id, + software_version=client_metadata.software_version, + ) + try: + # Register client + await self.provider.register_client(client_info) + + # Return client information + return PydanticJSONResponse(content=client_info, status_code=201) + except RegistrationError as e: + # Handle registration errors as defined in RFC 7591 Section 3.2.2 + return PydanticJSONResponse( + content=RegistrationErrorResponse(error=e.error, error_description=e.error_description), + status_code=400, + ) diff --git a/source/target-vendors/cp312/mcp/server/auth/handlers/revoke.py b/source/target-vendors/cp312/mcp/server/auth/handlers/revoke.py new file mode 100644 index 0000000..fa8cfc9 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/handlers/revoke.py @@ -0,0 +1,91 @@ +from dataclasses import dataclass +from functools import partial +from typing import Any, Literal + +from pydantic import BaseModel, ValidationError +from starlette.requests import Request +from starlette.responses import Response + +from mcp.server.auth.errors import ( + stringify_pydantic_error, +) +from mcp.server.auth.json_response import PydanticJSONResponse +from mcp.server.auth.middleware.client_auth import AuthenticationError, ClientAuthenticator +from mcp.server.auth.provider import AccessToken, OAuthAuthorizationServerProvider, RefreshToken + + +class RevocationRequest(BaseModel): + """ + # See https://datatracker.ietf.org/doc/html/rfc7009#section-2.1 + """ + + token: str + token_type_hint: Literal["access_token", "refresh_token"] | None = None + client_id: str + client_secret: str | None + + +class RevocationErrorResponse(BaseModel): + error: Literal["invalid_request", "unauthorized_client"] + error_description: str | None = None + + +@dataclass +class RevocationHandler: + provider: OAuthAuthorizationServerProvider[Any, Any, Any] + client_authenticator: ClientAuthenticator + + async def handle(self, request: Request) -> Response: + """ + Handler for the OAuth 2.0 Token Revocation endpoint. + """ + try: + client = await self.client_authenticator.authenticate_request(request) + except AuthenticationError as e: # pragma: no cover + return PydanticJSONResponse( + status_code=401, + content=RevocationErrorResponse( + error="unauthorized_client", + error_description=e.message, + ), + ) + + try: + form_data = await request.form() + revocation_request = RevocationRequest.model_validate(dict(form_data)) + except ValidationError as e: + return PydanticJSONResponse( + status_code=400, + content=RevocationErrorResponse( + error="invalid_request", + error_description=stringify_pydantic_error(e), + ), + ) + + loaders = [ + self.provider.load_access_token, + partial(self.provider.load_refresh_token, client), + ] + if revocation_request.token_type_hint == "refresh_token": # pragma: no cover + loaders = reversed(loaders) + + token: None | AccessToken | RefreshToken = None + for loader in loaders: + token = await loader(revocation_request.token) + if token is not None: + break + + # if token is not found, just return HTTP 200 per the RFC + if token and token.client_id == client.client_id: + # Revoke token; provider is not meant to be able to do validation + # at this point that would result in an error + await self.provider.revoke_token(token) + + # Return successful empty response + return Response( + status_code=200, + headers={ + "Cache-Control": "no-store", + "Pragma": "no-cache", + }, + ) diff --git a/source/target-vendors/cp312/mcp/server/auth/handlers/token.py b/source/target-vendors/cp312/mcp/server/auth/handlers/token.py new file mode 100644 index 0000000..4467da6 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/handlers/token.py @@ -0,0 +1,241 @@ +import base64 +import hashlib +import time +from dataclasses import dataclass +from typing import Annotated, Any, Literal + +from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, RootModel, ValidationError +from starlette.requests import Request + +from mcp.server.auth.errors import stringify_pydantic_error +from mcp.server.auth.json_response import PydanticJSONResponse +from mcp.server.auth.middleware.client_auth import AuthenticationError, ClientAuthenticator +from mcp.server.auth.provider import OAuthAuthorizationServerProvider, TokenError, TokenErrorCode +from mcp.shared.auth import OAuthToken + + +class AuthorizationCodeRequest(BaseModel): + # See https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3 + grant_type: Literal["authorization_code"] + code: str = Field(..., description="The authorization code") + redirect_uri: AnyUrl | None = Field(None, description="Must be the same as redirect URI provided in /authorize") + client_id: str + # we use the client_secret param, per https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1 + client_secret: str | None = None + # See https://datatracker.ietf.org/doc/html/rfc7636#section-4.5 + code_verifier: str = Field(..., description="PKCE code verifier") + # RFC 8707 resource indicator + resource: str | None = Field(None, description="Resource indicator for the token") + + +class RefreshTokenRequest(BaseModel): + # See https://datatracker.ietf.org/doc/html/rfc6749#section-6 + grant_type: Literal["refresh_token"] + refresh_token: str = Field(..., description="The refresh token") + scope: str | None = Field(None, description="Optional scope parameter") + client_id: str + # we use the client_secret param, per https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1 + client_secret: str | None = None + # RFC 8707 resource indicator + resource: str | None = Field(None, description="Resource indicator for the token") + + +class TokenRequest( + RootModel[ + Annotated[ + AuthorizationCodeRequest | RefreshTokenRequest, + Field(discriminator="grant_type"), + ] + ] +): + root: Annotated[ + AuthorizationCodeRequest | RefreshTokenRequest, + Field(discriminator="grant_type"), + ] + + +class TokenErrorResponse(BaseModel): + """ + See https://datatracker.ietf.org/doc/html/rfc6749#section-5.2 + """ + + error: TokenErrorCode + error_description: str | None = None + error_uri: AnyHttpUrl | None = None + + +class TokenSuccessResponse(RootModel[OAuthToken]): + # this is just a wrapper over OAuthToken; the only reason we do this + # is to have some separation between the HTTP response type, and the + # type returned by the provider + root: OAuthToken + + +@dataclass +class TokenHandler: + provider: OAuthAuthorizationServerProvider[Any, Any, Any] + client_authenticator: ClientAuthenticator + + def response(self, obj: TokenSuccessResponse | TokenErrorResponse): + status_code = 200 + if isinstance(obj, TokenErrorResponse): + status_code = 400 + + return PydanticJSONResponse( + content=obj, + status_code=status_code, + headers={ + "Cache-Control": "no-store", + "Pragma": "no-cache", + }, + ) + + async def handle(self, request: Request): + try: + client_info = await self.client_authenticator.authenticate_request(request) + except AuthenticationError as e: + # Authentication failures should return 401 + return PydanticJSONResponse( + content=TokenErrorResponse( + error="unauthorized_client", + error_description=e.message, + ), + status_code=401, + headers={ + "Cache-Control": "no-store", + "Pragma": "no-cache", + }, + ) + + try: + form_data = await request.form() + token_request = TokenRequest.model_validate(dict(form_data)).root + except ValidationError as validation_error: # pragma: no cover + return self.response( + TokenErrorResponse( + error="invalid_request", + error_description=stringify_pydantic_error(validation_error), + ) + ) + + if token_request.grant_type not in client_info.grant_types: # pragma: no cover + return self.response( + TokenErrorResponse( + error="unsupported_grant_type", + error_description=(f"Unsupported grant type (supported grant types are {client_info.grant_types})"), + ) + ) + + tokens: OAuthToken + + match token_request: + case AuthorizationCodeRequest(): + auth_code = await self.provider.load_authorization_code(client_info, token_request.code) + if auth_code is None or auth_code.client_id != token_request.client_id: + # if code belongs to different client, pretend it doesn't exist + return self.response( + TokenErrorResponse( + error="invalid_grant", + error_description="authorization code does not exist", + ) + ) + + # make auth codes expire after a deadline + # see https://datatracker.ietf.org/doc/html/rfc6749#section-10.5 + if auth_code.expires_at < time.time(): + return self.response( + TokenErrorResponse( + error="invalid_grant", + error_description="authorization code has expired", + ) + ) + + # verify redirect_uri doesn't change between /authorize and /tokens + # see https://datatracker.ietf.org/doc/html/rfc6749#section-10.6 + if auth_code.redirect_uri_provided_explicitly: + authorize_request_redirect_uri = auth_code.redirect_uri + else: # pragma: no cover + authorize_request_redirect_uri = None + + # Convert both sides to strings for comparison to handle AnyUrl vs string issues + token_redirect_str = str(token_request.redirect_uri) if token_request.redirect_uri is not None else None + auth_redirect_str = ( + str(authorize_request_redirect_uri) if authorize_request_redirect_uri is not None else None + ) + + if token_redirect_str != auth_redirect_str: + return self.response( + TokenErrorResponse( + error="invalid_request", + error_description=("redirect_uri did not match the one used when creating auth code"), + ) + ) + + # Verify PKCE code verifier + sha256 = hashlib.sha256(token_request.code_verifier.encode()).digest() + hashed_code_verifier = base64.urlsafe_b64encode(sha256).decode().rstrip("=") + + if hashed_code_verifier != auth_code.code_challenge: + # see https://datatracker.ietf.org/doc/html/rfc7636#section-4.6 + return self.response( + TokenErrorResponse( + error="invalid_grant", + error_description="incorrect code_verifier", + ) + ) + + try: + # Exchange authorization code for tokens + tokens = await self.provider.exchange_authorization_code(client_info, auth_code) + except TokenError as e: + return self.response( + TokenErrorResponse( + error=e.error, + error_description=e.error_description, + ) + ) + + case RefreshTokenRequest(): # pragma: no cover + refresh_token = await self.provider.load_refresh_token(client_info, token_request.refresh_token) + if refresh_token is None or refresh_token.client_id != token_request.client_id: + # if token belongs to different client, pretend it doesn't exist + return self.response( + TokenErrorResponse( + error="invalid_grant", + error_description="refresh token does not exist", + ) + ) + + if refresh_token.expires_at and refresh_token.expires_at < time.time(): + # if the refresh token has expired, pretend it doesn't exist + return self.response( + TokenErrorResponse( + error="invalid_grant", + error_description="refresh token has expired", + ) + ) + + # Parse scopes if provided + scopes = token_request.scope.split(" ") if token_request.scope else refresh_token.scopes + + for scope in scopes: + if scope not in refresh_token.scopes: + return self.response( + TokenErrorResponse( + error="invalid_scope", + error_description=(f"cannot request scope `{scope}` not provided by refresh token"), + ) + ) + + try: + # Exchange refresh token for new tokens + tokens = await self.provider.exchange_refresh_token(client_info, refresh_token, scopes) + except TokenError as e: + return self.response( + TokenErrorResponse( + error=e.error, + error_description=e.error_description, + ) + ) + + return self.response(TokenSuccessResponse(root=tokens)) diff --git a/source/target-vendors/cp312/mcp/server/auth/json_response.py b/source/target-vendors/cp312/mcp/server/auth/json_response.py new file mode 100644 index 0000000..bd95bd6 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/json_response.py @@ -0,0 +1,10 @@ +from typing import Any + +from starlette.responses import JSONResponse + + +class PydanticJSONResponse(JSONResponse): + # use pydantic json serialization instead of the stock `json.dumps`, + # so that we can handle serializing pydantic models like AnyHttpUrl + def render(self, content: Any) -> bytes: + return content.model_dump_json(exclude_none=True).encode("utf-8") diff --git a/source/target-vendors/cp312/mcp/server/auth/middleware/__init__.py b/source/target-vendors/cp312/mcp/server/auth/middleware/__init__.py new file mode 100644 index 0000000..ba3ff63 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/middleware/__init__.py @@ -0,0 +1,3 @@ +""" +Middleware for MCP authorization. +""" diff --git a/source/target-vendors/cp312/mcp/server/auth/middleware/auth_context.py b/source/target-vendors/cp312/mcp/server/auth/middleware/auth_context.py new file mode 100644 index 0000000..e2116c3 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/middleware/auth_context.py @@ -0,0 +1,48 @@ +import contextvars + +from starlette.types import ASGIApp, Receive, Scope, Send + +from mcp.server.auth.middleware.bearer_auth import AuthenticatedUser +from mcp.server.auth.provider import AccessToken + +# Create a contextvar to store the authenticated user +# The default is None, indicating no authenticated user is present +auth_context_var = contextvars.ContextVar[AuthenticatedUser | None]("auth_context", default=None) + + +def get_access_token() -> AccessToken | None: + """ + Get the access token from the current context. + + Returns: + The access token if an authenticated user is available, None otherwise. + """ + auth_user = auth_context_var.get() + return auth_user.access_token if auth_user else None + + +class AuthContextMiddleware: + """ + Middleware that extracts the authenticated user from the request + and sets it in a contextvar for easy access throughout the request lifecycle. + + This middleware should be added after the AuthenticationMiddleware in the + middleware stack to ensure that the user is properly authenticated before + being stored in the context. + """ + + def __init__(self, app: ASGIApp): + self.app = app + + async def __call__(self, scope: Scope, receive: Receive, send: Send): + user = scope.get("user") + if isinstance(user, AuthenticatedUser): + # Set the authenticated user in the contextvar + token = auth_context_var.set(user) + try: + await self.app(scope, receive, send) + finally: + auth_context_var.reset(token) + else: + # No authenticated user, just process the request + await self.app(scope, receive, send) diff --git a/source/target-vendors/cp312/mcp/server/auth/middleware/bearer_auth.py b/source/target-vendors/cp312/mcp/server/auth/middleware/bearer_auth.py new file mode 100644 index 0000000..64c9b88 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/middleware/bearer_auth.py @@ -0,0 +1,128 @@ +import json +import time +from typing import Any + +from pydantic import AnyHttpUrl +from starlette.authentication import AuthCredentials, AuthenticationBackend, SimpleUser +from starlette.requests import HTTPConnection +from starlette.types import Receive, Scope, Send + +from mcp.server.auth.provider import AccessToken, TokenVerifier + + +class AuthenticatedUser(SimpleUser): + """User with authentication info.""" + + def __init__(self, auth_info: AccessToken): + super().__init__(auth_info.client_id) + self.access_token = auth_info + self.scopes = auth_info.scopes + + +class BearerAuthBackend(AuthenticationBackend): + """ + Authentication backend that validates Bearer tokens using a TokenVerifier. + """ + + def __init__(self, token_verifier: TokenVerifier): + self.token_verifier = token_verifier + + async def authenticate(self, conn: HTTPConnection): + auth_header = next( + (conn.headers.get(key) for key in conn.headers if key.lower() == "authorization"), + None, + ) + if not auth_header or not auth_header.lower().startswith("bearer "): + return None + + token = auth_header[7:] # Remove "Bearer " prefix + + # Validate the token with the verifier + auth_info = await self.token_verifier.verify_token(token) + + if not auth_info: + return None + + if auth_info.expires_at and auth_info.expires_at < int(time.time()): + return None + + return AuthCredentials(auth_info.scopes), AuthenticatedUser(auth_info) + + +class RequireAuthMiddleware: + """ + Middleware that requires a valid Bearer token in the Authorization header. + + This will validate the token with the auth provider and store the resulting + auth info in the request state. + """ + + def __init__( + self, + app: Any, + required_scopes: list[str], + resource_metadata_url: AnyHttpUrl | None = None, + ): + """ + Initialize the middleware. + + Args: + app: ASGI application + required_scopes: List of scopes that the token must have + resource_metadata_url: Optional protected resource metadata URL for WWW-Authenticate header + """ + self.app = app + self.required_scopes = required_scopes + self.resource_metadata_url = resource_metadata_url + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + auth_user = scope.get("user") + if not isinstance(auth_user, AuthenticatedUser): + await self._send_auth_error( + send, status_code=401, error="invalid_token", description="Authentication required" + ) + return + + auth_credentials = scope.get("auth") + + for required_scope in self.required_scopes: + # auth_credentials should always be provided; this is just paranoia + if auth_credentials is None or required_scope not in auth_credentials.scopes: + await self._send_auth_error( + send, status_code=403, error="insufficient_scope", description=f"Required scope: {required_scope}" + ) + return + + await self.app(scope, receive, send) + + async def _send_auth_error(self, send: Send, status_code: int, error: str, description: str) -> None: + """Send an authentication error response with WWW-Authenticate header.""" + # Build WWW-Authenticate header value + www_auth_parts = [f'error="{error}"', f'error_description="{description}"'] + if self.resource_metadata_url: # pragma: no cover + www_auth_parts.append(f'resource_metadata="{self.resource_metadata_url}"') + + www_authenticate = f"Bearer {', '.join(www_auth_parts)}" + + # Send response + body = {"error": error, "error_description": description} + body_bytes = json.dumps(body).encode() + + await send( + { + "type": "http.response.start", + "status": status_code, + "headers": [ + (b"content-type", b"application/json"), + (b"content-length", str(len(body_bytes)).encode()), + (b"www-authenticate", www_authenticate.encode()), + ], + } + ) + + await send( + { + "type": "http.response.body", + "body": body_bytes, + } + ) diff --git a/source/target-vendors/cp312/mcp/server/auth/middleware/client_auth.py b/source/target-vendors/cp312/mcp/server/auth/middleware/client_auth.py new file mode 100644 index 0000000..6126c6e --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/middleware/client_auth.py @@ -0,0 +1,115 @@ +import base64 +import binascii +import hmac +import time +from typing import Any +from urllib.parse import unquote + +from starlette.requests import Request + +from mcp.server.auth.provider import OAuthAuthorizationServerProvider +from mcp.shared.auth import OAuthClientInformationFull + + +class AuthenticationError(Exception): + def __init__(self, message: str): + self.message = message # pragma: no cover + + +class ClientAuthenticator: + """ + ClientAuthenticator is a callable which validates requests from a client + application, used to verify /token calls. + If, during registration, the client requested to be issued a secret, the + authenticator asserts that /token calls must be authenticated with + that same token. + NOTE: clients can opt for no authentication during registration, in which case this + logic is skipped. + """ + + def __init__(self, provider: OAuthAuthorizationServerProvider[Any, Any, Any]): + """ + Initialize the dependency. + + Args: + provider: Provider to look up client information + """ + self.provider = provider + + async def authenticate_request(self, request: Request) -> OAuthClientInformationFull: + """ + Authenticate a client from an HTTP request. + + Extracts client credentials from the appropriate location based on the + client's registered authentication method and validates them. + + Args: + request: The HTTP request containing client credentials + + Returns: + The authenticated client information + + Raises: + AuthenticationError: If authentication fails + """ + form_data = await request.form() + client_id = form_data.get("client_id") + if not client_id: + raise AuthenticationError("Missing client_id") + + client = await self.provider.get_client(str(client_id)) + if not client: + raise AuthenticationError("Invalid client_id") # pragma: no cover + + request_client_secret: str | None = None + auth_header = request.headers.get("Authorization", "") + + if client.token_endpoint_auth_method == "client_secret_basic": + if not auth_header.startswith("Basic "): + raise AuthenticationError("Missing or invalid Basic authentication in Authorization header") + + try: + encoded_credentials = auth_header[6:] # Remove "Basic " prefix + decoded = base64.b64decode(encoded_credentials).decode("utf-8") + if ":" not in decoded: + raise ValueError("Invalid Basic auth format") + basic_client_id, request_client_secret = decoded.split(":", 1) + + # URL-decode both parts per RFC 6749 Section 2.3.1 + basic_client_id = unquote(basic_client_id) + request_client_secret = unquote(request_client_secret) + + if basic_client_id != client_id: + raise AuthenticationError("Client ID mismatch in Basic auth") + except (ValueError, UnicodeDecodeError, binascii.Error): + raise AuthenticationError("Invalid Basic authentication header") + + elif client.token_endpoint_auth_method == "client_secret_post": + raw_form_data = form_data.get("client_secret") + # form_data.get() can return a UploadFile or None, so we need to check if it's a string + if isinstance(raw_form_data, str): + request_client_secret = str(raw_form_data) + + elif client.token_endpoint_auth_method == "none": + request_client_secret = None + else: + raise AuthenticationError( # pragma: no cover + f"Unsupported auth method: {client.token_endpoint_auth_method}" + ) + + # If client from the store expects a secret, validate that the request provides + # that secret + if client.client_secret: # pragma: no branch + if not request_client_secret: + raise AuthenticationError("Client secret is required") # pragma: no cover + + # hmac.compare_digest requires that both arguments are either bytes or a `str` containing + # only ASCII characters. Since we do not control `request_client_secret`, we encode both + # arguments to bytes. + if not hmac.compare_digest(client.client_secret.encode(), request_client_secret.encode()): + raise AuthenticationError("Invalid client_secret") # pragma: no cover + + if client.client_secret_expires_at and client.client_secret_expires_at < int(time.time()): + raise AuthenticationError("Client secret has expired") # pragma: no cover + + return client diff --git a/source/target-vendors/cp312/mcp/server/auth/provider.py b/source/target-vendors/cp312/mcp/server/auth/provider.py new file mode 100644 index 0000000..96296c1 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/provider.py @@ -0,0 +1,301 @@ +from dataclasses import dataclass +from typing import Generic, Literal, Protocol, TypeVar +from urllib.parse import parse_qs, urlencode, urlparse, urlunparse + +from pydantic import AnyUrl, BaseModel + +from mcp.shared.auth import OAuthClientInformationFull, OAuthToken + + +class AuthorizationParams(BaseModel): + state: str | None + scopes: list[str] | None + code_challenge: str + redirect_uri: AnyUrl + redirect_uri_provided_explicitly: bool + resource: str | None = None # RFC 8707 resource indicator + + +class AuthorizationCode(BaseModel): + code: str + scopes: list[str] + expires_at: float + client_id: str + code_challenge: str + redirect_uri: AnyUrl + redirect_uri_provided_explicitly: bool + resource: str | None = None # RFC 8707 resource indicator + + +class RefreshToken(BaseModel): + token: str + client_id: str + scopes: list[str] + expires_at: int | None = None + + +class AccessToken(BaseModel): + token: str + client_id: str + scopes: list[str] + expires_at: int | None = None + resource: str | None = None # RFC 8707 resource indicator + + +RegistrationErrorCode = Literal[ + "invalid_redirect_uri", + "invalid_client_metadata", + "invalid_software_statement", + "unapproved_software_statement", +] + + +@dataclass(frozen=True) +class RegistrationError(Exception): + error: RegistrationErrorCode + error_description: str | None = None + + +AuthorizationErrorCode = Literal[ + "invalid_request", + "unauthorized_client", + "access_denied", + "unsupported_response_type", + "invalid_scope", + "server_error", + "temporarily_unavailable", +] + + +@dataclass(frozen=True) +class AuthorizeError(Exception): + error: AuthorizationErrorCode + error_description: str | None = None + + +TokenErrorCode = Literal[ + "invalid_request", + "invalid_client", + "invalid_grant", + "unauthorized_client", + "unsupported_grant_type", + "invalid_scope", +] + + +@dataclass(frozen=True) +class TokenError(Exception): + error: TokenErrorCode + error_description: str | None = None + + +class TokenVerifier(Protocol): + """Protocol for verifying bearer tokens.""" + + async def verify_token(self, token: str) -> AccessToken | None: + """Verify a bearer token and return access info if valid.""" + + +# NOTE: FastMCP doesn't render any of these types in the user response, so it's +# OK to add fields to subclasses which should not be exposed externally. +AuthorizationCodeT = TypeVar("AuthorizationCodeT", bound=AuthorizationCode) +RefreshTokenT = TypeVar("RefreshTokenT", bound=RefreshToken) +AccessTokenT = TypeVar("AccessTokenT", bound=AccessToken) + + +class OAuthAuthorizationServerProvider(Protocol, Generic[AuthorizationCodeT, RefreshTokenT, AccessTokenT]): + async def get_client(self, client_id: str) -> OAuthClientInformationFull | None: + """ + Retrieves client information by client ID. + + Implementors MAY raise NotImplementedError if dynamic client registration is + disabled in ClientRegistrationOptions. + + Args: + client_id: The ID of the client to retrieve. + + Returns: + The client information, or None if the client does not exist. + """ + + async def register_client(self, client_info: OAuthClientInformationFull) -> None: + """ + Saves client information as part of registering it. + + Implementors MAY raise NotImplementedError if dynamic client registration is + disabled in ClientRegistrationOptions. + + Args: + client_info: The client metadata to register. + + Raises: + RegistrationError: If the client metadata is invalid. + """ + + async def authorize(self, client: OAuthClientInformationFull, params: AuthorizationParams) -> str: + """ + Called as part of the /authorize endpoint, and returns a URL that the client + will be redirected to. + Many MCP implementations will redirect to a third-party provider to perform + a second OAuth exchange with that provider. In this sort of setup, the client + has an OAuth connection with the MCP server, and the MCP server has an OAuth + connection with the 3rd-party provider. At the end of this flow, the client + should be redirected to the redirect_uri from params.redirect_uri. + + +--------+ +------------+ +-------------------+ + | | | | | | + | Client | --> | MCP Server | --> | 3rd Party OAuth | + | | | | | Server | + +--------+ +------------+ +-------------------+ + | ^ | + +------------+ | | | + | | | | Redirect | + |redirect_uri|<-----+ +------------------+ + | | + +------------+ + + Implementations will need to define another handler on the MCP server return + flow to perform the second redirect, and generate and store an authorization + code as part of completing the OAuth authorization step. + + Implementations SHOULD generate an authorization code with at least 160 bits of + entropy, + and MUST generate an authorization code with at least 128 bits of entropy. + See https://datatracker.ietf.org/doc/html/rfc6749#section-10.10. + + Args: + client: The client requesting authorization. + params: The parameters of the authorization request. + + Returns: + A URL to redirect the client to for authorization. + + Raises: + AuthorizeError: If the authorization request is invalid. + """ + ... + + async def load_authorization_code( + self, client: OAuthClientInformationFull, authorization_code: str + ) -> AuthorizationCodeT | None: + """ + Loads an AuthorizationCode by its code. + + Args: + client: The client that requested the authorization code. + authorization_code: The authorization code to get the challenge for. + + Returns: + The AuthorizationCode, or None if not found + """ + ... + + async def exchange_authorization_code( + self, client: OAuthClientInformationFull, authorization_code: AuthorizationCodeT + ) -> OAuthToken: + """ + Exchanges an authorization code for an access token and refresh token. + + Args: + client: The client exchanging the authorization code. + authorization_code: The authorization code to exchange. + + Returns: + The OAuth token, containing access and refresh tokens. + + Raises: + TokenError: If the request is invalid + """ + ... + + async def load_refresh_token(self, client: OAuthClientInformationFull, refresh_token: str) -> RefreshTokenT | None: + """ + Loads a RefreshToken by its token string. + + Args: + client: The client that is requesting to load the refresh token. + refresh_token: The refresh token string to load. + + Returns: + The RefreshToken object if found, or None if not found. + """ + ... + + async def exchange_refresh_token( + self, + client: OAuthClientInformationFull, + refresh_token: RefreshTokenT, + scopes: list[str], + ) -> OAuthToken: + """ + Exchanges a refresh token for an access token and refresh token. + + Implementations SHOULD rotate both the access token and refresh token. + + Args: + client: The client exchanging the refresh token. + refresh_token: The refresh token to exchange. + scopes: Optional scopes to request with the new access token. + + Returns: + The OAuth token, containing access and refresh tokens. + + Raises: + TokenError: If the request is invalid + """ + ... + + async def load_access_token(self, token: str) -> AccessTokenT | None: + """ + Loads an access token by its token. + + Args: + token: The access token to verify. + + Returns: + The AuthInfo, or None if the token is invalid. + """ + + async def revoke_token( + self, + token: AccessTokenT | RefreshTokenT, + ) -> None: + """ + Revokes an access or refresh token. + + If the given token is invalid or already revoked, this method should do nothing. + + Implementations SHOULD revoke both the access token and its corresponding + refresh token, regardless of which of the access token or refresh token is + provided. + + Args: + token: the token to revoke + """ + + +def construct_redirect_uri(redirect_uri_base: str, **params: str | None) -> str: + parsed_uri = urlparse(redirect_uri_base) + query_params = [(k, v) for k, vs in parse_qs(parsed_uri.query).items() for v in vs] + for k, v in params.items(): + if v is not None: + query_params.append((k, v)) + + redirect_uri = urlunparse(parsed_uri._replace(query=urlencode(query_params))) + return redirect_uri + + +class ProviderTokenVerifier(TokenVerifier): + """Token verifier that uses an OAuthAuthorizationServerProvider. + + This is provided for backwards compatibility with existing auth_server_provider + configurations. For new implementations using AS/RS separation, consider using + the TokenVerifier protocol with a dedicated implementation like IntrospectionTokenVerifier. + """ + + def __init__(self, provider: "OAuthAuthorizationServerProvider[AuthorizationCode, RefreshToken, AccessToken]"): + self.provider = provider + + async def verify_token(self, token: str) -> AccessToken | None: + """Verify token using the provider's load_access_token method.""" + return await self.provider.load_access_token(token) diff --git a/source/target-vendors/cp312/mcp/server/auth/routes.py b/source/target-vendors/cp312/mcp/server/auth/routes.py new file mode 100644 index 0000000..71a9c8b --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/routes.py @@ -0,0 +1,253 @@ +from collections.abc import Awaitable, Callable +from typing import Any +from urllib.parse import urlparse + +from pydantic import AnyHttpUrl +from starlette.middleware.cors import CORSMiddleware +from starlette.requests import Request +from starlette.responses import Response +from starlette.routing import Route, request_response # type: ignore +from starlette.types import ASGIApp + +from mcp.server.auth.handlers.authorize import AuthorizationHandler +from mcp.server.auth.handlers.metadata import MetadataHandler +from mcp.server.auth.handlers.register import RegistrationHandler +from mcp.server.auth.handlers.revoke import RevocationHandler +from mcp.server.auth.handlers.token import TokenHandler +from mcp.server.auth.middleware.client_auth import ClientAuthenticator +from mcp.server.auth.provider import OAuthAuthorizationServerProvider +from mcp.server.auth.settings import ClientRegistrationOptions, RevocationOptions +from mcp.server.streamable_http import MCP_PROTOCOL_VERSION_HEADER +from mcp.shared.auth import OAuthMetadata + + +def validate_issuer_url(url: AnyHttpUrl): + """ + Validate that the issuer URL meets OAuth 2.0 requirements. + + Args: + url: The issuer URL to validate + + Raises: + ValueError: If the issuer URL is invalid + """ + + # RFC 8414 requires HTTPS, but we allow localhost HTTP for testing + if ( + url.scheme != "https" + and url.host != "localhost" + and (url.host is not None and not url.host.startswith("127.0.0.1")) + ): + raise ValueError("Issuer URL must be HTTPS") # pragma: no cover + + # No fragments or query parameters allowed + if url.fragment: + raise ValueError("Issuer URL must not have a fragment") # pragma: no cover + if url.query: + raise ValueError("Issuer URL must not have a query string") # pragma: no cover + + +AUTHORIZATION_PATH = "/authorize" +TOKEN_PATH = "/token" +REGISTRATION_PATH = "/register" +REVOCATION_PATH = "/revoke" + + +def cors_middleware( + handler: Callable[[Request], Response | Awaitable[Response]], + allow_methods: list[str], +) -> ASGIApp: + cors_app = CORSMiddleware( + app=request_response(handler), + allow_origins="*", + allow_methods=allow_methods, + allow_headers=[MCP_PROTOCOL_VERSION_HEADER], + ) + return cors_app + + +def create_auth_routes( + provider: OAuthAuthorizationServerProvider[Any, Any, Any], + issuer_url: AnyHttpUrl, + service_documentation_url: AnyHttpUrl | None = None, + client_registration_options: ClientRegistrationOptions | None = None, + revocation_options: RevocationOptions | None = None, +) -> list[Route]: + validate_issuer_url(issuer_url) + + client_registration_options = client_registration_options or ClientRegistrationOptions() + revocation_options = revocation_options or RevocationOptions() + metadata = build_metadata( + issuer_url, + service_documentation_url, + client_registration_options, + revocation_options, + ) + client_authenticator = ClientAuthenticator(provider) + + # Create routes + # Allow CORS requests for endpoints meant to be hit by the OAuth client + # (with the client secret). This is intended to support things like MCP Inspector, + # where the client runs in a web browser. + routes = [ + Route( + "/.well-known/oauth-authorization-server", + endpoint=cors_middleware( + MetadataHandler(metadata).handle, + ["GET", "OPTIONS"], + ), + methods=["GET", "OPTIONS"], + ), + Route( + AUTHORIZATION_PATH, + # do not allow CORS for authorization endpoint; + # clients should just redirect to this + endpoint=AuthorizationHandler(provider).handle, + methods=["GET", "POST"], + ), + Route( + TOKEN_PATH, + endpoint=cors_middleware( + TokenHandler(provider, client_authenticator).handle, + ["POST", "OPTIONS"], + ), + methods=["POST", "OPTIONS"], + ), + ] + + if client_registration_options.enabled: # pragma: no branch + registration_handler = RegistrationHandler( + provider, + options=client_registration_options, + ) + routes.append( + Route( + REGISTRATION_PATH, + endpoint=cors_middleware( + registration_handler.handle, + ["POST", "OPTIONS"], + ), + methods=["POST", "OPTIONS"], + ) + ) + + if revocation_options.enabled: # pragma: no branch + revocation_handler = RevocationHandler(provider, client_authenticator) + routes.append( + Route( + REVOCATION_PATH, + endpoint=cors_middleware( + revocation_handler.handle, + ["POST", "OPTIONS"], + ), + methods=["POST", "OPTIONS"], + ) + ) + + return routes + + +def build_metadata( + issuer_url: AnyHttpUrl, + service_documentation_url: AnyHttpUrl | None, + client_registration_options: ClientRegistrationOptions, + revocation_options: RevocationOptions, +) -> OAuthMetadata: + authorization_url = AnyHttpUrl(str(issuer_url).rstrip("/") + AUTHORIZATION_PATH) + token_url = AnyHttpUrl(str(issuer_url).rstrip("/") + TOKEN_PATH) + + # Create metadata + metadata = OAuthMetadata( + issuer=issuer_url, + authorization_endpoint=authorization_url, + token_endpoint=token_url, + scopes_supported=client_registration_options.valid_scopes, + response_types_supported=["code"], + response_modes_supported=None, + grant_types_supported=["authorization_code", "refresh_token"], + token_endpoint_auth_methods_supported=["client_secret_post", "client_secret_basic"], + token_endpoint_auth_signing_alg_values_supported=None, + service_documentation=service_documentation_url, + ui_locales_supported=None, + op_policy_uri=None, + op_tos_uri=None, + introspection_endpoint=None, + code_challenge_methods_supported=["S256"], + ) + + # Add registration endpoint if supported + if client_registration_options.enabled: # pragma: no branch + metadata.registration_endpoint = AnyHttpUrl(str(issuer_url).rstrip("/") + REGISTRATION_PATH) + + # Add revocation endpoint if supported + if revocation_options.enabled: # pragma: no branch + metadata.revocation_endpoint = AnyHttpUrl(str(issuer_url).rstrip("/") + REVOCATION_PATH) + metadata.revocation_endpoint_auth_methods_supported = ["client_secret_post", "client_secret_basic"] + + return metadata + + +def build_resource_metadata_url(resource_server_url: AnyHttpUrl) -> AnyHttpUrl: + """ + Build RFC 9728 compliant protected resource metadata URL. + + Inserts /.well-known/oauth-protected-resource between host and resource path + as specified in RFC 9728 §3.1. + + Args: + resource_server_url: The resource server URL (e.g., https://example.com/mcp) + + Returns: + The metadata URL (e.g., https://example.com/.well-known/oauth-protected-resource/mcp) + """ + parsed = urlparse(str(resource_server_url)) + # Handle trailing slash: if path is just "/", treat as empty + resource_path = parsed.path if parsed.path != "/" else "" + return AnyHttpUrl(f"{parsed.scheme}://{parsed.netloc}/.well-known/oauth-protected-resource{resource_path}") + + +def create_protected_resource_routes( + resource_url: AnyHttpUrl, + authorization_servers: list[AnyHttpUrl], + scopes_supported: list[str] | None = None, + resource_name: str | None = None, + resource_documentation: AnyHttpUrl | None = None, +) -> list[Route]: + """ + Create routes for OAuth 2.0 Protected Resource Metadata (RFC 9728). + + Args: + resource_url: The URL of this resource server + authorization_servers: List of authorization servers that can issue tokens + scopes_supported: Optional list of scopes supported by this resource + + Returns: + List of Starlette routes for protected resource metadata + """ + from mcp.server.auth.handlers.metadata import ProtectedResourceMetadataHandler + from mcp.shared.auth import ProtectedResourceMetadata + + metadata = ProtectedResourceMetadata( + resource=resource_url, + authorization_servers=authorization_servers, + scopes_supported=scopes_supported, + resource_name=resource_name, + resource_documentation=resource_documentation, + # bearer_methods_supported defaults to ["header"] in the model + ) + + handler = ProtectedResourceMetadataHandler(metadata) + + # RFC 9728 §3.1: Register route at /.well-known/oauth-protected-resource + resource path + metadata_url = build_resource_metadata_url(resource_url) + # Extract just the path part for route registration + parsed = urlparse(str(metadata_url)) + well_known_path = parsed.path + + return [ + Route( + well_known_path, + endpoint=cors_middleware(handler.handle, ["GET", "OPTIONS"]), + methods=["GET", "OPTIONS"], + ) + ] diff --git a/source/target-vendors/cp312/mcp/server/auth/settings.py b/source/target-vendors/cp312/mcp/server/auth/settings.py new file mode 100644 index 0000000..1649826 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/auth/settings.py @@ -0,0 +1,30 @@ +from pydantic import AnyHttpUrl, BaseModel, Field + + +class ClientRegistrationOptions(BaseModel): + enabled: bool = False + client_secret_expiry_seconds: int | None = None + valid_scopes: list[str] | None = None + default_scopes: list[str] | None = None + + +class RevocationOptions(BaseModel): + enabled: bool = False + + +class AuthSettings(BaseModel): + issuer_url: AnyHttpUrl = Field( + ..., + description="OAuth authorization server URL that issues tokens for this resource server.", + ) + service_documentation_url: AnyHttpUrl | None = None + client_registration_options: ClientRegistrationOptions | None = None + revocation_options: RevocationOptions | None = None + required_scopes: list[str] | None = None + + # Resource Server settings (when operating as RS only) + resource_server_url: AnyHttpUrl | None = Field( + ..., + description="The URL of the MCP server to be used as the resource identifier " + "and base route to look up OAuth Protected Resource Metadata.", + ) diff --git a/source/target-vendors/cp312/mcp/server/elicitation.py b/source/target-vendors/cp312/mcp/server/elicitation.py new file mode 100644 index 0000000..4919541 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/elicitation.py @@ -0,0 +1,190 @@ +"""Elicitation utilities for MCP servers.""" + +from __future__ import annotations + +import types +from collections.abc import Sequence +from typing import Generic, Literal, TypeVar, Union, get_args, get_origin + +from pydantic import BaseModel + +from mcp.server.session import ServerSession +from mcp.types import RequestId + +ElicitSchemaModelT = TypeVar("ElicitSchemaModelT", bound=BaseModel) + + +class AcceptedElicitation(BaseModel, Generic[ElicitSchemaModelT]): + """Result when user accepts the elicitation.""" + + action: Literal["accept"] = "accept" + data: ElicitSchemaModelT + + +class DeclinedElicitation(BaseModel): + """Result when user declines the elicitation.""" + + action: Literal["decline"] = "decline" + + +class CancelledElicitation(BaseModel): + """Result when user cancels the elicitation.""" + + action: Literal["cancel"] = "cancel" + + +ElicitationResult = AcceptedElicitation[ElicitSchemaModelT] | DeclinedElicitation | CancelledElicitation + + +class AcceptedUrlElicitation(BaseModel): + """Result when user accepts a URL mode elicitation.""" + + action: Literal["accept"] = "accept" + + +UrlElicitationResult = AcceptedUrlElicitation | DeclinedElicitation | CancelledElicitation + + +# Primitive types allowed in elicitation schemas +_ELICITATION_PRIMITIVE_TYPES = (str, int, float, bool) + + +def _validate_elicitation_schema(schema: type[BaseModel]) -> None: + """Validate that a Pydantic model only contains primitive field types.""" + for field_name, field_info in schema.model_fields.items(): + annotation = field_info.annotation + + if annotation is None or annotation is types.NoneType: # pragma: no cover + continue + elif _is_primitive_field(annotation): + continue + elif _is_string_sequence(annotation): + continue + else: + raise TypeError( + f"Elicitation schema field '{field_name}' must be a primitive type " + f"{_ELICITATION_PRIMITIVE_TYPES}, a sequence of strings (list[str], etc.), " + f"or Optional of these types. Nested models and complex types are not allowed." + ) + + +def _is_string_sequence(annotation: type) -> bool: + """Check if annotation is a sequence of strings (list[str], Sequence[str], etc).""" + origin = get_origin(annotation) + # Check if it's a sequence-like type with str elements + if origin: + try: + if issubclass(origin, Sequence): + args = get_args(annotation) + # Should have single str type arg + return len(args) == 1 and args[0] is str + except TypeError: # pragma: no cover + # origin is not a class, so it can't be a subclass of Sequence + pass + return False + + +def _is_primitive_field(annotation: type) -> bool: + """Check if a field is a primitive type allowed in elicitation schemas.""" + # Handle basic primitive types + if annotation in _ELICITATION_PRIMITIVE_TYPES: + return True + + # Handle Union types + origin = get_origin(annotation) + if origin is Union or origin is types.UnionType: + args = get_args(annotation) + # All args must be primitive types, None, or string sequences + return all( + arg is types.NoneType or arg in _ELICITATION_PRIMITIVE_TYPES or _is_string_sequence(arg) for arg in args + ) + + return False + + +async def elicit_with_validation( + session: ServerSession, + message: str, + schema: type[ElicitSchemaModelT], + related_request_id: RequestId | None = None, +) -> ElicitationResult[ElicitSchemaModelT]: + """Elicit information from the client/user with schema validation (form mode). + + This method can be used to interactively ask for additional information from the + client within a tool's execution. The client might display the message to the + user and collect a response according to the provided schema. Or in case a + client is an agent, it might decide how to handle the elicitation -- either by asking + the user or automatically generating a response. + + For sensitive data like credentials or OAuth flows, use elicit_url() instead. + """ + # Validate that schema only contains primitive types and fail loudly if not + _validate_elicitation_schema(schema) + + json_schema = schema.model_json_schema() + + result = await session.elicit_form( + message=message, + requestedSchema=json_schema, + related_request_id=related_request_id, + ) + + if result.action == "accept" and result.content is not None: + # Validate and parse the content using the schema + validated_data = schema.model_validate(result.content) + return AcceptedElicitation(data=validated_data) + elif result.action == "decline": + return DeclinedElicitation() + elif result.action == "cancel": # pragma: no cover + return CancelledElicitation() + else: # pragma: no cover + # This should never happen, but handle it just in case + raise ValueError(f"Unexpected elicitation action: {result.action}") + + +async def elicit_url( + session: ServerSession, + message: str, + url: str, + elicitation_id: str, + related_request_id: RequestId | None = None, +) -> UrlElicitationResult: + """Elicit information from the user via out-of-band URL navigation (URL mode). + + This method directs the user to an external URL where sensitive interactions can + occur without passing data through the MCP client. Use this for: + - Collecting sensitive credentials (API keys, passwords) + - OAuth authorization flows with third-party services + - Payment and subscription flows + - Any interaction where data should not pass through the LLM context + + The response indicates whether the user consented to navigate to the URL. + The actual interaction happens out-of-band. When the elicitation completes, + the server should send an ElicitCompleteNotification to notify the client. + + Args: + session: The server session + message: Human-readable explanation of why the interaction is needed + url: The URL the user should navigate to + elicitation_id: Unique identifier for tracking this elicitation + related_request_id: Optional ID of the request that triggered this elicitation + + Returns: + UrlElicitationResult indicating accept, decline, or cancel + """ + result = await session.elicit_url( + message=message, + url=url, + elicitation_id=elicitation_id, + related_request_id=related_request_id, + ) + + if result.action == "accept": + return AcceptedUrlElicitation() + elif result.action == "decline": + return DeclinedElicitation() + elif result.action == "cancel": + return CancelledElicitation() + else: # pragma: no cover + # This should never happen, but handle it just in case + raise ValueError(f"Unexpected elicitation action: {result.action}") diff --git a/source/target-vendors/cp312/mcp/server/experimental/__init__.py b/source/target-vendors/cp312/mcp/server/experimental/__init__.py new file mode 100644 index 0000000..824bb8b --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/experimental/__init__.py @@ -0,0 +1,11 @@ +""" +Server-side experimental features. + +WARNING: These APIs are experimental and may change without notice. + +Import directly from submodules: +- mcp.server.experimental.task_context.ServerTaskContext +- mcp.server.experimental.task_support.TaskSupport +- mcp.server.experimental.task_result_handler.TaskResultHandler +- mcp.server.experimental.request_context.Experimental +""" diff --git a/source/target-vendors/cp312/mcp/server/experimental/request_context.py b/source/target-vendors/cp312/mcp/server/experimental/request_context.py new file mode 100644 index 0000000..78e75be --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/experimental/request_context.py @@ -0,0 +1,238 @@ +""" +Experimental request context features. + +This module provides the Experimental class which gives access to experimental +features within a request context, such as task-augmented request handling. + +WARNING: These APIs are experimental and may change without notice. +""" + +from collections.abc import Awaitable, Callable +from dataclasses import dataclass, field +from typing import Any + +from mcp.server.experimental.task_context import ServerTaskContext +from mcp.server.experimental.task_support import TaskSupport +from mcp.server.session import ServerSession +from mcp.shared.exceptions import McpError +from mcp.shared.experimental.tasks.helpers import MODEL_IMMEDIATE_RESPONSE_KEY, is_terminal +from mcp.types import ( + METHOD_NOT_FOUND, + TASK_FORBIDDEN, + TASK_REQUIRED, + ClientCapabilities, + CreateTaskResult, + ErrorData, + Result, + TaskExecutionMode, + TaskMetadata, + Tool, +) + + +@dataclass +class Experimental: + """ + Experimental features context for task-augmented requests. + + Provides helpers for validating task execution compatibility and + running tasks with automatic lifecycle management. + + WARNING: This API is experimental and may change without notice. + """ + + task_metadata: TaskMetadata | None = None + _client_capabilities: ClientCapabilities | None = field(default=None, repr=False) + _session: ServerSession | None = field(default=None, repr=False) + _task_support: TaskSupport | None = field(default=None, repr=False) + + @property + def is_task(self) -> bool: + """Check if this request is task-augmented.""" + return self.task_metadata is not None + + @property + def client_supports_tasks(self) -> bool: + """Check if the client declared task support.""" + if self._client_capabilities is None: + return False + return self._client_capabilities.tasks is not None + + def validate_task_mode( + self, + tool_task_mode: TaskExecutionMode | None, + *, + raise_error: bool = True, + ) -> ErrorData | None: + """ + Validate that the request is compatible with the tool's task execution mode. + + Per MCP spec: + - "required": Clients MUST invoke as task. Server returns -32601 if not. + - "forbidden" (or None): Clients MUST NOT invoke as task. Server returns -32601 if they do. + - "optional": Either is acceptable. + + Args: + tool_task_mode: The tool's execution.taskSupport value + ("forbidden", "optional", "required", or None) + raise_error: If True, raises McpError on validation failure. If False, returns ErrorData. + + Returns: + None if valid, ErrorData if invalid and raise_error=False + + Raises: + McpError: If invalid and raise_error=True + """ + + mode = tool_task_mode or TASK_FORBIDDEN + + error: ErrorData | None = None + + if mode == TASK_REQUIRED and not self.is_task: + error = ErrorData( + code=METHOD_NOT_FOUND, + message="This tool requires task-augmented invocation", + ) + elif mode == TASK_FORBIDDEN and self.is_task: + error = ErrorData( + code=METHOD_NOT_FOUND, + message="This tool does not support task-augmented invocation", + ) + + if error is not None and raise_error: + raise McpError(error) + + return error + + def validate_for_tool( + self, + tool: Tool, + *, + raise_error: bool = True, + ) -> ErrorData | None: + """ + Validate that the request is compatible with the given tool. + + Convenience wrapper around validate_task_mode that extracts the mode from a Tool. + + Args: + tool: The Tool definition + raise_error: If True, raises McpError on validation failure. + + Returns: + None if valid, ErrorData if invalid and raise_error=False + """ + mode = tool.execution.taskSupport if tool.execution else None + return self.validate_task_mode(mode, raise_error=raise_error) + + def can_use_tool(self, tool_task_mode: TaskExecutionMode | None) -> bool: + """ + Check if this client can use a tool with the given task mode. + + Useful for filtering tool lists or providing warnings. + Returns False if tool requires "required" but client doesn't support tasks. + + Args: + tool_task_mode: The tool's execution.taskSupport value + + Returns: + True if the client can use this tool, False otherwise + """ + mode = tool_task_mode or TASK_FORBIDDEN + if mode == TASK_REQUIRED and not self.client_supports_tasks: + return False + return True + + async def run_task( + self, + work: Callable[[ServerTaskContext], Awaitable[Result]], + *, + task_id: str | None = None, + model_immediate_response: str | None = None, + ) -> CreateTaskResult: + """ + Create a task, spawn background work, and return CreateTaskResult immediately. + + This is the recommended way to handle task-augmented tool calls. It: + 1. Creates a task in the store + 2. Spawns the work function in a background task + 3. Returns CreateTaskResult immediately + + The work function receives a ServerTaskContext with: + - elicit() for sending elicitation requests + - create_message() for sampling requests + - update_status() for progress updates + - complete()/fail() for finishing the task + + When work() returns a Result, the task is auto-completed with that result. + If work() raises an exception, the task is auto-failed. + + Args: + work: Async function that does the actual work + task_id: Optional task ID (generated if not provided) + model_immediate_response: Optional string to include in _meta as + io.modelcontextprotocol/model-immediate-response + + Returns: + CreateTaskResult to return to the client + + Raises: + RuntimeError: If task support is not enabled or task_metadata is missing + + Example: + @server.call_tool() + async def handle_tool(name: str, args: dict): + ctx = server.request_context + + async def work(task: ServerTaskContext) -> CallToolResult: + result = await task.elicit( + message="Are you sure?", + requestedSchema={"type": "object", ...} + ) + confirmed = result.content.get("confirm", False) + return CallToolResult(content=[TextContent(text="Done" if confirmed else "Cancelled")]) + + return await ctx.experimental.run_task(work) + + WARNING: This API is experimental and may change without notice. + """ + if self._task_support is None: + raise RuntimeError("Task support not enabled. Call server.experimental.enable_tasks() first.") + if self._session is None: + raise RuntimeError("Session not available.") + if self.task_metadata is None: + raise RuntimeError( + "Request is not task-augmented (no task field in params). " + "The client must send a task-augmented request." + ) + + support = self._task_support + # Access task_group via TaskSupport - raises if not in run() context + task_group = support.task_group + + task = await support.store.create_task(self.task_metadata, task_id) + + task_ctx = ServerTaskContext( + task=task, + store=support.store, + session=self._session, + queue=support.queue, + handler=support.handler, + ) + + async def execute() -> None: + try: + result = await work(task_ctx) + if not is_terminal(task_ctx.task.status): + await task_ctx.complete(result) + except Exception as e: + if not is_terminal(task_ctx.task.status): + await task_ctx.fail(str(e)) + + task_group.start_soon(execute) + + meta: dict[str, Any] | None = None + if model_immediate_response is not None: + meta = {MODEL_IMMEDIATE_RESPONSE_KEY: model_immediate_response} + + return CreateTaskResult(task=task, **{"_meta": meta} if meta else {}) diff --git a/source/target-vendors/cp312/mcp/server/experimental/session_features.py b/source/target-vendors/cp312/mcp/server/experimental/session_features.py new file mode 100644 index 0000000..4842da5 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/experimental/session_features.py @@ -0,0 +1,220 @@ +""" +Experimental server session features for server→client task operations. + +This module provides the server-side equivalent of ExperimentalClientFeatures, +allowing the server to send task-augmented requests to the client and poll for results. + +WARNING: These APIs are experimental and may change without notice. +""" + +from collections.abc import AsyncIterator +from typing import TYPE_CHECKING, Any, TypeVar + +import mcp.types as types +from mcp.server.validation import validate_sampling_tools, validate_tool_use_result_messages +from mcp.shared.experimental.tasks.capabilities import ( + require_task_augmented_elicitation, + require_task_augmented_sampling, +) +from mcp.shared.experimental.tasks.polling import poll_until_terminal + +if TYPE_CHECKING: + from mcp.server.session import ServerSession + +ResultT = TypeVar("ResultT", bound=types.Result) + + +class ExperimentalServerSessionFeatures: + """ + Experimental server session features for server→client task operations. + + This provides the server-side equivalent of ExperimentalClientFeatures, + allowing the server to send task-augmented requests to the client and + poll for results. + + WARNING: These APIs are experimental and may change without notice. + + Access via session.experimental: + result = await session.experimental.elicit_as_task(...) + """ + + def __init__(self, session: "ServerSession") -> None: + self._session = session + + async def get_task(self, task_id: str) -> types.GetTaskResult: + """ + Send tasks/get to the client to get task status. + + Args: + task_id: The task identifier + + Returns: + GetTaskResult containing the task status + """ + return await self._session.send_request( + types.ServerRequest(types.GetTaskRequest(params=types.GetTaskRequestParams(taskId=task_id))), + types.GetTaskResult, + ) + + async def get_task_result( + self, + task_id: str, + result_type: type[ResultT], + ) -> ResultT: + """ + Send tasks/result to the client to retrieve the final result. + + Args: + task_id: The task identifier + result_type: The expected result type + + Returns: + The task result, validated against result_type + """ + return await self._session.send_request( + types.ServerRequest(types.GetTaskPayloadRequest(params=types.GetTaskPayloadRequestParams(taskId=task_id))), + result_type, + ) + + async def poll_task(self, task_id: str) -> AsyncIterator[types.GetTaskResult]: + """ + Poll a client task until it reaches terminal status. + + Yields GetTaskResult for each poll, allowing the caller to react to + status changes. Exits when task reaches a terminal status. + + Respects the pollInterval hint from the client. + + Args: + task_id: The task identifier + + Yields: + GetTaskResult for each poll + """ + async for status in poll_until_terminal(self.get_task, task_id): + yield status + + async def elicit_as_task( + self, + message: str, + requestedSchema: types.ElicitRequestedSchema, + *, + ttl: int = 60000, + ) -> types.ElicitResult: + """ + Send a task-augmented elicitation to the client and poll until complete. + + The client will create a local task, process the elicitation asynchronously, + and return the result when ready. This method handles the full flow: + 1. Send elicitation with task field + 2. Receive CreateTaskResult from client + 3. Poll client's task until terminal + 4. Retrieve and return the final ElicitResult + + Args: + message: The message to present to the user + requestedSchema: Schema defining the expected response + ttl: Task time-to-live in milliseconds + + Returns: + The client's elicitation response + + Raises: + McpError: If client doesn't support task-augmented elicitation + """ + client_caps = self._session.client_params.capabilities if self._session.client_params else None + require_task_augmented_elicitation(client_caps) + + create_result = await self._session.send_request( + types.ServerRequest( + types.ElicitRequest( + params=types.ElicitRequestFormParams( + message=message, + requestedSchema=requestedSchema, + task=types.TaskMetadata(ttl=ttl), + ) + ) + ), + types.CreateTaskResult, + ) + + task_id = create_result.task.taskId + + async for _ in self.poll_task(task_id): + pass + + return await self.get_task_result(task_id, types.ElicitResult) + + async def create_message_as_task( + self, + messages: list[types.SamplingMessage], + *, + max_tokens: int, + ttl: int = 60000, + system_prompt: str | None = None, + include_context: types.IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: types.ModelPreferences | None = None, + tools: list[types.Tool] | None = None, + tool_choice: types.ToolChoice | None = None, + ) -> types.CreateMessageResult: + """ + Send a task-augmented sampling request and poll until complete. + + The client will create a local task, process the sampling request + asynchronously, and return the result when ready. + + Args: + messages: The conversation messages for sampling + max_tokens: Maximum tokens in the response + ttl: Task time-to-live in milliseconds + system_prompt: Optional system prompt + include_context: Context inclusion strategy + temperature: Sampling temperature + stop_sequences: Stop sequences + metadata: Additional metadata + model_preferences: Model selection preferences + tools: Optional list of tools the LLM can use during sampling + tool_choice: Optional control over tool usage behavior + + Returns: + The sampling result from the client + + Raises: + McpError: If client doesn't support task-augmented sampling or tools + ValueError: If tool_use or tool_result message structure is invalid + """ + client_caps = self._session.client_params.capabilities if self._session.client_params else None + require_task_augmented_sampling(client_caps) + validate_sampling_tools(client_caps, tools, tool_choice) + validate_tool_use_result_messages(messages) + + create_result = await self._session.send_request( + types.ServerRequest( + types.CreateMessageRequest( + params=types.CreateMessageRequestParams( + messages=messages, + maxTokens=max_tokens, + systemPrompt=system_prompt, + includeContext=include_context, + temperature=temperature, + stopSequences=stop_sequences, + metadata=metadata, + modelPreferences=model_preferences, + tools=tools, + toolChoice=tool_choice, + task=types.TaskMetadata(ttl=ttl), + ) + ) + ), + types.CreateTaskResult, + ) + + task_id = create_result.task.taskId + + async for _ in self.poll_task(task_id): + pass + + return await self.get_task_result(task_id, types.CreateMessageResult) diff --git a/source/target-vendors/cp312/mcp/server/experimental/task_context.py b/source/target-vendors/cp312/mcp/server/experimental/task_context.py new file mode 100644 index 0000000..e6e14fc --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/experimental/task_context.py @@ -0,0 +1,612 @@ +""" +ServerTaskContext - Server-integrated task context with elicitation and sampling. + +This wraps the pure TaskContext and adds server-specific functionality: +- Elicitation (task.elicit()) +- Sampling (task.create_message()) +- Status notifications +""" + +from typing import Any + +import anyio + +from mcp.server.experimental.task_result_handler import TaskResultHandler +from mcp.server.session import ServerSession +from mcp.server.validation import validate_sampling_tools, validate_tool_use_result_messages +from mcp.shared.exceptions import McpError +from mcp.shared.experimental.tasks.capabilities import ( + require_task_augmented_elicitation, + require_task_augmented_sampling, +) +from mcp.shared.experimental.tasks.context import TaskContext +from mcp.shared.experimental.tasks.message_queue import QueuedMessage, TaskMessageQueue +from mcp.shared.experimental.tasks.resolver import Resolver +from mcp.shared.experimental.tasks.store import TaskStore +from mcp.types import ( + INVALID_REQUEST, + TASK_STATUS_INPUT_REQUIRED, + TASK_STATUS_WORKING, + ClientCapabilities, + CreateMessageResult, + CreateTaskResult, + ElicitationCapability, + ElicitRequestedSchema, + ElicitResult, + ErrorData, + IncludeContext, + ModelPreferences, + RequestId, + Result, + SamplingCapability, + SamplingMessage, + ServerNotification, + Task, + TaskMetadata, + TaskStatusNotification, + TaskStatusNotificationParams, + Tool, + ToolChoice, +) + + +class ServerTaskContext: + """ + Server-integrated task context with elicitation and sampling. + + This wraps a pure TaskContext and adds server-specific functionality: + - elicit() for sending elicitation requests to the client + - create_message() for sampling requests + - Status notifications via the session + + Example: + async def my_task_work(task: ServerTaskContext) -> CallToolResult: + await task.update_status("Starting...") + + result = await task.elicit( + message="Continue?", + requestedSchema={"type": "object", "properties": {"ok": {"type": "boolean"}}} + ) + + if result.content.get("ok"): + return CallToolResult(content=[TextContent(text="Done!")]) + else: + return CallToolResult(content=[TextContent(text="Cancelled")]) + """ + + def __init__( + self, + *, + task: Task, + store: TaskStore, + session: ServerSession, + queue: TaskMessageQueue, + handler: TaskResultHandler | None = None, + ): + """ + Create a ServerTaskContext. + + Args: + task: The Task object + store: The task store + session: The server session + queue: The message queue for elicitation/sampling + handler: The result handler for response routing (required for elicit/create_message) + """ + self._ctx = TaskContext(task=task, store=store) + self._session = session + self._queue = queue + self._handler = handler + self._store = store + + # Delegate pure properties to inner context + + @property + def task_id(self) -> str: + """The task identifier.""" + return self._ctx.task_id + + @property + def task(self) -> Task: + """The current task state.""" + return self._ctx.task + + @property + def is_cancelled(self) -> bool: + """Whether cancellation has been requested.""" + return self._ctx.is_cancelled + + def request_cancellation(self) -> None: + """Request cancellation of this task.""" + self._ctx.request_cancellation() + + # Enhanced methods with notifications + + async def update_status(self, message: str, *, notify: bool = True) -> None: + """ + Update the task's status message. + + Args: + message: The new status message + notify: Whether to send a notification to the client + """ + await self._ctx.update_status(message) + if notify: + await self._send_notification() + + async def complete(self, result: Result, *, notify: bool = True) -> None: + """ + Mark the task as completed with the given result. + + Args: + result: The task result + notify: Whether to send a notification to the client + """ + await self._ctx.complete(result) + if notify: + await self._send_notification() + + async def fail(self, error: str, *, notify: bool = True) -> None: + """ + Mark the task as failed with an error message. + + Args: + error: The error message + notify: Whether to send a notification to the client + """ + await self._ctx.fail(error) + if notify: + await self._send_notification() + + async def _send_notification(self) -> None: + """Send a task status notification to the client.""" + task = self._ctx.task + await self._session.send_notification( + ServerNotification( + TaskStatusNotification( + params=TaskStatusNotificationParams( + taskId=task.taskId, + status=task.status, + statusMessage=task.statusMessage, + createdAt=task.createdAt, + lastUpdatedAt=task.lastUpdatedAt, + ttl=task.ttl, + pollInterval=task.pollInterval, + ) + ) + ) + ) + + # Server-specific methods: elicitation and sampling + + def _check_elicitation_capability(self) -> None: + """Check if the client supports elicitation.""" + if not self._session.check_client_capability(ClientCapabilities(elicitation=ElicitationCapability())): + raise McpError( + ErrorData( + code=INVALID_REQUEST, + message="Client does not support elicitation capability", + ) + ) + + def _check_sampling_capability(self) -> None: + """Check if the client supports sampling.""" + if not self._session.check_client_capability(ClientCapabilities(sampling=SamplingCapability())): + raise McpError( + ErrorData( + code=INVALID_REQUEST, + message="Client does not support sampling capability", + ) + ) + + async def elicit( + self, + message: str, + requestedSchema: ElicitRequestedSchema, + ) -> ElicitResult: + """ + Send an elicitation request via the task message queue. + + This method: + 1. Checks client capability + 2. Updates task status to "input_required" + 3. Queues the elicitation request + 4. Waits for the response (delivered via tasks/result round-trip) + 5. Updates task status back to "working" + 6. Returns the result + + Args: + message: The message to present to the user + requestedSchema: Schema defining the expected response structure + + Returns: + The client's response + + Raises: + McpError: If client doesn't support elicitation capability + """ + self._check_elicitation_capability() + + if self._handler is None: + raise RuntimeError("handler is required for elicit(). Pass handler= to ServerTaskContext.") + + # Update status to input_required + await self._store.update_task(self.task_id, status=TASK_STATUS_INPUT_REQUIRED) + + # Build the request using session's helper + request = self._session._build_elicit_form_request( # pyright: ignore[reportPrivateUsage] + message=message, + requestedSchema=requestedSchema, + related_task_id=self.task_id, + ) + request_id: RequestId = request.id + + resolver: Resolver[dict[str, Any]] = Resolver() + self._handler._pending_requests[request_id] = resolver # pyright: ignore[reportPrivateUsage] + + queued = QueuedMessage( + type="request", + message=request, + resolver=resolver, + original_request_id=request_id, + ) + await self._queue.enqueue(self.task_id, queued) + + try: + # Wait for response (routed back via TaskResultHandler) + response_data = await resolver.wait() + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + return ElicitResult.model_validate(response_data) + except anyio.get_cancelled_exc_class(): # pragma: no cover + # Coverage can't track async exception handlers reliably. + # This path is tested in test_elicit_restores_status_on_cancellation + # which verifies status is restored to "working" after cancellation. + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + raise + + async def elicit_url( + self, + message: str, + url: str, + elicitation_id: str, + ) -> ElicitResult: + """ + Send a URL mode elicitation request via the task message queue. + + This directs the user to an external URL for out-of-band interactions + like OAuth flows, credential collection, or payment processing. + + This method: + 1. Checks client capability + 2. Updates task status to "input_required" + 3. Queues the elicitation request + 4. Waits for the response (delivered via tasks/result round-trip) + 5. Updates task status back to "working" + 6. Returns the result + + Args: + message: Human-readable explanation of why the interaction is needed + url: The URL the user should navigate to + elicitation_id: Unique identifier for tracking this elicitation + + Returns: + The client's response indicating acceptance, decline, or cancellation + + Raises: + McpError: If client doesn't support elicitation capability + RuntimeError: If handler is not configured + """ + self._check_elicitation_capability() + + if self._handler is None: + raise RuntimeError("handler is required for elicit_url(). Pass handler= to ServerTaskContext.") + + # Update status to input_required + await self._store.update_task(self.task_id, status=TASK_STATUS_INPUT_REQUIRED) + + # Build the request using session's helper + request = self._session._build_elicit_url_request( # pyright: ignore[reportPrivateUsage] + message=message, + url=url, + elicitation_id=elicitation_id, + related_task_id=self.task_id, + ) + request_id: RequestId = request.id + + resolver: Resolver[dict[str, Any]] = Resolver() + self._handler._pending_requests[request_id] = resolver # pyright: ignore[reportPrivateUsage] + + queued = QueuedMessage( + type="request", + message=request, + resolver=resolver, + original_request_id=request_id, + ) + await self._queue.enqueue(self.task_id, queued) + + try: + # Wait for response (routed back via TaskResultHandler) + response_data = await resolver.wait() + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + return ElicitResult.model_validate(response_data) + except anyio.get_cancelled_exc_class(): # pragma: no cover + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + raise + + async def create_message( + self, + messages: list[SamplingMessage], + *, + max_tokens: int, + system_prompt: str | None = None, + include_context: IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: ModelPreferences | None = None, + tools: list[Tool] | None = None, + tool_choice: ToolChoice | None = None, + ) -> CreateMessageResult: + """ + Send a sampling request via the task message queue. + + This method: + 1. Checks client capability + 2. Updates task status to "input_required" + 3. Queues the sampling request + 4. Waits for the response (delivered via tasks/result round-trip) + 5. Updates task status back to "working" + 6. Returns the result + + Args: + messages: The conversation messages for sampling + max_tokens: Maximum tokens in the response + system_prompt: Optional system prompt + include_context: Context inclusion strategy + temperature: Sampling temperature + stop_sequences: Stop sequences + metadata: Additional metadata + model_preferences: Model selection preferences + tools: Optional list of tools the LLM can use during sampling + tool_choice: Optional control over tool usage behavior + + Returns: + The sampling result from the client + + Raises: + McpError: If client doesn't support sampling capability or tools + ValueError: If tool_use or tool_result message structure is invalid + """ + self._check_sampling_capability() + client_caps = self._session.client_params.capabilities if self._session.client_params else None + validate_sampling_tools(client_caps, tools, tool_choice) + validate_tool_use_result_messages(messages) + + if self._handler is None: + raise RuntimeError("handler is required for create_message(). Pass handler= to ServerTaskContext.") + + # Update status to input_required + await self._store.update_task(self.task_id, status=TASK_STATUS_INPUT_REQUIRED) + + # Build the request using session's helper + request = self._session._build_create_message_request( # pyright: ignore[reportPrivateUsage] + messages=messages, + max_tokens=max_tokens, + system_prompt=system_prompt, + include_context=include_context, + temperature=temperature, + stop_sequences=stop_sequences, + metadata=metadata, + model_preferences=model_preferences, + tools=tools, + tool_choice=tool_choice, + related_task_id=self.task_id, + ) + request_id: RequestId = request.id + + resolver: Resolver[dict[str, Any]] = Resolver() + self._handler._pending_requests[request_id] = resolver # pyright: ignore[reportPrivateUsage] + + queued = QueuedMessage( + type="request", + message=request, + resolver=resolver, + original_request_id=request_id, + ) + await self._queue.enqueue(self.task_id, queued) + + try: + # Wait for response (routed back via TaskResultHandler) + response_data = await resolver.wait() + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + return CreateMessageResult.model_validate(response_data) + except anyio.get_cancelled_exc_class(): # pragma: no cover + # Coverage can't track async exception handlers reliably. + # This path is tested in test_create_message_restores_status_on_cancellation + # which verifies status is restored to "working" after cancellation. + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + raise + + async def elicit_as_task( + self, + message: str, + requestedSchema: ElicitRequestedSchema, + *, + ttl: int = 60000, + ) -> ElicitResult: + """ + Send a task-augmented elicitation via the queue, then poll client. + + This is for use inside a task-augmented tool call when you want the client + to handle the elicitation as its own task. The elicitation request is queued + and delivered when the client calls tasks/result. After the client responds + with CreateTaskResult, we poll the client's task until complete. + + Args: + message: The message to present to the user + requestedSchema: Schema defining the expected response structure + ttl: Task time-to-live in milliseconds for the client's task + + Returns: + The client's elicitation response + + Raises: + McpError: If client doesn't support task-augmented elicitation + RuntimeError: If handler is not configured + """ + client_caps = self._session.client_params.capabilities if self._session.client_params else None + require_task_augmented_elicitation(client_caps) + + if self._handler is None: + raise RuntimeError("handler is required for elicit_as_task()") + + # Update status to input_required + await self._store.update_task(self.task_id, status=TASK_STATUS_INPUT_REQUIRED) + + request = self._session._build_elicit_form_request( # pyright: ignore[reportPrivateUsage] + message=message, + requestedSchema=requestedSchema, + related_task_id=self.task_id, + task=TaskMetadata(ttl=ttl), + ) + request_id: RequestId = request.id + + resolver: Resolver[dict[str, Any]] = Resolver() + self._handler._pending_requests[request_id] = resolver # pyright: ignore[reportPrivateUsage] + + queued = QueuedMessage( + type="request", + message=request, + resolver=resolver, + original_request_id=request_id, + ) + await self._queue.enqueue(self.task_id, queued) + + try: + # Wait for initial response (CreateTaskResult from client) + response_data = await resolver.wait() + create_result = CreateTaskResult.model_validate(response_data) + client_task_id = create_result.task.taskId + + # Poll the client's task using session.experimental + async for _ in self._session.experimental.poll_task(client_task_id): + pass + + # Get final result from client + result = await self._session.experimental.get_task_result( + client_task_id, + ElicitResult, + ) + + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + return result + + except anyio.get_cancelled_exc_class(): # pragma: no cover + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + raise + + async def create_message_as_task( + self, + messages: list[SamplingMessage], + *, + max_tokens: int, + ttl: int = 60000, + system_prompt: str | None = None, + include_context: IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: ModelPreferences | None = None, + tools: list[Tool] | None = None, + tool_choice: ToolChoice | None = None, + ) -> CreateMessageResult: + """ + Send a task-augmented sampling request via the queue, then poll client. + + This is for use inside a task-augmented tool call when you want the client + to handle the sampling as its own task. The request is queued and delivered + when the client calls tasks/result. After the client responds with + CreateTaskResult, we poll the client's task until complete. + + Args: + messages: The conversation messages for sampling + max_tokens: Maximum tokens in the response + ttl: Task time-to-live in milliseconds for the client's task + system_prompt: Optional system prompt + include_context: Context inclusion strategy + temperature: Sampling temperature + stop_sequences: Stop sequences + metadata: Additional metadata + model_preferences: Model selection preferences + tools: Optional list of tools the LLM can use during sampling + tool_choice: Optional control over tool usage behavior + + Returns: + The sampling result from the client + + Raises: + McpError: If client doesn't support task-augmented sampling or tools + ValueError: If tool_use or tool_result message structure is invalid + RuntimeError: If handler is not configured + """ + client_caps = self._session.client_params.capabilities if self._session.client_params else None + require_task_augmented_sampling(client_caps) + validate_sampling_tools(client_caps, tools, tool_choice) + validate_tool_use_result_messages(messages) + + if self._handler is None: + raise RuntimeError("handler is required for create_message_as_task()") + + # Update status to input_required + await self._store.update_task(self.task_id, status=TASK_STATUS_INPUT_REQUIRED) + + # Build request WITH task field for task-augmented sampling + request = self._session._build_create_message_request( # pyright: ignore[reportPrivateUsage] + messages=messages, + max_tokens=max_tokens, + system_prompt=system_prompt, + include_context=include_context, + temperature=temperature, + stop_sequences=stop_sequences, + metadata=metadata, + model_preferences=model_preferences, + tools=tools, + tool_choice=tool_choice, + related_task_id=self.task_id, + task=TaskMetadata(ttl=ttl), + ) + request_id: RequestId = request.id + + resolver: Resolver[dict[str, Any]] = Resolver() + self._handler._pending_requests[request_id] = resolver # pyright: ignore[reportPrivateUsage] + + queued = QueuedMessage( + type="request", + message=request, + resolver=resolver, + original_request_id=request_id, + ) + await self._queue.enqueue(self.task_id, queued) + + try: + # Wait for initial response (CreateTaskResult from client) + response_data = await resolver.wait() + create_result = CreateTaskResult.model_validate(response_data) + client_task_id = create_result.task.taskId + + # Poll the client's task using session.experimental + async for _ in self._session.experimental.poll_task(client_task_id): + pass + + # Get final result from client + result = await self._session.experimental.get_task_result( + client_task_id, + CreateMessageResult, + ) + + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + return result + + except anyio.get_cancelled_exc_class(): # pragma: no cover + await self._store.update_task(self.task_id, status=TASK_STATUS_WORKING) + raise diff --git a/source/target-vendors/cp312/mcp/server/experimental/task_result_handler.py b/source/target-vendors/cp312/mcp/server/experimental/task_result_handler.py new file mode 100644 index 0000000..0b86921 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/experimental/task_result_handler.py @@ -0,0 +1,235 @@ +""" +TaskResultHandler - Integrated handler for tasks/result endpoint. + +This implements the dequeue-send-wait pattern from the MCP Tasks spec: +1. Dequeue all pending messages for the task +2. Send them to the client via transport with relatedRequestId routing +3. Wait if task is not in terminal state +4. Return final result when task completes + +This is the core of the task message queue pattern. +""" + +import logging +from typing import Any + +import anyio + +from mcp.server.session import ServerSession +from mcp.shared.exceptions import McpError +from mcp.shared.experimental.tasks.helpers import RELATED_TASK_METADATA_KEY, is_terminal +from mcp.shared.experimental.tasks.message_queue import TaskMessageQueue +from mcp.shared.experimental.tasks.resolver import Resolver +from mcp.shared.experimental.tasks.store import TaskStore +from mcp.shared.message import ServerMessageMetadata, SessionMessage +from mcp.types import ( + INVALID_PARAMS, + ErrorData, + GetTaskPayloadRequest, + GetTaskPayloadResult, + JSONRPCMessage, + RelatedTaskMetadata, + RequestId, +) + +logger = logging.getLogger(__name__) + + +class TaskResultHandler: + """ + Handler for tasks/result that implements the message queue pattern. + + This handler: + 1. Dequeues pending messages (elicitations, notifications) for the task + 2. Sends them to the client via the response stream + 3. Waits for responses and resolves them back to callers + 4. Blocks until task reaches terminal state + 5. Returns the final result + + Usage: + # Create handler with store and queue + handler = TaskResultHandler(task_store, message_queue) + + # Register it with the server + @server.experimental.get_task_result() + async def handle_task_result(req: GetTaskPayloadRequest) -> GetTaskPayloadResult: + ctx = server.request_context + return await handler.handle(req, ctx.session, ctx.request_id) + + # Or use the convenience method + handler.register(server) + """ + + def __init__( + self, + store: TaskStore, + queue: TaskMessageQueue, + ): + self._store = store + self._queue = queue + # Map from internal request ID to resolver for routing responses + self._pending_requests: dict[RequestId, Resolver[dict[str, Any]]] = {} + + async def send_message( + self, + session: ServerSession, + message: SessionMessage, + ) -> None: + """ + Send a message via the session. + + This is a helper for delivering queued task messages. + """ + await session.send_message(message) + + async def handle( + self, + request: GetTaskPayloadRequest, + session: ServerSession, + request_id: RequestId, + ) -> GetTaskPayloadResult: + """ + Handle a tasks/result request. + + This implements the dequeue-send-wait loop: + 1. Dequeue all pending messages + 2. Send each via transport with relatedRequestId = this request's ID + 3. If task not terminal, wait for status change + 4. Loop until task is terminal + 5. Return final result + + Args: + request: The GetTaskPayloadRequest + session: The server session for sending messages + request_id: The request ID for relatedRequestId routing + + Returns: + GetTaskPayloadResult with the task's final payload + """ + task_id = request.params.taskId + + while True: + task = await self._store.get_task(task_id) + if task is None: + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message=f"Task not found: {task_id}", + ) + ) + + await self._deliver_queued_messages(task_id, session, request_id) + + # If task is terminal, return result + if is_terminal(task.status): + result = await self._store.get_result(task_id) + # GetTaskPayloadResult is a Result with extra="allow" + # The stored result contains the actual payload data + # Per spec: tasks/result MUST include _meta with related-task metadata + related_task = RelatedTaskMetadata(taskId=task_id) + related_task_meta: dict[str, Any] = {RELATED_TASK_METADATA_KEY: related_task.model_dump(by_alias=True)} + if result is not None: + result_data = result.model_dump(by_alias=True) + existing_meta: dict[str, Any] = result_data.get("_meta") or {} + result_data["_meta"] = {**existing_meta, **related_task_meta} + return GetTaskPayloadResult.model_validate(result_data) + return GetTaskPayloadResult.model_validate({"_meta": related_task_meta}) + + # Wait for task update (status change or new messages) + await self._wait_for_task_update(task_id) + + async def _deliver_queued_messages( + self, + task_id: str, + session: ServerSession, + request_id: RequestId, + ) -> None: + """ + Dequeue and send all pending messages for a task. + + Each message is sent via the session's write stream with + relatedRequestId set so responses route back to this stream. + """ + while True: + message = await self._queue.dequeue(task_id) + if message is None: + break + + # If this is a request (not notification), wait for response + if message.type == "request" and message.resolver is not None: + # Store the resolver so we can route the response back + original_id = message.original_request_id + if original_id is not None: + self._pending_requests[original_id] = message.resolver + + logger.debug("Delivering queued message for task %s: %s", task_id, message.type) + + # Send the message with relatedRequestId for routing + session_message = SessionMessage( + message=JSONRPCMessage(message.message), + metadata=ServerMessageMetadata(related_request_id=request_id), + ) + await self.send_message(session, session_message) + + async def _wait_for_task_update(self, task_id: str) -> None: + """ + Wait for task to be updated (status change or new message). + + Races between store update and queue message - first one wins. + """ + async with anyio.create_task_group() as tg: + + async def wait_for_store() -> None: + try: + await self._store.wait_for_update(task_id) + except Exception: + pass + finally: + tg.cancel_scope.cancel() + + async def wait_for_queue() -> None: + try: + await self._queue.wait_for_message(task_id) + except Exception: + pass + finally: + tg.cancel_scope.cancel() + + tg.start_soon(wait_for_store) + tg.start_soon(wait_for_queue) + + def route_response(self, request_id: RequestId, response: dict[str, Any]) -> bool: + """ + Route a response back to the waiting resolver. + + This is called when a response arrives for a queued request. + + Args: + request_id: The request ID from the response + response: The response data + + Returns: + True if response was routed, False if no pending request + """ + resolver = self._pending_requests.pop(request_id, None) + if resolver is not None and not resolver.done(): + resolver.set_result(response) + return True + return False + + def route_error(self, request_id: RequestId, error: ErrorData) -> bool: + """ + Route an error back to the waiting resolver. + + Args: + request_id: The request ID from the error response + error: The error data + + Returns: + True if error was routed, False if no pending request + """ + resolver = self._pending_requests.pop(request_id, None) + if resolver is not None and not resolver.done(): + resolver.set_exception(McpError(error)) + return True + return False diff --git a/source/target-vendors/cp312/mcp/server/experimental/task_support.py b/source/target-vendors/cp312/mcp/server/experimental/task_support.py new file mode 100644 index 0000000..dbb2ed6 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/experimental/task_support.py @@ -0,0 +1,115 @@ +""" +TaskSupport - Configuration for experimental task support. + +This module provides the TaskSupport class which encapsulates all the +infrastructure needed for task-augmented requests: store, queue, and handler. +""" + +from collections.abc import AsyncIterator +from contextlib import asynccontextmanager +from dataclasses import dataclass, field + +import anyio +from anyio.abc import TaskGroup + +from mcp.server.experimental.task_result_handler import TaskResultHandler +from mcp.server.session import ServerSession +from mcp.shared.experimental.tasks.in_memory_task_store import InMemoryTaskStore +from mcp.shared.experimental.tasks.message_queue import InMemoryTaskMessageQueue, TaskMessageQueue +from mcp.shared.experimental.tasks.store import TaskStore + + +@dataclass +class TaskSupport: + """ + Configuration for experimental task support. + + Encapsulates the task store, message queue, result handler, and task group + for spawning background work. + + When enabled on a server, this automatically: + - Configures response routing for each session + - Provides default handlers for task operations + - Manages a task group for background task execution + + Example: + # Simple in-memory setup + server.experimental.enable_tasks() + + # Custom store/queue for distributed systems + server.experimental.enable_tasks( + store=RedisTaskStore(redis_url), + queue=RedisTaskMessageQueue(redis_url), + ) + """ + + store: TaskStore + queue: TaskMessageQueue + handler: TaskResultHandler = field(init=False) + _task_group: TaskGroup | None = field(init=False, default=None) + + def __post_init__(self) -> None: + """Create the result handler from store and queue.""" + self.handler = TaskResultHandler(self.store, self.queue) + + @property + def task_group(self) -> TaskGroup: + """Get the task group for spawning background work. + + Raises: + RuntimeError: If not within a run() context + """ + if self._task_group is None: + raise RuntimeError("TaskSupport not running. Ensure Server.run() is active.") + return self._task_group + + @asynccontextmanager + async def run(self) -> AsyncIterator[None]: + """ + Run the task support lifecycle. + + This creates a task group for spawning background task work. + Called automatically by Server.run(). + + Usage: + async with task_support.run(): + # Task group is now available + ... + """ + async with anyio.create_task_group() as tg: + self._task_group = tg + try: + yield + finally: + self._task_group = None + + def configure_session(self, session: ServerSession) -> None: + """ + Configure a session for task support. + + This registers the result handler as a response router so that + responses to queued requests (elicitation, sampling) are routed + back to the waiting resolvers. + + Called automatically by Server.run() for each new session. + + Args: + session: The session to configure + """ + session.add_response_router(self.handler) + + @classmethod + def in_memory(cls) -> "TaskSupport": + """ + Create in-memory task support. + + Suitable for development, testing, and single-process servers. + For distributed systems, provide custom store and queue implementations. + + Returns: + TaskSupport configured with in-memory store and queue + """ + return cls( + store=InMemoryTaskStore(), + queue=InMemoryTaskMessageQueue(), + ) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/__init__.py b/source/target-vendors/cp312/mcp/server/fastmcp/__init__.py new file mode 100644 index 0000000..a89902c --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/__init__.py @@ -0,0 +1,11 @@ +"""FastMCP - A more ergonomic interface for MCP servers.""" + +from importlib.metadata import version + +from mcp.types import Icon + +from .server import Context, FastMCP +from .utilities.types import Audio, Image + +__version__ = version("mcp") +__all__ = ["FastMCP", "Context", "Image", "Audio", "Icon"] diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/exceptions.py b/source/target-vendors/cp312/mcp/server/fastmcp/exceptions.py new file mode 100644 index 0000000..fb5bda1 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/exceptions.py @@ -0,0 +1,21 @@ +"""Custom exceptions for FastMCP.""" + + +class FastMCPError(Exception): + """Base error for FastMCP.""" + + +class ValidationError(FastMCPError): + """Error in validating parameters or return values.""" + + +class ResourceError(FastMCPError): + """Error in resource operations.""" + + +class ToolError(FastMCPError): + """Error in tool operations.""" + + +class InvalidSignature(Exception): + """Invalid signature for use with FastMCP.""" diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/prompts/__init__.py b/source/target-vendors/cp312/mcp/server/fastmcp/prompts/__init__.py new file mode 100644 index 0000000..7637269 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/prompts/__init__.py @@ -0,0 +1,4 @@ +from .base import Prompt +from .manager import PromptManager + +__all__ = ["Prompt", "PromptManager"] diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/prompts/base.py b/source/target-vendors/cp312/mcp/server/fastmcp/prompts/base.py new file mode 100644 index 0000000..48c65b5 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/prompts/base.py @@ -0,0 +1,183 @@ +"""Base classes for FastMCP prompts.""" + +from __future__ import annotations + +import inspect +from collections.abc import Awaitable, Callable, Sequence +from typing import TYPE_CHECKING, Any, Literal + +import pydantic_core +from pydantic import BaseModel, Field, TypeAdapter, validate_call + +from mcp.server.fastmcp.utilities.context_injection import find_context_parameter, inject_context +from mcp.server.fastmcp.utilities.func_metadata import func_metadata +from mcp.types import ContentBlock, Icon, TextContent + +if TYPE_CHECKING: + from mcp.server.fastmcp.server import Context + from mcp.server.session import ServerSessionT + from mcp.shared.context import LifespanContextT, RequestT + + +class Message(BaseModel): + """Base class for all prompt messages.""" + + role: Literal["user", "assistant"] + content: ContentBlock + + def __init__(self, content: str | ContentBlock, **kwargs: Any): + if isinstance(content, str): + content = TextContent(type="text", text=content) + super().__init__(content=content, **kwargs) + + +class UserMessage(Message): + """A message from the user.""" + + role: Literal["user", "assistant"] = "user" + + def __init__(self, content: str | ContentBlock, **kwargs: Any): + super().__init__(content=content, **kwargs) + + +class AssistantMessage(Message): + """A message from the assistant.""" + + role: Literal["user", "assistant"] = "assistant" + + def __init__(self, content: str | ContentBlock, **kwargs: Any): + super().__init__(content=content, **kwargs) + + +message_validator = TypeAdapter[UserMessage | AssistantMessage](UserMessage | AssistantMessage) + +SyncPromptResult = str | Message | dict[str, Any] | Sequence[str | Message | dict[str, Any]] +PromptResult = SyncPromptResult | Awaitable[SyncPromptResult] + + +class PromptArgument(BaseModel): + """An argument that can be passed to a prompt.""" + + name: str = Field(description="Name of the argument") + description: str | None = Field(None, description="Description of what the argument does") + required: bool = Field(default=False, description="Whether the argument is required") + + +class Prompt(BaseModel): + """A prompt template that can be rendered with parameters.""" + + name: str = Field(description="Name of the prompt") + title: str | None = Field(None, description="Human-readable title of the prompt") + description: str | None = Field(None, description="Description of what the prompt does") + arguments: list[PromptArgument] | None = Field(None, description="Arguments that can be passed to the prompt") + fn: Callable[..., PromptResult | Awaitable[PromptResult]] = Field(exclude=True) + icons: list[Icon] | None = Field(default=None, description="Optional list of icons for this prompt") + context_kwarg: str | None = Field(None, description="Name of the kwarg that should receive context", exclude=True) + + @classmethod + def from_function( + cls, + fn: Callable[..., PromptResult | Awaitable[PromptResult]], + name: str | None = None, + title: str | None = None, + description: str | None = None, + icons: list[Icon] | None = None, + context_kwarg: str | None = None, + ) -> Prompt: + """Create a Prompt from a function. + + The function can return: + - A string (converted to a message) + - A Message object + - A dict (converted to a message) + - A sequence of any of the above + """ + func_name = name or fn.__name__ + + if func_name == "": # pragma: no cover + raise ValueError("You must provide a name for lambda functions") + + # Find context parameter if it exists + if context_kwarg is None: # pragma: no branch + context_kwarg = find_context_parameter(fn) + + # Get schema from func_metadata, excluding context parameter + func_arg_metadata = func_metadata( + fn, + skip_names=[context_kwarg] if context_kwarg is not None else [], + ) + parameters = func_arg_metadata.arg_model.model_json_schema() + + # Convert parameters to PromptArguments + arguments: list[PromptArgument] = [] + if "properties" in parameters: # pragma: no branch + for param_name, param in parameters["properties"].items(): + required = param_name in parameters.get("required", []) + arguments.append( + PromptArgument( + name=param_name, + description=param.get("description"), + required=required, + ) + ) + + # ensure the arguments are properly cast + fn = validate_call(fn) + + return cls( + name=func_name, + title=title, + description=description or fn.__doc__ or "", + arguments=arguments, + fn=fn, + icons=icons, + context_kwarg=context_kwarg, + ) + + async def render( + self, + arguments: dict[str, Any] | None = None, + context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None, + ) -> list[Message]: + """Render the prompt with arguments.""" + # Validate required arguments + if self.arguments: + required = {arg.name for arg in self.arguments if arg.required} + provided = set(arguments or {}) + missing = required - provided + if missing: + raise ValueError(f"Missing required arguments: {missing}") + + try: + # Add context to arguments if needed + call_args = inject_context(self.fn, arguments or {}, context, self.context_kwarg) + + # Call function and check if result is a coroutine + result = self.fn(**call_args) + if inspect.iscoroutine(result): + result = await result + + # Validate messages + if not isinstance(result, list | tuple): + result = [result] + + # Convert result to messages + messages: list[Message] = [] + for msg in result: # type: ignore[reportUnknownVariableType] + try: + if isinstance(msg, Message): + messages.append(msg) + elif isinstance(msg, dict): + messages.append(message_validator.validate_python(msg)) + elif isinstance(msg, str): + content = TextContent(type="text", text=msg) + messages.append(UserMessage(content=content)) + else: # pragma: no cover + content = pydantic_core.to_json(msg, fallback=str, indent=2).decode() + messages.append(Message(role="user", content=content)) + except Exception: # pragma: no cover + raise ValueError(f"Could not convert prompt result to message: {msg}") + + return messages + except Exception as e: # pragma: no cover + raise ValueError(f"Error rendering prompt {self.name}: {e}") diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/prompts/manager.py b/source/target-vendors/cp312/mcp/server/fastmcp/prompts/manager.py new file mode 100644 index 0000000..6d032c7 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/prompts/manager.py @@ -0,0 +1,60 @@ +"""Prompt management functionality.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from mcp.server.fastmcp.prompts.base import Message, Prompt +from mcp.server.fastmcp.utilities.logging import get_logger + +if TYPE_CHECKING: + from mcp.server.fastmcp.server import Context + from mcp.server.session import ServerSessionT + from mcp.shared.context import LifespanContextT, RequestT + +logger = get_logger(__name__) + + +class PromptManager: + """Manages FastMCP prompts.""" + + def __init__(self, warn_on_duplicate_prompts: bool = True): + self._prompts: dict[str, Prompt] = {} + self.warn_on_duplicate_prompts = warn_on_duplicate_prompts + + def get_prompt(self, name: str) -> Prompt | None: + """Get prompt by name.""" + return self._prompts.get(name) + + def list_prompts(self) -> list[Prompt]: + """List all registered prompts.""" + return list(self._prompts.values()) + + def add_prompt( + self, + prompt: Prompt, + ) -> Prompt: + """Add a prompt to the manager.""" + + # Check for duplicates + existing = self._prompts.get(prompt.name) + if existing: + if self.warn_on_duplicate_prompts: + logger.warning(f"Prompt already exists: {prompt.name}") + return existing + + self._prompts[prompt.name] = prompt + return prompt + + async def render_prompt( + self, + name: str, + arguments: dict[str, Any] | None = None, + context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None, + ) -> list[Message]: + """Render a prompt by name with arguments.""" + prompt = self.get_prompt(name) + if not prompt: + raise ValueError(f"Unknown prompt: {name}") + + return await prompt.render(arguments, context=context) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/resources/__init__.py b/source/target-vendors/cp312/mcp/server/fastmcp/resources/__init__.py new file mode 100644 index 0000000..b5805fb --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/resources/__init__.py @@ -0,0 +1,23 @@ +from .base import Resource +from .resource_manager import ResourceManager +from .templates import ResourceTemplate +from .types import ( + BinaryResource, + DirectoryResource, + FileResource, + FunctionResource, + HttpResource, + TextResource, +) + +__all__ = [ + "Resource", + "TextResource", + "BinaryResource", + "FunctionResource", + "FileResource", + "HttpResource", + "DirectoryResource", + "ResourceTemplate", + "ResourceManager", +] diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/resources/base.py b/source/target-vendors/cp312/mcp/server/fastmcp/resources/base.py new file mode 100644 index 0000000..e34b97a --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/resources/base.py @@ -0,0 +1,50 @@ +"""Base classes and interfaces for FastMCP resources.""" + +import abc +from typing import Annotated, Any + +from pydantic import ( + AnyUrl, + BaseModel, + ConfigDict, + Field, + UrlConstraints, + ValidationInfo, + field_validator, +) + +from mcp.types import Annotations, Icon + + +class Resource(BaseModel, abc.ABC): + """Base class for all resources.""" + + model_config = ConfigDict(validate_default=True) + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] = Field(default=..., description="URI of the resource") + name: str | None = Field(description="Name of the resource", default=None) + title: str | None = Field(description="Human-readable title of the resource", default=None) + description: str | None = Field(description="Description of the resource", default=None) + mime_type: str = Field( + default="text/plain", + description="MIME type of the resource content", + pattern=r"^[a-zA-Z0-9]+/[a-zA-Z0-9\-+.]+(;\s*[a-zA-Z0-9\-_.]+=[a-zA-Z0-9\-_.]+)*$", + ) + icons: list[Icon] | None = Field(default=None, description="Optional list of icons for this resource") + annotations: Annotations | None = Field(default=None, description="Optional annotations for the resource") + meta: dict[str, Any] | None = Field(default=None, description="Optional metadata for this resource") + + @field_validator("name", mode="before") + @classmethod + def set_default_name(cls, name: str | None, info: ValidationInfo) -> str: + """Set default name from URI if not provided.""" + if name: + return name + if uri := info.data.get("uri"): + return str(uri) + raise ValueError("Either name or uri must be provided") + + @abc.abstractmethod + async def read(self) -> str | bytes: + """Read the resource content.""" + pass # pragma: no cover diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/resources/resource_manager.py b/source/target-vendors/cp312/mcp/server/fastmcp/resources/resource_manager.py new file mode 100644 index 0000000..20f67bb --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/resources/resource_manager.py @@ -0,0 +1,115 @@ +"""Resource manager functionality.""" + +from __future__ import annotations + +from collections.abc import Callable +from typing import TYPE_CHECKING, Any + +from pydantic import AnyUrl + +from mcp.server.fastmcp.resources.base import Resource +from mcp.server.fastmcp.resources.templates import ResourceTemplate +from mcp.server.fastmcp.utilities.logging import get_logger +from mcp.types import Annotations, Icon + +if TYPE_CHECKING: + from mcp.server.fastmcp.server import Context + from mcp.server.session import ServerSessionT + from mcp.shared.context import LifespanContextT, RequestT + +logger = get_logger(__name__) + + +class ResourceManager: + """Manages FastMCP resources.""" + + def __init__(self, warn_on_duplicate_resources: bool = True): + self._resources: dict[str, Resource] = {} + self._templates: dict[str, ResourceTemplate] = {} + self.warn_on_duplicate_resources = warn_on_duplicate_resources + + def add_resource(self, resource: Resource) -> Resource: + """Add a resource to the manager. + + Args: + resource: A Resource instance to add + + Returns: + The added resource. If a resource with the same URI already exists, + returns the existing resource. + """ + logger.debug( + "Adding resource", + extra={ + "uri": resource.uri, + "type": type(resource).__name__, + "resource_name": resource.name, + }, + ) + existing = self._resources.get(str(resource.uri)) + if existing: + if self.warn_on_duplicate_resources: + logger.warning(f"Resource already exists: {resource.uri}") + return existing + self._resources[str(resource.uri)] = resource + return resource + + def add_template( + self, + fn: Callable[..., Any], + uri_template: str, + name: str | None = None, + title: str | None = None, + description: str | None = None, + mime_type: str | None = None, + icons: list[Icon] | None = None, + annotations: Annotations | None = None, + meta: dict[str, Any] | None = None, + ) -> ResourceTemplate: + """Add a template from a function.""" + template = ResourceTemplate.from_function( + fn, + uri_template=uri_template, + name=name, + title=title, + description=description, + mime_type=mime_type, + icons=icons, + annotations=annotations, + meta=meta, + ) + self._templates[template.uri_template] = template + return template + + async def get_resource( + self, + uri: AnyUrl | str, + context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None, + ) -> Resource | None: + """Get resource by URI, checking concrete resources first, then templates.""" + uri_str = str(uri) + logger.debug("Getting resource", extra={"uri": uri_str}) + + # First check concrete resources + if resource := self._resources.get(uri_str): + return resource + + # Then check templates + for template in self._templates.values(): + if params := template.matches(uri_str): + try: + return await template.create_resource(uri_str, params, context=context) + except Exception as e: # pragma: no cover + raise ValueError(f"Error creating resource from template: {e}") + + raise ValueError(f"Unknown resource: {uri}") + + def list_resources(self) -> list[Resource]: + """List all registered resources.""" + logger.debug("Listing resources", extra={"count": len(self._resources)}) + return list(self._resources.values()) + + def list_templates(self) -> list[ResourceTemplate]: + """List all registered templates.""" + logger.debug("Listing templates", extra={"count": len(self._templates)}) + return list(self._templates.values()) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/resources/templates.py b/source/target-vendors/cp312/mcp/server/fastmcp/resources/templates.py new file mode 100644 index 0000000..89a8ceb --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/resources/templates.py @@ -0,0 +1,122 @@ +"""Resource template functionality.""" + +from __future__ import annotations + +import inspect +import re +from collections.abc import Callable +from typing import TYPE_CHECKING, Any + +from pydantic import BaseModel, Field, validate_call + +from mcp.server.fastmcp.resources.types import FunctionResource, Resource +from mcp.server.fastmcp.utilities.context_injection import find_context_parameter, inject_context +from mcp.server.fastmcp.utilities.func_metadata import func_metadata +from mcp.types import Annotations, Icon + +if TYPE_CHECKING: + from mcp.server.fastmcp.server import Context + from mcp.server.session import ServerSessionT + from mcp.shared.context import LifespanContextT, RequestT + + +class ResourceTemplate(BaseModel): + """A template for dynamically creating resources.""" + + uri_template: str = Field(description="URI template with parameters (e.g. weather://{city}/current)") + name: str = Field(description="Name of the resource") + title: str | None = Field(description="Human-readable title of the resource", default=None) + description: str | None = Field(description="Description of what the resource does") + mime_type: str = Field(default="text/plain", description="MIME type of the resource content") + icons: list[Icon] | None = Field(default=None, description="Optional list of icons for the resource template") + annotations: Annotations | None = Field(default=None, description="Optional annotations for the resource template") + meta: dict[str, Any] | None = Field(default=None, description="Optional metadata for this resource template") + fn: Callable[..., Any] = Field(exclude=True) + parameters: dict[str, Any] = Field(description="JSON schema for function parameters") + context_kwarg: str | None = Field(None, description="Name of the kwarg that should receive context") + + @classmethod + def from_function( + cls, + fn: Callable[..., Any], + uri_template: str, + name: str | None = None, + title: str | None = None, + description: str | None = None, + mime_type: str | None = None, + icons: list[Icon] | None = None, + annotations: Annotations | None = None, + meta: dict[str, Any] | None = None, + context_kwarg: str | None = None, + ) -> ResourceTemplate: + """Create a template from a function.""" + func_name = name or fn.__name__ + if func_name == "": + raise ValueError("You must provide a name for lambda functions") # pragma: no cover + + # Find context parameter if it exists + if context_kwarg is None: # pragma: no branch + context_kwarg = find_context_parameter(fn) + + # Get schema from func_metadata, excluding context parameter + func_arg_metadata = func_metadata( + fn, + skip_names=[context_kwarg] if context_kwarg is not None else [], + ) + parameters = func_arg_metadata.arg_model.model_json_schema() + + # ensure the arguments are properly cast + fn = validate_call(fn) + + return cls( + uri_template=uri_template, + name=func_name, + title=title, + description=description or fn.__doc__ or "", + mime_type=mime_type or "text/plain", + icons=icons, + annotations=annotations, + meta=meta, + fn=fn, + parameters=parameters, + context_kwarg=context_kwarg, + ) + + def matches(self, uri: str) -> dict[str, Any] | None: + """Check if URI matches template and extract parameters.""" + # Convert template to regex pattern + pattern = self.uri_template.replace("{", "(?P<").replace("}", ">[^/]+)") + match = re.match(f"^{pattern}$", uri) + if match: + return match.groupdict() + return None + + async def create_resource( + self, + uri: str, + params: dict[str, Any], + context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None, + ) -> Resource: + """Create a resource from the template with the given parameters.""" + try: + # Add context to params if needed + params = inject_context(self.fn, params, context, self.context_kwarg) + + # Call function and check if result is a coroutine + result = self.fn(**params) + if inspect.iscoroutine(result): + result = await result + + return FunctionResource( + uri=uri, # type: ignore + name=self.name, + title=self.title, + description=self.description, + mime_type=self.mime_type, + icons=self.icons, + annotations=self.annotations, + meta=self.meta, + fn=lambda: result, # Capture result in closure + ) + except Exception as e: + raise ValueError(f"Error creating resource from template: {e}") diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/resources/types.py b/source/target-vendors/cp312/mcp/server/fastmcp/resources/types.py new file mode 100644 index 0000000..5f72430 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/resources/types.py @@ -0,0 +1,203 @@ +"""Concrete resource implementations.""" + +import inspect +import json +from collections.abc import Callable +from pathlib import Path +from typing import Any + +import anyio +import anyio.to_thread +import httpx +import pydantic +import pydantic_core +from pydantic import AnyUrl, Field, ValidationInfo, validate_call + +from mcp.server.fastmcp.resources.base import Resource +from mcp.types import Annotations, Icon + + +class TextResource(Resource): + """A resource that reads from a string.""" + + text: str = Field(description="Text content of the resource") + + async def read(self) -> str: + """Read the text content.""" + return self.text # pragma: no cover + + +class BinaryResource(Resource): + """A resource that reads from bytes.""" + + data: bytes = Field(description="Binary content of the resource") + + async def read(self) -> bytes: + """Read the binary content.""" + return self.data # pragma: no cover + + +class FunctionResource(Resource): + """A resource that defers data loading by wrapping a function. + + The function is only called when the resource is read, allowing for lazy loading + of potentially expensive data. This is particularly useful when listing resources, + as the function won't be called until the resource is actually accessed. + + The function can return: + - str for text content (default) + - bytes for binary content + - other types will be converted to JSON + """ + + fn: Callable[[], Any] = Field(exclude=True) + + async def read(self) -> str | bytes: + """Read the resource by calling the wrapped function.""" + try: + # Call the function first to see if it returns a coroutine + result = self.fn() + # If it's a coroutine, await it + if inspect.iscoroutine(result): + result = await result + + if isinstance(result, Resource): # pragma: no cover + return await result.read() + elif isinstance(result, bytes): + return result + elif isinstance(result, str): + return result + else: + return pydantic_core.to_json(result, fallback=str, indent=2).decode() + except Exception as e: + raise ValueError(f"Error reading resource {self.uri}: {e}") + + @classmethod + def from_function( + cls, + fn: Callable[..., Any], + uri: str, + name: str | None = None, + title: str | None = None, + description: str | None = None, + mime_type: str | None = None, + icons: list[Icon] | None = None, + annotations: Annotations | None = None, + meta: dict[str, Any] | None = None, + ) -> "FunctionResource": + """Create a FunctionResource from a function.""" + func_name = name or fn.__name__ + if func_name == "": # pragma: no cover + raise ValueError("You must provide a name for lambda functions") + + # ensure the arguments are properly cast + fn = validate_call(fn) + + return cls( + uri=AnyUrl(uri), + name=func_name, + title=title, + description=description or fn.__doc__ or "", + mime_type=mime_type or "text/plain", + fn=fn, + icons=icons, + annotations=annotations, + meta=meta, + ) + + +class FileResource(Resource): + """A resource that reads from a file. + + Set is_binary=True to read file as binary data instead of text. + """ + + path: Path = Field(description="Path to the file") + is_binary: bool = Field( + default=False, + description="Whether to read the file as binary data", + ) + mime_type: str = Field( + default="text/plain", + description="MIME type of the resource content", + ) + + @pydantic.field_validator("path") + @classmethod + def validate_absolute_path(cls, path: Path) -> Path: # pragma: no cover + """Ensure path is absolute.""" + if not path.is_absolute(): + raise ValueError("Path must be absolute") + return path + + @pydantic.field_validator("is_binary") + @classmethod + def set_binary_from_mime_type(cls, is_binary: bool, info: ValidationInfo) -> bool: + """Set is_binary based on mime_type if not explicitly set.""" + if is_binary: + return True + mime_type = info.data.get("mime_type", "text/plain") + return not mime_type.startswith("text/") + + async def read(self) -> str | bytes: + """Read the file content.""" + try: + if self.is_binary: + return await anyio.to_thread.run_sync(self.path.read_bytes) + return await anyio.to_thread.run_sync(self.path.read_text) + except Exception as e: + raise ValueError(f"Error reading file {self.path}: {e}") + + +class HttpResource(Resource): + """A resource that reads from an HTTP endpoint.""" + + url: str = Field(description="URL to fetch content from") + mime_type: str = Field(default="application/json", description="MIME type of the resource content") + + async def read(self) -> str | bytes: + """Read the HTTP content.""" + async with httpx.AsyncClient() as client: # pragma: no cover + response = await client.get(self.url) + response.raise_for_status() + return response.text + + +class DirectoryResource(Resource): + """A resource that lists files in a directory.""" + + path: Path = Field(description="Path to the directory") + recursive: bool = Field(default=False, description="Whether to list files recursively") + pattern: str | None = Field(default=None, description="Optional glob pattern to filter files") + mime_type: str = Field(default="application/json", description="MIME type of the resource content") + + @pydantic.field_validator("path") + @classmethod + def validate_absolute_path(cls, path: Path) -> Path: # pragma: no cover + """Ensure path is absolute.""" + if not path.is_absolute(): + raise ValueError("Path must be absolute") + return path + + def list_files(self) -> list[Path]: # pragma: no cover + """List files in the directory.""" + if not self.path.exists(): + raise FileNotFoundError(f"Directory not found: {self.path}") + if not self.path.is_dir(): + raise NotADirectoryError(f"Not a directory: {self.path}") + + try: + if self.pattern: + return list(self.path.glob(self.pattern)) if not self.recursive else list(self.path.rglob(self.pattern)) + return list(self.path.glob("*")) if not self.recursive else list(self.path.rglob("*")) + except Exception as e: + raise ValueError(f"Error listing directory {self.path}: {e}") + + async def read(self) -> str: # Always returns JSON string # pragma: no cover + """Read the directory listing.""" + try: + files = await anyio.to_thread.run_sync(self.list_files) + file_list = [str(f.relative_to(self.path)) for f in files if f.is_file()] + return json.dumps({"files": file_list}, indent=2) + except Exception as e: + raise ValueError(f"Error reading directory {self.path}: {e}") diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/server.py b/source/target-vendors/cp312/mcp/server/fastmcp/server.py new file mode 100644 index 0000000..7a43bd7 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/server.py @@ -0,0 +1,1349 @@ +"""FastMCP - A more ergonomic interface for MCP servers.""" + +from __future__ import annotations as _annotations + +import inspect +import re +from collections.abc import ( + AsyncIterator, + Awaitable, + Callable, + Collection, + Iterable, + Sequence, +) +from contextlib import AbstractAsyncContextManager, asynccontextmanager +from typing import Any, Generic, Literal + +import anyio +import pydantic_core +from pydantic import BaseModel +from pydantic.networks import AnyUrl +from pydantic_settings import BaseSettings, SettingsConfigDict +from starlette.applications import Starlette +from starlette.middleware import Middleware +from starlette.middleware.authentication import AuthenticationMiddleware +from starlette.requests import Request +from starlette.responses import Response +from starlette.routing import Mount, Route +from starlette.types import Receive, Scope, Send + +from mcp.server.auth.middleware.auth_context import AuthContextMiddleware +from mcp.server.auth.middleware.bearer_auth import ( + BearerAuthBackend, + RequireAuthMiddleware, +) +from mcp.server.auth.provider import ( + OAuthAuthorizationServerProvider, + ProviderTokenVerifier, + TokenVerifier, +) +from mcp.server.auth.settings import AuthSettings +from mcp.server.elicitation import ( + ElicitationResult, + ElicitSchemaModelT, + UrlElicitationResult, + elicit_with_validation, +) +from mcp.server.elicitation import ( + elicit_url as _elicit_url, +) +from mcp.server.fastmcp.exceptions import ResourceError +from mcp.server.fastmcp.prompts import Prompt, PromptManager +from mcp.server.fastmcp.resources import FunctionResource, Resource, ResourceManager +from mcp.server.fastmcp.tools import Tool, ToolManager +from mcp.server.fastmcp.utilities.context_injection import find_context_parameter +from mcp.server.fastmcp.utilities.logging import configure_logging, get_logger +from mcp.server.lowlevel.helper_types import ReadResourceContents +from mcp.server.lowlevel.server import LifespanResultT +from mcp.server.lowlevel.server import Server as MCPServer +from mcp.server.lowlevel.server import lifespan as default_lifespan +from mcp.server.session import ServerSession, ServerSessionT +from mcp.server.sse import SseServerTransport +from mcp.server.stdio import stdio_server +from mcp.server.streamable_http import EventStore +from mcp.server.streamable_http_manager import StreamableHTTPSessionManager +from mcp.server.transport_security import TransportSecuritySettings +from mcp.shared.context import LifespanContextT, RequestContext, RequestT +from mcp.types import Annotations, AnyFunction, ContentBlock, GetPromptResult, Icon, ToolAnnotations +from mcp.types import Prompt as MCPPrompt +from mcp.types import PromptArgument as MCPPromptArgument +from mcp.types import Resource as MCPResource +from mcp.types import ResourceTemplate as MCPResourceTemplate +from mcp.types import Tool as MCPTool + +logger = get_logger(__name__) + + +class Settings(BaseSettings, Generic[LifespanResultT]): + """FastMCP server settings. + + All settings can be configured via environment variables with the prefix FASTMCP_. + For example, FASTMCP_DEBUG=true will set debug=True. + """ + + model_config = SettingsConfigDict( + env_prefix="FASTMCP_", + env_file=".env", + env_nested_delimiter="__", + nested_model_default_partial_update=True, + extra="ignore", + ) + + # Server settings + debug: bool + log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] + + # HTTP settings + host: str + port: int + mount_path: str + sse_path: str + message_path: str + streamable_http_path: str + + # StreamableHTTP settings + json_response: bool + stateless_http: bool + """Define if the server should create a new transport per request.""" + + # resource settings + warn_on_duplicate_resources: bool + + # tool settings + warn_on_duplicate_tools: bool + + # prompt settings + warn_on_duplicate_prompts: bool + + # TODO(Marcelo): Investigate if this is used. If it is, it's probably a good idea to remove it. + dependencies: list[str] + """A list of dependencies to install in the server environment.""" + + lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None + """A async context manager that will be called when the server is started.""" + + auth: AuthSettings | None + + # Transport security settings (DNS rebinding protection) + transport_security: TransportSecuritySettings | None + + +def lifespan_wrapper( + app: FastMCP[LifespanResultT], + lifespan: Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]], +) -> Callable[[MCPServer[LifespanResultT, Request]], AbstractAsyncContextManager[LifespanResultT]]: + @asynccontextmanager + async def wrap( + _: MCPServer[LifespanResultT, Request], + ) -> AsyncIterator[LifespanResultT]: + async with lifespan(app) as context: + yield context + + return wrap + + +class FastMCP(Generic[LifespanResultT]): + def __init__( # noqa: PLR0913 + self, + name: str | None = None, + instructions: str | None = None, + website_url: str | None = None, + icons: list[Icon] | None = None, + auth_server_provider: (OAuthAuthorizationServerProvider[Any, Any, Any] | None) = None, + token_verifier: TokenVerifier | None = None, + event_store: EventStore | None = None, + retry_interval: int | None = None, + *, + tools: list[Tool] | None = None, + debug: bool = False, + log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO", + host: str = "127.0.0.1", + port: int = 8000, + mount_path: str = "/", + sse_path: str = "/sse", + message_path: str = "/messages/", + streamable_http_path: str = "/mcp", + json_response: bool = False, + stateless_http: bool = False, + warn_on_duplicate_resources: bool = True, + warn_on_duplicate_tools: bool = True, + warn_on_duplicate_prompts: bool = True, + dependencies: Collection[str] = (), + lifespan: (Callable[[FastMCP[LifespanResultT]], AbstractAsyncContextManager[LifespanResultT]] | None) = None, + auth: AuthSettings | None = None, + transport_security: TransportSecuritySettings | None = None, + ): + # Auto-enable DNS rebinding protection for localhost (IPv4 and IPv6) + if transport_security is None and host in ("127.0.0.1", "localhost", "::1"): + transport_security = TransportSecuritySettings( + enable_dns_rebinding_protection=True, + allowed_hosts=["127.0.0.1:*", "localhost:*", "[::1]:*"], + allowed_origins=["http://127.0.0.1:*", "http://localhost:*", "http://[::1]:*"], + ) + + self.settings = Settings( + debug=debug, + log_level=log_level, + host=host, + port=port, + mount_path=mount_path, + sse_path=sse_path, + message_path=message_path, + streamable_http_path=streamable_http_path, + json_response=json_response, + stateless_http=stateless_http, + warn_on_duplicate_resources=warn_on_duplicate_resources, + warn_on_duplicate_tools=warn_on_duplicate_tools, + warn_on_duplicate_prompts=warn_on_duplicate_prompts, + dependencies=list(dependencies), + lifespan=lifespan, + auth=auth, + transport_security=transport_security, + ) + + self._mcp_server = MCPServer( + name=name or "FastMCP", + instructions=instructions, + website_url=website_url, + icons=icons, + # TODO(Marcelo): It seems there's a type mismatch between the lifespan type from an FastMCP and Server. + # We need to create a Lifespan type that is a generic on the server type, like Starlette does. + lifespan=(lifespan_wrapper(self, self.settings.lifespan) if self.settings.lifespan else default_lifespan), # type: ignore + ) + self._tool_manager = ToolManager(tools=tools, warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools) + self._resource_manager = ResourceManager(warn_on_duplicate_resources=self.settings.warn_on_duplicate_resources) + self._prompt_manager = PromptManager(warn_on_duplicate_prompts=self.settings.warn_on_duplicate_prompts) + # Validate auth configuration + if self.settings.auth is not None: + if auth_server_provider and token_verifier: # pragma: no cover + raise ValueError("Cannot specify both auth_server_provider and token_verifier") + if not auth_server_provider and not token_verifier: # pragma: no cover + raise ValueError("Must specify either auth_server_provider or token_verifier when auth is enabled") + elif auth_server_provider or token_verifier: # pragma: no cover + raise ValueError("Cannot specify auth_server_provider or token_verifier without auth settings") + + self._auth_server_provider = auth_server_provider + self._token_verifier = token_verifier + + # Create token verifier from provider if needed (backwards compatibility) + if auth_server_provider and not token_verifier: # pragma: no cover + self._token_verifier = ProviderTokenVerifier(auth_server_provider) + self._event_store = event_store + self._retry_interval = retry_interval + self._custom_starlette_routes: list[Route] = [] + self.dependencies = self.settings.dependencies + self._session_manager: StreamableHTTPSessionManager | None = None + + # Set up MCP protocol handlers + self._setup_handlers() + + # Configure logging + configure_logging(self.settings.log_level) + + @property + def name(self) -> str: + return self._mcp_server.name + + @property + def instructions(self) -> str | None: + return self._mcp_server.instructions + + @property + def website_url(self) -> str | None: + return self._mcp_server.website_url + + @property + def icons(self) -> list[Icon] | None: + return self._mcp_server.icons + + @property + def session_manager(self) -> StreamableHTTPSessionManager: + """Get the StreamableHTTP session manager. + + This is exposed to enable advanced use cases like mounting multiple + FastMCP servers in a single FastAPI application. + + Raises: + RuntimeError: If called before streamable_http_app() has been called. + """ + if self._session_manager is None: # pragma: no cover + raise RuntimeError( + "Session manager can only be accessed after" + "calling streamable_http_app()." + "The session manager is created lazily" + "to avoid unnecessary initialization." + ) + return self._session_manager # pragma: no cover + + def run( + self, + transport: Literal["stdio", "sse", "streamable-http"] = "stdio", + mount_path: str | None = None, + ) -> None: + """Run the FastMCP server. Note this is a synchronous function. + + Args: + transport: Transport protocol to use ("stdio", "sse", or "streamable-http") + mount_path: Optional mount path for SSE transport + """ + TRANSPORTS = Literal["stdio", "sse", "streamable-http"] + if transport not in TRANSPORTS.__args__: # type: ignore # pragma: no cover + raise ValueError(f"Unknown transport: {transport}") + + match transport: + case "stdio": + anyio.run(self.run_stdio_async) + case "sse": # pragma: no cover + anyio.run(lambda: self.run_sse_async(mount_path)) + case "streamable-http": # pragma: no cover + anyio.run(self.run_streamable_http_async) + + def _setup_handlers(self) -> None: + """Set up core MCP protocol handlers.""" + self._mcp_server.list_tools()(self.list_tools) + # Note: we disable the lowlevel server's input validation. + # FastMCP does ad hoc conversion of incoming data before validating - + # for now we preserve this for backwards compatibility. + self._mcp_server.call_tool(validate_input=False)(self.call_tool) + self._mcp_server.list_resources()(self.list_resources) + self._mcp_server.read_resource()(self.read_resource) + self._mcp_server.list_prompts()(self.list_prompts) + self._mcp_server.get_prompt()(self.get_prompt) + self._mcp_server.list_resource_templates()(self.list_resource_templates) + + async def list_tools(self) -> list[MCPTool]: + """List all available tools.""" + tools = self._tool_manager.list_tools() + return [ + MCPTool( + name=info.name, + title=info.title, + description=info.description, + inputSchema=info.parameters, + outputSchema=info.output_schema, + annotations=info.annotations, + icons=info.icons, + _meta=info.meta, + ) + for info in tools + ] + + def get_context(self) -> Context[ServerSession, LifespanResultT, Request]: + """ + Returns a Context object. Note that the context will only be valid + during a request; outside a request, most methods will error. + """ + try: + request_context = self._mcp_server.request_context + except LookupError: + request_context = None + return Context(request_context=request_context, fastmcp=self) + + async def call_tool(self, name: str, arguments: dict[str, Any]) -> Sequence[ContentBlock] | dict[str, Any]: + """Call a tool by name with arguments.""" + context = self.get_context() + return await self._tool_manager.call_tool(name, arguments, context=context, convert_result=True) + + async def list_resources(self) -> list[MCPResource]: + """List all available resources.""" + + resources = self._resource_manager.list_resources() + return [ + MCPResource( + uri=resource.uri, + name=resource.name or "", + title=resource.title, + description=resource.description, + mimeType=resource.mime_type, + icons=resource.icons, + annotations=resource.annotations, + _meta=resource.meta, + ) + for resource in resources + ] + + async def list_resource_templates(self) -> list[MCPResourceTemplate]: + templates = self._resource_manager.list_templates() + return [ + MCPResourceTemplate( + uriTemplate=template.uri_template, + name=template.name, + title=template.title, + description=template.description, + mimeType=template.mime_type, + icons=template.icons, + annotations=template.annotations, + _meta=template.meta, + ) + for template in templates + ] + + async def read_resource(self, uri: AnyUrl | str) -> Iterable[ReadResourceContents]: + """Read a resource by URI.""" + + context = self.get_context() + resource = await self._resource_manager.get_resource(uri, context=context) + if not resource: # pragma: no cover + raise ResourceError(f"Unknown resource: {uri}") + + try: + content = await resource.read() + return [ReadResourceContents(content=content, mime_type=resource.mime_type, meta=resource.meta)] + except Exception as e: # pragma: no cover + logger.exception(f"Error reading resource {uri}") + raise ResourceError(str(e)) + + def add_tool( + self, + fn: AnyFunction, + name: str | None = None, + title: str | None = None, + description: str | None = None, + annotations: ToolAnnotations | None = None, + icons: list[Icon] | None = None, + meta: dict[str, Any] | None = None, + structured_output: bool | None = None, + ) -> None: + """Add a tool to the server. + + The tool function can optionally request a Context object by adding a parameter + with the Context type annotation. See the @tool decorator for examples. + + Args: + fn: The function to register as a tool + name: Optional name for the tool (defaults to function name) + title: Optional human-readable title for the tool + description: Optional description of what the tool does + annotations: Optional ToolAnnotations providing additional tool information + structured_output: Controls whether the tool's output is structured or unstructured + - If None, auto-detects based on the function's return type annotation + - If True, creates a structured tool (return type annotation permitting) + - If False, unconditionally creates an unstructured tool + """ + self._tool_manager.add_tool( + fn, + name=name, + title=title, + description=description, + annotations=annotations, + icons=icons, + meta=meta, + structured_output=structured_output, + ) + + def remove_tool(self, name: str) -> None: + """Remove a tool from the server by name. + + Args: + name: The name of the tool to remove + + Raises: + ToolError: If the tool does not exist + """ + self._tool_manager.remove_tool(name) + + def tool( + self, + name: str | None = None, + title: str | None = None, + description: str | None = None, + annotations: ToolAnnotations | None = None, + icons: list[Icon] | None = None, + meta: dict[str, Any] | None = None, + structured_output: bool | None = None, + ) -> Callable[[AnyFunction], AnyFunction]: + """Decorator to register a tool. + + Tools can optionally request a Context object by adding a parameter with the + Context type annotation. The context provides access to MCP capabilities like + logging, progress reporting, and resource access. + + Args: + name: Optional name for the tool (defaults to function name) + title: Optional human-readable title for the tool + description: Optional description of what the tool does + annotations: Optional ToolAnnotations providing additional tool information + structured_output: Controls whether the tool's output is structured or unstructured + - If None, auto-detects based on the function's return type annotation + - If True, creates a structured tool (return type annotation permitting) + - If False, unconditionally creates an unstructured tool + + Example: + @server.tool() + def my_tool(x: int) -> str: + return str(x) + + @server.tool() + def tool_with_context(x: int, ctx: Context) -> str: + ctx.info(f"Processing {x}") + return str(x) + + @server.tool() + async def async_tool(x: int, context: Context) -> str: + await context.report_progress(50, 100) + return str(x) + """ + # Check if user passed function directly instead of calling decorator + if callable(name): + raise TypeError( + "The @tool decorator was used incorrectly. Did you forget to call it? Use @tool() instead of @tool" + ) + + def decorator(fn: AnyFunction) -> AnyFunction: + self.add_tool( + fn, + name=name, + title=title, + description=description, + annotations=annotations, + icons=icons, + meta=meta, + structured_output=structured_output, + ) + return fn + + return decorator + + def completion(self): + """Decorator to register a completion handler. + + The completion handler receives: + - ref: PromptReference or ResourceTemplateReference + - argument: CompletionArgument with name and partial value + - context: Optional CompletionContext with previously resolved arguments + + Example: + @mcp.completion() + async def handle_completion(ref, argument, context): + if isinstance(ref, ResourceTemplateReference): + # Return completions based on ref, argument, and context + return Completion(values=["option1", "option2"]) + return None + """ + return self._mcp_server.completion() + + def add_resource(self, resource: Resource) -> None: + """Add a resource to the server. + + Args: + resource: A Resource instance to add + """ + self._resource_manager.add_resource(resource) + + def resource( + self, + uri: str, + *, + name: str | None = None, + title: str | None = None, + description: str | None = None, + mime_type: str | None = None, + icons: list[Icon] | None = None, + annotations: Annotations | None = None, + meta: dict[str, Any] | None = None, + ) -> Callable[[AnyFunction], AnyFunction]: + """Decorator to register a function as a resource. + + The function will be called when the resource is read to generate its content. + The function can return: + - str for text content + - bytes for binary content + - other types will be converted to JSON + + If the URI contains parameters (e.g. "resource://{param}") or the function + has parameters, it will be registered as a template resource. + + Args: + uri: URI for the resource (e.g. "resource://my-resource" or "resource://{param}") + name: Optional name for the resource + title: Optional human-readable title for the resource + description: Optional description of the resource + mime_type: Optional MIME type for the resource + meta: Optional metadata dictionary for the resource + + Example: + @server.resource("resource://my-resource") + def get_data() -> str: + return "Hello, world!" + + @server.resource("resource://my-resource") + async get_data() -> str: + data = await fetch_data() + return f"Hello, world! {data}" + + @server.resource("resource://{city}/weather") + def get_weather(city: str) -> str: + return f"Weather for {city}" + + @server.resource("resource://{city}/weather") + async def get_weather(city: str) -> str: + data = await fetch_weather(city) + return f"Weather for {city}: {data}" + """ + # Check if user passed function directly instead of calling decorator + if callable(uri): + raise TypeError( + "The @resource decorator was used incorrectly. " + "Did you forget to call it? Use @resource('uri') instead of @resource" + ) + + def decorator(fn: AnyFunction) -> AnyFunction: + # Check if this should be a template + sig = inspect.signature(fn) + has_uri_params = "{" in uri and "}" in uri + has_func_params = bool(sig.parameters) + + if has_uri_params or has_func_params: + # Check for Context parameter to exclude from validation + context_param = find_context_parameter(fn) + + # Validate that URI params match function params (excluding context) + uri_params = set(re.findall(r"{(\w+)}", uri)) + # We need to remove the context_param from the resource function if + # there is any. + func_params = {p for p in sig.parameters.keys() if p != context_param} + + if uri_params != func_params: + raise ValueError( + f"Mismatch between URI parameters {uri_params} and function parameters {func_params}" + ) + + # Register as template + self._resource_manager.add_template( + fn=fn, + uri_template=uri, + name=name, + title=title, + description=description, + mime_type=mime_type, + icons=icons, + annotations=annotations, + meta=meta, + ) + else: + # Register as regular resource + resource = FunctionResource.from_function( + fn=fn, + uri=uri, + name=name, + title=title, + description=description, + mime_type=mime_type, + icons=icons, + annotations=annotations, + meta=meta, + ) + self.add_resource(resource) + return fn + + return decorator + + def add_prompt(self, prompt: Prompt) -> None: + """Add a prompt to the server. + + Args: + prompt: A Prompt instance to add + """ + self._prompt_manager.add_prompt(prompt) + + def prompt( + self, + name: str | None = None, + title: str | None = None, + description: str | None = None, + icons: list[Icon] | None = None, + ) -> Callable[[AnyFunction], AnyFunction]: + """Decorator to register a prompt. + + Args: + name: Optional name for the prompt (defaults to function name) + title: Optional human-readable title for the prompt + description: Optional description of what the prompt does + + Example: + @server.prompt() + def analyze_table(table_name: str) -> list[Message]: + schema = read_table_schema(table_name) + return [ + { + "role": "user", + "content": f"Analyze this schema:\n{schema}" + } + ] + + @server.prompt() + async def analyze_file(path: str) -> list[Message]: + content = await read_file(path) + return [ + { + "role": "user", + "content": { + "type": "resource", + "resource": { + "uri": f"file://{path}", + "text": content + } + } + } + ] + """ + # Check if user passed function directly instead of calling decorator + if callable(name): + raise TypeError( + "The @prompt decorator was used incorrectly. " + "Did you forget to call it? Use @prompt() instead of @prompt" + ) + + def decorator(func: AnyFunction) -> AnyFunction: + prompt = Prompt.from_function(func, name=name, title=title, description=description, icons=icons) + self.add_prompt(prompt) + return func + + return decorator + + def custom_route( + self, + path: str, + methods: list[str], + name: str | None = None, + include_in_schema: bool = True, + ): + """ + Decorator to register a custom HTTP route on the FastMCP server. + + Allows adding arbitrary HTTP endpoints outside the standard MCP protocol, + which can be useful for OAuth callbacks, health checks, or admin APIs. + The handler function must be an async function that accepts a Starlette + Request and returns a Response. + + Routes using this decorator will not require authorization. It is intended + for uses that are either a part of authorization flows or intended to be + public such as health check endpoints. + + Args: + path: URL path for the route (e.g., "/oauth/callback") + methods: List of HTTP methods to support (e.g., ["GET", "POST"]) + name: Optional name for the route (to reference this route with + Starlette's reverse URL lookup feature) + include_in_schema: Whether to include in OpenAPI schema, defaults to True + + Example: + @server.custom_route("/health", methods=["GET"]) + async def health_check(request: Request) -> Response: + return JSONResponse({"status": "ok"}) + """ + + def decorator( # pragma: no cover + func: Callable[[Request], Awaitable[Response]], + ) -> Callable[[Request], Awaitable[Response]]: + self._custom_starlette_routes.append( + Route( + path, + endpoint=func, + methods=methods, + name=name, + include_in_schema=include_in_schema, + ) + ) + return func + + return decorator # pragma: no cover + + async def run_stdio_async(self) -> None: + """Run the server using stdio transport.""" + async with stdio_server() as (read_stream, write_stream): + await self._mcp_server.run( + read_stream, + write_stream, + self._mcp_server.create_initialization_options(), + ) + + async def run_sse_async(self, mount_path: str | None = None) -> None: # pragma: no cover + """Run the server using SSE transport.""" + import uvicorn + + starlette_app = self.sse_app(mount_path) + + config = uvicorn.Config( + starlette_app, + host=self.settings.host, + port=self.settings.port, + log_level=self.settings.log_level.lower(), + ) + server = uvicorn.Server(config) + await server.serve() + + async def run_streamable_http_async(self) -> None: # pragma: no cover + """Run the server using StreamableHTTP transport.""" + import uvicorn + + starlette_app = self.streamable_http_app() + + config = uvicorn.Config( + starlette_app, + host=self.settings.host, + port=self.settings.port, + log_level=self.settings.log_level.lower(), + ) + server = uvicorn.Server(config) + await server.serve() + + def _normalize_path(self, mount_path: str, endpoint: str) -> str: + """ + Combine mount path and endpoint to return a normalized path. + + Args: + mount_path: The mount path (e.g. "/github" or "/") + endpoint: The endpoint path (e.g. "/messages/") + + Returns: + Normalized path (e.g. "/github/messages/") + """ + # Special case: root path + if mount_path == "/": + return endpoint + + # Remove trailing slash from mount path + if mount_path.endswith("/"): + mount_path = mount_path[:-1] + + # Ensure endpoint starts with slash + if not endpoint.startswith("/"): + endpoint = "/" + endpoint + + # Combine paths + return mount_path + endpoint + + def sse_app(self, mount_path: str | None = None) -> Starlette: + """Return an instance of the SSE server app.""" + from starlette.middleware import Middleware + from starlette.routing import Mount, Route + + # Update mount_path in settings if provided + if mount_path is not None: + self.settings.mount_path = mount_path + + # Create normalized endpoint considering the mount path + normalized_message_endpoint = self._normalize_path(self.settings.mount_path, self.settings.message_path) + + # Set up auth context and dependencies + + sse = SseServerTransport( + normalized_message_endpoint, + security_settings=self.settings.transport_security, + ) + + async def handle_sse(scope: Scope, receive: Receive, send: Send): # pragma: no cover + # Add client ID from auth context into request context if available + + async with sse.connect_sse( + scope, + receive, + send, + ) as streams: + await self._mcp_server.run( + streams[0], + streams[1], + self._mcp_server.create_initialization_options(), + ) + return Response() + + # Create routes + routes: list[Route | Mount] = [] + middleware: list[Middleware] = [] + required_scopes = [] + + # Set up auth if configured + if self.settings.auth: # pragma: no cover + required_scopes = self.settings.auth.required_scopes or [] + + # Add auth middleware if token verifier is available + if self._token_verifier: + middleware = [ + # extract auth info from request (but do not require it) + Middleware( + AuthenticationMiddleware, + backend=BearerAuthBackend(self._token_verifier), + ), + # Add the auth context middleware to store + # authenticated user in a contextvar + Middleware(AuthContextMiddleware), + ] + + # Add auth endpoints if auth server provider is configured + if self._auth_server_provider: + from mcp.server.auth.routes import create_auth_routes + + routes.extend( + create_auth_routes( + provider=self._auth_server_provider, + issuer_url=self.settings.auth.issuer_url, + service_documentation_url=self.settings.auth.service_documentation_url, + client_registration_options=self.settings.auth.client_registration_options, + revocation_options=self.settings.auth.revocation_options, + ) + ) + + # When auth is configured, require authentication + if self._token_verifier: # pragma: no cover + # Determine resource metadata URL + resource_metadata_url = None + if self.settings.auth and self.settings.auth.resource_server_url: + from mcp.server.auth.routes import build_resource_metadata_url + + # Build compliant metadata URL for WWW-Authenticate header + resource_metadata_url = build_resource_metadata_url(self.settings.auth.resource_server_url) + + # Auth is enabled, wrap the endpoints with RequireAuthMiddleware + routes.append( + Route( + self.settings.sse_path, + endpoint=RequireAuthMiddleware(handle_sse, required_scopes, resource_metadata_url), + methods=["GET"], + ) + ) + routes.append( + Mount( + self.settings.message_path, + app=RequireAuthMiddleware(sse.handle_post_message, required_scopes, resource_metadata_url), + ) + ) + else: # pragma: no cover + # Auth is disabled, no need for RequireAuthMiddleware + # Since handle_sse is an ASGI app, we need to create a compatible endpoint + async def sse_endpoint(request: Request) -> Response: + # Convert the Starlette request to ASGI parameters + return await handle_sse(request.scope, request.receive, request._send) # type: ignore[reportPrivateUsage] + + routes.append( + Route( + self.settings.sse_path, + endpoint=sse_endpoint, + methods=["GET"], + ) + ) + routes.append( + Mount( + self.settings.message_path, + app=sse.handle_post_message, + ) + ) + # Add protected resource metadata endpoint if configured as RS + if self.settings.auth and self.settings.auth.resource_server_url: # pragma: no cover + from mcp.server.auth.routes import create_protected_resource_routes + + routes.extend( + create_protected_resource_routes( + resource_url=self.settings.auth.resource_server_url, + authorization_servers=[self.settings.auth.issuer_url], + scopes_supported=self.settings.auth.required_scopes, + ) + ) + + # mount these routes last, so they have the lowest route matching precedence + routes.extend(self._custom_starlette_routes) + + # Create Starlette app with routes and middleware + return Starlette(debug=self.settings.debug, routes=routes, middleware=middleware) + + def streamable_http_app(self) -> Starlette: + """Return an instance of the StreamableHTTP server app.""" + from starlette.middleware import Middleware + + # Create session manager on first call (lazy initialization) + if self._session_manager is None: # pragma: no branch + self._session_manager = StreamableHTTPSessionManager( + app=self._mcp_server, + event_store=self._event_store, + retry_interval=self._retry_interval, + json_response=self.settings.json_response, + stateless=self.settings.stateless_http, # Use the stateless setting + security_settings=self.settings.transport_security, + ) + + # Create the ASGI handler + streamable_http_app = StreamableHTTPASGIApp(self._session_manager) + + # Create routes + routes: list[Route | Mount] = [] + middleware: list[Middleware] = [] + required_scopes = [] + + # Set up auth if configured + if self.settings.auth: # pragma: no cover + required_scopes = self.settings.auth.required_scopes or [] + + # Add auth middleware if token verifier is available + if self._token_verifier: + middleware = [ + Middleware( + AuthenticationMiddleware, + backend=BearerAuthBackend(self._token_verifier), + ), + Middleware(AuthContextMiddleware), + ] + + # Add auth endpoints if auth server provider is configured + if self._auth_server_provider: + from mcp.server.auth.routes import create_auth_routes + + routes.extend( + create_auth_routes( + provider=self._auth_server_provider, + issuer_url=self.settings.auth.issuer_url, + service_documentation_url=self.settings.auth.service_documentation_url, + client_registration_options=self.settings.auth.client_registration_options, + revocation_options=self.settings.auth.revocation_options, + ) + ) + + # Set up routes with or without auth + if self._token_verifier: # pragma: no cover + # Determine resource metadata URL + resource_metadata_url = None + if self.settings.auth and self.settings.auth.resource_server_url: + from mcp.server.auth.routes import build_resource_metadata_url + + # Build compliant metadata URL for WWW-Authenticate header + resource_metadata_url = build_resource_metadata_url(self.settings.auth.resource_server_url) + + routes.append( + Route( + self.settings.streamable_http_path, + endpoint=RequireAuthMiddleware(streamable_http_app, required_scopes, resource_metadata_url), + ) + ) + else: + # Auth is disabled, no wrapper needed + routes.append( + Route( + self.settings.streamable_http_path, + endpoint=streamable_http_app, + ) + ) + + # Add protected resource metadata endpoint if configured as RS + if self.settings.auth and self.settings.auth.resource_server_url: # pragma: no cover + from mcp.server.auth.routes import create_protected_resource_routes + + routes.extend( + create_protected_resource_routes( + resource_url=self.settings.auth.resource_server_url, + authorization_servers=[self.settings.auth.issuer_url], + scopes_supported=self.settings.auth.required_scopes, + ) + ) + + routes.extend(self._custom_starlette_routes) + + return Starlette( + debug=self.settings.debug, + routes=routes, + middleware=middleware, + lifespan=lambda app: self.session_manager.run(), + ) + + async def list_prompts(self) -> list[MCPPrompt]: + """List all available prompts.""" + prompts = self._prompt_manager.list_prompts() + return [ + MCPPrompt( + name=prompt.name, + title=prompt.title, + description=prompt.description, + arguments=[ + MCPPromptArgument( + name=arg.name, + description=arg.description, + required=arg.required, + ) + for arg in (prompt.arguments or []) + ], + icons=prompt.icons, + ) + for prompt in prompts + ] + + async def get_prompt(self, name: str, arguments: dict[str, Any] | None = None) -> GetPromptResult: + """Get a prompt by name with arguments.""" + try: + prompt = self._prompt_manager.get_prompt(name) + if not prompt: + raise ValueError(f"Unknown prompt: {name}") + + messages = await prompt.render(arguments, context=self.get_context()) + + return GetPromptResult( + description=prompt.description, + messages=pydantic_core.to_jsonable_python(messages), + ) + except Exception as e: + logger.exception(f"Error getting prompt {name}") + raise ValueError(str(e)) + + +class StreamableHTTPASGIApp: + """ + ASGI application for Streamable HTTP server transport. + """ + + def __init__(self, session_manager: StreamableHTTPSessionManager): + self.session_manager = session_manager + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: # pragma: no cover + await self.session_manager.handle_request(scope, receive, send) + + +class Context(BaseModel, Generic[ServerSessionT, LifespanContextT, RequestT]): + """Context object providing access to MCP capabilities. + + This provides a cleaner interface to MCP's RequestContext functionality. + It gets injected into tool and resource functions that request it via type hints. + + To use context in a tool function, add a parameter with the Context type annotation: + + ```python + @server.tool() + def my_tool(x: int, ctx: Context) -> str: + # Log messages to the client + ctx.info(f"Processing {x}") + ctx.debug("Debug info") + ctx.warning("Warning message") + ctx.error("Error message") + + # Report progress + ctx.report_progress(50, 100) + + # Access resources + data = ctx.read_resource("resource://data") + + # Get request info + request_id = ctx.request_id + client_id = ctx.client_id + + return str(x) + ``` + + The context parameter name can be anything as long as it's annotated with Context. + The context is optional - tools that don't need it can omit the parameter. + """ + + _request_context: RequestContext[ServerSessionT, LifespanContextT, RequestT] | None + _fastmcp: FastMCP | None + + def __init__( + self, + *, + request_context: (RequestContext[ServerSessionT, LifespanContextT, RequestT] | None) = None, + fastmcp: FastMCP | None = None, + **kwargs: Any, + ): + super().__init__(**kwargs) + self._request_context = request_context + self._fastmcp = fastmcp + + @property + def fastmcp(self) -> FastMCP: + """Access to the FastMCP server.""" + if self._fastmcp is None: # pragma: no cover + raise ValueError("Context is not available outside of a request") + return self._fastmcp # pragma: no cover + + @property + def request_context( + self, + ) -> RequestContext[ServerSessionT, LifespanContextT, RequestT]: + """Access to the underlying request context.""" + if self._request_context is None: # pragma: no cover + raise ValueError("Context is not available outside of a request") + return self._request_context + + async def report_progress(self, progress: float, total: float | None = None, message: str | None = None) -> None: + """Report progress for the current operation. + + Args: + progress: Current progress value e.g. 24 + total: Optional total value e.g. 100 + message: Optional message e.g. Starting render... + """ + progress_token = self.request_context.meta.progressToken if self.request_context.meta else None + + if progress_token is None: # pragma: no cover + return + + await self.request_context.session.send_progress_notification( + progress_token=progress_token, + progress=progress, + total=total, + message=message, + ) + + async def read_resource(self, uri: str | AnyUrl) -> Iterable[ReadResourceContents]: + """Read a resource by URI. + + Args: + uri: Resource URI to read + + Returns: + The resource content as either text or bytes + """ + assert self._fastmcp is not None, "Context is not available outside of a request" + return await self._fastmcp.read_resource(uri) + + async def elicit( + self, + message: str, + schema: type[ElicitSchemaModelT], + ) -> ElicitationResult[ElicitSchemaModelT]: + """Elicit information from the client/user. + + This method can be used to interactively ask for additional information from the + client within a tool's execution. The client might display the message to the + user and collect a response according to the provided schema. Or in case a + client is an agent, it might decide how to handle the elicitation -- either by asking + the user or automatically generating a response. + + Args: + schema: A Pydantic model class defining the expected response structure, according to the specification, + only primive types are allowed. + message: Optional message to present to the user. If not provided, will use + a default message based on the schema + + Returns: + An ElicitationResult containing the action taken and the data if accepted + + Note: + Check the result.action to determine if the user accepted, declined, or cancelled. + The result.data will only be populated if action is "accept" and validation succeeded. + """ + + return await elicit_with_validation( + session=self.request_context.session, + message=message, + schema=schema, + related_request_id=self.request_id, + ) + + async def elicit_url( + self, + message: str, + url: str, + elicitation_id: str, + ) -> UrlElicitationResult: + """Request URL mode elicitation from the client. + + This directs the user to an external URL for out-of-band interactions + that must not pass through the MCP client. Use this for: + - Collecting sensitive credentials (API keys, passwords) + - OAuth authorization flows with third-party services + - Payment and subscription flows + - Any interaction where data should not pass through the LLM context + + The response indicates whether the user consented to navigate to the URL. + The actual interaction happens out-of-band. When the elicitation completes, + call `self.session.send_elicit_complete(elicitation_id)` to notify the client. + + Args: + message: Human-readable explanation of why the interaction is needed + url: The URL the user should navigate to + elicitation_id: Unique identifier for tracking this elicitation + + Returns: + UrlElicitationResult indicating accept, decline, or cancel + """ + return await _elicit_url( + session=self.request_context.session, + message=message, + url=url, + elicitation_id=elicitation_id, + related_request_id=self.request_id, + ) + + async def log( + self, + level: Literal["debug", "info", "warning", "error"], + message: str, + *, + logger_name: str | None = None, + ) -> None: + """Send a log message to the client. + + Args: + level: Log level (debug, info, warning, error) + message: Log message + logger_name: Optional logger name + **extra: Additional structured data to include + """ + await self.request_context.session.send_log_message( + level=level, + data=message, + logger=logger_name, + related_request_id=self.request_id, + ) + + @property + def client_id(self) -> str | None: + """Get the client ID if available.""" + return ( + getattr(self.request_context.meta, "client_id", None) if self.request_context.meta else None + ) # pragma: no cover + + @property + def request_id(self) -> str: + """Get the unique ID for this request.""" + return str(self.request_context.request_id) + + @property + def session(self): + """Access to the underlying session for advanced usage.""" + return self.request_context.session + + async def close_sse_stream(self) -> None: + """Close the SSE stream to trigger client reconnection. + + This method closes the HTTP connection for the current request, triggering + client reconnection. Events continue to be stored in the event store and will + be replayed when the client reconnects with Last-Event-ID. + + Use this to implement polling behavior during long-running operations - + client will reconnect after the retry interval specified in the priming event. + + Note: + This is a no-op if not using StreamableHTTP transport with event_store. + The callback is only available when event_store is configured. + """ + if self._request_context and self._request_context.close_sse_stream: # pragma: no cover + await self._request_context.close_sse_stream() + + async def close_standalone_sse_stream(self) -> None: + """Close the standalone GET SSE stream to trigger client reconnection. + + This method closes the HTTP connection for the standalone GET stream used + for unsolicited server-to-client notifications. The client SHOULD reconnect + with Last-Event-ID to resume receiving notifications. + + Note: + This is a no-op if not using StreamableHTTP transport with event_store. + Currently, client reconnection for standalone GET streams is NOT + implemented - this is a known gap. + """ + if self._request_context and self._request_context.close_standalone_sse_stream: # pragma: no cover + await self._request_context.close_standalone_sse_stream() + + # Convenience methods for common log levels + async def debug(self, message: str, **extra: Any) -> None: + """Send a debug log message.""" + await self.log("debug", message, **extra) + + async def info(self, message: str, **extra: Any) -> None: + """Send an info log message.""" + await self.log("info", message, **extra) + + async def warning(self, message: str, **extra: Any) -> None: + """Send a warning log message.""" + await self.log("warning", message, **extra) + + async def error(self, message: str, **extra: Any) -> None: + """Send an error log message.""" + await self.log("error", message, **extra) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/tools/__init__.py b/source/target-vendors/cp312/mcp/server/fastmcp/tools/__init__.py new file mode 100644 index 0000000..ae9c656 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/tools/__init__.py @@ -0,0 +1,4 @@ +from .base import Tool +from .tool_manager import ToolManager + +__all__ = ["Tool", "ToolManager"] diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/tools/base.py b/source/target-vendors/cp312/mcp/server/fastmcp/tools/base.py new file mode 100644 index 0000000..1ae6d90 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/tools/base.py @@ -0,0 +1,126 @@ +from __future__ import annotations as _annotations + +import functools +import inspect +from collections.abc import Callable +from functools import cached_property +from typing import TYPE_CHECKING, Any + +from pydantic import BaseModel, Field + +from mcp.server.fastmcp.exceptions import ToolError +from mcp.server.fastmcp.utilities.context_injection import find_context_parameter +from mcp.server.fastmcp.utilities.func_metadata import FuncMetadata, func_metadata +from mcp.shared.exceptions import UrlElicitationRequiredError +from mcp.shared.tool_name_validation import validate_and_warn_tool_name +from mcp.types import Icon, ToolAnnotations + +if TYPE_CHECKING: + from mcp.server.fastmcp.server import Context + from mcp.server.session import ServerSessionT + from mcp.shared.context import LifespanContextT, RequestT + + +class Tool(BaseModel): + """Internal tool registration info.""" + + fn: Callable[..., Any] = Field(exclude=True) + name: str = Field(description="Name of the tool") + title: str | None = Field(None, description="Human-readable title of the tool") + description: str = Field(description="Description of what the tool does") + parameters: dict[str, Any] = Field(description="JSON schema for tool parameters") + fn_metadata: FuncMetadata = Field( + description="Metadata about the function including a pydantic model for tool arguments" + ) + is_async: bool = Field(description="Whether the tool is async") + context_kwarg: str | None = Field(None, description="Name of the kwarg that should receive context") + annotations: ToolAnnotations | None = Field(None, description="Optional annotations for the tool") + icons: list[Icon] | None = Field(default=None, description="Optional list of icons for this tool") + meta: dict[str, Any] | None = Field(default=None, description="Optional metadata for this tool") + + @cached_property + def output_schema(self) -> dict[str, Any] | None: + return self.fn_metadata.output_schema + + @classmethod + def from_function( + cls, + fn: Callable[..., Any], + name: str | None = None, + title: str | None = None, + description: str | None = None, + context_kwarg: str | None = None, + annotations: ToolAnnotations | None = None, + icons: list[Icon] | None = None, + meta: dict[str, Any] | None = None, + structured_output: bool | None = None, + ) -> Tool: + """Create a Tool from a function.""" + func_name = name or fn.__name__ + + validate_and_warn_tool_name(func_name) + + if func_name == "": + raise ValueError("You must provide a name for lambda functions") + + func_doc = description or fn.__doc__ or "" + is_async = _is_async_callable(fn) + + if context_kwarg is None: # pragma: no branch + context_kwarg = find_context_parameter(fn) + + func_arg_metadata = func_metadata( + fn, + skip_names=[context_kwarg] if context_kwarg is not None else [], + structured_output=structured_output, + ) + parameters = func_arg_metadata.arg_model.model_json_schema(by_alias=True) + + return cls( + fn=fn, + name=func_name, + title=title, + description=func_doc, + parameters=parameters, + fn_metadata=func_arg_metadata, + is_async=is_async, + context_kwarg=context_kwarg, + annotations=annotations, + icons=icons, + meta=meta, + ) + + async def run( + self, + arguments: dict[str, Any], + context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None, + convert_result: bool = False, + ) -> Any: + """Run the tool with arguments.""" + try: + result = await self.fn_metadata.call_fn_with_arg_validation( + self.fn, + self.is_async, + arguments, + {self.context_kwarg: context} if self.context_kwarg is not None else None, + ) + + if convert_result: + result = self.fn_metadata.convert_result(result) + + return result + except UrlElicitationRequiredError: + # Re-raise UrlElicitationRequiredError so it can be properly handled + # as an MCP error response with code -32042 + raise + except Exception as e: + raise ToolError(f"Error executing tool {self.name}: {e}") from e + + +def _is_async_callable(obj: Any) -> bool: + while isinstance(obj, functools.partial): # pragma: no cover + obj = obj.func + + return inspect.iscoroutinefunction(obj) or ( + callable(obj) and inspect.iscoroutinefunction(getattr(obj, "__call__", None)) + ) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/tools/tool_manager.py b/source/target-vendors/cp312/mcp/server/fastmcp/tools/tool_manager.py new file mode 100644 index 0000000..095753d --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/tools/tool_manager.py @@ -0,0 +1,93 @@ +from __future__ import annotations as _annotations + +from collections.abc import Callable +from typing import TYPE_CHECKING, Any + +from mcp.server.fastmcp.exceptions import ToolError +from mcp.server.fastmcp.tools.base import Tool +from mcp.server.fastmcp.utilities.logging import get_logger +from mcp.shared.context import LifespanContextT, RequestT +from mcp.types import Icon, ToolAnnotations + +if TYPE_CHECKING: + from mcp.server.fastmcp.server import Context + from mcp.server.session import ServerSessionT + +logger = get_logger(__name__) + + +class ToolManager: + """Manages FastMCP tools.""" + + def __init__( + self, + warn_on_duplicate_tools: bool = True, + *, + tools: list[Tool] | None = None, + ): + self._tools: dict[str, Tool] = {} + if tools is not None: + for tool in tools: + if warn_on_duplicate_tools and tool.name in self._tools: + logger.warning(f"Tool already exists: {tool.name}") + self._tools[tool.name] = tool + + self.warn_on_duplicate_tools = warn_on_duplicate_tools + + def get_tool(self, name: str) -> Tool | None: + """Get tool by name.""" + return self._tools.get(name) + + def list_tools(self) -> list[Tool]: + """List all registered tools.""" + return list(self._tools.values()) + + def add_tool( + self, + fn: Callable[..., Any], + name: str | None = None, + title: str | None = None, + description: str | None = None, + annotations: ToolAnnotations | None = None, + icons: list[Icon] | None = None, + meta: dict[str, Any] | None = None, + structured_output: bool | None = None, + ) -> Tool: + """Add a tool to the server.""" + tool = Tool.from_function( + fn, + name=name, + title=title, + description=description, + annotations=annotations, + icons=icons, + meta=meta, + structured_output=structured_output, + ) + existing = self._tools.get(tool.name) + if existing: + if self.warn_on_duplicate_tools: + logger.warning(f"Tool already exists: {tool.name}") + return existing + self._tools[tool.name] = tool + return tool + + def remove_tool(self, name: str) -> None: + """Remove a tool by name.""" + if name not in self._tools: + raise ToolError(f"Unknown tool: {name}") + del self._tools[name] + + async def call_tool( + self, + name: str, + arguments: dict[str, Any], + context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None, + convert_result: bool = False, + ) -> Any: + """Call a tool by name with arguments.""" + tool = self.get_tool(name) + if not tool: + raise ToolError(f"Unknown tool: {name}") + + return await tool.run(arguments, context=context, convert_result=convert_result) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/utilities/__init__.py b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/__init__.py new file mode 100644 index 0000000..be448f9 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/__init__.py @@ -0,0 +1 @@ +"""FastMCP utility modules.""" diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/utilities/context_injection.py b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/context_injection.py new file mode 100644 index 0000000..66d0cba --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/context_injection.py @@ -0,0 +1,68 @@ +"""Context injection utilities for FastMCP.""" + +from __future__ import annotations + +import inspect +import typing +from collections.abc import Callable +from typing import Any + + +def find_context_parameter(fn: Callable[..., Any]) -> str | None: + """Find the parameter that should receive the Context object. + + Searches through the function's signature to find a parameter + with a Context type annotation. + + Args: + fn: The function to inspect + + Returns: + The name of the context parameter, or None if not found + """ + from mcp.server.fastmcp.server import Context + + # Get type hints to properly resolve string annotations + try: + hints = typing.get_type_hints(fn) + except Exception: + # If we can't resolve type hints, we can't find the context parameter + return None + + # Check each parameter's type hint + for param_name, annotation in hints.items(): + # Handle direct Context type + if inspect.isclass(annotation) and issubclass(annotation, Context): + return param_name + + # Handle generic types like Optional[Context] + origin = typing.get_origin(annotation) + if origin is not None: + args = typing.get_args(annotation) + for arg in args: + if inspect.isclass(arg) and issubclass(arg, Context): + return param_name + + return None + + +def inject_context( + fn: Callable[..., Any], + kwargs: dict[str, Any], + context: Any | None, + context_kwarg: str | None, +) -> dict[str, Any]: + """Inject context into function kwargs if needed. + + Args: + fn: The function that will be called + kwargs: The current keyword arguments + context: The context object to inject (if any) + context_kwarg: The name of the parameter to inject into + + Returns: + Updated kwargs with context injected if applicable + """ + if context_kwarg is not None and context is not None: + return {**kwargs, context_kwarg: context} + return kwargs diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/utilities/func_metadata.py b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/func_metadata.py new file mode 100644 index 0000000..fa443d2 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/func_metadata.py @@ -0,0 +1,533 @@ +import inspect +import json +from collections.abc import Awaitable, Callable, Sequence +from itertools import chain +from types import GenericAlias +from typing import Annotated, Any, cast, get_args, get_origin, get_type_hints + +import pydantic_core +from pydantic import ( + BaseModel, + ConfigDict, + Field, + RootModel, + WithJsonSchema, + create_model, +) +from pydantic.fields import FieldInfo +from pydantic.json_schema import GenerateJsonSchema, JsonSchemaWarningKind +from typing_extensions import is_typeddict +from typing_inspection.introspection import ( + UNKNOWN, + AnnotationSource, + ForbiddenQualifier, + inspect_annotation, + is_union_origin, +) + +from mcp.server.fastmcp.exceptions import InvalidSignature +from mcp.server.fastmcp.utilities.logging import get_logger +from mcp.server.fastmcp.utilities.types import Audio, Image +from mcp.types import CallToolResult, ContentBlock, TextContent + +logger = get_logger(__name__) + + +class StrictJsonSchema(GenerateJsonSchema): + """A JSON schema generator that raises exceptions instead of emitting warnings. + + This is used to detect non-serializable types during schema generation. + """ + + def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: + # Raise an exception instead of emitting a warning + raise ValueError(f"JSON schema warning: {kind} - {detail}") + + +class ArgModelBase(BaseModel): + """A model representing the arguments to a function.""" + + def model_dump_one_level(self) -> dict[str, Any]: + """Return a dict of the model's fields, one level deep. + + That is, sub-models etc are not dumped - they are kept as pydantic models. + """ + kwargs: dict[str, Any] = {} + for field_name, field_info in self.__class__.model_fields.items(): + value = getattr(self, field_name) + # Use the alias if it exists, otherwise use the field name + output_name = field_info.alias if field_info.alias else field_name + kwargs[output_name] = value + return kwargs + + model_config = ConfigDict( + arbitrary_types_allowed=True, + ) + + +class FuncMetadata(BaseModel): + arg_model: Annotated[type[ArgModelBase], WithJsonSchema(None)] + output_schema: dict[str, Any] | None = None + output_model: Annotated[type[BaseModel], WithJsonSchema(None)] | None = None + wrap_output: bool = False + + async def call_fn_with_arg_validation( + self, + fn: Callable[..., Any | Awaitable[Any]], + fn_is_async: bool, + arguments_to_validate: dict[str, Any], + arguments_to_pass_directly: dict[str, Any] | None, + ) -> Any: + """Call the given function with arguments validated and injected. + + Arguments are first attempted to be parsed from JSON, then validated against + the argument model, before being passed to the function. + """ + arguments_pre_parsed = self.pre_parse_json(arguments_to_validate) + arguments_parsed_model = self.arg_model.model_validate(arguments_pre_parsed) + arguments_parsed_dict = arguments_parsed_model.model_dump_one_level() + + arguments_parsed_dict |= arguments_to_pass_directly or {} + + if fn_is_async: + return await fn(**arguments_parsed_dict) + else: + return fn(**arguments_parsed_dict) + + def convert_result(self, result: Any) -> Any: + """ + Convert the result of a function call to the appropriate format for + the lowlevel server tool call handler: + + - If output_model is None, return the unstructured content directly. + - If output_model is not None, convert the result to structured output format + (dict[str, Any]) and return both unstructured and structured content. + + Note: we return unstructured content here **even though the lowlevel server + tool call handler provides generic backwards compatibility serialization of + structured content**. This is for FastMCP backwards compatibility: we need to + retain FastMCP's ad hoc conversion logic for constructing unstructured output + from function return values, whereas the lowlevel server simply serializes + the structured output. + """ + if isinstance(result, CallToolResult): + if self.output_schema is not None: + assert self.output_model is not None, "Output model must be set if output schema is defined" + self.output_model.model_validate(result.structuredContent) + return result + + unstructured_content = _convert_to_content(result) + + if self.output_schema is None: + return unstructured_content + else: + if self.wrap_output: + result = {"result": result} + + assert self.output_model is not None, "Output model must be set if output schema is defined" + validated = self.output_model.model_validate(result) + structured_content = validated.model_dump(mode="json", by_alias=True) + + return (unstructured_content, structured_content) + + def pre_parse_json(self, data: dict[str, Any]) -> dict[str, Any]: + """Pre-parse data from JSON. + + Return a dict with same keys as input but with values parsed from JSON + if appropriate. + + This is to handle cases like `["a", "b", "c"]` being passed in as JSON inside + a string rather than an actual list. Claude desktop is prone to this - in fact + it seems incapable of NOT doing this. For sub-models, it tends to pass + dicts (JSON objects) as JSON strings, which can be pre-parsed here. + """ + new_data = data.copy() # Shallow copy + + # Build a mapping from input keys (including aliases) to field info + key_to_field_info: dict[str, FieldInfo] = {} + for field_name, field_info in self.arg_model.model_fields.items(): + # Map both the field name and its alias (if any) to the field info + key_to_field_info[field_name] = field_info + if field_info.alias: + key_to_field_info[field_info.alias] = field_info + + for data_key, data_value in data.items(): + if data_key not in key_to_field_info: # pragma: no cover + continue + + field_info = key_to_field_info[data_key] + if isinstance(data_value, str) and field_info.annotation is not str: + try: + pre_parsed = json.loads(data_value) + except json.JSONDecodeError: + continue # Not JSON - skip + if isinstance(pre_parsed, str | int | float): + # This is likely that the raw value is e.g. `"hello"` which we + # Should really be parsed as '"hello"' in Python - but if we parse + # it as JSON it'll turn into just 'hello'. So we skip it. + continue + new_data[data_key] = pre_parsed + assert new_data.keys() == data.keys() + return new_data + + model_config = ConfigDict( + arbitrary_types_allowed=True, + ) + + +def func_metadata( + func: Callable[..., Any], + skip_names: Sequence[str] = (), + structured_output: bool | None = None, +) -> FuncMetadata: + """Given a function, return metadata including a pydantic model representing its + signature. + + The use case for this is + ``` + meta = func_metadata(func) + validated_args = meta.arg_model.model_validate(some_raw_data_dict) + return func(**validated_args.model_dump_one_level()) + ``` + + **critically** it also provides pre-parse helper to attempt to parse things from + JSON. + + Args: + func: The function to convert to a pydantic model + skip_names: A list of parameter names to skip. These will not be included in + the model. + structured_output: Controls whether the tool's output is structured or unstructured + - If None, auto-detects based on the function's return type annotation + - If True, creates a structured tool (return type annotation permitting) + - If False, unconditionally creates an unstructured tool + + If structured, creates a Pydantic model for the function's result based on its annotation. + Supports various return types: + - BaseModel subclasses (used directly) + - Primitive types (str, int, float, bool, bytes, None) - wrapped in a + model with a 'result' field + - TypedDict - converted to a Pydantic model with same fields + - Dataclasses and other annotated classes - converted to Pydantic models + - Generic types (list, dict, Union, etc.) - wrapped in a model with a 'result' field + + Returns: + A FuncMetadata object containing: + - arg_model: A pydantic model representing the function's arguments + - output_model: A pydantic model for the return type if output is structured + - output_conversion: Records how function output should be converted before returning. + """ + try: + sig = inspect.signature(func, eval_str=True) + except NameError as e: # pragma: no cover + # This raise could perhaps be skipped, and we (FastMCP) just call + # model_rebuild right before using it 🤷 + raise InvalidSignature(f"Unable to evaluate type annotations for callable {func.__name__!r}") from e + params = sig.parameters + dynamic_pydantic_model_params: dict[str, Any] = {} + for param in params.values(): + if param.name.startswith("_"): # pragma: no cover + raise InvalidSignature(f"Parameter {param.name} of {func.__name__} cannot start with '_'") + if param.name in skip_names: + continue + + annotation = param.annotation if param.annotation is not inspect.Parameter.empty else Any + field_name = param.name + field_kwargs: dict[str, Any] = {} + field_metadata: list[Any] = [] + + if param.annotation is inspect.Parameter.empty: + field_metadata.append(WithJsonSchema({"title": param.name, "type": "string"})) + # Check if the parameter name conflicts with BaseModel attributes + # This is necessary because Pydantic warns about shadowing parent attributes + if hasattr(BaseModel, field_name) and callable(getattr(BaseModel, field_name)): + # Use an alias to avoid the shadowing warning + field_kwargs["alias"] = field_name + # Use a prefixed field name + field_name = f"field_{field_name}" + + if param.default is not inspect.Parameter.empty: + dynamic_pydantic_model_params[field_name] = ( + Annotated[(annotation, *field_metadata, Field(**field_kwargs))], + param.default, + ) + else: + dynamic_pydantic_model_params[field_name] = Annotated[(annotation, *field_metadata, Field(**field_kwargs))] + + arguments_model = create_model( + f"{func.__name__}Arguments", + __base__=ArgModelBase, + **dynamic_pydantic_model_params, + ) + + if structured_output is False: + return FuncMetadata(arg_model=arguments_model) + + # set up structured output support based on return type annotation + + if sig.return_annotation is inspect.Parameter.empty and structured_output is True: + raise InvalidSignature(f"Function {func.__name__}: return annotation required for structured output") + + try: + inspected_return_ann = inspect_annotation(sig.return_annotation, annotation_source=AnnotationSource.FUNCTION) + except ForbiddenQualifier as e: + raise InvalidSignature(f"Function {func.__name__}: return annotation contains an invalid type qualifier") from e + + return_type_expr = inspected_return_ann.type + + # `AnnotationSource.FUNCTION` allows no type qualifier to be used, so `return_type_expr` is guaranteed to *not* be + # unknown (i.e. a bare `Final`). + assert return_type_expr is not UNKNOWN + + if is_union_origin(get_origin(return_type_expr)): + args = get_args(return_type_expr) + # Check if CallToolResult appears in the union (excluding None for Optional check) + if any(isinstance(arg, type) and issubclass(arg, CallToolResult) for arg in args if arg is not type(None)): + raise InvalidSignature( + f"Function {func.__name__}: CallToolResult cannot be used in Union or Optional types. " + "To return empty results, use: CallToolResult(content=[])" + ) + + original_annotation: Any + # if the typehint is CallToolResult, the user either intends to return without validation + # or they provided validation as Annotated metadata + if isinstance(return_type_expr, type) and issubclass(return_type_expr, CallToolResult): + if inspected_return_ann.metadata: + return_type_expr = inspected_return_ann.metadata[0] + if len(inspected_return_ann.metadata) >= 2: + # Reconstruct the original annotation, by preserving the remaining metadata, + # i.e. from `Annotated[CallToolResult, ReturnType, Gt(1)]` to + # `Annotated[ReturnType, Gt(1)]`: + original_annotation = Annotated[ + (return_type_expr, *inspected_return_ann.metadata[1:]) + ] # pragma: no cover + else: + # We only had `Annotated[CallToolResult, ReturnType]`, treat the original annotation + # as beging `ReturnType`: + original_annotation = return_type_expr + else: + return FuncMetadata(arg_model=arguments_model) + else: + original_annotation = sig.return_annotation + + output_model, output_schema, wrap_output = _try_create_model_and_schema( + original_annotation, return_type_expr, func.__name__ + ) + + if output_model is None and structured_output is True: + # Model creation failed or produced warnings - no structured output + raise InvalidSignature( + f"Function {func.__name__}: return type {return_type_expr} is not serializable for structured output" + ) + + return FuncMetadata( + arg_model=arguments_model, + output_schema=output_schema, + output_model=output_model, + wrap_output=wrap_output, + ) + + +def _try_create_model_and_schema( + original_annotation: Any, + type_expr: Any, + func_name: str, +) -> tuple[type[BaseModel] | None, dict[str, Any] | None, bool]: + """Try to create a model and schema for the given annotation without warnings. + + Args: + original_annotation: The original return annotation (may be wrapped in `Annotated`). + type_expr: The underlying type expression derived from the return annotation + (`Annotated` and type qualifiers were stripped). + func_name: The name of the function. + + Returns: + tuple of (model or None, schema or None, wrap_output) + Model and schema are None if warnings occur or creation fails. + wrap_output is True if the result needs to be wrapped in {"result": ...} + """ + model = None + wrap_output = False + + # First handle special case: None + if type_expr is None: + model = _create_wrapped_model(func_name, original_annotation) + wrap_output = True + + # Handle GenericAlias types (list[str], dict[str, int], Union[str, int], etc.) + elif isinstance(type_expr, GenericAlias): + origin = get_origin(type_expr) + + # Special case: dict with string keys can use RootModel + if origin is dict: + args = get_args(type_expr) + if len(args) == 2 and args[0] is str: + # TODO: should we use the original annotation? We are loosing any potential `Annotated` + # metadata for Pydantic here: + model = _create_dict_model(func_name, type_expr) + else: + # dict with non-str keys needs wrapping + model = _create_wrapped_model(func_name, original_annotation) + wrap_output = True + else: + # All other generic types need wrapping (list, tuple, Union, Optional, etc.) + model = _create_wrapped_model(func_name, original_annotation) + wrap_output = True + + # Handle regular type objects + elif isinstance(type_expr, type): + type_annotation = cast(type[Any], type_expr) + + # Case 1: BaseModel subclasses (can be used directly) + if issubclass(type_annotation, BaseModel): + model = type_annotation + + # Case 2: TypedDicts: + elif is_typeddict(type_annotation): + model = _create_model_from_typeddict(type_annotation) + + # Case 3: Primitive types that need wrapping + elif type_annotation in (str, int, float, bool, bytes, type(None)): + model = _create_wrapped_model(func_name, original_annotation) + wrap_output = True + + # Case 4: Other class types (dataclasses, regular classes with annotations) + else: + type_hints = get_type_hints(type_annotation) + if type_hints: + # Classes with type hints can be converted to Pydantic models + model = _create_model_from_class(type_annotation, type_hints) + # Classes without type hints are not serializable - model remains None + + # Handle any other types not covered above + else: + # This includes typing constructs that aren't GenericAlias in Python 3.10 + # (e.g., Union, Optional in some Python versions) + model = _create_wrapped_model(func_name, original_annotation) + wrap_output = True + + if model: + # If we successfully created a model, try to get its schema + # Use StrictJsonSchema to raise exceptions instead of warnings + try: + schema = model.model_json_schema(schema_generator=StrictJsonSchema) + except (TypeError, ValueError, pydantic_core.SchemaError, pydantic_core.ValidationError) as e: + # These are expected errors when a type can't be converted to a Pydantic schema + # TypeError: When Pydantic can't handle the type + # ValueError: When there are issues with the type definition (including our custom warnings) + # SchemaError: When Pydantic can't build a schema + # ValidationError: When validation fails + logger.info(f"Cannot create schema for type {type_expr} in {func_name}: {type(e).__name__}: {e}") + return None, None, False + + return model, schema, wrap_output + + return None, None, False + + +_no_default = object() + + +def _create_model_from_class(cls: type[Any], type_hints: dict[str, Any]) -> type[BaseModel]: + """Create a Pydantic model from an ordinary class. + + The created model will: + - Have the same name as the class + - Have fields with the same names and types as the class's fields + - Include all fields whose type does not include None in the set of required fields + + Precondition: cls must have type hints (i.e., `type_hints` is non-empty) + """ + model_fields: dict[str, Any] = {} + for field_name, field_type in type_hints.items(): + if field_name.startswith("_"): # pragma: no cover + continue + + default = getattr(cls, field_name, _no_default) + if default is _no_default: + model_fields[field_name] = field_type + else: + model_fields[field_name] = (field_type, default) + + return create_model(cls.__name__, __config__=ConfigDict(from_attributes=True), **model_fields) + + +def _create_model_from_typeddict(td_type: type[Any]) -> type[BaseModel]: + """Create a Pydantic model from a TypedDict. + + The created model will have the same name and fields as the TypedDict. + """ + type_hints = get_type_hints(td_type) + required_keys = getattr(td_type, "__required_keys__", set(type_hints.keys())) + + model_fields: dict[str, Any] = {} + for field_name, field_type in type_hints.items(): + if field_name not in required_keys: + # For optional TypedDict fields, set default=None + # This makes them not required in the Pydantic model + # The model should use exclude_unset=True when dumping to get TypedDict semantics + model_fields[field_name] = (field_type, None) + else: + model_fields[field_name] = field_type + + return create_model(td_type.__name__, **model_fields) + + +def _create_wrapped_model(func_name: str, annotation: Any) -> type[BaseModel]: + """Create a model that wraps a type in a 'result' field. + + This is used for primitive types, generic types like list/dict, etc. + """ + model_name = f"{func_name}Output" + + return create_model(model_name, result=annotation) + + +def _create_dict_model(func_name: str, dict_annotation: Any) -> type[BaseModel]: + """Create a RootModel for dict[str, T] types.""" + + class DictModel(RootModel[dict_annotation]): + pass + + # Give it a meaningful name + DictModel.__name__ = f"{func_name}DictOutput" + DictModel.__qualname__ = f"{func_name}DictOutput" + + return DictModel + + +def _convert_to_content( + result: Any, +) -> Sequence[ContentBlock]: + """ + Convert a result to a sequence of content objects. + + Note: This conversion logic comes from previous versions of FastMCP and is being + retained for purposes of backwards compatibility. It produces different unstructured + output than the lowlevel server tool call handler, which just serializes structured + content verbatim. + """ + if result is None: # pragma: no cover + return [] + + if isinstance(result, ContentBlock): + return [result] + + if isinstance(result, Image): + return [result.to_image_content()] + + if isinstance(result, Audio): + return [result.to_audio_content()] + + if isinstance(result, list | tuple): + return list( + chain.from_iterable( + _convert_to_content(item) + for item in result # type: ignore + ) + ) + + if not isinstance(result, str): + result = pydantic_core.to_json(result, fallback=str, indent=2).decode() + + return [TextContent(type="text", text=result)] diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/utilities/logging.py b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/logging.py new file mode 100644 index 0000000..4b47d3b --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/logging.py @@ -0,0 +1,43 @@ +"""Logging utilities for FastMCP.""" + +import logging +from typing import Literal + + +def get_logger(name: str) -> logging.Logger: + """Get a logger nested under MCPnamespace. + + Args: + name: the name of the logger, which will be prefixed with 'FastMCP.' + + Returns: + a configured logger instance + """ + return logging.getLogger(name) + + +def configure_logging( + level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO", +) -> None: + """Configure logging for MCP. + + Args: + level: the log level to use + """ + handlers: list[logging.Handler] = [] + try: # pragma: no cover + from rich.console import Console + from rich.logging import RichHandler + + handlers.append(RichHandler(console=Console(stderr=True), rich_tracebacks=True)) + except ImportError: # pragma: no cover + pass + + if not handlers: # pragma: no cover + handlers.append(logging.StreamHandler()) + + logging.basicConfig( + level=level, + format="%(message)s", + handlers=handlers, + ) diff --git a/source/target-vendors/cp312/mcp/server/fastmcp/utilities/types.py b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/types.py new file mode 100644 index 0000000..d6928ca --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/fastmcp/utilities/types.py @@ -0,0 +1,101 @@ +"""Common types used across FastMCP.""" + +import base64 +from pathlib import Path + +from mcp.types import AudioContent, ImageContent + + +class Image: + """Helper class for returning images from tools.""" + + def __init__( + self, + path: str | Path | None = None, + data: bytes | None = None, + format: str | None = None, + ): + if path is None and data is None: # pragma: no cover + raise ValueError("Either path or data must be provided") + if path is not None and data is not None: # pragma: no cover + raise ValueError("Only one of path or data can be provided") + + self.path = Path(path) if path else None + self.data = data + self._format = format + self._mime_type = self._get_mime_type() + + def _get_mime_type(self) -> str: + """Get MIME type from format or guess from file extension.""" + if self._format: # pragma: no cover + return f"image/{self._format.lower()}" + + if self.path: + suffix = self.path.suffix.lower() + return { + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".webp": "image/webp", + }.get(suffix, "application/octet-stream") + return "image/png" # pragma: no cover # default for raw binary data + + def to_image_content(self) -> ImageContent: + """Convert to MCP ImageContent.""" + if self.path: + with open(self.path, "rb") as f: + data = base64.b64encode(f.read()).decode() + elif self.data is not None: # pragma: no cover + data = base64.b64encode(self.data).decode() + else: # pragma: no cover + raise ValueError("No image data available") + + return ImageContent(type="image", data=data, mimeType=self._mime_type) + + +class Audio: + """Helper class for returning audio from tools.""" + + def __init__( + self, + path: str | Path | None = None, + data: bytes | None = None, + format: str | None = None, + ): + if not bool(path) ^ bool(data): # pragma: no cover + raise ValueError("Either path or data can be provided") + + self.path = Path(path) if path else None + self.data = data + self._format = format + self._mime_type = self._get_mime_type() + + def _get_mime_type(self) -> str: + """Get MIME type from format or guess from file extension.""" + if self._format: # pragma: no cover + return f"audio/{self._format.lower()}" + + if self.path: + suffix = self.path.suffix.lower() + return { + ".wav": "audio/wav", + ".mp3": "audio/mpeg", + ".ogg": "audio/ogg", + ".flac": "audio/flac", + ".aac": "audio/aac", + ".m4a": "audio/mp4", + }.get(suffix, "application/octet-stream") + return "audio/wav" # pragma: no cover # default for raw binary data + + def to_audio_content(self) -> AudioContent: + """Convert to MCP AudioContent.""" + if self.path: + with open(self.path, "rb") as f: + data = base64.b64encode(f.read()).decode() + elif self.data is not None: # pragma: no cover + data = base64.b64encode(self.data).decode() + else: # pragma: no cover + raise ValueError("No audio data available") + + return AudioContent(type="audio", data=data, mimeType=self._mime_type) diff --git a/source/target-vendors/cp312/mcp/server/lowlevel/__init__.py b/source/target-vendors/cp312/mcp/server/lowlevel/__init__.py new file mode 100644 index 0000000..66df389 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/lowlevel/__init__.py @@ -0,0 +1,3 @@ +from .server import NotificationOptions, Server + +__all__ = ["Server", "NotificationOptions"] diff --git a/source/target-vendors/cp312/mcp/server/lowlevel/experimental.py b/source/target-vendors/cp312/mcp/server/lowlevel/experimental.py new file mode 100644 index 0000000..0e6655b --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/lowlevel/experimental.py @@ -0,0 +1,288 @@ +"""Experimental handlers for the low-level MCP server. + +WARNING: These APIs are experimental and may change without notice. +""" + +from __future__ import annotations + +import logging +from collections.abc import Awaitable, Callable +from typing import TYPE_CHECKING + +from mcp.server.experimental.task_support import TaskSupport +from mcp.server.lowlevel.func_inspection import create_call_wrapper +from mcp.shared.exceptions import McpError +from mcp.shared.experimental.tasks.helpers import cancel_task +from mcp.shared.experimental.tasks.in_memory_task_store import InMemoryTaskStore +from mcp.shared.experimental.tasks.message_queue import InMemoryTaskMessageQueue, TaskMessageQueue +from mcp.shared.experimental.tasks.store import TaskStore +from mcp.types import ( + INVALID_PARAMS, + CancelTaskRequest, + CancelTaskResult, + ErrorData, + GetTaskPayloadRequest, + GetTaskPayloadResult, + GetTaskRequest, + GetTaskResult, + ListTasksRequest, + ListTasksResult, + ServerCapabilities, + ServerResult, + ServerTasksCapability, + ServerTasksRequestsCapability, + TasksCancelCapability, + TasksListCapability, + TasksToolsCapability, +) + +if TYPE_CHECKING: + from mcp.server.lowlevel.server import Server + +logger = logging.getLogger(__name__) + + +class ExperimentalHandlers: + """Experimental request/notification handlers. + + WARNING: These APIs are experimental and may change without notice. + """ + + def __init__( + self, + server: Server, + request_handlers: dict[type, Callable[..., Awaitable[ServerResult]]], + notification_handlers: dict[type, Callable[..., Awaitable[None]]], + ): + self._server = server + self._request_handlers = request_handlers + self._notification_handlers = notification_handlers + self._task_support: TaskSupport | None = None + + @property + def task_support(self) -> TaskSupport | None: + """Get the task support configuration, if enabled.""" + return self._task_support + + def update_capabilities(self, capabilities: ServerCapabilities) -> None: + # Only add tasks capability if handlers are registered + if not any( + req_type in self._request_handlers + for req_type in [GetTaskRequest, ListTasksRequest, CancelTaskRequest, GetTaskPayloadRequest] + ): + return + + capabilities.tasks = ServerTasksCapability() + if ListTasksRequest in self._request_handlers: + capabilities.tasks.list = TasksListCapability() + if CancelTaskRequest in self._request_handlers: + capabilities.tasks.cancel = TasksCancelCapability() + + capabilities.tasks.requests = ServerTasksRequestsCapability( + tools=TasksToolsCapability() + ) # assuming always supported for now + + def enable_tasks( + self, + store: TaskStore | None = None, + queue: TaskMessageQueue | None = None, + ) -> TaskSupport: + """ + Enable experimental task support. + + This sets up the task infrastructure and auto-registers default handlers + for tasks/get, tasks/result, tasks/list, and tasks/cancel. + + Args: + store: Custom TaskStore implementation (defaults to InMemoryTaskStore) + queue: Custom TaskMessageQueue implementation (defaults to InMemoryTaskMessageQueue) + + Returns: + The TaskSupport configuration object + + Example: + # Simple in-memory setup + server.experimental.enable_tasks() + + # Custom store/queue for distributed systems + server.experimental.enable_tasks( + store=RedisTaskStore(redis_url), + queue=RedisTaskMessageQueue(redis_url), + ) + + WARNING: This API is experimental and may change without notice. + """ + if store is None: + store = InMemoryTaskStore() + if queue is None: + queue = InMemoryTaskMessageQueue() + + self._task_support = TaskSupport(store=store, queue=queue) + + # Auto-register default handlers + self._register_default_task_handlers() + + return self._task_support + + def _register_default_task_handlers(self) -> None: + """Register default handlers for task operations.""" + assert self._task_support is not None + support = self._task_support + + # Register get_task handler if not already registered + if GetTaskRequest not in self._request_handlers: + + async def _default_get_task(req: GetTaskRequest) -> ServerResult: + task = await support.store.get_task(req.params.taskId) + if task is None: + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message=f"Task not found: {req.params.taskId}", + ) + ) + return ServerResult( + GetTaskResult( + taskId=task.taskId, + status=task.status, + statusMessage=task.statusMessage, + createdAt=task.createdAt, + lastUpdatedAt=task.lastUpdatedAt, + ttl=task.ttl, + pollInterval=task.pollInterval, + ) + ) + + self._request_handlers[GetTaskRequest] = _default_get_task + + # Register get_task_result handler if not already registered + if GetTaskPayloadRequest not in self._request_handlers: + + async def _default_get_task_result(req: GetTaskPayloadRequest) -> ServerResult: + ctx = self._server.request_context + result = await support.handler.handle(req, ctx.session, ctx.request_id) + return ServerResult(result) + + self._request_handlers[GetTaskPayloadRequest] = _default_get_task_result + + # Register list_tasks handler if not already registered + if ListTasksRequest not in self._request_handlers: + + async def _default_list_tasks(req: ListTasksRequest) -> ServerResult: + cursor = req.params.cursor if req.params else None + tasks, next_cursor = await support.store.list_tasks(cursor) + return ServerResult(ListTasksResult(tasks=tasks, nextCursor=next_cursor)) + + self._request_handlers[ListTasksRequest] = _default_list_tasks + + # Register cancel_task handler if not already registered + if CancelTaskRequest not in self._request_handlers: + + async def _default_cancel_task(req: CancelTaskRequest) -> ServerResult: + result = await cancel_task(support.store, req.params.taskId) + return ServerResult(result) + + self._request_handlers[CancelTaskRequest] = _default_cancel_task + + def list_tasks( + self, + ) -> Callable[ + [Callable[[ListTasksRequest], Awaitable[ListTasksResult]]], + Callable[[ListTasksRequest], Awaitable[ListTasksResult]], + ]: + """Register a handler for listing tasks. + + WARNING: This API is experimental and may change without notice. + """ + + def decorator( + func: Callable[[ListTasksRequest], Awaitable[ListTasksResult]], + ) -> Callable[[ListTasksRequest], Awaitable[ListTasksResult]]: + logger.debug("Registering handler for ListTasksRequest") + wrapper = create_call_wrapper(func, ListTasksRequest) + + async def handler(req: ListTasksRequest) -> ServerResult: + result = await wrapper(req) + return ServerResult(result) + + self._request_handlers[ListTasksRequest] = handler + return func + + return decorator + + def get_task( + self, + ) -> Callable[ + [Callable[[GetTaskRequest], Awaitable[GetTaskResult]]], Callable[[GetTaskRequest], Awaitable[GetTaskResult]] + ]: + """Register a handler for getting task status. + + WARNING: This API is experimental and may change without notice. + """ + + def decorator( + func: Callable[[GetTaskRequest], Awaitable[GetTaskResult]], + ) -> Callable[[GetTaskRequest], Awaitable[GetTaskResult]]: + logger.debug("Registering handler for GetTaskRequest") + wrapper = create_call_wrapper(func, GetTaskRequest) + + async def handler(req: GetTaskRequest) -> ServerResult: + result = await wrapper(req) + return ServerResult(result) + + self._request_handlers[GetTaskRequest] = handler + return func + + return decorator + + def get_task_result( + self, + ) -> Callable[ + [Callable[[GetTaskPayloadRequest], Awaitable[GetTaskPayloadResult]]], + Callable[[GetTaskPayloadRequest], Awaitable[GetTaskPayloadResult]], + ]: + """Register a handler for getting task results/payload. + + WARNING: This API is experimental and may change without notice. + """ + + def decorator( + func: Callable[[GetTaskPayloadRequest], Awaitable[GetTaskPayloadResult]], + ) -> Callable[[GetTaskPayloadRequest], Awaitable[GetTaskPayloadResult]]: + logger.debug("Registering handler for GetTaskPayloadRequest") + wrapper = create_call_wrapper(func, GetTaskPayloadRequest) + + async def handler(req: GetTaskPayloadRequest) -> ServerResult: + result = await wrapper(req) + return ServerResult(result) + + self._request_handlers[GetTaskPayloadRequest] = handler + return func + + return decorator + + def cancel_task( + self, + ) -> Callable[ + [Callable[[CancelTaskRequest], Awaitable[CancelTaskResult]]], + Callable[[CancelTaskRequest], Awaitable[CancelTaskResult]], + ]: + """Register a handler for cancelling tasks. + + WARNING: This API is experimental and may change without notice. + """ + + def decorator( + func: Callable[[CancelTaskRequest], Awaitable[CancelTaskResult]], + ) -> Callable[[CancelTaskRequest], Awaitable[CancelTaskResult]]: + logger.debug("Registering handler for CancelTaskRequest") + wrapper = create_call_wrapper(func, CancelTaskRequest) + + async def handler(req: CancelTaskRequest) -> ServerResult: + result = await wrapper(req) + return ServerResult(result) + + self._request_handlers[CancelTaskRequest] = handler + return func + + return decorator diff --git a/source/target-vendors/cp312/mcp/server/lowlevel/func_inspection.py b/source/target-vendors/cp312/mcp/server/lowlevel/func_inspection.py new file mode 100644 index 0000000..6231aa8 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/lowlevel/func_inspection.py @@ -0,0 +1,54 @@ +import inspect +from collections.abc import Callable +from typing import Any, TypeVar, get_type_hints + +T = TypeVar("T") +R = TypeVar("R") + + +def create_call_wrapper(func: Callable[..., R], request_type: type[T]) -> Callable[[T], R]: + """ + Create a wrapper function that knows how to call func with the request object. + + Returns a wrapper function that takes the request and calls func appropriately. + + The wrapper handles three calling patterns: + 1. Positional-only parameter typed as request_type (no default): func(req) + 2. Positional/keyword parameter typed as request_type (no default): func(**{param_name: req}) + 3. No request parameter or parameter with default: func() + """ + try: + sig = inspect.signature(func) + type_hints = get_type_hints(func) + except (ValueError, TypeError, NameError): # pragma: no cover + return lambda _: func() + + # Check for positional-only parameter typed as request_type + for param_name, param in sig.parameters.items(): + if param.kind == inspect.Parameter.POSITIONAL_ONLY: + param_type = type_hints.get(param_name) + if param_type == request_type: # pragma: no branch + # Check if it has a default - if so, treat as old style + if param.default is not inspect.Parameter.empty: # pragma: no cover + return lambda _: func() + # Found positional-only parameter with correct type and no default + return lambda req: func(req) + + # Check for any positional/keyword parameter typed as request_type + for param_name, param in sig.parameters.items(): + if param.kind in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY): # pragma: no branch + param_type = type_hints.get(param_name) + if param_type == request_type: + # Check if it has a default - if so, treat as old style + if param.default is not inspect.Parameter.empty: # pragma: no cover + return lambda _: func() + + # Found keyword parameter with correct type and no default + # Need to capture param_name in closure properly + def make_keyword_wrapper(name: str) -> Callable[[Any], Any]: + return lambda req: func(**{name: req}) + + return make_keyword_wrapper(param_name) + + # No request parameter found - use old style + return lambda _: func() diff --git a/source/target-vendors/cp312/mcp/server/lowlevel/helper_types.py b/source/target-vendors/cp312/mcp/server/lowlevel/helper_types.py new file mode 100644 index 0000000..fecc716 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/lowlevel/helper_types.py @@ -0,0 +1,11 @@ +from dataclasses import dataclass +from typing import Any + + +@dataclass +class ReadResourceContents: + """Contents returned from a read_resource call.""" + + content: str | bytes + mime_type: str | None = None + meta: dict[str, Any] | None = None diff --git a/source/target-vendors/cp312/mcp/server/lowlevel/server.py b/source/target-vendors/cp312/mcp/server/lowlevel/server.py new file mode 100644 index 0000000..6745362 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/lowlevel/server.py @@ -0,0 +1,803 @@ +""" +MCP Server Module + +This module provides a framework for creating an MCP (Model Context Protocol) server. +It allows you to easily define and handle various types of requests and notifications +in an asynchronous manner. + +Usage: +1. Create a Server instance: + server = Server("your_server_name") + +2. Define request handlers using decorators: + @server.list_prompts() + async def handle_list_prompts(request: types.ListPromptsRequest) -> types.ListPromptsResult: + # Implementation + + @server.get_prompt() + async def handle_get_prompt( + name: str, arguments: dict[str, str] | None + ) -> types.GetPromptResult: + # Implementation + + @server.list_tools() + async def handle_list_tools(request: types.ListToolsRequest) -> types.ListToolsResult: + # Implementation + + @server.call_tool() + async def handle_call_tool( + name: str, arguments: dict | None + ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]: + # Implementation + + @server.list_resource_templates() + async def handle_list_resource_templates() -> list[types.ResourceTemplate]: + # Implementation + +3. Define notification handlers if needed: + @server.progress_notification() + async def handle_progress( + progress_token: str | int, progress: float, total: float | None, + message: str | None + ) -> None: + # Implementation + +4. Run the server: + async def main(): + async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): + await server.run( + read_stream, + write_stream, + InitializationOptions( + server_name="your_server_name", + server_version="your_version", + capabilities=server.get_capabilities( + notification_options=NotificationOptions(), + experimental_capabilities={}, + ), + ), + ) + + asyncio.run(main()) + +The Server class provides methods to register handlers for various MCP requests and +notifications. It automatically manages the request context and handles incoming +messages from the client. +""" + +from __future__ import annotations as _annotations + +import base64 +import contextvars +import json +import logging +import warnings +from collections.abc import AsyncIterator, Awaitable, Callable, Iterable +from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager +from typing import Any, Generic, TypeAlias, cast + +import anyio +import jsonschema +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import AnyUrl +from typing_extensions import TypeVar + +import mcp.types as types +from mcp.server.experimental.request_context import Experimental +from mcp.server.lowlevel.experimental import ExperimentalHandlers +from mcp.server.lowlevel.func_inspection import create_call_wrapper +from mcp.server.lowlevel.helper_types import ReadResourceContents +from mcp.server.models import InitializationOptions +from mcp.server.session import ServerSession +from mcp.shared.context import RequestContext +from mcp.shared.exceptions import McpError, UrlElicitationRequiredError +from mcp.shared.message import ServerMessageMetadata, SessionMessage +from mcp.shared.session import RequestResponder +from mcp.shared.tool_name_validation import validate_and_warn_tool_name + +logger = logging.getLogger(__name__) + +LifespanResultT = TypeVar("LifespanResultT", default=Any) +RequestT = TypeVar("RequestT", default=Any) + +# type aliases for tool call results +StructuredContent: TypeAlias = dict[str, Any] +UnstructuredContent: TypeAlias = Iterable[types.ContentBlock] +CombinationContent: TypeAlias = tuple[UnstructuredContent, StructuredContent] + +# This will be properly typed in each Server instance's context +request_ctx: contextvars.ContextVar[RequestContext[ServerSession, Any, Any]] = contextvars.ContextVar("request_ctx") + + +class NotificationOptions: + def __init__( + self, + prompts_changed: bool = False, + resources_changed: bool = False, + tools_changed: bool = False, + ): + self.prompts_changed = prompts_changed + self.resources_changed = resources_changed + self.tools_changed = tools_changed + + +@asynccontextmanager +async def lifespan(_: Server[LifespanResultT, RequestT]) -> AsyncIterator[dict[str, Any]]: + """Default lifespan context manager that does nothing. + + Args: + server: The server instance this lifespan is managing + + Returns: + An empty context object + """ + yield {} + + +class Server(Generic[LifespanResultT, RequestT]): + def __init__( + self, + name: str, + version: str | None = None, + instructions: str | None = None, + website_url: str | None = None, + icons: list[types.Icon] | None = None, + lifespan: Callable[ + [Server[LifespanResultT, RequestT]], + AbstractAsyncContextManager[LifespanResultT], + ] = lifespan, + ): + self.name = name + self.version = version + self.instructions = instructions + self.website_url = website_url + self.icons = icons + self.lifespan = lifespan + self.request_handlers: dict[type, Callable[..., Awaitable[types.ServerResult]]] = { + types.PingRequest: _ping_handler, + } + self.notification_handlers: dict[type, Callable[..., Awaitable[None]]] = {} + self._tool_cache: dict[str, types.Tool] = {} + self._experimental_handlers: ExperimentalHandlers | None = None + logger.debug("Initializing server %r", name) + + def create_initialization_options( + self, + notification_options: NotificationOptions | None = None, + experimental_capabilities: dict[str, dict[str, Any]] | None = None, + ) -> InitializationOptions: + """Create initialization options from this server instance.""" + + def pkg_version(package: str) -> str: + try: + from importlib.metadata import version + + return version(package) + except Exception: # pragma: no cover + pass + + return "unknown" # pragma: no cover + + return InitializationOptions( + server_name=self.name, + server_version=self.version if self.version else pkg_version("mcp"), + capabilities=self.get_capabilities( + notification_options or NotificationOptions(), + experimental_capabilities or {}, + ), + instructions=self.instructions, + website_url=self.website_url, + icons=self.icons, + ) + + def get_capabilities( + self, + notification_options: NotificationOptions, + experimental_capabilities: dict[str, dict[str, Any]], + ) -> types.ServerCapabilities: + """Convert existing handlers to a ServerCapabilities object.""" + prompts_capability = None + resources_capability = None + tools_capability = None + logging_capability = None + completions_capability = None + + # Set prompt capabilities if handler exists + if types.ListPromptsRequest in self.request_handlers: + prompts_capability = types.PromptsCapability(listChanged=notification_options.prompts_changed) + + # Set resource capabilities if handler exists + if types.ListResourcesRequest in self.request_handlers: + resources_capability = types.ResourcesCapability( + subscribe=False, listChanged=notification_options.resources_changed + ) + + # Set tool capabilities if handler exists + if types.ListToolsRequest in self.request_handlers: + tools_capability = types.ToolsCapability(listChanged=notification_options.tools_changed) + + # Set logging capabilities if handler exists + if types.SetLevelRequest in self.request_handlers: # pragma: no cover + logging_capability = types.LoggingCapability() + + # Set completions capabilities if handler exists + if types.CompleteRequest in self.request_handlers: + completions_capability = types.CompletionsCapability() + + capabilities = types.ServerCapabilities( + prompts=prompts_capability, + resources=resources_capability, + tools=tools_capability, + logging=logging_capability, + experimental=experimental_capabilities, + completions=completions_capability, + ) + if self._experimental_handlers: + self._experimental_handlers.update_capabilities(capabilities) + return capabilities + + @property + def request_context( + self, + ) -> RequestContext[ServerSession, LifespanResultT, RequestT]: + """If called outside of a request context, this will raise a LookupError.""" + return request_ctx.get() + + @property + def experimental(self) -> ExperimentalHandlers: + """Experimental APIs for tasks and other features. + + WARNING: These APIs are experimental and may change without notice. + """ + + # We create this inline so we only add these capabilities _if_ they're actually used + if self._experimental_handlers is None: + self._experimental_handlers = ExperimentalHandlers(self, self.request_handlers, self.notification_handlers) + return self._experimental_handlers + + def list_prompts(self): + def decorator( + func: Callable[[], Awaitable[list[types.Prompt]]] + | Callable[[types.ListPromptsRequest], Awaitable[types.ListPromptsResult]], + ): + logger.debug("Registering handler for PromptListRequest") + + wrapper = create_call_wrapper(func, types.ListPromptsRequest) + + async def handler(req: types.ListPromptsRequest): + result = await wrapper(req) + # Handle both old style (list[Prompt]) and new style (ListPromptsResult) + if isinstance(result, types.ListPromptsResult): + return types.ServerResult(result) + else: + # Old style returns list[Prompt] + return types.ServerResult(types.ListPromptsResult(prompts=result)) + + self.request_handlers[types.ListPromptsRequest] = handler + return func + + return decorator + + def get_prompt(self): + def decorator( + func: Callable[[str, dict[str, str] | None], Awaitable[types.GetPromptResult]], + ): + logger.debug("Registering handler for GetPromptRequest") + + async def handler(req: types.GetPromptRequest): + prompt_get = await func(req.params.name, req.params.arguments) + return types.ServerResult(prompt_get) + + self.request_handlers[types.GetPromptRequest] = handler + return func + + return decorator + + def list_resources(self): + def decorator( + func: Callable[[], Awaitable[list[types.Resource]]] + | Callable[[types.ListResourcesRequest], Awaitable[types.ListResourcesResult]], + ): + logger.debug("Registering handler for ListResourcesRequest") + + wrapper = create_call_wrapper(func, types.ListResourcesRequest) + + async def handler(req: types.ListResourcesRequest): + result = await wrapper(req) + # Handle both old style (list[Resource]) and new style (ListResourcesResult) + if isinstance(result, types.ListResourcesResult): + return types.ServerResult(result) + else: + # Old style returns list[Resource] + return types.ServerResult(types.ListResourcesResult(resources=result)) + + self.request_handlers[types.ListResourcesRequest] = handler + return func + + return decorator + + def list_resource_templates(self): + def decorator(func: Callable[[], Awaitable[list[types.ResourceTemplate]]]): + logger.debug("Registering handler for ListResourceTemplatesRequest") + + async def handler(_: Any): + templates = await func() + return types.ServerResult(types.ListResourceTemplatesResult(resourceTemplates=templates)) + + self.request_handlers[types.ListResourceTemplatesRequest] = handler + return func + + return decorator + + def read_resource(self): + def decorator( + func: Callable[[AnyUrl], Awaitable[str | bytes | Iterable[ReadResourceContents]]], + ): + logger.debug("Registering handler for ReadResourceRequest") + + async def handler(req: types.ReadResourceRequest): + result = await func(req.params.uri) + + def create_content(data: str | bytes, mime_type: str | None, meta: dict[str, Any] | None = None): + # Note: ResourceContents uses Field(alias="_meta"), so we must use the alias key + meta_kwargs: dict[str, Any] = {"_meta": meta} if meta is not None else {} + match data: + case str() as data: + return types.TextResourceContents( + uri=req.params.uri, + text=data, + mimeType=mime_type or "text/plain", + **meta_kwargs, + ) + case bytes() as data: # pragma: no cover + return types.BlobResourceContents( + uri=req.params.uri, + blob=base64.b64encode(data).decode(), + mimeType=mime_type or "application/octet-stream", + **meta_kwargs, + ) + + match result: + case str() | bytes() as data: # pragma: no cover + warnings.warn( + "Returning str or bytes from read_resource is deprecated. " + "Use Iterable[ReadResourceContents] instead.", + DeprecationWarning, + stacklevel=2, + ) + content = create_content(data, None) + case Iterable() as contents: + contents_list = [ + create_content( + content_item.content, content_item.mime_type, getattr(content_item, "meta", None) + ) + for content_item in contents + ] + return types.ServerResult( + types.ReadResourceResult( + contents=contents_list, + ) + ) + case _: # pragma: no cover + raise ValueError(f"Unexpected return type from read_resource: {type(result)}") + + return types.ServerResult( # pragma: no cover + types.ReadResourceResult( + contents=[content], + ) + ) + + self.request_handlers[types.ReadResourceRequest] = handler + return func + + return decorator + + def set_logging_level(self): # pragma: no cover + def decorator(func: Callable[[types.LoggingLevel], Awaitable[None]]): + logger.debug("Registering handler for SetLevelRequest") + + async def handler(req: types.SetLevelRequest): + await func(req.params.level) + return types.ServerResult(types.EmptyResult()) + + self.request_handlers[types.SetLevelRequest] = handler + return func + + return decorator + + def subscribe_resource(self): # pragma: no cover + def decorator(func: Callable[[AnyUrl], Awaitable[None]]): + logger.debug("Registering handler for SubscribeRequest") + + async def handler(req: types.SubscribeRequest): + await func(req.params.uri) + return types.ServerResult(types.EmptyResult()) + + self.request_handlers[types.SubscribeRequest] = handler + return func + + return decorator + + def unsubscribe_resource(self): # pragma: no cover + def decorator(func: Callable[[AnyUrl], Awaitable[None]]): + logger.debug("Registering handler for UnsubscribeRequest") + + async def handler(req: types.UnsubscribeRequest): + await func(req.params.uri) + return types.ServerResult(types.EmptyResult()) + + self.request_handlers[types.UnsubscribeRequest] = handler + return func + + return decorator + + def list_tools(self): + def decorator( + func: Callable[[], Awaitable[list[types.Tool]]] + | Callable[[types.ListToolsRequest], Awaitable[types.ListToolsResult]], + ): + logger.debug("Registering handler for ListToolsRequest") + + wrapper = create_call_wrapper(func, types.ListToolsRequest) + + async def handler(req: types.ListToolsRequest): + result = await wrapper(req) + + # Handle both old style (list[Tool]) and new style (ListToolsResult) + if isinstance(result, types.ListToolsResult): # pragma: no cover + # Refresh the tool cache with returned tools + for tool in result.tools: + validate_and_warn_tool_name(tool.name) + self._tool_cache[tool.name] = tool + return types.ServerResult(result) + else: + # Old style returns list[Tool] + # Clear and refresh the entire tool cache + self._tool_cache.clear() + for tool in result: + validate_and_warn_tool_name(tool.name) + self._tool_cache[tool.name] = tool + return types.ServerResult(types.ListToolsResult(tools=result)) + + self.request_handlers[types.ListToolsRequest] = handler + return func + + return decorator + + def _make_error_result(self, error_message: str) -> types.ServerResult: + """Create a ServerResult with an error CallToolResult.""" + return types.ServerResult( + types.CallToolResult( + content=[types.TextContent(type="text", text=error_message)], + isError=True, + ) + ) + + async def _get_cached_tool_definition(self, tool_name: str) -> types.Tool | None: + """Get tool definition from cache, refreshing if necessary. + + Returns the Tool object if found, None otherwise. + """ + if tool_name not in self._tool_cache: + if types.ListToolsRequest in self.request_handlers: + logger.debug("Tool cache miss for %s, refreshing cache", tool_name) + await self.request_handlers[types.ListToolsRequest](None) + + tool = self._tool_cache.get(tool_name) + if tool is None: + logger.warning("Tool '%s' not listed, no validation will be performed", tool_name) + + return tool + + def call_tool(self, *, validate_input: bool = True): + """Register a tool call handler. + + Args: + validate_input: If True, validates input against inputSchema. Default is True. + + The handler validates input against inputSchema (if validate_input=True), calls the tool function, + and builds a CallToolResult with the results: + - Unstructured content (iterable of ContentBlock): returned in content + - Structured content (dict): returned in structuredContent, serialized JSON text returned in content + - Both: returned in content and structuredContent + + If outputSchema is defined, validates structuredContent or errors if missing. + """ + + def decorator( + func: Callable[ + ..., + Awaitable[ + UnstructuredContent + | StructuredContent + | CombinationContent + | types.CallToolResult + | types.CreateTaskResult + ], + ], + ): + logger.debug("Registering handler for CallToolRequest") + + async def handler(req: types.CallToolRequest): + try: + tool_name = req.params.name + arguments = req.params.arguments or {} + tool = await self._get_cached_tool_definition(tool_name) + + # input validation + if validate_input and tool: + try: + jsonschema.validate(instance=arguments, schema=tool.inputSchema) + except jsonschema.ValidationError as e: + return self._make_error_result(f"Input validation error: {e.message}") + + # tool call + results = await func(tool_name, arguments) + + # output normalization + unstructured_content: UnstructuredContent + maybe_structured_content: StructuredContent | None + if isinstance(results, types.CallToolResult): + return types.ServerResult(results) + elif isinstance(results, types.CreateTaskResult): + # Task-augmented execution returns task info instead of result + return types.ServerResult(results) + elif isinstance(results, tuple) and len(results) == 2: + # tool returned both structured and unstructured content + unstructured_content, maybe_structured_content = cast(CombinationContent, results) + elif isinstance(results, dict): + # tool returned structured content only + maybe_structured_content = cast(StructuredContent, results) + unstructured_content = [types.TextContent(type="text", text=json.dumps(results, indent=2))] + elif hasattr(results, "__iter__"): # pragma: no cover + # tool returned unstructured content only + unstructured_content = cast(UnstructuredContent, results) + maybe_structured_content = None + else: # pragma: no cover + return self._make_error_result(f"Unexpected return type from tool: {type(results).__name__}") + + # output validation + if tool and tool.outputSchema is not None: + if maybe_structured_content is None: + return self._make_error_result( + "Output validation error: outputSchema defined but no structured output returned" + ) + else: + try: + jsonschema.validate(instance=maybe_structured_content, schema=tool.outputSchema) + except jsonschema.ValidationError as e: + return self._make_error_result(f"Output validation error: {e.message}") + + # result + return types.ServerResult( + types.CallToolResult( + content=list(unstructured_content), + structuredContent=maybe_structured_content, + isError=False, + ) + ) + except UrlElicitationRequiredError: + # Re-raise UrlElicitationRequiredError so it can be properly handled + # by _handle_request, which converts it to an error response with code -32042 + raise + except Exception as e: + return self._make_error_result(str(e)) + + self.request_handlers[types.CallToolRequest] = handler + return func + + return decorator + + def progress_notification(self): + def decorator( + func: Callable[[str | int, float, float | None, str | None], Awaitable[None]], + ): + logger.debug("Registering handler for ProgressNotification") + + async def handler(req: types.ProgressNotification): + await func( + req.params.progressToken, + req.params.progress, + req.params.total, + req.params.message, + ) + + self.notification_handlers[types.ProgressNotification] = handler + return func + + return decorator + + def completion(self): + """Provides completions for prompts and resource templates""" + + def decorator( + func: Callable[ + [ + types.PromptReference | types.ResourceTemplateReference, + types.CompletionArgument, + types.CompletionContext | None, + ], + Awaitable[types.Completion | None], + ], + ): + logger.debug("Registering handler for CompleteRequest") + + async def handler(req: types.CompleteRequest): + completion = await func(req.params.ref, req.params.argument, req.params.context) + return types.ServerResult( + types.CompleteResult( + completion=completion + if completion is not None + else types.Completion(values=[], total=None, hasMore=None), + ) + ) + + self.request_handlers[types.CompleteRequest] = handler + return func + + return decorator + + async def run( + self, + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], + write_stream: MemoryObjectSendStream[SessionMessage], + initialization_options: InitializationOptions, + # When False, exceptions are returned as messages to the client. + # When True, exceptions are raised, which will cause the server to shut down + # but also make tracing exceptions much easier during testing and when using + # in-process servers. + raise_exceptions: bool = False, + # When True, the server is stateless and + # clients can perform initialization with any node. The client must still follow + # the initialization lifecycle, but can do so with any available node + # rather than requiring initialization for each connection. + stateless: bool = False, + ): + async with AsyncExitStack() as stack: + lifespan_context = await stack.enter_async_context(self.lifespan(self)) + session = await stack.enter_async_context( + ServerSession( + read_stream, + write_stream, + initialization_options, + stateless=stateless, + ) + ) + + # Configure task support for this session if enabled + task_support = self._experimental_handlers.task_support if self._experimental_handlers else None + if task_support is not None: + task_support.configure_session(session) + await stack.enter_async_context(task_support.run()) + + async with anyio.create_task_group() as tg: + async for message in session.incoming_messages: + logger.debug("Received message: %s", message) + + tg.start_soon( + self._handle_message, + message, + session, + lifespan_context, + raise_exceptions, + ) + + async def _handle_message( + self, + message: RequestResponder[types.ClientRequest, types.ServerResult] | types.ClientNotification | Exception, + session: ServerSession, + lifespan_context: LifespanResultT, + raise_exceptions: bool = False, + ): + with warnings.catch_warnings(record=True) as w: + match message: + case RequestResponder(request=types.ClientRequest(root=req)) as responder: + with responder: + await self._handle_request(message, req, session, lifespan_context, raise_exceptions) + case types.ClientNotification(root=notify): + await self._handle_notification(notify) + case Exception(): # pragma: no cover + logger.error(f"Received exception from stream: {message}") + await session.send_log_message( + level="error", + data="Internal Server Error", + logger="mcp.server.exception_handler", + ) + if raise_exceptions: + raise message + + for warning in w: # pragma: no cover + logger.info("Warning: %s: %s", warning.category.__name__, warning.message) + + async def _handle_request( + self, + message: RequestResponder[types.ClientRequest, types.ServerResult], + req: types.ClientRequestType, + session: ServerSession, + lifespan_context: LifespanResultT, + raise_exceptions: bool, + ): + logger.info("Processing request of type %s", type(req).__name__) + + if handler := self.request_handlers.get(type(req)): + logger.debug("Dispatching request of type %s", type(req).__name__) + + token = None + try: + # Extract request context and close_sse_stream from message metadata + request_data = None + close_sse_stream_cb = None + close_standalone_sse_stream_cb = None + if message.message_metadata is not None and isinstance( + message.message_metadata, ServerMessageMetadata + ): # pragma: no cover + request_data = message.message_metadata.request_context + close_sse_stream_cb = message.message_metadata.close_sse_stream + close_standalone_sse_stream_cb = message.message_metadata.close_standalone_sse_stream + + # Set our global state that can be retrieved via + # app.get_request_context() + client_capabilities = session.client_params.capabilities if session.client_params else None + task_support = self._experimental_handlers.task_support if self._experimental_handlers else None + # Get task metadata from request params if present + task_metadata = None + if hasattr(req, "params") and req.params is not None: + task_metadata = getattr(req.params, "task", None) + token = request_ctx.set( + RequestContext( + message.request_id, + message.request_meta, + session, + lifespan_context, + Experimental( + task_metadata=task_metadata, + _client_capabilities=client_capabilities, + _session=session, + _task_support=task_support, + ), + request=request_data, + close_sse_stream=close_sse_stream_cb, + close_standalone_sse_stream=close_standalone_sse_stream_cb, + ) + ) + response = await handler(req) + except McpError as err: # pragma: no cover + response = err.error + except anyio.get_cancelled_exc_class(): # pragma: no cover + logger.info( + "Request %s cancelled - duplicate response suppressed", + message.request_id, + ) + return + except Exception as err: # pragma: no cover + if raise_exceptions: + raise err + response = types.ErrorData(code=0, message=str(err), data=None) + finally: + # Reset the global state after we are done + if token is not None: # pragma: no branch + request_ctx.reset(token) + + await message.respond(response) + else: # pragma: no cover + await message.respond( + types.ErrorData( + code=types.METHOD_NOT_FOUND, + message="Method not found", + ) + ) + + logger.debug("Response sent") + + async def _handle_notification(self, notify: Any): + if handler := self.notification_handlers.get(type(notify)): # type: ignore + logger.debug("Dispatching notification of type %s", type(notify).__name__) + + try: + await handler(notify) + except Exception: # pragma: no cover + logger.exception("Uncaught exception in notification handler") + + +async def _ping_handler(request: types.PingRequest) -> types.ServerResult: + return types.ServerResult(types.EmptyResult()) diff --git a/source/target-vendors/cp312/mcp/server/models.py b/source/target-vendors/cp312/mcp/server/models.py new file mode 100644 index 0000000..ddf716c --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/models.py @@ -0,0 +1,20 @@ +""" +This module provides simpler types to use with the server for managing prompts +and tools. +""" + +from pydantic import BaseModel + +from mcp.types import ( + Icon, + ServerCapabilities, +) + + +class InitializationOptions(BaseModel): + server_name: str + server_version: str + capabilities: ServerCapabilities + instructions: str | None = None + website_url: str | None = None + icons: list[Icon] | None = None diff --git a/source/target-vendors/cp312/mcp/server/session.py b/source/target-vendors/cp312/mcp/server/session.py new file mode 100644 index 0000000..8f0baa3 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/session.py @@ -0,0 +1,691 @@ +""" +ServerSession Module + +This module provides the ServerSession class, which manages communication between the +server and client in the MCP (Model Context Protocol) framework. It is most commonly +used in MCP servers to interact with the client. + +Common usage pattern: +``` + server = Server(name) + + @server.call_tool() + async def handle_tool_call(ctx: RequestContext, arguments: dict[str, Any]) -> Any: + # Check client capabilities before proceeding + if ctx.session.check_client_capability( + types.ClientCapabilities(experimental={"advanced_tools": dict()}) + ): + # Perform advanced tool operations + result = await perform_advanced_tool_operation(arguments) + else: + # Fall back to basic tool operations + result = await perform_basic_tool_operation(arguments) + + return result + + @server.list_prompts() + async def handle_list_prompts(ctx: RequestContext) -> list[types.Prompt]: + # Access session for any necessary checks or operations + if ctx.session.client_params: + # Customize prompts based on client initialization parameters + return generate_custom_prompts(ctx.session.client_params) + else: + return default_prompts +``` + +The ServerSession class is typically used internally by the Server class and should not +be instantiated directly by users of the MCP framework. +""" + +from enum import Enum +from typing import Any, TypeVar, overload + +import anyio +import anyio.lowlevel +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import AnyUrl + +import mcp.types as types +from mcp.server.experimental.session_features import ExperimentalServerSessionFeatures +from mcp.server.models import InitializationOptions +from mcp.server.validation import validate_sampling_tools, validate_tool_use_result_messages +from mcp.shared.experimental.tasks.capabilities import check_tasks_capability +from mcp.shared.experimental.tasks.helpers import RELATED_TASK_METADATA_KEY +from mcp.shared.message import ServerMessageMetadata, SessionMessage +from mcp.shared.session import ( + BaseSession, + RequestResponder, +) +from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS + + +class InitializationState(Enum): + NotInitialized = 1 + Initializing = 2 + Initialized = 3 + + +ServerSessionT = TypeVar("ServerSessionT", bound="ServerSession") + +ServerRequestResponder = ( + RequestResponder[types.ClientRequest, types.ServerResult] | types.ClientNotification | Exception +) + + +class ServerSession( + BaseSession[ + types.ServerRequest, + types.ServerNotification, + types.ServerResult, + types.ClientRequest, + types.ClientNotification, + ] +): + _initialized: InitializationState = InitializationState.NotInitialized + _client_params: types.InitializeRequestParams | None = None + _experimental_features: ExperimentalServerSessionFeatures | None = None + + def __init__( + self, + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], + write_stream: MemoryObjectSendStream[SessionMessage], + init_options: InitializationOptions, + stateless: bool = False, + ) -> None: + super().__init__(read_stream, write_stream, types.ClientRequest, types.ClientNotification) + self._initialization_state = ( + InitializationState.Initialized if stateless else InitializationState.NotInitialized + ) + + self._init_options = init_options + self._incoming_message_stream_writer, self._incoming_message_stream_reader = anyio.create_memory_object_stream[ + ServerRequestResponder + ](0) + self._exit_stack.push_async_callback(lambda: self._incoming_message_stream_reader.aclose()) + + @property + def client_params(self) -> types.InitializeRequestParams | None: + return self._client_params # pragma: no cover + + @property + def experimental(self) -> ExperimentalServerSessionFeatures: + """Experimental APIs for server→client task operations. + + WARNING: These APIs are experimental and may change without notice. + """ + if self._experimental_features is None: + self._experimental_features = ExperimentalServerSessionFeatures(self) + return self._experimental_features + + def check_client_capability(self, capability: types.ClientCapabilities) -> bool: # pragma: no cover + """Check if the client supports a specific capability.""" + if self._client_params is None: + return False + + client_caps = self._client_params.capabilities + + if capability.roots is not None: + if client_caps.roots is None: + return False + if capability.roots.listChanged and not client_caps.roots.listChanged: + return False + + if capability.sampling is not None: + if client_caps.sampling is None: + return False + if capability.sampling.context is not None and client_caps.sampling.context is None: + return False + if capability.sampling.tools is not None and client_caps.sampling.tools is None: + return False + + if capability.elicitation is not None and client_caps.elicitation is None: + return False + + if capability.experimental is not None: + if client_caps.experimental is None: + return False + for exp_key, exp_value in capability.experimental.items(): + if exp_key not in client_caps.experimental or client_caps.experimental[exp_key] != exp_value: + return False + + if capability.tasks is not None: + if client_caps.tasks is None: + return False + if not check_tasks_capability(capability.tasks, client_caps.tasks): + return False + + return True + + async def _receive_loop(self) -> None: + async with self._incoming_message_stream_writer: + await super()._receive_loop() + + async def _received_request(self, responder: RequestResponder[types.ClientRequest, types.ServerResult]): + match responder.request.root: + case types.InitializeRequest(params=params): + requested_version = params.protocolVersion + self._initialization_state = InitializationState.Initializing + self._client_params = params + with responder: + await responder.respond( + types.ServerResult( + types.InitializeResult( + protocolVersion=requested_version + if requested_version in SUPPORTED_PROTOCOL_VERSIONS + else types.LATEST_PROTOCOL_VERSION, + capabilities=self._init_options.capabilities, + serverInfo=types.Implementation( + name=self._init_options.server_name, + version=self._init_options.server_version, + websiteUrl=self._init_options.website_url, + icons=self._init_options.icons, + ), + instructions=self._init_options.instructions, + ) + ) + ) + self._initialization_state = InitializationState.Initialized + case types.PingRequest(): + # Ping requests are allowed at any time + pass + case _: + if self._initialization_state != InitializationState.Initialized: + raise RuntimeError("Received request before initialization was complete") + + async def _received_notification(self, notification: types.ClientNotification) -> None: + # Need this to avoid ASYNC910 + await anyio.lowlevel.checkpoint() + match notification.root: + case types.InitializedNotification(): + self._initialization_state = InitializationState.Initialized + case _: + if self._initialization_state != InitializationState.Initialized: # pragma: no cover + raise RuntimeError("Received notification before initialization was complete") + + async def send_log_message( + self, + level: types.LoggingLevel, + data: Any, + logger: str | None = None, + related_request_id: types.RequestId | None = None, + ) -> None: + """Send a log message notification.""" + await self.send_notification( + types.ServerNotification( + types.LoggingMessageNotification( + params=types.LoggingMessageNotificationParams( + level=level, + data=data, + logger=logger, + ), + ) + ), + related_request_id, + ) + + async def send_resource_updated(self, uri: AnyUrl) -> None: # pragma: no cover + """Send a resource updated notification.""" + await self.send_notification( + types.ServerNotification( + types.ResourceUpdatedNotification( + params=types.ResourceUpdatedNotificationParams(uri=uri), + ) + ) + ) + + @overload + async def create_message( + self, + messages: list[types.SamplingMessage], + *, + max_tokens: int, + system_prompt: str | None = None, + include_context: types.IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: types.ModelPreferences | None = None, + tools: None = None, + tool_choice: types.ToolChoice | None = None, + related_request_id: types.RequestId | None = None, + ) -> types.CreateMessageResult: + """Overload: Without tools, returns single content.""" + ... + + @overload + async def create_message( + self, + messages: list[types.SamplingMessage], + *, + max_tokens: int, + system_prompt: str | None = None, + include_context: types.IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: types.ModelPreferences | None = None, + tools: list[types.Tool], + tool_choice: types.ToolChoice | None = None, + related_request_id: types.RequestId | None = None, + ) -> types.CreateMessageResultWithTools: + """Overload: With tools, returns array-capable content.""" + ... + + async def create_message( + self, + messages: list[types.SamplingMessage], + *, + max_tokens: int, + system_prompt: str | None = None, + include_context: types.IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: types.ModelPreferences | None = None, + tools: list[types.Tool] | None = None, + tool_choice: types.ToolChoice | None = None, + related_request_id: types.RequestId | None = None, + ) -> types.CreateMessageResult | types.CreateMessageResultWithTools: + """Send a sampling/create_message request. + + Args: + messages: The conversation messages to send. + max_tokens: Maximum number of tokens to generate. + system_prompt: Optional system prompt. + include_context: Optional context inclusion setting. + Should only be set to "thisServer" or "allServers" + if the client has sampling.context capability. + temperature: Optional sampling temperature. + stop_sequences: Optional stop sequences. + metadata: Optional metadata to pass through to the LLM provider. + model_preferences: Optional model selection preferences. + tools: Optional list of tools the LLM can use during sampling. + Requires client to have sampling.tools capability. + tool_choice: Optional control over tool usage behavior. + Requires client to have sampling.tools capability. + related_request_id: Optional ID of a related request. + + Returns: + The sampling result from the client. + + Raises: + McpError: If tools are provided but client doesn't support them. + ValueError: If tool_use or tool_result message structure is invalid. + """ + client_caps = self._client_params.capabilities if self._client_params else None + validate_sampling_tools(client_caps, tools, tool_choice) + validate_tool_use_result_messages(messages) + + request = types.ServerRequest( + types.CreateMessageRequest( + params=types.CreateMessageRequestParams( + messages=messages, + systemPrompt=system_prompt, + includeContext=include_context, + temperature=temperature, + maxTokens=max_tokens, + stopSequences=stop_sequences, + metadata=metadata, + modelPreferences=model_preferences, + tools=tools, + toolChoice=tool_choice, + ), + ) + ) + metadata_obj = ServerMessageMetadata(related_request_id=related_request_id) + + # Use different result types based on whether tools are provided + if tools is not None: + return await self.send_request( + request=request, + result_type=types.CreateMessageResultWithTools, + metadata=metadata_obj, + ) + return await self.send_request( + request=request, + result_type=types.CreateMessageResult, + metadata=metadata_obj, + ) + + async def list_roots(self) -> types.ListRootsResult: + """Send a roots/list request.""" + return await self.send_request( + types.ServerRequest(types.ListRootsRequest()), + types.ListRootsResult, + ) + + async def elicit( + self, + message: str, + requestedSchema: types.ElicitRequestedSchema, + related_request_id: types.RequestId | None = None, + ) -> types.ElicitResult: + """Send a form mode elicitation/create request. + + Args: + message: The message to present to the user + requestedSchema: Schema defining the expected response structure + related_request_id: Optional ID of the request that triggered this elicitation + + Returns: + The client's response + + Note: + This method is deprecated in favor of elicit_form(). It remains for + backward compatibility but new code should use elicit_form(). + """ + return await self.elicit_form(message, requestedSchema, related_request_id) + + async def elicit_form( + self, + message: str, + requestedSchema: types.ElicitRequestedSchema, + related_request_id: types.RequestId | None = None, + ) -> types.ElicitResult: + """Send a form mode elicitation/create request. + + Args: + message: The message to present to the user + requestedSchema: Schema defining the expected response structure + related_request_id: Optional ID of the request that triggered this elicitation + + Returns: + The client's response with form data + """ + return await self.send_request( + types.ServerRequest( + types.ElicitRequest( + params=types.ElicitRequestFormParams( + message=message, + requestedSchema=requestedSchema, + ), + ) + ), + types.ElicitResult, + metadata=ServerMessageMetadata(related_request_id=related_request_id), + ) + + async def elicit_url( + self, + message: str, + url: str, + elicitation_id: str, + related_request_id: types.RequestId | None = None, + ) -> types.ElicitResult: + """Send a URL mode elicitation/create request. + + This directs the user to an external URL for out-of-band interactions + like OAuth flows, credential collection, or payment processing. + + Args: + message: Human-readable explanation of why the interaction is needed + url: The URL the user should navigate to + elicitation_id: Unique identifier for tracking this elicitation + related_request_id: Optional ID of the request that triggered this elicitation + + Returns: + The client's response indicating acceptance, decline, or cancellation + """ + return await self.send_request( + types.ServerRequest( + types.ElicitRequest( + params=types.ElicitRequestURLParams( + message=message, + url=url, + elicitationId=elicitation_id, + ), + ) + ), + types.ElicitResult, + metadata=ServerMessageMetadata(related_request_id=related_request_id), + ) + + async def send_ping(self) -> types.EmptyResult: # pragma: no cover + """Send a ping request.""" + return await self.send_request( + types.ServerRequest(types.PingRequest()), + types.EmptyResult, + ) + + async def send_progress_notification( + self, + progress_token: str | int, + progress: float, + total: float | None = None, + message: str | None = None, + related_request_id: str | None = None, + ) -> None: + """Send a progress notification.""" + await self.send_notification( + types.ServerNotification( + types.ProgressNotification( + params=types.ProgressNotificationParams( + progressToken=progress_token, + progress=progress, + total=total, + message=message, + ), + ) + ), + related_request_id, + ) + + async def send_resource_list_changed(self) -> None: # pragma: no cover + """Send a resource list changed notification.""" + await self.send_notification(types.ServerNotification(types.ResourceListChangedNotification())) + + async def send_tool_list_changed(self) -> None: # pragma: no cover + """Send a tool list changed notification.""" + await self.send_notification(types.ServerNotification(types.ToolListChangedNotification())) + + async def send_prompt_list_changed(self) -> None: # pragma: no cover + """Send a prompt list changed notification.""" + await self.send_notification(types.ServerNotification(types.PromptListChangedNotification())) + + async def send_elicit_complete( + self, + elicitation_id: str, + related_request_id: types.RequestId | None = None, + ) -> None: + """Send an elicitation completion notification. + + This should be sent when a URL mode elicitation has been completed + out-of-band to inform the client that it may retry any requests + that were waiting for this elicitation. + + Args: + elicitation_id: The unique identifier of the completed elicitation + related_request_id: Optional ID of the request that triggered this + """ + await self.send_notification( + types.ServerNotification( + types.ElicitCompleteNotification( + params=types.ElicitCompleteNotificationParams(elicitationId=elicitation_id) + ) + ), + related_request_id, + ) + + def _build_elicit_form_request( + self, + message: str, + requestedSchema: types.ElicitRequestedSchema, + related_task_id: str | None = None, + task: types.TaskMetadata | None = None, + ) -> types.JSONRPCRequest: + """Build a form mode elicitation request without sending it. + + Args: + message: The message to present to the user + requestedSchema: Schema defining the expected response structure + related_task_id: If provided, adds io.modelcontextprotocol/related-task metadata + task: If provided, makes this a task-augmented request + + Returns: + A JSONRPCRequest ready to be sent or queued + """ + params = types.ElicitRequestFormParams( + message=message, + requestedSchema=requestedSchema, + task=task, + ) + params_data = params.model_dump(by_alias=True, mode="json", exclude_none=True) + + # Add related-task metadata if associated with a parent task + if related_task_id is not None: + # Defensive: model_dump() never includes _meta, but guard against future changes + if "_meta" not in params_data: # pragma: no cover + params_data["_meta"] = {} + params_data["_meta"][RELATED_TASK_METADATA_KEY] = types.RelatedTaskMetadata( + taskId=related_task_id + ).model_dump(by_alias=True) + + request_id = f"task-{related_task_id}-{id(params)}" if related_task_id else self._request_id + if related_task_id is None: + self._request_id += 1 + + return types.JSONRPCRequest( + jsonrpc="2.0", + id=request_id, + method="elicitation/create", + params=params_data, + ) + + def _build_elicit_url_request( + self, + message: str, + url: str, + elicitation_id: str, + related_task_id: str | None = None, + ) -> types.JSONRPCRequest: + """Build a URL mode elicitation request without sending it. + + Args: + message: Human-readable explanation of why the interaction is needed + url: The URL the user should navigate to + elicitation_id: Unique identifier for tracking this elicitation + related_task_id: If provided, adds io.modelcontextprotocol/related-task metadata + + Returns: + A JSONRPCRequest ready to be sent or queued + """ + params = types.ElicitRequestURLParams( + message=message, + url=url, + elicitationId=elicitation_id, + ) + params_data = params.model_dump(by_alias=True, mode="json", exclude_none=True) + + # Add related-task metadata if associated with a parent task + if related_task_id is not None: + # Defensive: model_dump() never includes _meta, but guard against future changes + if "_meta" not in params_data: # pragma: no cover + params_data["_meta"] = {} + params_data["_meta"][RELATED_TASK_METADATA_KEY] = types.RelatedTaskMetadata( + taskId=related_task_id + ).model_dump(by_alias=True) + + request_id = f"task-{related_task_id}-{id(params)}" if related_task_id else self._request_id + if related_task_id is None: + self._request_id += 1 + + return types.JSONRPCRequest( + jsonrpc="2.0", + id=request_id, + method="elicitation/create", + params=params_data, + ) + + def _build_create_message_request( + self, + messages: list[types.SamplingMessage], + *, + max_tokens: int, + system_prompt: str | None = None, + include_context: types.IncludeContext | None = None, + temperature: float | None = None, + stop_sequences: list[str] | None = None, + metadata: dict[str, Any] | None = None, + model_preferences: types.ModelPreferences | None = None, + tools: list[types.Tool] | None = None, + tool_choice: types.ToolChoice | None = None, + related_task_id: str | None = None, + task: types.TaskMetadata | None = None, + ) -> types.JSONRPCRequest: + """Build a sampling/createMessage request without sending it. + + Args: + messages: The conversation messages to send + max_tokens: Maximum number of tokens to generate + system_prompt: Optional system prompt + include_context: Optional context inclusion setting + temperature: Optional sampling temperature + stop_sequences: Optional stop sequences + metadata: Optional metadata to pass through to the LLM provider + model_preferences: Optional model selection preferences + tools: Optional list of tools the LLM can use during sampling + tool_choice: Optional control over tool usage behavior + related_task_id: If provided, adds io.modelcontextprotocol/related-task metadata + task: If provided, makes this a task-augmented request + + Returns: + A JSONRPCRequest ready to be sent or queued + """ + params = types.CreateMessageRequestParams( + messages=messages, + systemPrompt=system_prompt, + includeContext=include_context, + temperature=temperature, + maxTokens=max_tokens, + stopSequences=stop_sequences, + metadata=metadata, + modelPreferences=model_preferences, + tools=tools, + toolChoice=tool_choice, + task=task, + ) + params_data = params.model_dump(by_alias=True, mode="json", exclude_none=True) + + # Add related-task metadata if associated with a parent task + if related_task_id is not None: + # Defensive: model_dump() never includes _meta, but guard against future changes + if "_meta" not in params_data: # pragma: no cover + params_data["_meta"] = {} + params_data["_meta"][RELATED_TASK_METADATA_KEY] = types.RelatedTaskMetadata( + taskId=related_task_id + ).model_dump(by_alias=True) + + request_id = f"task-{related_task_id}-{id(params)}" if related_task_id else self._request_id + if related_task_id is None: + self._request_id += 1 + + return types.JSONRPCRequest( + jsonrpc="2.0", + id=request_id, + method="sampling/createMessage", + params=params_data, + ) + + async def send_message(self, message: SessionMessage) -> None: + """Send a raw session message. + + This is primarily used by TaskResultHandler to deliver queued messages + (elicitation/sampling requests) to the client during task execution. + + WARNING: This is a low-level experimental method that may change without + notice. Prefer using higher-level methods like send_notification() or + send_request() for normal operations. + + Args: + message: The session message to send + """ + await self._write_stream.send(message) + + async def _handle_incoming(self, req: ServerRequestResponder) -> None: + await self._incoming_message_stream_writer.send(req) + + @property + def incoming_messages( + self, + ) -> MemoryObjectReceiveStream[ServerRequestResponder]: + return self._incoming_message_stream_reader diff --git a/source/target-vendors/cp312/mcp/server/sse.py b/source/target-vendors/cp312/mcp/server/sse.py new file mode 100644 index 0000000..19af93f --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/sse.py @@ -0,0 +1,249 @@ +""" +SSE Server Transport Module + +This module implements a Server-Sent Events (SSE) transport layer for MCP servers. + +Example usage: +``` + # Create an SSE transport at an endpoint + sse = SseServerTransport("/messages/") + + # Create Starlette routes for SSE and message handling + routes = [ + Route("/sse", endpoint=handle_sse, methods=["GET"]), + Mount("/messages/", app=sse.handle_post_message), + ] + + # Define handler functions + async def handle_sse(request): + async with sse.connect_sse( + request.scope, request.receive, request._send + ) as streams: + await app.run( + streams[0], streams[1], app.create_initialization_options() + ) + # Return empty response to avoid NoneType error + return Response() + + # Create and run Starlette app + starlette_app = Starlette(routes=routes) + uvicorn.run(starlette_app, host="127.0.0.1", port=port) +``` + +Note: The handle_sse function must return a Response to avoid a "TypeError: 'NoneType' +object is not callable" error when client disconnects. The example above returns +an empty Response() after the SSE connection ends to fix this. + +See SseServerTransport class documentation for more details. +""" + +import logging +from contextlib import asynccontextmanager +from typing import Any +from urllib.parse import quote +from uuid import UUID, uuid4 + +import anyio +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import ValidationError +from sse_starlette import EventSourceResponse +from starlette.requests import Request +from starlette.responses import Response +from starlette.types import Receive, Scope, Send + +import mcp.types as types +from mcp.server.transport_security import ( + TransportSecurityMiddleware, + TransportSecuritySettings, +) +from mcp.shared.message import ServerMessageMetadata, SessionMessage + +logger = logging.getLogger(__name__) + + +class SseServerTransport: + """ + SSE server transport for MCP. This class provides _two_ ASGI applications, + suitable to be used with a framework like Starlette and a server like Hypercorn: + + 1. connect_sse() is an ASGI application which receives incoming GET requests, + and sets up a new SSE stream to send server messages to the client. + 2. handle_post_message() is an ASGI application which receives incoming POST + requests, which should contain client messages that link to a + previously-established SSE session. + """ + + _endpoint: str + _read_stream_writers: dict[UUID, MemoryObjectSendStream[SessionMessage | Exception]] + _security: TransportSecurityMiddleware + + def __init__(self, endpoint: str, security_settings: TransportSecuritySettings | None = None) -> None: + """ + Creates a new SSE server transport, which will direct the client to POST + messages to the relative path given. + + Args: + endpoint: A relative path where messages should be posted + (e.g., "/messages/"). + security_settings: Optional security settings for DNS rebinding protection. + + Note: + We use relative paths instead of full URLs for several reasons: + 1. Security: Prevents cross-origin requests by ensuring clients only connect + to the same origin they established the SSE connection with + 2. Flexibility: The server can be mounted at any path without needing to + know its full URL + 3. Portability: The same endpoint configuration works across different + environments (development, staging, production) + + Raises: + ValueError: If the endpoint is a full URL instead of a relative path + """ + + super().__init__() + + # Validate that endpoint is a relative path and not a full URL + if "://" in endpoint or endpoint.startswith("//") or "?" in endpoint or "#" in endpoint: + raise ValueError( + f"Given endpoint: {endpoint} is not a relative path (e.g., '/messages/'), " + "expecting a relative path (e.g., '/messages/')." + ) + + # Ensure endpoint starts with a forward slash + if not endpoint.startswith("/"): + endpoint = "/" + endpoint + + self._endpoint = endpoint + self._read_stream_writers = {} + self._security = TransportSecurityMiddleware(security_settings) + logger.debug(f"SseServerTransport initialized with endpoint: {endpoint}") + + @asynccontextmanager + async def connect_sse(self, scope: Scope, receive: Receive, send: Send): # pragma: no cover + if scope["type"] != "http": + logger.error("connect_sse received non-HTTP request") + raise ValueError("connect_sse can only handle HTTP requests") + + # Validate request headers for DNS rebinding protection + request = Request(scope, receive) + error_response = await self._security.validate_request(request, is_post=False) + if error_response: + await error_response(scope, receive, send) + raise ValueError("Request validation failed") + + logger.debug("Setting up SSE connection") + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] + read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] + + write_stream: MemoryObjectSendStream[SessionMessage] + write_stream_reader: MemoryObjectReceiveStream[SessionMessage] + + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + session_id = uuid4() + self._read_stream_writers[session_id] = read_stream_writer + logger.debug(f"Created new session with ID: {session_id}") + + # Determine the full path for the message endpoint to be sent to the client. + # scope['root_path'] is the prefix where the current Starlette app + # instance is mounted. + # e.g., "" if top-level, or "/api_prefix" if mounted under "/api_prefix". + root_path = scope.get("root_path", "") + + # self._endpoint is the path *within* this app, e.g., "/messages". + # Concatenating them gives the full absolute path from the server root. + # e.g., "" + "/messages" -> "/messages" + # e.g., "/api_prefix" + "/messages" -> "/api_prefix/messages" + full_message_path_for_client = root_path.rstrip("/") + self._endpoint + + # This is the URI (path + query) the client will use to POST messages. + client_post_uri_data = f"{quote(full_message_path_for_client)}?session_id={session_id.hex}" + + sse_stream_writer, sse_stream_reader = anyio.create_memory_object_stream[dict[str, Any]](0) + + async def sse_writer(): + logger.debug("Starting SSE writer") + async with sse_stream_writer, write_stream_reader: + await sse_stream_writer.send({"event": "endpoint", "data": client_post_uri_data}) + logger.debug(f"Sent endpoint event: {client_post_uri_data}") + + async for session_message in write_stream_reader: + logger.debug(f"Sending message via SSE: {session_message}") + await sse_stream_writer.send( + { + "event": "message", + "data": session_message.message.model_dump_json(by_alias=True, exclude_none=True), + } + ) + + async with anyio.create_task_group() as tg: + + async def response_wrapper(scope: Scope, receive: Receive, send: Send): + """ + The EventSourceResponse returning signals a client close / disconnect. + In this case we close our side of the streams to signal the client that + the connection has been closed. + """ + await EventSourceResponse(content=sse_stream_reader, data_sender_callable=sse_writer)( + scope, receive, send + ) + await read_stream_writer.aclose() + await write_stream_reader.aclose() + logging.debug(f"Client session disconnected {session_id}") + + logger.debug("Starting SSE response task") + tg.start_soon(response_wrapper, scope, receive, send) + + logger.debug("Yielding read and write streams") + yield (read_stream, write_stream) + + async def handle_post_message(self, scope: Scope, receive: Receive, send: Send) -> None: # pragma: no cover + logger.debug("Handling POST message") + request = Request(scope, receive) + + # Validate request headers for DNS rebinding protection + error_response = await self._security.validate_request(request, is_post=True) + if error_response: + return await error_response(scope, receive, send) + + session_id_param = request.query_params.get("session_id") + if session_id_param is None: + logger.warning("Received request without session_id") + response = Response("session_id is required", status_code=400) + return await response(scope, receive, send) + + try: + session_id = UUID(hex=session_id_param) + logger.debug(f"Parsed session ID: {session_id}") + except ValueError: + logger.warning(f"Received invalid session ID: {session_id_param}") + response = Response("Invalid session ID", status_code=400) + return await response(scope, receive, send) + + writer = self._read_stream_writers.get(session_id) + if not writer: + logger.warning(f"Could not find session for ID: {session_id}") + response = Response("Could not find session", status_code=404) + return await response(scope, receive, send) + + body = await request.body() + logger.debug(f"Received JSON: {body}") + + try: + message = types.JSONRPCMessage.model_validate_json(body) + logger.debug(f"Validated client message: {message}") + except ValidationError as err: + logger.exception("Failed to parse message") + response = Response("Could not parse message", status_code=400) + await response(scope, receive, send) + await writer.send(err) + return + + # Pass the ASGI scope for framework-agnostic access to request data + metadata = ServerMessageMetadata(request_context=request) + session_message = SessionMessage(message, metadata=metadata) + logger.debug(f"Sending session message to writer: {session_message}") + response = Response("Accepted", status_code=202) + await response(scope, receive, send) + await writer.send(session_message) diff --git a/source/target-vendors/cp312/mcp/server/stdio.py b/source/target-vendors/cp312/mcp/server/stdio.py new file mode 100644 index 0000000..bcb9247 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/stdio.py @@ -0,0 +1,88 @@ +""" +Stdio Server Transport Module + +This module provides functionality for creating an stdio-based transport layer +that can be used to communicate with an MCP client through standard input/output +streams. + +Example usage: +``` + async def run_server(): + async with stdio_server() as (read_stream, write_stream): + # read_stream contains incoming JSONRPCMessages from stdin + # write_stream allows sending JSONRPCMessages to stdout + server = await create_my_server() + await server.run(read_stream, write_stream, init_options) + + anyio.run(run_server) +``` +""" + +import sys +from contextlib import asynccontextmanager +from io import TextIOWrapper + +import anyio +import anyio.lowlevel +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream + +import mcp.types as types +from mcp.shared.message import SessionMessage + + +@asynccontextmanager +async def stdio_server( + stdin: anyio.AsyncFile[str] | None = None, + stdout: anyio.AsyncFile[str] | None = None, +): + """ + Server transport for stdio: this communicates with an MCP client by reading + from the current process' stdin and writing to stdout. + """ + # Purposely not using context managers for these, as we don't want to close + # standard process handles. Encoding of stdin/stdout as text streams on + # python is platform-dependent (Windows is particularly problematic), so we + # re-wrap the underlying binary stream to ensure UTF-8. + if not stdin: + stdin = anyio.wrap_file(TextIOWrapper(sys.stdin.buffer, encoding="utf-8")) + if not stdout: + stdout = anyio.wrap_file(TextIOWrapper(sys.stdout.buffer, encoding="utf-8")) + + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] + read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] + + write_stream: MemoryObjectSendStream[SessionMessage] + write_stream_reader: MemoryObjectReceiveStream[SessionMessage] + + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + async def stdin_reader(): + try: + async with read_stream_writer: + async for line in stdin: + try: + message = types.JSONRPCMessage.model_validate_json(line) + except Exception as exc: # pragma: no cover + await read_stream_writer.send(exc) + continue + + session_message = SessionMessage(message) + await read_stream_writer.send(session_message) + except anyio.ClosedResourceError: # pragma: no cover + await anyio.lowlevel.checkpoint() + + async def stdout_writer(): + try: + async with write_stream_reader: + async for session_message in write_stream_reader: + json = session_message.message.model_dump_json(by_alias=True, exclude_none=True) + await stdout.write(json + "\n") + await stdout.flush() + except anyio.ClosedResourceError: # pragma: no cover + await anyio.lowlevel.checkpoint() + + async with anyio.create_task_group() as tg: + tg.start_soon(stdin_reader) + tg.start_soon(stdout_writer) + yield read_stream, write_stream diff --git a/source/target-vendors/cp312/mcp/server/streamable_http.py b/source/target-vendors/cp312/mcp/server/streamable_http.py new file mode 100644 index 0000000..2613b53 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/streamable_http.py @@ -0,0 +1,1067 @@ +""" +StreamableHTTP Server Transport Module + +This module implements an HTTP transport layer with Streamable HTTP. + +The transport handles bidirectional communication using HTTP requests and +responses, with streaming support for long-running operations. +""" + +import json +import logging +import re +from abc import ABC, abstractmethod +from collections.abc import AsyncGenerator, Awaitable, Callable +from contextlib import asynccontextmanager +from dataclasses import dataclass +from http import HTTPStatus +from typing import Any + +import anyio +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import ValidationError +from sse_starlette import EventSourceResponse +from starlette.requests import Request +from starlette.responses import Response +from starlette.types import Receive, Scope, Send + +from mcp.server.transport_security import ( + TransportSecurityMiddleware, + TransportSecuritySettings, +) +from mcp.shared.message import ServerMessageMetadata, SessionMessage +from mcp.shared.version import SUPPORTED_PROTOCOL_VERSIONS +from mcp.types import ( + DEFAULT_NEGOTIATED_VERSION, + INTERNAL_ERROR, + INVALID_PARAMS, + INVALID_REQUEST, + PARSE_ERROR, + ErrorData, + JSONRPCError, + JSONRPCMessage, + JSONRPCRequest, + JSONRPCResponse, + RequestId, +) + +logger = logging.getLogger(__name__) + + +# Header names +MCP_SESSION_ID_HEADER = "mcp-session-id" +MCP_PROTOCOL_VERSION_HEADER = "mcp-protocol-version" +LAST_EVENT_ID_HEADER = "last-event-id" + +# Content types +CONTENT_TYPE_JSON = "application/json" +CONTENT_TYPE_SSE = "text/event-stream" + +# Special key for the standalone GET stream +GET_STREAM_KEY = "_GET_stream" + +# Session ID validation pattern (visible ASCII characters ranging from 0x21 to 0x7E) +# Pattern ensures entire string contains only valid characters by using ^ and $ anchors +SESSION_ID_PATTERN = re.compile(r"^[\x21-\x7E]+$") + +# Type aliases +StreamId = str +EventId = str + + +@dataclass +class EventMessage: + """ + A JSONRPCMessage with an optional event ID for stream resumability. + """ + + message: JSONRPCMessage + event_id: str | None = None + + +EventCallback = Callable[[EventMessage], Awaitable[None]] + + +class EventStore(ABC): + """ + Interface for resumability support via event storage. + """ + + @abstractmethod + async def store_event(self, stream_id: StreamId, message: JSONRPCMessage | None) -> EventId: + """ + Stores an event for later retrieval. + + Args: + stream_id: ID of the stream the event belongs to + message: The JSON-RPC message to store, or None for priming events + + Returns: + The generated event ID for the stored event + """ + pass # pragma: no cover + + @abstractmethod + async def replay_events_after( + self, + last_event_id: EventId, + send_callback: EventCallback, + ) -> StreamId | None: + """ + Replays events that occurred after the specified event ID. + + Args: + last_event_id: The ID of the last event the client received + send_callback: A callback function to send events to the client + + Returns: + The stream ID of the replayed events + """ + pass # pragma: no cover + + +class StreamableHTTPServerTransport: + """ + HTTP server transport with event streaming support for MCP. + + Handles JSON-RPC messages in HTTP POST requests with SSE streaming. + Supports optional JSON responses and session management. + """ + + # Server notification streams for POST requests as well as standalone SSE stream + _read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] | None = None + _read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] | None = None + _write_stream: MemoryObjectSendStream[SessionMessage] | None = None + _write_stream_reader: MemoryObjectReceiveStream[SessionMessage] | None = None + _security: TransportSecurityMiddleware + + def __init__( + self, + mcp_session_id: str | None, + is_json_response_enabled: bool = False, + event_store: EventStore | None = None, + security_settings: TransportSecuritySettings | None = None, + retry_interval: int | None = None, + ) -> None: + """ + Initialize a new StreamableHTTP server transport. + + Args: + mcp_session_id: Optional session identifier for this connection. + Must contain only visible ASCII characters (0x21-0x7E). + is_json_response_enabled: If True, return JSON responses for requests + instead of SSE streams. Default is False. + event_store: Event store for resumability support. If provided, + resumability will be enabled, allowing clients to + reconnect and resume messages. + security_settings: Optional security settings for DNS rebinding protection. + retry_interval: Retry interval in milliseconds to suggest to clients in SSE + retry field. When set, the server will send a retry field in + SSE priming events to control client reconnection timing for + polling behavior. Only used when event_store is provided. + + Raises: + ValueError: If the session ID contains invalid characters. + """ + if mcp_session_id is not None and not SESSION_ID_PATTERN.fullmatch(mcp_session_id): + raise ValueError("Session ID must only contain visible ASCII characters (0x21-0x7E)") + + self.mcp_session_id = mcp_session_id + self.is_json_response_enabled = is_json_response_enabled + self._event_store = event_store + self._security = TransportSecurityMiddleware(security_settings) + self._retry_interval = retry_interval + self._request_streams: dict[ + RequestId, + tuple[ + MemoryObjectSendStream[EventMessage], + MemoryObjectReceiveStream[EventMessage], + ], + ] = {} + self._sse_stream_writers: dict[RequestId, MemoryObjectSendStream[dict[str, str]]] = {} + self._terminated = False + + @property + def is_terminated(self) -> bool: + """Check if this transport has been explicitly terminated.""" + return self._terminated + + def close_sse_stream(self, request_id: RequestId) -> None: # pragma: no cover + """Close SSE connection for a specific request without terminating the stream. + + This method closes the HTTP connection for the specified request, triggering + client reconnection. Events continue to be stored in the event store and will + be replayed when the client reconnects with Last-Event-ID. + + Use this to implement polling behavior during long-running operations - + client will reconnect after the retry interval specified in the priming event. + + Args: + request_id: The request ID whose SSE stream should be closed. + + Note: + This is a no-op if there is no active stream for the request ID. + Requires event_store to be configured for events to be stored during + the disconnect. + """ + writer = self._sse_stream_writers.pop(request_id, None) + if writer: + writer.close() + + # Also close and remove request streams + if request_id in self._request_streams: + send_stream, receive_stream = self._request_streams.pop(request_id) + send_stream.close() + receive_stream.close() + + def close_standalone_sse_stream(self) -> None: # pragma: no cover + """Close the standalone GET SSE stream, triggering client reconnection. + + This method closes the HTTP connection for the standalone GET stream used + for unsolicited server-to-client notifications. The client SHOULD reconnect + with Last-Event-ID to resume receiving notifications. + + Use this to implement polling behavior for the notification stream - + client will reconnect after the retry interval specified in the priming event. + + Note: + This is a no-op if there is no active standalone SSE stream. + Requires event_store to be configured for events to be stored during + the disconnect. + Currently, client reconnection for standalone GET streams is NOT + implemented - this is a known gap (see test_standalone_get_stream_reconnection). + """ + self.close_sse_stream(GET_STREAM_KEY) + + def _create_session_message( # pragma: no cover + self, + message: JSONRPCMessage, + request: Request, + request_id: RequestId, + protocol_version: str, + ) -> SessionMessage: + """Create a session message with metadata including close_sse_stream callback. + + The close_sse_stream callbacks are only provided when the client supports + resumability (protocol version >= 2025-11-25). Old clients can't resume if + the stream is closed early because they didn't receive a priming event. + """ + # Only provide close callbacks when client supports resumability + if self._event_store and protocol_version >= "2025-11-25": + + async def close_stream_callback() -> None: + self.close_sse_stream(request_id) + + async def close_standalone_stream_callback() -> None: + self.close_standalone_sse_stream() + + metadata = ServerMessageMetadata( + request_context=request, + close_sse_stream=close_stream_callback, + close_standalone_sse_stream=close_standalone_stream_callback, + ) + else: + metadata = ServerMessageMetadata(request_context=request) + + return SessionMessage(message, metadata=metadata) + + async def _maybe_send_priming_event( + self, + request_id: RequestId, + sse_stream_writer: MemoryObjectSendStream[dict[str, Any]], + protocol_version: str, + ) -> None: + """Send priming event for SSE resumability if event_store is configured. + + Only sends priming events to clients with protocol version >= 2025-11-25, + which includes the fix for handling empty SSE data. Older clients would + crash trying to parse empty data as JSON. + """ + if not self._event_store: + return + # Priming events have empty data which older clients cannot handle. + if protocol_version < "2025-11-25": + return + priming_event_id = await self._event_store.store_event( + str(request_id), # Convert RequestId to StreamId (str) + None, # Priming event has no payload + ) + priming_event: dict[str, str | int] = {"id": priming_event_id, "data": ""} + if self._retry_interval is not None: + priming_event["retry"] = self._retry_interval + await sse_stream_writer.send(priming_event) + + def _create_error_response( + self, + error_message: str, + status_code: HTTPStatus, + error_code: int = INVALID_REQUEST, + headers: dict[str, str] | None = None, + ) -> Response: + """Create an error response with a simple string message.""" + response_headers = {"Content-Type": CONTENT_TYPE_JSON} + if headers: # pragma: no cover + response_headers.update(headers) + + if self.mcp_session_id: + response_headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id + + # Return a properly formatted JSON error response + error_response = JSONRPCError( + jsonrpc="2.0", + id="server-error", # We don't have a request ID for general errors + error=ErrorData( + code=error_code, + message=error_message, + ), + ) + + return Response( + error_response.model_dump_json(by_alias=True, exclude_none=True), + status_code=status_code, + headers=response_headers, + ) + + def _create_json_response( # pragma: no cover + self, + response_message: JSONRPCMessage | None, + status_code: HTTPStatus = HTTPStatus.OK, + headers: dict[str, str] | None = None, + ) -> Response: + """Create a JSON response from a JSONRPCMessage""" + response_headers = {"Content-Type": CONTENT_TYPE_JSON} + if headers: + response_headers.update(headers) + + if self.mcp_session_id: + response_headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id + + return Response( + response_message.model_dump_json(by_alias=True, exclude_none=True) if response_message else None, + status_code=status_code, + headers=response_headers, + ) + + def _get_session_id(self, request: Request) -> str | None: # pragma: no cover + """Extract the session ID from request headers.""" + return request.headers.get(MCP_SESSION_ID_HEADER) + + def _create_event_data(self, event_message: EventMessage) -> dict[str, str]: # pragma: no cover + """Create event data dictionary from an EventMessage.""" + event_data = { + "event": "message", + "data": event_message.message.model_dump_json(by_alias=True, exclude_none=True), + } + + # If an event ID was provided, include it + if event_message.event_id: + event_data["id"] = event_message.event_id + + return event_data + + async def _clean_up_memory_streams(self, request_id: RequestId) -> None: # pragma: no cover + """Clean up memory streams for a given request ID.""" + if request_id in self._request_streams: + try: + # Close the request stream + await self._request_streams[request_id][0].aclose() + await self._request_streams[request_id][1].aclose() + except Exception: + # During cleanup, we catch all exceptions since streams might be in various states + logger.debug("Error closing memory streams - may already be closed") + finally: + # Remove the request stream from the mapping + self._request_streams.pop(request_id, None) + + async def handle_request(self, scope: Scope, receive: Receive, send: Send) -> None: + """Application entry point that handles all HTTP requests""" + request = Request(scope, receive) + + # Validate request headers for DNS rebinding protection + is_post = request.method == "POST" + error_response = await self._security.validate_request(request, is_post=is_post) + if error_response: # pragma: no cover + await error_response(scope, receive, send) + return + + if self._terminated: # pragma: no cover + # If the session has been terminated, return 404 Not Found + response = self._create_error_response( + "Not Found: Session has been terminated", + HTTPStatus.NOT_FOUND, + ) + await response(scope, receive, send) + return + + if request.method == "POST": + await self._handle_post_request(scope, request, receive, send) + elif request.method == "GET": # pragma: no cover + await self._handle_get_request(request, send) + elif request.method == "DELETE": # pragma: no cover + await self._handle_delete_request(request, send) + else: # pragma: no cover + await self._handle_unsupported_request(request, send) + + def _check_accept_headers(self, request: Request) -> tuple[bool, bool]: + """Check if the request accepts the required media types.""" + accept_header = request.headers.get("accept", "") + accept_types = [media_type.strip() for media_type in accept_header.split(",")] + + has_json = any(media_type.startswith(CONTENT_TYPE_JSON) for media_type in accept_types) + has_sse = any(media_type.startswith(CONTENT_TYPE_SSE) for media_type in accept_types) + + return has_json, has_sse + + def _check_content_type(self, request: Request) -> bool: + """Check if the request has the correct Content-Type.""" + content_type = request.headers.get("content-type", "") + content_type_parts = [part.strip() for part in content_type.split(";")[0].split(",")] + + return any(part == CONTENT_TYPE_JSON for part in content_type_parts) + + async def _validate_accept_header(self, request: Request, scope: Scope, send: Send) -> bool: # pragma: no cover + """Validate Accept header based on response mode. Returns True if valid.""" + has_json, has_sse = self._check_accept_headers(request) + if self.is_json_response_enabled: + # For JSON-only responses, only require application/json + if not has_json: + response = self._create_error_response( + "Not Acceptable: Client must accept application/json", + HTTPStatus.NOT_ACCEPTABLE, + ) + await response(scope, request.receive, send) + return False + # For SSE responses, require both content types + elif not (has_json and has_sse): + response = self._create_error_response( + "Not Acceptable: Client must accept both application/json and text/event-stream", + HTTPStatus.NOT_ACCEPTABLE, + ) + await response(scope, request.receive, send) + return False + return True + + async def _handle_post_request(self, scope: Scope, request: Request, receive: Receive, send: Send) -> None: + """Handle POST requests containing JSON-RPC messages.""" + writer = self._read_stream_writer + if writer is None: # pragma: no cover + raise ValueError("No read stream writer available. Ensure connect() is called first.") + try: + # Validate Accept header + if not await self._validate_accept_header(request, scope, send): + return + + # Validate Content-Type + if not self._check_content_type(request): # pragma: no cover + response = self._create_error_response( + "Unsupported Media Type: Content-Type must be application/json", + HTTPStatus.UNSUPPORTED_MEDIA_TYPE, + ) + await response(scope, receive, send) + return + + # Parse the body - only read it once + body = await request.body() + + try: + raw_message = json.loads(body) + except json.JSONDecodeError as e: + response = self._create_error_response(f"Parse error: {str(e)}", HTTPStatus.BAD_REQUEST, PARSE_ERROR) + await response(scope, receive, send) + return + + try: # pragma: no cover + message = JSONRPCMessage.model_validate(raw_message) + except ValidationError as e: # pragma: no cover + response = self._create_error_response( + f"Validation error: {str(e)}", + HTTPStatus.BAD_REQUEST, + INVALID_PARAMS, + ) + await response(scope, receive, send) + return + + # Check if this is an initialization request + is_initialization_request = ( + isinstance(message.root, JSONRPCRequest) and message.root.method == "initialize" + ) # pragma: no cover + + if is_initialization_request: # pragma: no cover + # Check if the server already has an established session + if self.mcp_session_id: + # Check if request has a session ID + request_session_id = self._get_session_id(request) + + # If request has a session ID but doesn't match, return 404 + if request_session_id and request_session_id != self.mcp_session_id: + response = self._create_error_response( + "Not Found: Invalid or expired session ID", + HTTPStatus.NOT_FOUND, + ) + await response(scope, receive, send) + return + elif not await self._validate_request_headers(request, send): # pragma: no cover + return + + # For notifications and responses only, return 202 Accepted + if not isinstance(message.root, JSONRPCRequest): # pragma: no cover + # Create response object and send it + response = self._create_json_response( + None, + HTTPStatus.ACCEPTED, + ) + await response(scope, receive, send) + + # Process the message after sending the response + metadata = ServerMessageMetadata(request_context=request) + session_message = SessionMessage(message, metadata=metadata) + await writer.send(session_message) + + return + + # Extract protocol version for priming event decision. + # For initialize requests, get from request params. + # For other requests, get from header (already validated). + protocol_version = ( + str(message.root.params.get("protocolVersion", DEFAULT_NEGOTIATED_VERSION)) + if is_initialization_request and message.root.params + else request.headers.get(MCP_PROTOCOL_VERSION_HEADER, DEFAULT_NEGOTIATED_VERSION) + ) + + # Extract the request ID outside the try block for proper scope + request_id = str(message.root.id) # pragma: no cover + # Register this stream for the request ID + self._request_streams[request_id] = anyio.create_memory_object_stream[EventMessage](0) # pragma: no cover + request_stream_reader = self._request_streams[request_id][1] # pragma: no cover + + if self.is_json_response_enabled: # pragma: no cover + # Process the message + metadata = ServerMessageMetadata(request_context=request) + session_message = SessionMessage(message, metadata=metadata) + await writer.send(session_message) + try: + # Process messages from the request-specific stream + # We need to collect all messages until we get a response + response_message = None + + # Use similar approach to SSE writer for consistency + async for event_message in request_stream_reader: + # If it's a response, this is what we're waiting for + if isinstance(event_message.message.root, JSONRPCResponse | JSONRPCError): + response_message = event_message.message + break + # For notifications and request, keep waiting + else: + logger.debug(f"received: {event_message.message.root.method}") + + # At this point we should have a response + if response_message: + # Create JSON response + response = self._create_json_response(response_message) + await response(scope, receive, send) + else: + # This shouldn't happen in normal operation + logger.error("No response message received before stream closed") + response = self._create_error_response( + "Error processing request: No response received", + HTTPStatus.INTERNAL_SERVER_ERROR, + ) + await response(scope, receive, send) + except Exception: + logger.exception("Error processing JSON response") + response = self._create_error_response( + "Error processing request", + HTTPStatus.INTERNAL_SERVER_ERROR, + INTERNAL_ERROR, + ) + await response(scope, receive, send) + finally: + await self._clean_up_memory_streams(request_id) + else: # pragma: no cover + # Create SSE stream + sse_stream_writer, sse_stream_reader = anyio.create_memory_object_stream[dict[str, str]](0) + + # Store writer reference so close_sse_stream() can close it + self._sse_stream_writers[request_id] = sse_stream_writer + + async def sse_writer(): + # Get the request ID from the incoming request message + try: + async with sse_stream_writer, request_stream_reader: + # Send priming event for SSE resumability + await self._maybe_send_priming_event(request_id, sse_stream_writer, protocol_version) + + # Process messages from the request-specific stream + async for event_message in request_stream_reader: + # Build the event data + event_data = self._create_event_data(event_message) + await sse_stream_writer.send(event_data) + + # If response, remove from pending streams and close + if isinstance( + event_message.message.root, + JSONRPCResponse | JSONRPCError, + ): + break + except anyio.ClosedResourceError: + # Expected when close_sse_stream() is called + logger.debug("SSE stream closed by close_sse_stream()") + except Exception: + logger.exception("Error in SSE writer") + finally: + logger.debug("Closing SSE writer") + self._sse_stream_writers.pop(request_id, None) + await self._clean_up_memory_streams(request_id) + + # Create and start EventSourceResponse + # SSE stream mode (original behavior) + # Set up headers + headers = { + "Cache-Control": "no-cache, no-transform", + "Connection": "keep-alive", + "Content-Type": CONTENT_TYPE_SSE, + **({MCP_SESSION_ID_HEADER: self.mcp_session_id} if self.mcp_session_id else {}), + } + response = EventSourceResponse( + content=sse_stream_reader, + data_sender_callable=sse_writer, + headers=headers, + ) + + # Start the SSE response (this will send headers immediately) + try: + # First send the response to establish the SSE connection + async with anyio.create_task_group() as tg: + tg.start_soon(response, scope, receive, send) + # Then send the message to be processed by the server + session_message = self._create_session_message(message, request, request_id, protocol_version) + await writer.send(session_message) + except Exception: + logger.exception("SSE response error") + await sse_stream_writer.aclose() + await sse_stream_reader.aclose() + await self._clean_up_memory_streams(request_id) + + except Exception as err: # pragma: no cover + logger.exception("Error handling POST request") + response = self._create_error_response( + f"Error handling POST request: {err}", + HTTPStatus.INTERNAL_SERVER_ERROR, + INTERNAL_ERROR, + ) + await response(scope, receive, send) + if writer: + await writer.send(Exception(err)) + return + + async def _handle_get_request(self, request: Request, send: Send) -> None: # pragma: no cover + """ + Handle GET request to establish SSE. + + This allows the server to communicate to the client without the client + first sending data via HTTP POST. The server can send JSON-RPC requests + and notifications on this stream. + """ + writer = self._read_stream_writer + if writer is None: + raise ValueError("No read stream writer available. Ensure connect() is called first.") + + # Validate Accept header - must include text/event-stream + _, has_sse = self._check_accept_headers(request) + + if not has_sse: + response = self._create_error_response( + "Not Acceptable: Client must accept text/event-stream", + HTTPStatus.NOT_ACCEPTABLE, + ) + await response(request.scope, request.receive, send) + return + + if not await self._validate_request_headers(request, send): + return + + # Handle resumability: check for Last-Event-ID header + if last_event_id := request.headers.get(LAST_EVENT_ID_HEADER): + await self._replay_events(last_event_id, request, send) + return + + headers = { + "Cache-Control": "no-cache, no-transform", + "Connection": "keep-alive", + "Content-Type": CONTENT_TYPE_SSE, + } + + if self.mcp_session_id: + headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id + + # Check if we already have an active GET stream + if GET_STREAM_KEY in self._request_streams: + response = self._create_error_response( + "Conflict: Only one SSE stream is allowed per session", + HTTPStatus.CONFLICT, + ) + await response(request.scope, request.receive, send) + return + + # Create SSE stream + sse_stream_writer, sse_stream_reader = anyio.create_memory_object_stream[dict[str, str]](0) + + async def standalone_sse_writer(): + try: + # Create a standalone message stream for server-initiated messages + + self._request_streams[GET_STREAM_KEY] = anyio.create_memory_object_stream[EventMessage](0) + standalone_stream_reader = self._request_streams[GET_STREAM_KEY][1] + + async with sse_stream_writer, standalone_stream_reader: + # Process messages from the standalone stream + async for event_message in standalone_stream_reader: + # For the standalone stream, we handle: + # - JSONRPCNotification (server sends notifications to client) + # - JSONRPCRequest (server sends requests to client) + # We should NOT receive JSONRPCResponse + + # Send the message via SSE + event_data = self._create_event_data(event_message) + await sse_stream_writer.send(event_data) + except Exception: + logger.exception("Error in standalone SSE writer") + finally: + logger.debug("Closing standalone SSE writer") + await self._clean_up_memory_streams(GET_STREAM_KEY) + + # Create and start EventSourceResponse + response = EventSourceResponse( + content=sse_stream_reader, + data_sender_callable=standalone_sse_writer, + headers=headers, + ) + + try: + # This will send headers immediately and establish the SSE connection + await response(request.scope, request.receive, send) + except Exception: + logger.exception("Error in standalone SSE response") + await sse_stream_writer.aclose() + await sse_stream_reader.aclose() + await self._clean_up_memory_streams(GET_STREAM_KEY) + + async def _handle_delete_request(self, request: Request, send: Send) -> None: # pragma: no cover + """Handle DELETE requests for explicit session termination.""" + # Validate session ID + if not self.mcp_session_id: + # If no session ID set, return Method Not Allowed + response = self._create_error_response( + "Method Not Allowed: Session termination not supported", + HTTPStatus.METHOD_NOT_ALLOWED, + ) + await response(request.scope, request.receive, send) + return + + if not await self._validate_request_headers(request, send): + return + + await self.terminate() + + response = self._create_json_response( + None, + HTTPStatus.OK, + ) + await response(request.scope, request.receive, send) + + async def terminate(self) -> None: + """Terminate the current session, closing all streams. + + Once terminated, all requests with this session ID will receive 404 Not Found. + """ + + self._terminated = True + logger.info(f"Terminating session: {self.mcp_session_id}") + + # We need a copy of the keys to avoid modification during iteration + request_stream_keys = list(self._request_streams.keys()) + + # Close all request streams asynchronously + for key in request_stream_keys: # pragma: no cover + await self._clean_up_memory_streams(key) + + # Clear the request streams dictionary immediately + self._request_streams.clear() + try: + if self._read_stream_writer is not None: # pragma: no branch + await self._read_stream_writer.aclose() + if self._read_stream is not None: # pragma: no branch + await self._read_stream.aclose() + if self._write_stream_reader is not None: # pragma: no branch + await self._write_stream_reader.aclose() + if self._write_stream is not None: # pragma: no branch + await self._write_stream.aclose() + except Exception as e: # pragma: no cover + # During cleanup, we catch all exceptions since streams might be in various states + logger.debug(f"Error closing streams: {e}") + + async def _handle_unsupported_request(self, request: Request, send: Send) -> None: # pragma: no cover + """Handle unsupported HTTP methods.""" + headers = { + "Content-Type": CONTENT_TYPE_JSON, + "Allow": "GET, POST, DELETE", + } + if self.mcp_session_id: + headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id + + response = self._create_error_response( + "Method Not Allowed", + HTTPStatus.METHOD_NOT_ALLOWED, + headers=headers, + ) + await response(request.scope, request.receive, send) + + async def _validate_request_headers(self, request: Request, send: Send) -> bool: # pragma: no cover + if not await self._validate_session(request, send): + return False + if not await self._validate_protocol_version(request, send): + return False + return True + + async def _validate_session(self, request: Request, send: Send) -> bool: # pragma: no cover + """Validate the session ID in the request.""" + if not self.mcp_session_id: + # If we're not using session IDs, return True + return True + + # Get the session ID from the request headers + request_session_id = self._get_session_id(request) + + # If no session ID provided but required, return error + if not request_session_id: + response = self._create_error_response( + "Bad Request: Missing session ID", + HTTPStatus.BAD_REQUEST, + ) + await response(request.scope, request.receive, send) + return False + + # If session ID doesn't match, return error + if request_session_id != self.mcp_session_id: + response = self._create_error_response( + "Not Found: Invalid or expired session ID", + HTTPStatus.NOT_FOUND, + ) + await response(request.scope, request.receive, send) + return False + + return True + + async def _validate_protocol_version(self, request: Request, send: Send) -> bool: # pragma: no cover + """Validate the protocol version header in the request.""" + # Get the protocol version from the request headers + protocol_version = request.headers.get(MCP_PROTOCOL_VERSION_HEADER) + + # If no protocol version provided, assume default version + if protocol_version is None: + protocol_version = DEFAULT_NEGOTIATED_VERSION + + # Check if the protocol version is supported + if protocol_version not in SUPPORTED_PROTOCOL_VERSIONS: + supported_versions = ", ".join(SUPPORTED_PROTOCOL_VERSIONS) + response = self._create_error_response( + f"Bad Request: Unsupported protocol version: {protocol_version}. " + + f"Supported versions: {supported_versions}", + HTTPStatus.BAD_REQUEST, + ) + await response(request.scope, request.receive, send) + return False + + return True + + async def _replay_events(self, last_event_id: str, request: Request, send: Send) -> None: # pragma: no cover + """ + Replays events that would have been sent after the specified event ID. + Only used when resumability is enabled. + """ + event_store = self._event_store + if not event_store: + return + + try: + headers = { + "Cache-Control": "no-cache, no-transform", + "Connection": "keep-alive", + "Content-Type": CONTENT_TYPE_SSE, + } + + if self.mcp_session_id: + headers[MCP_SESSION_ID_HEADER] = self.mcp_session_id + + # Get protocol version from header (already validated in _validate_protocol_version) + replay_protocol_version = request.headers.get(MCP_PROTOCOL_VERSION_HEADER, DEFAULT_NEGOTIATED_VERSION) + + # Create SSE stream for replay + sse_stream_writer, sse_stream_reader = anyio.create_memory_object_stream[dict[str, str]](0) + + async def replay_sender(): + try: + async with sse_stream_writer: + # Define an async callback for sending events + async def send_event(event_message: EventMessage) -> None: + event_data = self._create_event_data(event_message) + await sse_stream_writer.send(event_data) + + # Replay past events and get the stream ID + stream_id = await event_store.replay_events_after(last_event_id, send_event) + + # If stream ID not in mapping, create it + if stream_id and stream_id not in self._request_streams: + # Register SSE writer so close_sse_stream() can close it + self._sse_stream_writers[stream_id] = sse_stream_writer + + # Send priming event for this new connection + await self._maybe_send_priming_event(stream_id, sse_stream_writer, replay_protocol_version) + + # Create new request streams for this connection + self._request_streams[stream_id] = anyio.create_memory_object_stream[EventMessage](0) + msg_reader = self._request_streams[stream_id][1] + + # Forward messages to SSE + async with msg_reader: + async for event_message in msg_reader: + event_data = self._create_event_data(event_message) + + await sse_stream_writer.send(event_data) + except anyio.ClosedResourceError: + # Expected when close_sse_stream() is called + logger.debug("Replay SSE stream closed by close_sse_stream()") + except Exception: + logger.exception("Error in replay sender") + + # Create and start EventSourceResponse + response = EventSourceResponse( + content=sse_stream_reader, + data_sender_callable=replay_sender, + headers=headers, + ) + + try: + await response(request.scope, request.receive, send) + except Exception: + logger.exception("Error in replay response") + finally: + await sse_stream_writer.aclose() + await sse_stream_reader.aclose() + + except Exception: + logger.exception("Error replaying events") + response = self._create_error_response( + "Error replaying events", + HTTPStatus.INTERNAL_SERVER_ERROR, + INTERNAL_ERROR, + ) + await response(request.scope, request.receive, send) + + @asynccontextmanager + async def connect( + self, + ) -> AsyncGenerator[ + tuple[ + MemoryObjectReceiveStream[SessionMessage | Exception], + MemoryObjectSendStream[SessionMessage], + ], + None, + ]: + """Context manager that provides read and write streams for a connection. + + Yields: + Tuple of (read_stream, write_stream) for bidirectional communication + """ + + # Create the memory streams for this connection + + read_stream_writer, read_stream = anyio.create_memory_object_stream[SessionMessage | Exception](0) + write_stream, write_stream_reader = anyio.create_memory_object_stream[SessionMessage](0) + + # Store the streams + self._read_stream_writer = read_stream_writer + self._read_stream = read_stream + self._write_stream_reader = write_stream_reader + self._write_stream = write_stream + + # Start a task group for message routing + async with anyio.create_task_group() as tg: + # Create a message router that distributes messages to request streams + async def message_router(): # pragma: no cover + try: + async for session_message in write_stream_reader: + # Determine which request stream(s) should receive this message + message = session_message.message + target_request_id = None + # Check if this is a response + if isinstance(message.root, JSONRPCResponse | JSONRPCError): + response_id = str(message.root.id) + # If this response is for an existing request stream, + # send it there + target_request_id = response_id + # Extract related_request_id from meta if it exists + elif ( + session_message.metadata is not None + and isinstance( + session_message.metadata, + ServerMessageMetadata, + ) + and session_message.metadata.related_request_id is not None + ): + target_request_id = str(session_message.metadata.related_request_id) + + request_stream_id = target_request_id if target_request_id is not None else GET_STREAM_KEY + + # Store the event if we have an event store, + # regardless of whether a client is connected + # messages will be replayed on the re-connect + event_id = None + if self._event_store: + event_id = await self._event_store.store_event(request_stream_id, message) + logger.debug(f"Stored {event_id} from {request_stream_id}") + + if request_stream_id in self._request_streams: + try: + # Send both the message and the event ID + await self._request_streams[request_stream_id][0].send(EventMessage(message, event_id)) + except ( + anyio.BrokenResourceError, + anyio.ClosedResourceError, + ): + # Stream might be closed, remove from registry + self._request_streams.pop(request_stream_id, None) + else: + logger.debug( + f"""Request stream {request_stream_id} not found + for message. Still processing message as the client + might reconnect and replay.""" + ) + except anyio.ClosedResourceError: + if self._terminated: + logger.debug("Read stream closed by client") + else: + logger.exception("Unexpected closure of read stream in message router") + except Exception: + logger.exception("Error in message router") + + # Start the message router + tg.start_soon(message_router) + + try: + # Yield the streams for the caller to use + yield read_stream, write_stream + finally: + for stream_id in list(self._request_streams.keys()): # pragma: no cover + await self._clean_up_memory_streams(stream_id) + self._request_streams.clear() + + # Clean up the read and write streams + try: + await read_stream_writer.aclose() + await read_stream.aclose() + await write_stream_reader.aclose() + await write_stream.aclose() + except Exception as e: # pragma: no cover + # During cleanup, we catch all exceptions since streams might be in various states + logger.debug(f"Error closing streams: {e}") diff --git a/source/target-vendors/cp312/mcp/server/streamable_http_manager.py b/source/target-vendors/cp312/mcp/server/streamable_http_manager.py new file mode 100644 index 0000000..6a16724 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/streamable_http_manager.py @@ -0,0 +1,297 @@ +"""StreamableHTTP Session Manager for MCP servers.""" + +from __future__ import annotations + +import contextlib +import logging +from collections.abc import AsyncIterator +from http import HTTPStatus +from typing import Any +from uuid import uuid4 + +import anyio +from anyio.abc import TaskStatus +from starlette.requests import Request +from starlette.responses import Response +from starlette.types import Receive, Scope, Send + +from mcp.server.lowlevel.server import Server as MCPServer +from mcp.server.streamable_http import ( + MCP_SESSION_ID_HEADER, + EventStore, + StreamableHTTPServerTransport, +) +from mcp.server.transport_security import TransportSecuritySettings +from mcp.types import INVALID_REQUEST, ErrorData, JSONRPCError + +logger = logging.getLogger(__name__) + + +class StreamableHTTPSessionManager: + """ + Manages StreamableHTTP sessions with optional resumability via event store. + + This class abstracts away the complexity of session management, event storage, + and request handling for StreamableHTTP transports. It handles: + + 1. Session tracking for clients + 2. Resumability via an optional event store + 3. Connection management and lifecycle + 4. Request handling and transport setup + + Important: Only one StreamableHTTPSessionManager instance should be created + per application. The instance cannot be reused after its run() context has + completed. If you need to restart the manager, create a new instance. + + Args: + app: The MCP server instance + event_store: Optional event store for resumability support. + If provided, enables resumable connections where clients + can reconnect and receive missed events. + If None, sessions are still tracked but not resumable. + json_response: Whether to use JSON responses instead of SSE streams + stateless: If True, creates a completely fresh transport for each request + with no session tracking or state persistence between requests. + security_settings: Optional transport security settings. + retry_interval: Retry interval in milliseconds to suggest to clients in SSE + retry field. Used for SSE polling behavior. + """ + + def __init__( + self, + app: MCPServer[Any, Any], + event_store: EventStore | None = None, + json_response: bool = False, + stateless: bool = False, + security_settings: TransportSecuritySettings | None = None, + retry_interval: int | None = None, + ): + self.app = app + self.event_store = event_store + self.json_response = json_response + self.stateless = stateless + self.security_settings = security_settings + self.retry_interval = retry_interval + + # Session tracking (only used if not stateless) + self._session_creation_lock = anyio.Lock() + self._server_instances: dict[str, StreamableHTTPServerTransport] = {} + + # The task group will be set during lifespan + self._task_group = None + # Thread-safe tracking of run() calls + self._run_lock = anyio.Lock() + self._has_started = False + + @contextlib.asynccontextmanager + async def run(self) -> AsyncIterator[None]: + """ + Run the session manager with proper lifecycle management. + + This creates and manages the task group for all session operations. + + Important: This method can only be called once per instance. The same + StreamableHTTPSessionManager instance cannot be reused after this + context manager exits. Create a new instance if you need to restart. + + Use this in the lifespan context manager of your Starlette app: + + @contextlib.asynccontextmanager + async def lifespan(app: Starlette) -> AsyncIterator[None]: + async with session_manager.run(): + yield + """ + # Thread-safe check to ensure run() is only called once + async with self._run_lock: + if self._has_started: + raise RuntimeError( + "StreamableHTTPSessionManager .run() can only be called " + "once per instance. Create a new instance if you need to run again." + ) + self._has_started = True + + async with anyio.create_task_group() as tg: + # Store the task group for later use + self._task_group = tg + logger.info("StreamableHTTP session manager started") + try: + yield # Let the application run + finally: + logger.info("StreamableHTTP session manager shutting down") + # Cancel task group to stop all spawned tasks + tg.cancel_scope.cancel() + self._task_group = None + # Clear any remaining server instances + self._server_instances.clear() + + async def handle_request( + self, + scope: Scope, + receive: Receive, + send: Send, + ) -> None: + """ + Process ASGI request with proper session handling and transport setup. + + Dispatches to the appropriate handler based on stateless mode. + + Args: + scope: ASGI scope + receive: ASGI receive function + send: ASGI send function + """ + if self._task_group is None: + raise RuntimeError("Task group is not initialized. Make sure to use run().") + + # Dispatch to the appropriate handler + if self.stateless: + await self._handle_stateless_request(scope, receive, send) + else: + await self._handle_stateful_request(scope, receive, send) + + async def _handle_stateless_request( + self, + scope: Scope, + receive: Receive, + send: Send, + ) -> None: + """ + Process request in stateless mode - creating a new transport for each request. + + Args: + scope: ASGI scope + receive: ASGI receive function + send: ASGI send function + """ + logger.debug("Stateless mode: Creating new transport for this request") + # No session ID needed in stateless mode + http_transport = StreamableHTTPServerTransport( + mcp_session_id=None, # No session tracking in stateless mode + is_json_response_enabled=self.json_response, + event_store=None, # No event store in stateless mode + security_settings=self.security_settings, + ) + + # Start server in a new task + async def run_stateless_server(*, task_status: TaskStatus[None] = anyio.TASK_STATUS_IGNORED): + async with http_transport.connect() as streams: + read_stream, write_stream = streams + task_status.started() + try: + await self.app.run( + read_stream, + write_stream, + self.app.create_initialization_options(), + stateless=True, + ) + except Exception: # pragma: no cover + logger.exception("Stateless session crashed") + + # Assert task group is not None for type checking + assert self._task_group is not None + # Start the server task + await self._task_group.start(run_stateless_server) + + # Handle the HTTP request and return the response + await http_transport.handle_request(scope, receive, send) + + # Terminate the transport after the request is handled + await http_transport.terminate() + + async def _handle_stateful_request( + self, + scope: Scope, + receive: Receive, + send: Send, + ) -> None: + """ + Process request in stateful mode - maintaining session state between requests. + + Args: + scope: ASGI scope + receive: ASGI receive function + send: ASGI send function + """ + request = Request(scope, receive) + request_mcp_session_id = request.headers.get(MCP_SESSION_ID_HEADER) + + # Existing session case + if request_mcp_session_id is not None and request_mcp_session_id in self._server_instances: # pragma: no cover + transport = self._server_instances[request_mcp_session_id] + logger.debug("Session already exists, handling request directly") + await transport.handle_request(scope, receive, send) + return + + if request_mcp_session_id is None: + # New session case + logger.debug("Creating new transport") + async with self._session_creation_lock: + new_session_id = uuid4().hex + http_transport = StreamableHTTPServerTransport( + mcp_session_id=new_session_id, + is_json_response_enabled=self.json_response, + event_store=self.event_store, # May be None (no resumability) + security_settings=self.security_settings, + retry_interval=self.retry_interval, + ) + + assert http_transport.mcp_session_id is not None + self._server_instances[http_transport.mcp_session_id] = http_transport + logger.info(f"Created new transport with session ID: {new_session_id}") + + # Define the server runner + async def run_server(*, task_status: TaskStatus[None] = anyio.TASK_STATUS_IGNORED) -> None: + async with http_transport.connect() as streams: + read_stream, write_stream = streams + task_status.started() + try: + await self.app.run( + read_stream, + write_stream, + self.app.create_initialization_options(), + stateless=False, # Stateful mode + ) + except Exception as e: + logger.error( + f"Session {http_transport.mcp_session_id} crashed: {e}", + exc_info=True, + ) + finally: + # Only remove from instances if not terminated + if ( # pragma: no branch + http_transport.mcp_session_id + and http_transport.mcp_session_id in self._server_instances + and not http_transport.is_terminated + ): + logger.info( + "Cleaning up crashed session " + f"{http_transport.mcp_session_id} from " + "active instances." + ) + del self._server_instances[http_transport.mcp_session_id] + + # Assert task group is not None for type checking + assert self._task_group is not None + # Start the server task + await self._task_group.start(run_server) + + # Handle the HTTP request and return the response + await http_transport.handle_request(scope, receive, send) + else: + # Unknown or expired session ID - return 404 per MCP spec + # TODO: Align error code once spec clarifies + # See: https://github.com/modelcontextprotocol/python-sdk/issues/1821 + error_response = JSONRPCError( + jsonrpc="2.0", + id="server-error", + error=ErrorData( + code=INVALID_REQUEST, + message="Session not found", + ), + ) + response = Response( + content=error_response.model_dump_json(by_alias=True, exclude_none=True), + status_code=HTTPStatus.NOT_FOUND, + media_type="application/json", + ) + await response(scope, receive, send) diff --git a/source/target-vendors/cp312/mcp/server/transport_security.py b/source/target-vendors/cp312/mcp/server/transport_security.py new file mode 100644 index 0000000..ee1e450 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/transport_security.py @@ -0,0 +1,127 @@ +"""DNS rebinding protection for MCP server transports.""" + +import logging + +from pydantic import BaseModel, Field +from starlette.requests import Request +from starlette.responses import Response + +logger = logging.getLogger(__name__) + + +class TransportSecuritySettings(BaseModel): + """Settings for MCP transport security features. + + These settings help protect against DNS rebinding attacks by validating + incoming request headers. + """ + + enable_dns_rebinding_protection: bool = Field( + default=True, + description="Enable DNS rebinding protection (recommended for production)", + ) + + allowed_hosts: list[str] = Field( + default=[], + description="List of allowed Host header values. Only applies when " + + "enable_dns_rebinding_protection is True.", + ) + + allowed_origins: list[str] = Field( + default=[], + description="List of allowed Origin header values. Only applies when " + + "enable_dns_rebinding_protection is True.", + ) + + +class TransportSecurityMiddleware: + """Middleware to enforce DNS rebinding protection for MCP transport endpoints.""" + + def __init__(self, settings: TransportSecuritySettings | None = None): + # If not specified, disable DNS rebinding protection by default + # for backwards compatibility + self.settings = settings or TransportSecuritySettings(enable_dns_rebinding_protection=False) + + def _validate_host(self, host: str | None) -> bool: # pragma: no cover + """Validate the Host header against allowed values.""" + if not host: + logger.warning("Missing Host header in request") + return False + + # Check exact match first + if host in self.settings.allowed_hosts: + return True + + # Check wildcard port patterns + for allowed in self.settings.allowed_hosts: + if allowed.endswith(":*"): + # Extract base host from pattern + base_host = allowed[:-2] + # Check if the actual host starts with base host and has a port + if host.startswith(base_host + ":"): + return True + + logger.warning(f"Invalid Host header: {host}") + return False + + def _validate_origin(self, origin: str | None) -> bool: # pragma: no cover + """Validate the Origin header against allowed values.""" + # Origin can be absent for same-origin requests + if not origin: + return True + + # Check exact match first + if origin in self.settings.allowed_origins: + return True + + # Check wildcard port patterns + for allowed in self.settings.allowed_origins: + if allowed.endswith(":*"): + # Extract base origin from pattern + base_origin = allowed[:-2] + # Check if the actual origin starts with base origin and has a port + if origin.startswith(base_origin + ":"): + return True + + logger.warning(f"Invalid Origin header: {origin}") + return False + + def _validate_content_type(self, content_type: str | None) -> bool: # pragma: no cover + """Validate the Content-Type header for POST requests.""" + if not content_type: + logger.warning("Missing Content-Type header in POST request") + return False + + # Content-Type must start with application/json + if not content_type.lower().startswith("application/json"): + logger.warning(f"Invalid Content-Type header: {content_type}") + return False + + return True + + async def validate_request(self, request: Request, is_post: bool = False) -> Response | None: + """Validate request headers for DNS rebinding protection. + + Returns None if validation passes, or an error Response if validation fails. + """ + # Always validate Content-Type for POST requests + if is_post: # pragma: no branch + content_type = request.headers.get("content-type") + if not self._validate_content_type(content_type): # pragma: no cover + return Response("Invalid Content-Type header", status_code=400) + + # Skip remaining validation if DNS rebinding protection is disabled + if not self.settings.enable_dns_rebinding_protection: + return None + + # Validate Host header # pragma: no cover + host = request.headers.get("host") # pragma: no cover + if not self._validate_host(host): # pragma: no cover + return Response("Invalid Host header", status_code=421) # pragma: no cover + + # Validate Origin header # pragma: no cover + origin = request.headers.get("origin") # pragma: no cover + if not self._validate_origin(origin): # pragma: no cover + return Response("Invalid Origin header", status_code=403) # pragma: no cover + + return None # pragma: no cover diff --git a/source/target-vendors/cp312/mcp/server/validation.py b/source/target-vendors/cp312/mcp/server/validation.py new file mode 100644 index 0000000..2ccd705 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/validation.py @@ -0,0 +1,104 @@ +""" +Shared validation functions for server requests. + +This module provides validation logic for sampling and elicitation requests +that is shared across normal and task-augmented code paths. +""" + +from mcp.shared.exceptions import McpError +from mcp.types import ( + INVALID_PARAMS, + ClientCapabilities, + ErrorData, + SamplingMessage, + Tool, + ToolChoice, +) + + +def check_sampling_tools_capability(client_caps: ClientCapabilities | None) -> bool: + """ + Check if the client supports sampling tools capability. + + Args: + client_caps: The client's declared capabilities + + Returns: + True if client supports sampling.tools, False otherwise + """ + if client_caps is None: + return False + if client_caps.sampling is None: + return False + if client_caps.sampling.tools is None: + return False + return True + + +def validate_sampling_tools( + client_caps: ClientCapabilities | None, + tools: list[Tool] | None, + tool_choice: ToolChoice | None, +) -> None: + """ + Validate that the client supports sampling tools if tools are being used. + + Args: + client_caps: The client's declared capabilities + tools: The tools list, if provided + tool_choice: The tool choice setting, if provided + + Raises: + McpError: If tools/tool_choice are provided but client doesn't support them + """ + if tools is not None or tool_choice is not None: + if not check_sampling_tools_capability(client_caps): + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message="Client does not support sampling tools capability", + ) + ) + + +def validate_tool_use_result_messages(messages: list[SamplingMessage]) -> None: + """ + Validate tool_use/tool_result message structure per SEP-1577. + + This validation ensures: + 1. Messages with tool_result content contain ONLY tool_result content + 2. tool_result messages are preceded by a message with tool_use + 3. tool_result IDs match the tool_use IDs from the previous message + + See: https://github.com/modelcontextprotocol/modelcontextprotocol/issues/1577 + + Args: + messages: The list of sampling messages to validate + + Raises: + ValueError: If the message structure is invalid + """ + if not messages: + return + + last_content = messages[-1].content_as_list + has_tool_results = any(c.type == "tool_result" for c in last_content) + + previous_content = messages[-2].content_as_list if len(messages) >= 2 else None + has_previous_tool_use = previous_content and any(c.type == "tool_use" for c in previous_content) + + if has_tool_results: + # Per spec: "SamplingMessage with tool result content blocks + # MUST NOT contain other content types." + if any(c.type != "tool_result" for c in last_content): + raise ValueError("The last message must contain only tool_result content if any is present") + if previous_content is None: + raise ValueError("tool_result requires a previous message containing tool_use") + if not has_previous_tool_use: + raise ValueError("tool_result blocks do not match any tool_use in the previous message") + + if has_previous_tool_use and previous_content: + tool_use_ids = {c.id for c in previous_content if c.type == "tool_use"} + tool_result_ids = {c.toolUseId for c in last_content if c.type == "tool_result"} + if tool_use_ids != tool_result_ids: + raise ValueError("ids of tool_result blocks and tool_use blocks from previous message do not match") diff --git a/source/target-vendors/cp312/mcp/server/websocket.py b/source/target-vendors/cp312/mcp/server/websocket.py new file mode 100644 index 0000000..5d5efd1 --- /dev/null +++ b/source/target-vendors/cp312/mcp/server/websocket.py @@ -0,0 +1,62 @@ +import logging +from contextlib import asynccontextmanager + +import anyio +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic_core import ValidationError +from starlette.types import Receive, Scope, Send +from starlette.websockets import WebSocket + +import mcp.types as types +from mcp.shared.message import SessionMessage + +logger = logging.getLogger(__name__) + + +@asynccontextmanager # pragma: no cover +async def websocket_server(scope: Scope, receive: Receive, send: Send): + """ + WebSocket server transport for MCP. This is an ASGI application, suitable to be + used with a framework like Starlette and a server like Hypercorn. + """ + + websocket = WebSocket(scope, receive, send) + await websocket.accept(subprotocol="mcp") + + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] + read_stream_writer: MemoryObjectSendStream[SessionMessage | Exception] + + write_stream: MemoryObjectSendStream[SessionMessage] + write_stream_reader: MemoryObjectReceiveStream[SessionMessage] + + read_stream_writer, read_stream = anyio.create_memory_object_stream(0) + write_stream, write_stream_reader = anyio.create_memory_object_stream(0) + + async def ws_reader(): + try: + async with read_stream_writer: + async for msg in websocket.iter_text(): + try: + client_message = types.JSONRPCMessage.model_validate_json(msg) + except ValidationError as exc: + await read_stream_writer.send(exc) + continue + + session_message = SessionMessage(client_message) + await read_stream_writer.send(session_message) + except anyio.ClosedResourceError: + await websocket.close() + + async def ws_writer(): + try: + async with write_stream_reader: + async for session_message in write_stream_reader: + obj = session_message.message.model_dump_json(by_alias=True, exclude_none=True) + await websocket.send_text(obj) + except anyio.ClosedResourceError: + await websocket.close() + + async with anyio.create_task_group() as tg: + tg.start_soon(ws_reader) + tg.start_soon(ws_writer) + yield (read_stream, write_stream) diff --git a/source/target-vendors/cp312/mcp/shared/__init__.py b/source/target-vendors/cp312/mcp/shared/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/mcp/shared/_httpx_utils.py b/source/target-vendors/cp312/mcp/shared/_httpx_utils.py new file mode 100644 index 0000000..945ef80 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/_httpx_utils.py @@ -0,0 +1,87 @@ +"""Utilities for creating standardized httpx AsyncClient instances.""" + +from typing import Any, Protocol + +import httpx + +__all__ = ["create_mcp_http_client", "MCP_DEFAULT_TIMEOUT", "MCP_DEFAULT_SSE_READ_TIMEOUT"] + +# Default MCP timeout configuration +MCP_DEFAULT_TIMEOUT = 30.0 # General operations (seconds) +MCP_DEFAULT_SSE_READ_TIMEOUT = 300.0 # SSE streams - 5 minutes (seconds) + + +class McpHttpClientFactory(Protocol): # pragma: no branch + def __call__( # pragma: no branch + self, + headers: dict[str, str] | None = None, + timeout: httpx.Timeout | None = None, + auth: httpx.Auth | None = None, + ) -> httpx.AsyncClient: ... + + +def create_mcp_http_client( + headers: dict[str, str] | None = None, + timeout: httpx.Timeout | None = None, + auth: httpx.Auth | None = None, +) -> httpx.AsyncClient: + """Create a standardized httpx AsyncClient with MCP defaults. + + This function provides common defaults used throughout the MCP codebase: + - follow_redirects=True (always enabled) + - Default timeout of 30 seconds if not specified + + Args: + headers: Optional headers to include with all requests. + timeout: Request timeout as httpx.Timeout object. + Defaults to 30 seconds if not specified. + auth: Optional authentication handler. + + Returns: + Configured httpx.AsyncClient instance with MCP defaults. + + Note: + The returned AsyncClient must be used as a context manager to ensure + proper cleanup of connections. + + Examples: + # Basic usage with MCP defaults + async with create_mcp_http_client() as client: + response = await client.get("https://api.example.com") + + # With custom headers + headers = {"Authorization": "Bearer token"} + async with create_mcp_http_client(headers) as client: + response = await client.get("/endpoint") + + # With both custom headers and timeout + timeout = httpx.Timeout(60.0, read=300.0) + async with create_mcp_http_client(headers, timeout) as client: + response = await client.get("/long-request") + + # With authentication + from httpx import BasicAuth + auth = BasicAuth(username="user", password="pass") + async with create_mcp_http_client(headers, timeout, auth) as client: + response = await client.get("/protected-endpoint") + """ + # Set MCP defaults + kwargs: dict[str, Any] = { + "follow_redirects": True, + } + + # Handle timeout + if timeout is None: + kwargs["timeout"] = httpx.Timeout(MCP_DEFAULT_TIMEOUT, read=MCP_DEFAULT_SSE_READ_TIMEOUT) + else: + kwargs["timeout"] = timeout + + # Handle headers + if headers is not None: + kwargs["headers"] = headers + + # Handle authentication + if auth is not None: # pragma: no cover + kwargs["auth"] = auth + + return httpx.AsyncClient(**kwargs) diff --git a/source/target-vendors/cp312/mcp/shared/auth.py b/source/target-vendors/cp312/mcp/shared/auth.py new file mode 100644 index 0000000..d329099 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/auth.py @@ -0,0 +1,159 @@ +from typing import Any, Literal + +from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, field_validator + + +class OAuthToken(BaseModel): + """ + See https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 + """ + + access_token: str + token_type: Literal["Bearer"] = "Bearer" + expires_in: int | None = None + scope: str | None = None + refresh_token: str | None = None + + @field_validator("token_type", mode="before") + @classmethod + def normalize_token_type(cls, v: str | None) -> str | None: + if isinstance(v, str): + # Bearer is title-cased in the spec, so we normalize it + # https://datatracker.ietf.org/doc/html/rfc6750#section-4 + return v.title() + return v # pragma: no cover + + +class InvalidScopeError(Exception): + def __init__(self, message: str): + self.message = message + + +class InvalidRedirectUriError(Exception): + def __init__(self, message: str): + self.message = message + + +class OAuthClientMetadata(BaseModel): + """ + RFC 7591 OAuth 2.0 Dynamic Client Registration metadata. + See https://datatracker.ietf.org/doc/html/rfc7591#section-2 + for the full specification. + """ + + redirect_uris: list[AnyUrl] | None = Field(..., min_length=1) + # supported auth methods for the token endpoint + token_endpoint_auth_method: ( + Literal["none", "client_secret_post", "client_secret_basic", "private_key_jwt"] | None + ) = None + # supported grant_types of this implementation + grant_types: list[ + Literal["authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:jwt-bearer"] | str + ] = [ + "authorization_code", + "refresh_token", + ] + # The MCP spec requires the "code" response type, but OAuth + # servers may also return additional types they support + response_types: list[str] = ["code"] + scope: str | None = None + + # these fields are currently unused, but we support & store them for potential + # future use + client_name: str | None = None + client_uri: AnyHttpUrl | None = None + logo_uri: AnyHttpUrl | None = None + contacts: list[str] | None = None + tos_uri: AnyHttpUrl | None = None + policy_uri: AnyHttpUrl | None = None + jwks_uri: AnyHttpUrl | None = None + jwks: Any | None = None + software_id: str | None = None + software_version: str | None = None + + def validate_scope(self, requested_scope: str | None) -> list[str] | None: + if requested_scope is None: + return None + requested_scopes = requested_scope.split(" ") + allowed_scopes = [] if self.scope is None else self.scope.split(" ") + for scope in requested_scopes: + if scope not in allowed_scopes: # pragma: no branch + raise InvalidScopeError(f"Client was not registered with scope {scope}") + return requested_scopes # pragma: no cover + + def validate_redirect_uri(self, redirect_uri: AnyUrl | None) -> AnyUrl: + if redirect_uri is not None: + # Validate redirect_uri against client's registered redirect URIs + if self.redirect_uris is None or redirect_uri not in self.redirect_uris: + raise InvalidRedirectUriError(f"Redirect URI '{redirect_uri}' not registered for client") + return redirect_uri + elif self.redirect_uris is not None and len(self.redirect_uris) == 1: + return self.redirect_uris[0] + else: + raise InvalidRedirectUriError("redirect_uri must be specified when client has multiple registered URIs") + + +class OAuthClientInformationFull(OAuthClientMetadata): + """ + RFC 7591 OAuth 2.0 Dynamic Client Registration full response + (client information plus metadata). + """ + + client_id: str | None = None + client_secret: str | None = None + client_id_issued_at: int | None = None + client_secret_expires_at: int | None = None + + +class OAuthMetadata(BaseModel): + """ + RFC 8414 OAuth 2.0 Authorization Server Metadata. + See https://datatracker.ietf.org/doc/html/rfc8414#section-2 + """ + + issuer: AnyHttpUrl + authorization_endpoint: AnyHttpUrl + token_endpoint: AnyHttpUrl + registration_endpoint: AnyHttpUrl | None = None + scopes_supported: list[str] | None = None + response_types_supported: list[str] = ["code"] + response_modes_supported: list[str] | None = None + grant_types_supported: list[str] | None = None + token_endpoint_auth_methods_supported: list[str] | None = None + token_endpoint_auth_signing_alg_values_supported: list[str] | None = None + service_documentation: AnyHttpUrl | None = None + ui_locales_supported: list[str] | None = None + op_policy_uri: AnyHttpUrl | None = None + op_tos_uri: AnyHttpUrl | None = None + revocation_endpoint: AnyHttpUrl | None = None + revocation_endpoint_auth_methods_supported: list[str] | None = None + revocation_endpoint_auth_signing_alg_values_supported: list[str] | None = None + introspection_endpoint: AnyHttpUrl | None = None + introspection_endpoint_auth_methods_supported: list[str] | None = None + introspection_endpoint_auth_signing_alg_values_supported: list[str] | None = None + code_challenge_methods_supported: list[str] | None = None + client_id_metadata_document_supported: bool | None = None + + +class ProtectedResourceMetadata(BaseModel): + """ + RFC 9728 OAuth 2.0 Protected Resource Metadata. + See https://datatracker.ietf.org/doc/html/rfc9728#section-2 + """ + + resource: AnyHttpUrl + authorization_servers: list[AnyHttpUrl] = Field(..., min_length=1) + jwks_uri: AnyHttpUrl | None = None + scopes_supported: list[str] | None = None + bearer_methods_supported: list[str] | None = Field(default=["header"]) # MCP only supports header method + resource_signing_alg_values_supported: list[str] | None = None + resource_name: str | None = None + resource_documentation: AnyHttpUrl | None = None + resource_policy_uri: AnyHttpUrl | None = None + resource_tos_uri: AnyHttpUrl | None = None + # tls_client_certificate_bound_access_tokens default is False, but ommited here for clarity + tls_client_certificate_bound_access_tokens: bool | None = None + authorization_details_types_supported: list[str] | None = None + dpop_signing_alg_values_supported: list[str] | None = None + # dpop_bound_access_tokens_required default is False, but ommited here for clarity + dpop_bound_access_tokens_required: bool | None = None diff --git a/source/target-vendors/cp312/mcp/shared/auth_utils.py b/source/target-vendors/cp312/mcp/shared/auth_utils.py new file mode 100644 index 0000000..8f3c542 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/auth_utils.py @@ -0,0 +1,85 @@ +"""Utilities for OAuth 2.0 Resource Indicators (RFC 8707) and PKCE (RFC 7636).""" + +import time +from urllib.parse import urlparse, urlsplit, urlunsplit + +from pydantic import AnyUrl, HttpUrl + + +def resource_url_from_server_url(url: str | HttpUrl | AnyUrl) -> str: + """Convert server URL to canonical resource URL per RFC 8707. + + RFC 8707 section 2 states that resource URIs "MUST NOT include a fragment component". + Returns absolute URI with lowercase scheme/host for canonical form. + + Args: + url: Server URL to convert + + Returns: + Canonical resource URL string + """ + # Convert to string if needed + url_str = str(url) + + # Parse the URL and remove fragment, create canonical form + parsed = urlsplit(url_str) + canonical = urlunsplit(parsed._replace(scheme=parsed.scheme.lower(), netloc=parsed.netloc.lower(), fragment="")) + + return canonical + + +def check_resource_allowed(requested_resource: str, configured_resource: str) -> bool: + """Check if a requested resource URL matches a configured resource URL. + + A requested resource matches if it has the same scheme, domain, port, + and its path starts with the configured resource's path. This allows + hierarchical matching where a token for a parent resource can be used + for child resources. + + Args: + requested_resource: The resource URL being requested + configured_resource: The resource URL that has been configured + + Returns: + True if the requested resource matches the configured resource + """ + # Parse both URLs + requested = urlparse(requested_resource) + configured = urlparse(configured_resource) + + # Compare scheme, host, and port (origin) + if requested.scheme.lower() != configured.scheme.lower() or requested.netloc.lower() != configured.netloc.lower(): + return False + + # Handle cases like requested=/foo and configured=/foo/ + requested_path = requested.path + configured_path = configured.path + + # If requested path is shorter, it cannot be a child + if len(requested_path) < len(configured_path): + return False + + # Check if the requested path starts with the configured path + # Ensure both paths end with / for proper comparison + # This ensures that paths like "/api123" don't incorrectly match "/api" + if not requested_path.endswith("/"): + requested_path += "/" + if not configured_path.endswith("/"): + configured_path += "/" + + return requested_path.startswith(configured_path) + + +def calculate_token_expiry(expires_in: int | str | None) -> float | None: + """Calculate token expiry timestamp from expires_in seconds. + + Args: + expires_in: Seconds until token expiration (may be string from some servers) + + Returns: + Unix timestamp when token expires, or None if no expiry specified + """ + if expires_in is None: + return None # pragma: no cover + # Defensive: handle servers that return expires_in as string + return time.time() + int(expires_in) diff --git a/source/target-vendors/cp312/mcp/shared/context.py b/source/target-vendors/cp312/mcp/shared/context.py new file mode 100644 index 0000000..5cf6588 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/context.py @@ -0,0 +1,32 @@ +""" +Request context for MCP handlers. +""" + +from dataclasses import dataclass, field +from typing import Any, Generic + +from typing_extensions import TypeVar + +from mcp.shared.message import CloseSSEStreamCallback +from mcp.shared.session import BaseSession +from mcp.types import RequestId, RequestParams + +SessionT = TypeVar("SessionT", bound=BaseSession[Any, Any, Any, Any, Any]) +LifespanContextT = TypeVar("LifespanContextT") +RequestT = TypeVar("RequestT", default=Any) + + +@dataclass +class RequestContext(Generic[SessionT, LifespanContextT, RequestT]): + request_id: RequestId + meta: RequestParams.Meta | None + session: SessionT + lifespan_context: LifespanContextT + # NOTE: This is typed as Any to avoid circular imports. The actual type is + # mcp.server.experimental.request_context.Experimental, but importing it here + # triggers mcp.server.__init__ -> fastmcp -> tools -> back to this module. + # The Server sets this to an Experimental instance at runtime. + experimental: Any = field(default=None) + request: RequestT | None = None + close_sse_stream: CloseSSEStreamCallback | None = None + close_standalone_sse_stream: CloseSSEStreamCallback | None = None diff --git a/source/target-vendors/cp312/mcp/shared/exceptions.py b/source/target-vendors/cp312/mcp/shared/exceptions.py new file mode 100644 index 0000000..4943114 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/exceptions.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from typing import Any, cast + +from mcp.types import URL_ELICITATION_REQUIRED, ElicitRequestURLParams, ErrorData + + +class McpError(Exception): + """ + Exception type raised when an error arrives over an MCP connection. + """ + + error: ErrorData + + def __init__(self, error: ErrorData): + """Initialize McpError.""" + super().__init__(error.message) + self.error = error + + +class UrlElicitationRequiredError(McpError): + """ + Specialized error for when a tool requires URL mode elicitation(s) before proceeding. + + Servers can raise this error from tool handlers to indicate that the client + must complete one or more URL elicitations before the request can be processed. + + Example: + raise UrlElicitationRequiredError([ + ElicitRequestURLParams( + mode="url", + message="Authorization required for your files", + url="https://example.com/oauth/authorize", + elicitationId="auth-001" + ) + ]) + """ + + def __init__( + self, + elicitations: list[ElicitRequestURLParams], + message: str | None = None, + ): + """Initialize UrlElicitationRequiredError.""" + if message is None: + message = f"URL elicitation{'s' if len(elicitations) > 1 else ''} required" + + self._elicitations = elicitations + + error = ErrorData( + code=URL_ELICITATION_REQUIRED, + message=message, + data={"elicitations": [e.model_dump(by_alias=True, exclude_none=True) for e in elicitations]}, + ) + super().__init__(error) + + @property + def elicitations(self) -> list[ElicitRequestURLParams]: + """The list of URL elicitations required before the request can proceed.""" + return self._elicitations + + @classmethod + def from_error(cls, error: ErrorData) -> UrlElicitationRequiredError: + """Reconstruct from an ErrorData received over the wire.""" + if error.code != URL_ELICITATION_REQUIRED: + raise ValueError(f"Expected error code {URL_ELICITATION_REQUIRED}, got {error.code}") + + data = cast(dict[str, Any], error.data or {}) + raw_elicitations = cast(list[dict[str, Any]], data.get("elicitations", [])) + elicitations = [ElicitRequestURLParams.model_validate(e) for e in raw_elicitations] + return cls(elicitations, error.message) diff --git a/source/target-vendors/cp312/mcp/shared/experimental/__init__.py b/source/target-vendors/cp312/mcp/shared/experimental/__init__.py new file mode 100644 index 0000000..9b1b147 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/__init__.py @@ -0,0 +1,7 @@ +""" +Pure experimental MCP features (no server dependencies). + +WARNING: These APIs are experimental and may change without notice. + +For server-integrated experimental features, use mcp.server.experimental. +""" diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/__init__.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/__init__.py new file mode 100644 index 0000000..37d81af --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/__init__.py @@ -0,0 +1,12 @@ +""" +Pure task state management for MCP. + +WARNING: These APIs are experimental and may change without notice. + +Import directly from submodules: +- mcp.shared.experimental.tasks.store.TaskStore +- mcp.shared.experimental.tasks.context.TaskContext +- mcp.shared.experimental.tasks.in_memory_task_store.InMemoryTaskStore +- mcp.shared.experimental.tasks.message_queue.TaskMessageQueue +- mcp.shared.experimental.tasks.helpers.is_terminal +""" diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/capabilities.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/capabilities.py new file mode 100644 index 0000000..307fcdd --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/capabilities.py @@ -0,0 +1,115 @@ +""" +Tasks capability checking utilities. + +This module provides functions for checking and requiring task-related +capabilities. All tasks capability logic is centralized here to keep +the main session code clean. + +WARNING: These APIs are experimental and may change without notice. +""" + +from mcp.shared.exceptions import McpError +from mcp.types import ( + INVALID_REQUEST, + ClientCapabilities, + ClientTasksCapability, + ErrorData, +) + + +def check_tasks_capability( + required: ClientTasksCapability, + client: ClientTasksCapability, +) -> bool: + """ + Check if client's tasks capability matches the required capability. + + Args: + required: The capability being checked for + client: The client's declared capabilities + + Returns: + True if client has the required capability, False otherwise + """ + if required.requests is None: + return True + if client.requests is None: + return False + + # Check elicitation.create + if required.requests.elicitation is not None: + if client.requests.elicitation is None: + return False + if required.requests.elicitation.create is not None: + if client.requests.elicitation.create is None: + return False + + # Check sampling.createMessage + if required.requests.sampling is not None: + if client.requests.sampling is None: + return False + if required.requests.sampling.createMessage is not None: + if client.requests.sampling.createMessage is None: + return False + + return True + + +def has_task_augmented_elicitation(caps: ClientCapabilities) -> bool: + """Check if capabilities include task-augmented elicitation support.""" + if caps.tasks is None: + return False + if caps.tasks.requests is None: + return False + if caps.tasks.requests.elicitation is None: + return False + return caps.tasks.requests.elicitation.create is not None + + +def has_task_augmented_sampling(caps: ClientCapabilities) -> bool: + """Check if capabilities include task-augmented sampling support.""" + if caps.tasks is None: + return False + if caps.tasks.requests is None: + return False + if caps.tasks.requests.sampling is None: + return False + return caps.tasks.requests.sampling.createMessage is not None + + +def require_task_augmented_elicitation(client_caps: ClientCapabilities | None) -> None: + """ + Raise McpError if client doesn't support task-augmented elicitation. + + Args: + client_caps: The client's declared capabilities, or None if not initialized + + Raises: + McpError: If client doesn't support task-augmented elicitation + """ + if client_caps is None or not has_task_augmented_elicitation(client_caps): + raise McpError( + ErrorData( + code=INVALID_REQUEST, + message="Client does not support task-augmented elicitation", + ) + ) + + +def require_task_augmented_sampling(client_caps: ClientCapabilities | None) -> None: + """ + Raise McpError if client doesn't support task-augmented sampling. + + Args: + client_caps: The client's declared capabilities, or None if not initialized + + Raises: + McpError: If client doesn't support task-augmented sampling + """ + if client_caps is None or not has_task_augmented_sampling(client_caps): + raise McpError( + ErrorData( + code=INVALID_REQUEST, + message="Client does not support task-augmented sampling", + ) + ) diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/context.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/context.py new file mode 100644 index 0000000..12d1595 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/context.py @@ -0,0 +1,101 @@ +""" +TaskContext - Pure task state management. + +This module provides TaskContext, which manages task state without any +server/session dependencies. It can be used standalone for distributed +workers or wrapped by ServerTaskContext for full server integration. +""" + +from mcp.shared.experimental.tasks.store import TaskStore +from mcp.types import TASK_STATUS_COMPLETED, TASK_STATUS_FAILED, Result, Task + + +class TaskContext: + """ + Pure task state management - no session dependencies. + + This class handles: + - Task state (status, result) + - Cancellation tracking + - Store interactions + + For server-integrated features (elicit, create_message, notifications), + use ServerTaskContext from mcp.server.experimental. + + Example (distributed worker): + async def worker_job(task_id: str): + store = RedisTaskStore(redis_url) + task = await store.get_task(task_id) + ctx = TaskContext(task=task, store=store) + + await ctx.update_status("Working...") + result = await do_work() + await ctx.complete(result) + """ + + def __init__(self, task: Task, store: TaskStore): + self._task = task + self._store = store + self._cancelled = False + + @property + def task_id(self) -> str: + """The task identifier.""" + return self._task.taskId + + @property + def task(self) -> Task: + """The current task state.""" + return self._task + + @property + def is_cancelled(self) -> bool: + """Whether cancellation has been requested.""" + return self._cancelled + + def request_cancellation(self) -> None: + """ + Request cancellation of this task. + + This sets is_cancelled=True. Task work should check this + periodically and exit gracefully if set. + """ + self._cancelled = True + + async def update_status(self, message: str) -> None: + """ + Update the task's status message. + + Args: + message: The new status message + """ + self._task = await self._store.update_task( + self.task_id, + status_message=message, + ) + + async def complete(self, result: Result) -> None: + """ + Mark the task as completed with the given result. + + Args: + result: The task result + """ + await self._store.store_result(self.task_id, result) + self._task = await self._store.update_task( + self.task_id, + status=TASK_STATUS_COMPLETED, + ) + + async def fail(self, error: str) -> None: + """ + Mark the task as failed with an error message. + + Args: + error: The error message + """ + self._task = await self._store.update_task( + self.task_id, + status=TASK_STATUS_FAILED, + status_message=error, + ) diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/helpers.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/helpers.py new file mode 100644 index 0000000..5c87f9e --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/helpers.py @@ -0,0 +1,181 @@ +""" +Helper functions for pure task management. + +These helpers work with pure TaskContext and don't require server dependencies. +For server-integrated task helpers, use mcp.server.experimental. +""" + +from collections.abc import AsyncIterator +from contextlib import asynccontextmanager +from datetime import datetime, timezone +from uuid import uuid4 + +from mcp.shared.exceptions import McpError +from mcp.shared.experimental.tasks.context import TaskContext +from mcp.shared.experimental.tasks.store import TaskStore +from mcp.types import ( + INVALID_PARAMS, + TASK_STATUS_CANCELLED, + TASK_STATUS_COMPLETED, + TASK_STATUS_FAILED, + TASK_STATUS_WORKING, + CancelTaskResult, + ErrorData, + Task, + TaskMetadata, + TaskStatus, +) + +# Metadata key for model-immediate-response (per MCP spec) +# Servers MAY include this in CreateTaskResult._meta to provide an immediate +# response string while the task executes in the background. +MODEL_IMMEDIATE_RESPONSE_KEY = "io.modelcontextprotocol/model-immediate-response" + +# Metadata key for associating requests with a task (per MCP spec) +RELATED_TASK_METADATA_KEY = "io.modelcontextprotocol/related-task" + + +def is_terminal(status: TaskStatus) -> bool: + """ + Check if a task status represents a terminal state. + + Terminal states are those where the task has finished and will not change. + + Args: + status: The task status to check + + Returns: + True if the status is terminal (completed, failed, or cancelled) + """ + return status in (TASK_STATUS_COMPLETED, TASK_STATUS_FAILED, TASK_STATUS_CANCELLED) + + +async def cancel_task( + store: TaskStore, + task_id: str, +) -> CancelTaskResult: + """ + Cancel a task with spec-compliant validation. + + Per spec: "Receivers MUST reject cancellation of terminal status tasks + with -32602 (Invalid params)" + + This helper validates that the task exists and is not in a terminal state + before setting it to "cancelled". + + Args: + store: The task store + task_id: The task identifier to cancel + + Returns: + CancelTaskResult with the cancelled task state + + Raises: + McpError: With INVALID_PARAMS (-32602) if: + - Task does not exist + - Task is already in a terminal state (completed, failed, cancelled) + + Example: + @server.experimental.cancel_task() + async def handle_cancel(request: CancelTaskRequest) -> CancelTaskResult: + return await cancel_task(store, request.params.taskId) + """ + task = await store.get_task(task_id) + if task is None: + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message=f"Task not found: {task_id}", + ) + ) + + if is_terminal(task.status): + raise McpError( + ErrorData( + code=INVALID_PARAMS, + message=f"Cannot cancel task in terminal state '{task.status}'", + ) + ) + + # Update task to cancelled status + cancelled_task = await store.update_task(task_id, status=TASK_STATUS_CANCELLED) + return CancelTaskResult(**cancelled_task.model_dump()) + + +def generate_task_id() -> str: + """Generate a unique task ID.""" + return str(uuid4()) + + +def create_task_state( + metadata: TaskMetadata, + task_id: str | None = None, +) -> Task: + """ + Create a Task object with initial state. + + This is a helper for TaskStore implementations. + + Args: + metadata: Task metadata + task_id: Optional task ID (generated if not provided) + + Returns: + A new Task in "working" status + """ + now = datetime.now(timezone.utc) + return Task( + taskId=task_id or generate_task_id(), + status=TASK_STATUS_WORKING, + createdAt=now, + lastUpdatedAt=now, + ttl=metadata.ttl, + pollInterval=500, # Default 500ms poll interval + ) + + +@asynccontextmanager +async def task_execution( + task_id: str, + store: TaskStore, +) -> AsyncIterator[TaskContext]: + """ + Context manager for safe task execution (pure, no server dependencies). + + Loads a task from the store and provides a TaskContext for the work. + If an unhandled exception occurs, the task is automatically marked as failed + and the exception is suppressed (since the failure is captured in task state). + + This is useful for distributed workers that don't have a server session. + + Args: + task_id: The task identifier to execute + store: The task store (must be accessible by the worker) + + Yields: + TaskContext for updating status and completing/failing the task + + Raises: + ValueError: If the task is not found in the store + + Example (distributed worker): + async def worker_process(task_id: str): + store = RedisTaskStore(redis_url) + async with task_execution(task_id, store) as ctx: + await ctx.update_status("Working...") + result = await do_work() + await ctx.complete(result) + """ + task = await store.get_task(task_id) + if task is None: + raise ValueError(f"Task {task_id} not found") + + ctx = TaskContext(task, store) + try: + yield ctx + except Exception as e: + # Auto-fail the task if an exception occurs and task isn't already terminal + # Exception is suppressed since failure is captured in task state + if not is_terminal(ctx.task.status): + await ctx.fail(str(e)) + # Don't re-raise - the failure is recorded in task state diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/in_memory_task_store.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/in_memory_task_store.py new file mode 100644 index 0000000..7b630ce --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/in_memory_task_store.py @@ -0,0 +1,219 @@ +""" +In-memory implementation of TaskStore for demonstration purposes. + +This implementation stores all tasks in memory and provides automatic cleanup +based on the TTL duration specified in the task metadata using lazy expiration. + +Note: This is not suitable for production use as all data is lost on restart. +For production, consider implementing TaskStore with a database or distributed cache. +""" + +from dataclasses import dataclass, field +from datetime import datetime, timedelta, timezone + +import anyio + +from mcp.shared.experimental.tasks.helpers import create_task_state, is_terminal +from mcp.shared.experimental.tasks.store import TaskStore +from mcp.types import Result, Task, TaskMetadata, TaskStatus + + +@dataclass +class StoredTask: + """Internal storage representation of a task.""" + + task: Task + result: Result | None = None + # Time when this task should be removed (None = never) + expires_at: datetime | None = field(default=None) + + +class InMemoryTaskStore(TaskStore): + """ + A simple in-memory implementation of TaskStore. + + Features: + - Automatic TTL-based cleanup (lazy expiration) + - Thread-safe for single-process async use + - Pagination support for list_tasks + + Limitations: + - All data lost on restart + - Not suitable for distributed systems + - No persistence + + For production, implement TaskStore with Redis, PostgreSQL, etc. + """ + + def __init__(self, page_size: int = 10) -> None: + self._tasks: dict[str, StoredTask] = {} + self._page_size = page_size + self._update_events: dict[str, anyio.Event] = {} + + def _calculate_expiry(self, ttl_ms: int | None) -> datetime | None: + """Calculate expiry time from TTL in milliseconds.""" + if ttl_ms is None: + return None + return datetime.now(timezone.utc) + timedelta(milliseconds=ttl_ms) + + def _is_expired(self, stored: StoredTask) -> bool: + """Check if a task has expired.""" + if stored.expires_at is None: + return False + return datetime.now(timezone.utc) >= stored.expires_at + + def _cleanup_expired(self) -> None: + """Remove all expired tasks. Called lazily during access operations.""" + expired_ids = [task_id for task_id, stored in self._tasks.items() if self._is_expired(stored)] + for task_id in expired_ids: + del self._tasks[task_id] + + async def create_task( + self, + metadata: TaskMetadata, + task_id: str | None = None, + ) -> Task: + """Create a new task with the given metadata.""" + # Cleanup expired tasks on access + self._cleanup_expired() + + task = create_task_state(metadata, task_id) + + if task.taskId in self._tasks: + raise ValueError(f"Task with ID {task.taskId} already exists") + + stored = StoredTask( + task=task, + expires_at=self._calculate_expiry(metadata.ttl), + ) + self._tasks[task.taskId] = stored + + # Return a copy to prevent external modification + return Task(**task.model_dump()) + + async def get_task(self, task_id: str) -> Task | None: + """Get a task by ID.""" + # Cleanup expired tasks on access + self._cleanup_expired() + + stored = self._tasks.get(task_id) + if stored is None: + return None + + # Return a copy to prevent external modification + return Task(**stored.task.model_dump()) + + async def update_task( + self, + task_id: str, + status: TaskStatus | None = None, + status_message: str | None = None, + ) -> Task: + """Update a task's status and/or message.""" + stored = self._tasks.get(task_id) + if stored is None: + raise ValueError(f"Task with ID {task_id} not found") + + # Per spec: Terminal states MUST NOT transition to any other status + if status is not None and status != stored.task.status and is_terminal(stored.task.status): + raise ValueError(f"Cannot transition from terminal status '{stored.task.status}'") + + status_changed = False + if status is not None and stored.task.status != status: + stored.task.status = status + status_changed = True + + if status_message is not None: + stored.task.statusMessage = status_message + + # Update lastUpdatedAt on any change + stored.task.lastUpdatedAt = datetime.now(timezone.utc) + + # If task is now terminal and has TTL, reset expiry timer + if status is not None and is_terminal(status) and stored.task.ttl is not None: + stored.expires_at = self._calculate_expiry(stored.task.ttl) + + # Notify waiters if status changed + if status_changed: + await self.notify_update(task_id) + + return Task(**stored.task.model_dump()) + + async def store_result(self, task_id: str, result: Result) -> None: + """Store the result for a task.""" + stored = self._tasks.get(task_id) + if stored is None: + raise ValueError(f"Task with ID {task_id} not found") + + stored.result = result + + async def get_result(self, task_id: str) -> Result | None: + """Get the stored result for a task.""" + stored = self._tasks.get(task_id) + if stored is None: + return None + + return stored.result + + async def list_tasks( + self, + cursor: str | None = None, + ) -> tuple[list[Task], str | None]: + """List tasks with pagination.""" + # Cleanup expired tasks on access + self._cleanup_expired() + + all_task_ids = list(self._tasks.keys()) + + start_index = 0 + if cursor is not None: + try: + cursor_index = all_task_ids.index(cursor) + start_index = cursor_index + 1 + except ValueError: + raise ValueError(f"Invalid cursor: {cursor}") + + page_task_ids = all_task_ids[start_index : start_index + self._page_size] + tasks = [Task(**self._tasks[tid].task.model_dump()) for tid in page_task_ids] + + # Determine next cursor + next_cursor = None + if start_index + self._page_size < len(all_task_ids) and page_task_ids: + next_cursor = page_task_ids[-1] + + return tasks, next_cursor + + async def delete_task(self, task_id: str) -> bool: + """Delete a task.""" + if task_id not in self._tasks: + return False + + del self._tasks[task_id] + return True + + async def wait_for_update(self, task_id: str) -> None: + """Wait until the task status changes.""" + if task_id not in self._tasks: + raise ValueError(f"Task with ID {task_id} not found") + + # Create a fresh event for waiting (anyio.Event can't be cleared) + self._update_events[task_id] = anyio.Event() + event = self._update_events[task_id] + await event.wait() + + async def notify_update(self, task_id: str) -> None: + """Signal that a task has been updated.""" + if task_id in self._update_events: + self._update_events[task_id].set() + + # --- Testing/debugging helpers --- + + def cleanup(self) -> None: + """Cleanup all tasks (useful for testing or graceful shutdown).""" + self._tasks.clear() + self._update_events.clear() + + def get_all_tasks(self) -> list[Task]: + """Get all tasks (useful for debugging). Returns copies to prevent modification.""" + self._cleanup_expired() + return [Task(**stored.task.model_dump()) for stored in self._tasks.values()] diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/message_queue.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/message_queue.py new file mode 100644 index 0000000..69b6609 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/message_queue.py @@ -0,0 +1,241 @@ +""" +TaskMessageQueue - FIFO queue for task-related messages. + +This implements the core message queue pattern from the MCP Tasks spec. +When a handler needs to send a request (like elicitation) during a task-augmented +request, the message is enqueued instead of sent directly. Messages are delivered +to the client only through the `tasks/result` endpoint. + +This pattern enables: +1. Decoupling request handling from message delivery +2. Proper bidirectional communication via the tasks/result stream +3. Automatic status management (working <-> input_required) +""" + +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from datetime import datetime, timezone +from typing import Any, Literal + +import anyio + +from mcp.shared.experimental.tasks.resolver import Resolver +from mcp.types import JSONRPCNotification, JSONRPCRequest, RequestId + + +@dataclass +class QueuedMessage: + """ + A message queued for delivery via tasks/result. + + Messages are stored with their type and a resolver for requests + that expect responses. + """ + + type: Literal["request", "notification"] + """Whether this is a request (expects response) or notification (one-way).""" + + message: JSONRPCRequest | JSONRPCNotification + """The JSON-RPC message to send.""" + + timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc)) + """When the message was enqueued.""" + + resolver: Resolver[dict[str, Any]] | None = None + """Resolver to set when response arrives (only for requests).""" + + original_request_id: RequestId | None = None + """The original request ID used internally, for routing responses back.""" + + +class TaskMessageQueue(ABC): + """ + Abstract interface for task message queuing. + + This is a FIFO queue that stores messages to be delivered via `tasks/result`. + When a task-augmented handler calls elicit() or sends a notification, the + message is enqueued here instead of being sent directly to the client. + + The `tasks/result` handler then dequeues and sends these messages through + the transport, with `relatedRequestId` set to the tasks/result request ID + so responses are routed correctly. + + Implementations can use in-memory storage, Redis, etc. + """ + + @abstractmethod + async def enqueue(self, task_id: str, message: QueuedMessage) -> None: + """ + Add a message to the queue for a task. + + Args: + task_id: The task identifier + message: The message to enqueue + """ + + @abstractmethod + async def dequeue(self, task_id: str) -> QueuedMessage | None: + """ + Remove and return the next message from the queue. + + Args: + task_id: The task identifier + + Returns: + The next message, or None if queue is empty + """ + + @abstractmethod + async def peek(self, task_id: str) -> QueuedMessage | None: + """ + Return the next message without removing it. + + Args: + task_id: The task identifier + + Returns: + The next message, or None if queue is empty + """ + + @abstractmethod + async def is_empty(self, task_id: str) -> bool: + """ + Check if the queue is empty for a task. + + Args: + task_id: The task identifier + + Returns: + True if no messages are queued + """ + + @abstractmethod + async def clear(self, task_id: str) -> list[QueuedMessage]: + """ + Remove and return all messages from the queue. + + This is useful for cleanup when a task is cancelled or completed. + + Args: + task_id: The task identifier + + Returns: + All queued messages (may be empty) + """ + + @abstractmethod + async def wait_for_message(self, task_id: str) -> None: + """ + Wait until a message is available in the queue. + + This blocks until either: + 1. A message is enqueued for this task + 2. The wait is cancelled + + Args: + task_id: The task identifier + """ + + @abstractmethod + async def notify_message_available(self, task_id: str) -> None: + """ + Signal that a message is available for a task. + + This wakes up any coroutines waiting in wait_for_message(). + + Args: + task_id: The task identifier + """ + + +class InMemoryTaskMessageQueue(TaskMessageQueue): + """ + In-memory implementation of TaskMessageQueue. + + This is suitable for single-process servers. For distributed systems, + implement TaskMessageQueue with Redis, RabbitMQ, etc. + + Features: + - FIFO ordering per task + - Async wait for message availability + - Thread-safe for single-process async use + """ + + def __init__(self) -> None: + self._queues: dict[str, list[QueuedMessage]] = {} + self._events: dict[str, anyio.Event] = {} + + def _get_queue(self, task_id: str) -> list[QueuedMessage]: + """Get or create the queue for a task.""" + if task_id not in self._queues: + self._queues[task_id] = [] + return self._queues[task_id] + + async def enqueue(self, task_id: str, message: QueuedMessage) -> None: + """Add a message to the queue.""" + queue = self._get_queue(task_id) + queue.append(message) + # Signal that a message is available + await self.notify_message_available(task_id) + + async def dequeue(self, task_id: str) -> QueuedMessage | None: + """Remove and return the next message.""" + queue = self._get_queue(task_id) + if not queue: + return None + return queue.pop(0) + + async def peek(self, task_id: str) -> QueuedMessage | None: + """Return the next message without removing it.""" + queue = self._get_queue(task_id) + if not queue: + return None + return queue[0] + + async def is_empty(self, task_id: str) -> bool: + """Check if the queue is empty.""" + queue = self._get_queue(task_id) + return len(queue) == 0 + + async def clear(self, task_id: str) -> list[QueuedMessage]: + """Remove and return all messages.""" + queue = self._get_queue(task_id) + messages = list(queue) + queue.clear() + return messages + + async def wait_for_message(self, task_id: str) -> None: + """Wait until a message is available.""" + # Check if there are already messages + if not await self.is_empty(task_id): + return + + # Create a fresh event for waiting (anyio.Event can't be cleared) + self._events[task_id] = anyio.Event() + event = self._events[task_id] + + # Double-check after creating event (avoid race condition) + if not await self.is_empty(task_id): + return + + # Wait for a new message + await event.wait() + + async def notify_message_available(self, task_id: str) -> None: + """Signal that a message is available.""" + if task_id in self._events: + self._events[task_id].set() + + def cleanup(self, task_id: str | None = None) -> None: + """ + Clean up queues and events. + + Args: + task_id: If provided, clean up only this task. Otherwise clean up all. + """ + if task_id is not None: + self._queues.pop(task_id, None) + self._events.pop(task_id, None) + else: + self._queues.clear() + self._events.clear() diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/polling.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/polling.py new file mode 100644 index 0000000..39db2e6 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/polling.py @@ -0,0 +1,45 @@ +""" +Shared polling utilities for task operations. + +This module provides generic polling logic that works for both client→server +and server→client task polling. + +WARNING: These APIs are experimental and may change without notice. +""" + +from collections.abc import AsyncIterator, Awaitable, Callable + +import anyio + +from mcp.shared.experimental.tasks.helpers import is_terminal +from mcp.types import GetTaskResult + + +async def poll_until_terminal( + get_task: Callable[[str], Awaitable[GetTaskResult]], + task_id: str, + default_interval_ms: int = 500, +) -> AsyncIterator[GetTaskResult]: + """ + Poll a task until it reaches terminal status. + + This is a generic utility that works for both client→server and server→client + polling. The caller provides the get_task function appropriate for their direction. + + Args: + get_task: Async function that takes task_id and returns GetTaskResult + task_id: The task to poll + default_interval_ms: Fallback poll interval if server doesn't specify + + Yields: + GetTaskResult for each poll + """ + while True: + status = await get_task(task_id) + yield status + + if is_terminal(status.status): + break + + interval_ms = status.pollInterval if status.pollInterval is not None else default_interval_ms + await anyio.sleep(interval_ms / 1000) diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/resolver.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/resolver.py new file mode 100644 index 0000000..f27425b --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/resolver.py @@ -0,0 +1,60 @@ +""" +Resolver - An anyio-compatible future-like object for async result passing. + +This provides a simple way to pass a result (or exception) from one coroutine +to another without depending on asyncio.Future. +""" + +from typing import Generic, TypeVar, cast + +import anyio + +T = TypeVar("T") + + +class Resolver(Generic[T]): + """ + A simple resolver for passing results between coroutines. + + Unlike asyncio.Future, this works with any anyio-compatible async backend. + + Usage: + resolver: Resolver[str] = Resolver() + + # In one coroutine: + resolver.set_result("hello") + + # In another coroutine: + result = await resolver.wait() # returns "hello" + """ + + def __init__(self) -> None: + self._event = anyio.Event() + self._value: T | None = None + self._exception: BaseException | None = None + + def set_result(self, value: T) -> None: + """Set the result value and wake up waiters.""" + if self._event.is_set(): + raise RuntimeError("Resolver already completed") + self._value = value + self._event.set() + + def set_exception(self, exc: BaseException) -> None: + """Set an exception and wake up waiters.""" + if self._event.is_set(): + raise RuntimeError("Resolver already completed") + self._exception = exc + self._event.set() + + async def wait(self) -> T: + """Wait for the result and return it, or raise the exception.""" + await self._event.wait() + if self._exception is not None: + raise self._exception + # If we reach here, set_result() was called, so _value is set + return cast(T, self._value) + + def done(self) -> bool: + """Return True if the resolver has been completed.""" + return self._event.is_set() diff --git a/source/target-vendors/cp312/mcp/shared/experimental/tasks/store.py b/source/target-vendors/cp312/mcp/shared/experimental/tasks/store.py new file mode 100644 index 0000000..71fb451 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/experimental/tasks/store.py @@ -0,0 +1,156 @@ +""" +TaskStore - Abstract interface for task state storage. +""" + +from abc import ABC, abstractmethod + +from mcp.types import Result, Task, TaskMetadata, TaskStatus + + +class TaskStore(ABC): + """ + Abstract interface for task state storage. + + This is a pure storage interface - it doesn't manage execution. + Implementations can use in-memory storage, databases, Redis, etc. + + All methods are async to support various backends. + """ + + @abstractmethod + async def create_task( + self, + metadata: TaskMetadata, + task_id: str | None = None, + ) -> Task: + """ + Create a new task. + + Args: + metadata: Task metadata (ttl, etc.) + task_id: Optional task ID. If None, implementation should generate one. + + Returns: + The created Task with status="working" + + Raises: + ValueError: If task_id already exists + """ + + @abstractmethod + async def get_task(self, task_id: str) -> Task | None: + """ + Get a task by ID. + + Args: + task_id: The task identifier + + Returns: + The Task, or None if not found + """ + + @abstractmethod + async def update_task( + self, + task_id: str, + status: TaskStatus | None = None, + status_message: str | None = None, + ) -> Task: + """ + Update a task's status and/or message. + + Args: + task_id: The task identifier + status: New status (if changing) + status_message: New status message (if changing) + + Returns: + The updated Task + + Raises: + ValueError: If task not found + ValueError: If attempting to transition from a terminal status + (completed, failed, cancelled). Per spec, terminal states + MUST NOT transition to any other status. + """ + + @abstractmethod + async def store_result(self, task_id: str, result: Result) -> None: + """ + Store the result for a task. + + Args: + task_id: The task identifier + result: The result to store + + Raises: + ValueError: If task not found + """ + + @abstractmethod + async def get_result(self, task_id: str) -> Result | None: + """ + Get the stored result for a task. + + Args: + task_id: The task identifier + + Returns: + The stored Result, or None if not available + """ + + @abstractmethod + async def list_tasks( + self, + cursor: str | None = None, + ) -> tuple[list[Task], str | None]: + """ + List tasks with pagination. + + Args: + cursor: Optional cursor for pagination + + Returns: + Tuple of (tasks, next_cursor). next_cursor is None if no more pages. + """ + + @abstractmethod + async def delete_task(self, task_id: str) -> bool: + """ + Delete a task. + + Args: + task_id: The task identifier + + Returns: + True if deleted, False if not found + """ + + @abstractmethod + async def wait_for_update(self, task_id: str) -> None: + """ + Wait until the task status changes. + + This blocks until either: + 1. The task status changes + 2. The wait is cancelled + + Used by tasks/result to wait for task completion or status changes. + + Args: + task_id: The task identifier + + Raises: + ValueError: If task not found + """ + + @abstractmethod + async def notify_update(self, task_id: str) -> None: + """ + Signal that a task has been updated. + + This wakes up any coroutines waiting in wait_for_update(). + + Args: + task_id: The task identifier + """ diff --git a/source/target-vendors/cp312/mcp/shared/memory.py b/source/target-vendors/cp312/mcp/shared/memory.py new file mode 100644 index 0000000..06d404e --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/memory.py @@ -0,0 +1,98 @@ +""" +In-memory transports +""" + +from __future__ import annotations + +from collections.abc import AsyncGenerator +from contextlib import asynccontextmanager +from datetime import timedelta +from typing import Any + +import anyio +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream + +import mcp.types as types +from mcp.client.session import ClientSession, ElicitationFnT, ListRootsFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT +from mcp.server import Server +from mcp.server.fastmcp import FastMCP +from mcp.shared.message import SessionMessage + +MessageStream = tuple[MemoryObjectReceiveStream[SessionMessage | Exception], MemoryObjectSendStream[SessionMessage]] + + +@asynccontextmanager +async def create_client_server_memory_streams() -> AsyncGenerator[tuple[MessageStream, MessageStream], None]: + """ + Creates a pair of bidirectional memory streams for client-server communication. + + Returns: + A tuple of (client_streams, server_streams) where each is a tuple of + (read_stream, write_stream) + """ + # Create streams for both directions + server_to_client_send, server_to_client_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1) + client_to_server_send, client_to_server_receive = anyio.create_memory_object_stream[SessionMessage | Exception](1) + + client_streams = (server_to_client_receive, client_to_server_send) + server_streams = (client_to_server_receive, server_to_client_send) + + async with ( + server_to_client_receive, + client_to_server_send, + client_to_server_receive, + server_to_client_send, + ): + yield client_streams, server_streams + + +@asynccontextmanager +async def create_connected_server_and_client_session( + server: Server[Any] | FastMCP, + read_timeout_seconds: timedelta | None = None, + sampling_callback: SamplingFnT | None = None, + list_roots_callback: ListRootsFnT | None = None, + logging_callback: LoggingFnT | None = None, + message_handler: MessageHandlerFnT | None = None, + client_info: types.Implementation | None = None, + raise_exceptions: bool = False, + elicitation_callback: ElicitationFnT | None = None, +) -> AsyncGenerator[ClientSession, None]: + """Creates a ClientSession that is connected to a running MCP server.""" + + # TODO(Marcelo): we should have a proper `Client` that can use this "in-memory transport", + # and we should expose a method in the `FastMCP` so we don't access a private attribute. + if isinstance(server, FastMCP): # pragma: no cover + server = server._mcp_server # type: ignore[reportPrivateUsage] + + async with create_client_server_memory_streams() as (client_streams, server_streams): + client_read, client_write = client_streams + server_read, server_write = server_streams + + # Create a cancel scope for the server task + async with anyio.create_task_group() as tg: + tg.start_soon( + lambda: server.run( + server_read, + server_write, + server.create_initialization_options(), + raise_exceptions=raise_exceptions, + ) + ) + + try: + async with ClientSession( + read_stream=client_read, + write_stream=client_write, + read_timeout_seconds=read_timeout_seconds, + sampling_callback=sampling_callback, + list_roots_callback=list_roots_callback, + logging_callback=logging_callback, + message_handler=message_handler, + client_info=client_info, + elicitation_callback=elicitation_callback, + ) as client_session: + await client_session.initialize() + yield client_session + finally: # pragma: no cover + tg.cancel_scope.cancel() diff --git a/source/target-vendors/cp312/mcp/shared/message.py b/source/target-vendors/cp312/mcp/shared/message.py new file mode 100644 index 0000000..81503ea --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/message.py @@ -0,0 +1,50 @@ +""" +Message wrapper with metadata support. + +This module defines a wrapper type that combines JSONRPCMessage with metadata +to support transport-specific features like resumability. +""" + +from collections.abc import Awaitable, Callable +from dataclasses import dataclass + +from mcp.types import JSONRPCMessage, RequestId + +ResumptionToken = str + +ResumptionTokenUpdateCallback = Callable[[ResumptionToken], Awaitable[None]] + +# Callback type for closing SSE streams without terminating +CloseSSEStreamCallback = Callable[[], Awaitable[None]] + + +@dataclass +class ClientMessageMetadata: + """Metadata specific to client messages.""" + + resumption_token: ResumptionToken | None = None + on_resumption_token_update: Callable[[ResumptionToken], Awaitable[None]] | None = None + + +@dataclass +class ServerMessageMetadata: + """Metadata specific to server messages.""" + + related_request_id: RequestId | None = None + # Request-specific context (e.g., headers, auth info) + request_context: object | None = None + # Callback to close SSE stream for the current request without terminating + close_sse_stream: CloseSSEStreamCallback | None = None + # Callback to close the standalone GET SSE stream (for unsolicited notifications) + close_standalone_sse_stream: CloseSSEStreamCallback | None = None + + +MessageMetadata = ClientMessageMetadata | ServerMessageMetadata | None + + +@dataclass +class SessionMessage: + """A message with specific metadata for transport-specific features.""" + + message: JSONRPCMessage + metadata: MessageMetadata = None diff --git a/source/target-vendors/cp312/mcp/shared/metadata_utils.py b/source/target-vendors/cp312/mcp/shared/metadata_utils.py new file mode 100644 index 0000000..e3f49da --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/metadata_utils.py @@ -0,0 +1,45 @@ +"""Utility functions for working with metadata in MCP types. + +These utilities are primarily intended for client-side usage to properly display +human-readable names in user interfaces in a spec compliant way. +""" + +from mcp.types import Implementation, Prompt, Resource, ResourceTemplate, Tool + + +def get_display_name(obj: Tool | Resource | Prompt | ResourceTemplate | Implementation) -> str: + """ + Get the display name for an MCP object with proper precedence. + + This is a client-side utility function designed to help MCP clients display + human-readable names in their user interfaces. When servers provide a 'title' + field, it should be preferred over the programmatic 'name' field for display. + + For tools: title > annotations.title > name + For other objects: title > name + + Example: + # In a client displaying available tools + tools = await session.list_tools() + for tool in tools.tools: + display_name = get_display_name(tool) + print(f"Available tool: {display_name}") + + Args: + obj: An MCP object with name and optional title fields + + Returns: + The display name to use for UI presentation + """ + if isinstance(obj, Tool): + # Tools have special precedence: title > annotations.title > name + if hasattr(obj, "title") and obj.title is not None: + return obj.title + if obj.annotations and hasattr(obj.annotations, "title") and obj.annotations.title is not None: + return obj.annotations.title + return obj.name + else: + # All other objects: title > name + if hasattr(obj, "title") and obj.title is not None: + return obj.title + return obj.name diff --git a/source/target-vendors/cp312/mcp/shared/progress.py b/source/target-vendors/cp312/mcp/shared/progress.py new file mode 100644 index 0000000..a230c58 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/progress.py @@ -0,0 +1,58 @@ +from collections.abc import Generator +from contextlib import contextmanager +from dataclasses import dataclass, field +from typing import Generic + +from pydantic import BaseModel + +from mcp.shared.context import LifespanContextT, RequestContext +from mcp.shared.session import ( + BaseSession, + ReceiveNotificationT, + ReceiveRequestT, + SendNotificationT, + SendRequestT, + SendResultT, +) +from mcp.types import ProgressToken + + +class Progress(BaseModel): + progress: float + total: float | None + + +@dataclass +class ProgressContext(Generic[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT]): + session: BaseSession[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT] + progress_token: ProgressToken + total: float | None + current: float = field(default=0.0, init=False) + + async def progress(self, amount: float, message: str | None = None) -> None: + self.current += amount + + await self.session.send_progress_notification( + self.progress_token, self.current, total=self.total, message=message + ) + + +@contextmanager +def progress( + ctx: RequestContext[ + BaseSession[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT], + LifespanContextT, + ], + total: float | None = None, +) -> Generator[ + ProgressContext[SendRequestT, SendNotificationT, SendResultT, ReceiveRequestT, ReceiveNotificationT], + None, +]: + if ctx.meta is None or ctx.meta.progressToken is None: # pragma: no cover + raise ValueError("No progress token provided") + + progress_ctx = ProgressContext(ctx.session, ctx.meta.progressToken, total) + try: + yield progress_ctx + finally: + pass diff --git a/source/target-vendors/cp312/mcp/shared/response_router.py b/source/target-vendors/cp312/mcp/shared/response_router.py new file mode 100644 index 0000000..3179615 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/response_router.py @@ -0,0 +1,63 @@ +""" +ResponseRouter - Protocol for pluggable response routing. + +This module defines a protocol for routing JSON-RPC responses to alternative +handlers before falling back to the default response stream mechanism. + +The primary use case is task-augmented requests: when a TaskSession enqueues +a request (like elicitation), the response needs to be routed back to the +waiting resolver instead of the normal response stream. + +Design: +- Protocol-based for testability and flexibility +- Returns bool to indicate if response was handled +- Supports both success responses and errors +""" + +from typing import Any, Protocol + +from mcp.types import ErrorData, RequestId + + +class ResponseRouter(Protocol): + """ + Protocol for routing responses to alternative handlers. + + Implementations check if they have a pending request for the given ID + and deliver the response/error to the appropriate handler. + + Example: + class TaskResultHandler(ResponseRouter): + def route_response(self, request_id, response): + resolver = self._pending_requests.pop(request_id, None) + if resolver: + resolver.set_result(response) + return True + return False + """ + + def route_response(self, request_id: RequestId, response: dict[str, Any]) -> bool: + """ + Try to route a response to a pending request handler. + + Args: + request_id: The JSON-RPC request ID from the response + response: The response result data + + Returns: + True if the response was handled, False otherwise + """ + ... # pragma: no cover + + def route_error(self, request_id: RequestId, error: ErrorData) -> bool: + """ + Try to route an error to a pending request handler. + + Args: + request_id: The JSON-RPC request ID from the error response + error: The error data + + Returns: + True if the error was handled, False otherwise + """ + ... # pragma: no cover diff --git a/source/target-vendors/cp312/mcp/shared/session.py b/source/target-vendors/cp312/mcp/shared/session.py new file mode 100644 index 0000000..3033acd --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/session.py @@ -0,0 +1,550 @@ +import logging +from collections.abc import Callable +from contextlib import AsyncExitStack +from datetime import timedelta +from types import TracebackType +from typing import Any, Generic, Protocol, TypeVar + +import anyio +import httpx +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream +from pydantic import BaseModel +from typing_extensions import Self + +from mcp.shared.exceptions import McpError +from mcp.shared.message import MessageMetadata, ServerMessageMetadata, SessionMessage +from mcp.shared.response_router import ResponseRouter +from mcp.types import ( + CONNECTION_CLOSED, + INVALID_PARAMS, + CancelledNotification, + ClientNotification, + ClientRequest, + ClientResult, + ErrorData, + JSONRPCError, + JSONRPCMessage, + JSONRPCNotification, + JSONRPCRequest, + JSONRPCResponse, + ProgressNotification, + RequestParams, + ServerNotification, + ServerRequest, + ServerResult, +) + +SendRequestT = TypeVar("SendRequestT", ClientRequest, ServerRequest) +SendResultT = TypeVar("SendResultT", ClientResult, ServerResult) +SendNotificationT = TypeVar("SendNotificationT", ClientNotification, ServerNotification) +ReceiveRequestT = TypeVar("ReceiveRequestT", ClientRequest, ServerRequest) +ReceiveResultT = TypeVar("ReceiveResultT", bound=BaseModel) +ReceiveNotificationT = TypeVar("ReceiveNotificationT", ClientNotification, ServerNotification) + +RequestId = str | int + + +class ProgressFnT(Protocol): + """Protocol for progress notification callbacks.""" + + async def __call__( + self, progress: float, total: float | None, message: str | None + ) -> None: ... # pragma: no branch + + +class RequestResponder(Generic[ReceiveRequestT, SendResultT]): + """Handles responding to MCP requests and manages request lifecycle. + + This class MUST be used as a context manager to ensure proper cleanup and + cancellation handling: + + Example: + with request_responder as resp: + await resp.respond(result) + + The context manager ensures: + 1. Proper cancellation scope setup and cleanup + 2. Request completion tracking + 3. Cleanup of in-flight requests + """ + + def __init__( + self, + request_id: RequestId, + request_meta: RequestParams.Meta | None, + request: ReceiveRequestT, + session: """BaseSession[ + SendRequestT, + SendNotificationT, + SendResultT, + ReceiveRequestT, + ReceiveNotificationT + ]""", + on_complete: Callable[["RequestResponder[ReceiveRequestT, SendResultT]"], Any], + message_metadata: MessageMetadata = None, + ) -> None: + self.request_id = request_id + self.request_meta = request_meta + self.request = request + self.message_metadata = message_metadata + self._session = session + self._completed = False + self._cancel_scope = anyio.CancelScope() + self._on_complete = on_complete + self._entered = False # Track if we're in a context manager + + def __enter__(self) -> "RequestResponder[ReceiveRequestT, SendResultT]": + """Enter the context manager, enabling request cancellation tracking.""" + self._entered = True + self._cancel_scope = anyio.CancelScope() + self._cancel_scope.__enter__() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> None: + """Exit the context manager, performing cleanup and notifying completion.""" + try: + if self._completed: # pragma: no branch + self._on_complete(self) + finally: + self._entered = False + if not self._cancel_scope: # pragma: no cover + raise RuntimeError("No active cancel scope") + self._cancel_scope.__exit__(exc_type, exc_val, exc_tb) + + async def respond(self, response: SendResultT | ErrorData) -> None: + """Send a response for this request. + + Must be called within a context manager block. + Raises: + RuntimeError: If not used within a context manager + AssertionError: If request was already responded to + """ + if not self._entered: # pragma: no cover + raise RuntimeError("RequestResponder must be used as a context manager") + assert not self._completed, "Request already responded to" + + if not self.cancelled: # pragma: no branch + self._completed = True + + await self._session._send_response( # type: ignore[reportPrivateUsage] + request_id=self.request_id, response=response + ) + + async def cancel(self) -> None: + """Cancel this request and mark it as completed.""" + if not self._entered: # pragma: no cover + raise RuntimeError("RequestResponder must be used as a context manager") + if not self._cancel_scope: # pragma: no cover + raise RuntimeError("No active cancel scope") + + self._cancel_scope.cancel() + self._completed = True # Mark as completed so it's removed from in_flight + # Send an error response to indicate cancellation + await self._session._send_response( # type: ignore[reportPrivateUsage] + request_id=self.request_id, + response=ErrorData(code=0, message="Request cancelled", data=None), + ) + + @property + def in_flight(self) -> bool: # pragma: no cover + return not self._completed and not self.cancelled + + @property + def cancelled(self) -> bool: # pragma: no cover + return self._cancel_scope.cancel_called + + +class BaseSession( + Generic[ + SendRequestT, + SendNotificationT, + SendResultT, + ReceiveRequestT, + ReceiveNotificationT, + ], +): + """ + Implements an MCP "session" on top of read/write streams, including features + like request/response linking, notifications, and progress. + + This class is an async context manager that automatically starts processing + messages when entered. + """ + + _response_streams: dict[RequestId, MemoryObjectSendStream[JSONRPCResponse | JSONRPCError]] + _request_id: int + _in_flight: dict[RequestId, RequestResponder[ReceiveRequestT, SendResultT]] + _progress_callbacks: dict[RequestId, ProgressFnT] + _response_routers: list["ResponseRouter"] + + def __init__( + self, + read_stream: MemoryObjectReceiveStream[SessionMessage | Exception], + write_stream: MemoryObjectSendStream[SessionMessage], + receive_request_type: type[ReceiveRequestT], + receive_notification_type: type[ReceiveNotificationT], + # If none, reading will never time out + read_timeout_seconds: timedelta | None = None, + ) -> None: + self._read_stream = read_stream + self._write_stream = write_stream + self._response_streams = {} + self._request_id = 0 + self._receive_request_type = receive_request_type + self._receive_notification_type = receive_notification_type + self._session_read_timeout_seconds = read_timeout_seconds + self._in_flight = {} + self._progress_callbacks = {} + self._response_routers = [] + self._exit_stack = AsyncExitStack() + + def add_response_router(self, router: ResponseRouter) -> None: + """ + Register a response router to handle responses for non-standard requests. + + Response routers are checked in order before falling back to the default + response stream mechanism. This is used by TaskResultHandler to route + responses for queued task requests back to their resolvers. + + WARNING: This is an experimental API that may change without notice. + + Args: + router: A ResponseRouter implementation + """ + self._response_routers.append(router) + + async def __aenter__(self) -> Self: + self._task_group = anyio.create_task_group() + await self._task_group.__aenter__() + self._task_group.start_soon(self._receive_loop) + return self + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_val: BaseException | None, + exc_tb: TracebackType | None, + ) -> bool | None: + await self._exit_stack.aclose() + # Using BaseSession as a context manager should not block on exit (this + # would be very surprising behavior), so make sure to cancel the tasks + # in the task group. + self._task_group.cancel_scope.cancel() + return await self._task_group.__aexit__(exc_type, exc_val, exc_tb) + + async def send_request( + self, + request: SendRequestT, + result_type: type[ReceiveResultT], + request_read_timeout_seconds: timedelta | None = None, + metadata: MessageMetadata = None, + progress_callback: ProgressFnT | None = None, + ) -> ReceiveResultT: + """ + Sends a request and wait for a response. Raises an McpError if the + response contains an error. If a request read timeout is provided, it + will take precedence over the session read timeout. + + Do not use this method to emit notifications! Use send_notification() + instead. + """ + request_id = self._request_id + self._request_id = request_id + 1 + + response_stream, response_stream_reader = anyio.create_memory_object_stream[JSONRPCResponse | JSONRPCError](1) + self._response_streams[request_id] = response_stream + + # Set up progress token if progress callback is provided + request_data = request.model_dump(by_alias=True, mode="json", exclude_none=True) + if progress_callback is not None: # pragma: no cover + # Use request_id as progress token + if "params" not in request_data: + request_data["params"] = {} + if "_meta" not in request_data["params"]: # pragma: no branch + request_data["params"]["_meta"] = {} + request_data["params"]["_meta"]["progressToken"] = request_id + # Store the callback for this request + self._progress_callbacks[request_id] = progress_callback + + try: + jsonrpc_request = JSONRPCRequest( + jsonrpc="2.0", + id=request_id, + **request_data, + ) + + await self._write_stream.send(SessionMessage(message=JSONRPCMessage(jsonrpc_request), metadata=metadata)) + + # request read timeout takes precedence over session read timeout + timeout = None + if request_read_timeout_seconds is not None: # pragma: no cover + timeout = request_read_timeout_seconds.total_seconds() + elif self._session_read_timeout_seconds is not None: # pragma: no cover + timeout = self._session_read_timeout_seconds.total_seconds() + + try: + with anyio.fail_after(timeout): + response_or_error = await response_stream_reader.receive() + except TimeoutError: + raise McpError( + ErrorData( + code=httpx.codes.REQUEST_TIMEOUT, + message=( + f"Timed out while waiting for response to " + f"{request.__class__.__name__}. Waited " + f"{timeout} seconds." + ), + ) + ) + + if isinstance(response_or_error, JSONRPCError): + raise McpError(response_or_error.error) + else: + return result_type.model_validate(response_or_error.result) + + finally: + self._response_streams.pop(request_id, None) + self._progress_callbacks.pop(request_id, None) + await response_stream.aclose() + await response_stream_reader.aclose() + + async def send_notification( + self, + notification: SendNotificationT, + related_request_id: RequestId | None = None, + ) -> None: + """ + Emits a notification, which is a one-way message that does not expect + a response. + """ + # Some transport implementations may need to set the related_request_id + # to attribute to the notifications to the request that triggered them. + jsonrpc_notification = JSONRPCNotification( + jsonrpc="2.0", + **notification.model_dump(by_alias=True, mode="json", exclude_none=True), + ) + session_message = SessionMessage( # pragma: no cover + message=JSONRPCMessage(jsonrpc_notification), + metadata=ServerMessageMetadata(related_request_id=related_request_id) if related_request_id else None, + ) + await self._write_stream.send(session_message) + + async def _send_response(self, request_id: RequestId, response: SendResultT | ErrorData) -> None: + if isinstance(response, ErrorData): + jsonrpc_error = JSONRPCError(jsonrpc="2.0", id=request_id, error=response) + session_message = SessionMessage(message=JSONRPCMessage(jsonrpc_error)) + await self._write_stream.send(session_message) + else: + jsonrpc_response = JSONRPCResponse( + jsonrpc="2.0", + id=request_id, + result=response.model_dump(by_alias=True, mode="json", exclude_none=True), + ) + session_message = SessionMessage(message=JSONRPCMessage(jsonrpc_response)) + await self._write_stream.send(session_message) + + async def _receive_loop(self) -> None: + async with ( + self._read_stream, + self._write_stream, + ): + try: + async for message in self._read_stream: + if isinstance(message, Exception): # pragma: no cover + await self._handle_incoming(message) + elif isinstance(message.message.root, JSONRPCRequest): + try: + validated_request = self._receive_request_type.model_validate( + message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True) + ) + responder = RequestResponder( + request_id=message.message.root.id, + request_meta=validated_request.root.params.meta + if validated_request.root.params + else None, + request=validated_request, + session=self, + on_complete=lambda r: self._in_flight.pop(r.request_id, None), + message_metadata=message.metadata, + ) + self._in_flight[responder.request_id] = responder + await self._received_request(responder) + + if not responder._completed: # type: ignore[reportPrivateUsage] + await self._handle_incoming(responder) + except Exception as e: + # For request validation errors, send a proper JSON-RPC error + # response instead of crashing the server + logging.warning(f"Failed to validate request: {e}") + logging.debug(f"Message that failed validation: {message.message.root}") + error_response = JSONRPCError( + jsonrpc="2.0", + id=message.message.root.id, + error=ErrorData( + code=INVALID_PARAMS, + message="Invalid request parameters", + data="", + ), + ) + session_message = SessionMessage(message=JSONRPCMessage(error_response)) + await self._write_stream.send(session_message) + + elif isinstance(message.message.root, JSONRPCNotification): + try: + notification = self._receive_notification_type.model_validate( + message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True) + ) + # Handle cancellation notifications + if isinstance(notification.root, CancelledNotification): + cancelled_id = notification.root.params.requestId + if cancelled_id in self._in_flight: # pragma: no branch + await self._in_flight[cancelled_id].cancel() + else: + # Handle progress notifications callback + if isinstance(notification.root, ProgressNotification): # pragma: no cover + progress_token = notification.root.params.progressToken + # If there is a progress callback for this token, + # call it with the progress information + if progress_token in self._progress_callbacks: + callback = self._progress_callbacks[progress_token] + try: + await callback( + notification.root.params.progress, + notification.root.params.total, + notification.root.params.message, + ) + except Exception as e: + logging.error( + "Progress callback raised an exception: %s", + e, + ) + await self._received_notification(notification) + await self._handle_incoming(notification) + except Exception as e: # pragma: no cover + # For other validation errors, log and continue + logging.warning( + f"Failed to validate notification: {e}. Message was: {message.message.root}" + ) + else: # Response or error + await self._handle_response(message) + + except anyio.ClosedResourceError: + # This is expected when the client disconnects abruptly. + # Without this handler, the exception would propagate up and + # crash the server's task group. + logging.debug("Read stream closed by client") # pragma: no cover + except Exception as e: # pragma: no cover + # Other exceptions are not expected and should be logged. We purposefully + # catch all exceptions here to avoid crashing the server. + logging.exception(f"Unhandled exception in receive loop: {e}") + finally: + # after the read stream is closed, we need to send errors + # to any pending requests + for id, stream in self._response_streams.items(): + error = ErrorData(code=CONNECTION_CLOSED, message="Connection closed") + try: + await stream.send(JSONRPCError(jsonrpc="2.0", id=id, error=error)) + await stream.aclose() + except Exception: # pragma: no cover + # Stream might already be closed + pass + self._response_streams.clear() + + def _normalize_request_id(self, response_id: RequestId) -> RequestId: + """ + Normalize a response ID to match how request IDs are stored. + + Since the client always sends integer IDs, we normalize string IDs + to integers when possible. This matches the TypeScript SDK approach: + https://github.com/modelcontextprotocol/typescript-sdk/blob/a606fb17909ea454e83aab14c73f14ea45c04448/src/shared/protocol.ts#L861 + + Args: + response_id: The response ID from the incoming message. + + Returns: + The normalized ID (int if possible, otherwise original value). + """ + if isinstance(response_id, str): + try: + return int(response_id) + except ValueError: + logging.warning(f"Response ID {response_id!r} cannot be normalized to match pending requests") + return response_id + + async def _handle_response(self, message: SessionMessage) -> None: + """ + Handle an incoming response or error message. + + Checks response routers first (e.g., for task-related responses), + then falls back to the normal response stream mechanism. + """ + root = message.message.root + + # This check is always true at runtime: the caller (_receive_loop) only invokes + # this method in the else branch after checking for JSONRPCRequest and + # JSONRPCNotification. However, the type checker can't infer this from the + # method signature, so we need this guard for type narrowing. + if not isinstance(root, JSONRPCResponse | JSONRPCError): + return # pragma: no cover + + # Normalize response ID to handle type mismatches (e.g., "0" vs 0) + response_id = self._normalize_request_id(root.id) + + # First, check response routers (e.g., TaskResultHandler) + if isinstance(root, JSONRPCError): + # Route error to routers + for router in self._response_routers: + if router.route_error(response_id, root.error): + return # Handled + else: + # Route success response to routers + response_data: dict[str, Any] = root.result or {} + for router in self._response_routers: + if router.route_response(response_id, response_data): + return # Handled + + # Fall back to normal response streams + stream = self._response_streams.pop(response_id, None) + if stream: # pragma: no cover + await stream.send(root) + else: # pragma: no cover + await self._handle_incoming(RuntimeError(f"Received response with an unknown request ID: {message}")) + + async def _received_request(self, responder: RequestResponder[ReceiveRequestT, SendResultT]) -> None: + """ + Can be overridden by subclasses to handle a request without needing to + listen on the message stream. + + If the request is responded to within this method, it will not be + forwarded on to the message stream. + """ + + async def _received_notification(self, notification: ReceiveNotificationT) -> None: + """ + Can be overridden by subclasses to handle a notification without needing + to listen on the message stream. + """ + + async def send_progress_notification( + self, + progress_token: str | int, + progress: float, + total: float | None = None, + message: str | None = None, + ) -> None: + """ + Sends a progress notification for a request that is currently being + processed. + """ + + async def _handle_incoming( + self, + req: RequestResponder[ReceiveRequestT, SendResultT] | ReceiveNotificationT | Exception, + ) -> None: + """A generic handler for incoming messages. Overwritten by subclasses.""" + pass # pragma: no cover diff --git a/source/target-vendors/cp312/mcp/shared/tool_name_validation.py b/source/target-vendors/cp312/mcp/shared/tool_name_validation.py new file mode 100644 index 0000000..f35efa5 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/tool_name_validation.py @@ -0,0 +1,129 @@ +"""Tool name validation utilities according to SEP-986. + +Tool names SHOULD be between 1 and 128 characters in length (inclusive). +Tool names are case-sensitive. +Allowed characters: uppercase and lowercase ASCII letters (A-Z, a-z), +digits (0-9), underscore (_), dash (-), and dot (.). +Tool names SHOULD NOT contain spaces, commas, or other special characters. + +See: https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names +""" + +from __future__ import annotations + +import logging +import re +from dataclasses import dataclass, field + +logger = logging.getLogger(__name__) + +# Regular expression for valid tool names according to SEP-986 specification +TOOL_NAME_REGEX = re.compile(r"^[A-Za-z0-9._-]{1,128}$") + +# SEP reference URL for warning messages +SEP_986_URL = "https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names" + + +@dataclass +class ToolNameValidationResult: + """Result of tool name validation. + + Attributes: + is_valid: Whether the tool name conforms to SEP-986 requirements. + warnings: List of warning messages for non-conforming aspects. + """ + + is_valid: bool + warnings: list[str] = field(default_factory=lambda: []) + + +def validate_tool_name(name: str) -> ToolNameValidationResult: + """Validate a tool name according to the SEP-986 specification. + + Args: + name: The tool name to validate. + + Returns: + ToolNameValidationResult containing validation status and any warnings. + """ + warnings: list[str] = [] + + # Check for empty name + if not name: + return ToolNameValidationResult( + is_valid=False, + warnings=["Tool name cannot be empty"], + ) + + # Check length + if len(name) > 128: + return ToolNameValidationResult( + is_valid=False, + warnings=[f"Tool name exceeds maximum length of 128 characters (current: {len(name)})"], + ) + + # Check for problematic patterns (warnings, not validation failures) + if " " in name: + warnings.append("Tool name contains spaces, which may cause parsing issues") + + if "," in name: + warnings.append("Tool name contains commas, which may cause parsing issues") + + # Check for potentially confusing leading/trailing characters + if name.startswith("-") or name.endswith("-"): + warnings.append("Tool name starts or ends with a dash, which may cause parsing issues in some contexts") + + if name.startswith(".") or name.endswith("."): + warnings.append("Tool name starts or ends with a dot, which may cause parsing issues in some contexts") + + # Check for invalid characters + if not TOOL_NAME_REGEX.match(name): + # Find all invalid characters (unique, preserving order) + invalid_chars: list[str] = [] + seen: set[str] = set() + for char in name: + if not re.match(r"[A-Za-z0-9._-]", char) and char not in seen: + invalid_chars.append(char) + seen.add(char) + + warnings.append(f"Tool name contains invalid characters: {', '.join(repr(c) for c in invalid_chars)}") + warnings.append("Allowed characters are: A-Z, a-z, 0-9, underscore (_), dash (-), and dot (.)") + + return ToolNameValidationResult(is_valid=False, warnings=warnings) + + return ToolNameValidationResult(is_valid=True, warnings=warnings) + + +def issue_tool_name_warning(name: str, warnings: list[str]) -> None: + """Log warnings for non-conforming tool names. + + Args: + name: The tool name that triggered the warnings. + warnings: List of warning messages to log. + """ + if not warnings: + return + + logger.warning(f'Tool name validation warning for "{name}":') + for warning in warnings: + logger.warning(f" - {warning}") + logger.warning("Tool registration will proceed, but this may cause compatibility issues.") + logger.warning("Consider updating the tool name to conform to the MCP tool naming standard.") + logger.warning(f"See SEP-986 ({SEP_986_URL}) for more details.") + + +def validate_and_warn_tool_name(name: str) -> bool: + """Validate a tool name and issue warnings for non-conforming names. + + This is the primary entry point for tool name validation. It validates + the name and logs any warnings via the logging module. + + Args: + name: The tool name to validate. + + Returns: + True if the name is valid, False otherwise. + """ + result = validate_tool_name(name) + issue_tool_name_warning(name, result.warnings) + return result.is_valid diff --git a/source/target-vendors/cp312/mcp/shared/version.py b/source/target-vendors/cp312/mcp/shared/version.py new file mode 100644 index 0000000..d2a1e46 --- /dev/null +++ b/source/target-vendors/cp312/mcp/shared/version.py @@ -0,0 +1,3 @@ +from mcp.types import LATEST_PROTOCOL_VERSION + +SUPPORTED_PROTOCOL_VERSIONS: list[str] = ["2024-11-05", "2025-03-26", "2025-06-18", LATEST_PROTOCOL_VERSION] diff --git a/source/target-vendors/cp312/mcp/types.py b/source/target-vendors/cp312/mcp/types.py new file mode 100644 index 0000000..654c006 --- /dev/null +++ b/source/target-vendors/cp312/mcp/types.py @@ -0,0 +1,1999 @@ +from collections.abc import Callable +from datetime import datetime +from typing import Annotated, Any, Final, Generic, Literal, TypeAlias, TypeVar + +from pydantic import BaseModel, ConfigDict, Field, FileUrl, RootModel +from pydantic.networks import AnyUrl, UrlConstraints +from typing_extensions import deprecated + +""" +Model Context Protocol bindings for Python + +These bindings were generated from https://github.com/modelcontextprotocol/specification, +using Claude, with a prompt something like the following: + +Generate idiomatic Python bindings for this schema for MCP, or the "Model Context +Protocol." The schema is defined in TypeScript, but there's also a JSON Schema version +for reference. + +* For the bindings, let's use Pydantic V2 models. +* Each model should allow extra fields everywhere, by specifying `model_config = + ConfigDict(extra='allow')`. Do this in every case, instead of a custom base class. +* Union types should be represented with a Pydantic `RootModel`. +* Define additional model classes instead of using dictionaries. Do this even if they're + not separate types in the schema. +""" + +LATEST_PROTOCOL_VERSION = "2025-11-25" + +""" +The default negotiated version of the Model Context Protocol when no version is specified. +We need this to satisfy the MCP specification, which requires the server to assume a +specific version if none is provided by the client. See section "Protocol Version Header" at +https://modelcontextprotocol.io/specification +""" +DEFAULT_NEGOTIATED_VERSION = "2025-03-26" + +ProgressToken = str | int +Cursor = str +Role = Literal["user", "assistant"] +RequestId = Annotated[int, Field(strict=True)] | str +AnyFunction: TypeAlias = Callable[..., Any] + +TaskExecutionMode = Literal["forbidden", "optional", "required"] +TASK_FORBIDDEN: Final[Literal["forbidden"]] = "forbidden" +TASK_OPTIONAL: Final[Literal["optional"]] = "optional" +TASK_REQUIRED: Final[Literal["required"]] = "required" + + +class TaskMetadata(BaseModel): + """ + Metadata for augmenting a request with task execution. + Include this in the `task` field of the request parameters. + """ + + model_config = ConfigDict(extra="allow") + + ttl: Annotated[int, Field(strict=True)] | None = None + """Requested duration in milliseconds to retain task from creation.""" + + +class RequestParams(BaseModel): + class Meta(BaseModel): + progressToken: ProgressToken | None = None + """ + If specified, the caller requests out-of-band progress notifications for + this request (as represented by notifications/progress). The value of this + parameter is an opaque token that will be attached to any subsequent + notifications. The receiver is not obligated to provide these notifications. + """ + + model_config = ConfigDict(extra="allow") + + task: TaskMetadata | None = None + """ + If specified, the caller is requesting task-augmented execution for this request. + The request will return a CreateTaskResult immediately, and the actual result can be + retrieved later via tasks/result. + + Task augmentation is subject to capability negotiation - receivers MUST declare support + for task augmentation of specific request types in their capabilities. + """ + + meta: Meta | None = Field(alias="_meta", default=None) + + +class PaginatedRequestParams(RequestParams): + cursor: Cursor | None = None + """ + An opaque token representing the current pagination position. + If provided, the server should return results starting after this cursor. + """ + + +class NotificationParams(BaseModel): + class Meta(BaseModel): + model_config = ConfigDict(extra="allow") + + meta: Meta | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + + +RequestParamsT = TypeVar("RequestParamsT", bound=RequestParams | dict[str, Any] | None) +NotificationParamsT = TypeVar("NotificationParamsT", bound=NotificationParams | dict[str, Any] | None) +MethodT = TypeVar("MethodT", bound=str) + + +class Request(BaseModel, Generic[RequestParamsT, MethodT]): + """Base class for JSON-RPC requests.""" + + method: MethodT + params: RequestParamsT + model_config = ConfigDict(extra="allow") + + +class PaginatedRequest(Request[PaginatedRequestParams | None, MethodT], Generic[MethodT]): + """Base class for paginated requests, + matching the schema's PaginatedRequest interface.""" + + params: PaginatedRequestParams | None = None + + +class Notification(BaseModel, Generic[NotificationParamsT, MethodT]): + """Base class for JSON-RPC notifications.""" + + method: MethodT + params: NotificationParamsT + model_config = ConfigDict(extra="allow") + + +class Result(BaseModel): + """Base class for JSON-RPC results.""" + + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class PaginatedResult(Result): + nextCursor: Cursor | None = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + + +class JSONRPCRequest(Request[dict[str, Any] | None, str]): + """A request that expects a response.""" + + jsonrpc: Literal["2.0"] + id: RequestId + method: str + params: dict[str, Any] | None = None + + +class JSONRPCNotification(Notification[dict[str, Any] | None, str]): + """A notification which does not expect a response.""" + + jsonrpc: Literal["2.0"] + params: dict[str, Any] | None = None + + +class JSONRPCResponse(BaseModel): + """A successful (non-error) response to a request.""" + + jsonrpc: Literal["2.0"] + id: RequestId + result: dict[str, Any] + model_config = ConfigDict(extra="allow") + + +# MCP-specific error codes in the range [-32000, -32099] +URL_ELICITATION_REQUIRED = -32042 +"""Error code indicating that a URL mode elicitation is required before the request can be processed.""" + +# SDK error codes +CONNECTION_CLOSED = -32000 +# REQUEST_TIMEOUT = -32001 # the typescript sdk uses this + +# Standard JSON-RPC error codes +PARSE_ERROR = -32700 +INVALID_REQUEST = -32600 +METHOD_NOT_FOUND = -32601 +INVALID_PARAMS = -32602 +INTERNAL_ERROR = -32603 + + +class ErrorData(BaseModel): + """Error information for JSON-RPC error responses.""" + + code: int + """The error type that occurred.""" + + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single + sentence. + """ + + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the + sender (e.g. detailed error information, nested errors etc.). + """ + + model_config = ConfigDict(extra="allow") + + +class JSONRPCError(BaseModel): + """A response to a request that indicates an error occurred.""" + + jsonrpc: Literal["2.0"] + id: str | int + error: ErrorData + model_config = ConfigDict(extra="allow") + + +class JSONRPCMessage(RootModel[JSONRPCRequest | JSONRPCNotification | JSONRPCResponse | JSONRPCError]): + pass + + +class EmptyResult(Result): + """A response that indicates success but carries no data.""" + + +class BaseMetadata(BaseModel): + """Base class for entities with name and optional title fields.""" + + name: str + """The programmatic name of the entity.""" + + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class Icon(BaseModel): + """An icon for display in user interfaces.""" + + src: str + """URL or data URI for the icon.""" + + mimeType: str | None = None + """Optional MIME type for the icon.""" + + sizes: list[str] | None = None + """Optional list of strings specifying icon dimensions (e.g., ["48x48", "96x96"]).""" + + model_config = ConfigDict(extra="allow") + + +class Implementation(BaseMetadata): + """Describes the name and version of an MCP implementation.""" + + version: str + + websiteUrl: str | None = None + """An optional URL of the website for this implementation.""" + + icons: list[Icon] | None = None + """An optional list of icons for this implementation.""" + + model_config = ConfigDict(extra="allow") + + +class RootsCapability(BaseModel): + """Capability for root operations.""" + + listChanged: bool | None = None + """Whether the client supports notifications for changes to the roots list.""" + model_config = ConfigDict(extra="allow") + + +class SamplingContextCapability(BaseModel): + """ + Capability for context inclusion during sampling. + + Indicates support for non-'none' values in the includeContext parameter. + SOFT-DEPRECATED: New implementations should use tools parameter instead. + """ + + model_config = ConfigDict(extra="allow") + + +class SamplingToolsCapability(BaseModel): + """ + Capability indicating support for tool calling during sampling. + + When present in ClientCapabilities.sampling, indicates that the client + supports the tools and toolChoice parameters in sampling requests. + """ + + model_config = ConfigDict(extra="allow") + + +class FormElicitationCapability(BaseModel): + """Capability for form mode elicitation.""" + + model_config = ConfigDict(extra="allow") + + +class UrlElicitationCapability(BaseModel): + """Capability for URL mode elicitation.""" + + model_config = ConfigDict(extra="allow") + + +class ElicitationCapability(BaseModel): + """Capability for elicitation operations. + + Clients must support at least one mode (form or url). + """ + + form: FormElicitationCapability | None = None + """Present if the client supports form mode elicitation.""" + + url: UrlElicitationCapability | None = None + """Present if the client supports URL mode elicitation.""" + + model_config = ConfigDict(extra="allow") + + +class SamplingCapability(BaseModel): + """ + Sampling capability structure, allowing fine-grained capability advertisement. + """ + + context: SamplingContextCapability | None = None + """ + Present if the client supports non-'none' values for includeContext parameter. + SOFT-DEPRECATED: New implementations should use tools parameter instead. + """ + tools: SamplingToolsCapability | None = None + """ + Present if the client supports tools and toolChoice parameters in sampling requests. + Presence indicates full tool calling support during sampling. + """ + model_config = ConfigDict(extra="allow") + + +class TasksListCapability(BaseModel): + """Capability for tasks listing operations.""" + + model_config = ConfigDict(extra="allow") + + +class TasksCancelCapability(BaseModel): + """Capability for tasks cancel operations.""" + + model_config = ConfigDict(extra="allow") + + +class TasksCreateMessageCapability(BaseModel): + """Capability for tasks create messages.""" + + model_config = ConfigDict(extra="allow") + + +class TasksSamplingCapability(BaseModel): + """Capability for tasks sampling operations.""" + + model_config = ConfigDict(extra="allow") + + createMessage: TasksCreateMessageCapability | None = None + + +class TasksCreateElicitationCapability(BaseModel): + """Capability for tasks create elicitation operations.""" + + model_config = ConfigDict(extra="allow") + + +class TasksElicitationCapability(BaseModel): + """Capability for tasks elicitation operations.""" + + model_config = ConfigDict(extra="allow") + + create: TasksCreateElicitationCapability | None = None + + +class ClientTasksRequestsCapability(BaseModel): + """Capability for tasks requests operations.""" + + model_config = ConfigDict(extra="allow") + + sampling: TasksSamplingCapability | None = None + + elicitation: TasksElicitationCapability | None = None + + +class ClientTasksCapability(BaseModel): + """Capability for client tasks operations.""" + + model_config = ConfigDict(extra="allow") + + list: TasksListCapability | None = None + """Whether this client supports tasks/list.""" + + cancel: TasksCancelCapability | None = None + """Whether this client supports tasks/cancel.""" + + requests: ClientTasksRequestsCapability | None = None + """Specifies which request types can be augmented with tasks.""" + + +class ClientCapabilities(BaseModel): + """Capabilities a client may support.""" + + experimental: dict[str, dict[str, Any]] | None = None + """Experimental, non-standard capabilities that the client supports.""" + sampling: SamplingCapability | None = None + """ + Present if the client supports sampling from an LLM. + Can contain fine-grained capabilities like context and tools support. + """ + elicitation: ElicitationCapability | None = None + """Present if the client supports elicitation from the user.""" + roots: RootsCapability | None = None + """Present if the client supports listing roots.""" + tasks: ClientTasksCapability | None = None + """Present if the client supports task-augmented requests.""" + + model_config = ConfigDict(extra="allow") + + +class PromptsCapability(BaseModel): + """Capability for prompts operations.""" + + listChanged: bool | None = None + """Whether this server supports notifications for changes to the prompt list.""" + model_config = ConfigDict(extra="allow") + + +class ResourcesCapability(BaseModel): + """Capability for resources operations.""" + + subscribe: bool | None = None + """Whether this server supports subscribing to resource updates.""" + listChanged: bool | None = None + """Whether this server supports notifications for changes to the resource list.""" + model_config = ConfigDict(extra="allow") + + +class ToolsCapability(BaseModel): + """Capability for tools operations.""" + + listChanged: bool | None = None + """Whether this server supports notifications for changes to the tool list.""" + model_config = ConfigDict(extra="allow") + + +class LoggingCapability(BaseModel): + """Capability for logging operations.""" + + model_config = ConfigDict(extra="allow") + + +class CompletionsCapability(BaseModel): + """Capability for completions operations.""" + + model_config = ConfigDict(extra="allow") + + +class TasksCallCapability(BaseModel): + """Capability for tasks call operations.""" + + model_config = ConfigDict(extra="allow") + + +class TasksToolsCapability(BaseModel): + """Capability for tasks tools operations.""" + + model_config = ConfigDict(extra="allow") + call: TasksCallCapability | None = None + + +class ServerTasksRequestsCapability(BaseModel): + """Capability for tasks requests operations.""" + + model_config = ConfigDict(extra="allow") + + tools: TasksToolsCapability | None = None + + +class ServerTasksCapability(BaseModel): + """Capability for server tasks operations.""" + + model_config = ConfigDict(extra="allow") + + list: TasksListCapability | None = None + cancel: TasksCancelCapability | None = None + requests: ServerTasksRequestsCapability | None = None + + +class ServerCapabilities(BaseModel): + """Capabilities that a server may support.""" + + experimental: dict[str, dict[str, Any]] | None = None + """Experimental, non-standard capabilities that the server supports.""" + logging: LoggingCapability | None = None + """Present if the server supports sending log messages to the client.""" + prompts: PromptsCapability | None = None + """Present if the server offers any prompt templates.""" + resources: ResourcesCapability | None = None + """Present if the server offers any resources to read.""" + tools: ToolsCapability | None = None + """Present if the server offers any tools to call.""" + completions: CompletionsCapability | None = None + """Present if the server offers autocompletion suggestions for prompts and resources.""" + tasks: ServerTasksCapability | None = None + """Present if the server supports task-augmented requests.""" + model_config = ConfigDict(extra="allow") + + +TaskStatus = Literal["working", "input_required", "completed", "failed", "cancelled"] + +# Task status constants +TASK_STATUS_WORKING: Final[Literal["working"]] = "working" +TASK_STATUS_INPUT_REQUIRED: Final[Literal["input_required"]] = "input_required" +TASK_STATUS_COMPLETED: Final[Literal["completed"]] = "completed" +TASK_STATUS_FAILED: Final[Literal["failed"]] = "failed" +TASK_STATUS_CANCELLED: Final[Literal["cancelled"]] = "cancelled" + + +class RelatedTaskMetadata(BaseModel): + """ + Metadata for associating messages with a task. + + Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`. + """ + + model_config = ConfigDict(extra="allow") + taskId: str + """The task identifier this message is associated with.""" + + +class Task(BaseModel): + """Data associated with a task.""" + + model_config = ConfigDict(extra="allow") + + taskId: str + """The task identifier.""" + + status: TaskStatus + """Current task state.""" + + statusMessage: str | None = None + """ + Optional human-readable message describing the current task state. + This can provide context for any status, including: + - Reasons for "cancelled" status + - Summaries for "completed" status + - Diagnostic information for "failed" status (e.g., error details, what went wrong) + """ + + createdAt: datetime # Pydantic will enforce ISO 8601 and re-serialize as a string later + """ISO 8601 timestamp when the task was created.""" + + lastUpdatedAt: datetime + """ISO 8601 timestamp when the task was last updated.""" + + ttl: Annotated[int, Field(strict=True)] | None + """Actual retention duration from creation in milliseconds, null for unlimited.""" + + pollInterval: Annotated[int, Field(strict=True)] | None = None + """Suggested polling interval in milliseconds.""" + + +class CreateTaskResult(Result): + """A response to a task-augmented request.""" + + task: Task + + +class GetTaskRequestParams(RequestParams): + model_config = ConfigDict(extra="allow") + taskId: str + """The task identifier to query.""" + + +class GetTaskRequest(Request[GetTaskRequestParams, Literal["tasks/get"]]): + """A request to retrieve the state of a task.""" + + method: Literal["tasks/get"] = "tasks/get" + + params: GetTaskRequestParams + + +class GetTaskResult(Result, Task): + """The response to a tasks/get request.""" + + +class GetTaskPayloadRequestParams(RequestParams): + model_config = ConfigDict(extra="allow") + + taskId: str + """The task identifier to retrieve results for.""" + + +class GetTaskPayloadRequest(Request[GetTaskPayloadRequestParams, Literal["tasks/result"]]): + """A request to retrieve the result of a completed task.""" + + method: Literal["tasks/result"] = "tasks/result" + params: GetTaskPayloadRequestParams + + +class GetTaskPayloadResult(Result): + """ + The response to a tasks/result request. + The structure matches the result type of the original request. + For example, a tools/call task would return the CallToolResult structure. + """ + + +class CancelTaskRequestParams(RequestParams): + model_config = ConfigDict(extra="allow") + + taskId: str + """The task identifier to cancel.""" + + +class CancelTaskRequest(Request[CancelTaskRequestParams, Literal["tasks/cancel"]]): + """A request to cancel a task.""" + + method: Literal["tasks/cancel"] = "tasks/cancel" + params: CancelTaskRequestParams + + +class CancelTaskResult(Result, Task): + """The response to a tasks/cancel request.""" + + +class ListTasksRequest(PaginatedRequest[Literal["tasks/list"]]): + """A request to retrieve a list of tasks.""" + + method: Literal["tasks/list"] = "tasks/list" + + +class ListTasksResult(PaginatedResult): + """The response to a tasks/list request.""" + + tasks: list[Task] + + +class TaskStatusNotificationParams(NotificationParams, Task): + """Parameters for a `notifications/tasks/status` notification.""" + + +class TaskStatusNotification(Notification[TaskStatusNotificationParams, Literal["notifications/tasks/status"]]): + """ + An optional notification from the receiver to the requestor, informing them that a task's status has changed. + Receivers are not required to send these notifications + """ + + method: Literal["notifications/tasks/status"] = "notifications/tasks/status" + params: TaskStatusNotificationParams + + +class InitializeRequestParams(RequestParams): + """Parameters for the initialize request.""" + + protocolVersion: str | int + """The latest version of the Model Context Protocol that the client supports.""" + capabilities: ClientCapabilities + clientInfo: Implementation + model_config = ConfigDict(extra="allow") + + +class InitializeRequest(Request[InitializeRequestParams, Literal["initialize"]]): + """ + This request is sent from the client to the server when it first connects, asking it + to begin initialization. + """ + + method: Literal["initialize"] = "initialize" + params: InitializeRequestParams + + +class InitializeResult(Result): + """After receiving an initialize request from the client, the server sends this.""" + + protocolVersion: str | int + """The version of the Model Context Protocol that the server wants to use.""" + capabilities: ServerCapabilities + serverInfo: Implementation + instructions: str | None = None + """Instructions describing how to use the server and its features.""" + + +class InitializedNotification(Notification[NotificationParams | None, Literal["notifications/initialized"]]): + """ + This notification is sent from the client to the server after initialization has + finished. + """ + + method: Literal["notifications/initialized"] = "notifications/initialized" + params: NotificationParams | None = None + + +class PingRequest(Request[RequestParams | None, Literal["ping"]]): + """ + A ping, issued by either the server or the client, to check that the other party is + still alive. + """ + + method: Literal["ping"] = "ping" + params: RequestParams | None = None + + +class ProgressNotificationParams(NotificationParams): + """Parameters for progress notifications.""" + + progressToken: ProgressToken + """ + The progress token which was given in the initial request, used to associate this + notification with the request that is proceeding. + """ + progress: float + """ + The progress thus far. This should increase every time progress is made, even if the + total is unknown. + """ + total: float | None = None + """Total number of items to process (or total progress required), if known.""" + message: str | None = None + """ + Message related to progress. This should provide relevant human readable + progress information. + """ + model_config = ConfigDict(extra="allow") + + +class ProgressNotification(Notification[ProgressNotificationParams, Literal["notifications/progress"]]): + """ + An out-of-band notification used to inform the receiver of a progress update for a + long-running request. + """ + + method: Literal["notifications/progress"] = "notifications/progress" + params: ProgressNotificationParams + + +class ListResourcesRequest(PaginatedRequest[Literal["resources/list"]]): + """Sent from the client to request a list of resources the server has.""" + + method: Literal["resources/list"] = "resources/list" + + +class Annotations(BaseModel): + audience: list[Role] | None = None + priority: Annotated[float, Field(ge=0.0, le=1.0)] | None = None + model_config = ConfigDict(extra="allow") + + +class Resource(BaseMetadata): + """A known resource that the server is capable of reading.""" + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] + """The URI of this resource.""" + description: str | None = None + """A description of what this resource represents.""" + mimeType: str | None = None + """The MIME type of this resource, if known.""" + size: int | None = None + """ + The size of the raw resource content, in bytes (i.e., before base64 encoding + or any tokenization), if known. + + This can be used by Hosts to display file sizes and estimate context window usage. + """ + icons: list[Icon] | None = None + """An optional list of icons for this resource.""" + annotations: Annotations | None = None + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ResourceTemplate(BaseMetadata): + """A template description for resources available on the server.""" + + uriTemplate: str + """ + A URI template (according to RFC 6570) that can be used to construct resource + URIs. + """ + description: str | None = None + """A human-readable description of what this template is for.""" + mimeType: str | None = None + """ + The MIME type for all resources that match this template. This should only be + included if all resources matching this template have the same type. + """ + icons: list[Icon] | None = None + """An optional list of icons for this resource template.""" + annotations: Annotations | None = None + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ListResourcesResult(PaginatedResult): + """The server's response to a resources/list request from the client.""" + + resources: list[Resource] + + +class ListResourceTemplatesRequest(PaginatedRequest[Literal["resources/templates/list"]]): + """Sent from the client to request a list of resource templates the server has.""" + + method: Literal["resources/templates/list"] = "resources/templates/list" + + +class ListResourceTemplatesResult(PaginatedResult): + """The server's response to a resources/templates/list request from the client.""" + + resourceTemplates: list[ResourceTemplate] + + +class ReadResourceRequestParams(RequestParams): + """Parameters for reading a resource.""" + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] + """ + The URI of the resource to read. The URI can use any protocol; it is up to the + server how to interpret it. + """ + model_config = ConfigDict(extra="allow") + + +class ReadResourceRequest(Request[ReadResourceRequestParams, Literal["resources/read"]]): + """Sent from the client to the server, to read a specific resource URI.""" + + method: Literal["resources/read"] = "resources/read" + params: ReadResourceRequestParams + + +class ResourceContents(BaseModel): + """The contents of a specific resource or sub-resource.""" + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] + """The URI of this resource.""" + mimeType: str | None = None + """The MIME type of this resource, if known.""" + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class TextResourceContents(ResourceContents): + """Text contents of a resource.""" + + text: str + """ + The text of the item. This must only be set if the item can actually be represented + as text (not binary data). + """ + + +class BlobResourceContents(ResourceContents): + """Binary contents of a resource.""" + + blob: str + """A base64-encoded string representing the binary data of the item.""" + + +class ReadResourceResult(Result): + """The server's response to a resources/read request from the client.""" + + contents: list[TextResourceContents | BlobResourceContents] + + +class ResourceListChangedNotification( + Notification[NotificationParams | None, Literal["notifications/resources/list_changed"]] +): + """ + An optional notification from the server to the client, informing it that the list + of resources it can read from has changed. + """ + + method: Literal["notifications/resources/list_changed"] = "notifications/resources/list_changed" + params: NotificationParams | None = None + + +class SubscribeRequestParams(RequestParams): + """Parameters for subscribing to a resource.""" + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] + """ + The URI of the resource to subscribe to. The URI can use any protocol; it is up to + the server how to interpret it. + """ + model_config = ConfigDict(extra="allow") + + +class SubscribeRequest(Request[SubscribeRequestParams, Literal["resources/subscribe"]]): + """ + Sent from the client to request resources/updated notifications from the server + whenever a particular resource changes. + """ + + method: Literal["resources/subscribe"] = "resources/subscribe" + params: SubscribeRequestParams + + +class UnsubscribeRequestParams(RequestParams): + """Parameters for unsubscribing from a resource.""" + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] + """The URI of the resource to unsubscribe from.""" + model_config = ConfigDict(extra="allow") + + +class UnsubscribeRequest(Request[UnsubscribeRequestParams, Literal["resources/unsubscribe"]]): + """ + Sent from the client to request cancellation of resources/updated notifications from + the server. + """ + + method: Literal["resources/unsubscribe"] = "resources/unsubscribe" + params: UnsubscribeRequestParams + + +class ResourceUpdatedNotificationParams(NotificationParams): + """Parameters for resource update notifications.""" + + uri: Annotated[AnyUrl, UrlConstraints(host_required=False)] + """ + The URI of the resource that has been updated. This might be a sub-resource of the + one that the client actually subscribed to. + """ + model_config = ConfigDict(extra="allow") + + +class ResourceUpdatedNotification( + Notification[ResourceUpdatedNotificationParams, Literal["notifications/resources/updated"]] +): + """ + A notification from the server to the client, informing it that a resource has + changed and may need to be read again. + """ + + method: Literal["notifications/resources/updated"] = "notifications/resources/updated" + params: ResourceUpdatedNotificationParams + + +class ListPromptsRequest(PaginatedRequest[Literal["prompts/list"]]): + """Sent from the client to request a list of prompts and prompt templates.""" + + method: Literal["prompts/list"] = "prompts/list" + + +class PromptArgument(BaseModel): + """An argument for a prompt template.""" + + name: str + """The name of the argument.""" + description: str | None = None + """A human-readable description of the argument.""" + required: bool | None = None + """Whether this argument must be provided.""" + model_config = ConfigDict(extra="allow") + + +class Prompt(BaseMetadata): + """A prompt or prompt template that the server offers.""" + + description: str | None = None + """An optional description of what this prompt provides.""" + arguments: list[PromptArgument] | None = None + """A list of arguments to use for templating the prompt.""" + icons: list[Icon] | None = None + """An optional list of icons for this prompt.""" + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ListPromptsResult(PaginatedResult): + """The server's response to a prompts/list request from the client.""" + + prompts: list[Prompt] + + +class GetPromptRequestParams(RequestParams): + """Parameters for getting a prompt.""" + + name: str + """The name of the prompt or prompt template.""" + arguments: dict[str, str] | None = None + """Arguments to use for templating the prompt.""" + model_config = ConfigDict(extra="allow") + + +class GetPromptRequest(Request[GetPromptRequestParams, Literal["prompts/get"]]): + """Used by the client to get a prompt provided by the server.""" + + method: Literal["prompts/get"] = "prompts/get" + params: GetPromptRequestParams + + +class TextContent(BaseModel): + """Text content for a message.""" + + type: Literal["text"] + text: str + """The text content of the message.""" + annotations: Annotations | None = None + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ImageContent(BaseModel): + """Image content for a message.""" + + type: Literal["image"] + data: str + """The base64-encoded image data.""" + mimeType: str + """ + The MIME type of the image. Different providers may support different + image types. + """ + annotations: Annotations | None = None + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class AudioContent(BaseModel): + """Audio content for a message.""" + + type: Literal["audio"] + data: str + """The base64-encoded audio data.""" + mimeType: str + """ + The MIME type of the audio. Different providers may support different + audio types. + """ + annotations: Annotations | None = None + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ToolUseContent(BaseModel): + """ + Content representing an assistant's request to invoke a tool. + + This content type appears in assistant messages when the LLM wants to call a tool + during sampling. The server should execute the tool and return a ToolResultContent + in the next user message. + """ + + type: Literal["tool_use"] + """Discriminator for tool use content.""" + + name: str + """The name of the tool to invoke. Must match a tool name from the request's tools array.""" + + id: str + """Unique identifier for this tool call, used to correlate with ToolResultContent.""" + + input: dict[str, Any] + """Arguments to pass to the tool. Must conform to the tool's inputSchema.""" + + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ToolResultContent(BaseModel): + """ + Content representing the result of a tool execution. + + This content type appears in user messages as a response to a ToolUseContent + from the assistant. It contains the output of executing the requested tool. + """ + + type: Literal["tool_result"] + """Discriminator for tool result content.""" + + toolUseId: str + """The unique identifier that corresponds to the tool call's id field.""" + + content: list["ContentBlock"] = [] + """ + A list of content objects representing the tool result. + Defaults to empty list if not provided. + """ + + structuredContent: dict[str, Any] | None = None + """ + Optional structured tool output that matches the tool's outputSchema (if defined). + """ + + isError: bool | None = None + """Whether the tool execution resulted in an error.""" + + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +SamplingMessageContentBlock: TypeAlias = TextContent | ImageContent | AudioContent | ToolUseContent | ToolResultContent +"""Content block types allowed in sampling messages.""" + +SamplingContent: TypeAlias = TextContent | ImageContent | AudioContent +"""Basic content types for sampling responses (without tool use). +Used for backwards-compatible CreateMessageResult when tools are not used.""" + + +class SamplingMessage(BaseModel): + """Describes a message issued to or received from an LLM API.""" + + role: Role + content: SamplingMessageContentBlock | list[SamplingMessageContentBlock] + """ + Message content. Can be a single content block or an array of content blocks + for multi-modal messages and tool interactions. + """ + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + @property + def content_as_list(self) -> list[SamplingMessageContentBlock]: + """Returns the content as a list of content blocks, regardless of whether + it was originally a single block or a list.""" + return self.content if isinstance(self.content, list) else [self.content] + + +class EmbeddedResource(BaseModel): + """ + The contents of a resource, embedded into a prompt or tool call result. + + It is up to the client how best to render embedded resources for the benefit + of the LLM and/or the user. + """ + + type: Literal["resource"] + resource: TextResourceContents | BlobResourceContents + annotations: Annotations | None = None + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ResourceLink(Resource): + """ + A resource that the server is capable of reading, included in a prompt or tool call result. + + Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests. + """ + + type: Literal["resource_link"] + + +ContentBlock = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource +"""A content block that can be used in prompts and tool results.""" + +Content: TypeAlias = ContentBlock +# """DEPRECATED: Content is deprecated, you should use ContentBlock directly.""" + + +class PromptMessage(BaseModel): + """Describes a message returned as part of a prompt.""" + + role: Role + content: ContentBlock + model_config = ConfigDict(extra="allow") + + +class GetPromptResult(Result): + """The server's response to a prompts/get request from the client.""" + + description: str | None = None + """An optional description for the prompt.""" + messages: list[PromptMessage] + + +class PromptListChangedNotification( + Notification[NotificationParams | None, Literal["notifications/prompts/list_changed"]] +): + """ + An optional notification from the server to the client, informing it that the list + of prompts it offers has changed. + """ + + method: Literal["notifications/prompts/list_changed"] = "notifications/prompts/list_changed" + params: NotificationParams | None = None + + +class ListToolsRequest(PaginatedRequest[Literal["tools/list"]]): + """Sent from the client to request a list of tools the server has.""" + + method: Literal["tools/list"] = "tools/list" + + +class ToolAnnotations(BaseModel): + """ + Additional properties describing a Tool to clients. + + NOTE: all properties in ToolAnnotations are **hints**. + They are not guaranteed to provide a faithful description of + tool behavior (including descriptive properties like `title`). + + Clients should never make tool use decisions based on ToolAnnotations + received from untrusted servers. + """ + + title: str | None = None + """A human-readable title for the tool.""" + + readOnlyHint: bool | None = None + """ + If true, the tool does not modify its environment. + Default: false + """ + + destructiveHint: bool | None = None + """ + If true, the tool may perform destructive updates to its environment. + If false, the tool performs only additive updates. + (This property is meaningful only when `readOnlyHint == false`) + Default: true + """ + + idempotentHint: bool | None = None + """ + If true, calling the tool repeatedly with the same arguments + will have no additional effect on the its environment. + (This property is meaningful only when `readOnlyHint == false`) + Default: false + """ + + openWorldHint: bool | None = None + """ + If true, this tool may interact with an "open world" of external + entities. If false, the tool's domain of interaction is closed. + For example, the world of a web search tool is open, whereas that + of a memory tool is not. + Default: true + """ + + model_config = ConfigDict(extra="allow") + + +class ToolExecution(BaseModel): + """Execution-related properties for a tool.""" + + model_config = ConfigDict(extra="allow") + + taskSupport: TaskExecutionMode | None = None + """ + Indicates whether this tool supports task-augmented execution. + This allows clients to handle long-running operations through polling + the task system. + + - "forbidden": Tool does not support task-augmented execution (default when absent) + - "optional": Tool may support task-augmented execution + - "required": Tool requires task-augmented execution + + Default: "forbidden" + """ + + +class Tool(BaseMetadata): + """Definition for a tool the client can call.""" + + description: str | None = None + """A human-readable description of the tool.""" + inputSchema: dict[str, Any] + """A JSON Schema object defining the expected parameters for the tool.""" + outputSchema: dict[str, Any] | None = None + """ + An optional JSON Schema object defining the structure of the tool's output + returned in the structuredContent field of a CallToolResult. + """ + icons: list[Icon] | None = None + """An optional list of icons for this tool.""" + annotations: ToolAnnotations | None = None + """Optional additional tool information.""" + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + + execution: ToolExecution | None = None + + model_config = ConfigDict(extra="allow") + + +class ListToolsResult(PaginatedResult): + """The server's response to a tools/list request from the client.""" + + tools: list[Tool] + + +class CallToolRequestParams(RequestParams): + """Parameters for calling a tool.""" + + name: str + arguments: dict[str, Any] | None = None + model_config = ConfigDict(extra="allow") + + +class CallToolRequest(Request[CallToolRequestParams, Literal["tools/call"]]): + """Used by the client to invoke a tool provided by the server.""" + + method: Literal["tools/call"] = "tools/call" + params: CallToolRequestParams + + +class CallToolResult(Result): + """The server's response to a tool call.""" + + content: list[ContentBlock] + structuredContent: dict[str, Any] | None = None + """An optional JSON object that represents the structured result of the tool call.""" + isError: bool = False + + +class ToolListChangedNotification(Notification[NotificationParams | None, Literal["notifications/tools/list_changed"]]): + """ + An optional notification from the server to the client, informing it that the list + of tools it offers has changed. + """ + + method: Literal["notifications/tools/list_changed"] = "notifications/tools/list_changed" + params: NotificationParams | None = None + + +LoggingLevel = Literal["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"] + + +class SetLevelRequestParams(RequestParams): + """Parameters for setting the logging level.""" + + level: LoggingLevel + """The level of logging that the client wants to receive from the server.""" + model_config = ConfigDict(extra="allow") + + +class SetLevelRequest(Request[SetLevelRequestParams, Literal["logging/setLevel"]]): + """A request from the client to the server, to enable or adjust logging.""" + + method: Literal["logging/setLevel"] = "logging/setLevel" + params: SetLevelRequestParams + + +class LoggingMessageNotificationParams(NotificationParams): + """Parameters for logging message notifications.""" + + level: LoggingLevel + """The severity of this log message.""" + logger: str | None = None + """An optional name of the logger issuing this message.""" + data: Any + """ + The data to be logged, such as a string message or an object. Any JSON serializable + type is allowed here. + """ + model_config = ConfigDict(extra="allow") + + +class LoggingMessageNotification(Notification[LoggingMessageNotificationParams, Literal["notifications/message"]]): + """Notification of a log message passed from server to client.""" + + method: Literal["notifications/message"] = "notifications/message" + params: LoggingMessageNotificationParams + + +IncludeContext = Literal["none", "thisServer", "allServers"] + + +class ModelHint(BaseModel): + """Hints to use for model selection.""" + + name: str | None = None + """A hint for a model name.""" + + model_config = ConfigDict(extra="allow") + + +class ModelPreferences(BaseModel): + """ + The server's preferences for model selection, requested by the client during + sampling. + + Because LLMs can vary along multiple dimensions, choosing the "best" model is + rarely straightforward. Different models excel in different areas—some are + faster but less capable, others are more capable but more expensive, and so + on. This interface allows servers to express their priorities across multiple + dimensions to help clients make an appropriate selection for their use case. + + These preferences are always advisory. The client MAY ignore them. It is also + up to the client to decide how to interpret these preferences and how to + balance them against other considerations. + """ + + hints: list[ModelHint] | None = None + """ + Optional hints to use for model selection. + + If multiple hints are specified, the client MUST evaluate them in order + (such that the first match is taken). + + The client SHOULD prioritize these hints over the numeric priorities, but + MAY still use the priorities to select from ambiguous matches. + """ + + costPriority: float | None = None + """ + How much to prioritize cost when selecting a model. A value of 0 means cost + is not important, while a value of 1 means cost is the most important + factor. + """ + + speedPriority: float | None = None + """ + How much to prioritize sampling speed (latency) when selecting a model. A + value of 0 means speed is not important, while a value of 1 means speed is + the most important factor. + """ + + intelligencePriority: float | None = None + """ + How much to prioritize intelligence and capabilities when selecting a + model. A value of 0 means intelligence is not important, while a value of 1 + means intelligence is the most important factor. + """ + + model_config = ConfigDict(extra="allow") + + +class ToolChoice(BaseModel): + """ + Controls tool usage behavior during sampling. + + Allows the server to specify whether and how the LLM should use tools + in its response. + """ + + mode: Literal["auto", "required", "none"] | None = None + """ + Controls when tools are used: + - "auto": Model decides whether to use tools (default) + - "required": Model MUST use at least one tool before completing + - "none": Model should not use tools + """ + + model_config = ConfigDict(extra="allow") + + +class CreateMessageRequestParams(RequestParams): + """Parameters for creating a message.""" + + messages: list[SamplingMessage] + modelPreferences: ModelPreferences | None = None + """ + The server's preferences for which model to select. The client MAY ignore + these preferences. + """ + systemPrompt: str | None = None + """An optional system prompt the server wants to use for sampling.""" + includeContext: IncludeContext | None = None + """ + A request to include context from one or more MCP servers (including the caller), to + be attached to the prompt. + """ + temperature: float | None = None + maxTokens: int + """The maximum number of tokens to sample, as requested by the server.""" + stopSequences: list[str] | None = None + metadata: dict[str, Any] | None = None + """Optional metadata to pass through to the LLM provider.""" + tools: list["Tool"] | None = None + """ + Tool definitions for the LLM to use during sampling. + Requires clientCapabilities.sampling.tools to be present. + """ + toolChoice: ToolChoice | None = None + """ + Controls tool usage behavior. + Requires clientCapabilities.sampling.tools and the tools parameter to be present. + """ + model_config = ConfigDict(extra="allow") + + +class CreateMessageRequest(Request[CreateMessageRequestParams, Literal["sampling/createMessage"]]): + """A request from the server to sample an LLM via the client.""" + + method: Literal["sampling/createMessage"] = "sampling/createMessage" + params: CreateMessageRequestParams + + +StopReason = Literal["endTurn", "stopSequence", "maxTokens", "toolUse"] | str + + +class CreateMessageResult(Result): + """The client's response to a sampling/create_message request from the server. + + This is the backwards-compatible version that returns single content (no arrays). + Used when the request does not include tools. + """ + + role: Role + """The role of the message sender (typically 'assistant' for LLM responses).""" + content: SamplingContent + """Response content. Single content block (text, image, or audio).""" + model: str + """The name of the model that generated the message.""" + stopReason: StopReason | None = None + """The reason why sampling stopped, if known.""" + + +class CreateMessageResultWithTools(Result): + """The client's response to a sampling/create_message request when tools were provided. + + This version supports array content for tool use flows. + """ + + role: Role + """The role of the message sender (typically 'assistant' for LLM responses).""" + content: SamplingMessageContentBlock | list[SamplingMessageContentBlock] + """ + Response content. May be a single content block or an array. + May include ToolUseContent if stopReason is 'toolUse'. + """ + model: str + """The name of the model that generated the message.""" + stopReason: StopReason | None = None + """ + The reason why sampling stopped, if known. + 'toolUse' indicates the model wants to use a tool. + """ + + @property + def content_as_list(self) -> list[SamplingMessageContentBlock]: + """Returns the content as a list of content blocks, regardless of whether + it was originally a single block or a list.""" + return self.content if isinstance(self.content, list) else [self.content] + + +class ResourceTemplateReference(BaseModel): + """A reference to a resource or resource template definition.""" + + type: Literal["ref/resource"] + uri: str + """The URI or URI template of the resource.""" + model_config = ConfigDict(extra="allow") + + +@deprecated("`ResourceReference` is deprecated, you should use `ResourceTemplateReference`.") +class ResourceReference(ResourceTemplateReference): + pass + + +class PromptReference(BaseModel): + """Identifies a prompt.""" + + type: Literal["ref/prompt"] + name: str + """The name of the prompt or prompt template""" + model_config = ConfigDict(extra="allow") + + +class CompletionArgument(BaseModel): + """The argument's information for completion requests.""" + + name: str + """The name of the argument""" + value: str + """The value of the argument to use for completion matching.""" + model_config = ConfigDict(extra="allow") + + +class CompletionContext(BaseModel): + """Additional, optional context for completions.""" + + arguments: dict[str, str] | None = None + """Previously-resolved variables in a URI template or prompt.""" + model_config = ConfigDict(extra="allow") + + +class CompleteRequestParams(RequestParams): + """Parameters for completion requests.""" + + ref: ResourceTemplateReference | PromptReference + argument: CompletionArgument + context: CompletionContext | None = None + """Additional, optional context for completions""" + model_config = ConfigDict(extra="allow") + + +class CompleteRequest(Request[CompleteRequestParams, Literal["completion/complete"]]): + """A request from the client to the server, to ask for completion options.""" + + method: Literal["completion/complete"] = "completion/complete" + params: CompleteRequestParams + + +class Completion(BaseModel): + """Completion information.""" + + values: list[str] + """An array of completion values. Must not exceed 100 items.""" + total: int | None = None + """ + The total number of completion options available. This can exceed the number of + values actually sent in the response. + """ + hasMore: bool | None = None + """ + Indicates whether there are additional completion options beyond those provided in + the current response, even if the exact total is unknown. + """ + model_config = ConfigDict(extra="allow") + + +class CompleteResult(Result): + """The server's response to a completion/complete request""" + + completion: Completion + + +class ListRootsRequest(Request[RequestParams | None, Literal["roots/list"]]): + """ + Sent from the server to request a list of root URIs from the client. Roots allow + servers to ask for specific directories or files to operate on. A common example + for roots is providing a set of repositories or directories a server should operate + on. + + This request is typically used when the server needs to understand the file system + structure or access specific locations that the client has permission to read from. + """ + + method: Literal["roots/list"] = "roots/list" + params: RequestParams | None = None + + +class Root(BaseModel): + """Represents a root directory or file that the server can operate on.""" + + uri: FileUrl + """ + The URI identifying the root. This *must* start with file:// for now. + This restriction may be relaxed in future versions of the protocol to allow + other URI schemes. + """ + name: str | None = None + """ + An optional name for the root. This can be used to provide a human-readable + identifier for the root, which may be useful for display purposes or for + referencing the root in other parts of the application. + """ + meta: dict[str, Any] | None = Field(alias="_meta", default=None) + """ + See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) + for notes on _meta usage. + """ + model_config = ConfigDict(extra="allow") + + +class ListRootsResult(Result): + """ + The client's response to a roots/list request from the server. + This result contains an array of Root objects, each representing a root directory + or file that the server can operate on. + """ + + roots: list[Root] + + +class RootsListChangedNotification( + Notification[NotificationParams | None, Literal["notifications/roots/list_changed"]] +): + """ + A notification from the client to the server, informing it that the list of + roots has changed. + + This notification should be sent whenever the client adds, removes, or + modifies any root. The server should then request an updated list of roots + using the ListRootsRequest. + """ + + method: Literal["notifications/roots/list_changed"] = "notifications/roots/list_changed" + params: NotificationParams | None = None + + +class CancelledNotificationParams(NotificationParams): + """Parameters for cancellation notifications.""" + + requestId: RequestId | None = None + """ + The ID of the request to cancel. + + This MUST correspond to the ID of a request previously issued in the same direction. + This MUST be provided for cancelling non-task requests. + This MUST NOT be used for cancelling tasks (use the `tasks/cancel` request instead). + """ + reason: str | None = None + """An optional string describing the reason for the cancellation.""" + + model_config = ConfigDict(extra="allow") + + +class CancelledNotification(Notification[CancelledNotificationParams, Literal["notifications/cancelled"]]): + """ + This notification can be sent by either side to indicate that it is canceling a + previously-issued request. + """ + + method: Literal["notifications/cancelled"] = "notifications/cancelled" + params: CancelledNotificationParams + + +class ElicitCompleteNotificationParams(NotificationParams): + """Parameters for elicitation completion notifications.""" + + elicitationId: str + """The unique identifier of the elicitation that was completed.""" + + model_config = ConfigDict(extra="allow") + + +class ElicitCompleteNotification( + Notification[ElicitCompleteNotificationParams, Literal["notifications/elicitation/complete"]] +): + """ + A notification from the server to the client, informing it that a URL mode + elicitation has been completed. + + Clients MAY use the notification to automatically retry requests that received a + URLElicitationRequiredError, update the user interface, or otherwise continue + an interaction. However, because delivery of the notification is not guaranteed, + clients must not wait indefinitely for a notification from the server. + """ + + method: Literal["notifications/elicitation/complete"] = "notifications/elicitation/complete" + params: ElicitCompleteNotificationParams + + +ClientRequestType: TypeAlias = ( + PingRequest + | InitializeRequest + | CompleteRequest + | SetLevelRequest + | GetPromptRequest + | ListPromptsRequest + | ListResourcesRequest + | ListResourceTemplatesRequest + | ReadResourceRequest + | SubscribeRequest + | UnsubscribeRequest + | CallToolRequest + | ListToolsRequest + | GetTaskRequest + | GetTaskPayloadRequest + | ListTasksRequest + | CancelTaskRequest +) + + +class ClientRequest(RootModel[ClientRequestType]): + pass + + +ClientNotificationType: TypeAlias = ( + CancelledNotification + | ProgressNotification + | InitializedNotification + | RootsListChangedNotification + | TaskStatusNotification +) + + +class ClientNotification(RootModel[ClientNotificationType]): + pass + + +# Type for elicitation schema - a JSON Schema dict +ElicitRequestedSchema: TypeAlias = dict[str, Any] +"""Schema for elicitation requests.""" + + +class ElicitRequestFormParams(RequestParams): + """Parameters for form mode elicitation requests. + + Form mode collects non-sensitive information from the user via an in-band form + rendered by the client. + """ + + mode: Literal["form"] = "form" + """The elicitation mode (always "form" for this type).""" + + message: str + """The message to present to the user describing what information is being requested.""" + + requestedSchema: ElicitRequestedSchema + """ + A restricted subset of JSON Schema defining the structure of expected response. + Only top-level properties are allowed, without nesting. + """ + + model_config = ConfigDict(extra="allow") + + +class ElicitRequestURLParams(RequestParams): + """Parameters for URL mode elicitation requests. + + URL mode directs users to external URLs for sensitive out-of-band interactions + like OAuth flows, credential collection, or payment processing. + """ + + mode: Literal["url"] = "url" + """The elicitation mode (always "url" for this type).""" + + message: str + """The message to present to the user explaining why the interaction is needed.""" + + url: str + """The URL that the user should navigate to.""" + + elicitationId: str + """ + The ID of the elicitation, which must be unique within the context of the server. + The client MUST treat this ID as an opaque value. + """ + + model_config = ConfigDict(extra="allow") + + +# Union type for elicitation request parameters +ElicitRequestParams: TypeAlias = ElicitRequestURLParams | ElicitRequestFormParams +"""Parameters for elicitation requests - either form or URL mode.""" + + +class ElicitRequest(Request[ElicitRequestParams, Literal["elicitation/create"]]): + """A request from the server to elicit information from the client.""" + + method: Literal["elicitation/create"] = "elicitation/create" + params: ElicitRequestParams + + +class ElicitResult(Result): + """The client's response to an elicitation request.""" + + action: Literal["accept", "decline", "cancel"] + """ + The user action in response to the elicitation. + - "accept": User submitted the form/confirmed the action (or consented to URL navigation) + - "decline": User explicitly declined the action + - "cancel": User dismissed without making an explicit choice + """ + + content: dict[str, str | int | float | bool | list[str] | None] | None = None + """ + The submitted form data, only present when action is "accept" in form mode. + Contains values matching the requested schema. Values can be strings, integers, + booleans, or arrays of strings. + For URL mode, this field is omitted. + """ + + +class ElicitationRequiredErrorData(BaseModel): + """Error data for URLElicitationRequiredError. + + Servers return this when a request cannot be processed until one or more + URL mode elicitations are completed. + """ + + elicitations: list[ElicitRequestURLParams] + """List of URL mode elicitations that must be completed.""" + + model_config = ConfigDict(extra="allow") + + +ClientResultType: TypeAlias = ( + EmptyResult + | CreateMessageResult + | CreateMessageResultWithTools + | ListRootsResult + | ElicitResult + | GetTaskResult + | GetTaskPayloadResult + | ListTasksResult + | CancelTaskResult + | CreateTaskResult +) + + +class ClientResult(RootModel[ClientResultType]): + pass + + +ServerRequestType: TypeAlias = ( + PingRequest + | CreateMessageRequest + | ListRootsRequest + | ElicitRequest + | GetTaskRequest + | GetTaskPayloadRequest + | ListTasksRequest + | CancelTaskRequest +) + + +class ServerRequest(RootModel[ServerRequestType]): + pass + + +ServerNotificationType: TypeAlias = ( + CancelledNotification + | ProgressNotification + | LoggingMessageNotification + | ResourceUpdatedNotification + | ResourceListChangedNotification + | ToolListChangedNotification + | PromptListChangedNotification + | ElicitCompleteNotification + | TaskStatusNotification +) + + +class ServerNotification(RootModel[ServerNotificationType]): + pass + + +ServerResultType: TypeAlias = ( + EmptyResult + | InitializeResult + | CompleteResult + | GetPromptResult + | ListPromptsResult + | ListResourcesResult + | ListResourceTemplatesResult + | ReadResourceResult + | CallToolResult + | ListToolsResult + | GetTaskResult + | GetTaskPayloadResult + | ListTasksResult + | CancelTaskResult + | CreateTaskResult +) + + +class ServerResult(RootModel[ServerResultType]): + pass diff --git a/source/target-vendors/cp312/multipart/__init__.py b/source/target-vendors/cp312/multipart/__init__.py new file mode 100644 index 0000000..53c08d2 --- /dev/null +++ b/source/target-vendors/cp312/multipart/__init__.py @@ -0,0 +1,38 @@ +# Copyright 2012, Andrew Dunham +# +# 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. + +# This only works if using a file system, other loaders not implemented. + +import importlib.util +import sys +import warnings +from pathlib import Path + +for p in sys.path: + file_path = Path(p, "multipart.py") + try: + if file_path.is_file(): + spec = importlib.util.spec_from_file_location("multipart", file_path) + assert spec is not None, f"{file_path} found but not loadable!" + module = importlib.util.module_from_spec(spec) + sys.modules["multipart"] = module + assert spec.loader is not None, f"{file_path} must be loadable!" + spec.loader.exec_module(module) + break + except PermissionError: + pass +else: + warnings.warn("Please use `import python_multipart` instead.", PendingDeprecationWarning, stacklevel=2) + from python_multipart import * + from python_multipart import __all__, __version__ diff --git a/source/target-vendors/cp312/multipart/decoders.py b/source/target-vendors/cp312/multipart/decoders.py new file mode 100644 index 0000000..31acdfb --- /dev/null +++ b/source/target-vendors/cp312/multipart/decoders.py @@ -0,0 +1 @@ +from python_multipart.decoders import * diff --git a/source/target-vendors/cp312/multipart/exceptions.py b/source/target-vendors/cp312/multipart/exceptions.py new file mode 100644 index 0000000..36815d1 --- /dev/null +++ b/source/target-vendors/cp312/multipart/exceptions.py @@ -0,0 +1 @@ +from python_multipart.exceptions import * diff --git a/source/target-vendors/cp312/multipart/multipart.py b/source/target-vendors/cp312/multipart/multipart.py new file mode 100644 index 0000000..7bf567d --- /dev/null +++ b/source/target-vendors/cp312/multipart/multipart.py @@ -0,0 +1 @@ +from python_multipart.multipart import * diff --git a/source/target-vendors/cp312/pycparser-3.0.dist-info/METADATA b/source/target-vendors/cp312/pycparser-3.0.dist-info/METADATA new file mode 100644 index 0000000..b94a88b --- /dev/null +++ b/source/target-vendors/cp312/pycparser-3.0.dist-info/METADATA @@ -0,0 +1,244 @@ +Metadata-Version: 2.4 +Name: pycparser +Version: 3.0 +Summary: C parser in Python +Author-email: Eli Bendersky +Maintainer-email: Eli Bendersky +License-Expression: BSD-3-Clause +Project-URL: Homepage, https://github.com/eliben/pycparser +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Requires-Python: >=3.10 +Description-Content-Type: text/x-rst +License-File: LICENSE +Dynamic: license-file + +=============== +pycparser v3.00 +=============== + + +.. image:: https://github.com/eliben/pycparser/workflows/pycparser-tests/badge.svg + :align: center + :target: https://github.com/eliben/pycparser/actions + +---- + +.. contents:: + :backlinks: none + +.. sectnum:: + +Introduction +============ + +What is pycparser? +------------------ + +**pycparser** is a parser for the C language, written in pure Python. It is a +module designed to be easily integrated into applications that need to parse +C source code. + +What is it good for? +-------------------- + +Anything that needs C code to be parsed. The following are some uses for +**pycparser**, taken from real user reports: + +* C code obfuscator +* Front-end for various specialized C compilers +* Static code checker +* Automatic unit-test discovery +* Adding specialized extensions to the C language + +One of the most popular uses of **pycparser** is in the `cffi +`_ library, which uses it to parse the +declarations of C functions and types in order to auto-generate FFIs. + +**pycparser** is unique in the sense that it's written in pure Python - a very +high level language that's easy to experiment with and tweak. To people familiar +with Lex and Yacc, **pycparser**'s code will be simple to understand. It also +has no external dependencies (except for a Python interpreter), making it very +simple to install and deploy. + +Which version of C does pycparser support? +------------------------------------------ + +**pycparser** aims to support the full C99 language (according to the standard +ISO/IEC 9899). Some features from C11 are also supported, and patches to support +more are welcome. + +**pycparser** supports very few GCC extensions, but it's fairly easy to set +things up so that it parses code with a lot of GCC-isms successfully. See the +`FAQ `_ for more details. + +What grammar does pycparser follow? +----------------------------------- + +**pycparser** very closely follows the C grammar provided in Annex A of the C99 +standard (ISO/IEC 9899). + +How is pycparser licensed? +-------------------------- + +`BSD license `_. + +Contact details +--------------- + +For reporting problems with **pycparser** or submitting feature requests, please +open an `issue `_, or submit a +pull request. + + +Installing +========== + +Prerequisites +------------- + +**pycparser** is being tested with modern versions of Python on +Linux, macOS and Windows. See `the CI dashboard `__ +for details. + +**pycparser** has no external dependencies. + +Installation process +-------------------- + +The recommended way to install **pycparser** is with ``pip``:: + + > pip install pycparser + +Using +===== + +Interaction with the C preprocessor +----------------------------------- + +In order to be compilable, C code must be preprocessed by the C preprocessor - +``cpp``. A compatible ``cpp`` handles preprocessing directives like ``#include`` and +``#define``, removes comments, and performs other minor tasks that prepare the C +code for compilation. + +For all but the most trivial snippets of C code **pycparser**, like a C +compiler, must receive preprocessed C code in order to function correctly. If +you import the top-level ``parse_file`` function from the **pycparser** package, +it will interact with ``cpp`` for you, as long as it's in your PATH, or you +provide a path to it. + +Note also that you can use ``gcc -E`` or ``clang -E`` instead of ``cpp``. See +the ``using_gcc_E_libc.py`` example for more details. Windows users can download +and install a binary build of Clang for Windows `from this website +`_. + +What about the standard C library headers? +------------------------------------------ + +C code almost always ``#include``\s various header files from the standard C +library, like ``stdio.h``. While (with some effort) **pycparser** can be made to +parse the standard headers from any C compiler, it's much simpler to use the +provided "fake" standard includes for C11 in ``utils/fake_libc_include``. These +are standard C header files that contain only the bare necessities to allow +valid parsing of the files that use them. As a bonus, since they're minimal, it +can significantly improve the performance of parsing large C files. + +The key point to understand here is that **pycparser** doesn't really care about +the semantics of types. It only needs to know whether some token encountered in +the source is a previously defined type. This is essential in order to be able +to parse C correctly. + +See `this blog post +`_ +for more details. + +Note that the fake headers are not included in the ``pip`` package nor installed +via the package build (`#224 `_). + +Basic usage +----------- + +Take a look at the |examples|_ directory of the distribution for a few examples +of using **pycparser**. These should be enough to get you started. Please note +that most realistic C code samples would require running the C preprocessor +before passing the code to **pycparser**; see the previous sections for more +details. + +.. |examples| replace:: ``examples`` +.. _examples: examples + + +Advanced usage +-------------- + +The public interface of **pycparser** is well documented with comments in +``pycparser/c_parser.py``. For a detailed overview of the various AST nodes +created by the parser, see ``pycparser/_c_ast.cfg``. + +There's also a `FAQ available here `_. +In any case, you can always drop me an `email `_ for help. + + +Modifying +========= + +There are a few points to keep in mind when modifying **pycparser**: + +* The code for **pycparser**'s AST nodes is automatically generated from a + configuration file - ``_c_ast.cfg``, by ``_ast_gen.py``. If you modify the AST + configuration, make sure to re-generate the code. This can be done by running + the ``_ast_gen.py`` script (from the repository root or the + ``pycparser`` directory). +* Read the docstring in the constructor of the ``CParser`` class for details + on configuration and compatibility arguments. + + +Package contents +================ + +Once you unzip the ``pycparser`` package, you'll see the following files and +directories: + +README.rst: + This README file. + +LICENSE: + The pycparser license + +setup.py: + Legacy installation script (build metadata lives in ``pyproject.toml``). + +pyproject.toml: + Package metadata and build configuration. + +examples/: + A directory with some examples of using **pycparser** + +pycparser/: + The **pycparser** module source code. + +tests/: + Unit tests. + +utils/fake_libc_include: + Minimal standard C library include files that should allow to parse any C code. + Note that these headers now include C11 code, so they may not work when the + preprocessor is configured to an earlier C standard (like ``-std=c99``). + +utils/internal/: + Internal utilities for my own use. You probably don't need them. + + +Contributors +============ + +Some people have contributed to **pycparser** by opening issues on bugs they've +found and/or submitting patches. The list of contributors is in the CONTRIBUTORS +file in the source distribution. After **pycparser** moved to Github I stopped +updating this list because Github does a much better job at tracking +contributions. diff --git a/source/target-vendors/cp312/pycparser-3.0.dist-info/RECORD b/source/target-vendors/cp312/pycparser-3.0.dist-info/RECORD new file mode 100644 index 0000000..b3383a3 --- /dev/null +++ b/source/target-vendors/cp312/pycparser-3.0.dist-info/RECORD @@ -0,0 +1,13 @@ +pycparser/__init__.py,sha256=phViRyAuUmgqE4kNmaCqpm5WVEBIvzUSFapBv4XX3xo,2829 +pycparser/_ast_gen.py,sha256=ExH5Ym4pk7dQPEIkQr9RJim5feztdBQwSBPvpvE-5BM,11292 +pycparser/_c_ast.cfg,sha256=ld5ezE9yzIJFIVAUfw7ezJSlMi4nXKNCzfmqjOyQTNo,4255 +pycparser/ast_transforms.py,sha256=XwMsarc5aDddNWgIiKm4-jOWMRYib96yNQUo0_u28WA,5899 +pycparser/c_ast.py,sha256=uwkcZWHfXDQIw6WDvCL17iWM_-0R-URDqEMmPjXLOAc,32954 +pycparser/c_generator.py,sha256=RVKJPguv2CvovHHSfQkqimckUr9wGU9PofxCGj251QA,20661 +pycparser/c_lexer.py,sha256=B1VoqbYhPWkOJJWCem4OY4zj0IxrPktBZZFe2Y87kUg,25155 +pycparser/c_parser.py,sha256=3FBKGLjjlC3v8afwD_cnMR67ImoYIy73a4WKQR6hX7g,89798 +pycparser-3.0.dist-info/licenses/LICENSE,sha256=DIRjmTaep23de1xE_m0WSXQV_PAV9cu1CMJL-YuBxbE,1543 +pycparser-3.0.dist-info/METADATA,sha256=9UemCwq1TMLyQiE9H4eWCtgN991d_rmNF6RE1Iv7a5M,8229 +pycparser-3.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92 +pycparser-3.0.dist-info/top_level.txt,sha256=c-lPcS74L_8KoH7IE6PQF5ofyirRQNV4VhkbSFIPeWM,10 +pycparser-3.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/pycparser-3.0.dist-info/WHEEL b/source/target-vendors/cp312/pycparser-3.0.dist-info/WHEEL new file mode 100644 index 0000000..fbbd86c --- /dev/null +++ b/source/target-vendors/cp312/pycparser-3.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.10.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/pycparser-3.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/pycparser-3.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..bee14a4 --- /dev/null +++ b/source/target-vendors/cp312/pycparser-3.0.dist-info/licenses/LICENSE @@ -0,0 +1,27 @@ +pycparser -- A C parser in Python + +Copyright (c) 2008-2022, Eli Bendersky +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the copyright holder nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/pycparser-3.0.dist-info/top_level.txt b/source/target-vendors/cp312/pycparser-3.0.dist-info/top_level.txt new file mode 100644 index 0000000..dc1c9e1 --- /dev/null +++ b/source/target-vendors/cp312/pycparser-3.0.dist-info/top_level.txt @@ -0,0 +1 @@ +pycparser diff --git a/source/target-vendors/cp312/pycparser/__init__.py b/source/target-vendors/cp312/pycparser/__init__.py new file mode 100644 index 0000000..0606c03 --- /dev/null +++ b/source/target-vendors/cp312/pycparser/__init__.py @@ -0,0 +1,99 @@ +# ----------------------------------------------------------------- +# pycparser: __init__.py +# +# This package file exports some convenience functions for +# interacting with pycparser +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ----------------------------------------------------------------- +__all__ = ["c_lexer", "c_parser", "c_ast"] +__version__ = "3.00" + +import io +from subprocess import check_output + +from . import c_parser + +CParser = c_parser.CParser + + +def preprocess_file(filename, cpp_path="cpp", cpp_args=""): + """Preprocess a file using cpp. + + filename: + Name of the file you want to preprocess. + + cpp_path: + cpp_args: + Refer to the documentation of parse_file for the meaning of these + arguments. + + When successful, returns the preprocessed file's contents. + Errors from cpp will be printed out. + """ + path_list = [cpp_path] + if isinstance(cpp_args, list): + path_list += cpp_args + elif cpp_args != "": + path_list += [cpp_args] + path_list += [filename] + + try: + # Note the use of universal_newlines to treat all newlines + # as \n for Python's purpose + text = check_output(path_list, universal_newlines=True) + except OSError as e: + raise RuntimeError( + "Unable to invoke 'cpp'. " + + "Make sure its path was passed correctly\n" + + f"Original error: {e}" + ) + + return text + + +def parse_file( + filename, use_cpp=False, cpp_path="cpp", cpp_args="", parser=None, encoding=None +): + """Parse a C file using pycparser. + + filename: + Name of the file you want to parse. + + use_cpp: + Set to True if you want to execute the C pre-processor + on the file prior to parsing it. + + cpp_path: + If use_cpp is True, this is the path to 'cpp' on your + system. If no path is provided, it attempts to just + execute 'cpp', so it must be in your PATH. + + cpp_args: + If use_cpp is True, set this to the command line arguments strings + to cpp. Be careful with quotes - it's best to pass a raw string + (r'') here. For example: + r'-I../utils/fake_libc_include' + If several arguments are required, pass a list of strings. + + encoding: + Encoding to use for the file to parse + + parser: + Optional parser object to be used instead of the default CParser + + When successful, an AST is returned. ParseError can be + thrown if the file doesn't parse successfully. + + Errors from cpp will be printed out. + """ + if use_cpp: + text = preprocess_file(filename, cpp_path, cpp_args) + else: + with io.open(filename, encoding=encoding) as f: + text = f.read() + + if parser is None: + parser = CParser() + return parser.parse(text, filename) diff --git a/source/target-vendors/cp312/pycparser/_ast_gen.py b/source/target-vendors/cp312/pycparser/_ast_gen.py new file mode 100644 index 0000000..6df0b6a --- /dev/null +++ b/source/target-vendors/cp312/pycparser/_ast_gen.py @@ -0,0 +1,355 @@ +# ----------------------------------------------------------------- +# _ast_gen.py +# +# Generates the AST Node classes from a specification given in +# a configuration file. This module can also be run as a script to +# regenerate c_ast.py from _c_ast.cfg (from the repo root or the +# pycparser/ directory). Use 'make check' to reformat the generated +# file after running this script. +# +# The design of this module was inspired by astgen.py from the +# Python 2.5 code-base. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ----------------------------------------------------------------- +from string import Template +import os +from typing import IO + + +class ASTCodeGenerator: + def __init__(self, cfg_filename="_c_ast.cfg"): + """Initialize the code generator from a configuration + file. + """ + self.cfg_filename = cfg_filename + self.node_cfg = [ + NodeCfg(name, contents) + for (name, contents) in self.parse_cfgfile(cfg_filename) + ] + + def generate(self, file: IO[str]) -> None: + """Generates the code into file, an open file buffer.""" + src = Template(_PROLOGUE_COMMENT).substitute(cfg_filename=self.cfg_filename) + + src += _PROLOGUE_CODE + for node_cfg in self.node_cfg: + src += node_cfg.generate_source() + "\n\n" + + file.write(src) + + def parse_cfgfile(self, filename): + """Parse the configuration file and yield pairs of + (name, contents) for each node. + """ + with open(filename, "r") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + colon_i = line.find(":") + lbracket_i = line.find("[") + rbracket_i = line.find("]") + if colon_i < 1 or lbracket_i <= colon_i or rbracket_i <= lbracket_i: + raise RuntimeError(f"Invalid line in {filename}:\n{line}\n") + + name = line[:colon_i] + val = line[lbracket_i + 1 : rbracket_i] + vallist = [v.strip() for v in val.split(",")] if val else [] + yield name, vallist + + +class NodeCfg: + """Node configuration. + + name: node name + contents: a list of contents - attributes and child nodes + See comment at the top of the configuration file for details. + """ + + def __init__(self, name, contents): + self.name = name + self.all_entries = [] + self.attr = [] + self.child = [] + self.seq_child = [] + + for entry in contents: + clean_entry = entry.rstrip("*") + self.all_entries.append(clean_entry) + + if entry.endswith("**"): + self.seq_child.append(clean_entry) + elif entry.endswith("*"): + self.child.append(clean_entry) + else: + self.attr.append(entry) + + def generate_source(self): + src = self._gen_init() + src += "\n" + self._gen_children() + src += "\n" + self._gen_iter() + src += "\n" + self._gen_attr_names() + return src + + def _gen_init(self): + src = f"class {self.name}(Node):\n" + + if self.all_entries: + args = ", ".join(self.all_entries) + slots = ", ".join(f"'{e}'" for e in self.all_entries) + slots += ", 'coord', '__weakref__'" + arglist = f"(self, {args}, coord=None)" + else: + slots = "'coord', '__weakref__'" + arglist = "(self, coord=None)" + + src += f" __slots__ = ({slots})\n" + src += f" def __init__{arglist}:\n" + + for name in self.all_entries + ["coord"]: + src += f" self.{name} = {name}\n" + + return src + + def _gen_children(self): + src = " def children(self):\n" + + if self.all_entries: + src += " nodelist = []\n" + + for child in self.child: + src += f" if self.{child} is not None:\n" + src += f' nodelist.append(("{child}", self.{child}))\n' + + for seq_child in self.seq_child: + src += f" for i, child in enumerate(self.{seq_child} or []):\n" + src += f' nodelist.append((f"{seq_child}[{{i}}]", child))\n' + + src += " return tuple(nodelist)\n" + else: + src += " return ()\n" + + return src + + def _gen_iter(self): + src = " def __iter__(self):\n" + + if self.all_entries: + for child in self.child: + src += f" if self.{child} is not None:\n" + src += f" yield self.{child}\n" + + for seq_child in self.seq_child: + src += f" for child in (self.{seq_child} or []):\n" + src += " yield child\n" + + if not (self.child or self.seq_child): + # Empty generator + src += " return\n" + " yield\n" + else: + # Empty generator + src += " return\n" + " yield\n" + + return src + + def _gen_attr_names(self): + src = " attr_names = (" + "".join(f"{nm!r}, " for nm in self.attr) + ")" + return src + + +_PROLOGUE_COMMENT = r"""#----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from _c_ast.cfg +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + +""" +_PROLOGUE_CODE = r''' +import sys +from typing import Any, ClassVar, IO, Optional + +def _repr(obj): + """ + Get the representation of an object, with dedicated pprint-like format for lists. + """ + if isinstance(obj, list): + return '[' + (',\n '.join((_repr(e).replace('\n', '\n ') for e in obj))) + '\n]' + else: + return repr(obj) + +class Node: + __slots__ = () + """ Abstract base class for AST nodes. + """ + attr_names: ClassVar[tuple[str, ...]] = () + coord: Optional[Any] + def __repr__(self): + """ Generates a python representation of the current node + """ + result = self.__class__.__name__ + '(' + + indent = '' + separator = '' + for name in self.__slots__[:-2]: + result += separator + result += indent + result += name + '=' + (_repr(getattr(self, name)).replace('\n', '\n ' + (' ' * (len(name) + len(self.__class__.__name__))))) + + separator = ',' + indent = '\n ' + (' ' * len(self.__class__.__name__)) + + result += indent + ')' + + return result + + def children(self): + """ A sequence of all children that are Nodes + """ + pass + + def show( + self, + buf: IO[str] = sys.stdout, + offset: int = 0, + attrnames: bool = False, + showemptyattrs: bool = True, + nodenames: bool = False, + showcoord: bool = False, + _my_node_name: Optional[str] = None, + ): + """ Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + buf: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + showemptyattrs: + False if you want to suppress printing empty attributes. + + nodenames: + True if you want to see the actual node names + within their parents. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + lead = ' ' * offset + if nodenames and _my_node_name is not None: + buf.write(lead + self.__class__.__name__+ ' <' + _my_node_name + '>: ') + else: + buf.write(lead + self.__class__.__name__+ ': ') + + if self.attr_names: + def is_empty(v): + v is None or (hasattr(v, '__len__') and len(v) == 0) + nvlist = [(n, getattr(self,n)) for n in self.attr_names \ + if showemptyattrs or not is_empty(getattr(self,n))] + if attrnames: + attrstr = ', '.join(f'{name}={value}' for name, value in nvlist) + else: + attrstr = ', '.join(f'{value}' for _, value in nvlist) + buf.write(attrstr) + + if showcoord: + buf.write(f' (at {self.coord})') + buf.write('\n') + + for (child_name, child) in self.children(): + child.show( + buf, + offset=offset + 2, + attrnames=attrnames, + showemptyattrs=showemptyattrs, + nodenames=nodenames, + showcoord=showcoord, + _my_node_name=child_name) + + +class NodeVisitor: + """ A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + + _method_cache = None + + def visit(self, node: Node): + """ Visit a node. + """ + + if self._method_cache is None: + self._method_cache = {} + + visitor = self._method_cache.get(node.__class__.__name__, None) + if visitor is None: + method = 'visit_' + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + self._method_cache[node.__class__.__name__] = visitor + + return visitor(node) + + def generic_visit(self, node: Node): + """ Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for _, c in node.children(): + self.visit(c) + +''' + + +if __name__ == "__main__": + base_dir = os.path.dirname(os.path.abspath(__file__)) + cfg_path = os.path.join(base_dir, "_c_ast.cfg") + out_path = os.path.join(base_dir, "c_ast.py") + ast_gen = ASTCodeGenerator(cfg_path) + with open(out_path, "w") as out: + ast_gen.generate(out) diff --git a/source/target-vendors/cp312/pycparser/_c_ast.cfg b/source/target-vendors/cp312/pycparser/_c_ast.cfg new file mode 100644 index 0000000..0626533 --- /dev/null +++ b/source/target-vendors/cp312/pycparser/_c_ast.cfg @@ -0,0 +1,195 @@ +#----------------------------------------------------------------- +# pycparser: _c_ast.cfg +# +# Defines the AST Node classes used in pycparser. +# +# Each entry is a Node sub-class name, listing the attributes +# and child nodes of the class: +# * - a child node +# ** - a sequence of child nodes +# - an attribute +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +#----------------------------------------------------------------- + +# ArrayDecl is a nested declaration of an array with the given type. +# dim: the dimension (for example, constant 42) +# dim_quals: list of dimension qualifiers, to support C99's allowing 'const' +# and 'static' within the array dimension in function declarations. +ArrayDecl: [type*, dim*, dim_quals] + +ArrayRef: [name*, subscript*] + +# op: =, +=, /= etc. +# +Assignment: [op, lvalue*, rvalue*] + +Alignas: [alignment*] + +BinaryOp: [op, left*, right*] + +Break: [] + +Case: [expr*, stmts**] + +Cast: [to_type*, expr*] + +# Compound statement in C99 is a list of block items (declarations or +# statements). +# +Compound: [block_items**] + +# Compound literal (anonymous aggregate) for C99. +# (type-name) {initializer_list} +# type: the typename +# init: InitList for the initializer list +# +CompoundLiteral: [type*, init*] + +# type: int, char, float, string, etc. +# +Constant: [type, value] + +Continue: [] + +# name: the variable being declared +# quals: list of qualifiers (const, volatile) +# funcspec: list function specifiers (i.e. inline in C99) +# storage: list of storage specifiers (extern, register, etc.) +# type: declaration type (probably nested with all the modifiers) +# init: initialization value, or None +# bitsize: bit field size, or None +# +Decl: [name, quals, align, storage, funcspec, type*, init*, bitsize*] + +DeclList: [decls**] + +Default: [stmts**] + +DoWhile: [cond*, stmt*] + +# Represents the ellipsis (...) parameter in a function +# declaration +# +EllipsisParam: [] + +# An empty statement (a semicolon ';' on its own) +# +EmptyStatement: [] + +# Enumeration type specifier +# name: an optional ID +# values: an EnumeratorList +# +Enum: [name, values*] + +# A name/value pair for enumeration values +# +Enumerator: [name, value*] + +# A list of enumerators +# +EnumeratorList: [enumerators**] + +# A list of expressions separated by the comma operator. +# +ExprList: [exprs**] + +# This is the top of the AST, representing a single C file (a +# translation unit in K&R jargon). It contains a list of +# "external-declaration"s, which is either declarations (Decl), +# Typedef or function definitions (FuncDef). +# +FileAST: [ext**] + +# for (init; cond; next) stmt +# +For: [init*, cond*, next*, stmt*] + +# name: Id +# args: ExprList +# +FuncCall: [name*, args*] + +# type (args) +# +FuncDecl: [args*, type*] + +# Function definition: a declarator for the function name and +# a body, which is a compound statement. +# There's an optional list of parameter declarations for old +# K&R-style definitions +# +FuncDef: [decl*, param_decls**, body*] + +Goto: [name] + +ID: [name] + +# Holder for types that are a simple identifier (e.g. the built +# ins void, char etc. and typedef-defined types) +# +IdentifierType: [names] + +If: [cond*, iftrue*, iffalse*] + +# An initialization list used for compound literals. +# +InitList: [exprs**] + +Label: [name, stmt*] + +# A named initializer for C99. +# The name of a NamedInitializer is a sequence of Nodes, because +# names can be hierarchical and contain constant expressions. +# +NamedInitializer: [name**, expr*] + +# a list of comma separated function parameter declarations +# +ParamList: [params**] + +PtrDecl: [quals, type*] + +Return: [expr*] + +StaticAssert: [cond*, message*] + +# name: struct tag name +# decls: declaration of members +# +Struct: [name, decls**] + +# type: . or -> +# name.field or name->field +# +StructRef: [name*, type, field*] + +Switch: [cond*, stmt*] + +# cond ? iftrue : iffalse +# +TernaryOp: [cond*, iftrue*, iffalse*] + +# A base type declaration +# +TypeDecl: [declname, quals, align, type*] + +# A typedef declaration. +# Very similar to Decl, but without some attributes +# +Typedef: [name, quals, storage, type*] + +Typename: [name, quals, align, type*] + +UnaryOp: [op, expr*] + +# name: union tag name +# decls: declaration of members +# +Union: [name, decls**] + +While: [cond*, stmt*] + +Pragma: [string] diff --git a/source/target-vendors/cp312/pycparser/ast_transforms.py b/source/target-vendors/cp312/pycparser/ast_transforms.py new file mode 100644 index 0000000..1051737 --- /dev/null +++ b/source/target-vendors/cp312/pycparser/ast_transforms.py @@ -0,0 +1,174 @@ +# ------------------------------------------------------------------------------ +# pycparser: ast_transforms.py +# +# Some utilities used by the parser to create a friendlier AST. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ------------------------------------------------------------------------------ + +from typing import Any, List, Tuple, cast + +from . import c_ast + + +def fix_switch_cases(switch_node: c_ast.Switch) -> c_ast.Switch: + """The 'case' statements in a 'switch' come out of parsing with one + child node, so subsequent statements are just tucked to the parent + Compound. Additionally, consecutive (fall-through) case statements + come out messy. This is a peculiarity of the C grammar. The following: + + switch (myvar) { + case 10: + k = 10; + p = k + 1; + return 10; + case 20: + case 30: + return 20; + default: + break; + } + + Creates this tree (pseudo-dump): + + Switch + ID: myvar + Compound: + Case 10: + k = 10 + p = k + 1 + return 10 + Case 20: + Case 30: + return 20 + Default: + break + + The goal of this transform is to fix this mess, turning it into the + following: + + Switch + ID: myvar + Compound: + Case 10: + k = 10 + p = k + 1 + return 10 + Case 20: + Case 30: + return 20 + Default: + break + + A fixed AST node is returned. The argument may be modified. + """ + assert isinstance(switch_node, c_ast.Switch) + if not isinstance(switch_node.stmt, c_ast.Compound): + return switch_node + + # The new Compound child for the Switch, which will collect children in the + # correct order + new_compound = c_ast.Compound([], switch_node.stmt.coord) + + # The last Case/Default node + last_case: c_ast.Case | c_ast.Default | None = None + + # Goes over the children of the Compound below the Switch, adding them + # either directly below new_compound or below the last Case as appropriate + # (for `switch(cond) {}`, block_items would have been None) + for child in switch_node.stmt.block_items or []: + if isinstance(child, (c_ast.Case, c_ast.Default)): + # If it's a Case/Default: + # 1. Add it to the Compound and mark as "last case" + # 2. If its immediate child is also a Case or Default, promote it + # to a sibling. + new_compound.block_items.append(child) + _extract_nested_case(child, new_compound.block_items) + last_case = new_compound.block_items[-1] + else: + # Other statements are added as children to the last case, if it + # exists. + if last_case is None: + new_compound.block_items.append(child) + else: + last_case.stmts.append(child) + + switch_node.stmt = new_compound + return switch_node + + +def _extract_nested_case( + case_node: c_ast.Case | c_ast.Default, stmts_list: List[c_ast.Node] +) -> None: + """Recursively extract consecutive Case statements that are made nested + by the parser and add them to the stmts_list. + """ + if isinstance(case_node.stmts[0], (c_ast.Case, c_ast.Default)): + nested = case_node.stmts.pop() + stmts_list.append(nested) + _extract_nested_case(cast(Any, nested), stmts_list) + + +def fix_atomic_specifiers( + decl: c_ast.Decl | c_ast.Typedef, +) -> c_ast.Decl | c_ast.Typedef: + """Atomic specifiers like _Atomic(type) are unusually structured, + conferring a qualifier upon the contained type. + + This function fixes a decl with atomic specifiers to have a sane AST + structure, by removing spurious Typename->TypeDecl pairs and attaching + the _Atomic qualifier in the right place. + """ + # There can be multiple levels of _Atomic in a decl; fix them until a + # fixed point is reached. + while True: + decl, found = _fix_atomic_specifiers_once(decl) + if not found: + break + + # Make sure to add an _Atomic qual on the topmost decl if needed. Also + # restore the declname on the innermost TypeDecl (it gets placed in the + # wrong place during construction). + typ: Any = decl + while not isinstance(typ, c_ast.TypeDecl): + try: + typ = typ.type + except AttributeError: + return decl + if "_Atomic" in typ.quals and "_Atomic" not in decl.quals: + decl.quals.append("_Atomic") + if typ.declname is None: + typ.declname = decl.name + + return decl + + +def _fix_atomic_specifiers_once( + decl: c_ast.Decl | c_ast.Typedef, +) -> Tuple[c_ast.Decl | c_ast.Typedef, bool]: + """Performs one 'fix' round of atomic specifiers. + Returns (modified_decl, found) where found is True iff a fix was made. + """ + parent: Any = decl + grandparent: Any = None + node: Any = decl.type + while node is not None: + if isinstance(node, c_ast.Typename) and "_Atomic" in node.quals: + break + try: + grandparent = parent + parent = node + node = node.type + except AttributeError: + # If we've reached a node without a `type` field, it means we won't + # find what we're looking for at this point; give up the search + # and return the original decl unmodified. + return decl, False + + assert isinstance(parent, c_ast.TypeDecl) + assert grandparent is not None + cast(Any, grandparent).type = node.type + if "_Atomic" not in node.type.quals: + node.type.quals.append("_Atomic") + return decl, True diff --git a/source/target-vendors/cp312/pycparser/c_ast.py b/source/target-vendors/cp312/pycparser/c_ast.py new file mode 100644 index 0000000..b6f42af --- /dev/null +++ b/source/target-vendors/cp312/pycparser/c_ast.py @@ -0,0 +1,1341 @@ +# ----------------------------------------------------------------- +# ** ATTENTION ** +# This code was automatically generated from _c_ast.cfg +# +# Do not modify it directly. Modify the configuration file and +# run the generator again. +# ** ** *** ** ** +# +# pycparser: c_ast.py +# +# AST Node classes. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ----------------------------------------------------------------- + + +import sys +from typing import Any, ClassVar, IO, Optional + + +def _repr(obj): + """ + Get the representation of an object, with dedicated pprint-like format for lists. + """ + if isinstance(obj, list): + return "[" + (",\n ".join((_repr(e).replace("\n", "\n ") for e in obj))) + "\n]" + else: + return repr(obj) + + +class Node: + __slots__ = () + """ Abstract base class for AST nodes. + """ + attr_names: ClassVar[tuple[str, ...]] = () + coord: Optional[Any] + + def __repr__(self): + """Generates a python representation of the current node""" + result = self.__class__.__name__ + "(" + + indent = "" + separator = "" + for name in self.__slots__[:-2]: + result += separator + result += indent + result += ( + name + + "=" + + ( + _repr(getattr(self, name)).replace( + "\n", + "\n " + (" " * (len(name) + len(self.__class__.__name__))), + ) + ) + ) + + separator = "," + indent = "\n " + (" " * len(self.__class__.__name__)) + + result += indent + ")" + + return result + + def children(self): + """A sequence of all children that are Nodes""" + pass + + def show( + self, + buf: IO[str] = sys.stdout, + offset: int = 0, + attrnames: bool = False, + showemptyattrs: bool = True, + nodenames: bool = False, + showcoord: bool = False, + _my_node_name: Optional[str] = None, + ): + """Pretty print the Node and all its attributes and + children (recursively) to a buffer. + + buf: + Open IO buffer into which the Node is printed. + + offset: + Initial offset (amount of leading spaces) + + attrnames: + True if you want to see the attribute names in + name=value pairs. False to only see the values. + + showemptyattrs: + False if you want to suppress printing empty attributes. + + nodenames: + True if you want to see the actual node names + within their parents. + + showcoord: + Do you want the coordinates of each Node to be + displayed. + """ + lead = " " * offset + if nodenames and _my_node_name is not None: + buf.write(lead + self.__class__.__name__ + " <" + _my_node_name + ">: ") + else: + buf.write(lead + self.__class__.__name__ + ": ") + + if self.attr_names: + + def is_empty(v): + v is None or (hasattr(v, "__len__") and len(v) == 0) + + nvlist = [ + (n, getattr(self, n)) + for n in self.attr_names + if showemptyattrs or not is_empty(getattr(self, n)) + ] + if attrnames: + attrstr = ", ".join(f"{name}={value}" for name, value in nvlist) + else: + attrstr = ", ".join(f"{value}" for _, value in nvlist) + buf.write(attrstr) + + if showcoord: + buf.write(f" (at {self.coord})") + buf.write("\n") + + for child_name, child in self.children(): + child.show( + buf, + offset=offset + 2, + attrnames=attrnames, + showemptyattrs=showemptyattrs, + nodenames=nodenames, + showcoord=showcoord, + _my_node_name=child_name, + ) + + +class NodeVisitor: + """A base NodeVisitor class for visiting c_ast nodes. + Subclass it and define your own visit_XXX methods, where + XXX is the class name you want to visit with these + methods. + + For example: + + class ConstantVisitor(NodeVisitor): + def __init__(self): + self.values = [] + + def visit_Constant(self, node): + self.values.append(node.value) + + Creates a list of values of all the constant nodes + encountered below the given node. To use it: + + cv = ConstantVisitor() + cv.visit(node) + + Notes: + + * generic_visit() will be called for AST nodes for which + no visit_XXX method was defined. + * The children of nodes for which a visit_XXX was + defined will not be visited - if you need this, call + generic_visit() on the node. + You can use: + NodeVisitor.generic_visit(self, node) + * Modeled after Python's own AST visiting facilities + (the ast module of Python 3.0) + """ + + _method_cache = None + + def visit(self, node: Node): + """Visit a node.""" + + if self._method_cache is None: + self._method_cache = {} + + visitor = self._method_cache.get(node.__class__.__name__, None) + if visitor is None: + method = "visit_" + node.__class__.__name__ + visitor = getattr(self, method, self.generic_visit) + self._method_cache[node.__class__.__name__] = visitor + + return visitor(node) + + def generic_visit(self, node: Node): + """Called if no explicit visitor function exists for a + node. Implements preorder visiting of the node. + """ + for _, c in node.children(): + self.visit(c) + + +class ArrayDecl(Node): + __slots__ = ("type", "dim", "dim_quals", "coord", "__weakref__") + + def __init__(self, type, dim, dim_quals, coord=None): + self.type = type + self.dim = dim + self.dim_quals = dim_quals + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + if self.dim is not None: + nodelist.append(("dim", self.dim)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + if self.dim is not None: + yield self.dim + + attr_names = ("dim_quals",) + + +class ArrayRef(Node): + __slots__ = ("name", "subscript", "coord", "__weakref__") + + def __init__(self, name, subscript, coord=None): + self.name = name + self.subscript = subscript + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: + nodelist.append(("name", self.name)) + if self.subscript is not None: + nodelist.append(("subscript", self.subscript)) + return tuple(nodelist) + + def __iter__(self): + if self.name is not None: + yield self.name + if self.subscript is not None: + yield self.subscript + + attr_names = () + + +class Assignment(Node): + __slots__ = ("op", "lvalue", "rvalue", "coord", "__weakref__") + + def __init__(self, op, lvalue, rvalue, coord=None): + self.op = op + self.lvalue = lvalue + self.rvalue = rvalue + self.coord = coord + + def children(self): + nodelist = [] + if self.lvalue is not None: + nodelist.append(("lvalue", self.lvalue)) + if self.rvalue is not None: + nodelist.append(("rvalue", self.rvalue)) + return tuple(nodelist) + + def __iter__(self): + if self.lvalue is not None: + yield self.lvalue + if self.rvalue is not None: + yield self.rvalue + + attr_names = ("op",) + + +class Alignas(Node): + __slots__ = ("alignment", "coord", "__weakref__") + + def __init__(self, alignment, coord=None): + self.alignment = alignment + self.coord = coord + + def children(self): + nodelist = [] + if self.alignment is not None: + nodelist.append(("alignment", self.alignment)) + return tuple(nodelist) + + def __iter__(self): + if self.alignment is not None: + yield self.alignment + + attr_names = () + + +class BinaryOp(Node): + __slots__ = ("op", "left", "right", "coord", "__weakref__") + + def __init__(self, op, left, right, coord=None): + self.op = op + self.left = left + self.right = right + self.coord = coord + + def children(self): + nodelist = [] + if self.left is not None: + nodelist.append(("left", self.left)) + if self.right is not None: + nodelist.append(("right", self.right)) + return tuple(nodelist) + + def __iter__(self): + if self.left is not None: + yield self.left + if self.right is not None: + yield self.right + + attr_names = ("op",) + + +class Break(Node): + __slots__ = ("coord", "__weakref__") + + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + + +class Case(Node): + __slots__ = ("expr", "stmts", "coord", "__weakref__") + + def __init__(self, expr, stmts, coord=None): + self.expr = expr + self.stmts = stmts + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: + nodelist.append(("expr", self.expr)) + for i, child in enumerate(self.stmts or []): + nodelist.append((f"stmts[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + for child in self.stmts or []: + yield child + + attr_names = () + + +class Cast(Node): + __slots__ = ("to_type", "expr", "coord", "__weakref__") + + def __init__(self, to_type, expr, coord=None): + self.to_type = to_type + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.to_type is not None: + nodelist.append(("to_type", self.to_type)) + if self.expr is not None: + nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + def __iter__(self): + if self.to_type is not None: + yield self.to_type + if self.expr is not None: + yield self.expr + + attr_names = () + + +class Compound(Node): + __slots__ = ("block_items", "coord", "__weakref__") + + def __init__(self, block_items, coord=None): + self.block_items = block_items + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.block_items or []): + nodelist.append((f"block_items[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.block_items or []: + yield child + + attr_names = () + + +class CompoundLiteral(Node): + __slots__ = ("type", "init", "coord", "__weakref__") + + def __init__(self, type, init, coord=None): + self.type = type + self.init = init + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + if self.init is not None: + nodelist.append(("init", self.init)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + if self.init is not None: + yield self.init + + attr_names = () + + +class Constant(Node): + __slots__ = ("type", "value", "coord", "__weakref__") + + def __init__(self, type, value, coord=None): + self.type = type + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ( + "type", + "value", + ) + + +class Continue(Node): + __slots__ = ("coord", "__weakref__") + + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + + +class Decl(Node): + __slots__ = ( + "name", + "quals", + "align", + "storage", + "funcspec", + "type", + "init", + "bitsize", + "coord", + "__weakref__", + ) + + def __init__( + self, name, quals, align, storage, funcspec, type, init, bitsize, coord=None + ): + self.name = name + self.quals = quals + self.align = align + self.storage = storage + self.funcspec = funcspec + self.type = type + self.init = init + self.bitsize = bitsize + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + if self.init is not None: + nodelist.append(("init", self.init)) + if self.bitsize is not None: + nodelist.append(("bitsize", self.bitsize)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + if self.init is not None: + yield self.init + if self.bitsize is not None: + yield self.bitsize + + attr_names = ( + "name", + "quals", + "align", + "storage", + "funcspec", + ) + + +class DeclList(Node): + __slots__ = ("decls", "coord", "__weakref__") + + def __init__(self, decls, coord=None): + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.decls or []): + nodelist.append((f"decls[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.decls or []: + yield child + + attr_names = () + + +class Default(Node): + __slots__ = ("stmts", "coord", "__weakref__") + + def __init__(self, stmts, coord=None): + self.stmts = stmts + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.stmts or []): + nodelist.append((f"stmts[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.stmts or []: + yield child + + attr_names = () + + +class DoWhile(Node): + __slots__ = ("cond", "stmt", "coord", "__weakref__") + + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.stmt is not None: + nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.stmt is not None: + yield self.stmt + + attr_names = () + + +class EllipsisParam(Node): + __slots__ = ("coord", "__weakref__") + + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + + +class EmptyStatement(Node): + __slots__ = ("coord", "__weakref__") + + def __init__(self, coord=None): + self.coord = coord + + def children(self): + return () + + def __iter__(self): + return + yield + + attr_names = () + + +class Enum(Node): + __slots__ = ("name", "values", "coord", "__weakref__") + + def __init__(self, name, values, coord=None): + self.name = name + self.values = values + self.coord = coord + + def children(self): + nodelist = [] + if self.values is not None: + nodelist.append(("values", self.values)) + return tuple(nodelist) + + def __iter__(self): + if self.values is not None: + yield self.values + + attr_names = ("name",) + + +class Enumerator(Node): + __slots__ = ("name", "value", "coord", "__weakref__") + + def __init__(self, name, value, coord=None): + self.name = name + self.value = value + self.coord = coord + + def children(self): + nodelist = [] + if self.value is not None: + nodelist.append(("value", self.value)) + return tuple(nodelist) + + def __iter__(self): + if self.value is not None: + yield self.value + + attr_names = ("name",) + + +class EnumeratorList(Node): + __slots__ = ("enumerators", "coord", "__weakref__") + + def __init__(self, enumerators, coord=None): + self.enumerators = enumerators + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.enumerators or []): + nodelist.append((f"enumerators[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.enumerators or []: + yield child + + attr_names = () + + +class ExprList(Node): + __slots__ = ("exprs", "coord", "__weakref__") + + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.exprs or []): + nodelist.append((f"exprs[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.exprs or []: + yield child + + attr_names = () + + +class FileAST(Node): + __slots__ = ("ext", "coord", "__weakref__") + + def __init__(self, ext, coord=None): + self.ext = ext + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.ext or []): + nodelist.append((f"ext[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.ext or []: + yield child + + attr_names = () + + +class For(Node): + __slots__ = ("init", "cond", "next", "stmt", "coord", "__weakref__") + + def __init__(self, init, cond, next, stmt, coord=None): + self.init = init + self.cond = cond + self.next = next + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.init is not None: + nodelist.append(("init", self.init)) + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.next is not None: + nodelist.append(("next", self.next)) + if self.stmt is not None: + nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.init is not None: + yield self.init + if self.cond is not None: + yield self.cond + if self.next is not None: + yield self.next + if self.stmt is not None: + yield self.stmt + + attr_names = () + + +class FuncCall(Node): + __slots__ = ("name", "args", "coord", "__weakref__") + + def __init__(self, name, args, coord=None): + self.name = name + self.args = args + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: + nodelist.append(("name", self.name)) + if self.args is not None: + nodelist.append(("args", self.args)) + return tuple(nodelist) + + def __iter__(self): + if self.name is not None: + yield self.name + if self.args is not None: + yield self.args + + attr_names = () + + +class FuncDecl(Node): + __slots__ = ("args", "type", "coord", "__weakref__") + + def __init__(self, args, type, coord=None): + self.args = args + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.args is not None: + nodelist.append(("args", self.args)) + if self.type is not None: + nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.args is not None: + yield self.args + if self.type is not None: + yield self.type + + attr_names = () + + +class FuncDef(Node): + __slots__ = ("decl", "param_decls", "body", "coord", "__weakref__") + + def __init__(self, decl, param_decls, body, coord=None): + self.decl = decl + self.param_decls = param_decls + self.body = body + self.coord = coord + + def children(self): + nodelist = [] + if self.decl is not None: + nodelist.append(("decl", self.decl)) + if self.body is not None: + nodelist.append(("body", self.body)) + for i, child in enumerate(self.param_decls or []): + nodelist.append((f"param_decls[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + if self.decl is not None: + yield self.decl + if self.body is not None: + yield self.body + for child in self.param_decls or []: + yield child + + attr_names = () + + +class Goto(Node): + __slots__ = ("name", "coord", "__weakref__") + + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ("name",) + + +class ID(Node): + __slots__ = ("name", "coord", "__weakref__") + + def __init__(self, name, coord=None): + self.name = name + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ("name",) + + +class IdentifierType(Node): + __slots__ = ("names", "coord", "__weakref__") + + def __init__(self, names, coord=None): + self.names = names + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ("names",) + + +class If(Node): + __slots__ = ("cond", "iftrue", "iffalse", "coord", "__weakref__") + + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.iftrue is not None: + nodelist.append(("iftrue", self.iftrue)) + if self.iffalse is not None: + nodelist.append(("iffalse", self.iffalse)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.iftrue is not None: + yield self.iftrue + if self.iffalse is not None: + yield self.iffalse + + attr_names = () + + +class InitList(Node): + __slots__ = ("exprs", "coord", "__weakref__") + + def __init__(self, exprs, coord=None): + self.exprs = exprs + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.exprs or []): + nodelist.append((f"exprs[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.exprs or []: + yield child + + attr_names = () + + +class Label(Node): + __slots__ = ("name", "stmt", "coord", "__weakref__") + + def __init__(self, name, stmt, coord=None): + self.name = name + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.stmt is not None: + nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.stmt is not None: + yield self.stmt + + attr_names = ("name",) + + +class NamedInitializer(Node): + __slots__ = ("name", "expr", "coord", "__weakref__") + + def __init__(self, name, expr, coord=None): + self.name = name + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: + nodelist.append(("expr", self.expr)) + for i, child in enumerate(self.name or []): + nodelist.append((f"name[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + for child in self.name or []: + yield child + + attr_names = () + + +class ParamList(Node): + __slots__ = ("params", "coord", "__weakref__") + + def __init__(self, params, coord=None): + self.params = params + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.params or []): + nodelist.append((f"params[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.params or []: + yield child + + attr_names = () + + +class PtrDecl(Node): + __slots__ = ("quals", "type", "coord", "__weakref__") + + def __init__(self, quals, type, coord=None): + self.quals = quals + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ("quals",) + + +class Return(Node): + __slots__ = ("expr", "coord", "__weakref__") + + def __init__(self, expr, coord=None): + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: + nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + + attr_names = () + + +class StaticAssert(Node): + __slots__ = ("cond", "message", "coord", "__weakref__") + + def __init__(self, cond, message, coord=None): + self.cond = cond + self.message = message + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.message is not None: + nodelist.append(("message", self.message)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.message is not None: + yield self.message + + attr_names = () + + +class Struct(Node): + __slots__ = ("name", "decls", "coord", "__weakref__") + + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.decls or []): + nodelist.append((f"decls[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.decls or []: + yield child + + attr_names = ("name",) + + +class StructRef(Node): + __slots__ = ("name", "type", "field", "coord", "__weakref__") + + def __init__(self, name, type, field, coord=None): + self.name = name + self.type = type + self.field = field + self.coord = coord + + def children(self): + nodelist = [] + if self.name is not None: + nodelist.append(("name", self.name)) + if self.field is not None: + nodelist.append(("field", self.field)) + return tuple(nodelist) + + def __iter__(self): + if self.name is not None: + yield self.name + if self.field is not None: + yield self.field + + attr_names = ("type",) + + +class Switch(Node): + __slots__ = ("cond", "stmt", "coord", "__weakref__") + + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.stmt is not None: + nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.stmt is not None: + yield self.stmt + + attr_names = () + + +class TernaryOp(Node): + __slots__ = ("cond", "iftrue", "iffalse", "coord", "__weakref__") + + def __init__(self, cond, iftrue, iffalse, coord=None): + self.cond = cond + self.iftrue = iftrue + self.iffalse = iffalse + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.iftrue is not None: + nodelist.append(("iftrue", self.iftrue)) + if self.iffalse is not None: + nodelist.append(("iffalse", self.iffalse)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.iftrue is not None: + yield self.iftrue + if self.iffalse is not None: + yield self.iffalse + + attr_names = () + + +class TypeDecl(Node): + __slots__ = ("declname", "quals", "align", "type", "coord", "__weakref__") + + def __init__(self, declname, quals, align, type, coord=None): + self.declname = declname + self.quals = quals + self.align = align + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ( + "declname", + "quals", + "align", + ) + + +class Typedef(Node): + __slots__ = ("name", "quals", "storage", "type", "coord", "__weakref__") + + def __init__(self, name, quals, storage, type, coord=None): + self.name = name + self.quals = quals + self.storage = storage + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ( + "name", + "quals", + "storage", + ) + + +class Typename(Node): + __slots__ = ("name", "quals", "align", "type", "coord", "__weakref__") + + def __init__(self, name, quals, align, type, coord=None): + self.name = name + self.quals = quals + self.align = align + self.type = type + self.coord = coord + + def children(self): + nodelist = [] + if self.type is not None: + nodelist.append(("type", self.type)) + return tuple(nodelist) + + def __iter__(self): + if self.type is not None: + yield self.type + + attr_names = ( + "name", + "quals", + "align", + ) + + +class UnaryOp(Node): + __slots__ = ("op", "expr", "coord", "__weakref__") + + def __init__(self, op, expr, coord=None): + self.op = op + self.expr = expr + self.coord = coord + + def children(self): + nodelist = [] + if self.expr is not None: + nodelist.append(("expr", self.expr)) + return tuple(nodelist) + + def __iter__(self): + if self.expr is not None: + yield self.expr + + attr_names = ("op",) + + +class Union(Node): + __slots__ = ("name", "decls", "coord", "__weakref__") + + def __init__(self, name, decls, coord=None): + self.name = name + self.decls = decls + self.coord = coord + + def children(self): + nodelist = [] + for i, child in enumerate(self.decls or []): + nodelist.append((f"decls[{i}]", child)) + return tuple(nodelist) + + def __iter__(self): + for child in self.decls or []: + yield child + + attr_names = ("name",) + + +class While(Node): + __slots__ = ("cond", "stmt", "coord", "__weakref__") + + def __init__(self, cond, stmt, coord=None): + self.cond = cond + self.stmt = stmt + self.coord = coord + + def children(self): + nodelist = [] + if self.cond is not None: + nodelist.append(("cond", self.cond)) + if self.stmt is not None: + nodelist.append(("stmt", self.stmt)) + return tuple(nodelist) + + def __iter__(self): + if self.cond is not None: + yield self.cond + if self.stmt is not None: + yield self.stmt + + attr_names = () + + +class Pragma(Node): + __slots__ = ("string", "coord", "__weakref__") + + def __init__(self, string, coord=None): + self.string = string + self.coord = coord + + def children(self): + nodelist = [] + return tuple(nodelist) + + def __iter__(self): + return + yield + + attr_names = ("string",) diff --git a/source/target-vendors/cp312/pycparser/c_generator.py b/source/target-vendors/cp312/pycparser/c_generator.py new file mode 100644 index 0000000..424e00e --- /dev/null +++ b/source/target-vendors/cp312/pycparser/c_generator.py @@ -0,0 +1,573 @@ +# ------------------------------------------------------------------------------ +# pycparser: c_generator.py +# +# C code generator from pycparser AST nodes. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ------------------------------------------------------------------------------ +from typing import Callable, List, Optional + +from . import c_ast + + +class CGenerator: + """Uses the same visitor pattern as c_ast.NodeVisitor, but modified to + return a value from each visit method, using string accumulation in + generic_visit. + """ + + indent_level: int + reduce_parentheses: bool + + def __init__(self, reduce_parentheses: bool = False) -> None: + """Constructs C-code generator + + reduce_parentheses: + if True, eliminates needless parentheses on binary operators + """ + # Statements start with indentation of self.indent_level spaces, using + # the _make_indent method. + self.indent_level = 0 + self.reduce_parentheses = reduce_parentheses + + def _make_indent(self) -> str: + return " " * self.indent_level + + def visit(self, node: c_ast.Node) -> str: + method = "visit_" + node.__class__.__name__ + return getattr(self, method, self.generic_visit)(node) + + def generic_visit(self, node: Optional[c_ast.Node]) -> str: + if node is None: + return "" + else: + return "".join(self.visit(c) for c_name, c in node.children()) + + def visit_Constant(self, n: c_ast.Constant) -> str: + return n.value + + def visit_ID(self, n: c_ast.ID) -> str: + return n.name + + def visit_Pragma(self, n: c_ast.Pragma) -> str: + ret = "#pragma" + if n.string: + ret += " " + n.string + return ret + + def visit_ArrayRef(self, n: c_ast.ArrayRef) -> str: + arrref = self._parenthesize_unless_simple(n.name) + return arrref + "[" + self.visit(n.subscript) + "]" + + def visit_StructRef(self, n: c_ast.StructRef) -> str: + sref = self._parenthesize_unless_simple(n.name) + return sref + n.type + self.visit(n.field) + + def visit_FuncCall(self, n: c_ast.FuncCall) -> str: + fref = self._parenthesize_unless_simple(n.name) + args = self.visit(n.args) if n.args is not None else "" + return fref + "(" + args + ")" + + def visit_UnaryOp(self, n: c_ast.UnaryOp) -> str: + match n.op: + case "sizeof": + # Always parenthesize the argument of sizeof since it can be + # a name. + return f"sizeof({self.visit(n.expr)})" + case "p++": + operand = self._parenthesize_unless_simple(n.expr) + return f"{operand}++" + case "p--": + operand = self._parenthesize_unless_simple(n.expr) + return f"{operand}--" + case _: + operand = self._parenthesize_unless_simple(n.expr) + return f"{n.op}{operand}" + + # Precedence map of binary operators: + precedence_map = { + # Should be in sync with c_parser.CParser.precedence + # Higher numbers are stronger binding + "||": 0, # weakest binding + "&&": 1, + "|": 2, + "^": 3, + "&": 4, + "==": 5, + "!=": 5, + ">": 6, + ">=": 6, + "<": 6, + "<=": 6, + ">>": 7, + "<<": 7, + "+": 8, + "-": 8, + "*": 9, + "/": 9, + "%": 9, # strongest binding + } + + def visit_BinaryOp(self, n: c_ast.BinaryOp) -> str: + # Note: all binary operators are left-to-right associative + # + # If `n.left.op` has a stronger or equally binding precedence in + # comparison to `n.op`, no parenthesis are needed for the left: + # e.g., `(a*b) + c` is equivalent to `a*b + c`, as well as + # `(a+b) - c` is equivalent to `a+b - c` (same precedence). + # If the left operator is weaker binding than the current, then + # parentheses are necessary: + # e.g., `(a+b) * c` is NOT equivalent to `a+b * c`. + lval_str = self._parenthesize_if( + n.left, + lambda d: not ( + self._is_simple_node(d) + or self.reduce_parentheses + and isinstance(d, c_ast.BinaryOp) + and self.precedence_map[d.op] >= self.precedence_map[n.op] + ), + ) + # If `n.right.op` has a stronger -but not equal- binding precedence, + # parenthesis can be omitted on the right: + # e.g., `a + (b*c)` is equivalent to `a + b*c`. + # If the right operator is weaker or equally binding, then parentheses + # are necessary: + # e.g., `a * (b+c)` is NOT equivalent to `a * b+c` and + # `a - (b+c)` is NOT equivalent to `a - b+c` (same precedence). + rval_str = self._parenthesize_if( + n.right, + lambda d: not ( + self._is_simple_node(d) + or self.reduce_parentheses + and isinstance(d, c_ast.BinaryOp) + and self.precedence_map[d.op] > self.precedence_map[n.op] + ), + ) + return f"{lval_str} {n.op} {rval_str}" + + def visit_Assignment(self, n: c_ast.Assignment) -> str: + rval_str = self._parenthesize_if( + n.rvalue, lambda n: isinstance(n, c_ast.Assignment) + ) + return f"{self.visit(n.lvalue)} {n.op} {rval_str}" + + def visit_IdentifierType(self, n: c_ast.IdentifierType) -> str: + return " ".join(n.names) + + def _visit_expr(self, n: c_ast.Node) -> str: + match n: + case c_ast.InitList(): + return "{" + self.visit(n) + "}" + case c_ast.ExprList() | c_ast.Compound(): + return "(" + self.visit(n) + ")" + case _: + return self.visit(n) + + def visit_Decl(self, n: c_ast.Decl, no_type: bool = False) -> str: + # no_type is used when a Decl is part of a DeclList, where the type is + # explicitly only for the first declaration in a list. + # + s = n.name if no_type else self._generate_decl(n) + if n.bitsize: + s += " : " + self.visit(n.bitsize) + if n.init: + s += " = " + self._visit_expr(n.init) + return s + + def visit_DeclList(self, n: c_ast.DeclList) -> str: + s = self.visit(n.decls[0]) + if len(n.decls) > 1: + s += ", " + ", ".join( + self.visit_Decl(decl, no_type=True) for decl in n.decls[1:] + ) + return s + + def visit_Typedef(self, n: c_ast.Typedef) -> str: + s = "" + if n.storage: + s += " ".join(n.storage) + " " + s += self._generate_type(n.type) + return s + + def visit_Cast(self, n: c_ast.Cast) -> str: + s = "(" + self._generate_type(n.to_type, emit_declname=False) + ")" + return s + " " + self._parenthesize_unless_simple(n.expr) + + def visit_ExprList(self, n: c_ast.ExprList) -> str: + visited_subexprs = [] + for expr in n.exprs: + visited_subexprs.append(self._visit_expr(expr)) + return ", ".join(visited_subexprs) + + def visit_InitList(self, n: c_ast.InitList) -> str: + visited_subexprs = [] + for expr in n.exprs: + visited_subexprs.append(self._visit_expr(expr)) + return ", ".join(visited_subexprs) + + def visit_Enum(self, n: c_ast.Enum) -> str: + return self._generate_struct_union_enum(n, name="enum") + + def visit_Alignas(self, n: c_ast.Alignas) -> str: + return "_Alignas({})".format(self.visit(n.alignment)) + + def visit_Enumerator(self, n: c_ast.Enumerator) -> str: + if not n.value: + return "{indent}{name},\n".format( + indent=self._make_indent(), + name=n.name, + ) + else: + return "{indent}{name} = {value},\n".format( + indent=self._make_indent(), + name=n.name, + value=self.visit(n.value), + ) + + def visit_FuncDef(self, n: c_ast.FuncDef) -> str: + decl = self.visit(n.decl) + self.indent_level = 0 + body = self.visit(n.body) + if n.param_decls: + knrdecls = ";\n".join(self.visit(p) for p in n.param_decls) + return decl + "\n" + knrdecls + ";\n" + body + "\n" + else: + return decl + "\n" + body + "\n" + + def visit_FileAST(self, n: c_ast.FileAST) -> str: + s = "" + for ext in n.ext: + match ext: + case c_ast.FuncDef(): + s += self.visit(ext) + case c_ast.Pragma(): + s += self.visit(ext) + "\n" + case _: + s += self.visit(ext) + ";\n" + return s + + def visit_Compound(self, n: c_ast.Compound) -> str: + s = self._make_indent() + "{\n" + self.indent_level += 2 + if n.block_items: + s += "".join(self._generate_stmt(stmt) for stmt in n.block_items) + self.indent_level -= 2 + s += self._make_indent() + "}\n" + return s + + def visit_CompoundLiteral(self, n: c_ast.CompoundLiteral) -> str: + return "(" + self.visit(n.type) + "){" + self.visit(n.init) + "}" + + def visit_EmptyStatement(self, n: c_ast.EmptyStatement) -> str: + return ";" + + def visit_ParamList(self, n: c_ast.ParamList) -> str: + return ", ".join(self.visit(param) for param in n.params) + + def visit_Return(self, n: c_ast.Return) -> str: + s = "return" + if n.expr: + s += " " + self.visit(n.expr) + return s + ";" + + def visit_Break(self, n: c_ast.Break) -> str: + return "break;" + + def visit_Continue(self, n: c_ast.Continue) -> str: + return "continue;" + + def visit_TernaryOp(self, n: c_ast.TernaryOp) -> str: + s = "(" + self._visit_expr(n.cond) + ") ? " + s += "(" + self._visit_expr(n.iftrue) + ") : " + s += "(" + self._visit_expr(n.iffalse) + ")" + return s + + def visit_If(self, n: c_ast.If) -> str: + s = "if (" + if n.cond: + s += self.visit(n.cond) + s += ")\n" + s += self._generate_stmt(n.iftrue, add_indent=True) + if n.iffalse: + s += self._make_indent() + "else\n" + s += self._generate_stmt(n.iffalse, add_indent=True) + return s + + def visit_For(self, n: c_ast.For) -> str: + s = "for (" + if n.init: + s += self.visit(n.init) + s += ";" + if n.cond: + s += " " + self.visit(n.cond) + s += ";" + if n.next: + s += " " + self.visit(n.next) + s += ")\n" + s += self._generate_stmt(n.stmt, add_indent=True) + return s + + def visit_While(self, n: c_ast.While) -> str: + s = "while (" + if n.cond: + s += self.visit(n.cond) + s += ")\n" + s += self._generate_stmt(n.stmt, add_indent=True) + return s + + def visit_DoWhile(self, n: c_ast.DoWhile) -> str: + s = "do\n" + s += self._generate_stmt(n.stmt, add_indent=True) + s += self._make_indent() + "while (" + if n.cond: + s += self.visit(n.cond) + s += ");" + return s + + def visit_StaticAssert(self, n: c_ast.StaticAssert) -> str: + s = "_Static_assert(" + s += self.visit(n.cond) + if n.message: + s += "," + s += self.visit(n.message) + s += ")" + return s + + def visit_Switch(self, n: c_ast.Switch) -> str: + s = "switch (" + self.visit(n.cond) + ")\n" + s += self._generate_stmt(n.stmt, add_indent=True) + return s + + def visit_Case(self, n: c_ast.Case) -> str: + s = "case " + self.visit(n.expr) + ":\n" + for stmt in n.stmts: + s += self._generate_stmt(stmt, add_indent=True) + return s + + def visit_Default(self, n: c_ast.Default) -> str: + s = "default:\n" + for stmt in n.stmts: + s += self._generate_stmt(stmt, add_indent=True) + return s + + def visit_Label(self, n: c_ast.Label) -> str: + return n.name + ":\n" + self._generate_stmt(n.stmt) + + def visit_Goto(self, n: c_ast.Goto) -> str: + return "goto " + n.name + ";" + + def visit_EllipsisParam(self, n: c_ast.EllipsisParam) -> str: + return "..." + + def visit_Struct(self, n: c_ast.Struct) -> str: + return self._generate_struct_union_enum(n, "struct") + + def visit_Typename(self, n: c_ast.Typename) -> str: + return self._generate_type(n.type) + + def visit_Union(self, n: c_ast.Union) -> str: + return self._generate_struct_union_enum(n, "union") + + def visit_NamedInitializer(self, n: c_ast.NamedInitializer) -> str: + s = "" + for name in n.name: + if isinstance(name, c_ast.ID): + s += "." + name.name + else: + s += "[" + self.visit(name) + "]" + s += " = " + self._visit_expr(n.expr) + return s + + def visit_FuncDecl(self, n: c_ast.FuncDecl) -> str: + return self._generate_type(n) + + def visit_ArrayDecl(self, n: c_ast.ArrayDecl) -> str: + return self._generate_type(n, emit_declname=False) + + def visit_TypeDecl(self, n: c_ast.TypeDecl) -> str: + return self._generate_type(n, emit_declname=False) + + def visit_PtrDecl(self, n: c_ast.PtrDecl) -> str: + return self._generate_type(n, emit_declname=False) + + def _generate_struct_union_enum( + self, n: c_ast.Struct | c_ast.Union | c_ast.Enum, name: str + ) -> str: + """Generates code for structs, unions, and enums. name should be + 'struct', 'union', or 'enum'. + """ + if name in ("struct", "union"): + assert isinstance(n, (c_ast.Struct, c_ast.Union)) + members = n.decls + body_function = self._generate_struct_union_body + else: + assert name == "enum" + assert isinstance(n, c_ast.Enum) + members = None if n.values is None else n.values.enumerators + body_function = self._generate_enum_body + s = name + " " + (n.name or "") + if members is not None: + # None means no members + # Empty sequence means an empty list of members + s += "\n" + s += self._make_indent() + self.indent_level += 2 + s += "{\n" + s += body_function(members) + self.indent_level -= 2 + s += self._make_indent() + "}" + return s + + def _generate_struct_union_body(self, members: List[c_ast.Node]) -> str: + return "".join(self._generate_stmt(decl) for decl in members) + + def _generate_enum_body(self, members: List[c_ast.Enumerator]) -> str: + # `[:-2] + '\n'` removes the final `,` from the enumerator list + return "".join(self.visit(value) for value in members)[:-2] + "\n" + + def _generate_stmt(self, n: c_ast.Node, add_indent: bool = False) -> str: + """Generation from a statement node. This method exists as a wrapper + for individual visit_* methods to handle different treatment of + some statements in this context. + """ + if add_indent: + self.indent_level += 2 + indent = self._make_indent() + if add_indent: + self.indent_level -= 2 + + match n: + case ( + c_ast.Decl() + | c_ast.Assignment() + | c_ast.Cast() + | c_ast.UnaryOp() + | c_ast.BinaryOp() + | c_ast.TernaryOp() + | c_ast.FuncCall() + | c_ast.ArrayRef() + | c_ast.StructRef() + | c_ast.Constant() + | c_ast.ID() + | c_ast.Typedef() + | c_ast.ExprList() + ): + # These can also appear in an expression context so no semicolon + # is added to them automatically + # + return indent + self.visit(n) + ";\n" + case c_ast.Compound(): + # No extra indentation required before the opening brace of a + # compound - because it consists of multiple lines it has to + # compute its own indentation. + # + return self.visit(n) + case c_ast.If(): + return indent + self.visit(n) + case _: + return indent + self.visit(n) + "\n" + + def _generate_decl(self, n: c_ast.Decl) -> str: + """Generation from a Decl node.""" + s = "" + if n.funcspec: + s = " ".join(n.funcspec) + " " + if n.storage: + s += " ".join(n.storage) + " " + if n.align: + s += self.visit(n.align[0]) + " " + s += self._generate_type(n.type) + return s + + def _generate_type( + self, + n: c_ast.Node, + modifiers: List[c_ast.Node] = [], + emit_declname: bool = True, + ) -> str: + """Recursive generation from a type node. n is the type node. + modifiers collects the PtrDecl, ArrayDecl and FuncDecl modifiers + encountered on the way down to a TypeDecl, to allow proper + generation from it. + """ + # ~ print(n, modifiers) + match n: + case c_ast.TypeDecl(): + s = "" + if n.quals: + s += " ".join(n.quals) + " " + s += self.visit(n.type) + + nstr = n.declname if n.declname and emit_declname else "" + # Resolve modifiers. + # Wrap in parens to distinguish pointer to array and pointer to + # function syntax. + # + for i, modifier in enumerate(modifiers): + match modifier: + case c_ast.ArrayDecl(): + if i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl): + nstr = "(" + nstr + ")" + nstr += "[" + if modifier.dim_quals: + nstr += " ".join(modifier.dim_quals) + " " + if modifier.dim is not None: + nstr += self.visit(modifier.dim) + nstr += "]" + case c_ast.FuncDecl(): + if i != 0 and isinstance(modifiers[i - 1], c_ast.PtrDecl): + nstr = "(" + nstr + ")" + args = ( + self.visit(modifier.args) + if modifier.args is not None + else "" + ) + nstr += "(" + args + ")" + case c_ast.PtrDecl(): + if modifier.quals: + quals = " ".join(modifier.quals) + suffix = f" {nstr}" if nstr else "" + nstr = f"* {quals}{suffix}" + else: + nstr = "*" + nstr + if nstr: + s += " " + nstr + return s + case c_ast.Decl(): + return self._generate_decl(n.type) + case c_ast.Typename(): + return self._generate_type(n.type, emit_declname=emit_declname) + case c_ast.IdentifierType(): + return " ".join(n.names) + " " + case c_ast.ArrayDecl() | c_ast.PtrDecl() | c_ast.FuncDecl(): + return self._generate_type( + n.type, modifiers + [n], emit_declname=emit_declname + ) + case _: + return self.visit(n) + + def _parenthesize_if( + self, n: c_ast.Node, condition: Callable[[c_ast.Node], bool] + ) -> str: + """Visits 'n' and returns its string representation, parenthesized + if the condition function applied to the node returns True. + """ + s = self._visit_expr(n) + if condition(n): + return "(" + s + ")" + else: + return s + + def _parenthesize_unless_simple(self, n: c_ast.Node) -> str: + """Common use case for _parenthesize_if""" + return self._parenthesize_if(n, lambda d: not self._is_simple_node(d)) + + def _is_simple_node(self, n: c_ast.Node) -> bool: + """Returns True for nodes that are "simple" - i.e. nodes that always + have higher precedence than operators. + """ + return isinstance( + n, + (c_ast.Constant, c_ast.ID, c_ast.ArrayRef, c_ast.StructRef, c_ast.FuncCall), + ) diff --git a/source/target-vendors/cp312/pycparser/c_lexer.py b/source/target-vendors/cp312/pycparser/c_lexer.py new file mode 100644 index 0000000..ef59d69 --- /dev/null +++ b/source/target-vendors/cp312/pycparser/c_lexer.py @@ -0,0 +1,706 @@ +# ------------------------------------------------------------------------------ +# pycparser: c_lexer.py +# +# CLexer class: lexer for the C language +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ------------------------------------------------------------------------------ +import re +from dataclasses import dataclass +from enum import Enum +from typing import Callable, Dict, List, Optional, Tuple + + +@dataclass(slots=True) +class _Token: + type: str + value: str + lineno: int + column: int + + +class CLexer: + """A standalone lexer for C. + + Parameters for construction: + error_func: + Called with (msg, line, column) on lexing errors. + on_lbrace_func: + Called when an LBRACE token is produced (used for scope tracking). + on_rbrace_func: + Called when an RBRACE token is produced (used for scope tracking). + type_lookup_func: + Called with an identifier name; expected to return True if it is + a typedef name and should be tokenized as TYPEID. + + Call input(text) to initialize lexing, and then keep calling token() to + get the next token, until it returns None (at end of input). + """ + + def __init__( + self, + error_func: Callable[[str, int, int], None], + on_lbrace_func: Callable[[], None], + on_rbrace_func: Callable[[], None], + type_lookup_func: Callable[[str], bool], + ) -> None: + self.error_func = error_func + self.on_lbrace_func = on_lbrace_func + self.on_rbrace_func = on_rbrace_func + self.type_lookup_func = type_lookup_func + self._init_state() + + def input(self, text: str, filename: str = "") -> None: + """Initialize the lexer to the given input text. + + filename is an optional name identifying the file from which the input + comes. The lexer can modify it if #line directives are encountered. + """ + self._init_state() + self._lexdata = text + self._filename = filename + + def _init_state(self) -> None: + self._lexdata = "" + self._filename = "" + self._pos = 0 + self._line_start = 0 + self._pending_tok: Optional[_Token] = None + self._lineno = 1 + + @property + def filename(self) -> str: + return self._filename + + def token(self) -> Optional[_Token]: + # Lexing strategy overview: + # + # - We maintain a current position (self._pos), line number, and the + # byte offset of the current line start. The lexer is a simple loop + # that skips whitespace/newlines and emits one token per call. + # - A small amount of logic is handled manually before regex matching: + # + # * Preprocessor-style directives: if we see '#', we check whether + # it's a #line or #pragma directive and consume it inline. #line + # updates lineno/filename and produces no tokens. #pragma can yield + # both PPPRAGMA and PPPRAGMASTR, but token() returns a single token, + # so we stash the PPPRAGMASTR as _pending_tok to return on the next + # token() call. Otherwise we return PPHASH. + # * Newlines update lineno/line-start tracking so tokens can record + # accurate columns. + # + # - The bulk of tokens are recognized in _match_token: + # + # * _regex_rules: regex patterns for identifiers, literals, and other + # complex tokens (including error-producing patterns). The lexer + # uses a combined _regex_master to scan options at the same time. + # * _fixed_tokens: exact string matches for operators and punctuation, + # resolved by longest match. + # + # - Error patterns call the error callback and advance minimally, which + # keeps lexing resilient while reporting useful diagnostics. + text = self._lexdata + n = len(text) + + if self._pending_tok is not None: + tok = self._pending_tok + self._pending_tok = None + return tok + + while self._pos < n: + match text[self._pos]: + case " " | "\t": + self._pos += 1 + case "\n": + self._lineno += 1 + self._pos += 1 + self._line_start = self._pos + case "#": + if _line_pattern.match(text, self._pos + 1): + self._pos += 1 + self._handle_ppline() + continue + if _pragma_pattern.match(text, self._pos + 1): + self._pos += 1 + toks = self._handle_pppragma() + if len(toks) > 1: + self._pending_tok = toks[1] + if len(toks) > 0: + return toks[0] + continue + tok = self._make_token("PPHASH", "#", self._pos) + self._pos += 1 + return tok + case _: + if tok := self._match_token(): + return tok + else: + continue + + def _match_token(self) -> Optional[_Token]: + """Match one token at the current position. + + Returns a Token on success, or None if no token could be matched and + an error was reported. This method always advances _pos by the matched + length, or by 1 on error/no-match. + """ + text = self._lexdata + pos = self._pos + # We pick the longest match between: + # - the master regex (identifiers, literals, error patterns, etc.) + # - fixed operator/punctuator literals from the bucket for text[pos] + # + # The longest match is required to ensure we properly lex something + # like ".123" (a floating-point constant) as a single entity (with + # FLOAT_CONST), rather than a PERIOD followed by a number. + # + # The fixed-literal buckets are already length-sorted, so within that + # bucket we can take the first match. However, we still compare its + # length to the regex match because the regex may have matched a longer + # token that should take precedence. + best = None + + if m := _regex_master.match(text, pos): + tok_type = m.lastgroup + # All master-regex alternatives are named; lastgroup shouldn't be None. + assert tok_type is not None + value = m.group(tok_type) + length = len(value) + action, msg = _regex_actions[tok_type] + best = (length, tok_type, value, action, msg) + + if bucket := _fixed_tokens_by_first.get(text[pos]): + for entry in bucket: + if text.startswith(entry.literal, pos): + length = len(entry.literal) + if best is None or length > best[0]: + best = ( + length, + entry.tok_type, + entry.literal, + _RegexAction.TOKEN, + None, + ) + break + + if best is None: + msg = f"Illegal character {repr(text[pos])}" + self._error(msg, pos) + self._pos += 1 + return None + + length, tok_type, value, action, msg = best + if action == _RegexAction.ERROR: + if tok_type == "BAD_CHAR_CONST": + msg = f"Invalid char constant {value}" + # All other ERROR rules provide a message. + assert msg is not None + self._error(msg, pos) + self._pos += max(1, length) + return None + + if action == _RegexAction.ID: + tok_type = _keyword_map.get(value, "ID") + if tok_type == "ID" and self.type_lookup_func(value): + tok_type = "TYPEID" + + tok = self._make_token(tok_type, value, pos) + self._pos += length + + if tok.type == "LBRACE": + self.on_lbrace_func() + elif tok.type == "RBRACE": + self.on_rbrace_func() + + return tok + + def _make_token(self, tok_type: str, value: str, pos: int) -> _Token: + """Create a Token at an absolute input position. + + Expects tok_type/value and the absolute byte offset pos in the current + input. Does not advance lexer state; callers manage _pos themselves. + Returns a Token with lineno/column computed from current line tracking. + """ + column = pos - self._line_start + 1 + tok = _Token(tok_type, value, self._lineno, column) + return tok + + def _error(self, msg: str, pos: int) -> None: + column = pos - self._line_start + 1 + self.error_func(msg, self._lineno, column) + + def _handle_ppline(self) -> None: + # Since #line directives aren't supposed to return tokens but should + # only affect the lexer's state (update line/filename for coords), this + # method does a bit of parsing on its own. It doesn't return anything, + # but its side effect is to update self._pos past the directive, and + # potentially update self._lineno and self._filename, based on the + # directive's contents. + # + # Accepted #line forms from preprocessors: + # - "#line 66 \"kwas\\df.h\"" + # - "# 9" + # - "#line 10 \"include/me.h\" 1 2 3" (extra numeric flags) + # - "# 1 \"file.h\" 3" + # Errors we must report: + # - "#line \"file.h\"" (filename before line number) + # - "#line df" (garbage instead of number/string) + # + # We scan the directive line once (after an optional 'line' keyword), + # validating the order: NUMBER, optional STRING, then any NUMBERs. + # The NUMBERs tail is only accepted if a filename STRING was present. + text = self._lexdata + n = len(text) + line_end = text.find("\n", self._pos) + if line_end == -1: + line_end = n + line = text[self._pos : line_end] + pos = 0 + line_len = len(line) + + def skip_ws() -> None: + nonlocal pos + while pos < line_len and line[pos] in " \t": + pos += 1 + + skip_ws() + if line.startswith("line", pos): + pos += 4 + + def success(pp_line: Optional[str], pp_filename: Optional[str]) -> None: + if pp_line is None: + self._error("line number missing in #line", self._pos + line_len) + else: + self._lineno = int(pp_line) + if pp_filename is not None: + self._filename = pp_filename + self._pos = line_end + 1 + self._line_start = self._pos + + def fail(msg: str, offset: int) -> None: + self._error(msg, self._pos + offset) + self._pos = line_end + 1 + self._line_start = self._pos + + skip_ws() + if pos >= line_len: + success(None, None) + return + if line[pos] == '"': + fail("filename before line number in #line", pos) + return + + m = re.match(_decimal_constant, line[pos:]) + if not m: + fail("invalid #line directive", pos) + return + + pp_line = m.group(0) + pos += len(pp_line) + skip_ws() + if pos >= line_len: + success(pp_line, None) + return + + if line[pos] != '"': + fail("invalid #line directive", pos) + return + + m = re.match(_string_literal, line[pos:]) + if not m: + fail("invalid #line directive", pos) + return + + pp_filename = m.group(0).lstrip('"').rstrip('"') + pos += len(m.group(0)) + + # Consume arbitrary sequence of numeric flags after the directive + while True: + skip_ws() + if pos >= line_len: + break + m = re.match(_decimal_constant, line[pos:]) + if not m: + fail("invalid #line directive", pos) + return + pos += len(m.group(0)) + + success(pp_line, pp_filename) + + def _handle_pppragma(self) -> List[_Token]: + # Parse a full #pragma line; returns a list of tokens with 1 or 2 + # tokens - PPPRAGMA and an optional PPPRAGMASTR. If an empty list is + # returned, it means an error occurred, or we're at the end of input. + # + # Examples: + # - "#pragma" -> PPPRAGMA only + # - "#pragma once" -> PPPRAGMA, PPPRAGMASTR("once") + # - "# pragma omp parallel private(th_id)" -> PPPRAGMA, PPPRAGMASTR("omp parallel private(th_id)") + # - "#\tpragma {pack: 2, smack: 3}" -> PPPRAGMA, PPPRAGMASTR("{pack: 2, smack: 3}") + text = self._lexdata + n = len(text) + pos = self._pos + + while pos < n and text[pos] in " \t": + pos += 1 + if pos >= n: + self._pos = pos + return [] + + if not text.startswith("pragma", pos): + self._error("invalid #pragma directive", pos) + self._pos = pos + 1 + return [] + + pragma_pos = pos + pos += len("pragma") + toks = [self._make_token("PPPRAGMA", "pragma", pragma_pos)] + + while pos < n and text[pos] in " \t": + pos += 1 + + start = pos + while pos < n and text[pos] != "\n": + pos += 1 + if pos > start: + toks.append(self._make_token("PPPRAGMASTR", text[start:pos], start)) + if pos < n and text[pos] == "\n": + self._lineno += 1 + pos += 1 + self._line_start = pos + self._pos = pos + return toks + + +## +## Reserved keywords +## +_keywords: Tuple[str, ...] = ( + "AUTO", + "BREAK", + "CASE", + "CHAR", + "CONST", + "CONTINUE", + "DEFAULT", + "DO", + "DOUBLE", + "ELSE", + "ENUM", + "EXTERN", + "FLOAT", + "FOR", + "GOTO", + "IF", + "INLINE", + "INT", + "LONG", + "REGISTER", + "OFFSETOF", + "RESTRICT", + "RETURN", + "SHORT", + "SIGNED", + "SIZEOF", + "STATIC", + "STRUCT", + "SWITCH", + "TYPEDEF", + "UNION", + "UNSIGNED", + "VOID", + "VOLATILE", + "WHILE", + "__INT128", + "_BOOL", + "_COMPLEX", + "_NORETURN", + "_THREAD_LOCAL", + "_STATIC_ASSERT", + "_ATOMIC", + "_ALIGNOF", + "_ALIGNAS", + "_PRAGMA", +) + +_keyword_map: Dict[str, str] = {} + +for keyword in _keywords: + # Keywords from new C standard are mixed-case, like _Bool, _Alignas, etc. + if keyword.startswith("_") and len(keyword) > 1 and keyword[1].isalpha(): + _keyword_map[keyword[:2].upper() + keyword[2:].lower()] = keyword + else: + _keyword_map[keyword.lower()] = keyword + +## +## Regexes for use in tokens +## + +# valid C identifiers (K&R2: A.2.3), plus '$' (supported by some compilers) +_identifier = r"[a-zA-Z_$][0-9a-zA-Z_$]*" + +_hex_prefix = "0[xX]" +_hex_digits = "[0-9a-fA-F]+" +_bin_prefix = "0[bB]" +_bin_digits = "[01]+" + +# integer constants (K&R2: A.2.5.1) +_integer_suffix_opt = ( + r"(([uU]ll)|([uU]LL)|(ll[uU]?)|(LL[uU]?)|([uU][lL])|([lL][uU]?)|[uU])?" +) +_decimal_constant = ( + "(0" + _integer_suffix_opt + ")|([1-9][0-9]*" + _integer_suffix_opt + ")" +) +_octal_constant = "0[0-7]*" + _integer_suffix_opt +_hex_constant = _hex_prefix + _hex_digits + _integer_suffix_opt +_bin_constant = _bin_prefix + _bin_digits + _integer_suffix_opt + +_bad_octal_constant = "0[0-7]*[89]" + +# comments are not supported +_unsupported_c_style_comment = r"\/\*" +_unsupported_cxx_style_comment = r"\/\/" + +# character constants (K&R2: A.2.5.2) +# Note: a-zA-Z and '.-~^_!=&;,' are allowed as escape chars to support #line +# directives with Windows paths as filenames (..\..\dir\file) +# For the same reason, decimal_escape allows all digit sequences. We want to +# parse all correct code, even if it means to sometimes parse incorrect +# code. +# +# The original regexes were taken verbatim from the C syntax definition, +# and were later modified to avoid worst-case exponential running time. +# +# simple_escape = r"""([a-zA-Z._~!=&\^\-\\?'"])""" +# decimal_escape = r"""(\d+)""" +# hex_escape = r"""(x[0-9a-fA-F]+)""" +# bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-7])""" +# +# The following modifications were made to avoid the ambiguity that allowed +# backtracking: (https://github.com/eliben/pycparser/issues/61) +# +# - \x was removed from simple_escape, unless it was not followed by a hex +# digit, to avoid ambiguity with hex_escape. +# - hex_escape allows one or more hex characters, but requires that the next +# character(if any) is not hex +# - decimal_escape allows one or more decimal characters, but requires that the +# next character(if any) is not a decimal +# - bad_escape does not allow any decimals (8-9), to avoid conflicting with the +# permissive decimal_escape. +# +# Without this change, python's `re` module would recursively try parsing each +# ambiguous escape sequence in multiple ways. e.g. `\123` could be parsed as +# `\1`+`23`, `\12`+`3`, and `\123`. + +_simple_escape = r"""([a-wyzA-Z._~!=&\^\-\\?'"]|x(?![0-9a-fA-F]))""" +_decimal_escape = r"""(\d+)(?!\d)""" +_hex_escape = r"""(x[0-9a-fA-F]+)(?![0-9a-fA-F])""" +_bad_escape = r"""([\\][^a-zA-Z._~^!=&\^\-\\?'"x0-9])""" + +_escape_sequence = ( + r"""(\\(""" + _simple_escape + "|" + _decimal_escape + "|" + _hex_escape + "))" +) + +# This complicated regex with lookahead might be slow for strings, so because +# all of the valid escapes (including \x) allowed +# 0 or more non-escaped characters after the first character, +# simple_escape+decimal_escape+hex_escape got simplified to + +_escape_sequence_start_in_string = r"""(\\[0-9a-zA-Z._~!=&\^\-\\?'"])""" + +_cconst_char = r"""([^'\\\n]|""" + _escape_sequence + ")" +_char_const = "'" + _cconst_char + "'" +_wchar_const = "L" + _char_const +_u8char_const = "u8" + _char_const +_u16char_const = "u" + _char_const +_u32char_const = "U" + _char_const +_multicharacter_constant = "'" + _cconst_char + "{2,4}'" +_unmatched_quote = "('" + _cconst_char + "*\\n)|('" + _cconst_char + "*$)" +_bad_char_const = ( + r"""('""" + _cconst_char + """[^'\n]+')|('')|('""" + _bad_escape + r"""[^'\n]*')""" +) + +# string literals (K&R2: A.2.6) +_string_char = r"""([^"\\\n]|""" + _escape_sequence_start_in_string + ")" +_string_literal = '"' + _string_char + '*"' +_wstring_literal = "L" + _string_literal +_u8string_literal = "u8" + _string_literal +_u16string_literal = "u" + _string_literal +_u32string_literal = "U" + _string_literal +_bad_string_literal = '"' + _string_char + "*" + _bad_escape + _string_char + '*"' + +# floating constants (K&R2: A.2.5.3) +_exponent_part = r"""([eE][-+]?[0-9]+)""" +_fractional_constant = r"""([0-9]*\.[0-9]+)|([0-9]+\.)""" +_floating_constant = ( + "((((" + + _fractional_constant + + ")" + + _exponent_part + + "?)|([0-9]+" + + _exponent_part + + "))[FfLl]?)" +) +_binary_exponent_part = r"""([pP][+-]?[0-9]+)""" +_hex_fractional_constant = ( + "(((" + _hex_digits + r""")?\.""" + _hex_digits + ")|(" + _hex_digits + r"""\.))""" +) +_hex_floating_constant = ( + "(" + + _hex_prefix + + "(" + + _hex_digits + + "|" + + _hex_fractional_constant + + ")" + + _binary_exponent_part + + "[FfLl]?)" +) + + +class _RegexAction(Enum): + TOKEN = 0 + ID = 1 + ERROR = 2 + + +@dataclass(frozen=True) +class _RegexRule: + # tok_type: name of the token emitted for a match + # regex_pattern: the raw regex (no anchors) to match at the current position + # action: TOKEN for normal tokens, ID for identifiers, ERROR to report + # error_message: message used for ERROR entries + tok_type: str + regex_pattern: str + action: _RegexAction + error_message: Optional[str] + + +_regex_rules: List[_RegexRule] = [ + _RegexRule( + "UNSUPPORTED_C_STYLE_COMMENT", + _unsupported_c_style_comment, + _RegexAction.ERROR, + "Comments are not supported, see https://github.com/eliben/pycparser#3using.", + ), + _RegexRule( + "UNSUPPORTED_CXX_STYLE_COMMENT", + _unsupported_cxx_style_comment, + _RegexAction.ERROR, + "Comments are not supported, see https://github.com/eliben/pycparser#3using.", + ), + _RegexRule( + "BAD_STRING_LITERAL", + _bad_string_literal, + _RegexAction.ERROR, + "String contains invalid escape code", + ), + _RegexRule("WSTRING_LITERAL", _wstring_literal, _RegexAction.TOKEN, None), + _RegexRule("U8STRING_LITERAL", _u8string_literal, _RegexAction.TOKEN, None), + _RegexRule("U16STRING_LITERAL", _u16string_literal, _RegexAction.TOKEN, None), + _RegexRule("U32STRING_LITERAL", _u32string_literal, _RegexAction.TOKEN, None), + _RegexRule("STRING_LITERAL", _string_literal, _RegexAction.TOKEN, None), + _RegexRule("HEX_FLOAT_CONST", _hex_floating_constant, _RegexAction.TOKEN, None), + _RegexRule("FLOAT_CONST", _floating_constant, _RegexAction.TOKEN, None), + _RegexRule("INT_CONST_HEX", _hex_constant, _RegexAction.TOKEN, None), + _RegexRule("INT_CONST_BIN", _bin_constant, _RegexAction.TOKEN, None), + _RegexRule( + "BAD_CONST_OCT", + _bad_octal_constant, + _RegexAction.ERROR, + "Invalid octal constant", + ), + _RegexRule("INT_CONST_OCT", _octal_constant, _RegexAction.TOKEN, None), + _RegexRule("INT_CONST_DEC", _decimal_constant, _RegexAction.TOKEN, None), + _RegexRule("INT_CONST_CHAR", _multicharacter_constant, _RegexAction.TOKEN, None), + _RegexRule("CHAR_CONST", _char_const, _RegexAction.TOKEN, None), + _RegexRule("WCHAR_CONST", _wchar_const, _RegexAction.TOKEN, None), + _RegexRule("U8CHAR_CONST", _u8char_const, _RegexAction.TOKEN, None), + _RegexRule("U16CHAR_CONST", _u16char_const, _RegexAction.TOKEN, None), + _RegexRule("U32CHAR_CONST", _u32char_const, _RegexAction.TOKEN, None), + _RegexRule("UNMATCHED_QUOTE", _unmatched_quote, _RegexAction.ERROR, "Unmatched '"), + _RegexRule("BAD_CHAR_CONST", _bad_char_const, _RegexAction.ERROR, None), + _RegexRule("ID", _identifier, _RegexAction.ID, None), +] + +_regex_actions: Dict[str, Tuple[_RegexAction, Optional[str]]] = {} +_regex_pattern_parts: List[str] = [] +for _rule in _regex_rules: + _regex_actions[_rule.tok_type] = (_rule.action, _rule.error_message) + _regex_pattern_parts.append(f"(?P<{_rule.tok_type}>{_rule.regex_pattern})") +# The master regex is a single alternation of all token patterns, each wrapped +# in a named group. We match once at the current position and then use +# `lastgroup` to recover which token kind fired; this avoids iterating over all +# regexes on every character while keeping the same token-level semantics. +_regex_master: re.Pattern[str] = re.compile("|".join(_regex_pattern_parts)) + + +@dataclass(frozen=True) +class _FixedToken: + tok_type: str + literal: str + + +_fixed_tokens: List[_FixedToken] = [ + _FixedToken("ELLIPSIS", "..."), + _FixedToken("LSHIFTEQUAL", "<<="), + _FixedToken("RSHIFTEQUAL", ">>="), + _FixedToken("PLUSPLUS", "++"), + _FixedToken("MINUSMINUS", "--"), + _FixedToken("ARROW", "->"), + _FixedToken("LAND", "&&"), + _FixedToken("LOR", "||"), + _FixedToken("LSHIFT", "<<"), + _FixedToken("RSHIFT", ">>"), + _FixedToken("LE", "<="), + _FixedToken("GE", ">="), + _FixedToken("EQ", "=="), + _FixedToken("NE", "!="), + _FixedToken("TIMESEQUAL", "*="), + _FixedToken("DIVEQUAL", "/="), + _FixedToken("MODEQUAL", "%="), + _FixedToken("PLUSEQUAL", "+="), + _FixedToken("MINUSEQUAL", "-="), + _FixedToken("ANDEQUAL", "&="), + _FixedToken("OREQUAL", "|="), + _FixedToken("XOREQUAL", "^="), + _FixedToken("EQUALS", "="), + _FixedToken("PLUS", "+"), + _FixedToken("MINUS", "-"), + _FixedToken("TIMES", "*"), + _FixedToken("DIVIDE", "/"), + _FixedToken("MOD", "%"), + _FixedToken("OR", "|"), + _FixedToken("AND", "&"), + _FixedToken("NOT", "~"), + _FixedToken("XOR", "^"), + _FixedToken("LNOT", "!"), + _FixedToken("LT", "<"), + _FixedToken("GT", ">"), + _FixedToken("CONDOP", "?"), + _FixedToken("LPAREN", "("), + _FixedToken("RPAREN", ")"), + _FixedToken("LBRACKET", "["), + _FixedToken("RBRACKET", "]"), + _FixedToken("LBRACE", "{"), + _FixedToken("RBRACE", "}"), + _FixedToken("COMMA", ","), + _FixedToken("PERIOD", "."), + _FixedToken("SEMI", ";"), + _FixedToken("COLON", ":"), +] + +# To avoid scanning all fixed tokens on every character, we bucket them by the +# first character. When matching at position i, we only look at the bucket for +# text[i], and we pre-sort that bucket by token length so the first match is +# also the longest. This preserves longest-match semantics (e.g. '>>=' before +# '>>' before '>') while reducing the number of comparisons. +_fixed_tokens_by_first: Dict[str, List[_FixedToken]] = {} +for _entry in _fixed_tokens: + _fixed_tokens_by_first.setdefault(_entry.literal[0], []).append(_entry) +for _bucket in _fixed_tokens_by_first.values(): + _bucket.sort(key=lambda item: len(item.literal), reverse=True) + +_line_pattern: re.Pattern[str] = re.compile(r"([ \t]*line\W)|([ \t]*\d+)") +_pragma_pattern: re.Pattern[str] = re.compile(r"[ \t]*pragma\W") diff --git a/source/target-vendors/cp312/pycparser/c_parser.py b/source/target-vendors/cp312/pycparser/c_parser.py new file mode 100644 index 0000000..f980672 --- /dev/null +++ b/source/target-vendors/cp312/pycparser/c_parser.py @@ -0,0 +1,2376 @@ +# ------------------------------------------------------------------------------ +# pycparser: c_parser.py +# +# Recursive-descent parser for the C language. +# +# Eli Bendersky [https://eli.thegreenplace.net/] +# License: BSD +# ------------------------------------------------------------------------------ +from dataclasses import dataclass +from typing import ( + Any, + Dict, + List, + Literal, + NoReturn, + Optional, + Tuple, + TypedDict, + cast, +) + +from . import c_ast +from .c_lexer import CLexer, _Token +from .ast_transforms import fix_switch_cases, fix_atomic_specifiers + + +@dataclass +class Coord: + """Coordinates of a syntactic element. Consists of: + - File name + - Line number + - Column number + """ + + file: str + line: int + column: Optional[int] = None + + def __str__(self) -> str: + text = f"{self.file}:{self.line}" + if self.column: + text += f":{self.column}" + return text + + +class ParseError(Exception): + pass + + +class CParser: + """Recursive-descent C parser. + + Usage: + parser = CParser() + ast = parser.parse(text, filename) + + The `lexer` parameter lets you inject a lexer class (defaults to CLexer). + The parameters after `lexer` are accepted for backward compatibility with + the old PLY-based parser and are otherwise unused. + """ + + def __init__( + self, + lex_optimize: bool = True, + lexer: type[CLexer] = CLexer, + lextab: str = "pycparser.lextab", + yacc_optimize: bool = True, + yacctab: str = "pycparser.yacctab", + yacc_debug: bool = False, + taboutputdir: str = "", + ) -> None: + self.clex: CLexer = lexer( + error_func=self._lex_error_func, + on_lbrace_func=self._lex_on_lbrace_func, + on_rbrace_func=self._lex_on_rbrace_func, + type_lookup_func=self._lex_type_lookup_func, + ) + + # Stack of scopes for keeping track of symbols. _scope_stack[-1] is + # the current (topmost) scope. Each scope is a dictionary that + # specifies whether a name is a type. If _scope_stack[n][name] is + # True, 'name' is currently a type in the scope. If it's False, + # 'name' is used in the scope but not as a type (for instance, if we + # saw: int name; + # If 'name' is not a key in _scope_stack[n] then 'name' was not defined + # in this scope at all. + self._scope_stack: List[Dict[str, bool]] = [dict()] + self._tokens: _TokenStream = _TokenStream(self.clex) + + def parse( + self, text: str, filename: str = "", debug: bool = False + ) -> c_ast.FileAST: + """Parses C code and returns an AST. + + text: + A string containing the C source code + + filename: + Name of the file being parsed (for meaningful + error messages) + + debug: + Deprecated debug flag (unused); for backwards compatibility. + """ + self._scope_stack = [dict()] + self.clex.input(text, filename) + self._tokens = _TokenStream(self.clex) + + ast = self._parse_translation_unit_or_empty() + tok = self._peek() + if tok is not None: + self._parse_error(f"before: {tok.value}", self._tok_coord(tok)) + return ast + + # ------------------------------------------------------------------ + # Scope and declaration helpers + # ------------------------------------------------------------------ + def _coord(self, lineno: int, column: Optional[int] = None) -> Coord: + return Coord(file=self.clex.filename, line=lineno, column=column) + + def _parse_error(self, msg: str, coord: Coord | str | None) -> NoReturn: + raise ParseError(f"{coord}: {msg}") + + def _push_scope(self) -> None: + self._scope_stack.append(dict()) + + def _pop_scope(self) -> None: + assert len(self._scope_stack) > 1 + self._scope_stack.pop() + + def _add_typedef_name(self, name: str, coord: Optional[Coord]) -> None: + """Add a new typedef name (ie a TYPEID) to the current scope""" + if not self._scope_stack[-1].get(name, True): + self._parse_error( + f"Typedef {name!r} previously declared as non-typedef in this scope", + coord, + ) + self._scope_stack[-1][name] = True + + def _add_identifier(self, name: str, coord: Optional[Coord]) -> None: + """Add a new object, function, or enum member name (ie an ID) to the + current scope + """ + if self._scope_stack[-1].get(name, False): + self._parse_error( + f"Non-typedef {name!r} previously declared as typedef in this scope", + coord, + ) + self._scope_stack[-1][name] = False + + def _is_type_in_scope(self, name: str) -> bool: + """Is *name* a typedef-name in the current scope?""" + for scope in reversed(self._scope_stack): + # If name is an identifier in this scope it shadows typedefs in + # higher scopes. + in_scope = scope.get(name) + if in_scope is not None: + return in_scope + return False + + def _lex_error_func(self, msg: str, line: int, column: int) -> None: + self._parse_error(msg, self._coord(line, column)) + + def _lex_on_lbrace_func(self) -> None: + self._push_scope() + + def _lex_on_rbrace_func(self) -> None: + self._pop_scope() + + def _lex_type_lookup_func(self, name: str) -> bool: + """Looks up types that were previously defined with + typedef. + Passed to the lexer for recognizing identifiers that + are types. + """ + return self._is_type_in_scope(name) + + # To understand what's going on here, read sections A.8.5 and + # A.8.6 of K&R2 very carefully. + # + # A C type consists of a basic type declaration, with a list + # of modifiers. For example: + # + # int *c[5]; + # + # The basic declaration here is 'int c', and the pointer and + # the array are the modifiers. + # + # Basic declarations are represented by TypeDecl (from module c_ast) and the + # modifiers are FuncDecl, PtrDecl and ArrayDecl. + # + # The standard states that whenever a new modifier is parsed, it should be + # added to the end of the list of modifiers. For example: + # + # K&R2 A.8.6.2: Array Declarators + # + # In a declaration T D where D has the form + # D1 [constant-expression-opt] + # and the type of the identifier in the declaration T D1 is + # "type-modifier T", the type of the + # identifier of D is "type-modifier array of T" + # + # This is what this method does. The declarator it receives + # can be a list of declarators ending with TypeDecl. It + # tacks the modifier to the end of this list, just before + # the TypeDecl. + # + # Additionally, the modifier may be a list itself. This is + # useful for pointers, that can come as a chain from the rule + # p_pointer. In this case, the whole modifier list is spliced + # into the new location. + def _type_modify_decl(self, decl: Any, modifier: Any) -> c_ast.Node: + """Tacks a type modifier on a declarator, and returns + the modified declarator. + + Note: the declarator and modifier may be modified + """ + modifier_head = modifier + modifier_tail = modifier + + # The modifier may be a nested list. Reach its tail. + while modifier_tail.type: + modifier_tail = modifier_tail.type + + # If the decl is a basic type, just tack the modifier onto it. + if isinstance(decl, c_ast.TypeDecl): + modifier_tail.type = decl + return modifier + else: + # Otherwise, the decl is a list of modifiers. Reach + # its tail and splice the modifier onto the tail, + # pointing to the underlying basic type. + decl_tail = decl + while not isinstance(decl_tail.type, c_ast.TypeDecl): + decl_tail = decl_tail.type + + modifier_tail.type = decl_tail.type + decl_tail.type = modifier_head + return decl + + # Due to the order in which declarators are constructed, + # they have to be fixed in order to look like a normal AST. + # + # When a declaration arrives from syntax construction, it has + # these problems: + # * The innermost TypeDecl has no type (because the basic + # type is only known at the uppermost declaration level) + # * The declaration has no variable name, since that is saved + # in the innermost TypeDecl + # * The typename of the declaration is a list of type + # specifiers, and not a node. Here, basic identifier types + # should be separated from more complex types like enums + # and structs. + # + # This method fixes these problems. + def _fix_decl_name_type( + self, + decl: c_ast.Decl | c_ast.Typedef | c_ast.Typename, + typename: List[Any], + ) -> c_ast.Decl | c_ast.Typedef | c_ast.Typename: + """Fixes a declaration. Modifies decl.""" + # Reach the underlying basic type + typ = decl + while not isinstance(typ, c_ast.TypeDecl): + typ = typ.type + + decl.name = typ.declname + typ.quals = decl.quals[:] + + # The typename is a list of types. If any type in this + # list isn't an IdentifierType, it must be the only + # type in the list (it's illegal to declare "int enum ..") + # If all the types are basic, they're collected in the + # IdentifierType holder. + for tn in typename: + if not isinstance(tn, c_ast.IdentifierType): + if len(typename) > 1: + self._parse_error("Invalid multiple types specified", tn.coord) + else: + typ.type = tn + return decl + + if not typename: + # Functions default to returning int + if not isinstance(decl.type, c_ast.FuncDecl): + self._parse_error("Missing type in declaration", decl.coord) + typ.type = c_ast.IdentifierType(["int"], coord=decl.coord) + else: + # At this point, we know that typename is a list of IdentifierType + # nodes. Concatenate all the names into a single list. + typ.type = c_ast.IdentifierType( + [name for id in typename for name in id.names], coord=typename[0].coord + ) + return decl + + def _add_declaration_specifier( + self, + declspec: Optional["_DeclSpec"], + newspec: Any, + kind: "_DeclSpecKind", + append: bool = False, + ) -> "_DeclSpec": + """See _DeclSpec for the specifier dictionary layout.""" + if declspec is None: + spec: _DeclSpec = dict( + qual=[], storage=[], type=[], function=[], alignment=[] + ) + else: + spec = declspec + + if append: + spec[kind].append(newspec) + else: + spec[kind].insert(0, newspec) + + return spec + + def _build_declarations( + self, + spec: "_DeclSpec", + decls: List["_DeclInfo"], + typedef_namespace: bool = False, + ) -> List[c_ast.Node]: + """Builds a list of declarations all sharing the given specifiers. + If typedef_namespace is true, each declared name is added + to the "typedef namespace", which also includes objects, + functions, and enum constants. + """ + is_typedef = "typedef" in spec["storage"] + declarations = [] + + # Bit-fields are allowed to be unnamed. + if decls[0].get("bitsize") is None: + # When redeclaring typedef names as identifiers in inner scopes, a + # problem can occur where the identifier gets grouped into + # spec['type'], leaving decl as None. This can only occur for the + # first declarator. + if decls[0]["decl"] is None: + if ( + len(spec["type"]) < 2 + or len(spec["type"][-1].names) != 1 + or not self._is_type_in_scope(spec["type"][-1].names[0]) + ): + coord = "?" + for t in spec["type"]: + if hasattr(t, "coord"): + coord = t.coord + break + self._parse_error("Invalid declaration", coord) + + # Make this look as if it came from "direct_declarator:ID" + decls[0]["decl"] = c_ast.TypeDecl( + declname=spec["type"][-1].names[0], + type=None, + quals=None, + align=spec["alignment"], + coord=spec["type"][-1].coord, + ) + # Remove the "new" type's name from the end of spec['type'] + del spec["type"][-1] + # A similar problem can occur where the declaration ends up + # looking like an abstract declarator. Give it a name if this is + # the case. + elif not isinstance( + decls[0]["decl"], + (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType), + ): + decls_0_tail = cast(Any, decls[0]["decl"]) + while not isinstance(decls_0_tail, c_ast.TypeDecl): + decls_0_tail = decls_0_tail.type + if decls_0_tail.declname is None: + decls_0_tail.declname = spec["type"][-1].names[0] + del spec["type"][-1] + + for decl in decls: + assert decl["decl"] is not None + if is_typedef: + declaration = c_ast.Typedef( + name=None, + quals=spec["qual"], + storage=spec["storage"], + type=decl["decl"], + coord=decl["decl"].coord, + ) + else: + declaration = c_ast.Decl( + name=None, + quals=spec["qual"], + align=spec["alignment"], + storage=spec["storage"], + funcspec=spec["function"], + type=decl["decl"], + init=decl.get("init"), + bitsize=decl.get("bitsize"), + coord=decl["decl"].coord, + ) + + if isinstance( + declaration.type, + (c_ast.Enum, c_ast.Struct, c_ast.Union, c_ast.IdentifierType), + ): + fixed_decl = declaration + else: + fixed_decl = self._fix_decl_name_type(declaration, spec["type"]) + + # Add the type name defined by typedef to a + # symbol table (for usage in the lexer) + if typedef_namespace: + if is_typedef: + self._add_typedef_name(fixed_decl.name, fixed_decl.coord) + else: + self._add_identifier(fixed_decl.name, fixed_decl.coord) + + fixed_decl = fix_atomic_specifiers( + cast(c_ast.Decl | c_ast.Typedef, fixed_decl) + ) + declarations.append(fixed_decl) + + return declarations + + def _build_function_definition( + self, + spec: "_DeclSpec", + decl: c_ast.Node, + param_decls: Optional[List[c_ast.Node]], + body: c_ast.Node, + ) -> c_ast.Node: + """Builds a function definition.""" + if "typedef" in spec["storage"]: + self._parse_error("Invalid typedef", decl.coord) + + declaration = self._build_declarations( + spec=spec, + decls=[dict(decl=decl, init=None, bitsize=None)], + typedef_namespace=True, + )[0] + + return c_ast.FuncDef( + decl=declaration, param_decls=param_decls, body=body, coord=decl.coord + ) + + def _select_struct_union_class(self, token: str) -> type: + """Given a token (either STRUCT or UNION), selects the + appropriate AST class. + """ + if token == "struct": + return c_ast.Struct + else: + return c_ast.Union + + # ------------------------------------------------------------------ + # Token helpers + # ------------------------------------------------------------------ + def _peek(self, k: int = 1) -> Optional[_Token]: + """Return the k-th next token without consuming it (1-based).""" + return self._tokens.peek(k) + + def _peek_type(self, k: int = 1) -> Optional[str]: + """Return the type of the k-th next token, or None if absent (1-based).""" + tok = self._peek(k) + return tok.type if tok is not None else None + + def _advance(self) -> _Token: + tok = self._tokens.next() + if tok is None: + self._parse_error("At end of input", self.clex.filename) + else: + return tok + + def _accept(self, token_type: str) -> Optional[_Token]: + """Conditionally consume next token, only if it's of token_type. + + If it is of the expected type, consume and return it. + Otherwise, leaves the token intact and returns None. + """ + tok = self._peek() + if tok is not None and tok.type == token_type: + return self._advance() + return None + + def _expect(self, token_type: str) -> _Token: + tok = self._advance() + if tok.type != token_type: + self._parse_error(f"before: {tok.value}", self._tok_coord(tok)) + return tok + + def _mark(self) -> int: + return self._tokens.mark() + + def _reset(self, mark: int) -> None: + self._tokens.reset(mark) + + def _tok_coord(self, tok: _Token) -> Coord: + return self._coord(tok.lineno, tok.column) + + def _starts_declaration(self, tok: Optional[_Token] = None) -> bool: + tok = tok or self._peek() + if tok is None: + return False + return tok.type in _DECL_START + + def _starts_expression(self, tok: Optional[_Token] = None) -> bool: + tok = tok or self._peek() + if tok is None: + return False + return tok.type in _STARTS_EXPRESSION + + def _starts_statement(self) -> bool: + tok_type = self._peek_type() + if tok_type is None: + return False + if tok_type in _STARTS_STATEMENT: + return True + return self._starts_expression() + + def _starts_declarator(self, id_only: bool = False) -> bool: + tok_type = self._peek_type() + if tok_type is None: + return False + if tok_type in {"TIMES", "LPAREN"}: + return True + if id_only: + return tok_type == "ID" + return tok_type in {"ID", "TYPEID"} + + def _peek_declarator_name_info(self) -> Tuple[Optional[str], bool]: + mark = self._mark() + tok_type, saw_paren = self._scan_declarator_name_info() + self._reset(mark) + return tok_type, saw_paren + + def _parse_any_declarator( + self, allow_abstract: bool = False, typeid_paren_as_abstract: bool = False + ) -> Tuple[Optional[c_ast.Node], bool]: + # C declarators are ambiguous without lookahead. For example: + # int foo(int (aa)); -> aa is a name (ID) + # typedef char TT; + # int bar(int (TT)); -> TT is a type (TYPEID) in parens + name_type, saw_paren = self._peek_declarator_name_info() + if name_type is None or ( + typeid_paren_as_abstract and name_type == "TYPEID" and saw_paren + ): + if not allow_abstract: + tok = self._peek() + coord = self._tok_coord(tok) if tok is not None else self.clex.filename + self._parse_error("Invalid declarator", coord) + decl = self._parse_abstract_declarator_opt() + return decl, False + + if name_type == "TYPEID": + if typeid_paren_as_abstract: + decl = self._parse_typeid_noparen_declarator() + else: + decl = self._parse_typeid_declarator() + else: + decl = self._parse_id_declarator() + return decl, True + + def _scan_declarator_name_info(self) -> Tuple[Optional[str], bool]: + saw_paren = False + while self._accept("TIMES"): + while self._peek_type() in _TYPE_QUALIFIER: + self._advance() + + tok = self._peek() + if tok is None: + return None, saw_paren + if tok.type in {"ID", "TYPEID"}: + self._advance() + return tok.type, saw_paren + if tok.type == "LPAREN": + saw_paren = True + self._advance() + tok_type, nested_paren = self._scan_declarator_name_info() + if nested_paren: + saw_paren = True + depth = 1 + while True: + tok = self._peek() + if tok is None: + return None, saw_paren + if tok.type == "LPAREN": + depth += 1 + elif tok.type == "RPAREN": + depth -= 1 + self._advance() + if depth == 0: + break + continue + self._advance() + return tok_type, saw_paren + return None, saw_paren + + def _starts_direct_abstract_declarator(self) -> bool: + return self._peek_type() in {"LPAREN", "LBRACKET"} + + def _is_assignment_op(self) -> bool: + tok = self._peek() + return tok is not None and tok.type in _ASSIGNMENT_OPS + + def _try_parse_paren_type_name( + self, + ) -> Optional[Tuple[c_ast.Typename, int, _Token]]: + """Parse and return a parenthesized type name if present. + + Returns (typ, mark, lparen_tok) when the next tokens look like + '(' type_name ')', where typ is the parsed type name, mark is the + token-stream position before parsing, and lparen_tok is the LPAREN + token. Returns None if no parenthesized type name is present. + """ + mark = self._mark() + lparen_tok = self._accept("LPAREN") + if lparen_tok is None: + return None + if not self._starts_declaration(): + self._reset(mark) + return None + typ = self._parse_type_name() + if self._accept("RPAREN") is None: + self._reset(mark) + return None + return typ, mark, lparen_tok + + # ------------------------------------------------------------------ + # Top-level + # ------------------------------------------------------------------ + # BNF: translation_unit_or_empty : translation_unit | empty + def _parse_translation_unit_or_empty(self) -> c_ast.FileAST: + if self._peek() is None: + return c_ast.FileAST([]) + return c_ast.FileAST(self._parse_translation_unit()) + + # BNF: translation_unit : external_declaration+ + def _parse_translation_unit(self) -> List[c_ast.Node]: + ext = [] + while self._peek() is not None: + ext.extend(self._parse_external_declaration()) + return ext + + # BNF: external_declaration : function_definition + # | declaration + # | pp_directive + # | pppragma_directive + # | static_assert + # | ';' + def _parse_external_declaration(self) -> List[c_ast.Node]: + tok = self._peek() + if tok is None: + return [] + if tok.type == "PPHASH": + self._parse_pp_directive() + return [] + if tok.type in {"PPPRAGMA", "_PRAGMA"}: + return [self._parse_pppragma_directive()] + if self._accept("SEMI"): + return [] + if tok.type == "_STATIC_ASSERT": + return self._parse_static_assert() + + if not self._starts_declaration(tok): + # Special handling for old-style function definitions that have an + # implicit return type, e.g. + # + # foo() { + # return 5; + # } + # + # These get an implicit 'int' return type. + decl = self._parse_id_declarator() + param_decls = None + if self._peek_type() != "LBRACE": + self._parse_error("Invalid function definition", decl.coord) + spec: _DeclSpec = dict( + qual=[], + alignment=[], + storage=[], + type=[c_ast.IdentifierType(["int"], coord=decl.coord)], + function=[], + ) + func = self._build_function_definition( + spec=spec, + decl=decl, + param_decls=param_decls, + body=self._parse_compound_statement(), + ) + return [func] + + # From here on, parsing a standard declatation/definition. + spec, saw_type, spec_coord = self._parse_declaration_specifiers( + allow_no_type=True + ) + + name_type, _ = self._peek_declarator_name_info() + if name_type != "ID": + decls = self._parse_decl_body_with_spec(spec, saw_type) + self._expect("SEMI") + return decls + + decl = self._parse_id_declarator() + + if self._peek_type() == "LBRACE" or self._starts_declaration(): + param_decls = None + if self._starts_declaration(): + param_decls = self._parse_declaration_list() + if self._peek_type() != "LBRACE": + self._parse_error("Invalid function definition", decl.coord) + if not spec["type"]: + spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)] + func = self._build_function_definition( + spec=spec, + decl=decl, + param_decls=param_decls, + body=self._parse_compound_statement(), + ) + return [func] + + decl_dict: "_DeclInfo" = dict(decl=decl, init=None, bitsize=None) + if self._accept("EQUALS"): + decl_dict["init"] = self._parse_initializer() + decls = self._parse_init_declarator_list(first=decl_dict) + decls = self._build_declarations(spec=spec, decls=decls, typedef_namespace=True) + self._expect("SEMI") + return decls + + # ------------------------------------------------------------------ + # Declarations + # + # Declarations always come as lists (because they can be several in one + # line). When returning parsed declarations, a list is always returned - + # even if it contains a single element. + # ------------------------------------------------------------------ + def _parse_declaration(self) -> List[c_ast.Node]: + decls = self._parse_decl_body() + self._expect("SEMI") + return decls + + # BNF: decl_body : declaration_specifiers decl_body_with_spec + def _parse_decl_body(self) -> List[c_ast.Node]: + spec, saw_type, _ = self._parse_declaration_specifiers(allow_no_type=True) + return self._parse_decl_body_with_spec(spec, saw_type) + + # BNF: decl_body_with_spec : init_declarator_list + # | struct_or_union_or_enum_only + def _parse_decl_body_with_spec( + self, spec: "_DeclSpec", saw_type: bool + ) -> List[c_ast.Node]: + decls = None + if saw_type: + if self._starts_declarator(): + decls = self._parse_init_declarator_list() + else: + if self._starts_declarator(id_only=True): + decls = self._parse_init_declarator_list(id_only=True) + + if decls is None: + ty = spec["type"] + s_u_or_e = (c_ast.Struct, c_ast.Union, c_ast.Enum) + if len(ty) == 1 and isinstance(ty[0], s_u_or_e): + decls = [ + c_ast.Decl( + name=None, + quals=spec["qual"], + align=spec["alignment"], + storage=spec["storage"], + funcspec=spec["function"], + type=ty[0], + init=None, + bitsize=None, + coord=ty[0].coord, + ) + ] + else: + decls = self._build_declarations( + spec=spec, + decls=[dict(decl=None, init=None, bitsize=None)], + typedef_namespace=True, + ) + else: + decls = self._build_declarations( + spec=spec, decls=decls, typedef_namespace=True + ) + + return decls + + # BNF: declaration_list : declaration+ + def _parse_declaration_list(self) -> List[c_ast.Node]: + decls = [] + while self._starts_declaration(): + decls.extend(self._parse_declaration()) + return decls + + # BNF: declaration_specifiers : (storage_class_specifier + # | type_specifier + # | type_qualifier + # | function_specifier + # | alignment_specifier)+ + def _parse_declaration_specifiers( + self, allow_no_type: bool = False + ) -> Tuple["_DeclSpec", bool, Optional[Coord]]: + """Parse declaration-specifier sequence. + + allow_no_type: + If True, allow a missing type specifier without error. + + Returns: + (spec, saw_type, first_coord) where spec is a dict with + qual/storage/type/function/alignment entries, saw_type is True + if a type specifier was consumed, and first_coord is the coord + of the first specifier token (used for diagnostics). + """ + spec = None + saw_type = False + first_coord = None + + while True: + tok = self._peek() + if tok is None: + break + + if tok.type == "_ALIGNAS": + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_alignment_specifier(), "alignment", append=True + ) + continue + + if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN": + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_atomic_specifier(), "type", append=True + ) + saw_type = True + continue + + if tok.type in _TYPE_QUALIFIER: + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._advance().value, "qual", append=True + ) + continue + + if tok.type in _STORAGE_CLASS: + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._advance().value, "storage", append=True + ) + continue + + if tok.type in _FUNCTION_SPEC: + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._advance().value, "function", append=True + ) + continue + + if tok.type in _TYPE_SPEC_SIMPLE: + if first_coord is None: + first_coord = self._tok_coord(tok) + tok = self._advance() + spec = self._add_declaration_specifier( + spec, + c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), + "type", + append=True, + ) + saw_type = True + continue + + if tok.type == "TYPEID": + if saw_type: + break + if first_coord is None: + first_coord = self._tok_coord(tok) + tok = self._advance() + spec = self._add_declaration_specifier( + spec, + c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), + "type", + append=True, + ) + saw_type = True + continue + + if tok.type in {"STRUCT", "UNION"}: + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_struct_or_union_specifier(), "type", append=True + ) + saw_type = True + continue + + if tok.type == "ENUM": + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_enum_specifier(), "type", append=True + ) + saw_type = True + continue + + break + + if spec is None: + self._parse_error("Invalid declaration", self.clex.filename) + + if not saw_type and not allow_no_type: + self._parse_error("Missing type in declaration", first_coord) + + return spec, saw_type, first_coord + + # BNF: specifier_qualifier_list : (type_specifier + # | type_qualifier + # | alignment_specifier)+ + def _parse_specifier_qualifier_list(self) -> "_DeclSpec": + spec = None + saw_type = False + saw_alignment = False + first_coord = None + + while True: + tok = self._peek() + if tok is None: + break + + if tok.type == "_ALIGNAS": + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_alignment_specifier(), "alignment", append=True + ) + saw_alignment = True + continue + + if tok.type == "_ATOMIC" and self._peek_type(2) == "LPAREN": + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_atomic_specifier(), "type", append=True + ) + saw_type = True + continue + + if tok.type in _TYPE_QUALIFIER: + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._advance().value, "qual", append=True + ) + continue + + if tok.type in _TYPE_SPEC_SIMPLE: + if first_coord is None: + first_coord = self._tok_coord(tok) + tok = self._advance() + spec = self._add_declaration_specifier( + spec, + c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), + "type", + append=True, + ) + saw_type = True + continue + + if tok.type == "TYPEID": + if saw_type: + break + if first_coord is None: + first_coord = self._tok_coord(tok) + tok = self._advance() + spec = self._add_declaration_specifier( + spec, + c_ast.IdentifierType([tok.value], coord=self._tok_coord(tok)), + "type", + append=True, + ) + saw_type = True + continue + + if tok.type in {"STRUCT", "UNION"}: + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_struct_or_union_specifier(), "type", append=True + ) + saw_type = True + continue + + if tok.type == "ENUM": + if first_coord is None: + first_coord = self._tok_coord(tok) + spec = self._add_declaration_specifier( + spec, self._parse_enum_specifier(), "type", append=True + ) + saw_type = True + continue + + break + + if spec is None: + self._parse_error("Invalid specifier list", self.clex.filename) + + if not saw_type and not saw_alignment: + self._parse_error("Missing type in declaration", first_coord) + + if spec.get("storage") is None: + spec["storage"] = [] + if spec.get("function") is None: + spec["function"] = [] + + return spec + + # BNF: type_qualifier_list : type_qualifier+ + def _parse_type_qualifier_list(self) -> List[str]: + quals = [] + while self._peek_type() in _TYPE_QUALIFIER: + quals.append(self._advance().value) + return quals + + # BNF: alignment_specifier : _ALIGNAS '(' type_name | constant_expression ')' + def _parse_alignment_specifier(self) -> c_ast.Node: + tok = self._expect("_ALIGNAS") + self._expect("LPAREN") + + if self._starts_declaration(): + typ = self._parse_type_name() + self._expect("RPAREN") + return c_ast.Alignas(typ, self._tok_coord(tok)) + + expr = self._parse_constant_expression() + self._expect("RPAREN") + return c_ast.Alignas(expr, self._tok_coord(tok)) + + # BNF: atomic_specifier : _ATOMIC '(' type_name ')' + def _parse_atomic_specifier(self) -> c_ast.Node: + self._expect("_ATOMIC") + self._expect("LPAREN") + typ = self._parse_type_name() + self._expect("RPAREN") + typ.quals.append("_Atomic") + return typ + + # BNF: init_declarator_list : init_declarator (',' init_declarator)* + def _parse_init_declarator_list( + self, first: Optional["_DeclInfo"] = None, id_only: bool = False + ) -> List["_DeclInfo"]: + decls = ( + [first] + if first is not None + else [self._parse_init_declarator(id_only=id_only)] + ) + + while self._accept("COMMA"): + decls.append(self._parse_init_declarator(id_only=id_only)) + return decls + + # BNF: init_declarator : declarator ('=' initializer)? + def _parse_init_declarator(self, id_only: bool = False) -> "_DeclInfo": + decl = self._parse_id_declarator() if id_only else self._parse_declarator() + init = None + if self._accept("EQUALS"): + init = self._parse_initializer() + return dict(decl=decl, init=init, bitsize=None) + + # ------------------------------------------------------------------ + # Structs/unions/enums + # ------------------------------------------------------------------ + # BNF: struct_or_union_specifier : struct_or_union ID? '{' struct_declaration_list? '}' + # | struct_or_union ID + def _parse_struct_or_union_specifier(self) -> c_ast.Node: + tok = self._advance() + klass = self._select_struct_union_class(tok.value) + + if self._peek_type() in {"ID", "TYPEID"}: + name_tok = self._advance() + if self._peek_type() == "LBRACE": + self._advance() + if self._accept("RBRACE"): + return klass( + name=name_tok.value, decls=[], coord=self._tok_coord(name_tok) + ) + decls = self._parse_struct_declaration_list() + self._expect("RBRACE") + return klass( + name=name_tok.value, decls=decls, coord=self._tok_coord(name_tok) + ) + + return klass( + name=name_tok.value, decls=None, coord=self._tok_coord(name_tok) + ) + + if self._peek_type() == "LBRACE": + brace_tok = self._advance() + if self._accept("RBRACE"): + return klass(name=None, decls=[], coord=self._tok_coord(brace_tok)) + decls = self._parse_struct_declaration_list() + self._expect("RBRACE") + return klass(name=None, decls=decls, coord=self._tok_coord(brace_tok)) + + self._parse_error("Invalid struct/union declaration", self._tok_coord(tok)) + + # BNF: struct_declaration_list : struct_declaration+ + def _parse_struct_declaration_list(self) -> List[c_ast.Node]: + decls = [] + while self._peek_type() not in {None, "RBRACE"}: + items = self._parse_struct_declaration() + if items is None: + continue + decls.extend(items) + return decls + + # BNF: struct_declaration : specifier_qualifier_list struct_declarator_list? ';' + # | static_assert + # | pppragma_directive + def _parse_struct_declaration(self) -> Optional[List[c_ast.Node]]: + if self._peek_type() == "SEMI": + self._advance() + return None + if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}: + return [self._parse_pppragma_directive()] + + spec = self._parse_specifier_qualifier_list() + assert "typedef" not in spec.get("storage", []) + + decls = None + if self._starts_declarator() or self._peek_type() == "COLON": + decls = self._parse_struct_declarator_list() + if decls is not None: + self._expect("SEMI") + return self._build_declarations(spec=spec, decls=decls) + + if len(spec["type"]) == 1: + node = spec["type"][0] + if isinstance(node, c_ast.Node): + decl_type = node + else: + decl_type = c_ast.IdentifierType(node) + self._expect("SEMI") + return self._build_declarations( + spec=spec, decls=[dict(decl=decl_type, init=None, bitsize=None)] + ) + + self._expect("SEMI") + return self._build_declarations( + spec=spec, decls=[dict(decl=None, init=None, bitsize=None)] + ) + + # BNF: struct_declarator_list : struct_declarator (',' struct_declarator)* + def _parse_struct_declarator_list(self) -> List["_DeclInfo"]: + decls = [self._parse_struct_declarator()] + while self._accept("COMMA"): + decls.append(self._parse_struct_declarator()) + return decls + + # BNF: struct_declarator : declarator? ':' constant_expression + # | declarator (':' constant_expression)? + def _parse_struct_declarator(self) -> "_DeclInfo": + if self._accept("COLON"): + bitsize = self._parse_constant_expression() + return { + "decl": c_ast.TypeDecl(None, None, None, None), + "init": None, + "bitsize": bitsize, + } + + decl = self._parse_declarator() + if self._accept("COLON"): + bitsize = self._parse_constant_expression() + return {"decl": decl, "init": None, "bitsize": bitsize} + + return {"decl": decl, "init": None, "bitsize": None} + + # BNF: enum_specifier : ENUM ID? '{' enumerator_list? '}' + # | ENUM ID + def _parse_enum_specifier(self) -> c_ast.Node: + tok = self._expect("ENUM") + if self._peek_type() in {"ID", "TYPEID"}: + name_tok = self._advance() + if self._peek_type() == "LBRACE": + self._advance() + enums = self._parse_enumerator_list() + self._expect("RBRACE") + return c_ast.Enum(name_tok.value, enums, self._tok_coord(tok)) + return c_ast.Enum(name_tok.value, None, self._tok_coord(tok)) + + self._expect("LBRACE") + enums = self._parse_enumerator_list() + self._expect("RBRACE") + return c_ast.Enum(None, enums, self._tok_coord(tok)) + + # BNF: enumerator_list : enumerator (',' enumerator)* ','? + def _parse_enumerator_list(self) -> c_ast.Node: + enum = self._parse_enumerator() + enum_list = c_ast.EnumeratorList([enum], enum.coord) + while self._accept("COMMA"): + if self._peek_type() == "RBRACE": + break + enum = self._parse_enumerator() + enum_list.enumerators.append(enum) + return enum_list + + # BNF: enumerator : ID ('=' constant_expression)? + def _parse_enumerator(self) -> c_ast.Node: + name_tok = self._expect("ID") + if self._accept("EQUALS"): + value = self._parse_constant_expression() + else: + value = None + enum = c_ast.Enumerator(name_tok.value, value, self._tok_coord(name_tok)) + self._add_identifier(enum.name, enum.coord) + return enum + + # ------------------------------------------------------------------ + # Declarators + # ------------------------------------------------------------------ + # BNF: declarator : pointer? direct_declarator + def _parse_declarator(self) -> c_ast.Node: + decl, _ = self._parse_any_declarator( + allow_abstract=False, typeid_paren_as_abstract=False + ) + assert decl is not None + return decl + + # BNF: id_declarator : declarator with ID name + def _parse_id_declarator(self) -> c_ast.Node: + return self._parse_declarator_kind(kind="id", allow_paren=True) + + # BNF: typeid_declarator : declarator with TYPEID name + def _parse_typeid_declarator(self) -> c_ast.Node: + return self._parse_declarator_kind(kind="typeid", allow_paren=True) + + # BNF: typeid_noparen_declarator : declarator without parenthesized name + def _parse_typeid_noparen_declarator(self) -> c_ast.Node: + return self._parse_declarator_kind(kind="typeid", allow_paren=False) + + # BNF: declarator_kind : pointer? direct_declarator(kind) + def _parse_declarator_kind(self, kind: str, allow_paren: bool) -> c_ast.Node: + ptr = None + if self._peek_type() == "TIMES": + ptr = self._parse_pointer() + direct = self._parse_direct_declarator(kind, allow_paren=allow_paren) + if ptr is not None: + return self._type_modify_decl(direct, ptr) + return direct + + # BNF: direct_declarator : ID | TYPEID | '(' declarator ')' + # | direct_declarator '[' ... ']' + # | direct_declarator '(' ... ')' + def _parse_direct_declarator( + self, kind: str, allow_paren: bool = True + ) -> c_ast.Node: + if allow_paren and self._accept("LPAREN"): + decl = self._parse_declarator_kind(kind, allow_paren=True) + self._expect("RPAREN") + else: + if kind == "id": + name_tok = self._expect("ID") + else: + name_tok = self._expect("TYPEID") + decl = c_ast.TypeDecl( + declname=name_tok.value, + type=None, + quals=None, + align=None, + coord=self._tok_coord(name_tok), + ) + + return self._parse_decl_suffixes(decl) + + def _parse_decl_suffixes(self, decl: c_ast.Node) -> c_ast.Node: + """Parse a chain of array/function suffixes and attach them to decl.""" + while True: + if self._peek_type() == "LBRACKET": + decl = self._type_modify_decl(decl, self._parse_array_decl(decl)) + continue + if self._peek_type() == "LPAREN": + func = self._parse_function_decl(decl) + decl = self._type_modify_decl(decl, func) + continue + break + return decl + + # BNF: array_decl : '[' array_specifiers? assignment_expression? ']' + def _parse_array_decl(self, base_decl: c_ast.Node) -> c_ast.Node: + return self._parse_array_decl_common(base_type=None, coord=base_decl.coord) + + def _parse_array_decl_common( + self, base_type: Optional[c_ast.Node], coord: Optional[Coord] = None + ) -> c_ast.Node: + """Parse an array declarator suffix and return an ArrayDecl node. + + base_type: + Base declarator node to attach (None for direct-declarator parsing, + TypeDecl for abstract declarators). + + coord: + Coordinate to use for the ArrayDecl. If None, uses the '[' token. + """ + lbrack_tok = self._expect("LBRACKET") + if coord is None: + coord = self._tok_coord(lbrack_tok) + + def make_array_decl(dim, dim_quals): + return c_ast.ArrayDecl( + type=base_type, dim=dim, dim_quals=dim_quals, coord=coord + ) + + if self._accept("STATIC"): + dim_quals = ["static"] + (self._parse_type_qualifier_list() or []) + dim = self._parse_assignment_expression() + self._expect("RBRACKET") + return make_array_decl(dim, dim_quals) + + if self._peek_type() in _TYPE_QUALIFIER: + dim_quals = self._parse_type_qualifier_list() or [] + if self._accept("STATIC"): + dim_quals = dim_quals + ["static"] + dim = self._parse_assignment_expression() + self._expect("RBRACKET") + return make_array_decl(dim, dim_quals) + times_tok = self._accept("TIMES") + if times_tok: + self._expect("RBRACKET") + dim = c_ast.ID(times_tok.value, self._tok_coord(times_tok)) + return make_array_decl(dim, dim_quals) + dim = None + if self._starts_expression(): + dim = self._parse_assignment_expression() + self._expect("RBRACKET") + return make_array_decl(dim, dim_quals) + + times_tok = self._accept("TIMES") + if times_tok: + self._expect("RBRACKET") + dim = c_ast.ID(times_tok.value, self._tok_coord(times_tok)) + return make_array_decl(dim, []) + + dim = None + if self._starts_expression(): + dim = self._parse_assignment_expression() + self._expect("RBRACKET") + return make_array_decl(dim, []) + + # BNF: function_decl : '(' parameter_type_list_opt | identifier_list_opt ')' + def _parse_function_decl(self, base_decl: c_ast.Node) -> c_ast.Node: + self._expect("LPAREN") + if self._accept("RPAREN"): + args = None + else: + args = ( + self._parse_parameter_type_list() + if self._starts_declaration() + else self._parse_identifier_list_opt() + ) + self._expect("RPAREN") + + func = c_ast.FuncDecl(args=args, type=None, coord=base_decl.coord) + + if self._peek_type() == "LBRACE": + if func.args is not None: + for param in func.args.params: + if isinstance(param, c_ast.EllipsisParam): + break + name = getattr(param, "name", None) + if name: + self._add_identifier(name, param.coord) + + return func + + # BNF: pointer : '*' type_qualifier_list? pointer? + def _parse_pointer(self) -> Optional[c_ast.Node]: + stars = [] + times_tok = self._accept("TIMES") + while times_tok: + quals = self._parse_type_qualifier_list() or [] + stars.append((quals, self._tok_coord(times_tok))) + times_tok = self._accept("TIMES") + + if not stars: + return None + + ptr = None + for quals, coord in stars: + ptr = c_ast.PtrDecl(quals=quals, type=ptr, coord=coord) + return ptr + + # BNF: parameter_type_list : parameter_list (',' ELLIPSIS)? + def _parse_parameter_type_list(self) -> c_ast.ParamList: + params = self._parse_parameter_list() + if self._peek_type() == "COMMA" and self._peek_type(2) == "ELLIPSIS": + self._advance() + ell_tok = self._advance() + params.params.append(c_ast.EllipsisParam(self._tok_coord(ell_tok))) + return params + + # BNF: parameter_list : parameter_declaration (',' parameter_declaration)* + def _parse_parameter_list(self) -> c_ast.ParamList: + first = self._parse_parameter_declaration() + params = c_ast.ParamList([first], first.coord) + while self._peek_type() == "COMMA" and self._peek_type(2) != "ELLIPSIS": + self._advance() + params.params.append(self._parse_parameter_declaration()) + return params + + # BNF: parameter_declaration : declaration_specifiers declarator? + # | declaration_specifiers abstract_declarator_opt + def _parse_parameter_declaration(self) -> c_ast.Node: + spec, _, spec_coord = self._parse_declaration_specifiers(allow_no_type=True) + + if not spec["type"]: + spec["type"] = [c_ast.IdentifierType(["int"], coord=spec_coord)] + + if self._starts_declarator(): + decl, is_named = self._parse_any_declarator( + allow_abstract=True, typeid_paren_as_abstract=True + ) + if is_named: + return self._build_declarations( + spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)] + )[0] + return self._build_parameter_declaration(spec, decl, spec_coord) + + decl = self._parse_abstract_declarator_opt() + return self._build_parameter_declaration(spec, decl, spec_coord) + + def _build_parameter_declaration( + self, spec: "_DeclSpec", decl: Optional[c_ast.Node], spec_coord: Optional[Coord] + ) -> c_ast.Node: + if ( + len(spec["type"]) > 1 + and len(spec["type"][-1].names) == 1 + and self._is_type_in_scope(spec["type"][-1].names[0]) + ): + return self._build_declarations( + spec=spec, decls=[dict(decl=decl, init=None, bitsize=None)] + )[0] + + decl = c_ast.Typename( + name="", + quals=spec["qual"], + align=None, + type=decl or c_ast.TypeDecl(None, None, None, None), + coord=spec_coord, + ) + return self._fix_decl_name_type(decl, spec["type"]) + + # BNF: identifier_list_opt : identifier_list | empty + def _parse_identifier_list_opt(self) -> Optional[c_ast.Node]: + if self._peek_type() == "RPAREN": + return None + return self._parse_identifier_list() + + # BNF: identifier_list : identifier (',' identifier)* + def _parse_identifier_list(self) -> c_ast.Node: + first = self._parse_identifier() + params = c_ast.ParamList([first], first.coord) + while self._accept("COMMA"): + params.params.append(self._parse_identifier()) + return params + + # ------------------------------------------------------------------ + # Abstract declarators + # ------------------------------------------------------------------ + # BNF: type_name : specifier_qualifier_list abstract_declarator_opt + def _parse_type_name(self) -> c_ast.Typename: + spec = self._parse_specifier_qualifier_list() + decl = self._parse_abstract_declarator_opt() + + coord = None + if decl is not None: + coord = decl.coord + elif spec["type"]: + coord = spec["type"][0].coord + + typename = c_ast.Typename( + name="", + quals=spec["qual"][:], + align=None, + type=decl or c_ast.TypeDecl(None, None, None, None), + coord=coord, + ) + return cast(c_ast.Typename, self._fix_decl_name_type(typename, spec["type"])) + + # BNF: abstract_declarator_opt : pointer? direct_abstract_declarator? + def _parse_abstract_declarator_opt(self) -> Optional[c_ast.Node]: + if self._peek_type() == "TIMES": + ptr = self._parse_pointer() + if self._starts_direct_abstract_declarator(): + decl = self._parse_direct_abstract_declarator() + else: + decl = c_ast.TypeDecl(None, None, None, None) + assert ptr is not None + return self._type_modify_decl(decl, ptr) + + if self._starts_direct_abstract_declarator(): + return self._parse_direct_abstract_declarator() + + return None + + # BNF: direct_abstract_declarator : '(' parameter_type_list_opt ')' + # | '(' abstract_declarator ')' + # | '[' ... ']' + def _parse_direct_abstract_declarator(self) -> c_ast.Node: + lparen_tok = self._accept("LPAREN") + if lparen_tok: + if self._starts_declaration() or self._peek_type() == "RPAREN": + params = self._parse_parameter_type_list_opt() + self._expect("RPAREN") + decl = c_ast.FuncDecl( + args=params, + type=c_ast.TypeDecl(None, None, None, None), + coord=self._tok_coord(lparen_tok), + ) + else: + decl = self._parse_abstract_declarator_opt() + self._expect("RPAREN") + assert decl is not None + elif self._peek_type() == "LBRACKET": + decl = self._parse_abstract_array_base() + else: + self._parse_error("Invalid abstract declarator", self.clex.filename) + + return self._parse_decl_suffixes(decl) + + # BNF: parameter_type_list_opt : parameter_type_list | empty + def _parse_parameter_type_list_opt(self) -> Optional[c_ast.ParamList]: + if self._peek_type() == "RPAREN": + return None + return self._parse_parameter_type_list() + + # BNF: abstract_array_base : '[' array_specifiers? assignment_expression? ']' + def _parse_abstract_array_base(self) -> c_ast.Node: + return self._parse_array_decl_common( + base_type=c_ast.TypeDecl(None, None, None, None), coord=None + ) + + # ------------------------------------------------------------------ + # Statements + # ------------------------------------------------------------------ + # BNF: statement : labeled_statement | compound_statement + # | selection_statement | iteration_statement + # | jump_statement | expression_statement + # | static_assert | pppragma_directive + def _parse_statement(self) -> c_ast.Node | List[c_ast.Node]: + tok_type = self._peek_type() + match tok_type: + case "CASE" | "DEFAULT": + return self._parse_labeled_statement() + case "ID" if self._peek_type(2) == "COLON": + return self._parse_labeled_statement() + case "LBRACE": + return self._parse_compound_statement() + case "IF" | "SWITCH": + return self._parse_selection_statement() + case "WHILE" | "DO" | "FOR": + return self._parse_iteration_statement() + case "GOTO" | "BREAK" | "CONTINUE" | "RETURN": + return self._parse_jump_statement() + case "PPPRAGMA" | "_PRAGMA": + return self._parse_pppragma_directive() + case "_STATIC_ASSERT": + return self._parse_static_assert() + case _: + return self._parse_expression_statement() + + # BNF: pragmacomp_or_statement : pppragma_directive* statement + def _parse_pragmacomp_or_statement(self) -> c_ast.Node | List[c_ast.Node]: + if self._peek_type() in {"PPPRAGMA", "_PRAGMA"}: + pragmas = self._parse_pppragma_directive_list() + stmt = self._parse_statement() + return c_ast.Compound(block_items=pragmas + [stmt], coord=pragmas[0].coord) + return self._parse_statement() + + # BNF: block_item : declaration | statement + def _parse_block_item(self) -> c_ast.Node | List[c_ast.Node]: + if self._starts_declaration(): + return self._parse_declaration() + return self._parse_statement() + + # BNF: block_item_list : block_item+ + def _parse_block_item_list(self) -> List[c_ast.Node]: + items = [] + while self._peek_type() not in {"RBRACE", None}: + item = self._parse_block_item() + if isinstance(item, list): + if item == [None]: + continue + items.extend(item) + else: + items.append(item) + return items + + # BNF: compound_statement : '{' block_item_list? '}' + def _parse_compound_statement(self) -> c_ast.Node: + lbrace_tok = self._expect("LBRACE") + if self._accept("RBRACE"): + return c_ast.Compound(block_items=None, coord=self._tok_coord(lbrace_tok)) + block_items = self._parse_block_item_list() + self._expect("RBRACE") + return c_ast.Compound( + block_items=block_items, coord=self._tok_coord(lbrace_tok) + ) + + # BNF: labeled_statement : ID ':' statement + # | CASE constant_expression ':' statement + # | DEFAULT ':' statement + def _parse_labeled_statement(self) -> c_ast.Node: + tok_type = self._peek_type() + match tok_type: + case "ID": + name_tok = self._advance() + self._expect("COLON") + if self._starts_statement(): + stmt = self._parse_pragmacomp_or_statement() + else: + stmt = c_ast.EmptyStatement(self._tok_coord(name_tok)) + return c_ast.Label(name_tok.value, stmt, self._tok_coord(name_tok)) + case "CASE": + case_tok = self._advance() + expr = self._parse_constant_expression() + self._expect("COLON") + if self._starts_statement(): + stmt = self._parse_pragmacomp_or_statement() + else: + stmt = c_ast.EmptyStatement(self._tok_coord(case_tok)) + return c_ast.Case(expr, [stmt], self._tok_coord(case_tok)) + case "DEFAULT": + def_tok = self._advance() + self._expect("COLON") + if self._starts_statement(): + stmt = self._parse_pragmacomp_or_statement() + else: + stmt = c_ast.EmptyStatement(self._tok_coord(def_tok)) + return c_ast.Default([stmt], self._tok_coord(def_tok)) + case _: + self._parse_error("Invalid labeled statement", self.clex.filename) + + # BNF: selection_statement : IF '(' expression ')' statement (ELSE statement)? + # | SWITCH '(' expression ')' statement + def _parse_selection_statement(self) -> c_ast.Node: + tok = self._advance() + match tok.type: + case "IF": + self._expect("LPAREN") + cond = self._parse_expression() + self._expect("RPAREN") + then_stmt = self._parse_pragmacomp_or_statement() + if self._accept("ELSE"): + else_stmt = self._parse_pragmacomp_or_statement() + return c_ast.If(cond, then_stmt, else_stmt, self._tok_coord(tok)) + return c_ast.If(cond, then_stmt, None, self._tok_coord(tok)) + case "SWITCH": + self._expect("LPAREN") + expr = self._parse_expression() + self._expect("RPAREN") + stmt = self._parse_pragmacomp_or_statement() + return fix_switch_cases(c_ast.Switch(expr, stmt, self._tok_coord(tok))) + case _: + self._parse_error("Invalid selection statement", self._tok_coord(tok)) + + # BNF: iteration_statement : WHILE '(' expression ')' statement + # | DO statement WHILE '(' expression ')' ';' + # | FOR '(' (declaration | expression_opt) ';' + # expression_opt ';' expression_opt ')' statement + def _parse_iteration_statement(self) -> c_ast.Node: + tok = self._advance() + match tok.type: + case "WHILE": + self._expect("LPAREN") + cond = self._parse_expression() + self._expect("RPAREN") + stmt = self._parse_pragmacomp_or_statement() + return c_ast.While(cond, stmt, self._tok_coord(tok)) + case "DO": + stmt = self._parse_pragmacomp_or_statement() + self._expect("WHILE") + self._expect("LPAREN") + cond = self._parse_expression() + self._expect("RPAREN") + self._expect("SEMI") + return c_ast.DoWhile(cond, stmt, self._tok_coord(tok)) + case "FOR": + self._expect("LPAREN") + if self._starts_declaration(): + decls = self._parse_declaration() + init = c_ast.DeclList(decls, self._tok_coord(tok)) + cond = self._parse_expression_opt() + self._expect("SEMI") + next_expr = self._parse_expression_opt() + self._expect("RPAREN") + stmt = self._parse_pragmacomp_or_statement() + return c_ast.For(init, cond, next_expr, stmt, self._tok_coord(tok)) + + init = self._parse_expression_opt() + self._expect("SEMI") + cond = self._parse_expression_opt() + self._expect("SEMI") + next_expr = self._parse_expression_opt() + self._expect("RPAREN") + stmt = self._parse_pragmacomp_or_statement() + return c_ast.For(init, cond, next_expr, stmt, self._tok_coord(tok)) + case _: + self._parse_error("Invalid iteration statement", self._tok_coord(tok)) + + # BNF: jump_statement : GOTO ID ';' | BREAK ';' | CONTINUE ';' + # | RETURN expression? ';' + def _parse_jump_statement(self) -> c_ast.Node: + tok = self._advance() + match tok.type: + case "GOTO": + name_tok = self._expect("ID") + self._expect("SEMI") + return c_ast.Goto(name_tok.value, self._tok_coord(tok)) + case "BREAK": + self._expect("SEMI") + return c_ast.Break(self._tok_coord(tok)) + case "CONTINUE": + self._expect("SEMI") + return c_ast.Continue(self._tok_coord(tok)) + case "RETURN": + if self._accept("SEMI"): + return c_ast.Return(None, self._tok_coord(tok)) + expr = self._parse_expression() + self._expect("SEMI") + return c_ast.Return(expr, self._tok_coord(tok)) + case _: + self._parse_error("Invalid jump statement", self._tok_coord(tok)) + + # BNF: expression_statement : expression_opt ';' + def _parse_expression_statement(self) -> c_ast.Node: + expr = self._parse_expression_opt() + semi_tok = self._expect("SEMI") + if expr is None: + return c_ast.EmptyStatement(self._tok_coord(semi_tok)) + return expr + + # ------------------------------------------------------------------ + # Expressions + # ------------------------------------------------------------------ + # BNF: expression_opt : expression | empty + def _parse_expression_opt(self) -> Optional[c_ast.Node]: + if self._starts_expression(): + return self._parse_expression() + return None + + # BNF: expression : assignment_expression (',' assignment_expression)* + def _parse_expression(self) -> c_ast.Node: + expr = self._parse_assignment_expression() + if not self._accept("COMMA"): + return expr + exprs = [expr, self._parse_assignment_expression()] + while self._accept("COMMA"): + exprs.append(self._parse_assignment_expression()) + return c_ast.ExprList(exprs, expr.coord) + + # BNF: assignment_expression : conditional_expression + # | unary_expression assignment_op assignment_expression + def _parse_assignment_expression(self) -> c_ast.Node: + if self._peek_type() == "LPAREN" and self._peek_type(2) == "LBRACE": + self._advance() + comp = self._parse_compound_statement() + self._expect("RPAREN") + return comp + + expr = self._parse_conditional_expression() + if self._is_assignment_op(): + op = self._advance().value + rhs = self._parse_assignment_expression() + return c_ast.Assignment(op, expr, rhs, expr.coord) + return expr + + # BNF: conditional_expression : binary_expression + # | binary_expression '?' expression ':' conditional_expression + def _parse_conditional_expression(self) -> c_ast.Node: + expr = self._parse_binary_expression() + if self._accept("CONDOP"): + iftrue = self._parse_expression() + self._expect("COLON") + iffalse = self._parse_conditional_expression() + return c_ast.TernaryOp(expr, iftrue, iffalse, expr.coord) + return expr + + # BNF: binary_expression : cast_expression (binary_op cast_expression)* + def _parse_binary_expression( + self, min_prec: int = 0, lhs: Optional[c_ast.Node] = None + ) -> c_ast.Node: + if lhs is None: + lhs = self._parse_cast_expression() + + while True: + tok = self._peek() + if tok is None or tok.type not in _BINARY_PRECEDENCE: + break + prec = _BINARY_PRECEDENCE[tok.type] + if prec < min_prec: + break + + op = tok.value + self._advance() + rhs = self._parse_cast_expression() + + while True: + next_tok = self._peek() + if next_tok is None or next_tok.type not in _BINARY_PRECEDENCE: + break + next_prec = _BINARY_PRECEDENCE[next_tok.type] + if next_prec > prec: + rhs = self._parse_binary_expression(next_prec, rhs) + else: + break + + lhs = c_ast.BinaryOp(op, lhs, rhs, lhs.coord) + + return lhs + + # BNF: cast_expression : '(' type_name ')' cast_expression + # | unary_expression + def _parse_cast_expression(self) -> c_ast.Node: + result = self._try_parse_paren_type_name() + if result is not None: + typ, mark, lparen_tok = result + if self._peek_type() == "LBRACE": + # (type){...} is a compound literal, not a cast. Examples: + # (int){1} -> compound literal, handled in postfix + # (int) x -> cast, handled below + self._reset(mark) + else: + expr = self._parse_cast_expression() + return c_ast.Cast(typ, expr, self._tok_coord(lparen_tok)) + return self._parse_unary_expression() + + # BNF: unary_expression : postfix_expression + # | '++' unary_expression + # | '--' unary_expression + # | unary_op cast_expression + # | 'sizeof' unary_expression + # | 'sizeof' '(' type_name ')' + # | '_Alignof' '(' type_name ')' + def _parse_unary_expression(self) -> c_ast.Node: + tok_type = self._peek_type() + if tok_type in {"PLUSPLUS", "MINUSMINUS"}: + tok = self._advance() + expr = self._parse_unary_expression() + return c_ast.UnaryOp(tok.value, expr, expr.coord) + + if tok_type in {"AND", "TIMES", "PLUS", "MINUS", "NOT", "LNOT"}: + tok = self._advance() + expr = self._parse_cast_expression() + return c_ast.UnaryOp(tok.value, expr, expr.coord) + + if tok_type == "SIZEOF": + tok = self._advance() + result = self._try_parse_paren_type_name() + if result is not None: + typ, _, _ = result + return c_ast.UnaryOp(tok.value, typ, self._tok_coord(tok)) + expr = self._parse_unary_expression() + return c_ast.UnaryOp(tok.value, expr, self._tok_coord(tok)) + + if tok_type == "_ALIGNOF": + tok = self._advance() + self._expect("LPAREN") + typ = self._parse_type_name() + self._expect("RPAREN") + return c_ast.UnaryOp(tok.value, typ, self._tok_coord(tok)) + + return self._parse_postfix_expression() + + # BNF: postfix_expression : primary_expression postfix_suffix* + # | '(' type_name ')' '{' initializer_list ','? '}' + def _parse_postfix_expression(self) -> c_ast.Node: + result = self._try_parse_paren_type_name() + if result is not None: + typ, mark, _ = result + # Disambiguate between casts and compound literals: + # (int) x -> cast + # (int) {1} -> compound literal + if self._accept("LBRACE"): + init = self._parse_initializer_list() + self._accept("COMMA") + self._expect("RBRACE") + return c_ast.CompoundLiteral(typ, init) + else: + self._reset(mark) + + expr = self._parse_primary_expression() + while True: + if self._accept("LBRACKET"): + sub = self._parse_expression() + self._expect("RBRACKET") + expr = c_ast.ArrayRef(expr, sub, expr.coord) + continue + if self._accept("LPAREN"): + if self._peek_type() == "RPAREN": + self._advance() + args = None + else: + args = self._parse_argument_expression_list() + self._expect("RPAREN") + expr = c_ast.FuncCall(expr, args, expr.coord) + continue + if self._peek_type() in {"PERIOD", "ARROW"}: + op_tok = self._advance() + name_tok = self._advance() + if name_tok.type not in {"ID", "TYPEID"}: + self._parse_error( + "Invalid struct reference", self._tok_coord(name_tok) + ) + field = c_ast.ID(name_tok.value, self._tok_coord(name_tok)) + expr = c_ast.StructRef(expr, op_tok.value, field, expr.coord) + continue + if self._peek_type() in {"PLUSPLUS", "MINUSMINUS"}: + tok = self._advance() + expr = c_ast.UnaryOp("p" + tok.value, expr, expr.coord) + continue + break + return expr + + # BNF: primary_expression : ID | constant | string_literal + # | '(' expression ')' | offsetof + def _parse_primary_expression(self) -> c_ast.Node: + tok_type = self._peek_type() + if tok_type == "ID": + return self._parse_identifier() + if ( + tok_type in _INT_CONST + or tok_type in _FLOAT_CONST + or tok_type in _CHAR_CONST + ): + return self._parse_constant() + if tok_type in _STRING_LITERAL: + return self._parse_unified_string_literal() + if tok_type in _WSTR_LITERAL: + return self._parse_unified_wstring_literal() + if tok_type == "LPAREN": + self._advance() + expr = self._parse_expression() + self._expect("RPAREN") + return expr + if tok_type == "OFFSETOF": + off_tok = self._advance() + self._expect("LPAREN") + typ = self._parse_type_name() + self._expect("COMMA") + designator = self._parse_offsetof_member_designator() + self._expect("RPAREN") + coord = self._tok_coord(off_tok) + return c_ast.FuncCall( + c_ast.ID(off_tok.value, coord), + c_ast.ExprList([typ, designator], coord), + coord, + ) + + self._parse_error("Invalid expression", self.clex.filename) + + # BNF: offsetof_member_designator : identifier_or_typeid + # ('.' identifier_or_typeid | '[' expression ']')* + def _parse_offsetof_member_designator(self) -> c_ast.Node: + node = self._parse_identifier_or_typeid() + while True: + if self._accept("PERIOD"): + field = self._parse_identifier_or_typeid() + node = c_ast.StructRef(node, ".", field, node.coord) + continue + if self._accept("LBRACKET"): + expr = self._parse_expression() + self._expect("RBRACKET") + node = c_ast.ArrayRef(node, expr, node.coord) + continue + break + return node + + # BNF: argument_expression_list : assignment_expression (',' assignment_expression)* + def _parse_argument_expression_list(self) -> c_ast.Node: + expr = self._parse_assignment_expression() + exprs = [expr] + while self._accept("COMMA"): + exprs.append(self._parse_assignment_expression()) + return c_ast.ExprList(exprs, expr.coord) + + # BNF: constant_expression : conditional_expression + def _parse_constant_expression(self) -> c_ast.Node: + return self._parse_conditional_expression() + + # ------------------------------------------------------------------ + # Terminals + # ------------------------------------------------------------------ + # BNF: identifier : ID + def _parse_identifier(self) -> c_ast.Node: + tok = self._expect("ID") + return c_ast.ID(tok.value, self._tok_coord(tok)) + + # BNF: identifier_or_typeid : ID | TYPEID + def _parse_identifier_or_typeid(self) -> c_ast.Node: + tok = self._advance() + if tok.type not in {"ID", "TYPEID"}: + self._parse_error("Expected identifier", self._tok_coord(tok)) + return c_ast.ID(tok.value, self._tok_coord(tok)) + + # BNF: constant : INT_CONST | FLOAT_CONST | CHAR_CONST + def _parse_constant(self) -> c_ast.Node: + tok = self._advance() + if tok.type in _INT_CONST: + u_count = 0 + l_count = 0 + for ch in tok.value[-3:]: + if ch in ("l", "L"): + l_count += 1 + elif ch in ("u", "U"): + u_count += 1 + if u_count > 1: + raise ValueError("Constant cannot have more than one u/U suffix.") + if l_count > 2: + raise ValueError("Constant cannot have more than two l/L suffix.") + prefix = "unsigned " * u_count + "long " * l_count + return c_ast.Constant(prefix + "int", tok.value, self._tok_coord(tok)) + + if tok.type in _FLOAT_CONST: + if tok.value[-1] in ("f", "F"): + t = "float" + elif tok.value[-1] in ("l", "L"): + t = "long double" + else: + t = "double" + return c_ast.Constant(t, tok.value, self._tok_coord(tok)) + + if tok.type in _CHAR_CONST: + return c_ast.Constant("char", tok.value, self._tok_coord(tok)) + + self._parse_error("Invalid constant", self._tok_coord(tok)) + + # BNF: unified_string_literal : STRING_LITERAL+ + def _parse_unified_string_literal(self) -> c_ast.Node: + tok = self._expect("STRING_LITERAL") + node = c_ast.Constant("string", tok.value, self._tok_coord(tok)) + while self._peek_type() == "STRING_LITERAL": + tok2 = self._advance() + node.value = node.value[:-1] + tok2.value[1:] + return node + + # BNF: unified_wstring_literal : WSTRING_LITERAL+ + def _parse_unified_wstring_literal(self) -> c_ast.Node: + tok = self._advance() + if tok.type not in _WSTR_LITERAL: + self._parse_error("Invalid string literal", self._tok_coord(tok)) + node = c_ast.Constant("string", tok.value, self._tok_coord(tok)) + while self._peek_type() in _WSTR_LITERAL: + tok2 = self._advance() + node.value = node.value.rstrip()[:-1] + tok2.value[2:] + return node + + # ------------------------------------------------------------------ + # Initializers + # ------------------------------------------------------------------ + # BNF: initializer : assignment_expression + # | '{' initializer_list ','? '}' + # | '{' '}' + def _parse_initializer(self) -> c_ast.Node: + lbrace_tok = self._accept("LBRACE") + if lbrace_tok: + if self._accept("RBRACE"): + return c_ast.InitList([], self._tok_coord(lbrace_tok)) + init_list = self._parse_initializer_list() + self._accept("COMMA") + self._expect("RBRACE") + return init_list + + return self._parse_assignment_expression() + + # BNF: initializer_list : initializer_item (',' initializer_item)* ','? + def _parse_initializer_list(self) -> c_ast.Node: + items = [self._parse_initializer_item()] + while self._accept("COMMA"): + if self._peek_type() == "RBRACE": + break + items.append(self._parse_initializer_item()) + return c_ast.InitList(items, items[0].coord) + + # BNF: initializer_item : designation? initializer + def _parse_initializer_item(self) -> c_ast.Node: + designation = None + if self._peek_type() in {"LBRACKET", "PERIOD"}: + designation = self._parse_designation() + init = self._parse_initializer() + if designation is not None: + return c_ast.NamedInitializer(designation, init) + return init + + # BNF: designation : designator_list '=' + def _parse_designation(self) -> List[c_ast.Node]: + designators = self._parse_designator_list() + self._expect("EQUALS") + return designators + + # BNF: designator_list : designator+ + def _parse_designator_list(self) -> List[c_ast.Node]: + designators = [] + while self._peek_type() in {"LBRACKET", "PERIOD"}: + designators.append(self._parse_designator()) + return designators + + # BNF: designator : '[' constant_expression ']' + # | '.' identifier_or_typeid + def _parse_designator(self) -> c_ast.Node: + if self._accept("LBRACKET"): + expr = self._parse_constant_expression() + self._expect("RBRACKET") + return expr + if self._accept("PERIOD"): + return self._parse_identifier_or_typeid() + self._parse_error("Invalid designator", self.clex.filename) + + # ------------------------------------------------------------------ + # Preprocessor-like directives + # ------------------------------------------------------------------ + # BNF: pp_directive : '#' ... (unsupported) + def _parse_pp_directive(self) -> NoReturn: + tok = self._expect("PPHASH") + self._parse_error("Directives not supported yet", self._tok_coord(tok)) + + # BNF: pppragma_directive : PPPRAGMA PPPRAGMASTR? + # | _PRAGMA '(' string_literal ')' + def _parse_pppragma_directive(self) -> c_ast.Node: + if self._peek_type() == "PPPRAGMA": + tok = self._advance() + if self._peek_type() == "PPPRAGMASTR": + str_tok = self._advance() + return c_ast.Pragma(str_tok.value, self._tok_coord(str_tok)) + return c_ast.Pragma("", self._tok_coord(tok)) + + if self._peek_type() == "_PRAGMA": + tok = self._advance() + lparen = self._expect("LPAREN") + literal = self._parse_unified_string_literal() + self._expect("RPAREN") + return c_ast.Pragma(literal, self._tok_coord(lparen)) + + self._parse_error("Invalid pragma", self.clex.filename) + + # BNF: pppragma_directive_list : pppragma_directive+ + def _parse_pppragma_directive_list(self) -> List[c_ast.Node]: + pragmas = [] + while self._peek_type() in {"PPPRAGMA", "_PRAGMA"}: + pragmas.append(self._parse_pppragma_directive()) + return pragmas + + # BNF: static_assert : _STATIC_ASSERT '(' constant_expression (',' string_literal)? ')' + def _parse_static_assert(self) -> List[c_ast.Node]: + tok = self._expect("_STATIC_ASSERT") + self._expect("LPAREN") + cond = self._parse_constant_expression() + msg = None + if self._accept("COMMA"): + msg = self._parse_unified_string_literal() + self._expect("RPAREN") + return [c_ast.StaticAssert(cond, msg, self._tok_coord(tok))] + + +_ASSIGNMENT_OPS = { + "EQUALS", + "XOREQUAL", + "TIMESEQUAL", + "DIVEQUAL", + "MODEQUAL", + "PLUSEQUAL", + "MINUSEQUAL", + "LSHIFTEQUAL", + "RSHIFTEQUAL", + "ANDEQUAL", + "OREQUAL", +} + +# Precedence of operators (lower number = weather binding) +# If this changes, c_generator.CGenerator.precedence_map needs to change as +# well +_BINARY_PRECEDENCE = { + "LOR": 0, + "LAND": 1, + "OR": 2, + "XOR": 3, + "AND": 4, + "EQ": 5, + "NE": 5, + "GT": 6, + "GE": 6, + "LT": 6, + "LE": 6, + "RSHIFT": 7, + "LSHIFT": 7, + "PLUS": 8, + "MINUS": 8, + "TIMES": 9, + "DIVIDE": 9, + "MOD": 9, +} + +_STORAGE_CLASS = {"AUTO", "REGISTER", "STATIC", "EXTERN", "TYPEDEF", "_THREAD_LOCAL"} + +_FUNCTION_SPEC = {"INLINE", "_NORETURN"} + +_TYPE_QUALIFIER = {"CONST", "RESTRICT", "VOLATILE", "_ATOMIC"} + +_TYPE_SPEC_SIMPLE = { + "VOID", + "_BOOL", + "CHAR", + "SHORT", + "INT", + "LONG", + "FLOAT", + "DOUBLE", + "_COMPLEX", + "SIGNED", + "UNSIGNED", + "__INT128", +} + +_DECL_START = ( + _STORAGE_CLASS + | _FUNCTION_SPEC + | _TYPE_QUALIFIER + | _TYPE_SPEC_SIMPLE + | {"TYPEID", "STRUCT", "UNION", "ENUM", "_ALIGNAS", "_ATOMIC"} +) + +_EXPR_START = { + "ID", + "LPAREN", + "PLUSPLUS", + "MINUSMINUS", + "PLUS", + "MINUS", + "TIMES", + "AND", + "NOT", + "LNOT", + "SIZEOF", + "_ALIGNOF", + "OFFSETOF", +} + +_INT_CONST = { + "INT_CONST_DEC", + "INT_CONST_OCT", + "INT_CONST_HEX", + "INT_CONST_BIN", + "INT_CONST_CHAR", +} + +_FLOAT_CONST = {"FLOAT_CONST", "HEX_FLOAT_CONST"} + +_CHAR_CONST = { + "CHAR_CONST", + "WCHAR_CONST", + "U8CHAR_CONST", + "U16CHAR_CONST", + "U32CHAR_CONST", +} + +_STRING_LITERAL = {"STRING_LITERAL"} + +_WSTR_LITERAL = { + "WSTRING_LITERAL", + "U8STRING_LITERAL", + "U16STRING_LITERAL", + "U32STRING_LITERAL", +} + +_STARTS_EXPRESSION = ( + _EXPR_START + | _INT_CONST + | _FLOAT_CONST + | _CHAR_CONST + | _STRING_LITERAL + | _WSTR_LITERAL +) + +_STARTS_STATEMENT = { + "LBRACE", + "IF", + "SWITCH", + "WHILE", + "DO", + "FOR", + "GOTO", + "BREAK", + "CONTINUE", + "RETURN", + "CASE", + "DEFAULT", + "PPPRAGMA", + "_PRAGMA", + "_STATIC_ASSERT", + "SEMI", +} + + +class _TokenStream: + """Wraps a lexer to provide convenient, buffered access to the underlying + token stream. The lexer is expected to be initialized with the input + string already. + """ + + def __init__(self, lexer: CLexer) -> None: + self._lexer = lexer + self._buffer: List[Optional[_Token]] = [] + self._index = 0 + + def peek(self, k: int = 1) -> Optional[_Token]: + """Peek at the k-th next token in the stream, without consuming it. + + Examples: + k=1 returns the immediate next token. + k=2 returns the token after that. + """ + if k <= 0: + return None + self._fill(k) + return self._buffer[self._index + k - 1] + + def next(self) -> Optional[_Token]: + """Consume a single token and return it.""" + self._fill(1) + tok = self._buffer[self._index] + self._index += 1 + return tok + + # The 'mark' and 'reset' methods are useful for speculative parsing with + # backtracking; when the parser needs to examine a sequence of tokens + # and potentially decide to try a different path on the same sequence, it + # can call 'mark' to obtain the current token position, and if the first + # path fails restore the position with `reset(pos)`. + def mark(self) -> int: + return self._index + + def reset(self, mark: int) -> None: + self._index = mark + + def _fill(self, n: int) -> None: + while len(self._buffer) < self._index + n: + tok = self._lexer.token() + self._buffer.append(tok) + if tok is None: + break + + +# Declaration specifiers are represented by a dictionary with entries: +# - qual: a list of type qualifiers +# - storage: a list of storage class specifiers +# - type: a list of type specifiers +# - function: a list of function specifiers +# - alignment: a list of alignment specifiers +class _DeclSpec(TypedDict): + qual: List[Any] + storage: List[Any] + type: List[Any] + function: List[Any] + alignment: List[Any] + + +_DeclSpecKind = Literal["qual", "storage", "type", "function", "alignment"] + + +class _DeclInfo(TypedDict): + # Declarator payloads used by declaration/initializer parsing: + # - decl: the declarator node (may be None for abstract/implicit cases) + # - init: optional initializer expression + # - bitsize: optional bit-field width expression (for struct declarators) + decl: Optional[c_ast.Node] + init: Optional[c_ast.Node] + bitsize: Optional[c_ast.Node] diff --git a/source/target-vendors/cp312/pydantic-2.13.5.dist-info/METADATA b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/METADATA new file mode 100644 index 0000000..10d0af0 --- /dev/null +++ b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/METADATA @@ -0,0 +1,1307 @@ +Metadata-Version: 2.5 +Name: pydantic +Version: 2.13.5 +Summary: Data validation using Python type hints +Project-URL: Homepage, https://github.com/pydantic/pydantic +Project-URL: Documentation, https://docs.pydantic.dev +Project-URL: Funding, https://github.com/sponsors/samuelcolvin +Project-URL: Source, https://github.com/pydantic/pydantic +Project-URL: Changelog, https://docs.pydantic.dev/latest/changelog/ +Author-email: Samuel Colvin , Eric Jolibois , Hasan Ramezani , Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, Terrence Dorsey , David Montague , Serge Matveenko , Marcelo Trylesinski , Sydney Runkle , David Hewitt , Alex Hall , Victorien Plot +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 5 - Production/Stable +Classifier: Framework :: Hypothesis +Classifier: Framework :: Pydantic +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.9 +Requires-Dist: annotated-types>=0.6.0 +Requires-Dist: pydantic-core==2.46.5 +Requires-Dist: typing-extensions>=4.14.1 +Requires-Dist: typing-inspection>=0.4.2 +Provides-Extra: email +Requires-Dist: email-validator>=2.0.0; extra == 'email' +Provides-Extra: timezone +Requires-Dist: tzdata; (python_version >= '3.9' and platform_system == 'Windows') and extra == 'timezone' +Description-Content-Type: text/markdown + +# Pydantic Validation + +[![CI](https://img.shields.io/github/actions/workflow/status/pydantic/pydantic/ci.yml?branch=main&logo=github&label=CI)](https://github.com/pydantic/pydantic/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) +[![Coverage](https://coverage-badge.samuelcolvin.workers.dev/pydantic/pydantic.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/pydantic/pydantic) +[![pypi](https://img.shields.io/pypi/v/pydantic.svg)](https://pypi.python.org/pypi/pydantic) +[![CondaForge](https://img.shields.io/conda/v/conda-forge/pydantic.svg)](https://anaconda.org/conda-forge/pydantic) +[![downloads](https://static.pepy.tech/badge/pydantic/month)](https://pepy.tech/project/pydantic) +[![versions](https://img.shields.io/pypi/pyversions/pydantic.svg)](https://github.com/pydantic/pydantic) +[![license](https://img.shields.io/github/license/pydantic/pydantic.svg)](https://github.com/pydantic/pydantic/blob/main/LICENSE) +[![Pydantic v2](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/pydantic/pydantic/main/docs/badge/v2.json)](https://docs.pydantic.dev/latest/contributing/#badges) +[![llms.txt](https://img.shields.io/badge/llms.txt-green)](https://docs.pydantic.dev/latest/llms.txt) + +Data validation using Python type hints. + +Fast and extensible, Pydantic plays nicely with your linters/IDE/brain. +Define how data should be in pure, canonical Python 3.9+; validate it with Pydantic. + +## Pydantic Logfire :fire: + +We've launched Pydantic Logfire to help you monitor your applications. +[Learn more](https://pydantic.dev/logfire/?utm_source=pydantic_validation) + +## Pydantic V1.10 vs. V2 + +Pydantic V2 is a ground-up rewrite that offers many new features, performance improvements, and some breaking changes compared to Pydantic V1. + +If you're using Pydantic V1 you may want to look at the +[pydantic V1.10 Documentation](https://docs.pydantic.dev/) or, +[`1.10.X-fixes` git branch](https://github.com/pydantic/pydantic/tree/1.10.X-fixes). Pydantic V2 also ships with the latest version of Pydantic V1 built in so that you can incrementally upgrade your code base and projects: `from pydantic import v1 as pydantic_v1`. + +## Help + +See [documentation](https://docs.pydantic.dev/) for more details. + +## Installation + +Install using `pip install -U pydantic` or `conda install pydantic -c conda-forge`. +For more installation options to make Pydantic even faster, +see the [Install](https://docs.pydantic.dev/install/) section in the documentation. + +## A Simple Example + +```python +from datetime import datetime +from typing import Optional +from pydantic import BaseModel + +class User(BaseModel): + id: int + name: str = 'John Doe' + signup_ts: Optional[datetime] = None + friends: list[int] = [] + +external_data = {'id': '123', 'signup_ts': '2017-06-01 12:22', 'friends': [1, '2', b'3']} +user = User(**external_data) +print(user) +#> User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] +print(user.id) +#> 123 +``` + +## Contributing + +For guidance on setting up a development environment and how to make a +contribution to Pydantic, see +[Contributing to Pydantic](https://docs.pydantic.dev/contributing/). + +## Reporting a Security Vulnerability + +See our [security policy](https://github.com/pydantic/pydantic/security/policy). + +## Changelog + + + + + +## v2.13.5 (2026-08-28) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.5) + +### What's Changed + +#### Fixes + +* Allow reuse of validators when plugins are set by [@Viicos](https://github.com/Viicos) in [#13535](https://github.com/pydantic/pydantic/pull/13535) +* Fix missing GC traversal on some `pydantic-core` struct fields by [@Viicos](https://github.com/Viicos) in [#13624](https://github.com/pydantic/pydantic/pull/13624) +* Fix missing GC traversal in `pydantic-core` for `GeneralFieldsSerializer` by [@Viicos](https://github.com/Viicos) in [#13629](https://github.com/pydantic/pydantic/pull/13629) +* Count validated model fields once in smart unions by [@tamird](https://github.com/tamird) in [#13731](https://github.com/pydantic/pydantic/pull/13731) + +## v2.13.4 (2026-05-06) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.4) + +### What's Changed + +#### Packaging + +* Bump libc from 0.2.155 to 0.2.185 by [@Viicos](https://github.com/Viicos) in [#13109](https://github.com/pydantic/pydantic/pull/13109) +* Adapt `pydantic-core` linker flags on macOS by [@washingtoneg](https://github.com/washingtoneg) and [@Viicos](https://github.com/Viicos) in [#13147](https://github.com/pydantic/pydantic/pull/13147) + +#### Fixes + +* Preserve `RootModel` core metadata by [@Viicos](https://github.com/Viicos) in [#13129](https://github.com/pydantic/pydantic/pull/13129) + +## v2.13.3 (2026-04-20) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.3) + +### What's Changed + +#### Fixes + +* Handle `AttributeError` subclasses with `from_attributes` by [@Viicos](https://github.com/Viicos) in [#13096](https://github.com/pydantic/pydantic/pull/13096) + +## v2.13.2 (2026-04-17) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.2) + +### What's Changed + +#### Fixes + +* Fix `ValidationInfo.field_name` missing with `model_validate_json()` by [@Viicos](https://github.com/Viicos) in [#13084](https://github.com/pydantic/pydantic/pull/13084) + +## v2.13.1 (2026-04-15) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.1) + +### What's Changed + +#### Fixes + +* Fix `ValidationInfo.data` missing with `model_validate_json()` by [@davidhewitt](https://github.com/davidhewitt) in [#13079](https://github.com/pydantic/pydantic/pull/13079) + +## v2.13.0 (2026-04-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0) + +The highlights of the v2.13 release are available in the [blog post](https://pydantic.dev/articles/pydantic-v2-13-release). +Several minor changes (considered non-breaking changes according to our [versioning policy](https://pydantic.dev/docs/validation/2.13/get-started/version-policy/#pydantic-v2)) +are also included in this release. Make sure to look into them before upgrading. + +This release contains the updated `pydantic.v1` namespace, matching version 1.10.26 which includes support for Python 3.14. + +### What's Changed + +See the beta releases for all changes sinces 2.12. + +#### New Features + +* Allow default factories of private attributes to take validated model data by [@Viicos](https://github.com/Viicos) in [#13013](https://github.com/pydantic/pydantic/pull/13013) + +#### Changes + +* Warn when serializing fixed length tuples with too few items by [@arvindsaripalli](https://github.com/arvindsaripalli) in [#13016](https://github.com/pydantic/pydantic/pull/13016) + +#### Fixes + +* Change type of `Any` when synthesizing `_build_sources` for `BaseSettings.__init__()` signature in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#13049](https://github.com/pydantic/pydantic/pull/13049) +* Fix model equality when using runtime `extra` configuration by [@Viicos](https://github.com/Viicos) in [#13062](https://github.com/pydantic/pydantic/pull/13062) + +#### Packaging + +* Add zizmor for GitHub Actions workflow linting by [@Viicos](https://github.com/Viicos) in [#13039](https://github.com/pydantic/pydantic/pull/13039) +* Update jiter to v0.14.0 to fix a segmentation fault on musl Linux by [@Viicos](https://github.com/Viicos) in [#13064](https://github.com/pydantic/pydantic/pull/13064) + +### New Contributors + +* [@arvindsaripalli](https://github.com/arvindsaripalli) made their first contribution in [#13016](https://github.com/pydantic/pydantic/pull/13016) + +## v2.13.0b3 (2026-03-31) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0b3) + +### What's Changed + +#### New Features + +* Add `ascii_only` option to `StringConstraints` by [@ai-man-codes](https://github.com/ai-man-codes) in [#12907](https://github.com/pydantic/pydantic/pull/12907) +* Support `exclude_if` in computed fields by [@andresliszt](https://github.com/andresliszt) in [#12748](https://github.com/pydantic/pydantic/pull/12748) +* Push down constraints in unions involving `MISSING` sentinel by [@Viicos](https://github.com/Viicos) in [#12908](https://github.com/pydantic/pydantic/pull/12908) + +#### Changes + +* Track extra fields set after init in `model_fields_set` by [@navalprakhar](https://github.com/navalprakhar) in [#12817](https://github.com/pydantic/pydantic/pull/12817) +* Do not include annotations that are not part of named tuple fields by [@galuszkak](https://github.com/galuszkak) in [#12951](https://github.com/pydantic/pydantic/pull/12951) +* No longer fall back to trying all union members when the variant selected by discriminator fails to serialize by [@navalprakhar](https://github.com/navalprakhar) in [#12825](https://github.com/pydantic/pydantic/pull/12825) + +#### Fixes + +* Support discriminator metadata outside union type alias by [@Viicos](https://github.com/Viicos) in [#12785](https://github.com/pydantic/pydantic/pull/12785) +* Respect `extras_schema` when only `extra_fields_behavior` is set on the config in JSON Schema generation for typed dictionaries by [@Viicos](https://github.com/Viicos) in [#12810](https://github.com/pydantic/pydantic/pull/12810) +* Ensure `__pydantic_private__` is set in `model_construct()` with user-defined `model_post_init()` by [@nightcityblade](https://github.com/nightcityblade) in [#12816](https://github.com/pydantic/pydantic/pull/12816) +* Handle all schema generation errors in `InstanceOf` by [@Viicos](https://github.com/Viicos) in [#12705](https://github.com/pydantic/pydantic/pull/12705) +* Allow dynamic models created with `create_model()` to be used as annotations in the Mypy plugin by [@Br1an67](https://github.com/Br1an67) in [#12879](https://github.com/pydantic/pydantic/pull/12879) +* Check for `PlaceholderNode` in Mypy plugin by [@Viicos](https://github.com/Viicos) in [#12929](https://github.com/pydantic/pydantic/pull/12929) +* Try other branches in smart union in case of omit errors by [@mikeedjones](https://github.com/mikeedjones) in [#12758](https://github.com/pydantic/pydantic/pull/12758) +* Patch unset attributes with `MISSING` during model serialization with `exclude_unset` by [@davidhewitt](https://github.com/davidhewitt) in [#12905](https://github.com/pydantic/pydantic/pull/12905) +* Ensure custom `__init__()` is called when using `model_validate_strings()` by [@siewcapital](https://github.com/siewcapital) in [#12897](https://github.com/pydantic/pydantic/pull/12897) + +#### Packaging + +* Add riscv64 build target for manylinux by [@boosterl](https://github.com/boosterl) in [#12723](https://github.com/pydantic/pydantic/pull/12723) + +### New Contributors + +* [@kelsonbrito50](https://github.com/kelsonbrito50) made their first contribution in [#12860](https://github.com/pydantic/pydantic/pull/12860) +* [@boosterl](https://github.com/boosterl) made their first contribution in [#12723](https://github.com/pydantic/pydantic/pull/12723) +* [@adityagiri3600](https://github.com/adityagiri3600) made their first contribution in [#12868](https://github.com/pydantic/pydantic/pull/12868) +* [@navalprakhar](https://github.com/navalprakhar) made their first contribution in [#12817](https://github.com/pydantic/pydantic/pull/12817) +* [@Br1an67](https://github.com/Br1an67) made their first contribution in [#12879](https://github.com/pydantic/pydantic/pull/12879) +* [@rmorshea](https://github.com/rmorshea) made their first contribution in [#12910](https://github.com/pydantic/pydantic/pull/12910) +* [@N3XT3R1337](https://github.com/N3XT3R1337) made their first contribution in [#12922](https://github.com/pydantic/pydantic/pull/12922) +* [@ai-man-codes](https://github.com/ai-man-codes) made their first contribution in [#12907](https://github.com/pydantic/pydantic/pull/12907) +* [@Yume05-dev](https://github.com/Yume05-dev) made their first contribution in [#12953](https://github.com/pydantic/pydantic/pull/12953) +* [@galuszkak](https://github.com/galuszkak) made their first contribution in [#12951](https://github.com/pydantic/pydantic/pull/12951) +* [@siewcapital](https://github.com/siewcapital) made their first contribution in [#12897](https://github.com/pydantic/pydantic/pull/12897) + +## v2.13.0b2 (2026-02-24) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0b2) + +### What's Changed + +#### Fixes + +* Fix backported V1 namespace by [@Viicos](https://github.com/Viicos) in [#12855](https://github.com/pydantic/pydantic/pull/12855) +* Allow any type form to be used in `validate_as()` by [@bledden](https://github.com/bledden) in [#12846](https://github.com/pydantic/pydantic/pull/12846) +* Fix walrus operator precedence in `UrlConstraints.__get_pydantic_core_schema__()` by [@bysiber](https://github.com/bysiber) in [#12826](https://github.com/pydantic/pydantic/pull/12826) + +### New Contributors + +* [@bledden](https://github.com/bledden) made their first contribution in [#12846](https://github.com/pydantic/pydantic/pull/12846) +* [@bysiber](https://github.com/bysiber) made their first contribution in [#12827](https://github.com/pydantic/pydantic/pull/12827) + +## v2.13.0b1 (2026-02-23) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.13.0b1) + +This is the first beta release of the 2.13 version, mainly providing bug fixes and performance improvements +for validation and serialization. + +Notable changes include: + +* Add a new `polymorphic_serialization` option, solving issues with `serialize_as_any` introduced in 2.12. +* Latest V1.10.26 release under the `pydantic.v1` namespace. This version includes support for Python 3.14. +* The [`pydantic-core`](https://github.com/pydantic/pydantic-core/) repository was merged inside the main `pydantic` one. + +### What's Changed + +#### New Features + +* Add `polymorphic_serialization` option by [@davidhewitt](https://github.com/davidhewitt) in [#12518](https://github.com/pydantic/pydantic/pull/12518) +* Support Root models with `Literal` root types as discriminator field types by [@YassinNouh21](https://github.com/YassinNouh21) in [#12680](https://github.com/pydantic/pydantic/pull/12680) + +#### Changes + +* Migrate `pydantic-core` CI by [@Viicos](https://github.com/Viicos) in [#12752](https://github.com/pydantic/pydantic/pull/12752) +* Import `pydantic-core` into pydantic by [@davidhewitt](https://github.com/davidhewitt) in [#12481](https://github.com/pydantic/pydantic/pull/12481) +* Backport V1 changes up to v1.10.26 by [@Viicos](https://github.com/Viicos) in [#12663](https://github.com/pydantic/pydantic/pull/12663) +* Use the `complex()` constructor unconditionally when validating `complex` Python data by [@tanmaymunjal](https://github.com/tanmaymunjal) in [#12498](https://github.com/pydantic/pydantic/pull/12498) +* Add support for three-tuple input for `Decimal` by [@tanmaymunjal](https://github.com/tanmaymunjal) in [#12500](https://github.com/pydantic/pydantic/pull/12500) +* Align `@field_serializer` logic with `@field_validator` by [@Viicos](https://github.com/Viicos) in [#12577](https://github.com/pydantic/pydantic/pull/12577) +* Make `PydanticUserError` a `RuntimeError` instead of a `TypeError` by [@poliakovva](https://github.com/poliakovva) in [#12579](https://github.com/pydantic/pydantic/pull/12579) +* Remove redundant serialization attempts in nested unions by [@davidhewitt](https://github.com/davidhewitt) in [#12604](https://github.com/pydantic/pydantic/pull/12604) +* Copy `root` value when making root model shallow copies by [@YassinNouh21](https://github.com/YassinNouh21) in [#12679](https://github.com/pydantic/pydantic/pull/12679) +* Ensure deterministic JSON schema defaults by sorting sets by [@drshvik](https://github.com/drshvik) in [#12760](https://github.com/pydantic/pydantic/pull/12760) + +#### Performance + +* Refactor `DecoratorInfos.build()` implementation by [@Viicos](https://github.com/Viicos) in [#12536](https://github.com/pydantic/pydantic/pull/12536) +* Cache compiled regex in `pydantic-core` by [@Viicos](https://github.com/Viicos) in [#12549](https://github.com/pydantic/pydantic/pull/12549) +* Optimize creation of `Literal` validators by [@davidhewitt](https://github.com/davidhewitt) in [#12569](https://github.com/pydantic/pydantic/pull/12569) +* Optimize implementation of `LookupKey` by [@davidhewitt](https://github.com/davidhewitt) in [#12571](https://github.com/pydantic/pydantic/pull/12571) +* Use python strings for field names by [@davidhewitt](https://github.com/davidhewitt) in [#12631](https://github.com/pydantic/pydantic/pull/12631) +* Optimize datetime formatting code by [@davidhewitt](https://github.com/davidhewitt) in [#12626](https://github.com/pydantic/pydantic/pull/12626) +* Validate JSON model data by iteration by [@davidhewitt](https://github.com/davidhewitt) in [#12550](https://github.com/pydantic/pydantic/pull/12550) +* Optimize annotations evaluation of Pydantic models by [@Viicos](https://github.com/Viicos) in [#12681](https://github.com/pydantic/pydantic/pull/12681) +* Optimize `FieldInfo._copy()` by [@Viicos](https://github.com/Viicos) in [#12727](https://github.com/pydantic/pydantic/pull/12727) + +#### Fixes + +* Fix `FieldInfo` rebuilding when parameterizing generic models with an `Annotated` type by [@Viicos](https://github.com/Viicos) in [#12463](https://github.com/pydantic/pydantic/pull/12463) +* Fix nested model schema deduplication in JSON schema generation by [@marwan-alloreview](https://github.com/marwan-alloreview) in [#12494](https://github.com/pydantic/pydantic/pull/12494) +* Fix `InitVar` being ignored when using with the `pydantic.Field()` function by [@Viicos](https://github.com/Viicos) in [#12495](https://github.com/pydantic/pydantic/pull/12495) +* Fix support for enums with `NamedTuple` as values by [@Viicos](https://github.com/Viicos) in [#12506](https://github.com/pydantic/pydantic/pull/12506) +* Do not delete mock validator/serializer in `rebuild_dataclass()` by [@Viicos](https://github.com/Viicos) in [#12513](https://github.com/pydantic/pydantic/pull/12513) +* Require test suite to pass with free threading, switch back to global generic types cache by [@davidhewitt](https://github.com/davidhewitt) in [#12537](https://github.com/pydantic/pydantic/pull/12537) +* Refactor `__pydantic_extra__` annotation handling by [@Viicos](https://github.com/Viicos) in [#12563](https://github.com/pydantic/pydantic/pull/12563) +* Do not add claim of UUID "safety" provision by [@davidhewitt](https://github.com/davidhewitt) in [#12567](https://github.com/pydantic/pydantic/pull/12567) +* Use Python hash to perform lookup in tagged union serializer by [@davidhewitt](https://github.com/davidhewitt) in [#12594](https://github.com/pydantic/pydantic/pull/12594) +* Do not emit serialization warning `MISSING` sentinel is present in a nested model by [@Viicos](https://github.com/Viicos) in [#12635](https://github.com/pydantic/pydantic/pull/12635) +* Do not eagerly evaluate annotations in signature logic by [@Viicos](https://github.com/Viicos) in [#12660](https://github.com/pydantic/pydantic/pull/12660) +* Fix serialization of typed dict unions when `exclude_none` is set by [@davidhewitt](https://github.com/davidhewitt) in [#12677](https://github.com/pydantic/pydantic/pull/12677) +* Do not reuse prebuilt serializers/validators on rebuilds by [@lmmx](https://github.com/lmmx) in [#12689](https://github.com/pydantic/pydantic/pull/12689) +* Fix type annotation of `field_definitions` in `create_model()` by [@lehmann-hqs](https://github.com/lehmann-hqs) in [#12734](https://github.com/pydantic/pydantic/pull/12734) +* Fix incorrect dataclass constructor signature when overriding class `kw_only` with `Field()` by [@jfadia](https://github.com/jfadia) in [#12741](https://github.com/pydantic/pydantic/pull/12741) +* Use `typing.Union` when replacing types under Python 3.14 by [@Viicos](https://github.com/Viicos) in [#12733](https://github.com/pydantic/pydantic/pull/12733) +* Improve ImportString error when internal imports fail by [@tsembp](https://github.com/tsembp) in [#12740](https://github.com/pydantic/pydantic/pull/12740) +* Fix serializing complex numbers with negative zero imaginary part by [@lhnwrk](https://github.com/lhnwrk) in [#12770](https://github.com/pydantic/pydantic/pull/12770) +* Preserve custom docstrings on stdlib dataclasses in JSON schema by [@nightcityblade](https://github.com/nightcityblade) in [#12815](https://github.com/pydantic/pydantic/pull/12815) + +#### Packaging + +* Bump Rust url dependency from 2.5.4 to 2.5.7 in `pydantic-core` by [@dependabot](https://github.com/dependabot)[bot] in [#12508](https://github.com/pydantic/pydantic/pull/12508) +* Bump Rust minimum version to 1.88, use edition 2024 by [@davidhewitt](https://github.com/davidhewitt) and [@Viicos](https://github.com/Viicos) in [#12551](https://github.com/pydantic/pydantic/pull/12551) and [#12752](https://github.com/pydantic/pydantic/pull/12752) +* Bump PyO3 to 0.28, jiter to 0.13 by [@davidhewitt](https://github.com/davidhewitt) in [#12767](https://github.com/pydantic/pydantic/pull/12767) + +### New Contributors + +* [@marwan-alloreview](https://github.com/marwan-alloreview) made their first contribution in [#12494](https://github.com/pydantic/pydantic/pull/12494) +* [@tanmaymunjal](https://github.com/tanmaymunjal) made their first contribution in [#12498](https://github.com/pydantic/pydantic/pull/12498) +* [@poliakovva](https://github.com/poliakovva) made their first contribution in [#12579](https://github.com/pydantic/pydantic/pull/12579) +* [@lehmann-hqs](https://github.com/lehmann-hqs) made their first contribution in [#12734](https://github.com/pydantic/pydantic/pull/12734) +* [@jfadia](https://github.com/jfadia) made their first contribution in [#12741](https://github.com/pydantic/pydantic/pull/12741) +* [@tsembp](https://github.com/tsembp) made their first contribution in [#12740](https://github.com/pydantic/pydantic/pull/12740) +* [@drshvik](https://github.com/drshvik) made their first contribution in [#12760](https://github.com/pydantic/pydantic/pull/12760) +* [@lhnwrk](https://github.com/lhnwrk) made their first contribution in [#12770](https://github.com/pydantic/pydantic/pull/12770) +* [@nightcityblade](https://github.com/nightcityblade) made their first contribution in [#12815](https://github.com/pydantic/pydantic/pull/12811) + +## v2.12.5 (2025-11-26) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.5) + +This is the fifth 2.12 patch release, addressing an issue with the `MISSING` sentinel and providing several documentation improvements. + +The next 2.13 minor release will be published in a couple weeks, and will include a new *polymorphic serialization* feature addressing +the remaining unexpected changes to the *serialize as any* behavior. + +* Fix pickle error when using `model_construct()` on a model with `MISSING` as a default value by [@ornariece](https://github.com/ornariece) in [#12522](https://github.com/pydantic/pydantic/pull/12522). +* Several updates to the documentation by [@Viicos](https://github.com/Viicos). + +## v2.12.4 (2025-11-05) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.4) + +This is the fourth 2.12 patch release, fixing more regressions, and reverting a change in the `build()` method +of the [`AnyUrl` and Dsn types](https://docs.pydantic.dev/latest/api/networks/). + +This patch release also fixes an issue with the serialization of IP address types, when `serialize_as_any` is used. The next patch release +will try to address the remaining issues with *serialize as any* behavior by introducing a new *polymorphic serialization* feature, that +should be used in most cases in place of *serialize as any*. + +* Fix issue with forward references in parent `TypedDict` classes by [@Viicos](https://github.com/Viicos) in [#12427](https://github.com/pydantic/pydantic/pull/12427). + + This issue is only relevant on Python 3.14 and greater. + +* Exclude fields with `exclude_if` from JSON Schema required fields by [@Viicos](https://github.com/Viicos) in [#12430](https://github.com/pydantic/pydantic/pull/12430) +* Revert URL percent-encoding of credentials in the `build()` method + of the [`AnyUrl` and Dsn types](https://docs.pydantic.dev/latest/api/networks/) by [@davidhewitt](https://github.com/davidhewitt) in + [pydantic-core#1833](https://github.com/pydantic/pydantic-core/pull/1833). + + This was initially considered as a bugfix, but caused regressions and as such was fully reverted. The next release will include + an opt-in option to percent-encode components of the URL. + +* Add type inference for IP address types by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1868](https://github.com/pydantic/pydantic-core/pull/1868). + + The 2.12 changes to the `serialize_as_any` behavior made it so that IP address types could not properly serialize to JSON. + +* Avoid getting default values from defaultdict by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1853](https://github.com/pydantic/pydantic-core/pull/1853). + + This fixes a subtle regression in the validation behavior of the [`collections.defaultdict`](https://docs.python.org/3/library/collections.html#collections.defaultdict) + type. + +* Fix issue with field serializers on nested typed dictionaries by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1879](https://github.com/pydantic/pydantic-core/pull/1879). +* Add more `pydantic-core` builds for the three-threaded version of Python 3.14 by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1864](https://github.com/pydantic/pydantic-core/pull/1864). + +## v2.12.3 (2025-10-17) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.3) + +### What's Changed + +This is the third 2.12 patch release, fixing issues related to the `FieldInfo` class, and reverting a change to the supported +[*after* model validator](https://docs.pydantic.dev/latest/concepts/validators/#model-validators) function signatures. + +* Raise a warning when an invalid after model validator function signature is raised by [@Viicos](https://github.com/Viicos) in [#12414](https://github.com/pydantic/pydantic/pull/12414). + Starting in 2.12.0, using class methods for *after* model validators raised an error, but the error wasn't raised concistently. We decided + to emit a deprecation warning instead. +* Add [`FieldInfo.asdict()`](https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.FieldInfo.asdict) method, improve documentation around `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#12411](https://github.com/pydantic/pydantic/pull/12411). + This also add back support for mutations on `FieldInfo` classes, that are reused as `Annotated` metadata. **However**, note that this is still + *not* a supported pattern. Instead, please refer to the [added example](https://docs.pydantic.dev/latest/examples/dynamic_models/) in the documentation. + +The [blog post](https://pydantic.dev/articles/pydantic-v2-12-release#changes) section on changes was also updated to document the changes related to `serialize_as_any`. + +## v2.12.2 (2025-10-14) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.2) + +### What's Changed + +#### Fixes + +* Release a new `pydantic-core` version, as a corrupted CPython 3.10 `manylinux2014_aarch64` wheel got uploaded ([pydantic-core#1843](https://github.com/pydantic/pydantic-core/pull/1843)). +* Fix issue with recursive generic models with a parent model class by [@Viicos](https://github.com/Viicos) in [#12398](https://github.com/pydantic/pydantic/pull/12398) + +## v2.12.1 (2025-10-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.1) + +### What's Changed + +This is the first 2.12 patch release, addressing most (but not all yet) regressions from the initial 2.12.0 release. + +#### Fixes + +* Do not evaluate annotations when inspecting validators and serializers by [@Viicos](https://github.com/Viicos) in [#12355](https://github.com/pydantic/pydantic/pull/12355) +* Make sure `None` is converted as `NoneType` in Python 3.14 by [@Viicos](https://github.com/Viicos) in [#12370](https://github.com/pydantic/pydantic/pull/12370) +* Backport V1 runtime warning when using Python 3.14 by [@Viicos](https://github.com/Viicos) in [#12367](https://github.com/pydantic/pydantic/pull/12367) +* Fix error message for invalid validator signatures by [@Viicos](https://github.com/Viicos) in [#12366](https://github.com/pydantic/pydantic/pull/12366) +* Populate field name in `ValidationInfo` for validation of default value by [@Viicos](https://github.com/Viicos) in [pydantic-core#1826](https://github.com/pydantic/pydantic-core/pull/1826) +* Encode credentials in `MultiHostUrl` builder by [@willswire](https://github.com/willswire) in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) +* Respect field serializers when using `serialize_as_any` serialization flag by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) +* Fix various `RootModel` serialization issues by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1836](https://github.com/pydantic/pydantic-core/pull/1836) + +### New Contributors + +* [@willswire](https://github.com/willswire) made their first contribution in [pydantic-core#1829](https://github.com/pydantic/pydantic-core/pull/1829) + +## v2.12.0 (2025-10-07) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0) + +This is the final 2.12 release. It features the work of 20 external contributors and provides useful new features, along with initial Python 3.14 support. +Several minor changes (considered non-breaking changes according to our [versioning policy](https://docs.pydantic.dev/2.12/version-policy/#pydantic-v2)) +are also included in this release. Make sure to look into them before upgrading. + +**Note that Pydantic V1 is not compatible with Python 3.14 and greater**. + +### What's Changed + +See the beta releases for all changes sinces 2.11. + +#### New Features + +* Add `extra` parameter to the validate functions by [@anvilpete](https://github.com/anvilpete) in [#12233](https://github.com/pydantic/pydantic/pull/12233) +* Add `exclude_computed_fields` serialization option by [@Viicos](https://github.com/Viicos) in [#12334](https://github.com/pydantic/pydantic/pull/12334) +* Add `preverse_empty_path` URL options by [@Viicos](https://github.com/Viicos) in [#12336](https://github.com/pydantic/pydantic/pull/12336) +* Add `union_format` parameter to JSON Schema generation by [@Viicos](https://github.com/Viicos) in [#12147](https://github.com/pydantic/pydantic/pull/12147) +* Add `__qualname__` parameter for `create_model` by [@Atry](https://github.com/Atry) in [#12001](https://github.com/pydantic/pydantic/pull/12001) + +#### Fixes + +* Do not try to infer name from lambda definitions in pipelines API by [@Viicos](https://github.com/Viicos) in [#12289](https://github.com/pydantic/pydantic/pull/12289) +* Use proper namespace for functions in `TypeAdapter` by [@Viicos](https://github.com/Viicos) in [#12324](https://github.com/pydantic/pydantic/pull/12324) +* Use `Any` for context type annotation in `TypeAdapter` by [@inducer](https://github.com/inducer) in [#12279](https://github.com/pydantic/pydantic/pull/12279) +* Expose `FieldInfo` in `pydantic.fields.__all__` by [@Viicos](https://github.com/Viicos) in [#12339](https://github.com/pydantic/pydantic/pull/12339) +* Respect `validation_alias` in `@validate_call` by [@Viicos](https://github.com/Viicos) in [#12340](https://github.com/pydantic/pydantic/pull/12340) +* Use `Any` as context annotation in plugin API by [@Viicos](https://github.com/Viicos) in [#12341](https://github.com/pydantic/pydantic/pull/12341) +* Use proper `stacklevel` in warnings when possible by [@Viicos](https://github.com/Viicos) in [#12342](https://github.com/pydantic/pydantic/pull/12342) + +#### Packaging + +* Update V1 copy to v1.10.24 by [@Viicos](https://github.com/Viicos) in [#12338](https://github.com/pydantic/pydantic/pull/12338) + +### New Contributors + +* [@anvilpete](https://github.com/anvilpete) made their first contribution in [#12233](https://github.com/pydantic/pydantic/pull/12233) +* [@JonathanWindell](https://github.com/JonathanWindell) made their first contribution in [#12327](https://github.com/pydantic/pydantic/pull/12327) +* [@inducer](https://github.com/inducer) made their first contribution in [#12279](https://github.com/pydantic/pydantic/pull/12279) +* [@Atry](https://github.com/Atry) made their first contribution in [#12001](https://github.com/pydantic/pydantic/pull/12001) + +## v2.12.0b1 (2025-10-03) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0b1) + +This is the first beta release of the upcoming 2.12 release. + +### What's Changed + +#### New Features + +* Add support for `exclude_if` at the field level by [@andresliszt](https://github.com/andresliszt) in [#12141](https://github.com/pydantic/pydantic/pull/12141) +* Add `ValidateAs` annotation helper by [@Viicos](https://github.com/Viicos) in [#11942](https://github.com/pydantic/pydantic/pull/11942) +* Add configuration options for validation and JSON serialization of temporal types by [@ollz272](https://github.com/ollz272) in [#12068](https://github.com/pydantic/pydantic/pull/12068) +* Add support for PEP 728 by [@Viicos](https://github.com/Viicos) in [#12179](https://github.com/pydantic/pydantic/pull/12179) +* Add field name in serialization error by [@NicolasPllr1](https://github.com/NicolasPllr1) in [pydantic-core#1799](https://github.com/pydantic/pydantic-core/pull/1799) +* Add option to preserve empty URL paths by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1789](https://github.com/pydantic/pydantic-core/pull/1789) + +#### Changes + +* Raise error if an incompatible `pydantic-core` version is installed by [@Viicos](https://github.com/Viicos) in [#12196](https://github.com/pydantic/pydantic/pull/12196) +* Remove runtime warning for experimental features by [@Viicos](https://github.com/Viicos) in [#12265](https://github.com/pydantic/pydantic/pull/12265) +* Warn if registering virtual subclasses on Pydantic models by [@Viicos](https://github.com/Viicos) in [#11669](https://github.com/pydantic/pydantic/pull/11669) + +#### Fixes + +* Fix `__getattr__()` behavior on Pydantic models when a property raised an `AttributeError` and extra values are present by [@raspuchin](https://github.com/raspuchin) in [#12106](https://github.com/pydantic/pydantic/pull/12106) +* Add test to prevent regression with Pydantic models used as annotated metadata by [@Viicos](https://github.com/Viicos) in [#12133](https://github.com/pydantic/pydantic/pull/12133) +* Allow to use property setters on Pydantic dataclasses with `validate_assignment` set by [@Viicos](https://github.com/Viicos) in [#12173](https://github.com/pydantic/pydantic/pull/12173) +* Fix mypy v2 plugin for upcoming mypy release by [@cdce8p](https://github.com/cdce8p) in [#12209](https://github.com/pydantic/pydantic/pull/12209) +* Respect custom title in functions JSON Schema by [@Viicos](https://github.com/Viicos) in [#11892](https://github.com/pydantic/pydantic/pull/11892) +* Fix `ImportString` JSON serialization for objects with a `name` attribute by [@chr1sj0nes](https://github.com/chr1sj0nes) in [#12219](https://github.com/pydantic/pydantic/pull/12219) +* Do not error on fields overridden by methods in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#12290](https://github.com/pydantic/pydantic/pull/12290) + +#### Packaging + +* Bump `pydantic-core` to v2.40.1 by [@Viicos](https://github.com/Viicos) in [#12314](https://github.com/pydantic/pydantic/pull/12314) + +### New Contributors + +* [@raspuchin](https://github.com/raspuchin) made their first contribution in [#12106](https://github.com/pydantic/pydantic/pull/12106) +* [@chr1sj0nes](https://github.com/chr1sj0nes) made their first contribution in [#12219](https://github.com/pydantic/pydantic/pull/12219) + +## v2.12.0a1 (2025-07-26) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.12.0a1) + +This is the first alpha release of the upcoming 2.12 release, which adds initial support for Python 3.14. + +### What's Changed + +#### New Features + +* Add `__pydantic_on_complete__()` hook that is called once model is fully ready to be used by [@DouweM](https://github.com/DouweM) in [#11762](https://github.com/pydantic/pydantic/pull/11762) +* Add initial support for Python 3.14 by [@Viicos](https://github.com/Viicos) in [#11991](https://github.com/pydantic/pydantic/pull/11991) +* Add regex patterns to JSON schema for `Decimal` type by [@Dima-Bulavenko](https://github.com/Dima-Bulavenko) in [#11987](https://github.com/pydantic/pydantic/pull/11987) +* Add support for `doc` attribute on dataclass fields by [@Viicos](https://github.com/Viicos) in [#12077](https://github.com/pydantic/pydantic/pull/12077) +* Add experimental `MISSING` sentinel by [@Viicos](https://github.com/Viicos) in [#11883](https://github.com/pydantic/pydantic/pull/11883) + +#### Changes + +* Allow config and bases to be specified together in `create_model()` by [@Viicos](https://github.com/Viicos) in [#11714](https://github.com/pydantic/pydantic/pull/11714) +* Move some field logic out of the `GenerateSchema` class by [@Viicos](https://github.com/Viicos) in [#11733](https://github.com/pydantic/pydantic/pull/11733) +* Always make use of `inspect.getsourcelines()` for docstring extraction on Python 3.13 and greater by [@Viicos](https://github.com/Viicos) in [#11829](https://github.com/pydantic/pydantic/pull/11829) +* Only support the latest Mypy version by [@Viicos](https://github.com/Viicos) in [#11832](https://github.com/pydantic/pydantic/pull/11832) +* Do not implicitly convert after model validators to class methods by [@Viicos](https://github.com/Viicos) in [#11957](https://github.com/pydantic/pydantic/pull/11957) +* Refactor `FieldInfo` creation implementation by [@Viicos](https://github.com/Viicos) in [#11898](https://github.com/pydantic/pydantic/pull/11898) +* Make `Secret` covariant by [@bluenote10](https://github.com/bluenote10) in [#12008](https://github.com/pydantic/pydantic/pull/12008) +* Emit warning when field-specific metadata is used in invalid contexts by [@Viicos](https://github.com/Viicos) in [#12028](https://github.com/pydantic/pydantic/pull/12028) + +#### Fixes + +* Properly fetch plain serializer function when serializing default value in JSON Schema by [@Viicos](https://github.com/Viicos) in [#11721](https://github.com/pydantic/pydantic/pull/11721) +* Remove generics cache workaround by [@Viicos](https://github.com/Viicos) in [#11755](https://github.com/pydantic/pydantic/pull/11755) +* Remove coercion of decimal constraints by [@Viicos](https://github.com/Viicos) in [#11772](https://github.com/pydantic/pydantic/pull/11772) +* Fix crash when expanding root type in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11735](https://github.com/pydantic/pydantic/pull/11735) +* Only mark model as complete once all fields are complete by [@DouweM](https://github.com/DouweM) in [#11759](https://github.com/pydantic/pydantic/pull/11759) +* Do not provide `field_name` in validator core schemas by [@DouweM](https://github.com/DouweM) in [#11761](https://github.com/pydantic/pydantic/pull/11761) +* Fix issue with recursive generic models by [@Viicos](https://github.com/Viicos) in [#11775](https://github.com/pydantic/pydantic/pull/11775) +* Fix qualified name comparison of private attributes during namespace inspection by [@karta9821](https://github.com/karta9821) in [#11803](https://github.com/pydantic/pydantic/pull/11803) +* Make sure Pydantic dataclasses with slots and `validate_assignment` can be unpickled by [@Viicos](https://github.com/Viicos) in [#11769](https://github.com/pydantic/pydantic/pull/11769) +* Traverse `function-before` schemas during schema gathering by [@Viicos](https://github.com/Viicos) in [#11801](https://github.com/pydantic/pydantic/pull/11801) +* Fix check for stdlib dataclasses by [@Viicos](https://github.com/Viicos) in [#11822](https://github.com/pydantic/pydantic/pull/11822) +* Check if `FieldInfo` is complete after applying type variable map by [@Viicos](https://github.com/Viicos) in [#11855](https://github.com/pydantic/pydantic/pull/11855) +* Do not delete mock validator/serializer in `model_rebuild()` by [@Viicos](https://github.com/Viicos) in [#11890](https://github.com/pydantic/pydantic/pull/11890) +* Rebuild dataclass fields before schema generation by [@Viicos](https://github.com/Viicos) in [#11949](https://github.com/pydantic/pydantic/pull/11949) +* Always store the original field assignment on `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11946](https://github.com/pydantic/pydantic/pull/11946) +* Do not use deprecated methods as default field values by [@Viicos](https://github.com/Viicos) in [#11914](https://github.com/pydantic/pydantic/pull/11914) +* Allow callable discriminator to be applied on PEP 695 type aliases by [@Viicos](https://github.com/Viicos) in [#11941](https://github.com/pydantic/pydantic/pull/11941) +* Suppress core schema generation warning when using `SkipValidation` by [@ygsh0816](https://github.com/ygsh0816) in [#12002](https://github.com/pydantic/pydantic/pull/12002) +* Do not emit typechecking error for invalid `Field()` default with `validate_default` set to `True` by [@Viicos](https://github.com/Viicos) in [#11988](https://github.com/pydantic/pydantic/pull/11988) +* Refactor logic to support Pydantic's `Field()` function in dataclasses by [@Viicos](https://github.com/Viicos) in [#12051](https://github.com/pydantic/pydantic/pull/12051) + +#### Packaging + +* Update project metadata to use PEP 639 by [@Viicos](https://github.com/Viicos) in [#11694](https://github.com/pydantic/pydantic/pull/11694) +* Bump `mkdocs-llmstxt` to v0.2.0 by [@Viicos](https://github.com/Viicos) in [#11725](https://github.com/pydantic/pydantic/pull/11725) +* Bump `pydantic-core` to v2.35.1 by [@Viicos](https://github.com/Viicos) in [#11963](https://github.com/pydantic/pydantic/pull/11963) +* Bump dawidd6/action-download-artifact from 10 to 11 by [@dependabot](https://github.com/dependabot)[bot] in [#12033](https://github.com/pydantic/pydantic/pull/12033) +* Bump astral-sh/setup-uv from 5 to 6 by [@dependabot](https://github.com/dependabot)[bot] in [#11826](https://github.com/pydantic/pydantic/pull/11826) +* Update mypy to 1.17.0 by [@Viicos](https://github.com/Viicos) in [#12076](https://github.com/pydantic/pydantic/pull/12076) + +### New Contributors + +* [@parth-paradkar](https://github.com/parth-paradkar) made their first contribution in [#11695](https://github.com/pydantic/pydantic/pull/11695) +* [@dqkqd](https://github.com/dqkqd) made their first contribution in [#11739](https://github.com/pydantic/pydantic/pull/11739) +* [@fhightower](https://github.com/fhightower) made their first contribution in [#11722](https://github.com/pydantic/pydantic/pull/11722) +* [@gbaian10](https://github.com/gbaian10) made their first contribution in [#11766](https://github.com/pydantic/pydantic/pull/11766) +* [@DouweM](https://github.com/DouweM) made their first contribution in [#11759](https://github.com/pydantic/pydantic/pull/11759) +* [@bowenliang123](https://github.com/bowenliang123) made their first contribution in [#11719](https://github.com/pydantic/pydantic/pull/11719) +* [@rawwar](https://github.com/rawwar) made their first contribution in [#11799](https://github.com/pydantic/pydantic/pull/11799) +* [@karta9821](https://github.com/karta9821) made their first contribution in [#11803](https://github.com/pydantic/pydantic/pull/11803) +* [@jinnovation](https://github.com/jinnovation) made their first contribution in [#11834](https://github.com/pydantic/pydantic/pull/11834) +* [@zmievsa](https://github.com/zmievsa) made their first contribution in [#11861](https://github.com/pydantic/pydantic/pull/11861) +* [@Otto-AA](https://github.com/Otto-AA) made their first contribution in [#11860](https://github.com/pydantic/pydantic/pull/11860) +* [@ygsh0816](https://github.com/ygsh0816) made their first contribution in [#12002](https://github.com/pydantic/pydantic/pull/12002) +* [@lukland](https://github.com/lukland) made their first contribution in [#12015](https://github.com/pydantic/pydantic/pull/12015) +* [@Dima-Bulavenko](https://github.com/Dima-Bulavenko) made their first contribution in [#11987](https://github.com/pydantic/pydantic/pull/11987) +* [@GSemikozov](https://github.com/GSemikozov) made their first contribution in [#12050](https://github.com/pydantic/pydantic/pull/12050) +* [@hannah-heywa](https://github.com/hannah-heywa) made their first contribution in [#12082](https://github.com/pydantic/pydantic/pull/12082) + +## v2.11.10 (2025-10-04) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.10) + +### What's Changed + +#### Fixes + +* Backport v1.10.24 changes by [@Viicos](https://github.com/Viicos) + +## v2.11.9 (2025-09-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.9) + +### What's Changed + +#### Fixes + +* Backport v1.10.23 changes by [@Viicos](https://github.com/Viicos) + +## v2.11.8 (2025-09-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.8) + +### What's Changed + +#### Fixes + +* Fix mypy plugin for mypy 1.18 by [@cdce8p](https://github.com/cdce8p) in [#12209](https://github.com/pydantic/pydantic/pull/12209) + +## v2.11.7 (2025-06-14) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.7) + +### What's Changed + +#### Fixes + +* Copy `FieldInfo` instance if necessary during `FieldInfo` build by [@Viicos](https://github.com/Viicos) in [#11898](https://github.com/pydantic/pydantic/pull/11898) + +## v2.11.6 (2025-06-13) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.6) + +### What's Changed + +#### Fixes + +* Rebuild dataclass fields before schema generation by [@Viicos](https://github.com/Viicos) in [#11949](https://github.com/pydantic/pydantic/pull/11949) +* Always store the original field assignment on `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11946](https://github.com/pydantic/pydantic/pull/11946) + +## v2.11.5 (2025-05-22) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.5) + +### What's Changed + +#### Fixes + +* Check if `FieldInfo` is complete after applying type variable map by [@Viicos](https://github.com/Viicos) in [#11855](https://github.com/pydantic/pydantic/pull/11855) +* Do not delete mock validator/serializer in `model_rebuild()` by [@Viicos](https://github.com/Viicos) in [#11890](https://github.com/pydantic/pydantic/pull/11890) +* Do not duplicate metadata on model rebuild by [@Viicos](https://github.com/Viicos) in [#11902](https://github.com/pydantic/pydantic/pull/11902) + +## v2.11.4 (2025-04-29) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.4) + +### What's Changed + +#### Changes + +* Allow config and bases to be specified together in `create_model()` by [@Viicos](https://github.com/Viicos) in [#11714](https://github.com/pydantic/pydantic/pull/11714). + This change was backported as it was previously possible (although not meant to be supported) + to provide `model_config` as a field, which would make it possible to provide both configuration + and bases. + +#### Fixes + +* Remove generics cache workaround by [@Viicos](https://github.com/Viicos) in [#11755](https://github.com/pydantic/pydantic/pull/11755) +* Remove coercion of decimal constraints by [@Viicos](https://github.com/Viicos) in [#11772](https://github.com/pydantic/pydantic/pull/11772) +* Fix crash when expanding root type in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11735](https://github.com/pydantic/pydantic/pull/11735) +* Fix issue with recursive generic models by [@Viicos](https://github.com/Viicos) in [#11775](https://github.com/pydantic/pydantic/pull/11775) +* Traverse `function-before` schemas during schema gathering by [@Viicos](https://github.com/Viicos) in [#11801](https://github.com/pydantic/pydantic/pull/11801) + +#### Packaging + +* Bump `mkdocs-llmstxt` to v0.2.0 by [@Viicos](https://github.com/Viicos) in [#11725](https://github.com/pydantic/pydantic/pull/11725) + +## v2.11.3 (2025-04-08) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.3) + +### What's Changed + +#### Fixes + +* Preserve field description when rebuilding model fields by [@Viicos](https://github.com/Viicos) in [#11698](https://github.com/pydantic/pydantic/pull/11698) + +#### Packaging + +* Update V1 copy to v1.10.21 by [@Viicos](https://github.com/Viicos) in [#11706](https://github.com/pydantic/pydantic/pull/11706) + +## v2.11.2 (2025-04-03) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.2) + +### What's Changed + +#### Fixes + +* Bump `pydantic-core` to v2.33.1 by [@Viicos](https://github.com/Viicos) in [#11678](https://github.com/pydantic/pydantic/pull/11678) +* Make sure `__pydantic_private__` exists before setting private attributes by [@Viicos](https://github.com/Viicos) in [#11666](https://github.com/pydantic/pydantic/pull/11666) +* Do not override `FieldInfo._complete` when using field from parent class by [@Viicos](https://github.com/Viicos) in [#11668](https://github.com/pydantic/pydantic/pull/11668) +* Provide the available definitions when applying discriminated unions by [@Viicos](https://github.com/Viicos) in [#11670](https://github.com/pydantic/pydantic/pull/11670) +* Do not expand root type in the mypy plugin for variables by [@Viicos](https://github.com/Viicos) in [#11676](https://github.com/pydantic/pydantic/pull/11676) +* Mention the attribute name in model fields deprecation message by [@Viicos](https://github.com/Viicos) in [#11674](https://github.com/pydantic/pydantic/pull/11674) +* Properly validate parameterized mappings by [@Viicos](https://github.com/Viicos) in [#11658](https://github.com/pydantic/pydantic/pull/11658) + +## v2.11.1 (2025-03-28) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.1) + +### What's Changed + +#### Fixes + +* Do not override `'definitions-ref'` schemas containing serialization schemas or metadata by [@Viicos](https://github.com/Viicos) in [#11644](https://github.com/pydantic/pydantic/pull/11644) + +## v2.11.0 (2025-03-27) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0) + +### What's Changed + +Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). +See the [blog post](https://pydantic.dev/articles/pydantic-v2-11-release) for more details. + +#### New Features + +* Add `encoded_string()` method to the URL types by [@YassinNouh21](https://github.com/YassinNouh21) in [#11580](https://github.com/pydantic/pydantic/pull/11580) +* Add support for `defer_build` with `@validate_call` decorator by [@Viicos](https://github.com/Viicos) in [#11584](https://github.com/pydantic/pydantic/pull/11584) +* Allow `@with_config` decorator to be used with keyword arguments by [@Viicos](https://github.com/Viicos) in [#11608](https://github.com/pydantic/pydantic/pull/11608) +* Simplify customization of default value inclusion in JSON Schema generation by [@Viicos](https://github.com/Viicos) in [#11634](https://github.com/pydantic/pydantic/pull/11634) +* Add `generate_arguments_schema()` function by [@Viicos](https://github.com/Viicos) in [#11572](https://github.com/pydantic/pydantic/pull/11572) + +#### Fixes + +* Allow generic typed dictionaries to be used for unpacked variadic keyword parameters by [@Viicos](https://github.com/Viicos) in [#11571](https://github.com/pydantic/pydantic/pull/11571) +* Fix runtime error when computing model string representation involving cached properties and self-referenced models by [@Viicos](https://github.com/Viicos) in [#11579](https://github.com/pydantic/pydantic/pull/11579) +* Preserve other steps when using the ellipsis in the pipeline API by [@Viicos](https://github.com/Viicos) in [#11626](https://github.com/pydantic/pydantic/pull/11626) +* Fix deferred discriminator application logic by [@Viicos](https://github.com/Viicos) in [#11591](https://github.com/pydantic/pydantic/pull/11591) + +#### Packaging + +* Bump `pydantic-core` to v2.33.0 by [@Viicos](https://github.com/Viicos) in [#11631](https://github.com/pydantic/pydantic/pull/11631) + +### New Contributors + +* [@cmenon12](https://github.com/cmenon12) made their first contribution in [#11562](https://github.com/pydantic/pydantic/pull/11562) +* [@Jeukoh](https://github.com/Jeukoh) made their first contribution in [#11611](https://github.com/pydantic/pydantic/pull/11611) + +## v2.11.0b2 (2025-03-17) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0b2) + +### What's Changed + +#### New Features + +* Add experimental support for free threading by [@Viicos](https://github.com/Viicos) in [#11516](https://github.com/pydantic/pydantic/pull/11516) + +#### Fixes + +* Fix `NotRequired` qualifier not taken into account in stringified annotation by [@Viicos](https://github.com/Viicos) in [#11559](https://github.com/pydantic/pydantic/pull/11559) + +#### Packaging + +* Bump `pydantic-core` to v2.32.0 by [@Viicos](https://github.com/Viicos) in [#11567](https://github.com/pydantic/pydantic/pull/11567) + +### New Contributors + +* [@joren485](https://github.com/joren485) made their first contribution in [#11547](https://github.com/pydantic/pydantic/pull/11547) + +## v2.11.0b1 (2025-03-06) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0b1) + +### What's Changed + +#### New Features + +* Support unsubstituted type variables with both a default and a bound or constraints by [@FyZzyss](https://github.com/FyZzyss) in https://github.com/pydantic/pydantic/pull/10789 +* Add a `default_factory_takes_validated_data` property to `FieldInfo` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11034 +* Raise a better error when a generic alias is used inside `type[]` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11088 +* Properly support PEP 695 generics syntax by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11189 +* Properly support type variable defaults by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11332 +* Add support for validating v6, v7, v8 UUIDs by [@astei](https://github.com/astei) in https://github.com/pydantic/pydantic/pull/11436 +* Improve alias configuration APIs by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11468 + +#### Changes + +* Rework `create_model` field definitions format by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11032 +* Raise a deprecation warning when a field is annotated as final with a default value by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11168 +* Deprecate accessing `model_fields` and `model_computed_fields` on instances by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11169 +* **Breaking Change:** Move core schema generation logic for path types inside the `GenerateSchema` class by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/10846 +* Remove Python 3.8 Support by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11258 +* Optimize calls to `get_type_ref` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10863 +* Disable `pydantic-core` core schema validation by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11271 + +#### Performance + +* Only evaluate `FieldInfo` annotations if required during schema building by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10769 +* Improve `__setattr__` performance of Pydantic models by caching setter functions by [@MarkusSintonen](https://github.com/MarkusSintonen) in https://github.com/pydantic/pydantic/pull/10868 +* Improve annotation application performance by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11186 +* Improve performance of `_typing_extra` module by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11255 +* Refactor and optimize schema cleaning logic by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11244 +* Create a single dictionary when creating a `CoreConfig` instance by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11384 +* Bump `pydantic-core` and thus use `SchemaValidator` and `SchemaSerializer` caching by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11402 +* Reuse cached core schemas for parametrized generic Pydantic models by [@MarkusSintonen](https://github.com/MarkusSintonen) in https://github.com/pydantic/pydantic/pull/11434 + +#### Fixes + +* Improve `TypeAdapter` instance repr by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/10872 +* Use the correct frame when instantiating a parametrized `TypeAdapter` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10893 +* Infer final fields with a default value as class variables in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11121 +* Recursively unpack `Literal` values if using PEP 695 type aliases by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11114 +* Override `__subclasscheck__` on `ModelMetaclass` to avoid memory leak and performance issues by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11116 +* Remove unused `_extract_get_pydantic_json_schema()` parameter by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11155 +* Improve discriminated union error message for invalid union variants by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11161 +* Unpack PEP 695 type aliases if using the `Annotated` form by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11109 +* Add missing stacklevel in `deprecated_instance_property` warning by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11200 +* Copy `WithJsonSchema` schema to avoid sharing mutated data by [@thejcannon](https://github.com/thejcannon) in https://github.com/pydantic/pydantic/pull/11014 +* Do not cache parametrized models when in the process of parametrizing another model by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/10704 +* Add discriminated union related metadata entries to the `CoreMetadata` definition by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11216 +* Consolidate schema definitions logic in the `_Definitions` class by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11208 +* Support initializing root model fields with values of the `root` type in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11212 +* Fix various issues with dataclasses and `use_attribute_docstrings` by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11246 +* Only compute normalized decimal places if necessary in `decimal_places_validator` by [@misrasaurabh1](https://github.com/misrasaurabh1) in https://github.com/pydantic/pydantic/pull/11281 +* Add support for `validation_alias` in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11295 +* Fix JSON Schema reference collection with `"examples"` keys by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11305 +* Do not transform model serializer functions as class methods in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11298 +* Simplify `GenerateJsonSchema.literal_schema()` implementation by [@misrasaurabh1](https://github.com/misrasaurabh1) in https://github.com/pydantic/pydantic/pull/11321 +* Add additional allowed schemes for `ClickHouseDsn` by [@Maze21127](https://github.com/Maze21127) in https://github.com/pydantic/pydantic/pull/11319 +* Coerce decimal constraints to `Decimal` instances by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11350 +* Use the correct JSON Schema mode when handling function schemas by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11367 +* Improve exception message when encountering recursion errors during type evaluation by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11356 +* Always include `additionalProperties: True` for arbitrary dictionary schemas by [@austinyu](https://github.com/austinyu) in https://github.com/pydantic/pydantic/pull/11392 +* Expose `fallback` parameter in serialization methods by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11398 +* Fix path serialization behavior by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11416 +* Do not reuse validators and serializers during model rebuild by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11429 +* Collect model fields when rebuilding a model by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11388 +* Allow cached properties to be altered on frozen models by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11432 +* Fix tuple serialization for `Sequence` types by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11435 +* Fix: do not check for `__get_validators__` on classes where `__get_pydantic_core_schema__` is also defined by [@tlambert03](https://github.com/tlambert03) in https://github.com/pydantic/pydantic/pull/11444 +* Allow callable instances to be used as serializers by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11451 +* Improve error thrown when overriding field with a property by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11459 +* Fix JSON Schema generation with referenceable core schemas holding JSON metadata by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11475 +* Support strict specification on union member types by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11481 +* Implicitly set `validate_by_name` to `True` when `validate_by_alias` is `False` by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11503 +* Change type of `Any` when synthesizing `BaseSettings.__init__` signature in the mypy plugin by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11497 +* Support type variable defaults referencing other type variables by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11520 +* Fix `ValueError` on year zero by [@davidhewitt](https://github.com/davidhewitt) in https://github.com/pydantic/pydantic-core/pull/1583 +* `dataclass` `InitVar` shouldn't be required on serialization by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic-core/pull/1602 + +#### Packaging + +* Add a `check_pydantic_core_version()` function by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11324 +* Remove `greenlet` development dependency by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11351 +* Use the `typing-inspection` library by [@Viicos](https://github.com/Viicos) in https://github.com/pydantic/pydantic/pull/11479 +* Bump `pydantic-core` to `v2.31.1` by [@sydney-runkle](https://github.com/sydney-runkle) in https://github.com/pydantic/pydantic/pull/11526 + +## New Contributors + +* [@FyZzyss](https://github.com/FyZzyss) made their first contribution in https://github.com/pydantic/pydantic/pull/10789 +* [@tamird](https://github.com/tamird) made their first contribution in https://github.com/pydantic/pydantic/pull/10948 +* [@felixxm](https://github.com/felixxm) made their first contribution in https://github.com/pydantic/pydantic/pull/11077 +* [@alexprabhat99](https://github.com/alexprabhat99) made their first contribution in https://github.com/pydantic/pydantic/pull/11082 +* [@Kharianne](https://github.com/Kharianne) made their first contribution in https://github.com/pydantic/pydantic/pull/11111 +* [@mdaffad](https://github.com/mdaffad) made their first contribution in https://github.com/pydantic/pydantic/pull/11177 +* [@thejcannon](https://github.com/thejcannon) made their first contribution in https://github.com/pydantic/pydantic/pull/11014 +* [@thomasfrimannkoren](https://github.com/thomasfrimannkoren) made their first contribution in https://github.com/pydantic/pydantic/pull/11251 +* [@usernameMAI](https://github.com/usernameMAI) made their first contribution in https://github.com/pydantic/pydantic/pull/11275 +* [@ananiavito](https://github.com/ananiavito) made their first contribution in https://github.com/pydantic/pydantic/pull/11302 +* [@pawamoy](https://github.com/pawamoy) made their first contribution in https://github.com/pydantic/pydantic/pull/11311 +* [@Maze21127](https://github.com/Maze21127) made their first contribution in https://github.com/pydantic/pydantic/pull/11319 +* [@kauabh](https://github.com/kauabh) made their first contribution in https://github.com/pydantic/pydantic/pull/11369 +* [@jaceklaskowski](https://github.com/jaceklaskowski) made their first contribution in https://github.com/pydantic/pydantic/pull/11353 +* [@tmpbeing](https://github.com/tmpbeing) made their first contribution in https://github.com/pydantic/pydantic/pull/11375 +* [@petyosi](https://github.com/petyosi) made their first contribution in https://github.com/pydantic/pydantic/pull/11405 +* [@austinyu](https://github.com/austinyu) made their first contribution in https://github.com/pydantic/pydantic/pull/11392 +* [@mikeedjones](https://github.com/mikeedjones) made their first contribution in https://github.com/pydantic/pydantic/pull/11402 +* [@astei](https://github.com/astei) made their first contribution in https://github.com/pydantic/pydantic/pull/11436 +* [@dsayling](https://github.com/dsayling) made their first contribution in https://github.com/pydantic/pydantic/pull/11522 +* [@sobolevn](https://github.com/sobolevn) made their first contribution in https://github.com/pydantic/pydantic-core/pull/1645 + +## v2.11.0a2 (2025-02-10) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0a2) + +### What's Changed + +Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). +This is another early alpha release, meant to collect early feedback from users having issues with core schema builds. + +#### Performance + +* Create a single dictionary when creating a `CoreConfig` instance by [@sydney-runkle](https://github.com/sydney-runkle) in [#11384](https://github.com/pydantic/pydantic/pull/11384) + +#### Fixes + +* Use the correct JSON Schema mode when handling function schemas by [@Viicos](https://github.com/Viicos) in [#11367](https://github.com/pydantic/pydantic/pull/11367) +* Fix JSON Schema reference logic with `examples` keys by [@Viicos](https://github.com/Viicos) in [#11366](https://github.com/pydantic/pydantic/pull/11366) +* Improve exception message when encountering recursion errors during type evaluation by [@Viicos](https://github.com/Viicos) in [#11356](https://github.com/pydantic/pydantic/pull/11356) +* Always include `additionalProperties: True` for arbitrary dictionary schemas by [@austinyu](https://github.com/austinyu) in [#11392](https://github.com/pydantic/pydantic/pull/11392) +* Expose `fallback` parameter in serialization methods by [@Viicos](https://github.com/Viicos) in [#11398](https://github.com/pydantic/pydantic/pull/11398) +* Fix path serialization behavior by [@sydney-runkle](https://github.com/sydney-runkle) in [#11416](https://github.com/pydantic/pydantic/pull/11416) + +#### Packaging + +* Bump `ruff` from 0.9.2 to 0.9.5 by [@Viicos](https://github.com/Viicos) in [#11407](https://github.com/pydantic/pydantic/pull/11407) +* Bump `pydantic-core` to v2.29.0 by [@mikeedjones](https://github.com/mikeedjones) in [#11402](https://github.com/pydantic/pydantic/pull/11402) +* Use locally-built rust with symbols & pgo by [@davidhewitt](https://github.com/davidhewitt) in [#11403](https://github.com/pydantic/pydantic/pull/11403) + +### New Contributors + +* [@kauabh](https://github.com/kauabh) made their first contribution in [#11369](https://github.com/pydantic/pydantic/pull/11369) +* [@jaceklaskowski](https://github.com/jaceklaskowski) made their first contribution in [#11353](https://github.com/pydantic/pydantic/pull/11353) +* [@tmpbeing](https://github.com/tmpbeing) made their first contribution in [#11375](https://github.com/pydantic/pydantic/pull/11375) +* [@petyosi](https://github.com/petyosi) made their first contribution in [#11405](https://github.com/pydantic/pydantic/pull/11405) +* [@austinyu](https://github.com/austinyu) made their first contribution in [#11392](https://github.com/pydantic/pydantic/pull/11392) +* [@mikeedjones](https://github.com/mikeedjones) made their first contribution in [#11402](https://github.com/pydantic/pydantic/pull/11402) + +## v2.11.0a1 (2025-01-30) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.11.0a1) + +### What's Changed + +Pydantic v2.11 is a version strongly focused on build time performance of Pydantic models (and core schema generation in general). +This is an early alpha release, meant to collect early feedback from users having issues with core schema builds. + +#### New Features + +* Support unsubstituted type variables with both a default and a bound or constraints by [@FyZzyss](https://github.com/FyZzyss) in [#10789](https://github.com/pydantic/pydantic/pull/10789) +* Add a `default_factory_takes_validated_data` property to `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11034](https://github.com/pydantic/pydantic/pull/11034) +* Raise a better error when a generic alias is used inside `type[]` by [@Viicos](https://github.com/Viicos) in [#11088](https://github.com/pydantic/pydantic/pull/11088) +* Properly support PEP 695 generics syntax by [@Viicos](https://github.com/Viicos) in [#11189](https://github.com/pydantic/pydantic/pull/11189) +* Properly support type variable defaults by [@Viicos](https://github.com/Viicos) in [#11332](https://github.com/pydantic/pydantic/pull/11332) + +#### Changes + +* Rework `create_model` field definitions format by [@Viicos](https://github.com/Viicos) in [#11032](https://github.com/pydantic/pydantic/pull/11032) +* Raise a deprecation warning when a field is annotated as final with a default value by [@Viicos](https://github.com/Viicos) in [#11168](https://github.com/pydantic/pydantic/pull/11168) +* Deprecate accessing `model_fields` and `model_computed_fields` on instances by [@Viicos](https://github.com/Viicos) in [#11169](https://github.com/pydantic/pydantic/pull/11169) +* Move core schema generation logic for path types inside the `GenerateSchema` class by [@sydney-runkle](https://github.com/sydney-runkle) in [#10846](https://github.com/pydantic/pydantic/pull/10846) +* Move `deque` schema gen to `GenerateSchema` class by [@sydney-runkle](https://github.com/sydney-runkle) in [#11239](https://github.com/pydantic/pydantic/pull/11239) +* Move `Mapping` schema gen to `GenerateSchema` to complete removal of `prepare_annotations_for_known_type` workaround by [@sydney-runkle](https://github.com/sydney-runkle) in [#11247](https://github.com/pydantic/pydantic/pull/11247) +* Remove Python 3.8 Support by [@sydney-runkle](https://github.com/sydney-runkle) in [#11258](https://github.com/pydantic/pydantic/pull/11258) +* Disable `pydantic-core` core schema validation by [@sydney-runkle](https://github.com/sydney-runkle) in [#11271](https://github.com/pydantic/pydantic/pull/11271) + +#### Performance + +* Only evaluate `FieldInfo` annotations if required during schema building by [@Viicos](https://github.com/Viicos) in [#10769](https://github.com/pydantic/pydantic/pull/10769) +* Optimize calls to `get_type_ref` by [@Viicos](https://github.com/Viicos) in [#10863](https://github.com/pydantic/pydantic/pull/10863) +* Improve `__setattr__` performance of Pydantic models by caching setter functions by [@MarkusSintonen](https://github.com/MarkusSintonen) in [#10868](https://github.com/pydantic/pydantic/pull/10868) +* Improve annotation application performance by [@Viicos](https://github.com/Viicos) in [#11186](https://github.com/pydantic/pydantic/pull/11186) +* Improve performance of `_typing_extra` module by [@Viicos](https://github.com/Viicos) in [#11255](https://github.com/pydantic/pydantic/pull/11255) +* Refactor and optimize schema cleaning logic by [@Viicos](https://github.com/Viicos) and [@MarkusSintonen](https://github.com/MarkusSintonen) in [#11244](https://github.com/pydantic/pydantic/pull/11244) + +#### Fixes + +* Add validation tests for `_internal/_validators.py` by [@tkasuz](https://github.com/tkasuz) in [#10763](https://github.com/pydantic/pydantic/pull/10763) +* Improve `TypeAdapter` instance repr by [@sydney-runkle](https://github.com/sydney-runkle) in [#10872](https://github.com/pydantic/pydantic/pull/10872) +* Revert "ci: use locally built pydantic-core with debug symbols by [@sydney-runkle](https://github.com/sydney-runkle) in [#10942](https://github.com/pydantic/pydantic/pull/10942) +* Re-enable all FastAPI tests by [@tamird](https://github.com/tamird) in [#10948](https://github.com/pydantic/pydantic/pull/10948) +* Fix typo in HISTORY.md. by [@felixxm](https://github.com/felixxm) in [#11077](https://github.com/pydantic/pydantic/pull/11077) +* Infer final fields with a default value as class variables in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11121](https://github.com/pydantic/pydantic/pull/11121) +* Recursively unpack `Literal` values if using PEP 695 type aliases by [@Viicos](https://github.com/Viicos) in [#11114](https://github.com/pydantic/pydantic/pull/11114) +* Override `__subclasscheck__` on `ModelMetaclass` to avoid memory leak and performance issues by [@Viicos](https://github.com/Viicos) in [#11116](https://github.com/pydantic/pydantic/pull/11116) +* Remove unused `_extract_get_pydantic_json_schema()` parameter by [@Viicos](https://github.com/Viicos) in [#11155](https://github.com/pydantic/pydantic/pull/11155) +* Add FastAPI and SQLModel to third-party tests by [@sydney-runkle](https://github.com/sydney-runkle) in [#11044](https://github.com/pydantic/pydantic/pull/11044) +* Fix conditional expressions syntax for third-party tests by [@Viicos](https://github.com/Viicos) in [#11162](https://github.com/pydantic/pydantic/pull/11162) +* Move FastAPI tests to third-party workflow by [@Viicos](https://github.com/Viicos) in [#11164](https://github.com/pydantic/pydantic/pull/11164) +* Improve discriminated union error message for invalid union variants by [@Viicos](https://github.com/Viicos) in [#11161](https://github.com/pydantic/pydantic/pull/11161) +* Unpack PEP 695 type aliases if using the `Annotated` form by [@Viicos](https://github.com/Viicos) in [#11109](https://github.com/pydantic/pydantic/pull/11109) +* Include `openapi-python-client` check in issue creation for third-party failures, use `main` branch by [@sydney-runkle](https://github.com/sydney-runkle) in [#11182](https://github.com/pydantic/pydantic/pull/11182) +* Add pandera third-party tests by [@Viicos](https://github.com/Viicos) in [#11193](https://github.com/pydantic/pydantic/pull/11193) +* Add ODMantic third-party tests by [@sydney-runkle](https://github.com/sydney-runkle) in [#11197](https://github.com/pydantic/pydantic/pull/11197) +* Add missing stacklevel in `deprecated_instance_property` warning by [@Viicos](https://github.com/Viicos) in [#11200](https://github.com/pydantic/pydantic/pull/11200) +* Copy `WithJsonSchema` schema to avoid sharing mutated data by [@thejcannon](https://github.com/thejcannon) in [#11014](https://github.com/pydantic/pydantic/pull/11014) +* Do not cache parametrized models when in the process of parametrizing another model by [@Viicos](https://github.com/Viicos) in [#10704](https://github.com/pydantic/pydantic/pull/10704) +* Re-enable Beanie third-party tests by [@Viicos](https://github.com/Viicos) in [#11214](https://github.com/pydantic/pydantic/pull/11214) +* Add discriminated union related metadata entries to the `CoreMetadata` definition by [@Viicos](https://github.com/Viicos) in [#11216](https://github.com/pydantic/pydantic/pull/11216) +* Consolidate schema definitions logic in the `_Definitions` class by [@Viicos](https://github.com/Viicos) in [#11208](https://github.com/pydantic/pydantic/pull/11208) +* Support initializing root model fields with values of the `root` type in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11212](https://github.com/pydantic/pydantic/pull/11212) +* Fix various issues with dataclasses and `use_attribute_docstrings` by [@Viicos](https://github.com/Viicos) in [#11246](https://github.com/pydantic/pydantic/pull/11246) +* Only compute normalized decimal places if necessary in `decimal_places_validator` by [@misrasaurabh1](https://github.com/misrasaurabh1) in [#11281](https://github.com/pydantic/pydantic/pull/11281) +* Fix two misplaced sentences in validation errors documentation by [@ananiavito](https://github.com/ananiavito) in [#11302](https://github.com/pydantic/pydantic/pull/11302) +* Fix mkdocstrings inventory example in documentation by [@pawamoy](https://github.com/pawamoy) in [#11311](https://github.com/pydantic/pydantic/pull/11311) +* Add support for `validation_alias` in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11295](https://github.com/pydantic/pydantic/pull/11295) +* Do not transform model serializer functions as class methods in the mypy plugin by [@Viicos](https://github.com/Viicos) in [#11298](https://github.com/pydantic/pydantic/pull/11298) +* Simplify `GenerateJsonSchema.literal_schema()` implementation by [@misrasaurabh1](https://github.com/misrasaurabh1) in [#11321](https://github.com/pydantic/pydantic/pull/11321) +* Add additional allowed schemes for `ClickHouseDsn` by [@Maze21127](https://github.com/Maze21127) in [#11319](https://github.com/pydantic/pydantic/pull/11319) +* Coerce decimal constraints to `Decimal` instances by [@Viicos](https://github.com/Viicos) in [#11350](https://github.com/pydantic/pydantic/pull/11350) +* Fix `ValueError` on year zero by [@davidhewitt](https://github.com/davidhewitt) in [pydantic-core#1583](https://github.com/pydantic/pydantic-core/pull/1583) + +#### Packaging + +* Bump dawidd6/action-download-artifact from 6 to 7 by [@dependabot](https://github.com/dependabot) in [#11018](https://github.com/pydantic/pydantic/pull/11018) +* Re-enable memray related tests on Python 3.12+ by [@Viicos](https://github.com/Viicos) in [#11191](https://github.com/pydantic/pydantic/pull/11191) +* Bump astral-sh/setup-uv to 5 by [@dependabot](https://github.com/dependabot) in [#11205](https://github.com/pydantic/pydantic/pull/11205) +* Bump `ruff` to v0.9.0 by [@sydney-runkle](https://github.com/sydney-runkle) in [#11254](https://github.com/pydantic/pydantic/pull/11254) +* Regular `uv.lock` deps update by [@sydney-runkle](https://github.com/sydney-runkle) in [#11333](https://github.com/pydantic/pydantic/pull/11333) +* Add a `check_pydantic_core_version()` function by [@Viicos](https://github.com/Viicos) in [#11324](https://github.com/pydantic/pydantic/pull/11324) +* Remove `greenlet` development dependency by [@Viicos](https://github.com/Viicos) in [#11351](https://github.com/pydantic/pydantic/pull/11351) +* Bump `pydantic-core` to v2.28.0 by [@Viicos](https://github.com/Viicos) in [#11364](https://github.com/pydantic/pydantic/pull/11364) + +### New Contributors + +* [@FyZzyss](https://github.com/FyZzyss) made their first contribution in [#10789](https://github.com/pydantic/pydantic/pull/10789) +* [@tamird](https://github.com/tamird) made their first contribution in [#10948](https://github.com/pydantic/pydantic/pull/10948) +* [@felixxm](https://github.com/felixxm) made their first contribution in [#11077](https://github.com/pydantic/pydantic/pull/11077) +* [@alexprabhat99](https://github.com/alexprabhat99) made their first contribution in [#11082](https://github.com/pydantic/pydantic/pull/11082) +* [@Kharianne](https://github.com/Kharianne) made their first contribution in [#11111](https://github.com/pydantic/pydantic/pull/11111) +* [@mdaffad](https://github.com/mdaffad) made their first contribution in [#11177](https://github.com/pydantic/pydantic/pull/11177) +* [@thejcannon](https://github.com/thejcannon) made their first contribution in [#11014](https://github.com/pydantic/pydantic/pull/11014) +* [@thomasfrimannkoren](https://github.com/thomasfrimannkoren) made their first contribution in [#11251](https://github.com/pydantic/pydantic/pull/11251) +* [@usernameMAI](https://github.com/usernameMAI) made their first contribution in [#11275](https://github.com/pydantic/pydantic/pull/11275) +* [@ananiavito](https://github.com/ananiavito) made their first contribution in [#11302](https://github.com/pydantic/pydantic/pull/11302) +* [@pawamoy](https://github.com/pawamoy) made their first contribution in [#11311](https://github.com/pydantic/pydantic/pull/11311) +* [@Maze21127](https://github.com/Maze21127) made their first contribution in [#11319](https://github.com/pydantic/pydantic/pull/11319) + +## v2.10.6 (2025-01-23) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.6) + +### What's Changed + +#### Fixes + +* Fix JSON Schema reference collection with `'examples'` keys by [@Viicos](https://github.com/Viicos) in [#11325](https://github.com/pydantic/pydantic/pull/11325) +* Fix url python serialization by [@sydney-runkle](https://github.com/sydney-runkle) in [#11331](https://github.com/pydantic/pydantic/pull/11331) + +## v2.10.5 (2025-01-08) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.5) + +### What's Changed + +#### Fixes + +* Remove custom MRO implementation of Pydantic models by [@Viicos](https://github.com/Viicos) in [#11184](https://github.com/pydantic/pydantic/pull/11184) +* Fix URL serialization for unions by [@sydney-runkle](https://github.com/sydney-runkle) in [#11233](https://github.com/pydantic/pydantic/pull/11233) + +## v2.10.4 (2024-12-18) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.4) + +### What's Changed + +#### Fixes + +* Fix for comparison of `AnyUrl` objects by [@alexprabhat99](https://github.com/alexprabhat99) in [#11082](https://github.com/pydantic/pydantic/pull/11082) +* Properly fetch PEP 695 type params for functions, do not fetch annotations from signature by [@Viicos](https://github.com/Viicos) in [#11093](https://github.com/pydantic/pydantic/pull/11093) +* Include JSON Schema input core schema in function schemas by [@Viicos](https://github.com/Viicos) in [#11085](https://github.com/pydantic/pydantic/pull/11085) +* Add `len` to `_BaseUrl` to avoid TypeError by [@Kharianne](https://github.com/Kharianne) in [#11111](https://github.com/pydantic/pydantic/pull/11111) +* Make sure the type reference is removed from the seen references by [@Viicos](https://github.com/Viicos) in [#11143](https://github.com/pydantic/pydantic/pull/11143) + +### New Contributors + +* [@FyZzyss](https://github.com/FyZzyss) made their first contribution in [#10789](https://github.com/pydantic/pydantic/pull/10789) +* [@tamird](https://github.com/tamird) made their first contribution in [#10948](https://github.com/pydantic/pydantic/pull/10948) +* [@felixxm](https://github.com/felixxm) made their first contribution in [#11077](https://github.com/pydantic/pydantic/pull/11077) +* [@alexprabhat99](https://github.com/alexprabhat99) made their first contribution in [#11082](https://github.com/pydantic/pydantic/pull/11082) +* [@Kharianne](https://github.com/Kharianne) made their first contribution in [#11111](https://github.com/pydantic/pydantic/pull/11111) + +#### Packaging + +* Bump `pydantic-core` to v2.27.2 by [@davidhewitt](https://github.com/davidhewitt) in [#11138](https://github.com/pydantic/pydantic/pull/11138) + +## v2.10.3 (2024-12-03) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.3) + +### What's Changed + +#### Fixes + +* Set fields when `defer_build` is set on Pydantic dataclasses by [@Viicos](https://github.com/Viicos) in [#10984](https://github.com/pydantic/pydantic/pull/10984) +* Do not resolve the JSON Schema reference for `dict` core schema keys by [@Viicos](https://github.com/Viicos) in [#10989](https://github.com/pydantic/pydantic/pull/10989) +* Use the globals of the function when evaluating the return type for `PlainSerializer` and `WrapSerializer` functions by [@Viicos](https://github.com/Viicos) in [#11008](https://github.com/pydantic/pydantic/pull/11008) +* Fix host required enforcement for urls to be compatible with v2.9 behavior by [@sydney-runkle](https://github.com/sydney-runkle) in [#11027](https://github.com/pydantic/pydantic/pull/11027) +* Add a `default_factory_takes_validated_data` property to `FieldInfo` by [@Viicos](https://github.com/Viicos) in [#11034](https://github.com/pydantic/pydantic/pull/11034) +* Fix url json schema in `serialization` mode by [@sydney-runkle](https://github.com/sydney-runkle) in [#11035](https://github.com/pydantic/pydantic/pull/11035) + +## v2.10.2 (2024-11-25) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.2) + +### What's Changed + +#### Fixes + +* Only evaluate FieldInfo annotations if required during schema building by [@Viicos](https://github.com/Viicos) in [#10769](https://github.com/pydantic/pydantic/pull/10769) +* Do not evaluate annotations for private fields by [@Viicos](https://github.com/Viicos) in [#10962](https://github.com/pydantic/pydantic/pull/10962) +* Support serialization as any for `Secret` types and `Url` types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10947](https://github.com/pydantic/pydantic/pull/10947) +* Fix type hint of `Field.default` to be compatible with Python 3.8 and 3.9 by [@Viicos](https://github.com/Viicos) in [#10972](https://github.com/pydantic/pydantic/pull/10972) +* Add hashing support for URL types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10975](https://github.com/pydantic/pydantic/pull/10975) +* Hide `BaseModel.__replace__` definition from type checkers by [@Viicos](https://github.com/Viicos) in [#10979](https://github.com/pydantic/pydantic/pull/10979) + +## v2.10.1 (2024-11-21) + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.1) + +### What's Changed + +#### Fixes + +* Use the correct frame when instantiating a parametrized `TypeAdapter` by [@Viicos](https://github.com/Viicos) in [#10893](https://github.com/pydantic/pydantic/pull/10893) +* Relax check for validated data in `default_factory` utils by [@sydney-runkle](https://github.com/sydney-runkle) in [#10909](https://github.com/pydantic/pydantic/pull/10909) +* Fix type checking issue with `model_fields` and `model_computed_fields` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10911](https://github.com/pydantic/pydantic/pull/10911) +* Use the parent configuration during schema generation for stdlib `dataclass`es by [@sydney-runkle](https://github.com/sydney-runkle) in [#10928](https://github.com/pydantic/pydantic/pull/10928) +* Use the `globals` of the function when evaluating the return type of serializers and `computed_field`s by [@Viicos](https://github.com/Viicos) in [#10929](https://github.com/pydantic/pydantic/pull/10929) +* Fix URL constraint application by [@sydney-runkle](https://github.com/sydney-runkle) in [#10922](https://github.com/pydantic/pydantic/pull/10922) +* Fix URL equality with different validation methods by [@sydney-runkle](https://github.com/sydney-runkle) in [#10934](https://github.com/pydantic/pydantic/pull/10934) +* Fix JSON schema title when specified as `''` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10936](https://github.com/pydantic/pydantic/pull/10936) +* Fix `python` mode serialization for `complex` inference by [@sydney-runkle](https://github.com/sydney-runkle) in [pydantic-core#1549](https://github.com/pydantic/pydantic-core/pull/1549) + +#### Packaging + +* Bump `pydantic-core` version to `v2.27.1` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10938](https://github.com/pydantic/pydantic/pull/10938) + +### New Contributors + +## v2.10.0 (2024-11-20) + +The code released in v2.10.0 is practically identical to that of v2.10.0b2. + +[GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0) + +See the [v2.10 release blog post](https://pydantic.dev/articles/pydantic-v2-10-release) for the highlights! + +### What's Changed + +#### New Features + +* Support `fractions.Fraction` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10318](https://github.com/pydantic/pydantic/pull/10318) +* Support `Hashable` for json validation by [@sydney-runkle](https://github.com/sydney-runkle) in [#10324](https://github.com/pydantic/pydantic/pull/10324) +* Add a `SocketPath` type for `linux` systems by [@theunkn0wn1](https://github.com/theunkn0wn1) in [#10378](https://github.com/pydantic/pydantic/pull/10378) +* Allow arbitrary refs in JSON schema `examples` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10417](https://github.com/pydantic/pydantic/pull/10417) +* Support `defer_build` for Pydantic dataclasses by [@Viicos](https://github.com/Viicos) in [#10313](https://github.com/pydantic/pydantic/pull/10313) +* Adding v1 / v2 incompatibility warning for nested v1 model by [@sydney-runkle](https://github.com/sydney-runkle) in [#10431](https://github.com/pydantic/pydantic/pull/10431) +* Add support for unpacked `TypedDict` to type hint variadic keyword arguments with `@validate_call` by [@Viicos](https://github.com/Viicos) in [#10416](https://github.com/pydantic/pydantic/pull/10416) +* Support compiled patterns in `protected_namespaces` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10522](https://github.com/pydantic/pydantic/pull/10522) +* Add support for `propertyNames` in JSON schema by [@FlorianSW](https://github.com/FlorianSW) in [#10478](https://github.com/pydantic/pydantic/pull/10478) +* Adding `__replace__` protocol for Python 3.13+ support by [@sydney-runkle](https://github.com/sydney-runkle) in [#10596](https://github.com/pydantic/pydantic/pull/10596) +* Expose public `sort` method for JSON schema generation by [@sydney-runkle](https://github.com/sydney-runkle) in [#10595](https://github.com/pydantic/pydantic/pull/10595) +* Add runtime validation of `@validate_call` callable argument by [@kc0506](https://github.com/kc0506) in [#10627](https://github.com/pydantic/pydantic/pull/10627) +* Add `experimental_allow_partial` support by [@samuelcolvin](https://github.com/samuelcolvin) in [#10748](https://github.com/pydantic/pydantic/pull/10748) +* Support default factories taking validated data as an argument by [@Viicos](https://github.com/Viicos) in [#10678](https://github.com/pydantic/pydantic/pull/10678) +* Allow subclassing `ValidationError` and `PydanticCustomError` by [@Youssefares](https://github.com/Youssefares) in [pydantic/pydantic-core#1413](https://github.com/pydantic/pydantic-core/pull/1413) +* Add `trailing-strings` support to `experimental_allow_partial` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10825](https://github.com/pydantic/pydantic/pull/10825) +* Add `rebuild()` method for `TypeAdapter` and simplify `defer_build` patterns by [@sydney-runkle](https://github.com/sydney-runkle) in [#10537](https://github.com/pydantic/pydantic/pull/10537) +* Improve `TypeAdapter` instance repr by [@sydney-runkle](https://github.com/sydney-runkle) in [#10872](https://github.com/pydantic/pydantic/pull/10872) + +#### Changes + +* Don't allow customization of `SchemaGenerator` until interface is more stable by [@sydney-runkle](https://github.com/sydney-runkle) in [#10303](https://github.com/pydantic/pydantic/pull/10303) +* Cleanly `defer_build` on `TypeAdapters`, removing experimental flag by [@sydney-runkle](https://github.com/sydney-runkle) in [#10329](https://github.com/pydantic/pydantic/pull/10329) +* Fix `mro` of generic subclass by [@kc0506](https://github.com/kc0506) in [#10100](https://github.com/pydantic/pydantic/pull/10100) +* Strip whitespaces on JSON Schema title generation by [@sydney-runkle](https://github.com/sydney-runkle) in [#10404](https://github.com/pydantic/pydantic/pull/10404) +* Use `b64decode` and `b64encode` for `Base64Bytes` type by [@sydney-runkle](https://github.com/sydney-runkle) in [#10486](https://github.com/pydantic/pydantic/pull/10486) +* Relax protected namespace config default by [@sydney-runkle](https://github.com/sydney-runkle) in [#10441](https://github.com/pydantic/pydantic/pull/10441) +* Revalidate parametrized generics if instance's origin is subclass of OG class by [@sydney-runkle](https://github.com/sydney-runkle) in [#10666](https://github.com/pydantic/pydantic/pull/10666) +* Warn if configuration is specified on the `@dataclass` decorator and with the `__pydantic_config__` attribute by [@sydney-runkle](https://github.com/sydney-runkle) in [#10406](https://github.com/pydantic/pydantic/pull/10406) +* Recommend against using `Ellipsis` (...) with `Field` by [@Viicos](https://github.com/Viicos) in [#10661](https://github.com/pydantic/pydantic/pull/10661) +* Migrate to subclassing instead of annotated approach for pydantic url types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10662](https://github.com/pydantic/pydantic/pull/10662) +* Change JSON schema generation of `Literal`s and `Enums` by [@Viicos](https://github.com/Viicos) in [#10692](https://github.com/pydantic/pydantic/pull/10692) +* Simplify unions involving `Any` or `Never` when replacing type variables by [@Viicos](https://github.com/Viicos) in [#10338](https://github.com/pydantic/pydantic/pull/10338) +* Do not require padding when decoding `base64` bytes by [@bschoenmaeckers](https://github.com/bschoenmaeckers) in [pydantic/pydantic-core#1448](https://github.com/pydantic/pydantic-core/pull/1448) +* Support dates all the way to 1BC by [@changhc](https://github.com/changhc) in [pydantic/speedate#77](https://github.com/pydantic/speedate/pull/77) + +#### Performance + +* Schema cleaning: skip unnecessary copies during schema walking by [@Viicos](https://github.com/Viicos) in [#10286](https://github.com/pydantic/pydantic/pull/10286) +* Refactor namespace logic for annotations evaluation by [@Viicos](https://github.com/Viicos) in [#10530](https://github.com/pydantic/pydantic/pull/10530) +* Improve email regexp on edge cases by [@AlekseyLobanov](https://github.com/AlekseyLobanov) in [#10601](https://github.com/pydantic/pydantic/pull/10601) +* `CoreMetadata` refactor with an emphasis on documentation, schema build time performance, and reducing complexity by [@sydney-runkle](https://github.com/sydney-runkle) in [#10675](https://github.com/pydantic/pydantic/pull/10675) + +#### Packaging + +* Bump `pydantic-core` to `v2.27.0` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10825](https://github.com/pydantic/pydantic/pull/10825) +* Replaced pdm with uv by [@frfahim](https://github.com/frfahim) in [#10727](https://github.com/pydantic/pydantic/pull/10727) + +#### Fixes + +* Remove guarding check on `computed_field` with `field_serializer` by [@nix010](https://github.com/nix010) in [#10390](https://github.com/pydantic/pydantic/pull/10390) +* Fix `Predicate` issue in `v2.9.0` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10321](https://github.com/pydantic/pydantic/pull/10321) +* Fixing `annotated-types` bound by [@sydney-runkle](https://github.com/sydney-runkle) in [#10327](https://github.com/pydantic/pydantic/pull/10327) +* Turn `tzdata` install requirement into optional `timezone` dependency by [@jakob-keller](https://github.com/jakob-keller) in [#10331](https://github.com/pydantic/pydantic/pull/10331) +* Use correct types namespace when building `namedtuple` core schemas by [@Viicos](https://github.com/Viicos) in [#10337](https://github.com/pydantic/pydantic/pull/10337) +* Fix evaluation of stringified annotations during namespace inspection by [@Viicos](https://github.com/Viicos) in [#10347](https://github.com/pydantic/pydantic/pull/10347) +* Fix `IncEx` type alias definition by [@Viicos](https://github.com/Viicos) in [#10339](https://github.com/pydantic/pydantic/pull/10339) +* Do not error when trying to evaluate annotations of private attributes by [@Viicos](https://github.com/Viicos) in [#10358](https://github.com/pydantic/pydantic/pull/10358) +* Fix nested type statement by [@kc0506](https://github.com/kc0506) in [#10369](https://github.com/pydantic/pydantic/pull/10369) +* Improve typing of `ModelMetaclass.mro` by [@Viicos](https://github.com/Viicos) in [#10372](https://github.com/pydantic/pydantic/pull/10372) +* Fix class access of deprecated `computed_field`s by [@Viicos](https://github.com/Viicos) in [#10391](https://github.com/pydantic/pydantic/pull/10391) +* Make sure `inspect.iscoroutinefunction` works on coroutines decorated with `@validate_call` by [@MovisLi](https://github.com/MovisLi) in [#10374](https://github.com/pydantic/pydantic/pull/10374) +* Fix `NameError` when using `validate_call` with PEP 695 on a class by [@kc0506](https://github.com/kc0506) in [#10380](https://github.com/pydantic/pydantic/pull/10380) +* Fix `ZoneInfo` with various invalid types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10408](https://github.com/pydantic/pydantic/pull/10408) +* Fix `PydanticUserError` on empty `model_config` with annotations by [@cdwilson](https://github.com/cdwilson) in [#10412](https://github.com/pydantic/pydantic/pull/10412) +* Fix variance issue in `_IncEx` type alias, only allow `True` by [@Viicos](https://github.com/Viicos) in [#10414](https://github.com/pydantic/pydantic/pull/10414) +* Fix serialization schema generation when using `PlainValidator` by [@Viicos](https://github.com/Viicos) in [#10427](https://github.com/pydantic/pydantic/pull/10427) +* Fix schema generation error when serialization schema holds references by [@Viicos](https://github.com/Viicos) in [#10444](https://github.com/pydantic/pydantic/pull/10444) +* Inline references if possible when generating schema for `json_schema_input_type` by [@Viicos](https://github.com/Viicos) in [#10439](https://github.com/pydantic/pydantic/pull/10439) +* Fix recursive arguments in `Representation` by [@Viicos](https://github.com/Viicos) in [#10480](https://github.com/pydantic/pydantic/pull/10480) +* Fix representation for builtin function types by [@kschwab](https://github.com/kschwab) in [#10479](https://github.com/pydantic/pydantic/pull/10479) +* Add python validators for decimal constraints (`max_digits` and `decimal_places`) by [@sydney-runkle](https://github.com/sydney-runkle) in [#10506](https://github.com/pydantic/pydantic/pull/10506) +* Only fetch `__pydantic_core_schema__` from the current class during schema generation by [@Viicos](https://github.com/Viicos) in [#10518](https://github.com/pydantic/pydantic/pull/10518) +* Fix `stacklevel` on deprecation warnings for `BaseModel` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10520](https://github.com/pydantic/pydantic/pull/10520) +* Fix warning `stacklevel` in `BaseModel.__init__` by [@Viicos](https://github.com/Viicos) in [#10526](https://github.com/pydantic/pydantic/pull/10526) +* Improve error handling for in-evaluable refs for discriminator application by [@sydney-runkle](https://github.com/sydney-runkle) in [#10440](https://github.com/pydantic/pydantic/pull/10440) +* Change the signature of `ConfigWrapper.core_config` to take the title directly by [@Viicos](https://github.com/Viicos) in [#10562](https://github.com/pydantic/pydantic/pull/10562) +* Do not use the previous config from the stack for dataclasses without config by [@Viicos](https://github.com/Viicos) in [#10576](https://github.com/pydantic/pydantic/pull/10576) +* Fix serialization for IP types with `mode='python'` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10594](https://github.com/pydantic/pydantic/pull/10594) +* Support constraint application for `Base64Etc` types by [@sydney-runkle](https://github.com/sydney-runkle) in [#10584](https://github.com/pydantic/pydantic/pull/10584) +* Fix `validate_call` ignoring `Field` in `Annotated` by [@kc0506](https://github.com/kc0506) in [#10610](https://github.com/pydantic/pydantic/pull/10610) +* Raise an error when `Self` is invalid by [@kc0506](https://github.com/kc0506) in [#10609](https://github.com/pydantic/pydantic/pull/10609) +* Using `core_schema.InvalidSchema` instead of metadata injection + checks by [@sydney-runkle](https://github.com/sydney-runkle) in [#10523](https://github.com/pydantic/pydantic/pull/10523) +* Tweak type alias logic by [@kc0506](https://github.com/kc0506) in [#10643](https://github.com/pydantic/pydantic/pull/10643) +* Support usage of `type` with `typing.Self` and type aliases by [@kc0506](https://github.com/kc0506) in [#10621](https://github.com/pydantic/pydantic/pull/10621) +* Use overloads for `Field` and `PrivateAttr` functions by [@Viicos](https://github.com/Viicos) in [#10651](https://github.com/pydantic/pydantic/pull/10651) +* Clean up the `mypy` plugin implementation by [@Viicos](https://github.com/Viicos) in [#10669](https://github.com/pydantic/pydantic/pull/10669) +* Properly check for `typing_extensions` variant of `TypeAliasType` by [@Daraan](https://github.com/Daraan) in [#10713](https://github.com/pydantic/pydantic/pull/10713) +* Allow any mapping in `BaseModel.model_copy()` by [@Viicos](https://github.com/Viicos) in [#10751](https://github.com/pydantic/pydantic/pull/10751) +* Fix `isinstance` behavior for urls by [@sydney-runkle](https://github.com/sydney-runkle) in [#10766](https://github.com/pydantic/pydantic/pull/10766) +* Ensure `cached_property` can be set on Pydantic models by [@Viicos](https://github.com/Viicos) in [#10774](https://github.com/pydantic/pydantic/pull/10774) +* Fix equality checks for primitives in literals by [@sydney-runkle](https://github.com/sydney-runkle) in [pydantic/pydantic-core#1459](https://github.com/pydantic/pydantic-core/pull/1459) +* Properly enforce `host_required` for URLs by [@Viicos](https://github.com/Viicos) in [pydantic/pydantic-core#1488](https://github.com/pydantic/pydantic-core/pull/1488) +* Fix when `coerce_numbers_to_str` enabled and string has invalid Unicode character by [@andrey-berenda](https://github.com/andrey-berenda) in [pydantic/pydantic-core#1515](https://github.com/pydantic/pydantic-core/pull/1515) +* Fix serializing `complex` values in `Enum`s by [@changhc](https://github.com/changhc) in [pydantic/pydantic-core#1524](https://github.com/pydantic/pydantic-core/pull/1524) +* Refactor `_typing_extra` module by [@Viicos](https://github.com/Viicos) in [#10725](https://github.com/pydantic/pydantic/pull/10725) +* Support intuitive equality for urls by [@sydney-runkle](https://github.com/sydney-runkle) in [#10798](https://github.com/pydantic/pydantic/pull/10798) +* Add `bytearray` to `TypeAdapter.validate_json` signature by [@samuelcolvin](https://github.com/samuelcolvin) in [#10802](https://github.com/pydantic/pydantic/pull/10802) +* Ensure class access of method descriptors is performed when used as a default with `Field` by [@Viicos](https://github.com/Viicos) in [#10816](https://github.com/pydantic/pydantic/pull/10816) +* Fix circular import with `validate_call` by [@sydney-runkle](https://github.com/sydney-runkle) in [#10807](https://github.com/pydantic/pydantic/pull/10807) +* Fix error when using type aliases referencing other type aliases by [@Viicos](https://github.com/Viicos) in [#10809](https://github.com/pydantic/pydantic/pull/10809) +* Fix `IncEx` type alias to be compatible with mypy by [@Viicos](https://github.com/Viicos) in [#10813](https://github.com/pydantic/pydantic/pull/10813) +* Make `__signature__` a lazy property, do not deepcopy defaults by [@Viicos](https://github.com/Viicos) in [#10818](https://github.com/pydantic/pydantic/pull/10818) +* Make `__signature__` lazy for dataclasses, too by [@sydney-runkle](https://github.com/sydney-runkle) in [#10832](https://github.com/pydantic/pydantic/pull/10832) +* Subclass all single host url classes from `AnyUrl` to preserve behavior from v2.9 by [@sydney-runkle](https://github.com/sydney-runkle) in [#10856](https://github.com/pydantic/pydantic/pull/10856) + +### New Contributors + +* [@jakob-keller](https://github.com/jakob-keller) made their first contribution in [#10331](https://github.com/pydantic/pydantic/pull/10331) +* [@MovisLi](https://github.com/MovisLi) made their first contribution in [#10374](https://github.com/pydantic/pydantic/pull/10374) +* [@joaopalmeiro](https://github.com/joaopalmeiro) made their first contribution in [#10405](https://github.com/pydantic/pydantic/pull/10405) +* [@theunkn0wn1](https://github.com/theunkn0wn1) made their first contribution in [#10378](https://github.com/pydantic/pydantic/pull/10378) +* [@cdwilson](https://github.com/cdwilson) made their first contribution in [#10412](https://github.com/pydantic/pydantic/pull/10412) +* [@dlax](https://github.com/dlax) made their first contribution in [#10421](https://github.com/pydantic/pydantic/pull/10421) +* [@kschwab](https://github.com/kschwab) made their first contribution in [#10479](https://github.com/pydantic/pydantic/pull/10479) +* [@santibreo](https://github.com/santibreo) made their first contribution in [#10453](https://github.com/pydantic/pydantic/pull/10453) +* [@FlorianSW](https://github.com/FlorianSW) made their first contribution in [#10478](https://github.com/pydantic/pydantic/pull/10478) +* [@tkasuz](https://github.com/tkasuz) made their first contribution in [#10555](https://github.com/pydantic/pydantic/pull/10555) +* [@AlekseyLobanov](https://github.com/AlekseyLobanov) made their first contribution in [#10601](https://github.com/pydantic/pydantic/pull/10601) +* [@NiclasvanEyk](https://github.com/NiclasvanEyk) made their first contribution in [#10667](https://github.com/pydantic/pydantic/pull/10667) +* [@mschoettle](https://github.com/mschoettle) made their first contribution in [#10677](https://github.com/pydantic/pydantic/pull/10677) +* [@Daraan](https://github.com/Daraan) made their first contribution in [#10713](https://github.com/pydantic/pydantic/pull/10713) +* [@k4nar](https://github.com/k4nar) made their first contribution in [#10736](https://github.com/pydantic/pydantic/pull/10736) +* [@UriyaHarpeness](https://github.com/UriyaHarpeness) made their first contribution in [#10740](https://github.com/pydantic/pydantic/pull/10740) +* [@frfahim](https://github.com/frfahim) made their first contribution in [#10727](https://github.com/pydantic/pydantic/pull/10727) + +## v2.10.0b2 (2024-11-13) + +Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0b2) for details. + +## v2.10.0b1 (2024-11-06) + +Pre-release, see [the GitHub release](https://github.com/pydantic/pydantic/releases/tag/v2.10.0b1) for details. + + +... see [here](https://docs.pydantic.dev/changelog/#v0322-2019-08-17) for earlier changes. diff --git a/source/target-vendors/cp312/pydantic-2.13.5.dist-info/RECORD b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/RECORD new file mode 100644 index 0000000..51852ce --- /dev/null +++ b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/RECORD @@ -0,0 +1,111 @@ +pydantic/__init__.py,sha256=5iEnJ4wHv1OEzdKQPzaKaZKfO4pSQAC65ODrYI6_S8Y,15812 +pydantic/_migration.py,sha256=VF73LRCUz3Irb5xVt13jb3NAcXVnEF6T1-J0OLfeZ5A,12160 +pydantic/alias_generators.py,sha256=KM1n3u4JfLSBl1UuYg3hoYHzXJD-yvgrnq8u1ccwh_A,2124 +pydantic/aliases.py,sha256=vhCHyoSWnX-EJ-wWb5qj4xyRssgGWnTQfzQp4GSZ9ug,4937 +pydantic/annotated_handlers.py,sha256=WfyFSqwoEIFXBh7T73PycKloI1DiX45GWi0-JOsCR4Y,4407 +pydantic/class_validators.py,sha256=i_V3j-PYdGLSLmj_IJZekTRjunO8SIVz8LMlquPyP7E,148 +pydantic/color.py,sha256=AzqGfVQHF92_ZctDcue0DM4yTp2P6tekkwRINTWrLIo,21481 +pydantic/config.py,sha256=o1P67FMWIQG-_RfGtKislkHwo4pXm_6jfsR41P88v78,44533 +pydantic/dataclasses.py,sha256=4X9We0jj1KLwBtvYSkAFXNon46zrpBmRZANf4LfwbXg,18963 +pydantic/datetime_parse.py,sha256=QC-WgMxMr_wQ_mNXUS7AVf-2hLEhvvsPY1PQyhSGOdk,150 +pydantic/decorator.py,sha256=YX-jUApu5AKaVWKPoaV-n-4l7UbS69GEt9Ra3hszmKI,145 +pydantic/env_settings.py,sha256=6IHeeWEqlUPRUv3V-AXiF_W91fg2Jw_M3O0l34J_eyA,148 +pydantic/error_wrappers.py,sha256=RK6mqATc9yMD-KBD9IJS9HpKCprWHd8wo84Bnm-3fR8,150 +pydantic/errors.py,sha256=DrECPCWhSYrQ8Ba4O8hKzIAM2i9GBHTXWALzaFDpLf4,6013 +pydantic/fields.py,sha256=a8ZhJfI8FD6TQDD7-cWMm1ZXlQva0wMdT2Ey5VvVe-M,82023 +pydantic/functional_serializers.py,sha256=zwRAjZusORtEbtxpVU20kg8FpemyZz4Fq6wJk1mpwYQ,18117 +pydantic/functional_validators.py,sha256=7p-4jvP__9jZyvcdXiide5pAa_JlM7fJ1BgkqbjxSWM,31724 +pydantic/generics.py,sha256=0ZqZ9O9annIj_3mGBRqps4htey3b5lV1-d2tUxPMMnA,144 +pydantic/json.py,sha256=ZH8RkI7h4Bz-zp8OdTAxbJUoVvcoU-jhMdRZ0B-k0xc,140 +pydantic/json_schema.py,sha256=da3hQ9vQPLEhPsrDnUlijfQ1fuCCViGVnUzOrAZLgDs,125955 +pydantic/main.py,sha256=NbhCz-ku8wDgYLQMBi75Ov7hywdc8LewA3oUNIZ8JVQ,85334 +pydantic/mypy.py,sha256=ypnhh7hn-L-mk6sW4CcrdV2C5lyMzcM6FTBj21GufsE,61074 +pydantic/networks.py,sha256=gCB96gt0G7tiVDhVnJfpKr1ARL5qkH-SPZkuNkmG2O4,42102 +pydantic/parse.py,sha256=wkd82dgtvWtD895U_I6E1htqMlGhBSYEV39cuBSeo3A,141 +pydantic/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/root_model.py,sha256=cOMoeWdp536KF85uRIcW-oz1O7d5GRCpx9HTS4-1uf8,6394 +pydantic/schema.py,sha256=Vqqjvq_LnapVknebUd3Bp_J1p2gXZZnZRgL48bVEG7o,142 +pydantic/tools.py,sha256=iHQpd8SJ5DCTtPV5atAV06T89bjSaMFeZZ2LX9lasZY,141 +pydantic/type_adapter.py,sha256=T05g8WQczBsVU_35RdKxgjIi7Y7LIip67pF3NI7X4GE,36123 +pydantic/types.py,sha256=fpYcGnAncK4QjaFm3jZtqYwxJYzB7rJJPfAl89emzyQ,105961 +pydantic/typing.py,sha256=P7feA35MwTcLsR1uL7db0S-oydBxobmXa55YDoBgajQ,138 +pydantic/utils.py,sha256=15nR2QpqTBFlQV4TNtTItMyTJx_fbyV-gPmIEY1Gooc,141 +pydantic/validate_call_decorator.py,sha256=VLAi4hoFpjC-1eL0HixYaaWaEFO6htGcDctgsqa5VII,4416 +pydantic/validators.py,sha256=pwbIJXVb1CV2mAE4w_EGfNj7DwzsKaWw_tTL6cviTus,146 +pydantic/version.py,sha256=uKOxh0LjiZkZ0KfLmlpPYRAY-_NpIX8ijxOLDNhW8m8,3985 +pydantic/warnings.py,sha256=3QyQo6lN35cO7OXDbFEXWcNaPlGCRaregVZA-G-lZwI,4822 +pydantic/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/_internal/_config.py,sha256=Rzys1Joffn4JczElcYDqsZLRgBgHn2lYWqDR55oASPA,14839 +pydantic/_internal/_core_metadata.py,sha256=Y_g2t3i7uluK-wXCZvzJfRFMPUM23aBYLfae4FzBPy0,5162 +pydantic/_internal/_core_utils.py,sha256=1jru4VbJ0x63R6dtVcuOI-dKQTC_d_lSnJWEBQzGNEQ,6487 +pydantic/_internal/_dataclasses.py,sha256=Zgqcm1WaJLBwTQQC5mGKNowjlTgX3mfX_J5e2vd24lM,13188 +pydantic/_internal/_decorators.py,sha256=RDEG_Jau5NiJcfO0xgdT7EOgsU1LgWIYlX7wN5rYtVs,33620 +pydantic/_internal/_decorators_v1.py,sha256=tfdfdpQKY4R2XCOwqHbZeoQMur6VNigRrfhudXBHx38,6185 +pydantic/_internal/_discriminated_union.py,sha256=JLx_MVLep7Mxl1zbpdNZjvHDcz-J3OEW6WcdV184dcM,26255 +pydantic/_internal/_docs_extraction.py,sha256=fyznSAHh5AzohnXZStV0HvH-nRbavNHPyg-knx-S_EE,4127 +pydantic/_internal/_fields.py,sha256=hXeb-zodGwTDvG9OK1um18P64b7cqHb0GOngP4jrgcY,31557 +pydantic/_internal/_forward_ref.py,sha256=5n3Y7-3AKLn8_FS3Yc7KutLiPUhyXmAtkEZOaFnonwM,611 +pydantic/_internal/_generate_schema.py,sha256=PjogUawIXmf8LuLNe9seJph7WLW4MJ7-GBsXwCsQC9Q,136348 +pydantic/_internal/_generics.py,sha256=CXjcInlvci8VejaWn1f39kv0AcfJL0R523qRLFZVD-s,23393 +pydantic/_internal/_git.py,sha256=IwPh3DPfa2Xq3rBuB9Nx8luR2A1i69QdeTfWWXIuCVg,809 +pydantic/_internal/_import_utils.py,sha256=TRhxD5OuY6CUosioBdBcJUs0om7IIONiZdYAV7zQ8jM,402 +pydantic/_internal/_internal_dataclass.py,sha256=_bedc1XbuuygRGiLZqkUkwwFpQaoR1hKLlR501nyySY,144 +pydantic/_internal/_known_annotated_metadata.py,sha256=PynQIFQ61__4Gcrzn0D5ENllg7jPq_cxoLTmuFQBY88,16805 +pydantic/_internal/_mock_val_ser.py,sha256=wmRRFSBvqfcLbI41PsFliB4u2AZ3mJpZeiERbD3xKTo,8885 +pydantic/_internal/_model_construction.py,sha256=JoKmY4JrDBu3nG_tCIrJgtJJE1uq6v29TvTz5ElHE5g,38928 +pydantic/_internal/_namespace_utils.py,sha256=hl3-TRAr82U2jTyPP3t-QqsvKLirxtkLfNfrN-fp0x8,12878 +pydantic/_internal/_repr.py,sha256=jQfnJuyDxQpSRNhG29II9PX8e4Nv2qWZrEw2lqih3UE,5172 +pydantic/_internal/_schema_gather.py,sha256=8nJ-uM6Y4z6xpasnGonEMubtNVX_mxeeRDFmd_qMVLA,9052 +pydantic/_internal/_schema_generation_shared.py,sha256=F_rbQbrkoomgxsskdHpP0jUJ7TCfe0BADAEkq6CJ4nM,4842 +pydantic/_internal/_serializers.py,sha256=YIWvSmAR5fnbGSWCOQduWt1yB4ZQY42eAruc-enrb6c,1491 +pydantic/_internal/_signature.py,sha256=i_b6wtluiVWZRh1ZY8UvB2UZziP1KjqSXZgC-HxwOT0,6808 +pydantic/_internal/_typing_extra.py,sha256=dDxqF46lzuqCoKLrAH_k95EDbayEeKb2lHjuTJ5OBoY,31574 +pydantic/_internal/_utils.py,sha256=gN48BsR-FDrJDibCmo69ttQg67WbuFrdy_1NQL3cvLI,15959 +pydantic/_internal/_validate_call.py,sha256=OD_BspHaL9FKzZ9XrndhiEuMnjF3SRIJUHtwv6yUffU,5366 +pydantic/_internal/_validators.py,sha256=7GTjXXWFMLib4dxQ-HeaiHlAZiR2B2G8byCYMGrmQ48,20563 +pydantic/deprecated/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/deprecated/class_validators.py,sha256=n0jYQOcb5YQiw0b7YXyi7NPiYdV7ujWR4KyZumjTPok,10281 +pydantic/deprecated/config.py,sha256=k_lsVk57paxLJOcBueH07cu1OgEgWdVBxm6lfaC3CCU,2663 +pydantic/deprecated/copy_internals.py,sha256=Ghd-vkMd5EYCCgyCGtPKO58np9cEKBQC6qkBeIEFI2g,7618 +pydantic/deprecated/decorator.py,sha256=TBm6bJ7wJsNih_8Wq5IzDcwP32m9_vfxs96desLuk00,10845 +pydantic/deprecated/json.py,sha256=HlWCG35RRrxyzuTS6LTQiZBwRhmDZWmeqQH8rLW6wA8,4657 +pydantic/deprecated/parse.py,sha256=Gzd6b_g8zJXcuE7QRq5adhx_EMJahXfcpXCF0RgrqqI,2511 +pydantic/deprecated/tools.py,sha256=Nrm9oFRZWp8-jlfvPgJILEsywp4YzZD52XIGPDLxHcI,3330 +pydantic/experimental/__init__.py,sha256=QT7rKYdDsCiTJ9GEjmsQdWHScwpKrrNkGq6vqONP6RQ,104 +pydantic/experimental/arguments_schema.py,sha256=EFnjX_ulp-tPyUjQX5pmQtug1OFL_Acc8bcMbLd-fVY,1866 +pydantic/experimental/missing_sentinel.py,sha256=hQejgtF00wUuQMni9429evg-eXyIwpKvjsD8ofqfj-w,127 +pydantic/experimental/pipeline.py,sha256=auoW6l6g1FC41LciPmsI1M6ncf00Szde9B3C-yvb9mI,23956 +pydantic/plugin/__init__.py,sha256=a7Tw366U6K3kltCCNZY76nc9ss-7uGGQ40TXad9OypQ,7333 +pydantic/plugin/_loader.py,sha256=hAjgSljoIhGx3AVpIpuqw5SPttBNNeGBSTrqSMnNiJk,2213 +pydantic/plugin/_schema_validator.py,sha256=thbZz_-5sYPzxsC5uWK5GDfYcmmrsecC8Vw_A02mhwU,5815 +pydantic/v1/__init__.py,sha256=SxQPklgBs4XHJwE6BZ9qoewYoGiNyYUnmHzEFCZbfnI,2946 +pydantic/v1/_hypothesis_plugin.py,sha256=5ES5xWuw1FQAsymLezy8QgnVz0ZpVfU3jkmT74H27VQ,14847 +pydantic/v1/annotated_types.py,sha256=uk2NAAxqiNELKjiHhyhxKaIOh8F1lYW_LzrW3X7oZBc,3157 +pydantic/v1/class_validators.py,sha256=ULOaIUgYUDBsHL7EEVEarcM-UubKUggoN8hSbDonsFE,14672 +pydantic/v1/color.py,sha256=iZABLYp6OVoo2AFkP9Ipri_wSc6-Kklu8YuhSartd5g,16844 +pydantic/v1/config.py,sha256=a6P0Wer9x4cbwKW7Xv8poSUqM4WP-RLWwX6YMpYq9AA,6532 +pydantic/v1/dataclasses.py,sha256=784cqvInbwIPWr9usfpX3ch7z4t3J2tTK6N067_wk1o,18172 +pydantic/v1/datetime_parse.py,sha256=4Qy1kQpq3rNVZJeIHeSPDpuS2Bvhp1KPtzJG1xu-H00,7724 +pydantic/v1/decorator.py,sha256=zaaxxxoWPCm818D1bs0yhapRjXm32V8G0ZHWCdM1uXA,10339 +pydantic/v1/env_settings.py,sha256=A9VXwtRl02AY-jH0C0ouy5VNw3fi6F_pkzuHDjgAAOM,14105 +pydantic/v1/error_wrappers.py,sha256=6625Mfw9qkC2NwitB_JFAWe8B-Xv6zBU7rL9k28tfyo,5196 +pydantic/v1/errors.py,sha256=mIwPED5vGM5Q5v4C4Z1JPldTRH-omvEylH6ksMhOmPw,17726 +pydantic/v1/fields.py,sha256=VqWJCriUNiEyptXroDVJ501JpVA0en2VANcksqXL2b8,50649 +pydantic/v1/generics.py,sha256=YzyKTZN6x5Q1RGJ3WQ9jN-uwHJxL3W4qoZqwcZXqxWg,17829 +pydantic/v1/json.py,sha256=WQ5Hy_hIpfdR3YS8k6N2E6KMJzsdbBi_ldWOPJaV81M,3390 +pydantic/v1/main.py,sha256=vRB1TbpkzPN3P5ijJlc-cjNuO-HciNOpC4b8K3zZnfc,45697 +pydantic/v1/mypy.py,sha256=Cl8XRfCmIcVE3j5AEU52C8iDh8lcX__D3hz2jIWxMAs,38860 +pydantic/v1/networks.py,sha256=HYNtKAfOmOnKJpsDg1g6SIkj9WPhU_-i8l5e2JKBpG4,22124 +pydantic/v1/parse.py,sha256=BJtdqiZRtav9VRFCmOxoY-KImQmjPy-A_NoojiFUZxY,1821 +pydantic/v1/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic/v1/schema.py,sha256=aqBuA--cq8gAVkim5BJPFASHzOZ8dFtmFX_fNGr6ip4,47801 +pydantic/v1/tools.py,sha256=1lDdXHk0jL5uP3u5RCYAvUAlGClgAO-45lkq9j7fyBA,2881 +pydantic/v1/types.py,sha256=Bzl-RcnitPBHnqwwj9iv7JjHuN1GpnWH24dKkF3l9e8,35455 +pydantic/v1/typing.py,sha256=ovwtLpEZCbnghZaHfSNJupzetzHNkLXjn_66kgTnIV4,20102 +pydantic/v1/utils.py,sha256=1PqOIlz6OVWwGds3HBKlw4Et6asFou0UUpAto7jFOCs,26014 +pydantic/v1/validators.py,sha256=lyUkn1MWhHxlCX5ZfEgFj_CAHojoiPcaQeMdEM9XviU,22187 +pydantic/v1/version.py,sha256=YpHWOQKtGoxfyikzGrcmXJVKUVYB9EBdoCR994QxSnE,1039 +pydantic-2.13.5.dist-info/METADATA,sha256=BoWDDRNke9bz8FUmBD0yqLKiIdhrU3cwU9bFK7F6nAc,110178 +pydantic-2.13.5.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87 +pydantic-2.13.5.dist-info/licenses/LICENSE,sha256=qeGG88oWte74QxjnpwFyE1GgDLe4rjpDlLZ7SeNSnvM,1129 +pydantic-2.13.5.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/pydantic-2.13.5.dist-info/WHEEL b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/WHEEL new file mode 100644 index 0000000..51abe1f --- /dev/null +++ b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.32.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/pydantic-2.13.5.dist-info/licenses/LICENSE b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/licenses/LICENSE new file mode 100644 index 0000000..488c626 --- /dev/null +++ b/source/target-vendors/cp312/pydantic-2.13.5.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 to present Pydantic Services Inc. and individual contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/source/target-vendors/cp312/pydantic/__init__.py b/source/target-vendors/cp312/pydantic/__init__.py new file mode 100644 index 0000000..0121284 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/__init__.py @@ -0,0 +1,456 @@ +from importlib import import_module +from typing import TYPE_CHECKING +from warnings import warn + +from ._migration import getattr_migration +from .version import VERSION, _ensure_pydantic_core_version + +_ensure_pydantic_core_version() +del _ensure_pydantic_core_version + +if TYPE_CHECKING: + # import of virtually everything is supported via `__getattr__` below, + # but we need them here for type checking and IDE support + import pydantic_core + from pydantic_core.core_schema import ( + FieldSerializationInfo, + SerializationInfo, + SerializerFunctionWrapHandler, + ValidationInfo, + ValidatorFunctionWrapHandler, + ) + + from . import dataclasses + from .aliases import AliasChoices, AliasGenerator, AliasPath + from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler + from .config import ConfigDict, with_config + from .errors import * + from .fields import Field, PrivateAttr, computed_field + from .functional_serializers import ( + PlainSerializer, + SerializeAsAny, + WrapSerializer, + field_serializer, + model_serializer, + ) + from .functional_validators import ( + AfterValidator, + BeforeValidator, + InstanceOf, + ModelWrapValidatorHandler, + PlainValidator, + SkipValidation, + ValidateAs, + WrapValidator, + field_validator, + model_validator, + ) + from .json_schema import WithJsonSchema + from .main import * + from .networks import * + from .type_adapter import TypeAdapter + from .types import * + from .validate_call_decorator import validate_call + from .warnings import ( + PydanticDeprecatedSince20, + PydanticDeprecatedSince26, + PydanticDeprecatedSince29, + PydanticDeprecatedSince210, + PydanticDeprecatedSince211, + PydanticDeprecatedSince212, + PydanticDeprecationWarning, + PydanticExperimentalWarning, + ) + + # this encourages pycharm to import `ValidationError` from here, not pydantic_core + ValidationError = pydantic_core.ValidationError + from .deprecated.class_validators import root_validator, validator + from .deprecated.config import BaseConfig, Extra + from .deprecated.tools import * + from .root_model import RootModel + +__version__ = VERSION +__all__ = ( + # dataclasses + 'dataclasses', + # functional validators + 'field_validator', + 'model_validator', + 'AfterValidator', + 'BeforeValidator', + 'PlainValidator', + 'WrapValidator', + 'SkipValidation', + 'ValidateAs', + 'InstanceOf', + 'ModelWrapValidatorHandler', + # JSON Schema + 'WithJsonSchema', + # deprecated V1 functional validators, these are imported via `__getattr__` below + 'root_validator', + 'validator', + # functional serializers + 'field_serializer', + 'model_serializer', + 'PlainSerializer', + 'SerializeAsAny', + 'WrapSerializer', + # config + 'ConfigDict', + 'with_config', + # deprecated V1 config, these are imported via `__getattr__` below + 'BaseConfig', + 'Extra', + # validate_call + 'validate_call', + # errors + 'PydanticErrorCodes', + 'PydanticUserError', + 'PydanticSchemaGenerationError', + 'PydanticImportError', + 'PydanticUndefinedAnnotation', + 'PydanticInvalidForJsonSchema', + 'PydanticForbiddenQualifier', + # fields + 'Field', + 'computed_field', + 'PrivateAttr', + # alias + 'AliasChoices', + 'AliasGenerator', + 'AliasPath', + # main + 'BaseModel', + 'create_model', + # network + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'HttpUrl', + 'FtpUrl', + 'WebsocketUrl', + 'AnyWebsocketUrl', + 'UrlConstraints', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'NatsDsn', + 'MySQLDsn', + 'MariaDBDsn', + 'ClickHouseDsn', + 'SnowflakeDsn', + 'validate_email', + # root_model + 'RootModel', + # deprecated tools, these are imported via `__getattr__` below + 'parse_obj_as', + 'schema_of', + 'schema_json_of', + # types + 'Strict', + 'StrictStr', + 'conbytes', + 'conlist', + 'conset', + 'confrozenset', + 'constr', + 'StringConstraints', + 'ImportString', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'condecimal', + 'condate', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'UUID6', + 'UUID7', + 'UUID8', + 'FilePath', + 'DirectoryPath', + 'NewPath', + 'Json', + 'Secret', + 'SecretStr', + 'SecretBytes', + 'SocketPath', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'ByteSize', + 'PastDate', + 'FutureDate', + 'PastDatetime', + 'FutureDatetime', + 'AwareDatetime', + 'NaiveDatetime', + 'AllowInfNan', + 'EncoderProtocol', + 'EncodedBytes', + 'EncodedStr', + 'Base64Encoder', + 'Base64Bytes', + 'Base64Str', + 'Base64UrlBytes', + 'Base64UrlStr', + 'GetPydanticSchema', + 'Tag', + 'Discriminator', + 'JsonValue', + 'FailFast', + # type_adapter + 'TypeAdapter', + # version + '__version__', + 'VERSION', + # warnings + 'PydanticDeprecatedSince20', + 'PydanticDeprecatedSince26', + 'PydanticDeprecatedSince29', + 'PydanticDeprecatedSince210', + 'PydanticDeprecatedSince211', + 'PydanticDeprecatedSince212', + 'PydanticDeprecationWarning', + 'PydanticExperimentalWarning', + # annotated handlers + 'GetCoreSchemaHandler', + 'GetJsonSchemaHandler', + # pydantic_core + 'ValidationError', + 'ValidationInfo', + 'SerializationInfo', + 'ValidatorFunctionWrapHandler', + 'FieldSerializationInfo', + 'SerializerFunctionWrapHandler', + 'OnErrorOmit', +) + +# A mapping of {: (package, )} defining dynamic imports +_dynamic_imports: 'dict[str, tuple[str, str]]' = { + 'dataclasses': (__spec__.parent, '__module__'), + # functional validators + 'field_validator': (__spec__.parent, '.functional_validators'), + 'model_validator': (__spec__.parent, '.functional_validators'), + 'AfterValidator': (__spec__.parent, '.functional_validators'), + 'BeforeValidator': (__spec__.parent, '.functional_validators'), + 'PlainValidator': (__spec__.parent, '.functional_validators'), + 'WrapValidator': (__spec__.parent, '.functional_validators'), + 'SkipValidation': (__spec__.parent, '.functional_validators'), + 'InstanceOf': (__spec__.parent, '.functional_validators'), + 'ValidateAs': (__spec__.parent, '.functional_validators'), + 'ModelWrapValidatorHandler': (__spec__.parent, '.functional_validators'), + # JSON Schema + 'WithJsonSchema': (__spec__.parent, '.json_schema'), + # functional serializers + 'field_serializer': (__spec__.parent, '.functional_serializers'), + 'model_serializer': (__spec__.parent, '.functional_serializers'), + 'PlainSerializer': (__spec__.parent, '.functional_serializers'), + 'SerializeAsAny': (__spec__.parent, '.functional_serializers'), + 'WrapSerializer': (__spec__.parent, '.functional_serializers'), + # config + 'ConfigDict': (__spec__.parent, '.config'), + 'with_config': (__spec__.parent, '.config'), + # validate call + 'validate_call': (__spec__.parent, '.validate_call_decorator'), + # errors + 'PydanticErrorCodes': (__spec__.parent, '.errors'), + 'PydanticUserError': (__spec__.parent, '.errors'), + 'PydanticSchemaGenerationError': (__spec__.parent, '.errors'), + 'PydanticImportError': (__spec__.parent, '.errors'), + 'PydanticUndefinedAnnotation': (__spec__.parent, '.errors'), + 'PydanticInvalidForJsonSchema': (__spec__.parent, '.errors'), + 'PydanticForbiddenQualifier': (__spec__.parent, '.errors'), + # fields + 'Field': (__spec__.parent, '.fields'), + 'computed_field': (__spec__.parent, '.fields'), + 'PrivateAttr': (__spec__.parent, '.fields'), + # alias + 'AliasChoices': (__spec__.parent, '.aliases'), + 'AliasGenerator': (__spec__.parent, '.aliases'), + 'AliasPath': (__spec__.parent, '.aliases'), + # main + 'BaseModel': (__spec__.parent, '.main'), + 'create_model': (__spec__.parent, '.main'), + # network + 'AnyUrl': (__spec__.parent, '.networks'), + 'AnyHttpUrl': (__spec__.parent, '.networks'), + 'FileUrl': (__spec__.parent, '.networks'), + 'HttpUrl': (__spec__.parent, '.networks'), + 'FtpUrl': (__spec__.parent, '.networks'), + 'WebsocketUrl': (__spec__.parent, '.networks'), + 'AnyWebsocketUrl': (__spec__.parent, '.networks'), + 'UrlConstraints': (__spec__.parent, '.networks'), + 'EmailStr': (__spec__.parent, '.networks'), + 'NameEmail': (__spec__.parent, '.networks'), + 'IPvAnyAddress': (__spec__.parent, '.networks'), + 'IPvAnyInterface': (__spec__.parent, '.networks'), + 'IPvAnyNetwork': (__spec__.parent, '.networks'), + 'PostgresDsn': (__spec__.parent, '.networks'), + 'CockroachDsn': (__spec__.parent, '.networks'), + 'AmqpDsn': (__spec__.parent, '.networks'), + 'RedisDsn': (__spec__.parent, '.networks'), + 'MongoDsn': (__spec__.parent, '.networks'), + 'KafkaDsn': (__spec__.parent, '.networks'), + 'NatsDsn': (__spec__.parent, '.networks'), + 'MySQLDsn': (__spec__.parent, '.networks'), + 'MariaDBDsn': (__spec__.parent, '.networks'), + 'ClickHouseDsn': (__spec__.parent, '.networks'), + 'SnowflakeDsn': (__spec__.parent, '.networks'), + 'validate_email': (__spec__.parent, '.networks'), + # root_model + 'RootModel': (__spec__.parent, '.root_model'), + # types + 'Strict': (__spec__.parent, '.types'), + 'StrictStr': (__spec__.parent, '.types'), + 'conbytes': (__spec__.parent, '.types'), + 'conlist': (__spec__.parent, '.types'), + 'conset': (__spec__.parent, '.types'), + 'confrozenset': (__spec__.parent, '.types'), + 'constr': (__spec__.parent, '.types'), + 'StringConstraints': (__spec__.parent, '.types'), + 'ImportString': (__spec__.parent, '.types'), + 'conint': (__spec__.parent, '.types'), + 'PositiveInt': (__spec__.parent, '.types'), + 'NegativeInt': (__spec__.parent, '.types'), + 'NonNegativeInt': (__spec__.parent, '.types'), + 'NonPositiveInt': (__spec__.parent, '.types'), + 'confloat': (__spec__.parent, '.types'), + 'PositiveFloat': (__spec__.parent, '.types'), + 'NegativeFloat': (__spec__.parent, '.types'), + 'NonNegativeFloat': (__spec__.parent, '.types'), + 'NonPositiveFloat': (__spec__.parent, '.types'), + 'FiniteFloat': (__spec__.parent, '.types'), + 'condecimal': (__spec__.parent, '.types'), + 'condate': (__spec__.parent, '.types'), + 'UUID1': (__spec__.parent, '.types'), + 'UUID3': (__spec__.parent, '.types'), + 'UUID4': (__spec__.parent, '.types'), + 'UUID5': (__spec__.parent, '.types'), + 'UUID6': (__spec__.parent, '.types'), + 'UUID7': (__spec__.parent, '.types'), + 'UUID8': (__spec__.parent, '.types'), + 'FilePath': (__spec__.parent, '.types'), + 'DirectoryPath': (__spec__.parent, '.types'), + 'NewPath': (__spec__.parent, '.types'), + 'Json': (__spec__.parent, '.types'), + 'Secret': (__spec__.parent, '.types'), + 'SecretStr': (__spec__.parent, '.types'), + 'SecretBytes': (__spec__.parent, '.types'), + 'StrictBool': (__spec__.parent, '.types'), + 'StrictBytes': (__spec__.parent, '.types'), + 'StrictInt': (__spec__.parent, '.types'), + 'StrictFloat': (__spec__.parent, '.types'), + 'PaymentCardNumber': (__spec__.parent, '.types'), + 'ByteSize': (__spec__.parent, '.types'), + 'PastDate': (__spec__.parent, '.types'), + 'SocketPath': (__spec__.parent, '.types'), + 'FutureDate': (__spec__.parent, '.types'), + 'PastDatetime': (__spec__.parent, '.types'), + 'FutureDatetime': (__spec__.parent, '.types'), + 'AwareDatetime': (__spec__.parent, '.types'), + 'NaiveDatetime': (__spec__.parent, '.types'), + 'AllowInfNan': (__spec__.parent, '.types'), + 'EncoderProtocol': (__spec__.parent, '.types'), + 'EncodedBytes': (__spec__.parent, '.types'), + 'EncodedStr': (__spec__.parent, '.types'), + 'Base64Encoder': (__spec__.parent, '.types'), + 'Base64Bytes': (__spec__.parent, '.types'), + 'Base64Str': (__spec__.parent, '.types'), + 'Base64UrlBytes': (__spec__.parent, '.types'), + 'Base64UrlStr': (__spec__.parent, '.types'), + 'GetPydanticSchema': (__spec__.parent, '.types'), + 'Tag': (__spec__.parent, '.types'), + 'Discriminator': (__spec__.parent, '.types'), + 'JsonValue': (__spec__.parent, '.types'), + 'OnErrorOmit': (__spec__.parent, '.types'), + 'FailFast': (__spec__.parent, '.types'), + # type_adapter + 'TypeAdapter': (__spec__.parent, '.type_adapter'), + # warnings + 'PydanticDeprecatedSince20': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince26': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince29': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince210': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince211': (__spec__.parent, '.warnings'), + 'PydanticDeprecatedSince212': (__spec__.parent, '.warnings'), + 'PydanticDeprecationWarning': (__spec__.parent, '.warnings'), + 'PydanticExperimentalWarning': (__spec__.parent, '.warnings'), + # annotated handlers + 'GetCoreSchemaHandler': (__spec__.parent, '.annotated_handlers'), + 'GetJsonSchemaHandler': (__spec__.parent, '.annotated_handlers'), + # pydantic_core stuff + 'ValidationError': ('pydantic_core', '.'), + 'ValidationInfo': ('pydantic_core', '.core_schema'), + 'SerializationInfo': ('pydantic_core', '.core_schema'), + 'ValidatorFunctionWrapHandler': ('pydantic_core', '.core_schema'), + 'FieldSerializationInfo': ('pydantic_core', '.core_schema'), + 'SerializerFunctionWrapHandler': ('pydantic_core', '.core_schema'), + # deprecated, mostly not included in __all__ + 'root_validator': (__spec__.parent, '.deprecated.class_validators'), + 'validator': (__spec__.parent, '.deprecated.class_validators'), + 'BaseConfig': (__spec__.parent, '.deprecated.config'), + 'Extra': (__spec__.parent, '.deprecated.config'), + 'parse_obj_as': (__spec__.parent, '.deprecated.tools'), + 'schema_of': (__spec__.parent, '.deprecated.tools'), + 'schema_json_of': (__spec__.parent, '.deprecated.tools'), + # deprecated dynamic imports + 'FieldValidationInfo': ('pydantic_core', '.core_schema'), + 'GenerateSchema': (__spec__.parent, '._internal._generate_schema'), +} +_deprecated_dynamic_imports = {'FieldValidationInfo', 'GenerateSchema'} + +_getattr_migration = getattr_migration(__name__) + + +def __getattr__(attr_name: str) -> object: + if attr_name in _deprecated_dynamic_imports: + from pydantic.warnings import PydanticDeprecatedSince20 + + warn( + f'Importing {attr_name} from `pydantic` is deprecated. This feature is either no longer supported, or is not public.', + PydanticDeprecatedSince20, + stacklevel=2, + ) + + dynamic_attr = _dynamic_imports.get(attr_name) + if dynamic_attr is None: + return _getattr_migration(attr_name) + + package, module_name = dynamic_attr + + if module_name == '__module__': + result = import_module(f'.{attr_name}', package=package) + globals()[attr_name] = result + return result + else: + module = import_module(module_name, package=package) + result = getattr(module, attr_name) + g = globals() + for k, (_, v_module_name) in _dynamic_imports.items(): + if v_module_name == module_name and k not in _deprecated_dynamic_imports: + g[k] = getattr(module, k) + return result + + +def __dir__() -> list[str]: + return list(__all__) diff --git a/source/target-vendors/cp312/pydantic/_internal/__init__.py b/source/target-vendors/cp312/pydantic/_internal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/pydantic/_internal/_config.py b/source/target-vendors/cp312/pydantic/_internal/_config.py new file mode 100644 index 0000000..73b5870 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_config.py @@ -0,0 +1,386 @@ +from __future__ import annotations as _annotations + +import warnings +from contextlib import contextmanager +from re import Pattern +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Literal, + cast, +) + +from pydantic_core import core_schema +from typing_extensions import Self + +from ..aliases import AliasGenerator +from ..config import ConfigDict, ExtraValues, JsonDict, JsonEncoder, JsonSchemaExtraCallable +from ..errors import PydanticUserError +from ..warnings import PydanticDeprecatedSince20, PydanticDeprecatedSince210 + +if TYPE_CHECKING: + from .._internal._schema_generation_shared import GenerateSchema + from ..fields import ComputedFieldInfo, FieldInfo + +DEPRECATION_MESSAGE = 'Support for class-based `config` is deprecated, use ConfigDict instead.' + + +class ConfigWrapper: + """Internal wrapper for Config which exposes ConfigDict items as attributes.""" + + __slots__ = ('config_dict',) + + config_dict: ConfigDict + + # all annotations are copied directly from ConfigDict, and should be kept up to date, a test will fail if they + # stop matching + title: str | None + str_to_lower: bool + str_to_upper: bool + str_strip_whitespace: bool + str_min_length: int + str_max_length: int | None + extra: ExtraValues | None + frozen: bool + populate_by_name: bool + use_enum_values: bool + validate_assignment: bool + arbitrary_types_allowed: bool + from_attributes: bool + # whether to use the actual key provided in the data (e.g. alias or first alias for "field required" errors) instead of field_names + # to construct error `loc`s, default `True` + loc_by_alias: bool + alias_generator: Callable[[str], str] | AliasGenerator | None + model_title_generator: Callable[[type], str] | None + field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None + ignored_types: tuple[type, ...] + allow_inf_nan: bool + json_schema_extra: JsonDict | JsonSchemaExtraCallable | None + json_encoders: dict[type[object], JsonEncoder] | None + + # new in V2 + strict: bool + # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' + revalidate_instances: Literal['always', 'never', 'subclass-instances'] + ser_json_timedelta: Literal['iso8601', 'float'] + ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds'] + val_temporal_unit: Literal['seconds', 'milliseconds', 'infer'] + ser_json_bytes: Literal['utf8', 'base64', 'hex'] + val_json_bytes: Literal['utf8', 'base64', 'hex'] + ser_json_inf_nan: Literal['null', 'constants', 'strings'] + # whether to validate default values during validation, default False + validate_default: bool + validate_return: bool + protected_namespaces: tuple[str | Pattern[str], ...] + hide_input_in_errors: bool + defer_build: bool + plugin_settings: dict[str, object] | None + schema_generator: type[GenerateSchema] | None + json_schema_serialization_defaults_required: bool + json_schema_mode_override: Literal['validation', 'serialization', None] + coerce_numbers_to_str: bool + regex_engine: Literal['rust-regex', 'python-re'] + validation_error_cause: bool + use_attribute_docstrings: bool + cache_strings: bool | Literal['all', 'keys', 'none'] + validate_by_alias: bool + validate_by_name: bool + serialize_by_alias: bool + url_preserve_empty_path: bool + polymorphic_serialization: bool + + def __init__(self, config: ConfigDict | dict[str, Any] | type[Any] | None, *, check: bool = True): + if check: + self.config_dict = prepare_config(config) + else: + self.config_dict = cast(ConfigDict, config) + + @classmethod + def for_model( + cls, + bases: tuple[type[Any], ...], + namespace: dict[str, Any], + raw_annotations: dict[str, Any], + kwargs: dict[str, Any], + ) -> Self: + """Build a new `ConfigWrapper` instance for a `BaseModel`. + + The config wrapper built based on (in descending order of priority): + - options from `kwargs` + - options from the `namespace` + - options from the base classes (`bases`) + + Args: + bases: A tuple of base classes. + namespace: The namespace of the class being created. + raw_annotations: The (non-evaluated) annotations of the model. + kwargs: The kwargs passed to the class being created. + + Returns: + A `ConfigWrapper` instance for `BaseModel`. + """ + config_new = ConfigDict() + for base in bases: + config = getattr(base, 'model_config', None) + if config: + config_new.update(config.copy()) + + config_class_from_namespace = namespace.get('Config') + config_dict_from_namespace = namespace.get('model_config') + + if raw_annotations.get('model_config') and config_dict_from_namespace is None: + raise PydanticUserError( + '`model_config` cannot be used as a model field name. Use `model_config` for model configuration.', + code='model-config-invalid-field-name', + ) + + if config_class_from_namespace and config_dict_from_namespace: + raise PydanticUserError('"Config" and "model_config" cannot be used together', code='config-both') + + config_from_namespace = config_dict_from_namespace or prepare_config(config_class_from_namespace) + + config_new.update(config_from_namespace) + + for k in list(kwargs.keys()): + if k in config_keys: + config_new[k] = kwargs.pop(k) + + return cls(config_new) + + # we don't show `__getattr__` to type checkers so missing attributes cause errors + if not TYPE_CHECKING: # pragma: no branch + + def __getattr__(self, name: str) -> Any: + try: + return self.config_dict[name] + except KeyError: + try: + return config_defaults[name] + except KeyError: + raise AttributeError(f'Config has no attribute {name!r}') from None + + def core_config(self, title: str | None) -> core_schema.CoreConfig: + """Create a pydantic-core config. + + We don't use getattr here since we don't want to populate with defaults. + + Args: + title: The title to use if not set in config. + + Returns: + A `CoreConfig` object created from config. + """ + config = self.config_dict + + if config.get('schema_generator') is not None: + warnings.warn( + 'The `schema_generator` setting has been deprecated since v2.10. This setting no longer has any effect.', + PydanticDeprecatedSince210, + stacklevel=2, + ) + + if (populate_by_name := config.get('populate_by_name')) is not None: + # We include this patch for backwards compatibility purposes, but this config setting will be deprecated in v3.0, and likely removed in v4.0. + # Thus, the above warning and this patch can be removed then as well. + if config.get('validate_by_name') is None: + config['validate_by_alias'] = True + config['validate_by_name'] = populate_by_name + + # We dynamically patch validate_by_name to be True if validate_by_alias is set to False + # and validate_by_name is not explicitly set. + if config.get('validate_by_alias') is False and config.get('validate_by_name') is None: + config['validate_by_name'] = True + + if (not config.get('validate_by_alias', True)) and (not config.get('validate_by_name', False)): + raise PydanticUserError( + 'At least one of `validate_by_alias` or `validate_by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return core_schema.CoreConfig( + **{ # pyright: ignore[reportArgumentType] + k: v + for k, v in ( + ('title', config.get('title') or title or None), + ('extra_fields_behavior', config.get('extra')), + ('allow_inf_nan', config.get('allow_inf_nan')), + ('str_strip_whitespace', config.get('str_strip_whitespace')), + ('str_to_lower', config.get('str_to_lower')), + ('str_to_upper', config.get('str_to_upper')), + ('strict', config.get('strict')), + ('ser_json_timedelta', config.get('ser_json_timedelta')), + ('ser_json_temporal', config.get('ser_json_temporal')), + ('val_temporal_unit', config.get('val_temporal_unit')), + ('ser_json_bytes', config.get('ser_json_bytes')), + ('val_json_bytes', config.get('val_json_bytes')), + ('ser_json_inf_nan', config.get('ser_json_inf_nan')), + ('from_attributes', config.get('from_attributes')), + ('loc_by_alias', config.get('loc_by_alias')), + ('revalidate_instances', config.get('revalidate_instances')), + ('validate_default', config.get('validate_default')), + ('str_max_length', config.get('str_max_length')), + ('str_min_length', config.get('str_min_length')), + ('hide_input_in_errors', config.get('hide_input_in_errors')), + ('coerce_numbers_to_str', config.get('coerce_numbers_to_str')), + ('regex_engine', config.get('regex_engine')), + ('validation_error_cause', config.get('validation_error_cause')), + ('cache_strings', config.get('cache_strings')), + ('validate_by_alias', config.get('validate_by_alias')), + ('validate_by_name', config.get('validate_by_name')), + ('serialize_by_alias', config.get('serialize_by_alias')), + ('url_preserve_empty_path', config.get('url_preserve_empty_path')), + ('polymorphic_serialization', config.get('polymorphic_serialization')), + ) + if v is not None + } + ) + + def __repr__(self): + c = ', '.join(f'{k}={v!r}' for k, v in self.config_dict.items()) + return f'ConfigWrapper({c})' + + +class ConfigWrapperStack: + """A stack of `ConfigWrapper` instances.""" + + def __init__(self, config_wrapper: ConfigWrapper): + self._config_wrapper_stack: list[ConfigWrapper] = [config_wrapper] + + @property + def tail(self) -> ConfigWrapper: + return self._config_wrapper_stack[-1] + + @contextmanager + def push(self, config_wrapper: ConfigWrapper | ConfigDict | None): + if config_wrapper is None: + yield + return + + if not isinstance(config_wrapper, ConfigWrapper): + config_wrapper = ConfigWrapper(config_wrapper, check=False) + + self._config_wrapper_stack.append(config_wrapper) + try: + yield + finally: + self._config_wrapper_stack.pop() + + +config_defaults = ConfigDict( + title=None, + str_to_lower=False, + str_to_upper=False, + str_strip_whitespace=False, + str_min_length=0, + str_max_length=None, + # let the model / dataclass decide how to handle it + extra=None, + frozen=False, + populate_by_name=False, + use_enum_values=False, + validate_assignment=False, + arbitrary_types_allowed=False, + from_attributes=False, + loc_by_alias=True, + alias_generator=None, + model_title_generator=None, + field_title_generator=None, + ignored_types=(), + allow_inf_nan=True, + json_schema_extra=None, + strict=False, + revalidate_instances='never', + ser_json_timedelta='iso8601', + ser_json_temporal='iso8601', + val_temporal_unit='infer', + ser_json_bytes='utf8', + val_json_bytes='utf8', + ser_json_inf_nan='null', + validate_default=False, + validate_return=False, + protected_namespaces=('model_validate', 'model_dump'), + hide_input_in_errors=False, + json_encoders=None, + defer_build=False, + schema_generator=None, + plugin_settings=None, + json_schema_serialization_defaults_required=False, + json_schema_mode_override=None, + coerce_numbers_to_str=False, + regex_engine='rust-regex', + validation_error_cause=False, + use_attribute_docstrings=False, + cache_strings=True, + validate_by_alias=True, + validate_by_name=False, + serialize_by_alias=False, + url_preserve_empty_path=False, + polymorphic_serialization=False, +) + + +def prepare_config(config: ConfigDict | dict[str, Any] | type[Any] | None) -> ConfigDict: + """Create a `ConfigDict` instance from an existing dict, a class (e.g. old class-based config) or None. + + Args: + config: The input config. + + Returns: + A ConfigDict object created from config. + """ + if config is None: + return ConfigDict() + + if not isinstance(config, dict): + warnings.warn(DEPRECATION_MESSAGE, PydanticDeprecatedSince20, stacklevel=4) + config = {k: getattr(config, k) for k in dir(config) if not k.startswith('__')} + + config_dict = cast(ConfigDict, config) + check_deprecated(config_dict) + return config_dict + + +config_keys = set(ConfigDict.__annotations__.keys()) + + +V2_REMOVED_KEYS = { + 'allow_mutation', + 'error_msg_templates', + 'fields', + 'getter_dict', + 'smart_union', + 'underscore_attrs_are_private', + 'json_loads', + 'json_dumps', + 'copy_on_model_validation', + 'post_init_call', +} +V2_RENAMED_KEYS = { + 'allow_population_by_field_name': 'validate_by_name', + 'anystr_lower': 'str_to_lower', + 'anystr_strip_whitespace': 'str_strip_whitespace', + 'anystr_upper': 'str_to_upper', + 'keep_untouched': 'ignored_types', + 'max_anystr_length': 'str_max_length', + 'min_anystr_length': 'str_min_length', + 'orm_mode': 'from_attributes', + 'schema_extra': 'json_schema_extra', + 'validate_all': 'validate_default', +} + + +def check_deprecated(config_dict: ConfigDict) -> None: + """Check for deprecated config keys and warn the user. + + Args: + config_dict: The input config. + """ + deprecated_removed_keys = V2_REMOVED_KEYS & config_dict.keys() + deprecated_renamed_keys = V2_RENAMED_KEYS.keys() & config_dict.keys() + if deprecated_removed_keys or deprecated_renamed_keys: + renamings = {k: V2_RENAMED_KEYS[k] for k in sorted(deprecated_renamed_keys)} + renamed_bullets = [f'* {k!r} has been renamed to {v!r}' for k, v in renamings.items()] + removed_bullets = [f'* {k!r} has been removed' for k in sorted(deprecated_removed_keys)] + message = '\n'.join(['Valid config keys have changed in V2:'] + renamed_bullets + removed_bullets) + warnings.warn(message, UserWarning) diff --git a/source/target-vendors/cp312/pydantic/_internal/_core_metadata.py b/source/target-vendors/cp312/pydantic/_internal/_core_metadata.py new file mode 100644 index 0000000..9f2510c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_core_metadata.py @@ -0,0 +1,97 @@ +from __future__ import annotations as _annotations + +from typing import TYPE_CHECKING, Any, TypedDict, cast +from warnings import warn + +if TYPE_CHECKING: + from ..config import JsonDict, JsonSchemaExtraCallable + from ._schema_generation_shared import ( + GetJsonSchemaFunction, + ) + + +class CoreMetadata(TypedDict, total=False): + """A `TypedDict` for holding the metadata dict of the schema. + + Attributes: + pydantic_js_functions: List of JSON schema functions that resolve refs during application. + pydantic_js_annotation_functions: List of JSON schema functions that don't resolve refs during application. + pydantic_js_prefer_positional_arguments: Whether JSON schema generator will + prefer positional over keyword arguments for an 'arguments' schema. + custom validation function. Only applies to before, plain, and wrap validators. + pydantic_js_updates: key / value pair updates to apply to the JSON schema for a type. + pydantic_js_extra: WIP, either key/value pair updates to apply to the JSON schema, or a custom callable. + pydantic_internal_union_tag_key: Used internally by the `Tag` metadata to specify the tag used for a discriminated union. + pydantic_internal_union_discriminator: Used internally to specify the discriminator value for a discriminated union + when the discriminator was applied to a `'definition-ref'` schema, and that reference was missing at the time + of the annotation application. + + TODO: Perhaps we should move this structure to pydantic-core. At the moment, though, + it's easier to iterate on if we leave it in pydantic until we feel there is a semi-stable API. + + TODO: It's unfortunate how functionally oriented JSON schema generation is, especially that which occurs during + the core schema generation process. It's inevitable that we need to store some json schema related information + on core schemas, given that we generate JSON schemas directly from core schemas. That being said, debugging related + issues is quite difficult when JSON schema information is disguised via dynamically defined functions. + """ + + pydantic_js_functions: list[GetJsonSchemaFunction] + pydantic_js_annotation_functions: list[GetJsonSchemaFunction] + pydantic_js_prefer_positional_arguments: bool + pydantic_js_updates: JsonDict + pydantic_js_extra: JsonDict | JsonSchemaExtraCallable + pydantic_internal_union_tag_key: str + pydantic_internal_union_discriminator: str + + +def update_core_metadata( + core_metadata: Any, + /, + *, + pydantic_js_functions: list[GetJsonSchemaFunction] | None = None, + pydantic_js_annotation_functions: list[GetJsonSchemaFunction] | None = None, + pydantic_js_updates: JsonDict | None = None, + pydantic_js_extra: JsonDict | JsonSchemaExtraCallable | None = None, +) -> None: + from ..json_schema import PydanticJsonSchemaWarning + + """Update CoreMetadata instance in place. When we make modifications in this function, they + take effect on the `core_metadata` reference passed in as the first (and only) positional argument. + + First, cast to `CoreMetadata`, then finish with a cast to `dict[str, Any]` for core schema compatibility. + We do this here, instead of before / after each call to this function so that this typing hack + can be easily removed if/when we move `CoreMetadata` to `pydantic-core`. + + For parameter descriptions, see `CoreMetadata` above. + """ + core_metadata = cast(CoreMetadata, core_metadata) + + if pydantic_js_functions: + core_metadata.setdefault('pydantic_js_functions', []).extend(pydantic_js_functions) + + if pydantic_js_annotation_functions: + core_metadata.setdefault('pydantic_js_annotation_functions', []).extend(pydantic_js_annotation_functions) + + if pydantic_js_updates: + if (existing_updates := core_metadata.get('pydantic_js_updates')) is not None: + core_metadata['pydantic_js_updates'] = {**existing_updates, **pydantic_js_updates} + else: + core_metadata['pydantic_js_updates'] = pydantic_js_updates + + if pydantic_js_extra is not None: + existing_pydantic_js_extra = core_metadata.get('pydantic_js_extra') + if existing_pydantic_js_extra is None: + core_metadata['pydantic_js_extra'] = pydantic_js_extra + if isinstance(existing_pydantic_js_extra, dict): + if isinstance(pydantic_js_extra, dict): + core_metadata['pydantic_js_extra'] = {**existing_pydantic_js_extra, **pydantic_js_extra} + if callable(pydantic_js_extra): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported.' + 'The `callable` type is being ignored.' + "If you'd like support for this behavior, please open an issue on pydantic.", + PydanticJsonSchemaWarning, + ) + if callable(existing_pydantic_js_extra): + # if ever there's a case of a callable, we'll just keep the last json schema extra spec + core_metadata['pydantic_js_extra'] = pydantic_js_extra diff --git a/source/target-vendors/cp312/pydantic/_internal/_core_utils.py b/source/target-vendors/cp312/pydantic/_internal/_core_utils.py new file mode 100644 index 0000000..caa51e8 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_core_utils.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +import inspect +from collections.abc import Mapping, Sequence +from typing import TYPE_CHECKING, Any, Union + +from pydantic_core import CoreSchema, core_schema +from typing_extensions import TypeGuard, get_args, get_origin +from typing_inspection import typing_objects + +from . import _repr +from ._typing_extra import is_generic_alias + +if TYPE_CHECKING: + from rich.console import Console + +AnyFunctionSchema = Union[ + core_schema.AfterValidatorFunctionSchema, + core_schema.BeforeValidatorFunctionSchema, + core_schema.WrapValidatorFunctionSchema, + core_schema.PlainValidatorFunctionSchema, +] + + +FunctionSchemaWithInnerSchema = Union[ + core_schema.AfterValidatorFunctionSchema, + core_schema.BeforeValidatorFunctionSchema, + core_schema.WrapValidatorFunctionSchema, +] + +CoreSchemaField = Union[ + core_schema.ModelField, core_schema.DataclassField, core_schema.TypedDictField, core_schema.ComputedField +] +CoreSchemaOrField = Union[core_schema.CoreSchema, CoreSchemaField] + +_CORE_SCHEMA_FIELD_TYPES = {'typed-dict-field', 'dataclass-field', 'model-field', 'computed-field'} +_FUNCTION_WITH_INNER_SCHEMA_TYPES = {'function-before', 'function-after', 'function-wrap'} +_LIST_LIKE_SCHEMA_WITH_ITEMS_TYPES = {'list', 'set', 'frozenset'} + + +def is_core_schema( + schema: CoreSchemaOrField, +) -> TypeGuard[CoreSchema]: + return schema['type'] not in _CORE_SCHEMA_FIELD_TYPES + + +def is_core_schema_field( + schema: CoreSchemaOrField, +) -> TypeGuard[CoreSchemaField]: + return schema['type'] in _CORE_SCHEMA_FIELD_TYPES + + +def is_function_with_inner_schema( + schema: CoreSchemaOrField, +) -> TypeGuard[FunctionSchemaWithInnerSchema]: + return schema['type'] in _FUNCTION_WITH_INNER_SCHEMA_TYPES + + +def is_list_like_schema_with_items_schema( + schema: CoreSchema, +) -> TypeGuard[core_schema.ListSchema | core_schema.SetSchema | core_schema.FrozenSetSchema]: + return schema['type'] in _LIST_LIKE_SCHEMA_WITH_ITEMS_TYPES + + +def get_type_ref(type_: Any, args_override: tuple[type[Any], ...] | None = None) -> str: + """Produces the ref to be used for this type by pydantic_core's core schemas. + + This `args_override` argument was added for the purpose of creating valid recursive references + when creating generic models without needing to create a concrete class. + """ + origin = get_origin(type_) or type_ + + args = get_args(type_) if is_generic_alias(type_) else (args_override or ()) + generic_metadata = getattr(type_, '__pydantic_generic_metadata__', None) + if generic_metadata: + origin = generic_metadata['origin'] or origin + args = generic_metadata['args'] or args + + module_name = getattr(origin, '__module__', '') + if typing_objects.is_typealiastype(origin): + type_ref = f'{module_name}.{origin.__name__}:{id(origin)}' + else: + try: + qualname = getattr(origin, '__qualname__', f'') + except Exception: + qualname = getattr(origin, '__qualname__', '') + type_ref = f'{module_name}.{qualname}:{id(origin)}' + + arg_refs: list[str] = [] + for arg in args: + if isinstance(arg, str): + # Handle string literals as a special case; we may be able to remove this special handling if we + # wrap them in a ForwardRef at some point. + arg_ref = f'{arg}:str-{id(arg)}' + else: + arg_ref = f'{_repr.display_as_type(arg)}:{id(arg)}' + arg_refs.append(arg_ref) + if arg_refs: + type_ref = f'{type_ref}[{",".join(arg_refs)}]' + return type_ref + + +def get_ref(s: core_schema.CoreSchema) -> None | str: + """Get the ref from the schema if it has one. + This exists just for type checking to work correctly. + """ + return s.get('ref', None) + + +def _clean_schema_for_pretty_print(obj: Any, strip_metadata: bool = True) -> Any: # pragma: no cover + """A utility function to remove irrelevant information from a core schema.""" + if isinstance(obj, Mapping): + new_dct = {} + for k, v in obj.items(): + if k == 'metadata' and strip_metadata: + new_metadata = {} + + for meta_k, meta_v in v.items(): + if meta_k in ('pydantic_js_functions', 'pydantic_js_annotation_functions'): + new_metadata['js_metadata'] = '' + else: + new_metadata[meta_k] = _clean_schema_for_pretty_print(meta_v, strip_metadata=strip_metadata) + + if list(new_metadata.keys()) == ['js_metadata']: + new_metadata = {''} + + new_dct[k] = new_metadata + # Remove some defaults: + elif k in ('custom_init', 'root_model') and not v: + continue + else: + new_dct[k] = _clean_schema_for_pretty_print(v, strip_metadata=strip_metadata) + + return new_dct + elif isinstance(obj, Sequence) and not isinstance(obj, str): + return [_clean_schema_for_pretty_print(v, strip_metadata=strip_metadata) for v in obj] + else: + return obj + + +def pretty_print_core_schema( + val: Any, + *, + console: Console | None = None, + max_depth: int | None = None, + strip_metadata: bool = True, +) -> None: # pragma: no cover + """Pretty-print a core schema using the `rich` library. + + Args: + val: The core schema to print, or a Pydantic model/dataclass/type adapter + (in which case the cached core schema is fetched and printed). + console: A rich console to use when printing. Defaults to the global rich console instance. + max_depth: The number of nesting levels which may be printed. + strip_metadata: Whether to strip metadata in the output. If `True` any known core metadata + attributes will be stripped (but custom attributes are kept). Defaults to `True`. + """ + # lazy import: + from rich.pretty import pprint + + # circ. imports: + from pydantic import BaseModel, TypeAdapter + from pydantic.dataclasses import is_pydantic_dataclass + + if (inspect.isclass(val) and issubclass(val, BaseModel)) or is_pydantic_dataclass(val): + val = val.__pydantic_core_schema__ + if isinstance(val, TypeAdapter): + val = val.core_schema + cleaned_schema = _clean_schema_for_pretty_print(val, strip_metadata=strip_metadata) + + pprint(cleaned_schema, console=console, max_depth=max_depth) + + +pps = pretty_print_core_schema diff --git a/source/target-vendors/cp312/pydantic/_internal/_dataclasses.py b/source/target-vendors/cp312/pydantic/_internal/_dataclasses.py new file mode 100644 index 0000000..f00c8b7 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_dataclasses.py @@ -0,0 +1,315 @@ +"""Private logic for creating pydantic dataclasses.""" + +from __future__ import annotations as _annotations + +import copy +import dataclasses +import sys +import warnings +from collections.abc import Generator +from contextlib import contextmanager +from functools import partial +from typing import TYPE_CHECKING, Any, ClassVar, Protocol, cast + +from pydantic_core import ( + ArgsKwargs, + SchemaSerializer, + SchemaValidator, + core_schema, +) +from typing_extensions import TypeAlias, TypeIs + +from ..errors import PydanticUndefinedAnnotation +from ..fields import FieldInfo +from ..plugin._schema_validator import PluggableSchemaValidator, create_schema_validator +from ..warnings import PydanticDeprecatedSince20 +from . import _config, _decorators +from ._fields import collect_dataclass_fields +from ._generate_schema import GenerateSchema, InvalidSchemaError +from ._generics import get_standard_typevars_map +from ._mock_val_ser import set_dataclass_mocks +from ._namespace_utils import NsResolver +from ._signature import generate_pydantic_signature +from ._utils import LazyClassAttribute + +if TYPE_CHECKING: + from _typeshed import DataclassInstance as StandardDataclass + + from ..config import ConfigDict + + class PydanticDataclass(StandardDataclass, Protocol): + """A protocol containing attributes only available once a class has been decorated as a Pydantic dataclass. + + Attributes: + __pydantic_config__: Pydantic-specific configuration settings for the dataclass. + __pydantic_complete__: Whether dataclass building is completed, or if there are still undefined fields. + __pydantic_core_schema__: The pydantic-core schema used to build the SchemaValidator and SchemaSerializer. + __pydantic_decorators__: Metadata containing the decorators defined on the dataclass. + __pydantic_fields__: Metadata about the fields defined on the dataclass. + __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the dataclass. + __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the dataclass. + """ + + __pydantic_config__: ClassVar[ConfigDict] + __pydantic_complete__: ClassVar[bool] + __pydantic_core_schema__: ClassVar[core_schema.CoreSchema] + __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos] + __pydantic_fields__: ClassVar[dict[str, FieldInfo]] + __pydantic_serializer__: ClassVar[SchemaSerializer] + __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] + + @classmethod + def __pydantic_fields_complete__(cls) -> bool: ... + + +def set_dataclass_fields( + cls: type[StandardDataclass], + config_wrapper: _config.ConfigWrapper, + ns_resolver: NsResolver | None = None, +) -> None: + """Collect and set `cls.__pydantic_fields__`. + + Args: + cls: The class. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting dataclass annotations. + """ + typevars_map = get_standard_typevars_map(cls) + fields = collect_dataclass_fields( + cls, ns_resolver=ns_resolver, typevars_map=typevars_map, config_wrapper=config_wrapper + ) + + cls.__pydantic_fields__ = fields # type: ignore + + +def complete_dataclass( + cls: type[Any], + config_wrapper: _config.ConfigWrapper, + *, + raise_errors: bool = True, + ns_resolver: NsResolver | None = None, + _force_build: bool = False, +) -> bool: + """Finish building a pydantic dataclass. + + This logic is called on a class which has already been wrapped in `dataclasses.dataclass()`. + + This is somewhat analogous to `pydantic._internal._model_construction.complete_model_class`. + + Args: + cls: The class. + config_wrapper: The config wrapper instance. + raise_errors: Whether to raise errors, defaults to `True`. + ns_resolver: The namespace resolver instance to use when collecting dataclass fields + and during schema building. + _force_build: Whether to force building the dataclass, no matter if + [`defer_build`][pydantic.config.ConfigDict.defer_build] is set. + + Returns: + `True` if building a pydantic dataclass is successfully completed, `False` otherwise. + + Raises: + PydanticUndefinedAnnotation: If `raise_error` is `True` and there is an undefined annotations. + """ + original_init = cls.__init__ + + # dataclass.__init__ must be defined here so its `__qualname__` can be changed since functions can't be copied, + # and so that the mock validator is used if building was deferred: + def __init__(__dataclass_self__: PydanticDataclass, *args: Any, **kwargs: Any) -> None: + __tracebackhide__ = True + s = __dataclass_self__ + s.__pydantic_validator__.validate_python(ArgsKwargs(args, kwargs), self_instance=s) + + __init__.__qualname__ = f'{cls.__qualname__}.__init__' + + cls.__init__ = __init__ # type: ignore + cls.__pydantic_config__ = config_wrapper.config_dict # type: ignore + + set_dataclass_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) + + if not _force_build and config_wrapper.defer_build: + set_dataclass_mocks(cls) + return False + + if hasattr(cls, '__post_init_post_parse__'): + warnings.warn( + 'Support for `__post_init_post_parse__` has been dropped, the method will not be called', + PydanticDeprecatedSince20, + ) + + typevars_map = get_standard_typevars_map(cls) + gen_schema = GenerateSchema( + config_wrapper, + ns_resolver=ns_resolver, + typevars_map=typevars_map, + ) + + # set __signature__ attr only for the class, but not for its instances + # (because instances can define `__call__`, and `inspect.signature` shouldn't + # use the `__signature__` attribute and instead generate from `__call__`). + cls.__signature__ = LazyClassAttribute( + '__signature__', + partial( + generate_pydantic_signature, + # It's important that we reference the `original_init` here, + # as it is the one synthesized by the stdlib `dataclass` module: + init=original_init, + fields=cls.__pydantic_fields__, # type: ignore + validate_by_name=config_wrapper.validate_by_name, + extra=config_wrapper.extra, + is_dataclass=True, + ), + ) + + try: + schema = gen_schema.generate_schema(cls) + except PydanticUndefinedAnnotation as e: + if raise_errors: + raise + set_dataclass_mocks(cls, f'`{e.name}`') + return False + + core_config = config_wrapper.core_config(title=cls.__name__) + + try: + schema = gen_schema.clean_schema(schema) + except InvalidSchemaError: + set_dataclass_mocks(cls) + return False + + # We are about to set all the remaining required properties expected for this cast; + # __pydantic_decorators__ and __pydantic_fields__ should already be set + cls = cast('type[PydanticDataclass]', cls) + + cls.__pydantic_core_schema__ = schema + cls.__pydantic_validator__ = create_schema_validator( + schema, cls, cls.__module__, cls.__qualname__, 'dataclass', core_config, config_wrapper.plugin_settings + ) + cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config) + cls.__pydantic_complete__ = True + return True + + +def is_stdlib_dataclass(cls: type[Any], /) -> TypeIs[type[StandardDataclass]]: + """Returns `True` if the class is a stdlib dataclass and *not* a Pydantic dataclass. + + Unlike the stdlib `dataclasses.is_dataclass()` function, this does *not* include subclasses + of a dataclass that are themselves not dataclasses. + + Args: + cls: The class. + + Returns: + `True` if the class is a stdlib dataclass, `False` otherwise. + """ + return '__dataclass_fields__' in cls.__dict__ and not hasattr(cls, '__pydantic_validator__') + + +def as_dataclass_field(pydantic_field: FieldInfo) -> dataclasses.Field[Any]: + field_args: dict[str, Any] = {'default': pydantic_field} + + # Needed because if `doc` is set, the dataclass slots will be a dict (field name -> doc) instead of a tuple: + if sys.version_info >= (3, 14) and pydantic_field.description is not None: + field_args['doc'] = pydantic_field.description + + # Needed as the stdlib dataclass module processes kw_only in a specific way during class construction: + if sys.version_info >= (3, 10) and pydantic_field.kw_only is not None: + field_args['kw_only'] = pydantic_field.kw_only + + # Needed as the stdlib dataclass modules generates `__repr__()` during class construction: + if pydantic_field.repr is not True: + field_args['repr'] = pydantic_field.repr + + return dataclasses.field(**field_args) + + +DcFields: TypeAlias = dict[str, dataclasses.Field[Any]] + + +@contextmanager +def patch_base_fields(cls: type[Any]) -> Generator[None]: + """Temporarily patch the stdlib dataclasses bases of `cls` if the Pydantic `Field()` function is used. + + When creating a Pydantic dataclass, it is possible to inherit from stdlib dataclasses, where + the Pydantic `Field()` function is used. To create this Pydantic dataclass, we first apply + the stdlib `@dataclass` decorator on it. During the construction of the stdlib dataclass, + the `kw_only` and `repr` field arguments need to be understood by the stdlib *during* the + dataclass construction. To do so, we temporarily patch the fields dictionary of the affected + bases. + + For instance, with the following example: + + ```python {test="skip" lint="skip"} + import dataclasses as stdlib_dc + + import pydantic + import pydantic.dataclasses as pydantic_dc + + @stdlib_dc.dataclass + class A: + a: int = pydantic.Field(repr=False) + + # Notice that the `repr` attribute of the dataclass field is `True`: + A.__dataclass_fields__['a'] + #> dataclass.Field(default=FieldInfo(repr=False), repr=True, ...) + + @pydantic_dc.dataclass + class B(A): + b: int = pydantic.Field(repr=False) + ``` + + When passing `B` to the stdlib `@dataclass` decorator, it will look for fields in the parent classes + and reuse them directly. When this context manager is active, `A` will be temporarily patched to be + equivalent to: + + ```python {test="skip" lint="skip"} + @stdlib_dc.dataclass + class A: + a: int = stdlib_dc.field(default=Field(repr=False), repr=False) + ``` + + !!! note + This is only applied to the bases of `cls`, and not `cls` itself. The reason is that the Pydantic + dataclass decorator "owns" `cls` (in the previous example, `B`). As such, we instead modify the fields + directly (in the previous example, we simply do `setattr(B, 'b', as_dataclass_field(pydantic_field))`). + + !!! note + This approach is far from ideal, and can probably be the source of unwanted side effects/race conditions. + The previous implemented approach was mutating the `__annotations__` dict of `cls`, which is no longer a + safe operation in Python 3.14+, and resulted in unexpected behavior with field ordering anyway. + """ + # A list of two-tuples, the first element being a reference to the + # dataclass fields dictionary, the second element being a mapping between + # the field names that were modified, and their original `Field`: + original_fields_list: list[tuple[DcFields, DcFields]] = [] + + for base in cls.__mro__[1:]: + dc_fields: dict[str, dataclasses.Field[Any]] = base.__dict__.get('__dataclass_fields__', {}) + dc_fields_with_pydantic_field_defaults = { + field_name: field + for field_name, field in dc_fields.items() + if isinstance(field.default, FieldInfo) + # Only do the patching if one of the affected attributes is set: + and (field.default.description is not None or field.default.kw_only or field.default.repr is not True) + } + if dc_fields_with_pydantic_field_defaults: + original_fields_list.append((dc_fields, dc_fields_with_pydantic_field_defaults)) + for field_name, field in dc_fields_with_pydantic_field_defaults.items(): + default = cast(FieldInfo, field.default) + # `dataclasses.Field` isn't documented as working with `copy.copy()`. + # It is a class with `__slots__`, so should work (and we hope for the best): + new_dc_field = copy.copy(field) + # For base fields, no need to set `doc` from `FieldInfo.description`, this is only relevant + # for the class under construction and handled in `as_dataclass_field()`. + if sys.version_info >= (3, 10) and default.kw_only: + new_dc_field.kw_only = True + if default.repr is not True: + new_dc_field.repr = default.repr + dc_fields[field_name] = new_dc_field + + try: + yield + finally: + for fields, original_fields in original_fields_list: + for field_name, original_field in original_fields.items(): + fields[field_name] = original_field diff --git a/source/target-vendors/cp312/pydantic/_internal/_decorators.py b/source/target-vendors/cp312/pydantic/_internal/_decorators.py new file mode 100644 index 0000000..e24ad2c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_decorators.py @@ -0,0 +1,873 @@ +"""Logic related to validators applied to models etc. via the `@field_validator` and `@model_validator` decorators.""" + +from __future__ import annotations as _annotations + +import types +from collections import deque +from collections.abc import Iterable +from copy import copy +from dataclasses import dataclass, field +from functools import cached_property, partial, partialmethod +from inspect import Parameter, Signature, isdatadescriptor, ismethoddescriptor +from itertools import islice +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Generic, Literal, TypeVar, Union + +from pydantic_core import PydanticUndefined, PydanticUndefinedType, core_schema +from typing_extensions import Self, TypeAlias, is_typeddict + +from ..errors import PydanticUserError +from ._core_utils import get_type_ref +from ._internal_dataclass import slots_true +from ._namespace_utils import GlobalsNamespace, MappingNamespace +from ._typing_extra import get_function_type_hints, signature_no_eval +from ._utils import can_be_positional + +if TYPE_CHECKING: + from ..fields import ComputedFieldInfo + from ..functional_validators import FieldValidatorModes + from ._config import ConfigWrapper + + +@dataclass(**slots_true) +class ValidatorDecoratorInfo: + """A container for data from `@validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@validator'. + fields: A tuple of field names the validator should be called on. + mode: The proposed validator mode. + each_item: For complex objects (sets, lists etc.) whether to validate individual + elements rather than the whole object. + always: Whether this method and other validators should be called even if the value is missing. + check_fields: Whether to check that the fields actually exist on the model. + """ + + decorator_repr: ClassVar[str] = '@validator' + + fields: tuple[str, ...] + mode: Literal['before', 'after'] + each_item: bool + always: bool + check_fields: bool | None + + +@dataclass(**slots_true) +class FieldValidatorDecoratorInfo: + """A container for data from `@field_validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@field_validator'. + fields: A tuple of field names the validator should be called on. + mode: The proposed validator mode. + check_fields: Whether to check that the fields actually exist on the model. + json_schema_input_type: The input type of the function. This is only used to generate + the appropriate JSON Schema (in validation mode) and can only specified + when `mode` is either `'before'`, `'plain'` or `'wrap'`. + """ + + decorator_repr: ClassVar[str] = '@field_validator' + + fields: tuple[str, ...] + mode: FieldValidatorModes + check_fields: bool | None + json_schema_input_type: Any + + +@dataclass(**slots_true) +class RootValidatorDecoratorInfo: + """A container for data from `@root_validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@root_validator'. + mode: The proposed validator mode. + """ + + decorator_repr: ClassVar[str] = '@root_validator' + mode: Literal['before', 'after'] + + +@dataclass(**slots_true) +class FieldSerializerDecoratorInfo: + """A container for data from `@field_serializer` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@field_serializer'. + fields: A tuple of field names the serializer should be called on. + mode: The proposed serializer mode. + return_type: The type of the serializer's return value. + when_used: The serialization condition. Accepts a string with values `'always'`, `'unless-none'`, `'json'`, + and `'json-unless-none'`. + check_fields: Whether to check that the fields actually exist on the model. + """ + + decorator_repr: ClassVar[str] = '@field_serializer' + fields: tuple[str, ...] + mode: Literal['plain', 'wrap'] + return_type: Any + when_used: core_schema.WhenUsed + check_fields: bool | None + + +@dataclass(**slots_true) +class ModelSerializerDecoratorInfo: + """A container for data from `@model_serializer` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@model_serializer'. + mode: The proposed serializer mode. + return_type: The type of the serializer's return value. + when_used: The serialization condition. Accepts a string with values `'always'`, `'unless-none'`, `'json'`, + and `'json-unless-none'`. + """ + + decorator_repr: ClassVar[str] = '@model_serializer' + mode: Literal['plain', 'wrap'] + return_type: Any + when_used: core_schema.WhenUsed + + +@dataclass(**slots_true) +class ModelValidatorDecoratorInfo: + """A container for data from `@model_validator` so that we can access it + while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@model_validator'. + mode: The proposed serializer mode. + """ + + decorator_repr: ClassVar[str] = '@model_validator' + mode: Literal['wrap', 'before', 'after'] + + +DecoratorInfo: TypeAlias = """Union[ + ValidatorDecoratorInfo, + FieldValidatorDecoratorInfo, + RootValidatorDecoratorInfo, + FieldSerializerDecoratorInfo, + ModelSerializerDecoratorInfo, + ModelValidatorDecoratorInfo, + ComputedFieldInfo, +]""" + +ReturnType = TypeVar('ReturnType') +DecoratedType: TypeAlias = ( + 'Union[classmethod[Any, Any, ReturnType], staticmethod[Any, ReturnType], Callable[..., ReturnType], property]' +) + + +@dataclass # can't use slots here since we set attributes on `__post_init__` +class PydanticDescriptorProxy(Generic[ReturnType]): + """Wrap a classmethod, staticmethod, property or unbound function + and act as a descriptor that allows us to detect decorated items + from the class' attributes. + + This class' __get__ returns the wrapped item's __get__ result, + which makes it transparent for classmethods and staticmethods. + + Attributes: + wrapped: The decorator that has to be wrapped. + decorator_info: The decorator info. + shim: A wrapper function to wrap V1 style function. + """ + + wrapped: DecoratedType[ReturnType] + decorator_info: DecoratorInfo + shim: Callable[[Callable[..., Any]], Callable[..., Any]] | None = None + + def __post_init__(self): + for attr in 'setter', 'deleter': + if hasattr(self.wrapped, attr): + f = partial(self._call_wrapped_attr, name=attr) + setattr(self, attr, f) + + def _call_wrapped_attr(self, func: Callable[[Any], None], *, name: str) -> PydanticDescriptorProxy[ReturnType]: + self.wrapped = getattr(self.wrapped, name)(func) + if isinstance(self.wrapped, property): + # update ComputedFieldInfo.wrapped_property + from ..fields import ComputedFieldInfo + + if isinstance(self.decorator_info, ComputedFieldInfo): + self.decorator_info.wrapped_property = self.wrapped + return self + + def __get__(self, obj: object | None, obj_type: type[object] | None = None) -> PydanticDescriptorProxy[ReturnType]: + try: + return self.wrapped.__get__(obj, obj_type) # pyright: ignore[reportReturnType] + except AttributeError: + # not a descriptor, e.g. a partial object + return self.wrapped # type: ignore[return-value] + + def __set_name__(self, instance: Any, name: str) -> None: + if hasattr(self.wrapped, '__set_name__'): + self.wrapped.__set_name__(instance, name) # pyright: ignore[reportFunctionMemberAccess] + + def __getattr__(self, name: str, /) -> Any: + """Forward checks for __isabstractmethod__ and such.""" + return getattr(self.wrapped, name) + + +DecoratorInfoType = TypeVar('DecoratorInfoType', bound=DecoratorInfo) + + +@dataclass(**slots_true) +class Decorator(Generic[DecoratorInfoType]): + """A generic container class to join together the decorator metadata + (metadata from decorator itself, which we have when the + decorator is called but not when we are building the core-schema) + and the bound function (which we have after the class itself is created). + + Attributes: + cls_ref: The class ref. + cls_var_name: The decorated function name. + func: The decorated function. + shim: A wrapper function to wrap V1 style function. + info: The decorator info. + """ + + cls_ref: str + cls_var_name: str + func: Callable[..., Any] + shim: Callable[[Any], Any] | None + info: DecoratorInfoType + + @staticmethod + def build( + cls_: Any, + *, + cls_var_name: str, + shim: Callable[[Any], Any] | None, + info: DecoratorInfoType, + ) -> Decorator[DecoratorInfoType]: + """Build a new decorator. + + Args: + cls_: The class. + cls_var_name: The decorated function name. + shim: A wrapper function to wrap V1 style function. + info: The decorator info. + + Returns: + The new decorator instance. + """ + func = get_attribute_from_bases(cls_, cls_var_name) + if shim is not None: + func = shim(func) + func = unwrap_wrapped_function(func, unwrap_partial=False) + if not callable(func): + # TODO most likely this branch can be removed when we drop support for Python 3.12: + # This branch will get hit for classmethod properties + attribute = get_attribute_from_base_dicts(cls_, cls_var_name) # prevents the binding call to `__get__` + if isinstance(attribute, PydanticDescriptorProxy): + func = unwrap_wrapped_function(attribute.wrapped) + return Decorator( + cls_ref=get_type_ref(cls_), + cls_var_name=cls_var_name, + func=func, + shim=shim, + info=info, + ) + + def bind_to_cls(self, cls: Any) -> Decorator[DecoratorInfoType]: + """Bind the decorator to a class. + + Args: + cls: the class. + + Returns: + The new decorator instance. + """ + return self.build( + cls, + cls_var_name=self.cls_var_name, + shim=self.shim, + info=copy(self.info), + ) + + +def get_bases(tp: type[Any]) -> tuple[type[Any], ...]: + """Get the base classes of a class or typeddict. + + Args: + tp: The type or class to get the bases. + + Returns: + The base classes. + """ + if is_typeddict(tp): + return tp.__orig_bases__ # type: ignore + try: + return tp.__bases__ + except AttributeError: + return () + + +def mro(tp: type[Any]) -> tuple[type[Any], ...]: + """Calculate the Method Resolution Order of bases using the C3 algorithm. + + See https://www.python.org/download/releases/2.3/mro/ + """ + # try to use the existing mro, for performance mainly + # but also because it helps verify the implementation below + if not is_typeddict(tp): + try: + return tp.__mro__ + except AttributeError: + # GenericAlias and some other cases + pass + + bases = get_bases(tp) + return (tp,) + mro_for_bases(bases) + + +def mro_for_bases(bases: tuple[type[Any], ...]) -> tuple[type[Any], ...]: + def merge_seqs(seqs: list[deque[type[Any]]]) -> Iterable[type[Any]]: + while True: + non_empty = [seq for seq in seqs if seq] + if not non_empty: + # Nothing left to process, we're done. + return + candidate: type[Any] | None = None + for seq in non_empty: # Find merge candidates among seq heads. + candidate = seq[0] + not_head = [s for s in non_empty if candidate in islice(s, 1, None)] + if not_head: + # Reject the candidate. + candidate = None + else: + break + if not candidate: + raise TypeError('Inconsistent hierarchy, no C3 MRO is possible') + yield candidate + for seq in non_empty: + # Remove candidate. + if seq[0] == candidate: + seq.popleft() + + seqs = [deque(mro(base)) for base in bases] + [deque(bases)] + return tuple(merge_seqs(seqs)) + + +_sentinel = object() + + +def get_attribute_from_bases(tp: type[Any] | tuple[type[Any], ...], name: str) -> Any: + """Get the attribute from the next class in the MRO that has it, + aiming to simulate calling the method on the actual class. + + The reason for iterating over the mro instead of just getting + the attribute (which would do that for us) is to support TypedDict, + which lacks a real __mro__, but can have a virtual one constructed + from its bases (as done here). + + Args: + tp: The type or class to search for the attribute. If a tuple, this is treated as a set of base classes. + name: The name of the attribute to retrieve. + + Returns: + Any: The attribute value, if found. + + Raises: + AttributeError: If the attribute is not found in any class in the MRO. + """ + if isinstance(tp, tuple): + for base in mro_for_bases(tp): + attribute = base.__dict__.get(name, _sentinel) + if attribute is not _sentinel: + attribute_get = getattr(attribute, '__get__', None) + if attribute_get is not None: + return attribute_get(None, tp) + return attribute + raise AttributeError(f'{name} not found in {tp}') + else: + try: + return getattr(tp, name) + except AttributeError: + return get_attribute_from_bases(mro(tp), name) + + +def get_attribute_from_base_dicts(tp: type[Any], name: str) -> Any: + """Get an attribute out of the `__dict__` following the MRO. + This prevents the call to `__get__` on the descriptor, and allows + us to get the original function for classmethod properties. + + Args: + tp: The type or class to search for the attribute. + name: The name of the attribute to retrieve. + + Returns: + Any: The attribute value, if found. + + Raises: + KeyError: If the attribute is not found in any class's `__dict__` in the MRO. + """ + for base in reversed(mro(tp)): + if name in base.__dict__: + return base.__dict__[name] + return tp.__dict__[name] # raise the error + + +@dataclass(**slots_true) +class DecoratorInfos: + """Mapping of name in the class namespace to decorator info. + + note that the name in the class namespace is the function or attribute name + not the field name! + """ + + validators: dict[str, Decorator[ValidatorDecoratorInfo]] = field(default_factory=dict) + field_validators: dict[str, Decorator[FieldValidatorDecoratorInfo]] = field(default_factory=dict) + root_validators: dict[str, Decorator[RootValidatorDecoratorInfo]] = field(default_factory=dict) + field_serializers: dict[str, Decorator[FieldSerializerDecoratorInfo]] = field(default_factory=dict) + model_serializers: dict[str, Decorator[ModelSerializerDecoratorInfo]] = field(default_factory=dict) + model_validators: dict[str, Decorator[ModelValidatorDecoratorInfo]] = field(default_factory=dict) + computed_fields: dict[str, Decorator[ComputedFieldInfo]] = field(default_factory=dict) + + @classmethod + def build( + cls, + typ: type[Any], + # Default to `True` for backwards compatibility: + replace_wrapped_methods: bool = True, + ) -> Self: + """Build a `DecoratorInfos` instance for the given model, dataclass or `TypedDict` type. + + Decorators from parent classes are included, including "bare" classes (e.g. if `typ` + is a Pydantic model, non Pydantic parent model classes are also taken into account). + The collection of the decorators happens by respecting the MRO. + + If one of the bases has an `__pydantic_decorators__` attribute set, it is assumed to be + a `DecoratorInfos` instance and is used as-is. The `__pydantic_decorators__` attribute + is *not* being set on the provided `typ`. + + Args: + typ: The model, dataclass or `TypedDict` type to use when building the `DecoratorInfos` instance. + replace_wrapped_methods: Whether to replace the decorator's wrapped methods on `typ`. + This is useful e.g. for field validators which are initially class methods. This should + only be set to `True` if `typ` is a Pydantic model or dataclass (otherwise this results + in mutations of classes Pydantic doesn't "own"). + """ + # reminder: dicts are ordered and replacement does not alter the order + res = cls() + # Iterate over the bases, without the actual `typ`. + # `1:-1` because we don't need to include `object`/`TypedDict`: + for base in reversed(mro(typ)[1:-1]): + existing: DecoratorInfos | None = base.__dict__.get('__pydantic_decorators__') + if existing is None: + existing, _ = _decorator_infos_for_class(base, collect_to_replace=False) + res.validators.update({k: v.bind_to_cls(typ) for k, v in existing.validators.items()}) + res.field_validators.update({k: v.bind_to_cls(typ) for k, v in existing.field_validators.items()}) + res.root_validators.update({k: v.bind_to_cls(typ) for k, v in existing.root_validators.items()}) + res.field_serializers.update({k: v.bind_to_cls(typ) for k, v in existing.field_serializers.items()}) + res.model_serializers.update({k: v.bind_to_cls(typ) for k, v in existing.model_serializers.items()}) + res.model_validators.update({k: v.bind_to_cls(typ) for k, v in existing.model_validators.items()}) + res.computed_fields.update({k: v.bind_to_cls(typ) for k, v in existing.computed_fields.items()}) + + decorator_infos, to_replace = _decorator_infos_for_class(typ, collect_to_replace=True) + + res.validators.update(decorator_infos.validators) + res.field_validators.update(decorator_infos.field_validators) + res.root_validators.update(decorator_infos.root_validators) + res.field_serializers.update(decorator_infos.field_serializers) + res.model_serializers.update(decorator_infos.model_serializers) + res.model_validators.update(decorator_infos.model_validators) + res.computed_fields.update(decorator_infos.computed_fields) + + if replace_wrapped_methods and to_replace: + for name, value in to_replace: + setattr(typ, name, value) + + res._validate() + return res + + def _validate(self) -> None: + seen: set[str] = set() + for field_ser in self.field_serializers.values(): + for f_name in field_ser.info.fields: + if f_name in seen: + raise PydanticUserError( + f'Multiple field serializer functions were defined for field {f_name!r}, this is not allowed.', + code='multiple-field-serializers', + ) + seen.add(f_name) + + def update_from_config(self, config_wrapper: ConfigWrapper) -> None: + """Update the decorator infos from the configuration of the class they are attached to.""" + for name, computed_field_dec in self.computed_fields.items(): + computed_field_dec.info._update_from_config(config_wrapper, name) + + +def _decorator_infos_for_class( + typ: type[Any], + *, + collect_to_replace: bool, +) -> tuple[DecoratorInfos, list[tuple[str, Any]]]: + """Collect a `DecoratorInfos` for class, without looking into bases.""" + res = DecoratorInfos() + to_replace: list[tuple[str, Any]] = [] + + for var_name, var_value in vars(typ).items(): + if isinstance(var_value, PydanticDescriptorProxy): + info = var_value.decorator_info + if isinstance(info, ValidatorDecoratorInfo): + res.validators[var_name] = Decorator.build(typ, cls_var_name=var_name, shim=var_value.shim, info=info) + elif isinstance(info, FieldValidatorDecoratorInfo): + res.field_validators[var_name] = Decorator.build( + typ, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, RootValidatorDecoratorInfo): + res.root_validators[var_name] = Decorator.build( + typ, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, FieldSerializerDecoratorInfo): + res.field_serializers[var_name] = Decorator.build( + typ, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, ModelValidatorDecoratorInfo): + res.model_validators[var_name] = Decorator.build( + typ, cls_var_name=var_name, shim=var_value.shim, info=info + ) + elif isinstance(info, ModelSerializerDecoratorInfo): + res.model_serializers[var_name] = Decorator.build( + typ, cls_var_name=var_name, shim=var_value.shim, info=info + ) + else: + from ..fields import ComputedFieldInfo + + isinstance(var_value, ComputedFieldInfo) + res.computed_fields[var_name] = Decorator.build(typ, cls_var_name=var_name, shim=None, info=info) + if collect_to_replace: + to_replace.append((var_name, var_value.wrapped)) + + return res, to_replace + + +def inspect_validator( + validator: Callable[..., Any], *, mode: FieldValidatorModes, type: Literal['field', 'model'] +) -> bool: + """Look at a field or model validator function and determine whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + validator: The validator function to inspect. + mode: The proposed validator mode. + type: The type of validator, either 'field' or 'model'. + + Returns: + Whether the validator takes an info argument. + """ + try: + sig = signature_no_eval(validator) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no info argument is present: + return False + n_positional = count_positional_required_params(sig) + if mode == 'wrap': + if n_positional == 3: + return True + elif n_positional == 2: + return False + else: + assert mode in {'before', 'after', 'plain'}, f"invalid mode: {mode!r}, expected 'before', 'after' or 'plain" + if n_positional == 2: + return True + elif n_positional == 1: + return False + + raise PydanticUserError( + f'Unrecognized {type} validator function signature for {validator} with `mode={mode}`: {sig}', + code='validator-signature', + ) + + +def inspect_field_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> tuple[bool, bool]: + """Look at a field serializer function and determine if it is a field serializer, + and whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + serializer: The serializer function to inspect. + mode: The serializer mode, either 'plain' or 'wrap'. + + Returns: + Tuple of (is_field_serializer, info_arg). + """ + try: + sig = signature_no_eval(serializer) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no info argument is present and this is not a method: + return (False, False) + + first = next(iter(sig.parameters.values()), None) + is_field_serializer = first is not None and first.name == 'self' + + n_positional = count_positional_required_params(sig) + if is_field_serializer: + # -1 to correct for self parameter + info_arg = _serializer_info_arg(mode, n_positional - 1) + else: + info_arg = _serializer_info_arg(mode, n_positional) + + if info_arg is None: + raise PydanticUserError( + f'Unrecognized field_serializer function signature for {serializer} with `mode={mode}`:{sig}', + code='field-serializer-signature', + ) + + return is_field_serializer, info_arg + + +def inspect_annotated_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> bool: + """Look at a serializer function used via `Annotated` and determine whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + serializer: The serializer function to check. + mode: The serializer mode, either 'plain' or 'wrap'. + + Returns: + info_arg + """ + try: + sig = signature_no_eval(serializer) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no info argument is present: + return False + info_arg = _serializer_info_arg(mode, count_positional_required_params(sig)) + if info_arg is None: + raise PydanticUserError( + f'Unrecognized field_serializer function signature for {serializer} with `mode={mode}`:{sig}', + code='field-serializer-signature', + ) + else: + return info_arg + + +def inspect_model_serializer(serializer: Callable[..., Any], mode: Literal['plain', 'wrap']) -> bool: + """Look at a model serializer function and determine whether it takes an info argument. + + An error is raised if the function has an invalid signature. + + Args: + serializer: The serializer function to check. + mode: The serializer mode, either 'plain' or 'wrap'. + + Returns: + `info_arg` - whether the function expects an info argument. + """ + if isinstance(serializer, (staticmethod, classmethod)) or not is_instance_method_from_sig(serializer): + raise PydanticUserError( + '`@model_serializer` must be applied to instance methods', code='model-serializer-instance-method' + ) + + sig = signature_no_eval(serializer) + info_arg = _serializer_info_arg(mode, count_positional_required_params(sig)) + if info_arg is None: + raise PydanticUserError( + f'Unrecognized model_serializer function signature for {serializer} with `mode={mode}`:{sig}', + code='model-serializer-signature', + ) + else: + return info_arg + + +def _serializer_info_arg(mode: Literal['plain', 'wrap'], n_positional: int) -> bool | None: + if mode == 'plain': + if n_positional == 1: + # (input_value: Any, /) -> Any + return False + elif n_positional == 2: + # (model: Any, input_value: Any, /) -> Any + return True + else: + assert mode == 'wrap', f"invalid mode: {mode!r}, expected 'plain' or 'wrap'" + if n_positional == 2: + # (input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any + return False + elif n_positional == 3: + # (input_value: Any, serializer: SerializerFunctionWrapHandler, info: SerializationInfo, /) -> Any + return True + + return None + + +AnyDecoratorCallable: TypeAlias = ( + 'Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any], Callable[..., Any]]' +) + + +def is_instance_method_from_sig(function: AnyDecoratorCallable) -> bool: + """Whether the function is an instance method. + + It will consider a function as instance method if the first parameter of + function is `self`. + + Args: + function: The function to check. + + Returns: + `True` if the function is an instance method, `False` otherwise. + """ + sig = signature_no_eval(unwrap_wrapped_function(function)) + first = next(iter(sig.parameters.values()), None) + if first and first.name == 'self': + return True + return False + + +def ensure_classmethod_based_on_signature(function: AnyDecoratorCallable) -> Any: + """Apply the `@classmethod` decorator on the function. + + Args: + function: The function to apply the decorator on. + + Return: + The `@classmethod` decorator applied function. + """ + if not isinstance( + unwrap_wrapped_function(function, unwrap_class_static_method=False), classmethod + ) and _is_classmethod_from_sig(function): + return classmethod(function) # type: ignore[arg-type] + return function + + +def _is_classmethod_from_sig(function: AnyDecoratorCallable) -> bool: + sig = signature_no_eval(unwrap_wrapped_function(function)) + first = next(iter(sig.parameters.values()), None) + if first and first.name == 'cls': + return True + return False + + +def unwrap_wrapped_function( + func: Any, + *, + unwrap_partial: bool = True, + unwrap_class_static_method: bool = True, +) -> Any: + """Recursively unwraps a wrapped function until the underlying function is reached. + This handles property, functools.partial, functools.partialmethod, staticmethod, and classmethod. + + Args: + func: The function to unwrap. + unwrap_partial: If True (default), unwrap partial and partialmethod decorators. + unwrap_class_static_method: If True (default), also unwrap classmethod and staticmethod + decorators. If False, only unwrap partial and partialmethod decorators. + + Returns: + The underlying function of the wrapped function. + """ + # Define the types we want to check against as a single tuple. + unwrap_types = ( + (property, cached_property) + + ((partial, partialmethod) if unwrap_partial else ()) + + ((staticmethod, classmethod) if unwrap_class_static_method else ()) + ) + + while isinstance(func, unwrap_types): + if unwrap_class_static_method and isinstance(func, (classmethod, staticmethod)): + func = func.__func__ + elif isinstance(func, (partial, partialmethod)): + func = func.func + elif isinstance(func, property): + func = func.fget # arbitrary choice, convenient for computed fields + else: + # Make coverage happy as it can only get here in the last possible case + assert isinstance(func, cached_property) + func = func.func # type: ignore + + return func + + +_function_like = ( + partial, + partialmethod, + types.FunctionType, + types.BuiltinFunctionType, + types.MethodType, + types.WrapperDescriptorType, + types.MethodWrapperType, + types.MemberDescriptorType, +) + + +def get_callable_return_type( + callable_obj: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> Any | PydanticUndefinedType: + """Get the callable return type. + + Args: + callable_obj: The callable to analyze. + globalns: The globals namespace to use during type annotation evaluation. + localns: The locals namespace to use during type annotation evaluation. + + Returns: + The function return type. + """ + if isinstance(callable_obj, type): + # types are callables, and we assume the return type + # is the type itself (e.g. `int()` results in an instance of `int`). + return callable_obj + + if not isinstance(callable_obj, _function_like): + call_func = getattr(type(callable_obj), '__call__', None) # noqa: B004 + if call_func is not None: + callable_obj = call_func + + hints = get_function_type_hints( + unwrap_wrapped_function(callable_obj), + include_keys={'return'}, + globalns=globalns, + localns=localns, + ) + return hints.get('return', PydanticUndefined) + + +def count_positional_required_params(sig: Signature) -> int: + """Get the number of positional (required) arguments of a signature. + + This function should only be used to inspect signatures of validation and serialization functions. + The first argument (the value being serialized or validated) is counted as a required argument + even if a default value exists. + + Returns: + The number of positional arguments of a signature. + """ + parameters = list(sig.parameters.values()) + return sum( + 1 + for param in parameters + if can_be_positional(param) + # First argument is the value being validated/serialized, and can have a default value + # (e.g. `float`, which has signature `(x=0, /)`). We assume other parameters (the info arg + # for instance) should be required, and thus without any default value. + and (param.default is Parameter.empty or param is parameters[0]) + ) + + +def ensure_property(f: Any) -> Any: + """Ensure that a function is a `property` or `cached_property`, or is a valid descriptor. + + Args: + f: The function to check. + + Returns: + The function, or a `property` or `cached_property` instance wrapping the function. + """ + if ismethoddescriptor(f) or isdatadescriptor(f): + return f + else: + return property(f) diff --git a/source/target-vendors/cp312/pydantic/_internal/_decorators_v1.py b/source/target-vendors/cp312/pydantic/_internal/_decorators_v1.py new file mode 100644 index 0000000..3427377 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_decorators_v1.py @@ -0,0 +1,174 @@ +"""Logic for V1 validators, e.g. `@validator` and `@root_validator`.""" + +from __future__ import annotations as _annotations + +from inspect import Parameter, signature +from typing import Any, Union, cast + +from pydantic_core import core_schema +from typing_extensions import Protocol + +from ..errors import PydanticUserError +from ._utils import can_be_positional + + +class V1OnlyValueValidator(Protocol): + """A simple validator, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any) -> Any: ... + + +class V1ValidatorWithValues(Protocol): + """A validator with `values` argument, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, values: dict[str, Any]) -> Any: ... + + +class V1ValidatorWithValuesKwOnly(Protocol): + """A validator with keyword only `values` argument, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, *, values: dict[str, Any]) -> Any: ... + + +class V1ValidatorWithKwargs(Protocol): + """A validator with `kwargs` argument, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, **kwargs: Any) -> Any: ... + + +class V1ValidatorWithValuesAndKwargs(Protocol): + """A validator with `values` and `kwargs` arguments, supported for V1 validators and V2 validators.""" + + def __call__(self, __value: Any, values: dict[str, Any], **kwargs: Any) -> Any: ... + + +V1Validator = Union[ + V1ValidatorWithValues, V1ValidatorWithValuesKwOnly, V1ValidatorWithKwargs, V1ValidatorWithValuesAndKwargs +] + + +def can_be_keyword(param: Parameter) -> bool: + return param.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) + + +def make_generic_v1_field_validator(validator: V1Validator) -> core_schema.WithInfoValidatorFunction: + """Wrap a V1 style field validator for V2 compatibility. + + Args: + validator: The V1 style field validator. + + Returns: + A wrapped V2 style field validator. + + Raises: + PydanticUserError: If the signature is not supported or the parameters are + not available in Pydantic V2. + """ + sig = signature(validator) + + needs_values_kw = False + + for param_num, (param_name, parameter) in enumerate(sig.parameters.items()): + if can_be_keyword(parameter) and param_name in ('field', 'config'): + raise PydanticUserError( + 'The `field` and `config` parameters are not available in Pydantic V2, ' + 'please use the `info` parameter instead.', + code='validator-field-config-info', + ) + if parameter.kind is Parameter.VAR_KEYWORD: + needs_values_kw = True + elif can_be_keyword(parameter) and param_name == 'values': + needs_values_kw = True + elif can_be_positional(parameter) and param_num == 0: + # value + continue + elif parameter.default is Parameter.empty: # ignore params with defaults e.g. bound by functools.partial + raise PydanticUserError( + f'Unsupported signature for V1 style validator {validator}: {sig} is not supported.', + code='validator-v1-signature', + ) + + if needs_values_kw: + # (v, **kwargs), (v, values, **kwargs), (v, *, values, **kwargs) or (v, *, values) + val1 = cast(V1ValidatorWithValues, validator) + + def wrapper1(value: Any, info: core_schema.ValidationInfo) -> Any: + return val1(value, values=info.data) + + return wrapper1 + else: + val2 = cast(V1OnlyValueValidator, validator) + + def wrapper2(value: Any, _: core_schema.ValidationInfo) -> Any: + return val2(value) + + return wrapper2 + + +RootValidatorValues = dict[str, Any] +# technically tuple[model_dict, model_extra, fields_set] | tuple[dataclass_dict, init_vars] +RootValidatorFieldsTuple = tuple[Any, ...] + + +class V1RootValidatorFunction(Protocol): + """A simple root validator, supported for V1 validators and V2 validators.""" + + def __call__(self, __values: RootValidatorValues) -> RootValidatorValues: ... + + +class V2CoreBeforeRootValidator(Protocol): + """V2 validator with mode='before'.""" + + def __call__(self, __values: RootValidatorValues, __info: core_schema.ValidationInfo) -> RootValidatorValues: ... + + +class V2CoreAfterRootValidator(Protocol): + """V2 validator with mode='after'.""" + + def __call__( + self, __fields_tuple: RootValidatorFieldsTuple, __info: core_schema.ValidationInfo + ) -> RootValidatorFieldsTuple: ... + + +def make_v1_generic_root_validator( + validator: V1RootValidatorFunction, pre: bool +) -> V2CoreBeforeRootValidator | V2CoreAfterRootValidator: + """Wrap a V1 style root validator for V2 compatibility. + + Args: + validator: The V1 style field validator. + pre: Whether the validator is a pre validator. + + Returns: + A wrapped V2 style validator. + """ + if pre is True: + # mode='before' for pydantic-core + def _wrapper1(values: RootValidatorValues, _: core_schema.ValidationInfo) -> RootValidatorValues: + return validator(values) + + return _wrapper1 + + # mode='after' for pydantic-core + def _wrapper2(fields_tuple: RootValidatorFieldsTuple, _: core_schema.ValidationInfo) -> RootValidatorFieldsTuple: + if len(fields_tuple) == 2: + # dataclass, this is easy + values, init_vars = fields_tuple + values = validator(values) + return values, init_vars + else: + # ugly hack: to match v1 behaviour, we merge values and model_extra, then split them up based on fields + # afterwards + model_dict, model_extra, fields_set = fields_tuple + if model_extra: + fields = set(model_dict.keys()) + model_dict.update(model_extra) + model_dict_new = validator(model_dict) + for k in list(model_dict_new.keys()): + if k not in fields: + model_extra[k] = model_dict_new.pop(k) + else: + model_dict_new = validator(model_dict) + return model_dict_new, model_extra, fields_set + + return _wrapper2 diff --git a/source/target-vendors/cp312/pydantic/_internal/_discriminated_union.py b/source/target-vendors/cp312/pydantic/_internal/_discriminated_union.py new file mode 100644 index 0000000..fc52f30 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_discriminated_union.py @@ -0,0 +1,494 @@ +from __future__ import annotations as _annotations + +from collections.abc import Hashable, Sequence +from typing import TYPE_CHECKING, Any, cast + +from pydantic_core import CoreSchema, core_schema + +from ..errors import PydanticUserError +from . import _core_utils +from ._core_utils import ( + CoreSchemaField, +) + +if TYPE_CHECKING: + from ..types import Discriminator + from ._core_metadata import CoreMetadata + + +class MissingDefinitionForUnionRef(Exception): + """Raised when applying a discriminated union discriminator to a schema + requires a definition that is not yet defined + """ + + def __init__(self, ref: str) -> None: + self.ref = ref + super().__init__(f'Missing definition for ref {self.ref!r}') + + +def set_discriminator_in_metadata(schema: CoreSchema, discriminator: Any) -> None: + metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) + metadata['pydantic_internal_union_discriminator'] = discriminator + + +def apply_discriminator( + schema: core_schema.CoreSchema, + discriminator: str | Discriminator, + definitions: dict[str, core_schema.CoreSchema] | None = None, +) -> core_schema.CoreSchema: + """Applies the discriminator and returns a new core schema. + + Args: + schema: The input schema. + discriminator: The name of the field which will serve as the discriminator. + definitions: A mapping of schema ref to schema. + + Returns: + The new core schema. + + Raises: + TypeError: + - If `discriminator` is used with invalid union variant. + - If `discriminator` is used with `Union` type with one variant. + - If `discriminator` value mapped to multiple choices. + MissingDefinitionForUnionRef: + If the definition for ref is missing. + PydanticUserError: + - If a model in union doesn't have a discriminator field. + - If discriminator field has a non-string alias. + - If discriminator fields have different aliases. + - If discriminator field not of type `Literal`. + """ + from ..types import Discriminator + + if isinstance(discriminator, Discriminator): + if isinstance(discriminator.discriminator, str): + discriminator = discriminator.discriminator + else: + return discriminator._convert_schema(schema) + + return _ApplyInferredDiscriminator(discriminator, definitions or {}).apply(schema) + + +class _ApplyInferredDiscriminator: + """This class is used to convert an input schema containing a union schema into one where that union is + replaced with a tagged-union, with all the associated debugging and performance benefits. + + This is done by: + * Validating that the input schema is compatible with the provided discriminator + * Introspecting the schema to determine which discriminator values should map to which union choices + * Handling various edge cases such as 'definitions', 'default', 'nullable' schemas, and more + + I have chosen to implement the conversion algorithm in this class, rather than a function, + to make it easier to maintain state while recursively walking the provided CoreSchema. + """ + + def __init__(self, discriminator: str, definitions: dict[str, core_schema.CoreSchema]): + # `discriminator` should be the name of the field which will serve as the discriminator. + # It must be the python name of the field, and *not* the field's alias. Note that as of now, + # all members of a discriminated union _must_ use a field with the same name as the discriminator. + # This may change if/when we expose a way to manually specify the TaggedUnionSchema's choices. + self.discriminator = discriminator + + # `definitions` should contain a mapping of schema ref to schema for all schemas which might + # be referenced by some choice + self.definitions = definitions + + # `_discriminator_alias` will hold the value, if present, of the alias for the discriminator + # + # Note: following the v1 implementation, we currently disallow the use of different aliases + # for different choices. This is not a limitation of pydantic_core, but if we try to handle + # this, the inference logic gets complicated very quickly, and could result in confusing + # debugging challenges for users making subtle mistakes. + # + # Rather than trying to do the most powerful inference possible, I think we should eventually + # expose a way to more-manually control the way the TaggedUnionSchema is constructed through + # the use of a new type which would be placed as an Annotation on the Union type. This would + # provide the full flexibility/power of pydantic_core's TaggedUnionSchema where necessary for + # more complex cases, without over-complicating the inference logic for the common cases. + self._discriminator_alias: str | None = None + + # `_should_be_nullable` indicates whether the converted union has `None` as an allowed value. + # If `None` is an acceptable value of the (possibly-wrapped) union, we ignore it while + # constructing the TaggedUnionSchema, but set the `_should_be_nullable` attribute to True. + # Once we have constructed the TaggedUnionSchema, if `_should_be_nullable` is True, we ensure + # that the final schema gets wrapped as a NullableSchema. This has the same semantics on the + # python side, but resolves the issue that `None` cannot correspond to any discriminator values. + self._should_be_nullable = False + + # `_is_nullable` is used to track if the final produced schema will definitely be nullable; + # we set it to True if the input schema is wrapped in a nullable schema that we know will be preserved + # as an indication that, even if None is discovered as one of the union choices, we will not need to wrap + # the final value in another nullable schema. + # + # This is more complicated than just checking for the final outermost schema having type 'nullable' thanks + # to the possible presence of other wrapper schemas such as DefinitionsSchema, WithDefaultSchema, etc. + self._is_nullable = False + + # `_choices_to_handle` serves as a stack of choices to add to the tagged union. Initially, choices + # from the union in the wrapped schema will be appended to this list, and the recursive choice-handling + # algorithm may add more choices to this stack as (nested) unions are encountered. + self._choices_to_handle: list[core_schema.CoreSchema] = [] + + # `_tagged_union_choices` is built during the call to `apply`, and will hold the choices to be included + # in the output TaggedUnionSchema that will replace the union from the input schema + self._tagged_union_choices: dict[Hashable, core_schema.CoreSchema] = {} + + # `_used` is changed to True after applying the discriminator to prevent accidental reuse + self._used = False + + def apply(self, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """Return a new CoreSchema based on `schema` that uses a tagged-union with the discriminator provided + to this class. + + Args: + schema: The input schema. + + Returns: + The new core schema. + + Raises: + TypeError: + - If `discriminator` is used with invalid union variant. + - If `discriminator` is used with `Union` type with one variant. + - If `discriminator` value mapped to multiple choices. + ValueError: + If the definition for ref is missing. + PydanticUserError: + - If a model in union doesn't have a discriminator field. + - If discriminator field has a non-string alias. + - If discriminator fields have different aliases. + - If discriminator field not of type `Literal`. + """ + assert not self._used + schema = self._apply_to_root(schema) + if self._should_be_nullable and not self._is_nullable: + schema = core_schema.nullable_schema(schema) + self._used = True + return schema + + def _apply_to_root(self, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """This method handles the outer-most stage of recursion over the input schema: + unwrapping nullable or definitions schemas, and calling the `_handle_choice` + method iteratively on the choices extracted (recursively) from the possibly-wrapped union. + """ + if schema['type'] == 'nullable': + self._is_nullable = True + wrapped = self._apply_to_root(schema['schema']) + nullable_wrapper = schema.copy() + nullable_wrapper['schema'] = wrapped + return nullable_wrapper + + if schema['type'] == 'definitions': + wrapped = self._apply_to_root(schema['schema']) + definitions_wrapper = schema.copy() + definitions_wrapper['schema'] = wrapped + return definitions_wrapper + + if schema['type'] == 'definition-ref': + schema_ref = schema['schema_ref'] + if schema_ref not in self.definitions: # pragma: no cover + raise MissingDefinitionForUnionRef(schema_ref) + + def_schema = self.definitions[schema_ref] + # If using a referenceable union as discriminated (e.g. `type Pet = Cat | Dog; field: Pet = Field(discriminator=...)`): + if def_schema['type'] == 'union': + schema = def_schema.copy() + schema.pop('ref') + + if schema['type'] != 'union': + # If the schema is not a union, it probably means it just had a single member and + # was flattened by pydantic_core. + # However, it still may make sense to apply the discriminator to this schema, + # as a way to get discriminated-union-style error messages, so we allow this here. + schema = core_schema.union_schema([schema]) + + # Reverse the choices list before extending the stack so that they get handled in the order they occur + choices_schemas = [v[0] if isinstance(v, tuple) else v for v in schema['choices'][::-1]] + self._choices_to_handle.extend(choices_schemas) + while self._choices_to_handle: + choice = self._choices_to_handle.pop() + self._handle_choice(choice) + + if self._discriminator_alias is not None and self._discriminator_alias != self.discriminator: + # * We need to annotate `discriminator` as a union here to handle both branches of this conditional + # * We need to annotate `discriminator` as list[list[str | int]] and not list[list[str]] due to the + # invariance of list, and because list[list[str | int]] is the type of the discriminator argument + # to tagged_union_schema below + # * See the docstring of pydantic_core.core_schema.tagged_union_schema for more details about how to + # interpret the value of the discriminator argument to tagged_union_schema. (The list[list[str]] here + # is the appropriate way to provide a list of fallback attributes to check for a discriminator value.) + discriminator: str | list[list[str | int]] = [[self.discriminator], [self._discriminator_alias]] + else: + discriminator = self.discriminator + return core_schema.tagged_union_schema( + choices=self._tagged_union_choices, + discriminator=discriminator, + custom_error_type=schema.get('custom_error_type'), + custom_error_message=schema.get('custom_error_message'), + custom_error_context=schema.get('custom_error_context'), + strict=False, + from_attributes=True, + ref=schema.get('ref'), + metadata=schema.get('metadata'), + serialization=schema.get('serialization'), + ) + + def _handle_choice(self, choice: core_schema.CoreSchema) -> None: + """This method handles the "middle" stage of recursion over the input schema. + Specifically, it is responsible for handling each choice of the outermost union + (and any "coalesced" choices obtained from inner unions). + + Here, "handling" entails: + * Coalescing nested unions and compatible tagged-unions + * Tracking the presence of 'none' and 'nullable' schemas occurring as choices + * Validating that each allowed discriminator value maps to a unique choice + * Updating the _tagged_union_choices mapping that will ultimately be used to build the TaggedUnionSchema. + """ + if choice['type'] == 'definition-ref': + if choice['schema_ref'] not in self.definitions: + raise MissingDefinitionForUnionRef(choice['schema_ref']) + + if choice['type'] == 'none': + self._should_be_nullable = True + elif choice['type'] == 'definitions': + self._handle_choice(choice['schema']) + elif choice['type'] == 'nullable': + self._should_be_nullable = True + self._handle_choice(choice['schema']) # unwrap the nullable schema + elif choice['type'] == 'union': + # Reverse the choices list before extending the stack so that they get handled in the order they occur + choices_schemas = [v[0] if isinstance(v, tuple) else v for v in choice['choices'][::-1]] + self._choices_to_handle.extend(choices_schemas) + elif choice['type'] not in { + 'model', + 'typed-dict', + 'tagged-union', + 'lax-or-strict', + 'dataclass', + 'dataclass-args', + 'definition-ref', + } and not _core_utils.is_function_with_inner_schema(choice): + # We should eventually handle 'definition-ref' as well + err_str = f'The core schema type {choice["type"]!r} is not a valid discriminated union variant.' + if choice['type'] == 'list': + err_str += ( + ' If you are making use of a list of union types, make sure the discriminator is applied to the ' + 'union type and not the list (e.g. `list[Annotated[ | , Field(discriminator=...)]]`).' + ) + raise TypeError(err_str) + else: + if choice['type'] == 'tagged-union' and self._is_discriminator_shared(choice): + # In this case, this inner tagged-union is compatible with the outer tagged-union, + # and its choices can be coalesced into the outer TaggedUnionSchema. + subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))] + # Reverse the choices list before extending the stack so that they get handled in the order they occur + self._choices_to_handle.extend(subchoices[::-1]) + return + + inferred_discriminator_values = self._infer_discriminator_values_for_choice(choice, source_name=None) + self._set_unique_choice_for_values(choice, inferred_discriminator_values) + + def _is_discriminator_shared(self, choice: core_schema.TaggedUnionSchema) -> bool: + """This method returns a boolean indicating whether the discriminator for the `choice` + is the same as that being used for the outermost tagged union. This is used to + determine whether this TaggedUnionSchema choice should be "coalesced" into the top level, + or whether it should be treated as a separate (nested) choice. + """ + inner_discriminator = choice['discriminator'] + return inner_discriminator == self.discriminator or ( + isinstance(inner_discriminator, list) + and (self.discriminator in inner_discriminator or [self.discriminator] in inner_discriminator) + ) + + def _infer_discriminator_values_for_choice( # noqa C901 + self, choice: core_schema.CoreSchema, source_name: str | None + ) -> list[str | int]: + """This function recurses over `choice`, extracting all discriminator values that should map to this choice. + + `model_name` is accepted for the purpose of producing useful error messages. + """ + if choice['type'] == 'definitions': + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=source_name) + + elif _core_utils.is_function_with_inner_schema(choice): + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=source_name) + + elif choice['type'] == 'lax-or-strict': + return sorted( + set( + self._infer_discriminator_values_for_choice(choice['lax_schema'], source_name=None) + + self._infer_discriminator_values_for_choice(choice['strict_schema'], source_name=None) + ) + ) + + elif choice['type'] == 'tagged-union': + values: list[str | int] = [] + # Ignore str/int "choices" since these are just references to other choices + subchoices = [x for x in choice['choices'].values() if not isinstance(x, (str, int))] + for subchoice in subchoices: + subchoice_values = self._infer_discriminator_values_for_choice(subchoice, source_name=None) + values.extend(subchoice_values) + return values + + elif choice['type'] == 'union': + values = [] + for subchoice in choice['choices']: + subchoice_schema = subchoice[0] if isinstance(subchoice, tuple) else subchoice + subchoice_values = self._infer_discriminator_values_for_choice(subchoice_schema, source_name=None) + values.extend(subchoice_values) + return values + + elif choice['type'] == 'nullable': + self._should_be_nullable = True + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=None) + + elif choice['type'] == 'model': + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=choice['cls'].__name__) + + elif choice['type'] == 'dataclass': + return self._infer_discriminator_values_for_choice(choice['schema'], source_name=choice['cls'].__name__) + + elif choice['type'] == 'model-fields': + return self._infer_discriminator_values_for_model_choice(choice, source_name=source_name) + + elif choice['type'] == 'dataclass-args': + return self._infer_discriminator_values_for_dataclass_choice(choice, source_name=source_name) + + elif choice['type'] == 'typed-dict': + return self._infer_discriminator_values_for_typed_dict_choice(choice, source_name=source_name) + + elif choice['type'] == 'definition-ref': + schema_ref = choice['schema_ref'] + if schema_ref not in self.definitions: + raise MissingDefinitionForUnionRef(schema_ref) + return self._infer_discriminator_values_for_choice(self.definitions[schema_ref], source_name=source_name) + else: + err_str = f'The core schema type {choice["type"]!r} is not a valid discriminated union variant.' + if choice['type'] == 'list': + err_str += ( + ' If you are making use of a list of union types, make sure the discriminator is applied to the ' + 'union type and not the list (e.g. `list[Annotated[ | , Field(discriminator=...)]]`).' + ) + raise TypeError(err_str) + + def _infer_discriminator_values_for_typed_dict_choice( + self, choice: core_schema.TypedDictSchema, source_name: str | None = None + ) -> list[str | int]: + """This method just extracts the _infer_discriminator_values_for_choice logic specific to TypedDictSchema + for the sake of readability. + """ + source = 'TypedDict' if source_name is None else f'TypedDict {source_name!r}' + field = choice['fields'].get(self.discriminator) + if field is None: + raise PydanticUserError( + f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field' + ) + return self._infer_discriminator_values_for_field(field, source) + + def _infer_discriminator_values_for_model_choice( + self, choice: core_schema.ModelFieldsSchema, source_name: str | None = None + ) -> list[str | int]: + source = 'ModelFields' if source_name is None else f'Model {source_name!r}' + field = choice['fields'].get(self.discriminator) + if field is None: + raise PydanticUserError( + f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field' + ) + return self._infer_discriminator_values_for_field(field, source) + + def _infer_discriminator_values_for_dataclass_choice( + self, choice: core_schema.DataclassArgsSchema, source_name: str | None = None + ) -> list[str | int]: + source = 'DataclassArgs' if source_name is None else f'Dataclass {source_name!r}' + for field in choice['fields']: + if field['name'] == self.discriminator: + break + else: + raise PydanticUserError( + f'{source} needs a discriminator field for key {self.discriminator!r}', code='discriminator-no-field' + ) + return self._infer_discriminator_values_for_field(field, source) + + def _infer_discriminator_values_for_field(self, field: CoreSchemaField, source: str) -> list[str | int]: + if field['type'] == 'computed-field': + # This should never occur as a discriminator, as it is only relevant to serialization + return [] + alias = field.get('validation_alias', self.discriminator) + if not isinstance(alias, str): + raise PydanticUserError( + f'Alias {alias!r} is not supported in a discriminated union', code='discriminator-alias-type' + ) + if self._discriminator_alias is None: + self._discriminator_alias = alias + elif self._discriminator_alias != alias: + raise PydanticUserError( + f'Aliases for discriminator {self.discriminator!r} must be the same ' + f'(got {alias}, {self._discriminator_alias})', + code='discriminator-alias', + ) + return self._infer_discriminator_values_for_inner_schema(field['schema'], source) + + def _infer_discriminator_values_for_inner_schema( + self, schema: core_schema.CoreSchema, source: str + ) -> list[str | int]: + """When inferring discriminator values for a field, we typically extract the expected values from a literal + schema. This function does that, but also handles nested unions and defaults. + """ + if schema['type'] == 'literal': + return schema['expected'] + + elif schema['type'] == 'union': + # Generally when multiple values are allowed they should be placed in a single `Literal`, but + # we add this case to handle the situation where a field is annotated as a `Union` of `Literal`s. + # For example, this lets us handle `Union[Literal['key'], Union[Literal['Key'], Literal['KEY']]]` + values: list[Any] = [] + for choice in schema['choices']: + choice_schema = choice[0] if isinstance(choice, tuple) else choice + choice_values = self._infer_discriminator_values_for_inner_schema(choice_schema, source) + values.extend(choice_values) + return values + + elif schema['type'] == 'default': + # This will happen if the field has a default value; we ignore it while extracting the discriminator values + return self._infer_discriminator_values_for_inner_schema(schema['schema'], source) + + elif schema['type'] == 'function-after': + # After validators don't affect the discriminator values + return self._infer_discriminator_values_for_inner_schema(schema['schema'], source) + + elif schema['type'] == 'model' and schema.get('root_model'): + # Support RootModel[Literal[...]] as discriminator field type + return self._infer_discriminator_values_for_inner_schema(schema['schema'], source) + + elif schema['type'] in {'function-before', 'function-wrap', 'function-plain'}: + validator_type = repr(schema['type'].split('-')[1]) + raise PydanticUserError( + f'Cannot use a mode={validator_type} validator in the' + f' discriminator field {self.discriminator!r} of {source}', + code='discriminator-validator', + ) + + else: + raise PydanticUserError( + f'{source} needs field {self.discriminator!r} to be of type `Literal`', + code='discriminator-needs-literal', + ) + + def _set_unique_choice_for_values(self, choice: core_schema.CoreSchema, values: Sequence[str | int]) -> None: + """This method updates `self.tagged_union_choices` so that all provided (discriminator) `values` map to the + provided `choice`, validating that none of these values already map to another (different) choice. + """ + for discriminator_value in values: + if discriminator_value in self._tagged_union_choices: + # It is okay if `value` is already in tagged_union_choices as long as it maps to the same value. + # Because tagged_union_choices may map values to other values, we need to walk the choices dict + # until we get to a "real" choice, and confirm that is equal to the one assigned. + existing_choice = self._tagged_union_choices[discriminator_value] + if existing_choice != choice: + raise TypeError( + f'Value {discriminator_value!r} for discriminator ' + f'{self.discriminator!r} mapped to multiple choices' + ) + else: + self._tagged_union_choices[discriminator_value] = choice diff --git a/source/target-vendors/cp312/pydantic/_internal/_docs_extraction.py b/source/target-vendors/cp312/pydantic/_internal/_docs_extraction.py new file mode 100644 index 0000000..6df77bf --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_docs_extraction.py @@ -0,0 +1,113 @@ +"""Utilities related to attribute docstring extraction.""" + +from __future__ import annotations + +import ast +import inspect +import sys +import textwrap +from typing import Any + + +class DocstringVisitor(ast.NodeVisitor): + def __init__(self) -> None: + super().__init__() + + self.target: str | None = None + self.attrs: dict[str, str] = {} + self.previous_node_type: type[ast.AST] | None = None + + def visit(self, node: ast.AST) -> Any: + node_result = super().visit(node) + self.previous_node_type = type(node) + return node_result + + def visit_AnnAssign(self, node: ast.AnnAssign) -> Any: + if isinstance(node.target, ast.Name): + self.target = node.target.id + + def visit_Expr(self, node: ast.Expr) -> Any: + if ( + isinstance(node.value, ast.Constant) + and isinstance(node.value.value, str) + and self.previous_node_type is ast.AnnAssign + ): + docstring = inspect.cleandoc(node.value.value) + if self.target: + self.attrs[self.target] = docstring + self.target = None + + +def _dedent_source_lines(source: list[str]) -> str: + # Required for nested class definitions, e.g. in a function block + dedent_source = textwrap.dedent(''.join(source)) + if dedent_source.startswith((' ', '\t')): + # We are in the case where there's a dedented (usually multiline) string + # at a lower indentation level than the class itself. We wrap our class + # in a function as a workaround. + dedent_source = f'def dedent_workaround():\n{dedent_source}' + return dedent_source + + +def _extract_source_from_frame(cls: type[Any]) -> list[str] | None: + frame = inspect.currentframe() + + while frame: + if inspect.getmodule(frame) is inspect.getmodule(cls): + lnum = frame.f_lineno + try: + lines, _ = inspect.findsource(frame) + except OSError: # pragma: no cover + # Source can't be retrieved (maybe because running in an interactive terminal), + # we don't want to error here. + pass + else: + block_lines = inspect.getblock(lines[lnum - 1 :]) + dedent_source = _dedent_source_lines(block_lines) + try: + block_tree = ast.parse(dedent_source) + except SyntaxError: + pass + else: + stmt = block_tree.body[0] + if isinstance(stmt, ast.FunctionDef) and stmt.name == 'dedent_workaround': + # `_dedent_source_lines` wrapped the class around the workaround function + stmt = stmt.body[0] + if isinstance(stmt, ast.ClassDef) and stmt.name == cls.__name__: + return block_lines + + frame = frame.f_back + + +def extract_docstrings_from_cls(cls: type[Any], use_inspect: bool = False) -> dict[str, str]: + """Map model attributes and their corresponding docstring. + + Args: + cls: The class of the Pydantic model to inspect. + use_inspect: Whether to skip usage of frames to find the object and use + the `inspect` module instead. + + Returns: + A mapping containing attribute names and their corresponding docstring. + """ + if use_inspect or sys.version_info >= (3, 13): + # On Python < 3.13, `inspect.getsourcelines()` might not work as expected + # if two classes have the same name in the same source file. + # On Python 3.13+, it will use the new `__firstlineno__` class attribute, + # making it way more robust. + try: + source, _ = inspect.getsourcelines(cls) + except OSError: # pragma: no cover + return {} + else: + # TODO remove this implementation when we drop support for Python 3.12: + source = _extract_source_from_frame(cls) + + if not source: + return {} + + dedent_source = _dedent_source_lines(source) + + visitor = DocstringVisitor() + visitor.visit(ast.parse(dedent_source)) + return visitor.attrs diff --git a/source/target-vendors/cp312/pydantic/_internal/_fields.py b/source/target-vendors/cp312/pydantic/_internal/_fields.py new file mode 100644 index 0000000..9a2a96b --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_fields.py @@ -0,0 +1,729 @@ +"""Private logic related to fields (the `Field()` function and `FieldInfo` class), and arguments to `Annotated`.""" + +from __future__ import annotations as _annotations + +import dataclasses +import warnings +from collections.abc import Mapping +from functools import cache +from inspect import Parameter, ismethoddescriptor +from re import Pattern +from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast + +from pydantic_core import PydanticUndefined +from typing_extensions import TypeIs +from typing_inspection.introspection import AnnotationSource + +from pydantic import PydanticDeprecatedSince211 +from pydantic.errors import PydanticUserError + +from ..aliases import AliasGenerator +from . import _generics, _typing_extra +from ._config import ConfigWrapper +from ._docs_extraction import extract_docstrings_from_cls +from ._import_utils import import_cached_base_model, import_cached_field_info +from ._internal_dataclass import slots_true +from ._namespace_utils import NsResolver +from ._repr import Representation +from ._utils import can_be_positional, get_first_not_none + +if TYPE_CHECKING: + from annotated_types import BaseMetadata + + from ..fields import FieldInfo + from ..main import BaseModel + from ._dataclasses import PydanticDataclass, StandardDataclass + from ._decorators import DecoratorInfos + + +class PydanticMetadata(Representation): + """Base class for annotation markers like `Strict`.""" + + __slots__ = () + + +@dataclasses.dataclass(**slots_true) # TODO: make kw_only when we drop support for 3.9. +class PydanticExtraInfo: + # TODO: make use of PEP 747: + annotation: Any + complete: bool + + +def pydantic_general_metadata(**metadata: Any) -> BaseMetadata: + """Create a new `_PydanticGeneralMetadata` class with the given metadata. + + Args: + **metadata: The metadata to add. + + Returns: + The new `_PydanticGeneralMetadata` class. + """ + return _general_metadata_cls()(metadata) # type: ignore + + +@cache +def _general_metadata_cls() -> type[BaseMetadata]: + """Do it this way to avoid importing `annotated_types` at import time.""" + from annotated_types import BaseMetadata + + class _PydanticGeneralMetadata(PydanticMetadata, BaseMetadata): + """Pydantic general metadata like `max_digits`.""" + + def __init__(self, metadata: Any): + self.__dict__ = metadata + + return _PydanticGeneralMetadata # type: ignore + + +def _check_protected_namespaces( + protected_namespaces: tuple[str | Pattern[str], ...], + ann_name: str, + bases: tuple[type[Any], ...], + cls_name: str, +) -> None: + BaseModel = import_cached_base_model() + + for protected_namespace in protected_namespaces: + ns_violation = False + if isinstance(protected_namespace, Pattern): + ns_violation = protected_namespace.match(ann_name) is not None + elif isinstance(protected_namespace, str): + ns_violation = ann_name.startswith(protected_namespace) + + if ns_violation: + for b in bases: + if hasattr(b, ann_name): + if not (issubclass(b, BaseModel) and ann_name in getattr(b, '__pydantic_fields__', {})): + raise ValueError( + f'Field {ann_name!r} conflicts with member {getattr(b, ann_name)}' + f' of protected namespace {protected_namespace!r}.' + ) + else: + valid_namespaces: list[str] = [] + for pn in protected_namespaces: + if isinstance(pn, Pattern): + if not pn.match(ann_name): + valid_namespaces.append(f're.compile({pn.pattern!r})') + else: + if not ann_name.startswith(pn): + valid_namespaces.append(f"'{pn}'") + + valid_namespaces_str = f'({", ".join(valid_namespaces)}{",)" if len(valid_namespaces) == 1 else ")"}' + + warnings.warn( + f'Field {ann_name!r} in {cls_name!r} conflicts with protected namespace {protected_namespace!r}.\n\n' + f"You may be able to solve this by setting the 'protected_namespaces' configuration to {valid_namespaces_str}.", + UserWarning, + stacklevel=5, + ) + + +def _update_fields_from_docstrings(cls: type[Any], fields: dict[str, FieldInfo], use_inspect: bool = False) -> None: + fields_docs = extract_docstrings_from_cls(cls, use_inspect=use_inspect) + for ann_name, field_info in fields.items(): + if field_info.description is None and ann_name in fields_docs: + field_info.description = fields_docs[ann_name] + + +def _apply_field_title_generator_to_field_info( + title_generator: Callable[[str, FieldInfo], str], + field_name: str, + field_info: FieldInfo, +): + if field_info.title is None: + title = title_generator(field_name, field_info) + if not isinstance(title, str): + raise TypeError(f'field_title_generator {title_generator} must return str, not {title.__class__}') + + field_info.title = title + + +def _apply_alias_generator_to_field_info( + alias_generator: Callable[[str], str] | AliasGenerator, field_name: str, field_info: FieldInfo +): + """Apply an alias generator to aliases on a `FieldInfo` instance if appropriate. + + Args: + alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance. + field_name: The name of the field from which to generate the alias. + field_info: The `FieldInfo` instance to which the alias generator is (maybe) applied. + """ + # Apply an alias_generator if + # 1. An alias is not specified + # 2. An alias is specified, but the priority is <= 1 + if ( + field_info.alias_priority is None + or field_info.alias_priority <= 1 + or field_info.alias is None + or field_info.validation_alias is None + or field_info.serialization_alias is None + ): + alias, validation_alias, serialization_alias = None, None, None + + if isinstance(alias_generator, AliasGenerator): + alias, validation_alias, serialization_alias = alias_generator.generate_aliases(field_name) + elif callable(alias_generator): + alias = alias_generator(field_name) + if not isinstance(alias, str): + raise TypeError(f'alias_generator {alias_generator} must return str, not {alias.__class__}') + + # if priority is not set, we set to 1 + # which supports the case where the alias_generator from a child class is used + # to generate an alias for a field in a parent class + if field_info.alias_priority is None or field_info.alias_priority <= 1: + field_info.alias_priority = 1 + + # if the priority is 1, then we set the aliases to the generated alias + if field_info.alias_priority == 1: + field_info.serialization_alias = get_first_not_none(serialization_alias, alias) + field_info.validation_alias = get_first_not_none(validation_alias, alias) + field_info.alias = alias + + # if any of the aliases are not set, then we set them to the corresponding generated alias + if field_info.alias is None: + field_info.alias = alias + if field_info.serialization_alias is None: + field_info.serialization_alias = get_first_not_none(serialization_alias, alias) + if field_info.validation_alias is None: + field_info.validation_alias = get_first_not_none(validation_alias, alias) + + +def update_field_from_config(config_wrapper: ConfigWrapper, field_name: str, field_info: FieldInfo) -> None: + """Update the `FieldInfo` instance from the configuration set on the model it belongs to. + + This will apply the title and alias generators from the configuration. + + Args: + config_wrapper: The configuration from the model. + field_name: The field name the `FieldInfo` instance is attached to. + field_info: The `FieldInfo` instance to update. + """ + field_title_generator = field_info.field_title_generator or config_wrapper.field_title_generator + if field_title_generator is not None: + _apply_field_title_generator_to_field_info(field_title_generator, field_name, field_info) + if config_wrapper.alias_generator is not None: + _apply_alias_generator_to_field_info(config_wrapper.alias_generator, field_name, field_info) + + +_deprecated_method_names = {'dict', 'json', 'copy', '_iter', '_copy_and_set_values', '_calculate_keys'} + +_deprecated_classmethod_names = { + 'parse_obj', + 'parse_raw', + 'parse_file', + 'from_orm', + 'construct', + 'schema', + 'schema_json', + 'validate', + 'update_forward_refs', + '_get_value', +} + + +def collect_model_fields( # noqa: C901 + cls: type[BaseModel], + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + *, + typevars_map: Mapping[TypeVar, Any] | None = None, +) -> tuple[dict[str, FieldInfo], PydanticExtraInfo | None, set[str]]: + """Collect the fields and class variables names of a nascent Pydantic model. + + The fields collection process is *lenient*, meaning it won't error if string annotations + fail to evaluate. If this happens, the original annotation (and assigned value, if any) + is stored on the created `FieldInfo` instance. + + The `rebuild_model_fields()` should be called at a later point (e.g. when rebuilding the model), + and will make use of these stored attributes. + + Args: + cls: BaseModel or dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting model annotations. + typevars_map: A dictionary mapping type variables to their concrete types. + + Returns: + A three-tuple containing the model fields, the `PydanticExtraInfo` instance if the `__pydantic_extra__` annotation is set, + and class variables names. + + Raises: + NameError: + - If there is a conflict between a field name and protected namespaces. + - If there is a field other than `root` in `RootModel`. + - If a field shadows an attribute in the parent model. + """ + FieldInfo_ = import_cached_field_info() + BaseModel_ = import_cached_base_model() + + bases = cls.__bases__ + parent_fields_lookup: dict[str, FieldInfo] = {} + for base in reversed(bases): + if model_fields := getattr(base, '__pydantic_fields__', None): + parent_fields_lookup.update(model_fields) + + type_hints = _typing_extra.get_model_type_hints(cls, ns_resolver=ns_resolver) + + # `cls_annotations` is only used to determine if an annotation comes from a parent class + cls_annotations = _typing_extra.safe_get_annotations(cls) + + fields: dict[str, FieldInfo] = {} + + class_vars: set[str] = set() + for ann_name, (ann_type, evaluated) in type_hints.items(): + if ann_name == 'model_config': + # We never want to treat `model_config` as a field + # Note: we may need to change this logic if/when we introduce a `BareModel` class with no + # protected namespaces (where `model_config` might be allowed as a field name) + continue + + _check_protected_namespaces( + protected_namespaces=config_wrapper.protected_namespaces, + ann_name=ann_name, + bases=bases, + cls_name=cls.__name__, + ) + + if _typing_extra.is_classvar_annotation(ann_type): + class_vars.add(ann_name) + continue + + assigned_value = getattr(cls, ann_name, PydanticUndefined) + if assigned_value is not PydanticUndefined and ( + # One of the deprecated instance methods was used as a field name (e.g. `dict()`): + any(getattr(BaseModel_, depr_name, None) is assigned_value for depr_name in _deprecated_method_names) + # One of the deprecated class methods was used as a field name (e.g. `schema()`): + or ( + hasattr(assigned_value, '__func__') + and any( + getattr(getattr(BaseModel_, depr_name, None), '__func__', None) is assigned_value.__func__ # pyright: ignore[reportAttributeAccessIssue] + for depr_name in _deprecated_classmethod_names + ) + ) + ): + # Then `assigned_value` would be the method, even though no default was specified: + assigned_value = PydanticUndefined + + if not is_valid_field_name(ann_name): + continue + if cls.__pydantic_root_model__ and ann_name != 'root': + raise NameError( + f"Unexpected field with name {ann_name!r}; only 'root' is allowed as a field of a `RootModel`" + ) + + for base in bases: + if hasattr(base, ann_name): + if ann_name not in cls_annotations: + # Don't warn when a field exists in a parent class but has not been defined in the current class + continue + + # when building a generic model with `MyModel[int]`, the generic_origin check makes sure we don't get + # "... shadows an attribute" warnings + generic_origin = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') + if base is generic_origin: + # Don't warn when "shadowing" of attributes in parametrized generics + continue + + dataclass_fields = { + field.name for field in (dataclasses.fields(base) if dataclasses.is_dataclass(base) else ()) + } + if ann_name in dataclass_fields: + # Don't warn when inheriting stdlib dataclasses whose fields are "shadowed" by defaults being set + # on the class instance. + continue + + warnings.warn( + f'Field name "{ann_name}" in "{cls.__qualname__}" shadows an attribute in parent ' + f'"{base.__qualname__}"', + UserWarning, + stacklevel=4, + ) + + if assigned_value is PydanticUndefined: # no assignment, just a plain annotation + if ann_name in cls_annotations or ann_name not in parent_fields_lookup: + # field is either: + # - present in the current model's annotations (and *not* from parent classes) + # - not found on any base classes; this seems to be caused by fields not getting + # generated due to models not being fully defined while initializing recursive models. + # Nothing stops us from just creating a `FieldInfo` for this type hint, so we do this. + field_info = FieldInfo_.from_annotation(ann_type, _source=AnnotationSource.CLASS) + field_info._original_annotation = ann_type + if not evaluated: + field_info._complete = False + # Store the original annotation that should be used to rebuild + # the field info later: + else: + # The field was present on one of the (possibly multiple) base classes, we make a copy directly from it. + parent_field_info = parent_fields_lookup[ann_name]._copy() + + # The only case where substituting the type variables is relevant (i.e. when `typevars_map` is not empty) + # is when a generic class is parameterized (e.g. `MyGenericModel[int, str]`), which creates a new class object + # (unlike the stdlib genercis that create a generic alias). In this case, we are guaranteed to only have to copy + # from the origin/parent model (e.g. `MyGenericModel`). + if typevars_map: + field_info = _recreate_field_info( + parent_field_info, ns_resolver=ns_resolver, typevars_map=typevars_map, lenient=True + ) + else: + field_info = parent_field_info + + else: # An assigned value is present (either the default value, or a `Field()` function) + if isinstance(assigned_value, FieldInfo_) and ismethoddescriptor(assigned_value.default): + # `assigned_value` was fetched using `getattr`, which triggers a call to `__get__` + # for descriptors, so we do the same if the `= field(default=...)` form is used. + # Note that we only do this for method descriptors for now, we might want to + # extend this to any descriptor in the future (by simply checking for + # `hasattr(assigned_value.default, '__get__')`). + default = assigned_value.default.__get__(None, cls) + assigned_value.default = default + assigned_value._attributes_set['default'] = default + + field_info = FieldInfo_.from_annotated_attribute(ann_type, assigned_value, _source=AnnotationSource.CLASS) + + # Store the original annotation and assignment value that could be used to rebuild the field info later. + field_info._original_assignment = assigned_value + field_info._original_annotation = ann_type + if not evaluated: + field_info._complete = False + elif 'final' in field_info._qualifiers and not field_info.is_required(): + warnings.warn( + f'Annotation {ann_name!r} is marked as final and has a default value. Pydantic treats {ann_name!r} as a ' + 'class variable, but it will be considered as a normal field in V3 to be aligned with dataclasses. If you ' + f'still want {ann_name!r} to be considered as a class variable, annotate it as: `ClassVar[] = .`', + category=PydanticDeprecatedSince211, + # Incorrect when `create_model` is used, but the chance that final with a default is used is low in that case: + stacklevel=4, + ) + class_vars.add(ann_name) + continue + + # attributes which are fields are removed from the class namespace: + # 1. To match the behaviour of annotation-only fields + # 2. To avoid false positives in the NameError check above + try: + delattr(cls, ann_name) + except AttributeError: + pass # indicates the attribute was on a parent class + + # Use cls.__dict__['__pydantic_decorators__'] instead of cls.__pydantic_decorators__ + # to make sure the decorators have already been built for this exact class + decorators: DecoratorInfos = cls.__dict__['__pydantic_decorators__'] + if ann_name in decorators.computed_fields: + raise TypeError( + f'Field {ann_name!r} of class {cls.__name__!r} overrides symbol of same name in a parent class. ' + 'This override with a computed_field is incompatible.' + ) + fields[ann_name] = field_info + + if field_info._complete: + # If not complete, this will be called in `rebuild_model_fields()`: + update_field_from_config(config_wrapper, ann_name, field_info) + + if config_wrapper.use_attribute_docstrings: + _update_fields_from_docstrings(cls, fields) + + pydantic_extra_info: PydanticExtraInfo | None = None + if '__pydantic_extra__' in type_hints: + ann, complete = type_hints['__pydantic_extra__'] + pydantic_extra_info = PydanticExtraInfo( + annotation=ann, + complete=complete, + ) + + return fields, pydantic_extra_info, class_vars + + +def rebuild_model_fields( + cls: type[BaseModel], + *, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + typevars_map: Mapping[TypeVar, Any], +) -> tuple[dict[str, FieldInfo], PydanticExtraInfo | None]: + """Rebuild the (already present) model fields by trying to reevaluate annotations. + + This function should be called whenever a model with incomplete fields is encountered. + + Returns: + A two-tuple, the first element being the rebuilt fields, the second element being + the rebuild `PydanticExtraInfo` instance, if available. + + Raises: + NameError: If one of the annotations failed to evaluate. + + Note: + This function *doesn't* mutate the model fields in place, as it can be called during + schema generation, where you don't want to mutate other model's fields. + """ + rebuilt_fields: dict[str, FieldInfo] = {} + with ns_resolver.push(cls): + for f_name, field_info in cls.__pydantic_fields__.items(): + if field_info._complete: + rebuilt_fields[f_name] = field_info + else: + new_field = _recreate_field_info( + field_info, ns_resolver=ns_resolver, typevars_map=typevars_map, lenient=False + ) + update_field_from_config(config_wrapper, f_name, new_field) + rebuilt_fields[f_name] = new_field + + if cls.__pydantic_extra_info__ is not None and not cls.__pydantic_extra_info__.complete: + rebuilt_extra_info = PydanticExtraInfo( + annotation=_typing_extra.eval_type( + cls.__pydantic_extra_info__.annotation, *ns_resolver.types_namespace + ), + complete=True, + ) + else: + rebuilt_extra_info = cls.__pydantic_extra_info__ + + return rebuilt_fields, rebuilt_extra_info + + +def _recreate_field_info( + field_info: FieldInfo, + ns_resolver: NsResolver, + typevars_map: Mapping[TypeVar, Any], + *, + lenient: bool, +) -> FieldInfo: + FieldInfo_ = import_cached_field_info() + + existing_desc = field_info.description + if lenient: + ann = _generics.replace_types(field_info._original_annotation, typevars_map) + ann, evaluated = _typing_extra.try_eval_type( + ann, + *ns_resolver.types_namespace, + ) + else: + # Not the best pattern, maybe we could ship our own `eval_type()`, + # that would replace the type variables on the fly during evaluation. + ann = _typing_extra.eval_type( + field_info._original_annotation, + *ns_resolver.types_namespace, + ) + ann = _generics.replace_types(ann, typevars_map) + ann = _typing_extra.eval_type( + ann, + *ns_resolver.types_namespace, + ) + evaluated = True + + if (assign := field_info._original_assignment) is PydanticUndefined: + new_field = FieldInfo_.from_annotation(ann, _source=AnnotationSource.CLASS) + else: + new_field = FieldInfo_.from_annotated_attribute(ann, assign, _source=AnnotationSource.CLASS) + new_field._original_assignment = assign + new_field._original_annotation = ann + # The description might come from the docstring if `use_attribute_docstrings` was `True`: + new_field.description = new_field.description if new_field.description is not None else existing_desc + if not evaluated: + new_field._complete = False + + return new_field + + +def collect_dataclass_fields( + cls: type[StandardDataclass], + *, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver | None = None, + typevars_map: dict[Any, Any] | None = None, +) -> dict[str, FieldInfo]: + """Collect the fields of a dataclass. + + Args: + cls: dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting dataclass annotations. + Defaults to an empty instance. + typevars_map: A dictionary mapping type variables to their concrete types. + + Returns: + The dataclass fields. + """ + FieldInfo_ = import_cached_field_info() + + fields: dict[str, FieldInfo] = {} + ns_resolver = ns_resolver or NsResolver() + dataclass_fields = cls.__dataclass_fields__ + + # The logic here is similar to `_typing_extra.get_cls_type_hints`, + # although we do it manually as stdlib dataclasses already have annotations + # collected in each class: + for base in reversed(cls.__mro__): + if not dataclasses.is_dataclass(base): + continue + + with ns_resolver.push(base): + for ann_name, dataclass_field in dataclass_fields.items(): + base_anns = _typing_extra.safe_get_annotations(base) + + if ann_name not in base_anns: + # `__dataclass_fields__`contains every field, even the ones from base classes. + # Only collect the ones defined on `base`. + continue + + globalns, localns = ns_resolver.types_namespace + ann_type, evaluated = _typing_extra.try_eval_type(dataclass_field.type, globalns, localns) + + if _typing_extra.is_classvar_annotation(ann_type): + continue + + if ( + not dataclass_field.init + and dataclass_field.default is dataclasses.MISSING + and dataclass_field.default_factory is dataclasses.MISSING + ): + # TODO: We should probably do something with this so that validate_assignment behaves properly + # Issue: https://github.com/pydantic/pydantic/issues/5470 + continue + + if isinstance(dataclass_field.default, FieldInfo_): + if dataclass_field.default.init_var: + if dataclass_field.default.init is False: + raise PydanticUserError( + f'Dataclass field {ann_name} has init=False and init_var=True, but these are mutually exclusive.', + code='clashing-init-and-init-var', + ) + + # TODO: same note as above re validate_assignment + continue + field_info = FieldInfo_.from_annotated_attribute( + ann_type, dataclass_field.default, _source=AnnotationSource.DATACLASS + ) + field_info._original_assignment = dataclass_field.default + else: + field_info = FieldInfo_.from_annotated_attribute( + ann_type, dataclass_field, _source=AnnotationSource.DATACLASS + ) + field_info._original_assignment = dataclass_field + + if not evaluated: + field_info._complete = False + field_info._original_annotation = ann_type + + fields[ann_name] = field_info + update_field_from_config(config_wrapper, ann_name, field_info) + + if field_info.default is not PydanticUndefined and isinstance( + getattr(cls, ann_name, field_info), FieldInfo_ + ): + # We need this to fix the default when the "default" from __dataclass_fields__ is a pydantic.FieldInfo + setattr(cls, ann_name, field_info.default) + + if typevars_map: + for field in fields.values(): + # We don't pass any ns, as `field.annotation` + # was already evaluated. TODO: is this method relevant? + # Can't we juste use `_generics.replace_types`? + field.apply_typevars_map(typevars_map) + + if config_wrapper.use_attribute_docstrings: + _update_fields_from_docstrings( + cls, + fields, + # We can't rely on the (more reliable) frame inspection method + # for stdlib dataclasses: + use_inspect=not hasattr(cls, '__is_pydantic_dataclass__'), + ) + + return fields + + +def rebuild_dataclass_fields( + cls: type[PydanticDataclass], + *, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + typevars_map: Mapping[TypeVar, Any], +) -> dict[str, FieldInfo]: + """Rebuild the (already present) dataclass fields by trying to reevaluate annotations. + + This function should be called whenever a dataclass with incomplete fields is encountered. + + Raises: + NameError: If one of the annotations failed to evaluate. + + Note: + This function *doesn't* mutate the dataclass fields in place, as it can be called during + schema generation, where you don't want to mutate other dataclass's fields. + """ + FieldInfo_ = import_cached_field_info() + + rebuilt_fields: dict[str, FieldInfo] = {} + with ns_resolver.push(cls): + for f_name, field_info in cls.__pydantic_fields__.items(): + if field_info._complete: + rebuilt_fields[f_name] = field_info + else: + existing_desc = field_info.description + ann = _typing_extra.eval_type( + field_info._original_annotation, + *ns_resolver.types_namespace, + ) + ann = _generics.replace_types(ann, typevars_map) + new_field = FieldInfo_.from_annotated_attribute( + ann, + field_info._original_assignment, + _source=AnnotationSource.DATACLASS, + ) + + # The description might come from the docstring if `use_attribute_docstrings` was `True`: + new_field.description = new_field.description if new_field.description is not None else existing_desc + update_field_from_config(config_wrapper, f_name, new_field) + rebuilt_fields[f_name] = new_field + + return rebuilt_fields + + +def is_valid_field_name(name: str) -> bool: + return not name.startswith('_') + + +def is_valid_privateattr_name(name: str) -> bool: + return name.startswith('_') and not name.startswith('__') + + +def takes_validated_data_argument( + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any], +) -> TypeIs[Callable[[dict[str, Any]], Any]]: + """Whether the provided default factory callable has a validated data parameter.""" + try: + sig = _typing_extra.signature_no_eval(default_factory) + except (ValueError, TypeError): + # `inspect.signature` might not be able to infer a signature, e.g. with C objects. + # In this case, we assume no data argument is present: + return False + + parameters = list(sig.parameters.values()) + + return len(parameters) == 1 and can_be_positional(parameters[0]) and parameters[0].default is Parameter.empty + + +def resolve_default_value( + default: Any, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None, + *, + validated_data: dict[str, Any] | None = None, + call_default_factory: bool = False, +) -> Any: + """Resolve the default value using either a static default or a default_factory.""" + from ._utils import smart_deepcopy + + if default_factory is None: + return smart_deepcopy(default) + if call_default_factory: + if takes_validated_data_argument(default_factory=default_factory): + fac = cast('Callable[[dict[str, Any]], Any]', default_factory) + if validated_data is None: + raise ValueError( + "The default factory requires the 'validated_data' argument, which was not provided when calling 'get_default()'." + ) + return fac(validated_data) + else: + fac = cast('Callable[[], Any]', default_factory) + return fac() + + return PydanticUndefined diff --git a/source/target-vendors/cp312/pydantic/_internal/_forward_ref.py b/source/target-vendors/cp312/pydantic/_internal/_forward_ref.py new file mode 100644 index 0000000..231f81d --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_forward_ref.py @@ -0,0 +1,23 @@ +from __future__ import annotations as _annotations + +from dataclasses import dataclass +from typing import Union + + +@dataclass +class PydanticRecursiveRef: + type_ref: str + + __name__ = 'PydanticRecursiveRef' + __hash__ = object.__hash__ + + def __call__(self) -> None: + """Defining __call__ is necessary for the `typing` module to let you use an instance of + this class as the result of resolving a standard ForwardRef. + """ + + def __or__(self, other): + return Union[self, other] # type: ignore + + def __ror__(self, other): + return Union[other, self] # type: ignore diff --git a/source/target-vendors/cp312/pydantic/_internal/_generate_schema.py b/source/target-vendors/cp312/pydantic/_internal/_generate_schema.py new file mode 100644 index 0000000..98fae40 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_generate_schema.py @@ -0,0 +1,2934 @@ +"""Convert python types to pydantic-core schema.""" + +from __future__ import annotations as _annotations + +import collections.abc +import dataclasses +import datetime +import inspect +import os +import pathlib +import re +import sys +import typing +import warnings +from collections.abc import Generator, Iterable, Iterator, Mapping +from contextlib import contextmanager +from copy import copy +from decimal import Decimal +from enum import Enum +from fractions import Fraction +from functools import partial +from inspect import Parameter, _ParameterKind +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from itertools import chain +from operator import attrgetter +from types import FunctionType, GenericAlias, LambdaType, MethodType +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Final, + ForwardRef, + Literal, + TypeVar, + Union, + cast, + overload, +) +from uuid import UUID +from zoneinfo import ZoneInfo + +import typing_extensions +from pydantic_core import ( + MISSING, + CoreSchema, + MultiHostUrl, + PydanticCustomError, + PydanticSerializationUnexpectedValue, + PydanticUndefined, + Url, + core_schema, + to_jsonable_python, +) +from typing_extensions import TypeAlias, TypeAliasType, get_args, get_origin, is_typeddict +from typing_inspection import typing_objects +from typing_inspection.introspection import AnnotationSource, get_literal_values, is_union_origin + +from ..aliases import AliasChoices, AliasPath +from ..annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler +from ..config import ConfigDict, JsonDict, JsonEncoder, JsonSchemaExtraCallable +from ..errors import ( + PydanticForbiddenQualifier, + PydanticInvalidForJsonSchema, + PydanticSchemaGenerationError, + PydanticUndefinedAnnotation, + PydanticUserError, +) +from ..functional_validators import AfterValidator, BeforeValidator, FieldValidatorModes, PlainValidator, WrapValidator +from ..json_schema import JsonSchemaValue +from ..version import version_short +from ..warnings import ( + ArbitraryTypeWarning, + PydanticDeprecatedSince20, + TypedDictExtraConfigWarning, + UnsupportedFieldAttributeWarning, +) +from . import _decorators, _discriminated_union, _known_annotated_metadata, _repr, _typing_extra +from ._config import ConfigWrapper, ConfigWrapperStack +from ._core_metadata import CoreMetadata, update_core_metadata +from ._core_utils import ( + get_ref, + get_type_ref, + is_list_like_schema_with_items_schema, +) +from ._decorators import ( + Decorator, + DecoratorInfos, + FieldSerializerDecoratorInfo, + FieldValidatorDecoratorInfo, + ModelSerializerDecoratorInfo, + ModelValidatorDecoratorInfo, + RootValidatorDecoratorInfo, + ValidatorDecoratorInfo, + get_attribute_from_bases, + inspect_field_serializer, + inspect_model_serializer, + inspect_validator, +) +from ._docs_extraction import extract_docstrings_from_cls +from ._fields import ( + collect_dataclass_fields, + rebuild_dataclass_fields, + rebuild_model_fields, + takes_validated_data_argument, + update_field_from_config, +) +from ._forward_ref import PydanticRecursiveRef +from ._generics import get_standard_typevars_map, replace_types +from ._import_utils import import_cached_base_model, import_cached_field_info +from ._mock_val_ser import MockCoreSchema +from ._namespace_utils import NamespacesTuple, NsResolver +from ._schema_gather import MissingDefinitionError, gather_schemas_for_cleaning +from ._schema_generation_shared import CallbackGetCoreSchemaHandler +from ._utils import lenient_issubclass, smart_deepcopy + +if TYPE_CHECKING: + from ..fields import ComputedFieldInfo, FieldInfo + from ..main import BaseModel + from ..types import Discriminator + from ._dataclasses import StandardDataclass + from ._schema_generation_shared import GetJsonSchemaFunction + +_SUPPORTS_TYPEDDICT = sys.version_info >= (3, 12) + +FieldDecoratorInfo = Union[ValidatorDecoratorInfo, FieldValidatorDecoratorInfo, FieldSerializerDecoratorInfo] +FieldDecoratorInfoType = TypeVar('FieldDecoratorInfoType', bound=FieldDecoratorInfo) +AnyFieldDecorator = Union[ + Decorator[ValidatorDecoratorInfo], + Decorator[FieldValidatorDecoratorInfo], + Decorator[FieldSerializerDecoratorInfo], +] + +ModifyCoreSchemaWrapHandler: TypeAlias = GetCoreSchemaHandler +GetCoreSchemaFunction: TypeAlias = Callable[[Any, ModifyCoreSchemaWrapHandler], core_schema.CoreSchema] +ParametersCallback: TypeAlias = "Callable[[int, str, Any], Literal['skip'] | None]" + +TUPLE_TYPES: list[type] = [typing.Tuple, tuple] # noqa: UP006 +LIST_TYPES: list[type] = [typing.List, list, collections.abc.MutableSequence] # noqa: UP006 +SET_TYPES: list[type] = [typing.Set, set, collections.abc.MutableSet] # noqa: UP006 +FROZEN_SET_TYPES: list[type] = [typing.FrozenSet, frozenset, collections.abc.Set] # noqa: UP006 +DICT_TYPES: list[type] = [typing.Dict, dict] # noqa: UP006 +IP_TYPES: list[type] = [IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network] +SEQUENCE_TYPES: list[type] = [typing.Sequence, collections.abc.Sequence] +ITERABLE_TYPES: list[type] = [typing.Iterable, collections.abc.Iterable, typing.Generator, collections.abc.Generator] +TYPE_TYPES: list[type] = [typing.Type, type] # noqa: UP006 +PATTERN_TYPES: list[type] = [typing.Pattern, re.Pattern] +PATH_TYPES: list[type] = [ + os.PathLike, + pathlib.Path, + pathlib.PurePath, + pathlib.PosixPath, + pathlib.PurePosixPath, + pathlib.PureWindowsPath, +] +MAPPING_TYPES = [ + typing.Mapping, + typing.MutableMapping, + collections.abc.Mapping, + collections.abc.MutableMapping, + collections.OrderedDict, + typing_extensions.OrderedDict, + typing.DefaultDict, # noqa: UP006 + collections.defaultdict, +] +COUNTER_TYPES = [collections.Counter, typing.Counter] +DEQUE_TYPES: list[type] = [collections.deque, typing.Deque] # noqa: UP006 + +# Note: This does not play very well with type checkers. For example, +# `a: LambdaType = lambda x: x` will raise a type error by Pyright. +ValidateCallSupportedTypes = Union[ + LambdaType, + FunctionType, + MethodType, + partial, +] + +VALIDATE_CALL_SUPPORTED_TYPES = get_args(ValidateCallSupportedTypes) +UNSUPPORTED_STANDALONE_FIELDINFO_ATTRIBUTES: list[tuple[str, Any]] = [ + ('alias', None), + ('validation_alias', None), + ('serialization_alias', None), + # will be set if any alias is set, so disable it to avoid double warnings: + # 'alias_priority', + ('default', PydanticUndefined), + ('default_factory', None), + ('exclude', None), + ('deprecated', None), + ('repr', True), + ('validate_default', None), + ('frozen', None), + ('init', None), + ('init_var', None), + ('kw_only', None), +] +"""`FieldInfo` attributes (and their default value) that can't be used outside of a model (e.g. in a type adapter or a PEP 695 type alias).""" + +_mode_to_validator: dict[ + FieldValidatorModes, type[BeforeValidator | AfterValidator | PlainValidator | WrapValidator] +] = {'before': BeforeValidator, 'after': AfterValidator, 'plain': PlainValidator, 'wrap': WrapValidator} + + +def check_validator_fields_against_field_name( + info: FieldDecoratorInfo, + field: str, +) -> bool: + """Check if field name is in validator fields. + + Args: + info: The field info. + field: The field name to check. + + Returns: + `True` if field name is in validator fields, `False` otherwise. + """ + fields = info.fields + return '*' in fields or field in fields + + +def check_decorator_fields_exist(decorators: Iterable[AnyFieldDecorator], fields: Iterable[str]) -> None: + """Check if the defined fields in decorators exist in `fields` param. + + It ignores the check for a decorator if the decorator has `*` as field or `check_fields=False`. + + Args: + decorators: An iterable of decorators. + fields: An iterable of fields name. + + Raises: + PydanticUserError: If one of the field names does not exist in `fields` param. + """ + fields = set(fields) + for dec in decorators: + if '*' in dec.info.fields: + continue + if dec.info.check_fields is False: + continue + for field in dec.info.fields: + if field not in fields: + raise PydanticUserError( + f'Decorators defined with incorrect fields: {dec.cls_ref}.{dec.cls_var_name}' + " (use check_fields=False if you're inheriting from the model and intended this)", + code='decorator-missing-field', + ) + + +def filter_field_decorator_info_by_field( + validator_functions: Iterable[Decorator[FieldDecoratorInfoType]], field: str +) -> list[Decorator[FieldDecoratorInfoType]]: + return [dec for dec in validator_functions if check_validator_fields_against_field_name(dec.info, field)] + + +def apply_each_item_validators( + schema: core_schema.CoreSchema, + each_item_validators: list[Decorator[ValidatorDecoratorInfo]], +) -> core_schema.CoreSchema: + # This V1 compatibility shim should eventually be removed + + # fail early if each_item_validators is empty + if not each_item_validators: + return schema + + # push down any `each_item=True` validators + # note that this won't work for any Annotated types that get wrapped by a function validator + # but that's okay because that didn't exist in V1 + if schema['type'] == 'nullable': + schema['schema'] = apply_each_item_validators(schema['schema'], each_item_validators) + return schema + elif schema['type'] == 'tuple': + if (variadic_item_index := schema.get('variadic_item_index')) is not None: + schema['items_schema'][variadic_item_index] = apply_validators( + schema['items_schema'][variadic_item_index], + each_item_validators, + ) + elif is_list_like_schema_with_items_schema(schema): + inner_schema = schema.get('items_schema', core_schema.any_schema()) + schema['items_schema'] = apply_validators(inner_schema, each_item_validators) + elif schema['type'] == 'dict': + inner_schema = schema.get('values_schema', core_schema.any_schema()) + schema['values_schema'] = apply_validators(inner_schema, each_item_validators) + else: + raise TypeError( + f'`@validator(..., each_item=True)` cannot be applied to fields with a schema of {schema["type"]}' + ) + return schema + + +def _extract_json_schema_info_from_field_info( + info: FieldInfo | ComputedFieldInfo, +) -> tuple[JsonDict | None, JsonDict | JsonSchemaExtraCallable | None]: + json_schema_updates = { + 'title': info.title, + 'description': info.description, + 'deprecated': bool(info.deprecated) or info.deprecated == '' or None, + 'examples': to_jsonable_python(info.examples), + } + json_schema_updates = {k: v for k, v in json_schema_updates.items() if v is not None} + return (json_schema_updates or None, info.json_schema_extra) + + +JsonEncoders = dict[type[Any], JsonEncoder] + + +def _add_custom_serialization_from_json_encoders( + json_encoders: JsonEncoders | None, tp: Any, schema: CoreSchema +) -> CoreSchema: + """Iterate over the json_encoders and add the first matching encoder to the schema. + + Args: + json_encoders: A dictionary of types and their encoder functions. + tp: The type to check for a matching encoder. + schema: The schema to add the encoder to. + """ + if not json_encoders: + return schema + if 'serialization' in schema: + return schema + # Check the class type and its superclasses for a matching encoder + # Decimal.__class__.__mro__ (and probably other cases) doesn't include Decimal itself + # if the type is a GenericAlias (e.g. from list[int]) we need to use __class__ instead of .__mro__ + for base in (tp, *getattr(tp, '__mro__', tp.__class__.__mro__)[:-1]): + encoder = json_encoders.get(base) + if encoder is None: + continue + + warnings.warn( + f'`json_encoders` is deprecated. See https://docs.pydantic.dev/{version_short()}/concepts/serialization/#custom-serializers for alternatives', + PydanticDeprecatedSince20, + ) + + # TODO: in theory we should check that the schema accepts a serialization key + schema['serialization'] = core_schema.plain_serializer_function_ser_schema(encoder, when_used='json') + return schema + + return schema + + +GENERATE_SCHEMA_ERRORS = ( + PydanticForbiddenQualifier, + PydanticInvalidForJsonSchema, + PydanticSchemaGenerationError, + PydanticUndefinedAnnotation, +) +"""Errors raised during core schema generation. This does *not* include `InvalidSchemaError`, which is raised during schema cleaning.""" + + +class InvalidSchemaError(Exception): + """The core schema is invalid.""" + + +class GenerateSchema: + """Generate core schema for a Pydantic model, dataclass and types like `str`, `datetime`, ... .""" + + __slots__ = ( + '_config_wrapper_stack', + '_ns_resolver', + '_typevars_map', + 'field_name_stack', + 'model_type_stack', + 'defs', + ) + + def __init__( + self, + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver | None = None, + typevars_map: Mapping[TypeVar, Any] | None = None, + ) -> None: + # we need a stack for recursing into nested models + self._config_wrapper_stack = ConfigWrapperStack(config_wrapper) + self._ns_resolver = ns_resolver or NsResolver() + self._typevars_map = typevars_map + self.field_name_stack = _FieldNameStack() + self.model_type_stack = _ModelTypeStack() + self.defs = _Definitions() + + def __init_subclass__(cls) -> None: + super().__init_subclass__() + warnings.warn( + 'Subclassing `GenerateSchema` is not supported. The API is highly subject to change in minor versions.', + UserWarning, + stacklevel=2, + ) + + @property + def _config_wrapper(self) -> ConfigWrapper: + return self._config_wrapper_stack.tail + + @property + def _types_namespace(self) -> NamespacesTuple: + return self._ns_resolver.types_namespace + + @property + def _arbitrary_types(self) -> bool: + return self._config_wrapper.arbitrary_types_allowed + + # the following methods can be overridden but should be considered + # unstable / private APIs + def _list_schema(self, items_type: Any) -> CoreSchema: + return core_schema.list_schema(self.generate_schema(items_type)) + + def _dict_schema(self, keys_type: Any, values_type: Any) -> CoreSchema: + return core_schema.dict_schema(self.generate_schema(keys_type), self.generate_schema(values_type)) + + def _set_schema(self, items_type: Any) -> CoreSchema: + return core_schema.set_schema(self.generate_schema(items_type)) + + def _frozenset_schema(self, items_type: Any) -> CoreSchema: + return core_schema.frozenset_schema(self.generate_schema(items_type)) + + def _enum_schema(self, enum_type: type[Enum]) -> CoreSchema: + cases: list[Any] = list(enum_type.__members__.values()) + + enum_ref = get_type_ref(enum_type) + description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) + if ( + description == 'An enumeration.' + ): # This is the default value provided by enum.EnumMeta.__new__; don't use it + description = None + js_updates = {'title': enum_type.__name__, 'description': description} + js_updates = {k: v for k, v in js_updates.items() if v is not None} + + sub_type: Literal['str', 'int', 'float'] | None = None + if issubclass(enum_type, int): + sub_type = 'int' + value_ser_type: core_schema.SerSchema = core_schema.simple_ser_schema('int') + elif issubclass(enum_type, str): + # this handles `StrEnum` (3.11 only), and also `Foobar(str, Enum)` + sub_type = 'str' + value_ser_type = core_schema.simple_ser_schema('str') + elif issubclass(enum_type, float): + sub_type = 'float' + value_ser_type = core_schema.simple_ser_schema('float') + else: + # TODO this is an ugly hack, how do we trigger an Any schema for serialization? + value_ser_type = core_schema.plain_serializer_function_ser_schema(lambda x: x) + + if cases: + + def get_json_schema(schema: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + json_schema = handler(schema) + original_schema = handler.resolve_ref_schema(json_schema) + original_schema.update(js_updates) + return json_schema + + # we don't want to add the missing to the schema if it's the default one + default_missing = getattr(enum_type._missing_, '__func__', None) is Enum._missing_.__func__ # pyright: ignore[reportFunctionMemberAccess] + enum_schema = core_schema.enum_schema( + enum_type, + cases, + sub_type=sub_type, + missing=None if default_missing else enum_type._missing_, + ref=enum_ref, + metadata={'pydantic_js_functions': [get_json_schema]}, + ) + + if self._config_wrapper.use_enum_values: + enum_schema = core_schema.no_info_after_validator_function( + attrgetter('value'), enum_schema, serialization=value_ser_type + ) + + return enum_schema + + else: + + def get_json_schema_no_cases(_, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + json_schema = handler(core_schema.enum_schema(enum_type, cases, sub_type=sub_type, ref=enum_ref)) + original_schema = handler.resolve_ref_schema(json_schema) + original_schema.update(js_updates) + return json_schema + + # Use an isinstance check for enums with no cases. + # The most important use case for this is creating TypeVar bounds for generics that should + # be restricted to enums. This is more consistent than it might seem at first, since you can only + # subclass enum.Enum (or subclasses of enum.Enum) if all parent classes have no cases. + # We use the get_json_schema function when an Enum subclass has been declared with no cases + # so that we can still generate a valid json schema. + return core_schema.is_instance_schema( + enum_type, + metadata={'pydantic_js_functions': [get_json_schema_no_cases]}, + ) + + def _ip_schema(self, tp: Any) -> CoreSchema: + from ._validators import IP_VALIDATOR_LOOKUP, IpType + + ip_type_json_schema_format: dict[type[IpType], str] = { + IPv4Address: 'ipv4', + IPv4Network: 'ipv4network', + IPv4Interface: 'ipv4interface', + IPv6Address: 'ipv6', + IPv6Network: 'ipv6network', + IPv6Interface: 'ipv6interface', + } + + def ser_ip(ip: Any, info: core_schema.SerializationInfo) -> str | IpType: + if not isinstance(ip, (tp, str)): + raise PydanticSerializationUnexpectedValue( + f"Expected `{tp}` but got `{type(ip)}` with value `'{ip}'` - serialized value may not be as expected." + ) + if info.mode == 'python': + return ip + return str(ip) + + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.no_info_plain_validator_function(IP_VALIDATOR_LOOKUP[tp]), + strict_schema=core_schema.json_or_python_schema( + json_schema=core_schema.no_info_after_validator_function(tp, core_schema.str_schema()), + python_schema=core_schema.is_instance_schema(tp), + ), + serialization=core_schema.plain_serializer_function_ser_schema(ser_ip, info_arg=True, when_used='always'), + metadata={ + 'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': ip_type_json_schema_format[tp]}] + }, + ) + + def _path_schema(self, tp: Any, path_type: Any) -> CoreSchema: + if tp is os.PathLike and (path_type not in {str, bytes} and not typing_objects.is_any(path_type)): + raise PydanticUserError( + '`os.PathLike` can only be used with `str`, `bytes` or `Any`', code='schema-for-unknown-type' + ) + + path_constructor = pathlib.PurePath if tp is os.PathLike else tp + strict_inner_schema = ( + core_schema.bytes_schema(strict=True) if (path_type is bytes) else core_schema.str_schema(strict=True) + ) + lax_inner_schema = core_schema.bytes_schema() if (path_type is bytes) else core_schema.str_schema() + + def path_validator(input_value: str | bytes) -> os.PathLike[Any]: # type: ignore + try: + if path_type is bytes: + if isinstance(input_value, bytes): + try: + input_value = input_value.decode() + except UnicodeDecodeError as e: + raise PydanticCustomError('bytes_type', 'Input must be valid bytes') from e + else: + raise PydanticCustomError('bytes_type', 'Input must be bytes') + elif not isinstance(input_value, str): + raise PydanticCustomError('path_type', 'Input is not a valid path') + + return path_constructor(input_value) # type: ignore + except TypeError as e: + raise PydanticCustomError('path_type', 'Input is not a valid path') from e + + def ser_path(path: Any, info: core_schema.SerializationInfo) -> str | os.PathLike[Any]: + if not isinstance(path, (tp, str)): + raise PydanticSerializationUnexpectedValue( + f"Expected `{tp}` but got `{type(path)}` with value `'{path}'` - serialized value may not be as expected." + ) + if info.mode == 'python': + return path + return str(path) + + instance_schema = core_schema.json_or_python_schema( + json_schema=core_schema.no_info_after_validator_function(path_validator, lax_inner_schema), + python_schema=core_schema.is_instance_schema(tp), + ) + + schema = core_schema.lax_or_strict_schema( + lax_schema=core_schema.union_schema( + [ + instance_schema, + core_schema.no_info_after_validator_function(path_validator, strict_inner_schema), + ], + custom_error_type='path_type', + custom_error_message=f'Input is not a valid path for {tp}', + ), + strict_schema=instance_schema, + serialization=core_schema.plain_serializer_function_ser_schema(ser_path, info_arg=True, when_used='always'), + metadata={'pydantic_js_functions': [lambda source, handler: {**handler(source), 'format': 'path'}]}, + ) + return schema + + def _deque_schema(self, items_type: Any) -> CoreSchema: + from ._serializers import serialize_sequence_via_list + from ._validators import deque_validator + + item_type_schema = self.generate_schema(items_type) + + # we have to use a lax list schema here, because we need to validate the deque's + # items via a list schema, but it's ok if the deque itself is not a list + list_schema = core_schema.list_schema(item_type_schema, strict=False) + + check_instance = core_schema.json_or_python_schema( + json_schema=list_schema, + python_schema=core_schema.is_instance_schema(collections.deque, cls_repr='Deque'), + ) + + lax_schema = core_schema.no_info_wrap_validator_function(deque_validator, list_schema) + + return core_schema.lax_or_strict_schema( + lax_schema=lax_schema, + strict_schema=core_schema.chain_schema([check_instance, lax_schema]), + serialization=core_schema.wrap_serializer_function_ser_schema( + serialize_sequence_via_list, schema=item_type_schema, info_arg=True + ), + ) + + def _mapping_schema(self, tp: Any, keys_type: Any, values_type: Any) -> CoreSchema: + from ._validators import MAPPING_ORIGIN_MAP, defaultdict_validator, get_defaultdict_default_default_factory + + mapped_origin = MAPPING_ORIGIN_MAP[tp] + keys_schema = self.generate_schema(keys_type) + with warnings.catch_warnings(): + # We kind of abused `Field()` default factories to be able to specify + # the `defaultdict`'s `default_factory`. As a consequence, we get warnings + # as normally `FieldInfo.default_factory` is unsupported in the context where + # `Field()` is used and our only solution is to ignore them (note that this might + # wrongfully ignore valid warnings, e.g. if the `value_type` is a PEP 695 type alias + # with unsupported metadata). + warnings.simplefilter('ignore', category=UnsupportedFieldAttributeWarning) + values_schema = self.generate_schema(values_type) + dict_schema = core_schema.dict_schema(keys_schema, values_schema, strict=False) + + if mapped_origin is dict: + schema = dict_schema + else: + check_instance = core_schema.json_or_python_schema( + json_schema=dict_schema, + python_schema=core_schema.is_instance_schema(mapped_origin), + ) + + if tp is collections.defaultdict: + default_default_factory = get_defaultdict_default_default_factory(values_type) + coerce_instance_wrap = partial( + core_schema.no_info_wrap_validator_function, + partial(defaultdict_validator, default_default_factory=default_default_factory), + ) + else: + coerce_instance_wrap = partial(core_schema.no_info_after_validator_function, mapped_origin) + + lax_schema = coerce_instance_wrap(dict_schema) + strict_schema = core_schema.chain_schema([check_instance, lax_schema]) + + schema = core_schema.lax_or_strict_schema( + lax_schema=lax_schema, + strict_schema=strict_schema, + serialization=core_schema.wrap_serializer_function_ser_schema( + lambda v, h: h(v), schema=dict_schema, info_arg=False + ), + ) + + return schema + + def _fraction_schema(self) -> CoreSchema: + """Support for [`fractions.Fraction`][fractions.Fraction].""" + from ._validators import fraction_validator + + # TODO: note, this is a fairly common pattern, re lax / strict for attempted type coercion, + # can we use a helper function to reduce boilerplate? + return core_schema.lax_or_strict_schema( + lax_schema=core_schema.no_info_plain_validator_function(fraction_validator), + strict_schema=core_schema.json_or_python_schema( + json_schema=core_schema.no_info_plain_validator_function(fraction_validator), + python_schema=core_schema.is_instance_schema(Fraction), + ), + # use str serialization to guarantee round trip behavior + serialization=core_schema.to_string_ser_schema(when_used='always'), + metadata={'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'fraction'}]}, + ) + + def _arbitrary_type_schema(self, tp: Any) -> CoreSchema: + if not isinstance(tp, type): + warnings.warn( + f'{tp!r} is not a Python type (it may be an instance of an object),' + ' Pydantic will allow any object with no validation since we cannot even' + ' enforce that the input is an instance of the given type.' + ' To get rid of this error wrap the type with `pydantic.SkipValidation`.', + ArbitraryTypeWarning, + ) + return core_schema.any_schema() + return core_schema.is_instance_schema(tp) + + def _unknown_type_schema(self, obj: Any) -> CoreSchema: + raise PydanticSchemaGenerationError( + f'Unable to generate pydantic-core schema for {obj!r}. ' + 'Set `arbitrary_types_allowed=True` in the model_config to ignore this error' + ' or implement `__get_pydantic_core_schema__` on your type to fully support it.' + '\n\nIf you got this error by calling handler() within' + ' `__get_pydantic_core_schema__` then you likely need to call' + ' `handler.generate_schema()` since we do not call' + ' `__get_pydantic_core_schema__` on `` otherwise to avoid infinite recursion.' + ) + + def _apply_discriminator_to_union( + self, schema: CoreSchema, discriminator: str | Discriminator | None + ) -> CoreSchema: + if discriminator is None: + return schema + try: + return _discriminated_union.apply_discriminator( + schema, + discriminator, + self.defs._definitions, + ) + except _discriminated_union.MissingDefinitionForUnionRef: + # defer until defs are resolved + _discriminated_union.set_discriminator_in_metadata( + schema, + discriminator, + ) + return schema + + def clean_schema(self, schema: CoreSchema) -> CoreSchema: + return self.defs.finalize_schema(schema) + + def _add_js_function(self, metadata_schema: CoreSchema, js_function: Callable[..., Any]) -> None: + metadata = metadata_schema.get('metadata', {}) + pydantic_js_functions = metadata.setdefault('pydantic_js_functions', []) + # because of how we generate core schemas for nested generic models + # we can end up adding `BaseModel.__get_pydantic_json_schema__` multiple times + # this check may fail to catch duplicates if the function is a `functools.partial` + # or something like that, but if it does it'll fail by inserting the duplicate + if js_function not in pydantic_js_functions: + pydantic_js_functions.append(js_function) + metadata_schema['metadata'] = metadata + + def generate_schema( + self, + obj: Any, + ) -> core_schema.CoreSchema: + """Generate core schema. + + Args: + obj: The object to generate core schema for. + + Returns: + The generated core schema. + + Raises: + PydanticUndefinedAnnotation: + If it is not possible to evaluate forward reference. + PydanticSchemaGenerationError: + If it is not possible to generate pydantic-core schema. + TypeError: + - If `alias_generator` returns a disallowed type (must be str, AliasPath or AliasChoices). + - If V1 style validator with `each_item=True` applied on a wrong field. + PydanticUserError: + - If `typing.TypedDict` is used instead of `typing_extensions.TypedDict` on Python < 3.12. + - If `__modify_schema__` method is used instead of `__get_pydantic_json_schema__`. + """ + schema = self._generate_schema_from_get_schema_method(obj, obj) + + if schema is None: + schema = self._generate_schema_inner(obj) + + metadata_js_function = _extract_get_pydantic_json_schema(obj) + if metadata_js_function is not None: + metadata_schema = resolve_original_schema(schema, self.defs) + if metadata_schema: + self._add_js_function(metadata_schema, metadata_js_function) + + schema = _add_custom_serialization_from_json_encoders(self._config_wrapper.json_encoders, obj, schema) + + return schema + + def _model_schema(self, cls: type[BaseModel]) -> core_schema.CoreSchema: + """Generate schema for a Pydantic model.""" + BaseModel_ = import_cached_base_model() + + with self.defs.get_schema_or_ref(cls) as (model_ref, maybe_schema): + if maybe_schema is not None: + return maybe_schema + + schema = cls.__dict__.get('__pydantic_core_schema__') + if schema is not None and not isinstance(schema, MockCoreSchema): + if schema['type'] == 'definitions': + schema = self.defs.unpack_definitions(schema) + ref = get_ref(schema) + if ref: + return self.defs.create_definition_reference_schema(schema) + else: + return schema + + config_wrapper = ConfigWrapper(cls.model_config, check=False) + + with self._config_wrapper_stack.push(config_wrapper), self._ns_resolver.push(cls): + core_config = self._config_wrapper.core_config(title=cls.__name__) + + if cls.__pydantic_fields_complete__ or cls is BaseModel_: + fields = getattr(cls, '__pydantic_fields__', {}) + extra_info = getattr(cls, '__pydantic_extra_info__', None) + else: + if '__pydantic_fields__' not in cls.__dict__: + # This happens when we have a loop in the schema generation: + # class Base[T](BaseModel): + # t: T + # + # class Other(BaseModel): + # b: 'Base[Other]' + # When we build fields for `Other`, we evaluate the forward annotation. + # At this point, `Other` doesn't have the model fields set. We create + # `Base[Other]`; model fields are successfully built, and we try to generate + # a schema for `t: Other`. As `Other.__pydantic_fields__` aren't set, we abort. + raise PydanticUndefinedAnnotation( + name=cls.__name__, + message=f'Class {cls.__name__!r} is not defined', + ) + try: + fields, extra_info = rebuild_model_fields( + cls, + config_wrapper=self._config_wrapper, + ns_resolver=self._ns_resolver, + typevars_map=self._typevars_map or {}, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + decorators = cls.__pydantic_decorators__ + computed_fields = decorators.computed_fields + check_decorator_fields_exist( + chain( + decorators.field_validators.values(), + decorators.field_serializers.values(), + decorators.validators.values(), + ), + {*fields.keys(), *computed_fields.keys()}, + ) + + model_validators = decorators.model_validators.values() + + extras_schema = None + extras_keys_schema = None + if core_config.get('extra_fields_behavior') == 'allow' and extra_info is not None: + tp = get_origin(extra_info.annotation) + if tp not in DICT_TYPES: + raise PydanticSchemaGenerationError( + 'The type annotation for `__pydantic_extra__` must be `dict[str, ...]`' + ) + # See the comments in `_get_args_resolving_forward_refs()` for why we need + # to re-evaluate the annotation: + extra_keys_type, extra_items_type = self._get_args_resolving_forward_refs( + extra_info.annotation, + required=True, + ) + if extra_keys_type is not str: + extras_keys_schema = self.generate_schema(extra_keys_type) + if not typing_objects.is_any(extra_items_type): + extras_schema = self.generate_schema(extra_items_type) + + generic_origin: type[BaseModel] | None = getattr(cls, '__pydantic_generic_metadata__', {}).get('origin') + + if cls.__pydantic_root_model__: + inner_schema, metadata = self._common_field_schema('root', fields['root'], decorators) + if cls.__doc__ and metadata.get('pydantic_js_updates', {}).get('description'): + # This is a bit of a leaky abstraction, but as the model docstring takes priority + # over the root field's description, we need to override it here. This can't be done + # in the JSON Schema generation logic because the metadata's `pydantic_js_updates` are + # applied last, and overrides any value previously set (so the description set from the + # docstring in `GenerateJsonSchema._update_class_schema()` is overridden): + update_core_metadata( + metadata, pydantic_js_updates={'description': inspect.cleandoc(cls.__doc__)} + ) + + inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') + model_schema = core_schema.model_schema( + cls, + inner_schema, + generic_origin=generic_origin, + custom_init=getattr(cls, '__pydantic_custom_init__', None), + root_model=True, + post_init=getattr(cls, '__pydantic_post_init__', None), + config=core_config, + ref=model_ref, + metadata=metadata, + ) + else: + fields_schema: core_schema.CoreSchema = core_schema.model_fields_schema( + {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()}, + computed_fields=[ + self._computed_field_schema(d, decorators.field_serializers) + for d in computed_fields.values() + ], + extras_schema=extras_schema, + extras_keys_schema=extras_keys_schema, + model_name=cls.__name__, + ) + inner_schema = apply_validators(fields_schema, decorators.root_validators.values()) + inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') + + model_schema = core_schema.model_schema( + cls, + inner_schema, + generic_origin=generic_origin, + custom_init=getattr(cls, '__pydantic_custom_init__', None), + root_model=False, + post_init=getattr(cls, '__pydantic_post_init__', None), + config=core_config, + ref=model_ref, + ) + + schema = self._apply_model_serializers(model_schema, decorators.model_serializers.values()) + schema = apply_model_validators(schema, model_validators, 'outer') + return self.defs.create_definition_reference_schema(schema) + + def _resolve_self_type(self, obj: Any) -> Any: + obj = self.model_type_stack.get() + if obj is None: + raise PydanticUserError('`typing.Self` is invalid in this context', code='invalid-self-type') + return obj + + def _generate_schema_from_get_schema_method(self, obj: Any, source: Any) -> core_schema.CoreSchema | None: + BaseModel_ = import_cached_base_model() + + get_schema = getattr(obj, '__get_pydantic_core_schema__', None) + is_base_model_get_schema = ( + getattr(get_schema, '__func__', None) is BaseModel_.__get_pydantic_core_schema__.__func__ # pyright: ignore[reportFunctionMemberAccess] + ) + + if ( + get_schema is not None + # BaseModel.__get_pydantic_core_schema__ is defined for backwards compatibility, + # to allow existing code to call `super().__get_pydantic_core_schema__` in Pydantic + # model that overrides `__get_pydantic_core_schema__`. However, it raises a deprecation + # warning stating that the method will be removed, and during the core schema gen we actually + # don't call the method: + and not is_base_model_get_schema + ): + # Some referenceable types might have a `__get_pydantic_core_schema__` method + # defined on it by users (e.g. on a dataclass). This generally doesn't play well + # as these types are already recognized by the `GenerateSchema` class and isn't ideal + # as we might end up calling `get_schema_or_ref` (expensive) on types that are actually + # not referenceable: + with self.defs.get_schema_or_ref(obj) as (_, maybe_schema): + if maybe_schema is not None: + return maybe_schema + + if obj is source: + ref_mode = 'unpack' + else: + ref_mode = 'to-def' + schema = get_schema( + source, CallbackGetCoreSchemaHandler(self._generate_schema_inner, self, ref_mode=ref_mode) + ) + if schema['type'] == 'definitions': + schema = self.defs.unpack_definitions(schema) + + ref = get_ref(schema) + if ref: + return self.defs.create_definition_reference_schema(schema) + + # Note: if schema is of type `'definition-ref'`, we might want to copy it as a + # safety measure (because these are inlined in place -- i.e. mutated directly) + return schema + + if get_schema is None and (validators := getattr(obj, '__get_validators__', None)) is not None: + from pydantic.v1 import BaseModel as BaseModelV1 + + if issubclass(obj, BaseModelV1): + warnings.warn( + f'Mixing V1 models and V2 models (or constructs, like `TypeAdapter`) is not supported. Please upgrade `{obj.__name__}` to V2.', + UserWarning, + ) + else: + warnings.warn( + '`__get_validators__` is deprecated and will be removed, use `__get_pydantic_core_schema__` instead.', + PydanticDeprecatedSince20, + ) + return core_schema.chain_schema([core_schema.with_info_plain_validator_function(v) for v in validators()]) + + def _resolve_forward_ref(self, obj: Any) -> Any: + # we assume that types_namespace has the target of forward references in its scope, + # but this could fail, for example, if calling Validator on an imported type which contains + # forward references to other types only defined in the module from which it was imported + # `Validator(SomeImportedTypeAliasWithAForwardReference)` + # or the equivalent for BaseModel + # class Model(BaseModel): + # x: SomeImportedTypeAliasWithAForwardReference + try: + obj = _typing_extra.eval_type_backport(obj, *self._types_namespace) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + # if obj is still a ForwardRef, it means we can't evaluate it, raise PydanticUndefinedAnnotation + if isinstance(obj, ForwardRef): + raise PydanticUndefinedAnnotation(obj.__forward_arg__, f'Unable to evaluate forward reference {obj}') + + if self._typevars_map: + obj = replace_types(obj, self._typevars_map) + + return obj + + @overload + def _get_args_resolving_forward_refs(self, obj: Any, required: Literal[True]) -> tuple[Any, ...]: ... + + @overload + def _get_args_resolving_forward_refs(self, obj: Any) -> tuple[Any, ...] | None: ... + + def _get_args_resolving_forward_refs(self, obj: Any, required: bool = False) -> tuple[Any, ...] | None: + args = get_args(obj) + if args: + if isinstance(obj, GenericAlias): + # PEP 585 generic aliases don't convert args to ForwardRefs, unlike `typing.List/Dict` etc. + # This was fixed in https://github.com/python/cpython/pull/30900 (Python 3.11). + # TODO: this shouldn't be necessary (probably even this `_get_args_resolving_forward_refs()` function) + # once we drop support for Python 3.10 *or* if we implement our own `typing._eval_type()` implementation. + args = (_typing_extra._make_forward_ref(a) if isinstance(a, str) else a for a in args) + args = tuple(self._resolve_forward_ref(a) if isinstance(a, ForwardRef) else a for a in args) + elif required: # pragma: no cover + raise TypeError(f'Expected {obj} to have generic parameters but it had none') + return args + + def _get_first_arg_or_any(self, obj: Any) -> Any: + args = self._get_args_resolving_forward_refs(obj) + if not args: + return Any + return args[0] + + def _get_first_two_args_or_any(self, obj: Any) -> tuple[Any, Any]: + args = self._get_args_resolving_forward_refs(obj) + if not args: + return (Any, Any) + if len(args) < 2: + origin = get_origin(obj) + raise TypeError(f'Expected two type arguments for {origin}, got 1') + return args[0], args[1] + + def _generate_schema_inner(self, obj: Any) -> core_schema.CoreSchema: + if typing_objects.is_self(obj): + obj = self._resolve_self_type(obj) + + if typing_objects.is_annotated(get_origin(obj)): + return self._annotated_schema(obj) + + if isinstance(obj, dict): + # we assume this is already a valid schema + return obj # type: ignore[return-value] + + if isinstance(obj, str): + obj = ForwardRef(obj) + + if isinstance(obj, ForwardRef): + return self.generate_schema(self._resolve_forward_ref(obj)) + + BaseModel = import_cached_base_model() + + if lenient_issubclass(obj, BaseModel): + with self.model_type_stack.push(obj): + return self._model_schema(obj) + + if isinstance(obj, PydanticRecursiveRef): + return core_schema.definition_reference_schema(schema_ref=obj.type_ref) + + return self.match_type(obj) + + def match_type(self, obj: Any) -> core_schema.CoreSchema: # noqa: C901 + """Main mapping of types to schemas. + + The general structure is a series of if statements starting with the simple cases + (non-generic primitive types) and then handling generics and other more complex cases. + + Each case either generates a schema directly, calls into a public user-overridable method + (like `GenerateSchema.tuple_variable_schema`) or calls into a private method that handles some + boilerplate before calling into the user-facing method (e.g. `GenerateSchema._tuple_schema`). + + The idea is that we'll evolve this into adding more and more user facing methods over time + as they get requested and we figure out what the right API for them is. + """ + if obj is str: + return core_schema.str_schema() + elif obj is bytes: + return core_schema.bytes_schema() + elif obj is int: + return core_schema.int_schema() + elif obj is float: + return core_schema.float_schema() + elif obj is bool: + return core_schema.bool_schema() + elif obj is complex: + return core_schema.complex_schema() + elif typing_objects.is_any(obj) or obj is object: + return core_schema.any_schema() + elif obj is datetime.date: + return core_schema.date_schema() + elif obj is datetime.datetime: + return core_schema.datetime_schema() + elif obj is datetime.time: + return core_schema.time_schema() + elif obj is datetime.timedelta: + return core_schema.timedelta_schema() + elif obj is Decimal: + return core_schema.decimal_schema() + elif obj is UUID: + return core_schema.uuid_schema() + elif obj is Url: + return core_schema.url_schema() + elif obj is Fraction: + return self._fraction_schema() + elif obj is MultiHostUrl: + return core_schema.multi_host_url_schema() + elif obj is None or obj is _typing_extra.NoneType: + return core_schema.none_schema() + if obj is MISSING: + return core_schema.missing_sentinel_schema() + elif obj in IP_TYPES: + return self._ip_schema(obj) + elif obj in TUPLE_TYPES: + return self._tuple_schema(obj) + elif obj in LIST_TYPES: + return self._list_schema(Any) + elif obj in SET_TYPES: + return self._set_schema(Any) + elif obj in FROZEN_SET_TYPES: + return self._frozenset_schema(Any) + elif obj in SEQUENCE_TYPES: + return self._sequence_schema(Any) + elif obj in ITERABLE_TYPES: + return self._iterable_schema(obj) + elif obj in DICT_TYPES: + return self._dict_schema(Any, Any) + elif obj in PATH_TYPES: + return self._path_schema(obj, Any) + elif obj in DEQUE_TYPES: + return self._deque_schema(Any) + elif obj in MAPPING_TYPES: + return self._mapping_schema(obj, Any, Any) + elif obj in COUNTER_TYPES: + return self._mapping_schema(obj, Any, int) + elif typing_objects.is_typealiastype(obj): + return self._type_alias_type_schema(obj) + elif obj is type: + return self._type_schema() + elif _typing_extra.is_callable(obj): + return core_schema.callable_schema() + elif typing_objects.is_literal(get_origin(obj)): + return self._literal_schema(obj) + elif is_typeddict(obj): + return self._typed_dict_schema(obj, None) + elif inspect.isclass(obj) and issubclass(obj, Enum): + # NOTE: this must come before the `is_namedtuple()` check as enums values + # can be namedtuples: + return self._enum_schema(obj) + elif _typing_extra.is_namedtuple(obj): + return self._namedtuple_schema(obj, None) + elif typing_objects.is_newtype(obj): + # NewType, can't use isinstance because it fails <3.10 + return self.generate_schema(obj.__supertype__) + elif obj in PATTERN_TYPES: + return self._pattern_schema(obj) + elif _typing_extra.is_hashable(obj): + return self._hashable_schema() + elif isinstance(obj, typing.TypeVar): + return self._unsubstituted_typevar_schema(obj) + elif _typing_extra.is_finalvar(obj): + if obj is Final: + return core_schema.any_schema() + return self.generate_schema( + self._get_first_arg_or_any(obj), + ) + elif isinstance(obj, VALIDATE_CALL_SUPPORTED_TYPES): + return self._call_schema(obj) # pyright: ignore[reportArgumentType] + elif obj is ZoneInfo: + return self._zoneinfo_schema() + + # dataclasses.is_dataclass coerces dc instances to types, but we only handle + # the case of a dc type here + if dataclasses.is_dataclass(obj): + return self._dataclass_schema(obj, None) # pyright: ignore[reportArgumentType] + + origin = get_origin(obj) + if origin is not None: + return self._match_generic_type(obj, origin) + + if self._arbitrary_types: + return self._arbitrary_type_schema(obj) + return self._unknown_type_schema(obj) + + def _match_generic_type(self, obj: Any, origin: Any) -> CoreSchema: # noqa: C901 + # Need to handle generic dataclasses before looking for the schema properties because attribute accesses + # on _GenericAlias delegate to the origin type, so lose the information about the concrete parametrization + # As a result, currently, there is no way to cache the schema for generic dataclasses. This may be possible + # to resolve by modifying the value returned by `Generic.__class_getitem__`, but that is a dangerous game. + if dataclasses.is_dataclass(origin): + return self._dataclass_schema(obj, origin) # pyright: ignore[reportArgumentType] + if _typing_extra.is_namedtuple(origin): + return self._namedtuple_schema(obj, origin) + + schema = self._generate_schema_from_get_schema_method(origin, obj) + if schema is not None: + return schema + + if typing_objects.is_typealiastype(origin): + return self._type_alias_type_schema(obj) + elif is_union_origin(origin): + return self._union_schema(obj) + elif origin in TUPLE_TYPES: + return self._tuple_schema(obj) + elif origin in LIST_TYPES: + return self._list_schema(self._get_first_arg_or_any(obj)) + elif origin in SET_TYPES: + return self._set_schema(self._get_first_arg_or_any(obj)) + elif origin in FROZEN_SET_TYPES: + return self._frozenset_schema(self._get_first_arg_or_any(obj)) + elif origin in DICT_TYPES: + return self._dict_schema(*self._get_first_two_args_or_any(obj)) + elif origin in PATH_TYPES: + return self._path_schema(origin, self._get_first_arg_or_any(obj)) + elif origin in DEQUE_TYPES: + return self._deque_schema(self._get_first_arg_or_any(obj)) + elif origin in MAPPING_TYPES: + return self._mapping_schema(origin, *self._get_first_two_args_or_any(obj)) + elif origin in COUNTER_TYPES: + return self._mapping_schema(origin, self._get_first_arg_or_any(obj), int) + elif is_typeddict(origin): + return self._typed_dict_schema(obj, origin) + elif origin in TYPE_TYPES: + return self._subclass_schema(obj) + elif origin in SEQUENCE_TYPES: + return self._sequence_schema(self._get_first_arg_or_any(obj)) + elif origin in ITERABLE_TYPES: + return self._iterable_schema(obj) + elif origin in PATTERN_TYPES: + return self._pattern_schema(obj) + + if self._arbitrary_types: + return self._arbitrary_type_schema(origin) + return self._unknown_type_schema(obj) + + def _generate_td_field_schema( + self, + name: str, + field_info: FieldInfo, + decorators: DecoratorInfos, + *, + required: bool = True, + ) -> core_schema.TypedDictField: + """Prepare a TypedDictField to represent a model or typeddict field.""" + schema, metadata = self._common_field_schema(name, field_info, decorators) + return core_schema.typed_dict_field( + schema, + required=False if not field_info.is_required() else required, + serialization_exclude=field_info.exclude, + validation_alias=_convert_to_aliases(field_info.validation_alias), + serialization_alias=field_info.serialization_alias, + serialization_exclude_if=field_info.exclude_if, + metadata=metadata, + ) + + def _generate_md_field_schema( + self, + name: str, + field_info: FieldInfo, + decorators: DecoratorInfos, + ) -> core_schema.ModelField: + """Prepare a ModelField to represent a model field.""" + schema, metadata = self._common_field_schema(name, field_info, decorators) + return core_schema.model_field( + schema, + serialization_exclude=field_info.exclude, + validation_alias=_convert_to_aliases(field_info.validation_alias), + serialization_alias=field_info.serialization_alias, + serialization_exclude_if=field_info.exclude_if, + frozen=field_info.frozen, + metadata=metadata, + ) + + def _generate_dc_field_schema( + self, + name: str, + field_info: FieldInfo, + decorators: DecoratorInfos, + ) -> core_schema.DataclassField: + """Prepare a DataclassField to represent the parameter/field, of a dataclass.""" + schema, metadata = self._common_field_schema(name, field_info, decorators) + return core_schema.dataclass_field( + name, + schema, + init=field_info.init, + init_only=field_info.init_var or None, + kw_only=None if field_info.kw_only else False, + serialization_exclude=field_info.exclude, + validation_alias=_convert_to_aliases(field_info.validation_alias), + serialization_alias=field_info.serialization_alias, + serialization_exclude_if=field_info.exclude_if, + frozen=field_info.frozen, + metadata=metadata, + ) + + def _common_field_schema( # C901 + self, name: str, field_info: FieldInfo, decorators: DecoratorInfos + ) -> tuple[CoreSchema, dict[str, Any]]: + source_type, annotations = field_info.annotation, field_info.metadata + + def set_discriminator(schema: CoreSchema) -> CoreSchema: + schema = self._apply_discriminator_to_union(schema, field_info.discriminator) + return schema + + # Convert `@field_validator` decorators to `Before/After/Plain/WrapValidator` instances: + validators_from_decorators = [ + _mode_to_validator[decorator.info.mode]._from_decorator(decorator) + for decorator in filter_field_decorator_info_by_field(decorators.field_validators.values(), name) + ] + + with self.field_name_stack.push(name): + if field_info.discriminator is not None: + schema = self._apply_annotations( + source_type, annotations + validators_from_decorators, transform_inner_schema=set_discriminator + ) + else: + schema = self._apply_annotations( + source_type, + annotations + validators_from_decorators, + ) + + # This V1 compatibility shim should eventually be removed + # push down any `each_item=True` validators + # note that this won't work for any Annotated types that get wrapped by a function validator + # but that's okay because that didn't exist in V1 + this_field_validators = filter_field_decorator_info_by_field(decorators.validators.values(), name) + if _validators_require_validate_default(this_field_validators): + field_info.validate_default = True + each_item_validators = [v for v in this_field_validators if v.info.each_item is True] + this_field_validators = [v for v in this_field_validators if v not in each_item_validators] + schema = apply_each_item_validators(schema, each_item_validators) + + schema = apply_validators(schema, this_field_validators) + + # the default validator needs to go outside of any other validators + # so that it is the topmost validator for the field validator + # which uses it to check if the field has a default value or not + if not field_info.is_required(): + schema = wrap_default(field_info, schema) + + schema = self._apply_field_serializers( + schema, filter_field_decorator_info_by_field(decorators.field_serializers.values(), name) + ) + + pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(field_info) + core_metadata: dict[str, Any] = {} + update_core_metadata( + core_metadata, pydantic_js_updates=pydantic_js_updates, pydantic_js_extra=pydantic_js_extra + ) + + return schema, core_metadata + + def _union_schema(self, union_type: Any) -> core_schema.CoreSchema: + """Generate schema for a Union.""" + args = self._get_args_resolving_forward_refs(union_type, required=True) + choices: list[CoreSchema] = [] + nullable = False + for arg in args: + if arg is None or arg is _typing_extra.NoneType: + nullable = True + else: + choices.append(self.generate_schema(arg)) + + if len(choices) == 1: + s = choices[0] + else: + choices_with_tags: list[CoreSchema | tuple[CoreSchema, str]] = [] + for choice in choices: + tag = cast(CoreMetadata, choice.get('metadata', {})).get('pydantic_internal_union_tag_key') + if tag is not None: + choices_with_tags.append((choice, tag)) + else: + choices_with_tags.append(choice) + s = core_schema.union_schema(choices_with_tags) + + if nullable: + s = core_schema.nullable_schema(s) + return s + + def _type_alias_type_schema(self, obj: TypeAliasType) -> CoreSchema: + with self.defs.get_schema_or_ref(obj) as (ref, maybe_schema): + if maybe_schema is not None: + return maybe_schema + + origin: TypeAliasType = get_origin(obj) or obj + typevars_map = get_standard_typevars_map(obj) + + with self._ns_resolver.push(origin): + try: + annotation = _typing_extra.eval_type(origin.__value__, *self._types_namespace) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + annotation = replace_types(annotation, typevars_map) + schema = self.generate_schema(annotation) + assert schema['type'] != 'definitions' + schema['ref'] = ref # type: ignore + return self.defs.create_definition_reference_schema(schema) + + def _literal_schema(self, literal_type: Any) -> CoreSchema: + """Generate schema for a Literal.""" + expected = list(get_literal_values(literal_type, type_check=False, unpack_type_aliases='eager')) + assert expected, f'literal "expected" cannot be empty, obj={literal_type}' + schema = core_schema.literal_schema(expected) + + if self._config_wrapper.use_enum_values and any(isinstance(v, Enum) for v in expected): + schema = core_schema.no_info_after_validator_function( + lambda v: v.value if isinstance(v, Enum) else v, schema + ) + + return schema + + def _typed_dict_schema(self, typed_dict_cls: Any, origin: Any) -> core_schema.CoreSchema: + """Generate a core schema for a `TypedDict` class. + + To be able to build a `DecoratorInfos` instance for the `TypedDict` class (which will include + validators, serializers, etc.), we need to have access to the original bases of the class + (see https://docs.python.org/3/library/types.html#types.get_original_bases). + However, the `__orig_bases__` attribute was only added in 3.12 (https://github.com/python/cpython/pull/103698). + + For this reason, we require Python 3.12 (or using the `typing_extensions` backport). + """ + FieldInfo = import_cached_field_info() + + with ( + self.model_type_stack.push(typed_dict_cls), + self.defs.get_schema_or_ref(typed_dict_cls) as ( + typed_dict_ref, + maybe_schema, + ), + ): + if maybe_schema is not None: + return maybe_schema + + typevars_map = get_standard_typevars_map(typed_dict_cls) + if origin is not None: + typed_dict_cls = origin + + if not _SUPPORTS_TYPEDDICT and type(typed_dict_cls).__module__ == 'typing': + raise PydanticUserError( + 'Please use `typing_extensions.TypedDict` instead of `typing.TypedDict` on Python < 3.12.', + code='typed-dict-version', + ) + + try: + # if a typed dictionary class doesn't have config, we use the parent's config, hence a default of `None` + # see https://github.com/pydantic/pydantic/issues/10917 + config: ConfigDict | None = get_attribute_from_bases(typed_dict_cls, '__pydantic_config__') + except AttributeError: + config = None + + with self._config_wrapper_stack.push(config): + core_config = self._config_wrapper.core_config(title=typed_dict_cls.__name__) + + required_keys: frozenset[str] = typed_dict_cls.__required_keys__ + + fields: dict[str, core_schema.TypedDictField] = {} + + decorators = DecoratorInfos.build(typed_dict_cls, replace_wrapped_methods=False) + decorators.update_from_config(self._config_wrapper) + + if self._config_wrapper.use_attribute_docstrings: + field_docstrings = extract_docstrings_from_cls(typed_dict_cls, use_inspect=True) + else: + field_docstrings = None + + try: + annotations = _typing_extra.get_cls_type_hints(typed_dict_cls, ns_resolver=self._ns_resolver) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + readonly_fields: list[str] = [] + + for field_name, annotation in annotations.items(): + field_info = FieldInfo.from_annotation(annotation, _source=AnnotationSource.TYPED_DICT) + field_info.annotation = replace_types(field_info.annotation, typevars_map) + + required = ( + field_name in required_keys or 'required' in field_info._qualifiers + ) and 'not_required' not in field_info._qualifiers + if 'read_only' in field_info._qualifiers: + readonly_fields.append(field_name) + + if ( + field_docstrings is not None + and field_info.description is None + and field_name in field_docstrings + ): + field_info.description = field_docstrings[field_name] + update_field_from_config(self._config_wrapper, field_name, field_info) + + fields[field_name] = self._generate_td_field_schema( + field_name, field_info, decorators, required=required + ) + + if readonly_fields: + fields_repr = ', '.join(repr(f) for f in readonly_fields) + plural = len(readonly_fields) >= 2 + warnings.warn( + f'Item{"s" if plural else ""} {fields_repr} on TypedDict class {typed_dict_cls.__name__!r} ' + f'{"are" if plural else "is"} using the `ReadOnly` qualifier. Pydantic will not protect items ' + 'from any mutation on dictionary instances.', + UserWarning, + ) + + extra_behavior: core_schema.ExtraBehavior = 'ignore' + extras_schema: CoreSchema | None = None # For 'allow', equivalent to `Any` - no validation performed. + + # `__closed__` is `None` when not specified (equivalent to `False`): + is_closed = bool(getattr(typed_dict_cls, '__closed__', False)) + extra_items = getattr(typed_dict_cls, '__extra_items__', typing_extensions.NoExtraItems) + if is_closed: + extra_behavior = 'forbid' + extras_schema = None + elif not typing_objects.is_noextraitems(extra_items): + extra_behavior = 'allow' + extras_schema = self.generate_schema(replace_types(extra_items, typevars_map)) + + if (config_extra := self._config_wrapper.extra) in ('allow', 'forbid'): + if is_closed and config_extra == 'allow': + warnings.warn( + f"TypedDict class {typed_dict_cls.__qualname__!r} is closed, but 'extra' configuration " + "is set to `'allow'`. The 'extra' configuration value will be ignored.", + category=TypedDictExtraConfigWarning, + ) + elif not typing_objects.is_noextraitems(extra_items) and config_extra == 'forbid': + warnings.warn( + f"TypedDict class {typed_dict_cls.__qualname__!r} allows extra items, but 'extra' configuration " + "is set to `'forbid'`. The 'extra' configuration value will be ignored.", + category=TypedDictExtraConfigWarning, + ) + else: + extra_behavior = config_extra + + td_schema = core_schema.typed_dict_schema( + fields, + cls=typed_dict_cls, + computed_fields=[ + self._computed_field_schema(d, decorators.field_serializers) + for d in decorators.computed_fields.values() + ], + extra_behavior=extra_behavior, + extras_schema=extras_schema, + ref=typed_dict_ref, + config=core_config, + ) + + schema = self._apply_model_serializers(td_schema, decorators.model_serializers.values()) + schema = apply_model_validators(schema, decorators.model_validators.values(), 'all') + return self.defs.create_definition_reference_schema(schema) + + def _namedtuple_schema(self, namedtuple_cls: Any, origin: Any) -> core_schema.CoreSchema: + """Generate schema for a NamedTuple.""" + with ( + self.model_type_stack.push(namedtuple_cls), + self.defs.get_schema_or_ref(namedtuple_cls) as ( + namedtuple_ref, + maybe_schema, + ), + ): + if maybe_schema is not None: + return maybe_schema + typevars_map = get_standard_typevars_map(namedtuple_cls) + if origin is not None: + namedtuple_cls = origin + + try: + annotations = _typing_extra.get_cls_type_hints(namedtuple_cls, ns_resolver=self._ns_resolver) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + # Filter annotations to only include fields that are actually in the NamedTuple + # (as subclassing an existing NamedTuple is not supported yet - see https://github.com/python/typing/issues/427) + # and use `Any` if no annotation exist (i.e. when using `collections.namedtuple()`). + annotations = {field_name: annotations.get(field_name, Any) for field_name in namedtuple_cls._fields} + + if typevars_map: + annotations = { + field_name: replace_types(annotation, typevars_map) + for field_name, annotation in annotations.items() + } + + arguments_schema = core_schema.arguments_schema( + [ + self._generate_parameter_schema( + field_name, + annotation, + source=AnnotationSource.NAMED_TUPLE, + default=namedtuple_cls._field_defaults.get(field_name, Parameter.empty), + ) + for field_name, annotation in annotations.items() + ], + metadata={'pydantic_js_prefer_positional_arguments': True}, + ) + schema = core_schema.call_schema(arguments_schema, namedtuple_cls, ref=namedtuple_ref) + return self.defs.create_definition_reference_schema(schema) + + def _generate_parameter_schema( + self, + name: str, + annotation: type[Any], + source: AnnotationSource, + default: Any = Parameter.empty, + mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] | None = None, + ) -> core_schema.ArgumentsParameter: + """Generate the definition of a field in a namedtuple or a parameter in a function signature. + + This definition is meant to be used for the `'arguments'` core schema, which will be replaced + in V3 by the `'arguments-v3`'. + """ + FieldInfo = import_cached_field_info() + + if default is Parameter.empty: + field = FieldInfo.from_annotation(annotation, _source=source) + else: + field = FieldInfo.from_annotated_attribute(annotation, default, _source=source) + + assert field.annotation is not None, 'field.annotation should not be None when generating a schema' + update_field_from_config(self._config_wrapper, name, field) + + with self.field_name_stack.push(name): + schema = self._apply_annotations( + field.annotation, + [field], + # Because we pass `field` as metadata above (required for attributes relevant for + # JSON Scheme generation), we need to ignore the potential warnings about `FieldInfo` + # attributes that will not be used: + check_unsupported_field_info_attributes=False, + ) + + if not field.is_required(): + schema = wrap_default(field, schema) + + parameter_schema = core_schema.arguments_parameter( + name, + schema, + mode=mode, + alias=_convert_to_aliases(field.validation_alias), + ) + + return parameter_schema + + def _generate_parameter_v3_schema( + self, + name: str, + annotation: Any, + source: AnnotationSource, + mode: Literal[ + 'positional_only', + 'positional_or_keyword', + 'keyword_only', + 'var_args', + 'var_kwargs_uniform', + 'var_kwargs_unpacked_typed_dict', + ], + default: Any = Parameter.empty, + ) -> core_schema.ArgumentsV3Parameter: + """Generate the definition of a parameter in a function signature. + + This definition is meant to be used for the `'arguments-v3'` core schema, which will replace + the `'arguments`' schema in V3. + """ + FieldInfo = import_cached_field_info() + + if default is Parameter.empty: + field = FieldInfo.from_annotation(annotation, _source=source) + else: + field = FieldInfo.from_annotated_attribute(annotation, default, _source=source) + update_field_from_config(self._config_wrapper, name, field) + + with self.field_name_stack.push(name): + schema = self._apply_annotations( + field.annotation, + [field], + # Because we pass `field` as metadata above (required for attributes relevant for + # JSON Scheme generation), we need to ignore the potential warnings about `FieldInfo` + # attributes that will not be used: + check_unsupported_field_info_attributes=False, + ) + + if not field.is_required(): + schema = wrap_default(field, schema) + + parameter_schema = core_schema.arguments_v3_parameter( + name=name, + schema=schema, + mode=mode, + alias=_convert_to_aliases(field.validation_alias), + ) + + return parameter_schema + + def _tuple_schema(self, tuple_type: Any) -> core_schema.CoreSchema: + """Generate schema for a Tuple, e.g. `tuple[int, str]` or `tuple[int, ...]`.""" + # TODO: do we really need to resolve type vars here? + typevars_map = get_standard_typevars_map(tuple_type) + params = self._get_args_resolving_forward_refs(tuple_type) + + if typevars_map and params: + params = tuple(replace_types(param, typevars_map) for param in params) + + # NOTE: subtle difference: `tuple[()]` gives `params=()`, whereas `typing.Tuple[()]` gives `params=((),)` + # This is only true for <3.11, on Python 3.11+ `typing.Tuple[()]` gives `params=()` + if not params: + if tuple_type in TUPLE_TYPES: + return core_schema.tuple_schema([core_schema.any_schema()], variadic_item_index=0) + else: + # special case for `tuple[()]` which means `tuple[]` - an empty tuple + return core_schema.tuple_schema([]) + elif params[-1] is Ellipsis: + if len(params) == 2: + return core_schema.tuple_schema([self.generate_schema(params[0])], variadic_item_index=0) + else: + # TODO: something like https://github.com/pydantic/pydantic/issues/5952 + raise ValueError('Variable tuples can only have one type') + elif len(params) == 1 and params[0] == (): + # special case for `tuple[()]` which means `tuple[]` - an empty tuple + # NOTE: This conditional can be removed when we drop support for Python 3.10. + return core_schema.tuple_schema([]) + else: + return core_schema.tuple_schema([self.generate_schema(param) for param in params]) + + def _type_schema(self) -> core_schema.CoreSchema: + return core_schema.custom_error_schema( + core_schema.is_instance_schema(type), + custom_error_type='is_type', + custom_error_message='Input should be a type', + ) + + def _zoneinfo_schema(self) -> core_schema.CoreSchema: + """Generate schema for a zone_info.ZoneInfo object""" + from ._validators import validate_str_is_valid_iana_tz + + metadata = {'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'zoneinfo'}]} + return core_schema.no_info_plain_validator_function( + validate_str_is_valid_iana_tz, + serialization=core_schema.to_string_ser_schema(), + metadata=metadata, + ) + + def _union_is_subclass_schema(self, union_type: Any) -> core_schema.CoreSchema: + """Generate schema for `type[Union[X, ...]]`.""" + args = self._get_args_resolving_forward_refs(union_type, required=True) + return core_schema.union_schema([self.generate_schema(type[args]) for args in args]) + + def _subclass_schema(self, type_: Any) -> core_schema.CoreSchema: + """Generate schema for a type, e.g. `type[int]`.""" + type_param = self._get_first_arg_or_any(type_) + + # Assume `type[Annotated[, ...]]` is equivalent to `type[]`: + type_param = _typing_extra.annotated_type(type_param) or type_param + + if typing_objects.is_any(type_param): + return self._type_schema() + elif typing_objects.is_typealiastype(type_param): + return self.generate_schema(type[type_param.__value__]) + elif typing_objects.is_typevar(type_param): + if type_param.__bound__: + if is_union_origin(get_origin(type_param.__bound__)): + return self._union_is_subclass_schema(type_param.__bound__) + return core_schema.is_subclass_schema(type_param.__bound__) + elif type_param.__constraints__: + return core_schema.union_schema([self.generate_schema(type[c]) for c in type_param.__constraints__]) + else: + return self._type_schema() + elif is_union_origin(get_origin(type_param)): + return self._union_is_subclass_schema(type_param) + else: + if typing_objects.is_self(type_param): + type_param = self._resolve_self_type(type_param) + if _typing_extra.is_generic_alias(type_param): + raise PydanticUserError( + 'Subscripting `type[]` with an already parametrized type is not supported. ' + f'Instead of using type[{type_param!r}], use type[{_repr.display_as_type(get_origin(type_param))}].', + code=None, + ) + if not inspect.isclass(type_param): + # when using type[None], this doesn't type convert to type[NoneType], and None isn't a class + # so we handle it manually here + if type_param is None: + return core_schema.is_subclass_schema(_typing_extra.NoneType) + raise TypeError(f'Expected a class, got {type_param!r}') + return core_schema.is_subclass_schema(type_param) + + def _sequence_schema(self, items_type: Any) -> core_schema.CoreSchema: + """Generate schema for a Sequence, e.g. `Sequence[int]`.""" + from ._serializers import serialize_sequence_via_list + + item_type_schema = self.generate_schema(items_type) + list_schema = core_schema.list_schema(item_type_schema) + + json_schema = smart_deepcopy(list_schema) + python_schema = core_schema.is_instance_schema(typing.Sequence, cls_repr='Sequence') + if not typing_objects.is_any(items_type): + from ._validators import sequence_validator + + python_schema = core_schema.chain_schema( + [python_schema, core_schema.no_info_wrap_validator_function(sequence_validator, list_schema)], + ) + + serialization = core_schema.wrap_serializer_function_ser_schema( + serialize_sequence_via_list, schema=item_type_schema, info_arg=True + ) + return core_schema.json_or_python_schema( + json_schema=json_schema, python_schema=python_schema, serialization=serialization + ) + + def _iterable_schema(self, type_: Any) -> core_schema.GeneratorSchema: + """Generate a schema for an `Iterable`.""" + item_type = self._get_first_arg_or_any(type_) + + return core_schema.generator_schema(self.generate_schema(item_type)) + + def _pattern_schema(self, pattern_type: Any) -> core_schema.CoreSchema: + from . import _validators + + metadata = {'pydantic_js_functions': [lambda _1, _2: {'type': 'string', 'format': 'regex'}]} + ser = core_schema.plain_serializer_function_ser_schema( + attrgetter('pattern'), when_used='json', return_schema=core_schema.str_schema() + ) + if pattern_type is typing.Pattern or pattern_type is re.Pattern: + # bare type + return core_schema.no_info_plain_validator_function( + _validators.pattern_either_validator, serialization=ser, metadata=metadata + ) + + param = self._get_args_resolving_forward_refs( + pattern_type, + required=True, + )[0] + if param is str: + return core_schema.no_info_plain_validator_function( + _validators.pattern_str_validator, serialization=ser, metadata=metadata + ) + elif param is bytes: + return core_schema.no_info_plain_validator_function( + _validators.pattern_bytes_validator, serialization=ser, metadata=metadata + ) + else: + raise PydanticSchemaGenerationError(f'Unable to generate pydantic-core schema for {pattern_type!r}.') + + def _hashable_schema(self) -> core_schema.CoreSchema: + return core_schema.custom_error_schema( + schema=core_schema.json_or_python_schema( + json_schema=core_schema.chain_schema( + [core_schema.any_schema(), core_schema.is_instance_schema(collections.abc.Hashable)] + ), + python_schema=core_schema.is_instance_schema(collections.abc.Hashable), + ), + custom_error_type='is_hashable', + custom_error_message='Input should be hashable', + ) + + def _dataclass_schema( + self, dataclass: type[StandardDataclass], origin: type[StandardDataclass] | None + ) -> core_schema.CoreSchema: + """Generate schema for a dataclass.""" + with ( + self.model_type_stack.push(dataclass), + self.defs.get_schema_or_ref(dataclass) as ( + dataclass_ref, + maybe_schema, + ), + ): + if maybe_schema is not None: + return maybe_schema + + schema = dataclass.__dict__.get('__pydantic_core_schema__') + if schema is not None and not isinstance(schema, MockCoreSchema): + if schema['type'] == 'definitions': + schema = self.defs.unpack_definitions(schema) + ref = get_ref(schema) + if ref: + return self.defs.create_definition_reference_schema(schema) + else: + return schema + + typevars_map = get_standard_typevars_map(dataclass) + if origin is not None: + dataclass = origin + + # if (plain) dataclass doesn't have config, we use the parent's config, hence a default of `None` + # (Pydantic dataclasses have an empty dict config by default). + # see https://github.com/pydantic/pydantic/issues/10917 + config = getattr(dataclass, '__pydantic_config__', None) + + from ..dataclasses import is_pydantic_dataclass + + with self._ns_resolver.push(dataclass), self._config_wrapper_stack.push(config): + if is_pydantic_dataclass(dataclass): + if dataclass.__pydantic_fields_complete__(): + # Copy the field info instances to avoid mutating the `FieldInfo` instances + # of the generic dataclass generic origin (e.g. `apply_typevars_map` below). + # Note that we don't apply `deepcopy` on `__pydantic_fields__` because we + # don't want to copy the `FieldInfo` attributes: + fields = { + f_name: copy(field_info) for f_name, field_info in dataclass.__pydantic_fields__.items() + } + if typevars_map: + for field in fields.values(): + field.apply_typevars_map(typevars_map, *self._types_namespace) + else: + try: + fields = rebuild_dataclass_fields( + dataclass, + config_wrapper=self._config_wrapper, + ns_resolver=self._ns_resolver, + typevars_map=typevars_map or {}, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + else: + fields = collect_dataclass_fields( + dataclass, + typevars_map=typevars_map, + config_wrapper=self._config_wrapper, + ) + + if self._config_wrapper.extra == 'allow': + # disallow combination of init=False on a dataclass field and extra='allow' on a dataclass + for field_name, field in fields.items(): + if field.init is False: + raise PydanticUserError( + f'Field {field_name} has `init=False` and dataclass has config setting `extra="allow"`. ' + f'This combination is not allowed.', + code='dataclass-init-false-extra-allow', + ) + + decorators = dataclass.__dict__.get('__pydantic_decorators__') + if decorators is None: + decorators = DecoratorInfos.build(dataclass, replace_wrapped_methods=False) + decorators.update_from_config(self._config_wrapper) + # Move kw_only=False args to the start of the list, as this is how vanilla dataclasses work. + # Note that when kw_only is missing or None, it is treated as equivalent to kw_only=True + args = sorted( + (self._generate_dc_field_schema(k, v, decorators) for k, v in fields.items()), + key=lambda a: a.get('kw_only') is not False, + ) + has_post_init = hasattr(dataclass, '__post_init__') + has_slots = hasattr(dataclass, '__slots__') + + args_schema = core_schema.dataclass_args_schema( + dataclass.__name__, + args, + computed_fields=[ + self._computed_field_schema(d, decorators.field_serializers) + for d in decorators.computed_fields.values() + ], + collect_init_only=has_post_init, + ) + + inner_schema = apply_validators(args_schema, decorators.root_validators.values()) + + model_validators = decorators.model_validators.values() + inner_schema = apply_model_validators(inner_schema, model_validators, 'inner') + + core_config = self._config_wrapper.core_config(title=dataclass.__name__) + + dc_schema = core_schema.dataclass_schema( + dataclass, + inner_schema, + generic_origin=origin, + post_init=has_post_init, + ref=dataclass_ref, + fields=[field.name for field in dataclasses.fields(dataclass)], + slots=has_slots, + config=core_config, + # we don't use a custom __setattr__ for dataclasses, so we must + # pass along the frozen config setting to the pydantic-core schema + frozen=self._config_wrapper_stack.tail.frozen, + ) + schema = self._apply_model_serializers(dc_schema, decorators.model_serializers.values()) + schema = apply_model_validators(schema, model_validators, 'outer') + return self.defs.create_definition_reference_schema(schema) + + def _call_schema(self, function: ValidateCallSupportedTypes) -> core_schema.CallSchema: + """Generate schema for a Callable. + + TODO support functional validators once we support them in Config + """ + arguments_schema = self._arguments_schema(function) + + return_schema: core_schema.CoreSchema | None = None + config_wrapper = self._config_wrapper + if config_wrapper.validate_return: + sig = _typing_extra.signature_no_eval(function) + return_hint = sig.return_annotation + if return_hint is not sig.empty: + globalns, localns = self._types_namespace + type_hints = _typing_extra.get_function_type_hints( + function, globalns=globalns, localns=localns, include_keys={'return'} + ) + return_schema = self.generate_schema(type_hints['return']) + + return core_schema.call_schema( + arguments_schema, + function, + return_schema=return_schema, + ) + + def _arguments_schema( + self, function: ValidateCallSupportedTypes, parameters_callback: ParametersCallback | None = None + ) -> core_schema.ArgumentsSchema: + """Generate schema for a Signature.""" + mode_lookup: dict[_ParameterKind, Literal['positional_only', 'positional_or_keyword', 'keyword_only']] = { + Parameter.POSITIONAL_ONLY: 'positional_only', + Parameter.POSITIONAL_OR_KEYWORD: 'positional_or_keyword', + Parameter.KEYWORD_ONLY: 'keyword_only', + } + + sig = _typing_extra.signature_no_eval(function) + globalns, localns = self._types_namespace + type_hints = _typing_extra.get_function_type_hints(function, globalns=globalns, localns=localns) + + arguments_list: list[core_schema.ArgumentsParameter] = [] + var_args_schema: core_schema.CoreSchema | None = None + var_kwargs_schema: core_schema.CoreSchema | None = None + var_kwargs_mode: core_schema.VarKwargsMode | None = None + + for i, (name, p) in enumerate(sig.parameters.items()): + if p.annotation is sig.empty: + annotation = typing.cast(Any, Any) + else: + annotation = type_hints[name] + + if parameters_callback is not None: + result = parameters_callback(i, name, annotation) + if result == 'skip': + continue + + parameter_mode = mode_lookup.get(p.kind) + if parameter_mode is not None: + arg_schema = self._generate_parameter_schema( + name, annotation, AnnotationSource.FUNCTION, p.default, parameter_mode + ) + arguments_list.append(arg_schema) + elif p.kind == Parameter.VAR_POSITIONAL: + var_args_schema = self.generate_schema(annotation) + else: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + + unpack_type = _typing_extra.unpack_type(annotation) + if unpack_type is not None: + origin = get_origin(unpack_type) or unpack_type + if not is_typeddict(origin): + raise PydanticUserError( + f'Expected a `TypedDict` class inside `Unpack[...]`, got {unpack_type!r}', + code='unpack-typed-dict', + ) + non_pos_only_param_names = { + name for name, p in sig.parameters.items() if p.kind != Parameter.POSITIONAL_ONLY + } + overlapping_params = non_pos_only_param_names.intersection(origin.__annotations__) + if overlapping_params: + raise PydanticUserError( + f'Typed dictionary {origin.__name__!r} overlaps with parameter' + f'{"s" if len(overlapping_params) >= 2 else ""} ' + f'{", ".join(repr(p) for p in sorted(overlapping_params))}', + code='overlapping-unpack-typed-dict', + ) + + var_kwargs_mode = 'unpacked-typed-dict' + var_kwargs_schema = self._typed_dict_schema(unpack_type, get_origin(unpack_type)) + else: + var_kwargs_mode = 'uniform' + var_kwargs_schema = self.generate_schema(annotation) + + return core_schema.arguments_schema( + arguments_list, + var_args_schema=var_args_schema, + var_kwargs_mode=var_kwargs_mode, + var_kwargs_schema=var_kwargs_schema, + validate_by_name=self._config_wrapper.validate_by_name, + ) + + def _arguments_v3_schema( + self, function: ValidateCallSupportedTypes, parameters_callback: ParametersCallback | None = None + ) -> core_schema.ArgumentsV3Schema: + mode_lookup: dict[ + _ParameterKind, Literal['positional_only', 'positional_or_keyword', 'var_args', 'keyword_only'] + ] = { + Parameter.POSITIONAL_ONLY: 'positional_only', + Parameter.POSITIONAL_OR_KEYWORD: 'positional_or_keyword', + Parameter.VAR_POSITIONAL: 'var_args', + Parameter.KEYWORD_ONLY: 'keyword_only', + } + + sig = _typing_extra.signature_no_eval(function) + globalns, localns = self._types_namespace + type_hints = _typing_extra.get_function_type_hints(function, globalns=globalns, localns=localns) + + parameters_list: list[core_schema.ArgumentsV3Parameter] = [] + + for i, (name, p) in enumerate(sig.parameters.items()): + if parameters_callback is not None: + result = parameters_callback(i, name, p.annotation) + if result == 'skip': + continue + + if p.annotation is Parameter.empty: + annotation = typing.cast(Any, Any) + else: + annotation = type_hints[name] + + parameter_mode = mode_lookup.get(p.kind) + if parameter_mode is None: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + + unpack_type = _typing_extra.unpack_type(annotation) + if unpack_type is not None: + origin = get_origin(unpack_type) or unpack_type + if not is_typeddict(origin): + raise PydanticUserError( + f'Expected a `TypedDict` class inside `Unpack[...]`, got {unpack_type!r}', + code='unpack-typed-dict', + ) + non_pos_only_param_names = { + name for name, p in sig.parameters.items() if p.kind != Parameter.POSITIONAL_ONLY + } + overlapping_params = non_pos_only_param_names.intersection(origin.__annotations__) + if overlapping_params: + raise PydanticUserError( + f'Typed dictionary {origin.__name__!r} overlaps with parameter' + f'{"s" if len(overlapping_params) >= 2 else ""} ' + f'{", ".join(repr(p) for p in sorted(overlapping_params))}', + code='overlapping-unpack-typed-dict', + ) + parameter_mode = 'var_kwargs_unpacked_typed_dict' + annotation = unpack_type + else: + parameter_mode = 'var_kwargs_uniform' + + parameters_list.append( + self._generate_parameter_v3_schema( + name, annotation, AnnotationSource.FUNCTION, parameter_mode, default=p.default + ) + ) + + return core_schema.arguments_v3_schema( + parameters_list, + validate_by_name=self._config_wrapper.validate_by_name, + ) + + def _unsubstituted_typevar_schema(self, typevar: typing.TypeVar) -> core_schema.CoreSchema: + try: + has_default = typevar.has_default() # pyright: ignore[reportAttributeAccessIssue] + except AttributeError: + # Happens if using `typing.TypeVar` (and not `typing_extensions`) on Python < 3.13 + pass + else: + if has_default: + return self.generate_schema(typevar.__default__) # pyright: ignore[reportAttributeAccessIssue] + + if constraints := typevar.__constraints__: + return self._union_schema(typing.Union[constraints]) + + if bound := typevar.__bound__: + schema = self.generate_schema(bound) + schema['serialization'] = core_schema.simple_ser_schema('any') + return schema + + return core_schema.any_schema() + + def _computed_field_schema( + self, + d: Decorator[ComputedFieldInfo], + field_serializers: dict[str, Decorator[FieldSerializerDecoratorInfo]], + ) -> core_schema.ComputedField: + if d.info.return_type is not PydanticUndefined: + return_type = d.info.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type(d.func, localns=self._types_namespace.locals) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + if return_type is PydanticUndefined: + raise PydanticUserError( + 'Computed field is missing return type annotation or specifying `return_type`' + ' to the `@computed_field` decorator (e.g. `@computed_field(return_type=int | str)`)', + code='model-field-missing-annotation', + ) + + return_type = replace_types(return_type, self._typevars_map) + # Create a new ComputedFieldInfo so that different type parametrizations of the same + # generic model's computed field can have different return types. + d.info = dataclasses.replace(d.info, return_type=return_type) + return_type_schema = self.generate_schema(return_type) + # Apply serializers to computed field if there exist + return_type_schema = self._apply_field_serializers( + return_type_schema, + filter_field_decorator_info_by_field(field_serializers.values(), d.cls_var_name), + ) + + pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(d.info) + core_metadata: dict[str, Any] = {} + update_core_metadata( + core_metadata, + pydantic_js_updates={'readOnly': True, **(pydantic_js_updates if pydantic_js_updates else {})}, + pydantic_js_extra=pydantic_js_extra, + ) + exclude_if = d.info.exclude_if + # TODO: Should we support exclude_if from annotations? + return core_schema.computed_field( + d.cls_var_name, + return_schema=return_type_schema, + alias=d.info.alias, + serialization_exclude_if=exclude_if, + metadata=core_metadata, + ) + + def _annotated_schema(self, annotated_type: Any) -> core_schema.CoreSchema: + """Generate schema for an Annotated type, e.g. `Annotated[int, Field(...)]` or `Annotated[int, Gt(0)]`.""" + FieldInfo = import_cached_field_info() + source_type, *annotations = self._get_args_resolving_forward_refs( + annotated_type, + required=True, + ) + schema = self._apply_annotations(source_type, annotations) + # put the default validator last so that TypeAdapter.get_default_value() works + # even if there are function validators involved + for annotation in annotations: + if isinstance(annotation, FieldInfo): + schema = wrap_default(annotation, schema) + return schema + + def _apply_annotations( + self, + source_type: Any, + annotations: list[Any], + transform_inner_schema: Callable[[CoreSchema], CoreSchema] = lambda x: x, + check_unsupported_field_info_attributes: bool = True, + ) -> CoreSchema: + """Apply arguments from `Annotated` or from `FieldInfo` to a schema. + + This gets called by `GenerateSchema._annotated_schema` but differs from it in that it does + not expect `source_type` to be an `Annotated` object, it expects it to be the first argument of that + (in other words, `GenerateSchema._annotated_schema` just unpacks `Annotated`, this process it). + """ + annotations = list(_known_annotated_metadata.expand_grouped_metadata(annotations)) + + pydantic_js_annotation_functions: list[GetJsonSchemaFunction] = [] + + def inner_handler(obj: Any) -> CoreSchema: + schema = self._generate_schema_from_get_schema_method(obj, source_type) + + if schema is None: + schema = self._generate_schema_inner(obj) + + metadata_js_function = _extract_get_pydantic_json_schema(obj) + if metadata_js_function is not None: + metadata_schema = resolve_original_schema(schema, self.defs) + if metadata_schema is not None: + self._add_js_function(metadata_schema, metadata_js_function) + return transform_inner_schema(schema) + + get_inner_schema = CallbackGetCoreSchemaHandler(inner_handler, self) + + for annotation in annotations: + if annotation is None: + continue + get_inner_schema = self._get_wrapped_inner_schema( + get_inner_schema, + annotation, + pydantic_js_annotation_functions, + check_unsupported_field_info_attributes=check_unsupported_field_info_attributes, + ) + + schema = get_inner_schema(source_type) + if pydantic_js_annotation_functions: + core_metadata = schema.setdefault('metadata', {}) + update_core_metadata(core_metadata, pydantic_js_annotation_functions=pydantic_js_annotation_functions) + return _add_custom_serialization_from_json_encoders(self._config_wrapper.json_encoders, source_type, schema) + + def _apply_single_annotation( + self, + schema: core_schema.CoreSchema, + metadata: Any, + check_unsupported_field_info_attributes: bool = True, + ) -> core_schema.CoreSchema: + FieldInfo = import_cached_field_info() + + if isinstance(metadata, FieldInfo): + if ( + check_unsupported_field_info_attributes + # HACK: we don't want to emit the warning for `FieldInfo` subclasses, because FastAPI does weird manipulations + # with its subclasses and their annotations: + and type(metadata) is FieldInfo + ): + for attr, value in (unsupported_attributes := self._get_unsupported_field_info_attributes(metadata)): + warnings.warn( + f'The {attr!r} attribute with value {value!r} was provided to the `Field()` function, ' + f'which has no effect in the context it was used. {attr!r} is field-specific metadata, ' + 'and can only be attached to a model field using `Annotated` metadata or by assignment. ' + 'This may have happened because an `Annotated` type alias using the `type` statement was ' + 'used, or if the `Field()` function was attached to a single member of a union type.', + category=UnsupportedFieldAttributeWarning, + ) + + if ( + metadata.default_factory_takes_validated_data + and self.model_type_stack.get() is None + and 'defaut_factory' not in unsupported_attributes + ): + warnings.warn( + "A 'default_factory' taking validated data as an argument was provided to the `Field()` function, " + 'but no validated data is available in the context it was used.', + category=UnsupportedFieldAttributeWarning, + ) + + for field_metadata in metadata.metadata: + schema = self._apply_single_annotation(schema, field_metadata) + + if metadata.discriminator is not None: + schema = self._apply_discriminator_to_union(schema, metadata.discriminator) + return schema + + if schema['type'] == 'nullable': + # for nullable schemas, metadata is automatically applied to the inner schema + inner = schema.get('schema', core_schema.any_schema()) + inner = self._apply_single_annotation(inner, metadata) + if inner: + schema['schema'] = inner + return schema + + if schema['type'] == 'union' and any( + choice['type'] == 'missing-sentinel' for choice in core_schema.iter_union_choices(schema) + ): + # Same behavior as for nullable schemas. This is a bit gross, but we have to support the same pattern + filtered_choices = [ + choice + for choice in schema['choices'] + if (choice[0] if isinstance(choice, tuple) else choice)['type'] != 'missing-sentinel' + ] + if len(filtered_choices) >= 2: + # e.g. `Annotated[int | str | MISSING, Constraint(...)]`. We apply `Constraint(...)` to `int | str`, + # and create a new union semantically equivalent to `Annotated[int | str, Constraint(...)] | MISSING`: + filtered_union = core_schema.union_schema(filtered_choices) + filtered_union = self._apply_single_annotation(filtered_union, metadata) + new_union = schema.copy() + new_union['choices'] = [ + filtered_union, + next( + choice + for choice in schema['choices'] + if (choice[0] if isinstance(choice, tuple) else choice)['type'] == 'missing-sentinel' + ), + ] + return new_union + elif len(filtered_choices) == 1: + # e.g. `Annotated[int | MISSING, Constraint(...)]`. We apply `Constraint(...)` to `int`, and reconstruct + # a new union preserving the order. + inner = filtered_choices[0][0] if isinstance(filtered_choices[0], tuple) else filtered_choices[0] + inner = self._apply_single_annotation(inner, metadata) + + # Create a new union schema, preserving the order of the union: + new_union = schema.copy() + new_union['choices'] = [ + (inner, choice[1]) + if isinstance(choice, tuple) and choice[0]['type'] != 'missing-sentinel' + else inner + if not isinstance(choice, tuple) and choice['type'] != 'missing-sentinel' + else choice + for choice in schema['choices'] + ] + return new_union + + original_schema = schema + ref = schema.get('ref') + if ref is not None: + schema = schema.copy() + new_ref = ref + f'_{repr(metadata)}' + if (existing := self.defs.get_schema_from_ref(new_ref)) is not None: + return existing + schema['ref'] = new_ref # pyright: ignore[reportGeneralTypeIssues] + elif schema['type'] == 'definition-ref': + ref = schema['schema_ref'] + if (referenced_schema := self.defs.get_schema_from_ref(ref)) is not None: + schema = referenced_schema.copy() + new_ref = ref + f'_{repr(metadata)}' + if (existing := self.defs.get_schema_from_ref(new_ref)) is not None: + return existing + schema['ref'] = new_ref # pyright: ignore[reportGeneralTypeIssues] + + maybe_updated_schema = _known_annotated_metadata.apply_known_metadata(metadata, schema) + + if maybe_updated_schema is not None: + return maybe_updated_schema + return original_schema + + def _apply_single_annotation_json_schema( + self, schema: core_schema.CoreSchema, metadata: Any + ) -> core_schema.CoreSchema: + FieldInfo = import_cached_field_info() + + if isinstance(metadata, FieldInfo): + for field_metadata in metadata.metadata: + schema = self._apply_single_annotation_json_schema(schema, field_metadata) + + pydantic_js_updates, pydantic_js_extra = _extract_json_schema_info_from_field_info(metadata) + core_metadata = schema.setdefault('metadata', {}) + update_core_metadata( + core_metadata, pydantic_js_updates=pydantic_js_updates, pydantic_js_extra=pydantic_js_extra + ) + return schema + + def _get_unsupported_field_info_attributes(self, field_info: FieldInfo) -> list[tuple[str, Any]]: + """Get the list of unsupported `FieldInfo` attributes when not directly used in `Annotated` for field annotations.""" + unused_metadata: list[tuple[str, Any]] = [] + for unused_metadata_name, unset_value in UNSUPPORTED_STANDALONE_FIELDINFO_ATTRIBUTES: + if ( + (unused_metadata_value := getattr(field_info, unused_metadata_name)) is not unset_value + # `default` and `default_factory` can still be used with a type adapter, so only include them + # if used with a model-like class: + and ( + unused_metadata_name not in ('default', 'default_factory') + or self.model_type_stack.get() is not None + ) + # Setting `alias` will set `validation/serialization_alias` as well, so we want to avoid duplicate warnings: + and ( + unused_metadata_name not in ('validation_alias', 'serialization_alias') + or 'alias' not in field_info._attributes_set + ) + ): + unused_metadata.append((unused_metadata_name, unused_metadata_value)) + + return unused_metadata + + def _get_wrapped_inner_schema( + self, + get_inner_schema: GetCoreSchemaHandler, + annotation: Any, + pydantic_js_annotation_functions: list[GetJsonSchemaFunction], + check_unsupported_field_info_attributes: bool = False, + ) -> CallbackGetCoreSchemaHandler: + annotation_get_schema: GetCoreSchemaFunction | None = getattr(annotation, '__get_pydantic_core_schema__', None) + + def new_handler(source: Any) -> core_schema.CoreSchema: + if annotation_get_schema is not None: + schema = annotation_get_schema(source, get_inner_schema) + else: + schema = get_inner_schema(source) + schema = self._apply_single_annotation( + schema, + annotation, + check_unsupported_field_info_attributes=check_unsupported_field_info_attributes, + ) + schema = self._apply_single_annotation_json_schema(schema, annotation) + + metadata_js_function = _extract_get_pydantic_json_schema(annotation) + if metadata_js_function is not None: + pydantic_js_annotation_functions.append(metadata_js_function) + return schema + + return CallbackGetCoreSchemaHandler(new_handler, self) + + def _apply_field_serializers( + self, + schema: core_schema.CoreSchema, + serializers: list[Decorator[FieldSerializerDecoratorInfo]], + ) -> core_schema.CoreSchema: + """Apply field serializers to a schema.""" + if serializers: + schema = copy(schema) + if schema['type'] == 'definitions': + inner_schema = schema['schema'] + schema['schema'] = self._apply_field_serializers(inner_schema, serializers) + return schema + elif 'ref' in schema: + schema = self.defs.create_definition_reference_schema(schema) + + # use the last serializer to make it easy to override a serializer set on a parent model + serializer = serializers[-1] + is_field_serializer, info_arg = inspect_field_serializer(serializer.func, serializer.info.mode) + + if serializer.info.return_type is not PydanticUndefined: + return_type = serializer.info.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + serializer.func, localns=self._types_namespace.locals + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + if return_type is PydanticUndefined: + return_schema = None + else: + return_schema = self.generate_schema(return_type) + + if serializer.info.mode == 'wrap': + schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( + serializer.func, + is_field_serializer=is_field_serializer, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + else: + assert serializer.info.mode == 'plain' + schema['serialization'] = core_schema.plain_serializer_function_ser_schema( + serializer.func, + is_field_serializer=is_field_serializer, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + return schema + + def _apply_model_serializers( + self, schema: core_schema.CoreSchema, serializers: Iterable[Decorator[ModelSerializerDecoratorInfo]] + ) -> core_schema.CoreSchema: + """Apply model serializers to a schema.""" + ref: str | None = schema.pop('ref', None) # type: ignore + if serializers: + serializer = list(serializers)[-1] + info_arg = inspect_model_serializer(serializer.func, serializer.info.mode) + + if serializer.info.return_type is not PydanticUndefined: + return_type = serializer.info.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + serializer.func, localns=self._types_namespace.locals + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + if return_type is PydanticUndefined: + return_schema = None + else: + return_schema = self.generate_schema(return_type) + + if serializer.info.mode == 'wrap': + ser_schema: core_schema.SerSchema = core_schema.wrap_serializer_function_ser_schema( + serializer.func, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + else: + # plain + ser_schema = core_schema.plain_serializer_function_ser_schema( + serializer.func, + info_arg=info_arg, + return_schema=return_schema, + when_used=serializer.info.when_used, + ) + schema['serialization'] = ser_schema + if ref: + schema['ref'] = ref # type: ignore + return schema + + +_VALIDATOR_F_MATCH: Mapping[ + tuple[FieldValidatorModes, Literal['no-info', 'with-info']], + Callable[[Callable[..., Any], core_schema.CoreSchema], core_schema.CoreSchema], +] = { + ('before', 'no-info'): lambda f, schema: core_schema.no_info_before_validator_function(f, schema), + ('after', 'no-info'): lambda f, schema: core_schema.no_info_after_validator_function(f, schema), + ('plain', 'no-info'): lambda f, _: core_schema.no_info_plain_validator_function(f), + ('wrap', 'no-info'): lambda f, schema: core_schema.no_info_wrap_validator_function(f, schema), + ('before', 'with-info'): lambda f, schema: core_schema.with_info_before_validator_function(f, schema), + ('after', 'with-info'): lambda f, schema: core_schema.with_info_after_validator_function(f, schema), + ('plain', 'with-info'): lambda f, _: core_schema.with_info_plain_validator_function(f), + ('wrap', 'with-info'): lambda f, schema: core_schema.with_info_wrap_validator_function(f, schema), +} + + +# TODO V3: this function is only used for deprecated decorators. It should +# be removed once we drop support for those. +def apply_validators( + schema: core_schema.CoreSchema, + validators: Iterable[Decorator[RootValidatorDecoratorInfo]] + | Iterable[Decorator[ValidatorDecoratorInfo]] + | Iterable[Decorator[FieldValidatorDecoratorInfo]], +) -> core_schema.CoreSchema: + """Apply validators to a schema. + + Args: + schema: The schema to apply validators on. + validators: An iterable of validators. + field_name: The name of the field if validators are being applied to a model field. + + Returns: + The updated schema. + """ + for validator in validators: + # Actually, type could be 'field' or 'model', but this is only used for deprecated + # decorators, so let's not worry about it. + info_arg = inspect_validator(validator.func, mode=validator.info.mode, type='field') + val_type = 'with-info' if info_arg else 'no-info' + + schema = _VALIDATOR_F_MATCH[(validator.info.mode, val_type)](validator.func, schema) + return schema + + +def _validators_require_validate_default(validators: Iterable[Decorator[ValidatorDecoratorInfo]]) -> bool: + """In v1, if any of the validators for a field had `always=True`, the default value would be validated. + + This serves as an auxiliary function for re-implementing that logic, by looping over a provided + collection of (v1-style) ValidatorDecoratorInfo's and checking if any of them have `always=True`. + + We should be able to drop this function and the associated logic calling it once we drop support + for v1-style validator decorators. (Or we can extend it and keep it if we add something equivalent + to the v1-validator `always` kwarg to `field_validator`.) + """ + for validator in validators: + if validator.info.always: + return True + return False + + +def _convert_to_aliases( + alias: str | AliasChoices | AliasPath | None, +) -> str | list[str | int] | list[list[str | int]] | None: + if isinstance(alias, (AliasChoices, AliasPath)): + return alias.convert_to_aliases() + else: + return alias + + +def apply_model_validators( + schema: core_schema.CoreSchema, + validators: Iterable[Decorator[ModelValidatorDecoratorInfo]], + mode: Literal['inner', 'outer', 'all'], +) -> core_schema.CoreSchema: + """Apply model validators to a schema. + + If mode == 'inner', only "before" validators are applied + If mode == 'outer', validators other than "before" are applied + If mode == 'all', all validators are applied + + Args: + schema: The schema to apply validators on. + validators: An iterable of validators. + mode: The validator mode. + + Returns: + The updated schema. + """ + ref: str | None = schema.pop('ref', None) # type: ignore + for validator in validators: + if mode == 'inner' and validator.info.mode != 'before': + continue + if mode == 'outer' and validator.info.mode == 'before': + continue + info_arg = inspect_validator(validator.func, mode=validator.info.mode, type='model') + if validator.info.mode == 'wrap': + if info_arg: + schema = core_schema.with_info_wrap_validator_function(function=validator.func, schema=schema) + else: + schema = core_schema.no_info_wrap_validator_function(function=validator.func, schema=schema) + elif validator.info.mode == 'before': + if info_arg: + schema = core_schema.with_info_before_validator_function(function=validator.func, schema=schema) + else: + schema = core_schema.no_info_before_validator_function(function=validator.func, schema=schema) + else: + assert validator.info.mode == 'after' + if info_arg: + schema = core_schema.with_info_after_validator_function(function=validator.func, schema=schema) + else: + schema = core_schema.no_info_after_validator_function(function=validator.func, schema=schema) + if ref: + schema['ref'] = ref # type: ignore + return schema + + +def wrap_default(field_info: FieldInfo, schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """Wrap schema with default schema if default value or `default_factory` are available. + + Args: + field_info: The field info object. + schema: The schema to apply default on. + + Returns: + Updated schema by default value or `default_factory`. + """ + if field_info.default_factory: + return core_schema.with_default_schema( + schema, + default_factory=field_info.default_factory, + default_factory_takes_data=takes_validated_data_argument(field_info.default_factory), + validate_default=field_info.validate_default, + ) + elif field_info.default is not PydanticUndefined: + return core_schema.with_default_schema( + schema, default=field_info.default, validate_default=field_info.validate_default + ) + else: + return schema + + +def _extract_get_pydantic_json_schema(tp: Any) -> GetJsonSchemaFunction | None: + """Extract `__get_pydantic_json_schema__` from a type, handling the deprecated `__modify_schema__`.""" + js_modify_function = getattr(tp, '__get_pydantic_json_schema__', None) + + if hasattr(tp, '__modify_schema__'): + BaseModel = import_cached_base_model() + + has_custom_v2_modify_js_func = ( + js_modify_function is not None + and BaseModel.__get_pydantic_json_schema__.__func__ # type: ignore + not in (js_modify_function, getattr(js_modify_function, '__func__', None)) + ) + + if not has_custom_v2_modify_js_func: + cls_name = getattr(tp, '__name__', None) + raise PydanticUserError( + f'The `__modify_schema__` method is not supported in Pydantic v2. ' + f'Use `__get_pydantic_json_schema__` instead{f" in class `{cls_name}`" if cls_name else ""}.', + code='custom-json-schema', + ) + + if (origin := get_origin(tp)) is not None: + # Generic aliases proxy attribute access to the origin, *except* dunder attributes, + # such as `__get_pydantic_json_schema__`, hence the explicit check. + return _extract_get_pydantic_json_schema(origin) + + if js_modify_function is None: + return None + + return js_modify_function + + +def resolve_original_schema(schema: CoreSchema, definitions: _Definitions) -> CoreSchema | None: + if schema['type'] == 'definition-ref': + return definitions.get_schema_from_ref(schema['schema_ref']) + elif schema['type'] == 'definitions': + return schema['schema'] + else: + return schema + + +def _inlining_behavior( + def_ref: core_schema.DefinitionReferenceSchema, +) -> Literal['inline', 'keep', 'preserve_metadata']: + """Determine the inlining behavior of the `'definition-ref'` schema. + + - If no `'serialization'` schema and no metadata is attached, the schema can safely be inlined. + - If it has metadata but only related to the deferred discriminator application, it can be inlined + provided that such metadata is kept. + - Otherwise, the schema should not be inlined. Doing so would remove the `'serialization'` schema or metadata. + """ + if 'serialization' in def_ref: + return 'keep' + metadata = def_ref.get('metadata') + if not metadata: + return 'inline' + if len(metadata) == 1 and 'pydantic_internal_union_discriminator' in metadata: + return 'preserve_metadata' + return 'keep' + + +class _Definitions: + """Keeps track of references and definitions.""" + + _recursively_seen: set[str] + """A set of recursively seen references. + + When a referenceable type is encountered, the `get_schema_or_ref` context manager is + entered to compute the reference. If the type references itself by some way (e.g. for + a dataclass a Pydantic model, the class can be referenced as a field annotation), + entering the context manager again will yield a `'definition-ref'` schema that should + short-circuit the normal generation process, as the reference was already in this set. + """ + + _definitions: dict[str, core_schema.CoreSchema] + """A mapping of references to their corresponding schema. + + When a schema for a referenceable type is generated, it is stored in this mapping. If the + same type is encountered again, the reference is yielded by the `get_schema_or_ref` context + manager. + """ + + def __init__(self) -> None: + self._recursively_seen = set() + self._definitions = {} + + @contextmanager + def get_schema_or_ref(self, tp: Any, /) -> Generator[tuple[str, core_schema.DefinitionReferenceSchema | None]]: + """Get a definition for `tp` if one exists. + + If a definition exists, a tuple of `(ref_string, CoreSchema)` is returned. + If no definition exists yet, a tuple of `(ref_string, None)` is returned. + + Note that the returned `CoreSchema` will always be a `DefinitionReferenceSchema`, + not the actual definition itself. + + This should be called for any type that can be identified by reference. + This includes any recursive types. + + At present the following types can be named/recursive: + + - Pydantic model + - Pydantic and stdlib dataclasses + - Typed dictionaries + - Named tuples + - `TypeAliasType` instances + - Enums + """ + ref = get_type_ref(tp) + # return the reference if we're either (1) in a cycle or (2) it the reference was already encountered: + if ref in self._recursively_seen or ref in self._definitions: + yield (ref, core_schema.definition_reference_schema(ref)) + else: + self._recursively_seen.add(ref) + try: + yield (ref, None) + finally: + self._recursively_seen.discard(ref) + + def get_schema_from_ref(self, ref: str) -> CoreSchema | None: + """Resolve the schema from the given reference.""" + return self._definitions.get(ref) + + def create_definition_reference_schema(self, schema: CoreSchema) -> core_schema.DefinitionReferenceSchema: + """Store the schema as a definition and return a `'definition-reference'` schema pointing to it. + + The schema must have a reference attached to it. + """ + ref = schema['ref'] # pyright: ignore + self._definitions[ref] = schema + return core_schema.definition_reference_schema(ref) + + def unpack_definitions(self, schema: core_schema.DefinitionsSchema) -> CoreSchema: + """Store the definitions of the `'definitions'` core schema and return the inner core schema.""" + for def_schema in schema['definitions']: + self._definitions[def_schema['ref']] = def_schema # pyright: ignore + return schema['schema'] + + def finalize_schema(self, schema: CoreSchema) -> CoreSchema: + """Finalize the core schema. + + This traverses the core schema and referenced definitions, replaces `'definition-ref'` schemas + by the referenced definition if possible, and applies deferred discriminators. + """ + definitions = self._definitions + try: + gather_result = gather_schemas_for_cleaning( + schema, + definitions=definitions, + ) + except MissingDefinitionError as e: + raise InvalidSchemaError from e + + remaining_defs: dict[str, CoreSchema] = {} + + # Note: this logic doesn't play well when core schemas with deferred discriminator metadata + # and references are encountered. See the `test_deferred_discriminated_union_and_references()` test. + for ref, inlinable_def_ref in gather_result['collected_references'].items(): + if inlinable_def_ref is not None and (inlining_behavior := _inlining_behavior(inlinable_def_ref)) != 'keep': + if inlining_behavior == 'inline': + # `ref` was encountered, and only once: + # - `inlinable_def_ref` is a `'definition-ref'` schema and is guaranteed to be + # the only one. Transform it into the definition it points to. + # - Do not store the definition in the `remaining_defs`. + inlinable_def_ref.clear() # pyright: ignore[reportAttributeAccessIssue] + inlinable_def_ref.update(self._resolve_definition(ref, definitions)) # pyright: ignore + elif inlining_behavior == 'preserve_metadata': + # `ref` was encountered, and only once, but contains discriminator metadata. + # We will do the same thing as if `inlining_behavior` was `'inline'`, but make + # sure to keep the metadata for the deferred discriminator application logic below. + meta = inlinable_def_ref.pop('metadata') + inlinable_def_ref.clear() # pyright: ignore[reportAttributeAccessIssue] + inlinable_def_ref.update(self._resolve_definition(ref, definitions)) # pyright: ignore + inlinable_def_ref['metadata'] = meta + else: + # `ref` was encountered, at least two times (or only once, but with metadata or a serialization schema): + # - Do not inline the `'definition-ref'` schemas (they are not provided in the gather result anyway). + # - Store the definition in the `remaining_defs` + remaining_defs[ref] = self._resolve_definition(ref, definitions) + + for cs in gather_result['deferred_discriminator_schemas']: + discriminator: str | None = cs['metadata'].pop('pydantic_internal_union_discriminator', None) # pyright: ignore[reportTypedDictNotRequiredAccess] + if discriminator is None: + # This can happen in rare scenarios, when a deferred schema is present multiple times in the + # gather result (e.g. when using the `Sequence` type -- see `test_sequence_discriminated_union()`). + # In this case, a previous loop iteration applied the discriminator and so we can just skip it here. + continue + applied = _discriminated_union.apply_discriminator(cs.copy(), discriminator, remaining_defs) + # Mutate the schema directly to have the discriminator applied + cs.clear() # pyright: ignore[reportAttributeAccessIssue] + cs.update(applied) # pyright: ignore + + if remaining_defs: + schema = core_schema.definitions_schema(schema=schema, definitions=[*remaining_defs.values()]) + return schema + + def _resolve_definition(self, ref: str, definitions: dict[str, CoreSchema]) -> CoreSchema: + definition = definitions[ref] + if definition['type'] != 'definition-ref': + return definition + + # Some `'definition-ref'` schemas might act as "intermediate" references (e.g. when using + # a PEP 695 type alias (which is referenceable) that references another PEP 695 type alias): + visited: set[str] = set() + while definition['type'] == 'definition-ref' and _inlining_behavior(definition) == 'inline': + schema_ref = definition['schema_ref'] + if schema_ref in visited: + raise PydanticUserError( + f'{ref} contains a circular reference to itself.', code='circular-reference-schema' + ) + visited.add(schema_ref) + definition = definitions[schema_ref] + return {**definition, 'ref': ref} # pyright: ignore[reportReturnType] + + +class _FieldNameStack: + __slots__ = ('_stack',) + + def __init__(self) -> None: + self._stack: list[str] = [] + + @contextmanager + def push(self, field_name: str) -> Iterator[None]: + self._stack.append(field_name) + yield + self._stack.pop() + + def get(self) -> str | None: + if self._stack: + return self._stack[-1] + else: + return None + + +class _ModelTypeStack: + __slots__ = ('_stack',) + + def __init__(self) -> None: + self._stack: list[type] = [] + + @contextmanager + def push(self, type_obj: type) -> Iterator[None]: + self._stack.append(type_obj) + yield + self._stack.pop() + + def get(self) -> type | None: + if self._stack: + return self._stack[-1] + else: + return None diff --git a/source/target-vendors/cp312/pydantic/_internal/_generics.py b/source/target-vendors/cp312/pydantic/_internal/_generics.py new file mode 100644 index 0000000..f3e927c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_generics.py @@ -0,0 +1,530 @@ +from __future__ import annotations + +import operator +import sys +import types +import typing +from collections import ChainMap +from collections.abc import Iterator, Mapping +from contextlib import contextmanager +from contextvars import ContextVar +from functools import reduce +from itertools import zip_longest +from types import prepare_class +from typing import TYPE_CHECKING, Annotated, Any, TypedDict, TypeVar, cast +from weakref import WeakValueDictionary + +import typing_extensions +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from . import _typing_extra +from ._core_utils import get_type_ref +from ._forward_ref import PydanticRecursiveRef +from ._utils import all_identical, is_model_class + +if TYPE_CHECKING: + from ..main import BaseModel + +GenericTypesCacheKey = tuple[Any, Any, tuple[Any, ...]] + +# Note: We want to remove LimitedDict, but to do this, we'd need to improve the handling of generics caching. +# Right now, to handle recursive generics, we some types must remain cached for brief periods without references. +# By chaining the WeakValuesDict with a LimitedDict, we have a way to retain caching for all types with references, +# while also retaining a limited number of types even without references. This is generally enough to build +# specific recursive generic models without losing required items out of the cache. + +KT = TypeVar('KT') +VT = TypeVar('VT') +_LIMITED_DICT_SIZE = 100 + + +class LimitedDict(dict[KT, VT]): + def __init__(self, size_limit: int = _LIMITED_DICT_SIZE) -> None: + self.size_limit = size_limit + super().__init__() + + def __setitem__(self, key: KT, value: VT, /) -> None: + super().__setitem__(key, value) + if len(self) > self.size_limit: + excess = len(self) - self.size_limit + self.size_limit // 10 + to_remove = list(self.keys())[:excess] + for k in to_remove: + del self[k] + + +# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected +# once they are no longer referenced by the caller. +GenericTypesCache = WeakValueDictionary[GenericTypesCacheKey, 'type[BaseModel]'] + +if TYPE_CHECKING: + + class DeepChainMap(ChainMap[KT, VT]): # type: ignore + ... + +else: + + class DeepChainMap(ChainMap): + """Variant of ChainMap that allows direct updates to inner scopes. + + Taken from https://docs.python.org/3/library/collections.html#collections.ChainMap, + with some light modifications for this use case. + """ + + def clear(self) -> None: + for mapping in self.maps: + mapping.clear() + + def __setitem__(self, key: KT, value: VT) -> None: + for mapping in self.maps: + mapping[key] = value + + def __delitem__(self, key: KT) -> None: + hit = False + for mapping in self.maps: + if key in mapping: + del mapping[key] + hit = True + if not hit: + raise KeyError(key) + + +# Despite the fact that LimitedDict _seems_ no longer necessary, I'm very nervous to actually remove it +# and discover later on that we need to re-add all this infrastructure... +# _GENERIC_TYPES_CACHE = DeepChainMap(GenericTypesCache(), LimitedDict()) + +_GENERIC_TYPES_CACHE = GenericTypesCache() + + +class PydanticGenericMetadata(TypedDict): + origin: type[BaseModel] | None # analogous to typing._GenericAlias.__origin__ + args: tuple[Any, ...] # analogous to typing._GenericAlias.__args__ + parameters: tuple[TypeVar, ...] # analogous to typing.Generic.__parameters__ + + +def create_generic_submodel( + model_name: str, origin: type[BaseModel], args: tuple[Any, ...], params: tuple[Any, ...] +) -> type[BaseModel]: + """Dynamically create a submodel of a provided (generic) BaseModel. + + This is used when producing concrete parametrizations of generic models. This function + only *creates* the new subclass; the schema/validators/serialization must be updated to + reflect a concrete parametrization elsewhere. + + Args: + model_name: The name of the newly created model. + origin: The base class for the new model to inherit from. + args: A tuple of generic metadata arguments. + params: A tuple of generic metadata parameters. + + Returns: + The created submodel. + """ + namespace: dict[str, Any] = {'__module__': origin.__module__} + bases = (origin,) + meta, ns, kwds = prepare_class(model_name, bases) + namespace.update(ns) + created_model = meta( + model_name, + bases, + namespace, + __pydantic_generic_metadata__={ + 'origin': origin, + 'args': args, + 'parameters': params, + }, + __pydantic_reset_parent_namespace__=False, + **kwds, + ) + + model_module, called_globally = _get_caller_frame_info(depth=3) + if called_globally: # create global reference and therefore allow pickling + object_by_reference = None + reference_name = model_name + reference_module_globals = sys.modules[created_model.__module__].__dict__ + while object_by_reference is not created_model: + object_by_reference = reference_module_globals.setdefault(reference_name, created_model) + reference_name += '_' + + return created_model + + +def _get_caller_frame_info(depth: int = 2) -> tuple[str | None, bool]: + """Used inside a function to check whether it was called globally. + + Args: + depth: The depth to get the frame. + + Returns: + A tuple contains `module_name` and `called_globally`. + + Raises: + RuntimeError: If the function is not called inside a function. + """ + try: + previous_caller_frame = sys._getframe(depth) + except ValueError as e: + raise RuntimeError('This function must be used inside another function') from e + except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it + return None, False + frame_globals = previous_caller_frame.f_globals + return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals + + +DictValues: type[Any] = {}.values().__class__ + + +def iter_contained_typevars(v: Any) -> Iterator[TypeVar]: + """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found. + + This is inspired as an alternative to directly accessing the `__parameters__` attribute of a GenericAlias, + since __parameters__ of (nested) generic BaseModel subclasses won't show up in that list. + """ + if isinstance(v, TypeVar): + yield v + elif is_model_class(v): + yield from v.__pydantic_generic_metadata__['parameters'] + elif isinstance(v, (DictValues, list)): + for var in v: + yield from iter_contained_typevars(var) + else: + args = get_args(v) + for arg in args: + yield from iter_contained_typevars(arg) + + +def get_args(v: Any) -> Any: + pydantic_generic_metadata: PydanticGenericMetadata | None = getattr(v, '__pydantic_generic_metadata__', None) + if pydantic_generic_metadata: + return pydantic_generic_metadata.get('args') + return typing_extensions.get_args(v) + + +def get_origin(v: Any) -> Any: + pydantic_generic_metadata: PydanticGenericMetadata | None = getattr(v, '__pydantic_generic_metadata__', None) + if pydantic_generic_metadata: + return pydantic_generic_metadata.get('origin') + return typing_extensions.get_origin(v) + + +def get_standard_typevars_map(cls: Any) -> dict[TypeVar, Any] | None: + """Package a generic type's typevars and parametrization (if present) into a dictionary compatible with the + `replace_types` function. Specifically, this works with standard typing generics and typing._GenericAlias. + """ + origin = get_origin(cls) + if origin is None: + return None + if not hasattr(origin, '__parameters__'): + return None + + # In this case, we know that cls is a _GenericAlias, and origin is the generic type + # So it is safe to access cls.__args__ and origin.__parameters__ + args: tuple[Any, ...] = cls.__args__ # type: ignore + parameters: tuple[TypeVar, ...] = origin.__parameters__ + return dict(zip(parameters, args)) + + +def get_model_typevars_map(cls: type[BaseModel]) -> dict[TypeVar, Any]: + """Package a generic BaseModel's typevars and concrete parametrization (if present) into a dictionary compatible + with the `replace_types` function. + + Since BaseModel.__class_getitem__ does not produce a typing._GenericAlias, and the BaseModel generic info is + stored in the __pydantic_generic_metadata__ attribute, we need special handling here. + """ + # TODO: This could be unified with `get_standard_typevars_map` if we stored the generic metadata + # in the __origin__, __args__, and __parameters__ attributes of the model. + generic_metadata = cls.__pydantic_generic_metadata__ + origin = generic_metadata['origin'] + args = generic_metadata['args'] + if not args: + # No need to go into `iter_contained_typevars`: + return {} + return dict(zip(iter_contained_typevars(origin), args)) + + +def replace_types(type_: Any, type_map: Mapping[TypeVar, Any] | None) -> Any: + """Return type with all occurrences of `type_map` keys recursively replaced with their values. + + Args: + type_: The class or generic alias. + type_map: Mapping from `TypeVar` instance to concrete types. + + Returns: + A new type representing the basic structure of `type_` with all + `typevar_map` keys recursively replaced. + + Example: + ```python + from typing import Union + + from pydantic._internal._generics import replace_types + + replace_types(tuple[str, Union[list[str], float]], {str: int}) + #> tuple[int, Union[list[int], float]] + ``` + """ + if not type_map: + return type_ + + type_args = get_args(type_) + origin_type = get_origin(type_) + + if typing_objects.is_annotated(origin_type): + annotated_type, *annotations = type_args + annotated_type = replace_types(annotated_type, type_map) + # TODO remove parentheses when we drop support for Python 3.10: + return Annotated[(annotated_type, *annotations)] + + # Having type args is a good indicator that this is a typing special form + # instance or a generic alias of some sort. + if type_args: + resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args) + if all_identical(type_args, resolved_type_args): + # If all arguments are the same, there is no need to modify the + # type or create a new object at all + return type_ + + if ( + origin_type is not None + and isinstance(type_, _typing_extra.typing_base) + and not isinstance(origin_type, _typing_extra.typing_base) + and getattr(type_, '_name', None) is not None + ): + # In python < 3.9 generic aliases don't exist so any of these like `list`, + # `type` or `collections.abc.Callable` need to be translated. + # See: https://www.python.org/dev/peps/pep-0585 + origin_type = getattr(typing, type_._name) + assert origin_type is not None + + if is_union_origin(origin_type): + if any(typing_objects.is_any(arg) for arg in resolved_type_args): + # `Any | T` ~ `Any`: + resolved_type_args = (Any,) + # `Never | T` ~ `T`: + resolved_type_args = tuple( + arg + for arg in resolved_type_args + if not (typing_objects.is_noreturn(arg) or typing_objects.is_never(arg)) + ) + + # PEP-604 syntax (e.g. `list | str`) is represented with a types.UnionType object that does not + # implement `__getitem__()`. In Python 3.14+, `typing.Union` and `types.UnionType` are the same, + # and we instead rely on `typing.Union` as it implicitly converts string annotations to `ForwardRef` + # instances (this is to avoid type errors as per https://github.com/python/cpython/pull/105366). + # TODO remove type ignore comment when we drop support for Python 3.9 (https://github.com/microsoft/pyright/issues/11241): + if (3, 10) <= sys.version_info < (3, 14) and origin_type is types.UnionType: # pyright: ignore[reportAttributeAccessIssue] + return reduce(operator.or_, resolved_type_args) + # NotRequired[T] and Required[T] don't support tuple type resolved_type_args, hence the condition below + return origin_type[resolved_type_args[0] if len(resolved_type_args) == 1 else resolved_type_args] + + # We handle pydantic generic models separately as they don't have the same + # semantics as "typing" classes or generic aliases + + if not origin_type and is_model_class(type_): + parameters = type_.__pydantic_generic_metadata__['parameters'] + if not parameters: + return type_ + resolved_type_args = tuple(replace_types(t, type_map) for t in parameters) + if all_identical(parameters, resolved_type_args): + return type_ + return type_[resolved_type_args] + + # Handle special case for typehints that can have lists as arguments. + # `typing.Callable[[int, str], int]` is an example for this. + if isinstance(type_, list): + resolved_list = [replace_types(element, type_map) for element in type_] + if all_identical(type_, resolved_list): + return type_ + return resolved_list + + # If all else fails, we try to resolve the type directly and otherwise just + # return the input with no modifications. + return type_map.get(type_, type_) + + +def map_generic_model_arguments(cls: type[BaseModel], args: tuple[Any, ...]) -> dict[TypeVar, Any]: + """Return a mapping between the parameters of a generic model and the provided arguments during parameterization. + + Raises: + TypeError: If the number of arguments does not match the parameters (i.e. if providing too few or too many arguments). + + Example: + ```python {test="skip" lint="skip"} + class Model[T, U, V = int](BaseModel): ... + + map_generic_model_arguments(Model, (str, bytes)) + #> {T: str, U: bytes, V: int} + + map_generic_model_arguments(Model, (str,)) + #> TypeError: Too few arguments for ; actual 1, expected at least 2 + + map_generic_model_arguments(Model, (str, bytes, int, complex)) + #> TypeError: Too many arguments for ; actual 4, expected 3 + ``` + + Note: + This function is analogous to the private `typing._check_generic_specialization` function. + """ + parameters = cls.__pydantic_generic_metadata__['parameters'] + expected_len = len(parameters) + typevars_map: dict[TypeVar, Any] = {} + + _missing = object() + for parameter, argument in zip_longest(parameters, args, fillvalue=_missing): + if parameter is _missing: + raise TypeError(f'Too many arguments for {cls}; actual {len(args)}, expected {expected_len}') + + if argument is _missing: + param = cast(TypeVar, parameter) + try: + has_default = param.has_default() # pyright: ignore[reportAttributeAccessIssue] + except AttributeError: + # Happens if using `typing.TypeVar` (and not `typing_extensions`) on Python < 3.13. + has_default = False + if has_default: + # The default might refer to other type parameters. For an example, see: + # https://typing.python.org/en/latest/spec/generics.html#type-parameters-as-parameters-to-generics + typevars_map[param] = replace_types(param.__default__, typevars_map) # pyright: ignore[reportAttributeAccessIssue] + else: + expected_len -= sum(hasattr(p, 'has_default') and p.has_default() for p in parameters) # pyright: ignore[reportAttributeAccessIssue] + raise TypeError(f'Too few arguments for {cls}; actual {len(args)}, expected at least {expected_len}') + else: + param = cast(TypeVar, parameter) + typevars_map[param] = argument + + return typevars_map + + +_generic_recursion_cache: ContextVar[set[str] | None] = ContextVar('_generic_recursion_cache', default=None) + + +@contextmanager +def generic_recursion_self_type( + origin: type[BaseModel], args: tuple[Any, ...] +) -> Iterator[PydanticRecursiveRef | None]: + """This contextmanager should be placed around the recursive calls used to build a generic type, + and accept as arguments the generic origin type and the type arguments being passed to it. + + If the same origin and arguments are observed twice, it implies that a self-reference placeholder + can be used while building the core schema, and will produce a schema_ref that will be valid in the + final parent schema. + """ + previously_seen_type_refs = _generic_recursion_cache.get() + if previously_seen_type_refs is None: + previously_seen_type_refs = set() + token = _generic_recursion_cache.set(previously_seen_type_refs) + else: + token = None + + try: + type_ref = get_type_ref(origin, args_override=args) + if type_ref in previously_seen_type_refs: + self_type = PydanticRecursiveRef(type_ref=type_ref) + yield self_type + else: + previously_seen_type_refs.add(type_ref) + yield + previously_seen_type_refs.remove(type_ref) + finally: + if token: + _generic_recursion_cache.reset(token) + + +def recursively_defined_type_refs() -> set[str]: + visited = _generic_recursion_cache.get() + if not visited: + return set() # not in a generic recursion, so there are no types + + return visited.copy() # don't allow modifications + + +def get_cached_generic_type_early(parent: type[BaseModel], typevar_values: Any) -> type[BaseModel] | None: + """The use of a two-stage cache lookup approach was necessary to have the highest performance possible for + repeated calls to `__class_getitem__` on generic types (which may happen in tighter loops during runtime), + while still ensuring that certain alternative parametrizations ultimately resolve to the same type. + + As a concrete example, this approach was necessary to make Model[List[T]][int] equal to Model[List[int]]. + The approach could be modified to not use two different cache keys at different points, but the + _early_cache_key is optimized to be as quick to compute as possible (for repeated-access speed), and the + _late_cache_key is optimized to be as "correct" as possible, so that two types that will ultimately be the + same after resolving the type arguments will always produce cache hits. + + If we wanted to move to only using a single cache key per type, we would either need to always use the + slower/more computationally intensive logic associated with _late_cache_key, or would need to accept + that Model[List[T]][int] is a different type than Model[List[T]][int]. Because we rely on subclass relationships + during validation, I think it is worthwhile to ensure that types that are functionally equivalent are actually + equal. + """ + return _GENERIC_TYPES_CACHE.get(_early_cache_key(parent, typevar_values)) + + +def get_cached_generic_type_late( + parent: type[BaseModel], typevar_values: Any, origin: type[BaseModel], args: tuple[Any, ...] +) -> type[BaseModel] | None: + """See the docstring of `get_cached_generic_type_early` for more information about the two-stage cache lookup.""" + cached = _GENERIC_TYPES_CACHE.get(_late_cache_key(origin, args, typevar_values)) + if cached is not None: + set_cached_generic_type(parent, typevar_values, cached, origin, args) + return cached + + +def set_cached_generic_type( + parent: type[BaseModel], + typevar_values: tuple[Any, ...], + type_: type[BaseModel], + origin: type[BaseModel] | None = None, + args: tuple[Any, ...] | None = None, +) -> None: + """See the docstring of `get_cached_generic_type_early` for more information about why items are cached with + two different keys. + """ + _GENERIC_TYPES_CACHE[_early_cache_key(parent, typevar_values)] = type_ + if len(typevar_values) == 1: + _GENERIC_TYPES_CACHE[_early_cache_key(parent, typevar_values[0])] = type_ + if origin and args: + _GENERIC_TYPES_CACHE[_late_cache_key(origin, args, typevar_values)] = type_ + + +def _union_orderings_key(typevar_values: Any) -> Any: + """This is intended to help differentiate between Union types with the same arguments in different order. + + Thanks to caching internal to the `typing` module, it is not possible to distinguish between + List[Union[int, float]] and List[Union[float, int]] (and similarly for other "parent" origins besides List) + because `typing` considers Union[int, float] to be equal to Union[float, int]. + + However, you _can_ distinguish between (top-level) Union[int, float] vs. Union[float, int]. + Because we parse items as the first Union type that is successful, we get slightly more consistent behavior + if we make an effort to distinguish the ordering of items in a union. It would be best if we could _always_ + get the exact-correct order of items in the union, but that would require a change to the `typing` module itself. + (See https://github.com/python/cpython/issues/86483 for reference.) + """ + if isinstance(typevar_values, tuple): + return tuple(_union_orderings_key(value) for value in typevar_values) + elif typing_objects.is_union(typing_extensions.get_origin(typevar_values)): + return get_args(typevar_values) + else: + return () + + +def _early_cache_key(cls: type[BaseModel], typevar_values: Any) -> GenericTypesCacheKey: + """This is intended for minimal computational overhead during lookups of cached types. + + Note that this is overly simplistic, and it's possible that two different cls/typevar_values + inputs would ultimately result in the same type being created in BaseModel.__class_getitem__. + To handle this, we have a fallback _late_cache_key that is checked later if the _early_cache_key + lookup fails, and should result in a cache hit _precisely_ when the inputs to __class_getitem__ + would result in the same type. + """ + return cls, typevar_values, _union_orderings_key(typevar_values) + + +def _late_cache_key(origin: type[BaseModel], args: tuple[Any, ...], typevar_values: Any) -> GenericTypesCacheKey: + """This is intended for use later in the process of creating a new type, when we have more information + about the exact args that will be passed. If it turns out that a different set of inputs to + __class_getitem__ resulted in the same inputs to the generic type creation process, we can still + return the cached type, and update the cache with the _early_cache_key as well. + """ + # The _union_orderings_key is placed at the start here to ensure there cannot be a collision with an + # _early_cache_key, as that function will always produce a BaseModel subclass as the first item in the key, + # whereas this function will always produce a tuple as the first item in the key. + return _union_orderings_key(typevar_values), origin, args diff --git a/source/target-vendors/cp312/pydantic/_internal/_git.py b/source/target-vendors/cp312/pydantic/_internal/_git.py new file mode 100644 index 0000000..96dcda2 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_git.py @@ -0,0 +1,27 @@ +"""Git utilities, adopted from mypy's git utilities (https://github.com/python/mypy/blob/master/mypy/git.py).""" + +from __future__ import annotations + +import subprocess +from pathlib import Path + + +def is_git_repo(dir: Path) -> bool: + """Is the given directory version-controlled with git?""" + return dir.joinpath('.git').exists() + + +def have_git() -> bool: # pragma: no cover + """Can we run the git executable?""" + try: + subprocess.check_output(['git', '--help']) + return True + except subprocess.CalledProcessError: + return False + except OSError: + return False + + +def git_revision(dir: Path) -> str: + """Get the SHA-1 of the HEAD of a git repository.""" + return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=dir).decode('utf-8').strip() diff --git a/source/target-vendors/cp312/pydantic/_internal/_import_utils.py b/source/target-vendors/cp312/pydantic/_internal/_import_utils.py new file mode 100644 index 0000000..638102f --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_import_utils.py @@ -0,0 +1,20 @@ +from functools import cache +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pydantic import BaseModel + from pydantic.fields import FieldInfo + + +@cache +def import_cached_base_model() -> type['BaseModel']: + from pydantic import BaseModel + + return BaseModel + + +@cache +def import_cached_field_info() -> type['FieldInfo']: + from pydantic.fields import FieldInfo + + return FieldInfo diff --git a/source/target-vendors/cp312/pydantic/_internal/_internal_dataclass.py b/source/target-vendors/cp312/pydantic/_internal/_internal_dataclass.py new file mode 100644 index 0000000..33e152c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_internal_dataclass.py @@ -0,0 +1,7 @@ +import sys + +# `slots` is available on Python >= 3.10 +if sys.version_info >= (3, 10): + slots_true = {'slots': True} +else: + slots_true = {} diff --git a/source/target-vendors/cp312/pydantic/_internal/_known_annotated_metadata.py b/source/target-vendors/cp312/pydantic/_internal/_known_annotated_metadata.py new file mode 100644 index 0000000..5954dba --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_known_annotated_metadata.py @@ -0,0 +1,403 @@ +from __future__ import annotations + +from collections import defaultdict +from collections.abc import Iterable +from copy import copy +from functools import lru_cache, partial +from typing import TYPE_CHECKING, Any + +from pydantic_core import CoreSchema, PydanticCustomError, ValidationError, to_jsonable_python +from pydantic_core import core_schema as cs + +from ._fields import PydanticMetadata +from ._import_utils import import_cached_field_info + +if TYPE_CHECKING: + pass + +STRICT = {'strict'} +FAIL_FAST = {'fail_fast'} +LENGTH_CONSTRAINTS = {'min_length', 'max_length'} +INEQUALITY = {'le', 'ge', 'lt', 'gt'} +NUMERIC_CONSTRAINTS = {'multiple_of', *INEQUALITY} +ALLOW_INF_NAN = {'allow_inf_nan'} + +STR_CONSTRAINTS = { + *LENGTH_CONSTRAINTS, + *STRICT, + 'strip_whitespace', + 'to_lower', + 'to_upper', + 'pattern', + 'coerce_numbers_to_str', + 'ascii_only', +} +BYTES_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT} + +LIST_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST} +TUPLE_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST} +SET_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT, *FAIL_FAST} +DICT_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT} +GENERATOR_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *STRICT} +SEQUENCE_CONSTRAINTS = {*LENGTH_CONSTRAINTS, *FAIL_FAST} + +FLOAT_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *ALLOW_INF_NAN, *STRICT} +DECIMAL_CONSTRAINTS = {'max_digits', 'decimal_places', *FLOAT_CONSTRAINTS} +INT_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *ALLOW_INF_NAN, *STRICT} +BOOL_CONSTRAINTS = STRICT +UUID_CONSTRAINTS = STRICT + +DATE_TIME_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT} +TIMEDELTA_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT} +TIME_CONSTRAINTS = {*NUMERIC_CONSTRAINTS, *STRICT} +LAX_OR_STRICT_CONSTRAINTS = STRICT +ENUM_CONSTRAINTS = STRICT +COMPLEX_CONSTRAINTS = STRICT + +UNION_CONSTRAINTS = {'union_mode'} +URL_CONSTRAINTS = { + 'max_length', + 'allowed_schemes', + 'host_required', + 'default_host', + 'default_port', + 'default_path', +} + +TEXT_SCHEMA_TYPES = ('str', 'bytes', 'url', 'multi-host-url') +SEQUENCE_SCHEMA_TYPES = ('list', 'tuple', 'set', 'frozenset', 'generator', *TEXT_SCHEMA_TYPES) +NUMERIC_SCHEMA_TYPES = ('float', 'int', 'date', 'time', 'timedelta', 'datetime') + +CONSTRAINTS_TO_ALLOWED_SCHEMAS: dict[str, set[str]] = defaultdict(set) + +constraint_schema_pairings: list[tuple[set[str], tuple[str, ...]]] = [ + (STR_CONSTRAINTS, TEXT_SCHEMA_TYPES), + (BYTES_CONSTRAINTS, ('bytes',)), + (LIST_CONSTRAINTS, ('list',)), + (TUPLE_CONSTRAINTS, ('tuple',)), + (SET_CONSTRAINTS, ('set', 'frozenset')), + (DICT_CONSTRAINTS, ('dict',)), + (GENERATOR_CONSTRAINTS, ('generator',)), + (FLOAT_CONSTRAINTS, ('float',)), + (INT_CONSTRAINTS, ('int',)), + (DATE_TIME_CONSTRAINTS, ('date', 'time', 'datetime', 'timedelta')), + # TODO: this is a bit redundant, we could probably avoid some of these + (STRICT, (*TEXT_SCHEMA_TYPES, *SEQUENCE_SCHEMA_TYPES, *NUMERIC_SCHEMA_TYPES, 'typed-dict', 'model')), + (UNION_CONSTRAINTS, ('union',)), + (URL_CONSTRAINTS, ('url', 'multi-host-url')), + (BOOL_CONSTRAINTS, ('bool',)), + (UUID_CONSTRAINTS, ('uuid',)), + (LAX_OR_STRICT_CONSTRAINTS, ('lax-or-strict',)), + (ENUM_CONSTRAINTS, ('enum',)), + (DECIMAL_CONSTRAINTS, ('decimal',)), + (COMPLEX_CONSTRAINTS, ('complex',)), +] + +for constraints, schemas in constraint_schema_pairings: + for c in constraints: + CONSTRAINTS_TO_ALLOWED_SCHEMAS[c].update(schemas) + + +def as_jsonable_value(v: Any) -> Any: + if type(v) not in (int, str, float, bytes, bool, type(None)): + return to_jsonable_python(v) + return v + + +def expand_grouped_metadata(annotations: Iterable[Any]) -> Iterable[Any]: + """Expand the annotations. + + Args: + annotations: An iterable of annotations. + + Returns: + An iterable of expanded annotations. + + Example: + ```python + from annotated_types import Ge, Len + + from pydantic._internal._known_annotated_metadata import expand_grouped_metadata + + print(list(expand_grouped_metadata([Ge(4), Len(5)]))) + #> [Ge(ge=4), MinLen(min_length=5)] + ``` + """ + import annotated_types as at + + FieldInfo = import_cached_field_info() + + for annotation in annotations: + if isinstance(annotation, at.GroupedMetadata): + yield from annotation + elif isinstance(annotation, FieldInfo): + yield from annotation.metadata + # this is a bit problematic in that it results in duplicate metadata + # all of our "consumers" can handle it, but it is not ideal + # we probably should split up FieldInfo into: + # - annotated types metadata + # - individual metadata known only to Pydantic + annotation = copy(annotation) + annotation.metadata = [] + yield annotation + else: + yield annotation + + +@lru_cache +def _get_at_to_constraint_map() -> dict[type, str]: + """Return a mapping of annotated types to constraints. + + Normally, we would define a mapping like this in the module scope, but we can't do that + because we don't permit module level imports of `annotated_types`, in an attempt to speed up + the import time of `pydantic`. We still only want to have this dictionary defined in one place, + so we use this function to cache the result. + """ + import annotated_types as at + + return { + at.Gt: 'gt', + at.Ge: 'ge', + at.Lt: 'lt', + at.Le: 'le', + at.MultipleOf: 'multiple_of', + at.MinLen: 'min_length', + at.MaxLen: 'max_length', + } + + +def apply_known_metadata(annotation: Any, schema: CoreSchema) -> CoreSchema | None: # noqa: C901 + """Apply `annotation` to `schema` if it is an annotation we know about (Gt, Le, etc.). + Otherwise return `None`. + + This does not handle all known annotations. If / when it does, it can always + return a CoreSchema and return the unmodified schema if the annotation should be ignored. + + Assumes that GroupedMetadata has already been expanded via `expand_grouped_metadata`. + + Args: + annotation: The annotation. + schema: The schema. + + Returns: + An updated schema with annotation if it is an annotation we know about, `None` otherwise. + + Raises: + RuntimeError: If a constraint can't be applied to a specific schema type. + ValueError: If an unknown constraint is encountered. + """ + import annotated_types as at + + from ._validators import NUMERIC_VALIDATOR_LOOKUP, forbid_inf_nan_check + + schema = schema.copy() + schema_update, other_metadata = collect_known_metadata([annotation]) + schema_type = schema['type'] + + chain_schema_constraints: set[str] = { + 'pattern', + 'strip_whitespace', + 'to_lower', + 'to_upper', + 'coerce_numbers_to_str', + 'ascii_only', + } + chain_schema_steps: list[CoreSchema] = [] + + for constraint, value in schema_update.items(): + if constraint not in CONSTRAINTS_TO_ALLOWED_SCHEMAS: + raise ValueError(f'Unknown constraint {constraint}') + allowed_schemas = CONSTRAINTS_TO_ALLOWED_SCHEMAS[constraint] + + # if it becomes necessary to handle more than one constraint + # in this recursive case with function-after or function-wrap, we should refactor + # this is a bit challenging because we sometimes want to apply constraints to the inner schema, + # whereas other times we want to wrap the existing schema with a new one that enforces a new constraint. + if schema_type in {'function-before', 'function-wrap', 'function-after'} and constraint == 'strict': + schema['schema'] = apply_known_metadata(annotation, schema['schema']) # type: ignore # schema is function schema + return schema + + # if we're allowed to apply constraint directly to the schema, like le to int, do that + if schema_type in allowed_schemas: + if constraint == 'union_mode' and schema_type == 'union': + schema['mode'] = value # type: ignore # schema is UnionSchema + else: + schema[constraint] = value + continue + + # else, apply a function after validator to the schema to enforce the corresponding constraint + if constraint in chain_schema_constraints: + + def _apply_constraint_with_incompatibility_info( + value: Any, handler: cs.ValidatorFunctionWrapHandler + ) -> Any: + try: + x = handler(value) + except ValidationError as ve: + # if the error is about the type, it's likely that the constraint is incompatible the type of the field + # for example, the following invalid schema wouldn't be caught during schema build, but rather at this point + # with a cryptic 'string_type' error coming from the string validator, + # that we'd rather express as a constraint incompatibility error (TypeError) + # Annotated[list[int], Field(pattern='abc')] + if 'type' in ve.errors()[0]['type']: + raise TypeError( + f"Unable to apply constraint '{constraint}' to supplied value {value} for schema of type '{schema_type}'" # noqa: B023 + ) + raise ve + return x + + chain_schema_steps.append( + cs.no_info_wrap_validator_function( + _apply_constraint_with_incompatibility_info, cs.str_schema(**{constraint: value}) + ) + ) + elif constraint in NUMERIC_VALIDATOR_LOOKUP: + if constraint in LENGTH_CONSTRAINTS: + inner_schema = schema + while inner_schema['type'] in {'function-before', 'function-wrap', 'function-after'}: + inner_schema = inner_schema['schema'] # type: ignore + inner_schema_type = inner_schema['type'] + if inner_schema_type == 'list' or ( + inner_schema_type == 'json-or-python' and inner_schema['json_schema']['type'] == 'list' # type: ignore + ): + js_constraint_key = 'minItems' if constraint == 'min_length' else 'maxItems' + else: + js_constraint_key = 'minLength' if constraint == 'min_length' else 'maxLength' + else: + js_constraint_key = constraint + + schema = cs.no_info_after_validator_function( + partial(NUMERIC_VALIDATOR_LOOKUP[constraint], **{constraint: value}), schema + ) + metadata = schema.get('metadata', {}) + if (existing_json_schema_updates := metadata.get('pydantic_js_updates')) is not None: + metadata['pydantic_js_updates'] = { + **existing_json_schema_updates, + **{js_constraint_key: as_jsonable_value(value)}, + } + else: + metadata['pydantic_js_updates'] = {js_constraint_key: as_jsonable_value(value)} + schema['metadata'] = metadata + elif constraint == 'allow_inf_nan' and value is False: + schema = cs.no_info_after_validator_function( + forbid_inf_nan_check, + schema, + ) + else: + # It's rare that we'd get here, but it's possible if we add a new constraint and forget to handle it + # Most constraint errors are caught at runtime during attempted application + raise RuntimeError(f"Unable to apply constraint '{constraint}' to schema of type '{schema_type}'") + + for annotation in other_metadata: + if (annotation_type := type(annotation)) in (at_to_constraint_map := _get_at_to_constraint_map()): + constraint = at_to_constraint_map[annotation_type] + validator = NUMERIC_VALIDATOR_LOOKUP.get(constraint) + if validator is None: + raise ValueError(f'Unknown constraint {constraint}') + schema = cs.no_info_after_validator_function( + partial(validator, {constraint: getattr(annotation, constraint)}), schema + ) + continue + elif isinstance(annotation, (at.Predicate, at.Not)): + predicate_name = f'{annotation.func.__qualname__!r} ' if hasattr(annotation.func, '__qualname__') else '' + + # Note: B023 is ignored because even though we iterate over `other_metadata`, it is guaranteed + # to be of length 1. `apply_known_metadata()` is called from `GenerateSchema`, where annotations + # were already expanded via `expand_grouped_metadata()`. Confusing, but this falls into the annotations + # refactor. + if isinstance(annotation, at.Predicate): + + def val_func(v: Any) -> Any: + predicate_satisfied = annotation.func(v) # noqa: B023 + if not predicate_satisfied: + raise PydanticCustomError( + 'predicate_failed', + f'Predicate {predicate_name}failed', # pyright: ignore[reportArgumentType] # noqa: B023 + ) + return v + + else: + + def val_func(v: Any) -> Any: + predicate_satisfied = annotation.func(v) # noqa: B023 + if predicate_satisfied: + raise PydanticCustomError( + 'not_operation_failed', + f'Not of {predicate_name}failed', # pyright: ignore[reportArgumentType] # noqa: B023 + ) + return v + + schema = cs.no_info_after_validator_function(val_func, schema) + else: + # ignore any other unknown metadata + return None + + if chain_schema_steps: + chain_schema_steps = [schema] + chain_schema_steps + return cs.chain_schema(chain_schema_steps) + + return schema + + +def collect_known_metadata(annotations: Iterable[Any]) -> tuple[dict[str, Any], list[Any]]: + """Split `annotations` into known metadata and unknown annotations. + + Args: + annotations: An iterable of annotations. + + Returns: + A tuple contains a dict of known metadata and a list of unknown annotations. + + Example: + ```python + from annotated_types import Gt, Len + + from pydantic._internal._known_annotated_metadata import collect_known_metadata + + print(collect_known_metadata([Gt(1), Len(42), ...])) + #> ({'gt': 1, 'min_length': 42}, [Ellipsis]) + ``` + """ + annotations = expand_grouped_metadata(annotations) + + res: dict[str, Any] = {} + remaining: list[Any] = [] + + for annotation in annotations: + # isinstance(annotation, PydanticMetadata) also covers ._fields:_PydanticGeneralMetadata + if isinstance(annotation, PydanticMetadata): + res.update(annotation.__dict__) + # we don't use dataclasses.asdict because that recursively calls asdict on the field values + elif (annotation_type := type(annotation)) in (at_to_constraint_map := _get_at_to_constraint_map()): + constraint = at_to_constraint_map[annotation_type] + res[constraint] = getattr(annotation, constraint) + elif isinstance(annotation, type) and issubclass(annotation, PydanticMetadata): + # also support PydanticMetadata classes being used without initialisation, + # e.g. `Annotated[int, Strict]` as well as `Annotated[int, Strict()]` + res.update({k: v for k, v in vars(annotation).items() if not k.startswith('_')}) + else: + remaining.append(annotation) + # Nones can sneak in but pydantic-core will reject them + # it'd be nice to clean things up so we don't put in None (we probably don't _need_ to, it was just easier) + # but this is simple enough to kick that can down the road + res = {k: v for k, v in res.items() if v is not None} + return res, remaining + + +def check_metadata(metadata: dict[str, Any], allowed: Iterable[str], source_type: Any) -> None: + """A small utility function to validate that the given metadata can be applied to the target. + More than saving lines of code, this gives us a consistent error message for all of our internal implementations. + + Args: + metadata: A dict of metadata. + allowed: An iterable of allowed metadata. + source_type: The source type. + + Raises: + TypeError: If there is metadatas that can't be applied on source type. + """ + unknown = metadata.keys() - set(allowed) + if unknown: + raise TypeError( + f'The following constraints cannot be applied to {source_type!r}: {", ".join([f"{k!r}" for k in unknown])}' + ) diff --git a/source/target-vendors/cp312/pydantic/_internal/_mock_val_ser.py b/source/target-vendors/cp312/pydantic/_internal/_mock_val_ser.py new file mode 100644 index 0000000..9125ab3 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_mock_val_ser.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +from collections.abc import Iterator, Mapping +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar, Union + +from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator + +from ..errors import PydanticErrorCodes, PydanticUserError +from ..plugin._schema_validator import PluggableSchemaValidator + +if TYPE_CHECKING: + from ..dataclasses import PydanticDataclass + from ..main import BaseModel + from ..type_adapter import TypeAdapter + + +ValSer = TypeVar('ValSer', bound=Union[SchemaValidator, PluggableSchemaValidator, SchemaSerializer]) +T = TypeVar('T') + + +class MockCoreSchema(Mapping[str, Any]): + """Mocker for `pydantic_core.CoreSchema` which optionally attempts to + rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails. + """ + + __slots__ = '_error_message', '_code', '_attempt_rebuild', '_built_memo' + + def __init__( + self, + error_message: str, + *, + code: PydanticErrorCodes, + attempt_rebuild: Callable[[], CoreSchema | None] | None = None, + ) -> None: + self._error_message = error_message + self._code: PydanticErrorCodes = code + self._attempt_rebuild = attempt_rebuild + self._built_memo: CoreSchema | None = None + + def __getitem__(self, key: str) -> Any: + return self._get_built().__getitem__(key) + + def __len__(self) -> int: + return self._get_built().__len__() + + def __iter__(self) -> Iterator[str]: + return self._get_built().__iter__() + + def _get_built(self) -> CoreSchema: + if self._built_memo is not None: + return self._built_memo + + if self._attempt_rebuild: + schema = self._attempt_rebuild() + if schema is not None: + self._built_memo = schema + return schema + raise PydanticUserError(self._error_message, code=self._code) + + def rebuild(self) -> CoreSchema | None: + self._built_memo = None + if self._attempt_rebuild: + schema = self._attempt_rebuild() + if schema is not None: + return schema + else: + raise PydanticUserError(self._error_message, code=self._code) + return None + + +class MockValSer(Generic[ValSer]): + """Mocker for `pydantic_core.SchemaValidator` or `pydantic_core.SchemaSerializer` which optionally attempts to + rebuild the thing it's mocking when one of its methods is accessed and raises an error if that fails. + """ + + __slots__ = '_error_message', '_code', '_val_or_ser', '_attempt_rebuild' + + def __init__( + self, + error_message: str, + *, + code: PydanticErrorCodes, + val_or_ser: Literal['validator', 'serializer'], + attempt_rebuild: Callable[[], ValSer | None] | None = None, + ) -> None: + self._error_message = error_message + self._val_or_ser = SchemaValidator if val_or_ser == 'validator' else SchemaSerializer + self._code: PydanticErrorCodes = code + self._attempt_rebuild = attempt_rebuild + + def __getattr__(self, item: str) -> None: + __tracebackhide__ = True + if self._attempt_rebuild: + val_ser = self._attempt_rebuild() + if val_ser is not None: + return getattr(val_ser, item) + + # raise an AttributeError if `item` doesn't exist + getattr(self._val_or_ser, item) + raise PydanticUserError(self._error_message, code=self._code) + + def rebuild(self) -> ValSer | None: + if self._attempt_rebuild: + val_ser = self._attempt_rebuild() + if val_ser is not None: + return val_ser + else: + raise PydanticUserError(self._error_message, code=self._code) + return None + + +def set_type_adapter_mocks(adapter: TypeAdapter) -> None: + """Set `core_schema`, `validator` and `serializer` to mock core types on a type adapter instance. + + Args: + adapter: The type adapter instance to set the mocks on + """ + type_repr = str(adapter._type) + undefined_type_error_message = ( + f'`TypeAdapter[{type_repr}]` is not fully defined; you should define `{type_repr}` and all referenced types,' + f' then call `.rebuild()` on the instance.' + ) + + def attempt_rebuild_fn(attr_fn: Callable[[TypeAdapter], T]) -> Callable[[], T | None]: + def handler() -> T | None: + if adapter.rebuild(raise_errors=False, _parent_namespace_depth=5) is not False: + return attr_fn(adapter) + return None + + return handler + + adapter.core_schema = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.core_schema), + ) + adapter.validator = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='validator', + attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.validator), + ) + adapter.serializer = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='serializer', + attempt_rebuild=attempt_rebuild_fn(lambda ta: ta.serializer), + ) + + +def set_model_mocks(cls: type[BaseModel], undefined_name: str = 'all referenced types') -> None: + """Set `__pydantic_core_schema__`, `__pydantic_validator__` and `__pydantic_serializer__` to mock core types on a model. + + Args: + cls: The model class to set the mocks on + undefined_name: Name of the undefined thing, used in error messages + """ + undefined_type_error_message = ( + f'`{cls.__name__}` is not fully defined; you should define {undefined_name},' + f' then call `{cls.__name__}.model_rebuild()`.' + ) + + def attempt_rebuild_fn(attr_fn: Callable[[type[BaseModel]], T]) -> Callable[[], T | None]: + def handler() -> T | None: + if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5) is not False: + return attr_fn(cls) + return None + + return handler + + cls.__pydantic_core_schema__ = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__), + ) + cls.__pydantic_validator__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='validator', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__), + ) + cls.__pydantic_serializer__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='serializer', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__), + ) + + +def set_dataclass_mocks(cls: type[PydanticDataclass], undefined_name: str = 'all referenced types') -> None: + """Set `__pydantic_validator__` and `__pydantic_serializer__` to `MockValSer`s on a dataclass. + + Args: + cls: The model class to set the mocks on + undefined_name: Name of the undefined thing, used in error messages + """ + from ..dataclasses import rebuild_dataclass + + undefined_type_error_message = ( + f'`{cls.__name__}` is not fully defined; you should define {undefined_name},' + f' then call `pydantic.dataclasses.rebuild_dataclass({cls.__name__})`.' + ) + + def attempt_rebuild_fn(attr_fn: Callable[[type[PydanticDataclass]], T]) -> Callable[[], T | None]: + def handler() -> T | None: + if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5) is not False: + return attr_fn(cls) + return None + + return handler + + cls.__pydantic_core_schema__ = MockCoreSchema( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_core_schema__), + ) + cls.__pydantic_validator__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='validator', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_validator__), + ) + cls.__pydantic_serializer__ = MockValSer( # pyright: ignore[reportAttributeAccessIssue] + undefined_type_error_message, + code='class-not-fully-defined', + val_or_ser='serializer', + attempt_rebuild=attempt_rebuild_fn(lambda c: c.__pydantic_serializer__), + ) diff --git a/source/target-vendors/cp312/pydantic/_internal/_model_construction.py b/source/target-vendors/cp312/pydantic/_internal/_model_construction.py new file mode 100644 index 0000000..b794544 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_model_construction.py @@ -0,0 +1,868 @@ +"""Private logic for creating models.""" + +from __future__ import annotations as _annotations + +import operator +import sys +import typing +import warnings +import weakref +from abc import ABCMeta +from functools import cache, partial, wraps +from types import FunctionType +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, NoReturn, TypeVar, cast + +from pydantic_core import PydanticUndefined, SchemaSerializer +from typing_extensions import TypeAliasType, dataclass_transform, deprecated, get_args, get_origin +from typing_inspection import typing_objects + +from ..errors import PydanticUndefinedAnnotation, PydanticUserError +from ..plugin._schema_validator import create_schema_validator +from ..warnings import GenericBeforeBaseModelWarning, PydanticDeprecatedSince20 +from ._config import ConfigWrapper +from ._decorators import DecoratorInfos, PydanticDescriptorProxy, get_attribute_from_bases, unwrap_wrapped_function +from ._fields import collect_model_fields, is_valid_field_name, is_valid_privateattr_name, rebuild_model_fields +from ._generate_schema import GenerateSchema, InvalidSchemaError +from ._generics import PydanticGenericMetadata, get_model_typevars_map +from ._import_utils import import_cached_base_model, import_cached_field_info +from ._mock_val_ser import set_model_mocks +from ._namespace_utils import NsResolver +from ._signature import generate_pydantic_signature +from ._typing_extra import ( + _make_forward_ref, + eval_type_backport, + is_classvar_annotation, + parent_frame_namespace, +) +from ._utils import LazyClassAttribute, SafeGetItemProxy + +if TYPE_CHECKING: + from ..fields import Field as PydanticModelField + from ..fields import FieldInfo, ModelPrivateAttr + from ..fields import PrivateAttr as PydanticModelPrivateAttr + from ..main import BaseModel + from ._fields import PydanticExtraInfo +else: + PydanticModelField = object() + PydanticModelPrivateAttr = object() + +object_setattr = object.__setattr__ + + +class _ModelNamespaceDict(dict): + """A dictionary subclass that intercepts attribute setting on model classes and + warns about overriding of decorators. + """ + + def __setitem__(self, k: str, v: object) -> None: + existing: Any = self.get(k, None) + if existing and v is not existing and isinstance(existing, PydanticDescriptorProxy): + warnings.warn( + f'`{k}` overrides an existing Pydantic `{existing.decorator_info.decorator_repr}` decorator', + stacklevel=2, + ) + + return super().__setitem__(k, v) + + +def NoInitField( + *, + init: Literal[False] = False, +) -> Any: + """Only for typing purposes. Used as default value of `__pydantic_fields_set__`, + `__pydantic_extra__`, `__pydantic_private__`, so they could be ignored when + synthesizing the `__init__` signature. + """ + + +# For ModelMetaclass.register(): +_T = TypeVar('_T') + + +@dataclass_transform(kw_only_default=True, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr, NoInitField)) +class ModelMetaclass(ABCMeta): + def __new__( + mcs, + cls_name: str, + bases: tuple[type[Any], ...], + namespace: dict[str, Any], + __pydantic_generic_metadata__: PydanticGenericMetadata | None = None, + __pydantic_reset_parent_namespace__: bool = True, + _create_model_module: str | None = None, + **kwargs: Any, + ) -> type: + """Metaclass for creating Pydantic models. + + Args: + cls_name: The name of the class to be created. + bases: The base classes of the class to be created. + namespace: The attribute dictionary of the class to be created. + __pydantic_generic_metadata__: Metadata for generic models. + __pydantic_reset_parent_namespace__: Reset parent namespace. + _create_model_module: The module of the class to be created, if created by `create_model`. + **kwargs: Catch-all for any other keyword arguments. + + Returns: + The new class created by the metaclass. + """ + # Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we rely on the fact + # that `BaseModel` itself won't have any bases, but any subclass of it will, to determine whether the `__new__` + # call we're in the middle of is for the `BaseModel` class. + if bases: + raw_annotations: dict[str, Any] + if sys.version_info >= (3, 14): + if ( + '__annotations__' in namespace + ): # `from __future__ import annotations` was used in the model's module + raw_annotations = namespace['__annotations__'] + else: + # See https://docs.python.org/3.14/library/annotationlib.html#using-annotations-in-a-metaclass: + from annotationlib import Format, call_annotate_function, get_annotate_from_class_namespace + + if annotate := get_annotate_from_class_namespace(namespace): + raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF) + else: + raw_annotations = {} + else: + raw_annotations = namespace.get('__annotations__', {}) + + base_field_names, class_vars, base_private_attributes = mcs._collect_bases_data(bases) + + config_wrapper = ConfigWrapper.for_model(bases, namespace, raw_annotations, kwargs) + namespace['model_config'] = config_wrapper.config_dict + private_attributes = inspect_namespace( + namespace, raw_annotations, config_wrapper.ignored_types, class_vars, base_field_names + ) + if private_attributes or base_private_attributes: + original_model_post_init = get_model_post_init(namespace, bases) + if original_model_post_init is not None: + # if there are private attributes and a model_post_init function, we handle both + + @wraps(original_model_post_init) + def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None: + """We need to both initialize private attributes and call the user-defined model_post_init + method. + """ + init_private_attributes(self, context) + original_model_post_init(self, context) + + namespace['model_post_init'] = wrapped_model_post_init + else: + namespace['model_post_init'] = init_private_attributes + + namespace['__class_vars__'] = class_vars + namespace['__private_attributes__'] = {**base_private_attributes, **private_attributes} + + cls = cast('type[BaseModel]', super().__new__(mcs, cls_name, bases, namespace, **kwargs)) + BaseModel_ = import_cached_base_model() + + mro = cls.__mro__ + if Generic in mro and mro.index(Generic) < mro.index(BaseModel_): + warnings.warn( + GenericBeforeBaseModelWarning( + 'Classes should inherit from `BaseModel` before generic classes (e.g. `typing.Generic[T]`) ' + 'for pydantic generics to work properly.' + ), + stacklevel=2, + ) + + cls.__pydantic_custom_init__ = not getattr(cls.__init__, '__pydantic_base_init__', False) + cls.__pydantic_post_init__ = ( + None if cls.model_post_init is BaseModel_.model_post_init else 'model_post_init' + ) + + cls.__pydantic_setattr_handlers__ = {} + + cls.__pydantic_decorators__ = DecoratorInfos.build(cls, replace_wrapped_methods=True) + cls.__pydantic_decorators__.update_from_config(config_wrapper) + + # Use the getattr below to grab the __parameters__ from the `typing.Generic` parent class + if __pydantic_generic_metadata__: + cls.__pydantic_generic_metadata__ = __pydantic_generic_metadata__ + else: + parent_parameters = getattr(cls, '__pydantic_generic_metadata__', {}).get('parameters', ()) + parameters = getattr(cls, '__parameters__', None) or parent_parameters + if parameters and parent_parameters and not all(x in parameters for x in parent_parameters): + from ..root_model import RootModelRootType + + missing_parameters = tuple(x for x in parameters if x not in parent_parameters) + if RootModelRootType in parent_parameters and RootModelRootType not in parameters: + # This is a special case where the user has subclassed RootModel, but has not parameterized + # RootModel with the generic type identifiers being used. Ex: + # class MyModel(RootModel, Generic[T]): + # root: T + # Should instead just be: + # class MyModel(RootModel[T]): + # root: T + parameters_str = ', '.join([x.__name__ for x in missing_parameters]) + error_message = ( + f'{cls.__name__} is a subclass of `RootModel`, but does not include the generic type identifier(s) ' + f'{parameters_str} in its parameters. ' + f'You should parametrize RootModel directly, e.g., `class {cls.__name__}(RootModel[{parameters_str}]): ...`.' + ) + else: + combined_parameters = parent_parameters + missing_parameters + parameters_str = ', '.join([str(x) for x in combined_parameters]) + generic_type_label = f'typing.Generic[{parameters_str}]' + error_message = ( + f'All parameters must be present on typing.Generic;' + f' you should inherit from {generic_type_label}.' + ) + if Generic not in bases: # pragma: no cover + # We raise an error here not because it is desirable, but because some cases are mishandled. + # It would be nice to remove this error and still have things behave as expected, it's just + # challenging because we are using a custom `__class_getitem__` to parametrize generic models, + # and not returning a typing._GenericAlias from it. + bases_str = ', '.join([x.__name__ for x in bases] + [generic_type_label]) + error_message += ( + f' Note: `typing.Generic` must go last: `class {cls.__name__}({bases_str}): ...`)' + ) + raise TypeError(error_message) + + cls.__pydantic_generic_metadata__ = { + 'origin': None, + 'args': (), + 'parameters': parameters, + } + + cls.__pydantic_complete__ = False # Ensure this specific class gets completed + + # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487 + # for attributes not in `new_namespace` (e.g. private attributes) + for name, obj in private_attributes.items(): + obj.__set_name__(cls, name) + + if __pydantic_reset_parent_namespace__: + cls.__pydantic_parent_namespace__ = build_lenient_weakvaluedict(parent_frame_namespace()) + parent_namespace: dict[str, Any] | None = getattr(cls, '__pydantic_parent_namespace__', None) + if isinstance(parent_namespace, dict): + parent_namespace = unpack_lenient_weakvaluedict(parent_namespace) + + ns_resolver = NsResolver(parent_namespace=parent_namespace) + + set_model_fields(cls, config_wrapper=config_wrapper, ns_resolver=ns_resolver) + + # This is also set in `complete_model_class()`, after schema gen because they are recreated. + # We set them here as well for backwards compatibility: + cls.__pydantic_computed_fields__ = { + k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items() + } + + if config_wrapper.defer_build: + set_model_mocks(cls) + else: + # Any operation that requires accessing the field infos instances should be put inside + # `complete_model_class()`: + complete_model_class( + cls, + config_wrapper, + ns_resolver, + raise_errors=False, + create_model_module=_create_model_module, + ) + + if config_wrapper.frozen and '__hash__' not in namespace: + set_default_hash_func(cls, bases) + + # using super(cls, cls) on the next line ensures we only call the parent class's __pydantic_init_subclass__ + # I believe the `type: ignore` is only necessary because mypy doesn't realize that this code branch is + # only hit for _proper_ subclasses of BaseModel + super(cls, cls).__pydantic_init_subclass__(**kwargs) # type: ignore[misc] + return cls + else: + # These are instance variables, but have been assigned to `NoInitField` to trick the type checker. + for instance_slot in '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__': + namespace.pop( + instance_slot, + None, # In case the metaclass is used with a class other than `BaseModel`. + ) + namespace.get('__annotations__', {}).clear() + return super().__new__(mcs, cls_name, bases, namespace, **kwargs) + + if not TYPE_CHECKING: # pragma: no branch + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + + def __getattr__(self, item: str) -> Any: + """This is necessary to keep attribute access working for class attribute access.""" + private_attributes = self.__dict__.get('__private_attributes__') + if private_attributes and item in private_attributes: + return private_attributes[item] + raise AttributeError(item) + + @classmethod + def __prepare__(cls, *args: Any, **kwargs: Any) -> dict[str, object]: + return _ModelNamespaceDict() + + # Due to performance and memory issues, in the ABCMeta.__subclasscheck__ implementation, we don't support + # registered virtual subclasses. See https://github.com/python/cpython/issues/92810#issuecomment-2762454345. + # This may change once CPython is fixed (possibly in 3.15), in which case we should conditionally + # define `register()`. + def register(self, subclass: type[_T]) -> type[_T]: + warnings.warn( + f"For performance reasons, virtual subclasses registered using '{self.__qualname__}.register()' " + "are not supported in 'isinstance()' and 'issubclass()' checks.", + stacklevel=2, + ) + return super().register(subclass) + + __instancecheck__ = type.__instancecheck__ # pyright: ignore[reportAssignmentType] + __subclasscheck__ = type.__subclasscheck__ # pyright: ignore[reportAssignmentType] + + @staticmethod + def _collect_bases_data(bases: tuple[type[Any], ...]) -> tuple[set[str], set[str], dict[str, ModelPrivateAttr]]: + BaseModel = import_cached_base_model() + + field_names: set[str] = set() + class_vars: set[str] = set() + private_attributes: dict[str, ModelPrivateAttr] = {} + for base in bases: + if issubclass(base, BaseModel) and base is not BaseModel: + # model_fields might not be defined yet in the case of generics, so we use getattr here: + field_names.update(getattr(base, '__pydantic_fields__', {}).keys()) + class_vars.update(base.__class_vars__) + private_attributes.update(base.__private_attributes__) + return field_names, class_vars, private_attributes + + @property + @deprecated( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', category=None + ) + def __fields__(self) -> dict[str, FieldInfo]: + warnings.warn( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', + PydanticDeprecatedSince20, + stacklevel=2, + ) + return getattr(self, '__pydantic_fields__', {}) + + @property + def __pydantic_fields_complete__(self) -> bool: + """Whether the fields were successfully collected (i.e. type hints were successfully resolved). + + This is a private attribute, not meant to be used outside Pydantic. + """ + if '__pydantic_fields__' not in self.__dict__: + return False + + field_infos = cast('dict[str, FieldInfo]', self.__pydantic_fields__) # pyright: ignore[reportAttributeAccessIssue] + + pydantic_extra_info = cast('PydanticExtraInfo | None', self.__pydantic_extra_info__) # pyright: ignore[reportAttributeAccessIssue] + if pydantic_extra_info is not None: + extra_complete = pydantic_extra_info.complete + else: + extra_complete = True + + return all(field_info._complete for field_info in field_infos.values()) and extra_complete + + def __dir__(self) -> list[str]: + attributes = list(super().__dir__()) + if '__fields__' in attributes: + attributes.remove('__fields__') + return attributes + + +def init_private_attributes(self: BaseModel, context: Any, /) -> None: + """This function is meant to behave like a BaseModel method to initialize private attributes. + + It takes context as an argument since that's what pydantic-core passes when calling it. + + Args: + self: The BaseModel instance. + context: The context. + """ + if getattr(self, '__pydantic_private__', None) is None: + pydantic_private = {} + for name, private_attr in self.__private_attributes__.items(): + # Avoid needlessly creating a new dict for the validated data: + if private_attr.default_factory_takes_validated_data: + default = private_attr.get_default( + call_default_factory=True, validated_data={**self.__dict__, **pydantic_private} + ) + else: + default = private_attr.get_default(call_default_factory=True) + if default is not PydanticUndefined: + pydantic_private[name] = default + object_setattr(self, '__pydantic_private__', pydantic_private) + + +def get_model_post_init(namespace: dict[str, Any], bases: tuple[type[Any], ...]) -> Callable[..., Any] | None: + """Get the `model_post_init` method from the namespace or the class bases, or `None` if not defined.""" + if 'model_post_init' in namespace: + return namespace['model_post_init'] + + BaseModel = import_cached_base_model() + + model_post_init = get_attribute_from_bases(bases, 'model_post_init') + if model_post_init is not BaseModel.model_post_init: + return model_post_init + + +def inspect_namespace( # noqa C901 + namespace: dict[str, Any], + raw_annotations: dict[str, Any], + ignored_types: tuple[type[Any], ...], + base_class_vars: set[str], + base_class_fields: set[str], +) -> dict[str, ModelPrivateAttr]: + """Iterate over the namespace and: + * gather private attributes + * check for items which look like fields but are not (e.g. have no annotation) and warn. + + Args: + namespace: The attribute dictionary of the class to be created. + raw_annotations: The (non-evaluated) annotations of the model. + ignored_types: A tuple of ignore types. + base_class_vars: A set of base class class variables. + base_class_fields: A set of base class fields. + + Returns: + A dict containing private attributes info. + + Raises: + TypeError: If there is a `__root__` field in model. + NameError: If private attribute name is invalid. + PydanticUserError: + - If a field does not have a type annotation. + - If a field on base class was overridden by a non-annotated attribute. + """ + from ..fields import ModelPrivateAttr, PrivateAttr + + FieldInfo = import_cached_field_info() + + all_ignored_types = ignored_types + default_ignored_types() + + private_attributes: dict[str, ModelPrivateAttr] = {} + + if '__root__' in raw_annotations or '__root__' in namespace: + raise TypeError("To define root models, use `pydantic.RootModel` rather than a field called '__root__'") + + ignored_names: set[str] = set() + for var_name, value in list(namespace.items()): + if var_name == 'model_config' or var_name == '__pydantic_extra__': + continue + elif ( + isinstance(value, type) + and value.__module__ == namespace['__module__'] + and '__qualname__' in namespace + and value.__qualname__.startswith(f'{namespace["__qualname__"]}.') + ): + # `value` is a nested type defined in this namespace; don't error + continue + elif isinstance(value, all_ignored_types) or value.__class__.__module__ == 'functools': + ignored_names.add(var_name) + continue + elif isinstance(value, ModelPrivateAttr): + if var_name.startswith('__'): + raise NameError( + 'Private attributes must not use dunder names;' + f' use a single underscore prefix instead of {var_name!r}.' + ) + elif is_valid_field_name(var_name): + raise NameError( + 'Private attributes must not use valid field names;' + f' use sunder names, e.g. {"_" + var_name!r} instead of {var_name!r}.' + ) + private_attributes[var_name] = value + del namespace[var_name] + elif isinstance(value, FieldInfo) and not is_valid_field_name(var_name): + suggested_name = var_name.lstrip('_') or 'my_field' # don't suggest '' for all-underscore name + raise NameError( + f'Fields must not use names with leading underscores;' + f' e.g., use {suggested_name!r} instead of {var_name!r}.' + ) + + elif var_name.startswith('__'): + continue + elif is_valid_privateattr_name(var_name): + if var_name not in raw_annotations or not is_classvar_annotation(raw_annotations[var_name]): + private_attributes[var_name] = cast(ModelPrivateAttr, PrivateAttr(default=value)) + del namespace[var_name] + elif var_name in base_class_vars: + continue + elif var_name not in raw_annotations: + if var_name in base_class_fields: + raise PydanticUserError( + f'Field {var_name!r} defined on a base class was overridden by a non-annotated attribute. ' + f'All field definitions, including overrides, require a type annotation.', + code='model-field-overridden', + ) + elif isinstance(value, FieldInfo): + raise PydanticUserError( + f'Field {var_name!r} requires a type annotation', code='model-field-missing-annotation' + ) + else: + raise PydanticUserError( + f'A non-annotated attribute was detected: `{var_name} = {value!r}`. All model fields require a ' + f'type annotation; if `{var_name}` is not meant to be a field, you may be able to resolve this ' + f"error by annotating it as a `ClassVar` or updating `model_config['ignored_types']`.", + code='model-field-missing-annotation', + ) + + for ann_name, ann_type in raw_annotations.items(): + if ( + is_valid_privateattr_name(ann_name) + and ann_name not in private_attributes + and ann_name not in ignored_names + # This condition can be a false negative when `ann_type` is stringified, + # but it is handled in most cases in `set_model_fields`: + and not is_classvar_annotation(ann_type) + and ann_type not in all_ignored_types + and getattr(ann_type, '__module__', None) != 'functools' + ): + if isinstance(ann_type, str): + # Walking up the frames to get the module namespace where the model is defined + # (as the model class wasn't created yet, we unfortunately can't use `cls.__module__`): + frame = sys._getframe(2) + if frame is not None: + try: + ann_type = eval_type_backport( + _make_forward_ref(ann_type, is_argument=False, is_class=True), + globalns=frame.f_globals, + localns=frame.f_locals, + ) + except (NameError, TypeError): + pass + + if typing_objects.is_annotated(get_origin(ann_type)): + _, *metadata = get_args(ann_type) + private_attr = next((v for v in metadata if isinstance(v, ModelPrivateAttr)), None) + if private_attr is not None: + private_attributes[ann_name] = private_attr + continue + private_attributes[ann_name] = PrivateAttr() + + return private_attributes + + +def set_default_hash_func(cls: type[BaseModel], bases: tuple[type[Any], ...]) -> None: + base_hash_func = get_attribute_from_bases(bases, '__hash__') + new_hash_func = make_hash_func(cls) + if base_hash_func in {None, object.__hash__} or getattr(base_hash_func, '__code__', None) == new_hash_func.__code__: + # If `__hash__` is some default, we generate a hash function. + # It will be `None` if not overridden from BaseModel. + # It may be `object.__hash__` if there is another + # parent class earlier in the bases which doesn't override `__hash__` (e.g. `typing.Generic`). + # It may be a value set by `set_default_hash_func` if `cls` is a subclass of another frozen model. + # In the last case we still need a new hash function to account for new `model_fields`. + cls.__hash__ = new_hash_func + + +def make_hash_func(cls: type[BaseModel]) -> Any: + getter = operator.itemgetter(*cls.__pydantic_fields__.keys()) if cls.__pydantic_fields__ else lambda _: 0 + + def hash_func(self: Any) -> int: + try: + return hash(getter(self.__dict__)) + except KeyError: + # In rare cases (such as when using the deprecated copy method), the __dict__ may not contain + # all model fields, which is how we can get here. + # getter(self.__dict__) is much faster than any 'safe' method that accounts for missing keys, + # and wrapping it in a `try` doesn't slow things down much in the common case. + return hash(getter(SafeGetItemProxy(self.__dict__))) + + return hash_func + + +def set_model_fields( + cls: type[BaseModel], + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, +) -> None: + """Collect and set `cls.__pydantic_fields__` and `cls.__class_vars__`. + + Args: + cls: BaseModel or dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: Namespace resolver to use when getting model annotations. + """ + typevars_map = get_model_typevars_map(cls) + fields, pydantic_extra_info, class_vars = collect_model_fields( + cls, config_wrapper, ns_resolver, typevars_map=typevars_map + ) + + cls.__pydantic_fields__ = fields + cls.__pydantic_extra_info__ = pydantic_extra_info + cls.__class_vars__.update(class_vars) + + for k in class_vars: + # Class vars should not be private attributes + # We remove them _here_ and not earlier because we rely on inspecting the class to determine its classvars, + # but private attributes are determined by inspecting the namespace _prior_ to class creation. + # In the case that a classvar with a leading-'_' is defined via a ForwardRef (e.g., when using + # `__future__.annotations`), we want to remove the private attribute which was detected _before_ we knew it + # evaluated to a classvar + + value = cls.__private_attributes__.pop(k, None) + if value is not None and value.default is not PydanticUndefined: + setattr(cls, k, value.default) + + +def complete_model_class( + cls: type[BaseModel], + config_wrapper: ConfigWrapper, + ns_resolver: NsResolver, + *, + raise_errors: bool = True, + call_on_complete_hook: bool = True, + create_model_module: str | None = None, + is_force_rebuild: bool = False, +) -> bool: + """Finish building a model class. + + This logic must be called after class has been created since validation functions must be bound + and `get_type_hints` requires a class object. + + Args: + cls: BaseModel or dataclass. + config_wrapper: The config wrapper instance. + ns_resolver: The namespace resolver instance to use during schema building. + raise_errors: Whether to raise errors. + call_on_complete_hook: Whether to call the `__pydantic_on_complete__` hook. + create_model_module: The module of the class to be created, if created by `create_model`. + is_force_rebuild: Whether the model is being force-rebuilt (if True, pre-built serializers and + validators are not used, to avoid stale references). + + Returns: + `True` if the model is successfully completed, else `False`. + + Raises: + PydanticUndefinedAnnotation: If PydanticUndefinedAnnotation occurs in __get_pydantic_core_schema__ + and `raise_errors=True`. + """ + typevars_map = get_model_typevars_map(cls) + + if not cls.__pydantic_fields_complete__: + # Note: when coming from `ModelMetaclass.__new__()`, this results in fields being built twice. + # We do so a second time here so that we can get the ``NameError`` for the specific undefined annotation. + # Alternatively, we could let `GenerateSchema()` raise the error, but there are cases where incomplete + # fields are inherited in `collect_model_fields()` and can actually have their annotation resolved in the + # generate schema process. As we want to avoid having `__pydantic_fields_complete__` set to `False` + # when `__pydantic_complete__` is `True`, we rebuild here: + try: + cls.__pydantic_fields__, cls.__pydantic_extra_info__ = rebuild_model_fields( + cls, + config_wrapper=config_wrapper, + ns_resolver=ns_resolver, + typevars_map=typevars_map, + ) + except NameError as e: + exc = PydanticUndefinedAnnotation.from_name_error(e) + set_model_mocks(cls, f'`{exc.name}`') + if raise_errors: + raise exc from e + + if not raise_errors and not cls.__pydantic_fields_complete__: + # No need to continue with schema gen, it is guaranteed to fail + return False + + assert cls.__pydantic_fields_complete__ + + gen_schema = GenerateSchema( + config_wrapper, + ns_resolver, + typevars_map, + ) + + try: + schema = gen_schema.generate_schema(cls) + except PydanticUndefinedAnnotation as e: + if raise_errors: + raise + set_model_mocks(cls, f'`{e.name}`') + return False + + core_config = config_wrapper.core_config(title=cls.__name__) + + try: + schema = gen_schema.clean_schema(schema) + except InvalidSchemaError: + set_model_mocks(cls) + return False + + # This needs to happen *after* model schema generation, as the return types + # of the properties are evaluated and the `ComputedFieldInfo` are recreated: + cls.__pydantic_computed_fields__ = {k: v.info for k, v in cls.__pydantic_decorators__.computed_fields.items()} + + set_deprecated_descriptors(cls) + + cls.__pydantic_core_schema__ = schema + + cls.__pydantic_validator__ = create_schema_validator( + schema, + cls, + create_model_module or cls.__module__, + cls.__qualname__, + 'create_model' if create_model_module else 'BaseModel', + core_config, + config_wrapper.plugin_settings, + _use_prebuilt=not is_force_rebuild, + ) + cls.__pydantic_serializer__ = SchemaSerializer(schema, core_config, _use_prebuilt=not is_force_rebuild) + + # set __signature__ attr only for model class, but not for its instances + # (because instances can define `__call__`, and `inspect.signature` shouldn't + # use the `__signature__` attribute and instead generate from `__call__`). + cls.__signature__ = LazyClassAttribute( + '__signature__', + partial( + generate_pydantic_signature, + init=cls.__init__, + fields=cls.__pydantic_fields__, + validate_by_name=config_wrapper.validate_by_name, + extra=config_wrapper.extra, + ), + ) + + cls.__pydantic_complete__ = True + + if call_on_complete_hook: + cls.__pydantic_on_complete__() + + return True + + +def set_deprecated_descriptors(cls: type[BaseModel]) -> None: + """Set data descriptors on the class for deprecated fields.""" + for field, field_info in cls.__pydantic_fields__.items(): + if (msg := field_info.deprecation_message) is not None: + desc = _DeprecatedFieldDescriptor(msg) + desc.__set_name__(cls, field) + setattr(cls, field, desc) + + for field, computed_field_info in cls.__pydantic_computed_fields__.items(): + if ( + (msg := computed_field_info.deprecation_message) is not None + # Avoid having two warnings emitted: + and not hasattr(unwrap_wrapped_function(computed_field_info.wrapped_property), '__deprecated__') + ): + desc = _DeprecatedFieldDescriptor(msg, computed_field_info.wrapped_property) + desc.__set_name__(cls, field) + setattr(cls, field, desc) + + +class _DeprecatedFieldDescriptor: + """Read-only data descriptor used to emit a runtime deprecation warning before accessing a deprecated field. + + Attributes: + msg: The deprecation message to be emitted. + wrapped_property: The property instance if the deprecated field is a computed field, or `None`. + field_name: The name of the field being deprecated. + """ + + field_name: str + + def __init__(self, msg: str, wrapped_property: property | None = None) -> None: + self.msg = msg + self.wrapped_property = wrapped_property + + def __set_name__(self, cls: type[BaseModel], name: str) -> None: + self.field_name = name + + def __get__(self, obj: BaseModel | None, obj_type: type[BaseModel] | None = None) -> Any: + if obj is None: + if self.wrapped_property is not None: + return self.wrapped_property.__get__(None, obj_type) + raise AttributeError(self.field_name) + + warnings.warn(self.msg, DeprecationWarning, stacklevel=2) + + if self.wrapped_property is not None: + return self.wrapped_property.__get__(obj, obj_type) + return obj.__dict__[self.field_name] + + # Defined to make it a data descriptor and take precedence over the instance's dictionary. + # Note that it will not be called when setting a value on a model instance + # as `BaseModel.__setattr__` is defined and takes priority. + def __set__(self, obj: Any, value: Any) -> NoReturn: + raise AttributeError(self.field_name) + + +class _PydanticWeakRef: + """Wrapper for `weakref.ref` that enables `pickle` serialization. + + Cloudpickle fails to serialize weakref.ref objects due to an arcane error related to + to abstract base classes (`abc.ABC`). This class works around the issue by wrapping + `weakref.ref` instead of subclassing it. + + See https://github.com/pydantic/pydantic/issues/6763 for context. + + Semantics: + - If not pickled, behaves the same as a `weakref.ref`. + - If pickled along with the referenced object, the same `weakref.ref` behavior + will be maintained between them after unpickling. + - If pickled without the referenced object, after unpickling the underlying + reference will be cleared (`__call__` will always return `None`). + """ + + def __init__(self, obj: Any): + if obj is None: + # The object will be `None` upon deserialization if the serialized weakref + # had lost its underlying object. + self._wr = None + else: + self._wr = weakref.ref(obj) + + def __call__(self) -> Any: + if self._wr is None: + return None + else: + return self._wr() + + def __reduce__(self) -> tuple[Callable, tuple[weakref.ReferenceType | None]]: + return _PydanticWeakRef, (self(),) + + +def build_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: + """Takes an input dictionary, and produces a new value that (invertibly) replaces the values with weakrefs. + + We can't just use a WeakValueDictionary because many types (including int, str, etc.) can't be stored as values + in a WeakValueDictionary. + + The `unpack_lenient_weakvaluedict` function can be used to reverse this operation. + """ + if d is None: + return None + result = {} + for k, v in d.items(): + try: + proxy = _PydanticWeakRef(v) + except TypeError: + proxy = v + result[k] = proxy + return result + + +def unpack_lenient_weakvaluedict(d: dict[str, Any] | None) -> dict[str, Any] | None: + """Inverts the transform performed by `build_lenient_weakvaluedict`.""" + if d is None: + return None + + result = {} + for k, v in d.items(): + if isinstance(v, _PydanticWeakRef): + v = v() + if v is not None: + result[k] = v + else: + result[k] = v + return result + + +@cache +def default_ignored_types() -> tuple[type[Any], ...]: + from ..fields import ComputedFieldInfo + + ignored_types = [ + FunctionType, + property, + classmethod, + staticmethod, + PydanticDescriptorProxy, + ComputedFieldInfo, + TypeAliasType, # from `typing_extensions` + ] + + if sys.version_info >= (3, 12): + ignored_types.append(typing.TypeAliasType) + + return tuple(ignored_types) diff --git a/source/target-vendors/cp312/pydantic/_internal/_namespace_utils.py b/source/target-vendors/cp312/pydantic/_internal/_namespace_utils.py new file mode 100644 index 0000000..af0cddb --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_namespace_utils.py @@ -0,0 +1,293 @@ +from __future__ import annotations + +import sys +from collections.abc import Generator, Iterator, Mapping +from contextlib import contextmanager +from functools import cached_property +from typing import Any, Callable, NamedTuple, TypeVar + +from typing_extensions import ParamSpec, TypeAlias, TypeAliasType, TypeVarTuple + +GlobalsNamespace: TypeAlias = 'dict[str, Any]' +"""A global namespace. + +In most cases, this is a reference to the `__dict__` attribute of a module. +This namespace type is expected as the `globals` argument during annotations evaluation. +""" + +MappingNamespace: TypeAlias = Mapping[str, Any] +"""Any kind of namespace. + +In most cases, this is a local namespace (e.g. the `__dict__` attribute of a class, +the [`f_locals`][frame.f_locals] attribute of a frame object, when dealing with types +defined inside functions). +This namespace type is expected as the `locals` argument during annotations evaluation. +""" + +_TypeVarLike: TypeAlias = 'TypeVar | ParamSpec | TypeVarTuple' + + +class NamespacesTuple(NamedTuple): + """A tuple of globals and locals to be used during annotations evaluation. + + This datastructure is defined as a named tuple so that it can easily be unpacked: + + ```python {lint="skip" test="skip"} + def eval_type(typ: type[Any], ns: NamespacesTuple) -> None: + return eval(typ, *ns) + ``` + """ + + globals: GlobalsNamespace + """The namespace to be used as the `globals` argument during annotations evaluation.""" + + locals: MappingNamespace + """The namespace to be used as the `locals` argument during annotations evaluation.""" + + +def get_module_ns_of(obj: Any) -> dict[str, Any]: + """Get the namespace of the module where the object is defined. + + Caution: this function does not return a copy of the module namespace, so the result + should not be mutated. The burden of enforcing this is on the caller. + """ + module_name = getattr(obj, '__module__', None) + if module_name: + try: + return sys.modules[module_name].__dict__ + except KeyError: + # happens occasionally, see https://github.com/pydantic/pydantic/issues/2363 + return {} + return {} + + +# Note that this class is almost identical to `collections.ChainMap`, but need to enforce +# immutable mappings here: +class LazyLocalNamespace(Mapping[str, Any]): + """A lazily evaluated mapping, to be used as the `locals` argument during annotations evaluation. + + While the [`eval`][eval] function expects a mapping as the `locals` argument, it only + performs `__getitem__` calls. The [`Mapping`][collections.abc.Mapping] abstract base class + is fully implemented only for type checking purposes. + + Args: + *namespaces: The namespaces to consider, in ascending order of priority. + + Example: + ```python {lint="skip" test="skip"} + ns = LazyLocalNamespace({'a': 1, 'b': 2}, {'a': 3}) + ns['a'] + #> 3 + ns['b'] + #> 2 + ``` + """ + + def __init__(self, *namespaces: MappingNamespace) -> None: + self._namespaces = namespaces + + @cached_property + def data(self) -> dict[str, Any]: + return {k: v for ns in self._namespaces for k, v in ns.items()} + + def __len__(self) -> int: + return len(self.data) + + def __getitem__(self, key: str) -> Any: + return self.data[key] + + def __contains__(self, key: object) -> bool: + return key in self.data + + def __iter__(self) -> Iterator[str]: + return iter(self.data) + + +def ns_for_function(obj: Callable[..., Any], parent_namespace: MappingNamespace | None = None) -> NamespacesTuple: + """Return the global and local namespaces to be used when evaluating annotations for the provided function. + + The global namespace will be the `__dict__` attribute of the module the function was defined in. + The local namespace will contain the `__type_params__` introduced by PEP 695. + + Args: + obj: The object to use when building namespaces. + parent_namespace: Optional namespace to be added with the lowest priority in the local namespace. + If the passed function is a method, the `parent_namespace` will be the namespace of the class + the method is defined in. Thus, we also fetch type `__type_params__` from there (i.e. the + class-scoped type variables). + """ + locals_list: list[MappingNamespace] = [] + if parent_namespace is not None: + locals_list.append(parent_namespace) + + # Get the `__type_params__` attribute introduced by PEP 695. + # Note that the `typing._eval_type` function expects type params to be + # passed as a separate argument. However, internally, `_eval_type` calls + # `ForwardRef._evaluate` which will merge type params with the localns, + # essentially mimicking what we do here. + type_params: tuple[_TypeVarLike, ...] = getattr(obj, '__type_params__', ()) + if parent_namespace is not None: + # We also fetch type params from the parent namespace. If present, it probably + # means the function was defined in a class. This is to support the following: + # https://github.com/python/cpython/issues/124089. + type_params += parent_namespace.get('__type_params__', ()) + + locals_list.append({t.__name__: t for t in type_params}) + + # What about short-circuiting to `obj.__globals__`? + globalns = get_module_ns_of(obj) + + return NamespacesTuple(globalns, LazyLocalNamespace(*locals_list)) + + +class NsResolver: + """A class responsible for the namespaces resolving logic for annotations evaluation. + + This class handles the namespace logic when evaluating annotations mainly for class objects. + + It holds a stack of classes that are being inspected during the core schema building, + and the `types_namespace` property exposes the globals and locals to be used for + type annotation evaluation. Additionally -- if no class is present in the stack -- a + fallback globals and locals can be provided using the `namespaces_tuple` argument + (this is useful when generating a schema for a simple annotation, e.g. when using + `TypeAdapter`). + + The namespace creation logic is unfortunately flawed in some cases, for backwards + compatibility reasons and to better support valid edge cases. See the description + for the `parent_namespace` argument and the example for more details. + + Args: + namespaces_tuple: The default globals and locals to use if no class is present + on the stack. This can be useful when using the `GenerateSchema` class + with `TypeAdapter`, where the "type" being analyzed is a simple annotation. + parent_namespace: An optional parent namespace that will be added to the locals + with the lowest priority. For a given class defined in a function, the locals + of this function are usually used as the parent namespace: + + ```python {lint="skip" test="skip"} + from pydantic import BaseModel + + def func() -> None: + SomeType = int + + class Model(BaseModel): + f: 'SomeType' + + # when collecting fields, an namespace resolver instance will be created + # this way: + # ns_resolver = NsResolver(parent_namespace={'SomeType': SomeType}) + ``` + + For backwards compatibility reasons and to support valid edge cases, this parent + namespace will be used for *every* type being pushed to the stack. In the future, + we might want to be smarter by only doing so when the type being pushed is defined + in the same module as the parent namespace. + + Example: + ```python {lint="skip" test="skip"} + ns_resolver = NsResolver( + parent_namespace={'fallback': 1}, + ) + + class Sub: + m: 'Model' + + class Model: + some_local = 1 + sub: Sub + + ns_resolver = NsResolver() + + # This is roughly what happens when we build a core schema for `Model`: + with ns_resolver.push(Model): + ns_resolver.types_namespace + #> NamespacesTuple({'Sub': Sub}, {'Model': Model, 'some_local': 1}) + # First thing to notice here, the model being pushed is added to the locals. + # Because `NsResolver` is being used during the model definition, it is not + # yet added to the globals. This is useful when resolving self-referencing annotations. + + with ns_resolver.push(Sub): + ns_resolver.types_namespace + #> NamespacesTuple({'Sub': Sub}, {'Sub': Sub, 'Model': Model}) + # Second thing to notice: `Sub` is present in both the globals and locals. + # This is not an issue, just that as described above, the model being pushed + # is added to the locals, but it happens to be present in the globals as well + # because it is already defined. + # Third thing to notice: `Model` is also added in locals. This is a backwards + # compatibility workaround that allows for `Sub` to be able to resolve `'Model'` + # correctly (as otherwise models would have to be rebuilt even though this + # doesn't look necessary). + ``` + """ + + def __init__( + self, + namespaces_tuple: NamespacesTuple | None = None, + parent_namespace: MappingNamespace | None = None, + ) -> None: + self._base_ns_tuple = namespaces_tuple or NamespacesTuple({}, {}) + self._parent_ns = parent_namespace + self._types_stack: list[type[Any] | TypeAliasType] = [] + + @cached_property + def types_namespace(self) -> NamespacesTuple: + """The current global and local namespaces to be used for annotations evaluation.""" + if not self._types_stack: + # TODO: should we merge the parent namespace here? + # This is relevant for TypeAdapter, where there are no types on the stack, and we might + # need access to the parent_ns. Right now, we sidestep this in `type_adapter.py` by passing + # locals to both parent_ns and the base_ns_tuple, but this is a bit hacky. + # we might consider something like: + # if self._parent_ns is not None: + # # Hacky workarounds, see class docstring: + # # An optional parent namespace that will be added to the locals with the lowest priority + # locals_list: list[MappingNamespace] = [self._parent_ns, self._base_ns_tuple.locals] + # return NamespacesTuple(self._base_ns_tuple.globals, LazyLocalNamespace(*locals_list)) + return self._base_ns_tuple + + typ = self._types_stack[-1] + + globalns = get_module_ns_of(typ) + + locals_list: list[MappingNamespace] = [] + # Hacky workarounds, see class docstring: + # An optional parent namespace that will be added to the locals with the lowest priority + if self._parent_ns is not None: + locals_list.append(self._parent_ns) + if len(self._types_stack) > 1: + first_type = self._types_stack[0] + locals_list.append({first_type.__name__: first_type}) + + # Adding `__type_params__` *before* `vars(typ)`, as the latter takes priority + # (see https://github.com/python/cpython/pull/120272). + # TODO `typ.__type_params__` when we drop support for Python 3.11: + type_params: tuple[_TypeVarLike, ...] = getattr(typ, '__type_params__', ()) + if type_params: + # Adding `__type_params__` is mostly useful for generic classes defined using + # PEP 695 syntax *and* using forward annotations (see the example in + # https://github.com/python/cpython/issues/114053). For TypeAliasType instances, + # it is way less common, but still required if using a string annotation in the alias + # value, e.g. `type A[T] = 'T'` (which is not necessary in most cases). + locals_list.append({t.__name__: t for t in type_params}) + + # TypeAliasType instances don't have a `__dict__` attribute, so the check + # is necessary: + if hasattr(typ, '__dict__'): + locals_list.append(vars(typ)) + + # The `len(self._types_stack) > 1` check above prevents this from being added twice: + locals_list.append({typ.__name__: typ}) + + return NamespacesTuple(globalns, LazyLocalNamespace(*locals_list)) + + @contextmanager + def push(self, typ: type[Any] | TypeAliasType, /) -> Generator[None]: + """Push a type to the stack.""" + self._types_stack.append(typ) + # Reset the cached property: + self.__dict__.pop('types_namespace', None) + try: + yield + finally: + self._types_stack.pop() + self.__dict__.pop('types_namespace', None) diff --git a/source/target-vendors/cp312/pydantic/_internal/_repr.py b/source/target-vendors/cp312/pydantic/_internal/_repr.py new file mode 100644 index 0000000..7e80a9c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_repr.py @@ -0,0 +1,124 @@ +"""Tools to provide pretty/human-readable display of objects.""" + +from __future__ import annotations as _annotations + +import types +from collections.abc import Callable, Collection, Generator, Iterable +from typing import TYPE_CHECKING, Any, ForwardRef, cast + +import typing_extensions +from typing_extensions import TypeAlias +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from . import _typing_extra + +if TYPE_CHECKING: + # TODO remove type error comments when we drop support for Python 3.9 + ReprArgs: TypeAlias = Iterable[tuple[str | None, Any]] # pyright: ignore[reportGeneralTypeIssues] + RichReprResult: TypeAlias = Iterable[Any | tuple[Any] | tuple[str, Any] | tuple[str, Any, Any]] # pyright: ignore[reportGeneralTypeIssues] + + +class PlainRepr(str): + """String class where repr doesn't include quotes. Useful with Representation when you want to return a string + representation of something that is valid (or pseudo-valid) python. + """ + + def __repr__(self) -> str: + return str(self) + + +class Representation: + # Mixin to provide `__str__`, `__repr__`, and `__pretty__` and `__rich_repr__` methods. + # `__pretty__` is used by [devtools](https://python-devtools.helpmanual.io/). + # `__rich_repr__` is used by [rich](https://rich.readthedocs.io/en/stable/pretty.html). + # (this is not a docstring to avoid adding a docstring to classes which inherit from Representation) + + __slots__ = () + + def __repr_args__(self) -> ReprArgs: + """Returns the attributes to show in __str__, __repr__, and __pretty__ this is generally overridden. + + Can either return: + * name - value pairs, e.g.: `[('foo_name', 'foo'), ('bar_name', ['b', 'a', 'r'])]` + * or, just values, e.g.: `[(None, 'foo'), (None, ['b', 'a', 'r'])]` + """ + attrs_names = cast(Collection[str], self.__slots__) + if not attrs_names and hasattr(self, '__dict__'): + attrs_names = self.__dict__.keys() + attrs = ((s, getattr(self, s)) for s in attrs_names) + return [(a, v if v is not self else self.__repr_recursion__(v)) for a, v in attrs if v is not None] + + def __repr_name__(self) -> str: + """Name of the instance's class, used in __repr__.""" + return self.__class__.__name__ + + def __repr_recursion__(self, object: Any) -> str: + """Returns the string representation of a recursive object.""" + # This is copied over from the stdlib `pprint` module: + return f'' + + def __repr_str__(self, join_str: str) -> str: + return join_str.join(repr(v) if a is None else f'{a}={v!r}' for a, v in self.__repr_args__()) + + def __pretty__(self, fmt: Callable[[Any], Any], **kwargs: Any) -> Generator[Any]: + """Used by devtools (https://python-devtools.helpmanual.io/) to pretty print objects.""" + yield self.__repr_name__() + '(' + yield 1 + for name, value in self.__repr_args__(): + if name is not None: + yield name + '=' + yield fmt(value) + yield ',' + yield 0 + yield -1 + yield ')' + + def __rich_repr__(self) -> RichReprResult: + """Used by Rich (https://rich.readthedocs.io/en/stable/pretty.html) to pretty print objects.""" + for name, field_repr in self.__repr_args__(): + if name is None: + yield field_repr + else: + yield name, field_repr + + def __str__(self) -> str: + return self.__repr_str__(' ') + + def __repr__(self) -> str: + return f'{self.__repr_name__()}({self.__repr_str__(", ")})' + + +def display_as_type(obj: Any) -> str: + """Pretty representation of a type, should be as close as possible to the original type definition string. + + Takes some logic from `typing._type_repr`. + """ + if isinstance(obj, (types.FunctionType, types.BuiltinFunctionType)): + return obj.__name__ + elif obj is ...: + return '...' + elif isinstance(obj, Representation): + return repr(obj) + elif isinstance(obj, ForwardRef) or typing_objects.is_typealiastype(obj): + return str(obj) + + if not isinstance(obj, (_typing_extra.typing_base, _typing_extra.WithArgsTypes, type)): + obj = obj.__class__ + + if is_union_origin(typing_extensions.get_origin(obj)): + args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) + return f'Union[{args}]' + elif isinstance(obj, _typing_extra.WithArgsTypes): + if typing_objects.is_literal(typing_extensions.get_origin(obj)): + args = ', '.join(map(repr, typing_extensions.get_args(obj))) + else: + args = ', '.join(map(display_as_type, typing_extensions.get_args(obj))) + try: + return f'{obj.__qualname__}[{args}]' + except AttributeError: + return str(obj).replace('typing.', '').replace('typing_extensions.', '') # handles TypeAliasType in 3.12 + elif isinstance(obj, type): + return obj.__qualname__ + else: + return repr(obj).replace('typing.', '').replace('typing_extensions.', '') diff --git a/source/target-vendors/cp312/pydantic/_internal/_schema_gather.py b/source/target-vendors/cp312/pydantic/_internal/_schema_gather.py new file mode 100644 index 0000000..8e07b20 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_schema_gather.py @@ -0,0 +1,212 @@ +# pyright: reportTypedDictNotRequiredAccess=false, reportGeneralTypeIssues=false, reportArgumentType=false, reportAttributeAccessIssue=false +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import TypedDict + +from pydantic_core.core_schema import ( + ComputedField, + CoreSchema, + DefinitionReferenceSchema, + SerSchema, + iter_union_choices, +) +from typing_extensions import TypeAlias + +AllSchemas: TypeAlias = 'CoreSchema | SerSchema | ComputedField' + + +class GatherResult(TypedDict): + """Schema traversing result.""" + + collected_references: dict[str, DefinitionReferenceSchema | None] + """The collected definition references. + + If a definition reference schema can be inlined, it means that there is + only one in the whole core schema. As such, it is stored as the value. + Otherwise, the value is set to `None`. + """ + + deferred_discriminator_schemas: list[CoreSchema] + """The list of core schemas having the discriminator application deferred.""" + + +class MissingDefinitionError(LookupError): + """A reference was pointing to a non-existing core schema.""" + + def __init__(self, schema_reference: str, /) -> None: + self.schema_reference = schema_reference + + +@dataclass +class GatherContext: + """The current context used during core schema traversing. + + Context instances should only be used during schema traversing. + """ + + definitions: dict[str, CoreSchema] + """The available definitions.""" + + deferred_discriminator_schemas: list[CoreSchema] = field(init=False, default_factory=list) + """The list of core schemas having the discriminator application deferred. + + Internally, these core schemas have a specific key set in the core metadata dict. + """ + + collected_references: dict[str, DefinitionReferenceSchema | None] = field(init=False, default_factory=dict) + """The collected definition references. + + If a definition reference schema can be inlined, it means that there is + only one in the whole core schema. As such, it is stored as the value. + Otherwise, the value is set to `None`. + + During schema traversing, definition reference schemas can be added as candidates, or removed + (by setting the value to `None`). + """ + + +def traverse_metadata(schema: AllSchemas, ctx: GatherContext) -> None: + meta = schema.get('metadata') + if meta is not None and 'pydantic_internal_union_discriminator' in meta: + ctx.deferred_discriminator_schemas.append(schema) # pyright: ignore[reportArgumentType] + + +def traverse_definition_ref(def_ref_schema: DefinitionReferenceSchema, ctx: GatherContext) -> None: + schema_ref = def_ref_schema['schema_ref'] + + if schema_ref not in ctx.collected_references: + definition = ctx.definitions.get(schema_ref) + if definition is None: + raise MissingDefinitionError(schema_ref) + + # The `'definition-ref'` schema was only encountered once, make it + # a candidate to be inlined: + ctx.collected_references[schema_ref] = def_ref_schema + traverse_schema(definition, ctx) + if 'serialization' in def_ref_schema: + traverse_schema(def_ref_schema['serialization'], ctx) + traverse_metadata(def_ref_schema, ctx) + else: + # The `'definition-ref'` schema was already encountered, meaning + # the previously encountered schema (and this one) can't be inlined: + ctx.collected_references[schema_ref] = None + + +def traverse_schema(schema: AllSchemas, context: GatherContext) -> None: + # TODO When we drop 3.9, use a match statement to get better type checking and remove + # file-level type ignore. + # (the `'type'` could also be fetched in every `if/elif` statement, but this alters performance). + schema_type = schema['type'] + + if schema_type == 'definition-ref': + traverse_definition_ref(schema, context) + # `traverse_definition_ref` handles the possible serialization and metadata schemas: + return + elif schema_type == 'definitions': + traverse_schema(schema['schema'], context) + for definition in schema['definitions']: + traverse_schema(definition, context) + elif schema_type in {'list', 'set', 'frozenset', 'generator'}: + if 'items_schema' in schema: + traverse_schema(schema['items_schema'], context) + elif schema_type == 'tuple': + if 'items_schema' in schema: + for s in schema['items_schema']: + traverse_schema(s, context) + elif schema_type == 'dict': + if 'keys_schema' in schema: + traverse_schema(schema['keys_schema'], context) + if 'values_schema' in schema: + traverse_schema(schema['values_schema'], context) + elif schema_type == 'union': + for choice in iter_union_choices(schema): + traverse_schema(choice, context) + elif schema_type == 'tagged-union': + for v in schema['choices'].values(): + traverse_schema(v, context) + elif schema_type == 'chain': + for step in schema['steps']: + traverse_schema(step, context) + elif schema_type == 'lax-or-strict': + traverse_schema(schema['lax_schema'], context) + traverse_schema(schema['strict_schema'], context) + elif schema_type == 'json-or-python': + traverse_schema(schema['json_schema'], context) + traverse_schema(schema['python_schema'], context) + elif schema_type in {'model-fields', 'typed-dict'}: + if 'extras_schema' in schema: + traverse_schema(schema['extras_schema'], context) + if 'computed_fields' in schema: + for s in schema['computed_fields']: + traverse_schema(s, context) + for s in schema['fields'].values(): + traverse_schema(s, context) + elif schema_type == 'dataclass-args': + if 'computed_fields' in schema: + for s in schema['computed_fields']: + traverse_schema(s, context) + for s in schema['fields']: + traverse_schema(s, context) + elif schema_type == 'arguments': + for s in schema['arguments_schema']: + traverse_schema(s['schema'], context) + if 'var_args_schema' in schema: + traverse_schema(schema['var_args_schema'], context) + if 'var_kwargs_schema' in schema: + traverse_schema(schema['var_kwargs_schema'], context) + elif schema_type == 'arguments-v3': + for s in schema['arguments_schema']: + traverse_schema(s['schema'], context) + elif schema_type == 'call': + traverse_schema(schema['arguments_schema'], context) + if 'return_schema' in schema: + traverse_schema(schema['return_schema'], context) + elif schema_type == 'computed-field': + traverse_schema(schema['return_schema'], context) + elif schema_type == 'function-before': + if 'schema' in schema: + traverse_schema(schema['schema'], context) + if 'json_schema_input_schema' in schema: + traverse_schema(schema['json_schema_input_schema'], context) + elif schema_type == 'function-plain': + # TODO duplicate schema types for serializers and validators, needs to be deduplicated. + if 'return_schema' in schema: + traverse_schema(schema['return_schema'], context) + if 'json_schema_input_schema' in schema: + traverse_schema(schema['json_schema_input_schema'], context) + elif schema_type == 'function-wrap': + # TODO duplicate schema types for serializers and validators, needs to be deduplicated. + if 'return_schema' in schema: + traverse_schema(schema['return_schema'], context) + if 'schema' in schema: + traverse_schema(schema['schema'], context) + if 'json_schema_input_schema' in schema: + traverse_schema(schema['json_schema_input_schema'], context) + else: + if 'schema' in schema: + traverse_schema(schema['schema'], context) + + if 'serialization' in schema: + traverse_schema(schema['serialization'], context) + traverse_metadata(schema, context) + + +def gather_schemas_for_cleaning(schema: CoreSchema, definitions: dict[str, CoreSchema]) -> GatherResult: + """Traverse the core schema and definitions and return the necessary information for schema cleaning. + + During the core schema traversing, any `'definition-ref'` schema is: + + - Validated: the reference must point to an existing definition. If this is not the case, a + `MissingDefinitionError` exception is raised. + - Stored in the context: the actual reference is stored in the context. Depending on whether + the `'definition-ref'` schema is encountered more that once, the schema itself is also + saved in the context to be inlined (i.e. replaced by the definition it points to). + """ + context = GatherContext(definitions) + traverse_schema(schema, context) + + return { + 'collected_references': context.collected_references, + 'deferred_discriminator_schemas': context.deferred_discriminator_schemas, + } diff --git a/source/target-vendors/cp312/pydantic/_internal/_schema_generation_shared.py b/source/target-vendors/cp312/pydantic/_internal/_schema_generation_shared.py new file mode 100644 index 0000000..b231a82 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_schema_generation_shared.py @@ -0,0 +1,125 @@ +"""Types and utility functions used by various other internal tools.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any, Callable, Literal + +from pydantic_core import core_schema + +from ..annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler + +if TYPE_CHECKING: + from ..json_schema import GenerateJsonSchema, JsonSchemaValue + from ._core_utils import CoreSchemaOrField + from ._generate_schema import GenerateSchema + from ._namespace_utils import NamespacesTuple + + GetJsonSchemaFunction = Callable[[CoreSchemaOrField, GetJsonSchemaHandler], JsonSchemaValue] + HandlerOverride = Callable[[CoreSchemaOrField], JsonSchemaValue] + + +class GenerateJsonSchemaHandler(GetJsonSchemaHandler): + """JsonSchemaHandler implementation that doesn't do ref unwrapping by default. + + This is used for any Annotated metadata so that we don't end up with conflicting + modifications to the definition schema. + + Used internally by Pydantic, please do not rely on this implementation. + See `GetJsonSchemaHandler` for the handler API. + """ + + def __init__(self, generate_json_schema: GenerateJsonSchema, handler_override: HandlerOverride | None) -> None: + self.generate_json_schema = generate_json_schema + self.handler = handler_override or generate_json_schema.generate_inner + self.mode = generate_json_schema.mode + + def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue: + return self.handler(core_schema) + + def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue) -> JsonSchemaValue: + """Resolves `$ref` in the json schema. + + This returns the input json schema if there is no `$ref` in json schema. + + Args: + maybe_ref_json_schema: The input json schema that may contains `$ref`. + + Returns: + Resolved json schema. + + Raises: + LookupError: If it can't find the definition for `$ref`. + """ + if '$ref' not in maybe_ref_json_schema: + return maybe_ref_json_schema + ref = maybe_ref_json_schema['$ref'] + json_schema = self.generate_json_schema.get_schema_from_definitions(ref) + if json_schema is None: + raise LookupError( + f'Could not find a ref for {ref}.' + ' Maybe you tried to call resolve_ref_schema from within a recursive model?' + ) + return json_schema + + +class CallbackGetCoreSchemaHandler(GetCoreSchemaHandler): + """Wrapper to use an arbitrary function as a `GetCoreSchemaHandler`. + + Used internally by Pydantic, please do not rely on this implementation. + See `GetCoreSchemaHandler` for the handler API. + """ + + def __init__( + self, + handler: Callable[[Any], core_schema.CoreSchema], + generate_schema: GenerateSchema, + ref_mode: Literal['to-def', 'unpack'] = 'to-def', + ) -> None: + self._handler = handler + self._generate_schema = generate_schema + self._ref_mode = ref_mode + + def __call__(self, source_type: Any, /) -> core_schema.CoreSchema: + schema = self._handler(source_type) + if self._ref_mode == 'to-def': + ref = schema.get('ref') + if ref is not None: + return self._generate_schema.defs.create_definition_reference_schema(schema) + return schema + else: # ref_mode = 'unpack' + return self.resolve_ref_schema(schema) + + def _get_types_namespace(self) -> NamespacesTuple: + return self._generate_schema._types_namespace + + def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema: + return self._generate_schema.generate_schema(source_type) + + @property + def field_name(self) -> str | None: + return self._generate_schema.field_name_stack.get() + + def resolve_ref_schema(self, maybe_ref_schema: core_schema.CoreSchema) -> core_schema.CoreSchema: + """Resolves reference in the core schema. + + Args: + maybe_ref_schema: The input core schema that may contains reference. + + Returns: + Resolved core schema. + + Raises: + LookupError: If it can't find the definition for reference. + """ + if maybe_ref_schema['type'] == 'definition-ref': + ref = maybe_ref_schema['schema_ref'] + definition = self._generate_schema.defs.get_schema_from_ref(ref) + if definition is None: + raise LookupError( + f'Could not find a ref for {ref}.' + ' Maybe you tried to call resolve_ref_schema from within a recursive model?' + ) + return definition + elif maybe_ref_schema['type'] == 'definitions': + return self.resolve_ref_schema(maybe_ref_schema['schema']) + return maybe_ref_schema diff --git a/source/target-vendors/cp312/pydantic/_internal/_serializers.py b/source/target-vendors/cp312/pydantic/_internal/_serializers.py new file mode 100644 index 0000000..a4058e0 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_serializers.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import collections +import collections.abc +import typing +from typing import Any + +from pydantic_core import PydanticOmit, core_schema + +SEQUENCE_ORIGIN_MAP: dict[Any, Any] = { + typing.Deque: collections.deque, # noqa: UP006 + collections.deque: collections.deque, + list: list, + typing.List: list, # noqa: UP006 + tuple: tuple, + typing.Tuple: tuple, # noqa: UP006 + set: set, + typing.AbstractSet: set, + typing.Set: set, # noqa: UP006 + frozenset: frozenset, + typing.FrozenSet: frozenset, # noqa: UP006 + typing.Sequence: list, + typing.MutableSequence: list, + typing.MutableSet: set, + # this doesn't handle subclasses of these + # parametrized typing.Set creates one of these + collections.abc.MutableSet: set, + collections.abc.Set: frozenset, +} + + +def serialize_sequence_via_list( + v: Any, handler: core_schema.SerializerFunctionWrapHandler, info: core_schema.SerializationInfo +) -> Any: + items: list[Any] = [] + + mapped_origin = SEQUENCE_ORIGIN_MAP.get(type(v), None) + if mapped_origin is None: + # we shouldn't hit this branch, should probably add a serialization error or something + return v + + for index, item in enumerate(v): + try: + v = handler(item, index) + except PydanticOmit: # noqa: PERF203 + pass + else: + items.append(v) + + if info.mode_is_json(): + return items + else: + return mapped_origin(items) diff --git a/source/target-vendors/cp312/pydantic/_internal/_signature.py b/source/target-vendors/cp312/pydantic/_internal/_signature.py new file mode 100644 index 0000000..3b0c5ae --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_signature.py @@ -0,0 +1,189 @@ +from __future__ import annotations + +import dataclasses +from inspect import Parameter, Signature +from typing import TYPE_CHECKING, Any, Callable + +from pydantic_core import PydanticUndefined + +from ._typing_extra import signature_no_eval +from ._utils import is_valid_identifier + +if TYPE_CHECKING: + from ..config import ExtraValues + from ..fields import FieldInfo + + +# Copied over from stdlib dataclasses +class _HAS_DEFAULT_FACTORY_CLASS: + def __repr__(self): + return '' + + +_HAS_DEFAULT_FACTORY = _HAS_DEFAULT_FACTORY_CLASS() + + +def _field_name_for_signature(field_name: str, field_info: FieldInfo) -> str: + """Extract the correct name to use for the field when generating a signature. + + Assuming the field has a valid alias, this will return the alias. Otherwise, it will return the field name. + First priority is given to the alias, then the validation_alias, then the field name. + + Args: + field_name: The name of the field + field_info: The corresponding FieldInfo object. + + Returns: + The correct name to use when generating a signature. + """ + if isinstance(field_info.alias, str) and is_valid_identifier(field_info.alias): + return field_info.alias + if isinstance(field_info.validation_alias, str) and is_valid_identifier(field_info.validation_alias): + return field_info.validation_alias + + return field_name + + +def _process_param_defaults(param: Parameter) -> Parameter: + """Modify the signature for a parameter in a dataclass where the default value is a FieldInfo instance. + + Args: + param (Parameter): The parameter + + Returns: + Parameter: The custom processed parameter + """ + from ..fields import FieldInfo + + param_default = param.default + if isinstance(param_default, FieldInfo): + annotation = param.annotation + # Replace the annotation if appropriate + # inspect does "clever" things to show annotations as strings because we have + # `from __future__ import annotations` in main, we don't want that + if annotation == 'Any': + annotation = Any + + # Replace the field default + default = param_default.default + if default is PydanticUndefined: + if param_default.default_factory is None: + default = Signature.empty + else: + # this is used by dataclasses to indicate a factory exists: + default = dataclasses._HAS_DEFAULT_FACTORY # type: ignore + return param.replace( + annotation=annotation, name=_field_name_for_signature(param.name, param_default), default=default + ) + return param + + +def _generate_signature_parameters( # noqa: C901 (ignore complexity, could use a refactor) + init: Callable[..., None], + fields: dict[str, FieldInfo], + validate_by_name: bool, + extra: ExtraValues | None, +) -> dict[str, Parameter]: + """Generate a mapping of parameter names to Parameter objects for a pydantic BaseModel or dataclass.""" + from itertools import islice + + present_params = signature_no_eval(init).parameters.values() + merged_params: dict[str, Parameter] = {} + var_kw = None + use_var_kw = False + + for param in islice(present_params, 1, None): # skip self arg + # inspect does "clever" things to show annotations as strings because we have + # `from __future__ import annotations` in main, we don't want that + if fields.get(param.name): + # exclude params with init=False + if getattr(fields[param.name], 'init', True) is False: + continue + param = param.replace(name=_field_name_for_signature(param.name, fields[param.name])) + if param.annotation == 'Any': + param = param.replace(annotation=Any) + if param.kind is param.VAR_KEYWORD: + var_kw = param + continue + merged_params[param.name] = param + + if var_kw: # if custom init has no var_kw, fields which are not declared in it cannot be passed through + allow_names = validate_by_name + for field_name, field in fields.items(): + # when alias is a str it should be used for signature generation + param_name = _field_name_for_signature(field_name, field) + + if field_name in merged_params or param_name in merged_params: + continue + + if not is_valid_identifier(param_name): + if allow_names: + param_name = field_name + else: + use_var_kw = True + continue + + if field.is_required(): + default = Parameter.empty + elif field.default_factory is not None: + # Mimics stdlib dataclasses: + default = _HAS_DEFAULT_FACTORY + else: + default = field.default + merged_params[param_name] = Parameter( + param_name, + Parameter.KEYWORD_ONLY, + annotation=field.rebuild_annotation(), + default=default, + ) + + if extra == 'allow': + use_var_kw = True + + if var_kw and use_var_kw: + # Make sure the parameter for extra kwargs + # does not have the same name as a field + default_model_signature = [ + ('self', Parameter.POSITIONAL_ONLY), + ('data', Parameter.VAR_KEYWORD), + ] + if [(p.name, p.kind) for p in present_params] == default_model_signature: + # if this is the standard model signature, use extra_data as the extra args name + var_kw_name = 'extra_data' + else: + # else start from var_kw + var_kw_name = var_kw.name + + # generate a name that's definitely unique + while var_kw_name in fields: + var_kw_name += '_' + merged_params[var_kw_name] = var_kw.replace(name=var_kw_name) + + return merged_params + + +def generate_pydantic_signature( + init: Callable[..., None], + fields: dict[str, FieldInfo], + validate_by_name: bool, + extra: ExtraValues | None, + is_dataclass: bool = False, +) -> Signature: + """Generate signature for a pydantic BaseModel or dataclass. + + Args: + init: The class init. + fields: The model fields. + validate_by_name: The `validate_by_name` value of the config. + extra: The `extra` value of the config. + is_dataclass: Whether the model is a dataclass. + + Returns: + The dataclass/BaseModel subclass signature. + """ + merged_params = _generate_signature_parameters(init, fields, validate_by_name, extra) + + if is_dataclass: + merged_params = {k: _process_param_defaults(v) for k, v in merged_params.items()} + + return Signature(parameters=list(merged_params.values()), return_annotation=None) diff --git a/source/target-vendors/cp312/pydantic/_internal/_typing_extra.py b/source/target-vendors/cp312/pydantic/_internal/_typing_extra.py new file mode 100644 index 0000000..c217f11 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_typing_extra.py @@ -0,0 +1,785 @@ +"""Logic for interacting with type annotations, mostly extensions, shims and hacks to wrap Python's typing module.""" + +from __future__ import annotations + +import collections.abc +import re +import sys +import types +import typing +from functools import partial +from inspect import Signature, signature +from typing import TYPE_CHECKING, Any, Callable, cast + +import typing_extensions +from typing_extensions import deprecated, get_args, get_origin +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from pydantic.version import version_short + +from ._namespace_utils import GlobalsNamespace, MappingNamespace, NsResolver, get_module_ns_of + +if sys.version_info < (3, 10): + NoneType = type(None) + EllipsisType = type(Ellipsis) +else: + from types import EllipsisType as EllipsisType + from types import NoneType as NoneType + +if sys.version_info >= (3, 14): + import annotationlib + +if TYPE_CHECKING: + from pydantic import BaseModel + from pydantic.fields import FieldInfo + +# As per https://typing-extensions.readthedocs.io/en/latest/#runtime-use-of-types, +# always check for both `typing` and `typing_extensions` variants of a typing construct. +# (this is implemented differently than the suggested approach in the `typing_extensions` +# docs for performance). + + +_t_annotated = typing.Annotated +_te_annotated = typing_extensions.Annotated + + +def is_annotated(tp: Any, /) -> bool: + """Return whether the provided argument is a `Annotated` special form. + + ```python {test="skip" lint="skip"} + is_annotated(Annotated[int, ...]) + #> True + ``` + """ + origin = get_origin(tp) + return origin is _t_annotated or origin is _te_annotated + + +def annotated_type(tp: Any, /) -> Any | None: + """Return the type of the `Annotated` special form, or `None`.""" + return tp.__origin__ if typing_objects.is_annotated(get_origin(tp)) else None + + +def unpack_type(tp: Any, /) -> Any | None: + """Return the type wrapped by the `Unpack` special form, or `None`.""" + return get_args(tp)[0] if typing_objects.is_unpack(get_origin(tp)) else None + + +def is_hashable(tp: Any, /) -> bool: + """Return whether the provided argument is the `Hashable` class. + + ```python {test="skip" lint="skip"} + is_hashable(Hashable) + #> True + ``` + """ + # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes, + # hence the second check: + return tp is collections.abc.Hashable or get_origin(tp) is collections.abc.Hashable + + +def is_callable(tp: Any, /) -> bool: + """Return whether the provided argument is a `Callable`, parametrized or not. + + ```python {test="skip" lint="skip"} + is_callable(Callable[[int], str]) + #> True + is_callable(typing.Callable) + #> True + is_callable(collections.abc.Callable) + #> True + ``` + """ + # `get_origin` is documented as normalizing any typing-module aliases to `collections` classes, + # hence the second check: + return tp is collections.abc.Callable or get_origin(tp) is collections.abc.Callable + + +_classvar_re = re.compile(r'((\w+\.)?Annotated\[)?(\w+\.)?ClassVar\[') + + +def is_classvar_annotation(tp: Any, /) -> bool: + """Return whether the provided argument represents a class variable annotation. + + Although not explicitly stated by the typing specification, `ClassVar` can be used + inside `Annotated` and as such, this function checks for this specific scenario. + + Because this function is used to detect class variables before evaluating forward references + (or because evaluation failed), we also implement a naive regex match implementation. This is + required because class variables are inspected before fields are collected, so we try to be + as accurate as possible. + """ + if typing_objects.is_classvar(tp): + return True + + origin = get_origin(tp) + + if typing_objects.is_classvar(origin): + return True + + if typing_objects.is_annotated(origin): + annotated_type = tp.__origin__ + if typing_objects.is_classvar(annotated_type) or typing_objects.is_classvar(get_origin(annotated_type)): + return True + + str_ann: str | None = None + if isinstance(tp, typing.ForwardRef): + str_ann = tp.__forward_arg__ + if isinstance(tp, str): + str_ann = tp + + if str_ann is not None and _classvar_re.match(str_ann): + # stdlib dataclasses do something similar, although a bit more advanced + # (see `dataclass._is_type`). + return True + + return False + + +_t_final = typing.Final +_te_final = typing_extensions.Final + + +# TODO implement `is_finalvar_annotation` as Final can be wrapped with other special forms: +def is_finalvar(tp: Any, /) -> bool: + """Return whether the provided argument is a `Final` special form, parametrized or not. + + ```python {test="skip" lint="skip"} + is_finalvar(Final[int]) + #> True + is_finalvar(Final) + #> True + """ + # Final is not necessarily parametrized: + if tp is _t_final or tp is _te_final: + return True + origin = get_origin(tp) + return origin is _t_final or origin is _te_final + + +_NONE_TYPES: tuple[Any, ...] = (None, NoneType, typing.Literal[None], typing_extensions.Literal[None]) + + +def is_none_type(tp: Any, /) -> bool: + """Return whether the argument represents the `None` type as part of an annotation. + + ```python {test="skip" lint="skip"} + is_none_type(None) + #> True + is_none_type(NoneType) + #> True + is_none_type(Literal[None]) + #> True + is_none_type(type[None]) + #> False + """ + return tp in _NONE_TYPES + + +def is_namedtuple(tp: Any, /) -> bool: + """Return whether the provided argument is a named tuple class. + + The class can be created using `typing.NamedTuple` or `collections.namedtuple`. + Parametrized generic classes are *not* assumed to be named tuples. + """ + from ._utils import lenient_issubclass # circ. import + + return lenient_issubclass(tp, tuple) and hasattr(tp, '_fields') + + +# TODO In 2.12, delete this export. It is currently defined only to not break +# pydantic-settings which relies on it: +origin_is_union = is_union_origin + + +def is_generic_alias(tp: Any, /) -> bool: + return isinstance(tp, (types.GenericAlias, typing._GenericAlias)) # pyright: ignore[reportAttributeAccessIssue] + + +# TODO: Ideally, we should avoid relying on the private `typing` constructs: + +if sys.version_info < (3, 10): + WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # pyright: ignore[reportAttributeAccessIssue] +else: + WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias, types.UnionType) # pyright: ignore[reportAttributeAccessIssue] + + +# Similarly, we shouldn't rely on this `_Final` class, which is even more private than `_GenericAlias`: +typing_base: Any = typing._Final # pyright: ignore[reportAttributeAccessIssue] + + +### Annotation evaluations functions: + + +def parent_frame_namespace(*, parent_depth: int = 2, force: bool = False) -> dict[str, Any] | None: + """Fetch the local namespace of the parent frame where this function is called. + + Using this function is mostly useful to resolve forward annotations pointing to members defined in a local namespace, + such as assignments inside a function. Using the standard library tools, it is currently not possible to resolve + such annotations: + + ```python {lint="skip" test="skip"} + from typing import get_type_hints + + def func() -> None: + Alias = int + + class C: + a: 'Alias' + + # Raises a `NameError: 'Alias' is not defined` + get_type_hints(C) + ``` + + Pydantic uses this function when a Pydantic model is being defined to fetch the parent frame locals. However, + this only allows us to fetch the parent frame namespace and not other parents (e.g. a model defined in a function, + itself defined in another function). Inspecting the next outer frames (using `f_back`) is not reliable enough + (see https://discuss.python.org/t/20659). + + Because this function is mostly used to better resolve forward annotations, nothing is returned if the parent frame's + code object is defined at the module level. In this case, the locals of the frame will be the same as the module + globals where the class is defined (see `_namespace_utils.get_module_ns_of`). However, if you still want to fetch + the module globals (e.g. when rebuilding a model, where the frame where the rebuild call is performed might contain + members that you want to use for forward annotations evaluation), you can use the `force` parameter. + + Args: + parent_depth: The depth at which to get the frame. Defaults to 2, meaning the parent frame where this function + is called will be used. + force: Whether to always return the frame locals, even if the frame's code object is defined at the module level. + + Returns: + The locals of the namespace, or `None` if it was skipped as per the described logic. + """ + frame = sys._getframe(parent_depth) + + if frame.f_code.co_name.startswith('`, + # and we need to skip this frame as it is irrelevant. + frame = cast(types.FrameType, frame.f_back) # guaranteed to not be `None` + + # note, we don't copy frame.f_locals here (or during the last return call), because we don't expect the namespace to be + # modified down the line if this becomes a problem, we could implement some sort of frozen mapping structure to enforce this. + if force: + return frame.f_locals + + # If either of the following conditions are true, the class is defined at the top module level. + # To better understand why we need both of these checks, see + # https://github.com/pydantic/pydantic/pull/10113#discussion_r1714981531. + if frame.f_back is None or frame.f_code.co_name == '': + return None + + return frame.f_locals + + +def _type_convert(arg: Any) -> Any: + """Convert `None` to `NoneType` and strings to `ForwardRef` instances. + + This is a backport of the private `typing._type_convert` function. When + evaluating a type, `ForwardRef._evaluate` ends up being called, and is + responsible for making this conversion. However, we still have to apply + it for the first argument passed to our type evaluation functions, similarly + to the `typing.get_type_hints` function. + """ + if arg is None: + return NoneType + if isinstance(arg, str): + # Like `typing.get_type_hints`, assume the arg can be in any context, + # hence the proper `is_argument` and `is_class` args: + return _make_forward_ref(arg, is_argument=False, is_class=True) + return arg + + +def safe_get_annotations(obj: Any) -> dict[str, Any]: + """Get the annotations for the provided object, accounting for potential deferred forward references. + + Starting with Python 3.14, accessing the `__annotations__` attribute might raise a `NameError` if + a referenced symbol isn't defined yet. In this case, we return the annotation in the *forward ref* + format. + """ + if sys.version_info >= (3, 14): + return annotationlib.get_annotations(obj, format=annotationlib.Format.FORWARDREF) + else: + # TODO just do getattr(obj, '__annotations__', {}) when dropping support for Python 3.9: + if isinstance(obj, type): + return obj.__dict__.get('__annotations__', {}) + else: + return getattr(obj, '__annotations__', {}) + + +def get_model_type_hints( + model_class: type[BaseModel], + *, + ns_resolver: NsResolver | None = None, +) -> dict[str, tuple[Any, bool]]: + """Collect annotations from a Pydantic model class, including those from parent classes. + + Args: + model_class: The Pydantic model class to inspect. + ns_resolver: A namespace resolver instance to use. Defaults to an empty instance. + + Returns: + A dictionary mapping annotation names to a two-tuple: the first element is the evaluated + type or the original annotation if a `NameError` occurred, the second element is a boolean + indicating if whether the evaluation succeeded. + """ + hints: dict[str, Any] | dict[str, tuple[Any, bool]] = {} + ns_resolver = ns_resolver or NsResolver() + + for base in reversed(model_class.__mro__[:-1]): + # For Python 3.14, we could also use `Format.VALUE` and pass the globals/locals + # from the ns_resolver, but we want to be able to know which specific field failed + # to evaluate: + ann = safe_get_annotations(base) + + if not ann: + continue + + with ns_resolver.push(base): + base_model_fields: dict[str, FieldInfo] | None = base.__dict__.get('__pydantic_fields__') + + for name, value in ann.items(): + if name.startswith('_'): + globalns, localns = ns_resolver.types_namespace + + # For private attributes, we only need the annotation to detect the `ClassVar` special form. + # For this reason, we still try to evaluate it, but we also catch any possible exception (on + # top of the `NameError`s caught in `try_eval_type`) that could happen so that users are free + # to use any kind of forward annotation for private fields (e.g. circular imports, new typing + # syntax, etc). + try: + hints[name] = try_eval_type(value, globalns, localns) + except Exception: + hints[name] = (value, False) + else: + if base_model_fields is not None and name in base_model_fields: + # Avoid unnecessarily evaluating annotations from parent models, as we'll end up + # copying the `FieldInfo` instance from it anyway if we need to. + # We use the `annotation` attribute here, but in reality could put anything here, + # As we are guaranteed to not make use of it: + hints[name] = (base_model_fields[name].annotation, True) + else: + globalns, localns = ns_resolver.types_namespace + + hints[name] = try_eval_type(value, globalns, localns) + + return hints + + +def get_cls_type_hints( + obj: type[Any], + *, + ns_resolver: NsResolver | None = None, +) -> dict[str, Any]: + """Collect annotations from a class, including those from parent classes. + + Args: + obj: The class to inspect. + ns_resolver: A namespace resolver instance to use. Defaults to an empty instance. + """ + hints: dict[str, Any] = {} + ns_resolver = ns_resolver or NsResolver() + + for base in reversed(obj.__mro__): + # For Python 3.14, we could also use `Format.VALUE` and pass the globals/locals + # from the ns_resolver, but we want to be able to know which specific field failed + # to evaluate: + ann = safe_get_annotations(base) + + if not ann: + continue + + with ns_resolver.push(base): + globalns, localns = ns_resolver.types_namespace + for name, value in ann.items(): + hints[name] = eval_type(value, globalns, localns) + return hints + + +def try_eval_type( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> tuple[Any, bool]: + """Try evaluating the annotation using the provided namespaces. + + Args: + value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance + of `str`, it will be converted to a `ForwardRef`. + localns: The global namespace to use during annotation evaluation. + globalns: The local namespace to use during annotation evaluation. + + Returns: + A two-tuple containing the possibly evaluated type and a boolean indicating + whether the evaluation succeeded or not. + """ + value = _type_convert(value) + + try: + return eval_type_backport(value, globalns, localns), True + except NameError: + return value, False + + +def eval_type( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> Any: + """Evaluate the annotation using the provided namespaces. + + Args: + value: The value to evaluate. If `None`, it will be replaced by `type[None]`. If an instance + of `str`, it will be converted to a `ForwardRef`. + localns: The global namespace to use during annotation evaluation. + globalns: The local namespace to use during annotation evaluation. + """ + value = _type_convert(value) + return eval_type_backport(value, globalns, localns) + + +@deprecated( + '`eval_type_lenient` is deprecated, use `try_eval_type` instead.', + category=None, +) +def eval_type_lenient( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> Any: + ev, _ = try_eval_type(value, globalns, localns) + return ev + + +def eval_type_backport( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + type_params: tuple[Any, ...] | None = None, +) -> Any: + """An enhanced version of `typing._eval_type` which will fall back to using the `eval_type_backport` + package if it's installed to let older Python versions use newer typing constructs. + + Specifically, this transforms `X | Y` into `typing.Union[X, Y]` and `list[X]` into `typing.List[X]` + (as well as all the types made generic in PEP 585) if the original syntax is not supported in the + current Python version. + + This function will also display a helpful error if the value passed fails to evaluate. + """ + try: + return _eval_type_backport(value, globalns, localns, type_params) + except TypeError as e: + if 'Unable to evaluate type annotation' in str(e): + raise + + # If it is a `TypeError` and value isn't a `ForwardRef`, it would have failed during annotation definition. + # Thus we assert here for type checking purposes: + assert isinstance(value, typing.ForwardRef) + + message = f'Unable to evaluate type annotation {value.__forward_arg__!r}.' + if sys.version_info >= (3, 11): + e.add_note(message) + raise + else: + raise TypeError(message) from e + except RecursionError as e: + # TODO ideally recursion errors should be checked in `eval_type` above, but `eval_type_backport` + # is used directly in some places. + message = ( + "If you made use of an implicit recursive type alias (e.g. `MyType = list['MyType']), " + 'consider using PEP 695 type aliases instead. For more details, refer to the documentation: ' + f'https://docs.pydantic.dev/{version_short()}/concepts/types/#named-recursive-types' + ) + if sys.version_info >= (3, 11): + e.add_note(message) + raise + else: + raise RecursionError(f'{e.args[0]}\n{message}') + + +def _eval_type_backport( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + type_params: tuple[Any, ...] | None = None, +) -> Any: + try: + return _eval_type(value, globalns, localns, type_params) + except TypeError as e: + if not (isinstance(value, typing.ForwardRef) and is_backport_fixable_error(e)): + raise + + try: + from eval_type_backport import eval_type_backport + except ImportError: + raise TypeError( + f'Unable to evaluate type annotation {value.__forward_arg__!r}. If you are making use ' + 'of the new typing syntax (unions using `|` since Python 3.10 or builtins subscripting ' + 'since Python 3.9), you should either replace the use of new syntax with the existing ' + '`typing` constructs or install the `eval_type_backport` package.' + ) from e + + return eval_type_backport( + value, + globalns, + localns, # pyright: ignore[reportArgumentType], waiting on a new `eval_type_backport` release. + try_default=False, + ) + + +def _eval_type( + value: Any, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + type_params: tuple[Any, ...] | None = None, +) -> Any: + if sys.version_info >= (3, 14): + # Starting in 3.14, `_eval_type()` does *not* apply `_type_convert()` + # anymore. This means the `None` -> `type(None)` conversion does not apply: + evaluated = typing._eval_type( # type: ignore + value, + globalns, + localns, + type_params=type_params, + # This is relevant when evaluating types from `TypedDict` classes, where string annotations + # are automatically converted to `ForwardRef` instances with a module set. In this case, + # Our `globalns` is irrelevant and we need to indicate `typing._eval_type()` that it should + # infer it from the `ForwardRef.__forward_module__` attribute instead (`typing.get_type_hints()` + # does the same). Note that this would probably be unnecessary if we properly iterated over the + # `__orig_bases__` for TypedDicts in `get_cls_type_hints()`: + prefer_fwd_module=True, + ) + if evaluated is None: + evaluated = type(None) + return evaluated + elif sys.version_info >= (3, 13): + return typing._eval_type( # type: ignore + value, globalns, localns, type_params=type_params + ) + else: + return typing._eval_type( # type: ignore + value, globalns, localns + ) + + +def is_backport_fixable_error(e: TypeError) -> bool: + msg = str(e) + + return sys.version_info < (3, 10) and msg.startswith('unsupported operand type(s) for |: ') + + +def signature_no_eval(f: Callable[..., Any]) -> Signature: + """Get the signature of a callable without evaluating any annotations.""" + if sys.version_info >= (3, 14): + from annotationlib import Format + + return signature(f, annotation_format=Format.FORWARDREF) + else: + return signature(f) + + +def get_function_type_hints( + function: Callable[..., Any], + *, + include_keys: set[str] | None = None, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, +) -> dict[str, Any]: + """Return type hints for a function. + + This is similar to the `typing.get_type_hints` function, with a few differences: + - Support `functools.partial` by using the underlying `func` attribute. + - Do not wrap type annotation of a parameter with `Optional` if it has a default value of `None` + (related bug: https://github.com/python/cpython/issues/90353, only fixed in 3.11+). + """ + if isinstance(function, partial): + annotations = safe_get_annotations(function.func) + else: + annotations = safe_get_annotations(function) + + if globalns is None: + globalns = get_module_ns_of(function) + type_params: tuple[Any, ...] | None = None + if localns is None: + # If localns was specified, it is assumed to already contain type params. This is because + # Pydantic has more advanced logic to do so (see `_namespace_utils.ns_for_function`). + type_params = getattr(function, '__type_params__', ()) + + type_hints = {} + for name, value in annotations.items(): + if include_keys is not None and name not in include_keys: + continue + if value is None: + value = NoneType + elif isinstance(value, str): + value = _make_forward_ref(value) + + type_hints[name] = eval_type_backport(value, globalns, localns, type_params) + + return type_hints + + +# TODO use typing.ForwardRef directly when we stop supporting 3.9: +if sys.version_info < (3, 9, 8) or (3, 10) <= sys.version_info < (3, 10, 1): + + def _make_forward_ref( + arg: Any, + is_argument: bool = True, + *, + is_class: bool = False, + ) -> typing.ForwardRef: + """Wrapper for ForwardRef that accounts for the `is_class` argument missing in older versions. + The `module` argument is omitted as it breaks <3.9.8, =3.10.0 and isn't used in the calls below. + + See https://github.com/python/cpython/pull/28560 for some background. + The backport happened on 3.9.8, see: + https://github.com/pydantic/pydantic/discussions/6244#discussioncomment-6275458, + and on 3.10.1 for the 3.10 branch, see: + https://github.com/pydantic/pydantic/issues/6912 + + Implemented as EAFP with memory. + """ + return typing.ForwardRef(arg, is_argument) # pyright: ignore[reportCallIssue] + +else: + _make_forward_ref = typing.ForwardRef # pyright: ignore[reportAssignmentType] + + +if sys.version_info >= (3, 10): + get_type_hints = typing.get_type_hints + +else: + """ + For older versions of python, we have a custom implementation of `get_type_hints` which is a close as possible to + the implementation in CPython 3.10.8. + """ + + @typing.no_type_check + def get_type_hints( # noqa: C901 + obj: Any, + globalns: dict[str, Any] | None = None, + localns: dict[str, Any] | None = None, + include_extras: bool = False, + ) -> dict[str, Any]: # pragma: no cover + """Taken verbatim from python 3.10.8 unchanged, except: + * type annotations of the function definition above. + * prefixing `typing.` where appropriate + * Use `_make_forward_ref` instead of `typing.ForwardRef` to handle the `is_class` argument. + + https://github.com/python/cpython/blob/aaaf5174241496afca7ce4d4584570190ff972fe/Lib/typing.py#L1773-L1875 + + DO NOT CHANGE THIS METHOD UNLESS ABSOLUTELY NECESSARY. + ====================================================== + + Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]' with 'T' (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. For classes, the search + order is globals first then locals. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + if getattr(obj, '__no_type_check__', None): + return {} + # Classes require a special treatment. + if isinstance(obj, type): + hints = {} + for base in reversed(obj.__mro__): + if globalns is None: + base_globals = getattr(sys.modules.get(base.__module__, None), '__dict__', {}) + else: + base_globals = globalns + ann = base.__dict__.get('__annotations__', {}) + if isinstance(ann, types.GetSetDescriptorType): + ann = {} + base_locals = dict(vars(base)) if localns is None else localns + if localns is None and globalns is None: + # This is surprising, but required. Before Python 3.10, + # get_type_hints only evaluated the globalns of + # a class. To maintain backwards compatibility, we reverse + # the globalns and localns order so that eval() looks into + # *base_globals* first rather than *base_locals*. + # This only affects ForwardRefs. + base_globals, base_locals = base_locals, base_globals + for name, value in ann.items(): + if value is None: + value = type(None) + if isinstance(value, str): + value = _make_forward_ref(value, is_argument=False, is_class=True) + + value = eval_type_backport(value, base_globals, base_locals) + hints[name] = value + if not include_extras and hasattr(typing, '_strip_annotations'): + return { + k: typing._strip_annotations(t) # type: ignore + for k, t in hints.items() + } + else: + return hints + + if globalns is None: + if isinstance(obj, types.ModuleType): + globalns = obj.__dict__ + else: + nsobj = obj + # Find globalns for the unwrapped object. + while hasattr(nsobj, '__wrapped__'): + nsobj = nsobj.__wrapped__ + globalns = getattr(nsobj, '__globals__', {}) + if localns is None: + localns = globalns + elif localns is None: + localns = globalns + hints = getattr(obj, '__annotations__', None) + if hints is None: + # Return empty annotations for something that _could_ have them. + if isinstance(obj, typing._allowed_types): # type: ignore + return {} + else: + raise TypeError(f'{obj!r} is not a module, class, method, or function.') + defaults = typing._get_defaults(obj) # type: ignore + hints = dict(hints) + for name, value in hints.items(): + if value is None: + value = type(None) + if isinstance(value, str): + # class-level forward refs were handled above, this must be either + # a module-level annotation or a function argument annotation + + value = _make_forward_ref( + value, + is_argument=not isinstance(obj, types.ModuleType), + is_class=False, + ) + value = eval_type_backport(value, globalns, localns) + if name in defaults and defaults[name] is None: + value = typing.Optional[value] + hints[name] = value + return hints if include_extras else {k: typing._strip_annotations(t) for k, t in hints.items()} # type: ignore diff --git a/source/target-vendors/cp312/pydantic/_internal/_utils.py b/source/target-vendors/cp312/pydantic/_internal/_utils.py new file mode 100644 index 0000000..7a0346d --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_utils.py @@ -0,0 +1,446 @@ +"""Bucket of reusable internal utilities. + +This should be reduced as much as possible with functions only used in one place, moved to that place. +""" + +from __future__ import annotations as _annotations + +import dataclasses +import keyword +import sys +import warnings +import weakref +from collections import OrderedDict, defaultdict, deque +from collections.abc import Callable, Iterable, Mapping +from collections.abc import Set as AbstractSet +from copy import deepcopy +from functools import cached_property +from inspect import Parameter +from itertools import zip_longest +from types import BuiltinFunctionType, CodeType, FunctionType, GeneratorType, LambdaType, ModuleType +from typing import TYPE_CHECKING, Any, Generic, TypeVar, overload + +from pydantic_core import MISSING, PydanticUndefined +from typing_extensions import TypeAlias, TypeGuard, deprecated + +from pydantic import PydanticDeprecatedSince211 + +from . import _repr, _typing_extra +from ._import_utils import import_cached_base_model + +if TYPE_CHECKING: + # TODO remove type error comments when we drop support for Python 3.9 + MappingIntStrAny: TypeAlias = Mapping[int, Any] | Mapping[str, Any] # pyright: ignore[reportGeneralTypeIssues] + AbstractSetIntStr: TypeAlias = AbstractSet[int] | AbstractSet[str] # pyright: ignore[reportGeneralTypeIssues] + from ..main import BaseModel + + +# these are types that are returned unchanged by deepcopy +IMMUTABLE_NON_COLLECTIONS_TYPES: set[type[Any]] = { + int, + float, + complex, + str, + bool, + bytes, + type, + _typing_extra.NoneType, + FunctionType, + BuiltinFunctionType, + LambdaType, + weakref.ref, + CodeType, + # note: including ModuleType will differ from behaviour of deepcopy by not producing error. + # It might be not a good idea in general, but considering that this function used only internally + # against default values of fields, this will allow to actually have a field with module as default value + ModuleType, + NotImplemented.__class__, + Ellipsis.__class__, +} + +# these are types that if empty, might be copied with simple copy() instead of deepcopy() +BUILTIN_COLLECTIONS: set[type[Any]] = { + list, + set, + tuple, + frozenset, + dict, + OrderedDict, + defaultdict, + deque, +} + + +def can_be_positional(param: Parameter) -> bool: + """Return whether the parameter accepts a positional argument. + + ```python {test="skip" lint="skip"} + def func(a, /, b, *, c): + pass + + params = inspect.signature(func).parameters + can_be_positional(params['a']) + #> True + can_be_positional(params['b']) + #> True + can_be_positional(params['c']) + #> False + ``` + """ + return param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD) + + +def sequence_like(v: Any) -> bool: + return isinstance(v, (list, tuple, set, frozenset, GeneratorType, deque)) + + +def lenient_isinstance(o: Any, class_or_tuple: type[Any] | tuple[type[Any], ...] | None) -> bool: # pragma: no cover + try: + return isinstance(o, class_or_tuple) # type: ignore[arg-type] + except TypeError: + return False + + +def lenient_issubclass(cls: Any, class_or_tuple: Any) -> bool: # pragma: no cover + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) + except TypeError: + if isinstance(cls, _typing_extra.WithArgsTypes): + return False + raise # pragma: no cover + + +def is_model_class(cls: Any) -> TypeGuard[type[BaseModel]]: + """Returns true if cls is a _proper_ subclass of BaseModel, and provides proper type-checking, + unlike raw calls to lenient_issubclass. + """ + BaseModel = import_cached_base_model() + + return lenient_issubclass(cls, BaseModel) and cls is not BaseModel + + +def is_valid_identifier(identifier: str) -> bool: + """Checks that a string is a valid identifier and not a Python keyword. + :param identifier: The identifier to test. + :return: True if the identifier is valid. + """ + return identifier.isidentifier() and not keyword.iskeyword(identifier) + + +KeyType = TypeVar('KeyType') + + +def deep_update(mapping: dict[KeyType, Any], *updating_mappings: dict[KeyType, Any]) -> dict[KeyType, Any]: + updated_mapping = mapping.copy() + for updating_mapping in updating_mappings: + for k, v in updating_mapping.items(): + if k in updated_mapping and isinstance(updated_mapping[k], dict) and isinstance(v, dict): + updated_mapping[k] = deep_update(updated_mapping[k], v) + else: + updated_mapping[k] = v + return updated_mapping + + +def update_not_none(mapping: dict[Any, Any], **update: Any) -> None: + mapping.update({k: v for k, v in update.items() if v is not None}) + + +T = TypeVar('T') + + +def unique_list( + input_list: list[T] | tuple[T, ...], + *, + name_factory: Callable[[T], str] = str, +) -> list[T]: + """Make a list unique while maintaining order. + We update the list if another one with the same name is set + (e.g. model validator overridden in subclass). + """ + result: list[T] = [] + result_names: list[str] = [] + for v in input_list: + v_name = name_factory(v) + if v_name not in result_names: + result_names.append(v_name) + result.append(v) + else: + result[result_names.index(v_name)] = v + + return result + + +class ValueItems(_repr.Representation): + """Class for more convenient calculation of excluded or included fields on values.""" + + __slots__ = ('_items', '_type') + + def __init__(self, value: Any, items: AbstractSetIntStr | MappingIntStrAny) -> None: + items = self._coerce_items(items) + + if isinstance(value, (list, tuple)): + items = self._normalize_indexes(items, len(value)) # type: ignore + + self._items: MappingIntStrAny = items # type: ignore + + def is_excluded(self, item: Any) -> bool: + """Check if item is fully excluded. + + :param item: key or index of a value + """ + return self.is_true(self._items.get(item)) + + def is_included(self, item: Any) -> bool: + """Check if value is contained in self._items. + + :param item: key or index of value + """ + return item in self._items + + def for_element(self, e: int | str) -> AbstractSetIntStr | MappingIntStrAny | None: + """:param e: key or index of element on value + :return: raw values for element if self._items is dict and contain needed element + """ + item = self._items.get(e) # type: ignore + return item if not self.is_true(item) else None + + def _normalize_indexes(self, items: MappingIntStrAny, v_length: int) -> dict[int | str, Any]: + """:param items: dict or set of indexes which will be normalized + :param v_length: length of sequence indexes of which will be + + >>> self._normalize_indexes({0: True, -2: True, -1: True}, 4) + {0: True, 2: True, 3: True} + >>> self._normalize_indexes({'__all__': True}, 4) + {0: True, 1: True, 2: True, 3: True} + """ + normalized_items: dict[int | str, Any] = {} + all_items = None + for i, v in items.items(): + if not (isinstance(v, Mapping) or isinstance(v, AbstractSet) or self.is_true(v)): + raise TypeError(f'Unexpected type of exclude value for index "{i}" {v.__class__}') + if i == '__all__': + all_items = self._coerce_value(v) + continue + if not isinstance(i, int): + raise TypeError( + 'Excluding fields from a sequence of sub-models or dicts must be performed index-wise: ' + 'expected integer keys or keyword "__all__"' + ) + normalized_i = v_length + i if i < 0 else i + normalized_items[normalized_i] = self.merge(v, normalized_items.get(normalized_i)) + + if not all_items: + return normalized_items + if self.is_true(all_items): + for i in range(v_length): + normalized_items.setdefault(i, ...) + return normalized_items + for i in range(v_length): + normalized_item = normalized_items.setdefault(i, {}) + if not self.is_true(normalized_item): + normalized_items[i] = self.merge(all_items, normalized_item) + return normalized_items + + @classmethod + def merge(cls, base: Any, override: Any, intersect: bool = False) -> Any: + """Merge a `base` item with an `override` item. + + Both `base` and `override` are converted to dictionaries if possible. + Sets are converted to dictionaries with the sets entries as keys and + Ellipsis as values. + + Each key-value pair existing in `base` is merged with `override`, + while the rest of the key-value pairs are updated recursively with this function. + + Merging takes place based on the "union" of keys if `intersect` is + set to `False` (default) and on the intersection of keys if + `intersect` is set to `True`. + """ + override = cls._coerce_value(override) + base = cls._coerce_value(base) + if override is None: + return base + if cls.is_true(base) or base is None: + return override + if cls.is_true(override): + return base if intersect else override + + # intersection or union of keys while preserving ordering: + if intersect: + merge_keys = [k for k in base if k in override] + [k for k in override if k in base] + else: + merge_keys = list(base) + [k for k in override if k not in base] + + merged: dict[int | str, Any] = {} + for k in merge_keys: + merged_item = cls.merge(base.get(k), override.get(k), intersect=intersect) + if merged_item is not None: + merged[k] = merged_item + + return merged + + @staticmethod + def _coerce_items(items: AbstractSetIntStr | MappingIntStrAny) -> MappingIntStrAny: + if isinstance(items, Mapping): + pass + elif isinstance(items, AbstractSet): + items = dict.fromkeys(items, ...) # type: ignore + else: + class_name = getattr(items, '__class__', '???') + raise TypeError(f'Unexpected type of exclude value {class_name}') + return items # type: ignore + + @classmethod + def _coerce_value(cls, value: Any) -> Any: + if value is None or cls.is_true(value): + return value + return cls._coerce_items(value) + + @staticmethod + def is_true(v: Any) -> bool: + return v is True or v is ... + + def __repr_args__(self) -> _repr.ReprArgs: + return [(None, self._items)] + + +if TYPE_CHECKING: + + def LazyClassAttribute(name: str, get_value: Callable[[], T]) -> T: ... + +else: + + class LazyClassAttribute: + """A descriptor exposing an attribute only accessible on a class (hidden from instances). + + The attribute is lazily computed and cached during the first access. + """ + + def __init__(self, name: str, get_value: Callable[[], Any]) -> None: + self.name = name + self.get_value = get_value + + @cached_property + def value(self) -> Any: + return self.get_value() + + def __get__(self, instance: Any, owner: type[Any]) -> None: + if instance is None: + return self.value + raise AttributeError(f'{self.name!r} attribute of {owner.__name__!r} is class-only') + + +Obj = TypeVar('Obj') + + +def smart_deepcopy(obj: Obj) -> Obj: + """Return type as is for immutable built-in types + Use obj.copy() for built-in empty collections + Use copy.deepcopy() for non-empty collections and unknown objects. + """ + if obj is MISSING or obj is PydanticUndefined: + return obj # pyright: ignore[reportReturnType] + obj_type = obj.__class__ + if obj_type in IMMUTABLE_NON_COLLECTIONS_TYPES: + return obj # fastest case: obj is immutable and not collection therefore will not be copied anyway + try: + if not obj and obj_type in BUILTIN_COLLECTIONS: + # faster way for empty collections, no need to copy its members + return obj if obj_type is tuple else obj.copy() # tuple doesn't have copy method # type: ignore + except (TypeError, ValueError, RuntimeError): + # do we really dare to catch ALL errors? Seems a bit risky + pass + + return deepcopy(obj) # slowest way when we actually might need a deepcopy + + +_SENTINEL = object() + + +def all_identical(left: Iterable[Any], right: Iterable[Any]) -> bool: + """Check that the items of `left` are the same objects as those in `right`. + + >>> a, b = object(), object() + >>> all_identical([a, b, a], [a, b, a]) + True + >>> all_identical([a, b, [a]], [a, b, [a]]) # new list object, while "equal" is not "identical" + False + """ + for left_item, right_item in zip_longest(left, right, fillvalue=_SENTINEL): + if left_item is not right_item: + return False + return True + + +def get_first_not_none(a: Any, b: Any) -> Any: + """Return the first argument if it is not `None`, otherwise return the second argument.""" + return a if a is not None else b + + +@dataclasses.dataclass(frozen=True) +class SafeGetItemProxy: + """Wrapper redirecting `__getitem__` to `get` with a sentinel value as default + + This makes is safe to use in `operator.itemgetter` when some keys may be missing + """ + + # Define __slots__manually for performances + # @dataclasses.dataclass() only support slots=True in python>=3.10 + __slots__ = ('wrapped',) + + wrapped: Mapping[str, Any] + + def __getitem__(self, key: str, /) -> Any: + return self.wrapped.get(key, _SENTINEL) + + # required to pass the object to operator.itemgetter() instances due to a quirk of typeshed + # https://github.com/python/mypy/issues/13713 + # https://github.com/python/typeshed/pull/8785 + # Since this is typing-only, hide it in a typing.TYPE_CHECKING block + if TYPE_CHECKING: + + def __contains__(self, key: str, /) -> bool: + return self.wrapped.__contains__(key) + + +_ModelT = TypeVar('_ModelT', bound='BaseModel') +_RT = TypeVar('_RT') + + +class deprecated_instance_property(Generic[_ModelT, _RT]): + """A decorator exposing the decorated class method as a property, with a warning on instance access. + + This decorator takes a class method defined on the `BaseModel` class and transforms it into + an attribute. The attribute can be accessed on both the class and instances of the class. If accessed + via an instance, a deprecation warning is emitted stating that instance access will be removed in V3. + """ + + def __init__(self, fget: Callable[[type[_ModelT]], _RT], /) -> None: + # Note: fget should be a classmethod: + self.fget = fget + + @overload + def __get__(self, instance: None, objtype: type[_ModelT]) -> _RT: ... + @overload + @deprecated( + 'Accessing this attribute on the instance is deprecated, and will be removed in Pydantic V3. ' + 'Instead, you should access this attribute from the model class.', + category=None, + ) + def __get__(self, instance: _ModelT, objtype: type[_ModelT]) -> _RT: ... + def __get__(self, instance: _ModelT | None, objtype: type[_ModelT]) -> _RT: + if instance is not None: + # fmt: off + attr_name = ( + self.fget.__name__ + if sys.version_info >= (3, 10) + else self.fget.__func__.__name__ # pyright: ignore[reportFunctionMemberAccess] + ) + # fmt: on + warnings.warn( + f'Accessing the {attr_name!r} attribute on the instance is deprecated. ' + 'Instead, you should access this attribute from the model class.', + category=PydanticDeprecatedSince211, + stacklevel=2, + ) + return self.fget.__get__(instance, objtype)() diff --git a/source/target-vendors/cp312/pydantic/_internal/_validate_call.py b/source/target-vendors/cp312/pydantic/_internal/_validate_call.py new file mode 100644 index 0000000..49ccd4f --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_validate_call.py @@ -0,0 +1,141 @@ +from __future__ import annotations as _annotations + +import functools +import inspect +from collections.abc import Awaitable +from functools import partial +from typing import Any, Callable + +import pydantic_core + +from ..config import ConfigDict +from ..plugin._schema_validator import create_schema_validator +from ._config import ConfigWrapper +from ._generate_schema import GenerateSchema, ValidateCallSupportedTypes +from ._namespace_utils import MappingNamespace, NsResolver, ns_for_function +from ._typing_extra import signature_no_eval + + +def extract_function_name(func: ValidateCallSupportedTypes) -> str: + """Extract the name of a `ValidateCallSupportedTypes` object.""" + return f'partial({func.func.__name__})' if isinstance(func, functools.partial) else func.__name__ + + +def extract_function_qualname(func: ValidateCallSupportedTypes) -> str: + """Extract the qualname of a `ValidateCallSupportedTypes` object.""" + return f'partial({func.func.__qualname__})' if isinstance(func, functools.partial) else func.__qualname__ + + +def update_wrapper_attributes(wrapped: ValidateCallSupportedTypes, wrapper: Callable[..., Any]): + """Update the `wrapper` function with the attributes of the `wrapped` function. Return the updated function.""" + if inspect.iscoroutinefunction(wrapped): + + @functools.wraps(wrapped) + async def wrapper_function(*args, **kwargs): # type: ignore + return await wrapper(*args, **kwargs) + else: + + @functools.wraps(wrapped) + def wrapper_function(*args, **kwargs): + return wrapper(*args, **kwargs) + + # We need to manually update this because `partial` object has no `__name__` and `__qualname__`. + wrapper_function.__name__ = extract_function_name(wrapped) + wrapper_function.__qualname__ = extract_function_qualname(wrapped) + wrapper_function.raw_function = wrapped # type: ignore + + return wrapper_function + + +class ValidateCallWrapper: + """This is a wrapper around a function that validates the arguments passed to it, and optionally the return value.""" + + __slots__ = ( + 'function', + 'validate_return', + 'schema_type', + 'module', + 'qualname', + 'ns_resolver', + 'config_wrapper', + '__pydantic_complete__', + '__pydantic_validator__', + '__return_pydantic_validator__', + ) + + def __init__( + self, + function: ValidateCallSupportedTypes, + config: ConfigDict | None, + validate_return: bool, + parent_namespace: MappingNamespace | None, + ) -> None: + self.function = function + self.validate_return = validate_return + if isinstance(function, partial): + self.schema_type = function.func + self.module = function.func.__module__ + else: + self.schema_type = function + self.module = function.__module__ + self.qualname = extract_function_qualname(function) + + self.ns_resolver = NsResolver( + namespaces_tuple=ns_for_function(self.schema_type, parent_namespace=parent_namespace) + ) + self.config_wrapper = ConfigWrapper(config) + if not self.config_wrapper.defer_build: + self._create_validators() + else: + self.__pydantic_complete__ = False + + def _create_validators(self) -> None: + gen_schema = GenerateSchema(self.config_wrapper, self.ns_resolver) + schema = gen_schema.clean_schema(gen_schema.generate_schema(self.function)) + core_config = self.config_wrapper.core_config(title=self.qualname) + + self.__pydantic_validator__ = create_schema_validator( + schema, + self.schema_type, + self.module, + self.qualname, + 'validate_call', + core_config, + self.config_wrapper.plugin_settings, + ) + if self.validate_return: + signature = signature_no_eval(self.function) + return_type = signature.return_annotation if signature.return_annotation is not signature.empty else Any + gen_schema = GenerateSchema(self.config_wrapper, self.ns_resolver) + schema = gen_schema.clean_schema(gen_schema.generate_schema(return_type)) + validator = create_schema_validator( + schema, + self.schema_type, + self.module, + self.qualname, + 'validate_call', + core_config, + self.config_wrapper.plugin_settings, + ) + if inspect.iscoroutinefunction(self.function): + + async def return_val_wrapper(aw: Awaitable[Any]) -> None: + return validator.validate_python(await aw) + + self.__return_pydantic_validator__ = return_val_wrapper + else: + self.__return_pydantic_validator__ = validator.validate_python + else: + self.__return_pydantic_validator__ = None + + self.__pydantic_complete__ = True + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + if not self.__pydantic_complete__: + self._create_validators() + + res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs)) + if self.__return_pydantic_validator__: + return self.__return_pydantic_validator__(res) + else: + return res diff --git a/source/target-vendors/cp312/pydantic/_internal/_validators.py b/source/target-vendors/cp312/pydantic/_internal/_validators.py new file mode 100644 index 0000000..3ad6c92 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_internal/_validators.py @@ -0,0 +1,534 @@ +"""Validator functions for standard library types. + +Import of this module is deferred since it contains imports of many standard library modules. +""" + +from __future__ import annotations as _annotations + +import collections.abc +import math +import re +import typing +from collections.abc import Sequence +from decimal import Decimal +from fractions import Fraction +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from typing import Any, Callable, TypeVar, Union, cast +from zoneinfo import ZoneInfo, ZoneInfoNotFoundError + +import typing_extensions +from pydantic_core import PydanticCustomError, PydanticKnownError, core_schema +from typing_extensions import get_args, get_origin +from typing_inspection import typing_objects + +from pydantic._internal._import_utils import import_cached_field_info +from pydantic.errors import PydanticSchemaGenerationError + + +def sequence_validator( + input_value: Sequence[Any], + /, + validator: core_schema.ValidatorFunctionWrapHandler, +) -> Sequence[Any]: + """Validator for `Sequence` types, isinstance(v, Sequence) has already been called.""" + value_type = type(input_value) + + # We don't accept any plain string as a sequence + # Relevant issue: https://github.com/pydantic/pydantic/issues/5595 + if issubclass(value_type, (str, bytes)): + raise PydanticCustomError( + 'sequence_str', + "'{type_name}' instances are not allowed as a Sequence value", + {'type_name': value_type.__name__}, + ) + + # TODO: refactor sequence validation to validate with either a list or a tuple + # schema, depending on the type of the value. + # Additionally, we should be able to remove one of either this validator or the + # SequenceValidator in _std_types_schema.py (preferably this one, while porting over some logic). + # Effectively, a refactor for sequence validation is needed. + if value_type is tuple: + input_value = list(input_value) + + v_list = validator(input_value) + + # the rest of the logic is just re-creating the original type from `v_list` + if value_type is list: + return v_list + elif issubclass(value_type, range): + # return the list as we probably can't re-create the range + return v_list + elif value_type is tuple: + return tuple(v_list) + else: + # best guess at how to re-create the original type, more custom construction logic might be required + return value_type(v_list) # type: ignore[call-arg] + + +def import_string(value: Any) -> Any: + if isinstance(value, str): + try: + return _import_string_logic(value) + except ImportError as e: + raise PydanticCustomError('import_error', 'Invalid python path: {error}', {'error': str(e)}) from e + else: + # otherwise we just return the value and let the next validator do the rest of the work + return value + + +def _import_string_logic(dotted_path: str) -> Any: + """Inspired by uvicorn — dotted paths should include a colon before the final item if that item is not a module. + (This is necessary to distinguish between a submodule and an attribute when there is a conflict.). + + If the dotted path does not include a colon and the final item is not a valid module, importing as an attribute + rather than a submodule will be attempted automatically. + + So, for example, the following values of `dotted_path` result in the following returned values: + * 'collections': + * 'collections.abc': + * 'collections.abc:Mapping': + * `collections.abc.Mapping`: (though this is a bit slower than the previous line) + + An error will be raised under any of the following scenarios: + * `dotted_path` contains more than one colon (e.g., 'collections:abc:Mapping') + * the substring of `dotted_path` before the colon is not a valid module in the environment (e.g., '123:Mapping') + * the substring of `dotted_path` after the colon is not an attribute of the module (e.g., 'collections:abc123') + """ + from importlib import import_module + + components = dotted_path.strip().split(':') + if len(components) > 2: + raise ImportError(f"Import strings should have at most one ':'; received {dotted_path!r}") + attribute = None + if len(components) == 2: + attribute = components[1] + module_path = components[0] + if not module_path: + raise ImportError(f'Import strings should have a nonempty module name; received {dotted_path!r}') + + try: + module = import_module(module_path) + except ModuleNotFoundError: + if attribute is None and '.' in module_path: + # Try interpreting the final dotted segment as an attribute, not a submodule + maybe_module_path, maybe_attribute = module_path.rsplit('.', 1) + + try: + return _import_string_logic(f'{maybe_module_path}:{maybe_attribute}') + except ImportError: + pass + raise + + if attribute is not None: + try: + return getattr(module, attribute) + except AttributeError as e: + raise ImportError(f'cannot import name {attribute!r} from {module_path!r}') from e + else: + return module + + +def pattern_either_validator(input_value: Any, /) -> re.Pattern[Any]: + if isinstance(input_value, re.Pattern): + return input_value + elif isinstance(input_value, (str, bytes)): + # todo strict mode + return compile_pattern(input_value) # type: ignore + else: + raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') + + +def pattern_str_validator(input_value: Any, /) -> re.Pattern[str]: + if isinstance(input_value, re.Pattern): + if isinstance(input_value.pattern, str): + return input_value + else: + raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') + elif isinstance(input_value, str): + return compile_pattern(input_value) + elif isinstance(input_value, bytes): + raise PydanticCustomError('pattern_str_type', 'Input should be a string pattern') + else: + raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') + + +def pattern_bytes_validator(input_value: Any, /) -> re.Pattern[bytes]: + if isinstance(input_value, re.Pattern): + if isinstance(input_value.pattern, bytes): + return input_value + else: + raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') + elif isinstance(input_value, bytes): + return compile_pattern(input_value) + elif isinstance(input_value, str): + raise PydanticCustomError('pattern_bytes_type', 'Input should be a bytes pattern') + else: + raise PydanticCustomError('pattern_type', 'Input should be a valid pattern') + + +PatternType = TypeVar('PatternType', str, bytes) + + +def compile_pattern(pattern: PatternType) -> re.Pattern[PatternType]: + try: + return re.compile(pattern) + except re.error: + raise PydanticCustomError('pattern_regex', 'Input should be a valid regular expression') + + +def ip_v4_address_validator(input_value: Any, /) -> IPv4Address: + if isinstance(input_value, IPv4Address): + return input_value + + try: + return IPv4Address(input_value) + except ValueError: + raise PydanticCustomError('ip_v4_address', 'Input is not a valid IPv4 address') + + +def ip_v6_address_validator(input_value: Any, /) -> IPv6Address: + if isinstance(input_value, IPv6Address): + return input_value + + try: + return IPv6Address(input_value) + except ValueError: + raise PydanticCustomError('ip_v6_address', 'Input is not a valid IPv6 address') + + +def ip_v4_network_validator(input_value: Any, /) -> IPv4Network: + """Assume IPv4Network initialised with a default `strict` argument. + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv4Network + """ + if isinstance(input_value, IPv4Network): + return input_value + + try: + return IPv4Network(input_value) + except ValueError: + raise PydanticCustomError('ip_v4_network', 'Input is not a valid IPv4 network') + + +def ip_v6_network_validator(input_value: Any, /) -> IPv6Network: + """Assume IPv6Network initialised with a default `strict` argument. + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv6Network + """ + if isinstance(input_value, IPv6Network): + return input_value + + try: + return IPv6Network(input_value) + except ValueError: + raise PydanticCustomError('ip_v6_network', 'Input is not a valid IPv6 network') + + +def ip_v4_interface_validator(input_value: Any, /) -> IPv4Interface: + if isinstance(input_value, IPv4Interface): + return input_value + + try: + return IPv4Interface(input_value) + except ValueError: + raise PydanticCustomError('ip_v4_interface', 'Input is not a valid IPv4 interface') + + +def ip_v6_interface_validator(input_value: Any, /) -> IPv6Interface: + if isinstance(input_value, IPv6Interface): + return input_value + + try: + return IPv6Interface(input_value) + except ValueError: + raise PydanticCustomError('ip_v6_interface', 'Input is not a valid IPv6 interface') + + +def fraction_validator(input_value: Any, /) -> Fraction: + if isinstance(input_value, Fraction): + return input_value + + try: + return Fraction(input_value) + except ValueError: + raise PydanticCustomError('fraction_parsing', 'Input is not a valid fraction') + + +def forbid_inf_nan_check(x: Any) -> Any: + if not math.isfinite(x): + raise PydanticKnownError('finite_number') + return x + + +def _safe_repr(v: Any) -> int | float | str: + """The context argument for `PydanticKnownError` requires a number or str type, so we do a simple repr() coercion for types like timedelta. + + See tests/test_types.py::test_annotated_metadata_any_order for some context. + """ + if isinstance(v, (int, float, str)): + return v + return repr(v) + + +def greater_than_validator(x: Any, gt: Any) -> Any: + try: + if not (x > gt): + raise PydanticKnownError('greater_than', {'gt': _safe_repr(gt)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'gt' to supplied value {x}") + + +def greater_than_or_equal_validator(x: Any, ge: Any) -> Any: + try: + if not (x >= ge): + raise PydanticKnownError('greater_than_equal', {'ge': _safe_repr(ge)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'ge' to supplied value {x}") + + +def less_than_validator(x: Any, lt: Any) -> Any: + try: + if not (x < lt): + raise PydanticKnownError('less_than', {'lt': _safe_repr(lt)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'lt' to supplied value {x}") + + +def less_than_or_equal_validator(x: Any, le: Any) -> Any: + try: + if not (x <= le): + raise PydanticKnownError('less_than_equal', {'le': _safe_repr(le)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'le' to supplied value {x}") + + +def multiple_of_validator(x: Any, multiple_of: Any) -> Any: + try: + if x % multiple_of: + raise PydanticKnownError('multiple_of', {'multiple_of': _safe_repr(multiple_of)}) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'multiple_of' to supplied value {x}") + + +def min_length_validator(x: Any, min_length: Any) -> Any: + try: + if not (len(x) >= min_length): + raise PydanticKnownError( + 'too_short', {'field_type': 'Value', 'min_length': min_length, 'actual_length': len(x)} + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'min_length' to supplied value {x}") + + +def max_length_validator(x: Any, max_length: Any) -> Any: + try: + if len(x) > max_length: + raise PydanticKnownError( + 'too_long', + {'field_type': 'Value', 'max_length': max_length, 'actual_length': len(x)}, + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'max_length' to supplied value {x}") + + +def _extract_decimal_digits_info(decimal: Decimal) -> tuple[int, int]: + """Compute the total number of digits and decimal places for a given [`Decimal`][decimal.Decimal] instance. + + This function handles both normalized and non-normalized Decimal instances. + Example: Decimal('1.230') -> 4 digits, 3 decimal places + + Args: + decimal (Decimal): The decimal number to analyze. + + Returns: + tuple[int, int]: A tuple containing the number of decimal places and total digits. + + Though this could be divided into two separate functions, the logic is easier to follow if we couple the computation + of the number of decimals and digits together. + """ + try: + decimal_tuple = decimal.as_tuple() + + assert isinstance(decimal_tuple.exponent, int) + + exponent = decimal_tuple.exponent + num_digits = len(decimal_tuple.digits) + + if exponent >= 0: + # A positive exponent adds that many trailing zeros + # Ex: digit_tuple=(1, 2, 3), exponent=2 -> 12300 -> 0 decimal places, 5 digits + num_digits += exponent + decimal_places = 0 + else: + # If the absolute value of the negative exponent is larger than the + # number of digits, then it's the same as the number of digits, + # because it'll consume all the digits in digit_tuple and then + # add abs(exponent) - len(digit_tuple) leading zeros after the decimal point. + # Ex: digit_tuple=(1, 2, 3), exponent=-2 -> 1.23 -> 2 decimal places, 3 digits + # Ex: digit_tuple=(1, 2, 3), exponent=-4 -> 0.0123 -> 4 decimal places, 4 digits + decimal_places = abs(exponent) + num_digits = max(num_digits, decimal_places) + + return decimal_places, num_digits + except (AssertionError, AttributeError): + raise TypeError(f'Unable to extract decimal digits info from supplied value {decimal}') + + +def max_digits_validator(x: Any, max_digits: Any) -> Any: + try: + _, num_digits = _extract_decimal_digits_info(x) + _, normalized_num_digits = _extract_decimal_digits_info(x.normalize()) + if (num_digits > max_digits) and (normalized_num_digits > max_digits): + raise PydanticKnownError( + 'decimal_max_digits', + {'max_digits': max_digits}, + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'max_digits' to supplied value {x}") + + +def decimal_places_validator(x: Any, decimal_places: Any) -> Any: + try: + decimal_places_, _ = _extract_decimal_digits_info(x) + if decimal_places_ > decimal_places: + normalized_decimal_places, _ = _extract_decimal_digits_info(x.normalize()) + if normalized_decimal_places > decimal_places: + raise PydanticKnownError( + 'decimal_max_places', + {'decimal_places': decimal_places}, + ) + return x + except TypeError: + raise TypeError(f"Unable to apply constraint 'decimal_places' to supplied value {x}") + + +def deque_validator(input_value: Any, handler: core_schema.ValidatorFunctionWrapHandler) -> collections.deque[Any]: + return collections.deque(handler(input_value), maxlen=getattr(input_value, 'maxlen', None)) + + +def defaultdict_validator( + input_value: Any, handler: core_schema.ValidatorFunctionWrapHandler, default_default_factory: Callable[[], Any] +) -> collections.defaultdict[Any, Any]: + if isinstance(input_value, collections.defaultdict): + default_factory = input_value.default_factory + return collections.defaultdict(default_factory, handler(input_value)) + else: + return collections.defaultdict(default_default_factory, handler(input_value)) + + +def get_defaultdict_default_default_factory(values_source_type: Any) -> Callable[[], Any]: + FieldInfo = import_cached_field_info() + + values_type_origin = get_origin(values_source_type) + + def infer_default() -> Callable[[], Any]: + allowed_default_types: dict[Any, Any] = { + tuple: tuple, + collections.abc.Sequence: tuple, + collections.abc.MutableSequence: list, + list: list, + typing.Sequence: list, + set: set, + typing.MutableSet: set, + collections.abc.MutableSet: set, + collections.abc.Set: frozenset, + typing.MutableMapping: dict, + typing.Mapping: dict, + collections.abc.Mapping: dict, + collections.abc.MutableMapping: dict, + float: float, + int: int, + str: str, + bool: bool, + } + values_type = values_type_origin or values_source_type + instructions = 'set using `DefaultDict[..., Annotated[..., Field(default_factory=...)]]`' + if typing_objects.is_typevar(values_type): + + def type_var_default_factory() -> None: + raise RuntimeError( + 'Generic defaultdict cannot be used without a concrete value type or an' + ' explicit default factory, ' + instructions + ) + + return type_var_default_factory + elif values_type not in allowed_default_types: + # a somewhat subjective set of types that have reasonable default values + allowed_msg = ', '.join([t.__name__ for t in set(allowed_default_types.values())]) + raise PydanticSchemaGenerationError( + f'Unable to infer a default factory for keys of type {values_source_type}.' + f' Only {allowed_msg} are supported, other types require an explicit default factory' + ' ' + instructions + ) + return allowed_default_types[values_type] + + # Assume Annotated[..., Field(...)] + if typing_objects.is_annotated(values_type_origin): + field_info = next((v for v in get_args(values_source_type) if isinstance(v, FieldInfo)), None) + else: + field_info = None + if field_info and field_info.default_factory: + # Assume the default factory does not take any argument: + default_default_factory = cast(Callable[[], Any], field_info.default_factory) + else: + default_default_factory = infer_default() + return default_default_factory + + +def validate_str_is_valid_iana_tz(value: Any, /) -> ZoneInfo: + if isinstance(value, ZoneInfo): + return value + try: + return ZoneInfo(value) + except (ZoneInfoNotFoundError, ValueError, TypeError): + raise PydanticCustomError('zoneinfo_str', 'invalid timezone: {value}', {'value': value}) + + +NUMERIC_VALIDATOR_LOOKUP: dict[str, Callable] = { + 'gt': greater_than_validator, + 'ge': greater_than_or_equal_validator, + 'lt': less_than_validator, + 'le': less_than_or_equal_validator, + 'multiple_of': multiple_of_validator, + 'min_length': min_length_validator, + 'max_length': max_length_validator, + 'max_digits': max_digits_validator, + 'decimal_places': decimal_places_validator, +} + +IpType = Union[IPv4Address, IPv6Address, IPv4Network, IPv6Network, IPv4Interface, IPv6Interface] + +IP_VALIDATOR_LOOKUP: dict[type[IpType], Callable] = { + IPv4Address: ip_v4_address_validator, + IPv6Address: ip_v6_address_validator, + IPv4Network: ip_v4_network_validator, + IPv6Network: ip_v6_network_validator, + IPv4Interface: ip_v4_interface_validator, + IPv6Interface: ip_v6_interface_validator, +} + +MAPPING_ORIGIN_MAP: dict[Any, Any] = { + typing.DefaultDict: collections.defaultdict, # noqa: UP006 + collections.defaultdict: collections.defaultdict, + typing.OrderedDict: collections.OrderedDict, # noqa: UP006 + collections.OrderedDict: collections.OrderedDict, + typing_extensions.OrderedDict: collections.OrderedDict, + typing.Counter: collections.Counter, + collections.Counter: collections.Counter, + # this doesn't handle subclasses of these + typing.Mapping: dict, + typing.MutableMapping: dict, + # parametrized typing.{Mutable}Mapping creates one of these + collections.abc.Mapping: dict, + collections.abc.MutableMapping: dict, +} diff --git a/source/target-vendors/cp312/pydantic/_migration.py b/source/target-vendors/cp312/pydantic/_migration.py new file mode 100644 index 0000000..b4ecd28 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/_migration.py @@ -0,0 +1,316 @@ +import sys +from typing import Any, Callable + +from pydantic.warnings import PydanticDeprecatedSince20 + +from .version import version_short + +MOVED_IN_V2 = { + 'pydantic.utils:version_info': 'pydantic.version:version_info', + 'pydantic.error_wrappers:ValidationError': 'pydantic:ValidationError', + 'pydantic.utils:to_camel': 'pydantic.alias_generators:to_pascal', + 'pydantic.utils:to_lower_camel': 'pydantic.alias_generators:to_camel', + 'pydantic:PyObject': 'pydantic.types:ImportString', + 'pydantic.types:PyObject': 'pydantic.types:ImportString', + 'pydantic.generics:GenericModel': 'pydantic.BaseModel', +} + +DEPRECATED_MOVED_IN_V2 = { + 'pydantic.tools:schema_of': 'pydantic.deprecated.tools:schema_of', + 'pydantic.tools:parse_obj_as': 'pydantic.deprecated.tools:parse_obj_as', + 'pydantic.tools:schema_json_of': 'pydantic.deprecated.tools:schema_json_of', + 'pydantic.json:pydantic_encoder': 'pydantic.deprecated.json:pydantic_encoder', + 'pydantic:validate_arguments': 'pydantic.deprecated.decorator:validate_arguments', + 'pydantic.json:custom_pydantic_encoder': 'pydantic.deprecated.json:custom_pydantic_encoder', + 'pydantic.json:timedelta_isoformat': 'pydantic.deprecated.json:timedelta_isoformat', + 'pydantic.decorator:validate_arguments': 'pydantic.deprecated.decorator:validate_arguments', + 'pydantic.class_validators:validator': 'pydantic.deprecated.class_validators:validator', + 'pydantic.class_validators:root_validator': 'pydantic.deprecated.class_validators:root_validator', + 'pydantic.config:BaseConfig': 'pydantic.deprecated.config:BaseConfig', + 'pydantic.config:Extra': 'pydantic.deprecated.config:Extra', +} + +REDIRECT_TO_V1 = { + f'pydantic.utils:{obj}': f'pydantic.v1.utils:{obj}' + for obj in ( + 'deep_update', + 'GetterDict', + 'lenient_issubclass', + 'lenient_isinstance', + 'is_valid_field', + 'update_not_none', + 'import_string', + 'Representation', + 'ROOT_KEY', + 'smart_deepcopy', + 'sequence_like', + ) +} + + +REMOVED_IN_V2 = { + 'pydantic:ConstrainedBytes', + 'pydantic:ConstrainedDate', + 'pydantic:ConstrainedDecimal', + 'pydantic:ConstrainedFloat', + 'pydantic:ConstrainedFrozenSet', + 'pydantic:ConstrainedInt', + 'pydantic:ConstrainedList', + 'pydantic:ConstrainedSet', + 'pydantic:ConstrainedStr', + 'pydantic:JsonWrapper', + 'pydantic:NoneBytes', + 'pydantic:NoneStr', + 'pydantic:NoneStrBytes', + 'pydantic:Protocol', + 'pydantic:Required', + 'pydantic:StrBytes', + 'pydantic:compiled', + 'pydantic.config:get_config', + 'pydantic.config:inherit_config', + 'pydantic.config:prepare_config', + 'pydantic:create_model_from_namedtuple', + 'pydantic:create_model_from_typeddict', + 'pydantic.dataclasses:create_pydantic_model_from_dataclass', + 'pydantic.dataclasses:make_dataclass_validator', + 'pydantic.dataclasses:set_validation', + 'pydantic.datetime_parse:parse_date', + 'pydantic.datetime_parse:parse_time', + 'pydantic.datetime_parse:parse_datetime', + 'pydantic.datetime_parse:parse_duration', + 'pydantic.error_wrappers:ErrorWrapper', + 'pydantic.errors:AnyStrMaxLengthError', + 'pydantic.errors:AnyStrMinLengthError', + 'pydantic.errors:ArbitraryTypeError', + 'pydantic.errors:BoolError', + 'pydantic.errors:BytesError', + 'pydantic.errors:CallableError', + 'pydantic.errors:ClassError', + 'pydantic.errors:ColorError', + 'pydantic.errors:ConfigError', + 'pydantic.errors:DataclassTypeError', + 'pydantic.errors:DateError', + 'pydantic.errors:DateNotInTheFutureError', + 'pydantic.errors:DateNotInThePastError', + 'pydantic.errors:DateTimeError', + 'pydantic.errors:DecimalError', + 'pydantic.errors:DecimalIsNotFiniteError', + 'pydantic.errors:DecimalMaxDigitsError', + 'pydantic.errors:DecimalMaxPlacesError', + 'pydantic.errors:DecimalWholeDigitsError', + 'pydantic.errors:DictError', + 'pydantic.errors:DurationError', + 'pydantic.errors:EmailError', + 'pydantic.errors:EnumError', + 'pydantic.errors:EnumMemberError', + 'pydantic.errors:ExtraError', + 'pydantic.errors:FloatError', + 'pydantic.errors:FrozenSetError', + 'pydantic.errors:FrozenSetMaxLengthError', + 'pydantic.errors:FrozenSetMinLengthError', + 'pydantic.errors:HashableError', + 'pydantic.errors:IPv4AddressError', + 'pydantic.errors:IPv4InterfaceError', + 'pydantic.errors:IPv4NetworkError', + 'pydantic.errors:IPv6AddressError', + 'pydantic.errors:IPv6InterfaceError', + 'pydantic.errors:IPv6NetworkError', + 'pydantic.errors:IPvAnyAddressError', + 'pydantic.errors:IPvAnyInterfaceError', + 'pydantic.errors:IPvAnyNetworkError', + 'pydantic.errors:IntEnumError', + 'pydantic.errors:IntegerError', + 'pydantic.errors:InvalidByteSize', + 'pydantic.errors:InvalidByteSizeUnit', + 'pydantic.errors:InvalidDiscriminator', + 'pydantic.errors:InvalidLengthForBrand', + 'pydantic.errors:JsonError', + 'pydantic.errors:JsonTypeError', + 'pydantic.errors:ListError', + 'pydantic.errors:ListMaxLengthError', + 'pydantic.errors:ListMinLengthError', + 'pydantic.errors:ListUniqueItemsError', + 'pydantic.errors:LuhnValidationError', + 'pydantic.errors:MissingDiscriminator', + 'pydantic.errors:MissingError', + 'pydantic.errors:NoneIsAllowedError', + 'pydantic.errors:NoneIsNotAllowedError', + 'pydantic.errors:NotDigitError', + 'pydantic.errors:NotNoneError', + 'pydantic.errors:NumberNotGeError', + 'pydantic.errors:NumberNotGtError', + 'pydantic.errors:NumberNotLeError', + 'pydantic.errors:NumberNotLtError', + 'pydantic.errors:NumberNotMultipleError', + 'pydantic.errors:PathError', + 'pydantic.errors:PathNotADirectoryError', + 'pydantic.errors:PathNotAFileError', + 'pydantic.errors:PathNotExistsError', + 'pydantic.errors:PatternError', + 'pydantic.errors:PyObjectError', + 'pydantic.errors:PydanticTypeError', + 'pydantic.errors:PydanticValueError', + 'pydantic.errors:SequenceError', + 'pydantic.errors:SetError', + 'pydantic.errors:SetMaxLengthError', + 'pydantic.errors:SetMinLengthError', + 'pydantic.errors:StrError', + 'pydantic.errors:StrRegexError', + 'pydantic.errors:StrictBoolError', + 'pydantic.errors:SubclassError', + 'pydantic.errors:TimeError', + 'pydantic.errors:TupleError', + 'pydantic.errors:TupleLengthError', + 'pydantic.errors:UUIDError', + 'pydantic.errors:UUIDVersionError', + 'pydantic.errors:UrlError', + 'pydantic.errors:UrlExtraError', + 'pydantic.errors:UrlHostError', + 'pydantic.errors:UrlHostTldError', + 'pydantic.errors:UrlPortError', + 'pydantic.errors:UrlSchemeError', + 'pydantic.errors:UrlSchemePermittedError', + 'pydantic.errors:UrlUserInfoError', + 'pydantic.errors:WrongConstantError', + 'pydantic.main:validate_model', + 'pydantic.networks:stricturl', + 'pydantic:parse_file_as', + 'pydantic:parse_raw_as', + 'pydantic:stricturl', + 'pydantic.tools:parse_file_as', + 'pydantic.tools:parse_raw_as', + 'pydantic.types:ConstrainedBytes', + 'pydantic.types:ConstrainedDate', + 'pydantic.types:ConstrainedDecimal', + 'pydantic.types:ConstrainedFloat', + 'pydantic.types:ConstrainedFrozenSet', + 'pydantic.types:ConstrainedInt', + 'pydantic.types:ConstrainedList', + 'pydantic.types:ConstrainedSet', + 'pydantic.types:ConstrainedStr', + 'pydantic.types:JsonWrapper', + 'pydantic.types:NoneBytes', + 'pydantic.types:NoneStr', + 'pydantic.types:NoneStrBytes', + 'pydantic.types:StrBytes', + 'pydantic.typing:evaluate_forwardref', + 'pydantic.typing:AbstractSetIntStr', + 'pydantic.typing:AnyCallable', + 'pydantic.typing:AnyClassMethod', + 'pydantic.typing:CallableGenerator', + 'pydantic.typing:DictAny', + 'pydantic.typing:DictIntStrAny', + 'pydantic.typing:DictStrAny', + 'pydantic.typing:IntStr', + 'pydantic.typing:ListStr', + 'pydantic.typing:MappingIntStrAny', + 'pydantic.typing:NoArgAnyCallable', + 'pydantic.typing:NoneType', + 'pydantic.typing:ReprArgs', + 'pydantic.typing:SetStr', + 'pydantic.typing:StrPath', + 'pydantic.typing:TupleGenerator', + 'pydantic.typing:WithArgsTypes', + 'pydantic.typing:all_literal_values', + 'pydantic.typing:display_as_type', + 'pydantic.typing:get_all_type_hints', + 'pydantic.typing:get_args', + 'pydantic.typing:get_origin', + 'pydantic.typing:get_sub_types', + 'pydantic.typing:is_callable_type', + 'pydantic.typing:is_classvar', + 'pydantic.typing:is_finalvar', + 'pydantic.typing:is_literal_type', + 'pydantic.typing:is_namedtuple', + 'pydantic.typing:is_new_type', + 'pydantic.typing:is_none_type', + 'pydantic.typing:is_typeddict', + 'pydantic.typing:is_typeddict_special', + 'pydantic.typing:is_union', + 'pydantic.typing:new_type_supertype', + 'pydantic.typing:resolve_annotations', + 'pydantic.typing:typing_base', + 'pydantic.typing:update_field_forward_refs', + 'pydantic.typing:update_model_forward_refs', + 'pydantic.utils:ClassAttribute', + 'pydantic.utils:DUNDER_ATTRIBUTES', + 'pydantic.utils:PyObjectStr', + 'pydantic.utils:ValueItems', + 'pydantic.utils:almost_equal_floats', + 'pydantic.utils:get_discriminator_alias_and_values', + 'pydantic.utils:get_model', + 'pydantic.utils:get_unique_discriminator_alias', + 'pydantic.utils:in_ipython', + 'pydantic.utils:is_valid_identifier', + 'pydantic.utils:path_type', + 'pydantic.utils:validate_field_name', + 'pydantic:validate_model', +} + + +def getattr_migration(module: str) -> Callable[[str], Any]: + """Implement PEP 562 for objects that were either moved or removed on the migration + to V2. + + Args: + module: The module name. + + Returns: + A callable that will raise an error if the object is not found. + """ + # This avoids circular import with errors.py. + from .errors import PydanticImportError + + def wrapper(name: str) -> object: + """Raise an error if the object is not found, or warn if it was moved. + + In case it was moved, it still returns the object. + + Args: + name: The object name. + + Returns: + The object. + """ + if name == '__path__': + raise AttributeError(f'module {module!r} has no attribute {name!r}') + + import warnings + + from ._internal._validators import import_string + + import_path = f'{module}:{name}' + if import_path in MOVED_IN_V2.keys(): + new_location = MOVED_IN_V2[import_path] + warnings.warn( + f'`{import_path}` has been moved to `{new_location}`.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return import_string(MOVED_IN_V2[import_path]) + if import_path in DEPRECATED_MOVED_IN_V2: + # skip the warning here because a deprecation warning will be raised elsewhere + return import_string(DEPRECATED_MOVED_IN_V2[import_path]) + if import_path in REDIRECT_TO_V1: + new_location = REDIRECT_TO_V1[import_path] + warnings.warn( + f'`{import_path}` has been removed. We are importing from `{new_location}` instead.' + 'See the migration guide for more details: https://docs.pydantic.dev/latest/migration/', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return import_string(REDIRECT_TO_V1[import_path]) + if import_path == 'pydantic:BaseSettings': + raise PydanticImportError( + '`BaseSettings` has been moved to the `pydantic-settings` package. ' + f'See https://docs.pydantic.dev/{version_short()}/migration/#basesettings-has-moved-to-pydantic-settings ' + 'for more details.' + ) + if import_path in REMOVED_IN_V2: + raise PydanticImportError(f'`{import_path}` has been removed in V2.') + globals: dict[str, Any] = sys.modules[module].__dict__ + if name in globals: + return globals[name] + raise AttributeError(f'module {module!r} has no attribute {name!r}') + + return wrapper diff --git a/source/target-vendors/cp312/pydantic/alias_generators.py b/source/target-vendors/cp312/pydantic/alias_generators.py new file mode 100644 index 0000000..0b7653f --- /dev/null +++ b/source/target-vendors/cp312/pydantic/alias_generators.py @@ -0,0 +1,62 @@ +"""Alias generators for converting between different capitalization conventions.""" + +import re + +__all__ = ('to_pascal', 'to_camel', 'to_snake') + +# TODO: in V3, change the argument names to be more descriptive +# Generally, don't only convert from snake_case, or name the functions +# more specifically like snake_to_camel. + + +def to_pascal(snake: str) -> str: + """Convert a snake_case string to PascalCase. + + Args: + snake: The string to convert. + + Returns: + The PascalCase string. + """ + camel = snake.title() + return re.sub('([0-9A-Za-z])_(?=[0-9A-Z])', lambda m: m.group(1), camel) + + +def to_camel(snake: str) -> str: + """Convert a snake_case string to camelCase. + + Args: + snake: The string to convert. + + Returns: + The converted camelCase string. + """ + # If the string is already in camelCase and does not contain a digit followed + # by a lowercase letter, return it as it is + if re.match('^[a-z]+[A-Za-z0-9]*$', snake) and not re.search(r'\d[a-z]', snake): + return snake + + camel = to_pascal(snake) + return re.sub('(^_*[A-Z])', lambda m: m.group(1).lower(), camel) + + +def to_snake(camel: str) -> str: + """Convert a PascalCase, camelCase, or kebab-case string to snake_case. + + Args: + camel: The string to convert. + + Returns: + The converted string in snake_case. + """ + # Handle the sequence of uppercase letters followed by a lowercase letter + snake = re.sub(r'([A-Z]+)([A-Z][a-z])', lambda m: f'{m.group(1)}_{m.group(2)}', camel) + # Insert an underscore between a lowercase letter and an uppercase letter + snake = re.sub(r'([a-z])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Insert an underscore between a digit and an uppercase letter + snake = re.sub(r'([0-9])([A-Z])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Insert an underscore between a lowercase letter and a digit + snake = re.sub(r'([a-z])([0-9])', lambda m: f'{m.group(1)}_{m.group(2)}', snake) + # Replace hyphens with underscores to handle kebab-case + snake = snake.replace('-', '_') + return snake.lower() diff --git a/source/target-vendors/cp312/pydantic/aliases.py b/source/target-vendors/cp312/pydantic/aliases.py new file mode 100644 index 0000000..ac22737 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/aliases.py @@ -0,0 +1,135 @@ +"""Support for alias configurations.""" + +from __future__ import annotations + +import dataclasses +from typing import Any, Callable, Literal + +from pydantic_core import PydanticUndefined + +from ._internal import _internal_dataclass + +__all__ = ('AliasGenerator', 'AliasPath', 'AliasChoices') + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class AliasPath: + """!!! abstract "Usage Documentation" + [`AliasPath` and `AliasChoices`](../concepts/alias.md#aliaspath-and-aliaschoices) + + A data class used by `validation_alias` as a convenience to create aliases. + + Attributes: + path: A list of string or integer aliases. + """ + + path: list[int | str] + + def __init__(self, first_arg: str, *args: str | int) -> None: + self.path = [first_arg] + list(args) + + def convert_to_aliases(self) -> list[str | int]: + """Converts arguments to a list of string or integer aliases. + + Returns: + The list of aliases. + """ + return self.path + + def search_dict_for_path(self, d: dict) -> Any: + """Searches a dictionary for the path specified by the alias. + + Returns: + The value at the specified path, or `PydanticUndefined` if the path is not found. + """ + v = d + for k in self.path: + if isinstance(v, str): + # disallow indexing into a str, like for AliasPath('x', 0) and x='abc' + return PydanticUndefined + try: + v = v[k] + except (KeyError, IndexError, TypeError): + return PydanticUndefined + return v + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class AliasChoices: + """!!! abstract "Usage Documentation" + [`AliasPath` and `AliasChoices`](../concepts/alias.md#aliaspath-and-aliaschoices) + + A data class used by `validation_alias` as a convenience to create aliases. + + Attributes: + choices: A list containing a string or `AliasPath`. + """ + + choices: list[str | AliasPath] + + def __init__(self, first_choice: str | AliasPath, *choices: str | AliasPath) -> None: + self.choices = [first_choice] + list(choices) + + def convert_to_aliases(self) -> list[list[str | int]]: + """Converts arguments to a list of lists containing string or integer aliases. + + Returns: + The list of aliases. + """ + aliases: list[list[str | int]] = [] + for c in self.choices: + if isinstance(c, AliasPath): + aliases.append(c.convert_to_aliases()) + else: + aliases.append([c]) + return aliases + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class AliasGenerator: + """!!! abstract "Usage Documentation" + [Using an `AliasGenerator`](../concepts/alias.md#using-an-aliasgenerator) + + A data class used by `alias_generator` as a convenience to create various aliases. + + Attributes: + alias: A callable that takes a field name and returns an alias for it. + validation_alias: A callable that takes a field name and returns a validation alias for it. + serialization_alias: A callable that takes a field name and returns a serialization alias for it. + """ + + alias: Callable[[str], str] | None = None + validation_alias: Callable[[str], str | AliasPath | AliasChoices] | None = None + serialization_alias: Callable[[str], str] | None = None + + def _generate_alias( + self, + alias_kind: Literal['alias', 'validation_alias', 'serialization_alias'], + allowed_types: tuple[type[str] | type[AliasPath] | type[AliasChoices], ...], + field_name: str, + ) -> str | AliasPath | AliasChoices | None: + """Generate an alias of the specified kind. Returns None if the alias generator is None. + + Raises: + TypeError: If the alias generator produces an invalid type. + """ + alias = None + if alias_generator := getattr(self, alias_kind): + alias = alias_generator(field_name) + if alias and not isinstance(alias, allowed_types): + raise TypeError( + f'Invalid `{alias_kind}` type. `{alias_kind}` generator must produce one of `{allowed_types}`' + ) + return alias + + def generate_aliases(self, field_name: str) -> tuple[str | None, str | AliasPath | AliasChoices | None, str | None]: + """Generate `alias`, `validation_alias`, and `serialization_alias` for a field. + + Returns: + A tuple of three aliases - validation, alias, and serialization. + """ + alias = self._generate_alias('alias', (str,), field_name) + validation_alias = self._generate_alias('validation_alias', (str, AliasChoices, AliasPath), field_name) + serialization_alias = self._generate_alias('serialization_alias', (str,), field_name) + + return alias, validation_alias, serialization_alias # type: ignore diff --git a/source/target-vendors/cp312/pydantic/annotated_handlers.py b/source/target-vendors/cp312/pydantic/annotated_handlers.py new file mode 100644 index 0000000..d0cb5d3 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/annotated_handlers.py @@ -0,0 +1,122 @@ +"""Type annotations to use with `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__`.""" + +from __future__ import annotations as _annotations + +from typing import TYPE_CHECKING, Any, Union + +from pydantic_core import core_schema + +if TYPE_CHECKING: + from ._internal._namespace_utils import NamespacesTuple + from .json_schema import JsonSchemaMode, JsonSchemaValue + + CoreSchemaOrField = Union[ + core_schema.CoreSchema, + core_schema.ModelField, + core_schema.DataclassField, + core_schema.TypedDictField, + core_schema.ComputedField, + ] + +__all__ = 'GetJsonSchemaHandler', 'GetCoreSchemaHandler' + + +class GetJsonSchemaHandler: + """Handler to call into the next JSON schema generation function. + + Attributes: + mode: Json schema mode, can be `validation` or `serialization`. + """ + + mode: JsonSchemaMode + + def __call__(self, core_schema: CoreSchemaOrField, /) -> JsonSchemaValue: + """Call the inner handler and get the JsonSchemaValue it returns. + This will call the next JSON schema modifying function up until it calls + into `pydantic.json_schema.GenerateJsonSchema`, which will raise a + `pydantic.errors.PydanticInvalidForJsonSchema` error if it cannot generate + a JSON schema. + + Args: + core_schema: A `pydantic_core.core_schema.CoreSchema`. + + Returns: + JsonSchemaValue: The JSON schema generated by the inner JSON schema modify + functions. + """ + raise NotImplementedError + + def resolve_ref_schema(self, maybe_ref_json_schema: JsonSchemaValue, /) -> JsonSchemaValue: + """Get the real schema for a `{"$ref": ...}` schema. + If the schema given is not a `$ref` schema, it will be returned as is. + This means you don't have to check before calling this function. + + Args: + maybe_ref_json_schema: A JsonSchemaValue which may be a `$ref` schema. + + Raises: + LookupError: If the ref is not found. + + Returns: + JsonSchemaValue: A JsonSchemaValue that has no `$ref`. + """ + raise NotImplementedError + + +class GetCoreSchemaHandler: + """Handler to call into the next CoreSchema schema generation function.""" + + def __call__(self, source_type: Any, /) -> core_schema.CoreSchema: + """Call the inner handler and get the CoreSchema it returns. + This will call the next CoreSchema modifying function up until it calls + into Pydantic's internal schema generation machinery, which will raise a + `pydantic.errors.PydanticSchemaGenerationError` error if it cannot generate + a CoreSchema for the given source type. + + Args: + source_type: The input type. + + Returns: + CoreSchema: The `pydantic-core` CoreSchema generated. + """ + raise NotImplementedError + + def generate_schema(self, source_type: Any, /) -> core_schema.CoreSchema: + """Generate a schema unrelated to the current context. + Use this function if e.g. you are handling schema generation for a sequence + and want to generate a schema for its items. + Otherwise, you may end up doing something like applying a `min_length` constraint + that was intended for the sequence itself to its items! + + Args: + source_type: The input type. + + Returns: + CoreSchema: The `pydantic-core` CoreSchema generated. + """ + raise NotImplementedError + + def resolve_ref_schema(self, maybe_ref_schema: core_schema.CoreSchema, /) -> core_schema.CoreSchema: + """Get the real schema for a `definition-ref` schema. + If the schema given is not a `definition-ref` schema, it will be returned as is. + This means you don't have to check before calling this function. + + Args: + maybe_ref_schema: A `CoreSchema`, `ref`-based or not. + + Raises: + LookupError: If the `ref` is not found. + + Returns: + A concrete `CoreSchema`. + """ + raise NotImplementedError + + @property + def field_name(self) -> str | None: + """Get the name of the closest field to this validator.""" + raise NotImplementedError + + def _get_types_namespace(self) -> NamespacesTuple: + """Internal method used during type resolution for serializer annotations.""" + raise NotImplementedError diff --git a/source/target-vendors/cp312/pydantic/class_validators.py b/source/target-vendors/cp312/pydantic/class_validators.py new file mode 100644 index 0000000..9977150 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/class_validators.py @@ -0,0 +1,5 @@ +"""`class_validators` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/color.py b/source/target-vendors/cp312/pydantic/color.py new file mode 100644 index 0000000..9a42d58 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/color.py @@ -0,0 +1,604 @@ +"""Color definitions are used as per the CSS3 +[CSS Color Module Level 3](http://www.w3.org/TR/css3-color/#svg-color) specification. + +A few colors have multiple names referring to the sames colors, eg. `grey` and `gray` or `aqua` and `cyan`. + +In these cases the _last_ color when sorted alphabetically takes preferences, +eg. `Color((0, 255, 255)).as_named() == 'cyan'` because "cyan" comes after "aqua". + +Warning: Deprecated + The `Color` class is deprecated, use `pydantic_extra_types` instead. + See [`pydantic-extra-types.Color`](../usage/types/extra_types/color_types.md) + for more information. +""" + +import math +import re +from colorsys import hls_to_rgb, rgb_to_hls +from typing import Any, Callable, Optional, Union, cast + +from pydantic_core import CoreSchema, PydanticCustomError, core_schema +from typing_extensions import deprecated + +from ._internal import _repr +from ._internal._schema_generation_shared import GetJsonSchemaHandler as _GetJsonSchemaHandler +from .json_schema import JsonSchemaValue +from .warnings import PydanticDeprecatedSince20 + +ColorTuple = Union[tuple[int, int, int], tuple[int, int, int, float]] +ColorType = Union[ColorTuple, str] +HslColorTuple = Union[tuple[float, float, float], tuple[float, float, float, float]] + + +class RGBA: + """Internal use only as a representation of a color.""" + + __slots__ = 'r', 'g', 'b', 'alpha', '_tuple' + + def __init__(self, r: float, g: float, b: float, alpha: Optional[float]): + self.r = r + self.g = g + self.b = b + self.alpha = alpha + + self._tuple: tuple[float, float, float, Optional[float]] = (r, g, b, alpha) + + def __getitem__(self, item: Any) -> Any: + return self._tuple[item] + + +# these are not compiled here to avoid import slowdown, they'll be compiled the first time they're used, then cached +_r_255 = r'(\d{1,3}(?:\.\d+)?)' +_r_comma = r'\s*,\s*' +_r_alpha = r'(\d(?:\.\d+)?|\.\d+|\d{1,2}%)' +_r_h = r'(-?\d+(?:\.\d+)?|-?\.\d+)(deg|rad|turn)?' +_r_sl = r'(\d{1,3}(?:\.\d+)?)%' +r_hex_short = r'\s*(?:#|0x)?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?\s*' +r_hex_long = r'\s*(?:#|0x)?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?\s*' +# CSS3 RGB examples: rgb(0, 0, 0), rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 50%) +r_rgb = rf'\s*rgba?\(\s*{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_255}(?:{_r_comma}{_r_alpha})?\s*\)\s*' +# CSS3 HSL examples: hsl(270, 60%, 50%), hsla(270, 60%, 50%, 0.5), hsla(270, 60%, 50%, 50%) +r_hsl = rf'\s*hsla?\(\s*{_r_h}{_r_comma}{_r_sl}{_r_comma}{_r_sl}(?:{_r_comma}{_r_alpha})?\s*\)\s*' +# CSS4 RGB examples: rgb(0 0 0), rgb(0 0 0 / 0.5), rgb(0 0 0 / 50%), rgba(0 0 0 / 50%) +r_rgb_v4_style = rf'\s*rgba?\(\s*{_r_255}\s+{_r_255}\s+{_r_255}(?:\s*/\s*{_r_alpha})?\s*\)\s*' +# CSS4 HSL examples: hsl(270 60% 50%), hsl(270 60% 50% / 0.5), hsl(270 60% 50% / 50%), hsla(270 60% 50% / 50%) +r_hsl_v4_style = rf'\s*hsla?\(\s*{_r_h}\s+{_r_sl}\s+{_r_sl}(?:\s*/\s*{_r_alpha})?\s*\)\s*' + +# colors where the two hex characters are the same, if all colors match this the short version of hex colors can be used +repeat_colors = {int(c * 2, 16) for c in '0123456789abcdef'} +rads = 2 * math.pi + + +@deprecated( + 'The `Color` class is deprecated, use `pydantic_extra_types` instead. ' + 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_color/.', + category=PydanticDeprecatedSince20, +) +class Color(_repr.Representation): + """Represents a color.""" + + __slots__ = '_original', '_rgba' + + def __init__(self, value: ColorType) -> None: + self._rgba: RGBA + self._original: ColorType + if isinstance(value, (tuple, list)): + self._rgba = parse_tuple(value) + elif isinstance(value, str): + self._rgba = parse_str(value) + elif isinstance(value, Color): + self._rgba = value._rgba + value = value._original + else: + raise PydanticCustomError( + 'color_error', 'value is not a valid color: value must be a tuple, list or string' + ) + + # if we've got here value must be a valid color + self._original = value + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='color') + return field_schema + + def original(self) -> ColorType: + """Original value passed to `Color`.""" + return self._original + + def as_named(self, *, fallback: bool = False) -> str: + """Returns the name of the color if it can be found in `COLORS_BY_VALUE` dictionary, + otherwise returns the hexadecimal representation of the color or raises `ValueError`. + + Args: + fallback: If True, falls back to returning the hexadecimal representation of + the color instead of raising a ValueError when no named color is found. + + Returns: + The name of the color, or the hexadecimal representation of the color. + + Raises: + ValueError: When no named color is found and fallback is `False`. + """ + if self._rgba.alpha is None: + rgb = cast(tuple[int, int, int], self.as_rgb_tuple()) + try: + return COLORS_BY_VALUE[rgb] + except KeyError as e: + if fallback: + return self.as_hex() + else: + raise ValueError('no named color found, use fallback=True, as_hex() or as_rgb()') from e + else: + return self.as_hex() + + def as_hex(self) -> str: + """Returns the hexadecimal representation of the color. + + Hex string representing the color can be 3, 4, 6, or 8 characters depending on whether the string + a "short" representation of the color is possible and whether there's an alpha channel. + + Returns: + The hexadecimal representation of the color. + """ + values = [float_to_255(c) for c in self._rgba[:3]] + if self._rgba.alpha is not None: + values.append(float_to_255(self._rgba.alpha)) + + as_hex = ''.join(f'{v:02x}' for v in values) + if all(c in repeat_colors for c in values): + as_hex = ''.join(as_hex[c] for c in range(0, len(as_hex), 2)) + return '#' + as_hex + + def as_rgb(self) -> str: + """Color as an `rgb(, , )` or `rgba(, , , )` string.""" + if self._rgba.alpha is None: + return f'rgb({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)})' + else: + return ( + f'rgba({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)}, ' + f'{round(self._alpha_float(), 2)})' + ) + + def as_rgb_tuple(self, *, alpha: Optional[bool] = None) -> ColorTuple: + """Returns the color as an RGB or RGBA tuple. + + Args: + alpha: Whether to include the alpha channel. There are three options for this input: + + - `None` (default): Include alpha only if it's set. (e.g. not `None`) + - `True`: Always include alpha. + - `False`: Always omit alpha. + + Returns: + A tuple that contains the values of the red, green, and blue channels in the range 0 to 255. + If alpha is included, it is in the range 0 to 1. + """ + r, g, b = (float_to_255(c) for c in self._rgba[:3]) + if alpha is None: + if self._rgba.alpha is None: + return r, g, b + else: + return r, g, b, self._alpha_float() + elif alpha: + return r, g, b, self._alpha_float() + else: + # alpha is False + return r, g, b + + def as_hsl(self) -> str: + """Color as an `hsl(, , )` or `hsl(, , , )` string.""" + if self._rgba.alpha is None: + h, s, li = self.as_hsl_tuple(alpha=False) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%})' + else: + h, s, li, a = self.as_hsl_tuple(alpha=True) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%}, {round(a, 2)})' + + def as_hsl_tuple(self, *, alpha: Optional[bool] = None) -> HslColorTuple: + """Returns the color as an HSL or HSLA tuple. + + Args: + alpha: Whether to include the alpha channel. + + - `None` (default): Include the alpha channel only if it's set (e.g. not `None`). + - `True`: Always include alpha. + - `False`: Always omit alpha. + + Returns: + The color as a tuple of hue, saturation, lightness, and alpha (if included). + All elements are in the range 0 to 1. + + Note: + This is HSL as used in HTML and most other places, not HLS as used in Python's `colorsys`. + """ + h, l, s = rgb_to_hls(self._rgba.r, self._rgba.g, self._rgba.b) # noqa: E741 + if alpha is None: + if self._rgba.alpha is None: + return h, s, l + else: + return h, s, l, self._alpha_float() + if alpha: + return h, s, l, self._alpha_float() + else: + # alpha is False + return h, s, l + + def _alpha_float(self) -> float: + return 1 if self._rgba.alpha is None else self._rgba.alpha + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: Callable[[Any], CoreSchema] + ) -> core_schema.CoreSchema: + return core_schema.with_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, __input_value: Any, _: Any) -> 'Color': + return cls(__input_value) + + def __str__(self) -> str: + return self.as_named(fallback=True) + + def __repr_args__(self) -> '_repr.ReprArgs': + return [(None, self.as_named(fallback=True))] + [('rgb', self.as_rgb_tuple())] + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Color) and self.as_rgb_tuple() == other.as_rgb_tuple() + + def __hash__(self) -> int: + return hash(self.as_rgb_tuple()) + + +def parse_tuple(value: tuple[Any, ...]) -> RGBA: + """Parse a tuple or list to get RGBA values. + + Args: + value: A tuple or list. + + Returns: + An `RGBA` tuple parsed from the input tuple. + + Raises: + PydanticCustomError: If tuple is not valid. + """ + if len(value) == 3: + r, g, b = (parse_color_value(v) for v in value) + return RGBA(r, g, b, None) + elif len(value) == 4: + r, g, b = (parse_color_value(v) for v in value[:3]) + return RGBA(r, g, b, parse_float_alpha(value[3])) + else: + raise PydanticCustomError('color_error', 'value is not a valid color: tuples must have length 3 or 4') + + +def parse_str(value: str) -> RGBA: + """Parse a string representing a color to an RGBA tuple. + + Possible formats for the input string include: + + * named color, see `COLORS_BY_NAME` + * hex short eg. `fff` (prefix can be `#`, `0x` or nothing) + * hex long eg. `ffffff` (prefix can be `#`, `0x` or nothing) + * `rgb(, , )` + * `rgba(, , , )` + + Args: + value: A string representing a color. + + Returns: + An `RGBA` tuple parsed from the input string. + + Raises: + ValueError: If the input string cannot be parsed to an RGBA tuple. + """ + value_lower = value.lower() + try: + r, g, b = COLORS_BY_NAME[value_lower] + except KeyError: + pass + else: + return ints_to_rgba(r, g, b, None) + + m = re.fullmatch(r_hex_short, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v * 2, 16) for v in rgb) + if a: + alpha: Optional[float] = int(a * 2, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_hex_long, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v, 16) for v in rgb) + if a: + alpha = int(a, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_rgb, value_lower) or re.fullmatch(r_rgb_v4_style, value_lower) + if m: + return ints_to_rgba(*m.groups()) # type: ignore + + m = re.fullmatch(r_hsl, value_lower) or re.fullmatch(r_hsl_v4_style, value_lower) + if m: + return parse_hsl(*m.groups()) # type: ignore + + raise PydanticCustomError('color_error', 'value is not a valid color: string not recognised as a valid color') + + +def ints_to_rgba(r: Union[int, str], g: Union[int, str], b: Union[int, str], alpha: Optional[float] = None) -> RGBA: + """Converts integer or string values for RGB color and an optional alpha value to an `RGBA` object. + + Args: + r: An integer or string representing the red color value. + g: An integer or string representing the green color value. + b: An integer or string representing the blue color value. + alpha: A float representing the alpha value. Defaults to None. + + Returns: + An instance of the `RGBA` class with the corresponding color and alpha values. + """ + return RGBA(parse_color_value(r), parse_color_value(g), parse_color_value(b), parse_float_alpha(alpha)) + + +def parse_color_value(value: Union[int, str], max_val: int = 255) -> float: + """Parse the color value provided and return a number between 0 and 1. + + Args: + value: An integer or string color value. + max_val: Maximum range value. Defaults to 255. + + Raises: + PydanticCustomError: If the value is not a valid color. + + Returns: + A number between 0 and 1. + """ + try: + color = float(value) + except ValueError: + raise PydanticCustomError('color_error', 'value is not a valid color: color values must be a valid number') + if 0 <= color <= max_val: + return color / max_val + else: + raise PydanticCustomError( + 'color_error', + 'value is not a valid color: color values must be in the range 0 to {max_val}', + {'max_val': max_val}, + ) + + +def parse_float_alpha(value: Union[None, str, float, int]) -> Optional[float]: + """Parse an alpha value checking it's a valid float in the range 0 to 1. + + Args: + value: The input value to parse. + + Returns: + The parsed value as a float, or `None` if the value was None or equal 1. + + Raises: + PydanticCustomError: If the input value cannot be successfully parsed as a float in the expected range. + """ + if value is None: + return None + try: + if isinstance(value, str) and value.endswith('%'): + alpha = float(value[:-1]) / 100 + else: + alpha = float(value) + except ValueError: + raise PydanticCustomError('color_error', 'value is not a valid color: alpha values must be a valid float') + + if math.isclose(alpha, 1): + return None + elif 0 <= alpha <= 1: + return alpha + else: + raise PydanticCustomError('color_error', 'value is not a valid color: alpha values must be in the range 0 to 1') + + +def parse_hsl(h: str, h_units: str, sat: str, light: str, alpha: Optional[float] = None) -> RGBA: + """Parse raw hue, saturation, lightness, and alpha values and convert to RGBA. + + Args: + h: The hue value. + h_units: The unit for hue value. + sat: The saturation value. + light: The lightness value. + alpha: Alpha value. + + Returns: + An instance of `RGBA`. + """ + s_value, l_value = parse_color_value(sat, 100), parse_color_value(light, 100) + + h_value = float(h) + if h_units in {None, 'deg'}: + h_value = h_value % 360 / 360 + elif h_units == 'rad': + h_value = h_value % rads / rads + else: + # turns + h_value = h_value % 1 + + r, g, b = hls_to_rgb(h_value, l_value, s_value) + return RGBA(r, g, b, parse_float_alpha(alpha)) + + +def float_to_255(c: float) -> int: + """Converts a float value between 0 and 1 (inclusive) to an integer between 0 and 255 (inclusive). + + Args: + c: The float value to be converted. Must be between 0 and 1 (inclusive). + + Returns: + The integer equivalent of the given float value rounded to the nearest whole number. + + Raises: + ValueError: If the given float value is outside the acceptable range of 0 to 1 (inclusive). + """ + return int(round(c * 255)) + + +COLORS_BY_NAME = { + 'aliceblue': (240, 248, 255), + 'antiquewhite': (250, 235, 215), + 'aqua': (0, 255, 255), + 'aquamarine': (127, 255, 212), + 'azure': (240, 255, 255), + 'beige': (245, 245, 220), + 'bisque': (255, 228, 196), + 'black': (0, 0, 0), + 'blanchedalmond': (255, 235, 205), + 'blue': (0, 0, 255), + 'blueviolet': (138, 43, 226), + 'brown': (165, 42, 42), + 'burlywood': (222, 184, 135), + 'cadetblue': (95, 158, 160), + 'chartreuse': (127, 255, 0), + 'chocolate': (210, 105, 30), + 'coral': (255, 127, 80), + 'cornflowerblue': (100, 149, 237), + 'cornsilk': (255, 248, 220), + 'crimson': (220, 20, 60), + 'cyan': (0, 255, 255), + 'darkblue': (0, 0, 139), + 'darkcyan': (0, 139, 139), + 'darkgoldenrod': (184, 134, 11), + 'darkgray': (169, 169, 169), + 'darkgreen': (0, 100, 0), + 'darkgrey': (169, 169, 169), + 'darkkhaki': (189, 183, 107), + 'darkmagenta': (139, 0, 139), + 'darkolivegreen': (85, 107, 47), + 'darkorange': (255, 140, 0), + 'darkorchid': (153, 50, 204), + 'darkred': (139, 0, 0), + 'darksalmon': (233, 150, 122), + 'darkseagreen': (143, 188, 143), + 'darkslateblue': (72, 61, 139), + 'darkslategray': (47, 79, 79), + 'darkslategrey': (47, 79, 79), + 'darkturquoise': (0, 206, 209), + 'darkviolet': (148, 0, 211), + 'deeppink': (255, 20, 147), + 'deepskyblue': (0, 191, 255), + 'dimgray': (105, 105, 105), + 'dimgrey': (105, 105, 105), + 'dodgerblue': (30, 144, 255), + 'firebrick': (178, 34, 34), + 'floralwhite': (255, 250, 240), + 'forestgreen': (34, 139, 34), + 'fuchsia': (255, 0, 255), + 'gainsboro': (220, 220, 220), + 'ghostwhite': (248, 248, 255), + 'gold': (255, 215, 0), + 'goldenrod': (218, 165, 32), + 'gray': (128, 128, 128), + 'green': (0, 128, 0), + 'greenyellow': (173, 255, 47), + 'grey': (128, 128, 128), + 'honeydew': (240, 255, 240), + 'hotpink': (255, 105, 180), + 'indianred': (205, 92, 92), + 'indigo': (75, 0, 130), + 'ivory': (255, 255, 240), + 'khaki': (240, 230, 140), + 'lavender': (230, 230, 250), + 'lavenderblush': (255, 240, 245), + 'lawngreen': (124, 252, 0), + 'lemonchiffon': (255, 250, 205), + 'lightblue': (173, 216, 230), + 'lightcoral': (240, 128, 128), + 'lightcyan': (224, 255, 255), + 'lightgoldenrodyellow': (250, 250, 210), + 'lightgray': (211, 211, 211), + 'lightgreen': (144, 238, 144), + 'lightgrey': (211, 211, 211), + 'lightpink': (255, 182, 193), + 'lightsalmon': (255, 160, 122), + 'lightseagreen': (32, 178, 170), + 'lightskyblue': (135, 206, 250), + 'lightslategray': (119, 136, 153), + 'lightslategrey': (119, 136, 153), + 'lightsteelblue': (176, 196, 222), + 'lightyellow': (255, 255, 224), + 'lime': (0, 255, 0), + 'limegreen': (50, 205, 50), + 'linen': (250, 240, 230), + 'magenta': (255, 0, 255), + 'maroon': (128, 0, 0), + 'mediumaquamarine': (102, 205, 170), + 'mediumblue': (0, 0, 205), + 'mediumorchid': (186, 85, 211), + 'mediumpurple': (147, 112, 219), + 'mediumseagreen': (60, 179, 113), + 'mediumslateblue': (123, 104, 238), + 'mediumspringgreen': (0, 250, 154), + 'mediumturquoise': (72, 209, 204), + 'mediumvioletred': (199, 21, 133), + 'midnightblue': (25, 25, 112), + 'mintcream': (245, 255, 250), + 'mistyrose': (255, 228, 225), + 'moccasin': (255, 228, 181), + 'navajowhite': (255, 222, 173), + 'navy': (0, 0, 128), + 'oldlace': (253, 245, 230), + 'olive': (128, 128, 0), + 'olivedrab': (107, 142, 35), + 'orange': (255, 165, 0), + 'orangered': (255, 69, 0), + 'orchid': (218, 112, 214), + 'palegoldenrod': (238, 232, 170), + 'palegreen': (152, 251, 152), + 'paleturquoise': (175, 238, 238), + 'palevioletred': (219, 112, 147), + 'papayawhip': (255, 239, 213), + 'peachpuff': (255, 218, 185), + 'peru': (205, 133, 63), + 'pink': (255, 192, 203), + 'plum': (221, 160, 221), + 'powderblue': (176, 224, 230), + 'purple': (128, 0, 128), + 'red': (255, 0, 0), + 'rosybrown': (188, 143, 143), + 'royalblue': (65, 105, 225), + 'saddlebrown': (139, 69, 19), + 'salmon': (250, 128, 114), + 'sandybrown': (244, 164, 96), + 'seagreen': (46, 139, 87), + 'seashell': (255, 245, 238), + 'sienna': (160, 82, 45), + 'silver': (192, 192, 192), + 'skyblue': (135, 206, 235), + 'slateblue': (106, 90, 205), + 'slategray': (112, 128, 144), + 'slategrey': (112, 128, 144), + 'snow': (255, 250, 250), + 'springgreen': (0, 255, 127), + 'steelblue': (70, 130, 180), + 'tan': (210, 180, 140), + 'teal': (0, 128, 128), + 'thistle': (216, 191, 216), + 'tomato': (255, 99, 71), + 'turquoise': (64, 224, 208), + 'violet': (238, 130, 238), + 'wheat': (245, 222, 179), + 'white': (255, 255, 255), + 'whitesmoke': (245, 245, 245), + 'yellow': (255, 255, 0), + 'yellowgreen': (154, 205, 50), +} + +COLORS_BY_VALUE = {v: k for k, v in COLORS_BY_NAME.items()} diff --git a/source/target-vendors/cp312/pydantic/config.py b/source/target-vendors/cp312/pydantic/config.py new file mode 100644 index 0000000..6d89525 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/config.py @@ -0,0 +1,1296 @@ +"""Configuration for Pydantic models.""" + +from __future__ import annotations as _annotations + +import warnings +from re import Pattern +from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar, Union, cast, overload + +from typing_extensions import TypeAlias, TypedDict, Unpack, deprecated + +from ._migration import getattr_migration +from .aliases import AliasGenerator +from .errors import PydanticUserError +from .warnings import PydanticDeprecatedSince211 + +if TYPE_CHECKING: + from ._internal._generate_schema import GenerateSchema as _GenerateSchema + from .fields import ComputedFieldInfo, FieldInfo + +__all__ = ('ConfigDict', 'with_config') + + +JsonValue: TypeAlias = Union[int, float, str, bool, None, list['JsonValue'], 'JsonDict'] +JsonDict: TypeAlias = dict[str, JsonValue] + +JsonEncoder = Callable[[Any], Any] + +JsonSchemaExtraCallable: TypeAlias = Union[ + Callable[[JsonDict], None], + Callable[[JsonDict, type[Any]], None], +] + +ExtraValues = Literal['allow', 'ignore', 'forbid'] + + +class ConfigDict(TypedDict, total=False): + """A TypedDict for configuring Pydantic behaviour.""" + + title: str | None + """The title for the generated JSON schema, defaults to the model's name""" + + model_title_generator: Callable[[type], str] | None + """A callable that takes a model class and returns the title for it. Defaults to `None`.""" + + field_title_generator: Callable[[str, FieldInfo | ComputedFieldInfo], str] | None + """A callable that takes a field's name and info and returns title for it. Defaults to `None`.""" + + str_to_lower: bool + """Whether to convert all characters to lowercase for str types. Defaults to `False`.""" + + str_to_upper: bool + """Whether to convert all characters to uppercase for str types. Defaults to `False`.""" + + str_strip_whitespace: bool + """Whether to strip leading and trailing whitespace for str types.""" + + str_min_length: int + """The minimum length for str types. Defaults to `None`.""" + + str_max_length: int | None + """The maximum length for str types. Defaults to `None`.""" + + extra: ExtraValues | None + ''' + Whether to ignore, allow, or forbid extra data during model initialization. Defaults to `'ignore'`. + + Three configuration values are available: + + - `'ignore'`: Providing extra data is ignored (the default): + ```python + from pydantic import BaseModel, ConfigDict + + class User(BaseModel): + model_config = ConfigDict(extra='ignore') # (1)! + + name: str + + user = User(name='John Doe', age=20) # (2)! + print(user) + #> name='John Doe' + ``` + + 1. This is the default behaviour. + 2. The `age` argument is ignored. + + - `'forbid'`: Providing extra data is not permitted, and a [`ValidationError`][pydantic_core.ValidationError] + will be raised if this is the case: + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + + class Model(BaseModel): + x: int + + model_config = ConfigDict(extra='forbid') + + + try: + Model(x=1, y='a') + except ValidationError as exc: + print(exc) + """ + 1 validation error for Model + y + Extra inputs are not permitted [type=extra_forbidden, input_value='a', input_type=str] + """ + ``` + + - `'allow'`: Providing extra data is allowed and stored in the `__pydantic_extra__` dictionary attribute: + ```python + from pydantic import BaseModel, ConfigDict + + + class Model(BaseModel): + x: int + + model_config = ConfigDict(extra='allow') + + + m = Model(x=1, y='a') + assert m.__pydantic_extra__ == {'y': 'a'} + ``` + By default, no validation will be applied to these extra items, but you can set a type for the values by overriding + the type annotation for `__pydantic_extra__`: + ```python + from pydantic import BaseModel, ConfigDict, Field, ValidationError + + + class Model(BaseModel): + __pydantic_extra__: dict[str, int] = Field(init=False) # (1)! + + x: int + + model_config = ConfigDict(extra='allow') + + + try: + Model(x=1, y='a') + except ValidationError as exc: + print(exc) + """ + 1 validation error for Model + y + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] + """ + + m = Model(x=1, y='2') + assert m.x == 1 + assert m.y == 2 + assert m.model_dump() == {'x': 1, 'y': 2} + assert m.__pydantic_extra__ == {'y': 2} + ``` + + 1. The `= Field(init=False)` does not have any effect at runtime, but prevents the `__pydantic_extra__` field from + being included as a parameter to the model's `__init__` method by type checkers. + + As well as specifying an `extra` configuration value on the model, you can also provide it as an argument to the validation methods. + This will override any `extra` configuration value set on the model: + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + class Model(BaseModel): + x: int + model_config = ConfigDict(extra="allow") + + try: + # Override model config and forbid extra fields just this time + Model.model_validate({"x": 1, "y": 2}, extra="forbid") + except ValidationError as exc: + print(exc) + """ + 1 validation error for Model + y + Extra inputs are not permitted [type=extra_forbidden, input_value=2, input_type=int] + """ + ``` + ''' + + frozen: bool + """ + Whether models are faux-immutable, i.e. whether `__setattr__` is allowed, and also generates + a `__hash__()` method for the model. This makes instances of the model potentially hashable if all the + attributes are hashable. Defaults to `False`. + + Note: + On V1, the inverse of this setting was called `allow_mutation`, and was `True` by default. + """ + + populate_by_name: bool + """ + Whether an aliased field may be populated by its name as given by the model + attribute, as well as the alias. Defaults to `False`. + + !!! warning + `populate_by_name` usage is not recommended in v2.11+ and will be deprecated in v3. + Instead, you should use the [`validate_by_name`][pydantic.config.ConfigDict.validate_by_name] configuration setting. + + When `validate_by_name=True` and `validate_by_alias=True`, this is strictly equivalent to the + previous behavior of `populate_by_name=True`. + + In v2.11, we also introduced a [`validate_by_alias`][pydantic.config.ConfigDict.validate_by_alias] setting that introduces more fine grained + control for validation behavior. + + Here's how you might go about using the new settings to achieve the same behavior: + + ```python + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + my_field: str = Field(alias='my_alias') # (1)! + + m = Model(my_alias='foo') # (2)! + print(m) + #> my_field='foo' + + m = Model(my_field='foo') # (3)! + print(m) + #> my_field='foo' + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model is populated by the alias `'my_alias'`. + 3. The model is populated by the attribute name `'my_field'`. + """ + + use_enum_values: bool + """ + Whether to populate models with the `value` property of enums, rather than the raw enum. + This may be useful if you want to serialize `model.model_dump()` later. Defaults to `False`. + + !!! note + If you have an `Optional[Enum]` value that you set a default for, you need to use `validate_default=True` + for said Field to ensure that the `use_enum_values` flag takes effect on the default, as extracting an + enum's value occurs during validation, not serialization. + + ```python + from enum import Enum + from typing import Optional + + from pydantic import BaseModel, ConfigDict, Field + + class SomeEnum(Enum): + FOO = 'foo' + BAR = 'bar' + BAZ = 'baz' + + class SomeModel(BaseModel): + model_config = ConfigDict(use_enum_values=True) + + some_enum: SomeEnum + another_enum: Optional[SomeEnum] = Field( + default=SomeEnum.FOO, validate_default=True + ) + + model1 = SomeModel(some_enum=SomeEnum.BAR) + print(model1.model_dump()) + #> {'some_enum': 'bar', 'another_enum': 'foo'} + + model2 = SomeModel(some_enum=SomeEnum.BAR, another_enum=SomeEnum.BAZ) + print(model2.model_dump()) + #> {'some_enum': 'bar', 'another_enum': 'baz'} + ``` + """ + + validate_assignment: bool + """ + Whether to validate the data when the model is changed. Defaults to `False`. + + The default behavior of Pydantic is to validate the data when the model is created. + + In case the user changes the data after the model is created, the model is _not_ revalidated. + + ```python + from pydantic import BaseModel + + class User(BaseModel): + name: str + + user = User(name='John Doe') # (1)! + print(user) + #> name='John Doe' + user.name = 123 # (1)! + print(user) + #> name=123 + ``` + + 1. The validation happens only when the model is created. + 2. The validation does not happen when the data is changed. + + In case you want to revalidate the model when the data is changed, you can use `validate_assignment=True`: + + ```python + from pydantic import BaseModel, ValidationError + + class User(BaseModel, validate_assignment=True): # (1)! + name: str + + user = User(name='John Doe') # (2)! + print(user) + #> name='John Doe' + try: + user.name = 123 # (3)! + except ValidationError as e: + print(e) + ''' + 1 validation error for User + name + Input should be a valid string [type=string_type, input_value=123, input_type=int] + ''' + ``` + + 1. You can either use class keyword arguments, or `model_config` to set `validate_assignment=True`. + 2. The validation happens when the model is created. + 3. The validation _also_ happens when the data is changed. + """ + + arbitrary_types_allowed: bool + """ + Whether arbitrary types are allowed for field types. Defaults to `False`. + + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + # This is not a pydantic model, it's an arbitrary class + class Pet: + def __init__(self, name: str): + self.name = name + + class Model(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True) + + pet: Pet + owner: str + + pet = Pet(name='Hedwig') + # A simple check of instance type is used to validate the data + model = Model(owner='Harry', pet=pet) + print(model) + #> pet=<__main__.Pet object at 0x0123456789ab> owner='Harry' + print(model.pet) + #> <__main__.Pet object at 0x0123456789ab> + print(model.pet.name) + #> Hedwig + print(type(model.pet)) + #> + try: + # If the value is not an instance of the type, it's invalid + Model(owner='Harry', pet='Hedwig') + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + pet + Input should be an instance of Pet [type=is_instance_of, input_value='Hedwig', input_type=str] + ''' + + # Nothing in the instance of the arbitrary type is checked + # Here name probably should have been a str, but it's not validated + pet2 = Pet(name=42) + model2 = Model(owner='Harry', pet=pet2) + print(model2) + #> pet=<__main__.Pet object at 0x0123456789ab> owner='Harry' + print(model2.pet) + #> <__main__.Pet object at 0x0123456789ab> + print(model2.pet.name) + #> 42 + print(type(model2.pet)) + #> + ``` + """ + + from_attributes: bool + """ + Whether to build models and look up discriminators of tagged unions using python object attributes. + """ + + loc_by_alias: bool + """Whether to use the actual key provided in the data (e.g. alias) for error `loc`s rather than the field's name. Defaults to `True`.""" + + alias_generator: Callable[[str], str] | AliasGenerator | None + """ + A callable that takes a field name and returns an alias for it + or an instance of [`AliasGenerator`][pydantic.aliases.AliasGenerator]. Defaults to `None`. + + When using a callable, the alias generator is used for both validation and serialization. + If you want to use different alias generators for validation and serialization, you can use + [`AliasGenerator`][pydantic.aliases.AliasGenerator] instead. + + If data source field names do not match your code style (e.g. CamelCase fields), + you can automatically generate aliases using `alias_generator`. Here's an example with + a basic callable: + + ```python + from pydantic import BaseModel, ConfigDict + from pydantic.alias_generators import to_pascal + + class Voice(BaseModel): + model_config = ConfigDict(alias_generator=to_pascal) + + name: str + language_code: str + + voice = Voice(Name='Filiz', LanguageCode='tr-TR') + print(voice.language_code) + #> tr-TR + print(voice.model_dump(by_alias=True)) + #> {'Name': 'Filiz', 'LanguageCode': 'tr-TR'} + ``` + + If you want to use different alias generators for validation and serialization, you can use + [`AliasGenerator`][pydantic.aliases.AliasGenerator]. + + ```python + from pydantic import AliasGenerator, BaseModel, ConfigDict + from pydantic.alias_generators import to_camel, to_pascal + + class Athlete(BaseModel): + first_name: str + last_name: str + sport: str + + model_config = ConfigDict( + alias_generator=AliasGenerator( + validation_alias=to_camel, + serialization_alias=to_pascal, + ) + ) + + athlete = Athlete(firstName='John', lastName='Doe', sport='track') + print(athlete.model_dump(by_alias=True)) + #> {'FirstName': 'John', 'LastName': 'Doe', 'Sport': 'track'} + ``` + + Note: + Pydantic offers three built-in alias generators: [`to_pascal`][pydantic.alias_generators.to_pascal], + [`to_camel`][pydantic.alias_generators.to_camel], and [`to_snake`][pydantic.alias_generators.to_snake]. + """ + + ignored_types: tuple[type, ...] + """A tuple of types that may occur as values of class attributes without annotations. This is + typically used for custom descriptors (classes that behave like `property`). If an attribute is set on a + class without an annotation and has a type that is not in this tuple (or otherwise recognized by + _pydantic_), an error will be raised. Defaults to `()`. + """ + + allow_inf_nan: bool + """Whether to allow infinity (`+inf` an `-inf`) and NaN values to float and decimal fields. Defaults to `True`.""" + + json_schema_extra: JsonDict | JsonSchemaExtraCallable | None + """A dict or callable to provide extra JSON schema properties. Defaults to `None`.""" + + json_encoders: dict[type[object], JsonEncoder] | None + """ + A `dict` of custom JSON encoders for specific types. Defaults to `None`. + + /// version-deprecated | v2 + This configuration option is a carryover from v1. We originally planned to remove it in v2 but didn't have a 1:1 replacement + so we are keeping it for now. It is still deprecated and will likely be removed in the future. + /// + """ + + # new in V2 + strict: bool + """ + Whether strict validation is applied to all fields on the model. + + By default, Pydantic attempts to coerce values to the correct type, when possible. + + There are situations in which you may want to disable this behavior, and instead raise an error if a value's type + does not match the field's type annotation. + + To configure strict mode for all fields on a model, you can set `strict=True` on the model. + + ```python + from pydantic import BaseModel, ConfigDict + + class Model(BaseModel): + model_config = ConfigDict(strict=True) + + name: str + age: int + ``` + + See [Strict Mode](../concepts/strict_mode.md) for more details. + + See the [Conversion Table](../concepts/conversion_table.md) for more details on how Pydantic converts data in both + strict and lax modes. + + /// version-added | v2 + /// + """ + # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' + revalidate_instances: Literal['always', 'never', 'subclass-instances'] + """ + When and how to revalidate models and dataclasses during validation. Can be one of: + + - `'never'`: will *not* revalidate models and dataclasses during validation + - `'always'`: will revalidate models and dataclasses during validation + - `'subclass-instances'`: will revalidate models and dataclasses during validation if the instance is a + subclass of the model or dataclass + + The default is `'never'` (no revalidation). + + This configuration only affects *the current model* it is applied on, and does *not* propagate to the models + referenced in fields. + + ```python + from pydantic import BaseModel + + class User(BaseModel, revalidate_instances='never'): # (1)! + name: str + + class Transaction(BaseModel): + user: User + + my_user = User(name='John') + t = Transaction(user=my_user) + + my_user.name = 1 # (2)! + t = Transaction(user=my_user) # (3)! + print(t) + #> user=User(name=1) + ``` + + 1. This is the default behavior. + 2. The assignment is *not* validated, unless you set [`validate_assignment`][pydantic.ConfigDict.validate_assignment] in the configuration. + 3. Since `revalidate_instances` is set to `'never'`, the user instance is not revalidated. + + Here is an example demonstrating the behavior of `'subclass-instances'`: + + ```python + from pydantic import BaseModel + + class User(BaseModel, revalidate_instances='subclass-instances'): + name: str + + class SubUser(User): + age: int + + class Transaction(BaseModel): + user: User + + my_user = User(name='John') + my_user.name = 1 # (1)! + t = Transaction(user=my_user) # (2)! + print(t) + #> user=User(name=1) + + my_sub_user = SubUser(name='John', age=20) + t = Transaction(user=my_sub_user) + print(t) # (3)! + #> user=User(name='John') + ``` + + 1. The assignment is *not* validated, unless you set [`validate_assignment`][pydantic.ConfigDict.validate_assignment] in the configuration. + 2. Because `my_user` is a "direct" instance of `User`, it is *not* being revalidated. It would have been the case if + `revalidate_instances` was set to `'always'`. + 3. Because `my_sub_user` is an instance of a `User` subclass, it is being revalidated. In this case, Pydantic coerces `my_sub_user` to the defined + `User` class defined on `Transaction`. If one of its fields had an invalid value, a validation error would have been raised. + + /// version-added | v2 + /// + """ + + ser_json_timedelta: Literal['iso8601', 'float'] + """ + The format of JSON serialized timedeltas. Accepts the string values of `'iso8601'` and + `'float'`. Defaults to `'iso8601'`. + + - `'iso8601'` will serialize timedeltas to [ISO 8601 text format](https://en.wikipedia.org/wiki/ISO_8601#Durations). + - `'float'` will serialize timedeltas to the total number of seconds. + + /// version-changed | v2.12 + It is now recommended to use the [`ser_json_temporal`][pydantic.config.ConfigDict.ser_json_temporal] + setting. `ser_json_timedelta` will be deprecated in v3. + /// + """ + + ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds'] + """ + The format of JSON serialized temporal types from the [`datetime`][] module. This includes: + + - [`datetime.datetime`][] + - [`datetime.date`][] + - [`datetime.time`][] + - [`datetime.timedelta`][] + + Can be one of: + + - `'iso8601'` will serialize date-like types to [ISO 8601 text format](https://en.wikipedia.org/wiki/ISO_8601#Durations). + - `'milliseconds'` will serialize date-like types to a floating point number of milliseconds since the epoch. + - `'seconds'` will serialize date-like types to a floating point number of seconds since the epoch. + + Defaults to `'iso8601'`. + + /// version-added | v2.12 + This setting replaces [`ser_json_timedelta`][pydantic.config.ConfigDict.ser_json_timedelta], + which will be deprecated in v3. `ser_json_temporal` adds more configurability for the other temporal types. + /// + """ + + val_temporal_unit: Literal['seconds', 'milliseconds', 'infer'] + """ + The unit to assume for validating numeric input for datetime-like types ([`datetime.datetime`][] and [`datetime.date`][]). Can be one of: + + - `'seconds'` will validate date or time numeric inputs as seconds since the [epoch]. + - `'milliseconds'` will validate date or time numeric inputs as milliseconds since the [epoch]. + - `'infer'` will infer the unit from the string numeric input on unix time as: + + * seconds since the [epoch] if $-2^{10} <= v <= 2^{10}$ + * milliseconds since the [epoch] (if $v < -2^{10}$ or $v > 2^{10}$). + + Defaults to `'infer'`. + + /// version-added | v2.12 + /// + + [epoch]: https://en.wikipedia.org/wiki/Unix_time + """ + + ser_json_bytes: Literal['utf8', 'base64', 'hex'] + """ + The encoding of JSON serialized bytes. Defaults to `'utf8'`. + Set equal to `val_json_bytes` to get back an equal value after serialization round trip. + + - `'utf8'` will serialize bytes to UTF-8 strings. + - `'base64'` will serialize bytes to URL safe base64 strings. + - `'hex'` will serialize bytes to hexadecimal strings. + """ + + val_json_bytes: Literal['utf8', 'base64', 'hex'] + """ + /// version-added | v2.9 + /// + + The encoding of JSON serialized bytes to decode. Defaults to `'utf8'`. + Set equal to `ser_json_bytes` to get back an equal value after serialization round trip. + + - `'utf8'` will deserialize UTF-8 strings to bytes. + - `'base64'` will deserialize URL safe base64 strings to bytes. + - `'hex'` will deserialize hexadecimal strings to bytes. + """ + + ser_json_inf_nan: Literal['null', 'constants', 'strings'] + """ + The encoding of JSON serialized infinity and NaN float values. Defaults to `'null'`. + + - `'null'` will serialize infinity and NaN values as `null`. + - `'constants'` will serialize infinity and NaN values as `Infinity` and `NaN`. + - `'strings'` will serialize infinity as string `"Infinity"` and NaN as string `"NaN"`. + """ + + # whether to validate default values during validation, default False + validate_default: bool + """Whether to validate default values during validation. Defaults to `False`.""" + + validate_return: bool + """Whether to validate the return value from call validators. Defaults to `False`.""" + + protected_namespaces: tuple[str | Pattern[str], ...] + """ + A tuple of strings and/or regex patterns that prevent models from having fields with names that conflict with its existing members/methods. + + Strings are matched on a prefix basis. For instance, with `'dog'`, having a field named `'dog_name'` will be disallowed. + + Regex patterns are matched on the entire field name. For instance, with the pattern `'^dog$'`, having a field named `'dog'` will be disallowed, + but `'dog_name'` will be accepted. + + Defaults to `('model_validate', 'model_dump')`. This default is used to prevent collisions with the existing (and possibly future) + [validation](../concepts/models.md#validating-data) and [serialization](../concepts/serialization.md#serializing-data) methods. + + ```python + import warnings + + from pydantic import BaseModel + + warnings.filterwarnings('error') # Raise warnings as errors + + try: + + class Model(BaseModel): + model_dump_something: str + + except UserWarning as e: + print(e) + ''' + Field 'model_dump_something' in 'Model' conflicts with protected namespace 'model_dump'. + + You may be able to solve this by setting the 'protected_namespaces' configuration to ('model_validate',). + ''' + ``` + + You can customize this behavior using the `protected_namespaces` setting: + + ```python {test="skip"} + import re + import warnings + + from pydantic import BaseModel, ConfigDict + + with warnings.catch_warnings(record=True) as caught_warnings: + warnings.simplefilter('always') # Catch all warnings + + class Model(BaseModel): + safe_field: str + also_protect_field: str + protect_this: str + + model_config = ConfigDict( + protected_namespaces=( + 'protect_me_', + 'also_protect_', + re.compile('^protect_this$'), + ) + ) + + for warning in caught_warnings: + print(f'{warning.message}') + ''' + Field 'also_protect_field' in 'Model' conflicts with protected namespace 'also_protect_'. + You may be able to solve this by setting the 'protected_namespaces' configuration to ('protect_me_', re.compile('^protect_this$'))`. + + Field 'protect_this' in 'Model' conflicts with protected namespace 're.compile('^protect_this$')'. + You may be able to solve this by setting the 'protected_namespaces' configuration to ('protect_me_', 'also_protect_')`. + ''' + ``` + + While Pydantic will only emit a warning when an item is in a protected namespace but does not actually have a collision, + an error _is_ raised if there is an actual collision with an existing attribute: + + ```python + from pydantic import BaseModel, ConfigDict + + try: + + class Model(BaseModel): + model_validate: str + + model_config = ConfigDict(protected_namespaces=('model_',)) + + except ValueError as e: + print(e) + ''' + Field 'model_validate' conflicts with member > of protected namespace 'model_'. + ''' + ``` + + /// version-changed | v2.10 + The default protected namespaces was changed from `('model_',)` to `('model_validate', 'model_dump')`, to allow + for fields like `model_id`, `model_name` to be used. + /// + """ + + hide_input_in_errors: bool + """ + Whether to hide inputs when printing errors. Defaults to `False`. + + Pydantic shows the input value and type when it raises `ValidationError` during the validation. + + ```python + from pydantic import BaseModel, ValidationError + + class Model(BaseModel): + a: str + + try: + Model(a=123) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + a + Input should be a valid string [type=string_type, input_value=123, input_type=int] + ''' + ``` + + You can hide the input value and type by setting the `hide_input_in_errors` config to `True`. + + ```python + from pydantic import BaseModel, ConfigDict, ValidationError + + class Model(BaseModel): + a: str + model_config = ConfigDict(hide_input_in_errors=True) + + try: + Model(a=123) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + a + Input should be a valid string [type=string_type] + ''' + ``` + """ + + defer_build: bool + """ + Whether to defer model validator and serializer construction until the first model validation. Defaults to False. + + This can be useful to avoid the overhead of building models which are only + used nested within other models, or when you want to manually define type namespace via + [`Model.model_rebuild(_types_namespace=...)`][pydantic.BaseModel.model_rebuild]. + + /// version-changed | v2.10 + The setting also applies to [Pydantic dataclasses](../concepts/dataclasses.md) and [type adapters](../concepts/type_adapter.md). + /// + """ + + plugin_settings: dict[str, object] | None + """A `dict` of settings for plugins. Defaults to `None`.""" + + schema_generator: type[_GenerateSchema] | None + """ + The `GenerateSchema` class to use during core schema generation. + + /// version-deprecated | v2.10 + The `GenerateSchema` class is private and highly subject to change. + /// + """ + + json_schema_serialization_defaults_required: bool + """ + Whether fields with default values should be marked as required in the serialization schema. Defaults to `False`. + + This ensures that the serialization schema will reflect the fact a field with a default will always be present + when serializing the model, even though it is not required for validation. + + However, there are scenarios where this may be undesirable — in particular, if you want to share the schema + between validation and serialization, and don't mind fields with defaults being marked as not required during + serialization. See [#7209](https://github.com/pydantic/pydantic/issues/7209) for more details. + + ```python + from pydantic import BaseModel, ConfigDict + + class Model(BaseModel): + a: str = 'a' + + model_config = ConfigDict(json_schema_serialization_defaults_required=True) + + print(Model.model_json_schema(mode='validation')) + ''' + { + 'properties': {'a': {'default': 'a', 'title': 'A', 'type': 'string'}}, + 'title': 'Model', + 'type': 'object', + } + ''' + print(Model.model_json_schema(mode='serialization')) + ''' + { + 'properties': {'a': {'default': 'a', 'title': 'A', 'type': 'string'}}, + 'required': ['a'], + 'title': 'Model', + 'type': 'object', + } + ''' + ``` + + /// version-added | v2.4 + /// + """ + + json_schema_mode_override: Literal['validation', 'serialization', None] + """ + If not `None`, the specified mode will be used to generate the JSON schema regardless of what `mode` was passed to + the function call. Defaults to `None`. + + This provides a way to force the JSON schema generation to reflect a specific mode, e.g., to always use the + validation schema. + + It can be useful when using frameworks (such as FastAPI) that may generate different schemas for validation + and serialization that must both be referenced from the same schema; when this happens, we automatically append + `-Input` to the definition reference for the validation schema and `-Output` to the definition reference for the + serialization schema. By specifying a `json_schema_mode_override` though, this prevents the conflict between + the validation and serialization schemas (since both will use the specified schema), and so prevents the suffixes + from being added to the definition references. + + ```python + from pydantic import BaseModel, ConfigDict, Json + + class Model(BaseModel): + a: Json[int] # requires a string to validate, but will dump an int + + print(Model.model_json_schema(mode='serialization')) + ''' + { + 'properties': {'a': {'title': 'A', 'type': 'integer'}}, + 'required': ['a'], + 'title': 'Model', + 'type': 'object', + } + ''' + + class ForceInputModel(Model): + # the following ensures that even with mode='serialization', we + # will get the schema that would be generated for validation. + model_config = ConfigDict(json_schema_mode_override='validation') + + print(ForceInputModel.model_json_schema(mode='serialization')) + ''' + { + 'properties': { + 'a': { + 'contentMediaType': 'application/json', + 'contentSchema': {'type': 'integer'}, + 'title': 'A', + 'type': 'string', + } + }, + 'required': ['a'], + 'title': 'ForceInputModel', + 'type': 'object', + } + ''' + ``` + + /// version-added | v2.4 + /// + """ + + coerce_numbers_to_str: bool + """ + If `True`, enables automatic coercion of any `Number` type to `str` in "lax" (non-strict) mode. Defaults to `False`. + + Pydantic doesn't allow number types (`int`, `float`, `Decimal`) to be coerced as type `str` by default. + + ```python + from decimal import Decimal + + from pydantic import BaseModel, ConfigDict, ValidationError + + class Model(BaseModel): + value: str + + try: + print(Model(value=42)) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + value + Input should be a valid string [type=string_type, input_value=42, input_type=int] + ''' + + class Model(BaseModel): + model_config = ConfigDict(coerce_numbers_to_str=True) + + value: str + + repr(Model(value=42).value) + #> "42" + repr(Model(value=42.13).value) + #> "42.13" + repr(Model(value=Decimal('42.13')).value) + #> "42.13" + ``` + """ + + regex_engine: Literal['rust-regex', 'python-re'] + """ + The regex engine to be used for pattern validation. + Defaults to `'rust-regex'`. + + - `'rust-regex'` uses the [`regex`](https://docs.rs/regex) Rust crate, + which is non-backtracking and therefore more DDoS resistant, but does not support all regex features. + - `'python-re'` use the [`re`][] module, which supports all regex features, but may be slower. + + !!! note + If you use a compiled regex pattern, the `'python-re'` engine will be used regardless of this setting. + This is so that flags such as [`re.IGNORECASE`][] are respected. + + ```python + from pydantic import BaseModel, ConfigDict, Field, ValidationError + + class Model(BaseModel): + model_config = ConfigDict(regex_engine='python-re') + + value: str = Field(pattern=r'^abc(?=def)') + + print(Model(value='abcdef').value) + #> abcdef + + try: + print(Model(value='abxyzcdef')) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + value + String should match pattern '^abc(?=def)' [type=string_pattern_mismatch, input_value='abxyzcdef', input_type=str] + ''' + ``` + + /// version-added | v2.5 + /// + """ + + validation_error_cause: bool + """ + If `True`, Python exceptions that were part of a validation failure will be shown as an exception group as a cause. Can be useful for debugging. Defaults to `False`. + + Note: + Python 3.10 and older don't support exception groups natively. <=3.10, backport must be installed: `pip install exceptiongroup`. + + Note: + The structure of validation errors are likely to change in future Pydantic versions. Pydantic offers no guarantees about their structure. Should be used for visual traceback debugging only. + + /// version-added | v2.5 + /// + """ + + use_attribute_docstrings: bool + ''' + Whether docstrings of attributes (bare string literals immediately following the attribute declaration) + should be used for field descriptions. Defaults to `False`. + + ```python + from pydantic import BaseModel, ConfigDict, Field + + + class Model(BaseModel): + model_config = ConfigDict(use_attribute_docstrings=True) + + x: str + """ + Example of an attribute docstring + """ + + y: int = Field(description="Description in Field") + """ + Description in Field overrides attribute docstring + """ + + + print(Model.model_fields["x"].description) + # > Example of an attribute docstring + print(Model.model_fields["y"].description) + # > Description in Field + ``` + This requires the source code of the class to be available at runtime (and so won't work in the interactive interpreter shell). + + !!! warning "Usage with `TypedDict` and stdlib dataclasses" + Due to current limitations, attribute docstrings detection may not work as expected when using + [`TypedDict`][typing.TypedDict] and stdlib dataclasses, in particular when: + + - inheritance is being used. + - multiple classes have the same name in the same source file (unless Python 3.13 or greater is used). + + /// version-added | v2.7 + /// + ''' + + cache_strings: bool | Literal['all', 'keys', 'none'] + """ + Whether to cache strings to avoid constructing new Python objects. Defaults to True. + + Enabling this setting should significantly improve validation performance while increasing memory usage slightly. + + - `True` or `'all'` (the default): cache all strings + - `'keys'`: cache only dictionary keys + - `False` or `'none'`: no caching + + !!! note + `True` or `'all'` is required to cache strings during general validation because + validators don't know if they're in a key or a value. + + !!! tip + If repeated strings are rare, it's recommended to use `'keys'` or `'none'` to reduce memory usage, + as the performance difference is minimal if repeated strings are rare. + + /// version-added | v2.7 + /// + """ + + validate_by_alias: bool + """ + Whether an aliased field may be populated by its alias. Defaults to `True`. + + Here's an example of disabling validation by alias: + + ```py + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(validate_by_name=True, validate_by_alias=False) + + my_field: str = Field(validation_alias='my_alias') # (1)! + + m = Model(my_field='foo') # (2)! + print(m) + #> my_field='foo' + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model can only be populated by the attribute name `'my_field'`. + + !!! warning + You cannot set both `validate_by_alias` and `validate_by_name` to `False`. + This would make it impossible to populate an attribute. + + See [usage errors](../errors/usage_errors.md#validate-by-alias-and-name-false) for an example. + + If you set `validate_by_alias` to `False`, under the hood, Pydantic dynamically sets + `validate_by_name` to `True` to ensure that validation can still occur. + + /// version-added | v2.11 + This setting was introduced in conjunction with [`validate_by_name`][pydantic.ConfigDict.validate_by_name] + to empower users with more fine grained validation control. + /// + """ + + validate_by_name: bool + """ + Whether an aliased field may be populated by its name as given by the model + attribute. Defaults to `False`. + + ```python + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + my_field: str = Field(validation_alias='my_alias') # (1)! + + m = Model(my_alias='foo') # (2)! + print(m) + #> my_field='foo' + + m = Model(my_field='foo') # (3)! + print(m) + #> my_field='foo' + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model is populated by the alias `'my_alias'`. + 3. The model is populated by the attribute name `'my_field'`. + + !!! warning + You cannot set both `validate_by_alias` and `validate_by_name` to `False`. + This would make it impossible to populate an attribute. + + See [usage errors](../errors/usage_errors.md#validate-by-alias-and-name-false) for an example. + + /// version-added | v2.11 + This setting was introduced in conjunction with [`validate_by_alias`][pydantic.ConfigDict.validate_by_alias] + to empower users with more fine grained validation control. It is an alternative to [`populate_by_name`][pydantic.ConfigDict.populate_by_name], + that enables validation by name **and** by alias. + /// + """ + + serialize_by_alias: bool + """ + Whether an aliased field should be serialized by its alias. Defaults to `False`. + + Note: In v2.11, `serialize_by_alias` was introduced to address the + [popular request](https://github.com/pydantic/pydantic/issues/8379) + for consistency with alias behavior for validation and serialization settings. + In v3, the default value is expected to change to `True` for consistency with the validation default. + + ```python + from pydantic import BaseModel, ConfigDict, Field + + class Model(BaseModel): + model_config = ConfigDict(serialize_by_alias=True) + + my_field: str = Field(serialization_alias='my_alias') # (1)! + + m = Model(my_field='foo') + print(m.model_dump()) # (2)! + #> {'my_alias': 'foo'} + ``` + + 1. The field `'my_field'` has an alias `'my_alias'`. + 2. The model is serialized using the alias `'my_alias'` for the `'my_field'` attribute. + + + /// version-added | v2.11 + This setting was introduced to address the [popular request](https://github.com/pydantic/pydantic/issues/8379) + for consistency with alias behavior for validation and serialization. + + In v3, the default value is expected to change to `True` for consistency with the validation default. + /// + """ + + url_preserve_empty_path: bool + """ + Whether to preserve empty URL paths when validating values for a URL type. Defaults to `False`. + + ```python + from pydantic import AnyUrl, BaseModel, ConfigDict + + class Model(BaseModel): + model_config = ConfigDict(url_preserve_empty_path=True) + + url: AnyUrl + + m = Model(url='http://example.com') + print(m.url) + #> http://example.com + ``` + + /// version-added | v2.12 + /// + """ + + polymorphic_serialization: bool + """ + Whether to use polymorphic serialization for subclasses of the model or Pydantic dataclass. Defaults to `False`. + """ + + +_TypeT = TypeVar('_TypeT', bound=type) + + +@overload +@deprecated('Passing `config` as a keyword argument is deprecated. Pass `config` as a positional argument instead.') +def with_config(*, config: ConfigDict) -> Callable[[_TypeT], _TypeT]: ... + + +@overload +def with_config(config: ConfigDict, /) -> Callable[[_TypeT], _TypeT]: ... + + +@overload +def with_config(**config: Unpack[ConfigDict]) -> Callable[[_TypeT], _TypeT]: ... + + +def with_config(config: ConfigDict | None = None, /, **kwargs: Any) -> Callable[[_TypeT], _TypeT]: + """!!! abstract "Usage Documentation" + [Configuration with other types](../concepts/config.md#configuration-on-other-supported-types) + + A convenience decorator to set a [Pydantic configuration](config.md) on a `TypedDict` or a `dataclass` from the standard library. + + Although the configuration can be set using the `__pydantic_config__` attribute, it does not play well with type checkers, + especially with `TypedDict`. + + !!! example "Usage" + + ```python + from typing_extensions import TypedDict + + from pydantic import ConfigDict, TypeAdapter, with_config + + @with_config(ConfigDict(str_to_lower=True)) + class TD(TypedDict): + x: str + + ta = TypeAdapter(TD) + + print(ta.validate_python({'x': 'ABC'})) + #> {'x': 'abc'} + ``` + + /// deprecated-removed | v2.11 v3 + Passing `config` as a keyword argument. + /// + + /// version-changed | v2.11 + Keyword arguments can be provided directly instead of a config dictionary. + /// + """ + if config is not None and kwargs: + raise ValueError('Cannot specify both `config` and keyword arguments') + + if len(kwargs) == 1 and (kwargs_conf := kwargs.get('config')) is not None: + warnings.warn( + 'Passing `config` as a keyword argument is deprecated. Pass `config` as a positional argument instead', + category=PydanticDeprecatedSince211, + stacklevel=2, + ) + final_config = cast(ConfigDict, kwargs_conf) + else: + final_config = config if config is not None else cast(ConfigDict, kwargs) + + def inner(class_: _TypeT, /) -> _TypeT: + # Ideally, we would check for `class_` to either be a `TypedDict` or a stdlib dataclass. + # However, the `@with_config` decorator can be applied *after* `@dataclass`. To avoid + # common mistakes, we at least check for `class_` to not be a Pydantic model. + from ._internal._utils import is_model_class + + if is_model_class(class_): + raise PydanticUserError( + f'Cannot use `with_config` on {class_.__name__} as it is a Pydantic model', + code='with-config-on-model', + ) + class_.__pydantic_config__ = final_config + return class_ + + return inner + + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/dataclasses.py b/source/target-vendors/cp312/pydantic/dataclasses.py new file mode 100644 index 0000000..46401c3 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/dataclasses.py @@ -0,0 +1,413 @@ +"""Provide an enhanced dataclass that performs validation.""" + +from __future__ import annotations as _annotations + +import dataclasses +import functools +import sys +import types +from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, NoReturn, TypeVar, overload +from warnings import warn + +from typing_extensions import TypeGuard, dataclass_transform + +from ._internal import _config, _decorators, _mock_val_ser, _namespace_utils, _typing_extra +from ._internal import _dataclasses as _pydantic_dataclasses +from ._migration import getattr_migration +from .config import ConfigDict +from .errors import PydanticUserError +from .fields import Field, FieldInfo, PrivateAttr + +if TYPE_CHECKING: + from ._internal._dataclasses import PydanticDataclass + from ._internal._namespace_utils import MappingNamespace + +__all__ = 'dataclass', 'rebuild_dataclass' + +_T = TypeVar('_T') + +if sys.version_info >= (3, 10): + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + kw_only: bool = ..., + slots: bool = ..., + ) -> Callable[[type[_T]], type[PydanticDataclass]]: # type: ignore + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + _cls: type[_T], # type: ignore + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + kw_only: bool = ..., + slots: bool = ..., + ) -> type[PydanticDataclass]: ... + +else: + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + ) -> Callable[[type[_T]], type[PydanticDataclass]]: # type: ignore + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) + @overload + def dataclass( + _cls: type[_T], # type: ignore + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + ) -> type[PydanticDataclass]: ... + + +@dataclass_transform(field_specifiers=(dataclasses.field, Field, PrivateAttr)) +def dataclass( + _cls: type[_T] | None = None, + *, + init: Literal[False] = False, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool | None = None, + config: ConfigDict | type[object] | None = None, + validate_on_init: bool | None = None, + kw_only: bool = False, + slots: bool = False, +) -> Callable[[type[_T]], type[PydanticDataclass]] | type[PydanticDataclass]: + """!!! abstract "Usage Documentation" + [`dataclasses`](../concepts/dataclasses.md) + + A decorator used to create a Pydantic-enhanced dataclass, similar to the standard Python `dataclass`, + but with added validation. + + This function should be used similarly to `dataclasses.dataclass`. + + Args: + _cls: The target `dataclass`. + init: Included for signature compatibility with `dataclasses.dataclass`, and is passed through to + `dataclasses.dataclass` when appropriate. If specified, must be set to `False`, as pydantic inserts its + own `__init__` function. + repr: A boolean indicating whether to include the field in the `__repr__` output. + eq: Determines if a `__eq__` method should be generated for the class. + order: Determines if comparison magic methods should be generated, such as `__lt__`, but not `__eq__`. + unsafe_hash: Determines if a `__hash__` method should be included in the class, as in `dataclasses.dataclass`. + frozen: Determines if the generated class should be a 'frozen' `dataclass`, which does not allow its + attributes to be modified after it has been initialized. If not set, the value from the provided `config` argument will be used (and will default to `False` otherwise). + config: The Pydantic config to use for the `dataclass`. + validate_on_init: A deprecated parameter included for backwards compatibility; in V2, all Pydantic dataclasses + are validated on init. + kw_only: Determines if `__init__` method parameters must be specified by keyword only. Defaults to `False`. + slots: Determines if the generated class should be a 'slots' `dataclass`, which does not allow the addition of + new attributes after instantiation. + + Returns: + A decorator that accepts a class as its argument and returns a Pydantic `dataclass`. + + Raises: + AssertionError: Raised if `init` is not `False` or `validate_on_init` is `False`. + """ + assert init is False, 'pydantic.dataclasses.dataclass only supports init=False' + assert validate_on_init is not False, 'validate_on_init=False is no longer supported' + + if sys.version_info >= (3, 10): + kwargs = {'kw_only': kw_only, 'slots': slots} + else: + kwargs = {} + + def create_dataclass(cls: type[Any]) -> type[PydanticDataclass]: + """Create a Pydantic dataclass from a regular dataclass. + + Args: + cls: The class to create the Pydantic dataclass from. + + Returns: + A Pydantic dataclass. + """ + from ._internal._utils import is_model_class + + if is_model_class(cls): + raise PydanticUserError( + f'Cannot create a Pydantic dataclass from {cls.__name__} as it is already a Pydantic model', + code='dataclass-on-model', + ) + + original_cls = cls + + # we warn on conflicting config specifications, but only if the class doesn't have a dataclass base + # because a dataclass base might provide a __pydantic_config__ attribute that we don't want to warn about + has_dataclass_base = any(dataclasses.is_dataclass(base) for base in cls.__bases__) + if not has_dataclass_base and config is not None and hasattr(cls, '__pydantic_config__'): + warn( + f'`config` is set via both the `dataclass` decorator and `__pydantic_config__` for dataclass {cls.__name__}. ' + f'The `config` specification from `dataclass` decorator will take priority.', + category=UserWarning, + stacklevel=2, + ) + + # if config is not explicitly provided, try to read it from the type + config_dict = config if config is not None else getattr(cls, '__pydantic_config__', None) + config_wrapper = _config.ConfigWrapper(config_dict) + decorators = _decorators.DecoratorInfos.build(cls, replace_wrapped_methods=True) + decorators.update_from_config(config_wrapper) + + # Keep track of the original __doc__ so that we can restore it after applying the dataclasses decorator + # Otherwise, classes with no __doc__ will have their signature added into the JSON schema description, + # since dataclasses.dataclass will set this as the __doc__ + original_doc = cls.__doc__ + + if _pydantic_dataclasses.is_stdlib_dataclass(cls): + # Vanilla dataclasses include a default docstring (representing the class signature), + # which we don't want to preserve. + original_doc = None + + # We don't want to add validation to the existing std lib dataclass, so we will subclass it + # If the class is generic, we need to make sure the subclass also inherits from Generic + # with all the same parameters. + bases = (cls,) + if issubclass(cls, Generic): + generic_base = Generic[cls.__parameters__] # type: ignore + bases = bases + (generic_base,) + cls = types.new_class(cls.__name__, bases) + + # Respect frozen setting from dataclass constructor and fallback to config setting if not provided + if frozen is not None: + frozen_ = frozen + if config_wrapper.frozen: + # It's not recommended to define both, as the setting from the dataclass decorator will take priority. + warn( + f'`frozen` is set via both the `dataclass` decorator and `config` for dataclass {cls.__name__!r}.' + 'This is not recommended. The `frozen` specification on `dataclass` will take priority.', + category=UserWarning, + stacklevel=2, + ) + else: + frozen_ = config_wrapper.frozen or False + + # Make Pydantic's `Field()` function compatible with stdlib dataclasses. As we'll decorate + # `cls` with the stdlib `@dataclass` decorator first, there are two attributes, `kw_only` and + # `repr` that need to be understood *during* the stdlib creation. We do so in two steps: + + # 1. On the decorated class, wrap `Field()` assignment with `dataclass.field()`, with the + # two attributes set (done in `as_dataclass_field()`) + cls_anns = _typing_extra.safe_get_annotations(cls) + for field_name in cls_anns: + # We should look for assignments in `__dict__` instead, but for now we follow + # the same behavior as stdlib dataclasses (see https://github.com/python/cpython/issues/88609) + field_value = getattr(cls, field_name, None) + if isinstance(field_value, FieldInfo): + setattr(cls, field_name, _pydantic_dataclasses.as_dataclass_field(field_value)) + + # 2. For bases of `cls` that are stdlib dataclasses, we temporarily patch their fields + # (see the docstring of the context manager): + with _pydantic_dataclasses.patch_base_fields(cls): + cls = dataclasses.dataclass( # pyright: ignore[reportCallIssue] + cls, + # the value of init here doesn't affect anything except that it makes it easier to generate a signature + init=True, + repr=repr, + eq=eq, + order=order, + unsafe_hash=unsafe_hash, + frozen=frozen_, + **kwargs, + ) + + if config_wrapper.validate_assignment: + original_setattr = cls.__setattr__ + + @functools.wraps(cls.__setattr__) + def validated_setattr(instance: PydanticDataclass, name: str, value: Any, /) -> None: + if frozen_: + return original_setattr(instance, name, value) # pyright: ignore[reportCallIssue] + inst_cls = type(instance) + attr = getattr(inst_cls, name, None) + + if isinstance(attr, property): + attr.__set__(instance, value) + elif isinstance(attr, functools.cached_property): + instance.__dict__.__setitem__(name, value) + else: + inst_cls.__pydantic_validator__.validate_assignment(instance, name, value) + + cls.__setattr__ = validated_setattr.__get__(None, cls) # type: ignore + + if slots and not hasattr(cls, '__setstate__'): + # If slots is set, `pickle` (relied on by `copy.copy()`) will use + # `__setattr__()` to reconstruct the dataclass. However, the custom + # `__setattr__()` set above relies on `validate_assignment()`, which + # in turn expects all the field values to be already present on the + # instance, resulting in attribute errors. + # As such, we make use of `object.__setattr__()` instead. + # Note that we do so only if `__setstate__()` isn't already set (this is the + # case if on top of `slots`, `frozen` is used). + + # Taken from `dataclasses._dataclass_get/setstate()`: + def _dataclass_getstate(self: Any) -> list[Any]: + return [getattr(self, f.name) for f in dataclasses.fields(self)] + + def _dataclass_setstate(self: Any, state: list[Any]) -> None: + for field, value in zip(dataclasses.fields(self), state): + object.__setattr__(self, field.name, value) + + cls.__getstate__ = _dataclass_getstate # pyright: ignore[reportAttributeAccessIssue] + cls.__setstate__ = _dataclass_setstate # pyright: ignore[reportAttributeAccessIssue] + + # This is an undocumented attribute to distinguish stdlib/Pydantic dataclasses. + # It should be set as early as possible: + cls.__is_pydantic_dataclass__ = True + cls.__pydantic_decorators__ = decorators # type: ignore + cls.__doc__ = original_doc + # Can be non-existent for dynamically created classes: + firstlineno = getattr(original_cls, '__firstlineno__', None) + cls.__module__ = original_cls.__module__ + if sys.version_info >= (3, 13) and firstlineno is not None: + # As per https://docs.python.org/3/reference/datamodel.html#type.__firstlineno__: + # Setting the `__module__` attribute removes the `__firstlineno__` item from the type’s dictionary. + original_cls.__firstlineno__ = firstlineno + cls.__firstlineno__ = firstlineno + cls.__qualname__ = original_cls.__qualname__ + cls.__pydantic_fields_complete__ = classmethod(_pydantic_fields_complete) + cls.__pydantic_complete__ = False # `complete_dataclass` will set it to `True` if successful. + # TODO `parent_namespace` is currently None, but we could do the same thing as Pydantic models: + # fetch the parent ns using `parent_frame_namespace` (if the dataclass was defined in a function), + # and possibly cache it (see the `__pydantic_parent_namespace__` logic for models). + _pydantic_dataclasses.complete_dataclass(cls, config_wrapper, raise_errors=False) + return cls + + return create_dataclass if _cls is None else create_dataclass(_cls) + + +def _pydantic_fields_complete(cls: type[PydanticDataclass]) -> bool: + """Return whether the fields were successfully collected (i.e. type hints were successfully resolved). + + This is a private helper, not meant to be used outside Pydantic. + """ + return all(field_info._complete for field_info in cls.__pydantic_fields__.values()) + + +__getattr__ = getattr_migration(__name__) + +if sys.version_info < (3, 11): + # Monkeypatch dataclasses.InitVar so that typing doesn't error if it occurs as a type when evaluating type hints + # Starting in 3.11, typing.get_type_hints will not raise an error if the retrieved type hints are not callable. + + def _call_initvar(*args: Any, **kwargs: Any) -> NoReturn: + """This function does nothing but raise an error that is as similar as possible to what you'd get + if you were to try calling `InitVar[int]()` without this monkeypatch. The whole purpose is just + to ensure typing._type_check does not error if the type hint evaluates to `InitVar[]`. + """ + raise TypeError("'InitVar' object is not callable") + + dataclasses.InitVar.__call__ = _call_initvar + + +def rebuild_dataclass( + cls: type[PydanticDataclass], + *, + force: bool = False, + raise_errors: bool = True, + _parent_namespace_depth: int = 2, + _types_namespace: MappingNamespace | None = None, +) -> bool | None: + """Try to rebuild the pydantic-core schema for the dataclass. + + This may be necessary when one of the annotations is a ForwardRef which could not be resolved during + the initial attempt to build the schema, and automatic rebuilding fails. + + This is analogous to `BaseModel.model_rebuild`. + + Args: + cls: The class to rebuild the pydantic-core schema for. + force: Whether to force the rebuilding of the schema, defaults to `False`. + raise_errors: Whether to raise errors, defaults to `True`. + _parent_namespace_depth: The depth level of the parent namespace, defaults to 2. + _types_namespace: The types namespace, defaults to `None`. + + Returns: + Returns `None` if the schema is already "complete" and rebuilding was not required. + If rebuilding _was_ required, returns `True` if rebuilding was successful, otherwise `False`. + """ + if not force and cls.__pydantic_complete__: + return None + + for attr in ('__pydantic_core_schema__', '__pydantic_validator__', '__pydantic_serializer__'): + if attr in cls.__dict__ and not isinstance(getattr(cls, attr), _mock_val_ser.MockValSer): + # Deleting the validator/serializer is necessary as otherwise they can get reused in + # pydantic-core. Same applies for the core schema that can be reused in schema generation. + delattr(cls, attr) + + cls.__pydantic_complete__ = False + + if _types_namespace is not None: + rebuild_ns = _types_namespace + elif _parent_namespace_depth > 0: + rebuild_ns = _typing_extra.parent_frame_namespace(parent_depth=_parent_namespace_depth, force=True) or {} + else: + rebuild_ns = {} + + ns_resolver = _namespace_utils.NsResolver( + parent_namespace=rebuild_ns, + ) + + return _pydantic_dataclasses.complete_dataclass( + cls, + _config.ConfigWrapper(cls.__pydantic_config__, check=False), + raise_errors=raise_errors, + ns_resolver=ns_resolver, + # We could provide a different config instead (with `'defer_build'` set to `True`) + # of this explicit `_force_build` argument, but because config can come from the + # decorator parameter or the `__pydantic_config__` attribute, `complete_dataclass` + # will overwrite `__pydantic_config__` with the provided config above: + _force_build=True, + ) + + +def is_pydantic_dataclass(class_: type[Any], /) -> TypeGuard[type[PydanticDataclass]]: + """Whether a class is a pydantic dataclass. + + Args: + class_: The class. + + Returns: + `True` if the class is a pydantic dataclass, `False` otherwise. + """ + try: + return '__is_pydantic_dataclass__' in class_.__dict__ and dataclasses.is_dataclass(class_) + except AttributeError: + return False diff --git a/source/target-vendors/cp312/pydantic/datetime_parse.py b/source/target-vendors/cp312/pydantic/datetime_parse.py new file mode 100644 index 0000000..53d5264 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/datetime_parse.py @@ -0,0 +1,5 @@ +"""The `datetime_parse` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/decorator.py b/source/target-vendors/cp312/pydantic/decorator.py new file mode 100644 index 0000000..0d97560 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/decorator.py @@ -0,0 +1,5 @@ +"""The `decorator` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/deprecated/__init__.py b/source/target-vendors/cp312/pydantic/deprecated/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/pydantic/deprecated/class_validators.py b/source/target-vendors/cp312/pydantic/deprecated/class_validators.py new file mode 100644 index 0000000..e6ba195 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/class_validators.py @@ -0,0 +1,256 @@ +"""Old `@validator` and `@root_validator` function validators from V1.""" + +from __future__ import annotations as _annotations + +from functools import partial, partialmethod +from types import FunctionType +from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar, Union, overload +from warnings import warn + +from typing_extensions import Protocol, TypeAlias, deprecated + +from .._internal import _decorators, _decorators_v1 +from ..errors import PydanticUserError +from ..warnings import PydanticDeprecatedSince20 + +_ALLOW_REUSE_WARNING_MESSAGE = '`allow_reuse` is deprecated and will be ignored; it should no longer be necessary' + + +if TYPE_CHECKING: + + class _OnlyValueValidatorClsMethod(Protocol): + def __call__(self, __cls: Any, __value: Any) -> Any: ... + + class _V1ValidatorWithValuesClsMethod(Protocol): + def __call__(self, __cls: Any, __value: Any, values: dict[str, Any]) -> Any: ... + + class _V1ValidatorWithValuesKwOnlyClsMethod(Protocol): + def __call__(self, __cls: Any, __value: Any, *, values: dict[str, Any]) -> Any: ... + + class _V1ValidatorWithKwargsClsMethod(Protocol): + def __call__(self, __cls: Any, **kwargs: Any) -> Any: ... + + class _V1ValidatorWithValuesAndKwargsClsMethod(Protocol): + def __call__(self, __cls: Any, values: dict[str, Any], **kwargs: Any) -> Any: ... + + class _V1RootValidatorClsMethod(Protocol): + def __call__( + self, __cls: Any, __values: _decorators_v1.RootValidatorValues + ) -> _decorators_v1.RootValidatorValues: ... + + V1Validator = Union[ + _OnlyValueValidatorClsMethod, + _V1ValidatorWithValuesClsMethod, + _V1ValidatorWithValuesKwOnlyClsMethod, + _V1ValidatorWithKwargsClsMethod, + _V1ValidatorWithValuesAndKwargsClsMethod, + _decorators_v1.V1ValidatorWithValues, + _decorators_v1.V1ValidatorWithValuesKwOnly, + _decorators_v1.V1ValidatorWithKwargs, + _decorators_v1.V1ValidatorWithValuesAndKwargs, + ] + + V1RootValidator = Union[ + _V1RootValidatorClsMethod, + _decorators_v1.V1RootValidatorFunction, + ] + + _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]] + + # Allow both a V1 (assumed pre=False) or V2 (assumed mode='after') validator + # We lie to type checkers and say we return the same thing we get + # but in reality we return a proxy object that _mostly_ behaves like the wrapped thing + _V1ValidatorType = TypeVar('_V1ValidatorType', V1Validator, _PartialClsOrStaticMethod) + _V1RootValidatorFunctionType = TypeVar( + '_V1RootValidatorFunctionType', + _decorators_v1.V1RootValidatorFunction, + _V1RootValidatorClsMethod, + _PartialClsOrStaticMethod, + ) +else: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + + +@deprecated( + 'Pydantic V1 style `@validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@field_validator` validators,' + ' see the migration guide for more details', + category=None, +) +def validator( + __field: str, + *fields: str, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool | None = None, + allow_reuse: bool = False, +) -> Callable[[_V1ValidatorType], _V1ValidatorType]: + """Decorate methods on the class indicating that they should be used to validate fields. + + Args: + __field (str): The first field the validator should be called on; this is separate + from `fields` to ensure an error is raised if you don't pass at least one. + *fields (str): Additional field(s) the validator should be called on. + pre (bool, optional): Whether this validator should be called before the standard + validators (else after). Defaults to False. + each_item (bool, optional): For complex objects (sets, lists etc.) whether to validate + individual elements rather than the whole object. Defaults to False. + always (bool, optional): Whether this method and other validators should be called even if + the value is missing. Defaults to False. + check_fields (bool | None, optional): Whether to check that the fields actually exist on the model. + Defaults to None. + allow_reuse (bool, optional): Whether to track and raise an error if another validator refers to + the decorated function. Defaults to False. + + Returns: + Callable: A decorator that can be used to decorate a + function to be used as a validator. + """ + warn( + 'Pydantic V1 style `@validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@field_validator` validators,' + ' see the migration guide for more details', + DeprecationWarning, + stacklevel=2, + ) + + if allow_reuse is True: # pragma: no cover + warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning, stacklevel=2) + fields = __field, *fields + if isinstance(fields[0], FunctionType): + raise PydanticUserError( + '`@validator` should be used with fields and keyword arguments, not bare. ' + "E.g. usage should be `@validator('', ...)`", + code='decorator-missing-arguments', + ) + elif not all(isinstance(field, str) for field in fields): + raise PydanticUserError( + '`@validator` fields should be passed as separate string args. ' + "E.g. usage should be `@validator('', '', ...)`", + code='decorator-invalid-fields', + ) + + mode: Literal['before', 'after'] = 'before' if pre is True else 'after' + + def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: + if _decorators.is_instance_method_from_sig(f): + raise PydanticUserError( + '`@validator` cannot be applied to instance methods', code='validator-instance-method' + ) + # auto apply the @classmethod decorator + f = _decorators.ensure_classmethod_based_on_signature(f) + wrap = _decorators_v1.make_generic_v1_field_validator + validator_wrapper_info = _decorators.ValidatorDecoratorInfo( + fields=fields, + mode=mode, + each_item=each_item, + always=always, + check_fields=check_fields, + ) + return _decorators.PydanticDescriptorProxy(f, validator_wrapper_info, shim=wrap) + + return dec # type: ignore[return-value] + + +@overload +def root_validator( + *, + # if you don't specify `pre` the default is `pre=False` + # which means you need to specify `skip_on_failure=True` + skip_on_failure: Literal[True], + allow_reuse: bool = ..., +) -> Callable[ + [_V1RootValidatorFunctionType], + _V1RootValidatorFunctionType, +]: ... + + +@overload +def root_validator( + *, + # if you specify `pre=True` then you don't need to specify + # `skip_on_failure`, in fact it is not allowed as an argument! + pre: Literal[True], + allow_reuse: bool = ..., +) -> Callable[ + [_V1RootValidatorFunctionType], + _V1RootValidatorFunctionType, +]: ... + + +@overload +def root_validator( + *, + # if you explicitly specify `pre=False` then you + # MUST specify `skip_on_failure=True` + pre: Literal[False], + skip_on_failure: Literal[True], + allow_reuse: bool = ..., +) -> Callable[ + [_V1RootValidatorFunctionType], + _V1RootValidatorFunctionType, +]: ... + + +@deprecated( + 'Pydantic V1 style `@root_validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@model_validator` validators,' + ' see the migration guide for more details', + category=None, +) +def root_validator( + *__args, + pre: bool = False, + skip_on_failure: bool = False, + allow_reuse: bool = False, +) -> Any: + """Decorate methods on a model indicating that they should be used to validate (and perhaps + modify) data either before or after standard model parsing/validation is performed. + + Args: + pre (bool, optional): Whether this validator should be called before the standard + validators (else after). Defaults to False. + skip_on_failure (bool, optional): Whether to stop validation and return as soon as a + failure is encountered. Defaults to False. + allow_reuse (bool, optional): Whether to track and raise an error if another validator + refers to the decorated function. Defaults to False. + + Returns: + Any: A decorator that can be used to decorate a function to be used as a root_validator. + """ + warn( + 'Pydantic V1 style `@root_validator` validators are deprecated.' + ' You should migrate to Pydantic V2 style `@model_validator` validators,' + ' see the migration guide for more details', + DeprecationWarning, + stacklevel=2, + ) + + if __args: + # Ensure a nice error is raised if someone attempts to use the bare decorator + return root_validator()(*__args) # type: ignore + + if allow_reuse is True: # pragma: no cover + warn(_ALLOW_REUSE_WARNING_MESSAGE, DeprecationWarning, stacklevel=2) + mode: Literal['before', 'after'] = 'before' if pre is True else 'after' + if pre is False and skip_on_failure is not True: + raise PydanticUserError( + 'If you use `@root_validator` with pre=False (the default) you MUST specify `skip_on_failure=True`.' + ' Note that `@root_validator` is deprecated and should be replaced with `@model_validator`.', + code='root-validator-pre-skip', + ) + + wrap = partial(_decorators_v1.make_v1_generic_root_validator, pre=pre) + + def dec(f: Callable[..., Any] | classmethod[Any, Any, Any] | staticmethod[Any, Any]) -> Any: + if _decorators.is_instance_method_from_sig(f): + raise TypeError('`@root_validator` cannot be applied to instance methods') + # auto apply the @classmethod decorator + res = _decorators.ensure_classmethod_based_on_signature(f) + dec_info = _decorators.RootValidatorDecoratorInfo(mode=mode) + return _decorators.PydanticDescriptorProxy(res, dec_info, shim=wrap) + + return dec diff --git a/source/target-vendors/cp312/pydantic/deprecated/config.py b/source/target-vendors/cp312/pydantic/deprecated/config.py new file mode 100644 index 0000000..bd4692a --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/config.py @@ -0,0 +1,72 @@ +from __future__ import annotations as _annotations + +import warnings +from typing import TYPE_CHECKING, Any, Literal + +from typing_extensions import deprecated + +from .._internal import _config +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = 'BaseConfig', 'Extra' + + +class _ConfigMetaclass(type): + def __getattr__(self, item: str) -> Any: + try: + obj = _config.config_defaults[item] + warnings.warn(_config.DEPRECATION_MESSAGE, DeprecationWarning) + return obj + except KeyError as exc: + raise AttributeError(f"type object '{self.__name__}' has no attribute {exc}") from exc + + +@deprecated('BaseConfig is deprecated. Use the `pydantic.ConfigDict` instead.', category=PydanticDeprecatedSince20) +class BaseConfig(metaclass=_ConfigMetaclass): + """This class is only retained for backwards compatibility. + + !!! Warning "Deprecated" + BaseConfig is deprecated. Use the [`pydantic.ConfigDict`][pydantic.ConfigDict] instead. + """ + + def __getattr__(self, item: str) -> Any: + try: + obj = super().__getattribute__(item) + warnings.warn(_config.DEPRECATION_MESSAGE, DeprecationWarning) + return obj + except AttributeError as exc: + try: + return getattr(type(self), item) + except AttributeError: + # re-raising changes the displayed text to reflect that `self` is not a type + raise AttributeError(str(exc)) from exc + + def __init_subclass__(cls, **kwargs: Any) -> None: + warnings.warn(_config.DEPRECATION_MESSAGE, DeprecationWarning) + return super().__init_subclass__(**kwargs) + + +class _ExtraMeta(type): + def __getattribute__(self, __name: str) -> Any: + # The @deprecated decorator accesses other attributes, so we only emit a warning for the expected ones + if __name in {'allow', 'ignore', 'forbid'}: + warnings.warn( + "`pydantic.config.Extra` is deprecated, use literal values instead (e.g. `extra='allow'`)", + DeprecationWarning, + stacklevel=2, + ) + return super().__getattribute__(__name) + + +@deprecated( + "Extra is deprecated. Use literal values instead (e.g. `extra='allow'`)", category=PydanticDeprecatedSince20 +) +class Extra(metaclass=_ExtraMeta): + allow: Literal['allow'] = 'allow' + ignore: Literal['ignore'] = 'ignore' + forbid: Literal['forbid'] = 'forbid' diff --git a/source/target-vendors/cp312/pydantic/deprecated/copy_internals.py b/source/target-vendors/cp312/pydantic/deprecated/copy_internals.py new file mode 100644 index 0000000..0170dc0 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/copy_internals.py @@ -0,0 +1,224 @@ +from __future__ import annotations as _annotations + +import typing +from copy import deepcopy +from enum import Enum +from typing import Any + +import typing_extensions + +from .._internal import ( + _model_construction, + _typing_extra, + _utils, +) + +if typing.TYPE_CHECKING: + from .. import BaseModel + from .._internal._utils import AbstractSetIntStr, MappingIntStrAny + + AnyClassMethod = classmethod[Any, Any, Any] + TupleGenerator = typing.Generator[tuple[str, Any], None, None] + Model = typing.TypeVar('Model', bound='BaseModel') + # should be `set[int] | set[str] | dict[int, IncEx] | dict[str, IncEx] | None`, but mypy can't cope + IncEx: typing_extensions.TypeAlias = 'set[int] | set[str] | dict[int, Any] | dict[str, Any] | None' + +_object_setattr = _model_construction.object_setattr + + +def _iter( + self: BaseModel, + to_dict: bool = False, + by_alias: bool = False, + include: AbstractSetIntStr | MappingIntStrAny | None = None, + exclude: AbstractSetIntStr | MappingIntStrAny | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, +) -> TupleGenerator: + # Merge field set excludes with explicit exclude parameter with explicit overriding field set options. + # The extra "is not None" guards are not logically necessary but optimizes performance for the simple case. + if exclude is not None: + exclude = _utils.ValueItems.merge( + {k: v.exclude for k, v in self.__pydantic_fields__.items() if v.exclude is not None}, exclude + ) + + if include is not None: + include = _utils.ValueItems.merge(dict.fromkeys(self.__pydantic_fields__, True), include, intersect=True) + + allowed_keys = _calculate_keys(self, include=include, exclude=exclude, exclude_unset=exclude_unset) # type: ignore + if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none): + # huge boost for plain _iter() + yield from self.__dict__.items() + if self.__pydantic_extra__: + yield from self.__pydantic_extra__.items() + return + + value_exclude = _utils.ValueItems(self, exclude) if exclude is not None else None + value_include = _utils.ValueItems(self, include) if include is not None else None + + if self.__pydantic_extra__ is None: + items = self.__dict__.items() + else: + items = list(self.__dict__.items()) + list(self.__pydantic_extra__.items()) + + for field_key, v in items: + if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None): + continue + + if exclude_defaults: + try: + field = self.__pydantic_fields__[field_key] + except KeyError: + pass + else: + if not field.is_required() and field.default == v: + continue + + if by_alias and field_key in self.__pydantic_fields__: + dict_key = self.__pydantic_fields__[field_key].alias or field_key + else: + dict_key = field_key + + if to_dict or value_include or value_exclude: + v = _get_value( + type(self), + v, + to_dict=to_dict, + by_alias=by_alias, + include=value_include and value_include.for_element(field_key), + exclude=value_exclude and value_exclude.for_element(field_key), + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + yield dict_key, v + + +def _copy_and_set_values( + self: Model, + values: dict[str, Any], + fields_set: set[str], + extra: dict[str, Any] | None = None, + private: dict[str, Any] | None = None, + *, + deep: bool, # UP006 +) -> Model: + if deep: + # chances of having empty dict here are quite low for using smart_deepcopy + values = deepcopy(values) + extra = deepcopy(extra) + private = deepcopy(private) + + cls = self.__class__ + m = cls.__new__(cls) + _object_setattr(m, '__dict__', values) + _object_setattr(m, '__pydantic_extra__', extra) + _object_setattr(m, '__pydantic_fields_set__', fields_set) + _object_setattr(m, '__pydantic_private__', private) + + return m + + +@typing.no_type_check +def _get_value( + cls: type[BaseModel], + v: Any, + to_dict: bool, + by_alias: bool, + include: AbstractSetIntStr | MappingIntStrAny | None, + exclude: AbstractSetIntStr | MappingIntStrAny | None, + exclude_unset: bool, + exclude_defaults: bool, + exclude_none: bool, +) -> Any: + from .. import BaseModel + + if isinstance(v, BaseModel): + if to_dict: + return v.model_dump( + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=include, # type: ignore + exclude=exclude, # type: ignore + exclude_none=exclude_none, + ) + else: + return v.copy(include=include, exclude=exclude) + + value_exclude = _utils.ValueItems(v, exclude) if exclude else None + value_include = _utils.ValueItems(v, include) if include else None + + if isinstance(v, dict): + return { + k_: _get_value( + cls, + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(k_), + exclude=value_exclude and value_exclude.for_element(k_), + exclude_none=exclude_none, + ) + for k_, v_ in v.items() + if (not value_exclude or not value_exclude.is_excluded(k_)) + and (not value_include or value_include.is_included(k_)) + } + + elif _utils.sequence_like(v): + seq_args = ( + _get_value( + cls, + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(i), + exclude=value_exclude and value_exclude.for_element(i), + exclude_none=exclude_none, + ) + for i, v_ in enumerate(v) + if (not value_exclude or not value_exclude.is_excluded(i)) + and (not value_include or value_include.is_included(i)) + ) + + return v.__class__(*seq_args) if _typing_extra.is_namedtuple(v.__class__) else v.__class__(seq_args) + + elif isinstance(v, Enum) and getattr(cls.model_config, 'use_enum_values', False): + return v.value + + else: + return v + + +def _calculate_keys( + self: BaseModel, + include: MappingIntStrAny | None, + exclude: MappingIntStrAny | None, + exclude_unset: bool, + update: dict[str, Any] | None = None, # noqa UP006 +) -> typing.AbstractSet[str] | None: + if include is None and exclude is None and exclude_unset is False: + return None + + keys: typing.AbstractSet[str] + if exclude_unset: + keys = self.__pydantic_fields_set__.copy() + else: + keys = set(self.__dict__.keys()) + keys = keys | (self.__pydantic_extra__ or {}).keys() + + if include is not None: + keys &= include.keys() + + if update: + keys -= update.keys() + + if exclude: + keys -= {k for k, v in exclude.items() if _utils.ValueItems.is_true(v)} + + return keys diff --git a/source/target-vendors/cp312/pydantic/deprecated/decorator.py b/source/target-vendors/cp312/pydantic/deprecated/decorator.py new file mode 100644 index 0000000..e73ad20 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/decorator.py @@ -0,0 +1,284 @@ +import warnings +from collections.abc import Mapping +from functools import wraps +from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, overload + +from typing_extensions import deprecated + +from .._internal import _config, _typing_extra +from ..alias_generators import to_pascal +from ..errors import PydanticUserError +from ..functional_validators import field_validator +from ..main import BaseModel, create_model +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = ('validate_arguments',) + +if TYPE_CHECKING: + AnyCallable = Callable[..., Any] + + AnyCallableT = TypeVar('AnyCallableT', bound=AnyCallable) + ConfigType = Union[None, type[Any], dict[str, Any]] + + +@overload +def validate_arguments( + func: None = None, *, config: 'ConfigType' = None +) -> Callable[['AnyCallableT'], 'AnyCallableT']: ... + + +@overload +def validate_arguments(func: 'AnyCallableT') -> 'AnyCallableT': ... + + +@deprecated( + 'The `validate_arguments` method is deprecated; use `validate_call` instead.', + category=None, +) +def validate_arguments(func: Optional['AnyCallableT'] = None, *, config: 'ConfigType' = None) -> Any: + """Decorator to validate the arguments passed to a function.""" + warnings.warn( + 'The `validate_arguments` method is deprecated; use `validate_call` instead.', + PydanticDeprecatedSince20, + stacklevel=2, + ) + + def validate(_func: 'AnyCallable') -> 'AnyCallable': + vd = ValidatedFunction(_func, config) + + @wraps(_func) + def wrapper_function(*args: Any, **kwargs: Any) -> Any: + return vd.call(*args, **kwargs) + + wrapper_function.vd = vd # type: ignore + wrapper_function.validate = vd.init_model_instance # type: ignore + wrapper_function.raw_function = vd.raw_function # type: ignore + wrapper_function.model = vd.model # type: ignore + return wrapper_function + + if func: + return validate(func) + else: + return validate + + +ALT_V_ARGS = 'v__args' +ALT_V_KWARGS = 'v__kwargs' +V_POSITIONAL_ONLY_NAME = 'v__positional_only' +V_DUPLICATE_KWARGS = 'v__duplicate_kwargs' + + +class ValidatedFunction: + def __init__(self, function: 'AnyCallable', config: 'ConfigType'): + from inspect import Parameter, signature + + parameters: Mapping[str, Parameter] = signature(function).parameters + + if parameters.keys() & {ALT_V_ARGS, ALT_V_KWARGS, V_POSITIONAL_ONLY_NAME, V_DUPLICATE_KWARGS}: + raise PydanticUserError( + f'"{ALT_V_ARGS}", "{ALT_V_KWARGS}", "{V_POSITIONAL_ONLY_NAME}" and "{V_DUPLICATE_KWARGS}" ' + f'are not permitted as argument names when using the "{validate_arguments.__name__}" decorator', + code=None, + ) + + self.raw_function = function + self.arg_mapping: dict[int, str] = {} + self.positional_only_args: set[str] = set() + self.v_args_name = 'args' + self.v_kwargs_name = 'kwargs' + + type_hints = _typing_extra.get_type_hints(function, include_extras=True) + takes_args = False + takes_kwargs = False + fields: dict[str, tuple[Any, Any]] = {} + for i, (name, p) in enumerate(parameters.items()): + if p.annotation is p.empty: + annotation = Any + else: + annotation = type_hints[name] + + default = ... if p.default is p.empty else p.default + if p.kind == Parameter.POSITIONAL_ONLY: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_POSITIONAL_ONLY_NAME] = list[str], None + self.positional_only_args.add(name) + elif p.kind == Parameter.POSITIONAL_OR_KEYWORD: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_DUPLICATE_KWARGS] = list[str], None + elif p.kind == Parameter.KEYWORD_ONLY: + fields[name] = annotation, default + elif p.kind == Parameter.VAR_POSITIONAL: + self.v_args_name = name + fields[name] = tuple[annotation, ...], None + takes_args = True + else: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + self.v_kwargs_name = name + fields[name] = dict[str, annotation], None + takes_kwargs = True + + # these checks avoid a clash between "args" and a field with that name + if not takes_args and self.v_args_name in fields: + self.v_args_name = ALT_V_ARGS + + # same with "kwargs" + if not takes_kwargs and self.v_kwargs_name in fields: + self.v_kwargs_name = ALT_V_KWARGS + + if not takes_args: + # we add the field so validation below can raise the correct exception + fields[self.v_args_name] = list[Any], None + + if not takes_kwargs: + # same with kwargs + fields[self.v_kwargs_name] = dict[Any, Any], None + + self.create_model(fields, takes_args, takes_kwargs, config) + + def init_model_instance(self, *args: Any, **kwargs: Any) -> BaseModel: + values = self.build_values(args, kwargs) + return self.model(**values) + + def call(self, *args: Any, **kwargs: Any) -> Any: + m = self.init_model_instance(*args, **kwargs) + return self.execute(m) + + def build_values(self, args: tuple[Any, ...], kwargs: dict[str, Any]) -> dict[str, Any]: + values: dict[str, Any] = {} + if args: + arg_iter = enumerate(args) + while True: + try: + i, a = next(arg_iter) + except StopIteration: + break + arg_name = self.arg_mapping.get(i) + if arg_name is not None: + values[arg_name] = a + else: + values[self.v_args_name] = [a] + [a for _, a in arg_iter] + break + + var_kwargs: dict[str, Any] = {} + wrong_positional_args = [] + duplicate_kwargs = [] + fields_alias = [ + field.alias + for name, field in self.model.__pydantic_fields__.items() + if name not in (self.v_args_name, self.v_kwargs_name) + ] + non_var_fields = set(self.model.__pydantic_fields__) - {self.v_args_name, self.v_kwargs_name} + for k, v in kwargs.items(): + if k in non_var_fields or k in fields_alias: + if k in self.positional_only_args: + wrong_positional_args.append(k) + if k in values: + duplicate_kwargs.append(k) + values[k] = v + else: + var_kwargs[k] = v + + if var_kwargs: + values[self.v_kwargs_name] = var_kwargs + if wrong_positional_args: + values[V_POSITIONAL_ONLY_NAME] = wrong_positional_args + if duplicate_kwargs: + values[V_DUPLICATE_KWARGS] = duplicate_kwargs + return values + + def execute(self, m: BaseModel) -> Any: + d = { + k: v + for k, v in m.__dict__.items() + if k in m.__pydantic_fields_set__ or m.__pydantic_fields__[k].default_factory + } + var_kwargs = d.pop(self.v_kwargs_name, {}) + + if self.v_args_name in d: + args_: list[Any] = [] + in_kwargs = False + kwargs = {} + for name, value in d.items(): + if in_kwargs: + kwargs[name] = value + elif name == self.v_args_name: + args_ += value + in_kwargs = True + else: + args_.append(value) + return self.raw_function(*args_, **kwargs, **var_kwargs) + elif self.positional_only_args: + args_ = [] + kwargs = {} + for name, value in d.items(): + if name in self.positional_only_args: + args_.append(value) + else: + kwargs[name] = value + return self.raw_function(*args_, **kwargs, **var_kwargs) + else: + return self.raw_function(**d, **var_kwargs) + + def create_model(self, fields: dict[str, Any], takes_args: bool, takes_kwargs: bool, config: 'ConfigType') -> None: + pos_args = len(self.arg_mapping) + + config_wrapper = _config.ConfigWrapper(config) + + if config_wrapper.alias_generator: + raise PydanticUserError( + 'Setting the "alias_generator" property on custom Config for ' + '@validate_arguments is not yet supported, please remove.', + code=None, + ) + if config_wrapper.extra is None: + config_wrapper.config_dict['extra'] = 'forbid' + + class DecoratorBaseModel(BaseModel): + @field_validator(self.v_args_name, check_fields=False) + @classmethod + def check_args(cls, v: Optional[list[Any]]) -> Optional[list[Any]]: + if takes_args or v is None: + return v + + raise TypeError(f'{pos_args} positional arguments expected but {pos_args + len(v)} given') + + @field_validator(self.v_kwargs_name, check_fields=False) + @classmethod + def check_kwargs(cls, v: Optional[dict[str, Any]]) -> Optional[dict[str, Any]]: + if takes_kwargs or v is None: + return v + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v.keys())) + raise TypeError(f'unexpected keyword argument{plural}: {keys}') + + @field_validator(V_POSITIONAL_ONLY_NAME, check_fields=False) + @classmethod + def check_positional_only(cls, v: Optional[list[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'positional-only argument{plural} passed as keyword argument{plural}: {keys}') + + @field_validator(V_DUPLICATE_KWARGS, check_fields=False) + @classmethod + def check_duplicate_kwargs(cls, v: Optional[list[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'multiple values for argument{plural}: {keys}') + + model_config = config_wrapper.config_dict + + self.model = create_model(to_pascal(self.raw_function.__name__), __base__=DecoratorBaseModel, **fields) diff --git a/source/target-vendors/cp312/pydantic/deprecated/json.py b/source/target-vendors/cp312/pydantic/deprecated/json.py new file mode 100644 index 0000000..1e216a7 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/json.py @@ -0,0 +1,141 @@ +import datetime +import warnings +from collections import deque +from decimal import Decimal +from enum import Enum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from re import Pattern +from types import GeneratorType +from typing import TYPE_CHECKING, Any, Callable, Union +from uuid import UUID + +from typing_extensions import deprecated + +from .._internal._import_utils import import_cached_base_model +from ..color import Color +from ..networks import NameEmail +from ..types import SecretBytes, SecretStr +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = 'pydantic_encoder', 'custom_pydantic_encoder', 'timedelta_isoformat' + + +def isoformat(o: Union[datetime.date, datetime.time]) -> str: + return o.isoformat() + + +def decimal_encoder(dec_value: Decimal) -> Union[int, float]: + """Encodes a Decimal as int of there's no exponent, otherwise float. + + This is useful when we use ConstrainedDecimal to represent Numeric(x,0) + where a integer (but not int typed) is used. Encoding this as a float + results in failed round-tripping between encode and parse. + Our Id type is a prime example of this. + + >>> decimal_encoder(Decimal("1.0")) + 1.0 + + >>> decimal_encoder(Decimal("1")) + 1 + """ + exponent = dec_value.as_tuple().exponent + if isinstance(exponent, int) and exponent >= 0: + return int(dec_value) + else: + return float(dec_value) + + +ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = { + bytes: lambda o: o.decode(), + Color: str, + datetime.date: isoformat, + datetime.datetime: isoformat, + datetime.time: isoformat, + datetime.timedelta: lambda td: td.total_seconds(), + Decimal: decimal_encoder, + Enum: lambda o: o.value, + frozenset: list, + deque: list, + GeneratorType: list, + IPv4Address: str, + IPv4Interface: str, + IPv4Network: str, + IPv6Address: str, + IPv6Interface: str, + IPv6Network: str, + NameEmail: str, + Path: str, + Pattern: lambda o: o.pattern, + SecretBytes: str, + SecretStr: str, + set: list, + UUID: str, +} + + +@deprecated( + '`pydantic_encoder` is deprecated, use `pydantic_core.to_jsonable_python` instead.', + category=None, +) +def pydantic_encoder(obj: Any) -> Any: + warnings.warn( + '`pydantic_encoder` is deprecated, use `pydantic_core.to_jsonable_python` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from dataclasses import asdict, is_dataclass + + BaseModel = import_cached_base_model() + + if isinstance(obj, BaseModel): + return obj.model_dump() + elif is_dataclass(obj): + return asdict(obj) # type: ignore + + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = ENCODERS_BY_TYPE[base] + except KeyError: + continue + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable") + + +# TODO: Add a suggested migration path once there is a way to use custom encoders +@deprecated( + '`custom_pydantic_encoder` is deprecated, use `BaseModel.model_dump` instead.', + category=None, +) +def custom_pydantic_encoder(type_encoders: dict[Any, Callable[[type[Any]], Any]], obj: Any) -> Any: + warnings.warn( + '`custom_pydantic_encoder` is deprecated, use `BaseModel.model_dump` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = type_encoders[base] + except KeyError: + continue + + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + return pydantic_encoder(obj) + + +@deprecated('`timedelta_isoformat` is deprecated.', category=None) +def timedelta_isoformat(td: datetime.timedelta) -> str: + """ISO 8601 encoding for Python timedelta object.""" + warnings.warn('`timedelta_isoformat` is deprecated.', category=PydanticDeprecatedSince20, stacklevel=2) + minutes, seconds = divmod(td.seconds, 60) + hours, minutes = divmod(minutes, 60) + return f'{"-" if td.days < 0 else ""}P{abs(td.days)}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S' diff --git a/source/target-vendors/cp312/pydantic/deprecated/parse.py b/source/target-vendors/cp312/pydantic/deprecated/parse.py new file mode 100644 index 0000000..2a92e62 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/parse.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +import json +import pickle +import warnings +from enum import Enum +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable + +from typing_extensions import deprecated + +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + + +class Protocol(str, Enum): + json = 'json' + pickle = 'pickle' + + +@deprecated('`load_str_bytes` is deprecated.', category=None) +def load_str_bytes( + b: str | bytes, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: Protocol | None = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + warnings.warn('`load_str_bytes` is deprecated.', category=PydanticDeprecatedSince20, stacklevel=2) + if proto is None and content_type: + if content_type.endswith(('json', 'javascript')): + pass + elif allow_pickle and content_type.endswith('pickle'): + proto = Protocol.pickle + else: + raise TypeError(f'Unknown content-type: {content_type}') + + proto = proto or Protocol.json + + if proto == Protocol.json: + if isinstance(b, bytes): + b = b.decode(encoding) + return json_loads(b) # type: ignore + elif proto == Protocol.pickle: + if not allow_pickle: + raise RuntimeError('Trying to decode with pickle with allow_pickle=False') + bb = b if isinstance(b, bytes) else b.encode() # type: ignore + return pickle.loads(bb) + else: + raise TypeError(f'Unknown protocol: {proto}') + + +@deprecated('`load_file` is deprecated.', category=None) +def load_file( + path: str | Path, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: Protocol | None = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + warnings.warn('`load_file` is deprecated.', category=PydanticDeprecatedSince20, stacklevel=2) + path = Path(path) + b = path.read_bytes() + if content_type is None: + if path.suffix in ('.js', '.json'): + proto = Protocol.json + elif path.suffix == '.pkl': + proto = Protocol.pickle + + return load_str_bytes( + b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle, json_loads=json_loads + ) diff --git a/source/target-vendors/cp312/pydantic/deprecated/tools.py b/source/target-vendors/cp312/pydantic/deprecated/tools.py new file mode 100644 index 0000000..5ad7fae --- /dev/null +++ b/source/target-vendors/cp312/pydantic/deprecated/tools.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +import json +import warnings +from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union + +from typing_extensions import deprecated + +from ..json_schema import DEFAULT_REF_TEMPLATE, GenerateJsonSchema +from ..type_adapter import TypeAdapter +from ..warnings import PydanticDeprecatedSince20 + +if not TYPE_CHECKING: + # See PyCharm issues https://youtrack.jetbrains.com/issue/PY-21915 + # and https://youtrack.jetbrains.com/issue/PY-51428 + DeprecationWarning = PydanticDeprecatedSince20 + +__all__ = 'parse_obj_as', 'schema_of', 'schema_json_of' + +NameFactory = Union[str, Callable[[type[Any]], str]] + + +T = TypeVar('T') + + +@deprecated( + '`parse_obj_as` is deprecated. Use `pydantic.TypeAdapter.validate_python` instead.', + category=None, +) +def parse_obj_as(type_: type[T], obj: Any, type_name: NameFactory | None = None) -> T: + warnings.warn( + '`parse_obj_as` is deprecated. Use `pydantic.TypeAdapter.validate_python` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if type_name is not None: # pragma: no cover + warnings.warn( + 'The type_name parameter is deprecated. parse_obj_as no longer creates temporary models', + DeprecationWarning, + stacklevel=2, + ) + return TypeAdapter(type_).validate_python(obj) + + +@deprecated( + '`schema_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=None, +) +def schema_of( + type_: Any, + *, + title: NameFactory | None = None, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, +) -> dict[str, Any]: + """Generate a JSON schema (as dict) for the passed model or dynamically generated one.""" + warnings.warn( + '`schema_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + res = TypeAdapter(type_).json_schema( + by_alias=by_alias, + schema_generator=schema_generator, + ref_template=ref_template, + ) + if title is not None: + if isinstance(title, str): + res['title'] = title + else: + warnings.warn( + 'Passing a callable for the `title` parameter is deprecated and no longer supported', + DeprecationWarning, + stacklevel=2, + ) + res['title'] = title(type_) + return res + + +@deprecated( + '`schema_json_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=None, +) +def schema_json_of( + type_: Any, + *, + title: NameFactory | None = None, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + **dumps_kwargs: Any, +) -> str: + """Generate a JSON schema (as JSON) for the passed model or dynamically generated one.""" + warnings.warn( + '`schema_json_of` is deprecated. Use `pydantic.TypeAdapter.json_schema` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return json.dumps( + schema_of(type_, title=title, by_alias=by_alias, ref_template=ref_template, schema_generator=schema_generator), + **dumps_kwargs, + ) diff --git a/source/target-vendors/cp312/pydantic/env_settings.py b/source/target-vendors/cp312/pydantic/env_settings.py new file mode 100644 index 0000000..cd0b04e --- /dev/null +++ b/source/target-vendors/cp312/pydantic/env_settings.py @@ -0,0 +1,5 @@ +"""The `env_settings` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/error_wrappers.py b/source/target-vendors/cp312/pydantic/error_wrappers.py new file mode 100644 index 0000000..2985419 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/error_wrappers.py @@ -0,0 +1,5 @@ +"""The `error_wrappers` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/errors.py b/source/target-vendors/cp312/pydantic/errors.py new file mode 100644 index 0000000..33851bd --- /dev/null +++ b/source/target-vendors/cp312/pydantic/errors.py @@ -0,0 +1,189 @@ +"""Pydantic-specific errors.""" + +from __future__ import annotations as _annotations + +import re +from typing import Any, ClassVar, Literal + +from typing_extensions import Self +from typing_inspection.introspection import Qualifier + +from pydantic._internal import _repr + +from ._migration import getattr_migration +from .version import version_short + +__all__ = ( + 'PydanticUserError', + 'PydanticUndefinedAnnotation', + 'PydanticImportError', + 'PydanticSchemaGenerationError', + 'PydanticInvalidForJsonSchema', + 'PydanticForbiddenQualifier', + 'PydanticErrorCodes', +) + +# We use this URL to allow for future flexibility about how we host the docs, while allowing for Pydantic +# code in the while with "old" URLs to still work. +# 'u' refers to "user errors" - e.g. errors caused by developers using pydantic, as opposed to validation errors. +DEV_ERROR_DOCS_URL = f'https://errors.pydantic.dev/{version_short()}/u/' +PydanticErrorCodes = Literal[ + 'class-not-fully-defined', + 'custom-json-schema', + 'decorator-invalid-fields', + 'decorator-missing-arguments', + 'decorator-missing-field', + 'discriminator-no-field', + 'discriminator-alias-type', + 'discriminator-needs-literal', + 'discriminator-alias', + 'discriminator-validator', + 'callable-discriminator-no-tag', + 'typed-dict-version', + 'model-field-overridden', + 'model-field-missing-annotation', + 'config-both', + 'removed-kwargs', + 'circular-reference-schema', + 'invalid-for-json-schema', + 'json-schema-already-used', + 'base-model-instantiated', + 'undefined-annotation', + 'schema-for-unknown-type', + 'import-error', + 'create-model-field-definitions', + 'validator-instance-method', + 'validator-input-type', + 'root-validator-pre-skip', + 'model-serializer-instance-method', + 'validator-field-config-info', + 'validator-v1-signature', + 'validator-signature', + 'field-serializer-signature', + 'model-serializer-signature', + 'multiple-field-serializers', + 'invalid-annotated-type', + 'type-adapter-config-unused', + 'root-model-extra', + 'unevaluable-type-annotation', + 'dataclass-init-false-extra-allow', + 'clashing-init-and-init-var', + 'model-config-invalid-field-name', + 'with-config-on-model', + 'dataclass-on-model', + 'validate-call-type', + 'unpack-typed-dict', + 'overlapping-unpack-typed-dict', + 'invalid-self-type', + 'validate-by-alias-and-name-false', +] + + +class PydanticErrorMixin: + """A mixin class for common functionality shared by all Pydantic-specific errors. + + Attributes: + message: A message describing the error. + code: An optional error code from PydanticErrorCodes enum. + """ + + def __init__(self, message: str, *, code: PydanticErrorCodes | None) -> None: + self.message = message + self.code = code + + def __str__(self) -> str: + if self.code is None: + return self.message + else: + return f'{self.message}\n\nFor further information visit {DEV_ERROR_DOCS_URL}{self.code}' + + +class PydanticUserError(PydanticErrorMixin, RuntimeError): + """An error raised due to incorrect use of Pydantic.""" + + +class PydanticUndefinedAnnotation(PydanticErrorMixin, NameError): + """A subclass of `NameError` raised when handling undefined annotations during `CoreSchema` generation. + + Attributes: + name: Name of the error. + message: Description of the error. + """ + + def __init__(self, name: str, message: str) -> None: + self.name = name + super().__init__(message=message, code='undefined-annotation') + + @classmethod + def from_name_error(cls, name_error: NameError) -> Self: + """Convert a `NameError` to a `PydanticUndefinedAnnotation` error. + + Args: + name_error: `NameError` to be converted. + + Returns: + Converted `PydanticUndefinedAnnotation` error. + """ + try: + name = name_error.name # type: ignore # python > 3.10 + except AttributeError: + name = re.search(r".*'(.+?)'", str(name_error)).group(1) # type: ignore[union-attr] + return cls(name=name, message=str(name_error)) + + +class PydanticImportError(PydanticErrorMixin, ImportError): + """An error raised when an import fails due to module changes between V1 and V2. + + Attributes: + message: Description of the error. + """ + + def __init__(self, message: str) -> None: + super().__init__(message, code='import-error') + + +class PydanticSchemaGenerationError(PydanticUserError): + """An error raised during failures to generate a `CoreSchema` for some type. + + Attributes: + message: Description of the error. + """ + + def __init__(self, message: str) -> None: + super().__init__(message, code='schema-for-unknown-type') + + +class PydanticInvalidForJsonSchema(PydanticUserError): + """An error raised during failures to generate a JSON schema for some `CoreSchema`. + + Attributes: + message: Description of the error. + """ + + def __init__(self, message: str) -> None: + super().__init__(message, code='invalid-for-json-schema') + + +class PydanticForbiddenQualifier(PydanticUserError): + """An error raised if a forbidden type qualifier is found in a type annotation.""" + + _qualifier_repr_map: ClassVar[dict[Qualifier, str]] = { + 'required': 'typing.Required', + 'not_required': 'typing.NotRequired', + 'read_only': 'typing.ReadOnly', + 'class_var': 'typing.ClassVar', + 'init_var': 'dataclasses.InitVar', + 'final': 'typing.Final', + } + + def __init__(self, qualifier: Qualifier, annotation: Any) -> None: + super().__init__( + message=( + f'The annotation {_repr.display_as_type(annotation)!r} contains the {self._qualifier_repr_map[qualifier]!r} ' + f'type qualifier, which is invalid in the context it is defined.' + ), + code=None, + ) + + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/experimental/__init__.py b/source/target-vendors/cp312/pydantic/experimental/__init__.py new file mode 100644 index 0000000..5b5add1 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/experimental/__init__.py @@ -0,0 +1 @@ +"""The "experimental" module of pydantic contains potential new features that are subject to change.""" diff --git a/source/target-vendors/cp312/pydantic/experimental/arguments_schema.py b/source/target-vendors/cp312/pydantic/experimental/arguments_schema.py new file mode 100644 index 0000000..af4a8f3 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/experimental/arguments_schema.py @@ -0,0 +1,44 @@ +"""Experimental module exposing a function to generate a core schema that validates callable arguments.""" + +from __future__ import annotations + +from collections.abc import Callable +from typing import Any, Literal + +from pydantic_core import CoreSchema + +from pydantic import ConfigDict +from pydantic._internal import _config, _generate_schema, _namespace_utils + + +def generate_arguments_schema( + func: Callable[..., Any], + schema_type: Literal['arguments', 'arguments-v3'] = 'arguments-v3', + parameters_callback: Callable[[int, str, Any], Literal['skip'] | None] | None = None, + config: ConfigDict | None = None, +) -> CoreSchema: + """Generate the schema for the arguments of a function. + + Args: + func: The function to generate the schema for. + schema_type: The type of schema to generate. + parameters_callback: A callable that will be invoked for each parameter. The callback + should take three required arguments: the index, the name and the type annotation + (or [`Parameter.empty`][inspect.Parameter.empty] if not annotated) of the parameter. + The callback can optionally return `'skip'`, so that the parameter gets excluded + from the resulting schema. + config: The configuration to use. + + Returns: + The generated schema. + """ + generate_schema = _generate_schema.GenerateSchema( + _config.ConfigWrapper(config), + ns_resolver=_namespace_utils.NsResolver(namespaces_tuple=_namespace_utils.ns_for_function(func)), + ) + + if schema_type == 'arguments': + schema = generate_schema._arguments_schema(func, parameters_callback) # pyright: ignore[reportArgumentType] + else: + schema = generate_schema._arguments_v3_schema(func, parameters_callback) # pyright: ignore[reportArgumentType] + return generate_schema.clean_schema(schema) diff --git a/source/target-vendors/cp312/pydantic/experimental/missing_sentinel.py b/source/target-vendors/cp312/pydantic/experimental/missing_sentinel.py new file mode 100644 index 0000000..3e7f820 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/experimental/missing_sentinel.py @@ -0,0 +1,5 @@ +"""Experimental module exposing a function a `MISSING` sentinel.""" + +from pydantic_core import MISSING + +__all__ = ('MISSING',) diff --git a/source/target-vendors/cp312/pydantic/experimental/pipeline.py b/source/target-vendors/cp312/pydantic/experimental/pipeline.py new file mode 100644 index 0000000..9ead658 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/experimental/pipeline.py @@ -0,0 +1,663 @@ +"""Experimental pipeline API functionality. Be careful with this API, it's subject to change.""" + +from __future__ import annotations + +import datetime +import operator +import re +import sys +from collections import deque +from collections.abc import Container +from dataclasses import dataclass +from decimal import Decimal +from functools import cached_property, partial +from re import Pattern +from typing import TYPE_CHECKING, Annotated, Any, Callable, Generic, Protocol, TypeVar, Union, overload + +import annotated_types + +if TYPE_CHECKING: + from pydantic import GetCoreSchemaHandler + +from pydantic_core import PydanticCustomError +from pydantic_core import core_schema as cs + +from pydantic import Strict +from pydantic._internal._internal_dataclass import slots_true as _slots_true + +if sys.version_info < (3, 10): + EllipsisType = type(Ellipsis) +else: + from types import EllipsisType + +__all__ = ['validate_as', 'validate_as_deferred', 'transform'] + +_slots_frozen = {**_slots_true, 'frozen': True} + + +@dataclass(**_slots_frozen) +class _ValidateAs: + tp: type[Any] + strict: bool = False + + +@dataclass +class _ValidateAsDefer: + func: Callable[[], type[Any]] + + @cached_property + def tp(self) -> type[Any]: + return self.func() + + +@dataclass(**_slots_frozen) +class _Transform: + func: Callable[[Any], Any] + + +@dataclass(**_slots_frozen) +class _PipelineOr: + left: _Pipeline[Any, Any] + right: _Pipeline[Any, Any] + + +@dataclass(**_slots_frozen) +class _PipelineAnd: + left: _Pipeline[Any, Any] + right: _Pipeline[Any, Any] + + +@dataclass(**_slots_frozen) +class _Eq: + value: Any + + +@dataclass(**_slots_frozen) +class _NotEq: + value: Any + + +@dataclass(**_slots_frozen) +class _In: + values: Container[Any] + + +@dataclass(**_slots_frozen) +class _NotIn: + values: Container[Any] + + +_ConstraintAnnotation = Union[ + annotated_types.Le, + annotated_types.Ge, + annotated_types.Lt, + annotated_types.Gt, + annotated_types.Len, + annotated_types.MultipleOf, + annotated_types.Timezone, + annotated_types.Interval, + annotated_types.Predicate, + # common predicates not included in annotated_types + _Eq, + _NotEq, + _In, + _NotIn, + # regular expressions + Pattern[str], +] + + +@dataclass(**_slots_frozen) +class _Constraint: + constraint: _ConstraintAnnotation + + +_Step = Union[_ValidateAs, _ValidateAsDefer, _Transform, _PipelineOr, _PipelineAnd, _Constraint] + +_InT = TypeVar('_InT') +_OutT = TypeVar('_OutT') +_NewOutT = TypeVar('_NewOutT') + + +class _FieldTypeMarker: + pass + + +# TODO: ultimately, make this public, see https://github.com/pydantic/pydantic/pull/9459#discussion_r1628197626 +# Also, make this frozen eventually, but that doesn't work right now because of the generic base +# Which attempts to modify __orig_base__ and such. +# We could go with a manual freeze, but that seems overkill for now. +@dataclass(**_slots_true) +class _Pipeline(Generic[_InT, _OutT]): + """Abstract representation of a chain of validation, transformation, and parsing steps.""" + + _steps: tuple[_Step, ...] + + def transform( + self, + func: Callable[[_OutT], _NewOutT], + ) -> _Pipeline[_InT, _NewOutT]: + """Transform the output of the previous step. + + If used as the first step in a pipeline, the type of the field is used. + That is, the transformation is applied to after the value is parsed to the field's type. + """ + return _Pipeline[_InT, _NewOutT](self._steps + (_Transform(func),)) + + @overload + def validate_as(self, tp: type[_NewOutT], *, strict: bool = False) -> _Pipeline[_InT, _NewOutT]: ... + + @overload + def validate_as( + self, + tp: ellipsis, # noqa: F821 # TODO: use `_typing_extra.EllipsisType` when we drop Py3.9 + *, + strict: bool = False, + ) -> _Pipeline[_InT, Any]: ... + + # TODO PEP 747: use TypeForm to properly type Annotated aliases (e.g. NewPath, FilePath). + # This fallback accepts any type expression but loses generic type inference. + @overload + def validate_as(self, tp: Any, *, strict: bool = ...) -> _Pipeline[_InT, Any]: ... + + def validate_as(self, tp: type[_NewOutT] | EllipsisType | Any, *, strict: bool = False) -> _Pipeline[_InT, Any]: # type: ignore + """Validate / parse the input into a new type. + + If no type is provided, the type of the field is used. + + Types are parsed in Pydantic's `lax` mode by default, + but you can enable `strict` mode by passing `strict=True`. + """ + if isinstance(tp, EllipsisType): + return _Pipeline[_InT, Any](self._steps + (_ValidateAs(_FieldTypeMarker, strict=strict),)) + return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAs(tp, strict=strict),)) + + def validate_as_deferred(self, func: Callable[[], type[_NewOutT]]) -> _Pipeline[_InT, _NewOutT]: + """Parse the input into a new type, deferring resolution of the type until the current class + is fully defined. + + This is useful when you need to reference the class in it's own type annotations. + """ + return _Pipeline[_InT, _NewOutT](self._steps + (_ValidateAsDefer(func),)) + + # constraints + @overload + def constrain(self: _Pipeline[_InT, _NewOutGe], constraint: annotated_types.Ge) -> _Pipeline[_InT, _NewOutGe]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutGt], constraint: annotated_types.Gt) -> _Pipeline[_InT, _NewOutGt]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutLe], constraint: annotated_types.Le) -> _Pipeline[_InT, _NewOutLe]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutLt], constraint: annotated_types.Lt) -> _Pipeline[_InT, _NewOutLt]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutLen], constraint: annotated_types.Len + ) -> _Pipeline[_InT, _NewOutLen]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutT], constraint: annotated_types.MultipleOf + ) -> _Pipeline[_InT, _NewOutT]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutDatetime], constraint: annotated_types.Timezone + ) -> _Pipeline[_InT, _NewOutDatetime]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: annotated_types.Predicate) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain( + self: _Pipeline[_InT, _NewOutInterval], constraint: annotated_types.Interval + ) -> _Pipeline[_InT, _NewOutInterval]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _Eq) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotEq) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _In) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _OutT], constraint: _NotIn) -> _Pipeline[_InT, _OutT]: ... + + @overload + def constrain(self: _Pipeline[_InT, _NewOutT], constraint: Pattern[str]) -> _Pipeline[_InT, _NewOutT]: ... + + def constrain(self, constraint: _ConstraintAnnotation) -> Any: + """Constrain a value to meet a certain condition. + + We support most conditions from `annotated_types`, as well as regular expressions. + + Most of the time you'll be calling a shortcut method like `gt`, `lt`, `len`, etc + so you don't need to call this directly. + """ + return _Pipeline[_InT, _OutT](self._steps + (_Constraint(constraint),)) + + def predicate(self: _Pipeline[_InT, _NewOutT], func: Callable[[_NewOutT], bool]) -> _Pipeline[_InT, _NewOutT]: + """Constrain a value to meet a certain predicate.""" + return self.constrain(annotated_types.Predicate(func)) + + def gt(self: _Pipeline[_InT, _NewOutGt], gt: _NewOutGt) -> _Pipeline[_InT, _NewOutGt]: + """Constrain a value to be greater than a certain value.""" + return self.constrain(annotated_types.Gt(gt)) + + def lt(self: _Pipeline[_InT, _NewOutLt], lt: _NewOutLt) -> _Pipeline[_InT, _NewOutLt]: + """Constrain a value to be less than a certain value.""" + return self.constrain(annotated_types.Lt(lt)) + + def ge(self: _Pipeline[_InT, _NewOutGe], ge: _NewOutGe) -> _Pipeline[_InT, _NewOutGe]: + """Constrain a value to be greater than or equal to a certain value.""" + return self.constrain(annotated_types.Ge(ge)) + + def le(self: _Pipeline[_InT, _NewOutLe], le: _NewOutLe) -> _Pipeline[_InT, _NewOutLe]: + """Constrain a value to be less than or equal to a certain value.""" + return self.constrain(annotated_types.Le(le)) + + def len(self: _Pipeline[_InT, _NewOutLen], min_len: int, max_len: int | None = None) -> _Pipeline[_InT, _NewOutLen]: + """Constrain a value to have a certain length.""" + return self.constrain(annotated_types.Len(min_len, max_len)) + + @overload + def multiple_of(self: _Pipeline[_InT, _NewOutDiv], multiple_of: _NewOutDiv) -> _Pipeline[_InT, _NewOutDiv]: ... + + @overload + def multiple_of(self: _Pipeline[_InT, _NewOutMod], multiple_of: _NewOutMod) -> _Pipeline[_InT, _NewOutMod]: ... + + def multiple_of(self: _Pipeline[_InT, Any], multiple_of: Any) -> _Pipeline[_InT, Any]: + """Constrain a value to be a multiple of a certain number.""" + return self.constrain(annotated_types.MultipleOf(multiple_of)) + + def eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: + """Constrain a value to be equal to a certain value.""" + return self.constrain(_Eq(value)) + + def not_eq(self: _Pipeline[_InT, _OutT], value: _OutT) -> _Pipeline[_InT, _OutT]: + """Constrain a value to not be equal to a certain value.""" + return self.constrain(_NotEq(value)) + + def in_(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: + """Constrain a value to be in a certain set.""" + return self.constrain(_In(values)) + + def not_in(self: _Pipeline[_InT, _OutT], values: Container[_OutT]) -> _Pipeline[_InT, _OutT]: + """Constrain a value to not be in a certain set.""" + return self.constrain(_NotIn(values)) + + # timezone methods + def datetime_tz_naive(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: + return self.constrain(annotated_types.Timezone(None)) + + def datetime_tz_aware(self: _Pipeline[_InT, datetime.datetime]) -> _Pipeline[_InT, datetime.datetime]: + return self.constrain(annotated_types.Timezone(...)) + + def datetime_tz( + self: _Pipeline[_InT, datetime.datetime], tz: datetime.tzinfo + ) -> _Pipeline[_InT, datetime.datetime]: + return self.constrain(annotated_types.Timezone(tz)) # type: ignore + + def datetime_with_tz( + self: _Pipeline[_InT, datetime.datetime], tz: datetime.tzinfo | None + ) -> _Pipeline[_InT, datetime.datetime]: + return self.transform(partial(datetime.datetime.replace, tzinfo=tz)) + + # string methods + def str_lower(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.lower) + + def str_upper(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.upper) + + def str_title(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.title) + + def str_strip(self: _Pipeline[_InT, str]) -> _Pipeline[_InT, str]: + return self.transform(str.strip) + + def str_pattern(self: _Pipeline[_InT, str], pattern: str) -> _Pipeline[_InT, str]: + return self.constrain(re.compile(pattern)) + + def str_contains(self: _Pipeline[_InT, str], substring: str) -> _Pipeline[_InT, str]: + return self.predicate(lambda v: substring in v) + + def str_starts_with(self: _Pipeline[_InT, str], prefix: str) -> _Pipeline[_InT, str]: + return self.predicate(lambda v: v.startswith(prefix)) + + def str_ends_with(self: _Pipeline[_InT, str], suffix: str) -> _Pipeline[_InT, str]: + return self.predicate(lambda v: v.endswith(suffix)) + + # operators + def otherwise(self, other: _Pipeline[_OtherIn, _OtherOut]) -> _Pipeline[_InT | _OtherIn, _OutT | _OtherOut]: + """Combine two validation chains, returning the result of the first chain if it succeeds, and the second chain if it fails.""" + return _Pipeline((_PipelineOr(self, other),)) + + __or__ = otherwise + + def then(self, other: _Pipeline[_OutT, _OtherOut]) -> _Pipeline[_InT, _OtherOut]: + """Pipe the result of one validation chain into another.""" + return _Pipeline((_PipelineAnd(self, other),)) + + __and__ = then + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> cs.CoreSchema: + queue = deque(self._steps) + + s = None + + while queue: + step = queue.popleft() + s = _apply_step(step, s, handler, source_type) + + s = s or cs.any_schema() + return s + + def __supports_type__(self, _: _OutT) -> bool: + raise NotImplementedError + + +validate_as = _Pipeline[Any, Any](()).validate_as +validate_as_deferred = _Pipeline[Any, Any](()).validate_as_deferred +transform = _Pipeline[Any, Any]((_ValidateAs(_FieldTypeMarker),)).transform + + +def _check_func( + func: Callable[[Any], bool], predicate_err: str | Callable[[], str], s: cs.CoreSchema | None +) -> cs.CoreSchema: + def handler(v: Any) -> Any: + if func(v): + return v + raise ValueError(f'Expected {predicate_err if isinstance(predicate_err, str) else predicate_err()}') + + if s is None: + return cs.no_info_plain_validator_function(handler) + else: + return cs.no_info_after_validator_function(handler, s) + + +def _apply_step(step: _Step, s: cs.CoreSchema | None, handler: GetCoreSchemaHandler, source_type: Any) -> cs.CoreSchema: + if isinstance(step, _ValidateAs): + s = _apply_parse(s, step.tp, step.strict, handler, source_type) + elif isinstance(step, _ValidateAsDefer): + s = _apply_parse(s, step.tp, False, handler, source_type) + elif isinstance(step, _Transform): + s = _apply_transform(s, step.func, handler) + elif isinstance(step, _Constraint): + s = _apply_constraint(s, step.constraint) + elif isinstance(step, _PipelineOr): + s = cs.union_schema([handler(step.left), handler(step.right)]) + else: + assert isinstance(step, _PipelineAnd) + s = cs.chain_schema([handler(step.left), handler(step.right)]) + return s + + +def _apply_parse( + s: cs.CoreSchema | None, + tp: type[Any], + strict: bool, + handler: GetCoreSchemaHandler, + source_type: Any, +) -> cs.CoreSchema: + if tp is _FieldTypeMarker: + return cs.chain_schema([s, handler(source_type)]) if s else handler(source_type) + + if strict: + tp = Annotated[tp, Strict()] # type: ignore + + if s and s['type'] == 'any': + return handler(tp) + else: + return cs.chain_schema([s, handler(tp)]) if s else handler(tp) + + +def _apply_transform( + s: cs.CoreSchema | None, func: Callable[[Any], Any], handler: GetCoreSchemaHandler +) -> cs.CoreSchema: + if s is None: + return cs.no_info_plain_validator_function(func) + + if s['type'] == 'str': + if func is str.strip: + s = s.copy() + s['strip_whitespace'] = True + return s + elif func is str.lower: + s = s.copy() + s['to_lower'] = True + return s + elif func is str.upper: + s = s.copy() + s['to_upper'] = True + return s + + return cs.no_info_after_validator_function(func, s) + + +def _apply_constraint( # noqa: C901 + s: cs.CoreSchema | None, constraint: _ConstraintAnnotation +) -> cs.CoreSchema: + """Apply a single constraint to a schema.""" + if isinstance(constraint, annotated_types.Gt): + gt = constraint.gt + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(gt, int): + s['gt'] = gt + elif s['type'] == 'float' and isinstance(gt, float): + s['gt'] = gt + elif s['type'] == 'decimal' and isinstance(gt, Decimal): + s['gt'] = gt + else: + + def check_gt(v: Any) -> bool: + return v > gt + + s = _check_func(check_gt, f'> {gt}', s) + elif isinstance(constraint, annotated_types.Ge): + ge = constraint.ge + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(ge, int): + s['ge'] = ge + elif s['type'] == 'float' and isinstance(ge, float): + s['ge'] = ge + elif s['type'] == 'decimal' and isinstance(ge, Decimal): + s['ge'] = ge + + def check_ge(v: Any) -> bool: + return v >= ge + + s = _check_func(check_ge, f'>= {ge}', s) + elif isinstance(constraint, annotated_types.Lt): + lt = constraint.lt + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(lt, int): + s['lt'] = lt + elif s['type'] == 'float' and isinstance(lt, float): + s['lt'] = lt + elif s['type'] == 'decimal' and isinstance(lt, Decimal): + s['lt'] = lt + + def check_lt(v: Any) -> bool: + return v < lt + + s = _check_func(check_lt, f'< {lt}', s) + elif isinstance(constraint, annotated_types.Le): + le = constraint.le + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(le, int): + s['le'] = le + elif s['type'] == 'float' and isinstance(le, float): + s['le'] = le + elif s['type'] == 'decimal' and isinstance(le, Decimal): + s['le'] = le + + def check_le(v: Any) -> bool: + return v <= le + + s = _check_func(check_le, f'<= {le}', s) + elif isinstance(constraint, annotated_types.Len): + min_len = constraint.min_length + max_len = constraint.max_length + + if s and s['type'] in {'str', 'list', 'tuple', 'set', 'frozenset', 'dict'}: + assert ( + s['type'] == 'str' + or s['type'] == 'list' + or s['type'] == 'tuple' + or s['type'] == 'set' + or s['type'] == 'dict' + or s['type'] == 'frozenset' + ) + s = s.copy() + if min_len != 0: + s['min_length'] = min_len + if max_len is not None: + s['max_length'] = max_len + + def check_len(v: Any) -> bool: + if max_len is not None: + return (min_len <= len(v)) and (len(v) <= max_len) + return min_len <= len(v) + + s = _check_func(check_len, f'length >= {min_len} and length <= {max_len}', s) + elif isinstance(constraint, annotated_types.MultipleOf): + multiple_of = constraint.multiple_of + if s and s['type'] in {'int', 'float', 'decimal'}: + s = s.copy() + if s['type'] == 'int' and isinstance(multiple_of, int): + s['multiple_of'] = multiple_of + elif s['type'] == 'float' and isinstance(multiple_of, float): + s['multiple_of'] = multiple_of + elif s['type'] == 'decimal' and isinstance(multiple_of, Decimal): + s['multiple_of'] = multiple_of + + def check_multiple_of(v: Any) -> bool: + return v % multiple_of == 0 + + s = _check_func(check_multiple_of, f'% {multiple_of} == 0', s) + elif isinstance(constraint, annotated_types.Timezone): + tz = constraint.tz + + if tz is ...: + if s and s['type'] == 'datetime': + s = s.copy() + s['tz_constraint'] = 'aware' + else: + + def check_tz_aware(v: object) -> bool: + assert isinstance(v, datetime.datetime) + return v.tzinfo is not None + + s = _check_func(check_tz_aware, 'timezone aware', s) + elif tz is None: + if s and s['type'] == 'datetime': + s = s.copy() + s['tz_constraint'] = 'naive' + else: + + def check_tz_naive(v: object) -> bool: + assert isinstance(v, datetime.datetime) + return v.tzinfo is None + + s = _check_func(check_tz_naive, 'timezone naive', s) + else: + raise NotImplementedError('Constraining to a specific timezone is not yet supported') + elif isinstance(constraint, annotated_types.Interval): + if constraint.ge: + s = _apply_constraint(s, annotated_types.Ge(constraint.ge)) + if constraint.gt: + s = _apply_constraint(s, annotated_types.Gt(constraint.gt)) + if constraint.le: + s = _apply_constraint(s, annotated_types.Le(constraint.le)) + if constraint.lt: + s = _apply_constraint(s, annotated_types.Lt(constraint.lt)) + assert s is not None + elif isinstance(constraint, annotated_types.Predicate): + func = constraint.func + # Same logic as in `_known_annotated_metadata.apply_known_metadata()`: + predicate_name = f'{func.__qualname__!r} ' if hasattr(func, '__qualname__') else '' + + def predicate_func(v: Any) -> Any: + if not func(v): + raise PydanticCustomError( + 'predicate_failed', + f'Predicate {predicate_name}failed', # pyright: ignore[reportArgumentType] + ) + return v + + if s is None: + s = cs.no_info_plain_validator_function(predicate_func) + else: + s = cs.no_info_after_validator_function(predicate_func, s) + elif isinstance(constraint, _NotEq): + value = constraint.value + + def check_not_eq(v: Any) -> bool: + return operator.__ne__(v, value) + + s = _check_func(check_not_eq, f'!= {value}', s) + elif isinstance(constraint, _Eq): + value = constraint.value + + def check_eq(v: Any) -> bool: + return operator.__eq__(v, value) + + s = _check_func(check_eq, f'== {value}', s) + elif isinstance(constraint, _In): + values = constraint.values + + def check_in(v: Any) -> bool: + return operator.__contains__(values, v) + + s = _check_func(check_in, f'in {values}', s) + elif isinstance(constraint, _NotIn): + values = constraint.values + + def check_not_in(v: Any) -> bool: + return operator.__not__(operator.__contains__(values, v)) + + s = _check_func(check_not_in, f'not in {values}', s) + else: + assert isinstance(constraint, Pattern) + if s and s['type'] == 'str': + s = s.copy() + s['pattern'] = constraint.pattern + else: + + def check_pattern(v: object) -> bool: + assert isinstance(v, str) + return constraint.match(v) is not None + + s = _check_func(check_pattern, f'~ {constraint.pattern}', s) + return s + + +class _SupportsRange(annotated_types.SupportsLe, annotated_types.SupportsGe, Protocol): + pass + + +class _SupportsLen(Protocol): + def __len__(self) -> int: ... + + +_NewOutGt = TypeVar('_NewOutGt', bound=annotated_types.SupportsGt) +_NewOutGe = TypeVar('_NewOutGe', bound=annotated_types.SupportsGe) +_NewOutLt = TypeVar('_NewOutLt', bound=annotated_types.SupportsLt) +_NewOutLe = TypeVar('_NewOutLe', bound=annotated_types.SupportsLe) +_NewOutLen = TypeVar('_NewOutLen', bound=_SupportsLen) +_NewOutDiv = TypeVar('_NewOutDiv', bound=annotated_types.SupportsDiv) +_NewOutMod = TypeVar('_NewOutMod', bound=annotated_types.SupportsMod) +_NewOutDatetime = TypeVar('_NewOutDatetime', bound=datetime.datetime) +_NewOutInterval = TypeVar('_NewOutInterval', bound=_SupportsRange) +_OtherIn = TypeVar('_OtherIn') +_OtherOut = TypeVar('_OtherOut') diff --git a/source/target-vendors/cp312/pydantic/fields.py b/source/target-vendors/cp312/pydantic/fields.py new file mode 100644 index 0000000..ede966f --- /dev/null +++ b/source/target-vendors/cp312/pydantic/fields.py @@ -0,0 +1,1892 @@ +"""Defining fields on models.""" + +from __future__ import annotations as _annotations + +import dataclasses +import inspect +import re +import sys +from collections.abc import Callable, Mapping +from copy import copy +from dataclasses import Field as DataclassField +from functools import cached_property +from typing import TYPE_CHECKING, Annotated, Any, ClassVar, Literal, TypeVar, final, overload +from warnings import warn + +import annotated_types +import typing_extensions +from pydantic_core import MISSING, PydanticUndefined +from typing_extensions import Self, TypeAlias, TypedDict, Unpack, deprecated +from typing_inspection import typing_objects +from typing_inspection.introspection import UNKNOWN, AnnotationSource, ForbiddenQualifier, Qualifier, inspect_annotation + +from . import types +from ._internal import _decorators, _fields, _generics, _internal_dataclass, _repr, _typing_extra, _utils +from ._internal._namespace_utils import GlobalsNamespace, MappingNamespace +from .aliases import AliasChoices, AliasGenerator, AliasPath +from .config import JsonDict +from .errors import PydanticForbiddenQualifier, PydanticUserError +from .json_schema import PydanticJsonSchemaWarning +from .warnings import PydanticDeprecatedSince20 + +if TYPE_CHECKING: + from ._internal._config import ConfigWrapper + from ._internal._repr import ReprArgs + + +__all__ = 'Field', 'FieldInfo', 'PrivateAttr', 'computed_field' + + +_Unset: Any = PydanticUndefined + +if sys.version_info >= (3, 13): + import warnings + + Deprecated: TypeAlias = warnings.deprecated | deprecated +else: + Deprecated: TypeAlias = deprecated + + +class _FromFieldInfoInputs(TypedDict, total=False): + """This class exists solely to add type checking for the `**kwargs` in `FieldInfo.from_field`.""" + + # TODO PEP 747: use TypeForm: + annotation: type[Any] | None + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None + alias: str | None + alias_priority: int | None + validation_alias: str | AliasPath | AliasChoices | None + serialization_alias: str | None + title: str | None + field_title_generator: Callable[[str, FieldInfo], str] | None + description: str | None + examples: list[Any] | None + exclude: bool | None + exclude_if: Callable[[Any], bool] | None + gt: annotated_types.SupportsGt | None + ge: annotated_types.SupportsGe | None + lt: annotated_types.SupportsLt | None + le: annotated_types.SupportsLe | None + multiple_of: float | None + strict: bool | None + min_length: int | None + max_length: int | None + pattern: str | re.Pattern[str] | None + allow_inf_nan: bool | None + max_digits: int | None + decimal_places: int | None + union_mode: Literal['smart', 'left_to_right'] | None + discriminator: str | types.Discriminator | None + deprecated: Deprecated | str | bool | None + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None + frozen: bool | None + validate_default: bool | None + repr: bool + init: bool | None + init_var: bool | None + kw_only: bool | None + coerce_numbers_to_str: bool | None + fail_fast: bool | None + + +class _FieldInfoInputs(_FromFieldInfoInputs, total=False): + """This class exists solely to add type checking for the `**kwargs` in `FieldInfo.__init__`.""" + + default: Any + + +class _FieldInfoAsDict(TypedDict, closed=True): + # TODO PEP 747: use TypeForm: + annotation: Any + metadata: list[Any] + attributes: dict[str, Any] + + +@final +class FieldInfo(_repr.Representation): + """This class holds information about a field. + + `FieldInfo` is used for any field definition regardless of whether the [`Field()`][pydantic.fields.Field] + function is explicitly used. + + !!! warning + The `FieldInfo` class is meant to expose information about a field in a Pydantic model or dataclass. + `FieldInfo` instances shouldn't be instantiated directly, nor mutated. + + If you need to derive a new model from another one and are willing to alter `FieldInfo` instances, + refer to this [dynamic model example](../examples/dynamic_models.md). + + Attributes: + annotation: The type annotation of the field. + default: The default value of the field. + default_factory: A callable to generate the default value. The callable can either take 0 arguments + (in which case it is called as is) or a single argument containing the already validated data. + alias: The alias name of the field. + alias_priority: The priority of the field's alias. + validation_alias: The validation alias of the field. + serialization_alias: The serialization alias of the field. + title: The title of the field. + field_title_generator: A callable that takes a field name and returns title for it. + description: The description of the field. + examples: List of examples of the field. + exclude: Whether to exclude the field from the model serialization. + exclude_if: A callable that determines whether to exclude a field during serialization based on its value. + discriminator: Field name or Discriminator for discriminating the type in a tagged union. + deprecated: A deprecation message, an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport, + or a boolean. If `True`, a default deprecation message will be emitted when accessing the field. + json_schema_extra: A dict or callable to provide extra JSON schema properties. + frozen: Whether the field is frozen. + validate_default: Whether to validate the default value of the field. + repr: Whether to include the field in representation of the model. + init: Whether the field should be included in the constructor of the dataclass. + init_var: Whether the field should _only_ be included in the constructor of the dataclass, and not stored. + kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass. + metadata: The metadata list. Contains all the data that isn't expressed as direct `FieldInfo` attributes, including: + + * Type-specific constraints, such as `gt` or `min_length` (these are converted to metadata classes such as `annotated_types.Gt`). + * Any other arbitrary object used within [`Annotated`][typing.Annotated] metadata + (e.g. [custom types handlers](../concepts/types.md#as-an-annotation) or any object not recognized by Pydantic). + """ + + # TODO PEP 747: use TypeForm: + annotation: type[Any] | None + default: Any + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None + alias: str | None + alias_priority: int | None + validation_alias: str | AliasPath | AliasChoices | None + serialization_alias: str | None + title: str | None + field_title_generator: Callable[[str, FieldInfo], str] | None + description: str | None + examples: list[Any] | None + exclude: bool | None + exclude_if: Callable[[Any], bool] | None + discriminator: str | types.Discriminator | None + deprecated: Deprecated | str | bool | None + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None + frozen: bool | None + validate_default: bool | None + repr: bool + init: bool | None + init_var: bool | None + kw_only: bool | None + metadata: list[Any] + + __slots__ = ( + 'annotation', + 'default', + 'default_factory', + 'alias', + 'alias_priority', + 'validation_alias', + 'serialization_alias', + 'title', + 'field_title_generator', + 'description', + 'examples', + 'exclude', + 'exclude_if', + 'discriminator', + 'deprecated', + 'json_schema_extra', + 'frozen', + 'validate_default', + 'repr', + 'init', + 'init_var', + 'kw_only', + 'metadata', + '_attributes_set', + '_qualifiers', + '_complete', + '_original_assignment', + '_original_annotation', + '_final', + ) + + # used to convert kwargs to metadata/constraints, + # None has a special meaning - these items are collected into a `PydanticGeneralMetadata` + metadata_lookup: ClassVar[dict[str, Callable[[Any], Any] | None]] = { + 'strict': types.Strict, + 'gt': annotated_types.Gt, + 'ge': annotated_types.Ge, + 'lt': annotated_types.Lt, + 'le': annotated_types.Le, + 'multiple_of': annotated_types.MultipleOf, + 'min_length': annotated_types.MinLen, + 'max_length': annotated_types.MaxLen, + 'pattern': None, + 'allow_inf_nan': None, + 'max_digits': None, + 'decimal_places': None, + 'union_mode': None, + 'coerce_numbers_to_str': None, + 'fail_fast': types.FailFast, + } + + def __init__(self, **kwargs: Unpack[_FieldInfoInputs]) -> None: + """This class should generally not be initialized directly; instead, use the `pydantic.fields.Field` function + or one of the constructor classmethods. + + See the signature of `pydantic.fields.Field` for more details about the expected arguments. + """ + # Tracking the explicitly set attributes is necessary to correctly merge `Field()` functions + # (e.g. with `Annotated[int, Field(alias='a'), Field(alias=None)]`, even though `None` is the default value, + # we need to track that `alias=None` was explicitly set): + self._attributes_set = {k: v for k, v in kwargs.items() if v is not _Unset and k not in self.metadata_lookup} + kwargs = {k: _DefaultValues.get(k) if v is _Unset else v for k, v in kwargs.items()} # type: ignore + self.annotation = kwargs.get('annotation') + + # Note: in theory, the second `pop()` arguments are not required below, as defaults are already set from `_DefaultsValues`. + default = kwargs.pop('default', PydanticUndefined) + if default is Ellipsis: + self.default = PydanticUndefined + self._attributes_set.pop('default', None) + else: + self.default = default + + self.default_factory = kwargs.pop('default_factory', None) + + if self.default is not PydanticUndefined and self.default_factory is not None: + raise TypeError('cannot specify both default and default_factory') + + self.alias = kwargs.pop('alias', None) + self.validation_alias = kwargs.pop('validation_alias', None) + self.serialization_alias = kwargs.pop('serialization_alias', None) + alias_is_set = any(alias is not None for alias in (self.alias, self.validation_alias, self.serialization_alias)) + self.alias_priority = kwargs.pop('alias_priority', None) or 2 if alias_is_set else None + self.title = kwargs.pop('title', None) + self.field_title_generator = kwargs.pop('field_title_generator', None) + self.description = kwargs.pop('description', None) + self.examples = kwargs.pop('examples', None) + self.exclude = kwargs.pop('exclude', None) + self.exclude_if = kwargs.pop('exclude_if', None) + self.discriminator = kwargs.pop('discriminator', None) + # For compatibility with FastAPI<=0.110.0, we preserve the existing value if it is not overridden + self.deprecated = kwargs.pop('deprecated', getattr(self, 'deprecated', None)) + self.repr = kwargs.pop('repr', True) + self.json_schema_extra = kwargs.pop('json_schema_extra', None) + self.validate_default = kwargs.pop('validate_default', None) + self.frozen = kwargs.pop('frozen', None) + # currently only used on dataclasses + self.init = kwargs.pop('init', None) + self.init_var = kwargs.pop('init_var', None) + self.kw_only = kwargs.pop('kw_only', None) + + self.metadata = self._collect_metadata(kwargs) # type: ignore + + # Private attributes: + self._qualifiers: set[Qualifier] = set() + # Used to rebuild FieldInfo instances: + self._complete = True + self._original_annotation: Any = PydanticUndefined + self._original_assignment: Any = PydanticUndefined + # Used to track whether the `FieldInfo` instance represents the data about a field (and is exposed in `model_fields`/`__pydantic_fields__`), + # or if it is the result of the `Field()` function being used as metadata in an `Annotated` type/as an assignment + # (not an ideal pattern, see https://github.com/pydantic/pydantic/issues/11122): + self._final = False + + @staticmethod + def from_field(default: Any = PydanticUndefined, **kwargs: Unpack[_FromFieldInfoInputs]) -> FieldInfo: + """Create a new `FieldInfo` object with the `Field` function. + + Args: + default: The default value for the field. Defaults to Undefined. + **kwargs: Additional arguments dictionary. + + Raises: + TypeError: If 'annotation' is passed as a keyword argument. + + Returns: + A new FieldInfo object with the given parameters. + + Example: + This is how you can create a field with default value like this: + + ```python + import pydantic + + class MyModel(pydantic.BaseModel): + foo: int = pydantic.Field(4) + ``` + """ + if 'annotation' in kwargs: + raise TypeError('"annotation" is not permitted as a Field keyword argument') + return FieldInfo(default=default, **kwargs) + + @staticmethod + def from_annotation(annotation: type[Any], *, _source: AnnotationSource = AnnotationSource.ANY) -> FieldInfo: + """Creates a `FieldInfo` instance from a bare annotation. + + This function is used internally to create a `FieldInfo` from a bare annotation like this: + + ```python + import pydantic + + class MyModel(pydantic.BaseModel): + foo: int # <-- like this + ``` + + We also account for the case where the annotation can be an instance of `Annotated` and where + one of the (not first) arguments in `Annotated` is an instance of `FieldInfo`, e.g.: + + ```python + from typing import Annotated + + import annotated_types + + import pydantic + + class MyModel(pydantic.BaseModel): + foo: Annotated[int, annotated_types.Gt(42)] + bar: Annotated[int, pydantic.Field(gt=42)] + ``` + + Args: + annotation: An annotation object. + + Returns: + An instance of the field metadata. + """ + try: + inspected_ann = inspect_annotation( + annotation, + annotation_source=_source, + unpack_type_aliases='skip', + ) + except ForbiddenQualifier as e: + raise PydanticForbiddenQualifier(e.qualifier, annotation) + + # TODO check for classvar and error? + + # No assigned value, this happens when using a bare `Final` qualifier (also for other + # qualifiers, but they shouldn't appear here). In this case we infer the type as `Any` + # because we don't have any assigned value. + type_expr: Any = Any if inspected_ann.type is UNKNOWN else inspected_ann.type + final = 'final' in inspected_ann.qualifiers + metadata = inspected_ann.metadata + + attr_overrides = {'annotation': type_expr} + if final: + attr_overrides['frozen'] = True + field_info = FieldInfo._construct(metadata, **attr_overrides) + field_info._qualifiers = inspected_ann.qualifiers + field_info._final = True + return field_info + + @staticmethod + def from_annotated_attribute( + annotation: type[Any], default: Any, *, _source: AnnotationSource = AnnotationSource.ANY + ) -> FieldInfo: + """Create `FieldInfo` from an annotation with a default value. + + This is used in cases like the following: + + ```python + from typing import Annotated + + import annotated_types + + import pydantic + + class MyModel(pydantic.BaseModel): + foo: int = 4 # <-- like this + bar: Annotated[int, annotated_types.Gt(4)] = 4 # <-- or this + spam: Annotated[int, pydantic.Field(gt=4)] = 4 # <-- or this + ``` + + Args: + annotation: The type annotation of the field. + default: The default value of the field. + + Returns: + A field object with the passed values. + """ + if annotation is not MISSING and annotation is default: + raise PydanticUserError( + 'Error when building FieldInfo from annotated attribute. ' + "Make sure you don't have any field name clashing with a type annotation.", + code='unevaluable-type-annotation', + ) + + try: + inspected_ann = inspect_annotation( + annotation, + annotation_source=_source, + unpack_type_aliases='skip', + ) + except ForbiddenQualifier as e: + raise PydanticForbiddenQualifier(e.qualifier, annotation) + + # TODO check for classvar and error? + + # TODO infer from the default, this can be done in v3 once we treat final fields with + # a default as proper fields and not class variables: + type_expr: Any = Any if inspected_ann.type is UNKNOWN else inspected_ann.type + final = 'final' in inspected_ann.qualifiers + metadata = inspected_ann.metadata + + # HACK 1: the order in which the metadata is merged is inconsistent; we need to prepend + # metadata from the assignment at the beginning of the metadata. Changing this is only + # possible in v3 (at least). See https://github.com/pydantic/pydantic/issues/10507 + prepend_metadata: list[Any] | None = None + attr_overrides = {'annotation': type_expr} + if final: + attr_overrides['frozen'] = True + + # HACK 2: FastAPI is subclassing `FieldInfo` and historically expected the actual + # instance's type to be preserved when constructing new models with its subclasses as assignments. + # This code is never reached by Pydantic itself, and in an ideal world this shouldn't be necessary. + if not metadata and isinstance(default, FieldInfo) and type(default) is not FieldInfo: + field_info = default._copy() + field_info._attributes_set.update(attr_overrides) + for k, v in attr_overrides.items(): + setattr(field_info, k, v) + return field_info + + if isinstance(default, FieldInfo): + default_copy = default._copy() # Copy unnecessary when we remove HACK 1. + prepend_metadata = default_copy.metadata + default_copy.metadata = [] + metadata = metadata + [default_copy] + if 'init_var' in inspected_ann.qualifiers: + # Only relevant for dataclasses, when `f: InitVar[] = Field(...)` + # is used: + attr_overrides['init_var'] = True + elif isinstance(default, dataclasses.Field): + from_field = FieldInfo._from_dataclass_field(default) + prepend_metadata = from_field.metadata # Unnecessary when we remove HACK 1. + from_field.metadata = [] + metadata = metadata + [from_field] + if 'init_var' in inspected_ann.qualifiers: + attr_overrides['init_var'] = True + if (init := getattr(default, 'init', None)) is not None: + attr_overrides['init'] = init + if (kw_only := getattr(default, 'kw_only', None)) is not None: + attr_overrides['kw_only'] = kw_only + else: + # `default` is the actual default value + attr_overrides['default'] = default + + field_info = FieldInfo._construct( + prepend_metadata + metadata if prepend_metadata is not None else metadata, **attr_overrides + ) + field_info._qualifiers = inspected_ann.qualifiers + field_info._final = True + return field_info + + @classmethod + def _construct(cls, metadata: list[Any], **attr_overrides: Any) -> Self: + """Construct the final `FieldInfo` instance, by merging the possibly existing `FieldInfo` instances from the metadata. + + With the following example: + + ```python {test="skip" lint="skip"} + class Model(BaseModel): + f: Annotated[int, Gt(1), Field(description='desc', lt=2)] + ``` + + `metadata` refers to the metadata elements of the `Annotated` form. This metadata is iterated over from left to right: + + - If the element is a `Field()` function (which is itself a `FieldInfo` instance), the field attributes (such as + `description`) are saved to be set on the final `FieldInfo` instance. + On the other hand, some kwargs (such as `lt`) are stored as `metadata` (see `FieldInfo.__init__()`, calling + `FieldInfo._collect_metadata()`). In this case, the final metadata list is extended with the one from this instance. + - Else, the element is considered as a single metadata object, and is appended to the final metadata list. + + Args: + metadata: The list of metadata elements to merge together. If the `FieldInfo` instance to be constructed is for + a field with an assigned `Field()`, this `Field()` assignment should be added as the last element of the + provided metadata. + **attr_overrides: Extra attributes that should be set on the final merged `FieldInfo` instance. + + Returns: + The final merged `FieldInfo` instance. + """ + merged_metadata: list[Any] = [] + merged_kwargs: dict[str, Any] = {} + + for meta in metadata: + if isinstance(meta, FieldInfo): + merged_metadata.extend(meta.metadata) + + new_js_extra: JsonDict | None = None + current_js_extra = meta.json_schema_extra + if current_js_extra is not None and 'json_schema_extra' in merged_kwargs: + # We need to merge `json_schema_extra`'s: + existing_js_extra = merged_kwargs['json_schema_extra'] + if isinstance(existing_js_extra, dict): + if isinstance(current_js_extra, dict): + new_js_extra = { + **existing_js_extra, + **current_js_extra, + } + elif callable(current_js_extra): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported. ' + 'The `callable` type is being ignored. ' + "If you'd like support for this behavior, please open an issue on pydantic.", + UserWarning, + ) + elif callable(existing_js_extra) and isinstance(current_js_extra, dict): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported. ' + 'The `callable` type is being ignored. ' + "If you'd like support for this behavior, please open an issue on pydantic.", + UserWarning, + ) + + # HACK: It is common for users to define "make model partial" (or similar) utilities, that + # convert all model fields to be optional (i.e. have a default value). To do so, they mutate + # each `FieldInfo` instance from `model_fields` to set a `default`, and use `create_model()` + # with `Annotated[ | None, mutated_field_info]`` as an annotation. However, such + # mutations (by doing simple assignments) are only accidentally working, because we also + # need to track attributes explicitly set in `_attributes_set` (relying on default values for + # each attribute is *not* enough, for instance with `Annotated[int, Field(alias='a'), Field(alias=None)]` + # the resulting `FieldInfo` should have `alias=None`). + # To mitigate this, we add a special case when a "final" `FieldInfo` instance (that is an instance coming + # from `model_fields`) is used in annotated metadata (or assignment). In this case, we assume *all* attributes + # were explicitly set, and as such we use all of them (and this will correctly pick up the mutations). + # In theory, this shouldn't really be supported, you are only supposed to use the `Field()` function, not + # a `FieldInfo` instance directly (granted, `Field()` returns a `FieldInfo`, see + # https://github.com/pydantic/pydantic/issues/11122): + if meta._final: + merged_kwargs.update({attr: getattr(meta, attr) for attr in _Attrs}) + else: + merged_kwargs.update(meta._attributes_set) + + if new_js_extra is not None: + merged_kwargs['json_schema_extra'] = new_js_extra + elif typing_objects.is_deprecated(meta): + merged_kwargs['deprecated'] = meta + else: + merged_metadata.append(meta) + + merged_kwargs.update(attr_overrides) + merged_field_info = cls(**merged_kwargs) + merged_field_info.metadata = merged_metadata + return merged_field_info + + @staticmethod + @typing_extensions.deprecated( + "The 'merge_field_infos()' method is deprecated and will be removed in a future version. " + 'If you relied on this method, please open an issue in the Pydantic issue tracker.', + category=None, + ) + def merge_field_infos(*field_infos: FieldInfo, **overrides: Any) -> FieldInfo: + """Merge `FieldInfo` instances keeping only explicitly set attributes. + + Later `FieldInfo` instances override earlier ones. + + Returns: + FieldInfo: A merged FieldInfo instance. + """ + if len(field_infos) == 1: + # No merging necessary, but we still need to make a copy and apply the overrides + field_info = field_infos[0]._copy() + field_info._attributes_set.update(overrides) + + default_override = overrides.pop('default', PydanticUndefined) + if default_override is Ellipsis: + default_override = PydanticUndefined + if default_override is not PydanticUndefined: + field_info.default = default_override + + for k, v in overrides.items(): + setattr(field_info, k, v) + return field_info # type: ignore + + merged_field_info_kwargs: dict[str, Any] = {} + metadata = {} + for field_info in field_infos: + attributes_set = field_info._attributes_set.copy() + + try: + json_schema_extra = attributes_set.pop('json_schema_extra') + existing_json_schema_extra = merged_field_info_kwargs.get('json_schema_extra') + + if existing_json_schema_extra is None: + merged_field_info_kwargs['json_schema_extra'] = json_schema_extra + if isinstance(existing_json_schema_extra, dict): + if isinstance(json_schema_extra, dict): + merged_field_info_kwargs['json_schema_extra'] = { + **existing_json_schema_extra, + **json_schema_extra, + } + if callable(json_schema_extra): + warn( + 'Composing `dict` and `callable` type `json_schema_extra` is not supported.' + 'The `callable` type is being ignored.' + "If you'd like support for this behavior, please open an issue on pydantic.", + PydanticJsonSchemaWarning, + ) + elif callable(json_schema_extra): + # if ever there's a case of a callable, we'll just keep the last json schema extra spec + merged_field_info_kwargs['json_schema_extra'] = json_schema_extra + except KeyError: + pass + + # later FieldInfo instances override everything except json_schema_extra from earlier FieldInfo instances + merged_field_info_kwargs.update(attributes_set) + + for x in field_info.metadata: + if not isinstance(x, FieldInfo): + metadata[type(x)] = x + + merged_field_info_kwargs.update(overrides) + field_info = FieldInfo(**merged_field_info_kwargs) + field_info.metadata = list(metadata.values()) + return field_info + + @staticmethod + def _from_dataclass_field(dc_field: DataclassField[Any]) -> FieldInfo: + """Return a new `FieldInfo` instance from a `dataclasses.Field` instance. + + Args: + dc_field: The `dataclasses.Field` instance to convert. + + Returns: + The corresponding `FieldInfo` instance. + + Raises: + TypeError: If any of the `FieldInfo` kwargs does not match the `dataclass.Field` kwargs. + """ + default = dc_field.default + if default is dataclasses.MISSING: + default = _Unset + + if dc_field.default_factory is dataclasses.MISSING: + default_factory = _Unset + else: + default_factory = dc_field.default_factory + + # use the `Field` function so in correct kwargs raise the correct `TypeError` + dc_field_metadata = {k: v for k, v in dc_field.metadata.items() if k in _FIELD_ARG_NAMES} + if sys.version_info >= (3, 14) and dc_field.doc is not None: + dc_field_metadata['description'] = dc_field.doc + return Field(default=default, default_factory=default_factory, repr=dc_field.repr, **dc_field_metadata) # pyright: ignore[reportCallIssue] + + @staticmethod + def _collect_metadata(kwargs: dict[str, Any]) -> list[Any]: + """Collect annotations from kwargs. + + Args: + kwargs: Keyword arguments passed to the function. + + Returns: + A list of metadata objects - a combination of `annotated_types.BaseMetadata` and + `PydanticMetadata`. + """ + metadata: list[Any] = [] + general_metadata = {} + for key, value in list(kwargs.items()): + try: + marker = FieldInfo.metadata_lookup[key] + except KeyError: + continue + + del kwargs[key] + if value is not None: + if marker is None: + general_metadata[key] = value + else: + metadata.append(marker(value)) + if general_metadata: + metadata.append(_fields.pydantic_general_metadata(**general_metadata)) + return metadata + + @property + def deprecation_message(self) -> str | None: + """The deprecation message to be emitted, or `None` if not set.""" + if self.deprecated is None: + return None + if isinstance(self.deprecated, bool): + return 'deprecated' if self.deprecated else None + return self.deprecated if isinstance(self.deprecated, str) else self.deprecated.message + + @property + def default_factory_takes_validated_data(self) -> bool | None: + """Whether the provided default factory callable has a validated data parameter. + + Returns `None` if no default factory is set. + """ + if self.default_factory is not None: + return _fields.takes_validated_data_argument(self.default_factory) + + @overload + def get_default( + self, *, call_default_factory: Literal[True], validated_data: dict[str, Any] | None = None + ) -> Any: ... + + @overload + def get_default(self, *, call_default_factory: Literal[False] = ...) -> Any: ... + + def get_default(self, *, call_default_factory: bool = False, validated_data: dict[str, Any] | None = None) -> Any: + """Get the default value. + + We expose an option for whether to call the default_factory (if present), as calling it may + result in side effects that we want to avoid. However, there are times when it really should + be called (namely, when instantiating a model via `model_construct`). + + Args: + call_default_factory: Whether to call the default factory or not. + validated_data: The already validated data to be passed to the default factory. + + Returns: + The default value, calling the default factory if requested or `PydanticUndefined` if not set. + """ + return _fields.resolve_default_value( + default=self.default, + default_factory=self.default_factory, + validated_data=validated_data, + call_default_factory=call_default_factory, + ) + + def is_required(self) -> bool: + """Check if the field is required (i.e., does not have a default value or factory). + + Returns: + `True` if the field is required, `False` otherwise. + """ + return self.default is PydanticUndefined and self.default_factory is None + + def rebuild_annotation(self) -> Any: + """Attempts to rebuild the original annotation for use in function signatures. + + If metadata is present, it adds it to the original annotation using + `Annotated`. Otherwise, it returns the original annotation as-is. + + Note that because the metadata has been flattened, the original annotation + may not be reconstructed exactly as originally provided, e.g. if the original + type had unrecognized annotations, or was annotated with a call to `pydantic.Field`. + + Returns: + The rebuilt annotation. + """ + if not self.metadata: + return self.annotation + else: + # Annotated arguments must be a tuple + return Annotated[(self.annotation, *self.metadata)] # type: ignore + + def apply_typevars_map( + self, + typevars_map: Mapping[TypeVar, Any] | None, + globalns: GlobalsNamespace | None = None, + localns: MappingNamespace | None = None, + ) -> None: + """Apply a `typevars_map` to the annotation. + + This method is used when analyzing parametrized generic types to replace typevars with their concrete types. + + This method applies the `typevars_map` to the annotation in place. + + Args: + typevars_map: A dictionary mapping type variables to their concrete types. + globalns: The globals namespace to use during type annotation evaluation. + localns: The locals namespace to use during type annotation evaluation. + + See Also: + pydantic._internal._generics.replace_types is used for replacing the typevars with + their concrete types. + """ + annotation = _generics.replace_types(self.annotation, typevars_map) + annotation, evaluated = _typing_extra.try_eval_type(annotation, globalns, localns) + self.annotation = annotation + if not evaluated: + self._complete = False + self._original_annotation = self.annotation + + def asdict(self) -> _FieldInfoAsDict: + """Return a dictionary representation of the `FieldInfo` instance. + + The returned value is a dictionary with three items: + + * `annotation`: The type annotation of the field. + * `metadata`: The metadata list. + * `attributes`: A mapping of the remaining `FieldInfo` attributes to their values (e.g. `alias`, `title`). + """ + return { + 'annotation': self.annotation, + 'metadata': self.metadata, + 'attributes': {attr: getattr(self, attr) for attr in _Attrs}, + } + + def _copy(self) -> Self: + """Return a copy of the `FieldInfo` instance.""" + # Note: we can't define a custom `__copy__()`, as `FieldInfo` is being subclassed + # by some third-party libraries with extra attributes defined (and as `FieldInfo` + # is slotted, we can't make a copy of the `__dict__`). + if type(self) is FieldInfo: + # Fast-path if the instance isn't a subclass (`copy.copy()` relies on pickling which is slower): + copied = FieldInfo.__new__(FieldInfo) + for attr_name in FieldInfo.__slots__: + setattr(copied, attr_name, getattr(self, attr_name)) + else: + copied = copy(self) + + for attr_name in ('metadata', '_attributes_set', '_qualifiers'): + # Apply "deep-copy" behavior on collections attributes: + setattr(copied, attr_name, getattr(copied, attr_name).copy()) + + return copied # pyright: ignore[reportReturnType] + + def __repr_args__(self) -> ReprArgs: + yield 'annotation', _repr.PlainRepr(_repr.display_as_type(self.annotation)) + yield 'required', self.is_required() + + for s in self.__slots__: + # TODO: properly make use of the protocol (https://rich.readthedocs.io/en/stable/pretty.html#rich-repr-protocol) + # By yielding a three-tuple: + if s in ( + 'annotation', + '_attributes_set', + '_qualifiers', + '_complete', + '_original_assignment', + '_original_annotation', + '_final', + ): + continue + elif s == 'metadata' and not self.metadata: + continue + elif s == 'repr' and self.repr is True: + continue + if s == 'frozen' and self.frozen is False: + continue + if s == 'validation_alias' and self.validation_alias == self.alias: + continue + if s == 'serialization_alias' and self.serialization_alias == self.alias: + continue + if s == 'default' and self.default is not PydanticUndefined: + yield 'default', self.default + elif s == 'default_factory' and self.default_factory is not None: + yield 'default_factory', _repr.PlainRepr(_repr.display_as_type(self.default_factory)) + else: + value = getattr(self, s) + if value is not None and value is not PydanticUndefined: + yield s, value + + +class _EmptyKwargs(TypedDict): + """This class exists solely to ensure that type checking warns about passing `**extra` in `Field`.""" + + +_Attrs = { + 'default': ..., + 'default_factory': None, + 'alias': None, + 'alias_priority': None, + 'validation_alias': None, + 'serialization_alias': None, + 'title': None, + 'field_title_generator': None, + 'description': None, + 'examples': None, + 'exclude': None, + 'exclude_if': None, + 'discriminator': None, + 'deprecated': None, + 'json_schema_extra': None, + 'frozen': None, + 'validate_default': None, + 'repr': True, + 'init': None, + 'init_var': None, + 'kw_only': None, +} + +_DefaultValues = { + **_Attrs, + 'kw_only': None, + 'pattern': None, + 'strict': None, + 'gt': None, + 'ge': None, + 'lt': None, + 'le': None, + 'multiple_of': None, + 'allow_inf_nan': None, + 'max_digits': None, + 'decimal_places': None, + 'min_length': None, + 'max_length': None, + 'coerce_numbers_to_str': None, +} + + +_T = TypeVar('_T') + + +# NOTE: Actual return type is 'FieldInfo', but we want to help type checkers +# to understand the magic that happens at runtime with the following overloads: +@overload # type hint the return value as `Any` to avoid type checking regressions when using `...`. +def Field( + default: ellipsis, # noqa: F821 # TODO: use `_typing_extra.EllipsisType` when we drop Py3.9 + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: bool | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +@overload # `default` argument set, validate_default=True (no type checking on the default value) +def Field( + default: Any, + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[True], + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +@overload # `default` argument set, validate_default=False or unset +def Field( + default: _T, + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + # NOTE: to get proper type checking on `exclude_if`'s argument, we could use `_T` instead of `Any`. However, + # this requires (at least for pyright) adding an additional overload where `exclude_if` is required (otherwise + # `a: int = Field(default_factory=str)` results in a false negative). + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[False] = ..., + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> _T: ... +@overload # `default_factory` argument set, validate_default=True (no type checking on the default value) +def Field( # pyright: ignore[reportOverlappingOverload] + *, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any], + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[True], + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +@overload # `default_factory` argument set, validate_default=False or unset +def Field( + *, + default_factory: Callable[[], _T] | Callable[[dict[str, Any]], _T], + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + # NOTE: to get proper type checking on `exclude_if`'s argument, we could use `_T` instead of `Any`. However, + # this requires (at least for pyright) adding an additional overload where `exclude_if` is required (otherwise + # `a: int = Field(default_factory=str)` results in a false negative). + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: Literal[False] | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> _T: ... +@overload +def Field( # No default set + *, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: bool | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: ... +def Field( # noqa: C901 + default: Any = PydanticUndefined, + *, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = _Unset, + alias: str | None = _Unset, + alias_priority: int | None = _Unset, + validation_alias: str | AliasPath | AliasChoices | None = _Unset, + serialization_alias: str | None = _Unset, + title: str | None = _Unset, + field_title_generator: Callable[[str, FieldInfo], str] | None = _Unset, + description: str | None = _Unset, + examples: list[Any] | None = _Unset, + exclude: bool | None = _Unset, + exclude_if: Callable[[Any], bool] | None = _Unset, + discriminator: str | types.Discriminator | None = _Unset, + deprecated: Deprecated | str | bool | None = _Unset, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = _Unset, + frozen: bool | None = _Unset, + validate_default: bool | None = _Unset, + repr: bool = _Unset, + init: bool | None = _Unset, + init_var: bool | None = _Unset, + kw_only: bool | None = _Unset, + pattern: str | re.Pattern[str] | None = _Unset, + strict: bool | None = _Unset, + coerce_numbers_to_str: bool | None = _Unset, + gt: annotated_types.SupportsGt | None = _Unset, + ge: annotated_types.SupportsGe | None = _Unset, + lt: annotated_types.SupportsLt | None = _Unset, + le: annotated_types.SupportsLe | None = _Unset, + multiple_of: float | None = _Unset, + allow_inf_nan: bool | None = _Unset, + max_digits: int | None = _Unset, + decimal_places: int | None = _Unset, + min_length: int | None = _Unset, + max_length: int | None = _Unset, + union_mode: Literal['smart', 'left_to_right'] = _Unset, + fail_fast: bool | None = _Unset, + **extra: Unpack[_EmptyKwargs], +) -> Any: + """!!! abstract "Usage Documentation" + [Fields](../concepts/fields.md) + + Create a field for objects that can be configured. + + Used to provide extra information about a field, either for the model schema or complex validation. Some arguments + apply only to number fields (`int`, `float`, `Decimal`) and some apply only to `str`. + + Note: + - Any `_Unset` objects will be replaced by the corresponding value defined in the `_DefaultValues` dictionary. If a key for the `_Unset` object is not found in the `_DefaultValues` dictionary, it will default to `None` + + Args: + default: Default value if the field is not set. + default_factory: A callable to generate the default value. The callable can either take 0 arguments + (in which case it is called as is) or a single argument containing the already validated data. + alias: The name to use for the attribute when validating or serializing by alias. + This is often used for things like converting between snake and camel case. + alias_priority: Priority of the alias. This affects whether an alias generator is used. + validation_alias: Like `alias`, but only affects validation, not serialization. + serialization_alias: Like `alias`, but only affects serialization, not validation. + title: Human-readable title. + field_title_generator: A callable that takes a field name and returns title for it. + description: Human-readable description. + examples: Example values for this field. + exclude: Whether to exclude the field from the model serialization. + exclude_if: A callable that determines whether to exclude a field during serialization based on its value. + discriminator: Field name or Discriminator for discriminating the type in a tagged union. + deprecated: A deprecation message, an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport, + or a boolean. If `True`, a default deprecation message will be emitted when accessing the field. + json_schema_extra: A dict or callable to provide extra JSON schema properties. + frozen: Whether the field is frozen. If true, attempts to change the value on an instance will raise an error. + validate_default: If `True`, apply validation to the default value every time you create an instance. + Otherwise, for performance reasons, the default value of the field is trusted and not validated. + repr: A boolean indicating whether to include the field in the `__repr__` output. + init: Whether the field should be included in the constructor of the dataclass. + (Only applies to dataclasses.) + init_var: Whether the field should _only_ be included in the constructor of the dataclass. + (Only applies to dataclasses.) + kw_only: Whether the field should be a keyword-only argument in the constructor of the dataclass. + (Only applies to dataclasses.) + coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode). + strict: If `True`, strict validation is applied to the field. + See [Strict Mode](../concepts/strict_mode.md) for details. + gt: Greater than. If set, value must be greater than this. Only applicable to numbers. + ge: Greater than or equal. If set, value must be greater than or equal to this. Only applicable to numbers. + lt: Less than. If set, value must be less than this. Only applicable to numbers. + le: Less than or equal. If set, value must be less than or equal to this. Only applicable to numbers. + multiple_of: Value must be a multiple of this. Only applicable to numbers. + min_length: Minimum length for iterables. + max_length: Maximum length for iterables. + pattern: Pattern for strings (a regular expression). + allow_inf_nan: Allow `inf`, `-inf`, `nan`. Only applicable to float and [`Decimal`][decimal.Decimal] numbers. + max_digits: Maximum number of allow digits for strings. + decimal_places: Maximum number of decimal places allowed for numbers. + union_mode: The strategy to apply when validating a union. Can be `smart` (the default), or `left_to_right`. + See [Union Mode](../concepts/unions.md#union-modes) for details. + fail_fast: If `True`, validation will stop on the first error. If `False`, all validation errors will be collected. + This option can be applied only to iterable types (list, tuple, set, and frozenset). + extra: (Deprecated) Extra fields that will be included in the JSON schema. + + !!! warning Deprecated + The `extra` kwargs is deprecated. Use `json_schema_extra` instead. + + Returns: + A new [`FieldInfo`][pydantic.fields.FieldInfo]. The return annotation is `Any` so `Field` can be used on + type-annotated fields without causing a type error. + """ + # Check deprecated and removed params from V1. This logic should eventually be removed. + const = extra.pop('const', None) # type: ignore + if const is not None: + raise PydanticUserError('`const` is removed, use `Literal` instead', code='removed-kwargs') + + min_items = extra.pop('min_items', None) # type: ignore + if min_items is not None: + warn( + '`min_items` is deprecated and will be removed, use `min_length` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if min_length in (None, _Unset): + min_length = min_items # type: ignore + + max_items = extra.pop('max_items', None) # type: ignore + if max_items is not None: + warn( + '`max_items` is deprecated and will be removed, use `max_length` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if max_length in (None, _Unset): + max_length = max_items # type: ignore + + unique_items = extra.pop('unique_items', None) # type: ignore + if unique_items is not None: + raise PydanticUserError( + ( + '`unique_items` is removed, use `Set` instead' + '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)' + ), + code='removed-kwargs', + ) + + allow_mutation = extra.pop('allow_mutation', None) # type: ignore + if allow_mutation is not None: + warn( + '`allow_mutation` is deprecated and will be removed. use `frozen` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if allow_mutation is False: + frozen = True + + regex = extra.pop('regex', None) # type: ignore + if regex is not None: + raise PydanticUserError('`regex` is removed. use `pattern` instead', code='removed-kwargs') + + if extra: + warn( + 'Using extra keyword arguments on `Field` is deprecated and will be removed.' + ' Use `json_schema_extra` instead.' + f' (Extra keys: {", ".join(k.__repr__() for k in extra.keys())})', + PydanticDeprecatedSince20, + stacklevel=2, + ) + if not json_schema_extra or json_schema_extra is _Unset: + json_schema_extra = extra # type: ignore + + if ( + validation_alias + and validation_alias is not _Unset + and not isinstance(validation_alias, (str, AliasChoices, AliasPath)) + ): + raise TypeError('Invalid `validation_alias` type. it should be `str`, `AliasChoices`, or `AliasPath`') + + if serialization_alias in (_Unset, None) and isinstance(alias, str): + serialization_alias = alias + + if validation_alias in (_Unset, None): + validation_alias = alias + + include = extra.pop('include', None) # type: ignore + if include is not None: + warn( + '`include` is deprecated and does nothing. It will be removed, use `exclude` instead', + PydanticDeprecatedSince20, + stacklevel=2, + ) + + return FieldInfo.from_field( + default, + default_factory=default_factory, + alias=alias, + alias_priority=alias_priority, + validation_alias=validation_alias, + serialization_alias=serialization_alias, + title=title, + field_title_generator=field_title_generator, + description=description, + examples=examples, + exclude=exclude, + exclude_if=exclude_if, + discriminator=discriminator, + deprecated=deprecated, + json_schema_extra=json_schema_extra, + frozen=frozen, + pattern=pattern, + validate_default=validate_default, + repr=repr, + init=init, + init_var=init_var, + kw_only=kw_only, + coerce_numbers_to_str=coerce_numbers_to_str, + strict=strict, + gt=gt, + ge=ge, + lt=lt, + le=le, + multiple_of=multiple_of, + min_length=min_length, + max_length=max_length, + allow_inf_nan=allow_inf_nan, + max_digits=max_digits, + decimal_places=decimal_places, + union_mode=union_mode, + fail_fast=fail_fast, + ) + + +_FIELD_ARG_NAMES = set(inspect.signature(Field).parameters) +_FIELD_ARG_NAMES.remove('extra') # do not include the varkwargs parameter + + +class ModelPrivateAttr(_repr.Representation): + """A descriptor for private attributes in class models. + + !!! warning + You generally shouldn't be creating `ModelPrivateAttr` instances directly, instead use + `pydantic.fields.PrivateAttr`. (This is similar to `FieldInfo` vs. `Field`.) + + Attributes: + default: The default value of the attribute if not provided. + default_factory: A callable to generate the default value. The callable can either take 0 arguments + (in which case it is called as is) or a single argument containing the validated data (the model's + [`__dict__`][object.__dict__]) and the already initialized private attributes. + """ + + __slots__ = ('default', 'default_factory') + + def __init__( + self, + default: Any = PydanticUndefined, + *, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = None, + ) -> None: + if default is Ellipsis: + self.default = PydanticUndefined + else: + self.default = default + self.default_factory = default_factory + + if not TYPE_CHECKING: + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + + def __getattr__(self, item: str) -> Any: + """This function improves compatibility with custom descriptors by ensuring delegation happens + as expected when the default value of a private attribute is a descriptor. + """ + if item in {'__get__', '__set__', '__delete__'}: + if hasattr(self.default, item): + return getattr(self.default, item) + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') + + def __set_name__(self, cls: type[Any], name: str) -> None: + """Preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487.""" + default = self.default + if default is PydanticUndefined: + return + set_name = getattr(default, '__set_name__', None) + if callable(set_name): + set_name(cls, name) + + @property + def default_factory_takes_validated_data(self) -> bool | None: + """Whether the provided default factory callable has a validated data parameter. + + Returns `None` if no default factory is set. + """ + if self.default_factory is not None: + return _fields.takes_validated_data_argument(self.default_factory) + + @overload + def get_default( + self, *, call_default_factory: Literal[True], validated_data: dict[str, Any] | None = None + ) -> Any: ... + + @overload + def get_default(self, *, call_default_factory: Literal[False] = ...) -> Any: ... + + def get_default(self, *, call_default_factory: bool = False, validated_data: dict[str, Any] | None = None) -> Any: + """Get the default value. + + We expose an option for whether to call the default_factory (if present), as calling it may + result in side effects that we want to avoid. However, there are times when it really should + be called (namely, when instantiating a model via `model_construct`). + + Args: + call_default_factory: Whether to call the default factory or not. + validated_data: The already validated data to be passed to the default factory. + + Returns: + The default value, calling the default factory if requested or `None` if not set. + """ + return _fields.resolve_default_value( + default=self.default, + default_factory=self.default_factory, + validated_data=validated_data, + call_default_factory=call_default_factory, + ) + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and (self.default, self.default_factory) == ( + other.default, + other.default_factory, + ) + + +# NOTE: Actual return type is 'ModelPrivateAttr', but we want to help type checkers +# to understand the magic that happens at runtime. +@overload # `default` argument set +def PrivateAttr( + default: _T, + *, + init: Literal[False] = False, +) -> _T: ... +@overload # `default_factory` argument set +def PrivateAttr( + *, + default_factory: Callable[[], _T] | Callable[[dict[str, Any]], _T], + init: Literal[False] = False, +) -> _T: ... +@overload # No default set +def PrivateAttr( + *, + init: Literal[False] = False, +) -> Any: ... +def PrivateAttr( + default: Any = PydanticUndefined, + *, + default_factory: Callable[[], Any] | Callable[[dict[str, Any]], Any] | None = None, + init: Literal[False] = False, +) -> Any: + """!!! abstract "Usage Documentation" + [Private Model Attributes](../concepts/models.md#private-model-attributes) + + Indicates that an attribute is intended for private use and not handled during normal validation/serialization. + + Private attributes are not validated by Pydantic, so it's up to you to ensure they are used in a type-safe manner. + + Private attributes are stored in `__private_attributes__` on the model. + + Args: + default: The attribute's default value. Defaults to Undefined. + default_factory: A callable to generate the default value. The callable can either take 0 arguments + (in which case it is called as is) or a single argument containing the validated data (the model's + [`__dict__`][object.__dict__]) and the already initialized private attributes. + If both `default` and `default_factory` are set, an error will be raised. + init: Whether the attribute should be included in the constructor of the dataclass. Always `False`. + + Returns: + An instance of [`ModelPrivateAttr`][pydantic.fields.ModelPrivateAttr] class. + + Raises: + ValueError: If both `default` and `default_factory` are set. + """ + if default is not PydanticUndefined and default_factory is not None: + raise TypeError('cannot specify both default and default_factory') + + return ModelPrivateAttr( + default, + default_factory=default_factory, + ) + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class ComputedFieldInfo: + """A container for data from `@computed_field` so that we can access it while building the pydantic-core schema. + + Attributes: + decorator_repr: A class variable representing the decorator string, '@computed_field'. + wrapped_property: The wrapped computed field property. + return_type: The type of the computed field property's return value. + alias: The alias of the property to be used during serialization. + alias_priority: The priority of the alias. This affects whether an alias generator is used. + title: Title of the computed field to include in the serialization JSON schema. + field_title_generator: A callable that takes a field name and returns title for it. + description: Description of the computed field to include in the serialization JSON schema. + deprecated: A deprecation message, an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport, + or a boolean. If `True`, a default deprecation message will be emitted when accessing the field. + examples: Example values of the computed field to include in the serialization JSON schema. + json_schema_extra: A dict or callable to provide extra JSON schema properties. + repr: A boolean indicating whether to include the field in the __repr__ output. + """ + + decorator_repr: ClassVar[str] = '@computed_field' + wrapped_property: property + return_type: Any + alias: str | None + alias_priority: int | None + exclude_if: Callable[[Any], bool] | None + title: str | None + field_title_generator: Callable[[str, ComputedFieldInfo], str] | None + description: str | None + deprecated: Deprecated | str | bool | None + examples: list[Any] | None + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None + repr: bool + # NOTE: if you add a new field, add it to the `__copy__()` implementation. + + def __copy__(self) -> Self: + return type(self)( + wrapped_property=self.wrapped_property, + return_type=self.return_type, + alias=self.alias, + alias_priority=self.alias_priority, + exclude_if=self.exclude_if, + title=self.title, + field_title_generator=self.field_title_generator, + description=self.description, + deprecated=self.deprecated, + examples=self.examples.copy() if isinstance(self.examples, list) else self.examples, + json_schema_extra=self.json_schema_extra.copy() + if isinstance(self.json_schema_extra, dict) + else self.json_schema_extra, + repr=self.repr, + ) + + @property + def deprecation_message(self) -> str | None: + """The deprecation message to be emitted, or `None` if not set.""" + if self.deprecated is None: + return None + if isinstance(self.deprecated, bool): + return 'deprecated' if self.deprecated else None + return self.deprecated if isinstance(self.deprecated, str) else self.deprecated.message + + def _update_from_config(self, config_wrapper: ConfigWrapper, name: str) -> None: + """Update the instance from the configuration set on the class this computed field belongs to.""" + title_generator = self.field_title_generator or config_wrapper.field_title_generator + if title_generator is not None and self.title is None: + self.title = title_generator(name, self) + if config_wrapper.alias_generator is not None: + self._apply_alias_generator(config_wrapper.alias_generator, name) + + def _apply_alias_generator(self, alias_generator: Callable[[str], str] | AliasGenerator, name: str) -> None: + """Apply an alias generator to aliases if appropriate. + + Args: + alias_generator: A callable that takes a string and returns a string, or an `AliasGenerator` instance. + name: The name of the computed field from which to generate the alias. + """ + # Apply an alias_generator if + # 1. An alias is not specified + # 2. An alias is specified, but the priority is <= 1 + + if self.alias_priority is None or self.alias_priority <= 1 or self.alias is None: + alias, _, serialization_alias = None, None, None + + if isinstance(alias_generator, AliasGenerator): + alias, _, serialization_alias = alias_generator.generate_aliases(name) + elif callable(alias_generator): + alias = alias_generator(name) + + # if priority is not set, we set to 1 + # which supports the case where the alias_generator from a child class is used + # to generate an alias for a field in a parent class + if self.alias_priority is None or self.alias_priority <= 1: + self.alias_priority = 1 + + # if the priority is 1, then we set the aliases to the generated alias + # note that we use the serialization_alias with priority over alias, as computed_field + # aliases are used for serialization only (not validation) + if self.alias_priority == 1: + self.alias = _utils.get_first_not_none(serialization_alias, alias) + + +def _wrapped_property_is_private(property_: cached_property | property) -> bool: # type: ignore + """Returns true if provided property is private, False otherwise.""" + wrapped_name: str = '' + + if isinstance(property_, property): + wrapped_name = getattr(property_.fget, '__name__', '') + elif isinstance(property_, cached_property): # type: ignore + wrapped_name = getattr(property_.func, '__name__', '') # type: ignore + + return wrapped_name.startswith('_') and not wrapped_name.startswith('__') + + +# this should really be `property[T], cached_property[T]` but property is not generic unlike cached_property +# See https://github.com/python/typing/issues/985 and linked issues +PropertyT = TypeVar('PropertyT') + + +@overload +def computed_field(func: PropertyT, /) -> PropertyT: ... + + +@overload +def computed_field( + *, + alias: str | None = None, + alias_priority: int | None = None, + exclude_if: Callable[[Any], bool] | None = None, + title: str | None = None, + field_title_generator: Callable[[str, ComputedFieldInfo], str] | None = None, + description: str | None = None, + deprecated: Deprecated | str | bool | None = None, + examples: list[Any] | None = None, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = None, + repr: bool = True, + return_type: Any = PydanticUndefined, +) -> Callable[[PropertyT], PropertyT]: ... + + +def computed_field( + func: PropertyT | None = None, + /, + *, + alias: str | None = None, + alias_priority: int | None = None, + exclude_if: Callable[[Any], bool] | None = None, + title: str | None = None, + field_title_generator: Callable[[str, ComputedFieldInfo], str] | None = None, + description: str | None = None, + deprecated: Deprecated | str | bool | None = None, + examples: list[Any] | None = None, + json_schema_extra: JsonDict | Callable[[JsonDict], None] | None = None, + repr: bool | None = None, + return_type: Any = PydanticUndefined, +) -> PropertyT | Callable[[PropertyT], PropertyT]: + """!!! abstract "Usage Documentation" + [The `computed_field` decorator](../concepts/fields.md#the-computed_field-decorator) + + Decorator to include `property` and `cached_property` when serializing models or dataclasses. + + This is useful for fields that are computed from other fields, or for fields that are expensive to compute and should be cached. + + ```python + from pydantic import BaseModel, computed_field + + class Rectangle(BaseModel): + width: int + length: int + + @computed_field + @property + def area(self) -> int: + return self.width * self.length + + print(Rectangle(width=3, length=2).model_dump()) + #> {'width': 3, 'length': 2, 'area': 6} + ``` + + If applied to functions not yet decorated with `@property` or `@cached_property`, the function is + automatically wrapped with `property`. Although this is more concise, you will lose IntelliSense in your IDE, + and confuse static type checkers, thus explicit use of `@property` is recommended. + + !!! warning "Mypy Warning" + Even with the `@property` or `@cached_property` applied to your function before `@computed_field`, + mypy may throw a `Decorated property not supported` error. + See [mypy issue #1362](https://github.com/python/mypy/issues/1362), for more information. + To avoid this error message, add `# type: ignore[prop-decorator]` to the `@computed_field` line. + + [pyright](https://github.com/microsoft/pyright) supports `@computed_field` without error. + + ```python + import random + + from pydantic import BaseModel, computed_field + + class Square(BaseModel): + width: float + + @computed_field + def area(self) -> float: # converted to a `property` by `computed_field` + return round(self.width**2, 2) + + @area.setter + def area(self, new_area: float) -> None: + self.width = new_area**0.5 + + @computed_field(alias='the magic number', repr=False) + def random_number(self) -> int: + return random.randint(0, 1_000) + + square = Square(width=1.3) + + # `random_number` does not appear in representation + print(repr(square)) + #> Square(width=1.3, area=1.69) + + print(square.random_number) + #> 3 + + square.area = 4 + + print(square.model_dump_json(by_alias=True)) + #> {"width":2.0,"area":4.0,"the magic number":3} + ``` + + !!! warning "Overriding with `computed_field`" + You can't override a field from a parent class with a `computed_field` in the child class. + `mypy` complains about this behavior if allowed, and `dataclasses` doesn't allow this pattern either. + See the example below: + + ```python + from pydantic import BaseModel, computed_field + + class Parent(BaseModel): + a: str + + try: + + class Child(Parent): + @computed_field + @property + def a(self) -> str: + return 'new a' + + except TypeError as e: + print(e) + ''' + Field 'a' of class 'Child' overrides symbol of same name in a parent class. This override with a computed_field is incompatible. + ''' + ``` + + Private properties decorated with `@computed_field` have `repr=False` by default. + + ```python + from functools import cached_property + + from pydantic import BaseModel, computed_field + + class Model(BaseModel): + foo: int + + @computed_field + @cached_property + def _private_cached_property(self) -> int: + return -self.foo + + @computed_field + @property + def _private_property(self) -> int: + return -self.foo + + m = Model(foo=1) + print(repr(m)) + #> Model(foo=1) + ``` + + Args: + func: the function to wrap. + alias: alias to use when serializing this computed field, only used when `by_alias=True` + alias_priority: priority of the alias. This affects whether an alias generator is used + exclude_if: A callable that determines whether to exclude this computed field during serialization based on its value. + title: Title to use when including this computed field in JSON Schema + field_title_generator: A callable that takes a field name and returns title for it. + description: Description to use when including this computed field in JSON Schema, defaults to the function's + docstring + deprecated: A deprecation message (or an instance of `warnings.deprecated` or the `typing_extensions.deprecated` backport). + to be emitted when accessing the field. Or a boolean. This will automatically be set if the property is decorated with the + `deprecated` decorator. + examples: Example values to use when including this computed field in JSON Schema + json_schema_extra: A dict or callable to provide extra JSON schema properties. + repr: whether to include this computed field in model repr. + Default is `False` for private properties and `True` for public properties. + return_type: optional return for serialization logic to expect when serializing to JSON, if included + this must be correct, otherwise a `TypeError` is raised. + If you don't include a return type Any is used, which does runtime introspection to handle arbitrary + objects. + + Returns: + A proxy wrapper for the property. + """ + + def dec(f: Any) -> Any: + nonlocal description, deprecated, return_type, alias_priority + unwrapped = _decorators.unwrap_wrapped_function(f) + + if description is None and unwrapped.__doc__: + description = inspect.cleandoc(unwrapped.__doc__) + + if deprecated is None and hasattr(unwrapped, '__deprecated__'): + deprecated = unwrapped.__deprecated__ + + # if the function isn't already decorated with `@property` (or another descriptor), then we wrap it now + f = _decorators.ensure_property(f) + alias_priority = (alias_priority or 2) if alias is not None else None + + if repr is None: + repr_: bool = not _wrapped_property_is_private(property_=f) + else: + repr_ = repr + + dec_info = ComputedFieldInfo( + f, + return_type, + alias, + alias_priority, + exclude_if, + title, + field_title_generator, + description, + deprecated, + examples, + json_schema_extra, + repr_, + ) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + if func is None: + return dec + else: + return dec(func) diff --git a/source/target-vendors/cp312/pydantic/functional_serializers.py b/source/target-vendors/cp312/pydantic/functional_serializers.py new file mode 100644 index 0000000..ed63336 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/functional_serializers.py @@ -0,0 +1,470 @@ +"""This module contains related classes and functions for serialization.""" + +from __future__ import annotations + +import dataclasses +from functools import partial, partialmethod +from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, overload + +from pydantic_core import PydanticUndefined, core_schema +from pydantic_core.core_schema import SerializationInfo, SerializerFunctionWrapHandler, WhenUsed +from typing_extensions import TypeAlias + +from . import PydanticUndefinedAnnotation +from ._internal import _decorators, _internal_dataclass +from .annotated_handlers import GetCoreSchemaHandler +from .errors import PydanticUserError + + +@dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class PlainSerializer: + """Plain serializers use a function to modify the output of serialization. + + This is particularly helpful when you want to customize the serialization for annotated types. + Consider an input of `list`, which will be serialized into a space-delimited string. + + ```python + from typing import Annotated + + from pydantic import BaseModel, PlainSerializer + + CustomStr = Annotated[ + list, PlainSerializer(lambda x: ' '.join(x), return_type=str) + ] + + class StudentModel(BaseModel): + courses: CustomStr + + student = StudentModel(courses=['Math', 'Chemistry', 'English']) + print(student.model_dump()) + #> {'courses': 'Math Chemistry English'} + ``` + + Attributes: + func: The serializer function. + return_type: The return type for the function. If omitted it will be inferred from the type annotation. + when_used: Determines when this serializer should be used. Accepts a string with values `'always'`, + `'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'. + """ + + func: core_schema.SerializerFunction + return_type: Any = PydanticUndefined + when_used: WhenUsed = 'always' + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + """Gets the Pydantic core schema. + + Args: + source_type: The source type. + handler: The `GetCoreSchemaHandler` instance. + + Returns: + The Pydantic core schema. + """ + schema = handler(source_type) + if self.return_type is not PydanticUndefined: + return_type = self.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + self.func, + localns=handler._get_types_namespace().locals, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type) + schema['serialization'] = core_schema.plain_serializer_function_ser_schema( + function=self.func, + info_arg=_decorators.inspect_annotated_serializer(self.func, 'plain'), + return_schema=return_schema, + when_used=self.when_used, + ) + return schema + + +@dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class WrapSerializer: + """Wrap serializers receive the raw inputs along with a handler function that applies the standard serialization + logic, and can modify the resulting value before returning it as the final output of serialization. + + For example, here's a scenario in which a wrap serializer transforms timezones to UTC **and** utilizes the existing `datetime` serialization logic. + + ```python + from datetime import datetime, timezone + from typing import Annotated, Any + + from pydantic import BaseModel, WrapSerializer + + class EventDatetime(BaseModel): + start: datetime + end: datetime + + def convert_to_utc(value: Any, handler, info) -> dict[str, datetime]: + # Note that `handler` can actually help serialize the `value` for + # further custom serialization in case it's a subclass. + partial_result = handler(value, info) + if info.mode == 'json': + return { + k: datetime.fromisoformat(v).astimezone(timezone.utc) + for k, v in partial_result.items() + } + return {k: v.astimezone(timezone.utc) for k, v in partial_result.items()} + + UTCEventDatetime = Annotated[EventDatetime, WrapSerializer(convert_to_utc)] + + class EventModel(BaseModel): + event_datetime: UTCEventDatetime + + dt = EventDatetime( + start='2024-01-01T07:00:00-08:00', end='2024-01-03T20:00:00+06:00' + ) + event = EventModel(event_datetime=dt) + print(event.model_dump()) + ''' + { + 'event_datetime': { + 'start': datetime.datetime( + 2024, 1, 1, 15, 0, tzinfo=datetime.timezone.utc + ), + 'end': datetime.datetime( + 2024, 1, 3, 14, 0, tzinfo=datetime.timezone.utc + ), + } + } + ''' + + print(event.model_dump_json()) + ''' + {"event_datetime":{"start":"2024-01-01T15:00:00Z","end":"2024-01-03T14:00:00Z"}} + ''' + ``` + + Attributes: + func: The serializer function to be wrapped. + return_type: The return type for the function. If omitted it will be inferred from the type annotation. + when_used: Determines when this serializer should be used. Accepts a string with values `'always'`, + `'unless-none'`, `'json'`, and `'json-unless-none'`. Defaults to 'always'. + """ + + func: core_schema.WrapSerializerFunction + return_type: Any = PydanticUndefined + when_used: WhenUsed = 'always' + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + """This method is used to get the Pydantic core schema of the class. + + Args: + source_type: Source type. + handler: Core schema handler. + + Returns: + The generated core schema of the class. + """ + schema = handler(source_type) + if self.return_type is not PydanticUndefined: + return_type = self.return_type + else: + try: + # Do not pass in globals as the function could be defined in a different module. + # Instead, let `get_callable_return_type` infer the globals to use, but still pass + # in locals that may contain a parent/rebuild namespace: + return_type = _decorators.get_callable_return_type( + self.func, + localns=handler._get_types_namespace().locals, + ) + except NameError as e: + raise PydanticUndefinedAnnotation.from_name_error(e) from e + + return_schema = None if return_type is PydanticUndefined else handler.generate_schema(return_type) + schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( + function=self.func, + info_arg=_decorators.inspect_annotated_serializer(self.func, 'wrap'), + return_schema=return_schema, + when_used=self.when_used, + ) + return schema + + +if TYPE_CHECKING: + _Partial: TypeAlias = 'partial[Any] | partialmethod[Any]' + + FieldPlainSerializer: TypeAlias = 'core_schema.SerializerFunction | _Partial' + """A field serializer method or function in `plain` mode.""" + + FieldWrapSerializer: TypeAlias = 'core_schema.WrapSerializerFunction | _Partial' + """A field serializer method or function in `wrap` mode.""" + + FieldSerializer: TypeAlias = 'FieldPlainSerializer | FieldWrapSerializer' + """A field serializer method or function.""" + + _FieldPlainSerializerT = TypeVar('_FieldPlainSerializerT', bound=FieldPlainSerializer) + _FieldWrapSerializerT = TypeVar('_FieldWrapSerializerT', bound=FieldWrapSerializer) + + +@overload +def field_serializer( + field: str, + /, + *fields: str, + mode: Literal['wrap'], + return_type: Any = ..., + when_used: WhenUsed = ..., + check_fields: bool | None = ..., +) -> Callable[[_FieldWrapSerializerT], _FieldWrapSerializerT]: ... + + +@overload +def field_serializer( + field: str, + /, + *fields: str, + mode: Literal['plain'] = ..., + return_type: Any = ..., + when_used: WhenUsed = ..., + check_fields: bool | None = ..., +) -> Callable[[_FieldPlainSerializerT], _FieldPlainSerializerT]: ... + + +def field_serializer( # noqa: D417 + field: str, + /, + *fields: str, + mode: Literal['plain', 'wrap'] = 'plain', + # TODO PEP 747 (grep for 'return_type' on the whole code base): + return_type: Any = PydanticUndefined, + when_used: WhenUsed = 'always', + check_fields: bool | None = None, +) -> ( + Callable[[_FieldWrapSerializerT], _FieldWrapSerializerT] + | Callable[[_FieldPlainSerializerT], _FieldPlainSerializerT] +): + """Decorator that enables custom field serialization. + + In the below example, a field of type `set` is used to mitigate duplication. A `field_serializer` is used to serialize the data as a sorted list. + + ```python + from pydantic import BaseModel, field_serializer + + class StudentModel(BaseModel): + name: str = 'Jane' + courses: set[str] + + @field_serializer('courses', when_used='json') + def serialize_courses_in_order(self, courses: set[str]): + return sorted(courses) + + student = StudentModel(courses={'Math', 'Chemistry', 'English'}) + print(student.model_dump_json()) + #> {"name":"Jane","courses":["Chemistry","English","Math"]} + ``` + + See [the usage documentation](../concepts/serialization.md#serializers) for more information. + + Four signatures are supported for the decorated serializer: + + - `(self, value: Any, info: FieldSerializationInfo)` + - `(self, value: Any, nxt: SerializerFunctionWrapHandler, info: FieldSerializationInfo)` + - `(value: Any, info: SerializationInfo)` + - `(value: Any, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)` + + Args: + *fields: The field names the serializer should apply to. + mode: The serialization mode. + + - `plain` means the function will be called instead of the default serialization logic, + - `wrap` means the function will be called with an argument to optionally call the + default serialization logic. + return_type: Optional return type for the function, if omitted it will be inferred from the type annotation. + when_used: Determines the serializer will be used for serialization. + check_fields: Whether to check that the fields actually exist on the model. + + Raises: + PydanticUserError: + - If the decorator is used without any arguments (at least one field name must be provided). + - If the provided field names are not strings. + """ + if callable(field) or isinstance(field, classmethod): + raise PydanticUserError( + 'The `@field_serializer` decorator cannot be used without arguments, at least one field must be provided. ' + "For example: `@field_serializer('', ...)`.", + code='decorator-missing-arguments', + ) + + fields = field, *fields + if not all(isinstance(field, str) for field in fields): + raise PydanticUserError( + 'The provided field names to the `@field_serializer` decorator should be strings. ' + "For example: `@field_serializer('', '', ...).`", + code='decorator-invalid-fields', + ) + + def dec(f: FieldSerializer) -> _decorators.PydanticDescriptorProxy[Any]: + dec_info = _decorators.FieldSerializerDecoratorInfo( + fields=fields, + mode=mode, + return_type=return_type, + when_used=when_used, + check_fields=check_fields, + ) + return _decorators.PydanticDescriptorProxy(f, dec_info) # pyright: ignore[reportArgumentType] + + return dec # pyright: ignore[reportReturnType] + + +if TYPE_CHECKING: + # The first argument in the following callables represent the `self` type: + + ModelPlainSerializerWithInfo: TypeAlias = Callable[[Any, SerializationInfo[Any]], Any] + """A model serializer method with the `info` argument, in `plain` mode.""" + + ModelPlainSerializerWithoutInfo: TypeAlias = Callable[[Any], Any] + """A model serializer method without the `info` argument, in `plain` mode.""" + + ModelPlainSerializer: TypeAlias = 'ModelPlainSerializerWithInfo | ModelPlainSerializerWithoutInfo' + """A model serializer method in `plain` mode.""" + + ModelWrapSerializerWithInfo: TypeAlias = Callable[[Any, SerializerFunctionWrapHandler, SerializationInfo[Any]], Any] + """A model serializer method with the `info` argument, in `wrap` mode.""" + + ModelWrapSerializerWithoutInfo: TypeAlias = Callable[[Any, SerializerFunctionWrapHandler], Any] + """A model serializer method without the `info` argument, in `wrap` mode.""" + + ModelWrapSerializer: TypeAlias = 'ModelWrapSerializerWithInfo | ModelWrapSerializerWithoutInfo' + """A model serializer method in `wrap` mode.""" + + ModelSerializer: TypeAlias = 'ModelPlainSerializer | ModelWrapSerializer' + + _ModelPlainSerializerT = TypeVar('_ModelPlainSerializerT', bound=ModelPlainSerializer) + _ModelWrapSerializerT = TypeVar('_ModelWrapSerializerT', bound=ModelWrapSerializer) + + +@overload +def model_serializer(f: _ModelPlainSerializerT, /) -> _ModelPlainSerializerT: ... + + +@overload +def model_serializer( + *, mode: Literal['wrap'], when_used: WhenUsed = 'always', return_type: Any = ... +) -> Callable[[_ModelWrapSerializerT], _ModelWrapSerializerT]: ... + + +@overload +def model_serializer( + *, + mode: Literal['plain'] = ..., + when_used: WhenUsed = 'always', + return_type: Any = ..., +) -> Callable[[_ModelPlainSerializerT], _ModelPlainSerializerT]: ... + + +def model_serializer( + f: _ModelPlainSerializerT | _ModelWrapSerializerT | None = None, + /, + *, + mode: Literal['plain', 'wrap'] = 'plain', + when_used: WhenUsed = 'always', + return_type: Any = PydanticUndefined, +) -> ( + _ModelPlainSerializerT + | Callable[[_ModelWrapSerializerT], _ModelWrapSerializerT] + | Callable[[_ModelPlainSerializerT], _ModelPlainSerializerT] +): + """Decorator that enables custom model serialization. + + This is useful when a model need to be serialized in a customized manner, allowing for flexibility beyond just specific fields. + + An example would be to serialize temperature to the same temperature scale, such as degrees Celsius. + + ```python + from typing import Literal + + from pydantic import BaseModel, model_serializer + + class TemperatureModel(BaseModel): + unit: Literal['C', 'F'] + value: int + + @model_serializer() + def serialize_model(self): + if self.unit == 'F': + return {'unit': 'C', 'value': int((self.value - 32) / 1.8)} + return {'unit': self.unit, 'value': self.value} + + temperature = TemperatureModel(unit='F', value=212) + print(temperature.model_dump()) + #> {'unit': 'C', 'value': 100} + ``` + + Two signatures are supported for `mode='plain'`, which is the default: + + - `(self)` + - `(self, info: SerializationInfo)` + + And two other signatures for `mode='wrap'`: + + - `(self, nxt: SerializerFunctionWrapHandler)` + - `(self, nxt: SerializerFunctionWrapHandler, info: SerializationInfo)` + + See [the usage documentation](../concepts/serialization.md#serializers) for more information. + + Args: + f: The function to be decorated. + mode: The serialization mode. + + - `'plain'` means the function will be called instead of the default serialization logic + - `'wrap'` means the function will be called with an argument to optionally call the default + serialization logic. + when_used: Determines when this serializer should be used. + return_type: The return type for the function. If omitted it will be inferred from the type annotation. + + Returns: + The decorator function. + """ + + def dec(f: ModelSerializer) -> _decorators.PydanticDescriptorProxy[Any]: + dec_info = _decorators.ModelSerializerDecoratorInfo(mode=mode, return_type=return_type, when_used=when_used) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + if f is None: + return dec # pyright: ignore[reportReturnType] + else: + return dec(f) # pyright: ignore[reportReturnType] + + +AnyType = TypeVar('AnyType') + + +if TYPE_CHECKING: + SerializeAsAny = Annotated[AnyType, ...] # SerializeAsAny[list[str]] will be treated by type checkers as list[str] + """Annotation used to mark a type as having duck-typing serialization behavior. + + See [usage documentation](../concepts/serialization.md#serializing-with-duck-typing) for more details. + """ +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class SerializeAsAny: + """Annotation used to mark a type as having duck-typing serialization behavior. + + See [usage documentation](../concepts/serialization.md#serializing-with-duck-typing) for more details. + """ + + def __class_getitem__(cls, item: Any) -> Any: + return Annotated[item, SerializeAsAny()] + + def __get_pydantic_core_schema__( + self, source_type: Any, handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + schema = handler(source_type) + schema_to_update = schema + while schema_to_update['type'] == 'definitions': + schema_to_update = schema_to_update.copy() + schema_to_update = schema_to_update['schema'] + schema_to_update['serialization'] = core_schema.simple_ser_schema('any') + return schema + + __hash__ = object.__hash__ diff --git a/source/target-vendors/cp312/pydantic/functional_validators.py b/source/target-vendors/cp312/pydantic/functional_validators.py new file mode 100644 index 0000000..558e99c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/functional_validators.py @@ -0,0 +1,889 @@ +"""This module contains related classes and functions for validation.""" + +from __future__ import annotations as _annotations + +import dataclasses +import sys +import warnings +from functools import partialmethod +from typing import TYPE_CHECKING, Annotated, Any, Callable, Literal, TypeVar, Union, cast, overload + +from pydantic_core import PydanticUndefined, core_schema +from typing_extensions import Self, TypeAlias + +from ._internal import _decorators, _generics, _internal_dataclass +from .annotated_handlers import GetCoreSchemaHandler +from .errors import PydanticUserError +from .version import version_short +from .warnings import ArbitraryTypeWarning, PydanticDeprecatedSince212 + +if sys.version_info < (3, 11): + from typing_extensions import Protocol +else: + from typing import Protocol + +_inspect_validator = _decorators.inspect_validator + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class AfterValidator: + """!!! abstract "Usage Documentation" + [field *after* validators](../concepts/validators.md#field-after-validator) + + A metadata class that indicates that a validation should be applied **after** the inner validation logic. + + Attributes: + func: The validator function. + + Example: + ```python + from typing import Annotated + + from pydantic import AfterValidator, BaseModel, ValidationError + + MyInt = Annotated[int, AfterValidator(lambda v: v + 1)] + + class Model(BaseModel): + a: MyInt + + print(Model(a=1).a) + #> 2 + + try: + Model(a='a') + except ValidationError as e: + print(e.json(indent=2)) + ''' + [ + { + "type": "int_parsing", + "loc": [ + "a" + ], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "input": "a", + "url": "https://errors.pydantic.dev/2/v/int_parsing" + } + ] + ''' + ``` + """ + + func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + info_arg = _inspect_validator(self.func, mode='after', type='field') + if info_arg: + func = cast(core_schema.WithInfoValidatorFunction, self.func) + return core_schema.with_info_after_validator_function(func, schema=schema) + else: + func = cast(core_schema.NoInfoValidatorFunction, self.func) + return core_schema.no_info_after_validator_function(func, schema=schema) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls(func=decorator.func) + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class BeforeValidator: + """!!! abstract "Usage Documentation" + [field *before* validators](../concepts/validators.md#field-before-validator) + + A metadata class that indicates that a validation should be applied **before** the inner validation logic. + + Attributes: + func: The validator function. + json_schema_input_type: The input type used to generate the appropriate + JSON Schema (in validation mode). The actual input type is `Any`. + + Example: + ```python + from typing import Annotated + + from pydantic import BaseModel, BeforeValidator + + MyInt = Annotated[int, BeforeValidator(lambda v: v + 1)] + + class Model(BaseModel): + a: MyInt + + print(Model(a=1).a) + #> 2 + + try: + Model(a='a') + except TypeError as e: + print(e) + #> can only concatenate str (not "int") to str + ``` + """ + + func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction + json_schema_input_type: Any = PydanticUndefined + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + input_schema = ( + None + if self.json_schema_input_type is PydanticUndefined + else handler.generate_schema(self.json_schema_input_type) + ) + + info_arg = _inspect_validator(self.func, mode='before', type='field') + if info_arg: + func = cast(core_schema.WithInfoValidatorFunction, self.func) + return core_schema.with_info_before_validator_function( + func, + schema=schema, + json_schema_input_schema=input_schema, + ) + else: + func = cast(core_schema.NoInfoValidatorFunction, self.func) + return core_schema.no_info_before_validator_function( + func, schema=schema, json_schema_input_schema=input_schema + ) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls( + func=decorator.func, + json_schema_input_type=decorator.info.json_schema_input_type, + ) + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class PlainValidator: + """!!! abstract "Usage Documentation" + [field *plain* validators](../concepts/validators.md#field-plain-validator) + + A metadata class that indicates that a validation should be applied **instead** of the inner validation logic. + + !!! note + Before v2.9, `PlainValidator` wasn't always compatible with JSON Schema generation for `mode='validation'`. + You can now use the `json_schema_input_type` argument to specify the input type of the function + to be used in the JSON schema when `mode='validation'` (the default). See the example below for more details. + + Attributes: + func: The validator function. + json_schema_input_type: The input type used to generate the appropriate + JSON Schema (in validation mode). The actual input type is `Any`. + + Example: + ```python + from typing import Annotated, Union + + from pydantic import BaseModel, PlainValidator + + def validate(v: object) -> int: + if not isinstance(v, (int, str)): + raise ValueError(f'Expected int or str, got {type(v)}') + + return int(v) + 1 + + MyInt = Annotated[ + int, + PlainValidator(validate, json_schema_input_type=Union[str, int]), # (1)! + ] + + class Model(BaseModel): + a: MyInt + + print(Model(a='1').a) + #> 2 + + print(Model(a=1).a) + #> 2 + ``` + + 1. In this example, we've specified the `json_schema_input_type` as `Union[str, int]` which indicates to the JSON schema + generator that in validation mode, the input type for the `a` field can be either a [`str`][] or an [`int`][]. + """ + + func: core_schema.NoInfoValidatorFunction | core_schema.WithInfoValidatorFunction + json_schema_input_type: Any = Any + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + # Note that for some valid uses of PlainValidator, it is not possible to generate a core schema for the + # source_type, so calling `handler(source_type)` will error, which prevents us from generating a proper + # serialization schema. To work around this for use cases that will not involve serialization, we simply + # catch any PydanticSchemaGenerationError that may be raised while attempting to build the serialization schema + # and abort any attempts to handle special serialization. + from pydantic import PydanticSchemaGenerationError + + try: + schema = handler(source_type) + # TODO if `schema['serialization']` is one of `'include-exclude-dict/sequence', + # schema validation will fail. That's why we use 'type ignore' comments below. + serialization = schema.get( + 'serialization', + core_schema.wrap_serializer_function_ser_schema( + function=lambda v, h: h(v), + schema=schema, + return_schema=handler.generate_schema(source_type), + ), + ) + except PydanticSchemaGenerationError: + serialization = None + + input_schema = handler.generate_schema(self.json_schema_input_type) + + info_arg = _inspect_validator(self.func, mode='plain', type='field') + if info_arg: + func = cast(core_schema.WithInfoValidatorFunction, self.func) + return core_schema.with_info_plain_validator_function( + func, + serialization=serialization, # pyright: ignore[reportArgumentType] + json_schema_input_schema=input_schema, + ) + else: + func = cast(core_schema.NoInfoValidatorFunction, self.func) + return core_schema.no_info_plain_validator_function( + func, + serialization=serialization, # pyright: ignore[reportArgumentType] + json_schema_input_schema=input_schema, + ) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls( + func=decorator.func, + json_schema_input_type=decorator.info.json_schema_input_type, + ) + + +@dataclasses.dataclass(frozen=True, **_internal_dataclass.slots_true) +class WrapValidator: + """!!! abstract "Usage Documentation" + [field *wrap* validators](../concepts/validators.md#field-wrap-validator) + + A metadata class that indicates that a validation should be applied **around** the inner validation logic. + + Attributes: + func: The validator function. + json_schema_input_type: The input type used to generate the appropriate + JSON Schema (in validation mode). The actual input type is `Any`. + + ```python + from datetime import datetime + from typing import Annotated + + from pydantic import BaseModel, ValidationError, WrapValidator + + def validate_timestamp(v, handler): + if v == 'now': + # we don't want to bother with further validation, just return the new value + return datetime.now() + try: + return handler(v) + except ValidationError: + # validation failed, in this case we want to return a default value + return datetime(2000, 1, 1) + + MyTimestamp = Annotated[datetime, WrapValidator(validate_timestamp)] + + class Model(BaseModel): + a: MyTimestamp + + print(Model(a='now').a) + #> 2032-01-02 03:04:05.000006 + print(Model(a='invalid').a) + #> 2000-01-01 00:00:00 + ``` + """ + + func: core_schema.NoInfoWrapValidatorFunction | core_schema.WithInfoWrapValidatorFunction + json_schema_input_type: Any = PydanticUndefined + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source_type) + input_schema = ( + None + if self.json_schema_input_type is PydanticUndefined + else handler.generate_schema(self.json_schema_input_type) + ) + + info_arg = _inspect_validator(self.func, mode='wrap', type='field') + if info_arg: + func = cast(core_schema.WithInfoWrapValidatorFunction, self.func) + return core_schema.with_info_wrap_validator_function( + func, + schema=schema, + json_schema_input_schema=input_schema, + ) + else: + func = cast(core_schema.NoInfoWrapValidatorFunction, self.func) + return core_schema.no_info_wrap_validator_function( + func, + schema=schema, + json_schema_input_schema=input_schema, + ) + + @classmethod + def _from_decorator(cls, decorator: _decorators.Decorator[_decorators.FieldValidatorDecoratorInfo]) -> Self: + return cls( + func=decorator.func, + json_schema_input_type=decorator.info.json_schema_input_type, + ) + + +if TYPE_CHECKING: + + class _OnlyValueValidatorClsMethod(Protocol): + def __call__(self, cls: Any, value: Any, /) -> Any: ... + + class _V2ValidatorClsMethod(Protocol): + def __call__(self, cls: Any, value: Any, info: core_schema.ValidationInfo[Any], /) -> Any: ... + + class _OnlyValueWrapValidatorClsMethod(Protocol): + def __call__(self, cls: Any, value: Any, handler: core_schema.ValidatorFunctionWrapHandler, /) -> Any: ... + + class _V2WrapValidatorClsMethod(Protocol): + def __call__( + self, + cls: Any, + value: Any, + handler: core_schema.ValidatorFunctionWrapHandler, + info: core_schema.ValidationInfo[Any], + /, + ) -> Any: ... + + _V2Validator = Union[ + _V2ValidatorClsMethod, + core_schema.WithInfoValidatorFunction, + _OnlyValueValidatorClsMethod, + core_schema.NoInfoValidatorFunction, + ] + + _V2WrapValidator = Union[ + _V2WrapValidatorClsMethod, + core_schema.WithInfoWrapValidatorFunction, + _OnlyValueWrapValidatorClsMethod, + core_schema.NoInfoWrapValidatorFunction, + ] + + _PartialClsOrStaticMethod: TypeAlias = Union[classmethod[Any, Any, Any], staticmethod[Any, Any], partialmethod[Any]] + + _V2BeforeAfterOrPlainValidatorType = TypeVar( + '_V2BeforeAfterOrPlainValidatorType', + bound=Union[_V2Validator, _PartialClsOrStaticMethod], + ) + _V2WrapValidatorType = TypeVar('_V2WrapValidatorType', bound=Union[_V2WrapValidator, _PartialClsOrStaticMethod]) + +FieldValidatorModes: TypeAlias = Literal['before', 'after', 'wrap', 'plain'] + + +@overload +def field_validator( + field: str, + /, + *fields: str, + mode: Literal['wrap'], + check_fields: bool | None = ..., + json_schema_input_type: Any = ..., +) -> Callable[[_V2WrapValidatorType], _V2WrapValidatorType]: ... + + +@overload +def field_validator( + field: str, + /, + *fields: str, + mode: Literal['before', 'plain'], + check_fields: bool | None = ..., + json_schema_input_type: Any = ..., +) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... + + +@overload +def field_validator( + field: str, + /, + *fields: str, + mode: Literal['after'] = ..., + check_fields: bool | None = ..., +) -> Callable[[_V2BeforeAfterOrPlainValidatorType], _V2BeforeAfterOrPlainValidatorType]: ... + + +def field_validator( # noqa: D417 + field: str, + /, + *fields: str, + mode: FieldValidatorModes = 'after', + check_fields: bool | None = None, + json_schema_input_type: Any = PydanticUndefined, +) -> Callable[[Any], Any]: + """!!! abstract "Usage Documentation" + [field validators](../concepts/validators.md#field-validators) + + Decorate methods on the class indicating that they should be used to validate fields. + + Example usage: + ```python + from typing import Any + + from pydantic import ( + BaseModel, + ValidationError, + field_validator, + ) + + class Model(BaseModel): + a: str + + @field_validator('a') + @classmethod + def ensure_foobar(cls, v: Any): + if 'foobar' not in v: + raise ValueError('"foobar" not found in a') + return v + + print(repr(Model(a='this is foobar good'))) + #> Model(a='this is foobar good') + + try: + Model(a='snap') + except ValidationError as exc_info: + print(exc_info) + ''' + 1 validation error for Model + a + Value error, "foobar" not found in a [type=value_error, input_value='snap', input_type=str] + ''' + ``` + + For more in depth examples, see [Field Validators](../concepts/validators.md#field-validators). + + Args: + *fields: The field names the validator should apply to. + mode: Specifies whether to validate the fields before or after validation. + check_fields: Whether to check that the fields actually exist on the model. + json_schema_input_type: The input type of the function. This is only used to generate + the appropriate JSON Schema (in validation mode) and can only specified + when `mode` is either `'before'`, `'plain'` or `'wrap'`. + + Raises: + PydanticUserError: + - If the decorator is used without any arguments (at least one field name must be provided). + - If the provided field names are not strings. + - If `json_schema_input_type` is provided with an unsupported `mode`. + - If the decorator is applied to an instance method. + """ + if callable(field) or isinstance(field, classmethod): + raise PydanticUserError( + 'The `@field_validator` decorator cannot be used without arguments, at least one field must be provided. ' + "For example: `@field_validator('', ...)`.", + code='decorator-missing-arguments', + ) + + if mode not in ('before', 'plain', 'wrap') and json_schema_input_type is not PydanticUndefined: + raise PydanticUserError( + f"`json_schema_input_type` can't be used when mode is set to {mode!r}", + code='validator-input-type', + ) + + if json_schema_input_type is PydanticUndefined and mode == 'plain': + json_schema_input_type = Any + + fields = field, *fields + if not all(isinstance(field, str) for field in fields): + raise PydanticUserError( + 'The provided field names to the `@field_validator` decorator should be strings. ' + "For example: `@field_validator('', '', ...).`", + code='decorator-invalid-fields', + ) + + def dec( + f: Callable[..., Any] | staticmethod[Any, Any] | classmethod[Any, Any, Any], + ) -> _decorators.PydanticDescriptorProxy[Any]: + if _decorators.is_instance_method_from_sig(f): + raise PydanticUserError( + 'The `@field_validator` decorator cannot be applied to instance methods', + code='validator-instance-method', + ) + + # auto apply the @classmethod decorator + f = _decorators.ensure_classmethod_based_on_signature(f) + + dec_info = _decorators.FieldValidatorDecoratorInfo( + fields=fields, mode=mode, check_fields=check_fields, json_schema_input_type=json_schema_input_type + ) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + return dec + + +_ModelType = TypeVar('_ModelType') +_ModelTypeCo = TypeVar('_ModelTypeCo', covariant=True) + + +class ModelWrapValidatorHandler(core_schema.ValidatorFunctionWrapHandler, Protocol[_ModelTypeCo]): + """`@model_validator` decorated function handler argument type. This is used when `mode='wrap'`.""" + + def __call__( # noqa: D102 + self, + value: Any, + outer_location: str | int | None = None, + /, + ) -> _ModelTypeCo: # pragma: no cover + ... + + +class ModelWrapValidatorWithoutInfo(Protocol[_ModelType]): + """A `@model_validator` decorated function signature. + This is used when `mode='wrap'` and the function does not have info argument. + """ + + def __call__( # noqa: D102 + self, + cls: type[_ModelType], + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + handler: ModelWrapValidatorHandler[_ModelType], + /, + ) -> _ModelType: ... + + +class ModelWrapValidator(Protocol[_ModelType]): + """A `@model_validator` decorated function signature. This is used when `mode='wrap'`.""" + + def __call__( # noqa: D102 + self, + cls: type[_ModelType], + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + handler: ModelWrapValidatorHandler[_ModelType], + info: core_schema.ValidationInfo, + /, + ) -> _ModelType: ... + + +class FreeModelBeforeValidatorWithoutInfo(Protocol): + """A `@model_validator` decorated function signature. + This is used when `mode='before'` and the function does not have info argument. + """ + + def __call__( # noqa: D102 + self, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + /, + ) -> Any: ... + + +class ModelBeforeValidatorWithoutInfo(Protocol): + """A `@model_validator` decorated function signature. + This is used when `mode='before'` and the function does not have info argument. + """ + + def __call__( # noqa: D102 + self, + cls: Any, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + /, + ) -> Any: ... + + +class FreeModelBeforeValidator(Protocol): + """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" + + def __call__( # noqa: D102 + self, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + info: core_schema.ValidationInfo[Any], + /, + ) -> Any: ... + + +class ModelBeforeValidator(Protocol): + """A `@model_validator` decorated function signature. This is used when `mode='before'`.""" + + def __call__( # noqa: D102 + self, + cls: Any, + # this can be a dict, a model instance + # or anything else that gets passed to validate_python + # thus validators _must_ handle all cases + value: Any, + info: core_schema.ValidationInfo[Any], + /, + ) -> Any: ... + + +ModelAfterValidatorWithoutInfo = Callable[[_ModelType], _ModelType] +"""A `@model_validator` decorated function signature. This is used when `mode='after'` and the function does not +have info argument. +""" + +ModelAfterValidator = Callable[[_ModelType, core_schema.ValidationInfo[Any]], _ModelType] +"""A `@model_validator` decorated function signature. This is used when `mode='after'`.""" + +_AnyModelWrapValidator = Union[ModelWrapValidator[_ModelType], ModelWrapValidatorWithoutInfo[_ModelType]] +_AnyModelBeforeValidator = Union[ + FreeModelBeforeValidator, ModelBeforeValidator, FreeModelBeforeValidatorWithoutInfo, ModelBeforeValidatorWithoutInfo +] +_AnyModelAfterValidator = Union[ModelAfterValidator[_ModelType], ModelAfterValidatorWithoutInfo[_ModelType]] + + +@overload +def model_validator( + *, + mode: Literal['wrap'], +) -> Callable[ + [_AnyModelWrapValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] +]: ... + + +@overload +def model_validator( + *, + mode: Literal['before'], +) -> Callable[ + [_AnyModelBeforeValidator], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] +]: ... + + +@overload +def model_validator( + *, + mode: Literal['after'], +) -> Callable[ + [_AnyModelAfterValidator[_ModelType]], _decorators.PydanticDescriptorProxy[_decorators.ModelValidatorDecoratorInfo] +]: ... + + +def model_validator( + *, + mode: Literal['wrap', 'before', 'after'], +) -> Any: + """!!! abstract "Usage Documentation" + [Model Validators](../concepts/validators.md#model-validators) + + Decorate model methods for validation purposes. + + Example usage: + ```python + from typing_extensions import Self + + from pydantic import BaseModel, ValidationError, model_validator + + class Square(BaseModel): + width: float + height: float + + @model_validator(mode='after') + def verify_square(self) -> Self: + if self.width != self.height: + raise ValueError('width and height do not match') + return self + + s = Square(width=1, height=1) + print(repr(s)) + #> Square(width=1.0, height=1.0) + + try: + Square(width=1, height=2) + except ValidationError as e: + print(e) + ''' + 1 validation error for Square + Value error, width and height do not match [type=value_error, input_value={'width': 1, 'height': 2}, input_type=dict] + ''' + ``` + + For more in depth examples, see [Model Validators](../concepts/validators.md#model-validators). + + Args: + mode: A required string literal that specifies the validation mode. + It can be one of the following: 'wrap', 'before', or 'after'. + + Returns: + A decorator that can be used to decorate a function to be used as a model validator. + """ + + def dec(f: Any) -> _decorators.PydanticDescriptorProxy[Any]: + # auto apply the @classmethod decorator. NOTE: in V3, do not apply the conversion for 'after' validators: + f = _decorators.ensure_classmethod_based_on_signature(f) + if mode == 'after' and isinstance(f, classmethod): + warnings.warn( + category=PydanticDeprecatedSince212, + message=( + "Using `@model_validator` with mode='after' on a classmethod is deprecated. Instead, use an instance method. " + f'See the documentation at https://docs.pydantic.dev/{version_short()}/concepts/validators/#model-after-validator.' + ), + stacklevel=2, + ) + + dec_info = _decorators.ModelValidatorDecoratorInfo(mode=mode) + return _decorators.PydanticDescriptorProxy(f, dec_info) + + return dec + + +AnyType = TypeVar('AnyType') + + +if TYPE_CHECKING: + # If we add configurable attributes to IsInstance, we'd probably need to stop hiding it from type checkers like this + InstanceOf = Annotated[AnyType, ...] # `IsInstance[Sequence]` will be recognized by type checkers as `Sequence` + +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class InstanceOf: + '''Generic type for annotating a type that is an instance of a given class. + + Example: + ```python + from pydantic import BaseModel, InstanceOf + + class Foo: + ... + + class Bar(BaseModel): + foo: InstanceOf[Foo] + + Bar(foo=Foo()) + try: + Bar(foo=42) + except ValidationError as e: + print(e) + """ + [ + │ { + │ │ 'type': 'is_instance_of', + │ │ 'loc': ('foo',), + │ │ 'msg': 'Input should be an instance of Foo', + │ │ 'input': 42, + │ │ 'ctx': {'class': 'Foo'}, + │ │ 'url': 'https://errors.pydantic.dev/0.38.0/v/is_instance_of' + │ } + ] + """ + ``` + ''' + + @classmethod + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + from pydantic._internal._generate_schema import GENERATE_SCHEMA_ERRORS + + # use the generic _origin_ as the second argument to isinstance when appropriate + instance_of_schema = core_schema.is_instance_schema(_generics.get_origin(source) or source) + + try: + # Try to generate the "standard" schema, which will be used when loading from JSON + original_schema = handler(source) + except GENERATE_SCHEMA_ERRORS: + # If that fails, just produce a schema that can validate from python + return instance_of_schema + else: + # Use the "original" approach to serialization + instance_of_schema['serialization'] = core_schema.wrap_serializer_function_ser_schema( + function=lambda v, h: h(v), schema=original_schema + ) + return core_schema.json_or_python_schema(python_schema=instance_of_schema, json_schema=original_schema) + + __hash__ = object.__hash__ + + +if TYPE_CHECKING: + SkipValidation = Annotated[AnyType, ...] # SkipValidation[list[str]] will be treated by type checkers as list[str] +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class SkipValidation: + """If this is applied as an annotation (e.g., via `x: Annotated[int, SkipValidation]`), validation will be + skipped. You can also use `SkipValidation[int]` as a shorthand for `Annotated[int, SkipValidation]`. + + This can be useful if you want to use a type annotation for documentation/IDE/type-checking purposes, + and know that it is safe to skip validation for one or more of the fields. + + Because this converts the validation schema to `any_schema`, subsequent annotation-applied transformations + may not have the expected effects. Therefore, when used, this annotation should generally be the final + annotation applied to a type. + """ + + def __class_getitem__(cls, item: Any) -> Any: + return Annotated[item, SkipValidation()] + + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + with warnings.catch_warnings(): + warnings.simplefilter('ignore', ArbitraryTypeWarning) + original_schema = handler(source) + metadata = {'pydantic_js_annotation_functions': [lambda _c, h: h(original_schema)]} + return core_schema.any_schema( + metadata=metadata, + serialization=core_schema.wrap_serializer_function_ser_schema( + function=lambda v, h: h(v), schema=original_schema + ), + ) + + __hash__ = object.__hash__ + + +_FromTypeT = TypeVar('_FromTypeT') + + +class ValidateAs: + """A helper class to validate a custom type from a type that is natively supported by Pydantic. + + Args: + from_type: The type natively supported by Pydantic to use to perform validation. + instantiation_hook: A callable taking the validated type as an argument, and returning + the populated custom type. + + Example: + ```python {lint="skip"} + from typing import Annotated + + from pydantic import BaseModel, TypeAdapter, ValidateAs + + class MyCls: + def __init__(self, a: int) -> None: + self.a = a + + def __repr__(self) -> str: + return f"MyCls(a={self.a})" + + class Model(BaseModel): + a: int + + + ta = TypeAdapter( + Annotated[MyCls, ValidateAs(Model, lambda v: MyCls(a=v.a))] + ) + + print(ta.validate_python({'a': 1})) + #> MyCls(a=1) + ``` + """ + + # TODO: make use of PEP 747 + def __init__(self, from_type: type[_FromTypeT], /, instantiation_hook: Callable[[_FromTypeT], Any]) -> None: + self.from_type = from_type + self.instantiation_hook = instantiation_hook + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(self.from_type) + return core_schema.no_info_after_validator_function( + self.instantiation_hook, + schema=schema, + ) diff --git a/source/target-vendors/cp312/pydantic/generics.py b/source/target-vendors/cp312/pydantic/generics.py new file mode 100644 index 0000000..3f1070d --- /dev/null +++ b/source/target-vendors/cp312/pydantic/generics.py @@ -0,0 +1,5 @@ +"""The `generics` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/json.py b/source/target-vendors/cp312/pydantic/json.py new file mode 100644 index 0000000..bcaff9f --- /dev/null +++ b/source/target-vendors/cp312/pydantic/json.py @@ -0,0 +1,5 @@ +"""The `json` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/json_schema.py b/source/target-vendors/cp312/pydantic/json_schema.py new file mode 100644 index 0000000..b9b21fd --- /dev/null +++ b/source/target-vendors/cp312/pydantic/json_schema.py @@ -0,0 +1,2911 @@ +"""!!! abstract "Usage Documentation" + [JSON Schema](../concepts/json_schema.md) + +The `json_schema` module contains classes and functions to allow the way [JSON Schema](https://json-schema.org/) +is generated to be customized. + +In general you shouldn't need to use this module directly; instead, you can use +[`BaseModel.model_json_schema`][pydantic.BaseModel.model_json_schema] and +[`TypeAdapter.json_schema`][pydantic.TypeAdapter.json_schema]. +""" + +from __future__ import annotations as _annotations + +import collections.abc +import dataclasses +import inspect +import math +import os +import re +import warnings +from collections import Counter, defaultdict +from collections.abc import Hashable, Iterable, Sequence +from copy import deepcopy +from enum import Enum +from re import Pattern +from typing import ( + TYPE_CHECKING, + Annotated, + Any, + Callable, + Literal, + NewType, + TypeVar, + Union, + cast, + overload, +) + +import pydantic_core +from pydantic_core import MISSING, CoreSchema, PydanticOmit, core_schema, to_jsonable_python +from pydantic_core.core_schema import ComputedField +from typing_extensions import TypeAlias, assert_never, deprecated, final +from typing_inspection.introspection import get_literal_values + +from pydantic.warnings import PydanticDeprecatedSince26, PydanticDeprecatedSince29 + +from ._internal import ( + _config, + _core_metadata, + _core_utils, + _decorators, + _internal_dataclass, + _mock_val_ser, + _schema_generation_shared, + _typing_extra, +) +from .annotated_handlers import GetJsonSchemaHandler +from .config import JsonDict, JsonValue +from .errors import PydanticInvalidForJsonSchema, PydanticSchemaGenerationError, PydanticUserError + +if TYPE_CHECKING: + from . import ConfigDict + from ._internal._core_utils import CoreSchemaField, CoreSchemaOrField + from ._internal._dataclasses import PydanticDataclass + from ._internal._schema_generation_shared import GetJsonSchemaFunction + from .main import BaseModel + + +CoreSchemaOrFieldType = Literal[core_schema.CoreSchemaType, core_schema.CoreSchemaFieldType] +""" +A type alias for defined schema types that represents a union of +`core_schema.CoreSchemaType` and +`core_schema.CoreSchemaFieldType`. +""" + +JsonSchemaValue = dict[str, Any] +""" +A type alias for a JSON schema value. This is a dictionary of string keys to arbitrary JSON values. +""" + +JsonSchemaMode = Literal['validation', 'serialization'] +""" +A type alias that represents the mode of a JSON schema; either 'validation' or 'serialization'. + +For some types, the inputs to validation differ from the outputs of serialization. For example, +computed fields will only be present when serializing, and should not be provided when +validating. This flag provides a way to indicate whether you want the JSON schema required +for validation inputs, or that will be matched by serialization outputs. +""" + +_MODE_TITLE_MAPPING: dict[JsonSchemaMode, str] = {'validation': 'Input', 'serialization': 'Output'} + + +JsonSchemaWarningKind = Literal['skipped-choice', 'non-serializable-default', 'skipped-discriminator'] +""" +A type alias representing the kinds of warnings that can be emitted during JSON schema generation. + +See [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message] +for more details. +""" + + +class PydanticJsonSchemaWarning(UserWarning): + """This class is used to emit warnings produced during JSON schema generation. + See the [`GenerateJsonSchema.emit_warning`][pydantic.json_schema.GenerateJsonSchema.emit_warning] and + [`GenerateJsonSchema.render_warning_message`][pydantic.json_schema.GenerateJsonSchema.render_warning_message] + methods for more details; these can be overridden to control warning behavior. + """ + + +NoDefault = object() +"""A sentinel value used to indicate that no default value should be used when generating a JSON Schema +for a core schema with a default value. +""" + + +# ##### JSON Schema Generation ##### +DEFAULT_REF_TEMPLATE = '#/$defs/{model}' +"""The default format string used to generate reference names.""" + +# There are three types of references relevant to building JSON schemas: +# 1. core_schema "ref" values; these are not exposed as part of the JSON schema +# * these might look like the fully qualified path of a model, its id, or something similar +CoreRef = NewType('CoreRef', str) +# 2. keys of the "definitions" object that will eventually go into the JSON schema +# * by default, these look like "MyModel", though may change in the presence of collisions +# * eventually, we may want to make it easier to modify the way these names are generated +DefsRef = NewType('DefsRef', str) +# 3. the values corresponding to the "$ref" key in the schema +# * By default, these look like "#/$defs/MyModel", as in {"$ref": "#/$defs/MyModel"} +JsonRef = NewType('JsonRef', str) + +CoreModeRef = tuple[CoreRef, JsonSchemaMode] +JsonSchemaKeyT = TypeVar('JsonSchemaKeyT', bound=Hashable) + +_PRIMITIVE_JSON_SCHEMA_TYPES = ('string', 'boolean', 'null', 'integer', 'number') + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class _DefinitionsRemapping: + defs_remapping: dict[DefsRef, DefsRef] + json_remapping: dict[JsonRef, JsonRef] + + @staticmethod + def from_prioritized_choices( + prioritized_choices: dict[DefsRef, list[DefsRef]], + defs_to_json: dict[DefsRef, JsonRef], + definitions: dict[DefsRef, JsonSchemaValue], + ) -> _DefinitionsRemapping: + """ + This function should produce a remapping that replaces complex DefsRef with the simpler ones from the + prioritized_choices such that applying the name remapping would result in an equivalent JSON schema. + """ + # We need to iteratively simplify the definitions until we reach a fixed point. + # The reason for this is that outer definitions may reference inner definitions that get simplified + # into an equivalent reference, and the outer definitions won't be equivalent until we've simplified + # the inner definitions. + copied_definitions = deepcopy(definitions) + definitions_schema = {'$defs': copied_definitions} + for _iter in range(100): # prevent an infinite loop in the case of a bug, 100 iterations should be enough + # For every possible remapped DefsRef, collect all schemas that DefsRef might be used for: + schemas_for_alternatives: dict[DefsRef, list[JsonSchemaValue]] = defaultdict(list) + for defs_ref in copied_definitions: + alternatives = prioritized_choices[defs_ref] + for alternative in alternatives: + schemas_for_alternatives[alternative].append(copied_definitions[defs_ref]) + + # Deduplicate the schemas for each alternative; the idea is that we only want to remap to a new DefsRef + # if it introduces no ambiguity, i.e., there is only one distinct schema for that DefsRef. + for defs_ref in schemas_for_alternatives: + schemas_for_alternatives[defs_ref] = _deduplicate_schemas(schemas_for_alternatives[defs_ref]) + + # Build the remapping + defs_remapping: dict[DefsRef, DefsRef] = {} + json_remapping: dict[JsonRef, JsonRef] = {} + for original_defs_ref in definitions: + alternatives = prioritized_choices[original_defs_ref] + # Pick the first alternative that has only one schema, since that means there is no collision + remapped_defs_ref = next(x for x in alternatives if len(schemas_for_alternatives[x]) == 1) + defs_remapping[original_defs_ref] = remapped_defs_ref + + # Map all alternatives after the remapped one to the remapped one + # This ensures that intermediate simplifications are also remapped + remapped_index = alternatives.index(remapped_defs_ref) + for alt in alternatives[remapped_index:]: + json_remapping[defs_to_json[alt]] = defs_to_json[remapped_defs_ref] + remapping = _DefinitionsRemapping(defs_remapping, json_remapping) + new_definitions_schema = remapping.remap_json_schema({'$defs': copied_definitions}) + if definitions_schema == new_definitions_schema: + # We've reached the fixed point + return remapping + definitions_schema = new_definitions_schema + + raise PydanticInvalidForJsonSchema('Failed to simplify the JSON schema definitions') + + def remap_defs_ref(self, ref: DefsRef) -> DefsRef: + return self.defs_remapping.get(ref, ref) + + def remap_json_ref(self, ref: JsonRef) -> JsonRef: + return self.json_remapping.get(ref, ref) + + def remap_json_schema(self, schema: Any) -> Any: + """ + Recursively update the JSON schema replacing all $refs + """ + if isinstance(schema, str): + # Note: this may not really be a JsonRef; we rely on having no collisions between JsonRefs and other strings + return self.remap_json_ref(JsonRef(schema)) + elif isinstance(schema, list): + return [self.remap_json_schema(item) for item in schema] + elif isinstance(schema, dict): + for key, value in schema.items(): + if key == '$ref' and isinstance(value, str): + schema['$ref'] = self.remap_json_ref(JsonRef(value)) + elif key == '$defs': + schema['$defs'] = { + self.remap_defs_ref(DefsRef(key)): self.remap_json_schema(value) + for key, value in schema['$defs'].items() + } + else: + schema[key] = self.remap_json_schema(value) + return schema + + +class GenerateJsonSchema: + """!!! abstract "Usage Documentation" + [Customizing the JSON Schema Generation Process](../concepts/json_schema.md#customizing-the-json-schema-generation-process) + + A class for generating JSON schemas. + + This class generates JSON schemas based on configured parameters. The default schema dialect + is [https://json-schema.org/draft/2020-12/schema](https://json-schema.org/draft/2020-12/schema). + The class uses `by_alias` to configure how fields with + multiple names are handled and `ref_template` to format reference names. + + Attributes: + schema_dialect: The JSON schema dialect used to generate the schema. See + [Declaring a Dialect](https://json-schema.org/understanding-json-schema/reference/schema.html#id4) + in the JSON Schema documentation for more information about dialects. + ignored_warning_kinds: Warnings to ignore when generating the schema. `self.render_warning_message` will + do nothing if its argument `kind` is in `ignored_warning_kinds`; + this value can be modified on subclasses to easily control which warnings are emitted. + by_alias: Whether to use field aliases when generating the schema. + ref_template: The format string used when generating reference names. + core_to_json_refs: A mapping of core refs to JSON refs. + core_to_defs_refs: A mapping of core refs to definition refs. + defs_to_core_refs: A mapping of definition refs to core refs. + json_to_defs_refs: A mapping of JSON refs to definition refs. + definitions: Definitions in the schema. + + Args: + by_alias: Whether to use field aliases in the generated schemas. + ref_template: The format string to use when generating reference names. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + + Raises: + JsonSchemaError: If the instance of the class is inadvertently reused after generating a schema. + """ + + schema_dialect = 'https://json-schema.org/draft/2020-12/schema' + + # `self.render_warning_message` will do nothing if its argument `kind` is in `ignored_warning_kinds`; + # this value can be modified on subclasses to easily control which warnings are emitted + ignored_warning_kinds: set[JsonSchemaWarningKind] = {'skipped-choice'} + + def __init__( + self, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + ) -> None: + self.by_alias = by_alias + self.ref_template = ref_template + self.union_format: Literal['any_of', 'primitive_type_array'] = union_format + + self.core_to_json_refs: dict[CoreModeRef, JsonRef] = {} + self.core_to_defs_refs: dict[CoreModeRef, DefsRef] = {} + self.defs_to_core_refs: dict[DefsRef, CoreModeRef] = {} + self.json_to_defs_refs: dict[JsonRef, DefsRef] = {} + + self.definitions: dict[DefsRef, JsonSchemaValue] = {} + self._config_wrapper_stack = _config.ConfigWrapperStack(_config.ConfigWrapper({})) + + self._mode: JsonSchemaMode = 'validation' + + # The following includes a mapping of a fully-unique defs ref choice to a list of preferred + # alternatives, which are generally simpler, such as only including the class name. + # At the end of schema generation, we use these to produce a JSON schema with more human-readable + # definitions, which would also work better in a generated OpenAPI client, etc. + self._prioritized_defsref_choices: dict[DefsRef, list[DefsRef]] = {} + self._collision_counter: dict[str, int] = defaultdict(int) + self._collision_index: dict[str, int] = {} + + self._schema_type_to_method = self.build_schema_type_to_method() + + # When we encounter definitions we need to try to build them immediately + # so that they are available schemas that reference them + # But it's possible that CoreSchema was never going to be used + # (e.g. because the CoreSchema that references short circuits is JSON schema generation without needing + # the reference) so instead of failing altogether if we can't build a definition we + # store the error raised and re-throw it if we end up needing that def + self._core_defs_invalid_for_json_schema: dict[DefsRef, PydanticInvalidForJsonSchema] = {} + + # This changes to True after generating a schema, to prevent issues caused by accidental reuse + # of a single instance of a schema generator + self._used = False + + @property + def _config(self) -> _config.ConfigWrapper: + return self._config_wrapper_stack.tail + + @property + def mode(self) -> JsonSchemaMode: + if self._config.json_schema_mode_override is not None: + return self._config.json_schema_mode_override + else: + return self._mode + + def build_schema_type_to_method( + self, + ) -> dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]]: + """Builds a dictionary mapping fields to methods for generating JSON schemas. + + Returns: + A dictionary containing the mapping of `CoreSchemaOrFieldType` to a handler method. + + Raises: + TypeError: If no method has been defined for generating a JSON schema for a given pydantic core schema type. + """ + mapping: dict[CoreSchemaOrFieldType, Callable[[CoreSchemaOrField], JsonSchemaValue]] = {} + core_schema_types: list[CoreSchemaOrFieldType] = list(get_literal_values(CoreSchemaOrFieldType)) + for key in core_schema_types: + method_name = f'{key.replace("-", "_")}_schema' + try: + mapping[key] = getattr(self, method_name) + except AttributeError as e: # pragma: no cover + if os.getenv('PYDANTIC_PRIVATE_ALLOW_UNHANDLED_SCHEMA_TYPES'): + continue + raise TypeError( + f'No method for generating JsonSchema for core_schema.type={key!r} ' + f'(expected: {type(self).__name__}.{method_name})' + ) from e + return mapping + + def generate_definitions( + self, inputs: Sequence[tuple[JsonSchemaKeyT, JsonSchemaMode, core_schema.CoreSchema]] + ) -> tuple[dict[tuple[JsonSchemaKeyT, JsonSchemaMode], JsonSchemaValue], dict[DefsRef, JsonSchemaValue]]: + """Generates JSON schema definitions from a list of core schemas, pairing the generated definitions with a + mapping that links the input keys to the definition references. + + Args: + inputs: A sequence of tuples, where: + + - The first element is a JSON schema key type. + - The second element is the JSON mode: either 'validation' or 'serialization'. + - The third element is a core schema. + + Returns: + A tuple where: + + - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and + whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have + JsonRef references to definitions that are defined in the second returned element.) + - The second element is a dictionary whose keys are definition references for the JSON schemas + from the first returned element, and whose values are the actual JSON schema definitions. + + Raises: + PydanticUserError: Raised if the JSON schema generator has already been used to generate a JSON schema. + """ + if self._used: + raise PydanticUserError( + 'This JSON schema generator has already been used to generate a JSON schema. ' + f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.', + code='json-schema-already-used', + ) + + for _, mode, schema in inputs: + self._mode = mode + self.generate_inner(schema) + + definitions_remapping = self._build_definitions_remapping() + + json_schemas_map: dict[tuple[JsonSchemaKeyT, JsonSchemaMode], DefsRef] = {} + for key, mode, schema in inputs: + self._mode = mode + json_schema = self.generate_inner(schema) + json_schemas_map[(key, mode)] = definitions_remapping.remap_json_schema(json_schema) + + json_schema = {'$defs': self.definitions} + json_schema = definitions_remapping.remap_json_schema(json_schema) + self._used = True + return json_schemas_map, self.sort(json_schema['$defs']) # type: ignore + + def generate(self, schema: CoreSchema, mode: JsonSchemaMode = 'validation') -> JsonSchemaValue: + """Generates a JSON schema for a specified schema in a specified mode. + + Args: + schema: A Pydantic model. + mode: The mode in which to generate the schema. Defaults to 'validation'. + + Returns: + A JSON schema representing the specified schema. + + Raises: + PydanticUserError: If the JSON schema generator has already been used to generate a JSON schema. + """ + self._mode = mode + if self._used: + raise PydanticUserError( + 'This JSON schema generator has already been used to generate a JSON schema. ' + f'You must create a new instance of {type(self).__name__} to generate a new JSON schema.', + code='json-schema-already-used', + ) + + json_schema: JsonSchemaValue = self.generate_inner(schema) + json_ref_counts = self.get_json_ref_counts(json_schema) + + ref = cast(JsonRef, json_schema.get('$ref')) + while ref is not None: # may need to unpack multiple levels + ref_json_schema = self.get_schema_from_definitions(ref) + if json_ref_counts[ref] == 1 and ref_json_schema is not None and len(json_schema) == 1: + # "Unpack" the ref since this is the only reference and there are no sibling keys + json_schema = ref_json_schema.copy() # copy to prevent recursive dict reference + json_ref_counts[ref] -= 1 + ref = cast(JsonRef, json_schema.get('$ref')) + ref = None + + self._garbage_collect_definitions(json_schema) + definitions_remapping = self._build_definitions_remapping() + + if self.definitions: + json_schema['$defs'] = self.definitions + + json_schema = definitions_remapping.remap_json_schema(json_schema) + + # For now, we will not set the $schema key. However, if desired, this can be easily added by overriding + # this method and adding the following line after a call to super().generate(schema): + # json_schema['$schema'] = self.schema_dialect + + self._used = True + return self.sort(json_schema) + + def generate_inner(self, schema: CoreSchemaOrField) -> JsonSchemaValue: # noqa: C901 + """Generates a JSON schema for a given core schema. + + Args: + schema: The given core schema. + + Returns: + The generated JSON schema. + + TODO: the nested function definitions here seem like bad practice, I'd like to unpack these + in a future PR. It'd be great if we could shorten the call stack a bit for JSON schema generation, + and I think there's potential for that here. + """ + # If a schema with the same CoreRef has been handled, just return a reference to it + # Note that this assumes that it will _never_ be the case that the same CoreRef is used + # on types that should have different JSON schemas + if 'ref' in schema: + core_ref = CoreRef(schema['ref']) # type: ignore[typeddict-item] + core_mode_ref = (core_ref, self.mode) + if core_mode_ref in self.core_to_defs_refs and self.core_to_defs_refs[core_mode_ref] in self.definitions: + return {'$ref': self.core_to_json_refs[core_mode_ref]} + + def populate_defs(core_schema: CoreSchema, json_schema: JsonSchemaValue) -> JsonSchemaValue: + if 'ref' in core_schema: + core_ref = CoreRef(core_schema['ref']) # type: ignore[typeddict-item] + defs_ref, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) + json_ref = JsonRef(ref_json_schema['$ref']) + # Replace the schema if it's not a reference to itself + # What we want to avoid is having the def be just a ref to itself + # which is what would happen if we blindly assigned any + if json_schema.get('$ref', None) != json_ref: + self.definitions[defs_ref] = json_schema + self._core_defs_invalid_for_json_schema.pop(defs_ref, None) + json_schema = ref_json_schema + return json_schema + + def handler_func(schema_or_field: CoreSchemaOrField) -> JsonSchemaValue: + """Generate a JSON schema based on the input schema. + + Args: + schema_or_field: The core schema to generate a JSON schema from. + + Returns: + The generated JSON schema. + + Raises: + TypeError: If an unexpected schema type is encountered. + """ + # Generate the core-schema-type-specific bits of the schema generation: + json_schema: JsonSchemaValue | None = None + if self.mode == 'serialization' and 'serialization' in schema_or_field: + # In this case, we skip the JSON Schema generation of the schema + # and use the `'serialization'` schema instead (canonical example: + # `Annotated[int, PlainSerializer(str)]`). + ser_schema = schema_or_field['serialization'] # type: ignore + json_schema = self.ser_schema(ser_schema) + + # It might be that the 'serialization'` is skipped depending on `when_used`. + # This is only relevant for `nullable` schemas though, so we special case here. + if ( + json_schema is not None + and ser_schema.get('when_used') in ('unless-none', 'json-unless-none') + and schema_or_field['type'] == 'nullable' + ): + json_schema = self.get_union_of_schemas([{'type': 'null'}, json_schema]) + if json_schema is None: + if _core_utils.is_core_schema(schema_or_field) or _core_utils.is_core_schema_field(schema_or_field): + generate_for_schema_type = self._schema_type_to_method[schema_or_field['type']] + json_schema = generate_for_schema_type(schema_or_field) + else: + raise TypeError(f'Unexpected schema type: schema={schema_or_field}') + return json_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, handler_func) + + metadata = cast(_core_metadata.CoreMetadata, schema.get('metadata', {})) + + # TODO: I dislike that we have to wrap these basic dict updates in callables, is there any way around this? + + if js_updates := metadata.get('pydantic_js_updates'): + + def js_updates_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + ) -> JsonSchemaValue: + json_schema = {**current_handler(schema_or_field), **js_updates} + return json_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_updates_handler_func) + + if js_extra := metadata.get('pydantic_js_extra'): + + def js_extra_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + ) -> JsonSchemaValue: + json_schema = current_handler(schema_or_field) + if isinstance(js_extra, dict): + json_schema.update(to_jsonable_python(js_extra)) + elif callable(js_extra): + # similar to typing issue in _update_class_schema when we're working with callable js extra + js_extra(json_schema) # type: ignore + return json_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, js_extra_handler_func) + + for js_modify_function in metadata.get('pydantic_js_functions', ()): + + def new_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + js_modify_function: GetJsonSchemaFunction = js_modify_function, + ) -> JsonSchemaValue: + json_schema = js_modify_function(schema_or_field, current_handler) + if _core_utils.is_core_schema(schema_or_field): + json_schema = populate_defs(schema_or_field, json_schema) + original_schema = current_handler.resolve_ref_schema(json_schema) + ref = json_schema.pop('$ref', None) + if ref and json_schema: + original_schema.update(json_schema) + return original_schema + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) + + for js_modify_function in metadata.get('pydantic_js_annotation_functions', ()): + + def new_handler_func( + schema_or_field: CoreSchemaOrField, + current_handler: GetJsonSchemaHandler = current_handler, + js_modify_function: GetJsonSchemaFunction = js_modify_function, + ) -> JsonSchemaValue: + return js_modify_function(schema_or_field, current_handler) + + current_handler = _schema_generation_shared.GenerateJsonSchemaHandler(self, new_handler_func) + + json_schema = current_handler(schema) + if _core_utils.is_core_schema(schema): + json_schema = populate_defs(schema, json_schema) + return json_schema + + def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue: + """Override this method to customize the sorting of the JSON schema (e.g., don't sort at all, sort all keys unconditionally, etc.) + + By default, alphabetically sort the keys in the JSON schema, skipping the 'properties' and 'default' keys to preserve field definition order. + This sort is recursive, so it will sort all nested dictionaries as well. + """ + sorted_dict: dict[str, JsonSchemaValue] = {} + keys = value.keys() + if parent_key not in ('properties', 'default'): + keys = sorted(keys) + for key in keys: + sorted_dict[key] = self._sort_recursive(value[key], parent_key=key) + return sorted_dict + + def _sort_recursive(self, value: Any, parent_key: str | None = None) -> Any: + """Recursively sort a JSON schema value.""" + if isinstance(value, dict): + sorted_dict: dict[str, JsonSchemaValue] = {} + keys = value.keys() + if parent_key not in ('properties', 'default'): + keys = sorted(keys) + for key in keys: + sorted_dict[key] = self._sort_recursive(value[key], parent_key=key) + return sorted_dict + elif isinstance(value, list): + sorted_list: list[JsonSchemaValue] = [self._sort_recursive(item, parent_key) for item in value] + return sorted_list + else: + return value + + # ### Schema generation methods + + def invalid_schema(self, schema: core_schema.InvalidSchema) -> JsonSchemaValue: + """Placeholder - should never be called.""" + + raise RuntimeError('Cannot generate schema for invalid_schema. This is a bug! Please report it.') + + def any_schema(self, schema: core_schema.AnySchema) -> JsonSchemaValue: + """Generates a JSON schema that matches any value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {} + + def none_schema(self, schema: core_schema.NoneSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches `None`. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'null'} + + def bool_schema(self, schema: core_schema.BoolSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a bool value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'boolean'} + + def int_schema(self, schema: core_schema.IntSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches an int value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: dict[str, Any] = {'type': 'integer'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) + json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} + return json_schema + + def float_schema(self, schema: core_schema.FloatSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a float value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: dict[str, Any] = {'type': 'number'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.numeric) + json_schema = {k: v for k, v in json_schema.items() if v not in {math.inf, -math.inf}} + return json_schema + + def decimal_schema(self, schema: core_schema.DecimalSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a decimal value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + + def get_decimal_pattern(schema: core_schema.DecimalSchema) -> str: + max_digits = schema.get('max_digits') + decimal_places = schema.get('decimal_places') + + pattern = ( + r'^(?!^[-+.]*$)[+-]?0*' # check it is not empty string and not one or sequence of ".+-" characters. + ) + + # Case 1: Both max_digits and decimal_places are set + if max_digits is not None and decimal_places is not None: + integer_places = max(0, max_digits - decimal_places) + pattern += ( + rf'(?:' + rf'\d{{0,{integer_places}}}' + rf'|' + rf'(?=[\d.]{{1,{max_digits + 1}}}0*$)' + rf'\d{{0,{integer_places}}}\.\d{{0,{decimal_places}}}0*$' + rf')' + ) + + # Case 2: Only max_digits is set + elif max_digits is not None and decimal_places is None: + pattern += ( + rf'(?:' + rf'\d{{0,{max_digits}}}' + rf'|' + rf'(?=[\d.]{{1,{max_digits + 1}}}0*$)' + rf'\d*\.\d*0*$' + rf')' + ) + + # Case 3: Only decimal_places is set + elif max_digits is None and decimal_places is not None: + pattern += rf'\d*\.?\d{{0,{decimal_places}}}0*$' + + # Case 4: Both are None (no restrictions) + else: + pattern += r'\d*\.?\d*$' # look for arbitrary integer or decimal + + return pattern + + json_schema = self.str_schema(core_schema.str_schema(pattern=get_decimal_pattern(schema))) + if self.mode == 'validation': + multiple_of = schema.get('multiple_of') + le = schema.get('le') + ge = schema.get('ge') + lt = schema.get('lt') + gt = schema.get('gt') + json_schema = { + 'anyOf': [ + self.float_schema( + core_schema.float_schema( + allow_inf_nan=schema.get('allow_inf_nan'), + multiple_of=None if multiple_of is None else float(multiple_of), + le=None if le is None else float(le), + ge=None if ge is None else float(ge), + lt=None if lt is None else float(lt), + gt=None if gt is None else float(gt), + ) + ), + json_schema, + ], + } + return json_schema + + def str_schema(self, schema: core_schema.StringSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a string value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = {'type': 'string'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) + if isinstance(json_schema.get('pattern'), Pattern): + # TODO: should we add regex flags to the pattern? + json_schema['pattern'] = json_schema.get('pattern').pattern # type: ignore + return json_schema + + def bytes_schema(self, schema: core_schema.BytesSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a bytes value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = {'type': 'string', 'format': 'base64url' if self._config.ser_json_bytes == 'base64' else 'binary'} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) + return json_schema + + def date_schema(self, schema: core_schema.DateSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a date value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'date'} + + def time_schema(self, schema: core_schema.TimeSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a time value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'time'} + + def datetime_schema(self, schema: core_schema.DatetimeSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a datetime value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'date-time'} + + def timedelta_schema(self, schema: core_schema.TimedeltaSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a timedelta value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self._config.ser_json_timedelta == 'float': + return {'type': 'number'} + return {'type': 'string', 'format': 'duration'} + + def literal_schema(self, schema: core_schema.LiteralSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a literal value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + expected = [to_jsonable_python(v.value if isinstance(v, Enum) else v) for v in schema['expected']] + + result: dict[str, Any] = {} + if len(expected) == 1: + result['const'] = expected[0] + else: + result['enum'] = expected + + types = {type(e) for e in expected} + if types == {str}: + result['type'] = 'string' + elif types == {int}: + result['type'] = 'integer' + elif types == {float}: + result['type'] = 'number' + elif types == {bool}: + result['type'] = 'boolean' + elif types == {list}: + result['type'] = 'array' + elif types == {type(None)}: + result['type'] = 'null' + return result + + def missing_sentinel_schema(self, schema: core_schema.MissingSentinelSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches the `MISSING` sentinel value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + raise PydanticOmit + + def enum_schema(self, schema: core_schema.EnumSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches an Enum value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + enum_type = schema['cls'] + description = None if not enum_type.__doc__ else inspect.cleandoc(enum_type.__doc__) + if ( + description == 'An enumeration.' + ): # This is the default value provided by enum.EnumMeta.__new__; don't use it + description = None + result: dict[str, Any] = {'title': enum_type.__name__, 'description': description} + result = {k: v for k, v in result.items() if v is not None} + + expected = [to_jsonable_python(v.value) for v in schema['members']] + + result['enum'] = expected + + types = {type(e) for e in expected} + if isinstance(enum_type, str) or types == {str}: + result['type'] = 'string' + elif isinstance(enum_type, int) or types == {int}: + result['type'] = 'integer' + elif isinstance(enum_type, float) or types == {float}: + result['type'] = 'number' + elif types == {bool}: + result['type'] = 'boolean' + elif types == {list}: + result['type'] = 'array' + + return result + + def is_instance_schema(self, schema: core_schema.IsInstanceSchema) -> JsonSchemaValue: + """Handles JSON schema generation for a core schema that checks if a value is an instance of a class. + + Unless overridden in a subclass, this raises an error. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.handle_invalid_for_json_schema(schema, f'core_schema.IsInstanceSchema ({schema["cls"]})') + + def is_subclass_schema(self, schema: core_schema.IsSubclassSchema) -> JsonSchemaValue: + """Handles JSON schema generation for a core schema that checks if a value is a subclass of a class. + + For backwards compatibility with v1, this does not raise an error, but can be overridden to change this. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # Note: This is for compatibility with V1; you can override if you want different behavior. + return {} + + def callable_schema(self, schema: core_schema.CallableSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a callable value. + + Unless overridden in a subclass, this raises an error. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.handle_invalid_for_json_schema(schema, 'core_schema.CallableSchema') + + def list_schema(self, schema: core_schema.ListSchema) -> JsonSchemaValue: + """Returns a schema that matches a list schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) + json_schema = {'type': 'array', 'items': items_schema} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + @deprecated('`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', category=None) + @final + def tuple_positional_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: + """Replaced by `tuple_schema`.""" + warnings.warn( + '`tuple_positional_schema` is deprecated. Use `tuple_schema` instead.', + PydanticDeprecatedSince26, + stacklevel=2, + ) + return self.tuple_schema(schema) + + @deprecated('`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', category=None) + @final + def tuple_variable_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: + """Replaced by `tuple_schema`.""" + warnings.warn( + '`tuple_variable_schema` is deprecated. Use `tuple_schema` instead.', + PydanticDeprecatedSince26, + stacklevel=2, + ) + return self.tuple_schema(schema) + + def tuple_schema(self, schema: core_schema.TupleSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a tuple schema e.g. `tuple[int, + str, bool]` or `tuple[int, ...]`. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: JsonSchemaValue = {'type': 'array'} + if 'variadic_item_index' in schema: + variadic_item_index = schema['variadic_item_index'] + if variadic_item_index > 0: + json_schema['minItems'] = variadic_item_index + json_schema['prefixItems'] = [ + self.generate_inner(item) for item in schema['items_schema'][:variadic_item_index] + ] + if variadic_item_index + 1 == len(schema['items_schema']): + # if the variadic item is the last item, then represent it faithfully + json_schema['items'] = self.generate_inner(schema['items_schema'][variadic_item_index]) + else: + # otherwise, 'items' represents the schema for the variadic + # item plus the suffix, so just allow anything for simplicity + # for now + json_schema['items'] = True + else: + prefixItems = [self.generate_inner(item) for item in schema['items_schema']] + if prefixItems: + json_schema['prefixItems'] = prefixItems + json_schema['minItems'] = len(prefixItems) + json_schema['maxItems'] = len(prefixItems) + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + def set_schema(self, schema: core_schema.SetSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a set schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self._common_set_schema(schema) + + def frozenset_schema(self, schema: core_schema.FrozenSetSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a frozenset schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self._common_set_schema(schema) + + def _common_set_schema(self, schema: core_schema.SetSchema | core_schema.FrozenSetSchema) -> JsonSchemaValue: + items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) + json_schema = {'type': 'array', 'uniqueItems': True, 'items': items_schema} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + def generator_schema(self, schema: core_schema.GeneratorSchema) -> JsonSchemaValue: + """Returns a JSON schema that represents the provided GeneratorSchema. + + Args: + schema: The schema. + + Returns: + The generated JSON schema. + """ + items_schema = {} if 'items_schema' not in schema else self.generate_inner(schema['items_schema']) + json_schema = {'type': 'array', 'items': items_schema} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.array) + return json_schema + + def dict_schema(self, schema: core_schema.DictSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a dict schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema: JsonSchemaValue = {'type': 'object'} + + keys_schema = self.generate_inner(schema['keys_schema']).copy() if 'keys_schema' in schema else {} + if '$ref' not in keys_schema: + keys_pattern = keys_schema.pop('pattern', None) + # Don't give a title to patternProperties/propertyNames: + keys_schema.pop('title', None) + else: + # Here, we assume that if the keys schema is a definition reference, + # it can't be a simple string core schema (and thus no pattern can exist). + # However, this is only in practice (in theory, a definition reference core + # schema could be generated for a simple string schema). + # Note that we avoid calling `self.resolve_ref_schema`, as it might not exist yet. + keys_pattern = None + + values_schema = self.generate_inner(schema['values_schema']).copy() if 'values_schema' in schema else {} + # don't give a title to additionalProperties: + values_schema.pop('title', None) + + if values_schema or keys_pattern is not None: + if keys_pattern is None: + json_schema['additionalProperties'] = values_schema + else: + json_schema['patternProperties'] = {keys_pattern: values_schema} + else: # for `dict[str, Any]`, we allow any key and any value, since `str` is the default key type + json_schema['additionalProperties'] = True + + if ( + # The len check indicates that constraints are probably present: + (keys_schema.get('type') == 'string' and len(keys_schema) > 1) + # If this is a definition reference schema, it most likely has constraints: + or '$ref' in keys_schema + ): + keys_schema.pop('type', None) + json_schema['propertyNames'] = keys_schema + + self.update_with_validations(json_schema, schema, self.ValidationsMapping.object) + return json_schema + + def function_before_schema(self, schema: core_schema.BeforeValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-before schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): + return self.generate_inner(input_schema) + + return self.generate_inner(schema['schema']) + + def function_after_schema(self, schema: core_schema.AfterValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-after schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def function_plain_schema(self, schema: core_schema.PlainValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-plain schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): + return self.generate_inner(input_schema) + + return self.handle_invalid_for_json_schema( + schema, f'core_schema.PlainValidatorFunctionSchema ({schema["function"]})' + ) + + def function_wrap_schema(self, schema: core_schema.WrapValidatorFunctionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a function-wrap schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + if self.mode == 'validation' and (input_schema := schema.get('json_schema_input_schema')): + return self.generate_inner(input_schema) + + return self.generate_inner(schema['schema']) + + def default_schema(self, schema: core_schema.WithDefaultSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema with a default value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = self.generate_inner(schema['schema']) + + default = self.get_default_value(schema) + if default is NoDefault or default is MISSING: + return json_schema + + # we reflect the application of custom plain, no-info serializers to defaults for + # JSON Schemas viewed in serialization mode: + # TODO: improvements along with https://github.com/pydantic/pydantic/issues/8208 + if self.mode == 'serialization': + # `_get_ser_schema_for_default_value()` is used to unpack potentially nested validator schemas: + ser_schema = _get_ser_schema_for_default_value(schema['schema']) + if ( + ser_schema is not None + and (ser_func := ser_schema.get('function')) + and not (default is None and ser_schema.get('when_used') in ('unless-none', 'json-unless-none')) + ): + try: + default = ser_func(default) # type: ignore + except Exception: + # It might be that the provided default needs to be validated (read: parsed) first + # (assuming `validate_default` is enabled). However, we can't perform + # such validation during JSON Schema generation so we don't support + # this pattern for now. + # (One example is when using `foo: ByteSize = '1MB'`, which validates and + # serializes as an int. In this case, `ser_func` is `int` and `int('1MB')` fails). + self.emit_warning( + 'non-serializable-default', + f'Unable to serialize value {default!r} with the plain serializer; excluding default from JSON schema', + ) + return json_schema + + # Sort set/frozenset defaults to ensure deterministic JSON schema generation + # We only sort if len > 1 because sets of size 0 or 1 are already deterministic + if isinstance(default, collections.abc.Set) and len(default) > 1: + try: + default = sorted(default) + except TypeError: # pragma: no cover + # If items aren't comparable (e.g. mixed types), we can't sort them. + pass + + try: + encoded_default = self.encode_default(default) + except pydantic_core.PydanticSerializationError: + self.emit_warning( + 'non-serializable-default', + f'Default value {default} is not JSON serializable; excluding default from JSON schema', + ) + # Return the inner schema, as though there was no default + return json_schema + + json_schema['default'] = encoded_default + return json_schema + + def get_default_value(self, schema: core_schema.WithDefaultSchema) -> Any: + """Get the default value to be used when generating a JSON Schema for a core schema with a default. + + The default implementation is to use the statically defined default value. This method can be overridden + if you want to make use of the default factory. + + Args: + schema: The `'with-default'` core schema. + + Returns: + The default value to use, or [`NoDefault`][pydantic.json_schema.NoDefault] if no default + value is available. + """ + return schema.get('default', NoDefault) + + def nullable_schema(self, schema: core_schema.NullableSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows null values. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + null_schema = {'type': 'null'} + inner_json_schema = self.generate_inner(schema['schema']) + + if inner_json_schema == null_schema: + return null_schema + else: + return self.get_union_of_schemas([inner_json_schema, null_schema]) + + def union_schema(self, schema: core_schema.UnionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching any of the given schemas. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + generated: list[JsonSchemaValue] = [] + + for choice in core_schema.iter_union_choices(schema): + try: + generated.append(self.generate_inner(choice)) + except PydanticOmit: # noqa: PERF203 + continue + except PydanticInvalidForJsonSchema as exc: + self.emit_warning('skipped-choice', exc.message) + if len(generated) == 1: + return generated[0] + return self.get_union_of_schemas(generated) + + def get_union_of_schemas(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: + """Returns the JSON Schema representation for the union of the provided JSON Schemas. + + The result depends on the configured `'union_format'`. + + Args: + schemas: The list of JSON Schemas to be included in the union. + + Returns: + The JSON Schema representing the union of schemas. + """ + if self.union_format == 'primitive_type_array': + types: list[str] = [] + for schema in schemas: + schema_types: list[str] | str | None = schema.get('type') + if schema_types is None: + # No type, meaning it can be a ref or an empty schema. + break + if not isinstance(schema_types, list): + schema_types = [schema_types] + if not all(t in _PRIMITIVE_JSON_SCHEMA_TYPES for t in schema_types): + break + if len(schema) != 1: + # We only want to include types that don't have any constraints. For instance, + # if `schemas = [{'type': 'string', 'maxLength': 3}, {'type': 'string', 'minLength': 5}]`, + # we don't want to produce `{'type': 'string', 'maxLength': 3, 'minLength': 5}`. + # Same if we have some metadata (e.g. `title`) on a specific union member, we want to preserve it. + break + + types.extend(schema_types) + else: + # If we got there, all the schemas where valid to be used with the `'primitive_type_array` format + return {'type': list(dict.fromkeys(types))} + + return self.get_flattened_anyof(schemas) + + def tagged_union_schema(self, schema: core_schema.TaggedUnionSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching any of the given schemas, where + the schemas are tagged with a discriminator field that indicates which schema should be used to validate + the value. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + generated: dict[str, JsonSchemaValue] = {} + for k, v in schema['choices'].items(): + if isinstance(k, Enum): + k = k.value + try: + # Use str(k) since keys must be strings for json; while not technically correct, + # it's the closest that can be represented in valid JSON + generated[str(k)] = self.generate_inner(v).copy() + except PydanticOmit: + continue + except PydanticInvalidForJsonSchema as exc: + self.emit_warning('skipped-choice', exc.message) + + one_of_choices = _deduplicate_schemas(generated.values()) + json_schema: JsonSchemaValue = {'oneOf': one_of_choices} + + # This reflects the v1 behavior; TODO: we should make it possible to exclude OpenAPI stuff from the JSON schema + openapi_discriminator = self._extract_discriminator(schema, one_of_choices) + if openapi_discriminator is not None: + json_schema['discriminator'] = { + 'propertyName': openapi_discriminator, + 'mapping': {k: v.get('$ref', v) for k, v in generated.items()}, + } + + return json_schema + + def _extract_discriminator( + self, schema: core_schema.TaggedUnionSchema, one_of_choices: list[JsonDict] + ) -> str | None: + """Extract a compatible OpenAPI discriminator from the schema and one_of choices that end up in the final + schema.""" + openapi_discriminator: str | None = None + + if isinstance(schema['discriminator'], str): + return schema['discriminator'] + + if isinstance(schema['discriminator'], list): + # If the discriminator is a single item list containing a string, that is equivalent to the string case + if len(schema['discriminator']) == 1 and isinstance(schema['discriminator'][0], str): + return schema['discriminator'][0] + # When an alias is used that is different from the field name, the discriminator will be a list of single + # str lists, one for the attribute and one for the actual alias. The logic here will work even if there is + # more than one possible attribute, and looks for whether a single alias choice is present as a documented + # property on all choices. If so, that property will be used as the OpenAPI discriminator. + for alias_path in schema['discriminator']: + if not isinstance(alias_path, list): + break # this means that the discriminator is not a list of alias paths + if len(alias_path) != 1: + continue # this means that the "alias" does not represent a single field + alias = alias_path[0] + if not isinstance(alias, str): + continue # this means that the "alias" does not represent a field + alias_is_present_on_all_choices = True + for choice in one_of_choices: + try: + choice = self.resolve_ref_schema(choice) + except RuntimeError as exc: + # TODO: fixme - this is a workaround for the fact that we can't always resolve refs + # for tagged union choices at this point in the schema gen process, we might need to do + # another pass at the end like we do for core schemas + self.emit_warning('skipped-discriminator', str(exc)) + choice = {} + properties = choice.get('properties', {}) + if not isinstance(properties, dict) or alias not in properties: + alias_is_present_on_all_choices = False + break + if alias_is_present_on_all_choices: + openapi_discriminator = alias + break + return openapi_discriminator + + def chain_schema(self, schema: core_schema.ChainSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a core_schema.ChainSchema. + + When generating a schema for validation, we return the validation JSON schema for the first step in the chain. + For serialization, we return the serialization JSON schema for the last step in the chain. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + step_index = 0 if self.mode == 'validation' else -1 # use first step for validation, last for serialization + return self.generate_inner(schema['steps'][step_index]) + + def lax_or_strict_schema(self, schema: core_schema.LaxOrStrictSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching either the lax schema or the + strict schema. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # TODO: Need to read the default value off of model config or whatever + use_strict = schema.get('strict', False) # TODO: replace this default False + # If your JSON schema fails to generate it is probably + # because one of the following two branches failed. + if use_strict: + return self.generate_inner(schema['strict_schema']) + else: + return self.generate_inner(schema['lax_schema']) + + def json_or_python_schema(self, schema: core_schema.JsonOrPythonSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that allows values matching either the JSON schema or the + Python schema. + + The JSON schema is used instead of the Python schema. If you want to use the Python schema, you should override + this method. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['json_schema']) + + def typed_dict_schema(self, schema: core_schema.TypedDictSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a typed dict. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + total = schema.get('total', True) + named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ + (name, self.field_is_required(field, total), field) + for name, field in schema['fields'].items() + if self.field_is_present(field) + ] + if self.mode == 'serialization': + named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) + cls = schema.get('cls') + config = _get_typed_dict_config(cls) + with self._config_wrapper_stack.push(config): + json_schema = self._named_required_fields_schema(named_required_fields) + + # There's some duplication between `extra_behavior` and + # the config's `extra`/core config's `extra_fields_behavior`. + # However, it is common to manually create TypedDictSchemas, + # where you don't necessarily have a class. + # At runtime, `extra_behavior` takes priority over the config + # for validation, so follow the same for the JSON Schema: + if 'extras_schema' in schema and schema['extras_schema'] != core_schema.any_schema(): + allow_additional_props = self.generate_inner(schema['extras_schema']) + else: + allow_additional_props = True + + if schema.get('extra_behavior') == 'forbid': + json_schema['additionalProperties'] = False + elif schema.get('extra_behavior') == 'allow': + json_schema['additionalProperties'] = allow_additional_props + + if cls is not None: + # `_update_class_schema()` will not override + # `additionalProperties` if already present: + self._update_class_schema(json_schema, cls, config) + elif 'additionalProperties' not in json_schema: + extra = schema.get('config', {}).get('extra_fields_behavior') + if extra == 'forbid': + json_schema['additionalProperties'] = False + elif extra == 'allow': + json_schema['additionalProperties'] = allow_additional_props + + return json_schema + + @staticmethod + def _name_required_computed_fields( + computed_fields: list[ComputedField], + ) -> list[tuple[str, bool, core_schema.ComputedField]]: + return [(field['property_name'], True, field) for field in computed_fields] + + def _named_required_fields_schema( + self, named_required_fields: Sequence[tuple[str, bool, CoreSchemaField]] + ) -> JsonSchemaValue: + properties: dict[str, JsonSchemaValue] = {} + required_fields: list[str] = [] + for name, required, field in named_required_fields: + if self.by_alias: + name = self._get_alias_name(field, name) + try: + field_json_schema = self.generate_inner(field).copy() + except PydanticOmit: + continue + if 'title' not in field_json_schema and self.field_title_should_be_set(field): + title = self.get_title_from_name(name) + field_json_schema['title'] = title + field_json_schema = self.handle_ref_overrides(field_json_schema) + properties[name] = field_json_schema + if required: + required_fields.append(name) + + json_schema = {'type': 'object', 'properties': properties} + if required_fields: + json_schema['required'] = required_fields + return json_schema + + def _get_alias_name(self, field: CoreSchemaField, name: str) -> str: + if field['type'] == 'computed-field': + alias: Any = field.get('alias', name) + elif self.mode == 'validation': + alias = field.get('validation_alias', name) + else: + alias = field.get('serialization_alias', name) + if isinstance(alias, str): + name = alias + elif isinstance(alias, list): + alias = cast('list[str] | str', alias) + for path in alias: + if isinstance(path, list) and len(path) == 1 and isinstance(path[0], str): + # Use the first valid single-item string path; the code that constructs the alias array + # should ensure the first such item is what belongs in the JSON schema + name = path[0] + break + else: + assert_never(alias) + return name + + def typed_dict_field_schema(self, schema: core_schema.TypedDictField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a typed dict field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def dataclass_field_schema(self, schema: core_schema.DataclassField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a dataclass field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def model_field_schema(self, schema: core_schema.ModelField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a model field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def computed_field_schema(self, schema: core_schema.ComputedField) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a computed field. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['return_schema']) + + def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a model. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # We do not use schema['model'].model_json_schema() here + # because it could lead to inconsistent refs handling, etc. + cls = cast('type[BaseModel]', schema['cls']) + config = cls.model_config + + with self._config_wrapper_stack.push(config): + json_schema = self.generate_inner(schema['schema']) + + self._update_class_schema(json_schema, cls, config) + + return json_schema + + def _update_class_schema(self, json_schema: JsonSchemaValue, cls: type[Any], config: ConfigDict) -> None: + """Update json_schema with the following, extracted from `config` and `cls`: + + * title + * description + * additional properties + * json_schema_extra + * deprecated + + Done in place, hence there's no return value as the original json_schema is mutated. + No ref resolving is involved here, as that's not appropriate for simple updates. + """ + from ._internal._dataclasses import is_stdlib_dataclass + from .main import BaseModel + + if (config_title := config.get('title')) is not None: + json_schema.setdefault('title', config_title) + elif model_title_generator := config.get('model_title_generator'): + title = model_title_generator(cls) + if not isinstance(title, str): + raise TypeError(f'model_title_generator {model_title_generator} must return str, not {title.__class__}') + json_schema.setdefault('title', title) + if 'title' not in json_schema: + json_schema['title'] = cls.__name__ + + # BaseModel and dataclasses; don't use cls.__doc__ as it will contain the verbose class signature by default + if cls is BaseModel: + docstring = None + elif is_stdlib_dataclass(cls): # For Pydantic dataclasses, we already handle this at class creation + # The `dataclass` module generates a `__doc__` based on the `inspect.signature()` + # result, which we don't want to use as a description. Such `__doc__` startswith + # `cls.__name__(`, which could lead to mistakenly discarding it if for some reason + # an explicitly set class docstring follows the same pattern, but this is unlikely + # to happen. + doc = cls.__doc__ + docstring = None if doc is None or doc.startswith(f'{cls.__name__}(') else doc + else: + docstring = cls.__doc__ + + if docstring: + json_schema.setdefault('description', inspect.cleandoc(docstring)) + + extra = config.get('extra') + if 'additionalProperties' not in json_schema: # This check is particularly important for `typed_dict_schema()` + if extra == 'allow': + json_schema['additionalProperties'] = True + elif extra == 'forbid': + json_schema['additionalProperties'] = False + + json_schema_extra = config.get('json_schema_extra') + if issubclass(cls, BaseModel) and cls.__pydantic_root_model__: + root_json_schema_extra = cls.model_fields['root'].json_schema_extra + if json_schema_extra and root_json_schema_extra: + raise ValueError( + '"model_config[\'json_schema_extra\']" and "Field.json_schema_extra" on "RootModel.root"' + ' field must not be set simultaneously' + ) + if root_json_schema_extra: + json_schema_extra = root_json_schema_extra + + if isinstance(json_schema_extra, (staticmethod, classmethod)): + # In older versions of python, this is necessary to ensure staticmethod/classmethods are callable + json_schema_extra = json_schema_extra.__get__(cls) + + if isinstance(json_schema_extra, dict): + json_schema.update(json_schema_extra) + elif callable(json_schema_extra): + if len(_typing_extra.signature_no_eval(json_schema_extra).parameters) > 1: + json_schema_extra = cast(Callable[[JsonDict, type[Any]], None], json_schema_extra) + json_schema_extra(json_schema, cls) + else: + json_schema_extra = cast(Callable[[JsonDict], None], json_schema_extra) + json_schema_extra(json_schema) + elif json_schema_extra is not None: + raise ValueError( + f"model_config['json_schema_extra']={json_schema_extra} should be a dict, callable, or None" + ) + + if hasattr(cls, '__deprecated__'): + json_schema['deprecated'] = True + + def resolve_ref_schema(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: + """Resolve a JsonSchemaValue to the non-ref schema if it is a $ref schema. + + Args: + json_schema: The schema to resolve. + + Returns: + The resolved schema. + + Raises: + RuntimeError: If the schema reference can't be found in definitions. + """ + while '$ref' in json_schema: + ref = json_schema['$ref'] + schema_to_update = self.get_schema_from_definitions(JsonRef(ref)) + if schema_to_update is None: + raise RuntimeError(f'Cannot update undefined schema for $ref={ref}') + json_schema = schema_to_update + return json_schema + + def model_fields_schema(self, schema: core_schema.ModelFieldsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a model's fields. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ + (name, self.field_is_required(field, total=True), field) + for name, field in schema['fields'].items() + if self.field_is_present(field) + ] + if self.mode == 'serialization': + named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) + json_schema = self._named_required_fields_schema(named_required_fields) + extras_schema = schema.get('extras_schema', None) + if extras_schema is not None: + schema_to_update = self.resolve_ref_schema(json_schema) + schema_to_update['additionalProperties'] = self.generate_inner(extras_schema) + return json_schema + + def field_is_present(self, field: CoreSchemaField) -> bool: + """Whether the field should be included in the generated JSON schema. + + Args: + field: The schema for the field itself. + + Returns: + `True` if the field should be included in the generated JSON schema, `False` otherwise. + """ + if self.mode == 'serialization': + # If you still want to include the field in the generated JSON schema, + # override this method and return True + return not field.get('serialization_exclude') + elif self.mode == 'validation': + return True + else: + assert_never(self.mode) + + def field_is_required( + self, + field: core_schema.ModelField | core_schema.DataclassField | core_schema.TypedDictField, + total: bool, + ) -> bool: + """Whether the field should be marked as required in the generated JSON schema. + (Note that this is irrelevant if the field is not present in the JSON schema.). + + Args: + field: The schema for the field itself. + total: Only applies to `TypedDictField`s. + Indicates if the `TypedDict` this field belongs to is total, in which case any fields that don't + explicitly specify `required=False` are required. + + Returns: + `True` if the field should be marked as required in the generated JSON schema, `False` otherwise. + """ + if field['type'] == 'typed-dict-field': + required = field.get('required', total) + else: + required = field['schema']['type'] != 'default' + + if self.mode == 'serialization': + has_exclude_if = field.get('serialization_exclude_if') is not None + if self._config.json_schema_serialization_defaults_required: + return not has_exclude_if + else: + return required and not has_exclude_if + else: + return required + + def dataclass_args_schema(self, schema: core_schema.DataclassArgsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a dataclass's constructor arguments. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + named_required_fields: list[tuple[str, bool, CoreSchemaField]] = [ + (field['name'], self.field_is_required(field, total=True), field) + for field in schema['fields'] + if self.field_is_present(field) + ] + if self.mode == 'serialization': + named_required_fields.extend(self._name_required_computed_fields(schema.get('computed_fields', []))) + return self._named_required_fields_schema(named_required_fields) + + def dataclass_schema(self, schema: core_schema.DataclassSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a dataclass. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + + cls = schema['cls'] + config = cast('ConfigDict', getattr(cls, '__pydantic_config__', {})) + + with self._config_wrapper_stack.push(config): + json_schema = self.generate_inner(schema['schema']).copy() + + self._update_class_schema(json_schema, cls, config) + + return json_schema + + def arguments_schema(self, schema: core_schema.ArgumentsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's arguments. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + prefer_positional = schema.get('metadata', {}).get('pydantic_js_prefer_positional_arguments') + + arguments = schema['arguments_schema'] + kw_only_arguments = [a for a in arguments if a.get('mode') == 'keyword_only'] + kw_or_p_arguments = [a for a in arguments if a.get('mode') in {'positional_or_keyword', None}] + p_only_arguments = [a for a in arguments if a.get('mode') == 'positional_only'] + var_args_schema = schema.get('var_args_schema') + var_kwargs_schema = schema.get('var_kwargs_schema') + + if prefer_positional: + positional_possible = not kw_only_arguments and not var_kwargs_schema + if positional_possible: + return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) + + keyword_possible = not p_only_arguments and not var_args_schema + if keyword_possible: + return self.kw_arguments_schema(kw_or_p_arguments + kw_only_arguments, var_kwargs_schema) + + if not prefer_positional: + positional_possible = not kw_only_arguments and not var_kwargs_schema + if positional_possible: + return self.p_arguments_schema(p_only_arguments + kw_or_p_arguments, var_args_schema) + + raise PydanticInvalidForJsonSchema( + 'Unable to generate JSON schema for arguments validator with positional-only and keyword-only arguments' + ) + + def kw_arguments_schema( + self, arguments: list[core_schema.ArgumentsParameter], var_kwargs_schema: CoreSchema | None + ) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's keyword arguments. + + Args: + arguments: The core schema. + + Returns: + The generated JSON schema. + """ + properties: dict[str, JsonSchemaValue] = {} + required: list[str] = [] + for argument in arguments: + name = self.get_argument_name(argument) + argument_schema = self.generate_inner(argument['schema']).copy() + if 'title' not in argument_schema and self.field_title_should_be_set(argument['schema']): + argument_schema['title'] = self.get_title_from_name(name) + properties[name] = argument_schema + + if argument['schema']['type'] != 'default': + # This assumes that if the argument has a default value, + # the inner schema must be of type WithDefaultSchema. + # I believe this is true, but I am not 100% sure + required.append(name) + + json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} + if required: + json_schema['required'] = required + + if var_kwargs_schema: + additional_properties_schema = self.generate_inner(var_kwargs_schema) + if additional_properties_schema: + json_schema['additionalProperties'] = additional_properties_schema + else: + json_schema['additionalProperties'] = False + return json_schema + + def p_arguments_schema( + self, arguments: list[core_schema.ArgumentsParameter], var_args_schema: CoreSchema | None + ) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's positional arguments. + + Args: + arguments: The core schema. + + Returns: + The generated JSON schema. + """ + prefix_items: list[JsonSchemaValue] = [] + min_items = 0 + + for argument in arguments: + name = self.get_argument_name(argument) + + argument_schema = self.generate_inner(argument['schema']).copy() + if 'title' not in argument_schema and self.field_title_should_be_set(argument['schema']): + argument_schema['title'] = self.get_title_from_name(name) + prefix_items.append(argument_schema) + + if argument['schema']['type'] != 'default': + # This assumes that if the argument has a default value, + # the inner schema must be of type WithDefaultSchema. + # I believe this is true, but I am not 100% sure + min_items += 1 + + json_schema: JsonSchemaValue = {'type': 'array'} + if prefix_items: + json_schema['prefixItems'] = prefix_items + if min_items: + json_schema['minItems'] = min_items + + if var_args_schema: + items_schema = self.generate_inner(var_args_schema) + if items_schema: + json_schema['items'] = items_schema + else: + json_schema['maxItems'] = len(prefix_items) + + return json_schema + + def get_argument_name(self, argument: core_schema.ArgumentsParameter | core_schema.ArgumentsV3Parameter) -> str: + """Retrieves the name of an argument. + + Args: + argument: The core schema. + + Returns: + The name of the argument. + """ + name = argument['name'] + if self.by_alias: + alias = argument.get('alias') + if isinstance(alias, str): + name = alias + else: + pass # might want to do something else? + return name + + def arguments_v3_schema(self, schema: core_schema.ArgumentsV3Schema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function's arguments. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + arguments = schema['arguments_schema'] + properties: dict[str, JsonSchemaValue] = {} + required: list[str] = [] + for argument in arguments: + mode = argument.get('mode', 'positional_or_keyword') + name = self.get_argument_name(argument) + argument_schema = self.generate_inner(argument['schema']).copy() + if mode == 'var_args': + argument_schema = {'type': 'array', 'items': argument_schema} + elif mode == 'var_kwargs_uniform': + argument_schema = {'type': 'object', 'additionalProperties': argument_schema} + + argument_schema.setdefault('title', self.get_title_from_name(name)) + properties[name] = argument_schema + + if ( + (mode == 'var_kwargs_unpacked_typed_dict' and 'required' in argument_schema) + or mode not in {'var_args', 'var_kwargs_uniform', 'var_kwargs_unpacked_typed_dict'} + and argument['schema']['type'] != 'default' + ): + # This assumes that if the argument has a default value, + # the inner schema must be of type WithDefaultSchema. + # I believe this is true, but I am not 100% sure + required.append(name) + + json_schema: JsonSchemaValue = {'type': 'object', 'properties': properties} + if required: + json_schema['required'] = required + return json_schema + + def call_schema(self, schema: core_schema.CallSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a function call. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['arguments_schema']) + + def custom_error_schema(self, schema: core_schema.CustomErrorSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a custom error. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return self.generate_inner(schema['schema']) + + def json_schema(self, schema: core_schema.JsonSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a JSON object. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + content_core_schema = schema.get('schema') or core_schema.any_schema() + content_json_schema = self.generate_inner(content_core_schema) + if self.mode == 'validation': + return {'type': 'string', 'contentMediaType': 'application/json', 'contentSchema': content_json_schema} + else: + # self.mode == 'serialization' + return content_json_schema + + def url_schema(self, schema: core_schema.UrlSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a URL. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + json_schema = {'type': 'string', 'format': 'uri', 'minLength': 1} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) + return json_schema + + def multi_host_url_schema(self, schema: core_schema.MultiHostUrlSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a URL that can be used with multiple hosts. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + # Note: 'multi-host-uri' is a custom/pydantic-specific format, not part of the JSON Schema spec + json_schema = {'type': 'string', 'format': 'multi-host-uri', 'minLength': 1} + self.update_with_validations(json_schema, schema, self.ValidationsMapping.string) + return json_schema + + def uuid_schema(self, schema: core_schema.UuidSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a UUID. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string', 'format': 'uuid'} + + def definitions_schema(self, schema: core_schema.DefinitionsSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that defines a JSON object with definitions. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + for definition in schema['definitions']: + try: + self.generate_inner(definition) + except PydanticInvalidForJsonSchema as e: # noqa: PERF203 + core_ref: CoreRef = CoreRef(definition['ref']) # type: ignore + self._core_defs_invalid_for_json_schema[self.get_defs_ref((core_ref, self.mode))] = e + continue + return self.generate_inner(schema['schema']) + + def definition_ref_schema(self, schema: core_schema.DefinitionReferenceSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a schema that references a definition. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + core_ref = CoreRef(schema['schema_ref']) + _, ref_json_schema = self.get_cache_defs_ref_schema(core_ref) + return ref_json_schema + + def ser_schema( + self, schema: core_schema.SerSchema | core_schema.IncExSeqSerSchema | core_schema.IncExDictSerSchema + ) -> JsonSchemaValue | None: + """Generates a JSON schema that matches a schema that defines a serialized object. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + schema_type = schema['type'] + if schema_type == 'function-plain' or schema_type == 'function-wrap': + # PlainSerializerFunctionSerSchema or WrapSerializerFunctionSerSchema + return_schema = schema.get('return_schema') + if return_schema is not None: + return self.generate_inner(return_schema) + elif schema_type == 'format' or schema_type == 'to-string': + # FormatSerSchema or ToStringSerSchema + return self.str_schema(core_schema.str_schema()) + elif schema['type'] == 'model': + # ModelSerSchema + return self.generate_inner(schema['schema']) + return None + + def complex_schema(self, schema: core_schema.ComplexSchema) -> JsonSchemaValue: + """Generates a JSON schema that matches a complex number. + + JSON has no standard way to represent complex numbers. Complex number is not a numeric + type. Here we represent complex number as strings following the rule defined by Python. + For instance, '1+2j' is an accepted complex string. Details can be found in + [Python's `complex` documentation][complex]. + + Args: + schema: The core schema. + + Returns: + The generated JSON schema. + """ + return {'type': 'string'} + + # ### Utility methods + + def get_title_from_name(self, name: str) -> str: + """Retrieves a title from a name. + + Args: + name: The name to retrieve a title from. + + Returns: + The title. + """ + return name.title().replace('_', ' ').strip() + + def field_title_should_be_set(self, schema: CoreSchemaOrField) -> bool: + """Returns true if a field with the given schema should have a title set based on the field name. + + Intuitively, we want this to return true for schemas that wouldn't otherwise provide their own title + (e.g., int, float, str), and false for those that would (e.g., BaseModel subclasses). + + Args: + schema: The schema to check. + + Returns: + `True` if the field should have a title set, `False` otherwise. + """ + if _core_utils.is_core_schema_field(schema): + if schema['type'] == 'computed-field': + field_schema = schema['return_schema'] + else: + field_schema = schema['schema'] + return self.field_title_should_be_set(field_schema) + + elif _core_utils.is_core_schema(schema): + if schema.get('ref'): # things with refs, such as models and enums, should not have titles set + return False + if schema['type'] in {'default', 'nullable', 'definitions'}: + return self.field_title_should_be_set(schema['schema']) # type: ignore[typeddict-item] + if _core_utils.is_function_with_inner_schema(schema): + return self.field_title_should_be_set(schema['schema']) + if schema['type'] == 'definition-ref': + # Referenced schemas should not have titles set for the same reason + # schemas with refs should not + return False + return True # anything else should have title set + + else: + raise PydanticInvalidForJsonSchema(f'Unexpected schema type: schema={schema}') # pragma: no cover + + def normalize_name(self, name: str) -> str: + """Normalizes a name to be used as a key in a dictionary. + + Args: + name: The name to normalize. + + Returns: + The normalized name. + """ + return re.sub(r'[^a-zA-Z0-9.\-_]', '_', name).replace('.', '__') + + def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef: + """Override this method to change the way that definitions keys are generated from a core reference. + + Args: + core_mode_ref: The core reference. + + Returns: + The definitions key. + """ + # Split the core ref into "components"; generic origins and arguments are each separate components + core_ref, mode = core_mode_ref + components = re.split(r'([\][,])', core_ref) + # Remove IDs from each component + components = [x.rsplit(':', 1)[0] for x in components] + core_ref_no_id = ''.join(components) + # Remove everything before the last period from each "component" + components = [re.sub(r'(?:[^.[\]]+\.)+((?:[^.[\]]+))', r'\1', x) for x in components] + short_ref = ''.join(components) + + mode_title = _MODE_TITLE_MAPPING[mode] + + # It is important that the generated defs_ref values be such that at least one choice will not + # be generated for any other core_ref. Currently, this should be the case because we include + # the id of the source type in the core_ref + name = DefsRef(self.normalize_name(short_ref)) + name_mode = DefsRef(self.normalize_name(short_ref) + f'-{mode_title}') + module_qualname = DefsRef(self.normalize_name(core_ref_no_id)) + module_qualname_mode = DefsRef(f'{module_qualname}-{mode_title}') + module_qualname_id = DefsRef(self.normalize_name(core_ref)) + occurrence_index = self._collision_index.get(module_qualname_id) + if occurrence_index is None: + self._collision_counter[module_qualname] += 1 + occurrence_index = self._collision_index[module_qualname_id] = self._collision_counter[module_qualname] + + module_qualname_occurrence = DefsRef(f'{module_qualname}__{occurrence_index}') + module_qualname_occurrence_mode = DefsRef(f'{module_qualname_mode}__{occurrence_index}') + + self._prioritized_defsref_choices[module_qualname_occurrence_mode] = [ + name, + name_mode, + module_qualname, + module_qualname_mode, + module_qualname_occurrence, + module_qualname_occurrence_mode, + ] + + return module_qualname_occurrence_mode + + def get_cache_defs_ref_schema(self, core_ref: CoreRef) -> tuple[DefsRef, JsonSchemaValue]: + """This method wraps the get_defs_ref method with some cache-lookup/population logic, + and returns both the produced defs_ref and the JSON schema that will refer to the right definition. + + Args: + core_ref: The core reference to get the definitions reference for. + + Returns: + A tuple of the definitions reference and the JSON schema that will refer to it. + """ + core_mode_ref = (core_ref, self.mode) + maybe_defs_ref = self.core_to_defs_refs.get(core_mode_ref) + if maybe_defs_ref is not None: + json_ref = self.core_to_json_refs[core_mode_ref] + return maybe_defs_ref, {'$ref': json_ref} + + defs_ref = self.get_defs_ref(core_mode_ref) + + # populate the ref translation mappings + self.core_to_defs_refs[core_mode_ref] = defs_ref + self.defs_to_core_refs[defs_ref] = core_mode_ref + + json_ref = JsonRef(self.ref_template.format(model=defs_ref)) + self.core_to_json_refs[core_mode_ref] = json_ref + self.json_to_defs_refs[json_ref] = defs_ref + ref_json_schema = {'$ref': json_ref} + return defs_ref, ref_json_schema + + def handle_ref_overrides(self, json_schema: JsonSchemaValue) -> JsonSchemaValue: + """Remove any sibling keys that are redundant with the referenced schema. + + Args: + json_schema: The schema to remove redundant sibling keys from. + + Returns: + The schema with redundant sibling keys removed. + """ + if '$ref' in json_schema: + # prevent modifications to the input; this copy may be safe to drop if there is significant overhead + json_schema = json_schema.copy() + + referenced_json_schema = self.get_schema_from_definitions(JsonRef(json_schema['$ref'])) + if referenced_json_schema is None: + # This can happen when building schemas for models with not-yet-defined references. + # It may be a good idea to do a recursive pass at the end of the generation to remove + # any redundant override keys. + return json_schema + for k, v in list(json_schema.items()): + if k == '$ref': + continue + if k in referenced_json_schema and referenced_json_schema[k] == v: + del json_schema[k] # redundant key + + return json_schema + + def get_schema_from_definitions(self, json_ref: JsonRef) -> JsonSchemaValue | None: + try: + def_ref = self.json_to_defs_refs[json_ref] + if def_ref in self._core_defs_invalid_for_json_schema: + raise self._core_defs_invalid_for_json_schema[def_ref] + return self.definitions.get(def_ref, None) + except KeyError: + if json_ref.startswith(('http://', 'https://')): + return None + raise + + def encode_default(self, dft: Any) -> Any: + """Encode a default value to a JSON-serializable value. + + This is used to encode default values for fields in the generated JSON schema. + + Args: + dft: The default value to encode. + + Returns: + The encoded default value. + """ + from .type_adapter import TypeAdapter, _type_has_config + + config = self._config + try: + default = ( + dft + if _type_has_config(type(dft)) + else TypeAdapter(type(dft), config=config.config_dict).dump_python( + dft, by_alias=self.by_alias, mode='json' + ) + ) + except PydanticSchemaGenerationError: + raise pydantic_core.PydanticSerializationError(f'Unable to encode default value {dft}') + + return pydantic_core.to_jsonable_python( + default, timedelta_mode=config.ser_json_timedelta, bytes_mode=config.ser_json_bytes, by_alias=self.by_alias + ) + + def update_with_validations( + self, json_schema: JsonSchemaValue, core_schema: CoreSchema, mapping: dict[str, str] + ) -> None: + """Update the json_schema with the corresponding validations specified in the core_schema, + using the provided mapping to translate keys in core_schema to the appropriate keys for a JSON schema. + + Args: + json_schema: The JSON schema to update. + core_schema: The core schema to get the validations from. + mapping: A mapping from core_schema attribute names to the corresponding JSON schema attribute names. + """ + for core_key, json_schema_key in mapping.items(): + if core_key in core_schema: + json_schema[json_schema_key] = core_schema[core_key] + + class ValidationsMapping: + """This class just contains mappings from core_schema attribute names to the corresponding + JSON schema attribute names. While I suspect it is unlikely to be necessary, you can in + principle override this class in a subclass of GenerateJsonSchema (by inheriting from + GenerateJsonSchema.ValidationsMapping) to change these mappings. + """ + + numeric = { + 'multiple_of': 'multipleOf', + 'le': 'maximum', + 'ge': 'minimum', + 'lt': 'exclusiveMaximum', + 'gt': 'exclusiveMinimum', + } + bytes = { + 'min_length': 'minLength', + 'max_length': 'maxLength', + } + string = { + 'min_length': 'minLength', + 'max_length': 'maxLength', + 'pattern': 'pattern', + } + array = { + 'min_length': 'minItems', + 'max_length': 'maxItems', + } + object = { + 'min_length': 'minProperties', + 'max_length': 'maxProperties', + } + + def get_flattened_anyof(self, schemas: list[JsonSchemaValue]) -> JsonSchemaValue: + members = [] + for schema in schemas: + if len(schema) == 1 and 'anyOf' in schema: + members.extend(schema['anyOf']) + else: + members.append(schema) + members = _deduplicate_schemas(members) + if len(members) == 1: + return members[0] + return {'anyOf': members} + + def get_json_ref_counts(self, json_schema: JsonSchemaValue) -> dict[JsonRef, int]: + """Get all values corresponding to the key '$ref' anywhere in the json_schema.""" + json_refs: dict[JsonRef, int] = Counter() + + def _add_json_refs(schema: Any) -> None: + if isinstance(schema, dict): + if '$ref' in schema: + json_ref = JsonRef(schema['$ref']) + if not isinstance(json_ref, str): + return # in this case, '$ref' might have been the name of a property + already_visited = json_ref in json_refs + json_refs[json_ref] += 1 + if already_visited: + return # prevent recursion on a definition that was already visited + try: + defs_ref = self.json_to_defs_refs[json_ref] + if defs_ref in self._core_defs_invalid_for_json_schema: + raise self._core_defs_invalid_for_json_schema[defs_ref] + _add_json_refs(self.definitions[defs_ref]) + except KeyError: + if not json_ref.startswith(('http://', 'https://')): + raise + + for k, v in schema.items(): + if k == 'examples' and isinstance(v, list): + # Skip examples that may contain arbitrary values and references + # (see the comment in `_get_all_json_refs` for more details). + continue + _add_json_refs(v) + elif isinstance(schema, list): + for v in schema: + _add_json_refs(v) + + _add_json_refs(json_schema) + return json_refs + + def handle_invalid_for_json_schema(self, schema: CoreSchemaOrField, error_info: str) -> JsonSchemaValue: + raise PydanticInvalidForJsonSchema(f'Cannot generate a JsonSchema for {error_info}') + + def emit_warning(self, kind: JsonSchemaWarningKind, detail: str) -> None: + """This method simply emits PydanticJsonSchemaWarnings based on handling in the `warning_message` method.""" + message = self.render_warning_message(kind, detail) + if message is not None: + warnings.warn(message, PydanticJsonSchemaWarning) + + def render_warning_message(self, kind: JsonSchemaWarningKind, detail: str) -> str | None: + """This method is responsible for ignoring warnings as desired, and for formatting the warning messages. + + You can override the value of `ignored_warning_kinds` in a subclass of GenerateJsonSchema + to modify what warnings are generated. If you want more control, you can override this method; + just return None in situations where you don't want warnings to be emitted. + + Args: + kind: The kind of warning to render. It can be one of the following: + + - 'skipped-choice': A choice field was skipped because it had no valid choices. + - 'non-serializable-default': A default value was skipped because it was not JSON-serializable. + detail: A string with additional details about the warning. + + Returns: + The formatted warning message, or `None` if no warning should be emitted. + """ + if kind in self.ignored_warning_kinds: + return None + return f'{detail} [{kind}]' + + def _build_definitions_remapping(self) -> _DefinitionsRemapping: + defs_to_json: dict[DefsRef, JsonRef] = {} + for defs_refs in self._prioritized_defsref_choices.values(): + for defs_ref in defs_refs: + json_ref = JsonRef(self.ref_template.format(model=defs_ref)) + defs_to_json[defs_ref] = json_ref + + return _DefinitionsRemapping.from_prioritized_choices( + self._prioritized_defsref_choices, defs_to_json, self.definitions + ) + + def _garbage_collect_definitions(self, schema: JsonSchemaValue) -> None: + visited_defs_refs: set[DefsRef] = set() + unvisited_json_refs = _get_all_json_refs(schema) + while unvisited_json_refs: + next_json_ref = unvisited_json_refs.pop() + try: + next_defs_ref = self.json_to_defs_refs[next_json_ref] + if next_defs_ref in visited_defs_refs: + continue + visited_defs_refs.add(next_defs_ref) + unvisited_json_refs.update(_get_all_json_refs(self.definitions[next_defs_ref])) + except KeyError: + if not next_json_ref.startswith(('http://', 'https://')): + raise + + self.definitions = {k: v for k, v in self.definitions.items() if k in visited_defs_refs} + + +# ##### Start JSON Schema Generation Functions ##### + + +def model_json_schema( + cls: type[BaseModel] | type[PydanticDataclass], + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + mode: JsonSchemaMode = 'validation', +) -> dict[str, Any]: + """Utility function to generate a JSON Schema for a model. + + Args: + cls: The model class to generate a JSON Schema for. + by_alias: If `True` (the default), fields will be serialized according to their alias. + If `False`, fields will be serialized according to their attribute name. + ref_template: The template to use for generating JSON Schema references. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: The class to use for generating the JSON Schema. + mode: The mode to use for generating the JSON Schema. It can be one of the following: + + - 'validation': Generate a JSON Schema for validating data. + - 'serialization': Generate a JSON Schema for serializing data. + + Returns: + The generated JSON Schema. + """ + from .main import BaseModel + + schema_generator_instance = schema_generator( + by_alias=by_alias, ref_template=ref_template, union_format=union_format + ) + + if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): + cls.__pydantic_core_schema__.rebuild() + + if cls is BaseModel: + raise AttributeError('model_json_schema() must be called on a subclass of BaseModel, not BaseModel itself.') + + assert not isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' + return schema_generator_instance.generate(cls.__pydantic_core_schema__, mode=mode) + + +def models_json_schema( + models: Sequence[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode]], + *, + by_alias: bool = True, + title: str | None = None, + description: str | None = None, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, +) -> tuple[dict[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: + """Utility function to generate a JSON Schema for multiple models. + + Args: + models: A sequence of tuples of the form (model, mode). + by_alias: Whether field aliases should be used as keys in the generated JSON Schema. + title: The title of the generated JSON Schema. + description: The description of the generated JSON Schema. + ref_template: The reference template to use for generating JSON Schema references. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: The schema generator to use for generating the JSON Schema. + + Returns: + A tuple where: + - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and + whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have + JsonRef references to definitions that are defined in the second returned element.) + - The second element is a JSON schema containing all definitions referenced in the first returned + element, along with the optional title and description keys. + """ + for cls, _ in models: + if isinstance(cls.__pydantic_core_schema__, _mock_val_ser.MockCoreSchema): + cls.__pydantic_core_schema__.rebuild() + + instance = schema_generator(by_alias=by_alias, ref_template=ref_template, union_format=union_format) + inputs: list[tuple[type[BaseModel] | type[PydanticDataclass], JsonSchemaMode, CoreSchema]] = [ + (m, mode, m.__pydantic_core_schema__) for m, mode in models + ] + json_schemas_map, definitions = instance.generate_definitions(inputs) + + json_schema: dict[str, Any] = {} + if definitions: + json_schema['$defs'] = definitions + if title: + json_schema['title'] = title + if description: + json_schema['description'] = description + + return json_schemas_map, json_schema + + +# ##### End JSON Schema Generation Functions ##### + + +_HashableJsonValue: TypeAlias = Union[ + int, float, str, bool, None, tuple['_HashableJsonValue', ...], tuple[tuple[str, '_HashableJsonValue'], ...] +] + + +def _deduplicate_schemas(schemas: Iterable[JsonDict]) -> list[JsonDict]: + return list({_make_json_hashable(schema): schema for schema in schemas}.values()) + + +def _make_json_hashable(value: JsonValue) -> _HashableJsonValue: + if isinstance(value, dict): + return tuple(sorted((k, _make_json_hashable(v)) for k, v in value.items())) + elif isinstance(value, list): + return tuple(_make_json_hashable(v) for v in value) + else: + return value + + +@dataclasses.dataclass(**_internal_dataclass.slots_true) +class WithJsonSchema: + """!!! abstract "Usage Documentation" + [`WithJsonSchema` Annotation](../concepts/json_schema.md#withjsonschema-annotation) + + An annotation used to override the JSON Schema for a type. + + This is useful when you want to set a JSON Schema for a type that don't produce any JSON Schemas by default + (e.g. [`Callable`][collections.abc.Callable]). + + If `mode` is set this will only apply to that schema generation mode, allowing you to set different JSON Schemas for validation and serialization. + + !!! note + If the `WithJsonSchema` annotation is coupled with the [`Field()`][pydantic.Field] function, the behavior overriding will vary depending on the location: + + * If the [`Annotated`][typing.Annotated] metadata is specified at the "top-level" field, `Field()` metadata arguments + (excluding [constraints](../concepts/fields.md#field-constraints)) such as `title` and `description` will be applied on + top of the `WithJsonSchema`, no matter the order: + + ```python + from typing import Annotated + + from pydantic import BaseModel, Field, WithJsonSchema + + class Model(BaseModel): + field: Annotated[ + int, + Field(title='My Field'), + WithJsonSchema({'type': 'integer', 'extra': 'data'}), + ] + + Model.model_json_schema()['properties']['field'] + #> {'type': 'integer', 'extra': 'data', 'title': 'My Field'} + ``` + + * If the [`Annotated`][typing.Annotated] metadata is specified on a specific inner type, `WithJsonSchema` will unconditionally + override the JSON Schema: + + ```python + from typing import Annotated + + from pydantic import BaseModel, Field, WithJsonSchema + + class Model(BaseModel): + field: list[ + Annotated[ + int, + Field(title='My Field'), + WithJsonSchema({'type': 'integer', 'extra': 'data'}), + ] + ] + + Model.model_json_schema()['properties']['field'] + #> {'items': {'extra': 'data', 'type': 'integer'}, 'title': 'Field', 'type': 'array'} + ``` + + See also the documentation about [the annotated pattern](../concepts/fields.md#the-annotated-pattern). + """ + + json_schema: JsonSchemaValue | None + mode: Literal['validation', 'serialization'] | None = None + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + if self.mode is not None and self.mode != handler.mode: + return handler(core_schema) + if self.json_schema is None: + # This exception is handled in pydantic.json_schema.GenerateJsonSchema._named_required_fields_schema + raise PydanticOmit + else: + return self.json_schema.copy() + + def __hash__(self) -> int: + return hash(type(self.mode)) + + +class Examples: + """Add examples to a JSON schema. + + If the JSON Schema already contains examples, the provided examples + will be appended. + + If `mode` is set this will only apply to that schema generation mode, + allowing you to add different examples for validation and serialization. + """ + + @overload + @deprecated('Using a dict for `examples` is deprecated since v2.9 and will be removed in v3.0. Use a list instead.') + def __init__( + self, examples: dict[str, Any], mode: Literal['validation', 'serialization'] | None = None + ) -> None: ... + + @overload + def __init__(self, examples: list[Any], mode: Literal['validation', 'serialization'] | None = None) -> None: ... + + def __init__( + self, examples: dict[str, Any] | list[Any], mode: Literal['validation', 'serialization'] | None = None + ) -> None: + if isinstance(examples, dict): + warnings.warn( + 'Using a dict for `examples` is deprecated, use a list instead.', + PydanticDeprecatedSince29, + stacklevel=2, + ) + self.examples = examples + self.mode = mode + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + mode = self.mode or handler.mode + json_schema = handler(core_schema) + if mode != handler.mode: + return json_schema + examples = json_schema.get('examples') + if examples is None: + json_schema['examples'] = to_jsonable_python(self.examples) + if isinstance(examples, dict): + if isinstance(self.examples, list): + warnings.warn( + 'Updating existing JSON Schema examples of type dict with examples of type list. ' + 'Only the existing examples values will be retained. Note that dict support for ' + 'examples is deprecated and will be removed in v3.0.', + UserWarning, + ) + json_schema['examples'] = to_jsonable_python( + [ex for value in examples.values() for ex in value] + self.examples + ) + else: + json_schema['examples'] = to_jsonable_python({**examples, **self.examples}) + if isinstance(examples, list): + if isinstance(self.examples, list): + json_schema['examples'] = to_jsonable_python(examples + self.examples) + elif isinstance(self.examples, dict): + warnings.warn( + 'Updating existing JSON Schema examples of type list with examples of type dict. ' + 'Only the examples values will be retained. Note that dict support for ' + 'examples is deprecated and will be removed in v3.0.', + UserWarning, + ) + json_schema['examples'] = to_jsonable_python( + examples + [ex for value in self.examples.values() for ex in value] + ) + + return json_schema + + def __hash__(self) -> int: + return hash(type(self.mode)) + + +def _get_all_json_refs(item: Any) -> set[JsonRef]: + """Get all the definitions references from a JSON schema.""" + refs: set[JsonRef] = set() + stack = [item] + + while stack: + current = stack.pop() + if isinstance(current, dict): + for key, value in current.items(): + if key == 'examples' and isinstance(value, list): + # Skip examples that may contain arbitrary values and references + # (e.g. `{"examples": [{"$ref": "..."}]}`). Note: checking for value + # of type list is necessary to avoid skipping valid portions of the schema, + # for instance when "examples" is used as a property key. A more robust solution + # could be found, but would require more advanced JSON Schema parsing logic. + continue + if key == '$ref' and isinstance(value, str): + refs.add(JsonRef(value)) + elif isinstance(value, dict): + stack.append(value) + elif isinstance(value, list): + stack.extend(value) + elif isinstance(current, list): + stack.extend(current) + + return refs + + +AnyType = TypeVar('AnyType') + +if TYPE_CHECKING: + SkipJsonSchema = Annotated[AnyType, ...] +else: + + @dataclasses.dataclass(**_internal_dataclass.slots_true) + class SkipJsonSchema: + """!!! abstract "Usage Documentation" + [`SkipJsonSchema` Annotation](../concepts/json_schema.md#skipjsonschema-annotation) + + Add this as an annotation on a field to skip generating a JSON schema for that field. + + Example: + ```python + from pprint import pprint + from typing import Union + + from pydantic import BaseModel + from pydantic.json_schema import SkipJsonSchema + + class Model(BaseModel): + a: Union[int, None] = None # (1)! + b: Union[int, SkipJsonSchema[None]] = None # (2)! + c: SkipJsonSchema[Union[int, None]] = None # (3)! + + pprint(Model.model_json_schema()) + ''' + { + 'properties': { + 'a': { + 'anyOf': [ + {'type': 'integer'}, + {'type': 'null'} + ], + 'default': None, + 'title': 'A' + }, + 'b': { + 'default': None, + 'title': 'B', + 'type': 'integer' + } + }, + 'title': 'Model', + 'type': 'object' + } + ''' + ``` + + 1. The integer and null types are both included in the schema for `a`. + 2. The integer type is the only type included in the schema for `b`. + 3. The entirety of the `c` field is omitted from the schema. + """ + + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + def __get_pydantic_json_schema__( + self, core_schema: CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + raise PydanticOmit + + def __hash__(self) -> int: + return hash(type(self)) + + +def _get_typed_dict_config(cls: type[Any] | None) -> ConfigDict: + if cls is not None: + try: + return _decorators.get_attribute_from_bases(cls, '__pydantic_config__') + except AttributeError: + pass + return {} + + +def _get_ser_schema_for_default_value(schema: CoreSchema) -> core_schema.PlainSerializerFunctionSerSchema | None: + """Get a `'function-plain'` serialization schema that can be used to serialize a default value. + + This takes into account having the serialization schema nested under validation schema(s). + """ + if ( + (ser_schema := schema.get('serialization')) + and ser_schema['type'] == 'function-plain' + and not ser_schema.get('info_arg') + ): + return ser_schema + if _core_utils.is_function_with_inner_schema(schema): + return _get_ser_schema_for_default_value(schema['schema']) diff --git a/source/target-vendors/cp312/pydantic/main.py b/source/target-vendors/cp312/pydantic/main.py new file mode 100644 index 0000000..2ed62e5 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/main.py @@ -0,0 +1,1838 @@ +"""Logic for creating models.""" + +# Because `dict` is in the local namespace of the `BaseModel` class, we use `Dict` for annotations. +# TODO v3 fallback to `dict` when the deprecated `dict` method gets removed. +# ruff: noqa: UP035 + +from __future__ import annotations as _annotations + +import operator +import sys +import types +import warnings +from collections.abc import Generator, Mapping +from copy import copy, deepcopy +from functools import cached_property +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Dict, + Generic, + Literal, + TypeVar, + Union, + cast, + overload, +) + +import pydantic_core +import typing_extensions +from pydantic_core import PydanticUndefined, ValidationError +from typing_extensions import Self, TypeAlias, Unpack + +from . import PydanticDeprecatedSince20, PydanticDeprecatedSince211 +from ._internal import ( + _config, + _decorators, + _fields, + _forward_ref, + _generics, + _mock_val_ser, + _model_construction, + _namespace_utils, + _repr, + _typing_extra, + _utils, +) +from ._migration import getattr_migration +from .aliases import AliasChoices, AliasPath +from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler +from .config import ConfigDict, ExtraValues +from .errors import PydanticUndefinedAnnotation, PydanticUserError +from .json_schema import DEFAULT_REF_TEMPLATE, GenerateJsonSchema, JsonSchemaMode, JsonSchemaValue, model_json_schema +from .plugin._schema_validator import PluggableSchemaValidator + +if TYPE_CHECKING: + from inspect import Signature + from pathlib import Path + + from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator + + from ._internal._fields import PydanticExtraInfo + from ._internal._namespace_utils import MappingNamespace + from ._internal._utils import AbstractSetIntStr, MappingIntStrAny + from .deprecated.parse import Protocol as DeprecatedParseProtocol + from .fields import ComputedFieldInfo, FieldInfo, ModelPrivateAttr + + +__all__ = 'BaseModel', 'create_model' + +# Keep these type aliases available at runtime: +TupleGenerator: TypeAlias = Generator[tuple[str, Any], None, None] +# NOTE: In reality, `bool` should be replaced by `Literal[True]` but mypy fails to correctly apply bidirectional +# type inference (e.g. when using `{'a': {'b': True}}`): +# NOTE: Keep this type alias in sync with the stub definition in `pydantic-core`: +IncEx: TypeAlias = Union[set[int], set[str], Mapping[int, Union['IncEx', bool]], Mapping[str, Union['IncEx', bool]]] + +_object_setattr = _model_construction.object_setattr + + +def _check_frozen(model_cls: type[BaseModel], name: str, value: Any) -> None: + if model_cls.model_config.get('frozen'): + error_type = 'frozen_instance' + elif getattr(model_cls.__pydantic_fields__.get(name), 'frozen', False): + error_type = 'frozen_field' + else: + return + + raise ValidationError.from_exception_data( + model_cls.__name__, [{'type': error_type, 'loc': (name,), 'input': value}] + ) + + +def _model_field_setattr_handler(model: BaseModel, name: str, val: Any) -> None: + model.__dict__[name] = val + model.__pydantic_fields_set__.add(name) + + +def _private_setattr_handler(model: BaseModel, name: str, val: Any) -> None: + if getattr(model, '__pydantic_private__', None) is None: + # While the attribute should be present at this point, this may not be the case if + # users do unusual stuff with `model_post_init()` (which is where the `__pydantic_private__` + # is initialized, by wrapping the user-defined `model_post_init()`), e.g. if they mock + # the `model_post_init()` call. Ideally we should find a better way to init private attrs. + object.__setattr__(model, '__pydantic_private__', {}) + model.__pydantic_private__[name] = val # pyright: ignore[reportOptionalSubscript] + + +_SIMPLE_SETATTR_HANDLERS: Mapping[str, Callable[[BaseModel, str, Any], None]] = { + 'model_field': _model_field_setattr_handler, + 'validate_assignment': lambda model, name, val: model.__pydantic_validator__.validate_assignment(model, name, val), # pyright: ignore[reportAssignmentType] + 'private': _private_setattr_handler, + 'cached_property': lambda model, name, val: model.__dict__.__setitem__(name, val), + 'extra_known': lambda model, name, val: _object_setattr(model, name, val), +} + + +class BaseModel(metaclass=_model_construction.ModelMetaclass): + """!!! abstract "Usage Documentation" + [Models](../concepts/models.md) + + A base class for creating Pydantic models. + + Attributes: + __class_vars__: The names of the class variables defined on the model. + __private_attributes__: Metadata about the private attributes of the model. + __signature__: The synthesized `__init__` [`Signature`][inspect.Signature] of the model. + + __pydantic_complete__: Whether model building is completed, or if there are still undefined fields. + __pydantic_core_schema__: The core schema of the model. + __pydantic_custom_init__: Whether the model has a custom `__init__` function. + __pydantic_decorators__: Metadata containing the decorators defined on the model. + This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1. + __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. + The `origin` and `args` items map to the [`__origin__`][genericalias.__origin__] + and [`__args__`][genericalias.__args__] attributes of [generic aliases][types-genericalias], + and the `parameter` item maps to the `__parameter__` attribute of generic classes. + __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models. + __pydantic_post_init__: The name of the post-init method for the model, if defined. + __pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel]. + __pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model. + __pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model. + + __pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects. + __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects. + + __pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra] + is set to `'allow'`. + __pydantic_fields_set__: The names of fields explicitly set during instantiation. + __pydantic_private__: Values of private attributes set on the model instance. + """ + + # Note: Many of the below class vars are defined in the metaclass, but we define them here for type checking purposes. + + model_config: ClassVar[ConfigDict] = ConfigDict() + """ + Configuration for the model, should be a dictionary conforming to [`ConfigDict`][pydantic.config.ConfigDict]. + """ + + __class_vars__: ClassVar[set[str]] + """The names of the class variables defined on the model.""" + + __private_attributes__: ClassVar[Dict[str, ModelPrivateAttr]] # noqa: UP006 + """Metadata about the private attributes of the model.""" + + __signature__: ClassVar[Signature] + """The synthesized `__init__` [`Signature`][inspect.Signature] of the model.""" + + __pydantic_complete__: ClassVar[bool] = False + """Whether model building is completed, or if there are still undefined fields.""" + + __pydantic_core_schema__: ClassVar[CoreSchema] + """The core schema of the model.""" + + __pydantic_custom_init__: ClassVar[bool] + """Whether the model has a custom `__init__` method.""" + + # Must be set for `GenerateSchema.model_schema` to work for a plain `BaseModel` annotation. + __pydantic_decorators__: ClassVar[_decorators.DecoratorInfos] = _decorators.DecoratorInfos() + """Metadata containing the decorators defined on the model. + This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.""" + + __pydantic_generic_metadata__: ClassVar[_generics.PydanticGenericMetadata] + """A dictionary containing metadata about generic Pydantic models. + + The `origin` and `args` items map to the [`__origin__`][genericalias.__origin__] + and [`__args__`][genericalias.__args__] attributes of [generic aliases][types-genericalias], + and the `parameter` item maps to the `__parameter__` attribute of generic classes. + """ + + __pydantic_parent_namespace__: ClassVar[Dict[str, Any] | None] = None # noqa: UP006 + """Parent namespace of the model, used for automatic rebuilding of models.""" + + __pydantic_post_init__: ClassVar[None | Literal['model_post_init']] + """The name of the post-init method for the model, if defined.""" + + __pydantic_root_model__: ClassVar[bool] = False + """Whether the model is a [`RootModel`][pydantic.root_model.RootModel].""" + + __pydantic_serializer__: ClassVar[SchemaSerializer] + """The `pydantic-core` `SchemaSerializer` used to dump instances of the model.""" + + __pydantic_validator__: ClassVar[SchemaValidator | PluggableSchemaValidator] + """The `pydantic-core` `SchemaValidator` used to validate instances of the model.""" + + __pydantic_fields__: ClassVar[Dict[str, FieldInfo]] # noqa: UP006 + """A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects. + This replaces `Model.__fields__` from Pydantic V1. + """ + + __pydantic_setattr_handlers__: ClassVar[Dict[str, Callable[[BaseModel, str, Any], None]]] # noqa: UP006 + """`__setattr__` handlers. Memoizing the handlers leads to a dramatic performance improvement in `__setattr__`""" + + __pydantic_computed_fields__: ClassVar[Dict[str, ComputedFieldInfo]] # noqa: UP006 + """A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.""" + + __pydantic_extra_info__: ClassVar[PydanticExtraInfo | None] + """A wrapper around the `__pydantic_extra__` annotation, if explicitly annotated on a model. + + This is a private attribute, not meant to be used outside Pydantic. + """ + + __pydantic_extra__: Dict[str, Any] | None = _model_construction.NoInitField(init=False) # noqa: UP006 + """A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra] is set to `'allow'`.""" + + __pydantic_fields_set__: set[str] = _model_construction.NoInitField(init=False) + """The names of fields explicitly set during instantiation.""" + + __pydantic_private__: Dict[str, Any] | None = _model_construction.NoInitField(init=False) # noqa: UP006 + """Values of private attributes set on the model instance.""" + + if not TYPE_CHECKING: + # Prevent `BaseModel` from being instantiated directly + # (defined in an `if not TYPE_CHECKING` block for clarity and to avoid type checking errors): + __pydantic_core_schema__ = _mock_val_ser.MockCoreSchema( + 'Pydantic models should inherit from BaseModel, BaseModel cannot be instantiated directly', + code='base-model-instantiated', + ) + __pydantic_validator__ = _mock_val_ser.MockValSer( + 'Pydantic models should inherit from BaseModel, BaseModel cannot be instantiated directly', + val_or_ser='validator', + code='base-model-instantiated', + ) + __pydantic_serializer__ = _mock_val_ser.MockValSer( + 'Pydantic models should inherit from BaseModel, BaseModel cannot be instantiated directly', + val_or_ser='serializer', + code='base-model-instantiated', + ) + + __slots__ = '__dict__', '__pydantic_fields_set__', '__pydantic_extra__', '__pydantic_private__' + + def __init__(self, /, **data: Any) -> None: + """Create a new model by parsing and validating input data from keyword arguments. + + Raises [`ValidationError`][pydantic_core.ValidationError] if the input data cannot be + validated to form a valid model. + + `self` is explicitly positional-only to allow `self` as a field name. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self) + if self is not validated_self: + warnings.warn( + 'A custom validator is returning a value other than `self`.\n' + "Returning anything other than `self` from a top level model validator isn't supported when validating via `__init__`.\n" + 'See the `model_validator` docs (https://docs.pydantic.dev/latest/concepts/validators/#model-validators) for more details.', + stacklevel=2, + ) + + # The following line sets a flag that we use to determine when `__init__` gets overridden by the user + __init__.__pydantic_base_init__ = True # pyright: ignore[reportFunctionMemberAccess] + + @_utils.deprecated_instance_property + @classmethod + def model_fields(cls) -> dict[str, FieldInfo]: + """A mapping of field names to their respective [`FieldInfo`][pydantic.fields.FieldInfo] instances. + + !!! warning + Accessing this attribute from a model instance is deprecated, and will not work in Pydantic V3. + Instead, you should access this attribute from the model class. + """ + return getattr(cls, '__pydantic_fields__', {}) + + @_utils.deprecated_instance_property + @classmethod + def model_computed_fields(cls) -> dict[str, ComputedFieldInfo]: + """A mapping of computed field names to their respective [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] instances. + + !!! warning + Accessing this attribute from a model instance is deprecated, and will not work in Pydantic V3. + Instead, you should access this attribute from the model class. + """ + return getattr(cls, '__pydantic_computed_fields__', {}) + + @property + def model_extra(self) -> dict[str, Any] | None: + """Get extra fields set during validation. + + Returns: + A dictionary of extra fields, or `None` if `config.extra` is not set to `"allow"`. + """ + return self.__pydantic_extra__ + + @property + def model_fields_set(self) -> set[str]: + """Returns the set of fields that have been explicitly set on this model instance. + + Returns: + A set of strings representing the fields that have been set, + i.e. that were not filled from defaults. + """ + return self.__pydantic_fields_set__ + + @classmethod + def model_construct(cls, _fields_set: set[str] | None = None, **values: Any) -> Self: # noqa: C901 + """Creates a new instance of the `Model` class with validated data. + + Creates a new model setting `__dict__` and `__pydantic_fields_set__` from trusted or pre-validated data. + Default values are respected, but no other validation is performed. + + !!! note + `model_construct()` generally respects the `model_config.extra` setting on the provided model. + That is, if `model_config.extra == 'allow'`, then all extra passed values are added to the model instance's `__dict__` + and `__pydantic_extra__` fields. If `model_config.extra == 'ignore'` (the default), then all extra passed values are ignored. + Because no validation is performed with a call to `model_construct()`, having `model_config.extra == 'forbid'` does not result in + an error if extra values are passed, but they will be ignored. + + Args: + _fields_set: A set of field names that were originally explicitly set during instantiation. If provided, + this is directly used for the [`model_fields_set`][pydantic.BaseModel.model_fields_set] attribute. + Otherwise, the field names from the `values` argument will be used. + values: Trusted or pre-validated data dictionary. + + Returns: + A new instance of the `Model` class with validated data. + """ + m = cls.__new__(cls) + fields_values: dict[str, Any] = {} + fields_set = set() + + for name, field in cls.__pydantic_fields__.items(): + if field.alias is not None and field.alias in values: + fields_values[name] = values.pop(field.alias) + fields_set.add(name) + + if (name not in fields_set) and (field.validation_alias is not None): + validation_aliases: list[str | AliasPath] = ( + field.validation_alias.choices + if isinstance(field.validation_alias, AliasChoices) + else [field.validation_alias] + ) + + for alias in validation_aliases: + if isinstance(alias, str) and alias in values: + fields_values[name] = values.pop(alias) + fields_set.add(name) + break + elif isinstance(alias, AliasPath): + value = alias.search_dict_for_path(values) + if value is not PydanticUndefined: + fields_values[name] = value + fields_set.add(name) + break + + if name not in fields_set: + if name in values: + fields_values[name] = values.pop(name) + fields_set.add(name) + elif not field.is_required(): + fields_values[name] = field.get_default(call_default_factory=True, validated_data=fields_values) + if _fields_set is None: + _fields_set = fields_set + + _extra: dict[str, Any] | None = values if cls.model_config.get('extra') == 'allow' else None + _object_setattr(m, '__dict__', fields_values) + _object_setattr(m, '__pydantic_fields_set__', _fields_set) + if not cls.__pydantic_root_model__: + _object_setattr(m, '__pydantic_extra__', _extra) + _object_setattr(m, '__pydantic_private__', None) + + if cls.__pydantic_post_init__: + m.model_post_init(None) + # update private attributes with values set + if hasattr(m, '__pydantic_private__') and m.__pydantic_private__ is not None: + for k, v in values.items(): + if k in m.__private_attributes__: + m.__pydantic_private__[k] = v + + return m + + def model_copy(self, *, update: Mapping[str, Any] | None = None, deep: bool = False) -> Self: + """!!! abstract "Usage Documentation" + [`model_copy`](../concepts/models.md#model-copy) + + Returns a copy of the model. + + !!! note + The underlying instance's [`__dict__`][object.__dict__] attribute is copied. This + might have unexpected side effects if you store anything in it, on top of the model + fields (e.g. the value of [cached properties][functools.cached_property]). + + Args: + update: Values to change/add in the new model. Note: the data is not validated + before creating the new model. You should trust this data. + deep: Set to `True` to make a deep copy of the model. + + Returns: + New model instance. + """ + copied = self.__deepcopy__() if deep else self.__copy__() + if update: + if self.model_config.get('extra') == 'allow': + for k, v in update.items(): + if k in self.__pydantic_fields__: + copied.__dict__[k] = v + else: + if copied.__pydantic_extra__ is None: + copied.__pydantic_extra__ = {} + copied.__pydantic_extra__[k] = v + else: + copied.__dict__.update(update) + copied.__pydantic_fields_set__.update(update.keys()) + return copied + + def model_dump( + self, + *, + mode: Literal['json', 'python'] | str = 'python', + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + ) -> dict[str, Any]: + """!!! abstract "Usage Documentation" + [`model_dump`](../concepts/serialization.md#python-mode) + + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + Args: + mode: The mode in which `to_python` should run. + If mode is 'json', the output will only contain JSON serializable types. + If mode is 'python', the output may contain non-JSON-serializable Python objects. + include: A set of fields to include in the output. + exclude: A set of fields to exclude from the output. + context: Additional context to pass to the serializer. + by_alias: Whether to use the field's alias in the dictionary key if defined. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + + Returns: + A dictionary representation of the model. + """ + return self.__pydantic_serializer__.to_python( + self, + mode=mode, + by_alias=by_alias, + include=include, + exclude=exclude, + context=context, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + polymorphic_serialization=polymorphic_serialization, + ) + + def model_dump_json( + self, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + context: Any | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + ) -> str: + """!!! abstract "Usage Documentation" + [`model_dump_json`](../concepts/serialization.md#json-mode) + + Generates a JSON representation of the model using Pydantic's `to_json` method. + + Args: + indent: Indentation to use in the JSON output. If None is passed, the output will be compact. + ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. + If `False` (the default), these characters will be output as-is. + include: Field(s) to include in the JSON output. + exclude: Field(s) to exclude from the JSON output. + context: Additional context to pass to the serializer. + by_alias: Whether to serialize using field aliases. + exclude_unset: Whether to exclude fields that have not been explicitly set. + exclude_defaults: Whether to exclude fields that are set to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + + Returns: + A JSON string representation of the model. + """ + return self.__pydantic_serializer__.to_json( + self, + indent=indent, + ensure_ascii=ensure_ascii, + include=include, + exclude=exclude, + context=context, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + polymorphic_serialization=polymorphic_serialization, + ).decode() + + @classmethod + def model_json_schema( + cls, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + mode: JsonSchemaMode = 'validation', + *, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + ) -> dict[str, Any]: + """Generates a JSON schema for a model class. + + Args: + by_alias: Whether to use attribute aliases or not. + ref_template: The reference template. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: To override the logic used to generate the JSON schema, as a subclass of + `GenerateJsonSchema` with your desired modifications + mode: The mode in which to generate the schema. + + Returns: + The JSON schema for the given model class. + """ + return model_json_schema( + cls, + by_alias=by_alias, + ref_template=ref_template, + union_format=union_format, + schema_generator=schema_generator, + mode=mode, + ) + + @classmethod + def model_parametrized_name(cls, params: tuple[type[Any], ...]) -> str: + """Compute the class name for parametrizations of generic classes. + + This method can be overridden to achieve a custom naming scheme for generic BaseModels. + + Args: + params: Tuple of types of the class. Given a generic class + `Model` with 2 type variables and a concrete model `Model[str, int]`, + the value `(str, int)` would be passed to `params`. + + Returns: + String representing the new class where `params` are passed to `cls` as type variables. + + Raises: + TypeError: Raised when trying to generate concrete names for non-generic models. + """ + if not issubclass(cls, Generic): + raise TypeError('Concrete names should only be generated for generic models.') + + # Any strings received should represent forward references, so we handle them specially below. + # If we eventually move toward wrapping them in a ForwardRef in __class_getitem__ in the future, + # we may be able to remove this special case. + param_names = [param if isinstance(param, str) else _repr.display_as_type(param) for param in params] + params_component = ', '.join(param_names) + return f'{cls.__name__}[{params_component}]' + + def model_post_init(self, context: Any, /) -> None: + """Override this method to perform additional initialization after `__init__` and `model_construct`. + This is useful if you want to do some validation that requires the entire model to be initialized. + """ + + @classmethod + def model_rebuild( + cls, + *, + force: bool = False, + raise_errors: bool = True, + _parent_namespace_depth: int = 2, + _types_namespace: MappingNamespace | None = None, + ) -> bool | None: + """Try to rebuild the pydantic-core schema for the model. + + This may be necessary when one of the annotations is a ForwardRef which could not be resolved during + the initial attempt to build the schema, and automatic rebuilding fails. + + Args: + force: Whether to force the rebuilding of the model schema, defaults to `False`. + raise_errors: Whether to raise errors, defaults to `True`. + _parent_namespace_depth: The depth level of the parent namespace, defaults to 2. + _types_namespace: The types namespace, defaults to `None`. + + Returns: + Returns `None` if the schema is already "complete" and rebuilding was not required. + If rebuilding _was_ required, returns `True` if rebuilding was successful, otherwise `False`. + """ + already_complete = cls.__pydantic_complete__ + if already_complete and not force: + return None + + cls.__pydantic_complete__ = False + + for attr in ('__pydantic_core_schema__', '__pydantic_validator__', '__pydantic_serializer__'): + if attr in cls.__dict__ and not isinstance(getattr(cls, attr), _mock_val_ser.MockValSer): + # Deleting the validator/serializer is necessary as otherwise they can get reused in + # pydantic-core. We do so only if they aren't mock instances, otherwise — as `model_rebuild()` + # isn't thread-safe — concurrent model instantiations can lead to the parent validator being used. + # Same applies for the core schema that can be reused in schema generation. + delattr(cls, attr) + + if _types_namespace is not None: + rebuild_ns = _types_namespace + elif _parent_namespace_depth > 0: + rebuild_ns = _typing_extra.parent_frame_namespace(parent_depth=_parent_namespace_depth, force=True) or {} + else: + rebuild_ns = {} + + parent_ns = _model_construction.unpack_lenient_weakvaluedict(cls.__pydantic_parent_namespace__) or {} + + ns_resolver = _namespace_utils.NsResolver( + parent_namespace={**rebuild_ns, **parent_ns}, + ) + + return _model_construction.complete_model_class( + cls, + _config.ConfigWrapper(cls.model_config, check=False), + ns_resolver, + raise_errors=raise_errors, + # If the model was already complete, we don't need to call the hook again. + call_on_complete_hook=not already_complete, + is_force_rebuild=force, + ) + + @classmethod + def model_validate( + cls, + obj: Any, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Self: + """Validate a pydantic model instance. + + Args: + obj: The object to validate. + strict: Whether to enforce types strictly. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + from_attributes: Whether to extract data from object attributes. + context: Additional context to pass to the validator. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Raises: + ValidationError: If the object could not be validated. + + Returns: + The validated model instance. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return cls.__pydantic_validator__.validate_python( + obj, + strict=strict, + extra=extra, + from_attributes=from_attributes, + context=context, + by_alias=by_alias, + by_name=by_name, + ) + + @classmethod + def model_validate_json( + cls, + json_data: str | bytes | bytearray, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Self: + """!!! abstract "Usage Documentation" + [JSON Parsing](../concepts/json.md#json-parsing) + + Validate the given JSON data against the Pydantic model. + + Args: + json_data: The JSON data to validate. + strict: Whether to enforce types strictly. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Extra variables to pass to the validator. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated Pydantic model. + + Raises: + ValidationError: If `json_data` is not a JSON string or the object could not be validated. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return cls.__pydantic_validator__.validate_json( + json_data, strict=strict, extra=extra, context=context, by_alias=by_alias, by_name=by_name + ) + + @classmethod + def model_validate_strings( + cls, + obj: Any, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Self: + """Validate the given object with string data against the Pydantic model. + + Args: + obj: The object containing string data to validate. + strict: Whether to enforce types strictly. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Extra variables to pass to the validator. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated Pydantic model. + """ + # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks + __tracebackhide__ = True + + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return cls.__pydantic_validator__.validate_strings( + obj, strict=strict, extra=extra, context=context, by_alias=by_alias, by_name=by_name + ) + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[BaseModel], handler: GetCoreSchemaHandler, /) -> CoreSchema: + # This warning is only emitted when calling `super().__get_pydantic_core_schema__` from a model subclass. + # In the generate schema logic, this method (`BaseModel.__get_pydantic_core_schema__`) is special cased to + # *not* be called if not overridden. + warnings.warn( + 'The `__get_pydantic_core_schema__` method of the `BaseModel` class is deprecated. If you are calling ' + '`super().__get_pydantic_core_schema__` when overriding the method on a Pydantic model, consider using ' + '`handler(source)` instead. However, note that overriding this method on models can lead to unexpected ' + 'side effects.', + PydanticDeprecatedSince211, + stacklevel=2, + ) + # Logic copied over from `GenerateSchema._model_schema`: + schema = cls.__dict__.get('__pydantic_core_schema__') + if schema is not None and not isinstance(schema, _mock_val_ser.MockCoreSchema): + return cls.__pydantic_core_schema__ + + return handler(source) + + @classmethod + def __get_pydantic_json_schema__( + cls, + core_schema: CoreSchema, + handler: GetJsonSchemaHandler, + /, + ) -> JsonSchemaValue: + """Hook into generating the model's JSON schema. + + Args: + core_schema: A `pydantic-core` CoreSchema. + You can ignore this argument and call the handler with a new CoreSchema, + wrap this CoreSchema (`{'type': 'nullable', 'schema': current_schema}`), + or just call the handler with the original schema. + handler: Call into Pydantic's internal JSON schema generation. + This will raise a `pydantic.errors.PydanticInvalidForJsonSchema` if JSON schema + generation fails. + Since this gets called by `BaseModel.model_json_schema` you can override the + `schema_generator` argument to that function to change JSON schema generation globally + for a type. + + Returns: + A JSON schema, as a Python object. + """ + return handler(core_schema) + + @classmethod + def __pydantic_init_subclass__(cls, **kwargs: Any) -> None: + """This is intended to behave just like `__init_subclass__`, but is called by `ModelMetaclass` + only after basic class initialization is complete. In particular, attributes like `model_fields` will + be present when this is called, but forward annotations are not guaranteed to be resolved yet, + meaning that creating an instance of the class may fail. + + This is necessary because `__init_subclass__` will always be called by `type.__new__`, + and it would require a prohibitively large refactor to the `ModelMetaclass` to ensure that + `type.__new__` was called in such a manner that the class would already be sufficiently initialized. + + This will receive the same `kwargs` that would be passed to the standard `__init_subclass__`, namely, + any kwargs passed to the class definition that aren't used internally by Pydantic. + + Args: + **kwargs: Any keyword arguments passed to the class definition that aren't used internally + by Pydantic. + + Note: + You may want to override [`__pydantic_on_complete__()`][pydantic.main.BaseModel.__pydantic_on_complete__] + instead, which is called once the class and its fields are fully initialized and ready for validation. + """ + + @classmethod + def __pydantic_on_complete__(cls) -> None: + """This is called once the class and its fields are fully initialized and ready to be used. + + This typically happens when the class is created (just before + [`__pydantic_init_subclass__()`][pydantic.main.BaseModel.__pydantic_init_subclass__] is called on the superclass), + except when forward annotations are used that could not immediately be resolved. + In that case, it will be called later, when the model is rebuilt automatically or explicitly using + [`model_rebuild()`][pydantic.main.BaseModel.model_rebuild]. + """ + + def __class_getitem__( + cls, typevar_values: type[Any] | tuple[type[Any], ...] + ) -> type[BaseModel] | _forward_ref.PydanticRecursiveRef: + cached = _generics.get_cached_generic_type_early(cls, typevar_values) + if cached is not None: + return cached + + if cls is BaseModel: + raise TypeError('Type parameters should be placed on typing.Generic, not BaseModel') + if not hasattr(cls, '__parameters__'): + raise TypeError(f'{cls} cannot be parametrized because it does not inherit from typing.Generic') + if not cls.__pydantic_generic_metadata__['parameters'] and Generic not in cls.__bases__: + raise TypeError(f'{cls} is not a generic class') + + if not isinstance(typevar_values, tuple): + typevar_values = (typevar_values,) + + # For a model `class Model[T, U, V = int](BaseModel): ...` parametrized with `(str, bool)`, + # this gives us `{T: str, U: bool, V: int}`: + typevars_map = _generics.map_generic_model_arguments(cls, typevar_values) + # We also update the provided args to use defaults values (`(str, bool)` becomes `(str, bool, int)`): + typevar_values = tuple(v for v in typevars_map.values()) + + if _utils.all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map: + submodel = cls # if arguments are equal to parameters it's the same object + _generics.set_cached_generic_type(cls, typevar_values, submodel) + else: + parent_args = cls.__pydantic_generic_metadata__['args'] + if not parent_args: + args = typevar_values + else: + args = tuple(_generics.replace_types(arg, typevars_map) for arg in parent_args) + + origin = cls.__pydantic_generic_metadata__['origin'] or cls + model_name = origin.model_parametrized_name(args) + params = tuple( + dict.fromkeys(_generics.iter_contained_typevars(typevars_map.values())) + ) # use dict as ordered set + + with _generics.generic_recursion_self_type(origin, args) as maybe_self_type: + cached = _generics.get_cached_generic_type_late(cls, typevar_values, origin, args) + if cached is not None: + return cached + + if maybe_self_type is not None: + return maybe_self_type + + # Attempt to rebuild the origin in case new types have been defined + try: + # depth 2 gets you above this __class_getitem__ call. + # Note that we explicitly provide the parent ns, otherwise + # `model_rebuild` will use the parent ns no matter if it is the ns of a module. + # We don't want this here, as this has unexpected effects when a model + # is being parametrized during a forward annotation evaluation. + parent_ns = _typing_extra.parent_frame_namespace(parent_depth=2) or {} + origin.model_rebuild(_types_namespace=parent_ns) + except PydanticUndefinedAnnotation: + # It's okay if it fails, it just means there are still undefined types + # that could be evaluated later. + pass + + submodel = _generics.create_generic_submodel(model_name, origin, args, params) + + _generics.set_cached_generic_type(cls, typevar_values, submodel, origin, args) + + return submodel + + def __copy__(self) -> Self: + """Returns a shallow copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', copy(self.__dict__)) + _object_setattr(m, '__pydantic_extra__', copy(self.__pydantic_extra__)) + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + + if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None: + _object_setattr(m, '__pydantic_private__', None) + else: + _object_setattr( + m, + '__pydantic_private__', + {k: v for k, v in self.__pydantic_private__.items() if v is not PydanticUndefined}, + ) + + return m + + def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self: + """Returns a deep copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo)) + _object_setattr(m, '__pydantic_extra__', deepcopy(self.__pydantic_extra__, memo=memo)) + # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str], + # and attempting a deepcopy would be marginally slower. + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + + if not hasattr(self, '__pydantic_private__') or self.__pydantic_private__ is None: + _object_setattr(m, '__pydantic_private__', None) + else: + _object_setattr( + m, + '__pydantic_private__', + deepcopy({k: v for k, v in self.__pydantic_private__.items() if v is not PydanticUndefined}, memo=memo), + ) + + return m + + if not TYPE_CHECKING: + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + # The same goes for __setattr__ and __delattr__, see: https://github.com/pydantic/pydantic/issues/8643 + + def __getattr__(self, item: str) -> Any: + private_attributes = object.__getattribute__(self, '__private_attributes__') + if item in private_attributes: + attribute = private_attributes[item] + if hasattr(attribute, '__get__'): + return attribute.__get__(self, type(self)) # type: ignore + + try: + # Note: self.__pydantic_private__ cannot be None if self.__private_attributes__ has items + return self.__pydantic_private__[item] # type: ignore + except KeyError as exc: + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') from exc + else: + # `__pydantic_extra__` can fail to be set if the model is not yet fully initialized. + # See `BaseModel.__repr_args__` for more details + try: + pydantic_extra = object.__getattribute__(self, '__pydantic_extra__') + except AttributeError: + pydantic_extra = None + + if pydantic_extra and item in pydantic_extra: + return pydantic_extra[item] + else: + if hasattr(self.__class__, item): + return super().__getattribute__(item) # Raises AttributeError if appropriate + else: + # this is the current error + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') + + def __setattr__(self, name: str, value: Any) -> None: + if (setattr_handler := self.__pydantic_setattr_handlers__.get(name)) is not None: + setattr_handler(self, name, value) + # if None is returned from _setattr_handler, the attribute was set directly + elif (setattr_handler := self._setattr_handler(name, value)) is not None: + setattr_handler(self, name, value) # call here to not memo on possibly unknown fields + self.__pydantic_setattr_handlers__[name] = setattr_handler # memoize the handler for faster access + + def _setattr_handler(self, name: str, value: Any) -> Callable[[BaseModel, str, Any], None] | None: + """Get a handler for setting an attribute on the model instance. + + Returns: + A handler for setting an attribute on the model instance. Used for memoization of the handler. + Memoizing the handlers leads to a dramatic performance improvement in `__setattr__` + Returns `None` when memoization is not safe, then the attribute is set directly. + """ + cls = self.__class__ + if name in cls.__class_vars__: + raise AttributeError( + f'{name!r} is a ClassVar of `{cls.__name__}` and cannot be set on an instance. ' + f'If you want to set a value on the class, use `{cls.__name__}.{name} = value`.' + ) + elif not _fields.is_valid_field_name(name): + if (attribute := cls.__private_attributes__.get(name)) is not None: + if hasattr(attribute, '__set__'): + return lambda model, _name, val: attribute.__set__(model, val) + else: + return _SIMPLE_SETATTR_HANDLERS['private'] + else: + _object_setattr(self, name, value) + return None # Can not return memoized handler with possibly freeform attr names + + attr = getattr(cls, name, None) + # NOTE: We currently special case properties and `cached_property`, but we might need + # to generalize this to all data/non-data descriptors at some point. For non-data descriptors + # (such as `cached_property`), it isn't obvious though. `cached_property` caches the value + # to the instance's `__dict__`, but other non-data descriptors might do things differently. + if isinstance(attr, cached_property): + return _SIMPLE_SETATTR_HANDLERS['cached_property'] + + _check_frozen(cls, name, value) + + # We allow properties to be set only on non frozen models for now (to match dataclasses). + # This can be changed if it ever gets requested. + if isinstance(attr, property): + return lambda model, _name, val: attr.__set__(model, val) + elif cls.model_config.get('validate_assignment'): + return _SIMPLE_SETATTR_HANDLERS['validate_assignment'] + elif name not in cls.__pydantic_fields__: + if cls.model_config.get('extra') != 'allow': + # TODO - matching error + raise ValueError(f'"{cls.__name__}" object has no field "{name}"') + elif attr is None: + # attribute does not exist, so put it in extra + self.__pydantic_extra__[name] = value + self.__pydantic_fields_set__.add(name) + return None # Can not return memoized handler with possibly freeform attr names + else: + # attribute _does_ exist, and was not in extra, so update it + return _SIMPLE_SETATTR_HANDLERS['extra_known'] + else: + return _SIMPLE_SETATTR_HANDLERS['model_field'] + + def __delattr__(self, item: str) -> Any: + cls = self.__class__ + + if item in self.__private_attributes__: + attribute = self.__private_attributes__[item] + if hasattr(attribute, '__delete__'): + attribute.__delete__(self) # type: ignore + return + + try: + # Note: self.__pydantic_private__ cannot be None if self.__private_attributes__ has items + del self.__pydantic_private__[item] # type: ignore + return + except KeyError as exc: + raise AttributeError(f'{cls.__name__!r} object has no attribute {item!r}') from exc + + # Allow cached properties to be deleted (even if the class is frozen): + attr = getattr(cls, item, None) + if isinstance(attr, cached_property): + return object.__delattr__(self, item) + + _check_frozen(cls, name=item, value=None) + + if item in self.__pydantic_fields__: + object.__delattr__(self, item) + elif self.__pydantic_extra__ is not None and item in self.__pydantic_extra__: + del self.__pydantic_extra__[item] + else: + try: + object.__delattr__(self, item) + except AttributeError: + raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}') + + # Because we make use of `@dataclass_transform()`, `__replace__` is already synthesized by + # type checkers, so we define the implementation in this `if not TYPE_CHECKING:` block: + def __replace__(self, **changes: Any) -> Self: + return self.model_copy(update=changes) + + def __getstate__(self) -> dict[Any, Any]: + private = self.__pydantic_private__ + if private: + private = {k: v for k, v in private.items() if v is not PydanticUndefined} + return { + '__dict__': self.__dict__, + '__pydantic_extra__': self.__pydantic_extra__, + '__pydantic_fields_set__': self.__pydantic_fields_set__, + '__pydantic_private__': private, + } + + def __setstate__(self, state: dict[Any, Any]) -> None: + _object_setattr(self, '__pydantic_fields_set__', state.get('__pydantic_fields_set__', {})) + _object_setattr(self, '__pydantic_extra__', state.get('__pydantic_extra__', {})) + _object_setattr(self, '__pydantic_private__', state.get('__pydantic_private__', {})) + _object_setattr(self, '__dict__', state.get('__dict__', {})) + + if not TYPE_CHECKING: + + def __eq__(self, other: Any) -> bool: + if isinstance(other, BaseModel): + # When comparing instances of generic types for equality, as long as all field values are equal, + # only require their generic origin types to be equal, rather than exact type equality. + # This prevents headaches like MyGeneric(x=1) != MyGeneric[Any](x=1). + self_type = self.__pydantic_generic_metadata__['origin'] or self.__class__ + other_type = other.__pydantic_generic_metadata__['origin'] or other.__class__ + + # Perform common checks first + if not ( + self_type is other_type + and getattr(self, '__pydantic_private__', None) == getattr(other, '__pydantic_private__', None) + # We need to assume `None` and `{}` are equivalent, because extra behavior + # can be controlled at validation time: + and (self.__pydantic_extra__ or {}) == (other.__pydantic_extra__ or {}) + ): + return False + + # We only want to compare pydantic fields but ignoring fields is costly. + # We'll perform a fast check first, and fallback only when needed + # See GH-7444 and GH-7825 for rationale and a performance benchmark + + # First, do the fast (and sometimes faulty) __dict__ comparison + if self.__dict__ == other.__dict__: + # If the check above passes, then pydantic fields are equal, we can return early + return True + + # We don't want to trigger unnecessary costly filtering of __dict__ on all unequal objects, so we return + # early if there are no keys to ignore (we would just return False later on anyway) + model_fields = type(self).__pydantic_fields__.keys() + if self.__dict__.keys() <= model_fields and other.__dict__.keys() <= model_fields: + return False + + # If we reach here, there are non-pydantic-fields keys, mapped to unequal values, that we need to ignore + # Resort to costly filtering of the __dict__ objects + # We use operator.itemgetter because it is much faster than dict comprehensions + # NOTE: Contrary to standard python class and instances, when the Model class has a default value for an + # attribute and the model instance doesn't have a corresponding attribute, accessing the missing attribute + # raises an error in BaseModel.__getattr__ instead of returning the class attribute + # So we can use operator.itemgetter() instead of operator.attrgetter() + getter = operator.itemgetter(*model_fields) if model_fields else lambda _: _utils._SENTINEL + try: + return getter(self.__dict__) == getter(other.__dict__) + except KeyError: + # In rare cases (such as when using the deprecated BaseModel.copy() method), + # the __dict__ may not contain all model fields, which is how we can get here. + # getter(self.__dict__) is much faster than any 'safe' method that accounts + # for missing keys, and wrapping it in a `try` doesn't slow things down much + # in the common case. + self_fields_proxy = _utils.SafeGetItemProxy(self.__dict__) + other_fields_proxy = _utils.SafeGetItemProxy(other.__dict__) + return getter(self_fields_proxy) == getter(other_fields_proxy) + + # other instance is not a BaseModel + else: + return NotImplemented # delegate to the other item in the comparison + + if TYPE_CHECKING: + # We put `__init_subclass__` in a TYPE_CHECKING block because, even though we want the type-checking benefits + # described in the signature of `__init_subclass__` below, we don't want to modify the default behavior of + # subclass initialization. + + def __init_subclass__(cls, **kwargs: Unpack[ConfigDict]): + """This signature is included purely to help type-checkers check arguments to class declaration, which + provides a way to conveniently set model_config key/value pairs. + + ```python + from pydantic import BaseModel + + class MyModel(BaseModel, extra='allow'): ... + ``` + + However, this may be deceiving, since the _actual_ calls to `__init_subclass__` will not receive any + of the config arguments, and will only receive any keyword arguments passed during class initialization + that are _not_ expected keys in ConfigDict. (This is due to the way `ModelMetaclass.__new__` works.) + + Args: + **kwargs: Keyword arguments passed to the class definition, which set model_config + + Note: + You may want to override `__pydantic_init_subclass__` instead, which behaves similarly but is called + *after* the class is fully initialized. + """ + + def __iter__(self) -> TupleGenerator: + """So `dict(model)` works.""" + yield from [(k, v) for (k, v) in self.__dict__.items() if not k.startswith('_')] + extra = self.__pydantic_extra__ + if extra: + yield from extra.items() + + def __repr__(self) -> str: + return f'{self.__repr_name__()}({self.__repr_str__(", ")})' + + def __repr_args__(self) -> _repr.ReprArgs: + # Eagerly create the repr of computed fields, as this may trigger access of cached properties and as such + # modify the instance's `__dict__`. If we don't do it now, it could happen when iterating over the `__dict__` + # below if the instance happens to be referenced in a field, and would modify the `__dict__` size *during* iteration. + computed_fields_repr_args = [ + (k, getattr(self, k)) for k, v in self.__pydantic_computed_fields__.items() if v.repr + ] + + for k, v in self.__dict__.items(): + field = self.__pydantic_fields__.get(k) + if field and field.repr: + if v is not self: + yield k, v + else: + yield k, self.__repr_recursion__(v) + # `__pydantic_extra__` can fail to be set if the model is not yet fully initialized. + # This can happen if a `ValidationError` is raised during initialization and the instance's + # repr is generated as part of the exception handling. Therefore, we use `getattr` here + # with a fallback, even though the type hints indicate the attribute will always be present. + try: + pydantic_extra = object.__getattribute__(self, '__pydantic_extra__') + except AttributeError: + pydantic_extra = None + + if pydantic_extra is not None: + yield from ((k, v) for k, v in pydantic_extra.items()) + yield from computed_fields_repr_args + + # take logic from `_repr.Representation` without the side effects of inheritance, see #5740 + __repr_name__ = _repr.Representation.__repr_name__ + __repr_recursion__ = _repr.Representation.__repr_recursion__ + __repr_str__ = _repr.Representation.__repr_str__ + __pretty__ = _repr.Representation.__pretty__ + __rich_repr__ = _repr.Representation.__rich_repr__ + + def __str__(self) -> str: + return self.__repr_str__(' ') + + # ##### Deprecated methods from v1 ##### + @property + @typing_extensions.deprecated( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', category=None + ) + def __fields__(self) -> dict[str, FieldInfo]: + warnings.warn( + 'The `__fields__` attribute is deprecated, use the `model_fields` class property instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return getattr(type(self), '__pydantic_fields__', {}) + + @property + @typing_extensions.deprecated( + 'The `__fields_set__` attribute is deprecated, use `model_fields_set` instead.', + category=None, + ) + def __fields_set__(self) -> set[str]: + warnings.warn( + 'The `__fields_set__` attribute is deprecated, use `model_fields_set` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return self.__pydantic_fields_set__ + + @typing_extensions.deprecated('The `dict` method is deprecated; use `model_dump` instead.', category=None) + def dict( # noqa: D102 + self, + *, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> Dict[str, Any]: # noqa UP006 + warnings.warn( + 'The `dict` method is deprecated; use `model_dump` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return self.model_dump( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + @typing_extensions.deprecated('The `json` method is deprecated; use `model_dump_json` instead.', category=None) + def json( # noqa: D102 + self, + *, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + encoder: Callable[[Any], Any] | None = PydanticUndefined, # type: ignore[assignment] + models_as_dict: bool = PydanticUndefined, # type: ignore[assignment] + **dumps_kwargs: Any, + ) -> str: + warnings.warn( + 'The `json` method is deprecated; use `model_dump_json` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if encoder is not PydanticUndefined: + raise TypeError('The `encoder` argument is no longer supported; use field serializers instead.') + if models_as_dict is not PydanticUndefined: + raise TypeError('The `models_as_dict` argument is no longer supported; use a model serializer instead.') + if dumps_kwargs: + raise TypeError('`dumps_kwargs` keyword arguments are no longer supported.') + return self.model_dump_json( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + + @classmethod + @typing_extensions.deprecated('The `parse_obj` method is deprecated; use `model_validate` instead.', category=None) + def parse_obj(cls, obj: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `parse_obj` method is deprecated; use `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_validate(obj) + + @classmethod + @typing_extensions.deprecated( + 'The `parse_raw` method is deprecated; if your data is JSON use `model_validate_json`, ' + 'otherwise load the data then use `model_validate` instead.', + category=None, + ) + def parse_raw( # noqa: D102 + cls, + b: str | bytes, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: DeprecatedParseProtocol | None = None, + allow_pickle: bool = False, + ) -> Self: # pragma: no cover + warnings.warn( + 'The `parse_raw` method is deprecated; if your data is JSON use `model_validate_json`, ' + 'otherwise load the data then use `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import parse + + try: + obj = parse.load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + ) + except (ValueError, TypeError) as exc: + import json + + # try to match V1 + if isinstance(exc, UnicodeDecodeError): + type_str = 'value_error.unicodedecode' + elif isinstance(exc, json.JSONDecodeError): + type_str = 'value_error.jsondecode' + elif isinstance(exc, ValueError): + type_str = 'value_error' + else: + type_str = 'type_error' + + # ctx is missing here, but since we've added `input` to the error, we're not pretending it's the same + error: pydantic_core.InitErrorDetails = { + # The type: ignore on the next line is to ignore the requirement of LiteralString + 'type': pydantic_core.PydanticCustomError(type_str, str(exc)), # type: ignore + 'loc': ('__root__',), + 'input': b, + } + raise pydantic_core.ValidationError.from_exception_data(cls.__name__, [error]) + return cls.model_validate(obj) + + @classmethod + @typing_extensions.deprecated( + 'The `parse_file` method is deprecated; load the data from file, then if your data is JSON ' + 'use `model_validate_json`, otherwise `model_validate` instead.', + category=None, + ) + def parse_file( # noqa: D102 + cls, + path: str | Path, + *, + content_type: str | None = None, + encoding: str = 'utf8', + proto: DeprecatedParseProtocol | None = None, + allow_pickle: bool = False, + ) -> Self: + warnings.warn( + 'The `parse_file` method is deprecated; load the data from file, then if your data is JSON ' + 'use `model_validate_json`, otherwise `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import parse + + obj = parse.load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + ) + return cls.parse_obj(obj) + + @classmethod + @typing_extensions.deprecated( + 'The `from_orm` method is deprecated; set ' + "`model_config['from_attributes']=True` and use `model_validate` instead.", + category=None, + ) + def from_orm(cls, obj: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `from_orm` method is deprecated; set ' + "`model_config['from_attributes']=True` and use `model_validate` instead.", + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if not cls.model_config.get('from_attributes', None): + raise PydanticUserError( + 'You must set the config attribute `from_attributes=True` to use from_orm', code=None + ) + return cls.model_validate(obj) + + @classmethod + @typing_extensions.deprecated('The `construct` method is deprecated; use `model_construct` instead.', category=None) + def construct(cls, _fields_set: set[str] | None = None, **values: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `construct` method is deprecated; use `model_construct` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_construct(_fields_set=_fields_set, **values) + + @typing_extensions.deprecated( + 'The `copy` method is deprecated; use `model_copy` instead. ' + 'See the docstring of `BaseModel.copy` for details about how to handle `include` and `exclude`.', + category=None, + ) + def copy( + self, + *, + include: AbstractSetIntStr | MappingIntStrAny | None = None, + exclude: AbstractSetIntStr | MappingIntStrAny | None = None, + update: Dict[str, Any] | None = None, # noqa UP006 + deep: bool = False, + ) -> Self: # pragma: no cover + """Returns a copy of the model. + + !!! warning "Deprecated" + This method is now deprecated; use `model_copy` instead. + + If you need `include` or `exclude`, use: + + ```python {test="skip" lint="skip"} + data = self.model_dump(include=include, exclude=exclude, round_trip=True) + data = {**data, **(update or {})} + copied = self.model_validate(data) + ``` + + Args: + include: Optional set or mapping specifying which fields to include in the copied model. + exclude: Optional set or mapping specifying which fields to exclude in the copied model. + update: Optional dictionary of field-value pairs to override field values in the copied model. + deep: If True, the values of fields that are Pydantic models will be deep-copied. + + Returns: + A copy of the model with included, excluded and updated fields as specified. + """ + warnings.warn( + 'The `copy` method is deprecated; use `model_copy` instead. ' + 'See the docstring of `BaseModel.copy` for details about how to handle `include` and `exclude`.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + values = dict( + copy_internals._iter( + self, to_dict=False, by_alias=False, include=include, exclude=exclude, exclude_unset=False + ), + **(update or {}), + ) + if self.__pydantic_private__ is None: + private = None + else: + private = {k: v for k, v in self.__pydantic_private__.items() if v is not PydanticUndefined} + + if self.__pydantic_extra__ is None: + extra: dict[str, Any] | None = None + else: + extra = self.__pydantic_extra__.copy() + for k in list(self.__pydantic_extra__): + if k not in values: # k was in the exclude + extra.pop(k) + for k in list(values): + if k in self.__pydantic_extra__: # k must have come from extra + extra[k] = values.pop(k) + + # new `__pydantic_fields_set__` can have unset optional fields with a set value in `update` kwarg + if update: + fields_set = self.__pydantic_fields_set__ | update.keys() + else: + fields_set = set(self.__pydantic_fields_set__) + + # removing excluded fields from `__pydantic_fields_set__` + if exclude: + fields_set -= set(exclude) + + return copy_internals._copy_and_set_values(self, values, fields_set, extra, private, deep=deep) + + @classmethod + @typing_extensions.deprecated('The `schema` method is deprecated; use `model_json_schema` instead.', category=None) + def schema( # noqa: D102 + cls, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE + ) -> Dict[str, Any]: # noqa UP006 + warnings.warn( + 'The `schema` method is deprecated; use `model_json_schema` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_json_schema(by_alias=by_alias, ref_template=ref_template) + + @classmethod + @typing_extensions.deprecated( + 'The `schema_json` method is deprecated; use `model_json_schema` and json.dumps instead.', + category=None, + ) + def schema_json( # noqa: D102 + cls, *, by_alias: bool = True, ref_template: str = DEFAULT_REF_TEMPLATE, **dumps_kwargs: Any + ) -> str: # pragma: no cover + warnings.warn( + 'The `schema_json` method is deprecated; use `model_json_schema` and json.dumps instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + import json + + from .deprecated.json import pydantic_encoder + + return json.dumps( + cls.model_json_schema(by_alias=by_alias, ref_template=ref_template), + default=pydantic_encoder, + **dumps_kwargs, + ) + + @classmethod + @typing_extensions.deprecated('The `validate` method is deprecated; use `model_validate` instead.', category=None) + def validate(cls, value: Any) -> Self: # noqa: D102 + warnings.warn( + 'The `validate` method is deprecated; use `model_validate` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + return cls.model_validate(value) + + @classmethod + @typing_extensions.deprecated( + 'The `update_forward_refs` method is deprecated; use `model_rebuild` instead.', + category=None, + ) + def update_forward_refs(cls, **localns: Any) -> None: # noqa: D102 + warnings.warn( + 'The `update_forward_refs` method is deprecated; use `model_rebuild` instead.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + if localns: # pragma: no cover + raise TypeError('`localns` arguments are not longer accepted.') + cls.model_rebuild(force=True) + + @typing_extensions.deprecated( + 'The private method `_iter` will be removed and should no longer be used.', category=None + ) + def _iter(self, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_iter` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._iter(self, *args, **kwargs) + + @typing_extensions.deprecated( + 'The private method `_copy_and_set_values` will be removed and should no longer be used.', + category=None, + ) + def _copy_and_set_values(self, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_copy_and_set_values` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._copy_and_set_values(self, *args, **kwargs) + + @classmethod + @typing_extensions.deprecated( + 'The private method `_get_value` will be removed and should no longer be used.', + category=None, + ) + def _get_value(cls, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_get_value` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._get_value(cls, *args, **kwargs) + + @typing_extensions.deprecated( + 'The private method `_calculate_keys` will be removed and should no longer be used.', + category=None, + ) + def _calculate_keys(self, *args: Any, **kwargs: Any) -> Any: + warnings.warn( + 'The private method `_calculate_keys` will be removed and should no longer be used.', + category=PydanticDeprecatedSince20, + stacklevel=2, + ) + from .deprecated import copy_internals + + return copy_internals._calculate_keys(self, *args, **kwargs) + + +ModelT = TypeVar('ModelT', bound=BaseModel) + + +@overload +def create_model( + model_name: str, + /, + *, + __config__: ConfigDict | None = None, + __doc__: str | None = None, + __base__: None = None, + __module__: str = __name__, + __validators__: dict[str, Callable[..., Any]] | None = None, + __cls_kwargs__: dict[str, Any] | None = None, + __qualname__: str | None = None, + **field_definitions: Any | tuple[Any, Any], +) -> type[BaseModel]: ... + + +@overload +def create_model( + model_name: str, + /, + *, + __config__: ConfigDict | None = None, + __doc__: str | None = None, + __base__: type[ModelT] | tuple[type[ModelT], ...], + __module__: str = __name__, + __validators__: dict[str, Callable[..., Any]] | None = None, + __cls_kwargs__: dict[str, Any] | None = None, + __qualname__: str | None = None, + **field_definitions: Any | tuple[Any, Any], +) -> type[ModelT]: ... + + +def create_model( # noqa: C901 + model_name: str, + /, + *, + __config__: ConfigDict | None = None, + __doc__: str | None = None, + __base__: type[ModelT] | tuple[type[ModelT], ...] | None = None, + __module__: str | None = None, + __validators__: dict[str, Callable[..., Any]] | None = None, + __cls_kwargs__: dict[str, Any] | None = None, + __qualname__: str | None = None, + # TODO PEP 747: replace `Any` by the TypeForm: + **field_definitions: Any | tuple[Any, Any], +) -> type[ModelT]: + """!!! abstract "Usage Documentation" + [Dynamic Model Creation](../concepts/models.md#dynamic-model-creation) + + Dynamically creates and returns a new Pydantic model, in other words, `create_model` dynamically creates a + subclass of [`BaseModel`][pydantic.BaseModel]. + + !!! warning + This function may execute arbitrary code contained in field annotations, if string references need to be evaluated. + + See [Security implications of introspecting annotations](https://docs.python.org/3/library/annotationlib.html#annotationlib-security) for more information. + + Args: + model_name: The name of the newly created model. + __config__: The configuration of the new model. + __doc__: The docstring of the new model. + __base__: The base class or classes for the new model. + __module__: The name of the module that the model belongs to; + if `None`, the value is taken from `sys._getframe(1)` + __validators__: A dictionary of methods that validate fields. The keys are the names of the validation methods to + be added to the model, and the values are the validation methods themselves. You can read more about functional + validators [here](https://docs.pydantic.dev/2.9/concepts/validators/#field-validators). + __cls_kwargs__: A dictionary of keyword arguments for class creation, such as `metaclass`. + __qualname__: The qualified name of the newly created model. + **field_definitions: Field definitions of the new model. Either: + + - a single element, representing the type annotation of the field. + - a two-tuple, the first element being the type and the second element the assigned value + (either a default or the [`Field()`][pydantic.Field] function). + + Returns: + The new [model][pydantic.BaseModel]. + + Raises: + PydanticUserError: If `__base__` and `__config__` are both passed. + """ + if __base__ is None: + __base__ = (cast('type[ModelT]', BaseModel),) + elif not isinstance(__base__, tuple): + __base__ = (__base__,) + + __cls_kwargs__ = __cls_kwargs__ or {} + + fields: dict[str, Any] = {} + annotations: dict[str, Any] = {} + + for f_name, f_def in field_definitions.items(): + if isinstance(f_def, tuple): + if len(f_def) != 2: + raise PydanticUserError( + f'Field definition for {f_name!r} should a single element representing the type or a two-tuple, the first element ' + 'being the type and the second element the assigned value (either a default or the `Field()` function).', + code='create-model-field-definitions', + ) + + annotations[f_name] = f_def[0] + fields[f_name] = f_def[1] + else: + annotations[f_name] = f_def + + if __module__ is None: + f = sys._getframe(1) + __module__ = f.f_globals['__name__'] + + namespace: dict[str, Any] = {'__annotations__': annotations, '__module__': __module__} + if __doc__: + namespace['__doc__'] = __doc__ + if __qualname__ is not None: + namespace['__qualname__'] = __qualname__ + if __validators__: + namespace.update(__validators__) + namespace.update(fields) + if __config__: + namespace['model_config'] = __config__ + resolved_bases = types.resolve_bases(__base__) + meta, ns, kwds = types.prepare_class(model_name, resolved_bases, kwds=__cls_kwargs__) + if resolved_bases is not __base__: + ns['__orig_bases__'] = __base__ + namespace.update(ns) + + return meta( + model_name, + resolved_bases, + namespace, + __pydantic_reset_parent_namespace__=False, + _create_model_module=__module__, + **kwds, + ) + + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/mypy.py b/source/target-vendors/cp312/pydantic/mypy.py new file mode 100644 index 0000000..4c73b54 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/mypy.py @@ -0,0 +1,1414 @@ +"""This module includes classes and functions designed specifically for use with the mypy plugin.""" + +from __future__ import annotations + +import sys +from collections.abc import Iterator +from configparser import ConfigParser +from typing import Any, Callable + +# To avoid import error (https://github.com/python/mypy/issues/17726): +import mypy.types # noqa: F401 +from mypy.errorcodes import ErrorCode +from mypy.expandtype import expand_type, expand_type_by_instance +from mypy.nodes import ( + ARG_NAMED, + ARG_NAMED_OPT, + ARG_OPT, + ARG_POS, + ARG_STAR2, + INVARIANT, + MDEF, + Argument, + AssignmentStmt, + Block, + CallExpr, + ClassDef, + Context, + Decorator, + DictExpr, + EllipsisExpr, + Expression, + FuncDef, + IfStmt, + JsonDict, + MemberExpr, + NameExpr, + PassStmt, + PlaceholderNode, + RefExpr, + Statement, + StrExpr, + SymbolTableNode, + TempNode, + TypeAlias, + TypeInfo, + Var, +) +from mypy.options import Options +from mypy.plugin import ( + CheckerPluginInterface, + ClassDefContext, + DynamicClassDefContext, + MethodContext, + Plugin, + ReportConfigContext, + SemanticAnalyzerPluginInterface, +) +from mypy.plugins.common import ( + deserialize_and_fixup_type, +) +from mypy.semanal import set_callable_name +from mypy.server.trigger import make_wildcard_trigger +from mypy.state import state +from mypy.type_visitor import TypeTranslator +from mypy.typeops import map_type_from_supertype +from mypy.types import ( + AnyType, + CallableType, + Instance, + NoneType, + Type, + TypeOfAny, + TypeType, + TypeVarType, + UnionType, + get_proper_type, +) +from mypy.typevars import fill_typevars +from mypy.util import get_unique_redefinition_name +from mypy.version import __version__ as mypy_version + +from pydantic._internal import _fields +from pydantic.version import parse_mypy_version + +CONFIGFILE_KEY = 'pydantic-mypy' +METADATA_KEY = 'pydantic-mypy-metadata' +BASEMODEL_FULLNAME = 'pydantic.main.BaseModel' +CREATE_MODEL_FULLNAME = 'pydantic.main.create_model' +BASESETTINGS_FULLNAME = 'pydantic_settings.main.BaseSettings' +ROOT_MODEL_FULLNAME = 'pydantic.root_model.RootModel' +MODEL_METACLASS_FULLNAME = 'pydantic._internal._model_construction.ModelMetaclass' +FIELD_FULLNAME = 'pydantic.fields.Field' +DATACLASS_FULLNAME = 'pydantic.dataclasses.dataclass' +MODEL_VALIDATOR_FULLNAME = 'pydantic.functional_validators.model_validator' +DECORATOR_FULLNAMES = { + 'pydantic.functional_validators.field_validator', + 'pydantic.functional_validators.model_validator', + 'pydantic.functional_serializers.serializer', + 'pydantic.functional_serializers.model_serializer', + 'pydantic.deprecated.class_validators.validator', + 'pydantic.deprecated.class_validators.root_validator', +} +IMPLICIT_CLASSMETHOD_DECORATOR_FULLNAMES = DECORATOR_FULLNAMES - {'pydantic.functional_serializers.model_serializer'} + + +MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version) +BUILTINS_NAME = 'builtins' + +# Increment version if plugin changes and mypy caches should be invalidated +__version__ = 2 + + +def plugin(version: str) -> type[Plugin]: + """`version` is the mypy version string. + + We might want to use this to print a warning if the mypy version being used is + newer, or especially older, than we expect (or need). + + Args: + version: The mypy version string. + + Return: + The Pydantic mypy plugin type. + """ + return PydanticPlugin + + +class PydanticPlugin(Plugin): + """The Pydantic mypy plugin.""" + + def __init__(self, options: Options) -> None: + self.plugin_config = PydanticPluginConfig(options) + self._plugin_data = self.plugin_config.to_data() + super().__init__(options) + + def get_base_class_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None: + """Update Pydantic model class.""" + sym = self.lookup_fully_qualified(fullname) + if sym and isinstance(sym.node, TypeInfo): # pragma: no branch + # No branching may occur if the mypy cache has not been cleared + if sym.node.has_base(BASEMODEL_FULLNAME): + return self._pydantic_model_class_maker_callback + return None + + def get_metaclass_hook(self, fullname: str) -> Callable[[ClassDefContext], None] | None: + """Update Pydantic `ModelMetaclass` definition.""" + if fullname == MODEL_METACLASS_FULLNAME: + return self._pydantic_model_metaclass_marker_callback + return None + + def get_method_hook(self, fullname: str) -> Callable[[MethodContext], Type] | None: + """Adjust return type of `from_orm` method call.""" + if fullname.endswith('.from_orm'): + return from_attributes_callback + return None + + def get_dynamic_class_hook(self, fullname: str) -> Callable[[DynamicClassDefContext], None] | None: + """Recognize `create_model()` calls as dynamic BaseModel subclasses.""" + if fullname == CREATE_MODEL_FULLNAME: + return self._pydantic_create_model_callback + return None + + def report_config_data(self, ctx: ReportConfigContext) -> dict[str, Any]: + """Return all plugin config data. + + Used by mypy to determine if cache needs to be discarded. + """ + return self._plugin_data + + def _pydantic_model_class_maker_callback(self, ctx: ClassDefContext) -> None: + transformer = PydanticModelTransformer(ctx.cls, ctx.reason, ctx.api, self.plugin_config) + transformer.transform() + + def _pydantic_model_metaclass_marker_callback(self, ctx: ClassDefContext) -> None: + """Reset dataclass_transform_spec attribute of ModelMetaclass. + + Let the plugin handle it. This behavior can be disabled + if 'debug_dataclass_transform' is set to True', for testing purposes. + """ + if self.plugin_config.debug_dataclass_transform: + return + info_metaclass = ctx.cls.info.declared_metaclass + assert info_metaclass, "callback not passed from 'get_metaclass_hook'" + if getattr(info_metaclass.type, 'dataclass_transform_spec', None): + info_metaclass.type.dataclass_transform_spec = None + + def _pydantic_create_model_callback(self, ctx: DynamicClassDefContext) -> None: + """Make variables assigned from `create_model()` usable as types by mypy.""" + # Determine the base class from __base__ argument if provided + base_fullname = BASEMODEL_FULLNAME + for arg_name, arg_expr in zip(ctx.call.arg_names, ctx.call.args): + if arg_name == '__base__' and isinstance(arg_expr, RefExpr) and arg_expr.node is not None: + if isinstance(arg_expr.node, TypeInfo): + base_fullname = arg_expr.node.fullname + elif isinstance(arg_expr.node, Var) and isinstance(arg_expr.node.type, Instance): + base_fullname = arg_expr.node.type.type.fullname + + base_sym = ctx.api.lookup_fully_qualified_or_none(base_fullname) + if base_sym is None or not isinstance(base_sym.node, TypeInfo): + # Fall back to BaseModel + base_sym = ctx.api.lookup_fully_qualified_or_none(BASEMODEL_FULLNAME) + if base_sym is None or not isinstance(base_sym.node, TypeInfo): + return + + base_info = base_sym.node + base_instance = fill_typevars(base_info) + assert isinstance(base_instance, Instance) + + info = ctx.api.basic_new_typeinfo(ctx.name, base_instance, ctx.call.line) + info.metaclass_type = base_info.metaclass_type + + ctx.api.add_symbol_table_node(ctx.name, SymbolTableNode(MDEF, info)) + + +class PydanticPluginConfig: + """A Pydantic mypy plugin config holder. + + Attributes: + init_forbid_extra: Whether to add a `**kwargs` at the end of the generated `__init__` signature. + init_typed: Whether to annotate fields in the generated `__init__`. + warn_required_dynamic_aliases: Whether to raise required dynamic aliases error. + debug_dataclass_transform: Whether to not reset `dataclass_transform_spec` attribute + of `ModelMetaclass` for testing purposes. + """ + + __slots__ = ( + 'init_forbid_extra', + 'init_typed', + 'warn_required_dynamic_aliases', + 'debug_dataclass_transform', + ) + init_forbid_extra: bool + init_typed: bool + warn_required_dynamic_aliases: bool + debug_dataclass_transform: bool # undocumented + + def __init__(self, options: Options) -> None: + if options.config_file is None: # pragma: no cover + return + + toml_config = parse_toml(options.config_file) + if toml_config is not None: + config = toml_config.get('tool', {}).get('pydantic-mypy', {}) + for key in self.__slots__: + setting = config.get(key, False) + if not isinstance(setting, bool): + raise ValueError(f'Configuration value must be a boolean for key: {key}') + setattr(self, key, setting) + else: + plugin_config = ConfigParser() + plugin_config.read(options.config_file) + for key in self.__slots__: + setting = plugin_config.getboolean(CONFIGFILE_KEY, key, fallback=False) + setattr(self, key, setting) + + def to_data(self) -> dict[str, Any]: + """Returns a dict of config names to their values.""" + return {key: getattr(self, key) for key in self.__slots__} + + +def from_attributes_callback(ctx: MethodContext) -> Type: + """Raise an error if from_attributes is not enabled.""" + model_type: Instance + ctx_type = ctx.type + if isinstance(ctx_type, TypeType): + ctx_type = ctx_type.item + if isinstance(ctx_type, CallableType) and isinstance(ctx_type.ret_type, Instance): + model_type = ctx_type.ret_type # called on the class + elif isinstance(ctx_type, Instance): + model_type = ctx_type # called on an instance (unusual, but still valid) + else: # pragma: no cover + detail = f'ctx.type: {ctx_type} (of type {ctx_type.__class__.__name__})' + error_unexpected_behavior(detail, ctx.api, ctx.context) + return ctx.default_return_type + pydantic_metadata = model_type.type.metadata.get(METADATA_KEY) + if pydantic_metadata is None: + return ctx.default_return_type + if not model_type.type.has_base(BASEMODEL_FULLNAME): + # not a Pydantic v2 model + return ctx.default_return_type + from_attributes = pydantic_metadata.get('config', {}).get('from_attributes') + if from_attributes is not True: + error_from_attributes(model_type.type.name, ctx.api, ctx.context) + return ctx.default_return_type + + +class PydanticModelField: + """Based on mypy.plugins.dataclasses.DataclassAttribute.""" + + def __init__( + self, + name: str, + alias: str | None, + is_frozen: bool, + has_dynamic_alias: bool, + has_default: bool, + strict: bool | None, + line: int, + column: int, + type: Type | None, + info: TypeInfo, + ): + self.name = name + self.alias = alias + self.is_frozen = is_frozen + self.has_dynamic_alias = has_dynamic_alias + self.has_default = has_default + self.strict = strict + self.line = line + self.column = column + self.type = type + self.info = info + + def to_argument( + self, + current_info: TypeInfo, + typed: bool, + model_strict: bool, + force_optional: bool, + use_alias: bool, + api: SemanticAnalyzerPluginInterface, + force_typevars_invariant: bool, + is_root_model_root: bool, + ) -> Argument: + """Based on mypy.plugins.dataclasses.DataclassAttribute.to_argument.""" + variable = self.to_var(current_info, api, use_alias, force_typevars_invariant) + + strict = model_strict if self.strict is None else self.strict + if typed or strict: + type_annotation = self.expand_type(current_info, api, include_root_type=True) + else: + type_annotation = AnyType(TypeOfAny.explicit) + + return Argument( + variable=variable, + type_annotation=type_annotation, + initializer=None, + kind=ARG_OPT + if is_root_model_root + else (ARG_NAMED_OPT if force_optional or self.has_default else ARG_NAMED), + ) + + def expand_type( + self, + current_info: TypeInfo, + api: SemanticAnalyzerPluginInterface, + force_typevars_invariant: bool = False, + include_root_type: bool = False, + ) -> Type | None: + """Based on mypy.plugins.dataclasses.DataclassAttribute.expand_type.""" + if force_typevars_invariant: + # In some cases, mypy will emit an error "Cannot use a covariant type variable as a parameter" + # To prevent that, we add an option to replace typevars with invariant ones while building certain + # method signatures (in particular, `__init__`). There may be a better way to do this, if this causes + # us problems in the future, we should look into why the dataclasses plugin doesn't have this issue. + if isinstance(self.type, TypeVarType): + modified_type = self.type.copy_modified() + modified_type.variance = INVARIANT + self.type = modified_type + + if self.type is not None and self.info.self_type is not None: + # In general, it is not safe to call `expand_type()` during semantic analysis, + # however this plugin is called very late, so all types should be fully ready. + # Also, it is tricky to avoid eager expansion of Self types here (e.g. because + # we serialize attributes). + with state.strict_optional_set(api.options.strict_optional): + filled_with_typevars = fill_typevars(current_info) + # Cannot be TupleType as current_info represents a Pydantic model: + assert isinstance(filled_with_typevars, Instance) + if force_typevars_invariant: + for arg in filled_with_typevars.args: + if isinstance(arg, TypeVarType): + arg.variance = INVARIANT + + expanded_type = expand_type(self.type, {self.info.self_type.id: filled_with_typevars}) + if include_root_type and isinstance(expanded_type, Instance) and is_root_model(expanded_type.type): + # When a root model is used as a field, Pydantic allows both an instance of the root model + # as well as instances of the `root` field type: + root_type = expanded_type.type['root'].type + if root_type is None: + # Happens if the hint for 'root' has unsolved forward references + return expanded_type + expanded_root_type = expand_type_by_instance(root_type, expanded_type) + expanded_type = UnionType([expanded_type, expanded_root_type]) + return expanded_type + return self.type + + def to_var( + self, + current_info: TypeInfo, + api: SemanticAnalyzerPluginInterface, + use_alias: bool, + force_typevars_invariant: bool = False, + ) -> Var: + """Based on mypy.plugins.dataclasses.DataclassAttribute.to_var.""" + if use_alias and self.alias is not None: + name = self.alias + else: + name = self.name + + return Var(name, self.expand_type(current_info, api, force_typevars_invariant)) + + def serialize(self) -> JsonDict: + """Based on mypy.plugins.dataclasses.DataclassAttribute.serialize.""" + assert self.type + return { + 'name': self.name, + 'alias': self.alias, + 'is_frozen': self.is_frozen, + 'has_dynamic_alias': self.has_dynamic_alias, + 'has_default': self.has_default, + 'strict': self.strict, + 'line': self.line, + 'column': self.column, + 'type': self.type.serialize(), + } + + @classmethod + def deserialize(cls, info: TypeInfo, data: JsonDict, api: SemanticAnalyzerPluginInterface) -> PydanticModelField: + """Based on mypy.plugins.dataclasses.DataclassAttribute.deserialize.""" + data = data.copy() + typ = deserialize_and_fixup_type(data.pop('type'), api) + return cls(type=typ, info=info, **data) + + def expand_typevar_from_subtype(self, sub_type: TypeInfo, api: SemanticAnalyzerPluginInterface) -> None: + """Expands type vars in the context of a subtype when an attribute is inherited + from a generic super type. + """ + if self.type is not None: + with state.strict_optional_set(api.options.strict_optional): + self.type = map_type_from_supertype(self.type, sub_type, self.info) + + +class PydanticModelClassVar: + """Based on mypy.plugins.dataclasses.DataclassAttribute. + + ClassVars are ignored by subclasses. + + Attributes: + name: the ClassVar name + """ + + def __init__(self, name): + self.name = name + + @classmethod + def deserialize(cls, data: JsonDict) -> PydanticModelClassVar: + """Based on mypy.plugins.dataclasses.DataclassAttribute.deserialize.""" + data = data.copy() + return cls(**data) + + def serialize(self) -> JsonDict: + """Based on mypy.plugins.dataclasses.DataclassAttribute.serialize.""" + return { + 'name': self.name, + } + + +class PydanticModelTransformer: + """Transform the BaseModel subclass according to the plugin settings. + + Attributes: + tracked_config_fields: A set of field configs that the plugin has to track their value. + """ + + tracked_config_fields: set[str] = { + 'extra', + 'frozen', + 'from_attributes', + 'populate_by_name', + 'validate_by_alias', + 'validate_by_name', + 'alias_generator', + 'strict', + } + + def __init__( + self, + cls: ClassDef, + reason: Expression | Statement, + api: SemanticAnalyzerPluginInterface, + plugin_config: PydanticPluginConfig, + ) -> None: + self._cls = cls + self._reason = reason + self._api = api + + self.plugin_config = plugin_config + + def transform(self) -> bool: + """Configures the BaseModel subclass according to the plugin settings. + + In particular: + + * determines the model config and fields, + * adds a fields-aware signature for the initializer and construct methods + * freezes the class if frozen = True + * stores the fields, config, and if the class is settings in the mypy metadata for access by subclasses + """ + info = self._cls.info + is_a_root_model = is_root_model(info) + config = self.collect_config() + fields, class_vars = self.collect_fields_and_class_vars(config, is_a_root_model) + if fields is None or class_vars is None: + # Some definitions are not ready. We need another pass. + return False + for field in fields: + if field.type is None: + return False + + is_settings = info.has_base(BASESETTINGS_FULLNAME) + self.add_initializer(fields, config, is_settings, is_a_root_model) + self.add_model_construct_method(fields, config, is_settings, is_a_root_model) + self.set_frozen(fields, self._api, frozen=config.frozen is True) + + self.adjust_decorator_signatures() + + info.metadata[METADATA_KEY] = { + 'fields': {field.name: field.serialize() for field in fields}, + 'class_vars': {class_var.name: class_var.serialize() for class_var in class_vars}, + 'config': config.get_values_dict(), + } + + return True + + def adjust_decorator_signatures(self) -> None: + """When we decorate a function `f` with `pydantic.validator(...)`, `pydantic.field_validator` + or `pydantic.serializer(...)`, mypy sees `f` as a regular method taking a `self` instance, + even though pydantic internally wraps `f` with `classmethod` if necessary. + + Teach mypy this by marking any function whose outermost decorator is a `validator()`, + `field_validator()` or `serializer()` call as a `classmethod`. + """ + for sym in self._cls.info.names.values(): + if isinstance(sym.node, Decorator): + first_dec = sym.node.original_decorators[0] + if ( + isinstance(first_dec, CallExpr) + and isinstance(first_dec.callee, NameExpr) + and first_dec.callee.fullname in IMPLICIT_CLASSMETHOD_DECORATOR_FULLNAMES + # @model_validator(mode="after") is an exception, it expects a regular method + and not ( + first_dec.callee.fullname == MODEL_VALIDATOR_FULLNAME + and any( + first_dec.arg_names[i] == 'mode' and isinstance(arg, StrExpr) and arg.value == 'after' + for i, arg in enumerate(first_dec.args) + ) + ) + ): + # TODO: Only do this if the first argument of the decorated function is `cls` + sym.node.func.is_class = True + + def collect_config(self) -> ModelConfigData: # noqa: C901 (ignore complexity) + """Collects the values of the config attributes that are used by the plugin, accounting for parent classes.""" + cls = self._cls + config = ModelConfigData() + + has_config_kwargs = False + has_config_from_namespace = False + + # Handle `class MyModel(BaseModel, =, ...):` + for name, expr in cls.keywords.items(): + config_data = self.get_config_update(name, expr) + if config_data: + has_config_kwargs = True + config.update(config_data) + + # Handle `model_config` + stmt: Statement | None = None + for stmt in cls.defs.body: + if not isinstance(stmt, (AssignmentStmt, ClassDef)): + continue + + if isinstance(stmt, AssignmentStmt): + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr) or lhs.name != 'model_config': + continue + + if isinstance(stmt.rvalue, CallExpr): # calls to `dict` or `ConfigDict` + for arg_name, arg in zip(stmt.rvalue.arg_names, stmt.rvalue.args): + if arg_name is None: + continue + config.update(self.get_config_update(arg_name, arg, lax_extra=True)) + elif isinstance(stmt.rvalue, DictExpr): # dict literals + for key_expr, value_expr in stmt.rvalue.items: + if not isinstance(key_expr, StrExpr): + continue + config.update(self.get_config_update(key_expr.value, value_expr)) + + elif isinstance(stmt, ClassDef): + if stmt.name != 'Config': # 'deprecated' Config-class + continue + for substmt in stmt.defs.body: + if not isinstance(substmt, AssignmentStmt): + continue + lhs = substmt.lvalues[0] + if not isinstance(lhs, NameExpr): + continue + config.update(self.get_config_update(lhs.name, substmt.rvalue)) + + if has_config_kwargs: + self._api.fail( + 'Specifying config in two places is ambiguous, use either Config attribute or class kwargs', + cls, + ) + break + + has_config_from_namespace = True + + if has_config_kwargs or has_config_from_namespace: + if ( + stmt + and config.has_alias_generator + and not (config.validate_by_name or config.populate_by_name) + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(self._api, stmt) + + for info in cls.info.mro[1:]: # 0 is the current class + if METADATA_KEY not in info.metadata: + continue + + # Each class depends on the set of fields in its ancestors + self._api.add_plugin_dependency(make_wildcard_trigger(info.fullname)) + for name, value in info.metadata[METADATA_KEY]['config'].items(): + config.setdefault(name, value) + return config + + def collect_fields_and_class_vars( + self, model_config: ModelConfigData, is_root_model: bool + ) -> tuple[list[PydanticModelField] | None, list[PydanticModelClassVar] | None]: + """Collects the fields for the model, accounting for parent classes.""" + cls = self._cls + + # First, collect fields and ClassVars belonging to any class in the MRO, ignoring duplicates. + # + # We iterate through the MRO in reverse because attrs defined in the parent must appear + # earlier in the attributes list than attrs defined in the child. See: + # https://docs.python.org/3/library/dataclasses.html#inheritance + # + # However, we also want fields defined in the subtype to override ones defined + # in the parent. We can implement this via a dict without disrupting the attr order + # because dicts preserve insertion order in Python 3.7+. + found_fields: dict[str, PydanticModelField] = {} + found_class_vars: dict[str, PydanticModelClassVar] = {} + for info in reversed(cls.info.mro[1:-1]): # 0 is the current class, -2 is BaseModel, -1 is object + # if BASEMODEL_METADATA_TAG_KEY in info.metadata and BASEMODEL_METADATA_KEY not in info.metadata: + # # We haven't processed the base class yet. Need another pass. + # return None, None + if METADATA_KEY not in info.metadata: + continue + + # Each class depends on the set of attributes in its dataclass ancestors. + self._api.add_plugin_dependency(make_wildcard_trigger(info.fullname)) + + for name, data in info.metadata[METADATA_KEY]['fields'].items(): + field = PydanticModelField.deserialize(info, data, self._api) + # (The following comment comes directly from the dataclasses plugin) + # TODO: We shouldn't be performing type operations during the main + # semantic analysis pass, since some TypeInfo attributes might + # still be in flux. This should be performed in a later phase. + field.expand_typevar_from_subtype(cls.info, self._api) + found_fields[name] = field + + sym_node = cls.info.names.get(name) + if sym_node and sym_node.node and not isinstance(sym_node.node, (Var, PlaceholderNode)): + self._api.fail( + 'BaseModel field may only be overridden by another field', + sym_node.node, + ) + # Collect ClassVars + for name, data in info.metadata[METADATA_KEY]['class_vars'].items(): + found_class_vars[name] = PydanticModelClassVar.deserialize(data) + + # Second, collect fields and ClassVars belonging to the current class. + current_field_names: set[str] = set() + current_class_vars_names: set[str] = set() + for stmt in self._get_assignment_statements_from_block(cls.defs): + maybe_field = self.collect_field_or_class_var_from_stmt(stmt, model_config, found_class_vars) + if maybe_field is None: + continue + + lhs = stmt.lvalues[0] + assert isinstance(lhs, NameExpr) # collect_field_or_class_var_from_stmt guarantees this + if isinstance(maybe_field, PydanticModelField): + if is_root_model and lhs.name != 'root': + error_extra_fields_on_root_model(self._api, stmt) + else: + current_field_names.add(lhs.name) + found_fields[lhs.name] = maybe_field + elif isinstance(maybe_field, PydanticModelClassVar): + current_class_vars_names.add(lhs.name) + found_class_vars[lhs.name] = maybe_field + + return list(found_fields.values()), list(found_class_vars.values()) + + def _get_assignment_statements_from_if_statement(self, stmt: IfStmt) -> Iterator[AssignmentStmt]: + for body in stmt.body: + if not body.is_unreachable: + yield from self._get_assignment_statements_from_block(body) + if stmt.else_body is not None and not stmt.else_body.is_unreachable: + yield from self._get_assignment_statements_from_block(stmt.else_body) + + def _get_assignment_statements_from_block(self, block: Block) -> Iterator[AssignmentStmt]: + for stmt in block.body: + if isinstance(stmt, AssignmentStmt): + yield stmt + elif isinstance(stmt, IfStmt): + yield from self._get_assignment_statements_from_if_statement(stmt) + + def collect_field_or_class_var_from_stmt( # noqa C901 + self, stmt: AssignmentStmt, model_config: ModelConfigData, class_vars: dict[str, PydanticModelClassVar] + ) -> PydanticModelField | PydanticModelClassVar | None: + """Get pydantic model field from statement. + + Args: + stmt: The statement. + model_config: Configuration settings for the model. + class_vars: ClassVars already known to be defined on the model. + + Returns: + A pydantic model field if it could find the field in statement. Otherwise, `None`. + """ + cls = self._cls + + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr) or not _fields.is_valid_field_name(lhs.name) or lhs.name == 'model_config': + return None + + if not stmt.new_syntax: + if ( + isinstance(stmt.rvalue, CallExpr) + and isinstance(stmt.rvalue.callee, CallExpr) + and isinstance(stmt.rvalue.callee.callee, NameExpr) + and stmt.rvalue.callee.callee.fullname in DECORATOR_FULLNAMES + ): + # This is a (possibly-reused) validator or serializer, not a field + # In particular, it looks something like: my_validator = validator('my_field')(f) + # Eventually, we may want to attempt to respect model_config['ignored_types'] + return None + + if lhs.name in class_vars: + # Class vars are not fields and are not required to be annotated + return None + + # The assignment does not have an annotation, and it's not anything else we recognize + error_untyped_fields(self._api, stmt) + return None + + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr): + return None + + if not _fields.is_valid_field_name(lhs.name) or lhs.name == 'model_config': + return None + + sym = cls.info.names.get(lhs.name) + if sym is None: # pragma: no cover + # This is likely due to a star import (see the dataclasses plugin for a more detailed explanation) + # This is the same logic used in the dataclasses plugin + return None + + node = sym.node + if isinstance(node, PlaceholderNode): # pragma: no cover + # See the PlaceholderNode docstring for more detail about how this can occur + # Basically, it is an edge case when dealing with complex import logic + + # The dataclasses plugin now asserts this cannot happen, but I'd rather not error if it does.. + return None + + if isinstance(node, TypeAlias): + self._api.fail( + 'Type aliases inside BaseModel definitions are not supported at runtime', + node, + ) + # Skip processing this node. This doesn't match the runtime behaviour, + # but the only alternative would be to modify the SymbolTable, + # and it's a little hairy to do that in a plugin. + return None + + if not isinstance(node, Var): # pragma: no cover + # Don't know if this edge case still happens with the `is_valid_field` check above + # but better safe than sorry + + # The dataclasses plugin now asserts this cannot happen, but I'd rather not error if it does.. + return None + + # x: ClassVar[int] is not a field + if node.is_classvar: + return PydanticModelClassVar(lhs.name) + + # x: InitVar[int] is not supported in BaseModel + node_type = get_proper_type(node.type) + if isinstance(node_type, Instance) and node_type.type.fullname == 'dataclasses.InitVar': + self._api.fail( + 'InitVar is not supported in BaseModel', + node, + ) + + has_default = self.get_has_default(stmt) + strict = self.get_strict(stmt) + + if sym.type is None and node.is_final and node.is_inferred: + # This follows the logic from the dataclasses plugin. The following comment is taken verbatim: + # + # This is a special case, assignment like x: Final = 42 is classified + # annotated above, but mypy strips the `Final` turning it into x = 42. + # We do not support inferred types in dataclasses, so we can try inferring + # type for simple literals, and otherwise require an explicit type + # argument for Final[...]. + typ = self._api.analyze_simple_literal_type(stmt.rvalue, is_final=True) + if typ: + node.type = typ + else: + self._api.fail( + 'Need type argument for Final[...] with non-literal default in BaseModel', + stmt, + ) + node.type = AnyType(TypeOfAny.from_error) + + if node.is_final and has_default: + # TODO this path should be removed (see https://github.com/pydantic/pydantic/issues/11119) + return PydanticModelClassVar(lhs.name) + + alias, has_dynamic_alias = self.get_alias_info(stmt) + if ( + has_dynamic_alias + and not (model_config.validate_by_name or model_config.populate_by_name) + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(self._api, stmt) + is_frozen = self.is_field_frozen(stmt) + + init_type = self._infer_dataclass_attr_init_type(sym, lhs.name, stmt) + return PydanticModelField( + name=lhs.name, + has_dynamic_alias=has_dynamic_alias, + has_default=has_default, + strict=strict, + alias=alias, + is_frozen=is_frozen, + line=stmt.line, + column=stmt.column, + type=init_type, + info=cls.info, + ) + + def _infer_dataclass_attr_init_type(self, sym: SymbolTableNode, name: str, context: Context) -> Type | None: + """Infer __init__ argument type for an attribute. + + In particular, possibly use the signature of __set__. + """ + default = sym.type + if sym.implicit: + return default + t = get_proper_type(sym.type) + + # Perform a simple-minded inference from the signature of __set__, if present. + # We can't use mypy.checkmember here, since this plugin runs before type checking. + # We only support some basic scanerios here, which is hopefully sufficient for + # the vast majority of use cases. + if not isinstance(t, Instance): + return default + setter = t.type.get('__set__') + if setter: + if isinstance(setter.node, FuncDef): + super_info = t.type.get_containing_type_info('__set__') + assert super_info + if setter.type: + setter_type = get_proper_type(map_type_from_supertype(setter.type, t.type, super_info)) + else: + return AnyType(TypeOfAny.unannotated) + if isinstance(setter_type, CallableType) and setter_type.arg_kinds == [ + ARG_POS, + ARG_POS, + ARG_POS, + ]: + return expand_type_by_instance(setter_type.arg_types[2], t) + else: + self._api.fail(f'Unsupported signature for "__set__" in "{t.type.name}"', context) + else: + self._api.fail(f'Unsupported "__set__" in "{t.type.name}"', context) + + return default + + def add_initializer( + self, fields: list[PydanticModelField], config: ModelConfigData, is_settings: bool, is_root_model: bool + ) -> None: + """Adds a fields-aware `__init__` method to the class. + + The added `__init__` will be annotated with types vs. all `Any` depending on the plugin settings. + """ + if '__init__' in self._cls.info.names and not self._cls.info.names['__init__'].plugin_generated: + return # Don't generate an __init__ if one already exists + + typed = self.plugin_config.init_typed + model_strict = bool(config.strict) + use_alias = not (config.validate_by_name or config.populate_by_name) and config.validate_by_alias is not False + requires_dynamic_aliases = bool(config.has_alias_generator and not config.validate_by_name) + args = self.get_field_arguments( + fields, + typed=typed, + model_strict=model_strict, + requires_dynamic_aliases=requires_dynamic_aliases, + use_alias=use_alias, + is_settings=is_settings, + is_root_model=is_root_model, + force_typevars_invariant=True, + ) + + if is_settings: + base_settings_node = self._api.lookup_fully_qualified(BASESETTINGS_FULLNAME).node + assert isinstance(base_settings_node, TypeInfo) + if '__init__' in base_settings_node.names: + base_settings_init_node = base_settings_node.names['__init__'].node + assert isinstance(base_settings_init_node, FuncDef) + if base_settings_init_node is not None and base_settings_init_node.type is not None: + func_type = base_settings_init_node.type + assert isinstance(func_type, CallableType) + for arg_idx, arg_name in enumerate(func_type.arg_names): + if arg_name is None or arg_name.startswith('__') or not arg_name.startswith('_'): + continue + analyzed_variable_type = self._api.anal_type(func_type.arg_types[arg_idx]) + if analyzed_variable_type is not None and arg_name in ( + '_cli_settings_source', + '_build_sources', + ): + # These arg names are annotated with types explicitly parameterized with `Any`, and as such + # the Any causes issues with --disallow-any-explicit. As a workaround, change + # the Any type (as if the generic type was left unparameterized): + analyzed_variable_type = analyzed_variable_type.accept( + ChangeExplicitTypeOfAny(TypeOfAny.from_omitted_generics) + ) + variable = Var(arg_name, analyzed_variable_type) + args.append(Argument(variable, analyzed_variable_type, None, ARG_OPT)) + + if not self.should_init_forbid_extra(fields, config): + var = Var('kwargs') + args.append(Argument(var, AnyType(TypeOfAny.explicit), None, ARG_STAR2)) + + add_method(self._api, self._cls, '__init__', args=args, return_type=NoneType()) + + def add_model_construct_method( + self, + fields: list[PydanticModelField], + config: ModelConfigData, + is_settings: bool, + is_root_model: bool, + ) -> None: + """Adds a fully typed `model_construct` classmethod to the class. + + Similar to the fields-aware __init__ method, but always uses the field names (not aliases), + and does not treat settings fields as optional. + """ + set_str = self._api.named_type(f'{BUILTINS_NAME}.set', [self._api.named_type(f'{BUILTINS_NAME}.str')]) + optional_set_str = UnionType([set_str, NoneType()]) + fields_set_argument = Argument(Var('_fields_set', optional_set_str), optional_set_str, None, ARG_OPT) + with state.strict_optional_set(self._api.options.strict_optional): + args = self.get_field_arguments( + fields, + typed=True, + model_strict=bool(config.strict), + requires_dynamic_aliases=False, + use_alias=False, + is_settings=is_settings, + is_root_model=is_root_model, + ) + if not self.should_init_forbid_extra(fields, config): + var = Var('kwargs') + args.append(Argument(var, AnyType(TypeOfAny.explicit), None, ARG_STAR2)) + + args = args + [fields_set_argument] if is_root_model else [fields_set_argument] + args + + add_method( + self._api, + self._cls, + 'model_construct', + args=args, + return_type=fill_typevars(self._cls.info), + is_classmethod=True, + ) + + def set_frozen(self, fields: list[PydanticModelField], api: SemanticAnalyzerPluginInterface, frozen: bool) -> None: + """Marks all fields as properties so that attempts to set them trigger mypy errors. + + This is the same approach used by the attrs and dataclasses plugins. + """ + info = self._cls.info + for field in fields: + sym_node = info.names.get(field.name) + if sym_node is not None: + var = sym_node.node + if isinstance(var, Var): + var.is_property = frozen or field.is_frozen + elif isinstance(var, PlaceholderNode) and not self._api.final_iteration: + # See https://github.com/pydantic/pydantic/issues/5191 to hit this branch for test coverage + self._api.defer() + # `var` can also be a FuncDef or Decorator node (e.g. when overriding a field with a function or property). + # In that case, we don't want to do anything. Mypy will already raise an error that a field was not properly + # overridden. + else: + var = field.to_var(info, api, use_alias=False) + var.info = info + var.is_property = frozen + var._fullname = info.fullname + '.' + var.name + info.names[var.name] = SymbolTableNode(MDEF, var) + + def get_config_update(self, name: str, arg: Expression, lax_extra: bool = False) -> ModelConfigData | None: + """Determines the config update due to a single kwarg in the ConfigDict definition. + + Warns if a tracked config attribute is set to a value the plugin doesn't know how to interpret (e.g., an int) + """ + if name not in self.tracked_config_fields: + return None + if name == 'extra': + if isinstance(arg, StrExpr): + forbid_extra = arg.value == 'forbid' + elif isinstance(arg, MemberExpr): + forbid_extra = arg.name == 'forbid' + else: + if not lax_extra: + # Only emit an error for other types of `arg` (e.g., `NameExpr`, `ConditionalExpr`, etc.) when + # reading from a config class, etc. If a ConfigDict is used, then we don't want to emit an error + # because you'll get type checking from the ConfigDict itself. + # + # It would be nice if we could introspect the types better otherwise, but I don't know what the API + # is to evaluate an expr into its type and then check if that type is compatible with the expected + # type. Note that you can still get proper type checking via: `model_config = ConfigDict(...)`, just + # if you don't use an explicit string, the plugin won't be able to infer whether extra is forbidden. + error_invalid_config_value(name, self._api, arg) + return None + return ModelConfigData(forbid_extra=forbid_extra) + if name == 'alias_generator': + has_alias_generator = True + if isinstance(arg, NameExpr) and arg.fullname == 'builtins.None': + has_alias_generator = False + return ModelConfigData(has_alias_generator=has_alias_generator) + if isinstance(arg, NameExpr) and arg.fullname in ('builtins.True', 'builtins.False'): + return ModelConfigData(**{name: arg.fullname == 'builtins.True'}) + error_invalid_config_value(name, self._api, arg) + return None + + @staticmethod + def get_has_default(stmt: AssignmentStmt) -> bool: + """Returns a boolean indicating whether the field defined in `stmt` is a required field.""" + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only, so has no default + return False + if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME: + # The "default value" is a call to `Field`; at this point, the field has a default if and only if: + # * there is a positional argument that is not `...` + # * there is a keyword argument named "default" that is not `...` + # * there is a "default_factory" that is not `None` + for arg, name in zip(expr.args, expr.arg_names): + # If name is None, then this arg is the default because it is the only positional argument. + if name is None or name == 'default': + return arg.__class__ is not EllipsisExpr + if name == 'default_factory': + return not (isinstance(arg, NameExpr) and arg.fullname == 'builtins.None') + return False + # Has no default if the "default value" is Ellipsis (i.e., `field_name: Annotation = ...`) + return not isinstance(expr, EllipsisExpr) + + @staticmethod + def get_strict(stmt: AssignmentStmt) -> bool | None: + """Returns a the `strict` value of a field if defined, otherwise `None`.""" + expr = stmt.rvalue + if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME: + for arg, name in zip(expr.args, expr.arg_names): + if name != 'strict': + continue + if isinstance(arg, NameExpr): + if arg.fullname == 'builtins.True': + return True + elif arg.fullname == 'builtins.False': + return False + return None + return None + + @staticmethod + def get_alias_info(stmt: AssignmentStmt) -> tuple[str | None, bool]: + """Returns a pair (alias, has_dynamic_alias), extracted from the declaration of the field defined in `stmt`. + + `has_dynamic_alias` is True if and only if an alias is provided, but not as a string literal. + If `has_dynamic_alias` is True, `alias` will be None. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only + return None, False + + if not ( + isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME + ): + # Assigned value is not a call to pydantic.fields.Field + return None, False + + if 'validation_alias' in expr.arg_names: + arg = expr.args[expr.arg_names.index('validation_alias')] + elif 'alias' in expr.arg_names: + arg = expr.args[expr.arg_names.index('alias')] + else: + return None, False + + if isinstance(arg, StrExpr): + return arg.value, False + else: + return None, True + + @staticmethod + def is_field_frozen(stmt: AssignmentStmt) -> bool: + """Returns whether the field is frozen, extracted from the declaration of the field defined in `stmt`. + + Note that this is only whether the field was declared to be frozen in a ` = Field(frozen=True)` + sense; this does not determine whether the field is frozen because the entire model is frozen; that is + handled separately. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only + return False + + if not ( + isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME + ): + # Assigned value is not a call to pydantic.fields.Field + return False + + for i, arg_name in enumerate(expr.arg_names): + if arg_name == 'frozen': + arg = expr.args[i] + return isinstance(arg, NameExpr) and arg.fullname == 'builtins.True' + return False + + def get_field_arguments( + self, + fields: list[PydanticModelField], + typed: bool, + model_strict: bool, + use_alias: bool, + requires_dynamic_aliases: bool, + is_settings: bool, + is_root_model: bool, + force_typevars_invariant: bool = False, + ) -> list[Argument]: + """Helper function used during the construction of the `__init__` and `model_construct` method signatures. + + Returns a list of mypy Argument instances for use in the generated signatures. + """ + info = self._cls.info + arguments = [ + field.to_argument( + info, + typed=typed, + model_strict=model_strict, + force_optional=requires_dynamic_aliases or is_settings, + use_alias=use_alias, + api=self._api, + force_typevars_invariant=force_typevars_invariant, + is_root_model_root=is_root_model and field.name == 'root', + ) + for field in fields + if not (use_alias and field.has_dynamic_alias) + ] + return arguments + + def should_init_forbid_extra(self, fields: list[PydanticModelField], config: ModelConfigData) -> bool: + """Indicates whether the generated `__init__` should get a `**kwargs` at the end of its signature. + + We disallow arbitrary kwargs if the extra config setting is "forbid", or if the plugin config says to, + *unless* a required dynamic alias is present (since then we can't determine a valid signature). + """ + if not (config.validate_by_name or config.populate_by_name): + if self.is_dynamic_alias_present(fields, bool(config.has_alias_generator)): + return False + if config.forbid_extra: + return True + return self.plugin_config.init_forbid_extra + + @staticmethod + def is_dynamic_alias_present(fields: list[PydanticModelField], has_alias_generator: bool) -> bool: + """Returns whether any fields on the model have a "dynamic alias", i.e., an alias that cannot be + determined during static analysis. + """ + for field in fields: + if field.has_dynamic_alias: + return True + if has_alias_generator: + for field in fields: + if field.alias is None: + return True + return False + + +class ChangeExplicitTypeOfAny(TypeTranslator): + """A type translator used to change type of Any's, if explicit.""" + + def __init__(self, type_of_any: int) -> None: + self._type_of_any = type_of_any + super().__init__() + + def visit_any(self, t: AnyType) -> Type: # noqa: D102 + if t.type_of_any == TypeOfAny.explicit: + return t.copy_modified(type_of_any=self._type_of_any) + else: + return t + + +class ModelConfigData: + """Pydantic mypy plugin model config class.""" + + def __init__( + self, + forbid_extra: bool | None = None, + frozen: bool | None = None, + from_attributes: bool | None = None, + populate_by_name: bool | None = None, + validate_by_alias: bool | None = None, + validate_by_name: bool | None = None, + has_alias_generator: bool | None = None, + strict: bool | None = None, + ): + self.forbid_extra = forbid_extra + self.frozen = frozen + self.from_attributes = from_attributes + self.populate_by_name = populate_by_name + self.validate_by_alias = validate_by_alias + self.validate_by_name = validate_by_name + self.has_alias_generator = has_alias_generator + self.strict = strict + + def get_values_dict(self) -> dict[str, Any]: + """Returns a dict of Pydantic model config names to their values. + + It includes the config if config value is not `None`. + """ + return {k: v for k, v in self.__dict__.items() if v is not None} + + def update(self, config: ModelConfigData | None) -> None: + """Update Pydantic model config values.""" + if config is None: + return + for k, v in config.get_values_dict().items(): + setattr(self, k, v) + + def setdefault(self, key: str, value: Any) -> None: + """Set default value for Pydantic model config if config value is `None`.""" + if getattr(self, key) is None: + setattr(self, key, value) + + +def is_root_model(info: TypeInfo) -> bool: + """Return whether the type info is a root model subclass (or the `RootModel` class itself).""" + return info.has_base(ROOT_MODEL_FULLNAME) + + +ERROR_ORM = ErrorCode('pydantic-orm', 'Invalid from_attributes call', 'Pydantic') +ERROR_CONFIG = ErrorCode('pydantic-config', 'Invalid config value', 'Pydantic') +ERROR_ALIAS = ErrorCode('pydantic-alias', 'Dynamic alias disallowed', 'Pydantic') +ERROR_UNEXPECTED = ErrorCode('pydantic-unexpected', 'Unexpected behavior', 'Pydantic') +ERROR_UNTYPED = ErrorCode('pydantic-field', 'Untyped field disallowed', 'Pydantic') +ERROR_FIELD_DEFAULTS = ErrorCode('pydantic-field', 'Invalid Field defaults', 'Pydantic') +ERROR_EXTRA_FIELD_ROOT_MODEL = ErrorCode('pydantic-field', 'Extra field on RootModel subclass', 'Pydantic') + + +def error_from_attributes(model_name: str, api: CheckerPluginInterface, context: Context) -> None: + """Emits an error when the model does not have `from_attributes=True`.""" + api.fail(f'"{model_name}" does not have from_attributes=True', context, code=ERROR_ORM) + + +def error_invalid_config_value(name: str, api: SemanticAnalyzerPluginInterface, context: Context) -> None: + """Emits an error when the config value is invalid.""" + api.fail(f'Invalid value for "Config.{name}"', context, code=ERROR_CONFIG) + + +def error_required_dynamic_aliases(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + """Emits required dynamic aliases error. + + This will be called when `warn_required_dynamic_aliases=True`. + """ + api.fail('Required dynamic aliases disallowed', context, code=ERROR_ALIAS) + + +def error_unexpected_behavior( + detail: str, api: CheckerPluginInterface | SemanticAnalyzerPluginInterface, context: Context +) -> None: # pragma: no cover + """Emits unexpected behavior error.""" + # Can't think of a good way to test this, but I confirmed it renders as desired by adding to a non-error path + link = 'https://github.com/pydantic/pydantic/issues/new/choose' + full_message = f'The pydantic mypy plugin ran into unexpected behavior: {detail}\n' + full_message += f'Please consider reporting this bug at {link} so we can try to fix it!' + api.fail(full_message, context, code=ERROR_UNEXPECTED) + + +def error_untyped_fields(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + """Emits an error when there is an untyped field in the model.""" + api.fail('Untyped fields disallowed', context, code=ERROR_UNTYPED) + + +def error_extra_fields_on_root_model(api: CheckerPluginInterface, context: Context) -> None: + """Emits an error when there is more than just a root field defined for a subclass of RootModel.""" + api.fail('Only `root` is allowed as a field of a `RootModel`', context, code=ERROR_EXTRA_FIELD_ROOT_MODEL) + + +def add_method( + api: SemanticAnalyzerPluginInterface | CheckerPluginInterface, + cls: ClassDef, + name: str, + args: list[Argument], + return_type: Type, + self_type: Type | None = None, + tvar_def: TypeVarType | None = None, + is_classmethod: bool = False, +) -> None: + """Very closely related to `mypy.plugins.common.add_method_to_class`, with a few pydantic-specific changes.""" + info = cls.info + + # First remove any previously generated methods with the same name + # to avoid clashes and problems in the semantic analyzer. + if name in info.names: + sym = info.names[name] + if sym.plugin_generated and isinstance(sym.node, FuncDef): + cls.defs.body.remove(sym.node) # pragma: no cover + + if isinstance(api, SemanticAnalyzerPluginInterface): + function_type = api.named_type('builtins.function') + else: + function_type = api.named_generic_type('builtins.function', []) + + if is_classmethod: + self_type = self_type or TypeType(fill_typevars(info)) + first = [Argument(Var('_cls'), self_type, None, ARG_POS, True)] + else: + self_type = self_type or fill_typevars(info) + # `self` is positional *ONLY* here, but this can't be expressed + # fully in the mypy internal API. ARG_POS is the closest we can get. + # Using ARG_POS will, however, give mypy errors if a `self` field + # is present on a model: + # + # Name "self" already defined (possibly by an import) [no-redef] + # + # As a workaround, we give this argument a name that will + # never conflict. By its positional nature, this name will not + # be used or exposed to users. + first = [Argument(Var('__pydantic_self__'), self_type, None, ARG_POS)] + args = first + args + + arg_types, arg_names, arg_kinds = [], [], [] + for arg in args: + assert arg.type_annotation, 'All arguments must be fully typed.' + arg_types.append(arg.type_annotation) + arg_names.append(arg.variable.name) + arg_kinds.append(arg.kind) + + signature = CallableType( + arg_types, arg_kinds, arg_names, return_type, function_type, variables=[tvar_def] if tvar_def else None + ) + + func = FuncDef(name, args, Block([PassStmt()])) + func.info = info + func.type = set_callable_name(signature, func) + func.is_class = is_classmethod + func._fullname = info.fullname + '.' + name + func.line = info.line + + # NOTE: we would like the plugin generated node to dominate, but we still + # need to keep any existing definitions so they get semantically analyzed. + if name in info.names: + # Get a nice unique name instead. + r_name = get_unique_redefinition_name(name, info.names) + info.names[r_name] = info.names[name] + + # Add decorator for is_classmethod + # The dataclasses plugin claims this is unnecessary for classmethods, but not including it results in a + # signature incompatible with the superclass, which causes mypy errors to occur for every subclass of BaseModel. + if is_classmethod: + func.is_decorated = True + v = Var(name, func.type) + v.info = info + v._fullname = func._fullname + v.is_classmethod = True + dec = Decorator(func, [NameExpr('classmethod')], v) + dec.line = info.line + sym = SymbolTableNode(MDEF, dec) + else: + sym = SymbolTableNode(MDEF, func) + sym.plugin_generated = True + info.names[name] = sym + + info.defn.defs.body.append(func) + + +def parse_toml(config_file: str) -> dict[str, Any] | None: + """Returns a dict of config keys to values. + + It reads configs from toml file and returns `None` if the file is not a toml file. + """ + if not config_file.endswith('.toml'): + return None + + if sys.version_info >= (3, 11): + import tomllib as toml_ + else: + try: + import tomli as toml_ + except ImportError: # pragma: no cover + import warnings + + warnings.warn('No TOML parser installed, cannot read configuration from `pyproject.toml`.', stacklevel=2) + return None + + with open(config_file, 'rb') as rf: + return toml_.load(rf) diff --git a/source/target-vendors/cp312/pydantic/networks.py b/source/target-vendors/cp312/pydantic/networks.py new file mode 100644 index 0000000..4015bad --- /dev/null +++ b/source/target-vendors/cp312/pydantic/networks.py @@ -0,0 +1,1332 @@ +"""The networks module contains types for common network-related fields.""" + +from __future__ import annotations as _annotations + +import dataclasses as _dataclasses +import re +from dataclasses import fields +from functools import lru_cache +from importlib.metadata import version +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from typing import TYPE_CHECKING, Annotated, Any, ClassVar + +from pydantic_core import ( + MultiHostHost, + PydanticCustomError, + PydanticSerializationUnexpectedValue, + SchemaSerializer, + core_schema, +) +from pydantic_core import MultiHostUrl as _CoreMultiHostUrl +from pydantic_core import Url as _CoreUrl +from typing_extensions import Self, TypeAlias + +from pydantic.errors import PydanticUserError + +from ._internal import _repr, _schema_generation_shared +from ._migration import getattr_migration +from .annotated_handlers import GetCoreSchemaHandler +from .json_schema import JsonSchemaValue +from .type_adapter import TypeAdapter + +if TYPE_CHECKING: + import email_validator + + NetworkType: TypeAlias = 'str | bytes | int | tuple[str | bytes | int, str | int]' + +else: + email_validator = None + + +__all__ = [ + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'FtpUrl', + 'HttpUrl', + 'WebsocketUrl', + 'AnyWebsocketUrl', + 'UrlConstraints', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'NatsDsn', + 'validate_email', + 'MySQLDsn', + 'MariaDBDsn', + 'ClickHouseDsn', + 'SnowflakeDsn', +] + + +@_dataclasses.dataclass +class UrlConstraints: + """Url constraints. + + Attributes: + max_length: The maximum length of the url. Defaults to `None`. + allowed_schemes: The allowed schemes. Defaults to `None`. + host_required: Whether the host is required. Defaults to `None`. + default_host: The default host. Defaults to `None`. + default_port: The default port. Defaults to `None`. + default_path: The default path. Defaults to `None`. + preserve_empty_path: Whether to preserve empty URL paths. Defaults to `None`. + """ + + max_length: int | None = None + allowed_schemes: list[str] | None = None + host_required: bool | None = None + default_host: str | None = None + default_port: int | None = None + default_path: str | None = None + preserve_empty_path: bool | None = None + + def __hash__(self) -> int: + return hash( + ( + self.max_length, + tuple(self.allowed_schemes) if self.allowed_schemes is not None else None, + self.host_required, + self.default_host, + self.default_port, + self.default_path, + self.preserve_empty_path, + ) + ) + + @property + def defined_constraints(self) -> dict[str, Any]: + """Fetch a key / value mapping of constraints to values that are not None. Used for core schema updates.""" + return {field.name: value for field in fields(self) if (value := getattr(self, field.name)) is not None} + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + + # for function-wrap schemas, url constraints is applied to the inner schema + # because when we generate schemas for urls, we wrap a core_schema.url_schema() with a function-wrap schema + # that helps with validation on initialization, see _BaseUrl and _BaseMultiHostUrl below. + schema_to_mutate = schema['schema'] if schema['type'] == 'function-wrap' else schema + if (annotated_type := schema_to_mutate['type']) not in ('url', 'multi-host-url'): + raise PydanticUserError( + f"'UrlConstraints' cannot annotate '{annotated_type}'.", code='invalid-annotated-type' + ) + for constraint_key, constraint_value in self.defined_constraints.items(): + schema_to_mutate[constraint_key] = constraint_value + return schema + + +class _BaseUrl: + _constraints: ClassVar[UrlConstraints] = UrlConstraints() + _url: _CoreUrl + + def __init__(self, url: str | _CoreUrl | _BaseUrl) -> None: + self._url = _build_type_adapter(self.__class__).validate_python(url)._url + + @property + def scheme(self) -> str: + """The scheme part of the URL. + + e.g. `https` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.scheme + + @property + def username(self) -> str | None: + """The username part of the URL, or `None`. + + e.g. `user` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.username + + @property + def password(self) -> str | None: + """The password part of the URL, or `None`. + + e.g. `pass` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.password + + @property + def host(self) -> str | None: + """The host part of the URL, or `None`. + + If the URL must be punycode encoded, this is the encoded host, e.g if the input URL is `https://£££.com`, + `host` will be `xn--9aaa.com` + """ + return self._url.host + + def unicode_host(self) -> str | None: + """The host part of the URL as a unicode string, or `None`. + + e.g. `host` in `https://user:pass@host:port/path?query#fragment` + + If the URL must be punycode encoded, this is the decoded host, e.g if the input URL is `https://£££.com`, + `unicode_host()` will be `£££.com` + """ + return self._url.unicode_host() + + @property + def port(self) -> int | None: + """The port part of the URL, or `None`. + + e.g. `port` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.port + + @property + def path(self) -> str | None: + """The path part of the URL, or `None`. + + e.g. `/path` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.path + + @property + def query(self) -> str | None: + """The query part of the URL, or `None`. + + e.g. `query` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.query + + def query_params(self) -> list[tuple[str, str]]: + """The query part of the URL as a list of key-value pairs. + + e.g. `[('foo', 'bar')]` in `https://user:pass@host:port/path?foo=bar#fragment` + """ + return self._url.query_params() + + @property + def fragment(self) -> str | None: + """The fragment part of the URL, or `None`. + + e.g. `fragment` in `https://user:pass@host:port/path?query#fragment` + """ + return self._url.fragment + + def unicode_string(self) -> str: + """The URL as a unicode string, unlike `__str__()` this will not punycode encode the host. + + If the URL must be punycode encoded, this is the decoded string, e.g if the input URL is `https://£££.com`, + `unicode_string()` will be `https://£££.com` + """ + return self._url.unicode_string() + + def encoded_string(self) -> str: + """The URL's encoded string representation via __str__(). + + This returns the punycode-encoded host version of the URL as a string. + """ + return str(self) + + def __str__(self) -> str: + """The URL as a string, this will punycode encode the host if required.""" + return str(self._url) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({str(self._url)!r})' + + def __deepcopy__(self, memo: dict) -> Self: + return self.__class__(self._url) + + def __eq__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url == other._url + + def __lt__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url < other._url + + def __gt__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url > other._url + + def __le__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url <= other._url + + def __ge__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url >= other._url + + def __hash__(self) -> int: + return hash(self._url) + + def __len__(self) -> int: + return len(str(self._url)) + + @classmethod + def build( + cls, + *, + scheme: str, + username: str | None = None, + password: str | None = None, + host: str, + port: int | None = None, + path: str | None = None, + query: str | None = None, + fragment: str | None = None, + ) -> Self: + """Build a new `Url` instance from its component parts. + + Args: + scheme: The scheme part of the URL. + username: The username part of the URL, or omit for no username. + password: The password part of the URL, or omit for no password. + host: The host part of the URL. + port: The port part of the URL, or omit for no port. + path: The path part of the URL, or omit for no path. + query: The query part of the URL, or omit for no query. + fragment: The fragment part of the URL, or omit for no fragment. + + Returns: + An instance of URL + """ + return cls( + _CoreUrl.build( + scheme=scheme, + username=username, + password=password, + host=host, + port=port, + path=path, + query=query, + fragment=fragment, + ) + ) + + @classmethod + def serialize_url(cls, url: Any, info: core_schema.SerializationInfo) -> str | Self: + if not isinstance(url, cls): + raise PydanticSerializationUnexpectedValue( + f"Expected `{cls}` but got `{type(url)}` with value `'{url}'` - serialized value may not be as expected." + ) + if info.mode == 'json': + return str(url) + return url + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[_BaseUrl], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + def wrap_val(v, h): + if isinstance(v, source): + return v + if isinstance(v, _BaseUrl): + v = str(v) + core_url = h(v) + instance = source.__new__(source) + instance._url = core_url + return instance + + return core_schema.no_info_wrap_validator_function( + wrap_val, + schema=core_schema.url_schema(**cls._constraints.defined_constraints), + serialization=core_schema.plain_serializer_function_ser_schema( + cls.serialize_url, info_arg=True, when_used='always' + ), + ) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + # we use the url schema for json schema generation, but we might have to extract it from + # the function-wrap schema we use as a tool for validation on initialization + inner_schema = core_schema['schema'] if core_schema['type'] == 'function-wrap' else core_schema + return handler(inner_schema) + + __pydantic_serializer__ = SchemaSerializer(core_schema.any_schema(serialization=core_schema.to_string_ser_schema())) + + +class _BaseMultiHostUrl: + _constraints: ClassVar[UrlConstraints] = UrlConstraints() + _url: _CoreMultiHostUrl + + def __init__(self, url: str | _CoreMultiHostUrl | _BaseMultiHostUrl) -> None: + self._url = _build_type_adapter(self.__class__).validate_python(url)._url + + @property + def scheme(self) -> str: + """The scheme part of the URL. + + e.g. `https` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.scheme + + @property + def path(self) -> str | None: + """The path part of the URL, or `None`. + + e.g. `/path` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.path + + @property + def query(self) -> str | None: + """The query part of the URL, or `None`. + + e.g. `query` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.query + + def query_params(self) -> list[tuple[str, str]]: + """The query part of the URL as a list of key-value pairs. + + e.g. `[('foo', 'bar')]` in `https://foo.com,bar.com/path?foo=bar#fragment` + """ + return self._url.query_params() + + @property + def fragment(self) -> str | None: + """The fragment part of the URL, or `None`. + + e.g. `fragment` in `https://foo.com,bar.com/path?query#fragment` + """ + return self._url.fragment + + def hosts(self) -> list[MultiHostHost]: + '''The hosts of the `MultiHostUrl` as [`MultiHostHost`][pydantic_core.MultiHostHost] typed dicts. + + ```python + from pydantic_core import MultiHostUrl + + mhu = MultiHostUrl('https://foo.com:123,foo:bar@bar.com/path') + print(mhu.hosts()) + """ + [ + {'username': None, 'password': None, 'host': 'foo.com', 'port': 123}, + {'username': 'foo', 'password': 'bar', 'host': 'bar.com', 'port': 443} + ] + ``` + Returns: + A list of dicts, each representing a host. + ''' + return self._url.hosts() + + def encoded_string(self) -> str: + """The URL's encoded string representation via __str__(). + + This returns the punycode-encoded host version of the URL as a string. + """ + return str(self) + + def unicode_string(self) -> str: + """The URL as a unicode string, unlike `__str__()` this will not punycode encode the hosts.""" + return self._url.unicode_string() + + def __str__(self) -> str: + """The URL as a string, this will punycode encode the host if required.""" + return str(self._url) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({str(self._url)!r})' + + def __deepcopy__(self, memo: dict) -> Self: + return self.__class__(self._url) + + def __eq__(self, other: Any) -> bool: + return self.__class__ is other.__class__ and self._url == other._url + + def __hash__(self) -> int: + return hash(self._url) + + def __len__(self) -> int: + return len(str(self._url)) + + @classmethod + def build( + cls, + *, + scheme: str, + hosts: list[MultiHostHost] | None = None, + username: str | None = None, + password: str | None = None, + host: str | None = None, + port: int | None = None, + path: str | None = None, + query: str | None = None, + fragment: str | None = None, + ) -> Self: + """Build a new `MultiHostUrl` instance from its component parts. + + This method takes either `hosts` - a list of `MultiHostHost` typed dicts, or the individual components + `username`, `password`, `host` and `port`. + + Args: + scheme: The scheme part of the URL. + hosts: Multiple hosts to build the URL from. + username: The username part of the URL. + password: The password part of the URL. + host: The host part of the URL. + port: The port part of the URL. + path: The path part of the URL. + query: The query part of the URL, or omit for no query. + fragment: The fragment part of the URL, or omit for no fragment. + + Returns: + An instance of `MultiHostUrl` + """ + return cls( + _CoreMultiHostUrl.build( + scheme=scheme, + hosts=hosts, + username=username, + password=password, + host=host, + port=port, + path=path, + query=query, + fragment=fragment, + ) + ) + + @classmethod + def serialize_url(cls, url: Any, info: core_schema.SerializationInfo) -> str | Self: + if not isinstance(url, cls): + raise PydanticSerializationUnexpectedValue( + f"Expected `{cls}` but got `{type(url)}` with value `'{url}'` - serialized value may not be as expected." + ) + if info.mode == 'json': + return str(url) + return url + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[_BaseMultiHostUrl], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + def wrap_val(v, h): + if isinstance(v, source): + return v + if isinstance(v, _BaseMultiHostUrl): + v = str(v) + core_url = h(v) + instance = source.__new__(source) + instance._url = core_url + return instance + + return core_schema.no_info_wrap_validator_function( + wrap_val, + schema=core_schema.multi_host_url_schema(**cls._constraints.defined_constraints), + serialization=core_schema.plain_serializer_function_ser_schema( + cls.serialize_url, info_arg=True, when_used='always' + ), + ) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + # we use the url schema for json schema generation, but we might have to extract it from + # the function-wrap schema we use as a tool for validation on initialization + inner_schema = core_schema['schema'] if core_schema['type'] == 'function-wrap' else core_schema + return handler(inner_schema) + + __pydantic_serializer__ = SchemaSerializer(core_schema.any_schema(serialization=core_schema.to_string_ser_schema())) + + +@lru_cache +def _build_type_adapter(cls: type[_BaseUrl | _BaseMultiHostUrl]) -> TypeAdapter: + return TypeAdapter(cls) + + +class AnyUrl(_BaseUrl): + """Base type for all URLs. + + * Any scheme allowed + * Top-level domain (TLD) not required + * Host not required + + Assuming an input URL of `http://samuel:pass@example.com:8000/the/path/?query=here#fragment=is;this=bit`, + the types export the following properties: + + - `scheme`: the URL scheme (`http`), always set. + - `host`: the URL host (`example.com`). + - `username`: optional username if included (`samuel`). + - `password`: optional password if included (`pass`). + - `port`: optional port (`8000`). + - `path`: optional path (`/the/path/`). + - `query`: optional URL query (for example, `GET` arguments or "search string", such as `query=here`). + - `fragment`: optional fragment (`fragment=is;this=bit`). + """ + + +# Note: all single host urls inherit from `AnyUrl` to preserve compatibility with pre-v2.10 code +# Where urls were annotated variants of `AnyUrl`, which was an alias to `pydantic_core.Url` + + +class AnyHttpUrl(AnyUrl): + """A type that will accept any http or https URL. + + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['http', 'https']) + + +class HttpUrl(AnyUrl): + """A type that will accept any http or https URL. + + * TLD not required + * Host not required + * Max length 2083 + + ```python + from pydantic import BaseModel, HttpUrl, ValidationError + + class MyModel(BaseModel): + url: HttpUrl + + m = MyModel(url='http://www.example.com') # (1)! + print(m.url) + #> http://www.example.com/ + + try: + MyModel(url='ftp://invalid.url') + except ValidationError as e: + print(e) + ''' + 1 validation error for MyModel + url + URL scheme should be 'http' or 'https' [type=url_scheme, input_value='ftp://invalid.url', input_type=str] + ''' + + try: + MyModel(url='not a url') + except ValidationError as e: + print(e) + ''' + 1 validation error for MyModel + url + Input should be a valid URL, relative URL without a base [type=url_parsing, input_value='not a url', input_type=str] + ''' + ``` + + 1. Note: mypy would prefer `m = MyModel(url=HttpUrl('http://www.example.com'))`, but Pydantic will convert the string to an HttpUrl instance anyway. + + "International domains" (e.g. a URL where the host or TLD includes non-ascii characters) will be encoded via + [punycode](https://en.wikipedia.org/wiki/Punycode) (see + [this article](https://www.xudongz.com/blog/2017/idn-phishing/) for a good description of why this is important): + + ```python + from pydantic import BaseModel, HttpUrl + + class MyModel(BaseModel): + url: HttpUrl + + m1 = MyModel(url='http://puny£code.com') + print(m1.url) + #> http://xn--punycode-eja.com/ + m2 = MyModel(url='https://www.аррӏе.com/') + print(m2.url) + #> https://www.xn--80ak6aa92e.com/ + m3 = MyModel(url='https://www.example.珠宝/') + print(m3.url) + #> https://www.example.xn--pbt977c/ + ``` + + + !!! warning "Underscores in Hostnames" + In Pydantic, underscores are allowed in all parts of a domain except the TLD. + Technically this might be wrong - in theory the hostname cannot have underscores, but subdomains can. + + To explain this; consider the following two cases: + + - `exam_ple.co.uk`: the hostname is `exam_ple`, which should not be allowed since it contains an underscore. + - `foo_bar.example.com` the hostname is `example`, which should be allowed since the underscore is in the subdomain. + + Without having an exhaustive list of TLDs, it would be impossible to differentiate between these two. Therefore + underscores are allowed, but you can always do further validation in a validator if desired. + + Also, Chrome, Firefox, and Safari all currently accept `http://exam_ple.com` as a URL, so we're in good + (or at least big) company. + """ + + _constraints = UrlConstraints(max_length=2083, allowed_schemes=['http', 'https']) + + +class AnyWebsocketUrl(AnyUrl): + """A type that will accept any ws or wss URL. + + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['ws', 'wss']) + + +class WebsocketUrl(AnyUrl): + """A type that will accept any ws or wss URL. + + * TLD not required + * Host not required + * Max length 2083 + """ + + _constraints = UrlConstraints(max_length=2083, allowed_schemes=['ws', 'wss']) + + +class FileUrl(AnyUrl): + """A type that will accept any file URL. + + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['file']) + + +class FtpUrl(AnyUrl): + """A type that will accept ftp URL. + + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['ftp']) + + +class PostgresDsn(_BaseMultiHostUrl): + """A type that will accept any Postgres DSN. + + * User info required + * TLD not required + * Host required + * Supports multiple hosts + + If further validation is required, these properties can be used by validators to enforce specific behaviour: + + ```python + from pydantic import ( + BaseModel, + HttpUrl, + PostgresDsn, + ValidationError, + field_validator, + ) + + class MyModel(BaseModel): + url: HttpUrl + + m = MyModel(url='http://www.example.com') + + # the repr() method for a url will display all properties of the url + print(repr(m.url)) + #> HttpUrl('http://www.example.com/') + print(m.url.scheme) + #> http + print(m.url.host) + #> www.example.com + print(m.url.port) + #> 80 + + class MyDatabaseModel(BaseModel): + db: PostgresDsn + + @field_validator('db') + def check_db_name(cls, v): + assert v.path and len(v.path) > 1, 'database must be provided' + return v + + m = MyDatabaseModel(db='postgres://user:pass@localhost:5432/foobar') + print(m.db) + #> postgres://user:pass@localhost:5432/foobar + + try: + MyDatabaseModel(db='postgres://user:pass@localhost:5432') + except ValidationError as e: + print(e) + ''' + 1 validation error for MyDatabaseModel + db + Assertion failed, database must be provided + assert (None) + + where None = PostgresDsn('postgres://user:pass@localhost:5432').path [type=assertion_error, input_value='postgres://user:pass@localhost:5432', input_type=str] + ''' + ``` + """ + + _constraints = UrlConstraints( + host_required=True, + allowed_schemes=[ + 'postgres', + 'postgresql', + 'postgresql+asyncpg', + 'postgresql+pg8000', + 'postgresql+psycopg', + 'postgresql+psycopg2', + 'postgresql+psycopg2cffi', + 'postgresql+py-postgresql', + 'postgresql+pygresql', + ], + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportAttributeAccessIssue] + + +class CockroachDsn(AnyUrl): + """A type that will accept any Cockroach DSN. + + * User info required + * TLD not required + * Host required + """ + + _constraints = UrlConstraints( + host_required=True, + allowed_schemes=[ + 'cockroachdb', + 'cockroachdb+psycopg2', + 'cockroachdb+asyncpg', + ], + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportReturnType] + + +class AmqpDsn(AnyUrl): + """A type that will accept any AMQP DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['amqp', 'amqps']) + + +class RedisDsn(AnyUrl): + """A type that will accept any Redis DSN. + + * User info required + * TLD not required + * Host required (e.g., `rediss://:pass@localhost`) + """ + + _constraints = UrlConstraints( + allowed_schemes=['redis', 'rediss'], + default_host='localhost', + default_port=6379, + default_path='/0', + host_required=True, + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportReturnType] + + +class MongoDsn(_BaseMultiHostUrl): + """A type that will accept any MongoDB DSN. + + * User info not required + * Database name not required + * Port not required + * User info may be passed without user part (e.g., `mongodb://mongodb0.example.com:27017`). + + !!! warning + If a port isn't specified, the default MongoDB port `27017` will be used. If this behavior is + undesirable, you can use the following: + + ```python + from typing import Annotated + + from pydantic_core import MultiHostUrl + + from pydantic import UrlConstraints + + MongoDsnNoDefaultPort = Annotated[ + MultiHostUrl, + UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv']), + ] + ``` + """ + + _constraints = UrlConstraints(allowed_schemes=['mongodb', 'mongodb+srv'], default_port=27017) + + +class KafkaDsn(AnyUrl): + """A type that will accept any Kafka DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints(allowed_schemes=['kafka'], default_host='localhost', default_port=9092) + + +class NatsDsn(_BaseMultiHostUrl): + """A type that will accept any NATS DSN. + + NATS is a connective technology built for the ever increasingly hyper-connected world. + It is a single technology that enables applications to securely communicate across + any combination of cloud vendors, on-premise, edge, web and mobile, and devices. + More: https://nats.io + """ + + _constraints = UrlConstraints( + allowed_schemes=['nats', 'tls', 'ws', 'wss'], default_host='localhost', default_port=4222 + ) + + +class MySQLDsn(AnyUrl): + """A type that will accept any MySQL DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints( + allowed_schemes=[ + 'mysql', + 'mysql+mysqlconnector', + 'mysql+aiomysql', + 'mysql+asyncmy', + 'mysql+mysqldb', + 'mysql+pymysql', + 'mysql+cymysql', + 'mysql+pyodbc', + ], + default_port=3306, + host_required=True, + ) + + +class MariaDBDsn(AnyUrl): + """A type that will accept any MariaDB DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints( + allowed_schemes=['mariadb', 'mariadb+mariadbconnector', 'mariadb+pymysql'], + default_port=3306, + ) + + +class ClickHouseDsn(AnyUrl): + """A type that will accept any ClickHouse DSN. + + * User info required + * TLD not required + * Host not required + """ + + _constraints = UrlConstraints( + allowed_schemes=[ + 'clickhouse+native', + 'clickhouse+asynch', + 'clickhouse+http', + 'clickhouse', + 'clickhouses', + 'clickhousedb', + ], + default_host='localhost', + default_port=9000, + ) + + +class SnowflakeDsn(AnyUrl): + """A type that will accept any Snowflake DSN. + + * User info required + * TLD not required + * Host required + """ + + _constraints = UrlConstraints( + allowed_schemes=['snowflake'], + host_required=True, + ) + + @property + def host(self) -> str: + """The required URL host.""" + return self._url.host # pyright: ignore[reportReturnType] + + +def import_email_validator() -> None: + global email_validator + try: + import email_validator + except ImportError as e: + raise ImportError("email-validator is not installed, run `pip install 'pydantic[email]'`") from e + if not version('email-validator').partition('.')[0] == '2': + raise ImportError('email-validator version >= 2.0 required, run pip install -U email-validator') + + +if TYPE_CHECKING: + EmailStr = Annotated[str, ...] +else: + + class EmailStr: + """ + Info: + To use this type, you need to install the optional + [`email-validator`](https://github.com/JoshData/python-email-validator) package: + + ```bash + pip install email-validator + ``` + + Validate email addresses. + + ```python + from pydantic import BaseModel, EmailStr + + class Model(BaseModel): + email: EmailStr + + print(Model(email='contact@mail.com')) + #> email='contact@mail.com' + ``` + """ # noqa: D212 + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + import_email_validator() + return core_schema.no_info_after_validator_function(cls._validate, core_schema.str_schema()) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format='email') + return field_schema + + @classmethod + def _validate(cls, input_value: str, /) -> str: + return validate_email(input_value)[1] + + +class NameEmail(_repr.Representation): + """ + Info: + To use this type, you need to install the optional + [`email-validator`](https://github.com/JoshData/python-email-validator) package: + + ```bash + pip install email-validator + ``` + + Validate a name and email address combination, as specified by + [RFC 5322](https://datatracker.ietf.org/doc/html/rfc5322#section-3.4). + + The `NameEmail` has two properties: `name` and `email`. + In case the `name` is not provided, it's inferred from the email address. + + ```python + from pydantic import BaseModel, NameEmail + + class User(BaseModel): + email: NameEmail + + user = User(email='Fred Bloggs ') + print(user.email) + #> Fred Bloggs + print(user.email.name) + #> Fred Bloggs + + user = User(email='fred.bloggs@example.com') + print(user.email) + #> fred.bloggs + print(user.email.name) + #> fred.bloggs + ``` + """ # noqa: D212 + + __slots__ = 'name', 'email' + + def __init__(self, name: str, email: str): + self.name = name + self.email = email + + def __eq__(self, other: Any) -> bool: + return isinstance(other, NameEmail) and (self.name, self.email) == (other.name, other.email) + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format='name-email') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + import_email_validator() + + return core_schema.no_info_after_validator_function( + cls._validate, + core_schema.json_or_python_schema( + json_schema=core_schema.str_schema(), + python_schema=core_schema.union_schema( + [core_schema.is_instance_schema(cls), core_schema.str_schema()], + custom_error_type='name_email_type', + custom_error_message='Input is not a valid NameEmail', + ), + serialization=core_schema.to_string_ser_schema(), + ), + ) + + @classmethod + def _validate(cls, input_value: Self | str, /) -> Self: + if isinstance(input_value, str): + name, email = validate_email(input_value) + return cls(name, email) + else: + return input_value + + def __str__(self) -> str: + if '@' in self.name: + return f'"{self.name}" <{self.email}>' + + return f'{self.name} <{self.email}>' + + +IPvAnyAddressType: TypeAlias = 'IPv4Address | IPv6Address' +IPvAnyInterfaceType: TypeAlias = 'IPv4Interface | IPv6Interface' +IPvAnyNetworkType: TypeAlias = 'IPv4Network | IPv6Network' + +if TYPE_CHECKING: + IPvAnyAddress = IPvAnyAddressType + IPvAnyInterface = IPvAnyInterfaceType + IPvAnyNetwork = IPvAnyNetworkType +else: + + class IPvAnyAddress: + """Validate an IPv4 or IPv6 address. + + ```python + from pydantic import BaseModel + from pydantic.networks import IPvAnyAddress + + class IpModel(BaseModel): + ip: IPvAnyAddress + + print(IpModel(ip='127.0.0.1')) + #> ip=IPv4Address('127.0.0.1') + + try: + IpModel(ip='http://www.example.com') + except ValueError as e: + print(e.errors()) + ''' + [ + { + 'type': 'ip_any_address', + 'loc': ('ip',), + 'msg': 'value is not a valid IPv4 or IPv6 address', + 'input': 'http://www.example.com', + } + ] + ''' + ``` + """ + + __slots__ = () + + def __new__(cls, value: Any) -> IPvAnyAddressType: + """Validate an IPv4 or IPv6 address.""" + try: + return IPv4Address(value) + except ValueError: + pass + + try: + return IPv6Address(value) + except ValueError: + raise PydanticCustomError('ip_any_address', 'value is not a valid IPv4 or IPv6 address') + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='ipvanyaddress') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, input_value: Any, /) -> IPvAnyAddressType: + return cls(input_value) # type: ignore[return-value] + + class IPvAnyInterface: + """Validate an IPv4 or IPv6 interface.""" + + __slots__ = () + + def __new__(cls, value: NetworkType) -> IPvAnyInterfaceType: + """Validate an IPv4 or IPv6 interface.""" + try: + return IPv4Interface(value) + except ValueError: + pass + + try: + return IPv6Interface(value) + except ValueError: + raise PydanticCustomError('ip_any_interface', 'value is not a valid IPv4 or IPv6 interface') + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='ipvanyinterface') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, input_value: NetworkType, /) -> IPvAnyInterfaceType: + return cls(input_value) # type: ignore[return-value] + + class IPvAnyNetwork: + """Validate an IPv4 or IPv6 network.""" + + __slots__ = () + + def __new__(cls, value: NetworkType) -> IPvAnyNetworkType: + """Validate an IPv4 or IPv6 network.""" + # Assume IP Network is defined with a default value for `strict` argument. + # Define your own class if you want to specify network address check strictness. + try: + return IPv4Network(value) + except ValueError: + pass + + try: + return IPv6Network(value) + except ValueError: + raise PydanticCustomError('ip_any_network', 'value is not a valid IPv4 or IPv6 network') + + @classmethod + def __get_pydantic_json_schema__( + cls, core_schema: core_schema.CoreSchema, handler: _schema_generation_shared.GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = {} + field_schema.update(type='string', format='ipvanynetwork') + return field_schema + + @classmethod + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: GetCoreSchemaHandler, + ) -> core_schema.CoreSchema: + return core_schema.no_info_plain_validator_function( + cls._validate, serialization=core_schema.to_string_ser_schema() + ) + + @classmethod + def _validate(cls, input_value: NetworkType, /) -> IPvAnyNetworkType: + return cls(input_value) # type: ignore[return-value] + + +def _build_pretty_email_regex() -> re.Pattern[str]: + name_chars = r'[\w!#$%&\'*+\-/=?^_`{|}~]' + unquoted_name_group = rf'((?:{name_chars}+\s+)*{name_chars}+)' + quoted_name_group = r'"((?:[^"]|\")+)"' + email_group = r'<(.+)>' + return re.compile(rf'\s*(?:{unquoted_name_group}|{quoted_name_group})?\s*{email_group}\s*') + + +pretty_email_regex = _build_pretty_email_regex() + +MAX_EMAIL_LENGTH = 2048 +"""Maximum length for an email. +A somewhat arbitrary but very generous number compared to what is allowed by most implementations. +""" + + +def validate_email(value: str) -> tuple[str, str]: + """Email address validation using [email-validator](https://pypi.org/project/email-validator/). + + Returns: + A tuple containing the local part of the email (or the name for "pretty" email addresses) + and the normalized email. + + Raises: + PydanticCustomError: If the email is invalid. + + Note: + Note that: + + * Raw IP address (literal) domain parts are not allowed. + * `"John Doe "` style "pretty" email addresses are processed. + * Spaces are striped from the beginning and end of addresses, but no error is raised. + """ + if email_validator is None: + import_email_validator() + + if len(value) > MAX_EMAIL_LENGTH: + raise PydanticCustomError( + 'value_error', + 'value is not a valid email address: {reason}', + {'reason': f'Length must not exceed {MAX_EMAIL_LENGTH} characters'}, + ) + + m = pretty_email_regex.fullmatch(value) + name: str | None = None + if m: + unquoted_name, quoted_name, value = m.groups() + name = unquoted_name or quoted_name + + email = value.strip() + + try: + parts = email_validator.validate_email(email, check_deliverability=False) + except email_validator.EmailNotValidError as e: + raise PydanticCustomError( + 'value_error', 'value is not a valid email address: {reason}', {'reason': str(e.args[0])} + ) from e + + email = parts.normalized + assert email is not None + name = name or parts.local_part + return name, email + + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/parse.py b/source/target-vendors/cp312/pydantic/parse.py new file mode 100644 index 0000000..68b7f04 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/parse.py @@ -0,0 +1,5 @@ +"""The `parse` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/plugin/__init__.py b/source/target-vendors/cp312/pydantic/plugin/__init__.py new file mode 100644 index 0000000..840d20a --- /dev/null +++ b/source/target-vendors/cp312/pydantic/plugin/__init__.py @@ -0,0 +1,193 @@ +"""!!! abstract "Usage Documentation" + [Build a Plugin](../concepts/plugins.md#build-a-plugin) + +Plugin interface for Pydantic plugins, and related types. +""" + +from __future__ import annotations + +from typing import Any, Callable, Literal, NamedTuple + +from pydantic_core import CoreConfig, CoreSchema, ValidationError +from typing_extensions import Protocol, TypeAlias + +from pydantic.config import ExtraValues + +__all__ = ( + 'PydanticPluginProtocol', + 'BaseValidateHandlerProtocol', + 'ValidatePythonHandlerProtocol', + 'ValidateJsonHandlerProtocol', + 'ValidateStringsHandlerProtocol', + 'NewSchemaReturns', + 'SchemaTypePath', + 'SchemaKind', +) + +NewSchemaReturns: TypeAlias = 'tuple[ValidatePythonHandlerProtocol | None, ValidateJsonHandlerProtocol | None, ValidateStringsHandlerProtocol | None]' + + +class SchemaTypePath(NamedTuple): + """Path defining where `schema_type` was defined, or where `TypeAdapter` was called.""" + + module: str + name: str + + +SchemaKind: TypeAlias = Literal['BaseModel', 'TypeAdapter', 'dataclass', 'create_model', 'validate_call'] + + +class PydanticPluginProtocol(Protocol): + """Protocol defining the interface for Pydantic plugins.""" + + def new_schema_validator( + self, + schema: CoreSchema, + schema_type: Any, + schema_type_path: SchemaTypePath, + schema_kind: SchemaKind, + config: CoreConfig | None, + plugin_settings: dict[str, object], + ) -> tuple[ + ValidatePythonHandlerProtocol | None, ValidateJsonHandlerProtocol | None, ValidateStringsHandlerProtocol | None + ]: + """This method is called for each plugin every time a new [`SchemaValidator`][pydantic_core.SchemaValidator] + is created. + + It should return an event handler for each of the three validation methods, or `None` if the plugin does not + implement that method. + + Args: + schema: The schema to validate against. + schema_type: The original type which the schema was created from, e.g. the model class. + schema_type_path: Path defining where `schema_type` was defined, or where `TypeAdapter` was called. + schema_kind: The kind of schema to validate against. + config: The config to use for validation. + plugin_settings: Any plugin settings. + + Returns: + A tuple of optional event handlers for each of the three validation methods - + `validate_python`, `validate_json`, `validate_strings`. + """ + raise NotImplementedError('Pydantic plugins should implement `new_schema_validator`.') + + +class BaseValidateHandlerProtocol(Protocol): + """Base class for plugin callbacks protocols. + + You shouldn't implement this protocol directly, instead use one of the subclasses with adds the correctly + typed `on_error` method. + """ + + on_enter: Callable[..., None] + """`on_enter` is changed to be more specific on all subclasses""" + + def on_success(self, result: Any) -> None: + """Callback to be notified of successful validation. + + Args: + result: The result of the validation. + """ + return + + def on_error(self, error: ValidationError) -> None: + """Callback to be notified of validation errors. + + Args: + error: The validation error. + """ + return + + def on_exception(self, exception: Exception) -> None: + """Callback to be notified of validation exceptions. + + Args: + exception: The exception raised during validation. + """ + return + + +class ValidatePythonHandlerProtocol(BaseValidateHandlerProtocol, Protocol): + """Event handler for `SchemaValidator.validate_python`.""" + + def on_enter( + self, + input: Any, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + self_instance: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> None: + """Callback to be notified of validation start, and create an instance of the event handler. + + Args: + input: The input to be validated. + strict: Whether to validate the object in strict mode. + extra: Whether to ignore, allow, or forbid extra data during model validation. + from_attributes: Whether to validate objects as inputs by extracting attributes. + context: The context to use for validation, this is passed to functional validators. + self_instance: An instance of a model to set attributes on from validation, this is used when running + validation from the `__init__` method of a model. + by_alias: Whether to use the field's alias to match the input data to an attribute. + by_name: Whether to use the field's name to match the input data to an attribute. + """ + + +class ValidateJsonHandlerProtocol(BaseValidateHandlerProtocol, Protocol): + """Event handler for `SchemaValidator.validate_json`.""" + + def on_enter( + self, + input: str | bytes | bytearray, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + self_instance: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> None: + """Callback to be notified of validation start, and create an instance of the event handler. + + Args: + input: The JSON data to be validated. + strict: Whether to validate the object in strict mode. + extra: Whether to ignore, allow, or forbid extra data during model validation. + context: The context to use for validation, this is passed to functional validators. + self_instance: An instance of a model to set attributes on from validation, this is used when running + validation from the `__init__` method of a model. + by_alias: Whether to use the field's alias to match the input data to an attribute. + by_name: Whether to use the field's name to match the input data to an attribute. + """ + + +StringInput: TypeAlias = 'dict[str, StringInput]' + + +class ValidateStringsHandlerProtocol(BaseValidateHandlerProtocol, Protocol): + """Event handler for `SchemaValidator.validate_strings`.""" + + def on_enter( + self, + input: StringInput, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> None: + """Callback to be notified of validation start, and create an instance of the event handler. + + Args: + input: The string data to be validated. + strict: Whether to validate the object in strict mode. + extra: Whether to ignore, allow, or forbid extra data during model validation. + context: The context to use for validation, this is passed to functional validators. + by_alias: Whether to use the field's alias to match the input data to an attribute. + by_name: Whether to use the field's name to match the input data to an attribute. + """ diff --git a/source/target-vendors/cp312/pydantic/plugin/_loader.py b/source/target-vendors/cp312/pydantic/plugin/_loader.py new file mode 100644 index 0000000..e8226fa --- /dev/null +++ b/source/target-vendors/cp312/pydantic/plugin/_loader.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import importlib.metadata as importlib_metadata +import os +import warnings +from collections.abc import Iterable +from typing import TYPE_CHECKING, Final + +if TYPE_CHECKING: + from . import PydanticPluginProtocol + + +PYDANTIC_ENTRY_POINT_GROUP: Final[str] = 'pydantic' + +# cache of plugins +_plugins: dict[str, PydanticPluginProtocol] | None = None +# return no plugins while loading plugins to avoid recursion and errors while importing plugins +# this means that if plugins use pydantic +_loading_plugins: bool = False + + +def get_plugins() -> Iterable[PydanticPluginProtocol]: + """Load plugins for Pydantic. + + Inspired by: https://github.com/pytest-dev/pluggy/blob/1.3.0/src/pluggy/_manager.py#L376-L402 + """ + disabled_plugins = os.getenv('PYDANTIC_DISABLE_PLUGINS') + global _plugins, _loading_plugins + if _loading_plugins: + # this happens when plugins themselves use pydantic, we return no plugins + return () + elif disabled_plugins in ('__all__', '1', 'true'): + return () + elif _plugins is None: + _plugins = {} + # set _loading_plugins so any plugins that use pydantic don't themselves use plugins + _loading_plugins = True + try: + for dist in importlib_metadata.distributions(): + for entry_point in dist.entry_points: + if entry_point.group != PYDANTIC_ENTRY_POINT_GROUP: + continue + if entry_point.value in _plugins: + continue + if disabled_plugins is not None and entry_point.name in disabled_plugins.split(','): + continue + try: + _plugins[entry_point.value] = entry_point.load() + except (ImportError, AttributeError) as e: + warnings.warn( + f'{e.__class__.__name__} while loading the `{entry_point.name}` Pydantic plugin, ' + f'this plugin will not be installed.\n\n{e!r}', + stacklevel=2, + ) + finally: + _loading_plugins = False + + return _plugins.values() diff --git a/source/target-vendors/cp312/pydantic/plugin/_schema_validator.py b/source/target-vendors/cp312/pydantic/plugin/_schema_validator.py new file mode 100644 index 0000000..6ca5563 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/plugin/_schema_validator.py @@ -0,0 +1,152 @@ +"""Pluggable schema validator for pydantic.""" + +from __future__ import annotations + +import functools +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar + +from pydantic_core import CoreConfig, CoreSchema, SchemaValidator, ValidationError +from typing_extensions import ParamSpec + +if TYPE_CHECKING: + from . import BaseValidateHandlerProtocol, PydanticPluginProtocol, SchemaKind, SchemaTypePath + + +P = ParamSpec('P') +R = TypeVar('R') +Event = Literal['on_validate_python', 'on_validate_json', 'on_validate_strings'] +events: list[Event] = list(Event.__args__) # type: ignore + + +def create_schema_validator( + schema: CoreSchema, + schema_type: Any, + schema_type_module: str, + schema_type_name: str, + schema_kind: SchemaKind, + config: CoreConfig | None = None, + plugin_settings: dict[str, Any] | None = None, + _use_prebuilt: bool = True, +) -> SchemaValidator | PluggableSchemaValidator: + """Create a `SchemaValidator` or `PluggableSchemaValidator` if plugins are installed. + + Returns: + If plugins are installed then return `PluggableSchemaValidator`, otherwise return `SchemaValidator`. + """ + from . import SchemaTypePath + from ._loader import get_plugins + + plugins = get_plugins() + if plugins: + return PluggableSchemaValidator( + schema, + schema_type, + SchemaTypePath(schema_type_module, schema_type_name), + schema_kind, + config, + plugins, + plugin_settings or {}, + _use_prebuilt=_use_prebuilt, + ) + else: + return SchemaValidator(schema, config, _use_prebuilt=_use_prebuilt) + + +class PluggableSchemaValidator: + """Pluggable schema validator.""" + + __slots__ = '_schema_validator', 'validate_json', 'validate_python', 'validate_strings' + + def __init__( + self, + schema: CoreSchema, + schema_type: Any, + schema_type_path: SchemaTypePath, + schema_kind: SchemaKind, + config: CoreConfig | None, + plugins: Iterable[PydanticPluginProtocol], + plugin_settings: dict[str, Any], + _use_prebuilt: bool = True, + ) -> None: + self._schema_validator = SchemaValidator(schema, config, _use_prebuilt=_use_prebuilt) + + python_event_handlers: list[BaseValidateHandlerProtocol] = [] + json_event_handlers: list[BaseValidateHandlerProtocol] = [] + strings_event_handlers: list[BaseValidateHandlerProtocol] = [] + for plugin in plugins: + try: + p, j, s = plugin.new_schema_validator( + schema, schema_type, schema_type_path, schema_kind, config, plugin_settings + ) + except TypeError as e: # pragma: no cover + raise TypeError(f'Error using plugin `{plugin.__module__}:{plugin.__class__.__name__}`: {e}') from e + if p is not None: + python_event_handlers.append(p) + if j is not None: + json_event_handlers.append(j) + if s is not None: + strings_event_handlers.append(s) + + self.validate_python = build_wrapper(self._schema_validator.validate_python, python_event_handlers) + self.validate_json = build_wrapper(self._schema_validator.validate_json, json_event_handlers) + self.validate_strings = build_wrapper(self._schema_validator.validate_strings, strings_event_handlers) + + # Used to allow reuse of validators in pydantic-core (see pydantic-core/src/validators/prebuilt.rs): + @property + def __pydantic_schema_validator__(self) -> SchemaValidator: + """The underlying pydantic-core `SchemaValidator`. + + This is a private attribute, not meant to be used outside Pydantic. + """ + return self._schema_validator + + def __getattr__(self, name: str) -> Any: + return getattr(self._schema_validator, name) + + +def build_wrapper(func: Callable[P, R], event_handlers: list[BaseValidateHandlerProtocol]) -> Callable[P, R]: + if not event_handlers: + return func + else: + on_enters = tuple(h.on_enter for h in event_handlers if filter_handlers(h, 'on_enter')) + on_successes = tuple(h.on_success for h in event_handlers if filter_handlers(h, 'on_success')) + on_errors = tuple(h.on_error for h in event_handlers if filter_handlers(h, 'on_error')) + on_exceptions = tuple(h.on_exception for h in event_handlers if filter_handlers(h, 'on_exception')) + + @functools.wraps(func) + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: + for on_enter_handler in on_enters: + on_enter_handler(*args, **kwargs) + + try: + result = func(*args, **kwargs) + except ValidationError as error: + for on_error_handler in on_errors: + on_error_handler(error) + raise + except Exception as exception: + for on_exception_handler in on_exceptions: + on_exception_handler(exception) + raise + else: + for on_success_handler in on_successes: + on_success_handler(result) + return result + + return wrapper + + +def filter_handlers(handler_cls: BaseValidateHandlerProtocol, method_name: str) -> bool: + """Filter out handler methods which are not implemented by the plugin directly - e.g. those that are missing + or are inherited from the protocol. + """ + handler = getattr(handler_cls, method_name, None) + if handler is None: + return False + elif handler.__module__ == 'pydantic.plugin': + # this is the original handler, from the protocol due to runtime inheritance + # we don't want to call it + return False + else: + return True diff --git a/source/target-vendors/cp312/pydantic/py.typed b/source/target-vendors/cp312/pydantic/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/pydantic/root_model.py b/source/target-vendors/cp312/pydantic/root_model.py new file mode 100644 index 0000000..d290043 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/root_model.py @@ -0,0 +1,157 @@ +"""RootModel class and type definitions.""" + +from __future__ import annotations as _annotations + +from copy import copy, deepcopy +from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar + +from pydantic_core import PydanticUndefined +from typing_extensions import Self, dataclass_transform + +from . import PydanticUserError +from ._internal import _model_construction, _repr +from .main import BaseModel, _object_setattr + +if TYPE_CHECKING: + from .fields import Field as PydanticModelField + from .fields import PrivateAttr as PydanticModelPrivateAttr + + # dataclass_transform could be applied to RootModel directly, but `ModelMetaclass`'s dataclass_transform + # takes priority (at least with pyright). We trick type checkers into thinking we apply dataclass_transform + # on a new metaclass. + @dataclass_transform(kw_only_default=False, field_specifiers=(PydanticModelField, PydanticModelPrivateAttr)) + class _RootModelMetaclass(_model_construction.ModelMetaclass): ... +else: + _RootModelMetaclass = _model_construction.ModelMetaclass + +__all__ = ('RootModel',) + +RootModelRootType = TypeVar('RootModelRootType') + + +class RootModel(BaseModel, Generic[RootModelRootType], metaclass=_RootModelMetaclass): + """!!! abstract "Usage Documentation" + [`RootModel` and Custom Root Types](../concepts/models.md#rootmodel-and-custom-root-types) + + A Pydantic `BaseModel` for the root object of the model. + + Attributes: + root: The root object of the model. + __pydantic_root_model__: Whether the model is a RootModel. + __pydantic_private__: Private fields in the model. + __pydantic_extra__: Extra fields in the model. + + """ + + __pydantic_root_model__ = True + __pydantic_private__ = None + __pydantic_extra__ = None + + root: RootModelRootType + + def __init_subclass__(cls, **kwargs): + extra = cls.model_config.get('extra') + if extra is not None: + raise PydanticUserError( + "`RootModel` does not support setting `model_config['extra']`", code='root-model-extra' + ) + super().__init_subclass__(**kwargs) + + def __init__(self, /, root: RootModelRootType = PydanticUndefined, **data) -> None: # type: ignore + __tracebackhide__ = True + if data: + if root is not PydanticUndefined: + raise ValueError( + '"RootModel.__init__" accepts either a single positional argument or arbitrary keyword arguments' + ) + root = data # type: ignore + self.__pydantic_validator__.validate_python(root, self_instance=self) + + __init__.__pydantic_base_init__ = True # pyright: ignore[reportFunctionMemberAccess] + + @classmethod + def model_construct(cls, root: RootModelRootType, _fields_set: set[str] | None = None) -> Self: # type: ignore + """Create a new model using the provided root object and update fields set. + + Args: + root: The root object of the model. + _fields_set: The set of fields to be updated. + + Returns: + The new model. + + Raises: + NotImplemented: If the model is not a subclass of `RootModel`. + """ + return super().model_construct(root=root, _fields_set=_fields_set) + + def __getstate__(self) -> dict[Any, Any]: + return { + '__dict__': self.__dict__, + '__pydantic_fields_set__': self.__pydantic_fields_set__, + } + + def __setstate__(self, state: dict[Any, Any]) -> None: + _object_setattr(self, '__pydantic_fields_set__', state['__pydantic_fields_set__']) + _object_setattr(self, '__dict__', state['__dict__']) + + def __copy__(self) -> Self: + """Returns a shallow copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + new_dict = copy(self.__dict__) + new_dict['root'] = copy(self.__dict__['root']) + _object_setattr(m, '__dict__', new_dict) + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + return m + + def __deepcopy__(self, memo: dict[int, Any] | None = None) -> Self: + """Returns a deep copy of the model.""" + cls = type(self) + m = cls.__new__(cls) + _object_setattr(m, '__dict__', deepcopy(self.__dict__, memo=memo)) + # This next line doesn't need a deepcopy because __pydantic_fields_set__ is a set[str], + # and attempting a deepcopy would be marginally slower. + _object_setattr(m, '__pydantic_fields_set__', copy(self.__pydantic_fields_set__)) + return m + + if TYPE_CHECKING: + + def model_dump( # type: ignore + self, + *, + mode: Literal['json', 'python'] | str = 'python', + include: Any = None, + exclude: Any = None, + context: dict[str, Any] | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + serialize_as_any: bool = False, + ) -> Any: + """This method is included just to get a more accurate return type for type checkers. + It is included in this `if TYPE_CHECKING:` block since no override is actually necessary. + + See the documentation of `BaseModel.model_dump` for more details about the arguments. + + Generally, this method will have a return type of `RootModelRootType`, assuming that `RootModelRootType` is + not a `BaseModel` subclass. If `RootModelRootType` is a `BaseModel` subclass, then the return + type will likely be `dict[str, Any]`, as `model_dump` calls are recursive. The return type could + even be something different, in the case of a custom serializer. + Thus, `Any` is used here to catch all of these cases. + """ + ... + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, RootModel): + return NotImplemented + return self.__pydantic_fields__['root'].annotation == other.__pydantic_fields__[ + 'root' + ].annotation and super().__eq__(other) + + def __repr_args__(self) -> _repr.ReprArgs: + yield 'root', self.root diff --git a/source/target-vendors/cp312/pydantic/schema.py b/source/target-vendors/cp312/pydantic/schema.py new file mode 100644 index 0000000..a3245a6 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/schema.py @@ -0,0 +1,5 @@ +"""The `schema` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/tools.py b/source/target-vendors/cp312/pydantic/tools.py new file mode 100644 index 0000000..fdc68c4 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/tools.py @@ -0,0 +1,5 @@ +"""The `tools` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/type_adapter.py b/source/target-vendors/cp312/pydantic/type_adapter.py new file mode 100644 index 0000000..d962305 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/type_adapter.py @@ -0,0 +1,801 @@ +"""Type adapter specification.""" + +from __future__ import annotations as _annotations + +import sys +import types +from collections.abc import Callable, Iterable +from dataclasses import is_dataclass +from types import FrameType +from typing import ( + Any, + Generic, + Literal, + TypeVar, + cast, + final, + overload, +) + +from pydantic_core import CoreSchema, SchemaSerializer, SchemaValidator, Some +from typing_extensions import ParamSpec, is_typeddict + +from pydantic.errors import PydanticUserError +from pydantic.main import BaseModel, IncEx + +from ._internal import _config, _generate_schema, _mock_val_ser, _namespace_utils, _repr, _typing_extra, _utils +from .config import ConfigDict, ExtraValues +from .errors import PydanticUndefinedAnnotation +from .json_schema import ( + DEFAULT_REF_TEMPLATE, + GenerateJsonSchema, + JsonSchemaKeyT, + JsonSchemaMode, + JsonSchemaValue, +) +from .plugin._schema_validator import PluggableSchemaValidator, create_schema_validator + +T = TypeVar('T') +R = TypeVar('R') +P = ParamSpec('P') +TypeAdapterT = TypeVar('TypeAdapterT', bound='TypeAdapter') + + +def _getattr_no_parents(obj: Any, attribute: str) -> Any: + """Returns the attribute value without attempting to look up attributes from parent types.""" + if hasattr(obj, '__dict__'): + try: + return obj.__dict__[attribute] + except KeyError: + pass + + slots = getattr(obj, '__slots__', None) + if slots is not None and attribute in slots: + return getattr(obj, attribute) + else: + raise AttributeError(attribute) + + +def _type_has_config(type_: Any) -> bool: + """Returns whether the type has config.""" + type_ = _typing_extra.annotated_type(type_) or type_ + try: + return issubclass(type_, BaseModel) or is_dataclass(type_) or is_typeddict(type_) + except TypeError: + # type is not a class + return False + + +@final +class TypeAdapter(Generic[T]): + """!!! abstract "Usage Documentation" + [`TypeAdapter`](../concepts/type_adapter.md) + + Type adapters provide a flexible way to perform validation and serialization based on a Python type. + + A `TypeAdapter` instance exposes some of the functionality from `BaseModel` instance methods + for types that do not have such methods (such as dataclasses, primitive types, and more). + + **Note:** `TypeAdapter` instances are not types, and cannot be used as type annotations for fields. + + Args: + type: The type associated with the `TypeAdapter`. + config: Configuration for the `TypeAdapter`, should be a dictionary conforming to + [`ConfigDict`][pydantic.config.ConfigDict]. + + !!! note + You cannot provide a configuration when instantiating a `TypeAdapter` if the type you're using + has its own config that cannot be overridden (ex: `BaseModel`, `TypedDict`, and `dataclass`). A + [`type-adapter-config-unused`](../errors/usage_errors.md#type-adapter-config-unused) error will + be raised in this case. + _parent_depth: Depth at which to search for the [parent frame][frame-objects]. This frame is used when + resolving forward annotations during schema building, by looking for the globals and locals of this + frame. Defaults to 2, which will result in the frame where the `TypeAdapter` was instantiated. + + !!! note + This parameter is named with an underscore to suggest its private nature and discourage use. + It may be deprecated in a minor version, so we only recommend using it if you're comfortable + with potential change in behavior/support. It's default value is 2 because internally, + the `TypeAdapter` class makes another call to fetch the frame. + module: The module that passes to plugin if provided. + + Attributes: + core_schema: The core schema for the type. + validator: The schema validator for the type. + serializer: The schema serializer for the type. + pydantic_complete: Whether the core schema for the type is successfully built. + + ??? tip "Compatibility with `mypy`" + Depending on the type used, `mypy` might raise an error when instantiating a `TypeAdapter`. As a workaround, you can explicitly + annotate your variable: + + ```py + from typing import Union + + from pydantic import TypeAdapter + + ta: TypeAdapter[Union[str, int]] = TypeAdapter(Union[str, int]) # type: ignore[arg-type] + ``` + + ??? info "Namespace management nuances and implementation details" + + Here, we collect some notes on namespace management, and subtle differences from `BaseModel`: + + `BaseModel` uses its own `__module__` to find out where it was defined + and then looks for symbols to resolve forward references in those globals. + On the other hand, `TypeAdapter` can be initialized with arbitrary objects, + which may not be types and thus do not have a `__module__` available. + So instead we look at the globals in our parent stack frame. + + It is expected that the `ns_resolver` passed to this function will have the correct + namespace for the type we're adapting. See the source code for `TypeAdapter.__init__` + and `TypeAdapter.rebuild` for various ways to construct this namespace. + + This works for the case where this function is called in a module that + has the target of forward references in its scope, but + does not always work for more complex cases. + + For example, take the following: + + ```python {title="a.py"} + IntList = list[int] + OuterDict = dict[str, 'IntList'] + ``` + + ```python {test="skip" title="b.py"} + from a import OuterDict + + from pydantic import TypeAdapter + + IntList = int # replaces the symbol the forward reference is looking for + v = TypeAdapter(OuterDict) + v({'x': 1}) # should fail but doesn't + ``` + + If `OuterDict` were a `BaseModel`, this would work because it would resolve + the forward reference within the `a.py` namespace. + But `TypeAdapter(OuterDict)` can't determine what module `OuterDict` came from. + + In other words, the assumption that _all_ forward references exist in the + module we are being called from is not technically always true. + Although most of the time it is and it works fine for recursive models and such, + `BaseModel`'s behavior isn't perfect either and _can_ break in similar ways, + so there is no right or wrong between the two. + + But at the very least this behavior is _subtly_ different from `BaseModel`'s. + """ + + core_schema: CoreSchema + validator: SchemaValidator | PluggableSchemaValidator + serializer: SchemaSerializer + pydantic_complete: bool + + @overload + def __init__( + self, + type: type[T], + *, + config: ConfigDict | None = ..., + _parent_depth: int = ..., + module: str | None = ..., + ) -> None: ... + + # This second overload is for unsupported special forms (such as Annotated, Union, etc.) + # Currently there is no way to type this correctly + # See https://github.com/python/typing/pull/1618 + @overload + def __init__( + self, + type: Any, + *, + config: ConfigDict | None = ..., + _parent_depth: int = ..., + module: str | None = ..., + ) -> None: ... + + def __init__( + self, + type: Any, + *, + config: ConfigDict | None = None, + _parent_depth: int = 2, + module: str | None = None, + ) -> None: + if _type_has_config(type) and config is not None: + raise PydanticUserError( + 'Cannot use `config` when the type is a BaseModel, dataclass or TypedDict.' + ' These types can have their own config and setting the config via the `config`' + ' parameter to TypeAdapter will not override it, thus the `config` you passed to' + ' TypeAdapter becomes meaningless, which is probably not what you want.', + code='type-adapter-config-unused', + ) + + self._type = type + self._config = config + self._parent_depth = _parent_depth + self.pydantic_complete = False + + parent_frame = self._fetch_parent_frame() + if isinstance(type, types.FunctionType): + # Special case functions, which are *not* pushed to the `NsResolver` stack and without this special case + # would only have access to the parent namespace where the `TypeAdapter` was instantiated (if the function is defined + # in another module, we need to look at that module's globals). + if parent_frame is not None: + # `f_locals` is the namespace where the type adapter was instantiated (~ to `f_globals` if at the module level): + parent_ns = parent_frame.f_locals + else: # pragma: no cover + parent_ns = None + globalns, localns = _namespace_utils.ns_for_function( + type, + parent_namespace=parent_ns, + ) + parent_namespace = None + else: + if parent_frame is not None: + globalns = parent_frame.f_globals + # Do not provide a local ns if the type adapter happens to be instantiated at the module level: + localns = parent_frame.f_locals if parent_frame.f_locals is not globalns else {} + else: # pragma: no cover + globalns = {} + localns = {} + parent_namespace = localns + + self._module_name = module or cast(str, globalns.get('__name__', '')) + self._init_core_attrs( + ns_resolver=_namespace_utils.NsResolver( + namespaces_tuple=_namespace_utils.NamespacesTuple(locals=localns, globals=globalns), + parent_namespace=parent_namespace, + ), + force=False, + ) + + def _fetch_parent_frame(self) -> FrameType | None: + frame = sys._getframe(self._parent_depth) + if frame.f_globals.get('__name__') == 'typing': + # Because `TypeAdapter` is generic, explicitly parametrizing the class results + # in a `typing._GenericAlias` instance, which proxies instantiation calls to the + # "real" `TypeAdapter` class and thus adding an extra frame to the call. To avoid + # pulling anything from the `typing` module, use the correct frame (the one before): + return frame.f_back + + return frame + + def _init_core_attrs( + self, ns_resolver: _namespace_utils.NsResolver, force: bool, raise_errors: bool = False + ) -> bool: + """Initialize the core schema, validator, and serializer for the type. + + Args: + ns_resolver: The namespace resolver to use when building the core schema for the adapted type. + force: Whether to force the construction of the core schema, validator, and serializer. + If `force` is set to `False` and `_defer_build` is `True`, the core schema, validator, and serializer will be set to mocks. + raise_errors: Whether to raise errors if initializing any of the core attrs fails. + + Returns: + `True` if the core schema, validator, and serializer were successfully initialized, otherwise `False`. + + Raises: + PydanticUndefinedAnnotation: If `PydanticUndefinedAnnotation` occurs in`__get_pydantic_core_schema__` + and `raise_errors=True`. + """ + if not force and self._defer_build: + _mock_val_ser.set_type_adapter_mocks(self) + self.pydantic_complete = False + return False + + try: + self.core_schema = _getattr_no_parents(self._type, '__pydantic_core_schema__') + self.validator = _getattr_no_parents(self._type, '__pydantic_validator__') + self.serializer = _getattr_no_parents(self._type, '__pydantic_serializer__') + + # TODO: we don't go through the rebuild logic here directly because we don't want + # to repeat all of the namespace fetching logic that we've already done + # so we simply skip to the block below that does the actual schema generation + if ( + isinstance(self.core_schema, _mock_val_ser.MockCoreSchema) + or isinstance(self.validator, _mock_val_ser.MockValSer) + or isinstance(self.serializer, _mock_val_ser.MockValSer) + ): + raise AttributeError() + except AttributeError: + config_wrapper = _config.ConfigWrapper(self._config) + + schema_generator = _generate_schema.GenerateSchema(config_wrapper, ns_resolver=ns_resolver) + + try: + core_schema = schema_generator.generate_schema(self._type) + except PydanticUndefinedAnnotation: + if raise_errors: + raise + _mock_val_ser.set_type_adapter_mocks(self) + return False + + try: + self.core_schema = schema_generator.clean_schema(core_schema) + except _generate_schema.InvalidSchemaError: + _mock_val_ser.set_type_adapter_mocks(self) + return False + + core_config = config_wrapper.core_config(None) + + self.validator = create_schema_validator( + schema=self.core_schema, + schema_type=self._type, + schema_type_module=self._module_name, + schema_type_name=str(self._type), + schema_kind='TypeAdapter', + config=core_config, + plugin_settings=config_wrapper.plugin_settings, + ) + self.serializer = SchemaSerializer(self.core_schema, core_config) + + self.pydantic_complete = True + return True + + @property + def _defer_build(self) -> bool: + config = self._config if self._config is not None else self._model_config + if config: + return config.get('defer_build') is True + return False + + @property + def _model_config(self) -> ConfigDict | None: + type_: Any = _typing_extra.annotated_type(self._type) or self._type # Eg FastAPI heavily uses Annotated + if _utils.lenient_issubclass(type_, BaseModel): + return type_.model_config + return getattr(type_, '__pydantic_config__', None) + + def __repr__(self) -> str: + return f'TypeAdapter({_repr.display_as_type(self._type)})' + + def rebuild( + self, + *, + force: bool = False, + raise_errors: bool = True, + _parent_namespace_depth: int = 2, + _types_namespace: _namespace_utils.MappingNamespace | None = None, + ) -> bool | None: + """Try to rebuild the pydantic-core schema for the adapter's type. + + This may be necessary when one of the annotations is a ForwardRef which could not be resolved during + the initial attempt to build the schema, and automatic rebuilding fails. + + Args: + force: Whether to force the rebuilding of the type adapter's schema, defaults to `False`. + raise_errors: Whether to raise errors, defaults to `True`. + _parent_namespace_depth: Depth at which to search for the [parent frame][frame-objects]. This + frame is used when resolving forward annotations during schema rebuilding, by looking for + the locals of this frame. Defaults to 2, which will result in the frame where the method + was called. + _types_namespace: An explicit types namespace to use, instead of using the local namespace + from the parent frame. Defaults to `None`. + + Returns: + Returns `None` if the schema is already "complete" and rebuilding was not required. + If rebuilding _was_ required, returns `True` if rebuilding was successful, otherwise `False`. + """ + if not force and self.pydantic_complete: + return None + + if _types_namespace is not None: + rebuild_ns = _types_namespace + elif _parent_namespace_depth > 0: + rebuild_ns = _typing_extra.parent_frame_namespace(parent_depth=_parent_namespace_depth, force=True) or {} + else: + rebuild_ns = {} + + # we have to manually fetch globals here because there's no type on the stack of the NsResolver + # and so we skip the globalns = get_module_ns_of(typ) call that would normally happen + globalns = sys._getframe(max(_parent_namespace_depth - 1, 1)).f_globals + ns_resolver = _namespace_utils.NsResolver( + namespaces_tuple=_namespace_utils.NamespacesTuple(locals=rebuild_ns, globals=globalns), + parent_namespace=rebuild_ns, + ) + return self._init_core_attrs(ns_resolver=ns_resolver, force=True, raise_errors=raise_errors) + + def validate_python( + self, + object: Any, + /, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + experimental_allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> T: + """Validate a Python object against the model. + + Args: + object: The Python object to validate against the model. + strict: Whether to strictly check types. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + from_attributes: Whether to extract data from object attributes. + context: Additional context to pass to the validator. + experimental_allow_partial: **Experimental** whether to enable + [partial validation](../concepts/experimental.md#partial-validation), e.g. to process streams. + * False / 'off': Default behavior, no partial validation. + * True / 'on': Enable partial validation. + * 'trailing-strings': Enable partial validation and allow trailing strings in the input. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + !!! note + When using `TypeAdapter` with a Pydantic `dataclass`, the use of the `from_attributes` + argument is not supported. + + Returns: + The validated object. + """ + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return self.validator.validate_python( + object, + strict=strict, + extra=extra, + from_attributes=from_attributes, + context=context, + allow_partial=experimental_allow_partial, + by_alias=by_alias, + by_name=by_name, + ) + + def validate_json( + self, + data: str | bytes | bytearray, + /, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + experimental_allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> T: + """!!! abstract "Usage Documentation" + [JSON Parsing](../concepts/json.md#json-parsing) + + Validate a JSON string or bytes against the model. + + Args: + data: The JSON data to validate against the model. + strict: Whether to strictly check types. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Additional context to use during validation. + experimental_allow_partial: **Experimental** whether to enable + [partial validation](../concepts/experimental.md#partial-validation), e.g. to process streams. + * False / 'off': Default behavior, no partial validation. + * True / 'on': Enable partial validation. + * 'trailing-strings': Enable partial validation and allow trailing strings in the input. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated object. + """ + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return self.validator.validate_json( + data, + strict=strict, + extra=extra, + context=context, + allow_partial=experimental_allow_partial, + by_alias=by_alias, + by_name=by_name, + ) + + def validate_strings( + self, + obj: Any, + /, + *, + strict: bool | None = None, + extra: ExtraValues | None = None, + context: Any | None = None, + experimental_allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> T: + """Validate object contains string data against the model. + + Args: + obj: The object contains string data to validate. + strict: Whether to strictly check types. + extra: Whether to ignore, allow, or forbid extra data during model validation. + See the [`extra` configuration value][pydantic.ConfigDict.extra] for details. + context: Additional context to use during validation. + experimental_allow_partial: **Experimental** whether to enable + [partial validation](../concepts/experimental.md#partial-validation), e.g. to process streams. + * False / 'off': Default behavior, no partial validation. + * True / 'on': Enable partial validation. + * 'trailing-strings': Enable partial validation and allow trailing strings in the input. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Returns: + The validated object. + """ + if by_alias is False and by_name is not True: + raise PydanticUserError( + 'At least one of `by_alias` or `by_name` must be set to True.', + code='validate-by-alias-and-name-false', + ) + + return self.validator.validate_strings( + obj, + strict=strict, + extra=extra, + context=context, + allow_partial=experimental_allow_partial, + by_alias=by_alias, + by_name=by_name, + ) + + def get_default_value(self, *, strict: bool | None = None, context: Any | None = None) -> Some[T] | None: + """Get the default value for the wrapped type. + + Args: + strict: Whether to strictly check types. + context: Additional context to pass to the validator. + + Returns: + The default value wrapped in a `Some` if there is one or None if not. + """ + return self.validator.get_default_value(strict=strict, context=context) + + def dump_python( + self, + instance: T, + /, + *, + mode: Literal['json', 'python'] = 'python', + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + context: Any | None = None, + ) -> Any: + """Dump an instance of the adapted type to a Python object. + + Args: + instance: The Python object to serialize. + mode: The output format. + include: Fields to include in the output. + exclude: Fields to exclude from the output. + by_alias: Whether to use alias names for field names. + exclude_unset: Whether to exclude unset fields. + exclude_defaults: Whether to exclude fields with default values. + exclude_none: Whether to exclude fields with None values. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: Whether to output the serialized data in a way that is compatible with deserialization. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + context: Additional context to pass to the serializer. + + Returns: + The serialized object. + """ + return self.serializer.to_python( + instance, + mode=mode, + by_alias=by_alias, + include=include, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + polymorphic_serialization=polymorphic_serialization, + context=context, + ) + + def dump_json( + self, + instance: T, + /, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: IncEx | None = None, + exclude: IncEx | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + context: Any | None = None, + ) -> bytes: + """!!! abstract "Usage Documentation" + [JSON Serialization](../concepts/json.md#json-serialization) + + Serialize an instance of the adapted type to JSON. + + Args: + instance: The instance to be serialized. + indent: Number of spaces for JSON indentation. + ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. + If `False` (the default), these characters will be output as-is. + include: Fields to include. + exclude: Fields to exclude. + by_alias: Whether to use alias names for field names. + exclude_unset: Whether to exclude unset fields. + exclude_defaults: Whether to exclude fields with default values. + exclude_none: Whether to exclude fields with a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + While this can be useful for round-tripping, it is usually recommended to use the dedicated + `round_trip` parameter instead. + round_trip: Whether to serialize and deserialize the instance to ensure round-tripping. + warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered. If not provided, + a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + context: Additional context to pass to the serializer. + + Returns: + The JSON representation of the given instance as bytes. + """ + return self.serializer.to_json( + instance, + indent=indent, + ensure_ascii=ensure_ascii, + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + exclude_computed_fields=exclude_computed_fields, + round_trip=round_trip, + warnings=warnings, + fallback=fallback, + serialize_as_any=serialize_as_any, + polymorphic_serialization=polymorphic_serialization, + context=context, + ) + + def json_schema( + self, + *, + by_alias: bool = True, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + mode: JsonSchemaMode = 'validation', + ) -> dict[str, Any]: + """Generate a JSON schema for the adapted type. + + Args: + by_alias: Whether to use alias names for field names. + ref_template: The format string used for generating $ref strings. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: To override the logic used to generate the JSON schema, as a subclass of + `GenerateJsonSchema` with your desired modifications + mode: The mode in which to generate the schema. + schema_generator: The generator class used for creating the schema. + mode: The mode to use for schema generation. + + Returns: + The JSON schema for the model as a dictionary. + """ + schema_generator_instance = schema_generator( + by_alias=by_alias, ref_template=ref_template, union_format=union_format + ) + if isinstance(self.core_schema, _mock_val_ser.MockCoreSchema): + self.core_schema.rebuild() + assert not isinstance(self.core_schema, _mock_val_ser.MockCoreSchema), 'this is a bug! please report it' + return schema_generator_instance.generate(self.core_schema, mode=mode) + + @staticmethod + def json_schemas( + inputs: Iterable[tuple[JsonSchemaKeyT, JsonSchemaMode, TypeAdapter[Any]]], + /, + *, + by_alias: bool = True, + title: str | None = None, + description: str | None = None, + ref_template: str = DEFAULT_REF_TEMPLATE, + union_format: Literal['any_of', 'primitive_type_array'] = 'any_of', + schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema, + ) -> tuple[dict[tuple[JsonSchemaKeyT, JsonSchemaMode], JsonSchemaValue], JsonSchemaValue]: + """Generate a JSON schema including definitions from multiple type adapters. + + Args: + inputs: Inputs to schema generation. The first two items will form the keys of the (first) + output mapping; the type adapters will provide the core schemas that get converted into + definitions in the output JSON schema. + by_alias: Whether to use alias names. + title: The title for the schema. + description: The description for the schema. + ref_template: The format string used for generating $ref strings. + union_format: The format to use when combining schemas from unions together. Can be one of: + + - `'any_of'`: Use the [`anyOf`](https://json-schema.org/understanding-json-schema/reference/combining#anyOf) + keyword to combine schemas (the default). + - `'primitive_type_array'`: Use the [`type`](https://json-schema.org/understanding-json-schema/reference/type) + keyword as an array of strings, containing each type of the combination. If any of the schemas is not a primitive + type (`string`, `boolean`, `null`, `integer` or `number`) or contains constraints/metadata, falls back to + `any_of`. + schema_generator: The generator class used for creating the schema. + + Returns: + A tuple where: + + - The first element is a dictionary whose keys are tuples of JSON schema key type and JSON mode, and + whose values are the JSON schema corresponding to that pair of inputs. (These schemas may have + JsonRef references to definitions that are defined in the second returned element.) + - The second element is a JSON schema containing all definitions referenced in the first returned + element, along with the optional title and description keys. + + """ + schema_generator_instance = schema_generator( + by_alias=by_alias, ref_template=ref_template, union_format=union_format + ) + + inputs_ = [] + for key, mode, adapter in inputs: + # This is the same pattern we follow for model json schemas - we attempt a core schema rebuild if we detect a mock + if isinstance(adapter.core_schema, _mock_val_ser.MockCoreSchema): + adapter.core_schema.rebuild() + assert not isinstance(adapter.core_schema, _mock_val_ser.MockCoreSchema), ( + 'this is a bug! please report it' + ) + inputs_.append((key, mode, adapter.core_schema)) + + json_schemas_map, definitions = schema_generator_instance.generate_definitions(inputs_) + + json_schema: dict[str, Any] = {} + if definitions: + json_schema['$defs'] = definitions + if title: + json_schema['title'] = title + if description: + json_schema['description'] = description + + return json_schemas_map, json_schema diff --git a/source/target-vendors/cp312/pydantic/types.py b/source/target-vendors/cp312/pydantic/types.py new file mode 100644 index 0000000..467bc82 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/types.py @@ -0,0 +1,3310 @@ +"""The types module contains custom types used by pydantic.""" + +from __future__ import annotations as _annotations + +import base64 +import dataclasses as _dataclasses +import re +from collections.abc import Hashable, Iterator +from datetime import date, datetime +from decimal import Decimal +from enum import Enum +from pathlib import Path +from re import Pattern +from types import ModuleType +from typing import ( + TYPE_CHECKING, + Annotated, + Any, + Callable, + ClassVar, + Generic, + Literal, + TypeVar, + Union, + cast, +) +from uuid import UUID + +import annotated_types +from annotated_types import BaseMetadata, MaxLen, MinLen +from pydantic_core import CoreSchema, PydanticCustomError, SchemaSerializer, core_schema +from typing_extensions import Protocol, TypeAlias, TypeAliasType, deprecated, get_args, get_origin + +from ._internal import _fields, _internal_dataclass, _utils, _validators +from ._migration import getattr_migration +from .annotated_handlers import GetCoreSchemaHandler, GetJsonSchemaHandler +from .errors import PydanticUserError +from .json_schema import JsonSchemaValue +from .warnings import PydanticDeprecatedSince20 + +if TYPE_CHECKING: + from ._internal._core_metadata import CoreMetadata + +__all__ = ( + 'Strict', + 'StrictStr', + 'SocketPath', + 'conbytes', + 'conlist', + 'conset', + 'confrozenset', + 'constr', + 'ImportString', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'condecimal', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'UUID6', + 'UUID7', + 'UUID8', + 'FilePath', + 'DirectoryPath', + 'NewPath', + 'Json', + 'Secret', + 'SecretStr', + 'SecretBytes', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'ByteSize', + 'PastDate', + 'FutureDate', + 'PastDatetime', + 'FutureDatetime', + 'condate', + 'AwareDatetime', + 'NaiveDatetime', + 'AllowInfNan', + 'EncoderProtocol', + 'EncodedBytes', + 'EncodedStr', + 'Base64Encoder', + 'Base64Bytes', + 'Base64Str', + 'Base64UrlBytes', + 'Base64UrlStr', + 'GetPydanticSchema', + 'StringConstraints', + 'Tag', + 'Discriminator', + 'JsonValue', + 'OnErrorOmit', + 'FailFast', +) + + +T = TypeVar('T') + + +@_dataclasses.dataclass +class Strict(_fields.PydanticMetadata, BaseMetadata): + """!!! abstract "Usage Documentation" + [Strict Mode with `Annotated` `Strict`](../concepts/strict_mode.md#strict-mode-with-annotated-strict) + + A field metadata class to indicate that a field should be validated in strict mode. + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + strict: Whether to validate the field in strict mode. + + Example: + ```python + from typing import Annotated + + from pydantic.types import Strict + + StrictBool = Annotated[bool, Strict()] + ``` + """ + + strict: bool = True + + def __hash__(self) -> int: + return hash(self.strict) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +StrictBool = Annotated[bool, Strict()] +"""A boolean that must be either ``True`` or ``False``.""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def conint( + *, + strict: bool | None = None, + gt: int | None = None, + ge: int | None = None, + lt: int | None = None, + le: int | None = None, + multiple_of: int | None = None, +) -> type[int]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`Field`][pydantic.fields.Field] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `conint` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, conint + + class Foo(BaseModel): + bar: conint(strict=True, gt=0) + ``` + + === ":white_check_mark: Do this" + ```python + from typing import Annotated + + from pydantic import BaseModel, Field + + class Foo(BaseModel): + bar: Annotated[int, Field(strict=True, gt=0)] + ``` + + A wrapper around `int` that allows for additional constraints. + + Args: + strict: Whether to validate the integer in strict mode. Defaults to `None`. + gt: The value must be greater than this. + ge: The value must be greater than or equal to this. + lt: The value must be less than this. + le: The value must be less than or equal to this. + multiple_of: The value must be a multiple of this. + + Returns: + The wrapped integer type. + + ```python + from pydantic import BaseModel, ValidationError, conint + + class ConstrainedExample(BaseModel): + constrained_int: conint(gt=1) + + m = ConstrainedExample(constrained_int=2) + print(repr(m)) + #> ConstrainedExample(constrained_int=2) + + try: + ConstrainedExample(constrained_int=0) + except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('constrained_int',), + 'msg': 'Input should be greater than 1', + 'input': 0, + 'ctx': {'gt': 1}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' + ``` + + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + int, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, + ] + + +PositiveInt = Annotated[int, annotated_types.Gt(0)] +"""An integer that must be greater than zero. + +```python +from pydantic import BaseModel, PositiveInt, ValidationError + +class Model(BaseModel): + positive_int: PositiveInt + +m = Model(positive_int=1) +print(repr(m)) +#> Model(positive_int=1) + +try: + Model(positive_int=-1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('positive_int',), + 'msg': 'Input should be greater than 0', + 'input': -1, + 'ctx': {'gt': 0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' +``` +""" +NegativeInt = Annotated[int, annotated_types.Lt(0)] +"""An integer that must be less than zero. + +```python +from pydantic import BaseModel, NegativeInt, ValidationError + +class Model(BaseModel): + negative_int: NegativeInt + +m = Model(negative_int=-1) +print(repr(m)) +#> Model(negative_int=-1) + +try: + Model(negative_int=1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than', + 'loc': ('negative_int',), + 'msg': 'Input should be less than 0', + 'input': 1, + 'ctx': {'lt': 0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than', + } + ] + ''' +``` +""" +NonPositiveInt = Annotated[int, annotated_types.Le(0)] +"""An integer that must be less than or equal to zero. + +```python +from pydantic import BaseModel, NonPositiveInt, ValidationError + +class Model(BaseModel): + non_positive_int: NonPositiveInt + +m = Model(non_positive_int=0) +print(repr(m)) +#> Model(non_positive_int=0) + +try: + Model(non_positive_int=1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than_equal', + 'loc': ('non_positive_int',), + 'msg': 'Input should be less than or equal to 0', + 'input': 1, + 'ctx': {'le': 0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than_equal', + } + ] + ''' +``` +""" +NonNegativeInt = Annotated[int, annotated_types.Ge(0)] +"""An integer that must be greater than or equal to zero. + +```python +from pydantic import BaseModel, NonNegativeInt, ValidationError + +class Model(BaseModel): + non_negative_int: NonNegativeInt + +m = Model(non_negative_int=0) +print(repr(m)) +#> Model(non_negative_int=0) + +try: + Model(non_negative_int=-1) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than_equal', + 'loc': ('non_negative_int',), + 'msg': 'Input should be greater than or equal to 0', + 'input': -1, + 'ctx': {'ge': 0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal', + } + ] + ''' +``` +""" +StrictInt = Annotated[int, Strict()] +"""An integer that must be validated in strict mode. + +```python +from pydantic import BaseModel, StrictInt, ValidationError + +class StrictIntModel(BaseModel): + strict_int: StrictInt + +try: + StrictIntModel(strict_int=3.14159) +except ValidationError as e: + print(e) + ''' + 1 validation error for StrictIntModel + strict_int + Input should be a valid integer [type=int_type, input_value=3.14159, input_type=float] + ''' +``` +""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass +class AllowInfNan(_fields.PydanticMetadata): + """A field metadata class to indicate that a field should allow `-inf`, `inf`, and `nan`. + + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. Defaults to `True`. + + Example: + ```python + from typing import Annotated + + from pydantic.types import AllowInfNan + + LaxFloat = Annotated[float, AllowInfNan()] + ``` + """ + + allow_inf_nan: bool = True + + def __hash__(self) -> int: + return hash(self.allow_inf_nan) + + +def confloat( + *, + strict: bool | None = None, + gt: float | None = None, + ge: float | None = None, + lt: float | None = None, + le: float | None = None, + multiple_of: float | None = None, + allow_inf_nan: bool | None = None, +) -> type[float]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`Field`][pydantic.fields.Field] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `confloat` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, confloat + + class Foo(BaseModel): + bar: confloat(strict=True, gt=0) + ``` + + === ":white_check_mark: Do this" + ```python + from typing import Annotated + + from pydantic import BaseModel, Field + + class Foo(BaseModel): + bar: Annotated[float, Field(strict=True, gt=0)] + ``` + + A wrapper around `float` that allows for additional constraints. + + Args: + strict: Whether to validate the float in strict mode. + gt: The value must be greater than this. + ge: The value must be greater than or equal to this. + lt: The value must be less than this. + le: The value must be less than or equal to this. + multiple_of: The value must be a multiple of this. + allow_inf_nan: Whether to allow `-inf`, `inf`, and `nan`. + + Returns: + The wrapped float type. + + ```python + from pydantic import BaseModel, ValidationError, confloat + + class ConstrainedExample(BaseModel): + constrained_float: confloat(gt=1.0) + + m = ConstrainedExample(constrained_float=1.1) + print(repr(m)) + #> ConstrainedExample(constrained_float=1.1) + + try: + ConstrainedExample(constrained_float=0.9) + except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('constrained_float',), + 'msg': 'Input should be greater than 1', + 'input': 0.9, + 'ctx': {'gt': 1.0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' + ``` + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + float, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, + AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None, + ] + + +PositiveFloat = Annotated[float, annotated_types.Gt(0)] +"""A float that must be greater than zero. + +```python +from pydantic import BaseModel, PositiveFloat, ValidationError + +class Model(BaseModel): + positive_float: PositiveFloat + +m = Model(positive_float=1.0) +print(repr(m)) +#> Model(positive_float=1.0) + +try: + Model(positive_float=-1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('positive_float',), + 'msg': 'Input should be greater than 0', + 'input': -1.0, + 'ctx': {'gt': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' +``` +""" +NegativeFloat = Annotated[float, annotated_types.Lt(0)] +"""A float that must be less than zero. + +```python +from pydantic import BaseModel, NegativeFloat, ValidationError + +class Model(BaseModel): + negative_float: NegativeFloat + +m = Model(negative_float=-1.0) +print(repr(m)) +#> Model(negative_float=-1.0) + +try: + Model(negative_float=1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than', + 'loc': ('negative_float',), + 'msg': 'Input should be less than 0', + 'input': 1.0, + 'ctx': {'lt': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than', + } + ] + ''' +``` +""" +NonPositiveFloat = Annotated[float, annotated_types.Le(0)] +"""A float that must be less than or equal to zero. + +```python +from pydantic import BaseModel, NonPositiveFloat, ValidationError + +class Model(BaseModel): + non_positive_float: NonPositiveFloat + +m = Model(non_positive_float=0.0) +print(repr(m)) +#> Model(non_positive_float=0.0) + +try: + Model(non_positive_float=1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'less_than_equal', + 'loc': ('non_positive_float',), + 'msg': 'Input should be less than or equal to 0', + 'input': 1.0, + 'ctx': {'le': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/less_than_equal', + } + ] + ''' +``` +""" +NonNegativeFloat = Annotated[float, annotated_types.Ge(0)] +"""A float that must be greater than or equal to zero. + +```python +from pydantic import BaseModel, NonNegativeFloat, ValidationError + +class Model(BaseModel): + non_negative_float: NonNegativeFloat + +m = Model(non_negative_float=0.0) +print(repr(m)) +#> Model(non_negative_float=0.0) + +try: + Model(non_negative_float=-1.0) +except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than_equal', + 'loc': ('non_negative_float',), + 'msg': 'Input should be greater than or equal to 0', + 'input': -1.0, + 'ctx': {'ge': 0.0}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than_equal', + } + ] + ''' +``` +""" +StrictFloat = Annotated[float, Strict(True)] +"""A float that must be validated in strict mode. + +```python +from pydantic import BaseModel, StrictFloat, ValidationError + +class StrictFloatModel(BaseModel): + strict_float: StrictFloat + +try: + StrictFloatModel(strict_float='1.0') +except ValidationError as e: + print(e) + ''' + 1 validation error for StrictFloatModel + strict_float + Input should be a valid number [type=float_type, input_value='1.0', input_type=str] + ''' +``` +""" +FiniteFloat = Annotated[float, AllowInfNan(False)] +"""A float that must be finite (not ``-inf``, ``inf``, or ``nan``). + +```python +from pydantic import BaseModel, FiniteFloat + +class Model(BaseModel): + finite: FiniteFloat + +m = Model(finite=1.0) +print(m) +#> finite=1.0 +``` +""" + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def conbytes( + *, + min_length: int | None = None, + max_length: int | None = None, + strict: bool | None = None, +) -> type[bytes]: + """A wrapper around `bytes` that allows for additional constraints. + + Args: + min_length: The minimum length of the bytes. + max_length: The maximum length of the bytes. + strict: Whether to validate the bytes in strict mode. + + Returns: + The wrapped bytes type. + """ + return Annotated[ # pyright: ignore[reportReturnType] + bytes, + Strict(strict) if strict is not None else None, + annotated_types.Len(min_length or 0, max_length), + ] + + +StrictBytes = Annotated[bytes, Strict()] +"""A bytes that must be validated in strict mode.""" + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass(frozen=True) +class StringConstraints(annotated_types.GroupedMetadata): + """!!! abstract "Usage Documentation" + [String types](./standard_library_types.md#strings) + + A field metadata class to apply constraints to `str` types. + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + strip_whitespace: Whether to remove leading and trailing whitespace. + to_upper: Whether to convert the string to uppercase. + to_lower: Whether to convert the string to lowercase. + strict: Whether to validate the string in strict mode. + min_length: The minimum length of the string. + max_length: The maximum length of the string. + pattern: A regex pattern that the string must match. + ascii_only: Whether the string should contain only ASCII characters. + + Example: + ```python + from typing import Annotated + + from pydantic.types import StringConstraints + + ConstrainedStr = Annotated[str, StringConstraints(min_length=1, max_length=10)] + ``` + """ + + strip_whitespace: bool | None = None + to_upper: bool | None = None + to_lower: bool | None = None + strict: bool | None = None + min_length: int | None = None + max_length: int | None = None + pattern: str | Pattern[str] | None = None + ascii_only: bool | None = None + + def __iter__(self) -> Iterator[BaseMetadata]: + if self.min_length is not None: + yield MinLen(self.min_length) + if self.max_length is not None: + yield MaxLen(self.max_length) + if self.strict is not None: + yield Strict(self.strict) + if ( + self.strip_whitespace is not None + or self.pattern is not None + or self.to_lower is not None + or self.to_upper is not None + or self.ascii_only is not None + ): + yield _fields.pydantic_general_metadata( + strip_whitespace=self.strip_whitespace, + to_upper=self.to_upper, + to_lower=self.to_lower, + pattern=self.pattern, + ascii_only=self.ascii_only, + ) + + +def constr( + *, + strip_whitespace: bool | None = None, + to_upper: bool | None = None, + to_lower: bool | None = None, + strict: bool | None = None, + min_length: int | None = None, + max_length: int | None = None, + pattern: str | Pattern[str] | None = None, + ascii_only: bool | None = None, +) -> type[str]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`StringConstraints`][pydantic.types.StringConstraints] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `constr` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, constr + + class Foo(BaseModel): + bar: constr(strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$') + ``` + + === ":white_check_mark: Do this" + ```python + from typing import Annotated + + from pydantic import BaseModel, StringConstraints + + class Foo(BaseModel): + bar: Annotated[ + str, + StringConstraints( + strip_whitespace=True, to_upper=True, pattern=r'^[A-Z]+$' + ), + ] + ``` + + A wrapper around `str` that allows for additional constraints. + + ```python + from pydantic import BaseModel, constr + + class Foo(BaseModel): + bar: constr(strip_whitespace=True, to_upper=True) + + foo = Foo(bar=' hello ') + print(foo) + #> bar='HELLO' + ``` + + Args: + strip_whitespace: Whether to remove leading and trailing whitespace. + to_upper: Whether to turn all characters to uppercase. + to_lower: Whether to turn all characters to lowercase. + strict: Whether to validate the string in strict mode. + min_length: The minimum length of the string. + max_length: The maximum length of the string. + pattern: A regex pattern to validate the string against. + ascii_only: Whether the string should contain only ASCII characters. + + Returns: + The wrapped string type. + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + str, + StringConstraints( + strip_whitespace=strip_whitespace, + to_upper=to_upper, + to_lower=to_lower, + strict=strict, + min_length=min_length, + max_length=max_length, + pattern=pattern, + ascii_only=ascii_only, + ), + ] + + +StrictStr = Annotated[str, Strict()] +"""A string that must be validated in strict mode.""" + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ COLLECTION TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +HashableItemType = TypeVar('HashableItemType', bound=Hashable) + + +def conset( + item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None +) -> type[set[HashableItemType]]: + """A wrapper around `typing.Set` that allows for additional constraints. + + Args: + item_type: The type of the items in the set. + min_length: The minimum length of the set. + max_length: The maximum length of the set. + + Returns: + The wrapped set type. + """ + return Annotated[set[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] + + +def confrozenset( + item_type: type[HashableItemType], *, min_length: int | None = None, max_length: int | None = None +) -> type[frozenset[HashableItemType]]: + """A wrapper around `typing.FrozenSet` that allows for additional constraints. + + Args: + item_type: The type of the items in the frozenset. + min_length: The minimum length of the frozenset. + max_length: The maximum length of the frozenset. + + Returns: + The wrapped frozenset type. + """ + return Annotated[frozenset[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] + + +AnyItemType = TypeVar('AnyItemType') + + +def conlist( + item_type: type[AnyItemType], + *, + min_length: int | None = None, + max_length: int | None = None, + unique_items: bool | None = None, +) -> type[list[AnyItemType]]: + """A wrapper around [`list`][] that adds validation. + + Args: + item_type: The type of the items in the list. + min_length: The minimum length of the list. Defaults to None. + max_length: The maximum length of the list. Defaults to None. + unique_items: Whether the items in the list must be unique. Defaults to None. + !!! warning Deprecated + The `unique_items` parameter is deprecated, use `Set` instead. + See [this issue](https://github.com/pydantic/pydantic-core/issues/296) for more details. + + Returns: + The wrapped list type. + """ + if unique_items is not None: + raise PydanticUserError( + ( + '`unique_items` is removed, use `Set` instead' + '(this feature is discussed in https://github.com/pydantic/pydantic-core/issues/296)' + ), + code='removed-kwargs', + ) + return Annotated[list[item_type], annotated_types.Len(min_length or 0, max_length)] # pyright: ignore[reportReturnType] + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ IMPORT STRING TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +AnyType = TypeVar('AnyType') +if TYPE_CHECKING: + ImportString = Annotated[AnyType, ...] +else: + + class ImportString: + """A type that can be used to import a Python object from a string. + + `ImportString` expects a string and loads the Python object importable at that dotted path. + Attributes of modules may be separated from the module by `:` or `.`, e.g. if `'math:cos'` is provided, + the resulting field value would be the function `cos`. If a `.` is used and both an attribute and submodule + are present at the same path, the module will be preferred. + + On model instantiation, pointers will be evaluated and imported. There is + some nuance to this behavior, demonstrated in the examples below. + + ```python + import math + + from pydantic import BaseModel, Field, ImportString, ValidationError + + class ImportThings(BaseModel): + obj: ImportString + + # A string value will cause an automatic import + my_cos = ImportThings(obj='math.cos') + + # You can use the imported function as you would expect + cos_of_0 = my_cos.obj(0) + assert cos_of_0 == 1 + + # A string whose value cannot be imported will raise an error + try: + ImportThings(obj='foo.bar') + except ValidationError as e: + print(e) + ''' + 1 validation error for ImportThings + obj + Invalid python path: No module named 'foo' [type=import_error, input_value='foo.bar', input_type=str] + ''' + + # Actual python objects can be assigned as well + my_cos = ImportThings(obj=math.cos) + my_cos_2 = ImportThings(obj='math.cos') + my_cos_3 = ImportThings(obj='math:cos') + assert my_cos == my_cos_2 == my_cos_3 + + # You can set default field value either as Python object: + class ImportThingsDefaultPyObj(BaseModel): + obj: ImportString = math.cos + + # or as a string value (but only if used with `validate_default=True`) + class ImportThingsDefaultString(BaseModel): + obj: ImportString = Field(default='math.cos', validate_default=True) + + my_cos_default1 = ImportThingsDefaultPyObj() + my_cos_default2 = ImportThingsDefaultString() + assert my_cos_default1.obj == my_cos_default2.obj == math.cos + + # note: this will not work! + class ImportThingsMissingValidateDefault(BaseModel): + obj: ImportString = 'math.cos' + + my_cos_default3 = ImportThingsMissingValidateDefault() + assert my_cos_default3.obj == 'math.cos' # just string, not evaluated + ``` + + Serializing an `ImportString` type to json is also possible. + + ```python + from pydantic import BaseModel, ImportString + + class ImportThings(BaseModel): + obj: ImportString + + # Create an instance + m = ImportThings(obj='math.cos') + print(m) + #> obj= + print(m.model_dump_json()) + #> {"obj":"math.cos"} + ``` + """ + + @classmethod + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + serializer = core_schema.plain_serializer_function_ser_schema(cls._serialize, when_used='json') + if cls is source: + # Treat bare usage of ImportString (`schema is None`) as the same as ImportString[Any] + return core_schema.no_info_plain_validator_function( + function=_validators.import_string, serialization=serializer + ) + else: + return core_schema.no_info_before_validator_function( + function=_validators.import_string, schema=handler(source), serialization=serializer + ) + + @classmethod + def __get_pydantic_json_schema__(cls, cs: CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + return handler(core_schema.str_schema()) + + @staticmethod + def _serialize(v: Any) -> str: + if isinstance(v, ModuleType): + return v.__name__ + elif hasattr(v, '__module__') and hasattr(v, '__name__'): + return f'{v.__module__}.{v.__name__}' + # Handle special cases for sys.XXX streams + # if we see more of these, we should consider a more general solution + elif hasattr(v, 'name'): + if v.name == '': + return 'sys.stdout' + elif v.name == '': + return 'sys.stdin' + elif v.name == '': + return 'sys.stderr' + return v + + def __repr__(self) -> str: + return 'ImportString' + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def condecimal( + *, + strict: bool | None = None, + gt: int | Decimal | None = None, + ge: int | Decimal | None = None, + lt: int | Decimal | None = None, + le: int | Decimal | None = None, + multiple_of: int | Decimal | None = None, + max_digits: int | None = None, + decimal_places: int | None = None, + allow_inf_nan: bool | None = None, +) -> type[Decimal]: + """ + !!! warning "Discouraged" + This function is **discouraged** in favor of using + [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) with + [`Field`][pydantic.fields.Field] instead. + + This function will be **deprecated** in Pydantic 3.0. + + The reason is that `condecimal` returns a type, which doesn't play well with static analysis tools. + + === ":x: Don't do this" + ```python + from pydantic import BaseModel, condecimal + + class Foo(BaseModel): + bar: condecimal(strict=True, allow_inf_nan=True) + ``` + + === ":white_check_mark: Do this" + ```python + from decimal import Decimal + from typing import Annotated + + from pydantic import BaseModel, Field + + class Foo(BaseModel): + bar: Annotated[Decimal, Field(strict=True, allow_inf_nan=True)] + ``` + + A wrapper around Decimal that adds validation. + + Args: + strict: Whether to validate the value in strict mode. Defaults to `None`. + gt: The value must be greater than this. Defaults to `None`. + ge: The value must be greater than or equal to this. Defaults to `None`. + lt: The value must be less than this. Defaults to `None`. + le: The value must be less than or equal to this. Defaults to `None`. + multiple_of: The value must be a multiple of this. Defaults to `None`. + max_digits: The maximum number of digits. Defaults to `None`. + decimal_places: The number of decimal places. Defaults to `None`. + allow_inf_nan: Whether to allow infinity and NaN. Defaults to `None`. + + ```python + from decimal import Decimal + + from pydantic import BaseModel, ValidationError, condecimal + + class ConstrainedExample(BaseModel): + constrained_decimal: condecimal(gt=Decimal('1.0')) + + m = ConstrainedExample(constrained_decimal=Decimal('1.1')) + print(repr(m)) + #> ConstrainedExample(constrained_decimal=Decimal('1.1')) + + try: + ConstrainedExample(constrained_decimal=Decimal('0.9')) + except ValidationError as e: + print(e.errors()) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('constrained_decimal',), + 'msg': 'Input should be greater than 1.0', + 'input': Decimal('0.9'), + 'ctx': {'gt': Decimal('1.0')}, + 'url': 'https://errors.pydantic.dev/2/v/greater_than', + } + ] + ''' + ``` + """ # noqa: D212 + return Annotated[ # pyright: ignore[reportReturnType] + Decimal, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + annotated_types.MultipleOf(multiple_of) if multiple_of is not None else None, + _fields.pydantic_general_metadata(max_digits=max_digits, decimal_places=decimal_places), + AllowInfNan(allow_inf_nan) if allow_inf_nan is not None else None, + ] + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class UuidVersion: + """A field metadata class to indicate a [UUID](https://docs.python.org/3/library/uuid.html) version. + + Use this class as an annotation via [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated), as seen below. + + Attributes: + uuid_version: The version of the UUID. Must be one of 1, 3, 4, 5, 6, 7 or 8. + + Example: + ```python + from typing import Annotated + from uuid import UUID + + from pydantic.types import UuidVersion + + UUID1 = Annotated[UUID, UuidVersion(1)] + ``` + """ + + uuid_version: Literal[1, 3, 4, 5, 6, 7, 8] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.pop('anyOf', None) # remove the bytes/str union + field_schema.update(type='string', format=f'uuid{self.uuid_version}') + return field_schema + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + _check_annotated_type(schema['type'], 'uuid', self.__class__.__name__) + schema['version'] = self.uuid_version # type: ignore + return schema + + def __hash__(self) -> int: + return hash(self.uuid_version) + + +UUID1 = Annotated[UUID, UuidVersion(1)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 1. + +```python +import uuid + +from pydantic import UUID1, BaseModel + +class Model(BaseModel): + uuid1: UUID1 + +Model(uuid1=uuid.uuid1()) +``` +""" +UUID3 = Annotated[UUID, UuidVersion(3)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 3. + +```python +import uuid + +from pydantic import UUID3, BaseModel + +class Model(BaseModel): + uuid3: UUID3 + +Model(uuid3=uuid.uuid3(uuid.NAMESPACE_DNS, 'pydantic.org')) +``` +""" +UUID4 = Annotated[UUID, UuidVersion(4)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 4. + +```python +import uuid + +from pydantic import UUID4, BaseModel + +class Model(BaseModel): + uuid4: UUID4 + +Model(uuid4=uuid.uuid4()) +``` +""" +UUID5 = Annotated[UUID, UuidVersion(5)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 5. + +```python +import uuid + +from pydantic import UUID5, BaseModel + +class Model(BaseModel): + uuid5: UUID5 + +Model(uuid5=uuid.uuid5(uuid.NAMESPACE_DNS, 'pydantic.org')) +``` +""" +UUID6 = Annotated[UUID, UuidVersion(6)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 6. + +```python +import uuid + +from pydantic import UUID6, BaseModel + +class Model(BaseModel): + uuid6: UUID6 + +Model(uuid6=uuid.UUID('1efea953-c2d6-6790-aa0a-69db8c87df97')) +``` +""" +UUID7 = Annotated[UUID, UuidVersion(7)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 7. + +```python +import uuid + +from pydantic import UUID7, BaseModel + +class Model(BaseModel): + uuid7: UUID7 + +Model(uuid7=uuid.UUID('0194fdcb-1c47-7a09-b52c-561154de0b4a')) +``` +""" +UUID8 = Annotated[UUID, UuidVersion(8)] +"""A [UUID](https://docs.python.org/3/library/uuid.html) that must be version 8. + +```python +import uuid + +from pydantic import UUID8, BaseModel + +class Model(BaseModel): + uuid8: UUID8 + +Model(uuid8=uuid.UUID('81a0b92e-6078-8551-9c81-8ccb666bdab8')) +``` +""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +@_dataclasses.dataclass +class PathType: + path_type: Literal['file', 'dir', 'new', 'socket'] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + format_conversion = {'file': 'file-path', 'dir': 'directory-path'} + field_schema.update(format=format_conversion.get(self.path_type, 'path'), type='string') + return field_schema + + def __get_pydantic_core_schema__(self, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + function_lookup = { + 'file': cast(core_schema.WithInfoValidatorFunction, self.validate_file), + 'dir': cast(core_schema.WithInfoValidatorFunction, self.validate_directory), + 'new': cast(core_schema.WithInfoValidatorFunction, self.validate_new), + 'socket': cast(core_schema.WithInfoValidatorFunction, self.validate_socket), + } + + return core_schema.with_info_after_validator_function( + function_lookup[self.path_type], + handler(source), + ) + + @staticmethod + def validate_file(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.is_file(): + return path + else: + raise PydanticCustomError('path_not_file', 'Path does not point to a file') + + @staticmethod + def validate_socket(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.is_socket(): + return path + else: + raise PydanticCustomError('path_not_socket', 'Path does not point to a socket') + + @staticmethod + def validate_directory(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.is_dir(): + return path + else: + raise PydanticCustomError('path_not_directory', 'Path does not point to a directory') + + @staticmethod + def validate_new(path: Path, _: core_schema.ValidationInfo) -> Path: + if path.exists(): + raise PydanticCustomError('path_exists', 'Path already exists') + elif not path.parent.exists(): + raise PydanticCustomError('parent_does_not_exist', 'Parent directory does not exist') + else: + return path + + def __hash__(self) -> int: + return hash(self.path_type) + + +FilePath = Annotated[Path, PathType('file')] +"""A path that must point to a file. + +```python +from pathlib import Path + +from pydantic import BaseModel, FilePath, ValidationError + +class Model(BaseModel): + f: FilePath + +path = Path('text.txt') +path.touch() +m = Model(f='text.txt') +print(m.model_dump()) +#> {'f': PosixPath('text.txt')} +path.unlink() + +path = Path('directory') +path.mkdir(exist_ok=True) +try: + Model(f='directory') # directory +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a file [type=path_not_file, input_value='directory', input_type=str] + ''' +path.rmdir() + +try: + Model(f='not-exists-file') +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a file [type=path_not_file, input_value='not-exists-file', input_type=str] + ''' +``` +""" +DirectoryPath = Annotated[Path, PathType('dir')] +"""A path that must point to a directory. + +```python +from pathlib import Path + +from pydantic import BaseModel, DirectoryPath, ValidationError + +class Model(BaseModel): + f: DirectoryPath + +path = Path('directory/') +path.mkdir() +m = Model(f='directory/') +print(m.model_dump()) +#> {'f': PosixPath('directory')} +path.rmdir() + +path = Path('file.txt') +path.touch() +try: + Model(f='file.txt') # file +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a directory [type=path_not_directory, input_value='file.txt', input_type=str] + ''' +path.unlink() + +try: + Model(f='not-exists-directory') +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + f + Path does not point to a directory [type=path_not_directory, input_value='not-exists-directory', input_type=str] + ''' +``` +""" +NewPath = Annotated[Path, PathType('new')] +"""A path for a new file or directory that must not already exist. The parent directory must already exist.""" + +SocketPath = Annotated[Path, PathType('socket')] +"""A path to an existing socket file""" + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + # Json[list[str]] will be recognized by type checkers as list[str] + Json = Annotated[AnyType, ...] + +else: + + class Json: + """A special type wrapper which loads JSON before parsing. + + You can use the `Json` data type to make Pydantic first load a raw JSON string before + validating the loaded data into the parametrized type: + + ```python + from typing import Any + + from pydantic import BaseModel, Json, ValidationError + + class AnyJsonModel(BaseModel): + json_obj: Json[Any] + + class ConstrainedJsonModel(BaseModel): + json_obj: Json[list[int]] + + print(AnyJsonModel(json_obj='{"b": 1}')) + #> json_obj={'b': 1} + print(ConstrainedJsonModel(json_obj='[1, 2, 3]')) + #> json_obj=[1, 2, 3] + + try: + ConstrainedJsonModel(json_obj=12) + except ValidationError as e: + print(e) + ''' + 1 validation error for ConstrainedJsonModel + json_obj + JSON input should be string, bytes or bytearray [type=json_type, input_value=12, input_type=int] + ''' + + try: + ConstrainedJsonModel(json_obj='[a, b]') + except ValidationError as e: + print(e) + ''' + 1 validation error for ConstrainedJsonModel + json_obj + Invalid JSON: expected value at line 1 column 2 [type=json_invalid, input_value='[a, b]', input_type=str] + ''' + + try: + ConstrainedJsonModel(json_obj='["a", "b"]') + except ValidationError as e: + print(e) + ''' + 2 validation errors for ConstrainedJsonModel + json_obj.0 + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] + json_obj.1 + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='b', input_type=str] + ''' + ``` + + When you dump the model using `model_dump` or `model_dump_json`, the dumped value will be the result of validation, + not the original JSON string. However, you can use the argument `round_trip=True` to get the original JSON string back: + + ```python + from pydantic import BaseModel, Json + + class ConstrainedJsonModel(BaseModel): + json_obj: Json[list[int]] + + print(ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json()) + #> {"json_obj":[1,2,3]} + print( + ConstrainedJsonModel(json_obj='[1, 2, 3]').model_dump_json(round_trip=True) + ) + #> {"json_obj":"[1,2,3]"} + ``` + """ + + @classmethod + def __class_getitem__(cls, item: AnyType) -> AnyType: + return Annotated[item, cls()] + + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + if cls is source: + return core_schema.json_schema(None) + else: + return core_schema.json_schema(handler(source)) + + def __repr__(self) -> str: + return 'Json' + + def __hash__(self) -> int: + return hash(type(self)) + + def __eq__(self, other: Any) -> bool: + return type(other) is type(self) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# The `Secret` class being conceptually immutable, make the type variable covariant: +SecretType = TypeVar('SecretType', covariant=True) + + +class _SecretBase(Generic[SecretType]): + def __init__(self, secret_value: SecretType) -> None: + self._secret_value: SecretType = secret_value + + def get_secret_value(self) -> SecretType: + """Get the secret value. + + Returns: + The secret value. + """ + return self._secret_value + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() + + def __hash__(self) -> int: + return hash(self.get_secret_value()) + + def __str__(self) -> str: + return str(self._display()) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({self._display()!r})' + + def _display(self) -> str | bytes: + raise NotImplementedError + + +def _serialize_secret(value: Secret[SecretType], info: core_schema.SerializationInfo) -> str | Secret[SecretType]: + if info.mode == 'json': + return str(value) + else: + return value + + +class Secret(_SecretBase[SecretType]): + """A generic base class used for defining a field with sensitive information that you do not want to be visible in logging or tracebacks. + + You may either directly parametrize `Secret` with a type, or subclass from `Secret` with a parametrized type. The benefit of subclassing + is that you can define a custom `_display` method, which will be used for `repr()` and `str()` methods. The examples below demonstrate both + ways of using `Secret` to create a new secret type. + + 1. Directly parametrizing `Secret` with a type: + + ```python + from pydantic import BaseModel, Secret + + SecretBool = Secret[bool] + + class Model(BaseModel): + secret_bool: SecretBool + + m = Model(secret_bool=True) + print(m.model_dump()) + #> {'secret_bool': Secret('**********')} + + print(m.model_dump_json()) + #> {"secret_bool":"**********"} + + print(m.secret_bool.get_secret_value()) + #> True + ``` + + 2. Subclassing from parametrized `Secret`: + + ```python + from datetime import date + + from pydantic import BaseModel, Secret + + class SecretDate(Secret[date]): + def _display(self) -> str: + return '****/**/**' + + class Model(BaseModel): + secret_date: SecretDate + + m = Model(secret_date=date(2022, 1, 1)) + print(m.model_dump()) + #> {'secret_date': SecretDate('****/**/**')} + + print(m.model_dump_json()) + #> {"secret_date":"****/**/**"} + + print(m.secret_date.get_secret_value()) + #> 2022-01-01 + ``` + + The value returned by the `_display` method will be used for `repr()` and `str()`. + + You can enforce constraints on the underlying type through annotations: + For example: + + ```python + from typing import Annotated + + from pydantic import BaseModel, Field, Secret, ValidationError + + SecretPosInt = Secret[Annotated[int, Field(gt=0, strict=True)]] + + class Model(BaseModel): + sensitive_int: SecretPosInt + + m = Model(sensitive_int=42) + print(m.model_dump()) + #> {'sensitive_int': Secret('**********')} + + try: + m = Model(sensitive_int=-42) # (1)! + except ValidationError as exc_info: + print(exc_info.errors(include_url=False, include_input=False)) + ''' + [ + { + 'type': 'greater_than', + 'loc': ('sensitive_int',), + 'msg': 'Input should be greater than 0', + 'ctx': {'gt': 0}, + } + ] + ''' + + try: + m = Model(sensitive_int='42') # (2)! + except ValidationError as exc_info: + print(exc_info.errors(include_url=False, include_input=False)) + ''' + [ + { + 'type': 'int_type', + 'loc': ('sensitive_int',), + 'msg': 'Input should be a valid integer', + } + ] + ''' + ``` + + 1. The input value is not greater than 0, so it raises a validation error. + 2. The input value is not an integer, so it raises a validation error because the `SecretPosInt` type has strict mode enabled. + """ + + def _display(self) -> str | bytes: + return '**********' if self.get_secret_value() else '' + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + inner_type = None + # if origin_type is Secret, then cls is a GenericAlias, and we can extract the inner type directly + origin_type = get_origin(source) + if origin_type is not None: + inner_type = get_args(source)[0] + # otherwise, we need to get the inner type from the base class + else: + bases = getattr(cls, '__orig_bases__', getattr(cls, '__bases__', [])) + for base in bases: + if get_origin(base) is Secret: + inner_type = get_args(base)[0] + if bases == [] or inner_type is None: + raise TypeError( + f"Can't get secret type from {cls.__name__}. " + 'Please use Secret[], or subclass from Secret[] instead.' + ) + + inner_schema = handler.generate_schema(inner_type) # type: ignore + + def validate_secret_value(value, handler) -> Secret[SecretType]: + if isinstance(value, Secret): + value = value.get_secret_value() + validated_inner = handler(value) + return cls(validated_inner) + + return core_schema.json_or_python_schema( + python_schema=core_schema.no_info_wrap_validator_function( + validate_secret_value, + inner_schema, + ), + json_schema=core_schema.no_info_after_validator_function(lambda x: cls(x), inner_schema), + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret, + info_arg=True, + when_used='always', + ), + ) + + __pydantic_serializer__ = SchemaSerializer( + core_schema.any_schema( + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret, + info_arg=True, + when_used='always', + ) + ) + ) + + +def _secret_display(value: SecretType) -> str: # type: ignore + return '**********' if value else '' + + +def _serialize_secret_field( + value: _SecretField[SecretType], info: core_schema.SerializationInfo +) -> str | _SecretField[SecretType]: + if info.mode == 'json': + # we want the output to always be string without the `b'` prefix for bytes, + # hence we just use `secret_display` + return _secret_display(value.get_secret_value()) + else: + return value + + +class _SecretField(_SecretBase[SecretType]): + _inner_schema: ClassVar[CoreSchema] + _error_kind: ClassVar[str] + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + def get_json_schema(_core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler) -> JsonSchemaValue: + json_schema = handler(cls._inner_schema) + _utils.update_not_none( + json_schema, + type='string', + writeOnly=True, + format='password', + ) + return json_schema + + def get_secret_schema(strict: bool) -> CoreSchema: + inner_schema = {**cls._inner_schema, 'strict': strict} + json_schema = core_schema.no_info_after_validator_function( + source, # construct the type + inner_schema, # pyright: ignore[reportArgumentType] + ) + return core_schema.json_or_python_schema( + python_schema=core_schema.union_schema( + [ + core_schema.is_instance_schema(source), + json_schema, + ], + custom_error_type=cls._error_kind, + ), + json_schema=json_schema, + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret_field, + info_arg=True, + when_used='always', + ), + ) + + return core_schema.lax_or_strict_schema( + lax_schema=get_secret_schema(strict=False), + strict_schema=get_secret_schema(strict=True), + metadata={'pydantic_js_functions': [get_json_schema]}, + ) + + __pydantic_serializer__ = SchemaSerializer( + core_schema.any_schema( + serialization=core_schema.plain_serializer_function_ser_schema( + _serialize_secret_field, + info_arg=True, + when_used='always', + ) + ) + ) + + +class SecretStr(_SecretField[str]): + """A string used for storing sensitive information that you do not want to be visible in logging or tracebacks. + + When the secret value is nonempty, it is displayed as `'**********'` instead of the underlying value in + calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `''`. + + ```python + from pydantic import BaseModel, SecretStr + + class User(BaseModel): + username: str + password: SecretStr + + user = User(username='scolvin', password='password1') + + print(user) + #> username='scolvin' password=SecretStr('**********') + print(user.password.get_secret_value()) + #> password1 + print((SecretStr('password'), SecretStr(''))) + #> (SecretStr('**********'), SecretStr('')) + ``` + + As seen above, by default, [`SecretStr`][pydantic.types.SecretStr] (and [`SecretBytes`][pydantic.types.SecretBytes]) + will be serialized as `**********` when serializing to json. + + You can use the [`field_serializer`][pydantic.functional_serializers.field_serializer] to dump the + secret as plain-text when serializing to json. + + ```python + from pydantic import BaseModel, SecretBytes, SecretStr, field_serializer + + class Model(BaseModel): + password: SecretStr + password_bytes: SecretBytes + + @field_serializer('password', 'password_bytes', when_used='json') + def dump_secret(self, v): + return v.get_secret_value() + + model = Model(password='IAmSensitive', password_bytes=b'IAmSensitiveBytes') + print(model) + #> password=SecretStr('**********') password_bytes=SecretBytes(b'**********') + print(model.password) + #> ********** + print(model.model_dump()) + ''' + { + 'password': SecretStr('**********'), + 'password_bytes': SecretBytes(b'**********'), + } + ''' + print(model.model_dump_json()) + #> {"password":"IAmSensitive","password_bytes":"IAmSensitiveBytes"} + ``` + """ + + _inner_schema: ClassVar[CoreSchema] = core_schema.str_schema() + _error_kind: ClassVar[str] = 'string_type' + + def __len__(self) -> int: + return len(self._secret_value) + + def _display(self) -> str: + return _secret_display(self._secret_value) + + +class SecretBytes(_SecretField[bytes]): + """A bytes used for storing sensitive information that you do not want to be visible in logging or tracebacks. + + It displays `b'**********'` instead of the string value on `repr()` and `str()` calls. + When the secret value is nonempty, it is displayed as `b'**********'` instead of the underlying value in + calls to `repr()` and `str()`. If the value _is_ empty, it is displayed as `b''`. + + ```python + from pydantic import BaseModel, SecretBytes + + class User(BaseModel): + username: str + password: SecretBytes + + user = User(username='scolvin', password=b'password1') + #> username='scolvin' password=SecretBytes(b'**********') + print(user.password.get_secret_value()) + #> b'password1' + print((SecretBytes(b'password'), SecretBytes(b''))) + #> (SecretBytes(b'**********'), SecretBytes(b'')) + ``` + """ + + _inner_schema: ClassVar[CoreSchema] = core_schema.bytes_schema() + _error_kind: ClassVar[str] = 'bytes_type' + + def __len__(self) -> int: + return len(self._secret_value) + + def _display(self) -> bytes: + return _secret_display(self._secret_value).encode() + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class PaymentCardBrand(str, Enum): + amex = 'American Express' + mastercard = 'Mastercard' + visa = 'Visa' + other = 'other' + + def __str__(self) -> str: + return self.value + + +@deprecated( + 'The `PaymentCardNumber` class is deprecated, use `pydantic_extra_types` instead. ' + 'See https://docs.pydantic.dev/latest/api/pydantic_extra_types_payment/#pydantic_extra_types.payment.PaymentCardNumber.', + category=PydanticDeprecatedSince20, +) +class PaymentCardNumber(str): + """Based on: https://en.wikipedia.org/wiki/Payment_card_number.""" + + strip_whitespace: ClassVar[bool] = True + min_length: ClassVar[int] = 12 + max_length: ClassVar[int] = 19 + bin: str + last4: str + brand: PaymentCardBrand + + def __init__(self, card_number: str): + self.validate_digits(card_number) + + card_number = self.validate_luhn_check_digit(card_number) + + self.bin = card_number[:6] + self.last4 = card_number[-4:] + self.brand = self.validate_brand(card_number) + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + return core_schema.with_info_after_validator_function( + cls.validate, + core_schema.str_schema( + min_length=cls.min_length, max_length=cls.max_length, strip_whitespace=cls.strip_whitespace + ), + ) + + @classmethod + def validate(cls, input_value: str, /, _: core_schema.ValidationInfo) -> PaymentCardNumber: + """Validate the card number and return a `PaymentCardNumber` instance.""" + return cls(input_value) + + @property + def masked(self) -> str: + """Mask all but the last 4 digits of the card number. + + Returns: + A masked card number string. + """ + num_masked = len(self) - 10 # len(bin) + len(last4) == 10 + return f'{self.bin}{"*" * num_masked}{self.last4}' + + @classmethod + def validate_digits(cls, card_number: str) -> None: + """Validate that the card number is all digits.""" + if not card_number.isdigit(): + raise PydanticCustomError('payment_card_number_digits', 'Card number is not all digits') + + @classmethod + def validate_luhn_check_digit(cls, card_number: str) -> str: + """Based on: https://en.wikipedia.org/wiki/Luhn_algorithm.""" + sum_ = int(card_number[-1]) + length = len(card_number) + parity = length % 2 + for i in range(length - 1): + digit = int(card_number[i]) + if i % 2 == parity: + digit *= 2 + if digit > 9: + digit -= 9 + sum_ += digit + valid = sum_ % 10 == 0 + if not valid: + raise PydanticCustomError('payment_card_number_luhn', 'Card number is not luhn valid') + return card_number + + @staticmethod + def validate_brand(card_number: str) -> PaymentCardBrand: + """Validate length based on BIN for major brands: + https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN). + """ + if card_number[0] == '4': + brand = PaymentCardBrand.visa + elif 51 <= int(card_number[:2]) <= 55: + brand = PaymentCardBrand.mastercard + elif card_number[:2] in {'34', '37'}: + brand = PaymentCardBrand.amex + else: + brand = PaymentCardBrand.other + + required_length: None | int | str = None + if brand in PaymentCardBrand.mastercard: + required_length = 16 + valid = len(card_number) == required_length + elif brand == PaymentCardBrand.visa: + required_length = '13, 16 or 19' + valid = len(card_number) in {13, 16, 19} + elif brand == PaymentCardBrand.amex: + required_length = 15 + valid = len(card_number) == required_length + else: + valid = True + + if not valid: + raise PydanticCustomError( + 'payment_card_number_brand', + 'Length for a {brand} card must be {required_length}', + {'brand': brand, 'required_length': required_length}, + ) + return brand + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ByteSize(int): + """Converts a string representing a number of bytes with units (such as `'1KB'` or `'11.5MiB'`) into an integer. + + You can use the `ByteSize` data type to (case-insensitively) convert a string representation of a number of bytes into + an integer, and also to print out human-readable strings representing a number of bytes. + + In conformance with [IEC 80000-13 Standard](https://en.wikipedia.org/wiki/ISO/IEC_80000) we interpret `'1KB'` to mean 1000 bytes, + and `'1KiB'` to mean 1024 bytes. In general, including a middle `'i'` will cause the unit to be interpreted as a power of 2, + rather than a power of 10 (so, for example, `'1 MB'` is treated as `1_000_000` bytes, whereas `'1 MiB'` is treated as `1_048_576` bytes). + + !!! info + Note that `1b` will be parsed as "1 byte" and not "1 bit". + + ```python + from pydantic import BaseModel, ByteSize + + class MyModel(BaseModel): + size: ByteSize + + print(MyModel(size=52000).size) + #> 52000 + print(MyModel(size='3000 KiB').size) + #> 3072000 + + m = MyModel(size='50 PB') + print(m.size.human_readable()) + #> 44.4PiB + print(m.size.human_readable(decimal=True)) + #> 50.0PB + print(m.size.human_readable(separator=' ')) + #> 44.4 PiB + + print(m.size.to('TiB')) + #> 45474.73508864641 + ``` + """ + + byte_sizes = { + 'b': 1, + 'kb': 10**3, + 'mb': 10**6, + 'gb': 10**9, + 'tb': 10**12, + 'pb': 10**15, + 'eb': 10**18, + 'kib': 2**10, + 'mib': 2**20, + 'gib': 2**30, + 'tib': 2**40, + 'pib': 2**50, + 'eib': 2**60, + 'bit': 1 / 8, + 'kbit': 10**3 / 8, + 'mbit': 10**6 / 8, + 'gbit': 10**9 / 8, + 'tbit': 10**12 / 8, + 'pbit': 10**15 / 8, + 'ebit': 10**18 / 8, + 'kibit': 2**10 / 8, + 'mibit': 2**20 / 8, + 'gibit': 2**30 / 8, + 'tibit': 2**40 / 8, + 'pibit': 2**50 / 8, + 'eibit': 2**60 / 8, + } + byte_sizes.update({k.lower()[0]: v for k, v in byte_sizes.items() if 'i' not in k}) + + byte_string_pattern = r'^\s*(\d*\.?\d+)\s*(\w+)?' + byte_string_re = re.compile(byte_string_pattern, re.IGNORECASE) + + @classmethod + def __get_pydantic_core_schema__(cls, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + return core_schema.with_info_after_validator_function( + function=cls._validate, + schema=core_schema.union_schema( + [ + core_schema.str_schema(pattern=cls.byte_string_pattern), + core_schema.int_schema(ge=0), + ], + custom_error_type='byte_size', + custom_error_message='could not parse value and unit from byte string', + ), + serialization=core_schema.plain_serializer_function_ser_schema( + int, return_schema=core_schema.int_schema(ge=0) + ), + ) + + @classmethod + def _validate(cls, input_value: Any, /, _: core_schema.ValidationInfo) -> ByteSize: + try: + return cls(int(input_value)) + except ValueError: + pass + + str_match = cls.byte_string_re.match(str(input_value)) + if str_match is None: + raise PydanticCustomError('byte_size', 'could not parse value and unit from byte string') + + scalar, unit = str_match.groups() + if unit is None: + unit = 'b' + + try: + unit_mult = cls.byte_sizes[unit.lower()] + except KeyError: + raise PydanticCustomError('byte_size_unit', 'could not interpret byte unit: {unit}', {'unit': unit}) + + return cls(int(float(scalar) * unit_mult)) + + def human_readable(self, decimal: bool = False, separator: str = '') -> str: + """Converts a byte size to a human readable string. + + Args: + decimal: If True, use decimal units (e.g. 1000 bytes per KB). If False, use binary units + (e.g. 1024 bytes per KiB). + separator: A string used to split the value and unit. Defaults to an empty string (''). + + Returns: + A human readable string representation of the byte size. + """ + if decimal: + divisor = 1000 + units = 'B', 'KB', 'MB', 'GB', 'TB', 'PB' + final_unit = 'EB' + else: + divisor = 1024 + units = 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB' + final_unit = 'EiB' + + num = float(self) + for unit in units: + if abs(num) < divisor: + if unit == 'B': + return f'{num:0.0f}{separator}{unit}' + else: + return f'{num:0.1f}{separator}{unit}' + num /= divisor + + return f'{num:0.1f}{separator}{final_unit}' + + def to(self, unit: str) -> float: + """Converts a byte size to another unit, including both byte and bit units. + + Args: + unit: The unit to convert to. Must be one of the following: B, KB, MB, GB, TB, PB, EB, + KiB, MiB, GiB, TiB, PiB, EiB (byte units) and + bit, kbit, mbit, gbit, tbit, pbit, ebit, + kibit, mibit, gibit, tibit, pibit, eibit (bit units). + + Returns: + The byte size in the new unit. + """ + try: + unit_div = self.byte_sizes[unit.lower()] + except KeyError: + raise PydanticCustomError('byte_size_unit', 'Could not interpret byte unit: {unit}', {'unit': unit}) + + return self / unit_div + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +def _check_annotated_type(annotated_type: str, expected_type: str, annotation: str) -> None: + if annotated_type != expected_type: + raise PydanticUserError(f"'{annotation}' cannot annotate '{annotated_type}'.", code='invalid-annotated-type') + + +if TYPE_CHECKING: + PastDate = Annotated[date, ...] + FutureDate = Annotated[date, ...] +else: + + class PastDate: + """A date in the past.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.date_schema(now_op='past') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'date', cls.__name__) + schema['now_op'] = 'past' + return schema + + def __repr__(self) -> str: + return 'PastDate' + + class FutureDate: + """A date in the future.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.date_schema(now_op='future') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'date', cls.__name__) + schema['now_op'] = 'future' + return schema + + def __repr__(self) -> str: + return 'FutureDate' + + +def condate( + *, + strict: bool | None = None, + gt: date | None = None, + ge: date | None = None, + lt: date | None = None, + le: date | None = None, +) -> type[date]: + """A wrapper for date that adds constraints. + + Args: + strict: Whether to validate the date value in strict mode. Defaults to `None`. + gt: The value must be greater than this. Defaults to `None`. + ge: The value must be greater than or equal to this. Defaults to `None`. + lt: The value must be less than this. Defaults to `None`. + le: The value must be less than or equal to this. Defaults to `None`. + + Returns: + A date type with the specified constraints. + """ + return Annotated[ # pyright: ignore[reportReturnType] + date, + Strict(strict) if strict is not None else None, + annotated_types.Interval(gt=gt, ge=ge, lt=lt, le=le), + ] + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATETIME TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + AwareDatetime = Annotated[datetime, ...] + NaiveDatetime = Annotated[datetime, ...] + PastDatetime = Annotated[datetime, ...] + FutureDatetime = Annotated[datetime, ...] + +else: + + class AwareDatetime: + """A datetime that requires timezone info.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(tz_constraint='aware') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['tz_constraint'] = 'aware' + return schema + + def __repr__(self) -> str: + return 'AwareDatetime' + + class NaiveDatetime: + """A datetime that doesn't require timezone info.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(tz_constraint='naive') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['tz_constraint'] = 'naive' + return schema + + def __repr__(self) -> str: + return 'NaiveDatetime' + + class PastDatetime: + """A datetime that must be in the past.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(now_op='past') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['now_op'] = 'past' + return schema + + def __repr__(self) -> str: + return 'PastDatetime' + + class FutureDatetime: + """A datetime that must be in the future.""" + + @classmethod + def __get_pydantic_core_schema__( + cls, source: type[Any], handler: GetCoreSchemaHandler + ) -> core_schema.CoreSchema: + if cls is source: + # used directly as a type + return core_schema.datetime_schema(now_op='future') + else: + schema = handler(source) + _check_annotated_type(schema['type'], 'datetime', cls.__name__) + schema['now_op'] = 'future' + return schema + + def __repr__(self) -> str: + return 'FutureDatetime' + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Encoded TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class EncoderProtocol(Protocol): + """Protocol for encoding and decoding data to and from bytes.""" + + @classmethod + def decode(cls, data: bytes) -> bytes: + """Decode the data using the encoder. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + ... + + @classmethod + def encode(cls, value: bytes) -> bytes: + """Encode the data using the encoder. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + ... + + @classmethod + def get_json_format(cls) -> str: + """Get the JSON format for the encoded data. + + Returns: + The JSON format for the encoded data. + """ + ... + + +class Base64Encoder(EncoderProtocol): + """Standard (non-URL-safe) Base64 encoder.""" + + @classmethod + def decode(cls, data: bytes) -> bytes: + """Decode the data from base64 encoded bytes to original bytes data. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + try: + return base64.b64decode(data) + except ValueError as e: + raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) + + @classmethod + def encode(cls, value: bytes) -> bytes: + """Encode the data from bytes to a base64 encoded bytes. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return base64.b64encode(value) + + @classmethod + def get_json_format(cls) -> Literal['base64']: + """Get the JSON format for the encoded data. + + Returns: + The JSON format for the encoded data. + """ + return 'base64' + + +class Base64UrlEncoder(EncoderProtocol): + """URL-safe Base64 encoder.""" + + @classmethod + def decode(cls, data: bytes) -> bytes: + """Decode the data from base64 encoded bytes to original bytes data. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + try: + return base64.urlsafe_b64decode(data) + except ValueError as e: + raise PydanticCustomError('base64_decode', "Base64 decoding error: '{error}'", {'error': str(e)}) + + @classmethod + def encode(cls, value: bytes) -> bytes: + """Encode the data from bytes to a base64 encoded bytes. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return base64.urlsafe_b64encode(value) + + @classmethod + def get_json_format(cls) -> Literal['base64url']: + """Get the JSON format for the encoded data. + + Returns: + The JSON format for the encoded data. + """ + return 'base64url' + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class EncodedBytes: + """A bytes type that is encoded and decoded using the specified encoder. + + `EncodedBytes` needs an encoder that implements `EncoderProtocol` to operate. + + ```python + from typing import Annotated + + from pydantic import BaseModel, EncodedBytes, EncoderProtocol, ValidationError + + class MyEncoder(EncoderProtocol): + @classmethod + def decode(cls, data: bytes) -> bytes: + if data == b'**undecodable**': + raise ValueError('Cannot decode data') + return data[13:] + + @classmethod + def encode(cls, value: bytes) -> bytes: + return b'**encoded**: ' + value + + @classmethod + def get_json_format(cls) -> str: + return 'my-encoder' + + MyEncodedBytes = Annotated[bytes, EncodedBytes(encoder=MyEncoder)] + + class Model(BaseModel): + my_encoded_bytes: MyEncodedBytes + + # Initialize the model with encoded data + m = Model(my_encoded_bytes=b'**encoded**: some bytes') + + # Access decoded value + print(m.my_encoded_bytes) + #> b'some bytes' + + # Serialize into the encoded form + print(m.model_dump()) + #> {'my_encoded_bytes': b'**encoded**: some bytes'} + + # Validate encoded data + try: + Model(my_encoded_bytes=b'**undecodable**') + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + my_encoded_bytes + Value error, Cannot decode data [type=value_error, input_value=b'**undecodable**', input_type=bytes] + ''' + ``` + """ + + encoder: type[EncoderProtocol] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format=self.encoder.get_json_format()) + return field_schema + + def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + _check_annotated_type(schema['type'], 'bytes', self.__class__.__name__) + return core_schema.with_info_after_validator_function( + function=self.decode, + schema=schema, + serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode), + ) + + def decode(self, data: bytes, _: core_schema.ValidationInfo) -> bytes: + """Decode the data using the specified encoder. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + return self.encoder.decode(data) + + def encode(self, value: bytes) -> bytes: + """Encode the data using the specified encoder. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return self.encoder.encode(value) + + def __hash__(self) -> int: + return hash(self.encoder) + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class EncodedStr: + """A str type that is encoded and decoded using the specified encoder. + + `EncodedStr` needs an encoder that implements `EncoderProtocol` to operate. + + ```python + from typing import Annotated + + from pydantic import BaseModel, EncodedStr, EncoderProtocol, ValidationError + + class MyEncoder(EncoderProtocol): + @classmethod + def decode(cls, data: bytes) -> bytes: + if data == b'**undecodable**': + raise ValueError('Cannot decode data') + return data[13:] + + @classmethod + def encode(cls, value: bytes) -> bytes: + return b'**encoded**: ' + value + + @classmethod + def get_json_format(cls) -> str: + return 'my-encoder' + + MyEncodedStr = Annotated[str, EncodedStr(encoder=MyEncoder)] + + class Model(BaseModel): + my_encoded_str: MyEncodedStr + + # Initialize the model with encoded data + m = Model(my_encoded_str='**encoded**: some str') + + # Access decoded value + print(m.my_encoded_str) + #> some str + + # Serialize into the encoded form + print(m.model_dump()) + #> {'my_encoded_str': '**encoded**: some str'} + + # Validate encoded data + try: + Model(my_encoded_str='**undecodable**') + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + my_encoded_str + Value error, Cannot decode data [type=value_error, input_value='**undecodable**', input_type=str] + ''' + ``` + """ + + encoder: type[EncoderProtocol] + + def __get_pydantic_json_schema__( + self, core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler + ) -> JsonSchemaValue: + field_schema = handler(core_schema) + field_schema.update(type='string', format=self.encoder.get_json_format()) + return field_schema + + def __get_pydantic_core_schema__(self, source: type[Any], handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: + schema = handler(source) + _check_annotated_type(schema['type'], 'str', self.__class__.__name__) + return core_schema.with_info_after_validator_function( + function=self.decode_str, + schema=schema, + serialization=core_schema.plain_serializer_function_ser_schema(function=self.encode_str), + ) + + def decode_str(self, data: str, _: core_schema.ValidationInfo) -> str: + """Decode the data using the specified encoder. + + Args: + data: The data to decode. + + Returns: + The decoded data. + """ + return self.encoder.decode(data.encode()).decode() + + def encode_str(self, value: str) -> str: + """Encode the data using the specified encoder. + + Args: + value: The data to encode. + + Returns: + The encoded data. + """ + return self.encoder.encode(value.encode()).decode() # noqa: UP008 + + def __hash__(self) -> int: + return hash(self.encoder) + + +Base64Bytes = Annotated[bytes, EncodedBytes(encoder=Base64Encoder)] +"""A bytes type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. + +Note: + Under the hood, `Base64Bytes` uses the standard library [`base64.b64encode()`][base64.b64encode] and [`base64.b64decode()`][base64.b64decode] functions. + + As a result, attempting to decode url-safe base64 data using the `Base64Bytes` type may fail or produce an incorrect + decoding. + +/// version-changed | v2.10 +`Base64Bytes` now uses [`base64.b64encode()`][base64.b64encode] and [`base64.b64decode()`][base64.b64decode] +instead of [`base64.encodebytes()`][base64.encodebytes] and [`base64.decodebytes()`][base64.decodebytes]. + +These methods are considered legacy implementation. If you'd still like to use these legacy encoders/decoders, +you can achieve this by creating a custom annotated type, like follows: +```python +import base64 +from typing import Annotated, Literal + +from pydantic_core import PydanticCustomError + +from pydantic import EncodedBytes, EncoderProtocol + +class LegacyBase64Encoder(EncoderProtocol): + @classmethod + def decode(cls, data: bytes) -> bytes: + try: + return base64.decodebytes(data) + except ValueError as e: + raise PydanticCustomError( + 'base64_decode', + "Base64 decoding error: '{error}'", + {'error': str(e)}, + ) + + @classmethod + def encode(cls, value: bytes) -> bytes: + return base64.encodebytes(value) + + @classmethod + def get_json_format(cls) -> Literal['base64']: + return 'base64' + +LegacyBase64Bytes = Annotated[bytes, EncodedBytes(encoder=LegacyBase64Encoder)] +``` +/// + +```python +from pydantic import Base64Bytes, BaseModel, ValidationError + +class Model(BaseModel): + base64_bytes: Base64Bytes + +# Initialize the model with base64 data +m = Model(base64_bytes=b'VGhpcyBpcyB0aGUgd2F5') + +# Access decoded value +print(m.base64_bytes) +#> b'This is the way' + +# Serialize into the base64 form +print(m.model_dump()) +#> {'base64_bytes': b'VGhpcyBpcyB0aGUgd2F5'} + +# Validate base64 data +try: + print(Model(base64_bytes=b'undecodable').base64_bytes) +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + base64_bytes + Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value=b'undecodable', input_type=bytes] + ''' +``` +""" +Base64Str = Annotated[str, EncodedStr(encoder=Base64Encoder)] +"""A string type that is encoded and decoded using the standard (non-URL-safe) base64 encoder. + +Note: + Under the hood, `Base64Str` uses the standard library [`base64.b64encode()`][base64.b64encode] and [`base64.b64decode()`][base64.b64decode] functions. + + As a result, attempting to decode url-safe base64 data using the `Base64Str` type may fail or produce an incorrect + decoding. + +/// version-changed | v2.10 +`Base64Str` now uses [`base64.b64encode()`][base64.b64encode] and [`base64.b64decode()`][base64.b64decode] +instead of [`base64.encodebytes()`][base64.encodebytes] and [`base64.decodebytes()`][base64.decodebytes]. + +These methods are considered legacy implementation. See the documentation about the [`Base64Bytes`][pydantic.types.Base64Bytes] type +for more information on how to replicate the old behavior with the legacy encoders/decoders. +/// + + +```python +from pydantic import Base64Str, BaseModel, ValidationError + +class Model(BaseModel): + base64_str: Base64Str + +# Initialize the model with base64 data +m = Model(base64_str='VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y') + +# Access decoded value +print(m.base64_str) +#> These aren't the droids you're looking for + +# Serialize into the base64 form +print(m.model_dump()) +#> {'base64_str': 'VGhlc2UgYXJlbid0IHRoZSBkcm9pZHMgeW91J3JlIGxvb2tpbmcgZm9y'} + +# Validate base64 data +try: + print(Model(base64_str='undecodable').base64_str) +except ValidationError as e: + print(e) + ''' + 1 validation error for Model + base64_str + Base64 decoding error: 'Incorrect padding' [type=base64_decode, input_value='undecodable', input_type=str] + ''' +``` +""" +Base64UrlBytes = Annotated[bytes, EncodedBytes(encoder=Base64UrlEncoder)] +"""A bytes type that is encoded and decoded using the URL-safe base64 encoder. + +Note: + Under the hood, `Base64UrlBytes` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` + functions. + + As a result, the `Base64UrlBytes` type can be used to faithfully decode "vanilla" base64 data + (using `'+'` and `'/'`). + +```python +from pydantic import Base64UrlBytes, BaseModel + +class Model(BaseModel): + base64url_bytes: Base64UrlBytes + +# Initialize the model with base64 data +m = Model(base64url_bytes=b'SHc_dHc-TXc==') +print(m) +#> base64url_bytes=b'Hw?tw>Mw' +``` +""" +Base64UrlStr = Annotated[str, EncodedStr(encoder=Base64UrlEncoder)] +"""A str type that is encoded and decoded using the URL-safe base64 encoder. + +Note: + Under the hood, `Base64UrlStr` use standard library `base64.urlsafe_b64encode` and `base64.urlsafe_b64decode` + functions. + + As a result, the `Base64UrlStr` type can be used to faithfully decode "vanilla" base64 data (using `'+'` and `'/'`). + +```python +from pydantic import Base64UrlStr, BaseModel + +class Model(BaseModel): + base64url_str: Base64UrlStr + +# Initialize the model with base64 data +m = Model(base64url_str='SHc_dHc-TXc==') +print(m) +#> base64url_str='Hw?tw>Mw' +``` +""" + + +__getattr__ = getattr_migration(__name__) + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true) +class GetPydanticSchema: + """!!! abstract "Usage Documentation" + [Using `GetPydanticSchema` to Reduce Boilerplate](../concepts/types.md#using-getpydanticschema-to-reduce-boilerplate) + + A convenience class for creating an annotation that provides pydantic custom type hooks. + + This class is intended to eliminate the need to create a custom "marker" which defines the + `__get_pydantic_core_schema__` and `__get_pydantic_json_schema__` custom hook methods. + + For example, to have a field treated by type checkers as `int`, but by pydantic as `Any`, you can do: + ```python + from typing import Annotated, Any + + from pydantic import BaseModel, GetPydanticSchema + + HandleAsAny = GetPydanticSchema(lambda _s, h: h(Any)) + + class Model(BaseModel): + x: Annotated[int, HandleAsAny] # pydantic sees `x: Any` + + print(repr(Model(x='abc').x)) + #> 'abc' + ``` + """ + + get_pydantic_core_schema: Callable[[Any, GetCoreSchemaHandler], CoreSchema] | None = None + get_pydantic_json_schema: Callable[[Any, GetJsonSchemaHandler], JsonSchemaValue] | None = None + + # Note: we may want to consider adding a convenience staticmethod `def for_type(type_: Any) -> GetPydanticSchema:` + # which returns `GetPydanticSchema(lambda _s, h: h(type_))` + + if not TYPE_CHECKING: + # We put `__getattr__` in a non-TYPE_CHECKING block because otherwise, mypy allows arbitrary attribute access + + def __getattr__(self, item: str) -> Any: + """Use this rather than defining `__get_pydantic_core_schema__` etc. to reduce the number of nested calls.""" + if item == '__get_pydantic_core_schema__' and self.get_pydantic_core_schema: + return self.get_pydantic_core_schema + elif item == '__get_pydantic_json_schema__' and self.get_pydantic_json_schema: + return self.get_pydantic_json_schema + else: + return object.__getattribute__(self, item) + + __hash__ = object.__hash__ + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class Tag: + """Provides a way to specify the expected tag to use for a case of a (callable) discriminated union. + + Also provides a way to label a union case in error messages. + + When using a callable `Discriminator`, attach a `Tag` to each case in the `Union` to specify the tag that + should be used to identify that case. For example, in the below example, the `Tag` is used to specify that + if `get_discriminator_value` returns `'apple'`, the input should be validated as an `ApplePie`, and if it + returns `'pumpkin'`, the input should be validated as a `PumpkinPie`. + + The primary role of the `Tag` here is to map the return value from the callable `Discriminator` function to + the appropriate member of the `Union` in question. + + ```python + from typing import Annotated, Any, Literal, Union + + from pydantic import BaseModel, Discriminator, Tag + + class Pie(BaseModel): + time_to_cook: int + num_ingredients: int + + class ApplePie(Pie): + fruit: Literal['apple'] = 'apple' + + class PumpkinPie(Pie): + filling: Literal['pumpkin'] = 'pumpkin' + + def get_discriminator_value(v: Any) -> str: + if isinstance(v, dict): + return v.get('fruit', v.get('filling')) + return getattr(v, 'fruit', getattr(v, 'filling', None)) + + class ThanksgivingDinner(BaseModel): + dessert: Annotated[ + Union[ + Annotated[ApplePie, Tag('apple')], + Annotated[PumpkinPie, Tag('pumpkin')], + ], + Discriminator(get_discriminator_value), + ] + + apple_variation = ThanksgivingDinner.model_validate( + {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} + ) + print(repr(apple_variation)) + ''' + ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) + ''' + + pumpkin_variation = ThanksgivingDinner.model_validate( + { + 'dessert': { + 'filling': 'pumpkin', + 'time_to_cook': 40, + 'num_ingredients': 6, + } + } + ) + print(repr(pumpkin_variation)) + ''' + ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) + ''' + ``` + + !!! note + You must specify a `Tag` for every case in a `Tag` that is associated with a + callable `Discriminator`. Failing to do so will result in a `PydanticUserError` with code + [`callable-discriminator-no-tag`](../errors/usage_errors.md#callable-discriminator-no-tag). + + See the [Discriminated Unions] concepts docs for more details on how to use `Tag`s. + + [Discriminated Unions]: ../concepts/unions.md#discriminated-unions + """ + + tag: str + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + schema = handler(source_type) + metadata = cast('CoreMetadata', schema.setdefault('metadata', {})) + metadata['pydantic_internal_union_tag_key'] = self.tag + return schema + + +@_dataclasses.dataclass(**_internal_dataclass.slots_true, frozen=True) +class Discriminator: + """!!! abstract "Usage Documentation" + [Discriminated Unions with `Callable` `Discriminator`](../concepts/unions.md#discriminated-unions-with-callable-discriminator) + + Provides a way to use a custom callable as the way to extract the value of a union discriminator. + + This allows you to get validation behavior like you'd get from `Field(discriminator=)`, + but without needing to have a single shared field across all the union choices. This also makes it + possible to handle unions of models and primitive types with discriminated-union-style validation errors. + Finally, this allows you to use a custom callable as the way to identify which member of a union a value + belongs to, while still seeing all the performance benefits of a discriminated union. + + Consider this example, which is much more performant with the use of `Discriminator` and thus a `TaggedUnion` + than it would be as a normal `Union`. + + ```python + from typing import Annotated, Any, Literal, Union + + from pydantic import BaseModel, Discriminator, Tag + + class Pie(BaseModel): + time_to_cook: int + num_ingredients: int + + class ApplePie(Pie): + fruit: Literal['apple'] = 'apple' + + class PumpkinPie(Pie): + filling: Literal['pumpkin'] = 'pumpkin' + + def get_discriminator_value(v: Any) -> str: + if isinstance(v, dict): + return v.get('fruit', v.get('filling')) + return getattr(v, 'fruit', getattr(v, 'filling', None)) + + class ThanksgivingDinner(BaseModel): + dessert: Annotated[ + Union[ + Annotated[ApplePie, Tag('apple')], + Annotated[PumpkinPie, Tag('pumpkin')], + ], + Discriminator(get_discriminator_value), + ] + + apple_variation = ThanksgivingDinner.model_validate( + {'dessert': {'fruit': 'apple', 'time_to_cook': 60, 'num_ingredients': 8}} + ) + print(repr(apple_variation)) + ''' + ThanksgivingDinner(dessert=ApplePie(time_to_cook=60, num_ingredients=8, fruit='apple')) + ''' + + pumpkin_variation = ThanksgivingDinner.model_validate( + { + 'dessert': { + 'filling': 'pumpkin', + 'time_to_cook': 40, + 'num_ingredients': 6, + } + } + ) + print(repr(pumpkin_variation)) + ''' + ThanksgivingDinner(dessert=PumpkinPie(time_to_cook=40, num_ingredients=6, filling='pumpkin')) + ''' + ``` + + See the [Discriminated Unions] concepts docs for more details on how to use `Discriminator`s. + + [Discriminated Unions]: ../concepts/unions.md#discriminated-unions + """ + + discriminator: str | Callable[[Any], Hashable] + """The callable or field name for discriminating the type in a tagged union. + + A `Callable` discriminator must extract the value of the discriminator from the input. + A `str` discriminator must be the name of a field to discriminate against. + """ + custom_error_type: str | None = None + """Type to use in [custom errors](../errors/errors.md) replacing the standard discriminated union + validation errors. + """ + custom_error_message: str | None = None + """Message to use in custom errors.""" + custom_error_context: dict[str, int | str | float] | None = None + """Context to use in custom errors.""" + + def __get_pydantic_core_schema__(self, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + if isinstance(self.discriminator, str): + from pydantic import Field + + return handler(Annotated[source_type, Field(discriminator=self.discriminator)]) + else: + original_schema = handler(source_type) + return self._convert_schema(original_schema, handler) + + def _convert_schema( + self, original_schema: core_schema.CoreSchema, handler: GetCoreSchemaHandler | None = None + ) -> core_schema.TaggedUnionSchema: + if handler is not None and original_schema['type'] == 'definition-ref': + # Same logic as `_ApplyInferredDiscriminator._apply_to_root()` + try: + def_schema = handler.resolve_ref_schema(original_schema) + except LookupError: # pragma: no cover + from pydantic._internal._discriminated_union import MissingDefinitionForUnionRef + + raise MissingDefinitionForUnionRef(original_schema['schema_ref']) + + # If using a referenceable union as discriminated (e.g. `type Pet = Cat | Dog; field: Pet = Field(discriminator=...)`): + if def_schema['type'] == 'union': + original_schema = def_schema.copy() + original_schema.pop('ref') + + if original_schema['type'] != 'union': + # This likely indicates that the schema was a single-item union that was simplified. + # In this case, we do the same thing we do in + # `pydantic._internal._discriminated_union._ApplyInferredDiscriminator._apply_to_root`, namely, + # package the generated schema back into a single-item union. + original_schema = core_schema.union_schema([original_schema]) + + tagged_union_choices = {} + for choice in original_schema['choices']: + tag = None + if isinstance(choice, tuple): + choice, tag = choice + metadata = cast('CoreMetadata | None', choice.get('metadata')) + if metadata is not None: + tag = metadata.get('pydantic_internal_union_tag_key') or tag + if tag is None: + # `handler` is None when this method is called from `apply_discriminator()` (deferred discriminators) + if handler is not None and choice['type'] == 'definition-ref': + # If choice was built from a PEP 695 type alias, try to resolve the def: + try: + choice = handler.resolve_ref_schema(choice) + except LookupError: + pass + else: + metadata = cast('CoreMetadata | None', choice.get('metadata')) + if metadata is not None: + tag = metadata.get('pydantic_internal_union_tag_key') + + if tag is None: + raise PydanticUserError( + f'`Tag` not provided for choice {choice} used with `Discriminator`', + code='callable-discriminator-no-tag', + ) + tagged_union_choices[tag] = choice + + # Have to do these verbose checks to ensure falsy values ('' and {}) don't get ignored + custom_error_type = self.custom_error_type + if custom_error_type is None: + custom_error_type = original_schema.get('custom_error_type') + + custom_error_message = self.custom_error_message + if custom_error_message is None: + custom_error_message = original_schema.get('custom_error_message') + + custom_error_context = self.custom_error_context + if custom_error_context is None: + custom_error_context = original_schema.get('custom_error_context') + + custom_error_type = original_schema.get('custom_error_type') if custom_error_type is None else custom_error_type + return core_schema.tagged_union_schema( + tagged_union_choices, + self.discriminator, + custom_error_type=custom_error_type, + custom_error_message=custom_error_message, + custom_error_context=custom_error_context, + strict=original_schema.get('strict'), + ref=original_schema.get('ref'), + metadata=original_schema.get('metadata'), + serialization=original_schema.get('serialization'), + ) + + +_JSON_TYPES = {int, float, str, bool, list, dict, type(None)} + + +def _get_type_name(x: Any) -> str: + type_ = type(x) + if type_ in _JSON_TYPES: + return type_.__name__ + + # Handle proper subclasses; note we don't need to handle None or bool here + if isinstance(x, int): + return 'int' + if isinstance(x, float): + return 'float' + if isinstance(x, str): + return 'str' + if isinstance(x, list): + return 'list' + if isinstance(x, dict): + return 'dict' + + # Fail by returning the type's actual name + return getattr(type_, '__name__', '') + + +class _AllowAnyJson: + @classmethod + def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + python_schema = handler(source_type) + return core_schema.json_or_python_schema(json_schema=core_schema.any_schema(), python_schema=python_schema) + + +if TYPE_CHECKING: + # This seems to only be necessary for mypy + JsonValue: TypeAlias = Union[ + list['JsonValue'], + dict[str, 'JsonValue'], + str, + bool, + int, + float, + None, + ] + """A `JsonValue` is used to represent a value that can be serialized to JSON. + + It may be one of: + + * `list['JsonValue']` + * `dict[str, 'JsonValue']` + * `str` + * `bool` + * `int` + * `float` + * `None` + + The following example demonstrates how to use `JsonValue` to validate JSON data, + and what kind of errors to expect when input data is not json serializable. + + ```python + import json + + from pydantic import BaseModel, JsonValue, ValidationError + + class Model(BaseModel): + j: JsonValue + + valid_json_data = {'j': {'a': {'b': {'c': 1, 'd': [2, None]}}}} + invalid_json_data = {'j': {'a': {'b': ...}}} + + print(repr(Model.model_validate(valid_json_data))) + #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) + print(repr(Model.model_validate_json(json.dumps(valid_json_data)))) + #> Model(j={'a': {'b': {'c': 1, 'd': [2, None]}}}) + + try: + Model.model_validate(invalid_json_data) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + j.dict.a.dict.b + input was not a valid JSON value [type=invalid-json-value, input_value=Ellipsis, input_type=ellipsis] + ''' + ``` + """ + +else: + JsonValue = TypeAliasType( + 'JsonValue', + Annotated[ + Union[ + Annotated[list['JsonValue'], Tag('list')], + Annotated[dict[str, 'JsonValue'], Tag('dict')], + Annotated[str, Tag('str')], + Annotated[bool, Tag('bool')], + Annotated[int, Tag('int')], + Annotated[float, Tag('float')], + Annotated[None, Tag('NoneType')], + ], + Discriminator( + _get_type_name, + custom_error_type='invalid-json-value', + custom_error_message='input was not a valid JSON value', + ), + _AllowAnyJson, + ], + ) + + +class _OnErrorOmit: + @classmethod + def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> CoreSchema: + # there is no actual default value here but we use with_default_schema since it already has the on_error + # behavior implemented and it would be no more efficient to implement it on every other validator + # or as a standalone validator + return core_schema.with_default_schema(schema=handler(source_type), on_error='omit') + + +OnErrorOmit = Annotated[T, _OnErrorOmit] +""" +When used as an item in a list, the key type in a dict, optional values of a TypedDict, etc. +this annotation omits the item from the iteration if there is any error validating it. +That is, instead of a [`ValidationError`][pydantic_core.ValidationError] being propagated up and the entire iterable being discarded +any invalid items are discarded and the valid ones are returned. +""" + + +@_dataclasses.dataclass +class FailFast(_fields.PydanticMetadata, BaseMetadata): + """A `FailFast` annotation can be used to specify that validation should stop at the first error. + + This can be useful when you want to validate a large amount of data and you only need to know if it's valid or not. + + You might want to enable this setting if you want to validate your data faster (basically, if you use this, + validation will be more performant with the caveat that you get less information). + + ```python + from typing import Annotated + + from pydantic import BaseModel, FailFast, ValidationError + + class Model(BaseModel): + x: Annotated[list[int], FailFast()] + + # This will raise a single error for the first invalid value and stop validation + try: + obj = Model(x=[1, 2, 'a', 4, 5, 'b', 7, 8, 9, 'c']) + except ValidationError as e: + print(e) + ''' + 1 validation error for Model + x.2 + Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str] + ''' + ``` + """ + + fail_fast: bool = True diff --git a/source/target-vendors/cp312/pydantic/typing.py b/source/target-vendors/cp312/pydantic/typing.py new file mode 100644 index 0000000..0bda22d --- /dev/null +++ b/source/target-vendors/cp312/pydantic/typing.py @@ -0,0 +1,5 @@ +"""`typing` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/utils.py b/source/target-vendors/cp312/pydantic/utils.py new file mode 100644 index 0000000..8d1e2a8 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/utils.py @@ -0,0 +1,5 @@ +"""The `utils` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/v1/__init__.py b/source/target-vendors/cp312/pydantic/v1/__init__.py new file mode 100644 index 0000000..6ad3f46 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/__init__.py @@ -0,0 +1,131 @@ +# flake8: noqa +from pydantic.v1 import dataclasses +from pydantic.v1.annotated_types import create_model_from_namedtuple, create_model_from_typeddict +from pydantic.v1.class_validators import root_validator, validator +from pydantic.v1.config import BaseConfig, ConfigDict, Extra +from pydantic.v1.decorator import validate_arguments +from pydantic.v1.env_settings import BaseSettings +from pydantic.v1.error_wrappers import ValidationError +from pydantic.v1.errors import * +from pydantic.v1.fields import Field, PrivateAttr, Required +from pydantic.v1.main import * +from pydantic.v1.networks import * +from pydantic.v1.parse import Protocol +from pydantic.v1.tools import * +from pydantic.v1.types import * +from pydantic.v1.version import VERSION, compiled + +__version__ = VERSION + +# WARNING __all__ from pydantic.errors is not included here, it will be removed as an export here in v2 +# please use "from pydantic.v1.errors import ..." instead +__all__ = [ + # annotated types utils + 'create_model_from_namedtuple', + 'create_model_from_typeddict', + # dataclasses + 'dataclasses', + # class_validators + 'root_validator', + 'validator', + # config + 'BaseConfig', + 'ConfigDict', + 'Extra', + # decorator + 'validate_arguments', + # env_settings + 'BaseSettings', + # error_wrappers + 'ValidationError', + # fields + 'Field', + 'Required', + # main + 'BaseModel', + 'create_model', + 'validate_model', + # network + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'HttpUrl', + 'stricturl', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'validate_email', + # parse + 'Protocol', + # tools + 'parse_file_as', + 'parse_obj_as', + 'parse_raw_as', + 'schema_of', + 'schema_json_of', + # types + 'NoneStr', + 'NoneBytes', + 'StrBytes', + 'NoneStrBytes', + 'StrictStr', + 'ConstrainedBytes', + 'conbytes', + 'ConstrainedList', + 'conlist', + 'ConstrainedSet', + 'conset', + 'ConstrainedFrozenSet', + 'confrozenset', + 'ConstrainedStr', + 'constr', + 'PyObject', + 'ConstrainedInt', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'ConstrainedFloat', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'ConstrainedDecimal', + 'condecimal', + 'ConstrainedDate', + 'condate', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'FilePath', + 'DirectoryPath', + 'Json', + 'JsonWrapper', + 'SecretField', + 'SecretStr', + 'SecretBytes', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'PrivateAttr', + 'ByteSize', + 'PastDate', + 'FutureDate', + # version + 'compiled', + 'VERSION', +] diff --git a/source/target-vendors/cp312/pydantic/v1/_hypothesis_plugin.py b/source/target-vendors/cp312/pydantic/v1/_hypothesis_plugin.py new file mode 100644 index 0000000..b62234d --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/_hypothesis_plugin.py @@ -0,0 +1,391 @@ +""" +Register Hypothesis strategies for Pydantic custom types. + +This enables fully-automatic generation of test data for most Pydantic classes. + +Note that this module has *no* runtime impact on Pydantic itself; instead it +is registered as a setuptools entry point and Hypothesis will import it if +Pydantic is installed. See also: + +https://hypothesis.readthedocs.io/en/latest/strategies.html#registering-strategies-via-setuptools-entry-points +https://hypothesis.readthedocs.io/en/latest/data.html#hypothesis.strategies.register_type_strategy +https://hypothesis.readthedocs.io/en/latest/strategies.html#interaction-with-pytest-cov +https://docs.pydantic.dev/usage/types/#pydantic-types + +Note that because our motivation is to *improve user experience*, the strategies +are always sound (never generate invalid data) but sacrifice completeness for +maintainability (ie may be unable to generate some tricky but valid data). + +Finally, this module makes liberal use of `# type: ignore[]` pragmas. +This is because Hypothesis annotates `register_type_strategy()` with +`(T, SearchStrategy[T])`, but in most cases we register e.g. `ConstrainedInt` +to generate instances of the builtin `int` type which match the constraints. +""" + +import contextlib +import datetime +import ipaddress +import json +import math +from fractions import Fraction +from typing import Callable, Dict, Type, Union, cast, overload + +import hypothesis.strategies as st + +import pydantic +import pydantic.color +import pydantic.types +from pydantic.v1.utils import lenient_issubclass + +# FilePath and DirectoryPath are explicitly unsupported, as we'd have to create +# them on-disk, and that's unsafe in general without being told *where* to do so. +# +# URLs are unsupported because it's easy for users to define their own strategy for +# "normal" URLs, and hard for us to define a general strategy which includes "weird" +# URLs but doesn't also have unpredictable performance problems. +# +# conlist() and conset() are unsupported for now, because the workarounds for +# Cython and Hypothesis to handle parametrized generic types are incompatible. +# We are rethinking Hypothesis compatibility in Pydantic v2. + +# Emails +try: + import email_validator +except ImportError: # pragma: no cover + pass +else: + + def is_valid_email(s: str) -> bool: + # Hypothesis' st.emails() occasionally generates emails like 0@A0--0.ac + # that are invalid according to email-validator, so we filter those out. + try: + email_validator.validate_email(s, check_deliverability=False) + return True + except email_validator.EmailNotValidError: # pragma: no cover + return False + + # Note that these strategies deliberately stay away from any tricky Unicode + # or other encoding issues; we're just trying to generate *something* valid. + st.register_type_strategy(pydantic.EmailStr, st.emails().filter(is_valid_email)) # type: ignore[arg-type] + st.register_type_strategy( + pydantic.NameEmail, + st.builds( + '{} <{}>'.format, # type: ignore[arg-type] + st.from_regex('[A-Za-z0-9_]+( [A-Za-z0-9_]+){0,5}', fullmatch=True), + st.emails().filter(is_valid_email), + ), + ) + +# PyObject - dotted names, in this case taken from the math module. +st.register_type_strategy( + pydantic.PyObject, # type: ignore[arg-type] + st.sampled_from( + [cast(pydantic.PyObject, f'math.{name}') for name in sorted(vars(math)) if not name.startswith('_')] + ), +) + +# CSS3 Colors; as name, hex, rgb(a) tuples or strings, or hsl strings +_color_regexes = ( + '|'.join( + ( + pydantic.color.r_hex_short, + pydantic.color.r_hex_long, + pydantic.color.r_rgb, + pydantic.color.r_rgba, + pydantic.color.r_hsl, + pydantic.color.r_hsla, + ) + ) + # Use more precise regex patterns to avoid value-out-of-range errors + .replace(pydantic.color._r_sl, r'(?:(\d\d?(?:\.\d+)?|100(?:\.0+)?)%)') + .replace(pydantic.color._r_alpha, r'(?:(0(?:\.\d+)?|1(?:\.0+)?|\.\d+|\d{1,2}%))') + .replace(pydantic.color._r_255, r'(?:((?:\d|\d\d|[01]\d\d|2[0-4]\d|25[0-4])(?:\.\d+)?|255(?:\.0+)?))') +) +st.register_type_strategy( + pydantic.color.Color, + st.one_of( + st.sampled_from(sorted(pydantic.color.COLORS_BY_NAME)), + st.tuples( + st.integers(0, 255), + st.integers(0, 255), + st.integers(0, 255), + st.none() | st.floats(0, 1) | st.floats(0, 100).map('{}%'.format), + ), + st.from_regex(_color_regexes, fullmatch=True), + ), +) + + +# Card numbers, valid according to the Luhn algorithm + + +def add_luhn_digit(card_number: str) -> str: + # See https://en.wikipedia.org/wiki/Luhn_algorithm + for digit in '0123456789': + with contextlib.suppress(Exception): + pydantic.PaymentCardNumber.validate_luhn_check_digit(card_number + digit) + return card_number + digit + raise AssertionError('Unreachable') # pragma: no cover + + +card_patterns = ( + # Note that these patterns omit the Luhn check digit; that's added by the function above + '4[0-9]{14}', # Visa + '5[12345][0-9]{13}', # Mastercard + '3[47][0-9]{12}', # American Express + '[0-26-9][0-9]{10,17}', # other (incomplete to avoid overlap) +) +st.register_type_strategy( + pydantic.PaymentCardNumber, + st.from_regex('|'.join(card_patterns), fullmatch=True).map(add_luhn_digit), # type: ignore[arg-type] +) + +# UUIDs +st.register_type_strategy(pydantic.UUID1, st.uuids(version=1)) +st.register_type_strategy(pydantic.UUID3, st.uuids(version=3)) +st.register_type_strategy(pydantic.UUID4, st.uuids(version=4)) +st.register_type_strategy(pydantic.UUID5, st.uuids(version=5)) + +# Secrets +st.register_type_strategy(pydantic.SecretBytes, st.binary().map(pydantic.SecretBytes)) +st.register_type_strategy(pydantic.SecretStr, st.text().map(pydantic.SecretStr)) + +# IP addresses, networks, and interfaces +st.register_type_strategy(pydantic.IPvAnyAddress, st.ip_addresses()) # type: ignore[arg-type] +st.register_type_strategy( + pydantic.IPvAnyInterface, + st.from_type(ipaddress.IPv4Interface) | st.from_type(ipaddress.IPv6Interface), # type: ignore[arg-type] +) +st.register_type_strategy( + pydantic.IPvAnyNetwork, + st.from_type(ipaddress.IPv4Network) | st.from_type(ipaddress.IPv6Network), # type: ignore[arg-type] +) + +# We hook into the con***() functions and the ConstrainedNumberMeta metaclass, +# so here we only have to register subclasses for other constrained types which +# don't go via those mechanisms. Then there are the registration hooks below. +st.register_type_strategy(pydantic.StrictBool, st.booleans()) +st.register_type_strategy(pydantic.StrictStr, st.text()) + + +# FutureDate, PastDate +st.register_type_strategy(pydantic.FutureDate, st.dates(min_value=datetime.date.today() + datetime.timedelta(days=1))) +st.register_type_strategy(pydantic.PastDate, st.dates(max_value=datetime.date.today() - datetime.timedelta(days=1))) + + +# Constrained-type resolver functions +# +# For these ones, we actually want to inspect the type in order to work out a +# satisfying strategy. First up, the machinery for tracking resolver functions: + +RESOLVERS: Dict[type, Callable[[type], st.SearchStrategy]] = {} # type: ignore[type-arg] + + +@overload +def _registered(typ: Type[pydantic.types.T]) -> Type[pydantic.types.T]: + pass + + +@overload +def _registered(typ: pydantic.types.ConstrainedNumberMeta) -> pydantic.types.ConstrainedNumberMeta: + pass + + +def _registered( + typ: Union[Type[pydantic.types.T], pydantic.types.ConstrainedNumberMeta] +) -> Union[Type[pydantic.types.T], pydantic.types.ConstrainedNumberMeta]: + # This function replaces the version in `pydantic.types`, in order to + # effect the registration of new constrained types so that Hypothesis + # can generate valid examples. + pydantic.types._DEFINED_TYPES.add(typ) + for supertype, resolver in RESOLVERS.items(): + if issubclass(typ, supertype): + st.register_type_strategy(typ, resolver(typ)) # type: ignore + return typ + raise NotImplementedError(f'Unknown type {typ!r} has no resolver to register') # pragma: no cover + + +def resolves( + typ: Union[type, pydantic.types.ConstrainedNumberMeta] +) -> Callable[[Callable[..., st.SearchStrategy]], Callable[..., st.SearchStrategy]]: # type: ignore[type-arg] + def inner(f): # type: ignore + assert f not in RESOLVERS + RESOLVERS[typ] = f + return f + + return inner + + +# Type-to-strategy resolver functions + + +@resolves(pydantic.JsonWrapper) +def resolve_json(cls): # type: ignore[no-untyped-def] + try: + inner = st.none() if cls.inner_type is None else st.from_type(cls.inner_type) + except Exception: # pragma: no cover + finite = st.floats(allow_infinity=False, allow_nan=False) + inner = st.recursive( + base=st.one_of(st.none(), st.booleans(), st.integers(), finite, st.text()), + extend=lambda x: st.lists(x) | st.dictionaries(st.text(), x), # type: ignore + ) + inner_type = getattr(cls, 'inner_type', None) + return st.builds( + cls.inner_type.json if lenient_issubclass(inner_type, pydantic.BaseModel) else json.dumps, + inner, + ensure_ascii=st.booleans(), + indent=st.none() | st.integers(0, 16), + sort_keys=st.booleans(), + ) + + +@resolves(pydantic.ConstrainedBytes) +def resolve_conbytes(cls): # type: ignore[no-untyped-def] # pragma: no cover + min_size = cls.min_length or 0 + max_size = cls.max_length + if not cls.strip_whitespace: + return st.binary(min_size=min_size, max_size=max_size) + # Fun with regex to ensure we neither start nor end with whitespace + repeats = '{{{},{}}}'.format( + min_size - 2 if min_size > 2 else 0, + max_size - 2 if (max_size or 0) > 2 else '', + ) + if min_size >= 2: + pattern = rf'\W.{repeats}\W' + elif min_size == 1: + pattern = rf'\W(.{repeats}\W)?' + else: + assert min_size == 0 + pattern = rf'(\W(.{repeats}\W)?)?' + return st.from_regex(pattern.encode(), fullmatch=True) + + +@resolves(pydantic.ConstrainedDecimal) +def resolve_condecimal(cls): # type: ignore[no-untyped-def] + min_value = cls.ge + max_value = cls.le + if cls.gt is not None: + assert min_value is None, 'Set `gt` or `ge`, but not both' + min_value = cls.gt + if cls.lt is not None: + assert max_value is None, 'Set `lt` or `le`, but not both' + max_value = cls.lt + s = st.decimals(min_value, max_value, allow_nan=False, places=cls.decimal_places) + if cls.lt is not None: + s = s.filter(lambda d: d < cls.lt) + if cls.gt is not None: + s = s.filter(lambda d: cls.gt < d) + return s + + +@resolves(pydantic.ConstrainedFloat) +def resolve_confloat(cls): # type: ignore[no-untyped-def] + min_value = cls.ge + max_value = cls.le + exclude_min = False + exclude_max = False + + if cls.gt is not None: + assert min_value is None, 'Set `gt` or `ge`, but not both' + min_value = cls.gt + exclude_min = True + if cls.lt is not None: + assert max_value is None, 'Set `lt` or `le`, but not both' + max_value = cls.lt + exclude_max = True + + if cls.multiple_of is None: + return st.floats(min_value, max_value, exclude_min=exclude_min, exclude_max=exclude_max, allow_nan=False) + + if min_value is not None: + min_value = math.ceil(min_value / cls.multiple_of) + if exclude_min: + min_value = min_value + 1 + if max_value is not None: + assert max_value >= cls.multiple_of, 'Cannot build model with max value smaller than multiple of' + max_value = math.floor(max_value / cls.multiple_of) + if exclude_max: + max_value = max_value - 1 + + return st.integers(min_value, max_value).map(lambda x: x * cls.multiple_of) + + +@resolves(pydantic.ConstrainedInt) +def resolve_conint(cls): # type: ignore[no-untyped-def] + min_value = cls.ge + max_value = cls.le + if cls.gt is not None: + assert min_value is None, 'Set `gt` or `ge`, but not both' + min_value = cls.gt + 1 + if cls.lt is not None: + assert max_value is None, 'Set `lt` or `le`, but not both' + max_value = cls.lt - 1 + + if cls.multiple_of is None or cls.multiple_of == 1: + return st.integers(min_value, max_value) + + # These adjustments and the .map handle integer-valued multiples, while the + # .filter handles trickier cases as for confloat. + if min_value is not None: + min_value = math.ceil(Fraction(min_value) / Fraction(cls.multiple_of)) + if max_value is not None: + max_value = math.floor(Fraction(max_value) / Fraction(cls.multiple_of)) + return st.integers(min_value, max_value).map(lambda x: x * cls.multiple_of) + + +@resolves(pydantic.ConstrainedDate) +def resolve_condate(cls): # type: ignore[no-untyped-def] + if cls.ge is not None: + assert cls.gt is None, 'Set `gt` or `ge`, but not both' + min_value = cls.ge + elif cls.gt is not None: + min_value = cls.gt + datetime.timedelta(days=1) + else: + min_value = datetime.date.min + if cls.le is not None: + assert cls.lt is None, 'Set `lt` or `le`, but not both' + max_value = cls.le + elif cls.lt is not None: + max_value = cls.lt - datetime.timedelta(days=1) + else: + max_value = datetime.date.max + return st.dates(min_value, max_value) + + +@resolves(pydantic.ConstrainedStr) +def resolve_constr(cls): # type: ignore[no-untyped-def] # pragma: no cover + min_size = cls.min_length or 0 + max_size = cls.max_length + + if cls.regex is None and not cls.strip_whitespace: + return st.text(min_size=min_size, max_size=max_size) + + if cls.regex is not None: + strategy = st.from_regex(cls.regex) + if cls.strip_whitespace: + strategy = strategy.filter(lambda s: s == s.strip()) + elif cls.strip_whitespace: + repeats = '{{{},{}}}'.format( + min_size - 2 if min_size > 2 else 0, + max_size - 2 if (max_size or 0) > 2 else '', + ) + if min_size >= 2: + strategy = st.from_regex(rf'\W.{repeats}\W') + elif min_size == 1: + strategy = st.from_regex(rf'\W(.{repeats}\W)?') + else: + assert min_size == 0 + strategy = st.from_regex(rf'(\W(.{repeats}\W)?)?') + + if min_size == 0 and max_size is None: + return strategy + elif max_size is None: + return strategy.filter(lambda s: min_size <= len(s)) + return strategy.filter(lambda s: min_size <= len(s) <= max_size) + + +# Finally, register all previously-defined types, and patch in our new function +for typ in list(pydantic.types._DEFINED_TYPES): + _registered(typ) +pydantic.types._registered = _registered +st.register_type_strategy(pydantic.Json, resolve_json) diff --git a/source/target-vendors/cp312/pydantic/v1/annotated_types.py b/source/target-vendors/cp312/pydantic/v1/annotated_types.py new file mode 100644 index 0000000..d9eaaaf --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/annotated_types.py @@ -0,0 +1,72 @@ +import sys +from typing import TYPE_CHECKING, Any, Dict, FrozenSet, NamedTuple, Type + +from pydantic.v1.fields import Required +from pydantic.v1.main import BaseModel, create_model +from pydantic.v1.typing import is_typeddict, is_typeddict_special + +if TYPE_CHECKING: + from typing_extensions import TypedDict + +if sys.version_info < (3, 11): + + def is_legacy_typeddict(typeddict_cls: Type['TypedDict']) -> bool: # type: ignore[valid-type] + return is_typeddict(typeddict_cls) and type(typeddict_cls).__module__ == 'typing' + +else: + + def is_legacy_typeddict(_: Any) -> Any: + return False + + +def create_model_from_typeddict( + # Mypy bug: `Type[TypedDict]` is resolved as `Any` https://github.com/python/mypy/issues/11030 + typeddict_cls: Type['TypedDict'], # type: ignore[valid-type] + **kwargs: Any, +) -> Type['BaseModel']: + """ + Create a `BaseModel` based on the fields of a `TypedDict`. + Since `typing.TypedDict` in Python 3.8 does not store runtime information about optional keys, + we raise an error if this happens (see https://bugs.python.org/issue38834). + """ + field_definitions: Dict[str, Any] + + # Best case scenario: with python 3.9+ or when `TypedDict` is imported from `typing_extensions` + if not hasattr(typeddict_cls, '__required_keys__'): + raise TypeError( + 'You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.9.2. ' + 'Without it, there is no way to differentiate required and optional fields when subclassed.' + ) + + if is_legacy_typeddict(typeddict_cls) and any( + is_typeddict_special(t) for t in typeddict_cls.__annotations__.values() + ): + raise TypeError( + 'You should use `typing_extensions.TypedDict` instead of `typing.TypedDict` with Python < 3.11. ' + 'Without it, there is no way to reflect Required/NotRequired keys.' + ) + + required_keys: FrozenSet[str] = typeddict_cls.__required_keys__ # type: ignore[attr-defined] + field_definitions = { + field_name: (field_type, Required if field_name in required_keys else None) + for field_name, field_type in typeddict_cls.__annotations__.items() + } + + return create_model(typeddict_cls.__name__, **kwargs, **field_definitions) + + +def create_model_from_namedtuple(namedtuple_cls: Type['NamedTuple'], **kwargs: Any) -> Type['BaseModel']: + """ + Create a `BaseModel` based on the fields of a named tuple. + A named tuple can be created with `typing.NamedTuple` and declared annotations + but also with `collections.namedtuple`, in this case we consider all fields + to have type `Any`. + """ + # With python 3.10+, `__annotations__` always exists but can be empty hence the `getattr... or...` logic + namedtuple_annotations: Dict[str, Type[Any]] = getattr(namedtuple_cls, '__annotations__', None) or { + k: Any for k in namedtuple_cls._fields + } + field_definitions: Dict[str, Any] = { + field_name: (field_type, Required) for field_name, field_type in namedtuple_annotations.items() + } + return create_model(namedtuple_cls.__name__, **kwargs, **field_definitions) diff --git a/source/target-vendors/cp312/pydantic/v1/class_validators.py b/source/target-vendors/cp312/pydantic/v1/class_validators.py new file mode 100644 index 0000000..2f68fc8 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/class_validators.py @@ -0,0 +1,361 @@ +import warnings +from collections import ChainMap +from functools import partial, partialmethod, wraps +from itertools import chain +from types import FunctionType +from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Type, Union, overload + +from pydantic.v1.errors import ConfigError +from pydantic.v1.typing import AnyCallable +from pydantic.v1.utils import ROOT_KEY, in_ipython + +if TYPE_CHECKING: + from pydantic.v1.typing import AnyClassMethod + + +class Validator: + __slots__ = 'func', 'pre', 'each_item', 'always', 'check_fields', 'skip_on_failure' + + def __init__( + self, + func: AnyCallable, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool = False, + skip_on_failure: bool = False, + ): + self.func = func + self.pre = pre + self.each_item = each_item + self.always = always + self.check_fields = check_fields + self.skip_on_failure = skip_on_failure + + +if TYPE_CHECKING: + from inspect import Signature + + from pydantic.v1.config import BaseConfig + from pydantic.v1.fields import ModelField + from pydantic.v1.types import ModelOrDc + + ValidatorCallable = Callable[[Optional[ModelOrDc], Any, Dict[str, Any], ModelField, Type[BaseConfig]], Any] + ValidatorsList = List[ValidatorCallable] + ValidatorListDict = Dict[str, List[Validator]] + +_FUNCS: Set[str] = set() +VALIDATOR_CONFIG_KEY = '__validator_config__' +ROOT_VALIDATOR_CONFIG_KEY = '__root_validator_config__' + + +def validator( + *fields: str, + pre: bool = False, + each_item: bool = False, + always: bool = False, + check_fields: bool = True, + whole: Optional[bool] = None, + allow_reuse: bool = False, +) -> Callable[[AnyCallable], 'AnyClassMethod']: + """ + Decorate methods on the class indicating that they should be used to validate fields + :param fields: which field(s) the method should be called on + :param pre: whether or not this validator should be called before the standard validators (else after) + :param each_item: for complex objects (sets, lists etc.) whether to validate individual elements rather than the + whole object + :param always: whether this method and other validators should be called even if the value is missing + :param check_fields: whether to check that the fields actually exist on the model + :param allow_reuse: whether to track and raise an error if another validator refers to the decorated function + """ + if not fields: + raise ConfigError('validator with no fields specified') + elif isinstance(fields[0], FunctionType): + raise ConfigError( + "validators should be used with fields and keyword arguments, not bare. " # noqa: Q000 + "E.g. usage should be `@validator('', ...)`" + ) + elif not all(isinstance(field, str) for field in fields): + raise ConfigError( + "validator fields should be passed as separate string args. " # noqa: Q000 + "E.g. usage should be `@validator('', '', ...)`" + ) + + if whole is not None: + warnings.warn( + 'The "whole" keyword argument is deprecated, use "each_item" (inverse meaning, default False) instead', + DeprecationWarning, + ) + assert each_item is False, '"each_item" and "whole" conflict, remove "whole"' + each_item = not whole + + def dec(f: AnyCallable) -> 'AnyClassMethod': + f_cls = _prepare_validator(f, allow_reuse) + setattr( + f_cls, + VALIDATOR_CONFIG_KEY, + ( + fields, + Validator(func=f_cls.__func__, pre=pre, each_item=each_item, always=always, check_fields=check_fields), + ), + ) + return f_cls + + return dec + + +@overload +def root_validator(_func: AnyCallable) -> 'AnyClassMethod': + ... + + +@overload +def root_validator( + *, pre: bool = False, allow_reuse: bool = False, skip_on_failure: bool = False +) -> Callable[[AnyCallable], 'AnyClassMethod']: + ... + + +def root_validator( + _func: Optional[AnyCallable] = None, *, pre: bool = False, allow_reuse: bool = False, skip_on_failure: bool = False +) -> Union['AnyClassMethod', Callable[[AnyCallable], 'AnyClassMethod']]: + """ + Decorate methods on a model indicating that they should be used to validate (and perhaps modify) data either + before or after standard model parsing/validation is performed. + """ + if _func: + f_cls = _prepare_validator(_func, allow_reuse) + setattr( + f_cls, ROOT_VALIDATOR_CONFIG_KEY, Validator(func=f_cls.__func__, pre=pre, skip_on_failure=skip_on_failure) + ) + return f_cls + + def dec(f: AnyCallable) -> 'AnyClassMethod': + f_cls = _prepare_validator(f, allow_reuse) + setattr( + f_cls, ROOT_VALIDATOR_CONFIG_KEY, Validator(func=f_cls.__func__, pre=pre, skip_on_failure=skip_on_failure) + ) + return f_cls + + return dec + + +def _prepare_validator(function: AnyCallable, allow_reuse: bool) -> 'AnyClassMethod': + """ + Avoid validators with duplicated names since without this, validators can be overwritten silently + which generally isn't the intended behaviour, don't run in ipython (see #312) or if allow_reuse is False. + """ + f_cls = function if isinstance(function, classmethod) else classmethod(function) + if not in_ipython() and not allow_reuse: + ref = ( + getattr(f_cls.__func__, '__module__', '') + + '.' + + getattr(f_cls.__func__, '__qualname__', f'') + ) + if ref in _FUNCS: + raise ConfigError(f'duplicate validator function "{ref}"; if this is intended, set `allow_reuse=True`') + _FUNCS.add(ref) + return f_cls + + +class ValidatorGroup: + def __init__(self, validators: 'ValidatorListDict') -> None: + self.validators = validators + self.used_validators = {'*'} + + def get_validators(self, name: str) -> Optional[Dict[str, Validator]]: + self.used_validators.add(name) + validators = self.validators.get(name, []) + if name != ROOT_KEY: + validators += self.validators.get('*', []) + if validators: + return {getattr(v.func, '__name__', f''): v for v in validators} + else: + return None + + def check_for_unused(self) -> None: + unused_validators = set( + chain.from_iterable( + ( + getattr(v.func, '__name__', f'') + for v in self.validators[f] + if v.check_fields + ) + for f in (self.validators.keys() - self.used_validators) + ) + ) + if unused_validators: + fn = ', '.join(unused_validators) + raise ConfigError( + f"Validators defined with incorrect fields: {fn} " # noqa: Q000 + f"(use check_fields=False if you're inheriting from the model and intended this)" + ) + + +def extract_validators(namespace: Dict[str, Any]) -> Dict[str, List[Validator]]: + validators: Dict[str, List[Validator]] = {} + for var_name, value in namespace.items(): + validator_config = getattr(value, VALIDATOR_CONFIG_KEY, None) + if validator_config: + fields, v = validator_config + for field in fields: + if field in validators: + validators[field].append(v) + else: + validators[field] = [v] + return validators + + +def extract_root_validators(namespace: Dict[str, Any]) -> Tuple[List[AnyCallable], List[Tuple[bool, AnyCallable]]]: + from inspect import signature + + pre_validators: List[AnyCallable] = [] + post_validators: List[Tuple[bool, AnyCallable]] = [] + for name, value in namespace.items(): + validator_config: Optional[Validator] = getattr(value, ROOT_VALIDATOR_CONFIG_KEY, None) + if validator_config: + sig = signature(validator_config.func) + args = list(sig.parameters.keys()) + if args[0] == 'self': + raise ConfigError( + f'Invalid signature for root validator {name}: {sig}, "self" not permitted as first argument, ' + f'should be: (cls, values).' + ) + if len(args) != 2: + raise ConfigError(f'Invalid signature for root validator {name}: {sig}, should be: (cls, values).') + # check function signature + if validator_config.pre: + pre_validators.append(validator_config.func) + else: + post_validators.append((validator_config.skip_on_failure, validator_config.func)) + return pre_validators, post_validators + + +def inherit_validators(base_validators: 'ValidatorListDict', validators: 'ValidatorListDict') -> 'ValidatorListDict': + for field, field_validators in base_validators.items(): + if field not in validators: + validators[field] = [] + validators[field] += field_validators + return validators + + +def make_generic_validator(validator: AnyCallable) -> 'ValidatorCallable': + """ + Make a generic function which calls a validator with the right arguments. + + Unfortunately other approaches (eg. return a partial of a function that builds the arguments) is slow, + hence this laborious way of doing things. + + It's done like this so validators don't all need **kwargs in their signature, eg. any combination of + the arguments "values", "fields" and/or "config" are permitted. + """ + from inspect import signature + + if not isinstance(validator, (partial, partialmethod)): + # This should be the default case, so overhead is reduced + sig = signature(validator) + args = list(sig.parameters.keys()) + else: + # Fix the generated argument lists of partial methods + sig = signature(validator.func) + args = [ + k + for k in signature(validator.func).parameters.keys() + if k not in validator.args | validator.keywords.keys() + ] + + first_arg = args.pop(0) + if first_arg == 'self': + raise ConfigError( + f'Invalid signature for validator {validator}: {sig}, "self" not permitted as first argument, ' + f'should be: (cls, value, values, config, field), "values", "config" and "field" are all optional.' + ) + elif first_arg == 'cls': + # assume the second argument is value + return wraps(validator)(_generic_validator_cls(validator, sig, set(args[1:]))) + else: + # assume the first argument was value which has already been removed + return wraps(validator)(_generic_validator_basic(validator, sig, set(args))) + + +def prep_validators(v_funcs: Iterable[AnyCallable]) -> 'ValidatorsList': + return [make_generic_validator(f) for f in v_funcs if f] + + +all_kwargs = {'values', 'field', 'config'} + + +def _generic_validator_cls(validator: AnyCallable, sig: 'Signature', args: Set[str]) -> 'ValidatorCallable': + # assume the first argument is value + has_kwargs = False + if 'kwargs' in args: + has_kwargs = True + args -= {'kwargs'} + + if not args.issubset(all_kwargs): + raise ConfigError( + f'Invalid signature for validator {validator}: {sig}, should be: ' + f'(cls, value, values, config, field), "values", "config" and "field" are all optional.' + ) + + if has_kwargs: + return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field, config=config) + elif args == set(): + return lambda cls, v, values, field, config: validator(cls, v) + elif args == {'values'}: + return lambda cls, v, values, field, config: validator(cls, v, values=values) + elif args == {'field'}: + return lambda cls, v, values, field, config: validator(cls, v, field=field) + elif args == {'config'}: + return lambda cls, v, values, field, config: validator(cls, v, config=config) + elif args == {'values', 'field'}: + return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field) + elif args == {'values', 'config'}: + return lambda cls, v, values, field, config: validator(cls, v, values=values, config=config) + elif args == {'field', 'config'}: + return lambda cls, v, values, field, config: validator(cls, v, field=field, config=config) + else: + # args == {'values', 'field', 'config'} + return lambda cls, v, values, field, config: validator(cls, v, values=values, field=field, config=config) + + +def _generic_validator_basic(validator: AnyCallable, sig: 'Signature', args: Set[str]) -> 'ValidatorCallable': + has_kwargs = False + if 'kwargs' in args: + has_kwargs = True + args -= {'kwargs'} + + if not args.issubset(all_kwargs): + raise ConfigError( + f'Invalid signature for validator {validator}: {sig}, should be: ' + f'(value, values, config, field), "values", "config" and "field" are all optional.' + ) + + if has_kwargs: + return lambda cls, v, values, field, config: validator(v, values=values, field=field, config=config) + elif args == set(): + return lambda cls, v, values, field, config: validator(v) + elif args == {'values'}: + return lambda cls, v, values, field, config: validator(v, values=values) + elif args == {'field'}: + return lambda cls, v, values, field, config: validator(v, field=field) + elif args == {'config'}: + return lambda cls, v, values, field, config: validator(v, config=config) + elif args == {'values', 'field'}: + return lambda cls, v, values, field, config: validator(v, values=values, field=field) + elif args == {'values', 'config'}: + return lambda cls, v, values, field, config: validator(v, values=values, config=config) + elif args == {'field', 'config'}: + return lambda cls, v, values, field, config: validator(v, field=field, config=config) + else: + # args == {'values', 'field', 'config'} + return lambda cls, v, values, field, config: validator(v, values=values, field=field, config=config) + + +def gather_all_validators(type_: 'ModelOrDc') -> Dict[str, 'AnyClassMethod']: + all_attributes = ChainMap(*[cls.__dict__ for cls in type_.__mro__]) # type: ignore[arg-type,var-annotated] + return { + k: v + for k, v in all_attributes.items() + if hasattr(v, VALIDATOR_CONFIG_KEY) or hasattr(v, ROOT_VALIDATOR_CONFIG_KEY) + } diff --git a/source/target-vendors/cp312/pydantic/v1/color.py b/source/target-vendors/cp312/pydantic/v1/color.py new file mode 100644 index 0000000..b0bbf78 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/color.py @@ -0,0 +1,494 @@ +""" +Color definitions are used as per CSS3 specification: +http://www.w3.org/TR/css3-color/#svg-color + +A few colors have multiple names referring to the sames colors, eg. `grey` and `gray` or `aqua` and `cyan`. + +In these cases the LAST color when sorted alphabetically takes preferences, +eg. Color((0, 255, 255)).as_named() == 'cyan' because "cyan" comes after "aqua". +""" +import math +import re +from colorsys import hls_to_rgb, rgb_to_hls +from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union, cast + +from pydantic.v1.errors import ColorError +from pydantic.v1.utils import Representation, almost_equal_floats + +if TYPE_CHECKING: + from pydantic.v1.typing import CallableGenerator, ReprArgs + +ColorTuple = Union[Tuple[int, int, int], Tuple[int, int, int, float]] +ColorType = Union[ColorTuple, str] +HslColorTuple = Union[Tuple[float, float, float], Tuple[float, float, float, float]] + + +class RGBA: + """ + Internal use only as a representation of a color. + """ + + __slots__ = 'r', 'g', 'b', 'alpha', '_tuple' + + def __init__(self, r: float, g: float, b: float, alpha: Optional[float]): + self.r = r + self.g = g + self.b = b + self.alpha = alpha + + self._tuple: Tuple[float, float, float, Optional[float]] = (r, g, b, alpha) + + def __getitem__(self, item: Any) -> Any: + return self._tuple[item] + + +# these are not compiled here to avoid import slowdown, they'll be compiled the first time they're used, then cached +r_hex_short = r'\s*(?:#|0x)?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?\s*' +r_hex_long = r'\s*(?:#|0x)?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?\s*' +_r_255 = r'(\d{1,3}(?:\.\d+)?)' +_r_comma = r'\s*,\s*' +r_rgb = fr'\s*rgb\(\s*{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_255}\)\s*' +_r_alpha = r'(\d(?:\.\d+)?|\.\d+|\d{1,2}%)' +r_rgba = fr'\s*rgba\(\s*{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_255}{_r_comma}{_r_alpha}\s*\)\s*' +_r_h = r'(-?\d+(?:\.\d+)?|-?\.\d+)(deg|rad|turn)?' +_r_sl = r'(\d{1,3}(?:\.\d+)?)%' +r_hsl = fr'\s*hsl\(\s*{_r_h}{_r_comma}{_r_sl}{_r_comma}{_r_sl}\s*\)\s*' +r_hsla = fr'\s*hsl\(\s*{_r_h}{_r_comma}{_r_sl}{_r_comma}{_r_sl}{_r_comma}{_r_alpha}\s*\)\s*' + +# colors where the two hex characters are the same, if all colors match this the short version of hex colors can be used +repeat_colors = {int(c * 2, 16) for c in '0123456789abcdef'} +rads = 2 * math.pi + + +class Color(Representation): + __slots__ = '_original', '_rgba' + + def __init__(self, value: ColorType) -> None: + self._rgba: RGBA + self._original: ColorType + if isinstance(value, (tuple, list)): + self._rgba = parse_tuple(value) + elif isinstance(value, str): + self._rgba = parse_str(value) + elif isinstance(value, Color): + self._rgba = value._rgba + value = value._original + else: + raise ColorError(reason='value must be a tuple, list or string') + + # if we've got here value must be a valid color + self._original = value + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='color') + + def original(self) -> ColorType: + """ + Original value passed to Color + """ + return self._original + + def as_named(self, *, fallback: bool = False) -> str: + if self._rgba.alpha is None: + rgb = cast(Tuple[int, int, int], self.as_rgb_tuple()) + try: + return COLORS_BY_VALUE[rgb] + except KeyError as e: + if fallback: + return self.as_hex() + else: + raise ValueError('no named color found, use fallback=True, as_hex() or as_rgb()') from e + else: + return self.as_hex() + + def as_hex(self) -> str: + """ + Hex string representing the color can be 3, 4, 6 or 8 characters depending on whether the string + a "short" representation of the color is possible and whether there's an alpha channel. + """ + values = [float_to_255(c) for c in self._rgba[:3]] + if self._rgba.alpha is not None: + values.append(float_to_255(self._rgba.alpha)) + + as_hex = ''.join(f'{v:02x}' for v in values) + if all(c in repeat_colors for c in values): + as_hex = ''.join(as_hex[c] for c in range(0, len(as_hex), 2)) + return '#' + as_hex + + def as_rgb(self) -> str: + """ + Color as an rgb(, , ) or rgba(, , , ) string. + """ + if self._rgba.alpha is None: + return f'rgb({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)})' + else: + return ( + f'rgba({float_to_255(self._rgba.r)}, {float_to_255(self._rgba.g)}, {float_to_255(self._rgba.b)}, ' + f'{round(self._alpha_float(), 2)})' + ) + + def as_rgb_tuple(self, *, alpha: Optional[bool] = None) -> ColorTuple: + """ + Color as an RGB or RGBA tuple; red, green and blue are in the range 0 to 255, alpha if included is + in the range 0 to 1. + + :param alpha: whether to include the alpha channel, options are + None - (default) include alpha only if it's set (e.g. not None) + True - always include alpha, + False - always omit alpha, + """ + r, g, b = (float_to_255(c) for c in self._rgba[:3]) + if alpha is None: + if self._rgba.alpha is None: + return r, g, b + else: + return r, g, b, self._alpha_float() + elif alpha: + return r, g, b, self._alpha_float() + else: + # alpha is False + return r, g, b + + def as_hsl(self) -> str: + """ + Color as an hsl(, , ) or hsl(, , , ) string. + """ + if self._rgba.alpha is None: + h, s, li = self.as_hsl_tuple(alpha=False) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%})' + else: + h, s, li, a = self.as_hsl_tuple(alpha=True) # type: ignore + return f'hsl({h * 360:0.0f}, {s:0.0%}, {li:0.0%}, {round(a, 2)})' + + def as_hsl_tuple(self, *, alpha: Optional[bool] = None) -> HslColorTuple: + """ + Color as an HSL or HSLA tuple, e.g. hue, saturation, lightness and optionally alpha; all elements are in + the range 0 to 1. + + NOTE: this is HSL as used in HTML and most other places, not HLS as used in python's colorsys. + + :param alpha: whether to include the alpha channel, options are + None - (default) include alpha only if it's set (e.g. not None) + True - always include alpha, + False - always omit alpha, + """ + h, l, s = rgb_to_hls(self._rgba.r, self._rgba.g, self._rgba.b) + if alpha is None: + if self._rgba.alpha is None: + return h, s, l + else: + return h, s, l, self._alpha_float() + if alpha: + return h, s, l, self._alpha_float() + else: + # alpha is False + return h, s, l + + def _alpha_float(self) -> float: + return 1 if self._rgba.alpha is None else self._rgba.alpha + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls + + def __str__(self) -> str: + return self.as_named(fallback=True) + + def __repr_args__(self) -> 'ReprArgs': + return [(None, self.as_named(fallback=True))] + [('rgb', self.as_rgb_tuple())] # type: ignore + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Color) and self.as_rgb_tuple() == other.as_rgb_tuple() + + def __hash__(self) -> int: + return hash(self.as_rgb_tuple()) + + +def parse_tuple(value: Tuple[Any, ...]) -> RGBA: + """ + Parse a tuple or list as a color. + """ + if len(value) == 3: + r, g, b = (parse_color_value(v) for v in value) + return RGBA(r, g, b, None) + elif len(value) == 4: + r, g, b = (parse_color_value(v) for v in value[:3]) + return RGBA(r, g, b, parse_float_alpha(value[3])) + else: + raise ColorError(reason='tuples must have length 3 or 4') + + +def parse_str(value: str) -> RGBA: + """ + Parse a string to an RGBA tuple, trying the following formats (in this order): + * named color, see COLORS_BY_NAME below + * hex short eg. `fff` (prefix can be `#`, `0x` or nothing) + * hex long eg. `ffffff` (prefix can be `#`, `0x` or nothing) + * `rgb(, , ) ` + * `rgba(, , , )` + """ + value_lower = value.lower() + try: + r, g, b = COLORS_BY_NAME[value_lower] + except KeyError: + pass + else: + return ints_to_rgba(r, g, b, None) + + m = re.fullmatch(r_hex_short, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v * 2, 16) for v in rgb) + if a: + alpha: Optional[float] = int(a * 2, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_hex_long, value_lower) + if m: + *rgb, a = m.groups() + r, g, b = (int(v, 16) for v in rgb) + if a: + alpha = int(a, 16) / 255 + else: + alpha = None + return ints_to_rgba(r, g, b, alpha) + + m = re.fullmatch(r_rgb, value_lower) + if m: + return ints_to_rgba(*m.groups(), None) # type: ignore + + m = re.fullmatch(r_rgba, value_lower) + if m: + return ints_to_rgba(*m.groups()) # type: ignore + + m = re.fullmatch(r_hsl, value_lower) + if m: + h, h_units, s, l_ = m.groups() + return parse_hsl(h, h_units, s, l_) + + m = re.fullmatch(r_hsla, value_lower) + if m: + h, h_units, s, l_, a = m.groups() + return parse_hsl(h, h_units, s, l_, parse_float_alpha(a)) + + raise ColorError(reason='string not recognised as a valid color') + + +def ints_to_rgba(r: Union[int, str], g: Union[int, str], b: Union[int, str], alpha: Optional[float]) -> RGBA: + return RGBA(parse_color_value(r), parse_color_value(g), parse_color_value(b), parse_float_alpha(alpha)) + + +def parse_color_value(value: Union[int, str], max_val: int = 255) -> float: + """ + Parse a value checking it's a valid int in the range 0 to max_val and divide by max_val to give a number + in the range 0 to 1 + """ + try: + color = float(value) + except ValueError: + raise ColorError(reason='color values must be a valid number') + if 0 <= color <= max_val: + return color / max_val + else: + raise ColorError(reason=f'color values must be in the range 0 to {max_val}') + + +def parse_float_alpha(value: Union[None, str, float, int]) -> Optional[float]: + """ + Parse a value checking it's a valid float in the range 0 to 1 + """ + if value is None: + return None + try: + if isinstance(value, str) and value.endswith('%'): + alpha = float(value[:-1]) / 100 + else: + alpha = float(value) + except ValueError: + raise ColorError(reason='alpha values must be a valid float') + + if almost_equal_floats(alpha, 1): + return None + elif 0 <= alpha <= 1: + return alpha + else: + raise ColorError(reason='alpha values must be in the range 0 to 1') + + +def parse_hsl(h: str, h_units: str, sat: str, light: str, alpha: Optional[float] = None) -> RGBA: + """ + Parse raw hue, saturation, lightness and alpha values and convert to RGBA. + """ + s_value, l_value = parse_color_value(sat, 100), parse_color_value(light, 100) + + h_value = float(h) + if h_units in {None, 'deg'}: + h_value = h_value % 360 / 360 + elif h_units == 'rad': + h_value = h_value % rads / rads + else: + # turns + h_value = h_value % 1 + + r, g, b = hls_to_rgb(h_value, l_value, s_value) + return RGBA(r, g, b, alpha) + + +def float_to_255(c: float) -> int: + return int(round(c * 255)) + + +COLORS_BY_NAME = { + 'aliceblue': (240, 248, 255), + 'antiquewhite': (250, 235, 215), + 'aqua': (0, 255, 255), + 'aquamarine': (127, 255, 212), + 'azure': (240, 255, 255), + 'beige': (245, 245, 220), + 'bisque': (255, 228, 196), + 'black': (0, 0, 0), + 'blanchedalmond': (255, 235, 205), + 'blue': (0, 0, 255), + 'blueviolet': (138, 43, 226), + 'brown': (165, 42, 42), + 'burlywood': (222, 184, 135), + 'cadetblue': (95, 158, 160), + 'chartreuse': (127, 255, 0), + 'chocolate': (210, 105, 30), + 'coral': (255, 127, 80), + 'cornflowerblue': (100, 149, 237), + 'cornsilk': (255, 248, 220), + 'crimson': (220, 20, 60), + 'cyan': (0, 255, 255), + 'darkblue': (0, 0, 139), + 'darkcyan': (0, 139, 139), + 'darkgoldenrod': (184, 134, 11), + 'darkgray': (169, 169, 169), + 'darkgreen': (0, 100, 0), + 'darkgrey': (169, 169, 169), + 'darkkhaki': (189, 183, 107), + 'darkmagenta': (139, 0, 139), + 'darkolivegreen': (85, 107, 47), + 'darkorange': (255, 140, 0), + 'darkorchid': (153, 50, 204), + 'darkred': (139, 0, 0), + 'darksalmon': (233, 150, 122), + 'darkseagreen': (143, 188, 143), + 'darkslateblue': (72, 61, 139), + 'darkslategray': (47, 79, 79), + 'darkslategrey': (47, 79, 79), + 'darkturquoise': (0, 206, 209), + 'darkviolet': (148, 0, 211), + 'deeppink': (255, 20, 147), + 'deepskyblue': (0, 191, 255), + 'dimgray': (105, 105, 105), + 'dimgrey': (105, 105, 105), + 'dodgerblue': (30, 144, 255), + 'firebrick': (178, 34, 34), + 'floralwhite': (255, 250, 240), + 'forestgreen': (34, 139, 34), + 'fuchsia': (255, 0, 255), + 'gainsboro': (220, 220, 220), + 'ghostwhite': (248, 248, 255), + 'gold': (255, 215, 0), + 'goldenrod': (218, 165, 32), + 'gray': (128, 128, 128), + 'green': (0, 128, 0), + 'greenyellow': (173, 255, 47), + 'grey': (128, 128, 128), + 'honeydew': (240, 255, 240), + 'hotpink': (255, 105, 180), + 'indianred': (205, 92, 92), + 'indigo': (75, 0, 130), + 'ivory': (255, 255, 240), + 'khaki': (240, 230, 140), + 'lavender': (230, 230, 250), + 'lavenderblush': (255, 240, 245), + 'lawngreen': (124, 252, 0), + 'lemonchiffon': (255, 250, 205), + 'lightblue': (173, 216, 230), + 'lightcoral': (240, 128, 128), + 'lightcyan': (224, 255, 255), + 'lightgoldenrodyellow': (250, 250, 210), + 'lightgray': (211, 211, 211), + 'lightgreen': (144, 238, 144), + 'lightgrey': (211, 211, 211), + 'lightpink': (255, 182, 193), + 'lightsalmon': (255, 160, 122), + 'lightseagreen': (32, 178, 170), + 'lightskyblue': (135, 206, 250), + 'lightslategray': (119, 136, 153), + 'lightslategrey': (119, 136, 153), + 'lightsteelblue': (176, 196, 222), + 'lightyellow': (255, 255, 224), + 'lime': (0, 255, 0), + 'limegreen': (50, 205, 50), + 'linen': (250, 240, 230), + 'magenta': (255, 0, 255), + 'maroon': (128, 0, 0), + 'mediumaquamarine': (102, 205, 170), + 'mediumblue': (0, 0, 205), + 'mediumorchid': (186, 85, 211), + 'mediumpurple': (147, 112, 219), + 'mediumseagreen': (60, 179, 113), + 'mediumslateblue': (123, 104, 238), + 'mediumspringgreen': (0, 250, 154), + 'mediumturquoise': (72, 209, 204), + 'mediumvioletred': (199, 21, 133), + 'midnightblue': (25, 25, 112), + 'mintcream': (245, 255, 250), + 'mistyrose': (255, 228, 225), + 'moccasin': (255, 228, 181), + 'navajowhite': (255, 222, 173), + 'navy': (0, 0, 128), + 'oldlace': (253, 245, 230), + 'olive': (128, 128, 0), + 'olivedrab': (107, 142, 35), + 'orange': (255, 165, 0), + 'orangered': (255, 69, 0), + 'orchid': (218, 112, 214), + 'palegoldenrod': (238, 232, 170), + 'palegreen': (152, 251, 152), + 'paleturquoise': (175, 238, 238), + 'palevioletred': (219, 112, 147), + 'papayawhip': (255, 239, 213), + 'peachpuff': (255, 218, 185), + 'peru': (205, 133, 63), + 'pink': (255, 192, 203), + 'plum': (221, 160, 221), + 'powderblue': (176, 224, 230), + 'purple': (128, 0, 128), + 'red': (255, 0, 0), + 'rosybrown': (188, 143, 143), + 'royalblue': (65, 105, 225), + 'saddlebrown': (139, 69, 19), + 'salmon': (250, 128, 114), + 'sandybrown': (244, 164, 96), + 'seagreen': (46, 139, 87), + 'seashell': (255, 245, 238), + 'sienna': (160, 82, 45), + 'silver': (192, 192, 192), + 'skyblue': (135, 206, 235), + 'slateblue': (106, 90, 205), + 'slategray': (112, 128, 144), + 'slategrey': (112, 128, 144), + 'snow': (255, 250, 250), + 'springgreen': (0, 255, 127), + 'steelblue': (70, 130, 180), + 'tan': (210, 180, 140), + 'teal': (0, 128, 128), + 'thistle': (216, 191, 216), + 'tomato': (255, 99, 71), + 'turquoise': (64, 224, 208), + 'violet': (238, 130, 238), + 'wheat': (245, 222, 179), + 'white': (255, 255, 255), + 'whitesmoke': (245, 245, 245), + 'yellow': (255, 255, 0), + 'yellowgreen': (154, 205, 50), +} + +COLORS_BY_VALUE = {v: k for k, v in COLORS_BY_NAME.items()} diff --git a/source/target-vendors/cp312/pydantic/v1/config.py b/source/target-vendors/cp312/pydantic/v1/config.py new file mode 100644 index 0000000..18f7c99 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/config.py @@ -0,0 +1,191 @@ +import json +from enum import Enum +from typing import TYPE_CHECKING, Any, Callable, Dict, ForwardRef, Optional, Tuple, Type, Union + +from typing_extensions import Literal, Protocol + +from pydantic.v1.typing import AnyArgTCallable, AnyCallable +from pydantic.v1.utils import GetterDict +from pydantic.v1.version import compiled + +if TYPE_CHECKING: + from typing import overload + + from pydantic.v1.fields import ModelField + from pydantic.v1.main import BaseModel + + ConfigType = Type['BaseConfig'] + + class SchemaExtraCallable(Protocol): + @overload + def __call__(self, schema: Dict[str, Any]) -> None: + pass + + @overload + def __call__(self, schema: Dict[str, Any], model_class: Type[BaseModel]) -> None: + pass + +else: + SchemaExtraCallable = Callable[..., None] + +__all__ = 'BaseConfig', 'ConfigDict', 'get_config', 'Extra', 'inherit_config', 'prepare_config' + + +class Extra(str, Enum): + allow = 'allow' + ignore = 'ignore' + forbid = 'forbid' + + +# https://github.com/cython/cython/issues/4003 +# Fixed in Cython 3 and Pydantic v1 won't support Cython 3. +# Pydantic v2 doesn't depend on Cython at all. +if not compiled: + from typing_extensions import TypedDict + + class ConfigDict(TypedDict, total=False): + title: Optional[str] + anystr_lower: bool + anystr_strip_whitespace: bool + min_anystr_length: int + max_anystr_length: Optional[int] + validate_all: bool + extra: Extra + allow_mutation: bool + frozen: bool + allow_population_by_field_name: bool + use_enum_values: bool + fields: Dict[str, Union[str, Dict[str, str]]] + validate_assignment: bool + error_msg_templates: Dict[str, str] + arbitrary_types_allowed: bool + orm_mode: bool + getter_dict: Type[GetterDict] + alias_generator: Optional[Callable[[str], str]] + keep_untouched: Tuple[type, ...] + schema_extra: Union[Dict[str, object], 'SchemaExtraCallable'] + json_loads: Callable[[str], object] + json_dumps: AnyArgTCallable[str] + json_encoders: Dict[Type[object], AnyCallable] + underscore_attrs_are_private: bool + allow_inf_nan: bool + copy_on_model_validation: Literal['none', 'deep', 'shallow'] + # whether dataclass `__post_init__` should be run after validation + post_init_call: Literal['before_validation', 'after_validation'] + +else: + ConfigDict = dict # type: ignore + + +class BaseConfig: + title: Optional[str] = None + anystr_lower: bool = False + anystr_upper: bool = False + anystr_strip_whitespace: bool = False + min_anystr_length: int = 0 + max_anystr_length: Optional[int] = None + validate_all: bool = False + extra: Extra = Extra.ignore + allow_mutation: bool = True + frozen: bool = False + allow_population_by_field_name: bool = False + use_enum_values: bool = False + fields: Dict[str, Union[str, Dict[str, str]]] = {} + validate_assignment: bool = False + error_msg_templates: Dict[str, str] = {} + arbitrary_types_allowed: bool = False + orm_mode: bool = False + getter_dict: Type[GetterDict] = GetterDict + alias_generator: Optional[Callable[[str], str]] = None + keep_untouched: Tuple[type, ...] = () + schema_extra: Union[Dict[str, Any], 'SchemaExtraCallable'] = {} + json_loads: Callable[[str], Any] = json.loads + json_dumps: Callable[..., str] = json.dumps + json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable] = {} + underscore_attrs_are_private: bool = False + allow_inf_nan: bool = True + + # whether inherited models as fields should be reconstructed as base model, + # and whether such a copy should be shallow or deep + copy_on_model_validation: Literal['none', 'deep', 'shallow'] = 'shallow' + + # whether `Union` should check all allowed types before even trying to coerce + smart_union: bool = False + # whether dataclass `__post_init__` should be run before or after validation + post_init_call: Literal['before_validation', 'after_validation'] = 'before_validation' + + @classmethod + def get_field_info(cls, name: str) -> Dict[str, Any]: + """ + Get properties of FieldInfo from the `fields` property of the config class. + """ + + fields_value = cls.fields.get(name) + + if isinstance(fields_value, str): + field_info: Dict[str, Any] = {'alias': fields_value} + elif isinstance(fields_value, dict): + field_info = fields_value + else: + field_info = {} + + if 'alias' in field_info: + field_info.setdefault('alias_priority', 2) + + if field_info.get('alias_priority', 0) <= 1 and cls.alias_generator: + alias = cls.alias_generator(name) + if not isinstance(alias, str): + raise TypeError(f'Config.alias_generator must return str, not {alias.__class__}') + field_info.update(alias=alias, alias_priority=1) + return field_info + + @classmethod + def prepare_field(cls, field: 'ModelField') -> None: + """ + Optional hook to check or modify fields during model creation. + """ + pass + + +def get_config(config: Union[ConfigDict, Type[object], None]) -> Type[BaseConfig]: + if config is None: + return BaseConfig + + else: + config_dict = ( + config + if isinstance(config, dict) + else {k: getattr(config, k) for k in dir(config) if not k.startswith('__')} + ) + + class Config(BaseConfig): + ... + + for k, v in config_dict.items(): + setattr(Config, k, v) + return Config + + +def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType': + if not self_config: + base_classes: Tuple['ConfigType', ...] = (parent_config,) + elif self_config == parent_config: + base_classes = (self_config,) + else: + base_classes = self_config, parent_config + + namespace['json_encoders'] = { + **getattr(parent_config, 'json_encoders', {}), + **getattr(self_config, 'json_encoders', {}), + **namespace.get('json_encoders', {}), + } + + return type('Config', base_classes, namespace) + + +def prepare_config(config: Type[BaseConfig], cls_name: str) -> None: + if not isinstance(config.extra, Extra): + try: + config.extra = Extra(config.extra) + except ValueError: + raise ValueError(f'"{cls_name}": {config.extra} is not a valid value for "extra"') diff --git a/source/target-vendors/cp312/pydantic/v1/dataclasses.py b/source/target-vendors/cp312/pydantic/v1/dataclasses.py new file mode 100644 index 0000000..bd16702 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/dataclasses.py @@ -0,0 +1,500 @@ +""" +The main purpose is to enhance stdlib dataclasses by adding validation +A pydantic dataclass can be generated from scratch or from a stdlib one. + +Behind the scene, a pydantic dataclass is just like a regular one on which we attach +a `BaseModel` and magic methods to trigger the validation of the data. +`__init__` and `__post_init__` are hence overridden and have extra logic to be +able to validate input data. + +When a pydantic dataclass is generated from scratch, it's just a plain dataclass +with validation triggered at initialization + +The tricky part if for stdlib dataclasses that are converted after into pydantic ones e.g. + +```py +@dataclasses.dataclass +class M: + x: int + +ValidatedM = pydantic.dataclasses.dataclass(M) +``` + +We indeed still want to support equality, hashing, repr, ... as if it was the stdlib one! + +```py +assert isinstance(ValidatedM(x=1), M) +assert ValidatedM(x=1) == M(x=1) +``` + +This means we **don't want to create a new dataclass that inherits from it** +The trick is to create a wrapper around `M` that will act as a proxy to trigger +validation without altering default `M` behaviour. +""" +import copy +import dataclasses +import sys +from contextlib import contextmanager +from functools import wraps + +try: + from functools import cached_property +except ImportError: + # cached_property available only for python3.8+ + pass + +from typing import TYPE_CHECKING, Any, Callable, ClassVar, Dict, Generator, Optional, Type, TypeVar, Union, overload + +from typing_extensions import dataclass_transform + +from pydantic.v1.class_validators import gather_all_validators +from pydantic.v1.config import BaseConfig, ConfigDict, Extra, get_config +from pydantic.v1.error_wrappers import ValidationError +from pydantic.v1.errors import DataclassTypeError +from pydantic.v1.fields import Field, FieldInfo, Required, Undefined +from pydantic.v1.main import create_model, validate_model +from pydantic.v1.utils import ClassAttribute + +if TYPE_CHECKING: + from pydantic.v1.main import BaseModel + from pydantic.v1.typing import CallableGenerator, NoArgAnyCallable + + DataclassT = TypeVar('DataclassT', bound='Dataclass') + + DataclassClassOrWrapper = Union[Type['Dataclass'], 'DataclassProxy'] + + class Dataclass: + # stdlib attributes + __dataclass_fields__: ClassVar[Dict[str, Any]] + __dataclass_params__: ClassVar[Any] # in reality `dataclasses._DataclassParams` + __post_init__: ClassVar[Callable[..., None]] + + # Added by pydantic + __pydantic_run_validation__: ClassVar[bool] + __post_init_post_parse__: ClassVar[Callable[..., None]] + __pydantic_initialised__: ClassVar[bool] + __pydantic_model__: ClassVar[Type[BaseModel]] + __pydantic_validate_values__: ClassVar[Callable[['Dataclass'], None]] + __pydantic_has_field_info_default__: ClassVar[bool] # whether a `pydantic.Field` is used as default value + + def __init__(self, *args: object, **kwargs: object) -> None: + pass + + @classmethod + def __get_validators__(cls: Type['Dataclass']) -> 'CallableGenerator': + pass + + @classmethod + def __validate__(cls: Type['DataclassT'], v: Any) -> 'DataclassT': + pass + + +__all__ = [ + 'dataclass', + 'set_validation', + 'create_pydantic_model_from_dataclass', + 'is_builtin_dataclass', + 'make_dataclass_validator', +] + +_T = TypeVar('_T') + +if sys.version_info >= (3, 10): + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + kw_only: bool = ..., + ) -> Callable[[Type[_T]], 'DataclassClassOrWrapper']: + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + _cls: Type[_T], + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + kw_only: bool = ..., + ) -> 'DataclassClassOrWrapper': + ... + +else: + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + ) -> Callable[[Type[_T]], 'DataclassClassOrWrapper']: + ... + + @dataclass_transform(field_specifiers=(dataclasses.field, Field)) + @overload + def dataclass( + _cls: Type[_T], + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + ) -> 'DataclassClassOrWrapper': + ... + + +@dataclass_transform(field_specifiers=(dataclasses.field, Field)) +def dataclass( + _cls: Optional[Type[_T]] = None, + *, + init: bool = True, + repr: bool = True, + eq: bool = True, + order: bool = False, + unsafe_hash: bool = False, + frozen: bool = False, + config: Union[ConfigDict, Type[object], None] = None, + validate_on_init: Optional[bool] = None, + use_proxy: Optional[bool] = None, + kw_only: bool = False, +) -> Union[Callable[[Type[_T]], 'DataclassClassOrWrapper'], 'DataclassClassOrWrapper']: + """ + Like the python standard lib dataclasses but with type validation. + The result is either a pydantic dataclass that will validate input data + or a wrapper that will trigger validation around a stdlib dataclass + to avoid modifying it directly + """ + the_config = get_config(config) + + def wrap(cls: Type[Any]) -> 'DataclassClassOrWrapper': + should_use_proxy = ( + use_proxy + if use_proxy is not None + else ( + is_builtin_dataclass(cls) + and (cls.__bases__[0] is object or set(dir(cls)) == set(dir(cls.__bases__[0]))) + ) + ) + if should_use_proxy: + dc_cls_doc = '' + dc_cls = DataclassProxy(cls) + default_validate_on_init = False + else: + dc_cls_doc = cls.__doc__ or '' # needs to be done before generating dataclass + if sys.version_info >= (3, 10): + dc_cls = dataclasses.dataclass( + cls, + init=init, + repr=repr, + eq=eq, + order=order, + unsafe_hash=unsafe_hash, + frozen=frozen, + kw_only=kw_only, + ) + else: + dc_cls = dataclasses.dataclass( # type: ignore + cls, init=init, repr=repr, eq=eq, order=order, unsafe_hash=unsafe_hash, frozen=frozen + ) + default_validate_on_init = True + + should_validate_on_init = default_validate_on_init if validate_on_init is None else validate_on_init + _add_pydantic_validation_attributes(cls, the_config, should_validate_on_init, dc_cls_doc) + dc_cls.__pydantic_model__.__try_update_forward_refs__(**{cls.__name__: cls}) + return dc_cls + + if _cls is None: + return wrap + + return wrap(_cls) + + +@contextmanager +def set_validation(cls: Type['DataclassT'], value: bool) -> Generator[Type['DataclassT'], None, None]: + original_run_validation = cls.__pydantic_run_validation__ + try: + cls.__pydantic_run_validation__ = value + yield cls + finally: + cls.__pydantic_run_validation__ = original_run_validation + + +class DataclassProxy: + __slots__ = '__dataclass__' + + def __init__(self, dc_cls: Type['Dataclass']) -> None: + object.__setattr__(self, '__dataclass__', dc_cls) + + def __call__(self, *args: Any, **kwargs: Any) -> Any: + with set_validation(self.__dataclass__, True): + return self.__dataclass__(*args, **kwargs) + + def __getattr__(self, name: str) -> Any: + return getattr(self.__dataclass__, name) + + def __setattr__(self, __name: str, __value: Any) -> None: + return setattr(self.__dataclass__, __name, __value) + + def __instancecheck__(self, instance: Any) -> bool: + return isinstance(instance, self.__dataclass__) + + def __copy__(self) -> 'DataclassProxy': + return DataclassProxy(copy.copy(self.__dataclass__)) + + def __deepcopy__(self, memo: Any) -> 'DataclassProxy': + return DataclassProxy(copy.deepcopy(self.__dataclass__, memo)) + + +def _add_pydantic_validation_attributes( # noqa: C901 (ignore complexity) + dc_cls: Type['Dataclass'], + config: Type[BaseConfig], + validate_on_init: bool, + dc_cls_doc: str, +) -> None: + """ + We need to replace the right method. If no `__post_init__` has been set in the stdlib dataclass + it won't even exist (code is generated on the fly by `dataclasses`) + By default, we run validation after `__init__` or `__post_init__` if defined + """ + init = dc_cls.__init__ + + @wraps(init) + def handle_extra_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None: + if config.extra == Extra.ignore: + init(self, *args, **{k: v for k, v in kwargs.items() if k in self.__dataclass_fields__}) + + elif config.extra == Extra.allow: + for k, v in kwargs.items(): + self.__dict__.setdefault(k, v) + init(self, *args, **{k: v for k, v in kwargs.items() if k in self.__dataclass_fields__}) + + else: + init(self, *args, **kwargs) + + if hasattr(dc_cls, '__post_init__'): + try: + post_init = dc_cls.__post_init__.__wrapped__ # type: ignore[attr-defined] + except AttributeError: + post_init = dc_cls.__post_init__ + + @wraps(post_init) + def new_post_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None: + if config.post_init_call == 'before_validation': + post_init(self, *args, **kwargs) + + if self.__class__.__pydantic_run_validation__: + self.__pydantic_validate_values__() + if hasattr(self, '__post_init_post_parse__'): + self.__post_init_post_parse__(*args, **kwargs) + + if config.post_init_call == 'after_validation': + post_init(self, *args, **kwargs) + + setattr(dc_cls, '__init__', handle_extra_init) + setattr(dc_cls, '__post_init__', new_post_init) + + else: + + @wraps(init) + def new_init(self: 'Dataclass', *args: Any, **kwargs: Any) -> None: + handle_extra_init(self, *args, **kwargs) + + if self.__class__.__pydantic_run_validation__: + self.__pydantic_validate_values__() + + if hasattr(self, '__post_init_post_parse__'): + # We need to find again the initvars. To do that we use `__dataclass_fields__` instead of + # public method `dataclasses.fields` + + # get all initvars and their default values + initvars_and_values: Dict[str, Any] = {} + for i, f in enumerate(self.__class__.__dataclass_fields__.values()): + if f._field_type is dataclasses._FIELD_INITVAR: # type: ignore[attr-defined] + try: + # set arg value by default + initvars_and_values[f.name] = args[i] + except IndexError: + initvars_and_values[f.name] = kwargs.get(f.name, f.default) + + self.__post_init_post_parse__(**initvars_and_values) + + setattr(dc_cls, '__init__', new_init) + + setattr(dc_cls, '__pydantic_run_validation__', ClassAttribute('__pydantic_run_validation__', validate_on_init)) + setattr(dc_cls, '__pydantic_initialised__', False) + setattr(dc_cls, '__pydantic_model__', create_pydantic_model_from_dataclass(dc_cls, config, dc_cls_doc)) + setattr(dc_cls, '__pydantic_validate_values__', _dataclass_validate_values) + setattr(dc_cls, '__validate__', classmethod(_validate_dataclass)) + setattr(dc_cls, '__get_validators__', classmethod(_get_validators)) + + if dc_cls.__pydantic_model__.__config__.validate_assignment and not dc_cls.__dataclass_params__.frozen: + setattr(dc_cls, '__setattr__', _dataclass_validate_assignment_setattr) + + +def _get_validators(cls: 'DataclassClassOrWrapper') -> 'CallableGenerator': + yield cls.__validate__ + + +def _validate_dataclass(cls: Type['DataclassT'], v: Any) -> 'DataclassT': + with set_validation(cls, True): + if isinstance(v, cls): + v.__pydantic_validate_values__() + return v + elif isinstance(v, (list, tuple)): + return cls(*v) + elif isinstance(v, dict): + return cls(**v) + else: + raise DataclassTypeError(class_name=cls.__name__) + + +def create_pydantic_model_from_dataclass( + dc_cls: Type['Dataclass'], + config: Type[Any] = BaseConfig, + dc_cls_doc: Optional[str] = None, +) -> Type['BaseModel']: + field_definitions: Dict[str, Any] = {} + for field in dataclasses.fields(dc_cls): + default: Any = Undefined + default_factory: Optional['NoArgAnyCallable'] = None + field_info: FieldInfo + + if field.default is not dataclasses.MISSING: + default = field.default + elif field.default_factory is not dataclasses.MISSING: + default_factory = field.default_factory + else: + default = Required + + if isinstance(default, FieldInfo): + field_info = default + dc_cls.__pydantic_has_field_info_default__ = True + else: + field_info = Field(default=default, default_factory=default_factory, **field.metadata) + + field_definitions[field.name] = (field.type, field_info) + + validators = gather_all_validators(dc_cls) + model: Type['BaseModel'] = create_model( + dc_cls.__name__, + __config__=config, + __module__=dc_cls.__module__, + __validators__=validators, + __cls_kwargs__={'__resolve_forward_refs__': False}, + **field_definitions, + ) + model.__doc__ = dc_cls_doc if dc_cls_doc is not None else dc_cls.__doc__ or '' + return model + + +if sys.version_info >= (3, 8): + + def _is_field_cached_property(obj: 'Dataclass', k: str) -> bool: + return isinstance(getattr(type(obj), k, None), cached_property) + +else: + + def _is_field_cached_property(obj: 'Dataclass', k: str) -> bool: + return False + + +def _dataclass_validate_values(self: 'Dataclass') -> None: + # validation errors can occur if this function is called twice on an already initialised dataclass. + # for example if Extra.forbid is enabled, it would consider __pydantic_initialised__ an invalid extra property + if getattr(self, '__pydantic_initialised__'): + return + if getattr(self, '__pydantic_has_field_info_default__', False): + # We need to remove `FieldInfo` values since they are not valid as input + # It's ok to do that because they are obviously the default values! + input_data = { + k: v + for k, v in self.__dict__.items() + if not (isinstance(v, FieldInfo) or _is_field_cached_property(self, k)) + } + else: + input_data = {k: v for k, v in self.__dict__.items() if not _is_field_cached_property(self, k)} + d, _, validation_error = validate_model(self.__pydantic_model__, input_data, cls=self.__class__) + if validation_error: + raise validation_error + self.__dict__.update(d) + object.__setattr__(self, '__pydantic_initialised__', True) + + +def _dataclass_validate_assignment_setattr(self: 'Dataclass', name: str, value: Any) -> None: + if self.__pydantic_initialised__: + d = dict(self.__dict__) + d.pop(name, None) + known_field = self.__pydantic_model__.__fields__.get(name, None) + if known_field: + value, error_ = known_field.validate(value, d, loc=name, cls=self.__class__) + if error_: + raise ValidationError([error_], self.__class__) + + object.__setattr__(self, name, value) + + +def is_builtin_dataclass(_cls: Type[Any]) -> bool: + """ + Whether a class is a stdlib dataclass + (useful to discriminated a pydantic dataclass that is actually a wrapper around a stdlib dataclass) + + we check that + - `_cls` is a dataclass + - `_cls` is not a processed pydantic dataclass (with a basemodel attached) + - `_cls` is not a pydantic dataclass inheriting directly from a stdlib dataclass + e.g. + ``` + @dataclasses.dataclass + class A: + x: int + + @pydantic.dataclasses.dataclass + class B(A): + y: int + ``` + In this case, when we first check `B`, we make an extra check and look at the annotations ('y'), + which won't be a superset of all the dataclass fields (only the stdlib fields i.e. 'x') + """ + return ( + dataclasses.is_dataclass(_cls) + and not hasattr(_cls, '__pydantic_model__') + and set(_cls.__dataclass_fields__).issuperset(set(getattr(_cls, '__annotations__', {}))) + ) + + +def make_dataclass_validator(dc_cls: Type['Dataclass'], config: Type[BaseConfig]) -> 'CallableGenerator': + """ + Create a pydantic.dataclass from a builtin dataclass to add type validation + and yield the validators + It retrieves the parameters of the dataclass and forwards them to the newly created dataclass + """ + yield from _get_validators(dataclass(dc_cls, config=config, use_proxy=True)) diff --git a/source/target-vendors/cp312/pydantic/v1/datetime_parse.py b/source/target-vendors/cp312/pydantic/v1/datetime_parse.py new file mode 100644 index 0000000..a7598fc --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/datetime_parse.py @@ -0,0 +1,248 @@ +""" +Functions to parse datetime objects. + +We're using regular expressions rather than time.strptime because: +- They provide both validation and parsing. +- They're more flexible for datetimes. +- The date/datetime/time constructors produce friendlier error messages. + +Stolen from https://raw.githubusercontent.com/django/django/main/django/utils/dateparse.py at +9718fa2e8abe430c3526a9278dd976443d4ae3c6 + +Changed to: +* use standard python datetime types not django.utils.timezone +* raise ValueError when regex doesn't match rather than returning None +* support parsing unix timestamps for dates and datetimes +""" +import re +from datetime import date, datetime, time, timedelta, timezone +from typing import Dict, Optional, Type, Union + +from pydantic.v1 import errors + +date_expr = r'(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})' +time_expr = ( + r'(?P\d{1,2}):(?P\d{1,2})' + r'(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?' + r'(?PZ|[+-]\d{2}(?::?\d{2})?)?$' +) + +date_re = re.compile(f'{date_expr}$') +time_re = re.compile(time_expr) +datetime_re = re.compile(f'{date_expr}[T ]{time_expr}') + +standard_duration_re = re.compile( + r'^' + r'(?:(?P-?\d+) (days?, )?)?' + r'((?:(?P-?\d+):)(?=\d+:\d+))?' + r'(?:(?P-?\d+):)?' + r'(?P-?\d+)' + r'(?:\.(?P\d{1,6})\d{0,6})?' + r'$' +) + +# Support the sections of ISO 8601 date representation that are accepted by timedelta +iso8601_duration_re = re.compile( + r'^(?P[-+]?)' + r'P' + r'(?:(?P\d+(.\d+)?)D)?' + r'(?:T' + r'(?:(?P\d+(.\d+)?)H)?' + r'(?:(?P\d+(.\d+)?)M)?' + r'(?:(?P\d+(.\d+)?)S)?' + r')?' + r'$' +) + +EPOCH = datetime(1970, 1, 1) +# if greater than this, the number is in ms, if less than or equal it's in seconds +# (in seconds this is 11th October 2603, in ms it's 20th August 1970) +MS_WATERSHED = int(2e10) +# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 +MAX_NUMBER = int(3e20) +StrBytesIntFloat = Union[str, bytes, int, float] + + +def get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: + if isinstance(value, (int, float)): + return value + try: + return float(value) + except ValueError: + return None + except TypeError: + raise TypeError(f'invalid type; expected {native_expected_type}, string, bytes, int or float') + + +def from_unix_seconds(seconds: Union[int, float]) -> datetime: + if seconds > MAX_NUMBER: + return datetime.max + elif seconds < -MAX_NUMBER: + return datetime.min + + while abs(seconds) > MS_WATERSHED: + seconds /= 1000 + dt = EPOCH + timedelta(seconds=seconds) + return dt.replace(tzinfo=timezone.utc) + + +def _parse_timezone(value: Optional[str], error: Type[Exception]) -> Union[None, int, timezone]: + if value == 'Z': + return timezone.utc + elif value is not None: + offset_mins = int(value[-2:]) if len(value) > 3 else 0 + offset = 60 * int(value[1:3]) + offset_mins + if value[0] == '-': + offset = -offset + try: + return timezone(timedelta(minutes=offset)) + except ValueError: + raise error() + else: + return None + + +def parse_date(value: Union[date, StrBytesIntFloat]) -> date: + """ + Parse a date/int/float/string and return a datetime.date. + + Raise ValueError if the input is well formatted but not a valid date. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, date): + if isinstance(value, datetime): + return value.date() + else: + return value + + number = get_numeric(value, 'date') + if number is not None: + return from_unix_seconds(number).date() + + if isinstance(value, bytes): + value = value.decode() + + match = date_re.match(value) # type: ignore + if match is None: + raise errors.DateError() + + kw = {k: int(v) for k, v in match.groupdict().items()} + + try: + return date(**kw) + except ValueError: + raise errors.DateError() + + +def parse_time(value: Union[time, StrBytesIntFloat]) -> time: + """ + Parse a time/string and return a datetime.time. + + Raise ValueError if the input is well formatted but not a valid time. + Raise ValueError if the input isn't well formatted, in particular if it contains an offset. + """ + if isinstance(value, time): + return value + + number = get_numeric(value, 'time') + if number is not None: + if number >= 86400: + # doesn't make sense since the time time loop back around to 0 + raise errors.TimeError() + return (datetime.min + timedelta(seconds=number)).time() + + if isinstance(value, bytes): + value = value.decode() + + match = time_re.match(value) # type: ignore + if match is None: + raise errors.TimeError() + + kw = match.groupdict() + if kw['microsecond']: + kw['microsecond'] = kw['microsecond'].ljust(6, '0') + + tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.TimeError) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_['tzinfo'] = tzinfo + + try: + return time(**kw_) # type: ignore + except ValueError: + raise errors.TimeError() + + +def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: + """ + Parse a datetime/int/float/string and return a datetime.datetime. + + This function supports time zone offsets. When the input contains one, + the output uses a timezone with a fixed offset from UTC. + + Raise ValueError if the input is well formatted but not a valid datetime. + Raise ValueError if the input isn't well formatted. + """ + if isinstance(value, datetime): + return value + + number = get_numeric(value, 'datetime') + if number is not None: + return from_unix_seconds(number) + + if isinstance(value, bytes): + value = value.decode() + + match = datetime_re.match(value) # type: ignore + if match is None: + raise errors.DateTimeError() + + kw = match.groupdict() + if kw['microsecond']: + kw['microsecond'] = kw['microsecond'].ljust(6, '0') + + tzinfo = _parse_timezone(kw.pop('tzinfo'), errors.DateTimeError) + kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} + kw_['tzinfo'] = tzinfo + + try: + return datetime(**kw_) # type: ignore + except ValueError: + raise errors.DateTimeError() + + +def parse_duration(value: StrBytesIntFloat) -> timedelta: + """ + Parse a duration int/float/string and return a datetime.timedelta. + + The preferred format for durations in Django is '%d %H:%M:%S.%f'. + + Also supports ISO 8601 representation. + """ + if isinstance(value, timedelta): + return value + + if isinstance(value, (int, float)): + # below code requires a string + value = f'{value:f}' + elif isinstance(value, bytes): + value = value.decode() + + try: + match = standard_duration_re.match(value) or iso8601_duration_re.match(value) + except TypeError: + raise TypeError('invalid type; expected timedelta, string, bytes, int or float') + + if not match: + raise errors.DurationError() + + kw = match.groupdict() + sign = -1 if kw.pop('sign', '+') == '-' else 1 + if kw.get('microseconds'): + kw['microseconds'] = kw['microseconds'].ljust(6, '0') + + if kw.get('seconds') and kw.get('microseconds') and kw['seconds'].startswith('-'): + kw['microseconds'] = '-' + kw['microseconds'] + + kw_ = {k: float(v) for k, v in kw.items() if v is not None} + + return sign * timedelta(**kw_) diff --git a/source/target-vendors/cp312/pydantic/v1/decorator.py b/source/target-vendors/cp312/pydantic/v1/decorator.py new file mode 100644 index 0000000..2c7c2c2 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/decorator.py @@ -0,0 +1,264 @@ +from functools import wraps +from typing import TYPE_CHECKING, Any, Callable, Dict, List, Mapping, Optional, Tuple, Type, TypeVar, Union, overload + +from pydantic.v1 import validator +from pydantic.v1.config import Extra +from pydantic.v1.errors import ConfigError +from pydantic.v1.main import BaseModel, create_model +from pydantic.v1.typing import get_all_type_hints +from pydantic.v1.utils import to_camel + +__all__ = ('validate_arguments',) + +if TYPE_CHECKING: + from pydantic.v1.typing import AnyCallable + + AnyCallableT = TypeVar('AnyCallableT', bound=AnyCallable) + ConfigType = Union[None, Type[Any], Dict[str, Any]] + + +@overload +def validate_arguments(func: None = None, *, config: 'ConfigType' = None) -> Callable[['AnyCallableT'], 'AnyCallableT']: + ... + + +@overload +def validate_arguments(func: 'AnyCallableT') -> 'AnyCallableT': + ... + + +def validate_arguments(func: Optional['AnyCallableT'] = None, *, config: 'ConfigType' = None) -> Any: + """ + Decorator to validate the arguments passed to a function. + """ + + def validate(_func: 'AnyCallable') -> 'AnyCallable': + vd = ValidatedFunction(_func, config) + + @wraps(_func) + def wrapper_function(*args: Any, **kwargs: Any) -> Any: + return vd.call(*args, **kwargs) + + wrapper_function.vd = vd # type: ignore + wrapper_function.validate = vd.init_model_instance # type: ignore + wrapper_function.raw_function = vd.raw_function # type: ignore + wrapper_function.model = vd.model # type: ignore + return wrapper_function + + if func: + return validate(func) + else: + return validate + + +ALT_V_ARGS = 'v__args' +ALT_V_KWARGS = 'v__kwargs' +V_POSITIONAL_ONLY_NAME = 'v__positional_only' +V_DUPLICATE_KWARGS = 'v__duplicate_kwargs' + + +class ValidatedFunction: + def __init__(self, function: 'AnyCallableT', config: 'ConfigType'): # noqa C901 + from inspect import Parameter, signature + + parameters: Mapping[str, Parameter] = signature(function).parameters + + if parameters.keys() & {ALT_V_ARGS, ALT_V_KWARGS, V_POSITIONAL_ONLY_NAME, V_DUPLICATE_KWARGS}: + raise ConfigError( + f'"{ALT_V_ARGS}", "{ALT_V_KWARGS}", "{V_POSITIONAL_ONLY_NAME}" and "{V_DUPLICATE_KWARGS}" ' + f'are not permitted as argument names when using the "{validate_arguments.__name__}" decorator' + ) + + self.raw_function = function + self.arg_mapping: Dict[int, str] = {} + self.positional_only_args = set() + self.v_args_name = 'args' + self.v_kwargs_name = 'kwargs' + + type_hints = get_all_type_hints(function) + takes_args = False + takes_kwargs = False + fields: Dict[str, Tuple[Any, Any]] = {} + for i, (name, p) in enumerate(parameters.items()): + if p.annotation is p.empty: + annotation = Any + else: + annotation = type_hints[name] + + default = ... if p.default is p.empty else p.default + if p.kind == Parameter.POSITIONAL_ONLY: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_POSITIONAL_ONLY_NAME] = List[str], None + self.positional_only_args.add(name) + elif p.kind == Parameter.POSITIONAL_OR_KEYWORD: + self.arg_mapping[i] = name + fields[name] = annotation, default + fields[V_DUPLICATE_KWARGS] = List[str], None + elif p.kind == Parameter.KEYWORD_ONLY: + fields[name] = annotation, default + elif p.kind == Parameter.VAR_POSITIONAL: + self.v_args_name = name + fields[name] = Tuple[annotation, ...], None + takes_args = True + else: + assert p.kind == Parameter.VAR_KEYWORD, p.kind + self.v_kwargs_name = name + fields[name] = Dict[str, annotation], None # type: ignore + takes_kwargs = True + + # these checks avoid a clash between "args" and a field with that name + if not takes_args and self.v_args_name in fields: + self.v_args_name = ALT_V_ARGS + + # same with "kwargs" + if not takes_kwargs and self.v_kwargs_name in fields: + self.v_kwargs_name = ALT_V_KWARGS + + if not takes_args: + # we add the field so validation below can raise the correct exception + fields[self.v_args_name] = List[Any], None + + if not takes_kwargs: + # same with kwargs + fields[self.v_kwargs_name] = Dict[Any, Any], None + + self.create_model(fields, takes_args, takes_kwargs, config) + + def init_model_instance(self, *args: Any, **kwargs: Any) -> BaseModel: + values = self.build_values(args, kwargs) + return self.model(**values) + + def call(self, *args: Any, **kwargs: Any) -> Any: + m = self.init_model_instance(*args, **kwargs) + return self.execute(m) + + def build_values(self, args: Tuple[Any, ...], kwargs: Dict[str, Any]) -> Dict[str, Any]: + values: Dict[str, Any] = {} + if args: + arg_iter = enumerate(args) + while True: + try: + i, a = next(arg_iter) + except StopIteration: + break + arg_name = self.arg_mapping.get(i) + if arg_name is not None: + values[arg_name] = a + else: + values[self.v_args_name] = [a] + [a for _, a in arg_iter] + break + + var_kwargs: Dict[str, Any] = {} + wrong_positional_args = [] + duplicate_kwargs = [] + fields_alias = [ + field.alias + for name, field in self.model.__fields__.items() + if name not in (self.v_args_name, self.v_kwargs_name) + ] + non_var_fields = set(self.model.__fields__) - {self.v_args_name, self.v_kwargs_name} + for k, v in kwargs.items(): + if k in non_var_fields or k in fields_alias: + if k in self.positional_only_args: + wrong_positional_args.append(k) + if k in values: + duplicate_kwargs.append(k) + values[k] = v + else: + var_kwargs[k] = v + + if var_kwargs: + values[self.v_kwargs_name] = var_kwargs + if wrong_positional_args: + values[V_POSITIONAL_ONLY_NAME] = wrong_positional_args + if duplicate_kwargs: + values[V_DUPLICATE_KWARGS] = duplicate_kwargs + return values + + def execute(self, m: BaseModel) -> Any: + d = {k: v for k, v in m._iter() if k in m.__fields_set__ or m.__fields__[k].default_factory} + var_kwargs = d.pop(self.v_kwargs_name, {}) + + if self.v_args_name in d: + args_: List[Any] = [] + in_kwargs = False + kwargs = {} + for name, value in d.items(): + if in_kwargs: + kwargs[name] = value + elif name == self.v_args_name: + args_ += value + in_kwargs = True + else: + args_.append(value) + return self.raw_function(*args_, **kwargs, **var_kwargs) + elif self.positional_only_args: + args_ = [] + kwargs = {} + for name, value in d.items(): + if name in self.positional_only_args: + args_.append(value) + else: + kwargs[name] = value + return self.raw_function(*args_, **kwargs, **var_kwargs) + else: + return self.raw_function(**d, **var_kwargs) + + def create_model(self, fields: Dict[str, Any], takes_args: bool, takes_kwargs: bool, config: 'ConfigType') -> None: + pos_args = len(self.arg_mapping) + + class CustomConfig: + pass + + if not TYPE_CHECKING: # pragma: no branch + if isinstance(config, dict): + CustomConfig = type('Config', (), config) # noqa: F811 + elif config is not None: + CustomConfig = config # noqa: F811 + + if hasattr(CustomConfig, 'fields') or hasattr(CustomConfig, 'alias_generator'): + raise ConfigError( + 'Setting the "fields" and "alias_generator" property on custom Config for ' + '@validate_arguments is not yet supported, please remove.' + ) + + class DecoratorBaseModel(BaseModel): + @validator(self.v_args_name, check_fields=False, allow_reuse=True) + def check_args(cls, v: Optional[List[Any]]) -> Optional[List[Any]]: + if takes_args or v is None: + return v + + raise TypeError(f'{pos_args} positional arguments expected but {pos_args + len(v)} given') + + @validator(self.v_kwargs_name, check_fields=False, allow_reuse=True) + def check_kwargs(cls, v: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]: + if takes_kwargs or v is None: + return v + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v.keys())) + raise TypeError(f'unexpected keyword argument{plural}: {keys}') + + @validator(V_POSITIONAL_ONLY_NAME, check_fields=False, allow_reuse=True) + def check_positional_only(cls, v: Optional[List[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'positional-only argument{plural} passed as keyword argument{plural}: {keys}') + + @validator(V_DUPLICATE_KWARGS, check_fields=False, allow_reuse=True) + def check_duplicate_kwargs(cls, v: Optional[List[str]]) -> None: + if v is None: + return + + plural = '' if len(v) == 1 else 's' + keys = ', '.join(map(repr, v)) + raise TypeError(f'multiple values for argument{plural}: {keys}') + + class Config(CustomConfig): + extra = getattr(CustomConfig, 'extra', Extra.forbid) + + self.model = create_model(to_camel(self.raw_function.__name__), __base__=DecoratorBaseModel, **fields) diff --git a/source/target-vendors/cp312/pydantic/v1/env_settings.py b/source/target-vendors/cp312/pydantic/v1/env_settings.py new file mode 100644 index 0000000..5f6f217 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/env_settings.py @@ -0,0 +1,350 @@ +import os +import warnings +from pathlib import Path +from typing import AbstractSet, Any, Callable, ClassVar, Dict, List, Mapping, Optional, Tuple, Type, Union + +from pydantic.v1.config import BaseConfig, Extra +from pydantic.v1.fields import ModelField +from pydantic.v1.main import BaseModel +from pydantic.v1.types import JsonWrapper +from pydantic.v1.typing import StrPath, display_as_type, get_origin, is_union +from pydantic.v1.utils import deep_update, lenient_issubclass, path_type, sequence_like + +env_file_sentinel = str(object()) + +SettingsSourceCallable = Callable[['BaseSettings'], Dict[str, Any]] +DotenvType = Union[StrPath, List[StrPath], Tuple[StrPath, ...]] + + +class SettingsError(ValueError): + pass + + +class BaseSettings(BaseModel): + """ + Base class for settings, allowing values to be overridden by environment variables. + + This is useful in production for secrets you do not wish to save in code, it plays nicely with docker(-compose), + Heroku and any 12 factor app design. + """ + + def __init__( + __pydantic_self__, + _env_file: Optional[DotenvType] = env_file_sentinel, + _env_file_encoding: Optional[str] = None, + _env_nested_delimiter: Optional[str] = None, + _secrets_dir: Optional[StrPath] = None, + **values: Any, + ) -> None: + # Uses something other than `self` the first arg to allow "self" as a settable attribute + super().__init__( + **__pydantic_self__._build_values( + values, + _env_file=_env_file, + _env_file_encoding=_env_file_encoding, + _env_nested_delimiter=_env_nested_delimiter, + _secrets_dir=_secrets_dir, + ) + ) + + def _build_values( + self, + init_kwargs: Dict[str, Any], + _env_file: Optional[DotenvType] = None, + _env_file_encoding: Optional[str] = None, + _env_nested_delimiter: Optional[str] = None, + _secrets_dir: Optional[StrPath] = None, + ) -> Dict[str, Any]: + # Configure built-in sources + init_settings = InitSettingsSource(init_kwargs=init_kwargs) + env_settings = EnvSettingsSource( + env_file=(_env_file if _env_file != env_file_sentinel else self.__config__.env_file), + env_file_encoding=( + _env_file_encoding if _env_file_encoding is not None else self.__config__.env_file_encoding + ), + env_nested_delimiter=( + _env_nested_delimiter if _env_nested_delimiter is not None else self.__config__.env_nested_delimiter + ), + env_prefix_len=len(self.__config__.env_prefix), + ) + file_secret_settings = SecretsSettingsSource(secrets_dir=_secrets_dir or self.__config__.secrets_dir) + # Provide a hook to set built-in sources priority and add / remove sources + sources = self.__config__.customise_sources( + init_settings=init_settings, env_settings=env_settings, file_secret_settings=file_secret_settings + ) + if sources: + return deep_update(*reversed([source(self) for source in sources])) + else: + # no one should mean to do this, but I think returning an empty dict is marginally preferable + # to an informative error and much better than a confusing error + return {} + + class Config(BaseConfig): + env_prefix: str = '' + env_file: Optional[DotenvType] = None + env_file_encoding: Optional[str] = None + env_nested_delimiter: Optional[str] = None + secrets_dir: Optional[StrPath] = None + validate_all: bool = True + extra: Extra = Extra.forbid + arbitrary_types_allowed: bool = True + case_sensitive: bool = False + + @classmethod + def prepare_field(cls, field: ModelField) -> None: + env_names: Union[List[str], AbstractSet[str]] + field_info_from_config = cls.get_field_info(field.name) + + env = field_info_from_config.get('env') or field.field_info.extra.get('env') + if env is None: + if field.has_alias: + warnings.warn( + 'aliases are no longer used by BaseSettings to define which environment variables to read. ' + 'Instead use the "env" field setting. ' + 'See https://pydantic-docs.helpmanual.io/usage/settings/#environment-variable-names', + FutureWarning, + ) + env_names = {cls.env_prefix + field.name} + elif isinstance(env, str): + env_names = {env} + elif isinstance(env, (set, frozenset)): + env_names = env + elif sequence_like(env): + env_names = list(env) + else: + raise TypeError(f'invalid field env: {env!r} ({display_as_type(env)}); should be string, list or set') + + if not cls.case_sensitive: + env_names = env_names.__class__(n.lower() for n in env_names) + field.field_info.extra['env_names'] = env_names + + @classmethod + def customise_sources( + cls, + init_settings: SettingsSourceCallable, + env_settings: SettingsSourceCallable, + file_secret_settings: SettingsSourceCallable, + ) -> Tuple[SettingsSourceCallable, ...]: + return init_settings, env_settings, file_secret_settings + + @classmethod + def parse_env_var(cls, field_name: str, raw_val: str) -> Any: + return cls.json_loads(raw_val) + + # populated by the metaclass using the Config class defined above, annotated here to help IDEs only + __config__: ClassVar[Type[Config]] + + +class InitSettingsSource: + __slots__ = ('init_kwargs',) + + def __init__(self, init_kwargs: Dict[str, Any]): + self.init_kwargs = init_kwargs + + def __call__(self, settings: BaseSettings) -> Dict[str, Any]: + return self.init_kwargs + + def __repr__(self) -> str: + return f'InitSettingsSource(init_kwargs={self.init_kwargs!r})' + + +class EnvSettingsSource: + __slots__ = ('env_file', 'env_file_encoding', 'env_nested_delimiter', 'env_prefix_len') + + def __init__( + self, + env_file: Optional[DotenvType], + env_file_encoding: Optional[str], + env_nested_delimiter: Optional[str] = None, + env_prefix_len: int = 0, + ): + self.env_file: Optional[DotenvType] = env_file + self.env_file_encoding: Optional[str] = env_file_encoding + self.env_nested_delimiter: Optional[str] = env_nested_delimiter + self.env_prefix_len: int = env_prefix_len + + def __call__(self, settings: BaseSettings) -> Dict[str, Any]: # noqa C901 + """ + Build environment variables suitable for passing to the Model. + """ + d: Dict[str, Any] = {} + + if settings.__config__.case_sensitive: + env_vars: Mapping[str, Optional[str]] = os.environ + else: + env_vars = {k.lower(): v for k, v in os.environ.items()} + + dotenv_vars = self._read_env_files(settings.__config__.case_sensitive) + if dotenv_vars: + env_vars = {**dotenv_vars, **env_vars} + + for field in settings.__fields__.values(): + env_val: Optional[str] = None + for env_name in field.field_info.extra['env_names']: + env_val = env_vars.get(env_name) + if env_val is not None: + break + + is_complex, allow_parse_failure = self.field_is_complex(field) + if is_complex: + if env_val is None: + # field is complex but no value found so far, try explode_env_vars + env_val_built = self.explode_env_vars(field, env_vars) + if env_val_built: + d[field.alias] = env_val_built + else: + # field is complex and there's a value, decode that as JSON, then add explode_env_vars + try: + env_val = settings.__config__.parse_env_var(field.name, env_val) + except ValueError as e: + if not allow_parse_failure: + raise SettingsError(f'error parsing env var "{env_name}"') from e + + if isinstance(env_val, dict): + d[field.alias] = deep_update(env_val, self.explode_env_vars(field, env_vars)) + else: + d[field.alias] = env_val + elif env_val is not None: + # simplest case, field is not complex, we only need to add the value if it was found + d[field.alias] = env_val + + return d + + def _read_env_files(self, case_sensitive: bool) -> Dict[str, Optional[str]]: + env_files = self.env_file + if env_files is None: + return {} + + if isinstance(env_files, (str, os.PathLike)): + env_files = [env_files] + + dotenv_vars = {} + for env_file in env_files: + env_path = Path(env_file).expanduser() + if env_path.is_file(): + dotenv_vars.update( + read_env_file(env_path, encoding=self.env_file_encoding, case_sensitive=case_sensitive) + ) + + return dotenv_vars + + def field_is_complex(self, field: ModelField) -> Tuple[bool, bool]: + """ + Find out if a field is complex, and if so whether JSON errors should be ignored + """ + if lenient_issubclass(field.annotation, JsonWrapper): + return False, False + + if field.is_complex(): + allow_parse_failure = False + elif is_union(get_origin(field.type_)) and field.sub_fields and any(f.is_complex() for f in field.sub_fields): + allow_parse_failure = True + else: + return False, False + + return True, allow_parse_failure + + def explode_env_vars(self, field: ModelField, env_vars: Mapping[str, Optional[str]]) -> Dict[str, Any]: + """ + Process env_vars and extract the values of keys containing env_nested_delimiter into nested dictionaries. + + This is applied to a single field, hence filtering by env_var prefix. + """ + prefixes = [f'{env_name}{self.env_nested_delimiter}' for env_name in field.field_info.extra['env_names']] + result: Dict[str, Any] = {} + for env_name, env_val in env_vars.items(): + if not any(env_name.startswith(prefix) for prefix in prefixes): + continue + # we remove the prefix before splitting in case the prefix has characters in common with the delimiter + env_name_without_prefix = env_name[self.env_prefix_len :] + _, *keys, last_key = env_name_without_prefix.split(self.env_nested_delimiter) + env_var = result + for key in keys: + env_var = env_var.setdefault(key, {}) + env_var[last_key] = env_val + + return result + + def __repr__(self) -> str: + return ( + f'EnvSettingsSource(env_file={self.env_file!r}, env_file_encoding={self.env_file_encoding!r}, ' + f'env_nested_delimiter={self.env_nested_delimiter!r})' + ) + + +class SecretsSettingsSource: + __slots__ = ('secrets_dir',) + + def __init__(self, secrets_dir: Optional[StrPath]): + self.secrets_dir: Optional[StrPath] = secrets_dir + + def __call__(self, settings: BaseSettings) -> Dict[str, Any]: + """ + Build fields from "secrets" files. + """ + secrets: Dict[str, Optional[str]] = {} + + if self.secrets_dir is None: + return secrets + + secrets_path = Path(self.secrets_dir).expanduser() + + if not secrets_path.exists(): + warnings.warn(f'directory "{secrets_path}" does not exist') + return secrets + + if not secrets_path.is_dir(): + raise SettingsError(f'secrets_dir must reference a directory, not a {path_type(secrets_path)}') + + for field in settings.__fields__.values(): + for env_name in field.field_info.extra['env_names']: + path = find_case_path(secrets_path, env_name, settings.__config__.case_sensitive) + if not path: + # path does not exist, we currently don't return a warning for this + continue + + if path.is_file(): + secret_value = path.read_text().strip() + if field.is_complex(): + try: + secret_value = settings.__config__.parse_env_var(field.name, secret_value) + except ValueError as e: + raise SettingsError(f'error parsing env var "{env_name}"') from e + + secrets[field.alias] = secret_value + else: + warnings.warn( + f'attempted to load secret file "{path}" but found a {path_type(path)} instead.', + stacklevel=4, + ) + return secrets + + def __repr__(self) -> str: + return f'SecretsSettingsSource(secrets_dir={self.secrets_dir!r})' + + +def read_env_file( + file_path: StrPath, *, encoding: str = None, case_sensitive: bool = False +) -> Dict[str, Optional[str]]: + try: + from dotenv import dotenv_values + except ImportError as e: + raise ImportError('python-dotenv is not installed, run `pip install pydantic[dotenv]`') from e + + file_vars: Dict[str, Optional[str]] = dotenv_values(file_path, encoding=encoding or 'utf8') + if not case_sensitive: + return {k.lower(): v for k, v in file_vars.items()} + else: + return file_vars + + +def find_case_path(dir_path: Path, file_name: str, case_sensitive: bool) -> Optional[Path]: + """ + Find a file within path's directory matching filename, optionally ignoring case. + """ + for f in dir_path.iterdir(): + if f.name == file_name: + return f + elif not case_sensitive and f.name.lower() == file_name.lower(): + return f + return None diff --git a/source/target-vendors/cp312/pydantic/v1/error_wrappers.py b/source/target-vendors/cp312/pydantic/v1/error_wrappers.py new file mode 100644 index 0000000..bc7f263 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/error_wrappers.py @@ -0,0 +1,161 @@ +import json +from typing import TYPE_CHECKING, Any, Dict, Generator, List, Optional, Sequence, Tuple, Type, Union + +from pydantic.v1.json import pydantic_encoder +from pydantic.v1.utils import Representation + +if TYPE_CHECKING: + from typing_extensions import TypedDict + + from pydantic.v1.config import BaseConfig + from pydantic.v1.types import ModelOrDc + from pydantic.v1.typing import ReprArgs + + Loc = Tuple[Union[int, str], ...] + + class _ErrorDictRequired(TypedDict): + loc: Loc + msg: str + type: str + + class ErrorDict(_ErrorDictRequired, total=False): + ctx: Dict[str, Any] + + +__all__ = 'ErrorWrapper', 'ValidationError' + + +class ErrorWrapper(Representation): + __slots__ = 'exc', '_loc' + + def __init__(self, exc: Exception, loc: Union[str, 'Loc']) -> None: + self.exc = exc + self._loc = loc + + def loc_tuple(self) -> 'Loc': + if isinstance(self._loc, tuple): + return self._loc + else: + return (self._loc,) + + def __repr_args__(self) -> 'ReprArgs': + return [('exc', self.exc), ('loc', self.loc_tuple())] + + +# ErrorList is something like Union[List[Union[List[ErrorWrapper], ErrorWrapper]], ErrorWrapper] +# but recursive, therefore just use: +ErrorList = Union[Sequence[Any], ErrorWrapper] + + +class ValidationError(Representation, ValueError): + __slots__ = 'raw_errors', 'model', '_error_cache' + + def __init__(self, errors: Sequence[ErrorList], model: 'ModelOrDc') -> None: + self.raw_errors = errors + self.model = model + self._error_cache: Optional[List['ErrorDict']] = None + + def errors(self) -> List['ErrorDict']: + if self._error_cache is None: + try: + config = self.model.__config__ # type: ignore + except AttributeError: + config = self.model.__pydantic_model__.__config__ # type: ignore + self._error_cache = list(flatten_errors(self.raw_errors, config)) + return self._error_cache + + def json(self, *, indent: Union[None, int, str] = 2) -> str: + return json.dumps(self.errors(), indent=indent, default=pydantic_encoder) + + def __str__(self) -> str: + errors = self.errors() + no_errors = len(errors) + return ( + f'{no_errors} validation error{"" if no_errors == 1 else "s"} for {self.model.__name__}\n' + f'{display_errors(errors)}' + ) + + def __repr_args__(self) -> 'ReprArgs': + return [('model', self.model.__name__), ('errors', self.errors())] + + +def display_errors(errors: List['ErrorDict']) -> str: + return '\n'.join(f'{_display_error_loc(e)}\n {e["msg"]} ({_display_error_type_and_ctx(e)})' for e in errors) + + +def _display_error_loc(error: 'ErrorDict') -> str: + return ' -> '.join(str(e) for e in error['loc']) + + +def _display_error_type_and_ctx(error: 'ErrorDict') -> str: + t = 'type=' + error['type'] + ctx = error.get('ctx') + if ctx: + return t + ''.join(f'; {k}={v}' for k, v in ctx.items()) + else: + return t + + +def flatten_errors( + errors: Sequence[Any], config: Type['BaseConfig'], loc: Optional['Loc'] = None +) -> Generator['ErrorDict', None, None]: + for error in errors: + if isinstance(error, ErrorWrapper): + if loc: + error_loc = loc + error.loc_tuple() + else: + error_loc = error.loc_tuple() + + if isinstance(error.exc, ValidationError): + yield from flatten_errors(error.exc.raw_errors, config, error_loc) + else: + yield error_dict(error.exc, config, error_loc) + elif isinstance(error, list): + yield from flatten_errors(error, config, loc=loc) + else: + raise RuntimeError(f'Unknown error object: {error}') + + +def error_dict(exc: Exception, config: Type['BaseConfig'], loc: 'Loc') -> 'ErrorDict': + type_ = get_exc_type(exc.__class__) + msg_template = config.error_msg_templates.get(type_) or getattr(exc, 'msg_template', None) + ctx = exc.__dict__ + if msg_template: + msg = msg_template.format(**ctx) + else: + msg = str(exc) + + d: 'ErrorDict' = {'loc': loc, 'msg': msg, 'type': type_} + + if ctx: + d['ctx'] = ctx + + return d + + +_EXC_TYPE_CACHE: Dict[Type[Exception], str] = {} + + +def get_exc_type(cls: Type[Exception]) -> str: + # slightly more efficient than using lru_cache since we don't need to worry about the cache filling up + try: + return _EXC_TYPE_CACHE[cls] + except KeyError: + r = _get_exc_type(cls) + _EXC_TYPE_CACHE[cls] = r + return r + + +def _get_exc_type(cls: Type[Exception]) -> str: + if issubclass(cls, AssertionError): + return 'assertion_error' + + base_name = 'type_error' if issubclass(cls, TypeError) else 'value_error' + if cls in (TypeError, ValueError): + # just TypeError or ValueError, no extra code + return base_name + + # if it's not a TypeError or ValueError, we just take the lowercase of the exception name + # no chaining or snake case logic, use "code" for more complex error types. + code = getattr(cls, 'code', None) or cls.__name__.replace('Error', '').lower() + return base_name + '.' + code diff --git a/source/target-vendors/cp312/pydantic/v1/errors.py b/source/target-vendors/cp312/pydantic/v1/errors.py new file mode 100644 index 0000000..6e86442 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/errors.py @@ -0,0 +1,646 @@ +from decimal import Decimal +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable, Sequence, Set, Tuple, Type, Union + +from pydantic.v1.typing import display_as_type + +if TYPE_CHECKING: + from pydantic.v1.typing import DictStrAny + +# explicitly state exports to avoid "from pydantic.v1.errors import *" also importing Decimal, Path etc. +__all__ = ( + 'PydanticTypeError', + 'PydanticValueError', + 'ConfigError', + 'MissingError', + 'ExtraError', + 'NoneIsNotAllowedError', + 'NoneIsAllowedError', + 'WrongConstantError', + 'NotNoneError', + 'BoolError', + 'BytesError', + 'DictError', + 'EmailError', + 'UrlError', + 'UrlSchemeError', + 'UrlSchemePermittedError', + 'UrlUserInfoError', + 'UrlHostError', + 'UrlHostTldError', + 'UrlPortError', + 'UrlExtraError', + 'EnumError', + 'IntEnumError', + 'EnumMemberError', + 'IntegerError', + 'FloatError', + 'PathError', + 'PathNotExistsError', + 'PathNotAFileError', + 'PathNotADirectoryError', + 'PyObjectError', + 'SequenceError', + 'ListError', + 'SetError', + 'FrozenSetError', + 'TupleError', + 'TupleLengthError', + 'ListMinLengthError', + 'ListMaxLengthError', + 'ListUniqueItemsError', + 'SetMinLengthError', + 'SetMaxLengthError', + 'FrozenSetMinLengthError', + 'FrozenSetMaxLengthError', + 'AnyStrMinLengthError', + 'AnyStrMaxLengthError', + 'StrError', + 'StrRegexError', + 'NumberNotGtError', + 'NumberNotGeError', + 'NumberNotLtError', + 'NumberNotLeError', + 'NumberNotMultipleError', + 'DecimalError', + 'DecimalIsNotFiniteError', + 'DecimalMaxDigitsError', + 'DecimalMaxPlacesError', + 'DecimalWholeDigitsError', + 'DateTimeError', + 'DateError', + 'DateNotInThePastError', + 'DateNotInTheFutureError', + 'TimeError', + 'DurationError', + 'HashableError', + 'UUIDError', + 'UUIDVersionError', + 'ArbitraryTypeError', + 'ClassError', + 'SubclassError', + 'JsonError', + 'JsonTypeError', + 'PatternError', + 'DataclassTypeError', + 'CallableError', + 'IPvAnyAddressError', + 'IPvAnyInterfaceError', + 'IPvAnyNetworkError', + 'IPv4AddressError', + 'IPv6AddressError', + 'IPv4NetworkError', + 'IPv6NetworkError', + 'IPv4InterfaceError', + 'IPv6InterfaceError', + 'ColorError', + 'StrictBoolError', + 'NotDigitError', + 'LuhnValidationError', + 'InvalidLengthForBrand', + 'InvalidByteSize', + 'InvalidByteSizeUnit', + 'MissingDiscriminator', + 'InvalidDiscriminator', +) + + +def cls_kwargs(cls: Type['PydanticErrorMixin'], ctx: 'DictStrAny') -> 'PydanticErrorMixin': + """ + For built-in exceptions like ValueError or TypeError, we need to implement + __reduce__ to override the default behaviour (instead of __getstate__/__setstate__) + By default pickle protocol 2 calls `cls.__new__(cls, *args)`. + Since we only use kwargs, we need a little constructor to change that. + Note: the callable can't be a lambda as pickle looks in the namespace to find it + """ + return cls(**ctx) + + +class PydanticErrorMixin: + code: str + msg_template: str + + def __init__(self, **ctx: Any) -> None: + self.__dict__ = ctx + + def __str__(self) -> str: + return self.msg_template.format(**self.__dict__) + + def __reduce__(self) -> Tuple[Callable[..., 'PydanticErrorMixin'], Tuple[Type['PydanticErrorMixin'], 'DictStrAny']]: + return cls_kwargs, (self.__class__, self.__dict__) + + +class PydanticTypeError(PydanticErrorMixin, TypeError): + pass + + +class PydanticValueError(PydanticErrorMixin, ValueError): + pass + + +class ConfigError(RuntimeError): + pass + + +class MissingError(PydanticValueError): + msg_template = 'field required' + + +class ExtraError(PydanticValueError): + msg_template = 'extra fields not permitted' + + +class NoneIsNotAllowedError(PydanticTypeError): + code = 'none.not_allowed' + msg_template = 'none is not an allowed value' + + +class NoneIsAllowedError(PydanticTypeError): + code = 'none.allowed' + msg_template = 'value is not none' + + +class WrongConstantError(PydanticValueError): + code = 'const' + + def __str__(self) -> str: + permitted = ', '.join(repr(v) for v in self.permitted) # type: ignore + return f'unexpected value; permitted: {permitted}' + + +class NotNoneError(PydanticTypeError): + code = 'not_none' + msg_template = 'value is not None' + + +class BoolError(PydanticTypeError): + msg_template = 'value could not be parsed to a boolean' + + +class BytesError(PydanticTypeError): + msg_template = 'byte type expected' + + +class DictError(PydanticTypeError): + msg_template = 'value is not a valid dict' + + +class EmailError(PydanticValueError): + msg_template = 'value is not a valid email address' + + +class UrlError(PydanticValueError): + code = 'url' + + +class UrlSchemeError(UrlError): + code = 'url.scheme' + msg_template = 'invalid or missing URL scheme' + + +class UrlSchemePermittedError(UrlError): + code = 'url.scheme' + msg_template = 'URL scheme not permitted' + + def __init__(self, allowed_schemes: Set[str]): + super().__init__(allowed_schemes=allowed_schemes) + + +class UrlUserInfoError(UrlError): + code = 'url.userinfo' + msg_template = 'userinfo required in URL but missing' + + +class UrlHostError(UrlError): + code = 'url.host' + msg_template = 'URL host invalid' + + +class UrlHostTldError(UrlError): + code = 'url.host' + msg_template = 'URL host invalid, top level domain required' + + +class UrlPortError(UrlError): + code = 'url.port' + msg_template = 'URL port invalid, port cannot exceed 65535' + + +class UrlExtraError(UrlError): + code = 'url.extra' + msg_template = 'URL invalid, extra characters found after valid URL: {extra!r}' + + +class EnumMemberError(PydanticTypeError): + code = 'enum' + + def __str__(self) -> str: + permitted = ', '.join(repr(v.value) for v in self.enum_values) # type: ignore + return f'value is not a valid enumeration member; permitted: {permitted}' + + +class IntegerError(PydanticTypeError): + msg_template = 'value is not a valid integer' + + +class FloatError(PydanticTypeError): + msg_template = 'value is not a valid float' + + +class PathError(PydanticTypeError): + msg_template = 'value is not a valid path' + + +class _PathValueError(PydanticValueError): + def __init__(self, *, path: Path) -> None: + super().__init__(path=str(path)) + + +class PathNotExistsError(_PathValueError): + code = 'path.not_exists' + msg_template = 'file or directory at path "{path}" does not exist' + + +class PathNotAFileError(_PathValueError): + code = 'path.not_a_file' + msg_template = 'path "{path}" does not point to a file' + + +class PathNotADirectoryError(_PathValueError): + code = 'path.not_a_directory' + msg_template = 'path "{path}" does not point to a directory' + + +class PyObjectError(PydanticTypeError): + msg_template = 'ensure this value contains valid import path or valid callable: {error_message}' + + +class SequenceError(PydanticTypeError): + msg_template = 'value is not a valid sequence' + + +class IterableError(PydanticTypeError): + msg_template = 'value is not a valid iterable' + + +class ListError(PydanticTypeError): + msg_template = 'value is not a valid list' + + +class SetError(PydanticTypeError): + msg_template = 'value is not a valid set' + + +class FrozenSetError(PydanticTypeError): + msg_template = 'value is not a valid frozenset' + + +class DequeError(PydanticTypeError): + msg_template = 'value is not a valid deque' + + +class TupleError(PydanticTypeError): + msg_template = 'value is not a valid tuple' + + +class TupleLengthError(PydanticValueError): + code = 'tuple.length' + msg_template = 'wrong tuple length {actual_length}, expected {expected_length}' + + def __init__(self, *, actual_length: int, expected_length: int) -> None: + super().__init__(actual_length=actual_length, expected_length=expected_length) + + +class ListMinLengthError(PydanticValueError): + code = 'list.min_items' + msg_template = 'ensure this value has at least {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class ListMaxLengthError(PydanticValueError): + code = 'list.max_items' + msg_template = 'ensure this value has at most {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class ListUniqueItemsError(PydanticValueError): + code = 'list.unique_items' + msg_template = 'the list has duplicated items' + + +class SetMinLengthError(PydanticValueError): + code = 'set.min_items' + msg_template = 'ensure this value has at least {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class SetMaxLengthError(PydanticValueError): + code = 'set.max_items' + msg_template = 'ensure this value has at most {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class FrozenSetMinLengthError(PydanticValueError): + code = 'frozenset.min_items' + msg_template = 'ensure this value has at least {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class FrozenSetMaxLengthError(PydanticValueError): + code = 'frozenset.max_items' + msg_template = 'ensure this value has at most {limit_value} items' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class AnyStrMinLengthError(PydanticValueError): + code = 'any_str.min_length' + msg_template = 'ensure this value has at least {limit_value} characters' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class AnyStrMaxLengthError(PydanticValueError): + code = 'any_str.max_length' + msg_template = 'ensure this value has at most {limit_value} characters' + + def __init__(self, *, limit_value: int) -> None: + super().__init__(limit_value=limit_value) + + +class StrError(PydanticTypeError): + msg_template = 'str type expected' + + +class StrRegexError(PydanticValueError): + code = 'str.regex' + msg_template = 'string does not match regex "{pattern}"' + + def __init__(self, *, pattern: str) -> None: + super().__init__(pattern=pattern) + + +class _NumberBoundError(PydanticValueError): + def __init__(self, *, limit_value: Union[int, float, Decimal]) -> None: + super().__init__(limit_value=limit_value) + + +class NumberNotGtError(_NumberBoundError): + code = 'number.not_gt' + msg_template = 'ensure this value is greater than {limit_value}' + + +class NumberNotGeError(_NumberBoundError): + code = 'number.not_ge' + msg_template = 'ensure this value is greater than or equal to {limit_value}' + + +class NumberNotLtError(_NumberBoundError): + code = 'number.not_lt' + msg_template = 'ensure this value is less than {limit_value}' + + +class NumberNotLeError(_NumberBoundError): + code = 'number.not_le' + msg_template = 'ensure this value is less than or equal to {limit_value}' + + +class NumberNotFiniteError(PydanticValueError): + code = 'number.not_finite_number' + msg_template = 'ensure this value is a finite number' + + +class NumberNotMultipleError(PydanticValueError): + code = 'number.not_multiple' + msg_template = 'ensure this value is a multiple of {multiple_of}' + + def __init__(self, *, multiple_of: Union[int, float, Decimal]) -> None: + super().__init__(multiple_of=multiple_of) + + +class DecimalError(PydanticTypeError): + msg_template = 'value is not a valid decimal' + + +class DecimalIsNotFiniteError(PydanticValueError): + code = 'decimal.not_finite' + msg_template = 'value is not a valid decimal' + + +class DecimalMaxDigitsError(PydanticValueError): + code = 'decimal.max_digits' + msg_template = 'ensure that there are no more than {max_digits} digits in total' + + def __init__(self, *, max_digits: int) -> None: + super().__init__(max_digits=max_digits) + + +class DecimalMaxPlacesError(PydanticValueError): + code = 'decimal.max_places' + msg_template = 'ensure that there are no more than {decimal_places} decimal places' + + def __init__(self, *, decimal_places: int) -> None: + super().__init__(decimal_places=decimal_places) + + +class DecimalWholeDigitsError(PydanticValueError): + code = 'decimal.whole_digits' + msg_template = 'ensure that there are no more than {whole_digits} digits before the decimal point' + + def __init__(self, *, whole_digits: int) -> None: + super().__init__(whole_digits=whole_digits) + + +class DateTimeError(PydanticValueError): + msg_template = 'invalid datetime format' + + +class DateError(PydanticValueError): + msg_template = 'invalid date format' + + +class DateNotInThePastError(PydanticValueError): + code = 'date.not_in_the_past' + msg_template = 'date is not in the past' + + +class DateNotInTheFutureError(PydanticValueError): + code = 'date.not_in_the_future' + msg_template = 'date is not in the future' + + +class TimeError(PydanticValueError): + msg_template = 'invalid time format' + + +class DurationError(PydanticValueError): + msg_template = 'invalid duration format' + + +class HashableError(PydanticTypeError): + msg_template = 'value is not a valid hashable' + + +class UUIDError(PydanticTypeError): + msg_template = 'value is not a valid uuid' + + +class UUIDVersionError(PydanticValueError): + code = 'uuid.version' + msg_template = 'uuid version {required_version} expected' + + def __init__(self, *, required_version: int) -> None: + super().__init__(required_version=required_version) + + +class ArbitraryTypeError(PydanticTypeError): + code = 'arbitrary_type' + msg_template = 'instance of {expected_arbitrary_type} expected' + + def __init__(self, *, expected_arbitrary_type: Type[Any]) -> None: + super().__init__(expected_arbitrary_type=display_as_type(expected_arbitrary_type)) + + +class ClassError(PydanticTypeError): + code = 'class' + msg_template = 'a class is expected' + + +class SubclassError(PydanticTypeError): + code = 'subclass' + msg_template = 'subclass of {expected_class} expected' + + def __init__(self, *, expected_class: Type[Any]) -> None: + super().__init__(expected_class=display_as_type(expected_class)) + + +class JsonError(PydanticValueError): + msg_template = 'Invalid JSON' + + +class JsonTypeError(PydanticTypeError): + code = 'json' + msg_template = 'JSON object must be str, bytes or bytearray' + + +class PatternError(PydanticValueError): + code = 'regex_pattern' + msg_template = 'Invalid regular expression' + + +class DataclassTypeError(PydanticTypeError): + code = 'dataclass' + msg_template = 'instance of {class_name}, tuple or dict expected' + + +class CallableError(PydanticTypeError): + msg_template = '{value} is not callable' + + +class EnumError(PydanticTypeError): + code = 'enum_instance' + msg_template = '{value} is not a valid Enum instance' + + +class IntEnumError(PydanticTypeError): + code = 'int_enum_instance' + msg_template = '{value} is not a valid IntEnum instance' + + +class IPvAnyAddressError(PydanticValueError): + msg_template = 'value is not a valid IPv4 or IPv6 address' + + +class IPvAnyInterfaceError(PydanticValueError): + msg_template = 'value is not a valid IPv4 or IPv6 interface' + + +class IPvAnyNetworkError(PydanticValueError): + msg_template = 'value is not a valid IPv4 or IPv6 network' + + +class IPv4AddressError(PydanticValueError): + msg_template = 'value is not a valid IPv4 address' + + +class IPv6AddressError(PydanticValueError): + msg_template = 'value is not a valid IPv6 address' + + +class IPv4NetworkError(PydanticValueError): + msg_template = 'value is not a valid IPv4 network' + + +class IPv6NetworkError(PydanticValueError): + msg_template = 'value is not a valid IPv6 network' + + +class IPv4InterfaceError(PydanticValueError): + msg_template = 'value is not a valid IPv4 interface' + + +class IPv6InterfaceError(PydanticValueError): + msg_template = 'value is not a valid IPv6 interface' + + +class ColorError(PydanticValueError): + msg_template = 'value is not a valid color: {reason}' + + +class StrictBoolError(PydanticValueError): + msg_template = 'value is not a valid boolean' + + +class NotDigitError(PydanticValueError): + code = 'payment_card_number.digits' + msg_template = 'card number is not all digits' + + +class LuhnValidationError(PydanticValueError): + code = 'payment_card_number.luhn_check' + msg_template = 'card number is not luhn valid' + + +class InvalidLengthForBrand(PydanticValueError): + code = 'payment_card_number.invalid_length_for_brand' + msg_template = 'Length for a {brand} card must be {required_length}' + + +class InvalidByteSize(PydanticValueError): + msg_template = 'could not parse value and unit from byte string' + + +class InvalidByteSizeUnit(PydanticValueError): + msg_template = 'could not interpret byte unit: {unit}' + + +class MissingDiscriminator(PydanticValueError): + code = 'discriminated_union.missing_discriminator' + msg_template = 'Discriminator {discriminator_key!r} is missing in value' + + +class InvalidDiscriminator(PydanticValueError): + code = 'discriminated_union.invalid_discriminator' + msg_template = ( + 'No match for discriminator {discriminator_key!r} and value {discriminator_value!r} ' + '(allowed values: {allowed_values})' + ) + + def __init__(self, *, discriminator_key: str, discriminator_value: Any, allowed_values: Sequence[Any]) -> None: + super().__init__( + discriminator_key=discriminator_key, + discriminator_value=discriminator_value, + allowed_values=', '.join(map(repr, allowed_values)), + ) diff --git a/source/target-vendors/cp312/pydantic/v1/fields.py b/source/target-vendors/cp312/pydantic/v1/fields.py new file mode 100644 index 0000000..002b60c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/fields.py @@ -0,0 +1,1253 @@ +import copy +import re +from collections import Counter as CollectionCounter, defaultdict, deque +from collections.abc import Callable, Hashable as CollectionsHashable, Iterable as CollectionsIterable +from typing import ( + TYPE_CHECKING, + Any, + Counter, + DefaultDict, + Deque, + Dict, + ForwardRef, + FrozenSet, + Generator, + Iterable, + Iterator, + List, + Mapping, + Optional, + Pattern, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, +) + +from typing_extensions import Annotated, Final + +from pydantic.v1 import errors as errors_ +from pydantic.v1.class_validators import Validator, make_generic_validator, prep_validators +from pydantic.v1.error_wrappers import ErrorWrapper +from pydantic.v1.errors import ConfigError, InvalidDiscriminator, MissingDiscriminator, NoneIsNotAllowedError +from pydantic.v1.types import Json, JsonWrapper +from pydantic.v1.typing import ( + NoArgAnyCallable, + convert_generics, + display_as_type, + get_args, + get_origin, + is_finalvar, + is_literal_type, + is_new_type, + is_none_type, + is_typeddict, + is_typeddict_special, + is_union, + new_type_supertype, +) +from pydantic.v1.utils import ( + PyObjectStr, + Representation, + ValueItems, + get_discriminator_alias_and_values, + get_unique_discriminator_alias, + lenient_isinstance, + lenient_issubclass, + sequence_like, + smart_deepcopy, +) +from pydantic.v1.validators import constant_validator, dict_validator, find_validators, validate_json + +Required: Any = Ellipsis + +T = TypeVar('T') + + +class UndefinedType: + def __repr__(self) -> str: + return 'PydanticUndefined' + + def __copy__(self: T) -> T: + return self + + def __reduce__(self) -> str: + return 'Undefined' + + def __deepcopy__(self: T, _: Any) -> T: + return self + + +Undefined = UndefinedType() + +if TYPE_CHECKING: + from pydantic.v1.class_validators import ValidatorsList + from pydantic.v1.config import BaseConfig + from pydantic.v1.error_wrappers import ErrorList + from pydantic.v1.types import ModelOrDc + from pydantic.v1.typing import AbstractSetIntStr, MappingIntStrAny, ReprArgs + + ValidateReturn = Tuple[Optional[Any], Optional[ErrorList]] + LocStr = Union[Tuple[Union[int, str], ...], str] + BoolUndefined = Union[bool, UndefinedType] + + +class FieldInfo(Representation): + """ + Captures extra information about a field. + """ + + __slots__ = ( + 'default', + 'default_factory', + 'alias', + 'alias_priority', + 'title', + 'description', + 'exclude', + 'include', + 'const', + 'gt', + 'ge', + 'lt', + 'le', + 'multiple_of', + 'allow_inf_nan', + 'max_digits', + 'decimal_places', + 'min_items', + 'max_items', + 'unique_items', + 'min_length', + 'max_length', + 'allow_mutation', + 'repr', + 'regex', + 'discriminator', + 'extra', + ) + + # field constraints with the default value, it's also used in update_from_config below + __field_constraints__ = { + 'min_length': None, + 'max_length': None, + 'regex': None, + 'gt': None, + 'lt': None, + 'ge': None, + 'le': None, + 'multiple_of': None, + 'allow_inf_nan': None, + 'max_digits': None, + 'decimal_places': None, + 'min_items': None, + 'max_items': None, + 'unique_items': None, + 'allow_mutation': True, + } + + def __init__(self, default: Any = Undefined, **kwargs: Any) -> None: + self.default = default + self.default_factory = kwargs.pop('default_factory', None) + self.alias = kwargs.pop('alias', None) + self.alias_priority = kwargs.pop('alias_priority', 2 if self.alias is not None else None) + self.title = kwargs.pop('title', None) + self.description = kwargs.pop('description', None) + self.exclude = kwargs.pop('exclude', None) + self.include = kwargs.pop('include', None) + self.const = kwargs.pop('const', None) + self.gt = kwargs.pop('gt', None) + self.ge = kwargs.pop('ge', None) + self.lt = kwargs.pop('lt', None) + self.le = kwargs.pop('le', None) + self.multiple_of = kwargs.pop('multiple_of', None) + self.allow_inf_nan = kwargs.pop('allow_inf_nan', None) + self.max_digits = kwargs.pop('max_digits', None) + self.decimal_places = kwargs.pop('decimal_places', None) + self.min_items = kwargs.pop('min_items', None) + self.max_items = kwargs.pop('max_items', None) + self.unique_items = kwargs.pop('unique_items', None) + self.min_length = kwargs.pop('min_length', None) + self.max_length = kwargs.pop('max_length', None) + self.allow_mutation = kwargs.pop('allow_mutation', True) + self.regex = kwargs.pop('regex', None) + self.discriminator = kwargs.pop('discriminator', None) + self.repr = kwargs.pop('repr', True) + self.extra = kwargs + + def __repr_args__(self) -> 'ReprArgs': + field_defaults_to_hide: Dict[str, Any] = { + 'repr': True, + **self.__field_constraints__, + } + + attrs = ((s, getattr(self, s)) for s in self.__slots__) + return [(a, v) for a, v in attrs if v != field_defaults_to_hide.get(a, None)] + + def get_constraints(self) -> Set[str]: + """ + Gets the constraints set on the field by comparing the constraint value with its default value + + :return: the constraints set on field_info + """ + return {attr for attr, default in self.__field_constraints__.items() if getattr(self, attr) != default} + + def update_from_config(self, from_config: Dict[str, Any]) -> None: + """ + Update this FieldInfo based on a dict from get_field_info, only fields which have not been set are dated. + """ + for attr_name, value in from_config.items(): + try: + current_value = getattr(self, attr_name) + except AttributeError: + # attr_name is not an attribute of FieldInfo, it should therefore be added to extra + # (except if extra already has this value!) + self.extra.setdefault(attr_name, value) + else: + if current_value is self.__field_constraints__.get(attr_name, None): + setattr(self, attr_name, value) + elif attr_name == 'exclude': + self.exclude = ValueItems.merge(value, current_value) + elif attr_name == 'include': + self.include = ValueItems.merge(value, current_value, intersect=True) + + def _validate(self) -> None: + if self.default is not Undefined and self.default_factory is not None: + raise ValueError('cannot specify both default and default_factory') + + +def Field( + default: Any = Undefined, + *, + default_factory: Optional[NoArgAnyCallable] = None, + alias: Optional[str] = None, + title: Optional[str] = None, + description: Optional[str] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny', Any]] = None, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny', Any]] = None, + const: Optional[bool] = None, + gt: Optional[float] = None, + ge: Optional[float] = None, + lt: Optional[float] = None, + le: Optional[float] = None, + multiple_of: Optional[float] = None, + allow_inf_nan: Optional[bool] = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, + min_items: Optional[int] = None, + max_items: Optional[int] = None, + unique_items: Optional[bool] = None, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + allow_mutation: bool = True, + regex: Optional[str] = None, + discriminator: Optional[str] = None, + repr: bool = True, + **extra: Any, +) -> Any: + """ + Used to provide extra information about a field, either for the model schema or complex validation. Some arguments + apply only to number fields (``int``, ``float``, ``Decimal``) and some apply only to ``str``. + + :param default: since this is replacing the field’s default, its first argument is used + to set the default, use ellipsis (``...``) to indicate the field is required + :param default_factory: callable that will be called when a default value is needed for this field + If both `default` and `default_factory` are set, an error is raised. + :param alias: the public name of the field + :param title: can be any string, used in the schema + :param description: can be any string, used in the schema + :param exclude: exclude this field while dumping. + Takes same values as the ``include`` and ``exclude`` arguments on the ``.dict`` method. + :param include: include this field while dumping. + Takes same values as the ``include`` and ``exclude`` arguments on the ``.dict`` method. + :param const: this field is required and *must* take it's default value + :param gt: only applies to numbers, requires the field to be "greater than". The schema + will have an ``exclusiveMinimum`` validation keyword + :param ge: only applies to numbers, requires the field to be "greater than or equal to". The + schema will have a ``minimum`` validation keyword + :param lt: only applies to numbers, requires the field to be "less than". The schema + will have an ``exclusiveMaximum`` validation keyword + :param le: only applies to numbers, requires the field to be "less than or equal to". The + schema will have a ``maximum`` validation keyword + :param multiple_of: only applies to numbers, requires the field to be "a multiple of". The + schema will have a ``multipleOf`` validation keyword + :param allow_inf_nan: only applies to numbers, allows the field to be NaN or infinity (+inf or -inf), + which is a valid Python float. Default True, set to False for compatibility with JSON. + :param max_digits: only applies to Decimals, requires the field to have a maximum number + of digits within the decimal. It does not include a zero before the decimal point or trailing decimal zeroes. + :param decimal_places: only applies to Decimals, requires the field to have at most a number of decimal places + allowed. It does not include trailing decimal zeroes. + :param min_items: only applies to lists, requires the field to have a minimum number of + elements. The schema will have a ``minItems`` validation keyword + :param max_items: only applies to lists, requires the field to have a maximum number of + elements. The schema will have a ``maxItems`` validation keyword + :param unique_items: only applies to lists, requires the field not to have duplicated + elements. The schema will have a ``uniqueItems`` validation keyword + :param min_length: only applies to strings, requires the field to have a minimum length. The + schema will have a ``minLength`` validation keyword + :param max_length: only applies to strings, requires the field to have a maximum length. The + schema will have a ``maxLength`` validation keyword + :param allow_mutation: a boolean which defaults to True. When False, the field raises a TypeError if the field is + assigned on an instance. The BaseModel Config must set validate_assignment to True + :param regex: only applies to strings, requires the field match against a regular expression + pattern string. The schema will have a ``pattern`` validation keyword + :param discriminator: only useful with a (discriminated a.k.a. tagged) `Union` of sub models with a common field. + The `discriminator` is the name of this common field to shorten validation and improve generated schema + :param repr: show this field in the representation + :param **extra: any additional keyword arguments will be added as is to the schema + """ + field_info = FieldInfo( + default, + default_factory=default_factory, + alias=alias, + title=title, + description=description, + exclude=exclude, + include=include, + const=const, + gt=gt, + ge=ge, + lt=lt, + le=le, + multiple_of=multiple_of, + allow_inf_nan=allow_inf_nan, + max_digits=max_digits, + decimal_places=decimal_places, + min_items=min_items, + max_items=max_items, + unique_items=unique_items, + min_length=min_length, + max_length=max_length, + allow_mutation=allow_mutation, + regex=regex, + discriminator=discriminator, + repr=repr, + **extra, + ) + field_info._validate() + return field_info + + +# used to be an enum but changed to int's for small performance improvement as less access overhead +SHAPE_SINGLETON = 1 +SHAPE_LIST = 2 +SHAPE_SET = 3 +SHAPE_MAPPING = 4 +SHAPE_TUPLE = 5 +SHAPE_TUPLE_ELLIPSIS = 6 +SHAPE_SEQUENCE = 7 +SHAPE_FROZENSET = 8 +SHAPE_ITERABLE = 9 +SHAPE_GENERIC = 10 +SHAPE_DEQUE = 11 +SHAPE_DICT = 12 +SHAPE_DEFAULTDICT = 13 +SHAPE_COUNTER = 14 +SHAPE_NAME_LOOKUP = { + SHAPE_LIST: 'List[{}]', + SHAPE_SET: 'Set[{}]', + SHAPE_TUPLE_ELLIPSIS: 'Tuple[{}, ...]', + SHAPE_SEQUENCE: 'Sequence[{}]', + SHAPE_FROZENSET: 'FrozenSet[{}]', + SHAPE_ITERABLE: 'Iterable[{}]', + SHAPE_DEQUE: 'Deque[{}]', + SHAPE_DICT: 'Dict[{}]', + SHAPE_DEFAULTDICT: 'DefaultDict[{}]', + SHAPE_COUNTER: 'Counter[{}]', +} + +MAPPING_LIKE_SHAPES: Set[int] = {SHAPE_DEFAULTDICT, SHAPE_DICT, SHAPE_MAPPING, SHAPE_COUNTER} + + +class ModelField(Representation): + __slots__ = ( + 'type_', + 'outer_type_', + 'annotation', + 'sub_fields', + 'sub_fields_mapping', + 'key_field', + 'validators', + 'pre_validators', + 'post_validators', + 'default', + 'default_factory', + 'required', + 'final', + 'model_config', + 'name', + 'alias', + 'has_alias', + 'field_info', + 'discriminator_key', + 'discriminator_alias', + 'validate_always', + 'allow_none', + 'shape', + 'class_validators', + 'parse_json', + ) + + def __init__( + self, + *, + name: str, + type_: Type[Any], + class_validators: Optional[Dict[str, Validator]], + model_config: Type['BaseConfig'], + default: Any = None, + default_factory: Optional[NoArgAnyCallable] = None, + required: 'BoolUndefined' = Undefined, + final: bool = False, + alias: Optional[str] = None, + field_info: Optional[FieldInfo] = None, + ) -> None: + self.name: str = name + self.has_alias: bool = alias is not None + self.alias: str = alias if alias is not None else name + self.annotation = type_ + self.type_: Any = convert_generics(type_) + self.outer_type_: Any = type_ + self.class_validators = class_validators or {} + self.default: Any = default + self.default_factory: Optional[NoArgAnyCallable] = default_factory + self.required: 'BoolUndefined' = required + self.final: bool = final + self.model_config = model_config + self.field_info: FieldInfo = field_info or FieldInfo(default) + self.discriminator_key: Optional[str] = self.field_info.discriminator + self.discriminator_alias: Optional[str] = self.discriminator_key + + self.allow_none: bool = False + self.validate_always: bool = False + self.sub_fields: Optional[List[ModelField]] = None + self.sub_fields_mapping: Optional[Dict[str, 'ModelField']] = None # used for discriminated union + self.key_field: Optional[ModelField] = None + self.validators: 'ValidatorsList' = [] + self.pre_validators: Optional['ValidatorsList'] = None + self.post_validators: Optional['ValidatorsList'] = None + self.parse_json: bool = False + self.shape: int = SHAPE_SINGLETON + self.model_config.prepare_field(self) + self.prepare() + + def get_default(self) -> Any: + return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory() + + @staticmethod + def _get_field_info( + field_name: str, annotation: Any, value: Any, config: Type['BaseConfig'] + ) -> Tuple[FieldInfo, Any]: + """ + Get a FieldInfo from a root typing.Annotated annotation, value, or config default. + + The FieldInfo may be set in typing.Annotated or the value, but not both. If neither contain + a FieldInfo, a new one will be created using the config. + + :param field_name: name of the field for use in error messages + :param annotation: a type hint such as `str` or `Annotated[str, Field(..., min_length=5)]` + :param value: the field's assigned value + :param config: the model's config object + :return: the FieldInfo contained in the `annotation`, the value, or a new one from the config. + """ + field_info_from_config = config.get_field_info(field_name) + + field_info = None + if get_origin(annotation) is Annotated: + field_infos = [arg for arg in get_args(annotation)[1:] if isinstance(arg, FieldInfo)] + if len(field_infos) > 1: + raise ValueError(f'cannot specify multiple `Annotated` `Field`s for {field_name!r}') + field_info = next(iter(field_infos), None) + if field_info is not None: + field_info = copy.copy(field_info) + field_info.update_from_config(field_info_from_config) + if field_info.default not in (Undefined, Required): + raise ValueError(f'`Field` default cannot be set in `Annotated` for {field_name!r}') + if value is not Undefined and value is not Required: + # check also `Required` because of `validate_arguments` that sets `...` as default value + field_info.default = value + + if isinstance(value, FieldInfo): + if field_info is not None: + raise ValueError(f'cannot specify `Annotated` and value `Field`s together for {field_name!r}') + field_info = value + field_info.update_from_config(field_info_from_config) + elif field_info is None: + field_info = FieldInfo(value, **field_info_from_config) + value = None if field_info.default_factory is not None else field_info.default + field_info._validate() + return field_info, value + + @classmethod + def infer( + cls, + *, + name: str, + value: Any, + annotation: Any, + class_validators: Optional[Dict[str, Validator]], + config: Type['BaseConfig'], + ) -> 'ModelField': + from pydantic.v1.schema import get_annotation_from_field_info + + field_info, value = cls._get_field_info(name, annotation, value, config) + required: 'BoolUndefined' = Undefined + if value is Required: + required = True + value = None + elif value is not Undefined: + required = False + annotation = get_annotation_from_field_info(annotation, field_info, name, config.validate_assignment) + + return cls( + name=name, + type_=annotation, + alias=field_info.alias, + class_validators=class_validators, + default=value, + default_factory=field_info.default_factory, + required=required, + model_config=config, + field_info=field_info, + ) + + def set_config(self, config: Type['BaseConfig']) -> None: + self.model_config = config + info_from_config = config.get_field_info(self.name) + config.prepare_field(self) + new_alias = info_from_config.get('alias') + new_alias_priority = info_from_config.get('alias_priority') or 0 + if new_alias and new_alias_priority >= (self.field_info.alias_priority or 0): + self.field_info.alias = new_alias + self.field_info.alias_priority = new_alias_priority + self.alias = new_alias + new_exclude = info_from_config.get('exclude') + if new_exclude is not None: + self.field_info.exclude = ValueItems.merge(self.field_info.exclude, new_exclude) + new_include = info_from_config.get('include') + if new_include is not None: + self.field_info.include = ValueItems.merge(self.field_info.include, new_include, intersect=True) + + @property + def alt_alias(self) -> bool: + return self.name != self.alias + + def prepare(self) -> None: + """ + Prepare the field but inspecting self.default, self.type_ etc. + + Note: this method is **not** idempotent (because _type_analysis is not idempotent), + e.g. calling it it multiple times may modify the field and configure it incorrectly. + """ + self._set_default_and_type() + if self.type_.__class__ is ForwardRef or self.type_.__class__ is DeferredType: + # self.type_ is currently a ForwardRef and there's nothing we can do now, + # user will need to call model.update_forward_refs() + return + + self._type_analysis() + if self.required is Undefined: + self.required = True + if self.default is Undefined and self.default_factory is None: + self.default = None + self.populate_validators() + + def _set_default_and_type(self) -> None: + """ + Set the default value, infer the type if needed and check if `None` value is valid. + """ + if self.default_factory is not None: + if self.type_ is Undefined: + raise errors_.ConfigError( + f'you need to set the type of field {self.name!r} when using `default_factory`' + ) + return + + default_value = self.get_default() + + if default_value is not None and self.type_ is Undefined: + self.type_ = default_value.__class__ + self.outer_type_ = self.type_ + self.annotation = self.type_ + + if self.type_ is Undefined: + raise errors_.ConfigError(f'unable to infer type for attribute "{self.name}"') + + if self.required is False and default_value is None: + self.allow_none = True + + def _type_analysis(self) -> None: # noqa: C901 (ignore complexity) + # typing interface is horrible, we have to do some ugly checks + if lenient_issubclass(self.type_, JsonWrapper): + self.type_ = self.type_.inner_type + self.parse_json = True + elif lenient_issubclass(self.type_, Json): + self.type_ = Any + self.parse_json = True + elif isinstance(self.type_, TypeVar): + if self.type_.__bound__: + self.type_ = self.type_.__bound__ + elif self.type_.__constraints__: + self.type_ = Union[self.type_.__constraints__] + else: + self.type_ = Any + elif is_new_type(self.type_): + self.type_ = new_type_supertype(self.type_) + + if self.type_ is Any or self.type_ is object: + if self.required is Undefined: + self.required = False + self.allow_none = True + return + elif self.type_ is Pattern or self.type_ is re.Pattern: + # python 3.7 only, Pattern is a typing object but without sub fields + return + elif is_literal_type(self.type_): + return + elif is_typeddict(self.type_): + return + + if is_finalvar(self.type_): + self.final = True + + if self.type_ is Final: + self.type_ = Any + else: + self.type_ = get_args(self.type_)[0] + + self._type_analysis() + return + + origin = get_origin(self.type_) + + if origin is Annotated or is_typeddict_special(origin): + self.type_ = get_args(self.type_)[0] + self._type_analysis() + return + + if self.discriminator_key is not None and not is_union(origin): + raise TypeError('`discriminator` can only be used with `Union` type with more than one variant') + + # add extra check for `collections.abc.Hashable` for python 3.10+ where origin is not `None` + if origin is None or origin is CollectionsHashable: + # field is not "typing" object eg. Union, Dict, List etc. + # allow None for virtual superclasses of NoneType, e.g. Hashable + if isinstance(self.type_, type) and isinstance(None, self.type_): + self.allow_none = True + return + elif origin is Callable: + return + elif is_union(origin): + types_ = [] + for type_ in get_args(self.type_): + if is_none_type(type_) or type_ is Any or type_ is object: + if self.required is Undefined: + self.required = False + self.allow_none = True + if is_none_type(type_): + continue + types_.append(type_) + + if len(types_) == 1: + # Optional[] + self.type_ = types_[0] + # this is the one case where the "outer type" isn't just the original type + self.outer_type_ = self.type_ + # re-run to correctly interpret the new self.type_ + self._type_analysis() + else: + self.sub_fields = [self._create_sub_type(t, f'{self.name}_{display_as_type(t)}') for t in types_] + + if self.discriminator_key is not None: + self.prepare_discriminated_union_sub_fields() + return + elif issubclass(origin, Tuple): # type: ignore + # origin == Tuple without item type + args = get_args(self.type_) + if not args: # plain tuple + self.type_ = Any + self.shape = SHAPE_TUPLE_ELLIPSIS + elif len(args) == 2 and args[1] is Ellipsis: # e.g. Tuple[int, ...] + self.type_ = args[0] + self.shape = SHAPE_TUPLE_ELLIPSIS + self.sub_fields = [self._create_sub_type(args[0], f'{self.name}_0')] + elif args == ((),): # Tuple[()] means empty tuple + self.shape = SHAPE_TUPLE + self.type_ = Any + self.sub_fields = [] + else: + self.shape = SHAPE_TUPLE + self.sub_fields = [self._create_sub_type(t, f'{self.name}_{i}') for i, t in enumerate(args)] + return + elif issubclass(origin, List): + # Create self validators + get_validators = getattr(self.type_, '__get_validators__', None) + if get_validators: + self.class_validators.update( + {f'list_{i}': Validator(validator, pre=True) for i, validator in enumerate(get_validators())} + ) + + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_LIST + elif issubclass(origin, Set): + # Create self validators + get_validators = getattr(self.type_, '__get_validators__', None) + if get_validators: + self.class_validators.update( + {f'set_{i}': Validator(validator, pre=True) for i, validator in enumerate(get_validators())} + ) + + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_SET + elif issubclass(origin, FrozenSet): + # Create self validators + get_validators = getattr(self.type_, '__get_validators__', None) + if get_validators: + self.class_validators.update( + {f'frozenset_{i}': Validator(validator, pre=True) for i, validator in enumerate(get_validators())} + ) + + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_FROZENSET + elif issubclass(origin, Deque): + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_DEQUE + elif issubclass(origin, Sequence): + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_SEQUENCE + # priority to most common mapping: dict + elif origin is dict or origin is Dict: + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = get_args(self.type_)[1] + self.shape = SHAPE_DICT + elif issubclass(origin, DefaultDict): + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = get_args(self.type_)[1] + self.shape = SHAPE_DEFAULTDICT + elif issubclass(origin, Counter): + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = int + self.shape = SHAPE_COUNTER + elif issubclass(origin, Mapping): + self.key_field = self._create_sub_type(get_args(self.type_)[0], 'key_' + self.name, for_keys=True) + self.type_ = get_args(self.type_)[1] + self.shape = SHAPE_MAPPING + # Equality check as almost everything inherits form Iterable, including str + # check for Iterable and CollectionsIterable, as it could receive one even when declared with the other + elif origin in {Iterable, CollectionsIterable}: + self.type_ = get_args(self.type_)[0] + self.shape = SHAPE_ITERABLE + self.sub_fields = [self._create_sub_type(self.type_, f'{self.name}_type')] + elif issubclass(origin, Type): # type: ignore + return + elif hasattr(origin, '__get_validators__') or self.model_config.arbitrary_types_allowed: + # Is a Pydantic-compatible generic that handles itself + # or we have arbitrary_types_allowed = True + self.shape = SHAPE_GENERIC + self.sub_fields = [self._create_sub_type(t, f'{self.name}_{i}') for i, t in enumerate(get_args(self.type_))] + self.type_ = origin + return + else: + raise TypeError(f'Fields of type "{origin}" are not supported.') + + # type_ has been refined eg. as the type of a List and sub_fields needs to be populated + self.sub_fields = [self._create_sub_type(self.type_, '_' + self.name)] + + def prepare_discriminated_union_sub_fields(self) -> None: + """ + Prepare the mapping -> and update `sub_fields` + Note that this process can be aborted if a `ForwardRef` is encountered + """ + assert self.discriminator_key is not None + + if self.type_.__class__ is DeferredType: + return + + assert self.sub_fields is not None + sub_fields_mapping: Dict[str, 'ModelField'] = {} + all_aliases: Set[str] = set() + + for sub_field in self.sub_fields: + t = sub_field.type_ + if t.__class__ is ForwardRef: + # Stopping everything...will need to call `update_forward_refs` + return + + alias, discriminator_values = get_discriminator_alias_and_values(t, self.discriminator_key) + all_aliases.add(alias) + for discriminator_value in discriminator_values: + sub_fields_mapping[discriminator_value] = sub_field + + self.sub_fields_mapping = sub_fields_mapping + self.discriminator_alias = get_unique_discriminator_alias(all_aliases, self.discriminator_key) + + def _create_sub_type(self, type_: Type[Any], name: str, *, for_keys: bool = False) -> 'ModelField': + if for_keys: + class_validators = None + else: + # validators for sub items should not have `each_item` as we want to check only the first sublevel + class_validators = { + k: Validator( + func=v.func, + pre=v.pre, + each_item=False, + always=v.always, + check_fields=v.check_fields, + skip_on_failure=v.skip_on_failure, + ) + for k, v in self.class_validators.items() + if v.each_item + } + + field_info, _ = self._get_field_info(name, type_, None, self.model_config) + + return self.__class__( + type_=type_, + name=name, + class_validators=class_validators, + model_config=self.model_config, + field_info=field_info, + ) + + def populate_validators(self) -> None: + """ + Prepare self.pre_validators, self.validators, and self.post_validators based on self.type_'s __get_validators__ + and class validators. This method should be idempotent, e.g. it should be safe to call multiple times + without mis-configuring the field. + """ + self.validate_always = getattr(self.type_, 'validate_always', False) or any( + v.always for v in self.class_validators.values() + ) + + class_validators_ = self.class_validators.values() + if not self.sub_fields or self.shape == SHAPE_GENERIC: + get_validators = getattr(self.type_, '__get_validators__', None) + v_funcs = ( + *[v.func for v in class_validators_ if v.each_item and v.pre], + *(get_validators() if get_validators else list(find_validators(self.type_, self.model_config))), + *[v.func for v in class_validators_ if v.each_item and not v.pre], + ) + self.validators = prep_validators(v_funcs) + + self.pre_validators = [] + self.post_validators = [] + + if self.field_info and self.field_info.const: + self.post_validators.append(make_generic_validator(constant_validator)) + + if class_validators_: + self.pre_validators += prep_validators(v.func for v in class_validators_ if not v.each_item and v.pre) + self.post_validators += prep_validators(v.func for v in class_validators_ if not v.each_item and not v.pre) + + if self.parse_json: + self.pre_validators.append(make_generic_validator(validate_json)) + + self.pre_validators = self.pre_validators or None + self.post_validators = self.post_validators or None + + def validate( + self, v: Any, values: Dict[str, Any], *, loc: 'LocStr', cls: Optional['ModelOrDc'] = None + ) -> 'ValidateReturn': + assert self.type_.__class__ is not DeferredType + + if self.type_.__class__ is ForwardRef: + assert cls is not None + raise ConfigError( + f'field "{self.name}" not yet prepared so type is still a ForwardRef, ' + f'you might need to call {cls.__name__}.update_forward_refs().' + ) + + errors: Optional['ErrorList'] + if self.pre_validators: + v, errors = self._apply_validators(v, values, loc, cls, self.pre_validators) + if errors: + return v, errors + + if v is None: + if is_none_type(self.type_): + # keep validating + pass + elif self.allow_none: + if self.post_validators: + return self._apply_validators(v, values, loc, cls, self.post_validators) + else: + return None, None + else: + return v, ErrorWrapper(NoneIsNotAllowedError(), loc) + + if self.shape == SHAPE_SINGLETON: + v, errors = self._validate_singleton(v, values, loc, cls) + elif self.shape in MAPPING_LIKE_SHAPES: + v, errors = self._validate_mapping_like(v, values, loc, cls) + elif self.shape == SHAPE_TUPLE: + v, errors = self._validate_tuple(v, values, loc, cls) + elif self.shape == SHAPE_ITERABLE: + v, errors = self._validate_iterable(v, values, loc, cls) + elif self.shape == SHAPE_GENERIC: + v, errors = self._apply_validators(v, values, loc, cls, self.validators) + else: + # sequence, list, set, generator, tuple with ellipsis, frozen set + v, errors = self._validate_sequence_like(v, values, loc, cls) + + if not errors and self.post_validators: + v, errors = self._apply_validators(v, values, loc, cls, self.post_validators) + return v, errors + + def _validate_sequence_like( # noqa: C901 (ignore complexity) + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + """ + Validate sequence-like containers: lists, tuples, sets and generators + Note that large if-else blocks are necessary to enable Cython + optimization, which is why we disable the complexity check above. + """ + if not sequence_like(v): + e: errors_.PydanticTypeError + if self.shape == SHAPE_LIST: + e = errors_.ListError() + elif self.shape in (SHAPE_TUPLE, SHAPE_TUPLE_ELLIPSIS): + e = errors_.TupleError() + elif self.shape == SHAPE_SET: + e = errors_.SetError() + elif self.shape == SHAPE_FROZENSET: + e = errors_.FrozenSetError() + else: + e = errors_.SequenceError() + return v, ErrorWrapper(e, loc) + + loc = loc if isinstance(loc, tuple) else (loc,) + result = [] + errors: List[ErrorList] = [] + for i, v_ in enumerate(v): + v_loc = *loc, i + r, ee = self._validate_singleton(v_, values, v_loc, cls) + if ee: + errors.append(ee) + else: + result.append(r) + + if errors: + return v, errors + + converted: Union[List[Any], Set[Any], FrozenSet[Any], Tuple[Any, ...], Iterator[Any], Deque[Any]] = result + + if self.shape == SHAPE_SET: + converted = set(result) + elif self.shape == SHAPE_FROZENSET: + converted = frozenset(result) + elif self.shape == SHAPE_TUPLE_ELLIPSIS: + converted = tuple(result) + elif self.shape == SHAPE_DEQUE: + converted = deque(result, maxlen=getattr(v, 'maxlen', None)) + elif self.shape == SHAPE_SEQUENCE: + if isinstance(v, tuple): + converted = tuple(result) + elif isinstance(v, set): + converted = set(result) + elif isinstance(v, Generator): + converted = iter(result) + elif isinstance(v, deque): + converted = deque(result, maxlen=getattr(v, 'maxlen', None)) + return converted, None + + def _validate_iterable( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + """ + Validate Iterables. + + This intentionally doesn't validate values to allow infinite generators. + """ + + try: + iterable = iter(v) + except TypeError: + return v, ErrorWrapper(errors_.IterableError(), loc) + return iterable, None + + def _validate_tuple( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + e: Optional[Exception] = None + if not sequence_like(v): + e = errors_.TupleError() + else: + actual_length, expected_length = len(v), len(self.sub_fields) # type: ignore + if actual_length != expected_length: + e = errors_.TupleLengthError(actual_length=actual_length, expected_length=expected_length) + + if e: + return v, ErrorWrapper(e, loc) + + loc = loc if isinstance(loc, tuple) else (loc,) + result = [] + errors: List[ErrorList] = [] + for i, (v_, field) in enumerate(zip(v, self.sub_fields)): # type: ignore + v_loc = *loc, i + r, ee = field.validate(v_, values, loc=v_loc, cls=cls) + if ee: + errors.append(ee) + else: + result.append(r) + + if errors: + return v, errors + else: + return tuple(result), None + + def _validate_mapping_like( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + try: + v_iter = dict_validator(v) + except TypeError as exc: + return v, ErrorWrapper(exc, loc) + + loc = loc if isinstance(loc, tuple) else (loc,) + result, errors = {}, [] + for k, v_ in v_iter.items(): + v_loc = *loc, '__key__' + key_result, key_errors = self.key_field.validate(k, values, loc=v_loc, cls=cls) # type: ignore + if key_errors: + errors.append(key_errors) + continue + + v_loc = *loc, k + value_result, value_errors = self._validate_singleton(v_, values, v_loc, cls) + if value_errors: + errors.append(value_errors) + continue + + result[key_result] = value_result + if errors: + return v, errors + elif self.shape == SHAPE_DICT: + return result, None + elif self.shape == SHAPE_DEFAULTDICT: + return defaultdict(self.type_, result), None + elif self.shape == SHAPE_COUNTER: + return CollectionCounter(result), None + else: + return self._get_mapping_value(v, result), None + + def _get_mapping_value(self, original: T, converted: Dict[Any, Any]) -> Union[T, Dict[Any, Any]]: + """ + When type is `Mapping[KT, KV]` (or another unsupported mapping), we try to avoid + coercing to `dict` unwillingly. + """ + original_cls = original.__class__ + + if original_cls == dict or original_cls == Dict: + return converted + elif original_cls in {defaultdict, DefaultDict}: + return defaultdict(self.type_, converted) + else: + try: + # Counter, OrderedDict, UserDict, ... + return original_cls(converted) # type: ignore + except TypeError: + raise RuntimeError(f'Could not convert dictionary to {original_cls.__name__!r}') from None + + def _validate_singleton( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + if self.sub_fields: + if self.discriminator_key is not None: + return self._validate_discriminated_union(v, values, loc, cls) + + errors = [] + + if self.model_config.smart_union and is_union(get_origin(self.type_)): + # 1st pass: check if the value is an exact instance of one of the Union types + # (e.g. to avoid coercing a bool into an int) + for field in self.sub_fields: + if v.__class__ is field.outer_type_: + return v, None + + # 2nd pass: check if the value is an instance of any subclass of the Union types + for field in self.sub_fields: + # This whole logic will be improved later on to support more complex `isinstance` checks + # It will probably be done once a strict mode is added and be something like: + # ``` + # value, error = field.validate(v, values, strict=True) + # if error is None: + # return value, None + # ``` + try: + if isinstance(v, field.outer_type_): + return v, None + except TypeError: + # compound type + if lenient_isinstance(v, get_origin(field.outer_type_)): + value, error = field.validate(v, values, loc=loc, cls=cls) + if not error: + return value, None + + # 1st pass by default or 3rd pass with `smart_union` enabled: + # check if the value can be coerced into one of the Union types + for field in self.sub_fields: + value, error = field.validate(v, values, loc=loc, cls=cls) + if error: + errors.append(error) + else: + return value, None + return v, errors + else: + return self._apply_validators(v, values, loc, cls, self.validators) + + def _validate_discriminated_union( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'] + ) -> 'ValidateReturn': + assert self.discriminator_key is not None + assert self.discriminator_alias is not None + + try: + try: + discriminator_value = v[self.discriminator_alias] + except KeyError: + if self.model_config.allow_population_by_field_name: + discriminator_value = v[self.discriminator_key] + else: + raise + except KeyError: + return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc) + except TypeError: + try: + # BaseModel or dataclass + discriminator_value = getattr(v, self.discriminator_key) + except (AttributeError, TypeError): + return v, ErrorWrapper(MissingDiscriminator(discriminator_key=self.discriminator_key), loc) + + if self.sub_fields_mapping is None: + assert cls is not None + raise ConfigError( + f'field "{self.name}" not yet prepared so type is still a ForwardRef, ' + f'you might need to call {cls.__name__}.update_forward_refs().' + ) + + try: + sub_field = self.sub_fields_mapping[discriminator_value] + except (KeyError, TypeError): + # KeyError: `discriminator_value` is not in the dictionary. + # TypeError: `discriminator_value` is unhashable. + assert self.sub_fields_mapping is not None + return v, ErrorWrapper( + InvalidDiscriminator( + discriminator_key=self.discriminator_key, + discriminator_value=discriminator_value, + allowed_values=list(self.sub_fields_mapping), + ), + loc, + ) + else: + if not isinstance(loc, tuple): + loc = (loc,) + return sub_field.validate(v, values, loc=(*loc, display_as_type(sub_field.type_)), cls=cls) + + def _apply_validators( + self, v: Any, values: Dict[str, Any], loc: 'LocStr', cls: Optional['ModelOrDc'], validators: 'ValidatorsList' + ) -> 'ValidateReturn': + for validator in validators: + try: + v = validator(cls, v, values, self, self.model_config) + except (ValueError, TypeError, AssertionError) as exc: + return v, ErrorWrapper(exc, loc) + return v, None + + def is_complex(self) -> bool: + """ + Whether the field is "complex" eg. env variables should be parsed as JSON. + """ + from pydantic.v1.main import BaseModel + + return ( + self.shape != SHAPE_SINGLETON + or hasattr(self.type_, '__pydantic_model__') + or lenient_issubclass(self.type_, (BaseModel, list, set, frozenset, dict)) + ) + + def _type_display(self) -> PyObjectStr: + t = display_as_type(self.type_) + + if self.shape in MAPPING_LIKE_SHAPES: + t = f'Mapping[{display_as_type(self.key_field.type_)}, {t}]' # type: ignore + elif self.shape == SHAPE_TUPLE: + t = 'Tuple[{}]'.format(', '.join(display_as_type(f.type_) for f in self.sub_fields)) # type: ignore + elif self.shape == SHAPE_GENERIC: + assert self.sub_fields + t = '{}[{}]'.format( + display_as_type(self.type_), ', '.join(display_as_type(f.type_) for f in self.sub_fields) + ) + elif self.shape != SHAPE_SINGLETON: + t = SHAPE_NAME_LOOKUP[self.shape].format(t) + + if self.allow_none and (self.shape != SHAPE_SINGLETON or not self.sub_fields): + t = f'Optional[{t}]' + return PyObjectStr(t) + + def __repr_args__(self) -> 'ReprArgs': + args = [('name', self.name), ('type', self._type_display()), ('required', self.required)] + + if not self.required: + if self.default_factory is not None: + args.append(('default_factory', f'')) + else: + args.append(('default', self.default)) + + if self.alt_alias: + args.append(('alias', self.alias)) + return args + + +class ModelPrivateAttr(Representation): + __slots__ = ('default', 'default_factory') + + def __init__(self, default: Any = Undefined, *, default_factory: Optional[NoArgAnyCallable] = None) -> None: + self.default = default + self.default_factory = default_factory + + def get_default(self) -> Any: + return smart_deepcopy(self.default) if self.default_factory is None else self.default_factory() + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and (self.default, self.default_factory) == ( + other.default, + other.default_factory, + ) + + +def PrivateAttr( + default: Any = Undefined, + *, + default_factory: Optional[NoArgAnyCallable] = None, +) -> Any: + """ + Indicates that attribute is only used internally and never mixed with regular fields. + + Types or values of private attrs are not checked by pydantic and it's up to you to keep them relevant. + + Private attrs are stored in model __slots__. + + :param default: the attribute’s default value + :param default_factory: callable that will be called when a default value is needed for this attribute + If both `default` and `default_factory` are set, an error is raised. + """ + if default is not Undefined and default_factory is not None: + raise ValueError('cannot specify both default and default_factory') + + return ModelPrivateAttr( + default, + default_factory=default_factory, + ) + + +class DeferredType: + """ + Used to postpone field preparation, while creating recursive generic models. + """ + + +def is_finalvar_with_default_val(type_: Type[Any], val: Any) -> bool: + return is_finalvar(type_) and val is not Undefined and not isinstance(val, FieldInfo) diff --git a/source/target-vendors/cp312/pydantic/v1/generics.py b/source/target-vendors/cp312/pydantic/v1/generics.py new file mode 100644 index 0000000..fa1dcec --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/generics.py @@ -0,0 +1,400 @@ +import functools +import operator +import sys +import types +import typing +from typing import ( + TYPE_CHECKING, + Any, + ClassVar, + Dict, + ForwardRef, + Generic, + Iterator, + List, + Mapping, + Optional, + Tuple, + Type, + TypeVar, + Union, + cast, +) +from weakref import WeakKeyDictionary, WeakValueDictionary + +from typing_extensions import Annotated, Literal as ExtLiteral + +from pydantic.v1.class_validators import gather_all_validators +from pydantic.v1.fields import DeferredType +from pydantic.v1.main import BaseModel, create_model +from pydantic.v1.types import JsonWrapper +from pydantic.v1.typing import display_as_type, get_all_type_hints, get_args, get_origin, typing_base +from pydantic.v1.utils import all_identical, lenient_issubclass + +if sys.version_info >= (3, 8): + from typing import Literal + +GenericModelT = TypeVar('GenericModelT', bound='GenericModel') +TypeVarType = Any # since mypy doesn't allow the use of TypeVar as a type + +CacheKey = Tuple[Type[Any], Any, Tuple[Any, ...]] +Parametrization = Mapping[TypeVarType, Type[Any]] + +# weak dictionaries allow the dynamically created parametrized versions of generic models to get collected +# once they are no longer referenced by the caller. +if sys.version_info >= (3, 9): # Typing for weak dictionaries available at 3.9 + GenericTypesCache = WeakValueDictionary[CacheKey, Type[BaseModel]] + AssignedParameters = WeakKeyDictionary[Type[BaseModel], Parametrization] +else: + GenericTypesCache = WeakValueDictionary + AssignedParameters = WeakKeyDictionary + +# _generic_types_cache is a Mapping from __class_getitem__ arguments to the parametrized version of generic models. +# This ensures multiple calls of e.g. A[B] return always the same class. +_generic_types_cache = GenericTypesCache() + +# _assigned_parameters is a Mapping from parametrized version of generic models to assigned types of parametrizations +# as captured during construction of the class (not instances). +# E.g., for generic model `Model[A, B]`, when parametrized model `Model[int, str]` is created, +# `Model[int, str]`: {A: int, B: str}` will be stored in `_assigned_parameters`. +# (This information is only otherwise available after creation from the class name string). +_assigned_parameters = AssignedParameters() + + +class GenericModel(BaseModel): + __slots__ = () + __concrete__: ClassVar[bool] = False + + if TYPE_CHECKING: + # Putting this in a TYPE_CHECKING block allows us to replace `if Generic not in cls.__bases__` with + # `not hasattr(cls, "__parameters__")`. This means we don't need to force non-concrete subclasses of + # `GenericModel` to also inherit from `Generic`, which would require changes to the use of `create_model` below. + __parameters__: ClassVar[Tuple[TypeVarType, ...]] + + # Setting the return type as Type[Any] instead of Type[BaseModel] prevents PyCharm warnings + def __class_getitem__(cls: Type[GenericModelT], params: Union[Type[Any], Tuple[Type[Any], ...]]) -> Type[Any]: + """Instantiates a new class from a generic class `cls` and type variables `params`. + + :param params: Tuple of types the class . Given a generic class + `Model` with 2 type variables and a concrete model `Model[str, int]`, + the value `(str, int)` would be passed to `params`. + :return: New model class inheriting from `cls` with instantiated + types described by `params`. If no parameters are given, `cls` is + returned as is. + + """ + + def _cache_key(_params: Any) -> CacheKey: + args = get_args(_params) + # python returns a list for Callables, which is not hashable + if len(args) == 2 and isinstance(args[0], list): + args = (tuple(args[0]), args[1]) + return cls, _params, args + + cached = _generic_types_cache.get(_cache_key(params)) + if cached is not None: + return cached + if cls.__concrete__ and Generic not in cls.__bases__: + raise TypeError('Cannot parameterize a concrete instantiation of a generic model') + if not isinstance(params, tuple): + params = (params,) + if cls is GenericModel and any(isinstance(param, TypeVar) for param in params): + raise TypeError('Type parameters should be placed on typing.Generic, not GenericModel') + if not hasattr(cls, '__parameters__'): + raise TypeError(f'Type {cls.__name__} must inherit from typing.Generic before being parameterized') + + check_parameters_count(cls, params) + # Build map from generic typevars to passed params + typevars_map: Dict[TypeVarType, Type[Any]] = dict(zip(cls.__parameters__, params)) + if all_identical(typevars_map.keys(), typevars_map.values()) and typevars_map: + return cls # if arguments are equal to parameters it's the same object + + # Create new model with original model as parent inserting fields with DeferredType. + model_name = cls.__concrete_name__(params) + validators = gather_all_validators(cls) + + type_hints = get_all_type_hints(cls).items() + instance_type_hints = {k: v for k, v in type_hints if get_origin(v) is not ClassVar} + + fields = {k: (DeferredType(), cls.__fields__[k].field_info) for k in instance_type_hints if k in cls.__fields__} + + model_module, called_globally = get_caller_frame_info() + created_model = cast( + Type[GenericModel], # casting ensures mypy is aware of the __concrete__ and __parameters__ attributes + create_model( + model_name, + __module__=model_module or cls.__module__, + __base__=(cls,) + tuple(cls.__parameterized_bases__(typevars_map)), + __config__=None, + __validators__=validators, + __cls_kwargs__=None, + **fields, + ), + ) + + _assigned_parameters[created_model] = typevars_map + + if called_globally: # create global reference and therefore allow pickling + object_by_reference = None + reference_name = model_name + reference_module_globals = sys.modules[created_model.__module__].__dict__ + while object_by_reference is not created_model: + object_by_reference = reference_module_globals.setdefault(reference_name, created_model) + reference_name += '_' + + created_model.Config = cls.Config + + # Find any typevars that are still present in the model. + # If none are left, the model is fully "concrete", otherwise the new + # class is a generic class as well taking the found typevars as + # parameters. + new_params = tuple( + {param: None for param in iter_contained_typevars(typevars_map.values())} + ) # use dict as ordered set + created_model.__concrete__ = not new_params + if new_params: + created_model.__parameters__ = new_params + + # Save created model in cache so we don't end up creating duplicate + # models that should be identical. + _generic_types_cache[_cache_key(params)] = created_model + if len(params) == 1: + _generic_types_cache[_cache_key(params[0])] = created_model + + # Recursively walk class type hints and replace generic typevars + # with concrete types that were passed. + _prepare_model_fields(created_model, fields, instance_type_hints, typevars_map) + + return created_model + + @classmethod + def __concrete_name__(cls: Type[Any], params: Tuple[Type[Any], ...]) -> str: + """Compute class name for child classes. + + :param params: Tuple of types the class . Given a generic class + `Model` with 2 type variables and a concrete model `Model[str, int]`, + the value `(str, int)` would be passed to `params`. + :return: String representing a the new class where `params` are + passed to `cls` as type variables. + + This method can be overridden to achieve a custom naming scheme for GenericModels. + """ + param_names = [display_as_type(param) for param in params] + params_component = ', '.join(param_names) + return f'{cls.__name__}[{params_component}]' + + @classmethod + def __parameterized_bases__(cls, typevars_map: Parametrization) -> Iterator[Type[Any]]: + """ + Returns unbound bases of cls parameterised to given type variables + + :param typevars_map: Dictionary of type applications for binding subclasses. + Given a generic class `Model` with 2 type variables [S, T] + and a concrete model `Model[str, int]`, + the value `{S: str, T: int}` would be passed to `typevars_map`. + :return: an iterator of generic sub classes, parameterised by `typevars_map` + and other assigned parameters of `cls` + + e.g.: + ``` + class A(GenericModel, Generic[T]): + ... + + class B(A[V], Generic[V]): + ... + + assert A[int] in B.__parameterized_bases__({V: int}) + ``` + """ + + def build_base_model( + base_model: Type[GenericModel], mapped_types: Parametrization + ) -> Iterator[Type[GenericModel]]: + base_parameters = tuple(mapped_types[param] for param in base_model.__parameters__) + parameterized_base = base_model.__class_getitem__(base_parameters) + if parameterized_base is base_model or parameterized_base is cls: + # Avoid duplication in MRO + return + yield parameterized_base + + for base_model in cls.__bases__: + if not issubclass(base_model, GenericModel): + # not a class that can be meaningfully parameterized + continue + elif not getattr(base_model, '__parameters__', None): + # base_model is "GenericModel" (and has no __parameters__) + # or + # base_model is already concrete, and will be included transitively via cls. + continue + elif cls in _assigned_parameters: + if base_model in _assigned_parameters: + # cls is partially parameterised but not from base_model + # e.g. cls = B[S], base_model = A[S] + # B[S][int] should subclass A[int], (and will be transitively via B[int]) + # but it's not viable to consistently subclass types with arbitrary construction + # So don't attempt to include A[S][int] + continue + else: # base_model not in _assigned_parameters: + # cls is partially parameterized, base_model is original generic + # e.g. cls = B[str, T], base_model = B[S, T] + # Need to determine the mapping for the base_model parameters + mapped_types: Parametrization = { + key: typevars_map.get(value, value) for key, value in _assigned_parameters[cls].items() + } + yield from build_base_model(base_model, mapped_types) + else: + # cls is base generic, so base_class has a distinct base + # can construct the Parameterised base model using typevars_map directly + yield from build_base_model(base_model, typevars_map) + + +def replace_types(type_: Any, type_map: Mapping[Any, Any]) -> Any: + """Return type with all occurrences of `type_map` keys recursively replaced with their values. + + :param type_: Any type, class or generic alias + :param type_map: Mapping from `TypeVar` instance to concrete types. + :return: New type representing the basic structure of `type_` with all + `typevar_map` keys recursively replaced. + + >>> replace_types(Tuple[str, Union[List[str], float]], {str: int}) + Tuple[int, Union[List[int], float]] + + """ + if not type_map: + return type_ + + type_args = get_args(type_) + origin_type = get_origin(type_) + + if origin_type is Annotated: + annotated_type, *annotations = type_args + return Annotated[replace_types(annotated_type, type_map), tuple(annotations)] + + if (origin_type is ExtLiteral) or (sys.version_info >= (3, 8) and origin_type is Literal): + return type_map.get(type_, type_) + # Having type args is a good indicator that this is a typing module + # class instantiation or a generic alias of some sort. + if type_args: + resolved_type_args = tuple(replace_types(arg, type_map) for arg in type_args) + if all_identical(type_args, resolved_type_args): + # If all arguments are the same, there is no need to modify the + # type or create a new object at all + return type_ + if ( + origin_type is not None + and isinstance(type_, typing_base) + and not isinstance(origin_type, typing_base) + and getattr(type_, '_name', None) is not None + ): + # In python < 3.9 generic aliases don't exist so any of these like `list`, + # `type` or `collections.abc.Callable` need to be translated. + # See: https://www.python.org/dev/peps/pep-0585 + origin_type = getattr(typing, type_._name) + assert origin_type is not None + # PEP-604 syntax (Ex.: list | str) is represented with a types.UnionType object that does not have __getitem__. + # We also cannot use isinstance() since we have to compare types. + if sys.version_info >= (3, 10) and origin_type is types.UnionType: # noqa: E721 + return functools.reduce(operator.or_, resolved_type_args) + return origin_type[resolved_type_args] + + # We handle pydantic generic models separately as they don't have the same + # semantics as "typing" classes or generic aliases + if not origin_type and lenient_issubclass(type_, GenericModel) and not type_.__concrete__: + type_args = type_.__parameters__ + resolved_type_args = tuple(replace_types(t, type_map) for t in type_args) + if all_identical(type_args, resolved_type_args): + return type_ + return type_[resolved_type_args] + + # Handle special case for typehints that can have lists as arguments. + # `typing.Callable[[int, str], int]` is an example for this. + if isinstance(type_, (List, list)): + resolved_list = list(replace_types(element, type_map) for element in type_) + if all_identical(type_, resolved_list): + return type_ + return resolved_list + + # For JsonWrapperValue, need to handle its inner type to allow correct parsing + # of generic Json arguments like Json[T] + if not origin_type and lenient_issubclass(type_, JsonWrapper): + type_.inner_type = replace_types(type_.inner_type, type_map) + return type_ + + # If all else fails, we try to resolve the type directly and otherwise just + # return the input with no modifications. + new_type = type_map.get(type_, type_) + # Convert string to ForwardRef + if isinstance(new_type, str): + return ForwardRef(new_type) + else: + return new_type + + +def check_parameters_count(cls: Type[GenericModel], parameters: Tuple[Any, ...]) -> None: + actual = len(parameters) + expected = len(cls.__parameters__) + if actual != expected: + description = 'many' if actual > expected else 'few' + raise TypeError(f'Too {description} parameters for {cls.__name__}; actual {actual}, expected {expected}') + + +DictValues: Type[Any] = {}.values().__class__ + + +def iter_contained_typevars(v: Any) -> Iterator[TypeVarType]: + """Recursively iterate through all subtypes and type args of `v` and yield any typevars that are found.""" + if isinstance(v, TypeVar): + yield v + elif hasattr(v, '__parameters__') and not get_origin(v) and lenient_issubclass(v, GenericModel): + yield from v.__parameters__ + elif isinstance(v, (DictValues, list)): + for var in v: + yield from iter_contained_typevars(var) + else: + args = get_args(v) + for arg in args: + yield from iter_contained_typevars(arg) + + +def get_caller_frame_info() -> Tuple[Optional[str], bool]: + """ + Used inside a function to check whether it was called globally + + Will only work against non-compiled code, therefore used only in pydantic.generics + + :returns Tuple[module_name, called_globally] + """ + try: + previous_caller_frame = sys._getframe(2) + except ValueError as e: + raise RuntimeError('This function must be used inside another function') from e + except AttributeError: # sys module does not have _getframe function, so there's nothing we can do about it + return None, False + frame_globals = previous_caller_frame.f_globals + return frame_globals.get('__name__'), previous_caller_frame.f_locals is frame_globals + + +def _prepare_model_fields( + created_model: Type[GenericModel], + fields: Mapping[str, Any], + instance_type_hints: Mapping[str, type], + typevars_map: Mapping[Any, type], +) -> None: + """ + Replace DeferredType fields with concrete type hints and prepare them. + """ + + for key, field in created_model.__fields__.items(): + if key not in fields: + assert field.type_.__class__ is not DeferredType + # https://github.com/nedbat/coveragepy/issues/198 + continue # pragma: no cover + + assert field.type_.__class__ is DeferredType, field.type_.__class__ + + field_type_hint = instance_type_hints[key] + concrete_type = replace_types(field_type_hint, typevars_map) + field.type_ = concrete_type + field.outer_type_ = concrete_type + field.prepare() + created_model.__annotations__[key] = concrete_type diff --git a/source/target-vendors/cp312/pydantic/v1/json.py b/source/target-vendors/cp312/pydantic/v1/json.py new file mode 100644 index 0000000..41d0d5f --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/json.py @@ -0,0 +1,112 @@ +import datetime +from collections import deque +from decimal import Decimal +from enum import Enum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from re import Pattern +from types import GeneratorType +from typing import Any, Callable, Dict, Type, Union +from uuid import UUID + +from pydantic.v1.color import Color +from pydantic.v1.networks import NameEmail +from pydantic.v1.types import SecretBytes, SecretStr + +__all__ = 'pydantic_encoder', 'custom_pydantic_encoder', 'timedelta_isoformat' + + +def isoformat(o: Union[datetime.date, datetime.time]) -> str: + return o.isoformat() + + +def decimal_encoder(dec_value: Decimal) -> Union[int, float]: + """ + Encodes a Decimal as int of there's no exponent, otherwise float + + This is useful when we use ConstrainedDecimal to represent Numeric(x,0) + where a integer (but not int typed) is used. Encoding this as a float + results in failed round-tripping between encode and parse. + Our Id type is a prime example of this. + + >>> decimal_encoder(Decimal("1.0")) + 1.0 + + >>> decimal_encoder(Decimal("1")) + 1 + """ + if dec_value.as_tuple().exponent >= 0: + return int(dec_value) + else: + return float(dec_value) + + +ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = { + bytes: lambda o: o.decode(), + Color: str, + datetime.date: isoformat, + datetime.datetime: isoformat, + datetime.time: isoformat, + datetime.timedelta: lambda td: td.total_seconds(), + Decimal: decimal_encoder, + Enum: lambda o: o.value, + frozenset: list, + deque: list, + GeneratorType: list, + IPv4Address: str, + IPv4Interface: str, + IPv4Network: str, + IPv6Address: str, + IPv6Interface: str, + IPv6Network: str, + NameEmail: str, + Path: str, + Pattern: lambda o: o.pattern, + SecretBytes: str, + SecretStr: str, + set: list, + UUID: str, +} + + +def pydantic_encoder(obj: Any) -> Any: + from dataclasses import asdict, is_dataclass + + from pydantic.v1.main import BaseModel + + if isinstance(obj, BaseModel): + return obj.dict() + elif is_dataclass(obj): + return asdict(obj) + + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = ENCODERS_BY_TYPE[base] + except KeyError: + continue + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable") + + +def custom_pydantic_encoder(type_encoders: Dict[Any, Callable[[Type[Any]], Any]], obj: Any) -> Any: + # Check the class type and its superclasses for a matching encoder + for base in obj.__class__.__mro__[:-1]: + try: + encoder = type_encoders[base] + except KeyError: + continue + + return encoder(obj) + else: # We have exited the for loop without finding a suitable encoder + return pydantic_encoder(obj) + + +def timedelta_isoformat(td: datetime.timedelta) -> str: + """ + ISO 8601 encoding for Python timedelta object. + """ + minutes, seconds = divmod(td.seconds, 60) + hours, minutes = divmod(minutes, 60) + return f'{"-" if td.days < 0 else ""}P{abs(td.days)}DT{hours:d}H{minutes:d}M{seconds:d}.{td.microseconds:06d}S' diff --git a/source/target-vendors/cp312/pydantic/v1/main.py b/source/target-vendors/cp312/pydantic/v1/main.py new file mode 100644 index 0000000..36e9c44 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/main.py @@ -0,0 +1,1130 @@ +import sys +import warnings +from abc import ABCMeta +from copy import deepcopy +from enum import Enum +from functools import partial +from pathlib import Path +from types import FunctionType, prepare_class, resolve_bases +from typing import ( + TYPE_CHECKING, + AbstractSet, + Any, + Callable, + ClassVar, + Dict, + List, + Mapping, + Optional, + Tuple, + Type, + TypeVar, + Union, + cast, + no_type_check, + overload, +) + +from typing_extensions import dataclass_transform + +from pydantic.v1.class_validators import ValidatorGroup, extract_root_validators, extract_validators, inherit_validators +from pydantic.v1.config import BaseConfig, Extra, inherit_config, prepare_config +from pydantic.v1.error_wrappers import ErrorWrapper, ValidationError +from pydantic.v1.errors import ConfigError, DictError, ExtraError, MissingError +from pydantic.v1.fields import ( + MAPPING_LIKE_SHAPES, + Field, + ModelField, + ModelPrivateAttr, + PrivateAttr, + Undefined, + is_finalvar_with_default_val, +) +from pydantic.v1.json import custom_pydantic_encoder, pydantic_encoder +from pydantic.v1.parse import Protocol, load_file, load_str_bytes +from pydantic.v1.schema import default_ref_template, model_schema +from pydantic.v1.types import PyObject, StrBytes +from pydantic.v1.typing import ( + AnyCallable, + get_args, + get_origin, + is_classvar, + is_namedtuple, + is_union, + resolve_annotations, + update_model_forward_refs, +) +from pydantic.v1.utils import ( + DUNDER_ATTRIBUTES, + ROOT_KEY, + ClassAttribute, + GetterDict, + Representation, + ValueItems, + generate_model_signature, + is_valid_field, + is_valid_private_name, + lenient_issubclass, + sequence_like, + smart_deepcopy, + unique_list, + validate_field_name, +) + +if TYPE_CHECKING: + from inspect import Signature + + from pydantic.v1.class_validators import ValidatorListDict + from pydantic.v1.types import ModelOrDc + from pydantic.v1.typing import ( + AbstractSetIntStr, + AnyClassMethod, + CallableGenerator, + DictAny, + DictStrAny, + MappingIntStrAny, + ReprArgs, + SetStr, + TupleGenerator, + ) + + Model = TypeVar('Model', bound='BaseModel') + +__all__ = 'BaseModel', 'create_model', 'validate_model' + +_T = TypeVar('_T') + + +def validate_custom_root_type(fields: Dict[str, ModelField]) -> None: + if len(fields) > 1: + raise ValueError(f'{ROOT_KEY} cannot be mixed with other fields') + + +def generate_hash_function(frozen: bool) -> Optional[Callable[[Any], int]]: + def hash_function(self_: Any) -> int: + return hash(self_.__class__) + hash(tuple(self_.__dict__.values())) + + return hash_function if frozen else None + + +# If a field is of type `Callable`, its default value should be a function and cannot to ignored. +ANNOTATED_FIELD_UNTOUCHED_TYPES: Tuple[Any, ...] = (property, type, classmethod, staticmethod) +# When creating a `BaseModel` instance, we bypass all the methods, properties... added to the model +UNTOUCHED_TYPES: Tuple[Any, ...] = (FunctionType,) + ANNOTATED_FIELD_UNTOUCHED_TYPES +# Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we need to add this extra +# (somewhat hacky) boolean to keep track of whether we've created the `BaseModel` class yet, and therefore whether it's +# safe to refer to it. If it *hasn't* been created, we assume that the `__new__` call we're in the middle of is for +# the `BaseModel` class, since that's defined immediately after the metaclass. +_is_base_model_class_defined = False + + +@dataclass_transform(kw_only_default=True, field_specifiers=(Field,)) +class ModelMetaclass(ABCMeta): + @no_type_check # noqa C901 + def __new__(mcs, name, bases, namespace, **kwargs): # noqa C901 + fields: Dict[str, ModelField] = {} + config = BaseConfig + validators: 'ValidatorListDict' = {} + + pre_root_validators, post_root_validators = [], [] + private_attributes: Dict[str, ModelPrivateAttr] = {} + base_private_attributes: Dict[str, ModelPrivateAttr] = {} + slots: SetStr = namespace.get('__slots__', ()) + slots = {slots} if isinstance(slots, str) else set(slots) + class_vars: SetStr = set() + hash_func: Optional[Callable[[Any], int]] = None + + for base in reversed(bases): + if _is_base_model_class_defined and issubclass(base, BaseModel) and base != BaseModel: + fields.update(smart_deepcopy(base.__fields__)) + config = inherit_config(base.__config__, config) + validators = inherit_validators(base.__validators__, validators) + pre_root_validators += base.__pre_root_validators__ + post_root_validators += base.__post_root_validators__ + base_private_attributes.update(base.__private_attributes__) + class_vars.update(base.__class_vars__) + hash_func = base.__hash__ + + resolve_forward_refs = kwargs.pop('__resolve_forward_refs__', True) + allowed_config_kwargs: SetStr = { + key + for key in dir(config) + if not (key.startswith('__') and key.endswith('__')) # skip dunder methods and attributes + } + config_kwargs = {key: kwargs.pop(key) for key in kwargs.keys() & allowed_config_kwargs} + config_from_namespace = namespace.get('Config') + if config_kwargs and config_from_namespace: + raise TypeError('Specifying config in two places is ambiguous, use either Config attribute or class kwargs') + config = inherit_config(config_from_namespace, config, **config_kwargs) + + validators = inherit_validators(extract_validators(namespace), validators) + vg = ValidatorGroup(validators) + + for f in fields.values(): + f.set_config(config) + extra_validators = vg.get_validators(f.name) + if extra_validators: + f.class_validators.update(extra_validators) + # re-run prepare to add extra validators + f.populate_validators() + + prepare_config(config, name) + + untouched_types = ANNOTATED_FIELD_UNTOUCHED_TYPES + + def is_untouched(v: Any) -> bool: + return isinstance(v, untouched_types) or v.__class__.__name__ == 'cython_function_or_method' + + if (namespace.get('__module__'), namespace.get('__qualname__')) != ('pydantic.main', 'BaseModel'): + if sys.version_info >= (3, 14): + if '__annotations__' in namespace: + # `from __future__ import annotations` was used in the model's module + raw_annotations = namespace['__annotations__'] + else: + # See https://docs.python.org/3/library/annotationlib.html#using-annotations-in-a-metaclass: + from annotationlib import Format, call_annotate_function, get_annotate_from_class_namespace + + annotate = get_annotate_from_class_namespace(namespace) + if annotate is not None: + raw_annotations = call_annotate_function(annotate, format=Format.FORWARDREF) + else: + raw_annotations = {} + else: + raw_annotations = namespace.get('__annotations__', {}) + + annotations = resolve_annotations(raw_annotations, namespace.get('__module__', None)) + # annotation only fields need to come first in fields + for ann_name, ann_type in annotations.items(): + if is_classvar(ann_type): + class_vars.add(ann_name) + elif is_finalvar_with_default_val(ann_type, namespace.get(ann_name, Undefined)): + class_vars.add(ann_name) + elif is_valid_field(ann_name): + validate_field_name(bases, ann_name) + value = namespace.get(ann_name, Undefined) + allowed_types = get_args(ann_type) if is_union(get_origin(ann_type)) else (ann_type,) + if ( + is_untouched(value) + and ann_type != PyObject + and not any( + lenient_issubclass(get_origin(allowed_type), Type) for allowed_type in allowed_types + ) + ): + continue + fields[ann_name] = ModelField.infer( + name=ann_name, + value=value, + annotation=ann_type, + class_validators=vg.get_validators(ann_name), + config=config, + ) + elif ann_name not in namespace and config.underscore_attrs_are_private: + private_attributes[ann_name] = PrivateAttr() + + untouched_types = UNTOUCHED_TYPES + config.keep_untouched + for var_name, value in namespace.items(): + can_be_changed = var_name not in class_vars and not is_untouched(value) + if isinstance(value, ModelPrivateAttr): + if not is_valid_private_name(var_name): + raise NameError( + f'Private attributes "{var_name}" must not be a valid field name; ' + f'Use sunder or dunder names, e. g. "_{var_name}" or "__{var_name}__"' + ) + private_attributes[var_name] = value + elif config.underscore_attrs_are_private and is_valid_private_name(var_name) and can_be_changed: + private_attributes[var_name] = PrivateAttr(default=value) + elif is_valid_field(var_name) and var_name not in annotations and can_be_changed: + validate_field_name(bases, var_name) + inferred = ModelField.infer( + name=var_name, + value=value, + annotation=annotations.get(var_name, Undefined), + class_validators=vg.get_validators(var_name), + config=config, + ) + if var_name in fields: + if lenient_issubclass(inferred.type_, fields[var_name].type_): + inferred.type_ = fields[var_name].type_ + else: + raise TypeError( + f'The type of {name}.{var_name} differs from the new default value; ' + f'if you wish to change the type of this field, please use a type annotation' + ) + fields[var_name] = inferred + + _custom_root_type = ROOT_KEY in fields + if _custom_root_type: + validate_custom_root_type(fields) + vg.check_for_unused() + if config.json_encoders: + json_encoder = partial(custom_pydantic_encoder, config.json_encoders) + else: + json_encoder = pydantic_encoder + pre_rv_new, post_rv_new = extract_root_validators(namespace) + + if hash_func is None: + hash_func = generate_hash_function(config.frozen) + + exclude_from_namespace = fields | private_attributes.keys() | {'__slots__'} + new_namespace = { + '__config__': config, + '__fields__': fields, + '__exclude_fields__': { + name: field.field_info.exclude for name, field in fields.items() if field.field_info.exclude is not None + } + or None, + '__include_fields__': { + name: field.field_info.include for name, field in fields.items() if field.field_info.include is not None + } + or None, + '__validators__': vg.validators, + '__pre_root_validators__': unique_list( + pre_root_validators + pre_rv_new, + name_factory=lambda v: v.__name__, + ), + '__post_root_validators__': unique_list( + post_root_validators + post_rv_new, + name_factory=lambda skip_on_failure_and_v: skip_on_failure_and_v[1].__name__, + ), + '__schema_cache__': {}, + '__json_encoder__': staticmethod(json_encoder), + '__custom_root_type__': _custom_root_type, + '__private_attributes__': {**base_private_attributes, **private_attributes}, + '__slots__': slots | private_attributes.keys(), + '__hash__': hash_func, + '__class_vars__': class_vars, + **{n: v for n, v in namespace.items() if n not in exclude_from_namespace}, + } + + cls = super().__new__(mcs, name, bases, new_namespace, **kwargs) + # set __signature__ attr only for model class, but not for its instances + cls.__signature__ = ClassAttribute('__signature__', generate_model_signature(cls.__init__, fields, config)) + + if not _is_base_model_class_defined: + # Cython does not understand the `if TYPE_CHECKING:` condition in the + # BaseModel's body (where annotations are set), so clear them manually: + getattr(cls, '__annotations__', {}).clear() + + if resolve_forward_refs: + cls.__try_update_forward_refs__() + + # preserve `__set_name__` protocol defined in https://peps.python.org/pep-0487 + # for attributes not in `new_namespace` (e.g. private attributes) + for name, obj in namespace.items(): + if name not in new_namespace: + set_name = getattr(obj, '__set_name__', None) + if callable(set_name): + set_name(cls, name) + + return cls + + def __instancecheck__(self, instance: Any) -> bool: + """ + Avoid calling ABC _abc_subclasscheck unless we're pretty sure. + + See #3829 and python/cpython#92810 + """ + return hasattr(instance, '__post_root_validators__') and super().__instancecheck__(instance) + + +object_setattr = object.__setattr__ + + +class BaseModel(Representation, metaclass=ModelMetaclass): + if TYPE_CHECKING: + # populated by the metaclass, defined here to help IDEs only + __fields__: ClassVar[Dict[str, ModelField]] = {} + __include_fields__: ClassVar[Optional[Mapping[str, Any]]] = None + __exclude_fields__: ClassVar[Optional[Mapping[str, Any]]] = None + __validators__: ClassVar[Dict[str, AnyCallable]] = {} + __pre_root_validators__: ClassVar[List[AnyCallable]] + __post_root_validators__: ClassVar[List[Tuple[bool, AnyCallable]]] + __config__: ClassVar[Type[BaseConfig]] = BaseConfig + __json_encoder__: ClassVar[Callable[[Any], Any]] = lambda x: x + __schema_cache__: ClassVar['DictAny'] = {} + __custom_root_type__: ClassVar[bool] = False + __signature__: ClassVar['Signature'] + __private_attributes__: ClassVar[Dict[str, ModelPrivateAttr]] + __class_vars__: ClassVar[SetStr] + __fields_set__: ClassVar[SetStr] = set() + + Config = BaseConfig + __slots__ = ('__dict__', '__fields_set__') + __doc__ = '' # Null out the Representation docstring + + def __init__(__pydantic_self__, **data: Any) -> None: + """ + Create a new model by parsing and validating input data from keyword arguments. + + Raises ValidationError if the input data cannot be parsed to form a valid model. + """ + # Uses something other than `self` the first arg to allow "self" as a settable attribute + values, fields_set, validation_error = validate_model(__pydantic_self__.__class__, data) + if validation_error: + raise validation_error + try: + object_setattr(__pydantic_self__, '__dict__', values) + except TypeError as e: + raise TypeError( + 'Model values must be a dict; you may not have returned a dictionary from a root validator' + ) from e + object_setattr(__pydantic_self__, '__fields_set__', fields_set) + __pydantic_self__._init_private_attributes() + + @no_type_check + def __setattr__(self, name, value): # noqa: C901 (ignore complexity) + if name in self.__private_attributes__ or name in DUNDER_ATTRIBUTES: + return object_setattr(self, name, value) + + if self.__config__.extra is not Extra.allow and name not in self.__fields__: + raise ValueError(f'"{self.__class__.__name__}" object has no field "{name}"') + elif not self.__config__.allow_mutation or self.__config__.frozen: + raise TypeError(f'"{self.__class__.__name__}" is immutable and does not support item assignment') + elif name in self.__fields__ and self.__fields__[name].final: + raise TypeError( + f'"{self.__class__.__name__}" object "{name}" field is final and does not support reassignment' + ) + elif self.__config__.validate_assignment: + new_values = {**self.__dict__, name: value} + + for validator in self.__pre_root_validators__: + try: + new_values = validator(self.__class__, new_values) + except (ValueError, TypeError, AssertionError) as exc: + raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], self.__class__) + + known_field = self.__fields__.get(name, None) + if known_field: + # We want to + # - make sure validators are called without the current value for this field inside `values` + # - keep other values (e.g. submodels) untouched (using `BaseModel.dict()` will change them into dicts) + # - keep the order of the fields + if not known_field.field_info.allow_mutation: + raise TypeError(f'"{known_field.name}" has allow_mutation set to False and cannot be assigned') + dict_without_original_value = {k: v for k, v in self.__dict__.items() if k != name} + value, error_ = known_field.validate(value, dict_without_original_value, loc=name, cls=self.__class__) + if error_: + raise ValidationError([error_], self.__class__) + else: + new_values[name] = value + + errors = [] + for skip_on_failure, validator in self.__post_root_validators__: + if skip_on_failure and errors: + continue + try: + new_values = validator(self.__class__, new_values) + except (ValueError, TypeError, AssertionError) as exc: + errors.append(ErrorWrapper(exc, loc=ROOT_KEY)) + if errors: + raise ValidationError(errors, self.__class__) + + # update the whole __dict__ as other values than just `value` + # may be changed (e.g. with `root_validator`) + object_setattr(self, '__dict__', new_values) + else: + self.__dict__[name] = value + + self.__fields_set__.add(name) + + def __getstate__(self) -> 'DictAny': + private_attrs = ((k, getattr(self, k, Undefined)) for k in self.__private_attributes__) + return { + '__dict__': self.__dict__, + '__fields_set__': self.__fields_set__, + '__private_attribute_values__': {k: v for k, v in private_attrs if v is not Undefined}, + } + + def __setstate__(self, state: 'DictAny') -> None: + object_setattr(self, '__dict__', state['__dict__']) + object_setattr(self, '__fields_set__', state['__fields_set__']) + for name, value in state.get('__private_attribute_values__', {}).items(): + object_setattr(self, name, value) + + def _init_private_attributes(self) -> None: + for name, private_attr in self.__private_attributes__.items(): + default = private_attr.get_default() + if default is not Undefined: + object_setattr(self, name, default) + + def dict( + self, + *, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + by_alias: bool = False, + skip_defaults: Optional[bool] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> 'DictStrAny': + """ + Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. + + """ + if skip_defaults is not None: + warnings.warn( + f'{self.__class__.__name__}.dict(): "skip_defaults" is deprecated and replaced by "exclude_unset"', + DeprecationWarning, + ) + exclude_unset = skip_defaults + + return dict( + self._iter( + to_dict=True, + by_alias=by_alias, + include=include, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + ) + + def json( + self, + *, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + by_alias: bool = False, + skip_defaults: Optional[bool] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + encoder: Optional[Callable[[Any], Any]] = None, + models_as_dict: bool = True, + **dumps_kwargs: Any, + ) -> str: + """ + Generate a JSON representation of the model, `include` and `exclude` arguments as per `dict()`. + + `encoder` is an optional function to supply as `default` to json.dumps(), other arguments as per `json.dumps()`. + """ + if skip_defaults is not None: + warnings.warn( + f'{self.__class__.__name__}.json(): "skip_defaults" is deprecated and replaced by "exclude_unset"', + DeprecationWarning, + ) + exclude_unset = skip_defaults + encoder = cast(Callable[[Any], Any], encoder or self.__json_encoder__) + + # We don't directly call `self.dict()`, which does exactly this with `to_dict=True` + # because we want to be able to keep raw `BaseModel` instances and not as `dict`. + # This allows users to write custom JSON encoders for given `BaseModel` classes. + data = dict( + self._iter( + to_dict=models_as_dict, + by_alias=by_alias, + include=include, + exclude=exclude, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + ) + if self.__custom_root_type__: + data = data[ROOT_KEY] + return self.__config__.json_dumps(data, default=encoder, **dumps_kwargs) + + @classmethod + def _enforce_dict_if_root(cls, obj: Any) -> Any: + if cls.__custom_root_type__ and ( + not (isinstance(obj, dict) and obj.keys() == {ROOT_KEY}) + and not (isinstance(obj, BaseModel) and obj.__fields__.keys() == {ROOT_KEY}) + or cls.__fields__[ROOT_KEY].shape in MAPPING_LIKE_SHAPES + ): + return {ROOT_KEY: obj} + else: + return obj + + @classmethod + def parse_obj(cls: Type['Model'], obj: Any) -> 'Model': + obj = cls._enforce_dict_if_root(obj) + if not isinstance(obj, dict): + try: + obj = dict(obj) + except (TypeError, ValueError) as e: + exc = TypeError(f'{cls.__name__} expected dict not {obj.__class__.__name__}') + raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls) from e + return cls(**obj) + + @classmethod + def parse_raw( + cls: Type['Model'], + b: StrBytes, + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + ) -> 'Model': + try: + obj = load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=cls.__config__.json_loads, + ) + except (ValueError, TypeError, UnicodeDecodeError) as e: + raise ValidationError([ErrorWrapper(e, loc=ROOT_KEY)], cls) + return cls.parse_obj(obj) + + @classmethod + def parse_file( + cls: Type['Model'], + path: Union[str, Path], + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + ) -> 'Model': + obj = load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=cls.__config__.json_loads, + ) + return cls.parse_obj(obj) + + @classmethod + def from_orm(cls: Type['Model'], obj: Any) -> 'Model': + if not cls.__config__.orm_mode: + raise ConfigError('You must have the config attribute orm_mode=True to use from_orm') + obj = {ROOT_KEY: obj} if cls.__custom_root_type__ else cls._decompose_class(obj) + m = cls.__new__(cls) + values, fields_set, validation_error = validate_model(cls, obj) + if validation_error: + raise validation_error + object_setattr(m, '__dict__', values) + object_setattr(m, '__fields_set__', fields_set) + m._init_private_attributes() + return m + + @classmethod + def construct(cls: Type['Model'], _fields_set: Optional['SetStr'] = None, **values: Any) -> 'Model': + """ + Creates a new model setting __dict__ and __fields_set__ from trusted or pre-validated data. + Default values are respected, but no other validation is performed. + Behaves as if `Config.extra = 'allow'` was set since it adds all passed values + """ + m = cls.__new__(cls) + fields_values: Dict[str, Any] = {} + for name, field in cls.__fields__.items(): + if field.alt_alias and field.alias in values: + fields_values[name] = values[field.alias] + elif name in values: + fields_values[name] = values[name] + elif not field.required: + fields_values[name] = field.get_default() + fields_values.update(values) + object_setattr(m, '__dict__', fields_values) + if _fields_set is None: + _fields_set = set(values.keys()) + object_setattr(m, '__fields_set__', _fields_set) + m._init_private_attributes() + return m + + def _copy_and_set_values(self: 'Model', values: 'DictStrAny', fields_set: 'SetStr', *, deep: bool) -> 'Model': + if deep: + # chances of having empty dict here are quite low for using smart_deepcopy + values = deepcopy(values) + + cls = self.__class__ + m = cls.__new__(cls) + object_setattr(m, '__dict__', values) + object_setattr(m, '__fields_set__', fields_set) + for name in self.__private_attributes__: + value = getattr(self, name, Undefined) + if value is not Undefined: + if deep: + value = deepcopy(value) + object_setattr(m, name, value) + + return m + + def copy( + self: 'Model', + *, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + update: Optional['DictStrAny'] = None, + deep: bool = False, + ) -> 'Model': + """ + Duplicate a model, optionally choose which fields to include, exclude and change. + + :param include: fields to include in new model + :param exclude: fields to exclude from new model, as with values this takes precedence over include + :param update: values to change/add in the new model. Note: the data is not validated before creating + the new model: you should trust this data + :param deep: set to `True` to make a deep copy of the model + :return: new model instance + """ + + values = dict( + self._iter(to_dict=False, by_alias=False, include=include, exclude=exclude, exclude_unset=False), + **(update or {}), + ) + + # new `__fields_set__` can have unset optional fields with a set value in `update` kwarg + if update: + fields_set = self.__fields_set__ | update.keys() + else: + fields_set = set(self.__fields_set__) + + return self._copy_and_set_values(values, fields_set, deep=deep) + + @classmethod + def schema(cls, by_alias: bool = True, ref_template: str = default_ref_template) -> 'DictStrAny': + cached = cls.__schema_cache__.get((by_alias, ref_template)) + if cached is not None: + return cached + s = model_schema(cls, by_alias=by_alias, ref_template=ref_template) + cls.__schema_cache__[(by_alias, ref_template)] = s + return s + + @classmethod + def schema_json( + cls, *, by_alias: bool = True, ref_template: str = default_ref_template, **dumps_kwargs: Any + ) -> str: + from pydantic.v1.json import pydantic_encoder + + return cls.__config__.json_dumps( + cls.schema(by_alias=by_alias, ref_template=ref_template), default=pydantic_encoder, **dumps_kwargs + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls: Type['Model'], value: Any) -> 'Model': + if isinstance(value, cls): + copy_on_model_validation = cls.__config__.copy_on_model_validation + # whether to deep or shallow copy the model on validation, None means do not copy + deep_copy: Optional[bool] = None + if copy_on_model_validation not in {'deep', 'shallow', 'none'}: + # Warn about deprecated behavior + warnings.warn( + "`copy_on_model_validation` should be a string: 'deep', 'shallow' or 'none'", DeprecationWarning + ) + if copy_on_model_validation: + deep_copy = False + + if copy_on_model_validation == 'shallow': + # shallow copy + deep_copy = False + elif copy_on_model_validation == 'deep': + # deep copy + deep_copy = True + + if deep_copy is None: + return value + else: + return value._copy_and_set_values(value.__dict__, value.__fields_set__, deep=deep_copy) + + value = cls._enforce_dict_if_root(value) + + if isinstance(value, dict): + return cls(**value) + elif cls.__config__.orm_mode: + return cls.from_orm(value) + else: + try: + value_as_dict = dict(value) + except (TypeError, ValueError) as e: + raise DictError() from e + return cls(**value_as_dict) + + @classmethod + def _decompose_class(cls: Type['Model'], obj: Any) -> GetterDict: + if isinstance(obj, GetterDict): + return obj + return cls.__config__.getter_dict(obj) + + @classmethod + @no_type_check + def _get_value( + cls, + v: Any, + to_dict: bool, + by_alias: bool, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], + exclude_unset: bool, + exclude_defaults: bool, + exclude_none: bool, + ) -> Any: + if isinstance(v, BaseModel): + if to_dict: + v_dict = v.dict( + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=include, + exclude=exclude, + exclude_none=exclude_none, + ) + if ROOT_KEY in v_dict: + return v_dict[ROOT_KEY] + return v_dict + else: + return v.copy(include=include, exclude=exclude) + + value_exclude = ValueItems(v, exclude) if exclude else None + value_include = ValueItems(v, include) if include else None + + if isinstance(v, dict): + return { + k_: cls._get_value( + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(k_), + exclude=value_exclude and value_exclude.for_element(k_), + exclude_none=exclude_none, + ) + for k_, v_ in v.items() + if (not value_exclude or not value_exclude.is_excluded(k_)) + and (not value_include or value_include.is_included(k_)) + } + + elif sequence_like(v): + seq_args = ( + cls._get_value( + v_, + to_dict=to_dict, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + include=value_include and value_include.for_element(i), + exclude=value_exclude and value_exclude.for_element(i), + exclude_none=exclude_none, + ) + for i, v_ in enumerate(v) + if (not value_exclude or not value_exclude.is_excluded(i)) + and (not value_include or value_include.is_included(i)) + ) + + return v.__class__(*seq_args) if is_namedtuple(v.__class__) else v.__class__(seq_args) + + elif isinstance(v, Enum) and getattr(cls.Config, 'use_enum_values', False): + return v.value + + else: + return v + + @classmethod + def __try_update_forward_refs__(cls, **localns: Any) -> None: + """ + Same as update_forward_refs but will not raise exception + when forward references are not defined. + """ + update_model_forward_refs(cls, cls.__fields__.values(), cls.__config__.json_encoders, localns, (NameError,)) + + @classmethod + def update_forward_refs(cls, **localns: Any) -> None: + """ + Try to update ForwardRefs on fields based on this Model, globalns and localns. + """ + update_model_forward_refs(cls, cls.__fields__.values(), cls.__config__.json_encoders, localns) + + def __iter__(self) -> 'TupleGenerator': + """ + so `dict(model)` works + """ + yield from self.__dict__.items() + + def _iter( + self, + to_dict: bool = False, + by_alias: bool = False, + include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']] = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + ) -> 'TupleGenerator': + # Merge field set excludes with explicit exclude parameter with explicit overriding field set options. + # The extra "is not None" guards are not logically necessary but optimizes performance for the simple case. + if exclude is not None or self.__exclude_fields__ is not None: + exclude = ValueItems.merge(self.__exclude_fields__, exclude) + + if include is not None or self.__include_fields__ is not None: + include = ValueItems.merge(self.__include_fields__, include, intersect=True) + + allowed_keys = self._calculate_keys( + include=include, exclude=exclude, exclude_unset=exclude_unset # type: ignore + ) + if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none): + # huge boost for plain _iter() + yield from self.__dict__.items() + return + + value_exclude = ValueItems(self, exclude) if exclude is not None else None + value_include = ValueItems(self, include) if include is not None else None + + for field_key, v in self.__dict__.items(): + if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None): + continue + + if exclude_defaults: + model_field = self.__fields__.get(field_key) + if not getattr(model_field, 'required', True) and getattr(model_field, 'default', _missing) == v: + continue + + if by_alias and field_key in self.__fields__: + dict_key = self.__fields__[field_key].alias + else: + dict_key = field_key + + if to_dict or value_include or value_exclude: + v = self._get_value( + v, + to_dict=to_dict, + by_alias=by_alias, + include=value_include and value_include.for_element(field_key), + exclude=value_exclude and value_exclude.for_element(field_key), + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) + yield dict_key, v + + def _calculate_keys( + self, + include: Optional['MappingIntStrAny'], + exclude: Optional['MappingIntStrAny'], + exclude_unset: bool, + update: Optional['DictStrAny'] = None, + ) -> Optional[AbstractSet[str]]: + if include is None and exclude is None and exclude_unset is False: + return None + + keys: AbstractSet[str] + if exclude_unset: + keys = self.__fields_set__.copy() + else: + keys = self.__dict__.keys() + + if include is not None: + keys &= include.keys() + + if update: + keys -= update.keys() + + if exclude: + keys -= {k for k, v in exclude.items() if ValueItems.is_true(v)} + + return keys + + def __eq__(self, other: Any) -> bool: + if isinstance(other, BaseModel): + return self.dict() == other.dict() + else: + return self.dict() == other + + def __repr_args__(self) -> 'ReprArgs': + return [ + (k, v) + for k, v in self.__dict__.items() + if k not in DUNDER_ATTRIBUTES and (k not in self.__fields__ or self.__fields__[k].field_info.repr) + ] + + +_is_base_model_class_defined = True + + +@overload +def create_model( + __model_name: str, + *, + __config__: Optional[Type[BaseConfig]] = None, + __base__: None = None, + __module__: str = __name__, + __validators__: Dict[str, 'AnyClassMethod'] = None, + __cls_kwargs__: Dict[str, Any] = None, + **field_definitions: Any, +) -> Type['BaseModel']: + ... + + +@overload +def create_model( + __model_name: str, + *, + __config__: Optional[Type[BaseConfig]] = None, + __base__: Union[Type['Model'], Tuple[Type['Model'], ...]], + __module__: str = __name__, + __validators__: Dict[str, 'AnyClassMethod'] = None, + __cls_kwargs__: Dict[str, Any] = None, + **field_definitions: Any, +) -> Type['Model']: + ... + + +def create_model( + __model_name: str, + *, + __config__: Optional[Type[BaseConfig]] = None, + __base__: Union[None, Type['Model'], Tuple[Type['Model'], ...]] = None, + __module__: str = __name__, + __validators__: Dict[str, 'AnyClassMethod'] = None, + __cls_kwargs__: Dict[str, Any] = None, + __slots__: Optional[Tuple[str, ...]] = None, + **field_definitions: Any, +) -> Type['Model']: + """ + Dynamically create a model. + :param __model_name: name of the created model + :param __config__: config class to use for the new model + :param __base__: base class for the new model to inherit from + :param __module__: module of the created model + :param __validators__: a dict of method names and @validator class methods + :param __cls_kwargs__: a dict for class creation + :param __slots__: Deprecated, `__slots__` should not be passed to `create_model` + :param field_definitions: fields of the model (or extra fields if a base is supplied) + in the format `=(, )` or `=, e.g. + `foobar=(str, ...)` or `foobar=123`, or, for complex use-cases, in the format + `=` or `=(, )`, e.g. + `foo=Field(datetime, default_factory=datetime.utcnow, alias='bar')` or + `foo=(str, FieldInfo(title='Foo'))` + """ + if __slots__ is not None: + # __slots__ will be ignored from here on + warnings.warn('__slots__ should not be passed to create_model', RuntimeWarning) + + if __base__ is not None: + if __config__ is not None: + raise ConfigError('to avoid confusion __config__ and __base__ cannot be used together') + if not isinstance(__base__, tuple): + __base__ = (__base__,) + else: + __base__ = (cast(Type['Model'], BaseModel),) + + __cls_kwargs__ = __cls_kwargs__ or {} + + fields = {} + annotations = {} + + for f_name, f_def in field_definitions.items(): + if not is_valid_field(f_name): + warnings.warn(f'fields may not start with an underscore, ignoring "{f_name}"', RuntimeWarning) + if isinstance(f_def, tuple): + try: + f_annotation, f_value = f_def + except ValueError as e: + raise ConfigError( + 'field definitions should either be a tuple of (, ) or just a ' + 'default value, unfortunately this means tuples as ' + 'default values are not allowed' + ) from e + else: + f_annotation, f_value = None, f_def + + if f_annotation: + annotations[f_name] = f_annotation + fields[f_name] = f_value + + namespace: 'DictStrAny' = {'__annotations__': annotations, '__module__': __module__} + if __validators__: + namespace.update(__validators__) + namespace.update(fields) + if __config__: + namespace['Config'] = inherit_config(__config__, BaseConfig) + resolved_bases = resolve_bases(__base__) + meta, ns, kwds = prepare_class(__model_name, resolved_bases, kwds=__cls_kwargs__) + if resolved_bases is not __base__: + ns['__orig_bases__'] = __base__ + namespace.update(ns) + return meta(__model_name, resolved_bases, namespace, **kwds) + + +_missing = object() + + +def validate_model( # noqa: C901 (ignore complexity) + model: Type[BaseModel], input_data: 'DictStrAny', cls: 'ModelOrDc' = None +) -> Tuple['DictStrAny', 'SetStr', Optional[ValidationError]]: + """ + validate data against a model. + """ + values = {} + errors = [] + # input_data names, possibly alias + names_used = set() + # field names, never aliases + fields_set = set() + config = model.__config__ + check_extra = config.extra is not Extra.ignore + cls_ = cls or model + + for validator in model.__pre_root_validators__: + try: + input_data = validator(cls_, input_data) + except (ValueError, TypeError, AssertionError) as exc: + return {}, set(), ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls_) + + for name, field in model.__fields__.items(): + value = input_data.get(field.alias, _missing) + using_name = False + if value is _missing and config.allow_population_by_field_name and field.alt_alias: + value = input_data.get(field.name, _missing) + using_name = True + + if value is _missing: + if field.required: + errors.append(ErrorWrapper(MissingError(), loc=field.alias)) + continue + + value = field.get_default() + + if not config.validate_all and not field.validate_always: + values[name] = value + continue + else: + fields_set.add(name) + if check_extra: + names_used.add(field.name if using_name else field.alias) + + v_, errors_ = field.validate(value, values, loc=field.alias, cls=cls_) + if isinstance(errors_, ErrorWrapper): + errors.append(errors_) + elif isinstance(errors_, list): + errors.extend(errors_) + else: + values[name] = v_ + + if check_extra: + if isinstance(input_data, GetterDict): + extra = input_data.extra_keys() - names_used + else: + extra = input_data.keys() - names_used + if extra: + fields_set |= extra + if config.extra is Extra.allow: + for f in extra: + values[f] = input_data[f] + else: + for f in sorted(extra): + errors.append(ErrorWrapper(ExtraError(), loc=f)) + + for skip_on_failure, validator in model.__post_root_validators__: + if skip_on_failure and errors: + continue + try: + values = validator(cls_, values) + except (ValueError, TypeError, AssertionError) as exc: + errors.append(ErrorWrapper(exc, loc=ROOT_KEY)) + + if errors: + return values, fields_set, ValidationError(errors, cls_) + else: + return values, fields_set, None diff --git a/source/target-vendors/cp312/pydantic/v1/mypy.py b/source/target-vendors/cp312/pydantic/v1/mypy.py new file mode 100644 index 0000000..0a77569 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/mypy.py @@ -0,0 +1,949 @@ +import sys +from configparser import ConfigParser +from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Type as TypingType, Union + +from mypy.errorcodes import ErrorCode +from mypy.nodes import ( + ARG_NAMED, + ARG_NAMED_OPT, + ARG_OPT, + ARG_POS, + ARG_STAR2, + MDEF, + Argument, + AssignmentStmt, + Block, + CallExpr, + ClassDef, + Context, + Decorator, + EllipsisExpr, + FuncBase, + FuncDef, + JsonDict, + MemberExpr, + NameExpr, + PassStmt, + PlaceholderNode, + RefExpr, + StrExpr, + SymbolNode, + SymbolTableNode, + TempNode, + TypeInfo, + TypeVarExpr, + Var, +) +from mypy.options import Options +from mypy.plugin import ( + CheckerPluginInterface, + ClassDefContext, + FunctionContext, + MethodContext, + Plugin, + ReportConfigContext, + SemanticAnalyzerPluginInterface, +) +from mypy.plugins import dataclasses +from mypy.semanal import set_callable_name # type: ignore +from mypy.server.trigger import make_wildcard_trigger +from mypy.types import ( + AnyType, + CallableType, + Instance, + NoneType, + Overloaded, + ProperType, + Type, + TypeOfAny, + TypeType, + TypeVarId, + TypeVarType, + UnionType, + get_proper_type, +) +from mypy.typevars import fill_typevars +from mypy.util import get_unique_redefinition_name +from mypy.version import __version__ as mypy_version + +from pydantic.v1.utils import is_valid_field + +try: + from mypy.types import TypeVarDef # type: ignore[attr-defined] +except ImportError: # pragma: no cover + # Backward-compatible with TypeVarDef from Mypy 0.910. + from mypy.types import TypeVarType as TypeVarDef + +CONFIGFILE_KEY = 'pydantic-mypy' +METADATA_KEY = 'pydantic-mypy-metadata' +_NAMESPACE = __name__[:-5] # 'pydantic' in 1.10.X, 'pydantic.v1' in v2.X +BASEMODEL_FULLNAME = f'{_NAMESPACE}.main.BaseModel' +BASESETTINGS_FULLNAME = f'{_NAMESPACE}.env_settings.BaseSettings' +MODEL_METACLASS_FULLNAME = f'{_NAMESPACE}.main.ModelMetaclass' +FIELD_FULLNAME = f'{_NAMESPACE}.fields.Field' +DATACLASS_FULLNAME = f'{_NAMESPACE}.dataclasses.dataclass' + + +def parse_mypy_version(version: str) -> Tuple[int, ...]: + return tuple(map(int, version.partition('+')[0].split('.'))) + + +MYPY_VERSION_TUPLE = parse_mypy_version(mypy_version) +BUILTINS_NAME = 'builtins' if MYPY_VERSION_TUPLE >= (0, 930) else '__builtins__' + +# Increment version if plugin changes and mypy caches should be invalidated +__version__ = 2 + + +def plugin(version: str) -> 'TypingType[Plugin]': + """ + `version` is the mypy version string + + We might want to use this to print a warning if the mypy version being used is + newer, or especially older, than we expect (or need). + """ + return PydanticPlugin + + +class PydanticPlugin(Plugin): + def __init__(self, options: Options) -> None: + self.plugin_config = PydanticPluginConfig(options) + self._plugin_data = self.plugin_config.to_data() + super().__init__(options) + + def get_base_class_hook(self, fullname: str) -> 'Optional[Callable[[ClassDefContext], None]]': + sym = self.lookup_fully_qualified(fullname) + if sym and isinstance(sym.node, TypeInfo): # pragma: no branch + # No branching may occur if the mypy cache has not been cleared + if any(get_fullname(base) == BASEMODEL_FULLNAME for base in sym.node.mro): + return self._pydantic_model_class_maker_callback + return None + + def get_metaclass_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]: + if fullname == MODEL_METACLASS_FULLNAME: + return self._pydantic_model_metaclass_marker_callback + return None + + def get_function_hook(self, fullname: str) -> 'Optional[Callable[[FunctionContext], Type]]': + sym = self.lookup_fully_qualified(fullname) + if sym and sym.fullname == FIELD_FULLNAME: + return self._pydantic_field_callback + return None + + def get_method_hook(self, fullname: str) -> Optional[Callable[[MethodContext], Type]]: + if fullname.endswith('.from_orm'): + return from_orm_callback + return None + + def get_class_decorator_hook(self, fullname: str) -> Optional[Callable[[ClassDefContext], None]]: + """Mark pydantic.dataclasses as dataclass. + + Mypy version 1.1.1 added support for `@dataclass_transform` decorator. + """ + if fullname == DATACLASS_FULLNAME and MYPY_VERSION_TUPLE < (1, 1): + return dataclasses.dataclass_class_maker_callback # type: ignore[return-value] + return None + + def report_config_data(self, ctx: ReportConfigContext) -> Dict[str, Any]: + """Return all plugin config data. + + Used by mypy to determine if cache needs to be discarded. + """ + return self._plugin_data + + def _pydantic_model_class_maker_callback(self, ctx: ClassDefContext) -> None: + transformer = PydanticModelTransformer(ctx, self.plugin_config) + transformer.transform() + + def _pydantic_model_metaclass_marker_callback(self, ctx: ClassDefContext) -> None: + """Reset dataclass_transform_spec attribute of ModelMetaclass. + + Let the plugin handle it. This behavior can be disabled + if 'debug_dataclass_transform' is set to True', for testing purposes. + """ + if self.plugin_config.debug_dataclass_transform: + return + info_metaclass = ctx.cls.info.declared_metaclass + assert info_metaclass, "callback not passed from 'get_metaclass_hook'" + if getattr(info_metaclass.type, 'dataclass_transform_spec', None): + info_metaclass.type.dataclass_transform_spec = None # type: ignore[attr-defined] + + def _pydantic_field_callback(self, ctx: FunctionContext) -> 'Type': + """ + Extract the type of the `default` argument from the Field function, and use it as the return type. + + In particular: + * Check whether the default and default_factory argument is specified. + * Output an error if both are specified. + * Retrieve the type of the argument which is specified, and use it as return type for the function. + """ + default_any_type = ctx.default_return_type + + assert ctx.callee_arg_names[0] == 'default', '"default" is no longer first argument in Field()' + assert ctx.callee_arg_names[1] == 'default_factory', '"default_factory" is no longer second argument in Field()' + default_args = ctx.args[0] + default_factory_args = ctx.args[1] + + if default_args and default_factory_args: + error_default_and_default_factory_specified(ctx.api, ctx.context) + return default_any_type + + if default_args: + default_type = ctx.arg_types[0][0] + default_arg = default_args[0] + + # Fallback to default Any type if the field is required + if not isinstance(default_arg, EllipsisExpr): + return default_type + + elif default_factory_args: + default_factory_type = ctx.arg_types[1][0] + + # Functions which use `ParamSpec` can be overloaded, exposing the callable's types as a parameter + # Pydantic calls the default factory without any argument, so we retrieve the first item + if isinstance(default_factory_type, Overloaded): + if MYPY_VERSION_TUPLE > (0, 910): + default_factory_type = default_factory_type.items[0] + else: + # Mypy0.910 exposes the items of overloaded types in a function + default_factory_type = default_factory_type.items()[0] # type: ignore[operator] + + if isinstance(default_factory_type, CallableType): + ret_type = get_proper_type(default_factory_type.ret_type) + if ( + isinstance(ret_type, Instance) + and ret_type.args + and all(isinstance(arg, TypeVarType) for arg in ret_type.args) + ): + # Looks like the default factory is a type like `list` or `dict`, replace all args with `Any` + ret_type = ret_type.copy_modified(args=[default_any_type] * len(ret_type.args)) + return ret_type + + return default_any_type + + +class PydanticPluginConfig: + __slots__ = ( + 'init_forbid_extra', + 'init_typed', + 'warn_required_dynamic_aliases', + 'warn_untyped_fields', + 'debug_dataclass_transform', + ) + init_forbid_extra: bool + init_typed: bool + warn_required_dynamic_aliases: bool + warn_untyped_fields: bool + debug_dataclass_transform: bool # undocumented + + def __init__(self, options: Options) -> None: + if options.config_file is None: # pragma: no cover + return + + toml_config = parse_toml(options.config_file) + if toml_config is not None: + config = toml_config.get('tool', {}).get('pydantic-mypy', {}) + for key in self.__slots__: + setting = config.get(key, False) + if not isinstance(setting, bool): + raise ValueError(f'Configuration value must be a boolean for key: {key}') + setattr(self, key, setting) + else: + plugin_config = ConfigParser() + plugin_config.read(options.config_file) + for key in self.__slots__: + setting = plugin_config.getboolean(CONFIGFILE_KEY, key, fallback=False) + setattr(self, key, setting) + + def to_data(self) -> Dict[str, Any]: + return {key: getattr(self, key) for key in self.__slots__} + + +def from_orm_callback(ctx: MethodContext) -> Type: + """ + Raise an error if orm_mode is not enabled + """ + model_type: Instance + ctx_type = ctx.type + if isinstance(ctx_type, TypeType): + ctx_type = ctx_type.item + if isinstance(ctx_type, CallableType) and isinstance(ctx_type.ret_type, Instance): + model_type = ctx_type.ret_type # called on the class + elif isinstance(ctx_type, Instance): + model_type = ctx_type # called on an instance (unusual, but still valid) + else: # pragma: no cover + detail = f'ctx.type: {ctx_type} (of type {ctx_type.__class__.__name__})' + error_unexpected_behavior(detail, ctx.api, ctx.context) + return ctx.default_return_type + pydantic_metadata = model_type.type.metadata.get(METADATA_KEY) + if pydantic_metadata is None: + return ctx.default_return_type + orm_mode = pydantic_metadata.get('config', {}).get('orm_mode') + if orm_mode is not True: + error_from_orm(get_name(model_type.type), ctx.api, ctx.context) + return ctx.default_return_type + + +class PydanticModelTransformer: + tracked_config_fields: Set[str] = { + 'extra', + 'allow_mutation', + 'frozen', + 'orm_mode', + 'allow_population_by_field_name', + 'alias_generator', + } + + def __init__(self, ctx: ClassDefContext, plugin_config: PydanticPluginConfig) -> None: + self._ctx = ctx + self.plugin_config = plugin_config + + def transform(self) -> None: + """ + Configures the BaseModel subclass according to the plugin settings. + + In particular: + * determines the model config and fields, + * adds a fields-aware signature for the initializer and construct methods + * freezes the class if allow_mutation = False or frozen = True + * stores the fields, config, and if the class is settings in the mypy metadata for access by subclasses + """ + ctx = self._ctx + info = ctx.cls.info + + self.adjust_validator_signatures() + config = self.collect_config() + fields = self.collect_fields(config) + is_settings = any(get_fullname(base) == BASESETTINGS_FULLNAME for base in info.mro[:-1]) + self.add_initializer(fields, config, is_settings) + self.add_construct_method(fields) + self.set_frozen(fields, frozen=config.allow_mutation is False or config.frozen is True) + info.metadata[METADATA_KEY] = { + 'fields': {field.name: field.serialize() for field in fields}, + 'config': config.set_values_dict(), + } + + def adjust_validator_signatures(self) -> None: + """When we decorate a function `f` with `pydantic.validator(...), mypy sees + `f` as a regular method taking a `self` instance, even though pydantic + internally wraps `f` with `classmethod` if necessary. + + Teach mypy this by marking any function whose outermost decorator is a + `validator()` call as a classmethod. + """ + for name, sym in self._ctx.cls.info.names.items(): + if isinstance(sym.node, Decorator): + first_dec = sym.node.original_decorators[0] + if ( + isinstance(first_dec, CallExpr) + and isinstance(first_dec.callee, NameExpr) + and first_dec.callee.fullname == f'{_NAMESPACE}.class_validators.validator' + ): + sym.node.func.is_class = True + + def collect_config(self) -> 'ModelConfigData': + """ + Collects the values of the config attributes that are used by the plugin, accounting for parent classes. + """ + ctx = self._ctx + cls = ctx.cls + config = ModelConfigData() + for stmt in cls.defs.body: + if not isinstance(stmt, ClassDef): + continue + if stmt.name == 'Config': + for substmt in stmt.defs.body: + if not isinstance(substmt, AssignmentStmt): + continue + config.update(self.get_config_update(substmt)) + if ( + config.has_alias_generator + and not config.allow_population_by_field_name + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(ctx.api, stmt) + for info in cls.info.mro[1:]: # 0 is the current class + if METADATA_KEY not in info.metadata: + continue + + # Each class depends on the set of fields in its ancestors + ctx.api.add_plugin_dependency(make_wildcard_trigger(get_fullname(info))) + for name, value in info.metadata[METADATA_KEY]['config'].items(): + config.setdefault(name, value) + return config + + def collect_fields(self, model_config: 'ModelConfigData') -> List['PydanticModelField']: + """ + Collects the fields for the model, accounting for parent classes + """ + # First, collect fields belonging to the current class. + ctx = self._ctx + cls = self._ctx.cls + fields = [] # type: List[PydanticModelField] + known_fields = set() # type: Set[str] + for stmt in cls.defs.body: + if not isinstance(stmt, AssignmentStmt): # `and stmt.new_syntax` to require annotation + continue + + lhs = stmt.lvalues[0] + if not isinstance(lhs, NameExpr) or not is_valid_field(lhs.name): + continue + + if not stmt.new_syntax and self.plugin_config.warn_untyped_fields: + error_untyped_fields(ctx.api, stmt) + + # if lhs.name == '__config__': # BaseConfig not well handled; I'm not sure why yet + # continue + + sym = cls.info.names.get(lhs.name) + if sym is None: # pragma: no cover + # This is likely due to a star import (see the dataclasses plugin for a more detailed explanation) + # This is the same logic used in the dataclasses plugin + continue + + node = sym.node + if isinstance(node, PlaceholderNode): # pragma: no cover + # See the PlaceholderNode docstring for more detail about how this can occur + # Basically, it is an edge case when dealing with complex import logic + # This is the same logic used in the dataclasses plugin + continue + if not isinstance(node, Var): # pragma: no cover + # Don't know if this edge case still happens with the `is_valid_field` check above + # but better safe than sorry + continue + + # x: ClassVar[int] is ignored by dataclasses. + if node.is_classvar: + continue + + is_required = self.get_is_required(cls, stmt, lhs) + alias, has_dynamic_alias = self.get_alias_info(stmt) + if ( + has_dynamic_alias + and not model_config.allow_population_by_field_name + and self.plugin_config.warn_required_dynamic_aliases + ): + error_required_dynamic_aliases(ctx.api, stmt) + fields.append( + PydanticModelField( + name=lhs.name, + is_required=is_required, + alias=alias, + has_dynamic_alias=has_dynamic_alias, + line=stmt.line, + column=stmt.column, + ) + ) + known_fields.add(lhs.name) + all_fields = fields.copy() + for info in cls.info.mro[1:]: # 0 is the current class, -2 is BaseModel, -1 is object + if METADATA_KEY not in info.metadata: + continue + + superclass_fields = [] + # Each class depends on the set of fields in its ancestors + ctx.api.add_plugin_dependency(make_wildcard_trigger(get_fullname(info))) + + for name, data in info.metadata[METADATA_KEY]['fields'].items(): + if name not in known_fields: + field = PydanticModelField.deserialize(info, data) + known_fields.add(name) + superclass_fields.append(field) + else: + (field,) = (a for a in all_fields if a.name == name) + all_fields.remove(field) + superclass_fields.append(field) + all_fields = superclass_fields + all_fields + return all_fields + + def add_initializer(self, fields: List['PydanticModelField'], config: 'ModelConfigData', is_settings: bool) -> None: + """ + Adds a fields-aware `__init__` method to the class. + + The added `__init__` will be annotated with types vs. all `Any` depending on the plugin settings. + """ + ctx = self._ctx + typed = self.plugin_config.init_typed + use_alias = config.allow_population_by_field_name is not True + force_all_optional = is_settings or bool( + config.has_alias_generator and not config.allow_population_by_field_name + ) + init_arguments = self.get_field_arguments( + fields, typed=typed, force_all_optional=force_all_optional, use_alias=use_alias + ) + if not self.should_init_forbid_extra(fields, config): + var = Var('kwargs') + init_arguments.append(Argument(var, AnyType(TypeOfAny.explicit), None, ARG_STAR2)) + + if '__init__' not in ctx.cls.info.names: + add_method(ctx, '__init__', init_arguments, NoneType()) + + def add_construct_method(self, fields: List['PydanticModelField']) -> None: + """ + Adds a fully typed `construct` classmethod to the class. + + Similar to the fields-aware __init__ method, but always uses the field names (not aliases), + and does not treat settings fields as optional. + """ + ctx = self._ctx + set_str = ctx.api.named_type(f'{BUILTINS_NAME}.set', [ctx.api.named_type(f'{BUILTINS_NAME}.str')]) + optional_set_str = UnionType([set_str, NoneType()]) + fields_set_argument = Argument(Var('_fields_set', optional_set_str), optional_set_str, None, ARG_OPT) + construct_arguments = self.get_field_arguments(fields, typed=True, force_all_optional=False, use_alias=False) + construct_arguments = [fields_set_argument] + construct_arguments + + obj_type = ctx.api.named_type(f'{BUILTINS_NAME}.object') + self_tvar_name = '_PydanticBaseModel' # Make sure it does not conflict with other names in the class + tvar_fullname = ctx.cls.fullname + '.' + self_tvar_name + if MYPY_VERSION_TUPLE >= (1, 4): + tvd = TypeVarType( + self_tvar_name, + tvar_fullname, + ( + TypeVarId(-1, namespace=ctx.cls.fullname + '.construct') + if MYPY_VERSION_TUPLE >= (1, 11) + else TypeVarId(-1) + ), + [], + obj_type, + AnyType(TypeOfAny.from_omitted_generics), # type: ignore[arg-type] + ) + self_tvar_expr = TypeVarExpr( + self_tvar_name, + tvar_fullname, + [], + obj_type, + AnyType(TypeOfAny.from_omitted_generics), # type: ignore[arg-type] + ) + else: + tvd = TypeVarDef(self_tvar_name, tvar_fullname, -1, [], obj_type) + self_tvar_expr = TypeVarExpr(self_tvar_name, tvar_fullname, [], obj_type) + ctx.cls.info.names[self_tvar_name] = SymbolTableNode(MDEF, self_tvar_expr) + + # Backward-compatible with TypeVarDef from Mypy 0.910. + if isinstance(tvd, TypeVarType): + self_type = tvd + else: + self_type = TypeVarType(tvd) + + add_method( + ctx, + 'construct', + construct_arguments, + return_type=self_type, + self_type=self_type, + tvar_def=tvd, + is_classmethod=True, + ) + + def set_frozen(self, fields: List['PydanticModelField'], frozen: bool) -> None: + """ + Marks all fields as properties so that attempts to set them trigger mypy errors. + + This is the same approach used by the attrs and dataclasses plugins. + """ + ctx = self._ctx + info = ctx.cls.info + for field in fields: + sym_node = info.names.get(field.name) + if sym_node is not None: + var = sym_node.node + if isinstance(var, Var): + var.is_property = frozen + elif isinstance(var, PlaceholderNode) and not ctx.api.final_iteration: + # See https://github.com/pydantic/pydantic/issues/5191 to hit this branch for test coverage + ctx.api.defer() + else: # pragma: no cover + # I don't know whether it's possible to hit this branch, but I've added it for safety + try: + var_str = str(var) + except TypeError: + # This happens for PlaceholderNode; perhaps it will happen for other types in the future.. + var_str = repr(var) + detail = f'sym_node.node: {var_str} (of type {var.__class__})' + error_unexpected_behavior(detail, ctx.api, ctx.cls) + else: + var = field.to_var(info, use_alias=False) + var.info = info + var.is_property = frozen + var._fullname = get_fullname(info) + '.' + get_name(var) + info.names[get_name(var)] = SymbolTableNode(MDEF, var) + + def get_config_update(self, substmt: AssignmentStmt) -> Optional['ModelConfigData']: + """ + Determines the config update due to a single statement in the Config class definition. + + Warns if a tracked config attribute is set to a value the plugin doesn't know how to interpret (e.g., an int) + """ + lhs = substmt.lvalues[0] + if not (isinstance(lhs, NameExpr) and lhs.name in self.tracked_config_fields): + return None + if lhs.name == 'extra': + if isinstance(substmt.rvalue, StrExpr): + forbid_extra = substmt.rvalue.value == 'forbid' + elif isinstance(substmt.rvalue, MemberExpr): + forbid_extra = substmt.rvalue.name == 'forbid' + else: + error_invalid_config_value(lhs.name, self._ctx.api, substmt) + return None + return ModelConfigData(forbid_extra=forbid_extra) + if lhs.name == 'alias_generator': + has_alias_generator = True + if isinstance(substmt.rvalue, NameExpr) and substmt.rvalue.fullname == 'builtins.None': + has_alias_generator = False + return ModelConfigData(has_alias_generator=has_alias_generator) + if isinstance(substmt.rvalue, NameExpr) and substmt.rvalue.fullname in ('builtins.True', 'builtins.False'): + return ModelConfigData(**{lhs.name: substmt.rvalue.fullname == 'builtins.True'}) + error_invalid_config_value(lhs.name, self._ctx.api, substmt) + return None + + @staticmethod + def get_is_required(cls: ClassDef, stmt: AssignmentStmt, lhs: NameExpr) -> bool: + """ + Returns a boolean indicating whether the field defined in `stmt` is a required field. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only, so only non-required if Optional + value_type = get_proper_type(cls.info[lhs.name].type) + return not PydanticModelTransformer.type_has_implicit_default(value_type) + if isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME: + # The "default value" is a call to `Field`; at this point, the field is + # only required if default is Ellipsis (i.e., `field_name: Annotation = Field(...)`) or if default_factory + # is specified. + for arg, name in zip(expr.args, expr.arg_names): + # If name is None, then this arg is the default because it is the only positional argument. + if name is None or name == 'default': + return arg.__class__ is EllipsisExpr + if name == 'default_factory': + return False + # In this case, default and default_factory are not specified, so we need to look at the annotation + value_type = get_proper_type(cls.info[lhs.name].type) + return not PydanticModelTransformer.type_has_implicit_default(value_type) + # Only required if the "default value" is Ellipsis (i.e., `field_name: Annotation = ...`) + return isinstance(expr, EllipsisExpr) + + @staticmethod + def type_has_implicit_default(type_: Optional[ProperType]) -> bool: + """ + Returns True if the passed type will be given an implicit default value. + + In pydantic v1, this is the case for Optional types and Any (with default value None). + """ + if isinstance(type_, AnyType): + # Annotated as Any + return True + if isinstance(type_, UnionType) and any( + isinstance(item, NoneType) or isinstance(item, AnyType) for item in type_.items + ): + # Annotated as Optional, or otherwise having NoneType or AnyType in the union + return True + return False + + @staticmethod + def get_alias_info(stmt: AssignmentStmt) -> Tuple[Optional[str], bool]: + """ + Returns a pair (alias, has_dynamic_alias), extracted from the declaration of the field defined in `stmt`. + + `has_dynamic_alias` is True if and only if an alias is provided, but not as a string literal. + If `has_dynamic_alias` is True, `alias` will be None. + """ + expr = stmt.rvalue + if isinstance(expr, TempNode): + # TempNode means annotation-only + return None, False + + if not ( + isinstance(expr, CallExpr) and isinstance(expr.callee, RefExpr) and expr.callee.fullname == FIELD_FULLNAME + ): + # Assigned value is not a call to pydantic.fields.Field + return None, False + + for i, arg_name in enumerate(expr.arg_names): + if arg_name != 'alias': + continue + arg = expr.args[i] + if isinstance(arg, StrExpr): + return arg.value, False + else: + return None, True + return None, False + + def get_field_arguments( + self, fields: List['PydanticModelField'], typed: bool, force_all_optional: bool, use_alias: bool + ) -> List[Argument]: + """ + Helper function used during the construction of the `__init__` and `construct` method signatures. + + Returns a list of mypy Argument instances for use in the generated signatures. + """ + info = self._ctx.cls.info + arguments = [ + field.to_argument(info, typed=typed, force_optional=force_all_optional, use_alias=use_alias) + for field in fields + if not (use_alias and field.has_dynamic_alias) + ] + return arguments + + def should_init_forbid_extra(self, fields: List['PydanticModelField'], config: 'ModelConfigData') -> bool: + """ + Indicates whether the generated `__init__` should get a `**kwargs` at the end of its signature + + We disallow arbitrary kwargs if the extra config setting is "forbid", or if the plugin config says to, + *unless* a required dynamic alias is present (since then we can't determine a valid signature). + """ + if not config.allow_population_by_field_name: + if self.is_dynamic_alias_present(fields, bool(config.has_alias_generator)): + return False + if config.forbid_extra: + return True + return self.plugin_config.init_forbid_extra + + @staticmethod + def is_dynamic_alias_present(fields: List['PydanticModelField'], has_alias_generator: bool) -> bool: + """ + Returns whether any fields on the model have a "dynamic alias", i.e., an alias that cannot be + determined during static analysis. + """ + for field in fields: + if field.has_dynamic_alias: + return True + if has_alias_generator: + for field in fields: + if field.alias is None: + return True + return False + + +class PydanticModelField: + def __init__( + self, name: str, is_required: bool, alias: Optional[str], has_dynamic_alias: bool, line: int, column: int + ): + self.name = name + self.is_required = is_required + self.alias = alias + self.has_dynamic_alias = has_dynamic_alias + self.line = line + self.column = column + + def to_var(self, info: TypeInfo, use_alias: bool) -> Var: + name = self.name + if use_alias and self.alias is not None: + name = self.alias + return Var(name, info[self.name].type) + + def to_argument(self, info: TypeInfo, typed: bool, force_optional: bool, use_alias: bool) -> Argument: + if typed and info[self.name].type is not None: + type_annotation = info[self.name].type + else: + type_annotation = AnyType(TypeOfAny.explicit) + return Argument( + variable=self.to_var(info, use_alias), + type_annotation=type_annotation, + initializer=None, + kind=ARG_NAMED_OPT if force_optional or not self.is_required else ARG_NAMED, + ) + + def serialize(self) -> JsonDict: + return self.__dict__ + + @classmethod + def deserialize(cls, info: TypeInfo, data: JsonDict) -> 'PydanticModelField': + return cls(**data) + + +class ModelConfigData: + def __init__( + self, + forbid_extra: Optional[bool] = None, + allow_mutation: Optional[bool] = None, + frozen: Optional[bool] = None, + orm_mode: Optional[bool] = None, + allow_population_by_field_name: Optional[bool] = None, + has_alias_generator: Optional[bool] = None, + ): + self.forbid_extra = forbid_extra + self.allow_mutation = allow_mutation + self.frozen = frozen + self.orm_mode = orm_mode + self.allow_population_by_field_name = allow_population_by_field_name + self.has_alias_generator = has_alias_generator + + def set_values_dict(self) -> Dict[str, Any]: + return {k: v for k, v in self.__dict__.items() if v is not None} + + def update(self, config: Optional['ModelConfigData']) -> None: + if config is None: + return + for k, v in config.set_values_dict().items(): + setattr(self, k, v) + + def setdefault(self, key: str, value: Any) -> None: + if getattr(self, key) is None: + setattr(self, key, value) + + +ERROR_ORM = ErrorCode('pydantic-orm', 'Invalid from_orm call', 'Pydantic') +ERROR_CONFIG = ErrorCode('pydantic-config', 'Invalid config value', 'Pydantic') +ERROR_ALIAS = ErrorCode('pydantic-alias', 'Dynamic alias disallowed', 'Pydantic') +ERROR_UNEXPECTED = ErrorCode('pydantic-unexpected', 'Unexpected behavior', 'Pydantic') +ERROR_UNTYPED = ErrorCode('pydantic-field', 'Untyped field disallowed', 'Pydantic') +ERROR_FIELD_DEFAULTS = ErrorCode('pydantic-field', 'Invalid Field defaults', 'Pydantic') + + +def error_from_orm(model_name: str, api: CheckerPluginInterface, context: Context) -> None: + api.fail(f'"{model_name}" does not have orm_mode=True', context, code=ERROR_ORM) + + +def error_invalid_config_value(name: str, api: SemanticAnalyzerPluginInterface, context: Context) -> None: + api.fail(f'Invalid value for "Config.{name}"', context, code=ERROR_CONFIG) + + +def error_required_dynamic_aliases(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + api.fail('Required dynamic aliases disallowed', context, code=ERROR_ALIAS) + + +def error_unexpected_behavior( + detail: str, api: Union[CheckerPluginInterface, SemanticAnalyzerPluginInterface], context: Context +) -> None: # pragma: no cover + # Can't think of a good way to test this, but I confirmed it renders as desired by adding to a non-error path + link = 'https://github.com/pydantic/pydantic/issues/new/choose' + full_message = f'The pydantic mypy plugin ran into unexpected behavior: {detail}\n' + full_message += f'Please consider reporting this bug at {link} so we can try to fix it!' + api.fail(full_message, context, code=ERROR_UNEXPECTED) + + +def error_untyped_fields(api: SemanticAnalyzerPluginInterface, context: Context) -> None: + api.fail('Untyped fields disallowed', context, code=ERROR_UNTYPED) + + +def error_default_and_default_factory_specified(api: CheckerPluginInterface, context: Context) -> None: + api.fail('Field default and default_factory cannot be specified together', context, code=ERROR_FIELD_DEFAULTS) + + +def add_method( + ctx: ClassDefContext, + name: str, + args: List[Argument], + return_type: Type, + self_type: Optional[Type] = None, + tvar_def: Optional[TypeVarDef] = None, + is_classmethod: bool = False, + is_new: bool = False, + # is_staticmethod: bool = False, +) -> None: + """ + Adds a new method to a class. + + This can be dropped if/when https://github.com/python/mypy/issues/7301 is merged + """ + info = ctx.cls.info + + # First remove any previously generated methods with the same name + # to avoid clashes and problems in the semantic analyzer. + if name in info.names: + sym = info.names[name] + if sym.plugin_generated and isinstance(sym.node, FuncDef): + ctx.cls.defs.body.remove(sym.node) # pragma: no cover + + self_type = self_type or fill_typevars(info) + if is_classmethod or is_new: + first = [Argument(Var('_cls'), TypeType.make_normalized(self_type), None, ARG_POS)] + # elif is_staticmethod: + # first = [] + else: + self_type = self_type or fill_typevars(info) + first = [Argument(Var('__pydantic_self__'), self_type, None, ARG_POS)] + args = first + args + arg_types, arg_names, arg_kinds = [], [], [] + for arg in args: + assert arg.type_annotation, 'All arguments must be fully typed.' + arg_types.append(arg.type_annotation) + arg_names.append(get_name(arg.variable)) + arg_kinds.append(arg.kind) + + function_type = ctx.api.named_type(f'{BUILTINS_NAME}.function') + signature = CallableType( + arg_types, arg_kinds, arg_names, return_type, function_type, variables=[tvar_def] if tvar_def else None + ) + + func = FuncDef(name, args, Block([PassStmt()])) + func.info = info + func.type = set_callable_name(signature, func) + func.is_class = is_classmethod + # func.is_static = is_staticmethod + func._fullname = get_fullname(info) + '.' + name + func.line = info.line + + # NOTE: we would like the plugin generated node to dominate, but we still + # need to keep any existing definitions so they get semantically analyzed. + if name in info.names: + # Get a nice unique name instead. + r_name = get_unique_redefinition_name(name, info.names) + info.names[r_name] = info.names[name] + + if is_classmethod: # or is_staticmethod: + func.is_decorated = True + v = Var(name, func.type) + v.info = info + v._fullname = func._fullname + # if is_classmethod: + v.is_classmethod = True + dec = Decorator(func, [NameExpr('classmethod')], v) + # else: + # v.is_staticmethod = True + # dec = Decorator(func, [NameExpr('staticmethod')], v) + + dec.line = info.line + sym = SymbolTableNode(MDEF, dec) + else: + sym = SymbolTableNode(MDEF, func) + sym.plugin_generated = True + + info.names[name] = sym + info.defn.defs.body.append(func) + + +def get_fullname(x: Union[FuncBase, SymbolNode]) -> str: + """ + Used for compatibility with mypy 0.740; can be dropped once support for 0.740 is dropped. + """ + fn = x.fullname + if callable(fn): # pragma: no cover + return fn() + return fn + + +def get_name(x: Union[FuncBase, SymbolNode]) -> str: + """ + Used for compatibility with mypy 0.740; can be dropped once support for 0.740 is dropped. + """ + fn = x.name + if callable(fn): # pragma: no cover + return fn() + return fn + + +def parse_toml(config_file: str) -> Optional[Dict[str, Any]]: + if not config_file.endswith('.toml'): + return None + + read_mode = 'rb' + if sys.version_info >= (3, 11): + import tomllib as toml_ + else: + try: + import tomli as toml_ + except ImportError: + # older versions of mypy have toml as a dependency, not tomli + read_mode = 'r' + try: + import toml as toml_ # type: ignore[no-redef] + except ImportError: # pragma: no cover + import warnings + + warnings.warn('No TOML parser installed, cannot read configuration from `pyproject.toml`.') + return None + + with open(config_file, read_mode) as rf: + return toml_.load(rf) # type: ignore[arg-type] diff --git a/source/target-vendors/cp312/pydantic/v1/networks.py b/source/target-vendors/cp312/pydantic/v1/networks.py new file mode 100644 index 0000000..ba07b74 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/networks.py @@ -0,0 +1,747 @@ +import re +from ipaddress import ( + IPv4Address, + IPv4Interface, + IPv4Network, + IPv6Address, + IPv6Interface, + IPv6Network, + _BaseAddress, + _BaseNetwork, +) +from typing import ( + TYPE_CHECKING, + Any, + Collection, + Dict, + Generator, + List, + Match, + Optional, + Pattern, + Set, + Tuple, + Type, + Union, + cast, + no_type_check, +) + +from pydantic.v1 import errors +from pydantic.v1.utils import Representation, update_not_none +from pydantic.v1.validators import constr_length_validator, str_validator + +if TYPE_CHECKING: + import email_validator + from typing_extensions import TypedDict + + from pydantic.v1.config import BaseConfig + from pydantic.v1.fields import ModelField + from pydantic.v1.typing import AnyCallable + + CallableGenerator = Generator[AnyCallable, None, None] + + class Parts(TypedDict, total=False): + scheme: str + user: Optional[str] + password: Optional[str] + ipv4: Optional[str] + ipv6: Optional[str] + domain: Optional[str] + port: Optional[str] + path: Optional[str] + query: Optional[str] + fragment: Optional[str] + + class HostParts(TypedDict, total=False): + host: str + tld: Optional[str] + host_type: Optional[str] + port: Optional[str] + rebuild: bool + +else: + email_validator = None + + class Parts(dict): + pass + + +NetworkType = Union[str, bytes, int, Tuple[Union[str, bytes, int], Union[str, int]]] + +__all__ = [ + 'AnyUrl', + 'AnyHttpUrl', + 'FileUrl', + 'HttpUrl', + 'stricturl', + 'EmailStr', + 'NameEmail', + 'IPvAnyAddress', + 'IPvAnyInterface', + 'IPvAnyNetwork', + 'PostgresDsn', + 'CockroachDsn', + 'AmqpDsn', + 'RedisDsn', + 'MongoDsn', + 'KafkaDsn', + 'validate_email', +] + +_url_regex_cache = None +_multi_host_url_regex_cache = None +_ascii_domain_regex_cache = None +_int_domain_regex_cache = None +_host_regex_cache = None + +_host_regex = ( + r'(?:' + r'(?P(?:\d{1,3}\.){3}\d{1,3})(?=$|[/:#?])|' # ipv4 + r'(?P\[[A-F0-9]*:[A-F0-9:]+\])(?=$|[/:#?])|' # ipv6 + r'(?P[^\s/:?#]+)' # domain, validation occurs later + r')?' + r'(?::(?P\d+))?' # port +) +_scheme_regex = r'(?:(?P[a-z][a-z0-9+\-.]+)://)?' # scheme https://tools.ietf.org/html/rfc3986#appendix-A +_user_info_regex = r'(?:(?P[^\s:/]*)(?::(?P[^\s/]*))?@)?' +_path_regex = r'(?P/[^\s?#]*)?' +_query_regex = r'(?:\?(?P[^\s#]*))?' +_fragment_regex = r'(?:#(?P[^\s#]*))?' + + +def url_regex() -> Pattern[str]: + global _url_regex_cache + if _url_regex_cache is None: + _url_regex_cache = re.compile( + rf'{_scheme_regex}{_user_info_regex}{_host_regex}{_path_regex}{_query_regex}{_fragment_regex}', + re.IGNORECASE, + ) + return _url_regex_cache + + +def multi_host_url_regex() -> Pattern[str]: + """ + Compiled multi host url regex. + + Additionally to `url_regex` it allows to match multiple hosts. + E.g. host1.db.net,host2.db.net + """ + global _multi_host_url_regex_cache + if _multi_host_url_regex_cache is None: + _multi_host_url_regex_cache = re.compile( + rf'{_scheme_regex}{_user_info_regex}' + r'(?P([^/]*))' # validation occurs later + rf'{_path_regex}{_query_regex}{_fragment_regex}', + re.IGNORECASE, + ) + return _multi_host_url_regex_cache + + +def ascii_domain_regex() -> Pattern[str]: + global _ascii_domain_regex_cache + if _ascii_domain_regex_cache is None: + ascii_chunk = r'[_0-9a-z](?:[-_0-9a-z]{0,61}[_0-9a-z])?' + ascii_domain_ending = r'(?P\.[a-z]{2,63})?\.?' + _ascii_domain_regex_cache = re.compile( + fr'(?:{ascii_chunk}\.)*?{ascii_chunk}{ascii_domain_ending}', re.IGNORECASE + ) + return _ascii_domain_regex_cache + + +def int_domain_regex() -> Pattern[str]: + global _int_domain_regex_cache + if _int_domain_regex_cache is None: + int_chunk = r'[_0-9a-\U00040000](?:[-_0-9a-\U00040000]{0,61}[_0-9a-\U00040000])?' + int_domain_ending = r'(?P(\.[^\W\d_]{2,63})|(\.(?:xn--)[_0-9a-z-]{2,63}))?\.?' + _int_domain_regex_cache = re.compile(fr'(?:{int_chunk}\.)*?{int_chunk}{int_domain_ending}', re.IGNORECASE) + return _int_domain_regex_cache + + +def host_regex() -> Pattern[str]: + global _host_regex_cache + if _host_regex_cache is None: + _host_regex_cache = re.compile( + _host_regex, + re.IGNORECASE, + ) + return _host_regex_cache + + +class AnyUrl(str): + strip_whitespace = True + min_length = 1 + max_length = 2**16 + allowed_schemes: Optional[Collection[str]] = None + tld_required: bool = False + user_required: bool = False + host_required: bool = True + hidden_parts: Set[str] = set() + + __slots__ = ('scheme', 'user', 'password', 'host', 'tld', 'host_type', 'port', 'path', 'query', 'fragment') + + @no_type_check + def __new__(cls, url: Optional[str], **kwargs) -> object: + return str.__new__(cls, cls.build(**kwargs) if url is None else url) + + def __init__( + self, + url: str, + *, + scheme: str, + user: Optional[str] = None, + password: Optional[str] = None, + host: Optional[str] = None, + tld: Optional[str] = None, + host_type: str = 'domain', + port: Optional[str] = None, + path: Optional[str] = None, + query: Optional[str] = None, + fragment: Optional[str] = None, + ) -> None: + str.__init__(url) + self.scheme = scheme + self.user = user + self.password = password + self.host = host + self.tld = tld + self.host_type = host_type + self.port = port + self.path = path + self.query = query + self.fragment = fragment + + @classmethod + def build( + cls, + *, + scheme: str, + user: Optional[str] = None, + password: Optional[str] = None, + host: str, + port: Optional[str] = None, + path: Optional[str] = None, + query: Optional[str] = None, + fragment: Optional[str] = None, + **_kwargs: str, + ) -> str: + parts = Parts( + scheme=scheme, + user=user, + password=password, + host=host, + port=port, + path=path, + query=query, + fragment=fragment, + **_kwargs, # type: ignore[misc] + ) + + url = scheme + '://' + if user: + url += user + if password: + url += ':' + password + if user or password: + url += '@' + url += host + if port and ('port' not in cls.hidden_parts or cls.get_default_parts(parts).get('port') != port): + url += ':' + port + if path: + url += path + if query: + url += '?' + query + if fragment: + url += '#' + fragment + return url + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minLength=cls.min_length, maxLength=cls.max_length, format='uri') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Any, field: 'ModelField', config: 'BaseConfig') -> 'AnyUrl': + if value.__class__ == cls: + return value + value = str_validator(value) + if cls.strip_whitespace: + value = value.strip() + url: str = cast(str, constr_length_validator(value, field, config)) + + m = cls._match_url(url) + # the regex should always match, if it doesn't please report with details of the URL tried + assert m, 'URL regex failed unexpectedly' + + original_parts = cast('Parts', m.groupdict()) + parts = cls.apply_default_parts(original_parts) + parts = cls.validate_parts(parts) + + if m.end() != len(url): + raise errors.UrlExtraError(extra=url[m.end() :]) + + return cls._build_url(m, url, parts) + + @classmethod + def _build_url(cls, m: Match[str], url: str, parts: 'Parts') -> 'AnyUrl': + """ + Validate hosts and build the AnyUrl object. Split from `validate` so this method + can be altered in `MultiHostDsn`. + """ + host, tld, host_type, rebuild = cls.validate_host(parts) + + return cls( + None if rebuild else url, + scheme=parts['scheme'], + user=parts['user'], + password=parts['password'], + host=host, + tld=tld, + host_type=host_type, + port=parts['port'], + path=parts['path'], + query=parts['query'], + fragment=parts['fragment'], + ) + + @staticmethod + def _match_url(url: str) -> Optional[Match[str]]: + return url_regex().match(url) + + @staticmethod + def _validate_port(port: Optional[str]) -> None: + if port is not None and int(port) > 65_535: + raise errors.UrlPortError() + + @classmethod + def validate_parts(cls, parts: 'Parts', validate_port: bool = True) -> 'Parts': + """ + A method used to validate parts of a URL. + Could be overridden to set default values for parts if missing + """ + scheme = parts['scheme'] + if scheme is None: + raise errors.UrlSchemeError() + + if cls.allowed_schemes and scheme.lower() not in cls.allowed_schemes: + raise errors.UrlSchemePermittedError(set(cls.allowed_schemes)) + + if validate_port: + cls._validate_port(parts['port']) + + user = parts['user'] + if cls.user_required and user is None: + raise errors.UrlUserInfoError() + + return parts + + @classmethod + def validate_host(cls, parts: 'Parts') -> Tuple[str, Optional[str], str, bool]: + tld, host_type, rebuild = None, None, False + for f in ('domain', 'ipv4', 'ipv6'): + host = parts[f] # type: ignore[literal-required] + if host: + host_type = f + break + + if host is None: + if cls.host_required: + raise errors.UrlHostError() + elif host_type == 'domain': + is_international = False + d = ascii_domain_regex().fullmatch(host) + if d is None: + d = int_domain_regex().fullmatch(host) + if d is None: + raise errors.UrlHostError() + is_international = True + + tld = d.group('tld') + if tld is None and not is_international: + d = int_domain_regex().fullmatch(host) + assert d is not None + tld = d.group('tld') + is_international = True + + if tld is not None: + tld = tld[1:] + elif cls.tld_required: + raise errors.UrlHostTldError() + + if is_international: + host_type = 'int_domain' + rebuild = True + host = host.encode('idna').decode('ascii') + if tld is not None: + tld = tld.encode('idna').decode('ascii') + + return host, tld, host_type, rebuild # type: ignore + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return {} + + @classmethod + def apply_default_parts(cls, parts: 'Parts') -> 'Parts': + for key, value in cls.get_default_parts(parts).items(): + if not parts[key]: # type: ignore[literal-required] + parts[key] = value # type: ignore[literal-required] + return parts + + def __repr__(self) -> str: + extra = ', '.join(f'{n}={getattr(self, n)!r}' for n in self.__slots__ if getattr(self, n) is not None) + return f'{self.__class__.__name__}({super().__repr__()}, {extra})' + + +class AnyHttpUrl(AnyUrl): + allowed_schemes = {'http', 'https'} + + __slots__ = () + + +class HttpUrl(AnyHttpUrl): + tld_required = True + # https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers + max_length = 2083 + hidden_parts = {'port'} + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return {'port': '80' if parts['scheme'] == 'http' else '443'} + + +class FileUrl(AnyUrl): + allowed_schemes = {'file'} + host_required = False + + __slots__ = () + + +class MultiHostDsn(AnyUrl): + __slots__ = AnyUrl.__slots__ + ('hosts',) + + def __init__(self, *args: Any, hosts: Optional[List['HostParts']] = None, **kwargs: Any): + super().__init__(*args, **kwargs) + self.hosts = hosts + + @staticmethod + def _match_url(url: str) -> Optional[Match[str]]: + return multi_host_url_regex().match(url) + + @classmethod + def validate_parts(cls, parts: 'Parts', validate_port: bool = True) -> 'Parts': + return super().validate_parts(parts, validate_port=False) + + @classmethod + def _build_url(cls, m: Match[str], url: str, parts: 'Parts') -> 'MultiHostDsn': + hosts_parts: List['HostParts'] = [] + host_re = host_regex() + for host in m.groupdict()['hosts'].split(','): + d: Parts = host_re.match(host).groupdict() # type: ignore + host, tld, host_type, rebuild = cls.validate_host(d) + port = d.get('port') + cls._validate_port(port) + hosts_parts.append( + { + 'host': host, + 'host_type': host_type, + 'tld': tld, + 'rebuild': rebuild, + 'port': port, + } + ) + + if len(hosts_parts) > 1: + return cls( + None if any([hp['rebuild'] for hp in hosts_parts]) else url, + scheme=parts['scheme'], + user=parts['user'], + password=parts['password'], + path=parts['path'], + query=parts['query'], + fragment=parts['fragment'], + host_type=None, + hosts=hosts_parts, + ) + else: + # backwards compatibility with single host + host_part = hosts_parts[0] + return cls( + None if host_part['rebuild'] else url, + scheme=parts['scheme'], + user=parts['user'], + password=parts['password'], + host=host_part['host'], + tld=host_part['tld'], + host_type=host_part['host_type'], + port=host_part.get('port'), + path=parts['path'], + query=parts['query'], + fragment=parts['fragment'], + ) + + +class PostgresDsn(MultiHostDsn): + allowed_schemes = { + 'postgres', + 'postgresql', + 'postgresql+asyncpg', + 'postgresql+pg8000', + 'postgresql+psycopg', + 'postgresql+psycopg2', + 'postgresql+psycopg2cffi', + 'postgresql+py-postgresql', + 'postgresql+pygresql', + } + user_required = True + + __slots__ = () + + +class CockroachDsn(AnyUrl): + allowed_schemes = { + 'cockroachdb', + 'cockroachdb+psycopg2', + 'cockroachdb+asyncpg', + } + user_required = True + + +class AmqpDsn(AnyUrl): + allowed_schemes = {'amqp', 'amqps'} + host_required = False + + +class RedisDsn(AnyUrl): + __slots__ = () + allowed_schemes = {'redis', 'rediss'} + host_required = False + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return { + 'domain': 'localhost' if not (parts['ipv4'] or parts['ipv6']) else '', + 'port': '6379', + 'path': '/0', + } + + +class MongoDsn(AnyUrl): + allowed_schemes = {'mongodb'} + + # TODO: Needed to generic "Parts" for "Replica Set", "Sharded Cluster", and other mongodb deployment modes + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return { + 'port': '27017', + } + + +class KafkaDsn(AnyUrl): + allowed_schemes = {'kafka'} + + @staticmethod + def get_default_parts(parts: 'Parts') -> 'Parts': + return { + 'domain': 'localhost', + 'port': '9092', + } + + +def stricturl( + *, + strip_whitespace: bool = True, + min_length: int = 1, + max_length: int = 2**16, + tld_required: bool = True, + host_required: bool = True, + allowed_schemes: Optional[Collection[str]] = None, +) -> Type[AnyUrl]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + strip_whitespace=strip_whitespace, + min_length=min_length, + max_length=max_length, + tld_required=tld_required, + host_required=host_required, + allowed_schemes=allowed_schemes, + ) + return type('UrlValue', (AnyUrl,), namespace) + + +def import_email_validator() -> None: + global email_validator + try: + import email_validator + except ImportError as e: + raise ImportError('email-validator is not installed, run `pip install pydantic[email]`') from e + + +class EmailStr(str): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='email') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + # included here and below so the error happens straight away + import_email_validator() + + yield str_validator + yield cls.validate + + @classmethod + def validate(cls, value: Union[str]) -> str: + return validate_email(value)[1] + + +class NameEmail(Representation): + __slots__ = 'name', 'email' + + def __init__(self, name: str, email: str): + self.name = name + self.email = email + + def __eq__(self, other: Any) -> bool: + return isinstance(other, NameEmail) and (self.name, self.email) == (other.name, other.email) + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='name-email') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + import_email_validator() + + yield cls.validate + + @classmethod + def validate(cls, value: Any) -> 'NameEmail': + if value.__class__ == cls: + return value + value = str_validator(value) + return cls(*validate_email(value)) + + def __str__(self) -> str: + return f'{self.name} <{self.email}>' + + +class IPvAnyAddress(_BaseAddress): + __slots__ = () + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='ipvanyaddress') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Union[str, bytes, int]) -> Union[IPv4Address, IPv6Address]: + try: + return IPv4Address(value) + except ValueError: + pass + + try: + return IPv6Address(value) + except ValueError: + raise errors.IPvAnyAddressError() + + +class IPvAnyInterface(_BaseAddress): + __slots__ = () + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='ipvanyinterface') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: NetworkType) -> Union[IPv4Interface, IPv6Interface]: + try: + return IPv4Interface(value) + except ValueError: + pass + + try: + return IPv6Interface(value) + except ValueError: + raise errors.IPvAnyInterfaceError() + + +class IPvAnyNetwork(_BaseNetwork): # type: ignore + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='ipvanynetwork') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: NetworkType) -> Union[IPv4Network, IPv6Network]: + # Assume IP Network is defined with a default value for ``strict`` argument. + # Define your own class if you want to specify network address check strictness. + try: + return IPv4Network(value) + except ValueError: + pass + + try: + return IPv6Network(value) + except ValueError: + raise errors.IPvAnyNetworkError() + + +pretty_email_regex = re.compile(r'([\w ]*?) *<(.*)> *') +MAX_EMAIL_LENGTH = 2048 +"""Maximum length for an email. +A somewhat arbitrary but very generous number compared to what is allowed by most implementations. +""" + + +def validate_email(value: Union[str]) -> Tuple[str, str]: + """ + Email address validation using https://pypi.org/project/email-validator/ + Notes: + * raw ip address (literal) domain parts are not allowed. + * "John Doe " style "pretty" email addresses are processed + * spaces are striped from the beginning and end of addresses but no error is raised + """ + if email_validator is None: + import_email_validator() + + if len(value) > MAX_EMAIL_LENGTH: + raise errors.EmailError() + + m = pretty_email_regex.fullmatch(value) + name: Union[str, None] = None + if m: + name, value = m.groups() + email = value.strip() + try: + parts = email_validator.validate_email(email, check_deliverability=False) + except email_validator.EmailNotValidError as e: + raise errors.EmailError from e + + if hasattr(parts, 'normalized'): + # email-validator >= 2 + email = parts.normalized + assert email is not None + name = name or parts.local_part + return name, email + else: + # email-validator >1, <2 + at_index = email.index('@') + local_part = email[:at_index] # RFC 5321, local part must be case-sensitive. + global_part = email[at_index:].lower() + + return name or local_part, local_part + global_part diff --git a/source/target-vendors/cp312/pydantic/v1/parse.py b/source/target-vendors/cp312/pydantic/v1/parse.py new file mode 100644 index 0000000..431d75a --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/parse.py @@ -0,0 +1,66 @@ +import json +import pickle +from enum import Enum +from pathlib import Path +from typing import Any, Callable, Union + +from pydantic.v1.types import StrBytes + + +class Protocol(str, Enum): + json = 'json' + pickle = 'pickle' + + +def load_str_bytes( + b: StrBytes, + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + if proto is None and content_type: + if content_type.endswith(('json', 'javascript')): + pass + elif allow_pickle and content_type.endswith('pickle'): + proto = Protocol.pickle + else: + raise TypeError(f'Unknown content-type: {content_type}') + + proto = proto or Protocol.json + + if proto == Protocol.json: + if isinstance(b, bytes): + b = b.decode(encoding) + return json_loads(b) + elif proto == Protocol.pickle: + if not allow_pickle: + raise RuntimeError('Trying to decode with pickle with allow_pickle=False') + bb = b if isinstance(b, bytes) else b.encode() + return pickle.loads(bb) + else: + raise TypeError(f'Unknown protocol: {proto}') + + +def load_file( + path: Union[str, Path], + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, +) -> Any: + path = Path(path) + b = path.read_bytes() + if content_type is None: + if path.suffix in ('.js', '.json'): + proto = Protocol.json + elif path.suffix == '.pkl': + proto = Protocol.pickle + + return load_str_bytes( + b, proto=proto, content_type=content_type, encoding=encoding, allow_pickle=allow_pickle, json_loads=json_loads + ) diff --git a/source/target-vendors/cp312/pydantic/v1/py.typed b/source/target-vendors/cp312/pydantic/v1/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/pydantic/v1/schema.py b/source/target-vendors/cp312/pydantic/v1/schema.py new file mode 100644 index 0000000..a91fe2c --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/schema.py @@ -0,0 +1,1163 @@ +import re +import warnings +from collections import defaultdict +from dataclasses import is_dataclass +from datetime import date, datetime, time, timedelta +from decimal import Decimal +from enum import Enum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + ForwardRef, + FrozenSet, + Generic, + Iterable, + List, + Optional, + Pattern, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, +) +from uuid import UUID + +from typing_extensions import Annotated, Literal + +from pydantic.v1.fields import ( + MAPPING_LIKE_SHAPES, + SHAPE_DEQUE, + SHAPE_FROZENSET, + SHAPE_GENERIC, + SHAPE_ITERABLE, + SHAPE_LIST, + SHAPE_SEQUENCE, + SHAPE_SET, + SHAPE_SINGLETON, + SHAPE_TUPLE, + SHAPE_TUPLE_ELLIPSIS, + FieldInfo, + ModelField, +) +from pydantic.v1.json import pydantic_encoder +from pydantic.v1.networks import AnyUrl, EmailStr +from pydantic.v1.types import ( + ConstrainedDecimal, + ConstrainedFloat, + ConstrainedFrozenSet, + ConstrainedInt, + ConstrainedList, + ConstrainedSet, + ConstrainedStr, + SecretBytes, + SecretStr, + StrictBytes, + StrictStr, + conbytes, + condecimal, + confloat, + confrozenset, + conint, + conlist, + conset, + constr, +) +from pydantic.v1.typing import ( + all_literal_values, + get_args, + get_origin, + get_sub_types, + is_callable_type, + is_literal_type, + is_namedtuple, + is_none_type, + is_union, +) +from pydantic.v1.utils import ROOT_KEY, get_model, lenient_issubclass + +if TYPE_CHECKING: + from pydantic.v1.dataclasses import Dataclass + from pydantic.v1.main import BaseModel + +default_prefix = '#/definitions/' +default_ref_template = '#/definitions/{model}' + +TypeModelOrEnum = Union[Type['BaseModel'], Type[Enum]] +TypeModelSet = Set[TypeModelOrEnum] + + +def _apply_modify_schema( + modify_schema: Callable[..., None], field: Optional[ModelField], field_schema: Dict[str, Any] +) -> None: + from inspect import signature + + sig = signature(modify_schema) + args = set(sig.parameters.keys()) + if 'field' in args or 'kwargs' in args: + modify_schema(field_schema, field=field) + else: + modify_schema(field_schema) + + +def schema( + models: Sequence[Union[Type['BaseModel'], Type['Dataclass']]], + *, + by_alias: bool = True, + title: Optional[str] = None, + description: Optional[str] = None, + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, +) -> Dict[str, Any]: + """ + Process a list of models and generate a single JSON Schema with all of them defined in the ``definitions`` + top-level JSON key, including their sub-models. + + :param models: a list of models to include in the generated JSON Schema + :param by_alias: generate the schemas using the aliases defined, if any + :param title: title for the generated schema that includes the definitions + :param description: description for the generated schema + :param ref_prefix: the JSON Pointer prefix for schema references with ``$ref``, if None, will be set to the + default of ``#/definitions/``. Update it if you want the schemas to reference the definitions somewhere + else, e.g. for OpenAPI use ``#/components/schemas/``. The resulting generated schemas will still be at the + top-level key ``definitions``, so you can extract them from there. But all the references will have the set + prefix. + :param ref_template: Use a ``string.format()`` template for ``$ref`` instead of a prefix. This can be useful + for references that cannot be represented by ``ref_prefix`` such as a definition stored in another file. For + a sibling json file in a ``/schemas`` directory use ``"/schemas/${model}.json#"``. + :return: dict with the JSON Schema with a ``definitions`` top-level key including the schema definitions for + the models and sub-models passed in ``models``. + """ + clean_models = [get_model(model) for model in models] + flat_models = get_flat_models_from_models(clean_models) + model_name_map = get_model_name_map(flat_models) + definitions = {} + output_schema: Dict[str, Any] = {} + if title: + output_schema['title'] = title + if description: + output_schema['description'] = description + for model in clean_models: + m_schema, m_definitions, m_nested_models = model_process_schema( + model, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + ) + definitions.update(m_definitions) + model_name = model_name_map[model] + definitions[model_name] = m_schema + if definitions: + output_schema['definitions'] = definitions + return output_schema + + +def model_schema( + model: Union[Type['BaseModel'], Type['Dataclass']], + by_alias: bool = True, + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, +) -> Dict[str, Any]: + """ + Generate a JSON Schema for one model. With all the sub-models defined in the ``definitions`` top-level + JSON key. + + :param model: a Pydantic model (a class that inherits from BaseModel) + :param by_alias: generate the schemas using the aliases defined, if any + :param ref_prefix: the JSON Pointer prefix for schema references with ``$ref``, if None, will be set to the + default of ``#/definitions/``. Update it if you want the schemas to reference the definitions somewhere + else, e.g. for OpenAPI use ``#/components/schemas/``. The resulting generated schemas will still be at the + top-level key ``definitions``, so you can extract them from there. But all the references will have the set + prefix. + :param ref_template: Use a ``string.format()`` template for ``$ref`` instead of a prefix. This can be useful for + references that cannot be represented by ``ref_prefix`` such as a definition stored in another file. For a + sibling json file in a ``/schemas`` directory use ``"/schemas/${model}.json#"``. + :return: dict with the JSON Schema for the passed ``model`` + """ + model = get_model(model) + flat_models = get_flat_models_from_model(model) + model_name_map = get_model_name_map(flat_models) + model_name = model_name_map[model] + m_schema, m_definitions, nested_models = model_process_schema( + model, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix, ref_template=ref_template + ) + if model_name in nested_models: + # model_name is in Nested models, it has circular references + m_definitions[model_name] = m_schema + m_schema = get_schema_ref(model_name, ref_prefix, ref_template, False) + if m_definitions: + m_schema.update({'definitions': m_definitions}) + return m_schema + + +def get_field_info_schema(field: ModelField, schema_overrides: bool = False) -> Tuple[Dict[str, Any], bool]: + # If no title is explicitly set, we don't set title in the schema for enums. + # The behaviour is the same as `BaseModel` reference, where the default title + # is in the definitions part of the schema. + schema_: Dict[str, Any] = {} + if field.field_info.title or not lenient_issubclass(field.type_, Enum): + schema_['title'] = field.field_info.title or field.alias.title().replace('_', ' ') + + if field.field_info.title: + schema_overrides = True + + if field.field_info.description: + schema_['description'] = field.field_info.description + schema_overrides = True + + if not field.required and field.default is not None and not is_callable_type(field.outer_type_): + schema_['default'] = encode_default(field.default) + schema_overrides = True + + return schema_, schema_overrides + + +def field_schema( + field: ModelField, + *, + by_alias: bool = True, + model_name_map: Dict[TypeModelOrEnum, str], + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, + known_models: Optional[TypeModelSet] = None, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + Process a Pydantic field and return a tuple with a JSON Schema for it as the first item. + Also return a dictionary of definitions with models as keys and their schemas as values. If the passed field + is a model and has sub-models, and those sub-models don't have overrides (as ``title``, ``default``, etc), they + will be included in the definitions and referenced in the schema instead of included recursively. + + :param field: a Pydantic ``ModelField`` + :param by_alias: use the defined alias (if any) in the returned schema + :param model_name_map: used to generate the JSON Schema references to other models included in the definitions + :param ref_prefix: the JSON Pointer prefix to use for references to other schemas, if None, the default of + #/definitions/ will be used + :param ref_template: Use a ``string.format()`` template for ``$ref`` instead of a prefix. This can be useful for + references that cannot be represented by ``ref_prefix`` such as a definition stored in another file. For a + sibling json file in a ``/schemas`` directory use ``"/schemas/${model}.json#"``. + :param known_models: used to solve circular references + :return: tuple of the schema for this field and additional definitions + """ + s, schema_overrides = get_field_info_schema(field) + + validation_schema = get_field_schema_validations(field) + if validation_schema: + s.update(validation_schema) + schema_overrides = True + + f_schema, f_definitions, f_nested_models = field_type_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models or set(), + ) + + # $ref will only be returned when there are no schema_overrides + if '$ref' in f_schema: + return f_schema, f_definitions, f_nested_models + else: + s.update(f_schema) + return s, f_definitions, f_nested_models + + +numeric_types = (int, float, Decimal) +_str_types_attrs: Tuple[Tuple[str, Union[type, Tuple[type, ...]], str], ...] = ( + ('max_length', numeric_types, 'maxLength'), + ('min_length', numeric_types, 'minLength'), + ('regex', str, 'pattern'), +) + +_numeric_types_attrs: Tuple[Tuple[str, Union[type, Tuple[type, ...]], str], ...] = ( + ('gt', numeric_types, 'exclusiveMinimum'), + ('lt', numeric_types, 'exclusiveMaximum'), + ('ge', numeric_types, 'minimum'), + ('le', numeric_types, 'maximum'), + ('multiple_of', numeric_types, 'multipleOf'), +) + + +def get_field_schema_validations(field: ModelField) -> Dict[str, Any]: + """ + Get the JSON Schema validation keywords for a ``field`` with an annotation of + a Pydantic ``FieldInfo`` with validation arguments. + """ + f_schema: Dict[str, Any] = {} + + if lenient_issubclass(field.type_, Enum): + # schema is already updated by `enum_process_schema`; just update with field extra + if field.field_info.extra: + f_schema.update(field.field_info.extra) + return f_schema + + if lenient_issubclass(field.type_, (str, bytes)): + for attr_name, t, keyword in _str_types_attrs: + attr = getattr(field.field_info, attr_name, None) + if isinstance(attr, t): + f_schema[keyword] = attr + if lenient_issubclass(field.type_, numeric_types) and not issubclass(field.type_, bool): + for attr_name, t, keyword in _numeric_types_attrs: + attr = getattr(field.field_info, attr_name, None) + if isinstance(attr, t): + f_schema[keyword] = attr + if field.field_info is not None and field.field_info.const: + f_schema['const'] = field.default + if field.field_info.extra: + f_schema.update(field.field_info.extra) + modify_schema = getattr(field.outer_type_, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, f_schema) + return f_schema + + +def get_model_name_map(unique_models: TypeModelSet) -> Dict[TypeModelOrEnum, str]: + """ + Process a set of models and generate unique names for them to be used as keys in the JSON Schema + definitions. By default the names are the same as the class name. But if two models in different Python + modules have the same name (e.g. "users.Model" and "items.Model"), the generated names will be + based on the Python module path for those conflicting models to prevent name collisions. + + :param unique_models: a Python set of models + :return: dict mapping models to names + """ + name_model_map = {} + conflicting_names: Set[str] = set() + for model in unique_models: + model_name = normalize_name(model.__name__) + if model_name in conflicting_names: + model_name = get_long_model_name(model) + name_model_map[model_name] = model + elif model_name in name_model_map: + conflicting_names.add(model_name) + conflicting_model = name_model_map.pop(model_name) + name_model_map[get_long_model_name(conflicting_model)] = conflicting_model + name_model_map[get_long_model_name(model)] = model + else: + name_model_map[model_name] = model + return {v: k for k, v in name_model_map.items()} + + +def get_flat_models_from_model(model: Type['BaseModel'], known_models: Optional[TypeModelSet] = None) -> TypeModelSet: + """ + Take a single ``model`` and generate a set with itself and all the sub-models in the tree. I.e. if you pass + model ``Foo`` (subclass of Pydantic ``BaseModel``) as ``model``, and it has a field of type ``Bar`` (also + subclass of ``BaseModel``) and that model ``Bar`` has a field of type ``Baz`` (also subclass of ``BaseModel``), + the return value will be ``set([Foo, Bar, Baz])``. + + :param model: a Pydantic ``BaseModel`` subclass + :param known_models: used to solve circular references + :return: a set with the initial model and all its sub-models + """ + known_models = known_models or set() + flat_models: TypeModelSet = set() + flat_models.add(model) + known_models |= flat_models + fields = cast(Sequence[ModelField], model.__fields__.values()) + flat_models |= get_flat_models_from_fields(fields, known_models=known_models) + return flat_models + + +def get_flat_models_from_field(field: ModelField, known_models: TypeModelSet) -> TypeModelSet: + """ + Take a single Pydantic ``ModelField`` (from a model) that could have been declared as a subclass of BaseModel + (so, it could be a submodel), and generate a set with its model and all the sub-models in the tree. + I.e. if you pass a field that was declared to be of type ``Foo`` (subclass of BaseModel) as ``field``, and that + model ``Foo`` has a field of type ``Bar`` (also subclass of ``BaseModel``) and that model ``Bar`` has a field of + type ``Baz`` (also subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``. + + :param field: a Pydantic ``ModelField`` + :param known_models: used to solve circular references + :return: a set with the model used in the declaration for this field, if any, and all its sub-models + """ + from pydantic.v1.main import BaseModel + + flat_models: TypeModelSet = set() + + field_type = field.type_ + if lenient_issubclass(getattr(field_type, '__pydantic_model__', None), BaseModel): + field_type = field_type.__pydantic_model__ + + if field.sub_fields and not lenient_issubclass(field_type, BaseModel): + flat_models |= get_flat_models_from_fields(field.sub_fields, known_models=known_models) + elif lenient_issubclass(field_type, BaseModel) and field_type not in known_models: + flat_models |= get_flat_models_from_model(field_type, known_models=known_models) + elif lenient_issubclass(field_type, Enum): + flat_models.add(field_type) + return flat_models + + +def get_flat_models_from_fields(fields: Sequence[ModelField], known_models: TypeModelSet) -> TypeModelSet: + """ + Take a list of Pydantic ``ModelField``s (from a model) that could have been declared as subclasses of ``BaseModel`` + (so, any of them could be a submodel), and generate a set with their models and all the sub-models in the tree. + I.e. if you pass a the fields of a model ``Foo`` (subclass of ``BaseModel``) as ``fields``, and on of them has a + field of type ``Bar`` (also subclass of ``BaseModel``) and that model ``Bar`` has a field of type ``Baz`` (also + subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``. + + :param fields: a list of Pydantic ``ModelField``s + :param known_models: used to solve circular references + :return: a set with any model declared in the fields, and all their sub-models + """ + flat_models: TypeModelSet = set() + for field in fields: + flat_models |= get_flat_models_from_field(field, known_models=known_models) + return flat_models + + +def get_flat_models_from_models(models: Sequence[Type['BaseModel']]) -> TypeModelSet: + """ + Take a list of ``models`` and generate a set with them and all their sub-models in their trees. I.e. if you pass + a list of two models, ``Foo`` and ``Bar``, both subclasses of Pydantic ``BaseModel`` as models, and ``Bar`` has + a field of type ``Baz`` (also subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``. + """ + flat_models: TypeModelSet = set() + for model in models: + flat_models |= get_flat_models_from_model(model) + return flat_models + + +def get_long_model_name(model: TypeModelOrEnum) -> str: + return f'{model.__module__}__{model.__qualname__}'.replace('.', '__') + + +def field_type_schema( + field: ModelField, + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + schema_overrides: bool = False, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + Used by ``field_schema()``, you probably should be using that function. + + Take a single ``field`` and generate the schema for its type only, not including additional + information as title, etc. Also return additional schema definitions, from sub-models. + """ + from pydantic.v1.main import BaseModel # noqa: F811 + + definitions = {} + nested_models: Set[str] = set() + f_schema: Dict[str, Any] + if field.shape in { + SHAPE_LIST, + SHAPE_TUPLE_ELLIPSIS, + SHAPE_SEQUENCE, + SHAPE_SET, + SHAPE_FROZENSET, + SHAPE_ITERABLE, + SHAPE_DEQUE, + }: + items_schema, f_definitions, f_nested_models = field_singleton_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(f_definitions) + nested_models.update(f_nested_models) + f_schema = {'type': 'array', 'items': items_schema} + if field.shape in {SHAPE_SET, SHAPE_FROZENSET}: + f_schema['uniqueItems'] = True + + elif field.shape in MAPPING_LIKE_SHAPES: + f_schema = {'type': 'object'} + key_field = cast(ModelField, field.key_field) + regex = getattr(key_field.type_, 'regex', None) + items_schema, f_definitions, f_nested_models = field_singleton_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(f_definitions) + nested_models.update(f_nested_models) + if regex: + # Dict keys have a regex pattern + # items_schema might be a schema or empty dict, add it either way + f_schema['patternProperties'] = {ConstrainedStr._get_pattern(regex): items_schema} + if items_schema: + # The dict values are not simply Any, so they need a schema + f_schema['additionalProperties'] = items_schema + elif field.shape == SHAPE_TUPLE or (field.shape == SHAPE_GENERIC and not issubclass(field.type_, BaseModel)): + sub_schema = [] + sub_fields = cast(List[ModelField], field.sub_fields) + for sf in sub_fields: + sf_schema, sf_definitions, sf_nested_models = field_type_schema( + sf, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(sf_definitions) + nested_models.update(sf_nested_models) + sub_schema.append(sf_schema) + + sub_fields_len = len(sub_fields) + if field.shape == SHAPE_GENERIC: + all_of_schemas = sub_schema[0] if sub_fields_len == 1 else {'type': 'array', 'items': sub_schema} + f_schema = {'allOf': [all_of_schemas]} + else: + f_schema = { + 'type': 'array', + 'minItems': sub_fields_len, + 'maxItems': sub_fields_len, + } + if sub_fields_len >= 1: + f_schema['items'] = sub_schema + else: + assert field.shape in {SHAPE_SINGLETON, SHAPE_GENERIC}, field.shape + f_schema, f_definitions, f_nested_models = field_singleton_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(f_definitions) + nested_models.update(f_nested_models) + + # check field type to avoid repeated calls to the same __modify_schema__ method + if field.type_ != field.outer_type_: + if field.shape == SHAPE_GENERIC: + field_type = field.type_ + else: + field_type = field.outer_type_ + modify_schema = getattr(field_type, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, f_schema) + return f_schema, definitions, nested_models + + +def model_process_schema( + model: TypeModelOrEnum, + *, + by_alias: bool = True, + model_name_map: Dict[TypeModelOrEnum, str], + ref_prefix: Optional[str] = None, + ref_template: str = default_ref_template, + known_models: Optional[TypeModelSet] = None, + field: Optional[ModelField] = None, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + Used by ``model_schema()``, you probably should be using that function. + + Take a single ``model`` and generate its schema. Also return additional schema definitions, from sub-models. The + sub-models of the returned schema will be referenced, but their definitions will not be included in the schema. All + the definitions are returned as the second value. + """ + from inspect import getdoc, signature + + known_models = known_models or set() + if lenient_issubclass(model, Enum): + model = cast(Type[Enum], model) + s = enum_process_schema(model, field=field) + return s, {}, set() + model = cast(Type['BaseModel'], model) + s = {'title': model.__config__.title or model.__name__} + doc = getdoc(model) + if doc: + s['description'] = doc + known_models.add(model) + m_schema, m_definitions, nested_models = model_type_schema( + model, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + s.update(m_schema) + schema_extra = model.__config__.schema_extra + if callable(schema_extra): + if len(signature(schema_extra).parameters) == 1: + schema_extra(s) + else: + schema_extra(s, model) + else: + s.update(schema_extra) + return s, m_definitions, nested_models + + +def model_type_schema( + model: Type['BaseModel'], + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + You probably should be using ``model_schema()``, this function is indirectly used by that function. + + Take a single ``model`` and generate the schema for its type only, not including additional + information as title, etc. Also return additional schema definitions, from sub-models. + """ + properties = {} + required = [] + definitions: Dict[str, Any] = {} + nested_models: Set[str] = set() + for k, f in model.__fields__.items(): + try: + f_schema, f_definitions, f_nested_models = field_schema( + f, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + except SkipField as skip: + warnings.warn(skip.message, UserWarning) + continue + definitions.update(f_definitions) + nested_models.update(f_nested_models) + if by_alias: + properties[f.alias] = f_schema + if f.required: + required.append(f.alias) + else: + properties[k] = f_schema + if f.required: + required.append(k) + if ROOT_KEY in properties: + out_schema = properties[ROOT_KEY] + out_schema['title'] = model.__config__.title or model.__name__ + else: + out_schema = {'type': 'object', 'properties': properties} + if required: + out_schema['required'] = required + if model.__config__.extra == 'forbid': + out_schema['additionalProperties'] = False + return out_schema, definitions, nested_models + + +def enum_process_schema(enum: Type[Enum], *, field: Optional[ModelField] = None) -> Dict[str, Any]: + """ + Take a single `enum` and generate its schema. + + This is similar to the `model_process_schema` function, but applies to ``Enum`` objects. + """ + import inspect + + schema_: Dict[str, Any] = { + 'title': enum.__name__, + # Python assigns all enums a default docstring value of 'An enumeration', so + # all enums will have a description field even if not explicitly provided. + 'description': inspect.cleandoc(enum.__doc__ or 'An enumeration.'), + # Add enum values and the enum field type to the schema. + 'enum': [item.value for item in cast(Iterable[Enum], enum)], + } + + add_field_type_to_schema(enum, schema_) + + modify_schema = getattr(enum, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, schema_) + + return schema_ + + +def field_singleton_sub_fields_schema( + field: ModelField, + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + schema_overrides: bool = False, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + This function is indirectly used by ``field_schema()``, you probably should be using that function. + + Take a list of Pydantic ``ModelField`` from the declaration of a type with parameters, and generate their + schema. I.e., fields used as "type parameters", like ``str`` and ``int`` in ``Tuple[str, int]``. + """ + sub_fields = cast(List[ModelField], field.sub_fields) + definitions = {} + nested_models: Set[str] = set() + if len(sub_fields) == 1: + return field_type_schema( + sub_fields[0], + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + else: + s: Dict[str, Any] = {} + # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#discriminator-object + field_has_discriminator: bool = field.discriminator_key is not None + if field_has_discriminator: + assert field.sub_fields_mapping is not None + + discriminator_models_refs: Dict[str, Union[str, Dict[str, Any]]] = {} + + for discriminator_value, sub_field in field.sub_fields_mapping.items(): + if isinstance(discriminator_value, Enum): + discriminator_value = str(discriminator_value.value) + # sub_field is either a `BaseModel` or directly an `Annotated` `Union` of many + if is_union(get_origin(sub_field.type_)): + sub_models = get_sub_types(sub_field.type_) + discriminator_models_refs[discriminator_value] = { + model_name_map[sub_model]: get_schema_ref( + model_name_map[sub_model], ref_prefix, ref_template, False + ) + for sub_model in sub_models + } + else: + sub_field_type = sub_field.type_ + if hasattr(sub_field_type, '__pydantic_model__'): + sub_field_type = sub_field_type.__pydantic_model__ + + discriminator_model_name = model_name_map[sub_field_type] + discriminator_model_ref = get_schema_ref(discriminator_model_name, ref_prefix, ref_template, False) + discriminator_models_refs[discriminator_value] = discriminator_model_ref['$ref'] + + s['discriminator'] = { + 'propertyName': field.discriminator_alias if by_alias else field.discriminator_key, + 'mapping': discriminator_models_refs, + } + + sub_field_schemas = [] + for sf in sub_fields: + sub_schema, sub_definitions, sub_nested_models = field_type_schema( + sf, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + definitions.update(sub_definitions) + if schema_overrides and 'allOf' in sub_schema: + # if the sub_field is a referenced schema we only need the referenced + # object. Otherwise we will end up with several allOf inside anyOf/oneOf. + # See https://github.com/pydantic/pydantic/issues/1209 + sub_schema = sub_schema['allOf'][0] + + if sub_schema.keys() == {'discriminator', 'oneOf'}: + # we don't want discriminator information inside oneOf choices, this is dealt with elsewhere + sub_schema.pop('discriminator') + sub_field_schemas.append(sub_schema) + nested_models.update(sub_nested_models) + s['oneOf' if field_has_discriminator else 'anyOf'] = sub_field_schemas + return s, definitions, nested_models + + +# Order is important, e.g. subclasses of str must go before str +# this is used only for standard library types, custom types should use __modify_schema__ instead +field_class_to_schema: Tuple[Tuple[Any, Dict[str, Any]], ...] = ( + (Path, {'type': 'string', 'format': 'path'}), + (datetime, {'type': 'string', 'format': 'date-time'}), + (date, {'type': 'string', 'format': 'date'}), + (time, {'type': 'string', 'format': 'time'}), + (timedelta, {'type': 'number', 'format': 'time-delta'}), + (IPv4Network, {'type': 'string', 'format': 'ipv4network'}), + (IPv6Network, {'type': 'string', 'format': 'ipv6network'}), + (IPv4Interface, {'type': 'string', 'format': 'ipv4interface'}), + (IPv6Interface, {'type': 'string', 'format': 'ipv6interface'}), + (IPv4Address, {'type': 'string', 'format': 'ipv4'}), + (IPv6Address, {'type': 'string', 'format': 'ipv6'}), + (Pattern, {'type': 'string', 'format': 'regex'}), + (str, {'type': 'string'}), + (bytes, {'type': 'string', 'format': 'binary'}), + (bool, {'type': 'boolean'}), + (int, {'type': 'integer'}), + (float, {'type': 'number'}), + (Decimal, {'type': 'number'}), + (UUID, {'type': 'string', 'format': 'uuid'}), + (dict, {'type': 'object'}), + (list, {'type': 'array', 'items': {}}), + (tuple, {'type': 'array', 'items': {}}), + (set, {'type': 'array', 'items': {}, 'uniqueItems': True}), + (frozenset, {'type': 'array', 'items': {}, 'uniqueItems': True}), +) + +json_scheme = {'type': 'string', 'format': 'json-string'} + + +def add_field_type_to_schema(field_type: Any, schema_: Dict[str, Any]) -> None: + """ + Update the given `schema` with the type-specific metadata for the given `field_type`. + + This function looks through `field_class_to_schema` for a class that matches the given `field_type`, + and then modifies the given `schema` with the information from that type. + """ + for type_, t_schema in field_class_to_schema: + # Fallback for `typing.Pattern` and `re.Pattern` as they are not a valid class + if lenient_issubclass(field_type, type_) or field_type is type_ is Pattern: + schema_.update(t_schema) + break + + +def get_schema_ref(name: str, ref_prefix: Optional[str], ref_template: str, schema_overrides: bool) -> Dict[str, Any]: + if ref_prefix: + schema_ref = {'$ref': ref_prefix + name} + else: + schema_ref = {'$ref': ref_template.format(model=name)} + return {'allOf': [schema_ref]} if schema_overrides else schema_ref + + +def field_singleton_schema( # noqa: C901 (ignore complexity) + field: ModelField, + *, + by_alias: bool, + model_name_map: Dict[TypeModelOrEnum, str], + ref_template: str, + schema_overrides: bool = False, + ref_prefix: Optional[str] = None, + known_models: TypeModelSet, +) -> Tuple[Dict[str, Any], Dict[str, Any], Set[str]]: + """ + This function is indirectly used by ``field_schema()``, you should probably be using that function. + + Take a single Pydantic ``ModelField``, and return its schema and any additional definitions from sub-models. + """ + from pydantic.v1.main import BaseModel + + definitions: Dict[str, Any] = {} + nested_models: Set[str] = set() + field_type = field.type_ + + # Recurse into this field if it contains sub_fields and is NOT a + # BaseModel OR that BaseModel is a const + if field.sub_fields and ( + (field.field_info and field.field_info.const) or not lenient_issubclass(field_type, BaseModel) + ): + return field_singleton_sub_fields_schema( + field, + by_alias=by_alias, + model_name_map=model_name_map, + schema_overrides=schema_overrides, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + if field_type is Any or field_type is object or field_type.__class__ == TypeVar or get_origin(field_type) is type: + return {}, definitions, nested_models # no restrictions + if is_none_type(field_type): + return {'type': 'null'}, definitions, nested_models + if is_callable_type(field_type): + raise SkipField(f'Callable {field.name} was excluded from schema since JSON schema has no equivalent type.') + f_schema: Dict[str, Any] = {} + if field.field_info is not None and field.field_info.const: + f_schema['const'] = field.default + + if is_literal_type(field_type): + values = tuple(x.value if isinstance(x, Enum) else x for x in all_literal_values(field_type)) + + if len({v.__class__ for v in values}) > 1: + return field_schema( + multitypes_literal_field_for_schema(values, field), + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + ) + + # All values have the same type + field_type = values[0].__class__ + f_schema['enum'] = list(values) + add_field_type_to_schema(field_type, f_schema) + elif lenient_issubclass(field_type, Enum): + enum_name = model_name_map[field_type] + f_schema, schema_overrides = get_field_info_schema(field, schema_overrides) + f_schema.update(get_schema_ref(enum_name, ref_prefix, ref_template, schema_overrides)) + definitions[enum_name] = enum_process_schema(field_type, field=field) + elif is_namedtuple(field_type): + sub_schema, *_ = model_process_schema( + field_type.__pydantic_model__, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + field=field, + ) + items_schemas = list(sub_schema['properties'].values()) + f_schema.update( + { + 'type': 'array', + 'items': items_schemas, + 'minItems': len(items_schemas), + 'maxItems': len(items_schemas), + } + ) + elif not hasattr(field_type, '__pydantic_model__'): + add_field_type_to_schema(field_type, f_schema) + + modify_schema = getattr(field_type, '__modify_schema__', None) + if modify_schema: + _apply_modify_schema(modify_schema, field, f_schema) + + if f_schema: + return f_schema, definitions, nested_models + + # Handle dataclass-based models + if lenient_issubclass(getattr(field_type, '__pydantic_model__', None), BaseModel): + field_type = field_type.__pydantic_model__ + + if issubclass(field_type, BaseModel): + model_name = model_name_map[field_type] + if field_type not in known_models: + sub_schema, sub_definitions, sub_nested_models = model_process_schema( + field_type, + by_alias=by_alias, + model_name_map=model_name_map, + ref_prefix=ref_prefix, + ref_template=ref_template, + known_models=known_models, + field=field, + ) + definitions.update(sub_definitions) + definitions[model_name] = sub_schema + nested_models.update(sub_nested_models) + else: + nested_models.add(model_name) + schema_ref = get_schema_ref(model_name, ref_prefix, ref_template, schema_overrides) + return schema_ref, definitions, nested_models + + # For generics with no args + args = get_args(field_type) + if args is not None and not args and Generic in field_type.__bases__: + return f_schema, definitions, nested_models + + raise ValueError(f'Value not declarable with JSON Schema, field: {field}') + + +def multitypes_literal_field_for_schema(values: Tuple[Any, ...], field: ModelField) -> ModelField: + """ + To support `Literal` with values of different types, we split it into multiple `Literal` with same type + e.g. `Literal['qwe', 'asd', 1, 2]` becomes `Union[Literal['qwe', 'asd'], Literal[1, 2]]` + """ + literal_distinct_types = defaultdict(list) + for v in values: + literal_distinct_types[v.__class__].append(v) + distinct_literals = (Literal[tuple(same_type_values)] for same_type_values in literal_distinct_types.values()) + + return ModelField( + name=field.name, + type_=Union[tuple(distinct_literals)], # type: ignore + class_validators=field.class_validators, + model_config=field.model_config, + default=field.default, + required=field.required, + alias=field.alias, + field_info=field.field_info, + ) + + +def encode_default(dft: Any) -> Any: + from pydantic.v1.main import BaseModel + + if isinstance(dft, BaseModel) or is_dataclass(dft): + dft = cast('dict[str, Any]', pydantic_encoder(dft)) + + if isinstance(dft, dict): + return {encode_default(k): encode_default(v) for k, v in dft.items()} + elif isinstance(dft, Enum): + return dft.value + elif isinstance(dft, (int, float, str)): + return dft + elif isinstance(dft, (list, tuple)): + t = dft.__class__ + seq_args = (encode_default(v) for v in dft) + return t(*seq_args) if is_namedtuple(t) else t(seq_args) + elif dft is None: + return None + else: + return pydantic_encoder(dft) + + +_map_types_constraint: Dict[Any, Callable[..., type]] = {int: conint, float: confloat, Decimal: condecimal} + + +def get_annotation_from_field_info( + annotation: Any, field_info: FieldInfo, field_name: str, validate_assignment: bool = False +) -> Type[Any]: + """ + Get an annotation with validation implemented for numbers and strings based on the field_info. + :param annotation: an annotation from a field specification, as ``str``, ``ConstrainedStr`` + :param field_info: an instance of FieldInfo, possibly with declarations for validations and JSON Schema + :param field_name: name of the field for use in error messages + :param validate_assignment: default False, flag for BaseModel Config value of validate_assignment + :return: the same ``annotation`` if unmodified or a new annotation with validation in place + """ + constraints = field_info.get_constraints() + used_constraints: Set[str] = set() + if constraints: + annotation, used_constraints = get_annotation_with_constraints(annotation, field_info) + if validate_assignment: + used_constraints.add('allow_mutation') + + unused_constraints = constraints - used_constraints + if unused_constraints: + raise ValueError( + f'On field "{field_name}" the following field constraints are set but not enforced: ' + f'{", ".join(unused_constraints)}. ' + f'\nFor more details see https://docs.pydantic.dev/usage/schema/#unenforced-field-constraints' + ) + + return annotation + + +def get_annotation_with_constraints(annotation: Any, field_info: FieldInfo) -> Tuple[Type[Any], Set[str]]: # noqa: C901 + """ + Get an annotation with used constraints implemented for numbers and strings based on the field_info. + + :param annotation: an annotation from a field specification, as ``str``, ``ConstrainedStr`` + :param field_info: an instance of FieldInfo, possibly with declarations for validations and JSON Schema + :return: the same ``annotation`` if unmodified or a new annotation along with the used constraints. + """ + used_constraints: Set[str] = set() + + def go(type_: Any) -> Type[Any]: + if ( + is_literal_type(type_) + or isinstance(type_, ForwardRef) + or lenient_issubclass(type_, (ConstrainedList, ConstrainedSet, ConstrainedFrozenSet)) + ): + return type_ + origin = get_origin(type_) + if origin is not None: + args: Tuple[Any, ...] = get_args(type_) + if any(isinstance(a, ForwardRef) for a in args): + # forward refs cause infinite recursion below + return type_ + + if origin is Annotated: + return go(args[0]) + if is_union(origin): + return Union[tuple(go(a) for a in args)] # type: ignore + + if issubclass(origin, List) and ( + field_info.min_items is not None + or field_info.max_items is not None + or field_info.unique_items is not None + ): + used_constraints.update({'min_items', 'max_items', 'unique_items'}) + return conlist( + go(args[0]), + min_items=field_info.min_items, + max_items=field_info.max_items, + unique_items=field_info.unique_items, + ) + + if issubclass(origin, Set) and (field_info.min_items is not None or field_info.max_items is not None): + used_constraints.update({'min_items', 'max_items'}) + return conset(go(args[0]), min_items=field_info.min_items, max_items=field_info.max_items) + + if issubclass(origin, FrozenSet) and (field_info.min_items is not None or field_info.max_items is not None): + used_constraints.update({'min_items', 'max_items'}) + return confrozenset(go(args[0]), min_items=field_info.min_items, max_items=field_info.max_items) + + for t in (Tuple, List, Set, FrozenSet, Sequence): + if issubclass(origin, t): # type: ignore + return t[tuple(go(a) for a in args)] # type: ignore + + if issubclass(origin, Dict): + return Dict[args[0], go(args[1])] # type: ignore + + attrs: Optional[Tuple[str, ...]] = None + constraint_func: Optional[Callable[..., type]] = None + if isinstance(type_, type): + if issubclass(type_, (SecretStr, SecretBytes)): + attrs = ('max_length', 'min_length') + + def constraint_func(**kw: Any) -> Type[Any]: # noqa: F811 + return type(type_.__name__, (type_,), kw) + + elif issubclass(type_, str) and not issubclass(type_, (EmailStr, AnyUrl)): + attrs = ('max_length', 'min_length', 'regex') + if issubclass(type_, StrictStr): + + def constraint_func(**kw: Any) -> Type[Any]: + return type(type_.__name__, (type_,), kw) + + else: + constraint_func = constr + elif issubclass(type_, bytes): + attrs = ('max_length', 'min_length', 'regex') + if issubclass(type_, StrictBytes): + + def constraint_func(**kw: Any) -> Type[Any]: + return type(type_.__name__, (type_,), kw) + + else: + constraint_func = conbytes + elif issubclass(type_, numeric_types) and not issubclass( + type_, + ( + ConstrainedInt, + ConstrainedFloat, + ConstrainedDecimal, + ConstrainedList, + ConstrainedSet, + ConstrainedFrozenSet, + bool, + ), + ): + # Is numeric type + attrs = ('gt', 'lt', 'ge', 'le', 'multiple_of') + if issubclass(type_, float): + attrs += ('allow_inf_nan',) + if issubclass(type_, Decimal): + attrs += ('max_digits', 'decimal_places') + numeric_type = next(t for t in numeric_types if issubclass(type_, t)) # pragma: no branch + constraint_func = _map_types_constraint[numeric_type] + + if attrs: + used_constraints.update(set(attrs)) + kwargs = { + attr_name: attr + for attr_name, attr in ((attr_name, getattr(field_info, attr_name)) for attr_name in attrs) + if attr is not None + } + if kwargs: + constraint_func = cast(Callable[..., type], constraint_func) + return constraint_func(**kwargs) + return type_ + + return go(annotation), used_constraints + + +def normalize_name(name: str) -> str: + """ + Normalizes the given name. This can be applied to either a model *or* enum. + """ + return re.sub(r'[^a-zA-Z0-9.\-_]', '_', name) + + +class SkipField(Exception): + """ + Utility exception used to exclude fields from schema. + """ + + def __init__(self, message: str) -> None: + self.message = message diff --git a/source/target-vendors/cp312/pydantic/v1/tools.py b/source/target-vendors/cp312/pydantic/v1/tools.py new file mode 100644 index 0000000..6838a23 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/tools.py @@ -0,0 +1,92 @@ +import json +from functools import lru_cache +from pathlib import Path +from typing import TYPE_CHECKING, Any, Callable, Optional, Type, TypeVar, Union + +from pydantic.v1.parse import Protocol, load_file, load_str_bytes +from pydantic.v1.types import StrBytes +from pydantic.v1.typing import display_as_type + +__all__ = ('parse_file_as', 'parse_obj_as', 'parse_raw_as', 'schema_of', 'schema_json_of') + +NameFactory = Union[str, Callable[[Type[Any]], str]] + +if TYPE_CHECKING: + from pydantic.v1.typing import DictStrAny + + +def _generate_parsing_type_name(type_: Any) -> str: + return f'ParsingModel[{display_as_type(type_)}]' + + +@lru_cache(maxsize=2048) +def _get_parsing_type(type_: Any, *, type_name: Optional[NameFactory] = None) -> Any: + from pydantic.v1.main import create_model + + if type_name is None: + type_name = _generate_parsing_type_name + if not isinstance(type_name, str): + type_name = type_name(type_) + return create_model(type_name, __root__=(type_, ...)) + + +T = TypeVar('T') + + +def parse_obj_as(type_: Type[T], obj: Any, *, type_name: Optional[NameFactory] = None) -> T: + model_type = _get_parsing_type(type_, type_name=type_name) # type: ignore[arg-type] + return model_type(__root__=obj).__root__ + + +def parse_file_as( + type_: Type[T], + path: Union[str, Path], + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, + type_name: Optional[NameFactory] = None, +) -> T: + obj = load_file( + path, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=json_loads, + ) + return parse_obj_as(type_, obj, type_name=type_name) + + +def parse_raw_as( + type_: Type[T], + b: StrBytes, + *, + content_type: str = None, + encoding: str = 'utf8', + proto: Protocol = None, + allow_pickle: bool = False, + json_loads: Callable[[str], Any] = json.loads, + type_name: Optional[NameFactory] = None, +) -> T: + obj = load_str_bytes( + b, + proto=proto, + content_type=content_type, + encoding=encoding, + allow_pickle=allow_pickle, + json_loads=json_loads, + ) + return parse_obj_as(type_, obj, type_name=type_name) + + +def schema_of(type_: Any, *, title: Optional[NameFactory] = None, **schema_kwargs: Any) -> 'DictStrAny': + """Generate a JSON schema (as dict) for the passed model or dynamically generated one""" + return _get_parsing_type(type_, type_name=title).schema(**schema_kwargs) + + +def schema_json_of(type_: Any, *, title: Optional[NameFactory] = None, **schema_json_kwargs: Any) -> str: + """Generate a JSON schema (as JSON) for the passed model or dynamically generated one""" + return _get_parsing_type(type_, type_name=title).schema_json(**schema_json_kwargs) diff --git a/source/target-vendors/cp312/pydantic/v1/types.py b/source/target-vendors/cp312/pydantic/v1/types.py new file mode 100644 index 0000000..e1840d9 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/types.py @@ -0,0 +1,1205 @@ +import abc +import math +import re +import warnings +from datetime import date +from decimal import Decimal, InvalidOperation +from enum import Enum +from pathlib import Path +from types import new_class +from typing import ( + TYPE_CHECKING, + Any, + Callable, + ClassVar, + Dict, + FrozenSet, + List, + Optional, + Pattern, + Set, + Tuple, + Type, + TypeVar, + Union, + cast, + overload, +) +from uuid import UUID +from weakref import WeakSet + +from pydantic.v1 import errors +from pydantic.v1.datetime_parse import parse_date +from pydantic.v1.utils import import_string, update_not_none +from pydantic.v1.validators import ( + bytes_validator, + constr_length_validator, + constr_lower, + constr_strip_whitespace, + constr_upper, + decimal_validator, + float_finite_validator, + float_validator, + frozenset_validator, + int_validator, + list_validator, + number_multiple_validator, + number_size_validator, + path_exists_validator, + path_validator, + set_validator, + str_validator, + strict_bytes_validator, + strict_float_validator, + strict_int_validator, + strict_str_validator, +) + +__all__ = [ + 'NoneStr', + 'NoneBytes', + 'StrBytes', + 'NoneStrBytes', + 'StrictStr', + 'ConstrainedBytes', + 'conbytes', + 'ConstrainedList', + 'conlist', + 'ConstrainedSet', + 'conset', + 'ConstrainedFrozenSet', + 'confrozenset', + 'ConstrainedStr', + 'constr', + 'PyObject', + 'ConstrainedInt', + 'conint', + 'PositiveInt', + 'NegativeInt', + 'NonNegativeInt', + 'NonPositiveInt', + 'ConstrainedFloat', + 'confloat', + 'PositiveFloat', + 'NegativeFloat', + 'NonNegativeFloat', + 'NonPositiveFloat', + 'FiniteFloat', + 'ConstrainedDecimal', + 'condecimal', + 'UUID1', + 'UUID3', + 'UUID4', + 'UUID5', + 'FilePath', + 'DirectoryPath', + 'Json', + 'JsonWrapper', + 'SecretField', + 'SecretStr', + 'SecretBytes', + 'StrictBool', + 'StrictBytes', + 'StrictInt', + 'StrictFloat', + 'PaymentCardNumber', + 'ByteSize', + 'PastDate', + 'FutureDate', + 'ConstrainedDate', + 'condate', +] + +NoneStr = Optional[str] +NoneBytes = Optional[bytes] +StrBytes = Union[str, bytes] +NoneStrBytes = Optional[StrBytes] +OptionalInt = Optional[int] +OptionalIntFloat = Union[OptionalInt, float] +OptionalIntFloatDecimal = Union[OptionalIntFloat, Decimal] +OptionalDate = Optional[date] +StrIntFloat = Union[str, int, float] + +if TYPE_CHECKING: + from typing_extensions import Annotated + + from pydantic.v1.dataclasses import Dataclass + from pydantic.v1.main import BaseModel + from pydantic.v1.typing import CallableGenerator + + ModelOrDc = Type[Union[BaseModel, Dataclass]] + +T = TypeVar('T') +_DEFINED_TYPES: 'WeakSet[type]' = WeakSet() + + +@overload +def _registered(typ: Type[T]) -> Type[T]: + pass + + +@overload +def _registered(typ: 'ConstrainedNumberMeta') -> 'ConstrainedNumberMeta': + pass + + +def _registered(typ: Union[Type[T], 'ConstrainedNumberMeta']) -> Union[Type[T], 'ConstrainedNumberMeta']: + # In order to generate valid examples of constrained types, Hypothesis needs + # to inspect the type object - so we keep a weakref to each contype object + # until it can be registered. When (or if) our Hypothesis plugin is loaded, + # it monkeypatches this function. + # If Hypothesis is never used, the total effect is to keep a weak reference + # which has minimal memory usage and doesn't even affect garbage collection. + _DEFINED_TYPES.add(typ) + return typ + + +class ConstrainedNumberMeta(type): + def __new__(cls, name: str, bases: Any, dct: Dict[str, Any]) -> 'ConstrainedInt': # type: ignore + new_cls = cast('ConstrainedInt', type.__new__(cls, name, bases, dct)) + + if new_cls.gt is not None and new_cls.ge is not None: + raise errors.ConfigError('bounds gt and ge cannot be specified at the same time') + if new_cls.lt is not None and new_cls.le is not None: + raise errors.ConfigError('bounds lt and le cannot be specified at the same time') + + return _registered(new_cls) # type: ignore + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BOOLEAN TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + StrictBool = bool +else: + + class StrictBool(int): + """ + StrictBool to allow for bools which are not type-coerced. + """ + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='boolean') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Any) -> bool: + """ + Ensure that we only allow bools. + """ + if isinstance(value, bool): + return value + + raise errors.StrictBoolError() + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ INTEGER TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedInt(int, metaclass=ConstrainedNumberMeta): + strict: bool = False + gt: OptionalInt = None + ge: OptionalInt = None + lt: OptionalInt = None + le: OptionalInt = None + multiple_of: OptionalInt = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + exclusiveMinimum=cls.gt, + exclusiveMaximum=cls.lt, + minimum=cls.ge, + maximum=cls.le, + multipleOf=cls.multiple_of, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_int_validator if cls.strict else int_validator + yield number_size_validator + yield number_multiple_validator + + +def conint( + *, + strict: bool = False, + gt: Optional[int] = None, + ge: Optional[int] = None, + lt: Optional[int] = None, + le: Optional[int] = None, + multiple_of: Optional[int] = None, +) -> Type[int]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict(strict=strict, gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of) + return type('ConstrainedIntValue', (ConstrainedInt,), namespace) + + +if TYPE_CHECKING: + PositiveInt = int + NegativeInt = int + NonPositiveInt = int + NonNegativeInt = int + StrictInt = int +else: + + class PositiveInt(ConstrainedInt): + gt = 0 + + class NegativeInt(ConstrainedInt): + lt = 0 + + class NonPositiveInt(ConstrainedInt): + le = 0 + + class NonNegativeInt(ConstrainedInt): + ge = 0 + + class StrictInt(ConstrainedInt): + strict = True + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FLOAT TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedFloat(float, metaclass=ConstrainedNumberMeta): + strict: bool = False + gt: OptionalIntFloat = None + ge: OptionalIntFloat = None + lt: OptionalIntFloat = None + le: OptionalIntFloat = None + multiple_of: OptionalIntFloat = None + allow_inf_nan: Optional[bool] = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + exclusiveMinimum=cls.gt, + exclusiveMaximum=cls.lt, + minimum=cls.ge, + maximum=cls.le, + multipleOf=cls.multiple_of, + ) + # Modify constraints to account for differences between IEEE floats and JSON + if field_schema.get('exclusiveMinimum') == -math.inf: + del field_schema['exclusiveMinimum'] + if field_schema.get('minimum') == -math.inf: + del field_schema['minimum'] + if field_schema.get('exclusiveMaximum') == math.inf: + del field_schema['exclusiveMaximum'] + if field_schema.get('maximum') == math.inf: + del field_schema['maximum'] + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_float_validator if cls.strict else float_validator + yield number_size_validator + yield number_multiple_validator + yield float_finite_validator + + +def confloat( + *, + strict: bool = False, + gt: float = None, + ge: float = None, + lt: float = None, + le: float = None, + multiple_of: float = None, + allow_inf_nan: Optional[bool] = None, +) -> Type[float]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict(strict=strict, gt=gt, ge=ge, lt=lt, le=le, multiple_of=multiple_of, allow_inf_nan=allow_inf_nan) + return type('ConstrainedFloatValue', (ConstrainedFloat,), namespace) + + +if TYPE_CHECKING: + PositiveFloat = float + NegativeFloat = float + NonPositiveFloat = float + NonNegativeFloat = float + StrictFloat = float + FiniteFloat = float +else: + + class PositiveFloat(ConstrainedFloat): + gt = 0 + + class NegativeFloat(ConstrainedFloat): + lt = 0 + + class NonPositiveFloat(ConstrainedFloat): + le = 0 + + class NonNegativeFloat(ConstrainedFloat): + ge = 0 + + class StrictFloat(ConstrainedFloat): + strict = True + + class FiniteFloat(ConstrainedFloat): + allow_inf_nan = False + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTES TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedBytes(bytes): + strip_whitespace = False + to_upper = False + to_lower = False + min_length: OptionalInt = None + max_length: OptionalInt = None + strict: bool = False + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minLength=cls.min_length, maxLength=cls.max_length) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_bytes_validator if cls.strict else bytes_validator + yield constr_strip_whitespace + yield constr_upper + yield constr_lower + yield constr_length_validator + + +def conbytes( + *, + strip_whitespace: bool = False, + to_upper: bool = False, + to_lower: bool = False, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + strict: bool = False, +) -> Type[bytes]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + strip_whitespace=strip_whitespace, + to_upper=to_upper, + to_lower=to_lower, + min_length=min_length, + max_length=max_length, + strict=strict, + ) + return _registered(type('ConstrainedBytesValue', (ConstrainedBytes,), namespace)) + + +if TYPE_CHECKING: + StrictBytes = bytes +else: + + class StrictBytes(ConstrainedBytes): + strict = True + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STRING TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedStr(str): + strip_whitespace = False + to_upper = False + to_lower = False + min_length: OptionalInt = None + max_length: OptionalInt = None + curtail_length: OptionalInt = None + regex: Optional[Union[str, Pattern[str]]] = None + strict = False + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + minLength=cls.min_length, + maxLength=cls.max_length, + pattern=cls.regex and cls._get_pattern(cls.regex), + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield strict_str_validator if cls.strict else str_validator + yield constr_strip_whitespace + yield constr_upper + yield constr_lower + yield constr_length_validator + yield cls.validate + + @classmethod + def validate(cls, value: Union[str]) -> Union[str]: + if cls.curtail_length and len(value) > cls.curtail_length: + value = value[: cls.curtail_length] + + if cls.regex: + if not re.match(cls.regex, value): + raise errors.StrRegexError(pattern=cls._get_pattern(cls.regex)) + + return value + + @staticmethod + def _get_pattern(regex: Union[str, Pattern[str]]) -> str: + return regex if isinstance(regex, str) else regex.pattern + + +def constr( + *, + strip_whitespace: bool = False, + to_upper: bool = False, + to_lower: bool = False, + strict: bool = False, + min_length: Optional[int] = None, + max_length: Optional[int] = None, + curtail_length: Optional[int] = None, + regex: Optional[str] = None, +) -> Type[str]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + strip_whitespace=strip_whitespace, + to_upper=to_upper, + to_lower=to_lower, + strict=strict, + min_length=min_length, + max_length=max_length, + curtail_length=curtail_length, + regex=regex and re.compile(regex), + ) + return _registered(type('ConstrainedStrValue', (ConstrainedStr,), namespace)) + + +if TYPE_CHECKING: + StrictStr = str +else: + + class StrictStr(ConstrainedStr): + strict = True + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# This types superclass should be Set[T], but cython chokes on that... +class ConstrainedSet(set): # type: ignore + # Needed for pydantic to detect that this is a set + __origin__ = set + __args__: Set[Type[T]] # type: ignore + + min_items: Optional[int] = None + max_items: Optional[int] = None + item_type: Type[T] # type: ignore + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.set_length_validator + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items) + + @classmethod + def set_length_validator(cls, v: 'Optional[Set[T]]') -> 'Optional[Set[T]]': + if v is None: + return None + + v = set_validator(v) + v_len = len(v) + + if cls.min_items is not None and v_len < cls.min_items: + raise errors.SetMinLengthError(limit_value=cls.min_items) + + if cls.max_items is not None and v_len > cls.max_items: + raise errors.SetMaxLengthError(limit_value=cls.max_items) + + return v + + +def conset(item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None) -> Type[Set[T]]: + # __args__ is needed to conform to typing generics api + namespace = {'min_items': min_items, 'max_items': max_items, 'item_type': item_type, '__args__': [item_type]} + # We use new_class to be able to deal with Generic types + return new_class('ConstrainedSetValue', (ConstrainedSet,), {}, lambda ns: ns.update(namespace)) + + +# This types superclass should be FrozenSet[T], but cython chokes on that... +class ConstrainedFrozenSet(frozenset): # type: ignore + # Needed for pydantic to detect that this is a set + __origin__ = frozenset + __args__: FrozenSet[Type[T]] # type: ignore + + min_items: Optional[int] = None + max_items: Optional[int] = None + item_type: Type[T] # type: ignore + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.frozenset_length_validator + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items) + + @classmethod + def frozenset_length_validator(cls, v: 'Optional[FrozenSet[T]]') -> 'Optional[FrozenSet[T]]': + if v is None: + return None + + v = frozenset_validator(v) + v_len = len(v) + + if cls.min_items is not None and v_len < cls.min_items: + raise errors.FrozenSetMinLengthError(limit_value=cls.min_items) + + if cls.max_items is not None and v_len > cls.max_items: + raise errors.FrozenSetMaxLengthError(limit_value=cls.max_items) + + return v + + +def confrozenset( + item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None +) -> Type[FrozenSet[T]]: + # __args__ is needed to conform to typing generics api + namespace = {'min_items': min_items, 'max_items': max_items, 'item_type': item_type, '__args__': [item_type]} + # We use new_class to be able to deal with Generic types + return new_class('ConstrainedFrozenSetValue', (ConstrainedFrozenSet,), {}, lambda ns: ns.update(namespace)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LIST TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +# This types superclass should be List[T], but cython chokes on that... +class ConstrainedList(list): # type: ignore + # Needed for pydantic to detect that this is a list + __origin__ = list + __args__: Tuple[Type[T], ...] # type: ignore + + min_items: Optional[int] = None + max_items: Optional[int] = None + unique_items: Optional[bool] = None + item_type: Type[T] # type: ignore + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.list_length_validator + if cls.unique_items: + yield cls.unique_items_validator + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, minItems=cls.min_items, maxItems=cls.max_items, uniqueItems=cls.unique_items) + + @classmethod + def list_length_validator(cls, v: 'Optional[List[T]]') -> 'Optional[List[T]]': + if v is None: + return None + + v = list_validator(v) + v_len = len(v) + + if cls.min_items is not None and v_len < cls.min_items: + raise errors.ListMinLengthError(limit_value=cls.min_items) + + if cls.max_items is not None and v_len > cls.max_items: + raise errors.ListMaxLengthError(limit_value=cls.max_items) + + return v + + @classmethod + def unique_items_validator(cls, v: 'Optional[List[T]]') -> 'Optional[List[T]]': + if v is None: + return None + + for i, value in enumerate(v, start=1): + if value in v[i:]: + raise errors.ListUniqueItemsError() + + return v + + +def conlist( + item_type: Type[T], *, min_items: Optional[int] = None, max_items: Optional[int] = None, unique_items: bool = None +) -> Type[List[T]]: + # __args__ is needed to conform to typing generics api + namespace = dict( + min_items=min_items, max_items=max_items, unique_items=unique_items, item_type=item_type, __args__=(item_type,) + ) + # We use new_class to be able to deal with Generic types + return new_class('ConstrainedListValue', (ConstrainedList,), {}, lambda ns: ns.update(namespace)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PYOBJECT TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +if TYPE_CHECKING: + PyObject = Callable[..., Any] +else: + + class PyObject: + validate_always = True + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, value: Any) -> Any: + if isinstance(value, Callable): + return value + + try: + value = str_validator(value) + except errors.StrError: + raise errors.PyObjectError(error_message='value is neither a valid import path not a valid callable') + + try: + return import_string(value) + except ImportError as e: + raise errors.PyObjectError(error_message=str(e)) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DECIMAL TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class ConstrainedDecimal(Decimal, metaclass=ConstrainedNumberMeta): + gt: OptionalIntFloatDecimal = None + ge: OptionalIntFloatDecimal = None + lt: OptionalIntFloatDecimal = None + le: OptionalIntFloatDecimal = None + max_digits: OptionalInt = None + decimal_places: OptionalInt = None + multiple_of: OptionalIntFloatDecimal = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + exclusiveMinimum=cls.gt, + exclusiveMaximum=cls.lt, + minimum=cls.ge, + maximum=cls.le, + multipleOf=cls.multiple_of, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield decimal_validator + yield number_size_validator + yield number_multiple_validator + yield cls.validate + + @classmethod + def validate(cls, value: Decimal) -> Decimal: + try: + normalized_value = value.normalize() + except InvalidOperation: + normalized_value = value + digit_tuple, exponent = normalized_value.as_tuple()[1:] + if exponent in {'F', 'n', 'N'}: + raise errors.DecimalIsNotFiniteError() + + if exponent >= 0: + # A positive exponent adds that many trailing zeros. + digits = len(digit_tuple) + exponent + decimals = 0 + else: + # If the absolute value of the negative exponent is larger than the + # number of digits, then it's the same as the number of digits, + # because it'll consume all of the digits in digit_tuple and then + # add abs(exponent) - len(digit_tuple) leading zeros after the + # decimal point. + if abs(exponent) > len(digit_tuple): + digits = decimals = abs(exponent) + else: + digits = len(digit_tuple) + decimals = abs(exponent) + whole_digits = digits - decimals + + if cls.max_digits is not None and digits > cls.max_digits: + raise errors.DecimalMaxDigitsError(max_digits=cls.max_digits) + + if cls.decimal_places is not None and decimals > cls.decimal_places: + raise errors.DecimalMaxPlacesError(decimal_places=cls.decimal_places) + + if cls.max_digits is not None and cls.decimal_places is not None: + expected = cls.max_digits - cls.decimal_places + if whole_digits > expected: + raise errors.DecimalWholeDigitsError(whole_digits=expected) + + return value + + +def condecimal( + *, + gt: Decimal = None, + ge: Decimal = None, + lt: Decimal = None, + le: Decimal = None, + max_digits: Optional[int] = None, + decimal_places: Optional[int] = None, + multiple_of: Decimal = None, +) -> Type[Decimal]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict( + gt=gt, ge=ge, lt=lt, le=le, max_digits=max_digits, decimal_places=decimal_places, multiple_of=multiple_of + ) + return type('ConstrainedDecimalValue', (ConstrainedDecimal,), namespace) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UUID TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + UUID1 = UUID + UUID3 = UUID + UUID4 = UUID + UUID5 = UUID +else: + + class UUID1(UUID): + _required_version = 1 + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format=f'uuid{cls._required_version}') + + class UUID3(UUID1): + _required_version = 3 + + class UUID4(UUID1): + _required_version = 4 + + class UUID5(UUID1): + _required_version = 5 + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PATH TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + FilePath = Path + DirectoryPath = Path +else: + + class FilePath(Path): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(format='file-path') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield path_validator + yield path_exists_validator + yield cls.validate + + @classmethod + def validate(cls, value: Path) -> Path: + if not value.is_file(): + raise errors.PathNotAFileError(path=value) + + return value + + class DirectoryPath(Path): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(format='directory-path') + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield path_validator + yield path_exists_validator + yield cls.validate + + @classmethod + def validate(cls, value: Path) -> Path: + if not value.is_dir(): + raise errors.PathNotADirectoryError(path=value) + + return value + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class JsonWrapper: + pass + + +class JsonMeta(type): + def __getitem__(self, t: Type[Any]) -> Type[JsonWrapper]: + if t is Any: + return Json # allow Json[Any] to replicate plain Json + return _registered(type('JsonWrapperValue', (JsonWrapper,), {'inner_type': t})) + + +if TYPE_CHECKING: + Json = Annotated[T, ...] # Json[list[str]] will be recognized by type checkers as list[str] + +else: + + class Json(metaclass=JsonMeta): + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + field_schema.update(type='string', format='json-string') + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SECRET TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class SecretField(abc.ABC): + """ + Note: this should be implemented as a generic like `SecretField(ABC, Generic[T])`, + the `__init__()` should be part of the abstract class and the + `get_secret_value()` method should use the generic `T` type. + + However Cython doesn't support very well generics at the moment and + the generated code fails to be imported (see + https://github.com/cython/cython/issues/2753). + """ + + def __eq__(self, other: Any) -> bool: + return isinstance(other, self.__class__) and self.get_secret_value() == other.get_secret_value() + + def __str__(self) -> str: + return '**********' if self.get_secret_value() else '' + + def __hash__(self) -> int: + return hash(self.get_secret_value()) + + @abc.abstractmethod + def get_secret_value(self) -> Any: # pragma: no cover + ... + + +class SecretStr(SecretField): + min_length: OptionalInt = None + max_length: OptionalInt = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + type='string', + writeOnly=True, + format='password', + minLength=cls.min_length, + maxLength=cls.max_length, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + yield constr_length_validator + + @classmethod + def validate(cls, value: Any) -> 'SecretStr': + if isinstance(value, cls): + return value + value = str_validator(value) + return cls(value) + + def __init__(self, value: str): + self._secret_value = value + + def __repr__(self) -> str: + return f"SecretStr('{self}')" + + def __len__(self) -> int: + return len(self._secret_value) + + def display(self) -> str: + warnings.warn('`secret_str.display()` is deprecated, use `str(secret_str)` instead', DeprecationWarning) + return str(self) + + def get_secret_value(self) -> str: + return self._secret_value + + +class SecretBytes(SecretField): + min_length: OptionalInt = None + max_length: OptionalInt = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none( + field_schema, + type='string', + writeOnly=True, + format='password', + minLength=cls.min_length, + maxLength=cls.max_length, + ) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + yield constr_length_validator + + @classmethod + def validate(cls, value: Any) -> 'SecretBytes': + if isinstance(value, cls): + return value + value = bytes_validator(value) + return cls(value) + + def __init__(self, value: bytes): + self._secret_value = value + + def __repr__(self) -> str: + return f"SecretBytes(b'{self}')" + + def __len__(self) -> int: + return len(self._secret_value) + + def display(self) -> str: + warnings.warn('`secret_bytes.display()` is deprecated, use `str(secret_bytes)` instead', DeprecationWarning) + return str(self) + + def get_secret_value(self) -> bytes: + return self._secret_value + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PAYMENT CARD TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +class PaymentCardBrand(str, Enum): + # If you add another card type, please also add it to the + # Hypothesis strategy in `pydantic._hypothesis_plugin`. + amex = 'American Express' + mastercard = 'Mastercard' + visa = 'Visa' + other = 'other' + + def __str__(self) -> str: + return self.value + + +class PaymentCardNumber(str): + """ + Based on: https://en.wikipedia.org/wiki/Payment_card_number + """ + + strip_whitespace: ClassVar[bool] = True + min_length: ClassVar[int] = 12 + max_length: ClassVar[int] = 19 + bin: str + last4: str + brand: PaymentCardBrand + + def __init__(self, card_number: str): + self.bin = card_number[:6] + self.last4 = card_number[-4:] + self.brand = self._get_brand(card_number) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield str_validator + yield constr_strip_whitespace + yield constr_length_validator + yield cls.validate_digits + yield cls.validate_luhn_check_digit + yield cls + yield cls.validate_length_for_brand + + @property + def masked(self) -> str: + num_masked = len(self) - 10 # len(bin) + len(last4) == 10 + return f'{self.bin}{"*" * num_masked}{self.last4}' + + @classmethod + def validate_digits(cls, card_number: str) -> str: + if not card_number.isdigit(): + raise errors.NotDigitError + return card_number + + @classmethod + def validate_luhn_check_digit(cls, card_number: str) -> str: + """ + Based on: https://en.wikipedia.org/wiki/Luhn_algorithm + """ + sum_ = int(card_number[-1]) + length = len(card_number) + parity = length % 2 + for i in range(length - 1): + digit = int(card_number[i]) + if i % 2 == parity: + digit *= 2 + if digit > 9: + digit -= 9 + sum_ += digit + valid = sum_ % 10 == 0 + if not valid: + raise errors.LuhnValidationError + return card_number + + @classmethod + def validate_length_for_brand(cls, card_number: 'PaymentCardNumber') -> 'PaymentCardNumber': + """ + Validate length based on BIN for major brands: + https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_(IIN) + """ + required_length: Union[None, int, str] = None + if card_number.brand in PaymentCardBrand.mastercard: + required_length = 16 + valid = len(card_number) == required_length + elif card_number.brand == PaymentCardBrand.visa: + required_length = '13, 16 or 19' + valid = len(card_number) in {13, 16, 19} + elif card_number.brand == PaymentCardBrand.amex: + required_length = 15 + valid = len(card_number) == required_length + else: + valid = True + if not valid: + raise errors.InvalidLengthForBrand(brand=card_number.brand, required_length=required_length) + return card_number + + @staticmethod + def _get_brand(card_number: str) -> PaymentCardBrand: + if card_number[0] == '4': + brand = PaymentCardBrand.visa + elif 51 <= int(card_number[:2]) <= 55: + brand = PaymentCardBrand.mastercard + elif card_number[:2] in {'34', '37'}: + brand = PaymentCardBrand.amex + else: + brand = PaymentCardBrand.other + return brand + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ BYTE SIZE TYPE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +BYTE_SIZES = { + 'b': 1, + 'kb': 10**3, + 'mb': 10**6, + 'gb': 10**9, + 'tb': 10**12, + 'pb': 10**15, + 'eb': 10**18, + 'kib': 2**10, + 'mib': 2**20, + 'gib': 2**30, + 'tib': 2**40, + 'pib': 2**50, + 'eib': 2**60, +} +BYTE_SIZES.update({k.lower()[0]: v for k, v in BYTE_SIZES.items() if 'i' not in k}) +byte_string_re = re.compile(r'^\s*(\d*\.?\d+)\s*(\w+)?', re.IGNORECASE) + + +class ByteSize(int): + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield cls.validate + + @classmethod + def validate(cls, v: StrIntFloat) -> 'ByteSize': + try: + return cls(int(v)) + except ValueError: + pass + + str_match = byte_string_re.match(str(v)) + if str_match is None: + raise errors.InvalidByteSize() + + scalar, unit = str_match.groups() + if unit is None: + unit = 'b' + + try: + unit_mult = BYTE_SIZES[unit.lower()] + except KeyError: + raise errors.InvalidByteSizeUnit(unit=unit) + + return cls(int(float(scalar) * unit_mult)) + + def human_readable(self, decimal: bool = False) -> str: + if decimal: + divisor = 1000 + units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'] + final_unit = 'EB' + else: + divisor = 1024 + units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'] + final_unit = 'EiB' + + num = float(self) + for unit in units: + if abs(num) < divisor: + return f'{num:0.1f}{unit}' + num /= divisor + + return f'{num:0.1f}{final_unit}' + + def to(self, unit: str) -> float: + try: + unit_div = BYTE_SIZES[unit.lower()] + except KeyError: + raise errors.InvalidByteSizeUnit(unit=unit) + + return self / unit_div + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DATE TYPES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +if TYPE_CHECKING: + PastDate = date + FutureDate = date +else: + + class PastDate(date): + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield parse_date + yield cls.validate + + @classmethod + def validate(cls, value: date) -> date: + if value >= date.today(): + raise errors.DateNotInThePastError() + + return value + + class FutureDate(date): + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield parse_date + yield cls.validate + + @classmethod + def validate(cls, value: date) -> date: + if value <= date.today(): + raise errors.DateNotInTheFutureError() + + return value + + +class ConstrainedDate(date, metaclass=ConstrainedNumberMeta): + gt: OptionalDate = None + ge: OptionalDate = None + lt: OptionalDate = None + le: OptionalDate = None + + @classmethod + def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + update_not_none(field_schema, exclusiveMinimum=cls.gt, exclusiveMaximum=cls.lt, minimum=cls.ge, maximum=cls.le) + + @classmethod + def __get_validators__(cls) -> 'CallableGenerator': + yield parse_date + yield number_size_validator + + +def condate( + *, + gt: date = None, + ge: date = None, + lt: date = None, + le: date = None, +) -> Type[date]: + # use kwargs then define conf in a dict to aid with IDE type hinting + namespace = dict(gt=gt, ge=ge, lt=lt, le=le) + return type('ConstrainedDateValue', (ConstrainedDate,), namespace) diff --git a/source/target-vendors/cp312/pydantic/v1/typing.py b/source/target-vendors/cp312/pydantic/v1/typing.py new file mode 100644 index 0000000..c5c5979 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/typing.py @@ -0,0 +1,627 @@ +import functools +import operator +import sys +import typing +from collections.abc import Callable +from os import PathLike +from typing import ( # type: ignore + TYPE_CHECKING, + AbstractSet, + Any, + Callable as TypingCallable, + ClassVar, + Dict, + ForwardRef, + Generator, + Iterable, + List, + Mapping, + NewType, + Optional, + Sequence, + Set, + Tuple, + Type, + TypeVar, + Union, + _eval_type, + cast, + get_type_hints, +) + +from typing_extensions import ( + Annotated, + Final, + Literal, + NotRequired as TypedDictNotRequired, + Required as TypedDictRequired, +) + +try: + from typing import _TypingBase as typing_base # type: ignore +except ImportError: + from typing import _Final as typing_base # type: ignore + +try: + from typing import GenericAlias as TypingGenericAlias # type: ignore +except ImportError: + # python < 3.9 does not have GenericAlias (list[int], tuple[str, ...] and so on) + TypingGenericAlias = () + +try: + from types import UnionType as TypesUnionType # type: ignore +except ImportError: + # python < 3.10 does not have UnionType (str | int, byte | bool and so on) + TypesUnionType = () + + +if sys.version_info < (3, 9): + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + return type_._evaluate(globalns, localns) + +elif sys.version_info < (3, 12, 4): + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + # Even though it is the right signature for python 3.9, mypy complains with + # `error: Too many arguments for "_evaluate" of "ForwardRef"` hence the cast... + # Python 3.13/3.12.4+ made `recursive_guard` a kwarg, so name it explicitly to avoid: + # TypeError: ForwardRef._evaluate() missing 1 required keyword-only argument: 'recursive_guard' + return cast(Any, type_)._evaluate(globalns, localns, recursive_guard=set()) + +elif sys.version_info < (3, 14): + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + # Pydantic 1.x will not support PEP 695 syntax, but provide `type_params` to avoid + # warnings: + return cast(Any, type_)._evaluate(globalns, localns, type_params=(), recursive_guard=set()) + +else: + + def evaluate_forwardref(type_: ForwardRef, globalns: Any, localns: Any) -> Any: + # Pydantic 1.x will not support PEP 695 syntax, but provide `type_params` to avoid + # warnings: + return typing.evaluate_forward_ref( + type_, + globals=globalns, + locals=localns, + type_params=(), + _recursive_guard=set(), + ) + + +if sys.version_info < (3, 9): + # Ensure we always get all the whole `Annotated` hint, not just the annotated type. + # For 3.7 to 3.8, `get_type_hints` doesn't recognize `typing_extensions.Annotated`, + # so it already returns the full annotation + get_all_type_hints = get_type_hints + +else: + + def get_all_type_hints(obj: Any, globalns: Any = None, localns: Any = None) -> Any: + return get_type_hints(obj, globalns, localns, include_extras=True) + + +_T = TypeVar('_T') + +AnyCallable = TypingCallable[..., Any] +NoArgAnyCallable = TypingCallable[[], Any] + +# workaround for https://github.com/python/mypy/issues/9496 +AnyArgTCallable = TypingCallable[..., _T] + + +# Annotated[...] is implemented by returning an instance of one of these classes, depending on +# python/typing_extensions version. +AnnotatedTypeNames = {'AnnotatedMeta', '_AnnotatedAlias'} + + +LITERAL_TYPES: Set[Any] = {Literal} +if hasattr(typing, 'Literal'): + LITERAL_TYPES.add(typing.Literal) + + +if sys.version_info < (3, 8): + + def get_origin(t: Type[Any]) -> Optional[Type[Any]]: + if type(t).__name__ in AnnotatedTypeNames: + # weirdly this is a runtime requirement, as well as for mypy + return cast(Type[Any], Annotated) + return getattr(t, '__origin__', None) + +else: + from typing import get_origin as _typing_get_origin + + def get_origin(tp: Type[Any]) -> Optional[Type[Any]]: + """ + We can't directly use `typing.get_origin` since we need a fallback to support + custom generic classes like `ConstrainedList` + It should be useless once https://github.com/cython/cython/issues/3537 is + solved and https://github.com/pydantic/pydantic/pull/1753 is merged. + """ + if type(tp).__name__ in AnnotatedTypeNames: + return cast(Type[Any], Annotated) # mypy complains about _SpecialForm + return _typing_get_origin(tp) or getattr(tp, '__origin__', None) + + +if sys.version_info < (3, 8): + from typing import _GenericAlias + + def get_args(t: Type[Any]) -> Tuple[Any, ...]: + """Compatibility version of get_args for python 3.7. + + Mostly compatible with the python 3.8 `typing` module version + and able to handle almost all use cases. + """ + if type(t).__name__ in AnnotatedTypeNames: + return t.__args__ + t.__metadata__ + if isinstance(t, _GenericAlias): + res = t.__args__ + if t.__origin__ is Callable and res and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return getattr(t, '__args__', ()) + +else: + from typing import get_args as _typing_get_args + + def _generic_get_args(tp: Type[Any]) -> Tuple[Any, ...]: + """ + In python 3.9, `typing.Dict`, `typing.List`, ... + do have an empty `__args__` by default (instead of the generic ~T for example). + In order to still support `Dict` for example and consider it as `Dict[Any, Any]`, + we retrieve the `_nparams` value that tells us how many parameters it needs. + """ + if hasattr(tp, '_nparams'): + return (Any,) * tp._nparams + # Special case for `tuple[()]`, which used to return ((),) with `typing.Tuple` + # in python 3.10- but now returns () for `tuple` and `Tuple`. + # This will probably be clarified in pydantic v2 + try: + if tp == Tuple[()] or sys.version_info >= (3, 9) and tp == tuple[()]: # type: ignore[misc] + return ((),) + # there is a TypeError when compiled with cython + except TypeError: # pragma: no cover + pass + return () + + def get_args(tp: Type[Any]) -> Tuple[Any, ...]: + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if type(tp).__name__ in AnnotatedTypeNames: + return tp.__args__ + tp.__metadata__ + # the fallback is needed for the same reasons as `get_origin` (see above) + return _typing_get_args(tp) or getattr(tp, '__args__', ()) or _generic_get_args(tp) + + +if sys.version_info < (3, 9): + + def convert_generics(tp: Type[Any]) -> Type[Any]: + """Python 3.9 and older only supports generics from `typing` module. + They convert strings to ForwardRef automatically. + + Examples:: + typing.List['Hero'] == typing.List[ForwardRef('Hero')] + """ + return tp + +else: + + def convert_generics(tp: Type[Any]) -> Type[Any]: + """ + Recursively searches for `str` type hints and replaces them with ForwardRef. + + Examples:: + convert_generics(list['Hero']) == list[ForwardRef('Hero')] + convert_generics(dict['Hero', 'Team']) == dict[ForwardRef('Hero'), ForwardRef('Team')] + convert_generics(typing.Dict['Hero', 'Team']) == typing.Dict[ForwardRef('Hero'), ForwardRef('Team')] + convert_generics(list[str | 'Hero'] | int) == list[str | ForwardRef('Hero')] | int + """ + origin = get_origin(tp) + if not origin or not hasattr(tp, '__args__'): + return tp + + args = get_args(tp) + + # typing.Annotated needs special treatment + if origin is Annotated: + return Annotated[(convert_generics(args[0]), *args[1:])] # type: ignore + + # recursively replace `str` instances inside of `GenericAlias` with `ForwardRef(arg)` + converted = tuple( + ForwardRef(arg) if isinstance(arg, str) and isinstance(tp, TypingGenericAlias) else convert_generics(arg) + for arg in args + ) + + if converted == args: + return tp + elif isinstance(tp, TypingGenericAlias): + return TypingGenericAlias(origin, converted) + elif isinstance(tp, TypesUnionType): + # recreate types.UnionType (PEP604, Python >= 3.10) + return functools.reduce(operator.or_, converted) # type: ignore + else: + try: + setattr(tp, '__args__', converted) + except AttributeError: + pass + return tp + + +if sys.version_info < (3, 10): + + def is_union(tp: Optional[Type[Any]]) -> bool: + return tp is Union + + WithArgsTypes = (TypingGenericAlias,) + +else: + import types + import typing + + def is_union(tp: Optional[Type[Any]]) -> bool: + return tp is Union or tp is types.UnionType # noqa: E721 + + WithArgsTypes = (typing._GenericAlias, types.GenericAlias, types.UnionType) + + +StrPath = Union[str, PathLike] + + +if TYPE_CHECKING: + from pydantic.v1.fields import ModelField + + TupleGenerator = Generator[Tuple[str, Any], None, None] + DictStrAny = Dict[str, Any] + DictAny = Dict[Any, Any] + SetStr = Set[str] + ListStr = List[str] + IntStr = Union[int, str] + AbstractSetIntStr = AbstractSet[IntStr] + DictIntStrAny = Dict[IntStr, Any] + MappingIntStrAny = Mapping[IntStr, Any] + CallableGenerator = Generator[AnyCallable, None, None] + ReprArgs = Sequence[Tuple[Optional[str], Any]] + + MYPY = False + if MYPY: + AnyClassMethod = classmethod[Any] + else: + # classmethod[TargetType, CallableParamSpecType, CallableReturnType] + AnyClassMethod = classmethod[Any, Any, Any] + +__all__ = ( + 'AnyCallable', + 'NoArgAnyCallable', + 'NoneType', + 'is_none_type', + 'display_as_type', + 'resolve_annotations', + 'is_callable_type', + 'is_literal_type', + 'all_literal_values', + 'is_namedtuple', + 'is_typeddict', + 'is_typeddict_special', + 'is_new_type', + 'new_type_supertype', + 'is_classvar', + 'is_finalvar', + 'update_field_forward_refs', + 'update_model_forward_refs', + 'TupleGenerator', + 'DictStrAny', + 'DictAny', + 'SetStr', + 'ListStr', + 'IntStr', + 'AbstractSetIntStr', + 'DictIntStrAny', + 'CallableGenerator', + 'ReprArgs', + 'AnyClassMethod', + 'CallableGenerator', + 'WithArgsTypes', + 'get_args', + 'get_origin', + 'get_sub_types', + 'typing_base', + 'get_all_type_hints', + 'is_union', + 'StrPath', + 'MappingIntStrAny', +) + + +NoneType = None.__class__ + + +NONE_TYPES: Tuple[Any, Any, Any] = (None, NoneType, Literal[None]) + + +if sys.version_info < (3, 8): + # Even though this implementation is slower, we need it for python 3.7: + # In python 3.7 "Literal" is not a builtin type and uses a different + # mechanism. + # for this reason `Literal[None] is Literal[None]` evaluates to `False`, + # breaking the faster implementation used for the other python versions. + + def is_none_type(type_: Any) -> bool: + return type_ in NONE_TYPES + +elif sys.version_info[:2] == (3, 8): + + def is_none_type(type_: Any) -> bool: + for none_type in NONE_TYPES: + if type_ is none_type: + return True + # With python 3.8, specifically 3.8.10, Literal "is" check sare very flakey + # can change on very subtle changes like use of types in other modules, + # hopefully this check avoids that issue. + if is_literal_type(type_): # pragma: no cover + return all_literal_values(type_) == (None,) + return False + +else: + + def is_none_type(type_: Any) -> bool: + return type_ in NONE_TYPES + + +def display_as_type(v: Type[Any]) -> str: + if not isinstance(v, typing_base) and not isinstance(v, WithArgsTypes) and not isinstance(v, type): + v = v.__class__ + + if is_union(get_origin(v)): + return f'Union[{", ".join(map(display_as_type, get_args(v)))}]' + + if isinstance(v, WithArgsTypes): + # Generic alias are constructs like `list[int]` + return str(v).replace('typing.', '') + + try: + return v.__name__ + except AttributeError: + # happens with typing objects + return str(v).replace('typing.', '') + + +def resolve_annotations(raw_annotations: Dict[str, Type[Any]], module_name: Optional[str]) -> Dict[str, Type[Any]]: + """ + Partially taken from typing.get_type_hints. + + Resolve string or ForwardRef annotations into type objects if possible. + """ + base_globals: Optional[Dict[str, Any]] = None + if module_name: + try: + module = sys.modules[module_name] + except KeyError: + # happens occasionally, see https://github.com/pydantic/pydantic/issues/2363 + pass + else: + base_globals = module.__dict__ + + annotations = {} + for name, value in raw_annotations.items(): + if isinstance(value, str): + if (3, 10) > sys.version_info >= (3, 9, 8) or sys.version_info >= (3, 10, 1): + value = ForwardRef(value, is_argument=False, is_class=True) + else: + value = ForwardRef(value, is_argument=False) + try: + if sys.version_info >= (3, 13): + value = _eval_type(value, base_globals, None, type_params=()) + else: + value = _eval_type(value, base_globals, None) + except NameError: + # this is ok, it can be fixed with update_forward_refs + pass + annotations[name] = value + return annotations + + +def is_callable_type(type_: Type[Any]) -> bool: + return type_ is Callable or get_origin(type_) is Callable + + +def is_literal_type(type_: Type[Any]) -> bool: + return Literal is not None and get_origin(type_) in LITERAL_TYPES + + +def literal_values(type_: Type[Any]) -> Tuple[Any, ...]: + return get_args(type_) + + +def all_literal_values(type_: Type[Any]) -> Tuple[Any, ...]: + """ + This method is used to retrieve all Literal values as + Literal can be used recursively (see https://www.python.org/dev/peps/pep-0586) + e.g. `Literal[Literal[Literal[1, 2, 3], "foo"], 5, None]` + """ + if not is_literal_type(type_): + return (type_,) + + values = literal_values(type_) + return tuple(x for value in values for x in all_literal_values(value)) + + +def is_namedtuple(type_: Type[Any]) -> bool: + """ + Check if a given class is a named tuple. + It can be either a `typing.NamedTuple` or `collections.namedtuple` + """ + from pydantic.v1.utils import lenient_issubclass + + return lenient_issubclass(type_, tuple) and hasattr(type_, '_fields') + + +def is_typeddict(type_: Type[Any]) -> bool: + """ + Check if a given class is a typed dict (from `typing` or `typing_extensions`) + In 3.10, there will be a public method (https://docs.python.org/3.10/library/typing.html#typing.is_typeddict) + """ + from pydantic.v1.utils import lenient_issubclass + + return lenient_issubclass(type_, dict) and hasattr(type_, '__total__') + + +def _check_typeddict_special(type_: Any) -> bool: + return type_ is TypedDictRequired or type_ is TypedDictNotRequired + + +def is_typeddict_special(type_: Any) -> bool: + """ + Check if type is a TypedDict special form (Required or NotRequired). + """ + return _check_typeddict_special(type_) or _check_typeddict_special(get_origin(type_)) + + +test_type = NewType('test_type', str) + + +def is_new_type(type_: Type[Any]) -> bool: + """ + Check whether type_ was created using typing.NewType + """ + return isinstance(type_, test_type.__class__) and hasattr(type_, '__supertype__') # type: ignore + + +def new_type_supertype(type_: Type[Any]) -> Type[Any]: + while hasattr(type_, '__supertype__'): + type_ = type_.__supertype__ + return type_ + + +def _check_classvar(v: Optional[Type[Any]]) -> bool: + if v is None: + return False + + return v.__class__ == ClassVar.__class__ and getattr(v, '_name', None) == 'ClassVar' + + +def _check_finalvar(v: Optional[Type[Any]]) -> bool: + """ + Check if a given type is a `typing.Final` type. + """ + if v is None: + return False + + return v.__class__ == Final.__class__ and (sys.version_info < (3, 8) or getattr(v, '_name', None) == 'Final') + + +def is_classvar(ann_type: Type[Any]) -> bool: + if _check_classvar(ann_type) or _check_classvar(get_origin(ann_type)): + return True + + # this is an ugly workaround for class vars that contain forward references and are therefore themselves + # forward references, see #3679 + if ann_type.__class__ == ForwardRef and ann_type.__forward_arg__.startswith('ClassVar['): + return True + + return False + + +def is_finalvar(ann_type: Type[Any]) -> bool: + return _check_finalvar(ann_type) or _check_finalvar(get_origin(ann_type)) + + +def update_field_forward_refs(field: 'ModelField', globalns: Any, localns: Any) -> None: + """ + Try to update ForwardRefs on fields based on this ModelField, globalns and localns. + """ + prepare = False + if field.type_.__class__ == ForwardRef: + prepare = True + field.type_ = evaluate_forwardref(field.type_, globalns, localns or None) + if field.outer_type_.__class__ == ForwardRef: + prepare = True + field.outer_type_ = evaluate_forwardref(field.outer_type_, globalns, localns or None) + if prepare: + field.prepare() + + if field.sub_fields: + for sub_f in field.sub_fields: + update_field_forward_refs(sub_f, globalns=globalns, localns=localns) + + if field.discriminator_key is not None: + field.prepare_discriminated_union_sub_fields() + + +def update_model_forward_refs( + model: Type[Any], + fields: Iterable['ModelField'], + json_encoders: Dict[Union[Type[Any], str, ForwardRef], AnyCallable], + localns: 'DictStrAny', + exc_to_suppress: Tuple[Type[BaseException], ...] = (), +) -> None: + """ + Try to update model fields ForwardRefs based on model and localns. + """ + if model.__module__ in sys.modules: + globalns = sys.modules[model.__module__].__dict__.copy() + else: + globalns = {} + + globalns.setdefault(model.__name__, model) + + for f in fields: + try: + update_field_forward_refs(f, globalns=globalns, localns=localns) + except exc_to_suppress: + pass + + for key in set(json_encoders.keys()): + if isinstance(key, str): + fr: ForwardRef = ForwardRef(key) + elif isinstance(key, ForwardRef): + fr = key + else: + continue + + try: + new_key = evaluate_forwardref(fr, globalns, localns or None) + except exc_to_suppress: # pragma: no cover + continue + + json_encoders[new_key] = json_encoders.pop(key) + + +def get_class(type_: Type[Any]) -> Union[None, bool, Type[Any]]: + """ + Tries to get the class of a Type[T] annotation. Returns True if Type is used + without brackets. Otherwise returns None. + """ + if type_ is type: + return True + + if get_origin(type_) is None: + return None + + args = get_args(type_) + if not args or not isinstance(args[0], type): + return True + else: + return args[0] + + +def get_sub_types(tp: Any) -> List[Any]: + """ + Return all the types that are allowed by type `tp` + `tp` can be a `Union` of allowed types or an `Annotated` type + """ + origin = get_origin(tp) + if origin is Annotated: + return get_sub_types(get_args(tp)[0]) + elif is_union(origin): + return [x for t in get_args(tp) for x in get_sub_types(t)] + else: + return [tp] diff --git a/source/target-vendors/cp312/pydantic/v1/utils.py b/source/target-vendors/cp312/pydantic/v1/utils.py new file mode 100644 index 0000000..2094e84 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/utils.py @@ -0,0 +1,807 @@ +import keyword +import warnings +import weakref +from collections import OrderedDict, defaultdict, deque +from copy import deepcopy +from itertools import islice, zip_longest +from types import BuiltinFunctionType, CodeType, FunctionType, GeneratorType, LambdaType, ModuleType +from typing import ( + TYPE_CHECKING, + AbstractSet, + Any, + Callable, + Collection, + Dict, + Generator, + Iterable, + Iterator, + List, + Mapping, + NoReturn, + Optional, + Set, + Tuple, + Type, + TypeVar, + Union, +) + +from typing_extensions import Annotated + +from pydantic.v1.errors import ConfigError +from pydantic.v1.typing import ( + NoneType, + WithArgsTypes, + all_literal_values, + display_as_type, + get_args, + get_origin, + is_literal_type, + is_union, +) +from pydantic.v1.version import version_info + +if TYPE_CHECKING: + from inspect import Signature + from pathlib import Path + + from pydantic.v1.config import BaseConfig + from pydantic.v1.dataclasses import Dataclass + from pydantic.v1.fields import ModelField + from pydantic.v1.main import BaseModel + from pydantic.v1.typing import AbstractSetIntStr, DictIntStrAny, IntStr, MappingIntStrAny, ReprArgs + + RichReprResult = Iterable[Union[Any, Tuple[Any], Tuple[str, Any], Tuple[str, Any, Any]]] + +__all__ = ( + 'import_string', + 'sequence_like', + 'validate_field_name', + 'lenient_isinstance', + 'lenient_issubclass', + 'in_ipython', + 'is_valid_identifier', + 'deep_update', + 'update_not_none', + 'almost_equal_floats', + 'get_model', + 'to_camel', + 'to_lower_camel', + 'is_valid_field', + 'smart_deepcopy', + 'PyObjectStr', + 'Representation', + 'GetterDict', + 'ValueItems', + 'version_info', # required here to match behaviour in v1.3 + 'ClassAttribute', + 'path_type', + 'ROOT_KEY', + 'get_unique_discriminator_alias', + 'get_discriminator_alias_and_values', + 'DUNDER_ATTRIBUTES', +) + +ROOT_KEY = '__root__' +# these are types that are returned unchanged by deepcopy +IMMUTABLE_NON_COLLECTIONS_TYPES: Set[Type[Any]] = { + int, + float, + complex, + str, + bool, + bytes, + type, + NoneType, + FunctionType, + BuiltinFunctionType, + LambdaType, + weakref.ref, + CodeType, + # note: including ModuleType will differ from behaviour of deepcopy by not producing error. + # It might be not a good idea in general, but considering that this function used only internally + # against default values of fields, this will allow to actually have a field with module as default value + ModuleType, + NotImplemented.__class__, + Ellipsis.__class__, +} + +# these are types that if empty, might be copied with simple copy() instead of deepcopy() +BUILTIN_COLLECTIONS: Set[Type[Any]] = { + list, + set, + tuple, + frozenset, + dict, + OrderedDict, + defaultdict, + deque, +} + + +def import_string(dotted_path: str) -> Any: + """ + Stolen approximately from django. Import a dotted module path and return the attribute/class designated by the + last name in the path. Raise ImportError if the import fails. + """ + from importlib import import_module + + try: + module_path, class_name = dotted_path.strip(' ').rsplit('.', 1) + except ValueError as e: + raise ImportError(f'"{dotted_path}" doesn\'t look like a module path') from e + + module = import_module(module_path) + try: + return getattr(module, class_name) + except AttributeError as e: + raise ImportError(f'Module "{module_path}" does not define a "{class_name}" attribute') from e + + +def truncate(v: Union[str], *, max_len: int = 80) -> str: + """ + Truncate a value and add a unicode ellipsis (three dots) to the end if it was too long + """ + warnings.warn('`truncate` is no-longer used by pydantic and is deprecated', DeprecationWarning) + if isinstance(v, str) and len(v) > (max_len - 2): + # -3 so quote + string + … + quote has correct length + return (v[: (max_len - 3)] + '…').__repr__() + try: + v = v.__repr__() + except TypeError: + v = v.__class__.__repr__(v) # in case v is a type + if len(v) > max_len: + v = v[: max_len - 1] + '…' + return v + + +def sequence_like(v: Any) -> bool: + return isinstance(v, (list, tuple, set, frozenset, GeneratorType, deque)) + + +def validate_field_name(bases: Iterable[Type[Any]], field_name: str) -> None: + """ + Ensure that the field's name does not shadow an existing attribute of the model. + """ + for base in bases: + if getattr(base, field_name, None): + raise NameError( + f'Field name "{field_name}" shadows a BaseModel attribute; ' + f'use a different field name with "alias=\'{field_name}\'".' + ) + + +def lenient_isinstance(o: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]) -> bool: + try: + return isinstance(o, class_or_tuple) # type: ignore[arg-type] + except TypeError: + return False + + +def lenient_issubclass(cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]) -> bool: + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] + except TypeError: + if isinstance(cls, WithArgsTypes): + return False + raise # pragma: no cover + + +def in_ipython() -> bool: + """ + Check whether we're in an ipython environment, including jupyter notebooks. + """ + try: + eval('__IPYTHON__') + except NameError: + return False + else: # pragma: no cover + return True + + +def is_valid_identifier(identifier: str) -> bool: + """ + Checks that a string is a valid identifier and not a Python keyword. + :param identifier: The identifier to test. + :return: True if the identifier is valid. + """ + return identifier.isidentifier() and not keyword.iskeyword(identifier) + + +KeyType = TypeVar('KeyType') + + +def deep_update(mapping: Dict[KeyType, Any], *updating_mappings: Dict[KeyType, Any]) -> Dict[KeyType, Any]: + updated_mapping = mapping.copy() + for updating_mapping in updating_mappings: + for k, v in updating_mapping.items(): + if k in updated_mapping and isinstance(updated_mapping[k], dict) and isinstance(v, dict): + updated_mapping[k] = deep_update(updated_mapping[k], v) + else: + updated_mapping[k] = v + return updated_mapping + + +def update_not_none(mapping: Dict[Any, Any], **update: Any) -> None: + mapping.update({k: v for k, v in update.items() if v is not None}) + + +def almost_equal_floats(value_1: float, value_2: float, *, delta: float = 1e-8) -> bool: + """ + Return True if two floats are almost equal + """ + return abs(value_1 - value_2) <= delta + + +def generate_model_signature( + init: Callable[..., None], fields: Dict[str, 'ModelField'], config: Type['BaseConfig'] +) -> 'Signature': + """ + Generate signature for model based on its fields + """ + from inspect import Parameter, Signature, signature + + from pydantic.v1.config import Extra + + present_params = signature(init).parameters.values() + merged_params: Dict[str, Parameter] = {} + var_kw = None + use_var_kw = False + + for param in islice(present_params, 1, None): # skip self arg + if param.kind is param.VAR_KEYWORD: + var_kw = param + continue + merged_params[param.name] = param + + if var_kw: # if custom init has no var_kw, fields which are not declared in it cannot be passed through + allow_names = config.allow_population_by_field_name + for field_name, field in fields.items(): + param_name = field.alias + if field_name in merged_params or param_name in merged_params: + continue + elif not is_valid_identifier(param_name): + if allow_names and is_valid_identifier(field_name): + param_name = field_name + else: + use_var_kw = True + continue + + # TODO: replace annotation with actual expected types once #1055 solved + kwargs = {'default': field.default} if not field.required else {} + merged_params[param_name] = Parameter( + param_name, Parameter.KEYWORD_ONLY, annotation=field.annotation, **kwargs + ) + + if config.extra is Extra.allow: + use_var_kw = True + + if var_kw and use_var_kw: + # Make sure the parameter for extra kwargs + # does not have the same name as a field + default_model_signature = [ + ('__pydantic_self__', Parameter.POSITIONAL_OR_KEYWORD), + ('data', Parameter.VAR_KEYWORD), + ] + if [(p.name, p.kind) for p in present_params] == default_model_signature: + # if this is the standard model signature, use extra_data as the extra args name + var_kw_name = 'extra_data' + else: + # else start from var_kw + var_kw_name = var_kw.name + + # generate a name that's definitely unique + while var_kw_name in fields: + var_kw_name += '_' + merged_params[var_kw_name] = var_kw.replace(name=var_kw_name) + + return Signature(parameters=list(merged_params.values()), return_annotation=None) + + +def get_model(obj: Union[Type['BaseModel'], Type['Dataclass']]) -> Type['BaseModel']: + from pydantic.v1.main import BaseModel + + try: + model_cls = obj.__pydantic_model__ # type: ignore + except AttributeError: + model_cls = obj + + if not issubclass(model_cls, BaseModel): + raise TypeError('Unsupported type, must be either BaseModel or dataclass') + return model_cls + + +def to_camel(string: str) -> str: + return ''.join(word.capitalize() for word in string.split('_')) + + +def to_lower_camel(string: str) -> str: + if len(string) >= 1: + pascal_string = to_camel(string) + return pascal_string[0].lower() + pascal_string[1:] + return string.lower() + + +T = TypeVar('T') + + +def unique_list( + input_list: Union[List[T], Tuple[T, ...]], + *, + name_factory: Callable[[T], str] = str, +) -> List[T]: + """ + Make a list unique while maintaining order. + We update the list if another one with the same name is set + (e.g. root validator overridden in subclass) + """ + result: List[T] = [] + result_names: List[str] = [] + for v in input_list: + v_name = name_factory(v) + if v_name not in result_names: + result_names.append(v_name) + result.append(v) + else: + result[result_names.index(v_name)] = v + + return result + + +class PyObjectStr(str): + """ + String class where repr doesn't include quotes. Useful with Representation when you want to return a string + representation of something that valid (or pseudo-valid) python. + """ + + def __repr__(self) -> str: + return str(self) + + +class Representation: + """ + Mixin to provide __str__, __repr__, and __pretty__ methods. See #884 for more details. + + __pretty__ is used by [devtools](https://python-devtools.helpmanual.io/) to provide human readable representations + of objects. + """ + + __slots__: Tuple[str, ...] = tuple() + + def __repr_args__(self) -> 'ReprArgs': + """ + Returns the attributes to show in __str__, __repr__, and __pretty__ this is generally overridden. + + Can either return: + * name - value pairs, e.g.: `[('foo_name', 'foo'), ('bar_name', ['b', 'a', 'r'])]` + * or, just values, e.g.: `[(None, 'foo'), (None, ['b', 'a', 'r'])]` + """ + attrs = ((s, getattr(self, s)) for s in self.__slots__) + return [(a, v) for a, v in attrs if v is not None] + + def __repr_name__(self) -> str: + """ + Name of the instance's class, used in __repr__. + """ + return self.__class__.__name__ + + def __repr_str__(self, join_str: str) -> str: + return join_str.join(repr(v) if a is None else f'{a}={v!r}' for a, v in self.__repr_args__()) + + def __pretty__(self, fmt: Callable[[Any], Any], **kwargs: Any) -> Generator[Any, None, None]: + """ + Used by devtools (https://python-devtools.helpmanual.io/) to provide a human readable representations of objects + """ + yield self.__repr_name__() + '(' + yield 1 + for name, value in self.__repr_args__(): + if name is not None: + yield name + '=' + yield fmt(value) + yield ',' + yield 0 + yield -1 + yield ')' + + def __str__(self) -> str: + return self.__repr_str__(' ') + + def __repr__(self) -> str: + return f'{self.__repr_name__()}({self.__repr_str__(", ")})' + + def __rich_repr__(self) -> 'RichReprResult': + """Get fields for Rich library""" + for name, field_repr in self.__repr_args__(): + if name is None: + yield field_repr + else: + yield name, field_repr + + +class GetterDict(Representation): + """ + Hack to make object's smell just enough like dicts for validate_model. + + We can't inherit from Mapping[str, Any] because it upsets cython so we have to implement all methods ourselves. + """ + + __slots__ = ('_obj',) + + def __init__(self, obj: Any): + self._obj = obj + + def __getitem__(self, key: str) -> Any: + try: + return getattr(self._obj, key) + except AttributeError as e: + raise KeyError(key) from e + + def get(self, key: Any, default: Any = None) -> Any: + return getattr(self._obj, key, default) + + def extra_keys(self) -> Set[Any]: + """ + We don't want to get any other attributes of obj if the model didn't explicitly ask for them + """ + return set() + + def keys(self) -> List[Any]: + """ + Keys of the pseudo dictionary, uses a list not set so order information can be maintained like python + dictionaries. + """ + return list(self) + + def values(self) -> List[Any]: + return [self[k] for k in self] + + def items(self) -> Iterator[Tuple[str, Any]]: + for k in self: + yield k, self.get(k) + + def __iter__(self) -> Iterator[str]: + for name in dir(self._obj): + if not name.startswith('_'): + yield name + + def __len__(self) -> int: + return sum(1 for _ in self) + + def __contains__(self, item: Any) -> bool: + return item in self.keys() + + def __eq__(self, other: Any) -> bool: + return dict(self) == dict(other.items()) + + def __repr_args__(self) -> 'ReprArgs': + return [(None, dict(self))] + + def __repr_name__(self) -> str: + return f'GetterDict[{display_as_type(self._obj)}]' + + +class ValueItems(Representation): + """ + Class for more convenient calculation of excluded or included fields on values. + """ + + __slots__ = ('_items', '_type') + + def __init__(self, value: Any, items: Union['AbstractSetIntStr', 'MappingIntStrAny']) -> None: + items = self._coerce_items(items) + + if isinstance(value, (list, tuple)): + items = self._normalize_indexes(items, len(value)) + + self._items: 'MappingIntStrAny' = items + + def is_excluded(self, item: Any) -> bool: + """ + Check if item is fully excluded. + + :param item: key or index of a value + """ + return self.is_true(self._items.get(item)) + + def is_included(self, item: Any) -> bool: + """ + Check if value is contained in self._items + + :param item: key or index of value + """ + return item in self._items + + def for_element(self, e: 'IntStr') -> Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']]: + """ + :param e: key or index of element on value + :return: raw values for element if self._items is dict and contain needed element + """ + + item = self._items.get(e) + return item if not self.is_true(item) else None + + def _normalize_indexes(self, items: 'MappingIntStrAny', v_length: int) -> 'DictIntStrAny': + """ + :param items: dict or set of indexes which will be normalized + :param v_length: length of sequence indexes of which will be + + >>> self._normalize_indexes({0: True, -2: True, -1: True}, 4) + {0: True, 2: True, 3: True} + >>> self._normalize_indexes({'__all__': True}, 4) + {0: True, 1: True, 2: True, 3: True} + """ + + normalized_items: 'DictIntStrAny' = {} + all_items = None + for i, v in items.items(): + if not (isinstance(v, Mapping) or isinstance(v, AbstractSet) or self.is_true(v)): + raise TypeError(f'Unexpected type of exclude value for index "{i}" {v.__class__}') + if i == '__all__': + all_items = self._coerce_value(v) + continue + if not isinstance(i, int): + raise TypeError( + 'Excluding fields from a sequence of sub-models or dicts must be performed index-wise: ' + 'expected integer keys or keyword "__all__"' + ) + normalized_i = v_length + i if i < 0 else i + normalized_items[normalized_i] = self.merge(v, normalized_items.get(normalized_i)) + + if not all_items: + return normalized_items + if self.is_true(all_items): + for i in range(v_length): + normalized_items.setdefault(i, ...) + return normalized_items + for i in range(v_length): + normalized_item = normalized_items.setdefault(i, {}) + if not self.is_true(normalized_item): + normalized_items[i] = self.merge(all_items, normalized_item) + return normalized_items + + @classmethod + def merge(cls, base: Any, override: Any, intersect: bool = False) -> Any: + """ + Merge a ``base`` item with an ``override`` item. + + Both ``base`` and ``override`` are converted to dictionaries if possible. + Sets are converted to dictionaries with the sets entries as keys and + Ellipsis as values. + + Each key-value pair existing in ``base`` is merged with ``override``, + while the rest of the key-value pairs are updated recursively with this function. + + Merging takes place based on the "union" of keys if ``intersect`` is + set to ``False`` (default) and on the intersection of keys if + ``intersect`` is set to ``True``. + """ + override = cls._coerce_value(override) + base = cls._coerce_value(base) + if override is None: + return base + if cls.is_true(base) or base is None: + return override + if cls.is_true(override): + return base if intersect else override + + # intersection or union of keys while preserving ordering: + if intersect: + merge_keys = [k for k in base if k in override] + [k for k in override if k in base] + else: + merge_keys = list(base) + [k for k in override if k not in base] + + merged: 'DictIntStrAny' = {} + for k in merge_keys: + merged_item = cls.merge(base.get(k), override.get(k), intersect=intersect) + if merged_item is not None: + merged[k] = merged_item + + return merged + + @staticmethod + def _coerce_items(items: Union['AbstractSetIntStr', 'MappingIntStrAny']) -> 'MappingIntStrAny': + if isinstance(items, Mapping): + pass + elif isinstance(items, AbstractSet): + items = dict.fromkeys(items, ...) + else: + class_name = getattr(items, '__class__', '???') + assert_never( + items, + f'Unexpected type of exclude value {class_name}', + ) + return items + + @classmethod + def _coerce_value(cls, value: Any) -> Any: + if value is None or cls.is_true(value): + return value + return cls._coerce_items(value) + + @staticmethod + def is_true(v: Any) -> bool: + return v is True or v is ... + + def __repr_args__(self) -> 'ReprArgs': + return [(None, self._items)] + + +class ClassAttribute: + """ + Hide class attribute from its instances + """ + + __slots__ = ( + 'name', + 'value', + ) + + def __init__(self, name: str, value: Any) -> None: + self.name = name + self.value = value + + def __get__(self, instance: Any, owner: Type[Any]) -> None: + if instance is None: + return self.value + raise AttributeError(f'{self.name!r} attribute of {owner.__name__!r} is class-only') + + +path_types = { + 'is_dir': 'directory', + 'is_file': 'file', + 'is_mount': 'mount point', + 'is_symlink': 'symlink', + 'is_block_device': 'block device', + 'is_char_device': 'char device', + 'is_fifo': 'FIFO', + 'is_socket': 'socket', +} + + +def path_type(p: 'Path') -> str: + """ + Find out what sort of thing a path is. + """ + assert p.exists(), 'path does not exist' + for method, name in path_types.items(): + if getattr(p, method)(): + return name + + return 'unknown' + + +Obj = TypeVar('Obj') + + +def smart_deepcopy(obj: Obj) -> Obj: + """ + Return type as is for immutable built-in types + Use obj.copy() for built-in empty collections + Use copy.deepcopy() for non-empty collections and unknown objects + """ + + obj_type = obj.__class__ + if obj_type in IMMUTABLE_NON_COLLECTIONS_TYPES: + return obj # fastest case: obj is immutable and not collection therefore will not be copied anyway + try: + if not obj and obj_type in BUILTIN_COLLECTIONS: + # faster way for empty collections, no need to copy its members + return obj if obj_type is tuple else obj.copy() # type: ignore # tuple doesn't have copy method + except (TypeError, ValueError, RuntimeError): + # do we really dare to catch ALL errors? Seems a bit risky + pass + + return deepcopy(obj) # slowest way when we actually might need a deepcopy + + +def is_valid_field(name: str) -> bool: + if not name.startswith('_'): + return True + return ROOT_KEY == name + + +DUNDER_ATTRIBUTES = { + '__annotations__', + '__classcell__', + '__doc__', + '__module__', + '__orig_bases__', + '__orig_class__', + '__qualname__', + '__firstlineno__', + '__static_attributes__', + '__classdictcell__', +} + + +def is_valid_private_name(name: str) -> bool: + return not is_valid_field(name) and name not in DUNDER_ATTRIBUTES + + +_EMPTY = object() + + +def all_identical(left: Iterable[Any], right: Iterable[Any]) -> bool: + """ + Check that the items of `left` are the same objects as those in `right`. + + >>> a, b = object(), object() + >>> all_identical([a, b, a], [a, b, a]) + True + >>> all_identical([a, b, [a]], [a, b, [a]]) # new list object, while "equal" is not "identical" + False + """ + for left_item, right_item in zip_longest(left, right, fillvalue=_EMPTY): + if left_item is not right_item: + return False + return True + + +def assert_never(obj: NoReturn, msg: str) -> NoReturn: + """ + Helper to make sure that we have covered all possible types. + + This is mostly useful for ``mypy``, docs: + https://mypy.readthedocs.io/en/latest/literal_types.html#exhaustive-checks + """ + raise TypeError(msg) + + +def get_unique_discriminator_alias(all_aliases: Collection[str], discriminator_key: str) -> str: + """Validate that all aliases are the same and if that's the case return the alias""" + unique_aliases = set(all_aliases) + if len(unique_aliases) > 1: + raise ConfigError( + f'Aliases for discriminator {discriminator_key!r} must be the same (got {", ".join(sorted(all_aliases))})' + ) + return unique_aliases.pop() + + +def get_discriminator_alias_and_values(tp: Any, discriminator_key: str) -> Tuple[str, Tuple[str, ...]]: + """ + Get alias and all valid values in the `Literal` type of the discriminator field + `tp` can be a `BaseModel` class or directly an `Annotated` `Union` of many. + """ + is_root_model = getattr(tp, '__custom_root_type__', False) + + if get_origin(tp) is Annotated: + tp = get_args(tp)[0] + + if hasattr(tp, '__pydantic_model__'): + tp = tp.__pydantic_model__ + + if is_union(get_origin(tp)): + alias, all_values = _get_union_alias_and_all_values(tp, discriminator_key) + return alias, tuple(v for values in all_values for v in values) + elif is_root_model: + union_type = tp.__fields__[ROOT_KEY].type_ + alias, all_values = _get_union_alias_and_all_values(union_type, discriminator_key) + + if len(set(all_values)) > 1: + raise ConfigError( + f'Field {discriminator_key!r} is not the same for all submodels of {display_as_type(tp)!r}' + ) + + return alias, all_values[0] + + else: + try: + t_discriminator_type = tp.__fields__[discriminator_key].type_ + except AttributeError as e: + raise TypeError(f'Type {tp.__name__!r} is not a valid `BaseModel` or `dataclass`') from e + except KeyError as e: + raise ConfigError(f'Model {tp.__name__!r} needs a discriminator field for key {discriminator_key!r}') from e + + if not is_literal_type(t_discriminator_type): + raise ConfigError(f'Field {discriminator_key!r} of model {tp.__name__!r} needs to be a `Literal`') + + return tp.__fields__[discriminator_key].alias, all_literal_values(t_discriminator_type) + + +def _get_union_alias_and_all_values( + union_type: Type[Any], discriminator_key: str +) -> Tuple[str, Tuple[Tuple[str, ...], ...]]: + zipped_aliases_values = [get_discriminator_alias_and_values(t, discriminator_key) for t in get_args(union_type)] + # unzip: [('alias_a',('v1', 'v2)), ('alias_b', ('v3',))] => [('alias_a', 'alias_b'), (('v1', 'v2'), ('v3',))] + all_aliases, all_values = zip(*zipped_aliases_values) + return get_unique_discriminator_alias(all_aliases, discriminator_key), all_values diff --git a/source/target-vendors/cp312/pydantic/v1/validators.py b/source/target-vendors/cp312/pydantic/v1/validators.py new file mode 100644 index 0000000..c0940e8 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/validators.py @@ -0,0 +1,768 @@ +import math +import re +from collections import OrderedDict, deque +from collections.abc import Hashable as CollectionsHashable +from datetime import date, datetime, time, timedelta +from decimal import Decimal, DecimalException +from enum import Enum, IntEnum +from ipaddress import IPv4Address, IPv4Interface, IPv4Network, IPv6Address, IPv6Interface, IPv6Network +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Deque, + Dict, + ForwardRef, + FrozenSet, + Generator, + Hashable, + List, + NamedTuple, + Pattern, + Set, + Tuple, + Type, + TypeVar, + Union, +) +from uuid import UUID +from warnings import warn + +from pydantic.v1 import errors +from pydantic.v1.datetime_parse import parse_date, parse_datetime, parse_duration, parse_time +from pydantic.v1.typing import ( + AnyCallable, + all_literal_values, + display_as_type, + get_class, + is_callable_type, + is_literal_type, + is_namedtuple, + is_none_type, + is_typeddict, +) +from pydantic.v1.utils import almost_equal_floats, lenient_issubclass, sequence_like + +if TYPE_CHECKING: + from typing_extensions import Literal, TypedDict + + from pydantic.v1.config import BaseConfig + from pydantic.v1.fields import ModelField + from pydantic.v1.types import ConstrainedDecimal, ConstrainedFloat, ConstrainedInt + + ConstrainedNumber = Union[ConstrainedDecimal, ConstrainedFloat, ConstrainedInt] + AnyOrderedDict = OrderedDict[Any, Any] + Number = Union[int, float, Decimal] + StrBytes = Union[str, bytes] + + +def str_validator(v: Any) -> Union[str]: + if isinstance(v, str): + if isinstance(v, Enum): + return v.value + else: + return v + elif isinstance(v, (float, int, Decimal)): + # is there anything else we want to add here? If you think so, create an issue. + return str(v) + elif isinstance(v, (bytes, bytearray)): + return v.decode() + else: + raise errors.StrError() + + +def strict_str_validator(v: Any) -> Union[str]: + if isinstance(v, str) and not isinstance(v, Enum): + return v + raise errors.StrError() + + +def bytes_validator(v: Any) -> Union[bytes]: + if isinstance(v, bytes): + return v + elif isinstance(v, bytearray): + return bytes(v) + elif isinstance(v, str): + return v.encode() + elif isinstance(v, (float, int, Decimal)): + return str(v).encode() + else: + raise errors.BytesError() + + +def strict_bytes_validator(v: Any) -> Union[bytes]: + if isinstance(v, bytes): + return v + elif isinstance(v, bytearray): + return bytes(v) + else: + raise errors.BytesError() + + +BOOL_FALSE = {0, '0', 'off', 'f', 'false', 'n', 'no'} +BOOL_TRUE = {1, '1', 'on', 't', 'true', 'y', 'yes'} + + +def bool_validator(v: Any) -> bool: + if v is True or v is False: + return v + if isinstance(v, bytes): + v = v.decode() + if isinstance(v, str): + v = v.lower() + try: + if v in BOOL_TRUE: + return True + if v in BOOL_FALSE: + return False + except TypeError: + raise errors.BoolError() + raise errors.BoolError() + + +# matches the default limit cpython, see https://github.com/python/cpython/pull/96500 +max_str_int = 4_300 + + +def int_validator(v: Any) -> int: + if isinstance(v, int) and not (v is True or v is False): + return v + + # see https://github.com/pydantic/pydantic/issues/1477 and in turn, https://github.com/python/cpython/issues/95778 + # this check should be unnecessary once patch releases are out for 3.7, 3.8, 3.9 and 3.10 + # but better to check here until then. + # NOTICE: this does not fully protect user from the DOS risk since the standard library JSON implementation + # (and other std lib modules like xml) use `int()` and are likely called before this, the best workaround is to + # 1. update to the latest patch release of python once released, 2. use a different JSON library like ujson + if isinstance(v, (str, bytes, bytearray)) and len(v) > max_str_int: + raise errors.IntegerError() + + try: + return int(v) + except (TypeError, ValueError, OverflowError): + raise errors.IntegerError() + + +def strict_int_validator(v: Any) -> int: + if isinstance(v, int) and not (v is True or v is False): + return v + raise errors.IntegerError() + + +def float_validator(v: Any) -> float: + if isinstance(v, float): + return v + + try: + return float(v) + except (TypeError, ValueError): + raise errors.FloatError() + + +def strict_float_validator(v: Any) -> float: + if isinstance(v, float): + return v + raise errors.FloatError() + + +def float_finite_validator(v: 'Number', field: 'ModelField', config: 'BaseConfig') -> 'Number': + allow_inf_nan = getattr(field.type_, 'allow_inf_nan', None) + if allow_inf_nan is None: + allow_inf_nan = config.allow_inf_nan + + if allow_inf_nan is False and (math.isnan(v) or math.isinf(v)): + raise errors.NumberNotFiniteError() + return v + + +def number_multiple_validator(v: 'Number', field: 'ModelField') -> 'Number': + field_type: ConstrainedNumber = field.type_ + if field_type.multiple_of is not None: + mod = float(v) / float(field_type.multiple_of) % 1 + if not almost_equal_floats(mod, 0.0) and not almost_equal_floats(mod, 1.0): + raise errors.NumberNotMultipleError(multiple_of=field_type.multiple_of) + return v + + +def number_size_validator(v: 'Number', field: 'ModelField') -> 'Number': + field_type: ConstrainedNumber = field.type_ + if field_type.gt is not None and not v > field_type.gt: + raise errors.NumberNotGtError(limit_value=field_type.gt) + elif field_type.ge is not None and not v >= field_type.ge: + raise errors.NumberNotGeError(limit_value=field_type.ge) + + if field_type.lt is not None and not v < field_type.lt: + raise errors.NumberNotLtError(limit_value=field_type.lt) + if field_type.le is not None and not v <= field_type.le: + raise errors.NumberNotLeError(limit_value=field_type.le) + + return v + + +def constant_validator(v: 'Any', field: 'ModelField') -> 'Any': + """Validate ``const`` fields. + + The value provided for a ``const`` field must be equal to the default value + of the field. This is to support the keyword of the same name in JSON + Schema. + """ + if v != field.default: + raise errors.WrongConstantError(given=v, permitted=[field.default]) + + return v + + +def anystr_length_validator(v: 'StrBytes', config: 'BaseConfig') -> 'StrBytes': + v_len = len(v) + + min_length = config.min_anystr_length + if v_len < min_length: + raise errors.AnyStrMinLengthError(limit_value=min_length) + + max_length = config.max_anystr_length + if max_length is not None and v_len > max_length: + raise errors.AnyStrMaxLengthError(limit_value=max_length) + + return v + + +def anystr_strip_whitespace(v: 'StrBytes') -> 'StrBytes': + return v.strip() + + +def anystr_upper(v: 'StrBytes') -> 'StrBytes': + return v.upper() + + +def anystr_lower(v: 'StrBytes') -> 'StrBytes': + return v.lower() + + +def ordered_dict_validator(v: Any) -> 'AnyOrderedDict': + if isinstance(v, OrderedDict): + return v + + try: + return OrderedDict(v) + except (TypeError, ValueError): + raise errors.DictError() + + +def dict_validator(v: Any) -> Dict[Any, Any]: + if isinstance(v, dict): + return v + + try: + return dict(v) + except (TypeError, ValueError): + raise errors.DictError() + + +def list_validator(v: Any) -> List[Any]: + if isinstance(v, list): + return v + elif sequence_like(v): + return list(v) + else: + raise errors.ListError() + + +def tuple_validator(v: Any) -> Tuple[Any, ...]: + if isinstance(v, tuple): + return v + elif sequence_like(v): + return tuple(v) + else: + raise errors.TupleError() + + +def set_validator(v: Any) -> Set[Any]: + if isinstance(v, set): + return v + elif sequence_like(v): + return set(v) + else: + raise errors.SetError() + + +def frozenset_validator(v: Any) -> FrozenSet[Any]: + if isinstance(v, frozenset): + return v + elif sequence_like(v): + return frozenset(v) + else: + raise errors.FrozenSetError() + + +def deque_validator(v: Any) -> Deque[Any]: + if isinstance(v, deque): + return v + elif sequence_like(v): + return deque(v) + else: + raise errors.DequeError() + + +def enum_member_validator(v: Any, field: 'ModelField', config: 'BaseConfig') -> Enum: + try: + enum_v = field.type_(v) + except ValueError: + # field.type_ should be an enum, so will be iterable + raise errors.EnumMemberError(enum_values=list(field.type_)) + return enum_v.value if config.use_enum_values else enum_v + + +def uuid_validator(v: Any, field: 'ModelField') -> UUID: + try: + if isinstance(v, str): + v = UUID(v) + elif isinstance(v, (bytes, bytearray)): + try: + v = UUID(v.decode()) + except ValueError: + # 16 bytes in big-endian order as the bytes argument fail + # the above check + v = UUID(bytes=v) + except ValueError: + raise errors.UUIDError() + + if not isinstance(v, UUID): + raise errors.UUIDError() + + required_version = getattr(field.type_, '_required_version', None) + if required_version and v.version != required_version: + raise errors.UUIDVersionError(required_version=required_version) + + return v + + +def decimal_validator(v: Any) -> Decimal: + if isinstance(v, Decimal): + return v + elif isinstance(v, (bytes, bytearray)): + v = v.decode() + + v = str(v).strip() + + try: + v = Decimal(v) + except DecimalException: + raise errors.DecimalError() + + if not v.is_finite(): + raise errors.DecimalIsNotFiniteError() + + return v + + +def hashable_validator(v: Any) -> Hashable: + if isinstance(v, Hashable): + return v + + raise errors.HashableError() + + +def ip_v4_address_validator(v: Any) -> IPv4Address: + if isinstance(v, IPv4Address): + return v + + try: + return IPv4Address(v) + except ValueError: + raise errors.IPv4AddressError() + + +def ip_v6_address_validator(v: Any) -> IPv6Address: + if isinstance(v, IPv6Address): + return v + + try: + return IPv6Address(v) + except ValueError: + raise errors.IPv6AddressError() + + +def ip_v4_network_validator(v: Any) -> IPv4Network: + """ + Assume IPv4Network initialised with a default ``strict`` argument + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv4Network + """ + if isinstance(v, IPv4Network): + return v + + try: + return IPv4Network(v) + except ValueError: + raise errors.IPv4NetworkError() + + +def ip_v6_network_validator(v: Any) -> IPv6Network: + """ + Assume IPv6Network initialised with a default ``strict`` argument + + See more: + https://docs.python.org/library/ipaddress.html#ipaddress.IPv6Network + """ + if isinstance(v, IPv6Network): + return v + + try: + return IPv6Network(v) + except ValueError: + raise errors.IPv6NetworkError() + + +def ip_v4_interface_validator(v: Any) -> IPv4Interface: + if isinstance(v, IPv4Interface): + return v + + try: + return IPv4Interface(v) + except ValueError: + raise errors.IPv4InterfaceError() + + +def ip_v6_interface_validator(v: Any) -> IPv6Interface: + if isinstance(v, IPv6Interface): + return v + + try: + return IPv6Interface(v) + except ValueError: + raise errors.IPv6InterfaceError() + + +def path_validator(v: Any) -> Path: + if isinstance(v, Path): + return v + + try: + return Path(v) + except TypeError: + raise errors.PathError() + + +def path_exists_validator(v: Any) -> Path: + if not v.exists(): + raise errors.PathNotExistsError(path=v) + + return v + + +def callable_validator(v: Any) -> AnyCallable: + """ + Perform a simple check if the value is callable. + + Note: complete matching of argument type hints and return types is not performed + """ + if callable(v): + return v + + raise errors.CallableError(value=v) + + +def enum_validator(v: Any) -> Enum: + if isinstance(v, Enum): + return v + + raise errors.EnumError(value=v) + + +def int_enum_validator(v: Any) -> IntEnum: + if isinstance(v, IntEnum): + return v + + raise errors.IntEnumError(value=v) + + +def make_literal_validator(type_: Any) -> Callable[[Any], Any]: + permitted_choices = all_literal_values(type_) + + # To have a O(1) complexity and still return one of the values set inside the `Literal`, + # we create a dict with the set values (a set causes some problems with the way intersection works). + # In some cases the set value and checked value can indeed be different (see `test_literal_validator_str_enum`) + allowed_choices = {v: v for v in permitted_choices} + + def literal_validator(v: Any) -> Any: + try: + return allowed_choices[v] + except (KeyError, TypeError): + raise errors.WrongConstantError(given=v, permitted=permitted_choices) + + return literal_validator + + +def constr_length_validator(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + v_len = len(v) + + min_length = field.type_.min_length if field.type_.min_length is not None else config.min_anystr_length + if v_len < min_length: + raise errors.AnyStrMinLengthError(limit_value=min_length) + + max_length = field.type_.max_length if field.type_.max_length is not None else config.max_anystr_length + if max_length is not None and v_len > max_length: + raise errors.AnyStrMaxLengthError(limit_value=max_length) + + return v + + +def constr_strip_whitespace(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + strip_whitespace = field.type_.strip_whitespace or config.anystr_strip_whitespace + if strip_whitespace: + v = v.strip() + + return v + + +def constr_upper(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + upper = field.type_.to_upper or config.anystr_upper + if upper: + v = v.upper() + + return v + + +def constr_lower(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes': + lower = field.type_.to_lower or config.anystr_lower + if lower: + v = v.lower() + return v + + +def validate_json(v: Any, config: 'BaseConfig') -> Any: + if v is None: + # pass None through to other validators + return v + try: + return config.json_loads(v) # type: ignore + except ValueError: + raise errors.JsonError() + except TypeError: + raise errors.JsonTypeError() + + +T = TypeVar('T') + + +def make_arbitrary_type_validator(type_: Type[T]) -> Callable[[T], T]: + def arbitrary_type_validator(v: Any) -> T: + if isinstance(v, type_): + return v + raise errors.ArbitraryTypeError(expected_arbitrary_type=type_) + + return arbitrary_type_validator + + +def make_class_validator(type_: Type[T]) -> Callable[[Any], Type[T]]: + def class_validator(v: Any) -> Type[T]: + if lenient_issubclass(v, type_): + return v + raise errors.SubclassError(expected_class=type_) + + return class_validator + + +def any_class_validator(v: Any) -> Type[T]: + if isinstance(v, type): + return v + raise errors.ClassError() + + +def none_validator(v: Any) -> 'Literal[None]': + if v is None: + return v + raise errors.NotNoneError() + + +def pattern_validator(v: Any) -> Pattern[str]: + if isinstance(v, Pattern): + return v + + str_value = str_validator(v) + + try: + return re.compile(str_value) + except re.error: + raise errors.PatternError() + + +NamedTupleT = TypeVar('NamedTupleT', bound=NamedTuple) + + +def make_namedtuple_validator( + namedtuple_cls: Type[NamedTupleT], config: Type['BaseConfig'] +) -> Callable[[Tuple[Any, ...]], NamedTupleT]: + from pydantic.v1.annotated_types import create_model_from_namedtuple + + NamedTupleModel = create_model_from_namedtuple( + namedtuple_cls, + __config__=config, + __module__=namedtuple_cls.__module__, + ) + namedtuple_cls.__pydantic_model__ = NamedTupleModel # type: ignore[attr-defined] + + def namedtuple_validator(values: Tuple[Any, ...]) -> NamedTupleT: + annotations = NamedTupleModel.__annotations__ + + if len(values) > len(annotations): + raise errors.ListMaxLengthError(limit_value=len(annotations)) + + dict_values: Dict[str, Any] = dict(zip(annotations, values)) + validated_dict_values: Dict[str, Any] = dict(NamedTupleModel(**dict_values)) + return namedtuple_cls(**validated_dict_values) + + return namedtuple_validator + + +def make_typeddict_validator( + typeddict_cls: Type['TypedDict'], config: Type['BaseConfig'] # type: ignore[valid-type] +) -> Callable[[Any], Dict[str, Any]]: + from pydantic.v1.annotated_types import create_model_from_typeddict + + TypedDictModel = create_model_from_typeddict( + typeddict_cls, + __config__=config, + __module__=typeddict_cls.__module__, + ) + typeddict_cls.__pydantic_model__ = TypedDictModel # type: ignore[attr-defined] + + def typeddict_validator(values: 'TypedDict') -> Dict[str, Any]: # type: ignore[valid-type] + return TypedDictModel.parse_obj(values).dict(exclude_unset=True) + + return typeddict_validator + + +class IfConfig: + def __init__(self, validator: AnyCallable, *config_attr_names: str, ignored_value: Any = False) -> None: + self.validator = validator + self.config_attr_names = config_attr_names + self.ignored_value = ignored_value + + def check(self, config: Type['BaseConfig']) -> bool: + return any(getattr(config, name) not in {None, self.ignored_value} for name in self.config_attr_names) + + +# order is important here, for example: bool is a subclass of int so has to come first, datetime before date same, +# IPv4Interface before IPv4Address, etc +_VALIDATORS: List[Tuple[Type[Any], List[Any]]] = [ + (IntEnum, [int_validator, enum_member_validator]), + (Enum, [enum_member_validator]), + ( + str, + [ + str_validator, + IfConfig(anystr_strip_whitespace, 'anystr_strip_whitespace'), + IfConfig(anystr_upper, 'anystr_upper'), + IfConfig(anystr_lower, 'anystr_lower'), + IfConfig(anystr_length_validator, 'min_anystr_length', 'max_anystr_length'), + ], + ), + ( + bytes, + [ + bytes_validator, + IfConfig(anystr_strip_whitespace, 'anystr_strip_whitespace'), + IfConfig(anystr_upper, 'anystr_upper'), + IfConfig(anystr_lower, 'anystr_lower'), + IfConfig(anystr_length_validator, 'min_anystr_length', 'max_anystr_length'), + ], + ), + (bool, [bool_validator]), + (int, [int_validator]), + (float, [float_validator, IfConfig(float_finite_validator, 'allow_inf_nan', ignored_value=True)]), + (Path, [path_validator]), + (datetime, [parse_datetime]), + (date, [parse_date]), + (time, [parse_time]), + (timedelta, [parse_duration]), + (OrderedDict, [ordered_dict_validator]), + (dict, [dict_validator]), + (list, [list_validator]), + (tuple, [tuple_validator]), + (set, [set_validator]), + (frozenset, [frozenset_validator]), + (deque, [deque_validator]), + (UUID, [uuid_validator]), + (Decimal, [decimal_validator]), + (IPv4Interface, [ip_v4_interface_validator]), + (IPv6Interface, [ip_v6_interface_validator]), + (IPv4Address, [ip_v4_address_validator]), + (IPv6Address, [ip_v6_address_validator]), + (IPv4Network, [ip_v4_network_validator]), + (IPv6Network, [ip_v6_network_validator]), +] + + +def find_validators( # noqa: C901 (ignore complexity) + type_: Type[Any], config: Type['BaseConfig'] +) -> Generator[AnyCallable, None, None]: + from pydantic.v1.dataclasses import is_builtin_dataclass, make_dataclass_validator + + if type_ is Any or type_ is object: + return + type_type = type_.__class__ + if type_type == ForwardRef or type_type == TypeVar: + return + + if is_none_type(type_): + yield none_validator + return + if type_ is Pattern or type_ is re.Pattern: + yield pattern_validator + return + if type_ is Hashable or type_ is CollectionsHashable: + yield hashable_validator + return + if is_callable_type(type_): + yield callable_validator + return + if is_literal_type(type_): + yield make_literal_validator(type_) + return + if is_builtin_dataclass(type_): + yield from make_dataclass_validator(type_, config) + return + if type_ is Enum: + yield enum_validator + return + if type_ is IntEnum: + yield int_enum_validator + return + if is_namedtuple(type_): + yield tuple_validator + yield make_namedtuple_validator(type_, config) + return + if is_typeddict(type_): + yield make_typeddict_validator(type_, config) + return + + class_ = get_class(type_) + if class_ is not None: + if class_ is not Any and isinstance(class_, type): + yield make_class_validator(class_) + else: + yield any_class_validator + return + + for val_type, validators in _VALIDATORS: + try: + if issubclass(type_, val_type): + for v in validators: + if isinstance(v, IfConfig): + if v.check(config): + yield v.validator + else: + yield v + return + except TypeError: + raise RuntimeError(f'error checking inheritance of {type_!r} (type: {display_as_type(type_)})') + + if config.arbitrary_types_allowed: + yield make_arbitrary_type_validator(type_) + else: + if hasattr(type_, '__pydantic_core_schema__'): + warn(f'Mixing V1 and V2 models is not supported. `{type_.__name__}` is a V2 model.', UserWarning) + raise RuntimeError(f'no validator found for {type_}, see `arbitrary_types_allowed` in Config') diff --git a/source/target-vendors/cp312/pydantic/v1/version.py b/source/target-vendors/cp312/pydantic/v1/version.py new file mode 100644 index 0000000..6ba1cb0 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/v1/version.py @@ -0,0 +1,38 @@ +__all__ = 'compiled', 'VERSION', 'version_info' + +VERSION = '1.10.26' + +try: + import cython # type: ignore +except ImportError: + compiled: bool = False +else: # pragma: no cover + try: + compiled = cython.compiled + except AttributeError: + compiled = False + + +def version_info() -> str: + import platform + import sys + from importlib import import_module + from pathlib import Path + + optional_deps = [] + for p in ('devtools', 'dotenv', 'email-validator', 'typing-extensions'): + try: + import_module(p.replace('-', '_')) + except ImportError: + continue + optional_deps.append(p) + + info = { + 'pydantic version': VERSION, + 'pydantic compiled': compiled, + 'install path': Path(__file__).resolve().parent, + 'python version': sys.version, + 'platform': platform.platform(), + 'optional deps. installed': optional_deps, + } + return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items()) diff --git a/source/target-vendors/cp312/pydantic/validate_call_decorator.py b/source/target-vendors/cp312/pydantic/validate_call_decorator.py new file mode 100644 index 0000000..4bc8991 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/validate_call_decorator.py @@ -0,0 +1,116 @@ +"""Decorator for validating function calls.""" + +from __future__ import annotations as _annotations + +import inspect +from functools import partial +from types import BuiltinFunctionType +from typing import TYPE_CHECKING, Any, Callable, TypeVar, cast, overload + +from ._internal import _generate_schema, _typing_extra, _validate_call +from .errors import PydanticUserError + +__all__ = ('validate_call',) + +if TYPE_CHECKING: + from .config import ConfigDict + + AnyCallableT = TypeVar('AnyCallableT', bound=Callable[..., Any]) + + +_INVALID_TYPE_ERROR_CODE = 'validate-call-type' + + +def _check_function_type(function: object) -> None: + """Check if the input function is a supported type for `validate_call`.""" + if isinstance(function, _generate_schema.VALIDATE_CALL_SUPPORTED_TYPES): + try: + _typing_extra.signature_no_eval(cast(_generate_schema.ValidateCallSupportedTypes, function)) + except (ValueError, TypeError): + raise PydanticUserError( + f"Input function `{function}` doesn't have a valid signature", code=_INVALID_TYPE_ERROR_CODE + ) + + if isinstance(function, partial): + try: + assert not isinstance(partial.func, partial), 'Partial of partial' + _check_function_type(function.func) + except PydanticUserError as e: + raise PydanticUserError( + f'Partial of `{function.func}` is invalid because the type of `{function.func}` is not supported by `validate_call`', + code=_INVALID_TYPE_ERROR_CODE, + ) from e + + return + + if isinstance(function, BuiltinFunctionType): + raise PydanticUserError(f'Input built-in function `{function}` is not supported', code=_INVALID_TYPE_ERROR_CODE) + if isinstance(function, (classmethod, staticmethod, property)): + name = type(function).__name__ + raise PydanticUserError( + f'The `@{name}` decorator should be applied after `@validate_call` (put `@{name}` on top)', + code=_INVALID_TYPE_ERROR_CODE, + ) + + if inspect.isclass(function): + raise PydanticUserError( + f'Unable to validate {function}: `validate_call` should be applied to functions, not classes (put `@validate_call` on top of `__init__` or `__new__` instead)', + code=_INVALID_TYPE_ERROR_CODE, + ) + if callable(function): + raise PydanticUserError( + f'Unable to validate {function}: `validate_call` should be applied to functions, not instances or other callables. Use `validate_call` explicitly on `__call__` instead.', + code=_INVALID_TYPE_ERROR_CODE, + ) + + raise PydanticUserError( + f'Unable to validate {function}: `validate_call` should be applied to one of the following: function, method, partial, or lambda', + code=_INVALID_TYPE_ERROR_CODE, + ) + + +@overload +def validate_call( + *, config: ConfigDict | None = None, validate_return: bool = False +) -> Callable[[AnyCallableT], AnyCallableT]: ... + + +@overload +def validate_call(func: AnyCallableT, /) -> AnyCallableT: ... + + +def validate_call( + func: AnyCallableT | None = None, + /, + *, + config: ConfigDict | None = None, + validate_return: bool = False, +) -> AnyCallableT | Callable[[AnyCallableT], AnyCallableT]: + """!!! abstract "Usage Documentation" + [Validation Decorator](../concepts/validation_decorator.md) + + Returns a decorated wrapper around the function that validates the arguments and, optionally, the return value. + + Usage may be either as a plain decorator `@validate_call` or with arguments `@validate_call(...)`. + + Args: + func: The function to be decorated. + config: The configuration dictionary. + validate_return: Whether to validate the return value. + + Returns: + The decorated function. + """ + parent_namespace = _typing_extra.parent_frame_namespace() + + def validate(function: AnyCallableT) -> AnyCallableT: + _check_function_type(function) + validate_call_wrapper = _validate_call.ValidateCallWrapper( + cast(_generate_schema.ValidateCallSupportedTypes, function), config, validate_return, parent_namespace + ) + return _validate_call.update_wrapper_attributes(function, validate_call_wrapper.__call__) # type: ignore + + if func is not None: + return validate(func) + else: + return validate diff --git a/source/target-vendors/cp312/pydantic/validators.py b/source/target-vendors/cp312/pydantic/validators.py new file mode 100644 index 0000000..7921b04 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/validators.py @@ -0,0 +1,5 @@ +"""The `validators` module is a backport module from V1.""" + +from ._migration import getattr_migration + +__getattr__ = getattr_migration(__name__) diff --git a/source/target-vendors/cp312/pydantic/version.py b/source/target-vendors/cp312/pydantic/version.py new file mode 100644 index 0000000..560f34a --- /dev/null +++ b/source/target-vendors/cp312/pydantic/version.py @@ -0,0 +1,113 @@ +"""The `version` module holds the version information for Pydantic.""" + +from __future__ import annotations as _annotations + +import sys + +from pydantic_core import __version__ as __pydantic_core_version__ + +__all__ = 'VERSION', 'version_info' + +VERSION = '2.13.5' +"""The version of Pydantic. + +This version specifier is guaranteed to be compliant with the [specification], +introduced by [PEP 440]. + +[specification]: https://packaging.python.org/en/latest/specifications/version-specifiers/ +[PEP 440]: https://peps.python.org/pep-0440/ +""" + +# Keep this in sync with the version constraint in the `pyproject.toml` dependencies: +_COMPATIBLE_PYDANTIC_CORE_VERSION = '2.46.5' + + +def version_short() -> str: + """Return the `major.minor` part of Pydantic version. + + It returns '2.1' if Pydantic version is '2.1.1'. + """ + return '.'.join(VERSION.split('.')[:2]) + + +def version_info() -> str: + """Return complete version information for Pydantic and its dependencies.""" + import importlib.metadata + import platform + from pathlib import Path + + import pydantic_core._pydantic_core as pdc + + from ._internal import _git as git + + # get data about packages that are closely related to pydantic, use pydantic or often conflict with pydantic + package_names = { + 'email-validator', + 'fastapi', + 'mypy', + 'pydantic-extra-types', + 'pydantic-settings', + 'pyright', + 'typing_extensions', + } + related_packages = [] + + for dist in importlib.metadata.distributions(): + name = dist.metadata['Name'] + if name in package_names: + related_packages.append(f'{name}-{dist.version}') + + pydantic_dir = Path(__file__).parents[1].resolve() + most_recent_commit = ( + git.git_revision(pydantic_dir) if git.is_git_repo(pydantic_dir) and git.have_git() else 'unknown' + ) + + info = { + 'pydantic version': VERSION, + 'pydantic-core version': __pydantic_core_version__, + 'pydantic-core build': getattr(pdc, 'build_info', None) or pdc.build_profile, # pyright: ignore[reportPrivateImportUsage] + 'python version': sys.version, + 'platform': platform.platform(), + 'related packages': ' '.join(related_packages), + 'commit': most_recent_commit, + } + return '\n'.join('{:>30} {}'.format(k + ':', str(v).replace('\n', ' ')) for k, v in info.items()) + + +def check_pydantic_core_version() -> bool: + """Check that the installed `pydantic-core` dependency is compatible.""" + return __pydantic_core_version__ == _COMPATIBLE_PYDANTIC_CORE_VERSION + + +def _ensure_pydantic_core_version() -> None: # pragma: no cover + if not check_pydantic_core_version(): + raise_error = True + # Do not raise the error if pydantic is installed in editable mode (i.e. in development): + if sys.version_info >= (3, 13): # origin property added in 3.13 + from importlib.metadata import distribution + + dist = distribution('pydantic') + if getattr(getattr(dist.origin, 'dir_info', None), 'editable', False): + raise_error = False + + if raise_error: + raise SystemError( + f'The installed pydantic-core version ({__pydantic_core_version__}) is incompatible ' + f'with the current pydantic version, which requires {_COMPATIBLE_PYDANTIC_CORE_VERSION}. ' + "If you encounter this error, make sure that you haven't upgraded pydantic-core manually." + ) + + +def parse_mypy_version(version: str) -> tuple[int, int, int]: + """Parse `mypy` string version to a 3-tuple of ints. + + It parses normal version like `1.11.0` and extra info followed by a `+` sign + like `1.11.0+dev.d6d9d8cd4f27c52edac1f537e236ec48a01e54cb.dirty`. + + Args: + version: The mypy version string. + + Returns: + A triple of ints, e.g. `(1, 11, 0)`. + """ + return tuple(map(int, version.partition('+')[0].split('.'))) # pyright: ignore[reportReturnType] diff --git a/source/target-vendors/cp312/pydantic/warnings.py b/source/target-vendors/cp312/pydantic/warnings.py new file mode 100644 index 0000000..02323b8 --- /dev/null +++ b/source/target-vendors/cp312/pydantic/warnings.py @@ -0,0 +1,122 @@ +"""Pydantic-specific warnings.""" + +from __future__ import annotations as _annotations + +from .version import version_short + +__all__ = ( + 'PydanticDeprecatedSince20', + 'PydanticDeprecatedSince26', + 'PydanticDeprecatedSince29', + 'PydanticDeprecatedSince210', + 'PydanticDeprecatedSince211', + 'PydanticDeprecatedSince212', + 'PydanticDeprecationWarning', + 'PydanticExperimentalWarning', + 'ArbitraryTypeWarning', + 'UnsupportedFieldAttributeWarning', + 'TypedDictExtraConfigWarning', +) + + +class PydanticDeprecationWarning(DeprecationWarning): + """A Pydantic specific deprecation warning. + + This warning is raised when using deprecated functionality in Pydantic. It provides information on when the + deprecation was introduced and the expected version in which the corresponding functionality will be removed. + + Attributes: + message: Description of the warning. + since: Pydantic version in what the deprecation was introduced. + expected_removal: Pydantic version in what the corresponding functionality expected to be removed. + """ + + message: str + since: tuple[int, int] + expected_removal: tuple[int, int] + + def __init__( + self, message: str, *args: object, since: tuple[int, int], expected_removal: tuple[int, int] | None = None + ) -> None: + super().__init__(message, *args) + self.message = message.rstrip('.') + self.since = since + self.expected_removal = expected_removal if expected_removal is not None else (since[0] + 1, 0) + + def __str__(self) -> str: + message = ( + f'{self.message}. Deprecated in Pydantic V{self.since[0]}.{self.since[1]}' + f' to be removed in V{self.expected_removal[0]}.{self.expected_removal[1]}.' + ) + if self.since == (2, 0): + message += f' See Pydantic V2 Migration Guide at https://errors.pydantic.dev/{version_short()}/migration/' + return message + + +class PydanticDeprecatedSince20(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.0.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 0), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince26(PydanticDeprecationWarning): # pragma: no cover + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.6.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 6), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince29(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.9.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 9), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince210(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.10.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 10), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince211(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.11.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 11), expected_removal=(3, 0)) + + +class PydanticDeprecatedSince212(PydanticDeprecationWarning): + """A specific `PydanticDeprecationWarning` subclass defining functionality deprecated since Pydantic 2.12.""" + + def __init__(self, message: str, *args: object) -> None: + super().__init__(message, *args, since=(2, 12), expected_removal=(3, 0)) + + +class GenericBeforeBaseModelWarning(Warning): + pass + + +class PydanticExperimentalWarning(Warning): + """A Pydantic specific experimental functionality warning. + + It is raised to warn users that the functionality may change or be removed in future versions of Pydantic. + """ + + +class CoreSchemaGenerationWarning(UserWarning): + """A warning raised during core schema generation.""" + + +class ArbitraryTypeWarning(CoreSchemaGenerationWarning): + """A warning raised when Pydantic fails to generate a core schema for an arbitrary type.""" + + +class UnsupportedFieldAttributeWarning(CoreSchemaGenerationWarning): + """A warning raised when a `Field()` attribute isn't supported in the context it is used.""" + + +class TypedDictExtraConfigWarning(CoreSchemaGenerationWarning): + """A warning raised when the [`extra`][pydantic.ConfigDict.extra] configuration is incompatible with the `closed` or `extra_items` specification.""" diff --git a/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/METADATA b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/METADATA new file mode 100644 index 0000000..d3f72db --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/METADATA @@ -0,0 +1,173 @@ +Metadata-Version: 2.4 +Name: pydantic_core +Version: 2.46.5 +Classifier: Development Status :: 3 - Alpha +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Implementation :: GraalPy +Classifier: Programming Language :: Rust +Classifier: Framework :: Pydantic +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS +Classifier: Typing :: Typed +Requires-Dist: typing-extensions>=4.14.1 +License-File: LICENSE +Summary: Core functionality for Pydantic validation and serialization +Home-Page: https://github.com/pydantic/pydantic +Author-email: Samuel Colvin , Adrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>, David Montague , David Hewitt , Sydney Runkle , Victorien Plot +License-Expression: MIT +Requires-Python: >=3.9 +Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM +Project-URL: Funding, https://github.com/sponsors/samuelcolvin +Project-URL: Homepage, https://github.com/pydantic +Project-URL: Source, https://github.com/pydantic/pydantic/tree/main/pydantic-core + +# pydantic-core + +[![CI](https://github.com/pydantic/pydantic-core/workflows/ci/badge.svg?event=push)](https://github.com/pydantic/pydantic-core/actions?query=event%3Apush+branch%3Amain+workflow%3Aci) +[![Coverage](https://codecov.io/gh/pydantic/pydantic-core/branch/main/graph/badge.svg)](https://codecov.io/gh/pydantic/pydantic-core) +[![pypi](https://img.shields.io/pypi/v/pydantic-core.svg)](https://pypi.python.org/pypi/pydantic-core) +[![versions](https://img.shields.io/pypi/pyversions/pydantic-core.svg)](https://github.com/pydantic/pydantic-core) +[![license](https://img.shields.io/github/license/pydantic/pydantic-core.svg)](https://github.com/pydantic/pydantic-core/blob/main/LICENSE) + +This package provides the core functionality for [pydantic](https://docs.pydantic.dev) validation and serialization. + +Pydantic-core is currently around 17x faster than pydantic V1. +See [`tests/benchmarks/`](./tests/benchmarks/) for details. + +## Example of direct usage + +*NOTE: You should not need to use pydantic-core directly; instead, use pydantic, which in turn uses pydantic-core.* + +```py +from pydantic_core import SchemaValidator, ValidationError + + +v = SchemaValidator( + { + 'type': 'typed-dict', + 'fields': { + 'name': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'str', + }, + }, + 'age': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'int', + 'ge': 18, + }, + }, + 'is_developer': { + 'type': 'typed-dict-field', + 'schema': { + 'type': 'default', + 'schema': {'type': 'bool'}, + 'default': True, + }, + }, + }, + } +) + +r1 = v.validate_python({'name': 'Samuel', 'age': 35}) +assert r1 == {'name': 'Samuel', 'age': 35, 'is_developer': True} + +# pydantic-core can also validate JSON directly +r2 = v.validate_json('{"name": "Samuel", "age": 35}') +assert r1 == r2 + +try: + v.validate_python({'name': 'Samuel', 'age': 11}) +except ValidationError as e: + print(e) + """ + 1 validation error for model + age + Input should be greater than or equal to 18 + [type=greater_than_equal, context={ge: 18}, input_value=11, input_type=int] + """ +``` + +## Getting Started + +### Prerequisites + +You'll need: + +1. **[Rust](https://rustup.rs/)** - Rust stable (or nightly for coverage) +2. **[uv](https://docs.astral.sh/uv/getting-started/installation/)** - Fast Python package manager (will install Python 3.9+ automatically) +3. **[git](https://git-scm.com/)** - For version control +4. **[make](https://www.gnu.org/software/make/)** - For running development commands (or use `nmake` on Windows) + +### Quick Start + +```bash +# Clone the repository (or from your fork) +git clone git@github.com:pydantic/pydantic-core.git +cd pydantic-core + +# Install all dependencies using uv, setup pre-commit hooks, and build the development version +make install +``` + +Verify your installation by running: + +```bash +make +``` + +This runs a full development cycle: formatting, building, linting, and testing + +### Development Commands + +Run `make help` to see all available commands, or use these common ones: + +```bash +make build-dev # to build the package during development +make build-prod # to perform an optimised build for benchmarking +make test # to run the tests +make testcov # to run the tests and generate a coverage report +make lint # to run the linter +make format # to format python and rust code +make all # to run to run build-dev + format + lint + test +``` + +### Useful Resources + +* [`python/pydantic_core/_pydantic_core.pyi`](./python/pydantic_core/_pydantic_core.pyi) - Python API types +* [`python/pydantic_core/core_schema.py`](./python/pydantic_core/core_schema.py) - Core schema definitions +* [`tests/`](./tests) - Comprehensive usage examples + +## Profiling + +It's possible to profile the code using the [`flamegraph` utility from `flamegraph-rs`](https://github.com/flamegraph-rs/flamegraph). (Tested on Linux.) You can install this with `cargo install flamegraph`. + +Run `make build-profiling` to install a release build with debugging symbols included (needed for profiling). + +Once that is built, you can profile pytest benchmarks with (e.g.): + +```bash +flamegraph -- pytest tests/benchmarks/test_micro_benchmarks.py -k test_list_of_ints_core_py --benchmark-enable +``` + +The `flamegraph` command will produce an interactive SVG at `flamegraph.svg`. + +## Releasing + +TBC (needs to be integrated into `pydantic` repository release process). + diff --git a/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/RECORD b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/RECORD new file mode 100644 index 0000000..4197d83 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/RECORD @@ -0,0 +1,10 @@ +pydantic_core/__init__.py,sha256=nK1ikrdSVK9gapcKrpv_blrp8LCAic1jrK-jkbYHlNI,5115 +pydantic_core/_pydantic_core.cpython-312-x86_64-linux-gnu.so,sha256=lfaO8lNaUQKgNELgc9SQbAEhGyCJAvVuJOwjzqQCtaA,4692312 +pydantic_core/_pydantic_core.pyi,sha256=H_lG8iKiv3Bpfd3rixY7xzs67gE-s0eiAqJaSbnF8Ss,45932 +pydantic_core/core_schema.py,sha256=1PM31yf_kGpm_H7GLnNFRkIPAQGPL9zh6rf2SxohVxg,155574 +pydantic_core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic_core-2.46.5.dist-info/METADATA,sha256=KXaMA4wLs1ZMCofvUO940YojckdL3vC6NWqMD9S9YCg,6573 +pydantic_core-2.46.5.dist-info/WHEEL,sha256=cdZhYY2bcH9hrDcqDVEEdpL0M5tjmmAr-lwUq15CEdY,147 +pydantic_core-2.46.5.dist-info/licenses/LICENSE,sha256=Kv3TDVS01itvSIprzBVG6E7FBh8T9CCcA9ASNIeDeVo,1080 +pydantic_core-2.46.5.dist-info/sboms/pydantic-core.cyclonedx.json,sha256=T0DHkPDLOEp5NmMzGQQRepFKUO8iCxEsOZ138UY-PdU,125376 +pydantic_core-2.46.5.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/WHEEL b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/WHEEL new file mode 100644 index 0000000..8cb0d6d --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: maturin (1.15.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 diff --git a/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/licenses/LICENSE b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/licenses/LICENSE new file mode 100644 index 0000000..0716871 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Samuel Colvin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/sboms/pydantic-core.cyclonedx.json b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/sboms/pydantic-core.cyclonedx.json new file mode 100644 index 0000000..33f43e2 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core-2.46.5.dist-info/sboms/pydantic-core.cyclonedx.json @@ -0,0 +1,3961 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "version": 1, + "serialNumber": "urn:uuid:ebbad0c8-2245-43ff-8954-129abd5895b6", + "metadata": { + "timestamp": "2026-08-28T09:11:36.556516169Z", + "tools": [ + { + "vendor": "CycloneDX", + "name": "cargo-cyclonedx", + "version": "0.5.9" + } + ], + "component": { + "type": "library", + "bom-ref": "path+file:///home/runner/work/pydantic/pydantic/pydantic-core#2.46.5", + "name": "pydantic-core", + "version": "2.46.5", + "scope": "required", + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/pydantic-core@2.46.5?download_url=file://.", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pydantic/pydantic" + }, + { + "type": "vcs", + "url": "https://github.com/pydantic/pydantic.git" + } + ], + "components": [ + { + "type": "library", + "bom-ref": "path+file:///home/runner/work/pydantic/pydantic/pydantic-core#2.46.5 bin-target-0", + "name": "_pydantic_core", + "version": "2.46.5", + "purl": "pkg:cargo/pydantic-core@2.46.5?download_url=file://.#src/lib.rs" + } + ] + }, + "properties": [ + { + "name": "cdx:rustc:sbom:target:all_targets", + "value": "true" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#ahash@0.8.12", + "author": "Tom Kaitchuck ", + "name": "ahash", + "version": "0.8.12", + "description": "A non-cryptographic hash function using AES-NI for high performance", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/ahash@0.8.12", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/ahash" + }, + { + "type": "vcs", + "url": "https://github.com/tkaitchuck/ahash" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.3", + "author": "Andrew Gallant ", + "name": "aho-corasick", + "version": "1.1.3", + "description": "Fast multiple substring searching.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" + } + ], + "licenses": [ + { + "expression": "Unlicense OR MIT" + } + ], + "purl": "pkg:cargo/aho-corasick@1.1.3", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/BurntSushi/aho-corasick" + }, + { + "type": "vcs", + "url": "https://github.com/BurntSushi/aho-corasick" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#allocator-api2@0.2.21", + "author": "Zakarum ", + "name": "allocator-api2", + "version": "0.2.21", + "description": "Mirror of Rust's allocator API", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/allocator-api2@0.2.21", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/allocator-api2" + }, + { + "type": "website", + "url": "https://github.com/zakarumych/allocator-api2" + }, + { + "type": "vcs", + "url": "https://github.com/zakarumych/allocator-api2" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.3.0", + "author": "Josh Stone ", + "name": "autocfg", + "version": "1.3.0", + "description": "Automatic cfg for Rust compiler features", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/autocfg@1.3.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/autocfg/" + }, + { + "type": "vcs", + "url": "https://github.com/cuviper/autocfg" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", + "author": "Marshall Pierce ", + "name": "base64", + "version": "0.22.1", + "description": "encodes and decodes base64 as bytes or utf8", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/base64@0.22.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/base64" + }, + { + "type": "vcs", + "url": "https://github.com/marshallpierce/rust-base64" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.9.1", + "author": "The Rust Project Developers", + "name": "bitflags", + "version": "2.9.1", + "description": "A macro to generate structures which behave like bitflags. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/bitflags@2.9.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/bitflags" + }, + { + "type": "website", + "url": "https://github.com/bitflags/bitflags" + }, + { + "type": "vcs", + "url": "https://github.com/bitflags/bitflags" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bitvec@1.0.1", + "name": "bitvec", + "version": "1.0.1", + "description": "Addresses memory by bits, for packed collections and bitfields", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/bitvec@1.0.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/bitvec/latest/bitvec" + }, + { + "type": "website", + "url": "https://bitvecto-rs.github.io/bitvec" + }, + { + "type": "vcs", + "url": "https://github.com/bitvecto-rs/bitvec" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bumpalo@3.19.0", + "author": "Nick Fitzgerald ", + "name": "bumpalo", + "version": "3.19.0", + "description": "A fast bump allocation arena for Rust.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/bumpalo@3.19.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/bumpalo" + }, + { + "type": "vcs", + "url": "https://github.com/fitzgen/bumpalo" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.0.101", + "author": "Alex Crichton ", + "name": "cc", + "version": "1.0.101", + "description": "A build-time dependency for Cargo build scripts to assist in invoking the native C compiler to compile native C code into a static archive to be linked into Rust code. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/cc@1.0.101", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/cc" + }, + { + "type": "website", + "url": "https://github.com/rust-lang/cc-rs" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/cc-rs" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.0", + "author": "Alex Crichton ", + "name": "cfg-if", + "version": "1.0.0", + "description": "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/cfg-if@1.0.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/cfg-if" + }, + { + "type": "website", + "url": "https://github.com/alexcrichton/cfg-if" + }, + { + "type": "vcs", + "url": "https://github.com/alexcrichton/cfg-if" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "author": "Jane Lusby ", + "name": "displaydoc", + "version": "0.2.5", + "description": "A derive macro for implementing the display Trait via a doc comment and string interpolation ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/displaydoc@0.2.5", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/displaydoc" + }, + { + "type": "website", + "url": "https://github.com/yaahc/displaydoc" + }, + { + "type": "vcs", + "url": "https://github.com/yaahc/displaydoc" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#enum_dispatch@0.3.13", + "author": "Anton Lazarev ", + "name": "enum_dispatch", + "version": "0.3.13", + "description": "Near drop-in replacement for dynamic-dispatched method calls with up to 10x the speed", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/enum_dispatch@0.3.13", + "externalReferences": [ + { + "type": "vcs", + "url": "https://gitlab.com/antonok/enum_dispatch" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.2", + "name": "equivalent", + "version": "1.0.2", + "description": "Traits for key comparison in maps.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/equivalent@1.0.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/indexmap-rs/equivalent" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foldhash@0.2.0", + "author": "Orson Peters ", + "name": "foldhash", + "version": "0.2.0", + "description": "A fast, non-cryptographic, minimally DoS-resistant hashing algorithm.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + } + ], + "licenses": [ + { + "expression": "Zlib" + } + ], + "purl": "pkg:cargo/foldhash@0.2.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/orlp/foldhash" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", + "author": "The rust-url developers", + "name": "form_urlencoded", + "version": "1.2.2", + "description": "Parser and serializer for the application/x-www-form-urlencoded syntax, as used by HTML forms.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/form_urlencoded@1.2.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/servo/rust-url" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#funty@2.0.0", + "author": "myrrlyn ", + "name": "funty", + "version": "2.0.0", + "description": "Trait generalization over the primitive types", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/funty@2.0.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/funty" + }, + { + "type": "vcs", + "url": "https://github.com/myrrlyn/funty" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.3", + "author": "The Rand Project Developers", + "name": "getrandom", + "version": "0.3.3", + "description": "A small cross-platform library for retrieving random data from system source", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/getrandom@0.3.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/getrandom" + }, + { + "type": "vcs", + "url": "https://github.com/rust-random/getrandom" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1", + "author": "Amanieu d'Antras ", + "name": "hashbrown", + "version": "0.16.1", + "description": "A Rust port of Google's SwissTable hash map", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/hashbrown@0.16.1", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/rust-lang/hashbrown" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "name": "heck", + "version": "0.5.0", + "description": "heck is a case conversion library.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/heck@0.5.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/withoutboats/heck" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#hex@0.4.3", + "author": "KokaKiwi ", + "name": "hex", + "version": "0.4.3", + "description": "Encoding and decoding data into/from hexadecimal representation.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/hex@0.4.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/hex/" + }, + { + "type": "vcs", + "url": "https://github.com/KokaKiwi/rust-hex" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_collections@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_collections", + "version": "1.5.0", + "description": "Collection of API for use in ICU libraries.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_collections@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locid@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_locid", + "version": "1.5.0", + "description": "API for managing Unicode Language and Locale Identifiers", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_locid@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locid_transform@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_locid_transform", + "version": "1.5.0", + "description": "API for Unicode Language and Locale Identifiers canonicalization", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_locid_transform@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locid_transform_data@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_locid_transform_data", + "version": "1.5.0", + "description": "Data for the icu_locid_transform crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_locid_transform_data@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_normalizer", + "version": "1.5.0", + "description": "API for normalizing text into Unicode Normalization Forms", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_normalizer@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer_data@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_normalizer_data", + "version": "1.5.0", + "description": "Data for the icu_normalizer crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_normalizer_data@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties@1.5.1", + "author": "The ICU4X Project Developers", + "name": "icu_properties", + "version": "1.5.1", + "description": "Definitions for Unicode properties", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_properties@1.5.1", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties_data@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_properties_data", + "version": "1.5.0", + "description": "Data for the icu_properties crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_properties_data@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_provider@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_provider", + "version": "1.5.0", + "description": "Trait and struct definitions for the ICU data provider", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_provider@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#icu_provider_macros@1.5.0", + "author": "The ICU4X Project Developers", + "name": "icu_provider_macros", + "version": "1.5.0", + "description": "Proc macros for ICU data providers", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/icu_provider_macros@1.5.0", + "externalReferences": [ + { + "type": "website", + "url": "https://icu4x.unicode.org" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", + "author": "The rust-url developers", + "name": "idna", + "version": "1.1.0", + "description": "IDNA (Internationalizing Domain Names in Applications) and Punycode.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/idna@1.1.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/servo/rust-url/" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#idna_adapter@1.2.0", + "author": "The rust-url developers", + "name": "idna_adapter", + "version": "1.2.0", + "description": "Back end adapter for idna", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/idna_adapter@1.2.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/idna_adapter/latest/idna_adapter/" + }, + { + "type": "website", + "url": "https://docs.rs/crate/idna_adapter/latest" + }, + { + "type": "vcs", + "url": "https://github.com/hsivonen/idna_adapter" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.11", + "author": "David Tolnay ", + "name": "itoa", + "version": "1.0.11", + "description": "Fast integer primitive to string conversion", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/itoa@1.0.11", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/itoa" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/itoa" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#jiter@0.14.0", + "author": "Samuel Colvin ", + "name": "jiter", + "version": "0.14.0", + "description": "Fast Iterable JSON parser", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "b6f3b5d3f84b36f4ad09fd1da896d23d9852a1aa86556578dd0289f43dce311d" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/jiter@0.14.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pydantic/jiter/" + }, + { + "type": "vcs", + "url": "https://github.com/pydantic/jiter/" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#js-sys@0.3.77", + "author": "The wasm-bindgen Developers", + "name": "js-sys", + "version": "0.3.77", + "description": "Bindings for all JS global objects and functions in all JS environments like Node.js and browsers, built on `#[wasm_bindgen]` using the `wasm-bindgen` crate. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/js-sys@0.3.77", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/js-sys" + }, + { + "type": "website", + "url": "https://rustwasm.github.io/wasm-bindgen/" + }, + { + "type": "vcs", + "url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/js-sys" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-float@1.0.5", + "author": "Alex Huszagh ", + "name": "lexical-parse-float", + "version": "1.0.5", + "description": "Efficient parsing of floats from strings.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "de6f9cb01fb0b08060209a057c048fcbab8717b4c1ecd2eac66ebfe39a65b0f2" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/lexical-parse-float@1.0.5", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/Alexhuszagh/rust-lexical" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-integer@1.0.5", + "author": "Alex Huszagh ", + "name": "lexical-parse-integer", + "version": "1.0.5", + "description": "Efficient parsing of integers from strings.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "72207aae22fc0a121ba7b6d479e42cbfea549af1479c3f3a4f12c70dd66df12e" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/lexical-parse-integer@1.0.5", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/Alexhuszagh/rust-lexical" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lexical-util@1.0.6", + "author": "Alex Huszagh ", + "name": "lexical-util", + "version": "1.0.6", + "description": "Shared utilities for lexical creates.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "5a82e24bf537fd24c177ffbbdc6ebcc8d54732c35b50a3f28cc3f4e4c949a0b3" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/lexical-util@1.0.6", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/Alexhuszagh/rust-lexical" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.185", + "author": "The Rust Project Developers", + "name": "libc", + "version": "0.2.185", + "description": "Raw FFI bindings to platform libraries like libc.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/libc@0.2.185", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/rust-lang/libc" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#litemap@0.7.3", + "author": "The ICU4X Project Developers", + "name": "litemap", + "version": "0.7.3", + "description": "A key-value Map implementation based on a flat, sorted Vec.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/litemap@0.7.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/litemap" + }, + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#log@0.4.27", + "author": "The Rust Project Developers", + "name": "log", + "version": "0.4.27", + "description": "A lightweight logging facade for Rust ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/log@0.4.27", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/log" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/log" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#lru@0.16.3", + "author": "Jerome Froelich ", + "name": "lru", + "version": "0.16.3", + "description": "A LRU cache implementation", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/lru@0.16.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/lru/" + }, + { + "type": "website", + "url": "https://github.com/jeromefroe/lru-rs" + }, + { + "type": "vcs", + "url": "https://github.com/jeromefroe/lru-rs.git" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.4", + "author": "Andrew Gallant , bluss", + "name": "memchr", + "version": "2.7.4", + "description": "Provides extremely fast (uses SIMD on x86_64, aarch64 and wasm32) routines for 1, 2 or 3 byte search and single substring search. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + } + ], + "licenses": [ + { + "expression": "Unlicense OR MIT" + } + ], + "purl": "pkg:cargo/memchr@2.7.4", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/memchr/" + }, + { + "type": "website", + "url": "https://github.com/BurntSushi/memchr" + }, + { + "type": "vcs", + "url": "https://github.com/BurntSushi/memchr" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", + "author": "The Rust Project Developers", + "name": "num-bigint", + "version": "0.4.6", + "description": "Big integer implementation for Rust", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/num-bigint@0.4.6", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/num-bigint" + }, + { + "type": "website", + "url": "https://github.com/rust-num/num-bigint" + }, + { + "type": "vcs", + "url": "https://github.com/rust-num/num-bigint" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", + "author": "The Rust Project Developers", + "name": "num-integer", + "version": "0.1.46", + "description": "Integer traits and functions", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/num-integer@0.1.46", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/num-integer" + }, + { + "type": "website", + "url": "https://github.com/rust-num/num-integer" + }, + { + "type": "vcs", + "url": "https://github.com/rust-num/num-integer" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", + "author": "The Rust Project Developers", + "name": "num-traits", + "version": "0.2.19", + "description": "Numeric traits for generic mathematics", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/num-traits@0.2.19", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/num-traits" + }, + { + "type": "website", + "url": "https://github.com/rust-num/num-traits" + }, + { + "type": "vcs", + "url": "https://github.com/rust-num/num-traits" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "author": "Aleksey Kladov ", + "name": "once_cell", + "version": "1.21.3", + "description": "Single assignment cells and lazy values.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/once_cell@1.21.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/once_cell" + }, + { + "type": "vcs", + "url": "https://github.com/matklad/once_cell" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", + "author": "The rust-url developers", + "name": "percent-encoding", + "version": "2.3.2", + "description": "Percent encoding and decoding", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/percent-encoding@2.3.2", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/servo/rust-url/" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.6.0", + "name": "portable-atomic", + "version": "1.6.0", + "description": "Portable atomic types including support for 128-bit atomics, atomic float, etc. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/portable-atomic@1.6.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/taiki-e/portable-atomic" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "author": "David Tolnay , Alex Crichton ", + "name": "proc-macro2", + "version": "1.0.86", + "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/proc-macro2@1.0.86", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/proc-macro2" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/proc-macro2" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-build-config", + "version": "0.28.3", + "description": "Build configuration for the PyO3 ecosystem", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "e368e7ddfdeb98c9bca7f8383be1648fd84ab466bf2bc015e94008db6d35611e" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-build-config@0.28.3", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.28.3", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-ffi", + "version": "0.28.3", + "description": "Python-API bindings for the PyO3 ecosystem", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "7f29e10af80b1f7ccaf7f69eace800a03ecd13e883acfacc1e5d0988605f651e" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-ffi@0.28.3", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "other", + "url": "python" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.28.3", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-macros-backend", + "version": "0.28.3", + "description": "Code generation for PyO3 package", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "c4cdc218d835738f81c2338f822078af45b4afdf8b2e33cbb5916f108b813acb" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-macros-backend@0.28.3", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.28.3", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-macros", + "version": "0.28.3", + "description": "Proc macros for PyO3 package", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "df6e520eff47c45997d2fc7dd8214b25dd1310918bbb2642156ef66a67f29813" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-macros@0.28.3", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", + "author": "PyO3 Project and Contributors ", + "name": "pyo3", + "version": "0.28.3", + "description": "Bindings to Python interpreter", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "91fd8e38a3b50ed1167fb981cd6fd60147e091784c427b8f7183a7ee32c31c12" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3@0.28.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/crate/pyo3/" + }, + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#python3-dll-a@0.2.14", + "author": "Sergey Kvachonok , messense , Adam Reichold ", + "name": "python3-dll-a", + "version": "0.2.14", + "description": "Standalone python3(y)(t).dll import library generator", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "d381ef313ae70b4da5f95f8a4de773c6aa5cd28f73adec4b4a31df70b66780d8" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/python3-dll-a@0.2.14", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/PyO3/python3-dll-a" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "author": "David Tolnay ", + "name": "quote", + "version": "1.0.44", + "description": "Quasi-quoting macro quote!(...)", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/quote@1.0.44", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/quote/" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/quote" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#r-efi@5.2.0", + "name": "r-efi", + "version": "5.2.0", + "description": "UEFI Reference Specification Protocol Constants and Definitions", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0 OR LGPL-2.1-or-later" + } + ], + "purl": "pkg:cargo/r-efi@5.2.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/r-efi/r-efi/wiki" + }, + { + "type": "vcs", + "url": "https://github.com/r-efi/r-efi" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#radium@0.7.0", + "author": "Nika Layzell , myrrlyn ", + "name": "radium", + "version": "0.7.0", + "description": "Portable interfaces for maybe-atomic types", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/radium@0.7.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/radium" + }, + { + "type": "website", + "url": "https://github.com/bitvecto-rs/radium" + }, + { + "type": "vcs", + "url": "https://github.com/bitvecto-rs/radium" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.13", + "author": "The Rust Project Developers, Andrew Gallant ", + "name": "regex-automata", + "version": "0.4.13", + "description": "Automata construction and matching using regular expressions.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/regex-automata@0.4.13", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/regex-automata" + }, + { + "type": "website", + "url": "https://github.com/rust-lang/regex/tree/master/regex-automata" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/regex" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.5", + "author": "The Rust Project Developers, Andrew Gallant ", + "name": "regex-syntax", + "version": "0.8.5", + "description": "A regular expression parser.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/regex-syntax@0.8.5", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/regex-syntax" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/regex/tree/master/regex-syntax" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", + "author": "The Rust Project Developers, Andrew Gallant ", + "name": "regex", + "version": "1.12.3", + "description": "An implementation of regular expressions for Rust. This implementation uses finite automata and guarantees linear time matching on all inputs. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/regex@1.12.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/regex" + }, + { + "type": "website", + "url": "https://github.com/rust-lang/regex" + }, + { + "type": "vcs", + "url": "https://github.com/rust-lang/regex" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rustversion@1.0.17", + "author": "David Tolnay ", + "name": "rustversion", + "version": "1.0.17", + "description": "Conditional compilation according to rustc compiler version", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/rustversion@1.0.17", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/rustversion" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/rustversion" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", + "author": "Erick Tryzelaar , David Tolnay ", + "name": "serde", + "version": "1.0.228", + "description": "A generic serialization/deserialization framework", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/serde@1.0.228", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/serde" + }, + { + "type": "website", + "url": "https://serde.rs" + }, + { + "type": "vcs", + "url": "https://github.com/serde-rs/serde" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", + "author": "Erick Tryzelaar , David Tolnay ", + "name": "serde_core", + "version": "1.0.228", + "description": "Serde traits only, with no support for derive -- use the `serde` crate instead", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/serde_core@1.0.228", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/serde_core" + }, + { + "type": "website", + "url": "https://serde.rs" + }, + { + "type": "vcs", + "url": "https://github.com/serde-rs/serde" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228", + "author": "Erick Tryzelaar , David Tolnay ", + "name": "serde_derive", + "version": "1.0.228", + "description": "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/serde_derive@1.0.228", + "externalReferences": [ + { + "type": "documentation", + "url": "https://serde.rs/derive.html" + }, + { + "type": "website", + "url": "https://serde.rs" + }, + { + "type": "vcs", + "url": "https://github.com/serde-rs/serde" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", + "author": "Erick Tryzelaar , David Tolnay ", + "name": "serde_json", + "version": "1.0.149", + "description": "A JSON serialization file format", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/serde_json@1.0.149", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/serde_json" + }, + { + "type": "vcs", + "url": "https://github.com/serde-rs/json" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", + "author": "The Servo Project Developers", + "name": "smallvec", + "version": "1.15.1", + "description": "'Small vector' optimization: store up to a small number of items on the stack", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/smallvec@1.15.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/smallvec/" + }, + { + "type": "vcs", + "url": "https://github.com/servo/rust-smallvec" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#speedate@0.17.0", + "author": "Samuel Colvin ", + "name": "speedate", + "version": "0.17.0", + "description": "Fast and simple datetime, date, time and duration parsing", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "aba069c070b5e213f2a094deb7e5ed50ecb092be36102a4f4042e8d2056d060e" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/speedate@0.17.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pydantic/speedate/" + }, + { + "type": "vcs", + "url": "https://github.com/pydantic/speedate/" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.0", + "author": "Robert Grosse ", + "name": "stable_deref_trait", + "version": "1.2.0", + "description": "An unsafe marker trait for types like Box and Rc that dereference to a stable address even when moved, and hence can be used with libraries such as owning_ref and rental. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/stable_deref_trait@1.2.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/stable_deref_trait/1.2.0/stable_deref_trait" + }, + { + "type": "vcs", + "url": "https://github.com/storyyeller/stable_deref_trait" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0", + "author": "Nikolai Vazquez", + "name": "static_assertions", + "version": "1.1.0", + "description": "Compile-time assertions to ensure that invariants are met.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/static_assertions@1.1.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/static_assertions/" + }, + { + "type": "website", + "url": "https://github.com/nvzqz/static-assertions-rs" + }, + { + "type": "vcs", + "url": "https://github.com/nvzqz/static-assertions-rs" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#strum@0.27.2", + "author": "Peter Glotfelty ", + "name": "strum", + "version": "0.27.2", + "description": "Helpful macros for working with enums and strings", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/strum@0.27.2", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/strum" + }, + { + "type": "website", + "url": "https://github.com/Peternator7/strum" + }, + { + "type": "vcs", + "url": "https://github.com/Peternator7/strum" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#strum_macros@0.27.2", + "author": "Peter Glotfelty ", + "name": "strum_macros", + "version": "0.27.2", + "description": "Helpful macros for working with enums and strings", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/strum_macros@0.27.2", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/strum" + }, + { + "type": "website", + "url": "https://github.com/Peternator7/strum" + }, + { + "type": "vcs", + "url": "https://github.com/Peternator7/strum" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82", + "author": "David Tolnay ", + "name": "syn", + "version": "2.0.82", + "description": "Parser for Rust source code", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/syn@2.0.82", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/syn" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/syn" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.1", + "author": "Nika Layzell ", + "name": "synstructure", + "version": "0.13.1", + "description": "Helper methods and macros for custom derives", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/synstructure@0.13.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/synstructure" + }, + { + "type": "vcs", + "url": "https://github.com/mystor/synstructure" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tap@1.0.1", + "author": "Elliott Linder , myrrlyn ", + "name": "tap", + "version": "1.0.1", + "description": "Generic extensions for tapping values in Rust", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/tap@1.0.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/tap" + }, + { + "type": "website", + "url": "https://github.com/myrrlyn/tap" + }, + { + "type": "vcs", + "url": "https://github.com/myrrlyn/tap" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.4", + "author": "Dan Gohman ", + "name": "target-lexicon", + "version": "0.13.4", + "description": "LLVM target triple types", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 WITH LLVM-exception" + } + ], + "purl": "pkg:cargo/target-lexicon@0.13.4", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/target-lexicon/" + }, + { + "type": "vcs", + "url": "https://github.com/bytecodealliance/target-lexicon" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.6", + "author": "The ICU4X Project Developers", + "name": "tinystr", + "version": "0.7.6", + "description": "A small ASCII-only bounded length string representation.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/tinystr@0.7.6", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12", + "author": "David Tolnay ", + "name": "unicode-ident", + "version": "1.0.12", + "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + } + ], + "licenses": [ + { + "expression": "(MIT OR Apache-2.0) AND Unicode-DFS-2016" + } + ], + "purl": "pkg:cargo/unicode-ident@1.0.12", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/unicode-ident" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/unicode-ident" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8", + "author": "The rust-url developers", + "name": "url", + "version": "2.5.8", + "description": "URL library for Rust, based on the WHATWG URL Standard", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/url@2.5.8", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/url" + }, + { + "type": "vcs", + "url": "https://github.com/servo/rust-url" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#utf16_iter@1.0.5", + "author": "Henri Sivonen ", + "name": "utf16_iter", + "version": "1.0.5", + "description": "Iterator by char over potentially-invalid UTF-16 in &[u16]", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/utf16_iter@1.0.5", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/utf16_iter/" + }, + { + "type": "website", + "url": "https://docs.rs/utf16_iter/" + }, + { + "type": "vcs", + "url": "https://github.com/hsivonen/utf16_iter" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4", + "author": "Henri Sivonen ", + "name": "utf8_iter", + "version": "1.0.4", + "description": "Iterator by char over potentially-invalid UTF-8 in &[u8]", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/utf8_iter@1.0.4", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/utf8_iter/" + }, + { + "type": "website", + "url": "https://docs.rs/utf8_iter/" + }, + { + "type": "vcs", + "url": "https://github.com/hsivonen/utf8_iter" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#uuid@1.23.0", + "author": "Ashley Mannix, Dylan DPC, Hunar Roop Kahlon", + "name": "uuid", + "version": "1.23.0", + "description": "A library to generate and parse UUIDs.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/uuid@1.23.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/uuid" + }, + { + "type": "website", + "url": "https://github.com/uuid-rs/uuid" + }, + { + "type": "vcs", + "url": "https://github.com/uuid-rs/uuid" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5", + "author": "Sergio Benitez ", + "name": "version_check", + "version": "0.9.5", + "description": "Tiny crate to check the version of the installed/running rustc.", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/version_check@0.9.5", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/version_check/" + }, + { + "type": "vcs", + "url": "https://github.com/SergioBenitez/version_check" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wasi@0.14.2+wasi-0.2.4", + "author": "The Cranelift Project Developers", + "name": "wasi", + "version": "0.14.2+wasi-0.2.4", + "description": "WASI API bindings for Rust", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/wasi@0.14.2+wasi-0.2.4", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wasi" + }, + { + "type": "vcs", + "url": "https://github.com/bytecodealliance/wasi-rs" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-backend@0.2.100", + "author": "The wasm-bindgen Developers", + "name": "wasm-bindgen-backend", + "version": "0.2.100", + "description": "Backend code generation of the wasm-bindgen tool ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/wasm-bindgen-backend@0.2.100", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wasm-bindgen-backend" + }, + { + "type": "website", + "url": "https://rustwasm.github.io/wasm-bindgen/" + }, + { + "type": "vcs", + "url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro-support@0.2.100", + "author": "The wasm-bindgen Developers", + "name": "wasm-bindgen-macro-support", + "version": "0.2.100", + "description": "The part of the implementation of the `#[wasm_bindgen]` attribute that is not in the shared backend crate ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/wasm-bindgen-macro-support@0.2.100", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wasm-bindgen" + }, + { + "type": "website", + "url": "https://rustwasm.github.io/wasm-bindgen/" + }, + { + "type": "vcs", + "url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro@0.2.100", + "author": "The wasm-bindgen Developers", + "name": "wasm-bindgen-macro", + "version": "0.2.100", + "description": "Definition of the `#[wasm_bindgen]` attribute, an internal dependency ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/wasm-bindgen-macro@0.2.100", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wasm-bindgen" + }, + { + "type": "website", + "url": "https://rustwasm.github.io/wasm-bindgen/" + }, + { + "type": "vcs", + "url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-shared@0.2.100", + "author": "The wasm-bindgen Developers", + "name": "wasm-bindgen-shared", + "version": "0.2.100", + "description": "Shared support between wasm-bindgen and wasm-bindgen cli, an internal dependency. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/wasm-bindgen-shared@0.2.100", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wasm-bindgen-shared" + }, + { + "type": "website", + "url": "https://rustwasm.github.io/wasm-bindgen/" + }, + { + "type": "other", + "url": "wasm_bindgen" + }, + { + "type": "vcs", + "url": "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen@0.2.100", + "author": "The wasm-bindgen Developers", + "name": "wasm-bindgen", + "version": "0.2.100", + "description": "Easy support for interacting between JS and Rust. ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/wasm-bindgen@0.2.100", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wasm-bindgen" + }, + { + "type": "website", + "url": "https://rustwasm.github.io/" + }, + { + "type": "vcs", + "url": "https://github.com/rustwasm/wasm-bindgen" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wit-bindgen-rt@0.39.0", + "name": "wit-bindgen-rt", + "version": "0.39.0", + "description": "Runtime support for the `wit-bindgen` crate ", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/wit-bindgen-rt@0.39.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/bytecodealliance/wit-bindgen" + }, + { + "type": "vcs", + "url": "https://github.com/bytecodealliance/wit-bindgen" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#write16@1.0.0", + "name": "write16", + "version": "1.0.0", + "description": "A UTF-16 analog of the Write trait", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/write16@1.0.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/write16/" + }, + { + "type": "website", + "url": "https://docs.rs/write16/" + }, + { + "type": "vcs", + "url": "https://github.com/hsivonen/write16" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#writeable@0.5.5", + "author": "The ICU4X Project Developers", + "name": "writeable", + "version": "0.5.5", + "description": "A more efficient alternative to fmt::Display", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/writeable@0.5.5", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#wyz@0.5.1", + "author": "myrrlyn ", + "name": "wyz", + "version": "0.5.1", + "description": "myrrlyn’s utility collection", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/wyz@0.5.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/wyz" + }, + { + "type": "website", + "url": "https://myrrlyn.net/crates/wyz" + }, + { + "type": "vcs", + "url": "https://github.com/myrrlyn/wyz" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#yoke-derive@0.7.4", + "author": "Manish Goregaokar ", + "name": "yoke-derive", + "version": "0.7.4", + "description": "Custom derive for the yoke crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/yoke-derive@0.7.4", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#yoke@0.7.4", + "author": "Manish Goregaokar ", + "name": "yoke", + "version": "0.7.4", + "description": "Abstraction allowing borrowed data to be carried along with the backing data it borrows from", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/yoke@0.7.4", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.25", + "author": "Joshua Liebow-Feeser , Jack Wrenn ", + "name": "zerocopy-derive", + "version": "0.8.25", + "description": "Custom derive for traits from the zerocopy crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" + } + ], + "licenses": [ + { + "expression": "BSD-2-Clause OR Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/zerocopy-derive@0.8.25", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/google/zerocopy" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.25", + "author": "Joshua Liebow-Feeser , Jack Wrenn ", + "name": "zerocopy", + "version": "0.8.25", + "description": "Zerocopy makes zero-cost memory manipulation effortless. We write \"unsafe\" so you don't have to.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" + } + ], + "licenses": [ + { + "expression": "BSD-2-Clause OR Apache-2.0 OR MIT" + } + ], + "purl": "pkg:cargo/zerocopy@0.8.25", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/google/zerocopy" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom-derive@0.1.4", + "author": "Manish Goregaokar ", + "name": "zerofrom-derive", + "version": "0.1.4", + "description": "Custom derive for the zerofrom crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/zerofrom-derive@0.1.4", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.4", + "author": "Manish Goregaokar ", + "name": "zerofrom", + "version": "0.1.4", + "description": "ZeroFrom trait for constructing", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/zerofrom@0.1.4", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec-derive@0.10.3", + "author": "Manish Goregaokar ", + "name": "zerovec-derive", + "version": "0.10.3", + "description": "Custom derive for the zerovec crate", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/zerovec-derive@0.10.3", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4", + "author": "The ICU4X Project Developers", + "name": "zerovec", + "version": "0.10.4", + "description": "Zero-copy vector backed by a byte array", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" + } + ], + "licenses": [ + { + "expression": "Unicode-3.0" + } + ], + "purl": "pkg:cargo/zerovec@0.10.4", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/unicode-org/icu4x" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#zmij@1.0.6", + "author": "David Tolnay ", + "name": "zmij", + "version": "1.0.6", + "description": "A double-to-string conversion algorithm based on Schubfach and yy", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "aac060176f7020d62c3bcc1cdbcec619d54f48b07ad1963a3f80ce7a0c17755f" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/zmij@1.0.6", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/zmij" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/zmij" + } + ] + } + ], + "dependencies": [ + { + "ref": "path+file:///home/runner/work/pydantic/pydantic/pydantic-core#2.46.5", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#ahash@0.8.12", + "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1", + "registry+https://github.com/rust-lang/crates.io-index#enum_dispatch@0.3.13", + "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1", + "registry+https://github.com/rust-lang/crates.io-index#hex@0.4.3", + "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", + "registry+https://github.com/rust-lang/crates.io-index#jiter@0.14.0", + "registry+https://github.com/rust-lang/crates.io-index#lru@0.16.3", + "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", + "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", + "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", + "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", + "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", + "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", + "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", + "registry+https://github.com/rust-lang/crates.io-index#speedate@0.17.0", + "registry+https://github.com/rust-lang/crates.io-index#strum@0.27.2", + "registry+https://github.com/rust-lang/crates.io-index#strum_macros@0.27.2", + "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8", + "registry+https://github.com/rust-lang/crates.io-index#uuid@1.23.0", + "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#ahash@0.8.12", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.0", + "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.3", + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5", + "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.25" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#allocator-api2@0.2.21" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.3.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.22.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.9.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#bitvec@1.0.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#funty@2.0.0", + "registry+https://github.com/rust-lang/crates.io-index#radium@0.7.0", + "registry+https://github.com/rust-lang/crates.io-index#tap@1.0.1", + "registry+https://github.com/rust-lang/crates.io-index#wyz@0.5.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#bumpalo@3.19.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.0.101" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#enum_dispatch@0.3.13", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.2" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#foldhash@0.2.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#funty@2.0.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#getrandom@0.3.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.0", + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.185", + "registry+https://github.com/rust-lang/crates.io-index#r-efi@5.2.0", + "registry+https://github.com/rust-lang/crates.io-index#wasi@0.14.2+wasi-0.2.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#allocator-api2@0.2.21", + "registry+https://github.com/rust-lang/crates.io-index#equivalent@1.0.2", + "registry+https://github.com/rust-lang/crates.io-index#foldhash@0.2.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#hex@0.4.3" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_collections@1.5.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#yoke@0.7.4", + "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.4", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locid@1.5.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#litemap@0.7.3", + "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.6", + "registry+https://github.com/rust-lang/crates.io-index#writeable@0.5.5", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locid_transform@1.5.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#icu_locid@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_locid_transform_data@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_provider@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.6", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_locid_transform_data@1.5.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer@1.5.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#icu_collections@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer_data@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_properties@1.5.1", + "registry+https://github.com/rust-lang/crates.io-index#icu_provider@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", + "registry+https://github.com/rust-lang/crates.io-index#utf16_iter@1.0.5", + "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4", + "registry+https://github.com/rust-lang/crates.io-index#write16@1.0.0", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer_data@1.5.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties@1.5.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#icu_collections@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_locid_transform@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_properties_data@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_provider@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.6", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_properties_data@1.5.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_provider@1.5.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#icu_locid@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_provider_macros@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.0", + "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.6", + "registry+https://github.com/rust-lang/crates.io-index#writeable@0.5.5", + "registry+https://github.com/rust-lang/crates.io-index#yoke@0.7.4", + "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.4", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#icu_provider_macros@1.5.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#idna_adapter@1.2.0", + "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", + "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#idna_adapter@1.2.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#icu_normalizer@1.5.0", + "registry+https://github.com/rust-lang/crates.io-index#icu_properties@1.5.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.11" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#jiter@0.14.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#ahash@0.8.12", + "registry+https://github.com/rust-lang/crates.io-index#bitvec@1.0.1", + "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-float@1.0.5", + "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", + "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", + "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#js-sys@0.3.77", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen@0.2.100" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-float@1.0.5", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-integer@1.0.5", + "registry+https://github.com/rust-lang/crates.io-index#lexical-util@1.0.6", + "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-integer@1.0.5", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#lexical-util@1.0.6", + "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#lexical-util@1.0.6", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.185" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#litemap@0.7.3" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#log@0.4.27" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#lru@0.16.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#hashbrown@0.16.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.4" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", + "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#num-integer@0.1.46", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#autocfg@1.3.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.6.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#python3-dll-a@0.2.14", + "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.28.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.185", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.28.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.28.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.28.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.185", + "registry+https://github.com/rust-lang/crates.io-index#num-bigint@0.4.6", + "registry+https://github.com/rust-lang/crates.io-index#num-traits@0.2.19", + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.6.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.28.3", + "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#python3-dll-a@0.2.14", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cc@1.0.101" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#r-efi@5.2.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#radium@0.7.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.13", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.3", + "registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.4", + "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.5" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.5" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#regex@1.12.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#aho-corasick@1.1.3", + "registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.4", + "registry+https://github.com/rust-lang/crates.io-index#regex-automata@0.4.13", + "registry+https://github.com/rust-lang/crates.io-index#regex-syntax@0.8.5" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#rustversion@1.0.17" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", + "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_derive@1.0.228", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#serde_json@1.0.149", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.11", + "registry+https://github.com/rust-lang/crates.io-index#memchr@2.7.4", + "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", + "registry+https://github.com/rust-lang/crates.io-index#serde_core@1.0.228", + "registry+https://github.com/rust-lang/crates.io-index#zmij@1.0.6" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#speedate@0.17.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#lexical-parse-float@1.0.5", + "registry+https://github.com/rust-lang/crates.io-index#strum@0.27.2", + "registry+https://github.com/rust-lang/crates.io-index#strum_macros@0.27.2" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#static_assertions@1.1.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#strum@0.27.2", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#strum_macros@0.27.2" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#strum_macros@0.27.2", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#tap@1.0.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.4" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#tinystr@0.7.6", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#displaydoc@0.2.5", + "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#url@2.5.8", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#form_urlencoded@1.2.2", + "registry+https://github.com/rust-lang/crates.io-index#idna@1.1.0", + "registry+https://github.com/rust-lang/crates.io-index#percent-encoding@2.3.2", + "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#utf16_iter@1.0.5" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#utf8_iter@1.0.4" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#uuid@1.23.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#js-sys@0.3.77", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen@0.2.100" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#version_check@0.9.5" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wasi@0.14.2+wasi-0.2.4", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#wit-bindgen-rt@0.39.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-backend@0.2.100", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#bumpalo@3.19.0", + "registry+https://github.com/rust-lang/crates.io-index#log@0.4.27", + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-shared@0.2.100" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro-support@0.2.100", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-backend@0.2.100", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-shared@0.2.100" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro@0.2.100", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro-support@0.2.100" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-shared@0.2.100", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.12" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen@0.2.100", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.0", + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "registry+https://github.com/rust-lang/crates.io-index#rustversion@1.0.17", + "registry+https://github.com/rust-lang/crates.io-index#wasm-bindgen-macro@0.2.100" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wit-bindgen-rt@0.39.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.9.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#write16@1.0.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#writeable@0.5.5" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#wyz@0.5.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#tap@1.0.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#yoke-derive@0.7.4", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82", + "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#yoke@0.7.4", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#serde@1.0.228", + "registry+https://github.com/rust-lang/crates.io-index#stable_deref_trait@1.2.0", + "registry+https://github.com/rust-lang/crates.io-index#yoke-derive@0.7.4", + "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.25", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.25", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#zerocopy-derive@0.8.25" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom-derive@0.1.4", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82", + "registry+https://github.com/rust-lang/crates.io-index#synstructure@0.13.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.4", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#zerofrom-derive@0.1.4" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec-derive@0.10.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.86", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.44", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.82" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zerovec@0.10.4", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#yoke@0.7.4", + "registry+https://github.com/rust-lang/crates.io-index#zerofrom@0.1.4", + "registry+https://github.com/rust-lang/crates.io-index#zerovec-derive@0.10.3" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#zmij@1.0.6" + } + ] +} \ No newline at end of file diff --git a/source/target-vendors/cp312/pydantic_core/__init__.py b/source/target-vendors/cp312/pydantic_core/__init__.py new file mode 100644 index 0000000..d5facd1 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core/__init__.py @@ -0,0 +1,171 @@ +from __future__ import annotations + +import sys as _sys +from typing import Any as _Any + +from typing_extensions import Sentinel + +from ._pydantic_core import ( + ArgsKwargs, + MultiHostUrl, + PydanticCustomError, + PydanticKnownError, + PydanticOmit, + PydanticSerializationError, + PydanticSerializationUnexpectedValue, + PydanticUndefined, + PydanticUndefinedType, + PydanticUseDefault, + SchemaError, + SchemaSerializer, + SchemaValidator, + Some, + TzInfo, + Url, + ValidationError, + __version__, + from_json, + to_json, + to_jsonable_python, +) +from .core_schema import CoreConfig, CoreSchema, CoreSchemaType, ErrorType + +if _sys.version_info < (3, 11): + from typing_extensions import NotRequired as _NotRequired +else: + from typing import NotRequired as _NotRequired + +if _sys.version_info < (3, 12): + from typing_extensions import TypedDict as _TypedDict +else: + from typing import TypedDict as _TypedDict + +__all__ = [ + '__version__', + 'UNSET', + 'CoreConfig', + 'CoreSchema', + 'CoreSchemaType', + 'SchemaValidator', + 'SchemaSerializer', + 'Some', + 'Url', + 'MultiHostUrl', + 'ArgsKwargs', + 'PydanticUndefined', + 'PydanticUndefinedType', + 'SchemaError', + 'ErrorDetails', + 'InitErrorDetails', + 'ValidationError', + 'PydanticCustomError', + 'PydanticKnownError', + 'PydanticOmit', + 'PydanticUseDefault', + 'PydanticSerializationError', + 'PydanticSerializationUnexpectedValue', + 'TzInfo', + 'to_json', + 'from_json', + 'to_jsonable_python', +] + + +class ErrorDetails(_TypedDict): + type: str + """ + The type of error that occurred, this is an identifier designed for + programmatic use that will change rarely or never. + + `type` is unique for each error message, and can hence be used as an identifier to build custom error messages. + """ + loc: tuple[int | str, ...] + """Tuple of strings and ints identifying where in the schema the error occurred.""" + msg: str + """A human readable error message.""" + input: _Any + """The input data at this `loc` that caused the error.""" + ctx: _NotRequired[dict[str, _Any]] + """ + Values which are required to render the error message, and could hence be useful in rendering custom error messages. + Also useful for passing custom error data forward. + """ + url: _NotRequired[str] + """ + The documentation URL giving information about the error. No URL is available if + a [`PydanticCustomError`][pydantic_core.PydanticCustomError] is used. + """ + + +class InitErrorDetails(_TypedDict): + type: str | PydanticCustomError + """The type of error that occurred, this should be a "slug" identifier that changes rarely or never.""" + loc: _NotRequired[tuple[int | str, ...]] + """Tuple of strings and ints identifying where in the schema the error occurred.""" + input: _Any + """The input data at this `loc` that caused the error.""" + ctx: _NotRequired[dict[str, _Any]] + """ + Values which are required to render the error message, and could hence be useful in rendering custom error messages. + Also useful for passing custom error data forward. + """ + + +class ErrorTypeInfo(_TypedDict): + """ + Gives information about errors. + """ + + type: ErrorType + """The type of error that occurred, this should be a "slug" identifier that changes rarely or never.""" + message_template_python: str + """String template to render a human readable error message from using context, when the input is Python.""" + example_message_python: str + """Example of a human readable error message, when the input is Python.""" + message_template_json: _NotRequired[str] + """String template to render a human readable error message from using context, when the input is JSON data.""" + example_message_json: _NotRequired[str] + """Example of a human readable error message, when the input is JSON data.""" + example_context: dict[str, _Any] | None + """Example of context values.""" + + +class MultiHostHost(_TypedDict): + """ + A host part of a multi-host URL. + """ + + username: str | None + """The username part of this host, or `None`.""" + password: str | None + """The password part of this host, or `None`.""" + host: str | None + """The host part of this host, or `None`.""" + port: int | None + """The port part of this host, or `None`.""" + + +MISSING = Sentinel('MISSING') +"""A singleton indicating a field value was not provided during validation. + +This singleton can be used a default value, as an alternative to `None` when it has +an explicit meaning. During serialization, any field with `MISSING` as a value is excluded +from the output. + +Example: + ```python + from pydantic import BaseModel + + from pydantic_core import MISSING + + + class Configuration(BaseModel): + timeout: int | None | MISSING = MISSING + + + # configuration defaults, stored somewhere else: + defaults = {'timeout': 200} + + conf = Configuration.model_validate({...}) + timeout = conf.timeout if timeout.timeout is not MISSING else defaults['timeout'] +""" diff --git a/source/target-vendors/cp312/pydantic_core/_pydantic_core.cpython-312-x86_64-linux-gnu.so b/source/target-vendors/cp312/pydantic_core/_pydantic_core.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..a2dcaf3fc6986f2bf3531a5c7a0b628dd2a70cf8 GIT binary patch literal 4692312 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�B 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 {h0qkL0~cYAkSB2p-{E^)z$IwDq^xPY%8*Sk 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

      0e^LkxXE{O4#l z?9Wj0-Oo{EPSUJ@n=lv=eBs^gZ&L;%_YYINU4PC#_yzXAV)}DDy@^czX`-c>x9cy< z40d69??#rT!=`m&dIswx4F==zGaYECN4h&>slf>*4pxqMF!$H1OJ(T2u*EUg|sq?bY_35@C}@l9g|dU-l>%662hEpd{k zQHD>yeZ3Z??A$N*+{-ARmkQp+YRjmE`hy!}J(f|WtF5=+N?$hgMe0|}RD-X0O}j8b zL$9-`wt31bjffgu)`~744XpS7$O|d8$WB0}A->&j>xT3KE3@s$3$Ywb`J!hoAk%L+ zO>Z#8%nZp2gXu8z)ByUo{;}YHmt*8`jIY%nZ`+0(6M6;-J&BX#9S&tL{gPd<+E7P`p74cK3wpAW!*HS$vJNnex#_8*NNgQU zDx+s*EOvLKug`L+iHQpmD@?2$Er(8xCgx@q_Sh#2tKlhwiG?Glxr$p_nY&w?n3}>6I?-jzg)Aruv2k>rB+umaST+ueMBciIgcC%){0N z$<}B%gxtk;u*DD)qzMfslOcbSG!Q3+R`0DuL;jqVkPT{rG+hr{CwEr|Z>03#5JEPQD>8E|M|8lU-e_rwt}yg= z@RN&l)1gi@IAN#@{(NgP*n5Ts>AjJ>8}4L-gFkyA8FC@L{kM($)inp_`)kF&b;-eL zZr;vTuJj!rPKy3De1Dycw&Qacx$qun3;Nl@)=9_}+2hC&Hn;M|g#rC+V(UVWt+kuY zU$bdD8PMkoG%*rsqY`6TT2)Q6Wzkq)&;`)27UjbBIcrS)hil7MO|)B_t!e z-~@@p>7gNp{4(}FgY@WEZvb{>ojx-apJh4cdEhT2_1%{)wwv)w@2U9 z;1uzn$CWszx|7#pOK(RZHAnBI!%JHrITXt}Iys8DJ9^?w^)DCfEG%$!!&%zpuT%2i ze*Sh&Mju7|ex3}JIfu?I22MBuSX$vD!(lL)TgVAnhe$ibFAMzBS!Wy49!=@Tw-9pM ztz69U3krX&SDX_yrnfh0q^vx&8_LQ^>~z5y3b~iVDZ@V#H_f);gg^K}Gc@l!gx?82 ziXeom5wpP~YVa_!#BuB5c}{*Xk_ZEOd#t}O?D%YdGe zkIw@7sfV5oJ$Tj|+V)_t{q2MCmvaab$|aC}Z6V=m<*-e{$_x2=B<)#TNZWO2qR@8w zj|Ny-s{9oRYy8LnuHw*(kU@^zPWpZ^{`LAVF9_&=YznWTfB(xlf1CL4&Cl@LGQSP{ z7n6RQ?|(ZW;qK}p;b3bnF?i@oh?~3HI#`O?T1xyr;a|oYSK;*TwNA%?o*4P-hYEVg z(3PT#5WV@4$NMj$fa_cQ@CYJ5cywxOC<~e6l;e!+2YgZu=VJfM?IQcy7M<9Fe(oFm zkR9BXkdwt=zaz)Dt2Yv<@p){!lirzzw(@Hohd&|*kA0jk=xMTpz3}I8DYOk|ANt3o z$b9s93m4nL&(5I($I=R)F7%({uv~;sJS&ngjw2gCgF#(nvxEeWbtHugnd)1)BHdhB z8Rt0{GiQ`xscMER2YTkWxVW+SU~{>e&@;+D^Z5pkHT`3nuz6TMVy< zjMCQgkfkT>5B?m<(EYg(#>tNyH@r4_R~h_OAN&*zng!QdhWa|cr0bjG=Oz9&31{e` z14Yc-O3X}*J`X-&T&@1aX!_bLovd6Pn|zMB;qw9;z{dvmk^V`Ht7=Tg)hw<>ahRbu z$qFr3r~hWj;H}cnpYA{xb8;C>m|uY34REIzNs~i%LcER)veU%V=>SFS-7_K|H-1DuF7t?dT=fz8xJO6i<0_8G$7LFk zkLx!gAGc*hK5oT`eB7cD`M8%ygaa~nv z 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

      ;ltRNBAlJ*J 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 z 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 # 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°2q`hAC3Fj++# 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

      W5gO5Wu{c``F%5^jt1NA8 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

      AeMkS=6 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�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%0D}=i85qbCR#30Z{S+dA{km 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 s}dq8y_R&t_mNvugeqJllA(v$|GoOC|NU4Fxh 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�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%0D)ttL{>m%sEdr?Q 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�G-G}fpAQ7fEg9>2cB1& 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�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 z zIeUXVL32u4?Wyx73-uwH*=}`TI~EE6t4hiFB~Yle|1wd*Brt6rTe33(qj&Tv?J=ID z15P53^FB}KrU~M+%BA7<%B%kt30fmfd&>I~;ucG+RA;0CWQFxYYJuN>5&@~)L6Mc(+jYO+i+3S}(ARs~CcDi+q_ zPTJBQn?kEK>%^^M9zc&zf;Bk%idG|lm|4zi%E+ZhYU-sOHeDqHSa-?w_cXCffsT(6d()f230}<4iwtUV1p!;S-*QcrgKYus2fRf41 zed}-x1XT6f-U0$@0I8x+Kc}Aw#U+5ZWof<{Or+l<0yCpMedj`2BGx4+hu_%H1(8NA zpQ?yP)de-}8`gAuP*W}l(lrT| zVNC*B5XSORps=bT|Ggy1Rd?YDljZ+SH^0zpFtV601nvU+b?{ZPpZOnx!F@mX@}IY) z@>HT<^;Bpk1QHj}4lu99cBH^c?M4vZ`wE@c2ZUuu)d~vgh1j@0G`7uPjcp4A2n%tZ zkQ2hAB27P4e_+&NO?hs|vrZK!0%E0p2N~sYQcnGjn$$`D@^_Pr$5uE9-}kHMXffN| z;^gx1kJ4=*5<`KOJlZrp$7_YNp0?z5yWWm`5>WFS{vdf~q(v8np~`3=(hBz$YG`x0 z*HAP>m)|@2mL8P`!XmI)^a zQ$?fos2U7o(;L=6!BfsQ7f`d-j;j*xoD|_TaeJ27<3s<~?@L=J!1_csP>e)f36W=H zRM&=iiDTii*E@v6&0l}8gqP4S79V5Vk`3KT9lEjkVvKg{j0S!^W9-UID$N{QHj>L^ zPB6m~gQl?<5}p5 zV_ZTX5uDH`DjcEmQvHUNfa14U@{)zipccJf5?gBgnuRt zlY_F@nX$D{=@h7?ftGfJck(iMav9(ZwUHi6<6YcopyKhj6LD_UiBTeV%*4W3x*T6m& zKEpi<7e}RSOn!tj<4IL)li~kzPC;J#VD~`Ug5RPCQ5Owcs|Q!;K_u(J1w2sRe%lqV zZunRIjzG9cx>|*L9lX)x`RDScz1)Ah!{cf_KEQt}^VsV7zUt9*`1iOs$s4!{>J!oW zjsHW5omAq-lt})J4%#2e*dawK3-zcrV`!0Cd+9QaH{zQ3U)Fq+J@r_HUHbm-1f}4H zQKi0bD$)b!Cz|Z;N?Ho^_5-s!)3cFLjPp0>aDzxY3kpvs=h7ilJ-KN=Qh%oMCtCrw zf&TTEd^yH{iZ6L>lxQF7urH*T|9f`zD-#gZ{(VR7-+L2kKfu2+^M%2;o{F+-Z>1W4 zioVX!ey!~&Obff?bsNyW|Ie#*Bca@UwHOBWsGSEeUHji88$9JNx3pd!`4Ieo`Zp66 zje5g&)^q!iG`79#4tf5^{0Vo1c359tM<+eyhg*Y{UX|F_YdKxU)B9L7epmLtdWoH? z*a7J!E{B&~P~1#fI5ywcAC1m97}k1dd3;()dHj@p6!=JPRPvt1;*sk3Xm&APU06+q zv+`M^qlhlGlO?($^QzN{C<{qM*^5M!-DiG@b6{5Gh!}#xix0;WfCsC-AGezt`Y2tl zf73$*#&b?V{Ec=}F@04{0@~`PHIc@@Qae>*p(`bO{5>-C_|Lw#D#f&UDAV6J1X7$6 ziiOk^qDi9av8Q;sagqL*-Tk}hV_4e9Ui@t`HT%y#uhC;ls$jAB{*7vd8?%C2gBv$! zNq2jVB(paZ7ye0sYU5XujZ}es1Q$~qfaswm{>8ULLhm7dnkxr1tNYG+ny8JJvqp89 zbzIj4qq?EC*{I$@?f0iN@0b^iN}18r!R;E=%I8RA#~2tD!WS{iOreHKs=zpxU zGZ}cDzu}ElspKM)(R7CHu?y4E&n6$zL(wb~=RcDE-~~QtFYs68If{n*9JIS?`yzyK z?9MqZs~mrolSa_P8;&GGdLX#Mzva4aNS^&ddSK%*akU##^%t72-~o6d7W5zpbudG( zlSA{L>NiV9mwp&a!ni*nS&H>92u z=k`MFdWNuNZI9THrk+P>EloW}0PpzM{XI=R2WC@G8)dgfJtWKcAQoTZ_gj=pJwl$4 zbY`eMLB)os=;u1+rm)ArX_a1sXyVS4=!|ZLa%OdMX%^j(qpvffkuNd+wtvKRX`)#} z*3Lmn1d^q+VY z>UpX&>iNA<&l2YW>9)knUnl<4#z$WKC}oSQQjD7NQXmuHs_*;zKE~NqQur^2piV1H z4wTXv(%)g(t$MTy30}0ZfXa~UAqmd-nIpkPJ7!35Gx{Sfwxuj(7n@~Hf+@SLHqVm? z_J;OuD13WWlL;`ExQe_x%0d1WL}+KR&iy7t7>n;65@B_mjILi#gjMm6{ugxk!u>{v zy5yVFAW69V{hs}A(%>U(_Dg=SO*Dve$e%a!o712MbMiC)zoJ3n zbC6wW8bs&NfzQVe4QcSZ@hloV;+3t@U{!pTXz-YpZmYITgGz_#X}#r_4}V4GtsdY$ zDTt>QCJ%xJwSr_a@BwY%4JrSbmyHIKUlzdi$@3D@;D(!}r>^xYdO8}+p}$g?E?Y=V zCFC>_k|Lppwcv!c1C4aP2sHSoo;~ua69Y=B(HEdXq_585LKu>Yc)GmB5kdbGi)W28$=Jqw zR!t-r)zvJ)C|kY;szj>H8h#MOXtgT-m1;H}b6j;C4=Wzc5B&+R8W&nV0BQLS`@$ zg9jxLoA#1I5||WZ32rq6}z+-<|Ksml5LRlHQ5mS%U!_#5oFLh#2KP%TLAv8Ct8d z=$ygwFJqfaXA$VlBT+vuNBvBpe)cobT zhbGFUejXw9^C+i&&Ms+HrC1kA4RYgQj)05(iRShT96Fc100BQ32+>+~JUhHX4%({t z(twDU21LBr`ns7Q9VbEhHv3%yL0XkKr!cur&J8C>i~Z%8vR+Hja_V^_;*vFKK^jcv z_oePq)m2?HlGNFFx%uFO{Pc&j%YDoF>EC|gOL;cIiT{WB>E~?RN|%(Me)WH|S6i`% zP5*e240c+$Cd}XY#VVT{VmgTE9-CJ)kh?7H3g%#uUy43-B1^tl#^bRYnjL484{JW9 zWjbL*1>4xLhRzf*pPANvYjm}n+0E0i4^JtCO)1-72b-Dnda(J^waWQEOt@hNq0Ylt ztt`STEEhfm1zVN(jKCi|xnXX;bqRxWY)L_T^H$9Uu}`Z3ra?93i8Jz0tK8}KoL6ca zW1iH|5kzG|Pr<=28({I)y2epsTYa7NA~&ysbYSW4@`Jr|s34&1X&P;bZj@+AH+`|^ zU|tlGc|4|9@(iR0&gj={^SO&m&T>Wz26ez7@IvqToV?I@DKrTqQCJy&^GNv2$lU_K zbC807o?Ho?3i3lDY@f2e-tT_GV>?}35yoo`97M^J$Evn*GrwX}&_;D|=9MhcH*KP` zTt>Up?-px0BPw2Aqa0HE-PA3Q=&@PaV$1tM?mbKQ!TYZ6{SCM3eWIa^g}(aZ%M&M6 zgy4)PE11G6_$3hc8|QtgZPkKpsvd^t@&U>`7x47B<3^w4uJkO8qfC@g#out~=KyGA z!Hi)zh7VSWVEx!!@Kp6!P}L$0G2?=FlOlUNIYo-ThQV^3Km0};<_#+V=ioN4rAoH` zW}AQOaGGXq{!NvHp^Gd1%jdf2xIKXb0~Oi=#4xELa-KOtDqwsp?0oZYdOswdgAe_0 zFLXget#sc($BfOupk$MaBqZZf@>=KV=m|DUE*7wOCC)1kdt_F#E(7o6Ra~cvj(7v_ zwurQX-@*AZHC9n{Tw_rK^Oed!Q&9n{u{v~y&2lz(Q5%- zXl01kBK~l8^c*rF9lbW`%$(>oArU~1@}pn3LCLJX{f}c5b86c+uNn;ybwpXW|dP-#Qm`NQG#HK$rA*u)H-vlI&*-L+>ry``3IEOd)!_YkoLES zaqZ$U3xeDB{m^&8Z9QD6gI%fna!YOafKm!>Tl%)u)ytJ?$}RP#N-4PQPp;I*ds>TU z=9ZdEDb^c^rGQf}Y~RQ2dkXL6CNIpZHy3qrs;K>M{osS-)MaIJ^BiaY;4R(@|F7%& zW;v%3%Q^Olyk98WTE&-3?hCxWWMdx{lRZ?H?H8DM+2_jnhCF;2ycM#QIra~-)kue2 z#pHwsnFX7aq(r@#((d6ATs=d!h6L%7aT=xymCQz!z__4i`dqef*{wh zi&te8{Hc&=@&w*UlNMpL(MG~)2ddLG(rNcx6egigQ50`QReU(e;gr&NlH*mXu;&DzUjFHGO-{8kyg*Jl)mKMT1*&_; z9fx~}YT@|$Mx0-hAd~d?fkE8yjH8fM`)D2jtE=usazdhf{t6N>485TZ#nL5+8BXbr{voeGV{k|(%HO{T`?BOI-!!D_!J6!0DHBJhZjCB1dM|H2jun~0QKlub z{!ut8lvv8&^Q_fEv^Wo%#1NE*K2q+c=}%ataR=@CU)@ zU>aLK_0P_sR8nDu0u|sAL-GCEga2Un?9JP-sex5nj`+mG?~XKTC$fqxvf|ENZ;^Lw zVJ!8c3SP>3{^YHX_te!v4(0#b@$PbS zC*$3ffps$8)FL9f#MjI#hZJ}|-Y0*MBK=oWCq0AgHf zQIGv})LevfH^_E`UtzH1N0}Et(c}d-60wbG0T_2;VCFMkmO~VGtdap`rG$PjHveB; zV>6#!M;NV~x@PJZ9FwR&k~Xv!Yi$!r{F%S@-H-5Tec~Veh(Zx$;(>XrwCIoz<+3Ad zQbG05jSYWo|0QHMK0>I$oDZCjidqW%p85_7cz;#jJb&Ux1z9TIH-pF2g`55_;ql4e z9Xt+tcw68RV};qDy)+9RYaep(cx5HQN_?0={5G%k27Qkkn@>!PWiAD??ODjoI6E3S+vu9 z{D@7@&se|dQak9l8g@?{-bFQ*MQjI(lH^6Lq9p1#WIy@RXO?i9%!a&F^$@Z%Q2dQe zpGfhDv602nlz&g)szdc3v^p{c+l0S_SFDa)eQcCJa$phKa%n;GJfpHJC!q-coX(Rq zce*!tmG}68SO2u?z%Py;=dJw!C#g4>Gieva*8ZT*8~l{_+EY5Cc7AdwrN>Q-OrAe6 zQrq@P*B7Z6dKQ}Ql^*L{!r)YC*5znT)Gci)XWMbs4uW+T8tgeXs<&{|e-(vgB zkIny}8wU|r_g@qnR<|nBq-_Yv8|Vh*|3>-sN++evbumEWg=6KEI#Tdg4O*WnHwC_t z55!bFf6?@1tXf@IGR|1v-%zE)Zv?(&uL(p`-6^wE#c6=g$SuLgY5U2y(6M5P>FZ*N zhC$xYwUL?Qtvl7FUZUHVi9%KdddJ~f-M(z^t{S~8Mwr}*Z`H8^|DfTli5w27WsclP ze{DvW`JbH1c^`JtT(chXQtG;pj0LZ;PN^>Nuj#p#dW1}&R;o&YZcnC?wX4KvrjrHq z3pw7US<0|L->_(*c_}FsE)??T#Hc!s4^N=Dx@+=YY7NAh`=8GQ-cG@X<HEK$fG7uT2E?Jj29F_!ANje+4@ZAT+Q6T;s-dD(81 z(&zHIN1BM90S@GJUpyaATZ8TrhxL65w?U!@`@y=F%j;z3>*4+*e@LdPh8?(ul99$s zjm&rh5d8KFdMPGKL;Q_BXSNxe#_9pbDK#Q2;*a=C%oBf6p*{Al6sTXq!@}|>*@={A ze^NzbX~Cjl*Q&C|ho3b0g2_{+O(q(4L0Q33+Ak(N@#1cym+o6t57YT!!!iq4aBN|P z|KM{gm<5UL7PpA!#fdWO{=Em?*3hc>CCJ?FFJ4ZFS9}Cv7KgoYt=lfShzkAJr)uje z_#_3a&~G@K1t0vuYCOm;Ba}=PHMZeMN&F?)BJ{AC%LQ+)Z#66^*7EWwNw z$wCfM0lt+{F|o{};i^EA#C4OZXc?WFSiaA?iul4v(}9?9$twP6XT;2>Se}_*m`o{H z9zVuXKJg!{?Uk482UWRK#yKKhZCsrs>}bD5-%rP*F2)q;&o8lWZk4OW(R?xs#_lQUk>kv!F~n zGSdR}RF16Qf<*mUm(J!A*YIW%_4+^J-`Gr|mN%CvSM8=t-9h#_BDHA+;OIn>bm4$% zCrOm_&Jaw1x%?7g%UE0@O|M28*{1}%=;_!+&#D%-flwRpkYtITBsR{;Sdpd&t%}b1 z_~ZHCjE~>-2V&dlQS##L;p6XvsTz#f1aXBD2$P6(FP)omjBH(g5)xRMuNpZ`rWj6+>tMgsr+AvM=vpe zvt*r!eA0$iMPF$W6z`G$DOPo}ST$MU@;NMZsEWrtkDVOS=pL_@M2<0YW z>XMs-mdH~mx%u{HaRI(!LbY~Mj!?}Xy9J?INPj!p zoL<6h4i9Y3-rB*nA_%p^@<15g7x}>I78jgJ)Mjc(6&=doki#1b z6xgr(cW3N9<6K0>B=_zpTnB+^$ts~+C|n1ffN(9y6|Og5&_THV_=kaTeRUba^~u>= z6t2y4Hy5r)ov^LKwd4n8fj<61TDX2oPj>Zx>z-tU>$hmf5tdn?BC3WRjGzki2C3>V z$w<{4dHR@W#UeQfuH1@0cY3ZrxA=?Bz@05kiJXC^m-#!NV*XsUvqgVyjQEurZ|0vx zQ_!`t@&yjvsF`Fd2(P@m_ZNXncRzTT_H`<-nl1Mdd!?Q-6yZT4^$@r#e-ap4=g+@; zEn44&I#>SOlIbFl8MNRL1gT|xi;q7`fqbociXUS!zY3C2MPN6l z`9dYZu0iIKYvTs3{pwNC>iEFw_{4&0g5){fvN+iV7H**$Gyklh5&DaNda1lY78c$( z)WEMjgK@XtUEAPmy_P@ErLZ`=WsULsKZxjzKTA5XpnLyr@Es zv~j%Q)znw<-fdzvHMY;cSC5EH`StHaZQwp6Aj?&HUwPuURpP%C`cez&l?XhQ}On+8v}&Ix|c(I*lwX4<7o{9OquRKdRDeW z{5!a=#bVqy@A+^4CF2l}G(MoO0<2MhBdSYd$qXKH;o|>=3}d4DOX`F$ZgW~eay7h0 zs5q%QF%5}+>7dxqHIbRWpf&byl?E%e!ElF{Ok?Hx@cVNHmB*ltNpxFnr+4*^vsTz` zwezP>&yI;q7*8YU$p4=bc(g2S>5Xml5h!Rk?$1Yt{`3|-hKa%!c5 zN29zqV4<09&7ZE5Mt3{W`P0v;4RlI=NOtjiA&?!hlgcN6(K!yf$=MnD z)|D>Ryn^-jqU0oXmpJS(u5*3spxoj9_@A3^{Wji`dYLMXoyoWUld-1eXsogZycTx0 zFhY$o+qaI(1mF4){<1wU$E zpcRCC%7aeLsgrBneI(cV;@fi6oQuy*t2sZqz^OS3DD*Eo6Y7g^5cNhyy`_G?W1Xg> zssiu2x{xaR4qX-_*LPKkhizcuCZ*g5n$CXVsFdHJqoxy!_bM?phY3Sq#NsfZ7!o5& zZ{KO}3sVPT<;tW5D&-{yLpsj6ob6@Lr-f9}efKy;#AKseh7xEtEbmMmfF+C>%96pk7?ATw%5w>PI?n_ zydQWvO3q~esi&M;Wx*{Qr$ro(FQsvV0N({>sx#MQU_kXH=w>cW=o_ z|1aK1MSAv?Kt2Ig=MlBfbn=8p7A<$K@UmVxn@qnc4)vP?X{`59x&Pjs zQgK|cz7`{;I7q*Ej9<}38^4z0`+SM4C3*_(%-~mwj=-#>n4E%ULKbCzkk`U>8f=a4SEZYdN*N3ACL3i+>|6=M~d(j-anj%c+RGwW?D2 zD70V?hyKfgs{D1{K1wpzUCAi>KkE%ULpn~P0o{gR8;`_Xrk0?g!0e>=RG~t|Uow$V z$1NA3mh(F8bgJdJI>-(Yi~mDYplZZqPvW<{WmIZn#XhUb;|qw{%u#bf4JXog9m-8C z^%DB&M(dUofq`?JA`nc{+Iuzapoe&&;4DozaRy8O4lhjmeh+2mxI!sAM+5pHl#0ba zRrW&zJNeA!j}zZri66q%N$D?yt@I}iORwA9PBnTC*JF27;uKT0 zOZ^_cRE1#ENS3yM3t(&7g7#In&z1*jrGE&$aSV;WCcV%WJV{pKo%BQQP;tL;;?brs zu+VU&+#HEB(5BD}y+j>OlGTx!w`d@VI#eoy;c-|_Y~Y2`-c!jvtOd7?N-eYVgzTt#ldm_p>l_w0&^fsq-}l#l3@jFoEEa-h z#Tu|ShliSImw;O3^IPwKdJCbKkD9`E*jaH2#ZGrvsbbqL_Y3;A`r>|7%XE38AiGx}q%pG&6QfL|@fqq4$F6;1!;VF# zN)Nw=w+yyYf2s@lb5fMvj#Xd~cv!|?kk9zEby3_oTcx_YHBhNiYGrfJk?q;BJXUv< z%+MGST1T9Om#5`)B}RSU#w=fO_uomQnr&R(EyT>c$thD_oLsss-AhhOD^mxaouy0- zI9WvfFJXMCcICu^n=&;IPmFlPtZQ?Xso#PNp)z&5!;4f= z?3duT475O*3g&bD(P?GMCUvsrdb(*)?Pr@BwbK9i1Qemm{L3E?)F{UXS#CwlrHYo` znWaYsB4y4T^r+E+7WP|xzNeCVjj7IMN=SRh7_3acPhbc@O`#7h^L zMwO#a-2*NWWy_BKSbSqfpBkm*n^2#cvbjFxB_^aDL>{UUr|bPw^ab@{-t-VRCMf|r z$y5UUTsVhnN_-9}TD?Fso>-Nv#V{pEV8Hz|KC-7+4g&vMio#0+fo zq^JlB<)+efo65XoBTS__aTU6aJVk_59>HL8JVnIVYF?!v_P(uO9`2y8%r%4>qic*# zv=t+d-jf5>u(R22Q=!ANXEp)@;Vp8%_zUoi^H+ z6R0zG>MVZONw&_lDOFU;tY&;Tuh9&2RghFtXD?2qML@HD*`G`k5unjT`h}W^`UTM3 zzHlzwL3yT$lre9HzJuIFqj>~C-1G(cP3;w5sjvy~i6+dYkIZ)Zh~RHpNVO>;4m^}b zNS2hK5thi{{UX#s*z3{si76qUq>AR;3X^_YuQZaxf&b(l2ap1w;3MJCy!b)>wIrl3>7aeQJ|@sU zhAfsVC*|)*RHbdI3S2psjn$$^BTci^QMqzn_$f-lmAR_N)rV)P9!%f_F9FYNKb}(U zCz$S#@-H|B-C?4i_kgJ$Vrr%)$W>qC+&E{c=88bo7_Q>G`hS~i#WOCO;S@4z*;2^J z_f!BqW2YxFi(4JzMJ53w7hGADI0CObM_YuE%nEt*oWpIX)4UpRY#>_jUZ9_l5LTu! zCVc#bRMC^O)z;g11FGX2V~XwgP%^KO)7a{3JFc5ewS5qE;;0hxxl3pNSn_oYRTCgf z0ON4(x;3fxqKwNZYa{C?*q0zBh1d9@xJm&76p8VIAms;scR`$Ug*Czha8r--Q7?|D#uo}JJYX;SJm zA$rtOfj(qKNENQ9klN&>aF>J&o92uOJthJ`F)(Q<_bt0&J*1New$jpc$J;7{Aq#=SQSLmjv@*#YI?57)}) z>l`fYbPHu!36TMq`^StHy9onkPnEix4w#i4SYxxl$^X3nI#SAzGKxu!G-;hq>dUy? zRhnWy@upKx3~#brF9cp}-Sx8GuUWGO*}v9*Y*e6|WaWcmHyc?$+@=Q)#|2t4n;x11 zHA0A;yw5nFHbcwdP!%VOG9jVE0KJ5LKl3>}LqRuL+7EuTK8G8sul@-SnzYw7(*6^? zr1UsUuXTM%E6=qBd#--_yL}GIs3j~#$;mn?b7G{=*b>{u z!gy-fRopQo#nuch=g4oxbc38Dw{x8;T5u!M-8M-i_T2HN?2r^U2rs_3fA5tU7sJPt zk2L-eDhr3HWt$~Om|zb^dM|I$_@-$0^Kshhd@}pySr}7i1?38~Ivl|gem3LLYzIRn z4VWB!M{RT_&p{vbNU;KGy8gQrPM&MesA<&xy|+4PZU}=k=L1Re{jSN8=Fc3HmgX-V zpXFb8vC>I%GaIA+MTA$%xlj{G^Kq%7Yk%UTxdtFvD?ue`UdnGE&9A12jY6pcIk z6$hPm8jkY)S98Nr?BsS!XOSH#QcLxzq8-(bEGCRfPsM`CxYs&k!l=vUoin%~*9w!< zZJExoabpf*VaIx%YYVsEVA?`4&WlljwlGLjQ43ZxrJyXJPF`$0C)n}Ob`a8gXs-0$ zH-@mjI%^?jSC0piS%|rJk(1t43imui&LP*+5j5lWzSGi(LXItpZbm0n@gu;j5d|D( zUaW8)c8QLA-8N_6k4J*TwGN~5C%y;9`KR3(?6?jw*#E@{MD#`ez~4D%f?NK%i?X4| z;-|t?=?p(_fn2WB8<%D@KoXDRb%K2thAESzHjHaOO=`pGfgW(E8oAVe?w(8|L5BSv z%CJx6M^L$|g|oc&Px~sqDmMk28}%RLE5t!wpY$>lSzFV@i8~iPU67lJF}IvG^FZlOxK9m*k4^Y9y+b zlokV97)(Cp5#w3GqOu?Q>@9&o^rdt32C;@vUaMwA`;R5TM+Op{b-a11PKaILSAN$d zIC^2zKq|MxGHiF?0oYb z36cD#^`OM&*=Nq=<*|uwn?mbV*Iptw*7J>ka&Dy0{?xAPk)ddCnt(E3?qWO6T>GVB zW$VvXk3E0s(IVB;;f4h0Ha?G})zSqcvE3+LZdX`G1N$6_&#k{yxWYo1H7b`7)T(XW zwIoH1LObPbQWMz0mx~LMUO?fV<>huDJUHJJhe)FxGN4gLW+?%&NtCXUrYbXc-%k}? z+zgc*#a-6+7_ETi?;9+$R1x}vpW7yf^HccE75WAK&t8_$2amEH5(V`7YqmOGH5hyY zLl+zsNc;kg5wQ>Ql8;N`sL#n!fno^k&^!@6lBb!_cO7w{P8FTRj7iGxW>WsI>SBCC z+S}0ILdlI>SU86!lm5yvjv+R zr_hfrOLZO9B&-*k7c%I+)qYd{#^Dn0rhYN8@A)s?=pr%byLN9JcUdUZf22i&l_SzZ zeO)ZeL|=QP6Y8kc3ZA;Pzl3@xn;U<7okaT_+p8HaJxat&)CZz{4n=Gzo2-Y?s`zwN z!@92xG(G+KT*+Pug*g)-JM`km)SfCDq&7m%>%_W{`kEIyWxM9u|NnS96Zk5sEB+@e z5^;G!2t-AR8a23rih@8*Am9tWXjD|(qawu}H9_2?Ni;9dxK*odt);D1YiZT06xRkp z7FTSmqE?M7Ge!kb5m0&m@9*51w`5W1|MUOz(af8fJ9jzv?DyPrMJl+;{Oe7m!yJre z#WgQ46_Y^!3wAs9(e^!5zZb4Ed9K}#hXvGLq!|$8jXmTWvT9=d%TxfpRtW2Tx;s)` z@z)tE0~*x?LhY$V*)6Ej^ginj6*C6Mt{nh=WD8Kl8{$I*V+-<+p)hVIw4R z6L;yX#X^zV-6hiXEQKfMMH9hR%9DBCeu`c)D<{%g`&r(q+18ZY4;6ZHi1)605{QdI z)-t{mggvp~l{D+>N7(moA4+AxG6Yjo#LKS4NFmRq->v;?N}Ol!A938= zH;`#=anSKvJl#zk0&QDBB!DC|)H|)2Cr4(Qk{{w9&Nd|_8HMBbZEvPzr12&y=tw!@ z9^Ql{5-4sAn^GG2d)%{`Oj@-LzW;XLh6A+)@(wJ@$0jKu z+xdQ7{}&NkUOZ8f3j=y`@igfKrX84b+}0F8Bc^B!ei$>HwIR*a95_dBekTiBu7Pc= zm&}dR?Zgf*ai8AL;Xo|o`MmRGJeyPe0g6N#dY~nQQzI#R*PdoO*U=y&y@iHlJ5L~m zXnv)P=VN|C&So0Vd9+}%X)86-mGKP0AjM@o;~q0TuDB!*zM)DSkNX@)L{b;D%@A2%pHh{6x1dA8wE=_4Xt-&~MNJhB1P3 z*Fen9L#Q)Acj(jU3DGWWfVhGsTDTQ<{J%CnZu#Ms+PxXYmE&l}N2li&SVl zB~O8r5%3FqCfVhUs@NY-MP1^U}^_PPYZ*|6(uy^FSIiRFd+(a1&K@nIuo zvvm-{ORh`_;kU84%V|Ya5!a^!y&c`BAd8{{K!`ZSjh4G}+0UYYBKr)5&Pr7<-!26x=0fz`4z4dNK$L1fbD-;DcD(}T2ScZdRKZ7lh+weh(fQGjM>35 z!ogPaxwt|V;BcVsfT#@|p|JZBC$CjE@>-9P*9Rc4Q{ISy+{hcz_0Fg-E)x?)UPCio z2<%sQ9r`084L^h1nZVxQ0_SYNfxxc3!U^mh%?@5>V=b5aataZIZiW302}dMKUN{18 z%5O}1tJ}!5kqpkHx0Bj8IH`^Fo~Kd$|M7flYf8x7SMWPo@ZzPgmj9XnSJx9eYynI% zCAgc5A>Lo6rQP2v_$bn_MIgdmi7&i2cQFwj4ENWD+YT=nc9yx^jSrmg_e?QfMk^)( zcj``zgR5yDc+y+Gw-e*YN+gS-obSEH$#Lr>=v>PG>qCJNRVH9b*dlfC1 z-L0m&u)DW<+C=+l^G&pW`cNp^^RLSg?P|e0d`}bYAKvnlqCGYWK(zl&pAPiK2cM=y``;+8DTWa! z(4ot~zh6^E(*3f#)6%^|{sw1%zY$C9S4oyl@-`?=rdJsu6S2g!Xy6GLX=)ChfPG`} zF~vFnKK=>YFR*v*1f-Yn|EM>dx~`)oS5(HoCi*>wF;Y3|*9G@+2|1*rhry(W8Ecv5q;Ol^mC8G=6lxe<@@PJE>u-OkV{;*Pg0x+Rt9I zfE8puZfphrbWT+?alM&^PqYob=%mOKZG{)@7#%%!Z$K(RIHH&z$%3nD2HB>C1RrI0 zn$5Up)qR<4KafKv$c{_Z(L|n(o;-sjiol~M{cr~!bo%b$OTJ1ES3})VOMTUDyc(r` z&C+;_{75hyB5B;2mcNhpYrkFYdlV+%XL`sCj=VPSeWYPo&`}mXS9;#=;?IVyRc>p; zcw}rk_Cqd|*?eF%t?}Z01HZcilv`;JLdab$ggz&#EF3W3+x{O?!h{zYi|us14`*ah z>`-{v#Ev-zS9>3`N-y2HlCEi(e4vTciJzG(?bwrK6Ykg3e?UqDjWZtB&Hn@&6=&AO zQ47N-Z}G*Mt^(~!Rd`6?ij*{1eXF_Nt57i(A}G}=PIsMpMXP}MHn$5I&$}32WN45# zJIun5-`$?$cUL@Cgk<>l(umyda<|LvzKE+7{?P5tDeBUCC=I5WW8g!lSD4lE2EXY% z>mL`w+Lr1~Vu#20oz^PowwwY}PSFO)vA^P7kpCabW!^vWZrt8{?i$lw>Qp`nB=7@- zZUD}b(Ro%JYf-2rboCp583~g!)rTHbYl8PxUU%UI2-eGR^$OhD3G|SvfwSGbtMmxm zpJqjD@TxC$&UU&cXZ!o7h1!E<61;ZLl=hI=&uI_KsmN>I&1nx1H9hn8+{QWEXY(%D z>!@~F@0{VB?fOW%LmOA=6du>W7jO_oY$)HTOot%-XhKoSeIv)UM*3ytbolb`*$PCJ z3F$2wmm1B?+Af-03TM$NY-0z~K(e6q0-6ye1RT_ngV1^FN4sL5eye%e?UV*2wN}jw zhRO`;oEG9tsz!~-M~yf-P$Np@Wf#bWv3At&Y;G*0pfu=J+<4dJBkqsPw&cB`2=hpW zkNv+TnPG0TvhxFec0K}dTCh$XOvP+=O9kuHE@CgIraT&uU1om3q<7se$jMS~`(|6M z7H-t&$v|&&_aq%MUqd@xEiatQb7?!VJ2ItZ2YDFgh>I?}sDQP=PMHBa2rkY8npvfGN)6}Nd;cA&RnvhLiNjIY zCL*%dCu@de@RpQl>TmKO&T{jwB_81Qj*<6{b9!`Mrm(mKULV7vPB)`{`oDP71yI$T zCT%wA_1_t?(McDzq^)IFUmYwx)-qKcv+POxTVg(x`?9(*#W^*kO3-?)*ePgKCB|2s z%FrDiQ9)wg^#Ru5^n=l!rLMHxV-}^=yV^Uam!!j(VpvWcsHcb$Q;@ODO=i=%Ja4my zolwYLkNt6>u-;qMA0Gg?Gjb;<6fzv=nL=S?C=?DiF%ZUFYv(m~+Ig8`;P2|8@)gfk z(f9#)jI|28;)c{J?9xCKbXbISA|QyNLKL)7k&aYw*X-CTi3083>bL?+xEQ?mFwXc( z<(bX!5#J(-78o50BTE*Xbq;diGJdL~tib-6`?Qd@o@)hm(i9n(<|4kH5|M_f;@cXR zLK3bhNUg#;%M$->Bp=?Khfi--%7@sqZ^7CY_!M2|r@Y3g1eMjf;kFCL8I;4Y_ zIC^nv5q4+f!qO8%xnPU1XYZPl3m5O@h&E({6BqBW&hd{~x`7~XC&LFZ$n^2@$6M>1i2D!=S_@TVfNH8LUYN!?$H zXSo(OIkp#7Cky^|mbjM}FrZK#eCuuaYggRIzs4*}s94j6x0?NJu*dC&@H&?qA_;(GbXkq&HPh272r2?Fk$!aFR}?9mD4C zoTNvq0D@uvTTC!y#UnX+z`3s-52h&4ypF!5MS|HlXU*wKNQX8K8(r{BDHQ>Y zo^rf7Mb%D5JW|&(flX(oi>~&(oz^m$gDMh7AQMo4B@=c{Wzu0iYBrsMGXzFUS~A@B z6O!S=lw=4SlVrH`-;xa4)Vz>-!$C_OS-HJPDA>+?3Id`sF%2`54ZCJ$_Tuo|P?B*T z(S~mo_zYiHD)j)BGnxAEzc{8oD^t^lNB@|n|ADvt6qix&4EiFB{VAs2Vrbq_Tt_EN z1|{u*hy_#Dc)a&>$KxaBWRz+o3~GN>)HKWMd%ZFDSq$VoWA3gltpf^YwGKF2*AAXU z5mK9;cgy9o76H3p?lH2YhRIGAJMON%bCJd;jHlyexc*Ey{2aYXZ1n=a(>rwOxVGn> ze^iRM|AqIFhA+f?H7xP=*%9OI8rjcy&T3yD{y##?e#aGQY0`z)bmZ()JERcrN6n@s zf2hhkb9N+2G>+I%A_i3X72f^ZilI*xr&^&wsxLL?Ii60(_JgN?b4oSiHJJpJ7B?|c-O+A z+}@@jb2V%1Eab4KY1tVmCj2);Muj8;A+#vtz*?pIuU>E_0R$$M$ZAfc1;ID>btMQ` zf;69scny0f{2SzmO!R(;_MBsBur!3kR=?AOAd%`X_?;{mYfrrPU!+)meJ@zP0?IQy zejo49f#ttBIK}d{iECDk`IZ>yIX2K0r^EEC10x_{`oHOwV*0jtRu)Y_i`ne{`a#C- z2VWJi`xRcTo(%N*x+iINUrP%=%I>GC0Gzix;p~7cexHh0`422Vj8_S4fXsBK8D1?j z0xr3?E9hq$0od7^0i`?LZnE+G4i2miYhY}`3@rgj1l7|%{pW6C{99uPxMOj47lKqv z*PbC=Tl+)}F*qkD@Kx!Axb|DX=9*o!C^Vhz+jcrcZ>6xrqhy*RTtDel@xUr@O^Wwl z`BJ#8;-wrB0}&lU=qcXU1%Y{Ro;%fIF5F+_i>~pjr%3ao)D8vKyb2A@|P3}H%iJmBxrc?%~MVw zA+6#taBO9%{H3;;LV}@4Dt{rxOu`psoh`BU6lhONFw0d%S*(;0f zy8g}+#1aX+BsCyJ#F0M_+(FS67bfTym7YH$6cy$cI)^ks!8Xa7q71jt#RHtE2ps(b za=LK~?Lw!e_Gh|<#M?c(7O4M4;kZ^>cSm+SV4}17|L*K;f#LQ^1`ZqsxyG9egX_wH zbI-{pE3^*un*fQS^|S*A|Fr{#|01u+0iWY+ifzrNsLU~=;z24Q|0{n3qXLGOmL-4w zeOKJf*UFWo!72vn)o$1#$KNko8oV*6gEV+yU`iUu6P4`{di$gd10a}$o7lv)F%F?` zz1n{8|CrZzRv;0+_0G_ff!^9n0s|mCFyai_ap>LsQpyo3gHYJFG21!B{zf~W?iiie zcFkwA89A9434kbFvnaQAMxy^ixfP2!nu~wW*7S(?kIcPrT>XaJtGC4b=-<#<8yVi( zo=2u+zN_ikR5s4ITr7S_G=3_^;Bonh3-|K2n47Cmp)i&kwOVn-ji-MrXOUV=83qeT zjl?l24_Js3M3!+XxU{F~u-_oEp--ibd)%_P5>X1DIEgKmc>W8^nxRjWx$@$jB13zj zOOmccYb6m|2-!o_9;t}W92P0*RZI}t#GNogNv=s?(<$uHJhrf`X=0JD6a!>ivW$Rk z6-)hn?KCnZL8zbCcYt7)e4Q@3kFzb%IoYC#%V0WV%Yc5(KxG}+^+0}_xBa{mwIEV+ zI`Nfdb90{-KhYNNvUndd*J(=xO6lA~$DyEKy*1_fPiR~3-&%?P>!qcVEU5z4ZW_TNT?^t zYkue2EtKM>jZULV4?;AELy2K*6x$>UqwJYJl>VpwBn##rPxWG(+Y!zZjX$@zwC9X- z&z!Y5=Zp)^n}N*orf>aea-PaYTLQOrxKsjOMdRn^lc|FxlEW#%zq+V9R|qz<-h29K z)=2;-1W2>mWLvUYvU6B@GY6>K+A;|+w3SLUg#6?LYc$9k0S8{i#-))a#mJfmoAbow z76)WAc)MB>fxYHmPtk8`obJEDTb<~)rtUBNVvpsW`ZUpdIODUOC_Uon0#vHSYaAhY zwy(QCZ#n;gYACvB0T*UC(wJmkqltp2c_0U38#M;%$Mg4a7P5Sjk%mus8cvM&uYZ09 z{~B@5l@bEZ7R#cbbF~1^nkU-Idhbt9tsxo2mGt+#yvoFx`KuwD%EAfFwM7;Vxs!tl zA{YV!Bo*}>nA$K^k{B?ZDm8;06+n%Up7A@y;-jPSbC6kQTTWW->Vy@uxr#Bx5=EKRq}h_t_a1$n!;neB8((bv z;24T>5O$Yaoo+c+E`PH(9MDpR)g`=9JkyrewGnq(P)Vn$H|PiR{?{j@fd+lZ-$E(^ zoK~uHk@#kbq-!1hGs+lgK?*l>tA$mF!&&~qh#6vYvy}TL(l|ljg0e`74Btw@eY830 z?lE|UQ+6Q3tQo+R?JdyA-#k@AXsx*_6G(2bR@%G&JHYS&SmQG zBUcnhyab1h_^Y{fD^X&D-cehd;z993kvieY{<^2EABVEsB4DJL3<&NtrI@RGn>zqS{ry}Mt%BaN@< zSK>0|QivulD)a_C$O)>7Qtf@~Ga(tTcRVw$2f#tIB~^3O?SvP)Tg27R194Tz+YV%G zD8sDHrZ*x4hxxsS0*6?lBnwBVUT?k6|Fs%@#*s1De51f%I;l3B!sAg$Iiz)E{JCVo z^G8AAp3_+Et+JlgZUtQRc8`_gHOg(wvwH&Lm`_y}b!k2L(*fXl6(?K@48A*EKh z$W-)5lO?GRGJ5=pZ&8Iz01^-WaEgk;(@TDo`YfE@j zzlNo?TMb_ts9t4FM~u_v*GS{L28c}6tAn3g4nR!Pr_5fgNL($UbpZ1$p|$It{4myk zI?&U+|DNj7+il!ph7N=$*rB#RkVqCZRY8!5St-5Bv$@&BPIJWe=x+r#tKEW`Nfw++ z!H07LO)}5l2bESVQ5Y+hINPp4Dg@##>U57fgOde!OPO(S|1nsK6PxR{b7C`}YBJe0 z5_1}T7Y4RcgIps!CVD|CbL?KZESBgwVtW}^(BlTPGMmG_nWT(;pBHJgT*aM3OND#P z+9eo0>?j$c+bhX}YmN}));V;Ol*sc(NM(RB26-n9g&lq??kTpWT4F&hhDs9H;CYbMWQi00G|j>Lu6)o%kKhPShZI zSruu}(f~@@qKkhL>31nzC!|-ZIWo4$*uj+8Ag6No<~h4}d) z;-jB|JQq71t+eT!B7d#XeebHr8Gvb>Z;JOMdLPOIDMF5et}ttcRibCTFK$YyL%ZqQ zmIlM^jpL*51E((3A>*TedMQgCnn=;^)S+uDyHkgz^G52>{?@e-@!?$pIn6=Wd(Zp~ zUuDQab9)3FRLm0&N~&SUK}(xSP-_|yEEKR0%VeR42<|oKirE|@+#Ow{s?~2ez(XKMM-Jd@wLaR$2nV<>1|IgTjISttEVt|_hRJLRujZDS zskjx~YMauA&tX@e2kfe}>8x>OYZhWDwo^Jg<4*^6waF~vKc+dQSHoZk$1s#khOpK3 zX@($1;245C#x%tcN}K1HfnzGw`*br6<&YyBVzeA-x=CtMux&*_{~>2!uhZFw1(sOU z5|@j2E%wF^v{T-Fg%N7vvHxH9M(+9@AFlSd5!VRWL?*LI7VJP}ru(F@t6I;=`xFD|2-B`VxH4w zp4I~p)KTIF@4Oo_b(zbB==f_3yCFo8mh6%`yGm_0swI_}A*w88n_DFChrF4f1ElL5753bxTPhrBdJM@U z-}gQqEkdLZ#?QT(8vr(bosqgN6^=)x)>M^4iTGyAi;p*%FQS`nIt#lxX>vZ})H9@h zL-B(eG@4AxV;GgFaGNOyFk?~V>XsGp7m5F+%XFe5zN7O79gdcHe&K|s^NU0hv#H0t zMWT9DiZ^SRFVG61rACI<%@p9JgcLg*!4JGf&?_~Ivj3nu5@|{a^zofS#KAJhxVb+H z;%pU)Z4J1vtC)ssC{}mnINU&sCX7SMPYZo(oujWb{uvVab#y=}4-6x)f~qC&t0eDB zpJW6%zD_4h1x^a399kp_>NV3~U@N6$3yrRqE#y+ci?fNMmHl*?U0wRB@_?YVX8%6V zgUNCcp*CL*0FkEhke-zU@gO5;#0_(D*P%8i{w^v2Vhr-G-3iI=W8Ig|d>)VE{BlO9#K&8T(&@w^ye$+nJsc*d% z7o@y^o#cHba?AFE6SiPdKT394+xgpj?Zbf5;|)8h_dQ?AF!F z(nWd;!IO8MT}Ra4`li95>It&|kNFG5Sizv6^2A2FShL6oUKPb;Eg9Wr)24u{d72&q zu&fph1akZ*M?TM5_28i>aVwc%2H}6`0HD*8CdflXGQ=3 z=Z!xA5A2e&Z9c(VREjONRAnGpev~ADk^G*Ke6pM6A6*m~N+7||BZw;M6*aKf(QhJWLfKHXvpyueaBA>kMm;by(Xncq6cO*8X^`CYT8};-v6{ zX#DvsOg{-?5sO>oRZu*d;1Gp#@|wp(HskxHfij+zn+BuyXhMtpjvM&zVbC$<{WM=3 z?*&L2TSXOGw6r`cI@AySgIPPH45g(mnacr}NUb&sK-Ew1MUJ;>aL;hv0%hT17-?9< z`}k34kC*_Jd5yD)xBwM4O~pzIK4&XL4{(*0H( zBGXK7B25>nW75>sTdf>mNc+l&D5;PysepE6Ay-`sBcGHfNz8X0UzDERMp}TG9vEU- z7K(`<%OxmI`q3~USq6YXG;?y(q=uxqvh-A&`HSfk;5ae|%MtF?H8i(O4K0Ot9abVE;dzkRx|;wBaK3rmK#Mq6%h zSrOSowYW@N1e_yF4JTbp0C#O0Z-x_{>Y>U?AC*lTJ;r(lm-X;|f%A@#`X|^3^ zSVXqMi;PF*ZzdH%4Ql&Jo31Ur|9JS@Al7CykO#S-8&0z*mwa#3z}^56jl=NVrX$j5 zrV4sI2!Hr64ZRzLhaQMNafIs~;$wA{1g>xqqtcq4{qGQa8y<%Uf|*;*PXT_I0shhy z0f&Hp6z1%3zCm_l@YSA_1BSyk1%}()kcQ!nLmdpqiI@BjFnp-28yJ2wpfd~`o)XP7 zARsZZL;^%JA+OphT@h-aH0Kd4VB&TZ3}^G$dwXwU4n}OuXZ7>>>9_1_{ zHTRI3W3{7|tN$Pv2?&cE2-|o>q}@-T;VaE)5FS?IK=@|wjv%zUv?l~Klu(X1G`!!M zxXVTd8os>)63U_B7Q9KL;otjr24Q0>#36HXW6^LnReJM20S)_hK*Rc1Q)swfnkXNH z(FqMl8XCT))}%b7>7O)a0UCbqWSZE{^^^mKBR2&N6Y(?*`|R#u_`d9n{{apEAa>dn zDW6aFt2i+6QXTr3IoKTPrb?Yf!bM1B`j%(24R zU~UV*+=0_z9;B!E!l6vi5|IgZi%}{3L%gCwI|s3bU1YrTmW*0k8o6UpbQEEzceIu_ zEUKC5rWI+z7x0j)@}ssa$W0xQrl$o_9avlv@4abjZs6{C_t&ms-is6)ngyXzh2iZ~CvUOeP!9OIJa8!~Yc>x+EGI_iP1h zEH65A9lxKC4gHSGThUQVBG=h*8KYi^T=#5>PE*}JJR7L&vCi!FLlA&}uL+s43loFf zn7tG3hWia#t!@QkdCD6E$L;c!o{T+ftmP`W{TjQj^C1P#pJ-$J&@^IjQ3?c)QP|gc%ihm9 z9wGBhLdA!O+T)A-_uOax(_GuFSfCv%n`KIu|57(-$IrRaflX=-Ak%$W{k9VC`F{*c znD%{OP($tB=F2+k0DM_HTVKTZ_VfLuzkm>b{;4-RT90vbV$CH&+ZIo?XS zkoo4^Z98fxunl`cr2f{?z>-ZC+)81E-d%K(oNihEw&~OslfRAgG;uEA){JU*tKz_M zrG0s$2lXt#(!Kg_+B3h!x%q0bV5S~`&M1XI{#|e8)wt8#EnMmgx)tNC+2buE@~(c< zNOFdAy}fmZx!z__Q0+%slw=?~TsSK83ICe{YEX6gqg%Gg^CC!4i|eh8W~5gyQ*-P# zx@Lu3KJH#_m;CZ(XU$91dsBsRz|GK&Z#T{i)fZCIr6t|OHCz^QcY1m%z07t5$xRqeZ#sMad+x`a*MFa^iRvTOZR#Pux>9S$RW0kv`RXd; zyNOZbQlFSNp$V?u>7FRL%2hH)N#YjV^@U7uEyBf6~#sJ*bz3+hyTN!KN(KD9WHTByI-1EAMx%M z&iyeX%gzj(-px7nqiAb!TG-1d*=A!WzOlKE#A+nR# zPH`2YiPgxA}i)-Ivy(mS=cls?2LAYVFOy)hyI{gGIo|hPjiH z+R7##B`FaL~^2zkY03e;X}}m=t#3%qASE!&DH-z$i_q6bVnT>oJI28 z$$#PUTqw7Njg0JklIO{S8}?yXt$Lj3eX{_Z?YJxQF22Y)?sj*W`=7jx#oV)t5M^bk zA5-!wd_|5I44Ww`OdX=`{t&%3tC!-3tVfu^_qV#*V-}8 zv!=s~ZDQQki}Ux{5+r1M9@Zt5a}`U;0-6@<{6!&MEBxdp z{J2^+ETOuh+*(}LIImq@tlEnUmv*Yf@{9}W2LDKt>34ex><@;Ja6U2yLE^5h9M^VEoG8c zU0KnVU!C=DI)I!Ew1-ES(2zFnGaZvsxJS!fDgPHdlTg43M>MoNai!hKCjaMMdE&m? z6L_?YnA0Vm8O@s~uG+E3-a9&dJvAFe=I@kD)RbhpC(A*rCRSo zI-SXLoNz;M!kz4Va5Dh8!#FhfA=1zDz58G_Gy%pP^1si9e^|PsAA+BpkRJHrO4Vd% zCkR`IGJSE+Um99>E4_(>oOM@&@sn-cSzUn>#Dy%HFU|>T$DVM43>w|Rk95BI;)=Y# z_Hfpnqlidjy}E|LVji3uu3M^bZaAahd9R_;o*ei;5DaoFVjjQ$&k(O0=0X&~oPA^T zakBHn-IgNvH1PNMJoVYt>CeVd5(oyKxQ&Bg)2uWEd*O7{8s9aYJaHQb!QJ-h27>40 zWmP4Q$gsC>rlayR3J7f zoiAjQDxxk(dzMi1xcYwrJ%OkkbI2w2GP>BwF@Bn?QjgV>G-9>{1!WfY9!fl$a~7}k z{)9hL;QbyiUBy2kOZ}_UehjNPK+rZG23|U+)CQUo=fU(%xgVUDE=15RbF#qOXxTD0 z0YNo%Z_vL%(09#e0ad3Ev<wI+L zMR!sXa0Wg)L#m%7@fEdc2%dpEQV`s%lb_S-`biSsAV!<%qYEMU{00SNU}c!li!|)O zP&Wp@Libz;{5r7^b>KI^NRB#VGiX5$Q^H^m=pR?zA979P>vKf@a|TFP!n@;F)bZW7 z9r~e?DJ%^Lg_DrCiN$~Bw8S)(ygq27#l;Hq2xdzT~`iRbB9< zTfNk0D-d`AJKNxoh zQ+z3O*>#xqsRNm^djjX3h*vyD`~=kv!$HowTkY=3yl5xi-Q^D7Qf{Vhe0N0|eDLdn zjh$g>o9e7rb_bsXs;74VH~vy{;9V*IU7b<&m0h{-uGeUcV|UlV(0!NL!K3M*e?s8H zOY@Z2ycCwq2f+g@3AZenl^eS9wh3H$5pVa?S93x};KX|!`pj_RRd(gW`@3jZKDeZSiT)!6SYk)DRU@@{E{OKu)G@^Zjy@1_Mf@&-Cb-t3{~Q+x3| z^OjBMrLQIzN1P+?mz?txI`S@Y1^?&@4$dxk9tF*jccd$Ir7N|jXI6EGs+1ggd%9A` zxl+rrOYNjma^&@PrG~pw4`i46ZdisR&+ug1+dDb(?D>~3GJb90GZ&dNVZ6_7160EV zjJwCA9C-$uXH}dG(mCz>$a(e@ADRmAt z;TC@T+F8+lR69zYdGOTzz~3eYo-8WR*6wa*!Vc=BuJ_?hLAxf7?!_2<+V1TJCk*pM>g z{!acy<{l>s;_fKmKuTC*&0depeIZi*yds$zPv+^G`LIfziz)`HnNS6#av7*jLYxD~ zA8MM=CNh+O1mc|)n=llJ;?;4PUVE1j-3bj|A*bdS;+$2F(|yiA-pw)oYI=g#XSMVR zdCiuv_-Fg^KIMtb8cxG%Fv&eFz58jaJW8Xr$&|3Vy)E|XnKKR5p_*=Q;4MAGpH<$B zQQmw~@uiA=zpT7@YVqaegsxm+A=-6xgDy7|*9F78nFmrbZ?=24-vv)b*)!bBqt|rF zW)zU824Xpf-!|Z?WWn4W2JxE)tNh6-g8nI)(;O`Xvd4@=>|8y$@n1E^vjgWCcHmT| zU<$(J5#xaM(j8p;9jP5Z75R~VxwsrP^Qn#ICoia9PxNeAQ{^~0Zh_K68bG2H9BwFX z<#&1FQF}Hau~%`KZISw#p_H-rJ<`a!uYnLjz%@7u;>-uWlml5)Oc5Q?s-9^qHshW> zxXn3g0lz3JGW6IY;BYv>f@s@M*-UvqeAR-Jp0|~gt)-&N08F5k&1_MSBQ^~k|4XW*W-%{@|54EBqq^dSBUUIUF~?o* zvJt5p|K+KGb%6U;A8|K^yZD^qy>z+D#cbC9z-DH7^vb}o0sK~gpnjM1sM(>ig$=$M zyS`A$iyd$JQqgBke*_s+XiQLOOlF~VH(H?^e}}18hA~=Izkzyx3)buIB*HstD#}ck z6!FCUviR~CfT;5FzvI{<9wlprY7B<8nGmWr2;pIOTcT|7M4nvDbQybiSb)>8VSEJ8 zR4X;D{N(;`Q9aWA`@}mw=wDx64sX?Lf>#zN!zeX*>{nmmEg0u%sEykhMVe#hP>gm> zJ!h=AoG^;sDd8JV^G?mS;$!MtF%CB~p5T4A#imU51f{zCOiBgXydFAo7^SykKPMe?YrjQ%SyI6c}biP+4^qj$M#Zw{dCJb*C#*M6~UpS7P;lo?m zv>2WLexFG#dwm(reJwWXypc5nDw2z$*F4umZz@N9TifpIh#M@W9@BN4(^d4yZd0h&ZXX9;3a6qA1t|h{L;% z3dJ9)0qGSonVB7;OmW3AZMeuack!*ocHlPgV+Z?lF)#$a0cl+S!aFbF2zC!9tvg&_ z>Ai7?!}ZCMRZJ~XmF~^|-1Z!Bp zy{6xIU@Sgd!XU4_>C(cc=hAiDu;e@zHGM33z-n!;5Isai{ksRYLhAz_B*G7UOk;T%H zaLCSK8d?#3hK%e;(OCS_Jj-d@lMYt6^L5wCOqRO3S)}nZenYYTAW`?6Vx@umaV+W% ze?sg6(VQ}JqmW9PkX9lcj{as2@TucgEP1k?ReOtB=@TPHRE8e$={6MbEyGrU1t_ER9Uek1wBIwNx%ip#l1TekYcpD^SSTh3>#^o@J@ zc}A~mqq)nZ^xdff)Eqw?jN>#nyH)nVH#T=ErBJOeuYTQxnK0CQkF-?XV+IQq1DKvz zF$voz7a!mbv1P1<-anQQU2xr+9|O?B(GEZ@*6B@T39UFW0swvA3jlqunG2b*UflTt`;y%tW|6!-V-hO{uE47s? zbzOF;H&jaY_LHvEij%Fb>g-YvtCZ~R+g+*ouGGQVr4p1<;0)UWGstAtX^uo{k53l7 z-w)gINJ@wYHQo<&e4T;7gN+n~0?2gl^!w>fU$4*J7{B^B#gJ?I!D4F1t5l&kMx_pN zze^WkF7N5RwwDa~#qERJd$sp)pTcbNgH!Pe+3!aOQG{yY5=n3SgMkG)jwGyODZb;A zweQ0tlLh@Xn%4tsvP1ldtP0{!uqO#YVWF_R`KqZCnrCF1lJ}U(jKZhz6hv&=o*Xx( zHx2e8GEN5NROY^{Zi6h!H~9bM(4;(<=Vnr#VaVY$oRmqqoKC|yZ*W^n;GJuE(9xs} zElO<{G-g!o#JxnSGbxW7>74KZ7vCT;EtB%!y#kYR4Np=gWf47*NvSIwoFr(}>dqq4 zJXCx0I2|)IDcAAV>279H%ACAZ<|H=dxy6^Ge{7^lSz^P_Fe#g5F9vM+Dt-sLS=?=D zOBS3MktlF?fr)vXK521b)0mi{g?R)P=FwP~M_^$_CF-O;M3qUgI}?tSg^1p(+4I$} zXV=DM&$MmX%9Mn*rMRkWOFb(~oR?#!WiD8hZCWnTCop?Wuh;i3GcENy!?bMU)@FVc zKO{AC)M=)nifc#HQZwcK;o~k$OT7tA%VDbFM@>sCP}xxzyyk5UaE*$mtm3LxFR>+X4Yk`GcJDx z{+A_c&9*$IEO88k;+L^#VW@4`Nst<57)=}uD%Gl7v3?_a2 z2F8SGQ0ge7`$;zw^Aj0yOs!$E)1$NjEhJcNxk(nx+X6l6DJh|kni8fJCs9Z&{zJ;d z{1-EoHZec-wmdg9F+YcF)FF(*z{HFnmSJ6v53S4b2p8^=i?Fq@2tZlXBl*rA*4Hzuq{Lvf(@B&*q${mJuaKIh#i~>D|!VnUr1gl#V84 zrJ%)t3%#jNU{c=Ptw||naN*tol&sU6$P7{@WdNng-vXsA!Et1_W5J>S&h3xHX&=~? z;#l69vt(CRc4Jm*r5LmFc!2TW6_}OBb!S%Y_Qp?{mGSo^rGidAxQ0$%?kvmwsaQJW zk6M<&cbDk9Y0kX7e+x4l|8shro!98GEfO^*2{)_v})$R7&RMNv>3r zE0vpF>L`_xd3m5Kb-F9{_QzQ*?nSAH@(o54Pr0C4X%Cs^<+ZH;wjW7}Z1a)_p?Uce zQqb{^p1-C$eZBj4lzD0Gq0-2Um1SPO^D9aP=H>hUF!ORIUr;_YFZF4*dHHIOz`SHd z(|c-9XI@GX>dL%)l)@S2WmZ0B=|UvfBmI`GReo1@)kq>8VfnaZ-^bP*of_wc2AzZ>`=r8QsLwXMW;?j-M5agN^lNzPRq+2AXu zqpyg*;YGrG;_H;d%sH*d)yF$rEVez z7L}DTAA2xALC)c#Xnae~=)(kwG-|UCvEnaMZJ2zRq`_ zqUV?HQQlm=k5sq9gfe#bkwsh>&(%lND%2kyp#D(06dBs!78HiMM6}6*g&PL487E9j z>)u**xNMm^eE3+kt#nJr11#aH9TCg8mN$|6nk(~P+BB#5eSUr=Bl-h-cTe#rT${^E zo63s^Eh;O`NtBh0A%u@)p?H&yI4d$?3H9Cuv2Z(a?=kW-9dR~K>(=#%+y*SUKYSl< zxE^;-WWuWt=TiPo%17p|s{bUn{)1eD7XSp<-gTUf#zE=A4SW)zUB8xFu@>0^G84p{ z6jZ*(t~V4bZ-=`4I#-Pua;YkTjx+uHkK~e@W)PWuO4XhK;XQtz+zmGrujK}&SF@|) zH|DqXisph1>)z8bv%yRbT^y}nyee66#1E1wtTD&m@wUH>U0`O2M{aLzSRQHk28)t0 z=zX>KTh0v&z;A&H`+%`RWX&oe+>yo|^Z+p8Hr$+A{jGGb+zwyjABdsv%~P*hTxzT4 z(p=y_urhH$Vf3s8;;6A)FN!T$$A~Lherr6oW$di)2j+N>>+S0UX9yDKq@-phwf`Fb24ZUwq`4FhEuBaEJjm-<{GQ@EuJlfkf-niG!U8Vd61h0naH~SDnUjiVK*zOx-8>v~4zom2 zR>z8$N0X$W`Bcx71)J%k8ZIp$ z8tgY#IMqwF@aFnd3zdn9vnmre*6~qfE=i^gLQfTslpV@|Yo|`8$uG=@td%{ELsuiwWSex;6}9Y88mg&M>aiJ&F<@Gz zO)@??OAp#eZYz#PL9mpXLX>&_mq6Lh%Z(qd5!u%?Yw%kyxGTv`34}tQ1jAq*zhmO{K zi+pdmo64f`X?_A2(sb*$FO7@-i|cpbM-5X%meA*h@tIOFYH{Q` zZT*M;(N&F$#NS7KGZ2FQTo7#h%Qie3^~1#x`xw^iv9IsB_8!C6M2R(IP!;u9=R`YP zCfL;#a|#&jd1P#KO`2a_cF~7;+*S$KCbf)Nm4R#VcgvFhA*x8z!@d=DwY@1C_h~Uw zzjuGS+;UcKH2HjOyFHn$Ct!D!ete2qH@}D9*B;dn081Y@z?%i{(X5XFCYO<4=Uvtw zBu?EvF5Wkqh@!q?su_4et3s2T-!X27Uq_)c3BRiR-bC()dFvLtlpo-2PbV-d6ypX} zxGg$5Rz=`}P_WBTk>RS^Q{S&Fuk0VW!&{}x#XD<_^}pRzt#RA0z`w?~2`>vp!F%y6 z-LWQ6R;F{FBUzRsjnB&UlF-qb%nI>^QdBts8!Ihk=AOJjBvHi}a{PQE?dOS#TIcmd6VaE&~cqEiwZVO8zDyk6?5qtrC3f5nWiAm1uaObyRpQq22OS9oB{o-p=EEC6;NXFF}cbRCM#$*+|xA9yi zS;t!tTNrEEYko!UI}+=4^e@IJZ?@|k=W)@{#JZ!`ENIdtQ-}Gz3bs5c9j2n?lFq72 z0I>`x$bIq&#=CdsOSfm?s&xjr(i1L%fnqYuq@>{X}1`cEO; z1wN^fYE+7mkY_sAU|RJ`MOxL5ZB|GeIHc0bqGnC2tU1=Nz$`FjY^A1)?n?}4b+zd@ zj-gDxLWoc?2Os@#2~I5bSFiuVby1beXYlMdYm$C{%}u(@>y*JR7QQna#6XR9w$I9~ zU6h_A^%eXTc+AZ*$94CN9mL$P5Oc?H4LQ(n&lPiLsnMAG+B9>wY3d_rCJC$2XFA*I zU2iY->er}ioOo9)u01Q%sOr=wtUQr{G%CTQm1myc!)aDlK=>HvsR3p;G(dq&^DA4| z=rqx*I5A@{!As!w_KfE8jv>hv7=IS0nm3OMIN-EH!5$P8ooV2Ses-W-zl;yPYxye8 z<8EaL{&DOT)f8I$^h1=RD(=)Z{(N-)2eSX3kLAKD=$$=v;T^V^D*E*FP@dAK_)+2P ztBOQp+EBQQ=anr_ZxoSf(1L*uYTGQJwC@rh0qc(B_3_!=keB#}sz?@0`n&^;RpdTb zk-J#a&rxGjKrH_(L(G7mGD1@`)Cchf%&v z*qTW8f598UGKWbEC8;f!t2YuFZFaq_c$Kc~o{03b%@d+Pf7%!NI3!QJT%3!xmPbMS z%{MG1Bn$j@{3D-gRUy%P@6QIN+>S>&4yOyd~$H%%a4DN+HCd)YC z(3WBKz9fhofGi9Q{V>=1jiZw&+x}?VDz{}RY`m91I{@}B}zZ=oKhu5`e-iGH{v_C6DdHiO@z??^NjYp7` zJ859jPOi{9sKM7Ufb>NE5Ku@kkIzJuXK?g!T}-55xBm`Ru@aW=Z_d_Q97K73 z4nIU|lJ(y3yI3;5=5t~89DCx=AC^7BX zbwKf=aiy3Us{@gua9R)^ls|hKmrFoG-&XVBm;B z)$vaJSKoH@6{$xi!5D!tf77BzJr`-X&1w!j484})ee(a*uAy>XMzY`(mR|ig1PsSi zqw!bG6x$mxJpUOQ#$4o% zIxj$Xboq-2kRF{}`~Jf?A2cF^79B8X0b_#}zN4;TEIuF@+sptJ82I&~*oO77`iSl;+auO-!jZpEUt-C?J(VFVe7M zAT*Z&qh!I8A2B6c@Te>Au?Wb^ZOil^zazp3Jjnh#!r~A`9r*6b)`n8xGp#7ra=`Ny zxnv&-9V8BHW)-R5Qi!Ca23ChZpPt*f(|!x`yW1X~`reA9e>_4OtMBrr0a`|}p1_RkOOanbgu+Jo>SI6rXx&T!I- zmYH&5*7m8WUsQ?%Tr~@j1_f{CGn{;fDliWYkm!+Y#qsvthXZr4U3+Nq+N_{k2@sa* zL+J#oxTZQ%qVczk=w&X% zpVln>zgW77jr_3P_G}tS2TJ3{YOm_;L%`Hq){dnwr{*0WG6n;O{Hu|s>vf;uV{M#i z1&o#Ue;>M?#{KX$lUfFlQ;JJ@Np37M!HdRU@=rCq7(4O}0a)Aq$90w%T6oG|H` zBN?*S^lYD;c5-ACoT}F?WA~?U`|?emfdi-z#~^1@U(Bz6(gf7-t~cS=eN<_C1Mvli zf4qgxRxwV|GIqHhjph*nHBdzkU&u-*Rm;M4kwhJ}=)N$xznS}as@ngjoLekH-)V}& z7v2X4VZXs$Z#DsLs;km1MwNuj9sT6J=QIWTqJD7^smR;ZuzkTc2|(R=gt^SfA+B0l z%21-US}{7%sw3s|C9I9Nl6FQ~b)@kgJX8M9SEx6b;q^4)zb^M7UdM{W%zXbf&?wj; zqFzOs9x>KwJ&QEns~eK5-pN&Ks33#bfH(d{P`8SQ-k;X@$$Ar4N{9pXCeh(dMBi|T zM2>eMZ~S|JQ&6S2npfT9qognWCbONlU*H@0o4m35=HCMCLT>$~{L1`#=Syk!pDH*& z1s_PiuH&cIQ?F<1^*8IX`}^iEcypcJyv-Y5nfCpe9lCamdZ9fg?Z>nq?N3pWrRgFD zkXuzvy_&i$Xdr_DS&12xNRj@RsXL^*868#s{6@bYx;?SE;HZsppXH*b1S(%4)Q)&n+=j_ z&of*F(R)jHW1XWb{`p4G^R7y_u`H{|St_Ea zY460KNJj7P`jFn^*$^oF`&|2v!Ajux{M@7j|v@vd$-|K`74 z8w9yLS3B(|snevqF`_aGI3sa#VOdbZCkqQokxLE>P+0%^_P|h^ zcqF%dxatIm4_P<+Jdz9YWEdTFu5f!_ioqrBq*SM%k%mT%bW?&xwxd=j;k^s9-Tnlo z%UHWGmxDs{yqRkZ+$;dpY-c#!$;sLFmiS<5Szz6bc=p(7_Ha)kyRz~ZYo&lpBnsv# ztavK5x&=!tQEXR53&AAOQJj>_>O$@5(Uu7yrDNGFAbAfDa*4afa za(0Mk%VAF>m7b5x1Eox$Xm+b`M-*x9S5ZoId+k5vu3@F7w0Zhat&4RCtg?6I%`-ZO zR^_KdtMY#|v`Y9PlS%R-S#Z{yF0@K_QivS(D0~q2Q3*CN){Ijb6{*W>i&V z?j!|OMdluxim94zWiw)`#LwUd-hQ9ztj{dD;$mKR}r9+9}!);!QsoI)esrwsL zj+N>!xC)}gQgt%C9?3OWH^+)2P0>=#k@RNov}-q&M818)k;pLOsurA|MI@ZE20Cah z&S+(V9pGrNH<7%W?n_yK`!frS?|nUhM)H#d4^ylEs>at)NF9~&Pt@J2SfYAZYT5Yq zl3>~Rs6r=Iw3+l1TQ=^od?4R^Eyt>fhOCuiGLf-zEJ6wwj6DG={+^t0tyjs4=o#Z6 zs%YYJ(Bxv47TGr>O923}kc@f~tP0Ds(a<2T6HLXe6Hk^mlZ7`>O~uX867La zM!Odkc3uor%;OZ(K`Z4<61gz&vgSj5@QbA9Htree=&@BIcp-E}%iVVhWG!P4ex2yC z+GKxz*A?jzC4}mxwTUkE(6rEMp6VaWBBm7S@8X=dbJuWK(BZnLZ_(RG<7^vjKrr=+ zB74!+eIIM$HD1cBC^GgU%~F$swGgjOWf+IS73ZJL0n=RKJv`ER|Ll!<|FqE$EwJWl z^Ar7D@g?x@Rdmxp^0ZzfvSxFwdpZar`%n*oOW-f+t-?}Fcq~6kQN^f*dL6BeILzB( zLf|hFXNpdW4{obSE{w$~sXytMGHX==LKR|4<_HL#V#;hZjMh^xz=bxu1};u8eOQQg z-oHQW$t2x)r}{OTuwkmLh?Kt^#+1FTunZSd=GkPtYz~>Dd!zK6Y0EXoSWKA%pQVg> z(_8t98IyWO;KzPiUBx4yX>~DWvw7iNHa`_prg>0dTO9iIKZtJ^7#2%Rm=#O3)bT1Z zSFux+bFp55^Cg%!Zy!STf^aY7_@h=RSumTLEZl3c5F$4E9uv8>H~6*rL2<1LTFx&e$kj zvsjU4l#s6>a{Gd!7osh-r44UeFin){)0|7cD6LBpYF5XG{xgQQ8KGw10ELWDGr=J{ z)U1ssL8w`&Ld}Lb-{vsypH-b!iAJVE%~Vgap!nZ{y@i^UW`&x4FYJ$M<*A4TXADCB z3Gie1+wEgJ#g!G#MG`|Z0+1ZCvPR4?%Qf2Ko@<%}?i9Hb)1}{0Bwa~V+YRElXOy}` z^wQG%BQ~uX8_=x?Lsy-hXPjO}b`>iKDQAo04kPB?mkP!b%W_K%HxL99HXCUyWDz9f zF|+BAc+CCkSb*EMc4{4W4h8Smy(Pv@LcPROGmHS6FJDy%)*H4Gk`;oL4O?Pkf)K1y z)va-Pe|wvw1RST$AmVq!*s7OB#4fhVGas6~u>NfMQ#InbH0i&eCqT5;9Opj;0Ng5N z?`Y4-u>Dc<=P{6+Xk`2{|1i8ZSva^6_*WmJfrhumGli3phHcaWm@numLQmt+Z*R>h ziqG?R7h{2Y-4DDf5~W3AiL+unn8kz2#H^CTM_sYo^4cMj5?AcDOf${P^~r+5Wzt_C zH3uUj*`lI;;gZ__`2S>{DssQ(u1(~pIs&yW(zp&9U}Hll(EM2pPw{4JaVPrUXgyB= zDuT{C1d}~g6bSb7a16vybgPYT>rXnE%)g44W#;kl2dFZ|#xqXgV;vCnSK$v3AVP`f zxCJg)6_QXTGzs{-=#j{E+TK?7G=F$`lH@Tl8v`_gmJv1g$dTjNsFDc|2D=nQkR?sIrNibR(qE92i*%wN&xu$D33#&Rv>MC5F=oh+z&1xD90 z5wDziKfZ|slsEB=<2*W+xxdJI2L$U19J; znAeZWttF>PSsvacmt;ssyz!k30>ZWgctW#a86rf@^*yQ-(3b|wzAkKwZNP+W%}s@E zsYFS02gP&=2KA=dZl}Bi#wv8{tB|!8Pel!I;Z+Lz4@0;9`jziOw@wA4{FAgq?g}-W zEL*IlpkaWE!4l-7EsDXK^qPyoYU2r#MK91__qX*(x7R`Tg;NDl*gf7$VPC6j*D+XV zn%XFmVbT8WMT@~Y1~g6uh^^F4bvf!Uhl){#3!~@E9~sMS3-vuIwH6Zxa#uh#B())C z553ccrYf#mb_vg`D&rp$YDv;-9A@XS9o|J;!7xlLEVsFv<5+lz`bcHth%YXX73b7F zgrtDml`1% zfReP34cro7x56|sipEv6{<%Vy!ZnbbnzNZIPR?vi(Pztug5SRm*Z7n}vMS=9catTi z2t`4N3ddJS%KnHXNESRpQ=u?$o5@Vw;AB1xk3r4WmEqTMRePr3mhLM1Az0mme>W(p zl)>V!5l|TG2Dm`7E{amdY_6^;&cMka~}b zJWtomaGUiqpl4`I$dWp{B8-D;ldi&BeO7UeDS;J<>t_kuEHr;M&nsL0p$A&!Nk!zh z@my*Wb!t4R9)pT@AAbwqx3?$UPfJxW@(s&#l(y%oU4RDqQ0@yTAui*@weB(h-0jLlZ580ZnLZ}5Jdb<)^ zMuE(gj?1*foajA>E~Iwkq-Nes;xH=aq>tBA(t-etQ3eaR_(xy1Wm{*H)h}XCWH_O+ zwI18qp`tn>RkmSEM6IFXnmqM2u(CQDSL6`qWy-knMZz77t4QN7Z8GEmd+;FKszwrt ztbWW^37CQOV@Ddh2K})&>d*MFKSe=*GD#z4?A?;xA7d#U`V+_T7E_30TV-VFa5 zs{o|59?=f1VhZzVE%)a7<*Mob+F1#;IM~0_&Z8__Z+Xc%hd75{42x7>s<*%i-)LQ;b z*7D^EIkwPW#qu5IV7@;^`W7BV->t}GTK_v5x7j4?e>Tl2^v4L*nByZQPDQdeX8oT6 z3K(vZdrirMRSI!r z*+6|LmHTcs@5C7Ntvr=tmhvwd^MsQ$aW9@@yoS2&q@1=5G_daq%xQChpS{|mxeNST zjfn)-5V+~sGttr%H5X?W!$^#lK44sds{w#k)(Q}eB*#YJ>}=`OVq2oADh(^&Ue0mM z&MM=pDZbb3@a{ZteonnnuAOcw-E~8}Eg5pt;b5NhH~Xu?6<> z&`ClMoe#i23$Urf?p9mViqwy&KSWKpjD2C6#cOzbE+$qZDmsG|%?8BYs0SSsDa zCPB?R&8@dX_Pd=;M5Y@F#7bED)RU0S+^nKn|5DW>WMY~-`T_3#MHv0Db&qJvT}BQr z3Is<$5C!r}k$p?8ivo$(KUa$92!D}x*OJG^}&imeo7yFEu{-Sh+fq7{6DoKYz9cD=D$&gi+6`|f<{;VdB4=A_dEYD)|y+K z4~&X&PQL)4-5M2>(CRHDcYsG{gChy@_>JY5EI7Iq@A`UH&($k20M#Qr(rSWe+<#6> z>+qswG!m*F*6Qq_RUxZNw{rD&wE$mu3ODSRbLS|E^;@0&CXxT3Mz z#oAeYK)SJapF!kA?m~hocG9s13bO5qxg2A^lnbjP{z*mNq7Go#dY+hi1wn`P0juvTriFlrn zg;`trv`G(pPNo0&zS?huN99EmwfX*OM4sr(jer|@EB}ms{3u^|M=sYQar(^&PG|Jx zs`d`zjentPoynh|jPcr?baHUULrsKtm#REXA8vRfyUJ_z=1{%)h&O(Ts@z3?cGRD3 z`IA}s!ei-x9(r@r^$70X1A3DLalE@!Pn%FEqvw}j$ZI|Ht_(gzKQl!l9QE;(NKx}i zs_kJFKU}rl$}hh~f3D(BW``D#xYd_kZ(%9^Sp7P|mFX&l%neUkfWRZUJ^{2jc4CV^ z!W9>0fnJ#rCg{3BYysrC^|=I$7(YCqaLfil6@(ph5hpTqEwKi-66XzJIh=Ae#6u0}aWsquEENc&~p zAoo6Ofwfz@tIE7w3b4T1UPBB1eAf{dO7cK>lfuO3E^uX|-s0B?APExTF0$h7`%{79 zHVi$j`}e-{VbZl^EcCvGtF0vhEEYjN(`j8m?&PQ&GIdiOb&oxcL^frzzAD>67X(>s z*+!D3Jg*q|^CVLrFs+139cdtQ& zPZe(C=v5Sj?f77GcwV9>8%uh`+3U=k^5$7T6+?kOl}aaafnp6Gx|_Cp;^g5k0Yr2a2Bf`smDzG+(F~`p#Or zIxp@2nvn)?we(3h3mL9zfx_G2G)Do;nKMLq*STplq0ym1Zkk8tItmzB9{s?rg` z^dy3-ykS+O;bd?kh@zP8CI9Oa=GdzkA>6c3i=a~OdKE_+|G^D==aL1r)aL)0JCdPU zFCz`%rZGXLd4dws5La+wVdYsH?&JxEMXco!{X)%I`52)Dd%TwwN?`MjOX7ZrUjMYY zuqqbctJu=ed{vf;8hA#dLJ_bJ&>$i=9zKZroo9%gR9R62Xo?ds^w2=5GQyIcX2y_R zyu~?Ghj~{QI-h}<5E>47XO^oNOB0uwkLH+s`h&H+ocDGzNQ@uil(Q*D&w`MFa(xbE zOs5WfHtT~zYFbMsnI(g!5RKt6(|5lI8r$ za5+DSNsy2LA*Hf331)=1oc3t;V!qxd{|{+r0v}a%{qY0{3<|!WL}T5e1{+$J1VuqX zGLXOU9*HXVGo*04o*nnh4 z{u5XgSO3kxb=Cwreq{hZ|6!eazzhc-p%WR@m8%HHT+vJ781vT6t-9WvJn4G>WFGjl z-_|xRIzZ_wjjk(=?jSoWgSk4MTd<0;=gw7rTH@FZTcG z+g?Ga(~CK9ybVK3T+AQ8iy(yAyw6cnljaTo+c)OeY98vCaxC2&Ht{henb@0fafnw7 zLTGdeknx5s(ih8wEN>V9M@d|xs+=LL=u4VEwm-2TE~X|B>hlQECvi@*psbmebhu^T zT&PA(cgwMhXW+gLPmy|^JaA4gAV$RG_t6&M-8NqvItn}57KvyW@~d3se=ao7nQv9n zDoz|vGX~>!23h2_)bV=!6E_8O>(%jEw3eU4Lm;t&WbO|w?z;?)1cycMXpH;Y8p(mdu9^D0KdB+&h!j9%bXC^qe%PJ9yGj=XCzFLI)5t*3@ldY`5H3Ma>GAM;h zko`~A`L+5?O16Hf4H%zUR3$PKAOcL0oH|2N>ul-)Wil~9wucN!0j^`x!+3O9LrO{5 z4Q>OdE{v8x97>GlOE_MU#e^YiS1=$O2NI3-54;I%21H_(nDQd@Dw6}UL!rV7gtrA# zEVZG*ACoXcgbw4@n)K$ibTy0IJTwN!FO5Beo3vCd{#V~j^@LU6OP|1Vvyumb1L?s_ zwUe?2r6y$y&>FqX3>vRrh13_Rk`|~_-^jZe6tlr9HbEgop-uSQ-?kEkc#%XGnd8=) z&sNoZEv?P-HS|!%7K(jFvw#veeg+1@`GpVbyCJ1QGZy~|B^Lmy*0pMjJt?w96WH)e zXinmr7+fudHhH4*lC1Lck}NP!!5*Iquvo0$a*64wcyvztT6d!L1*#zVW!6a9V3COv zl6%{vQy75Ob`R1i2pXX@$k!4qCC#E1uu%8G$G#>vdI}yjfm{&pFS)=sj0{<;j2OOL zz^fvNRNm$XB;pvS&p-9m4628@eE!rQ-`6`vMisUf=MrM(;0oEC=u)yV3#NU$60=MsW4m7a(5tv$Woxz*5dk20cb2iaU&lNtJCe{Mb*@cH;&*PS%jS-tiK4m> zOom(LLu^Ni^-4Ls9Q&4*2r3eJr={s>%2A@HHW|SzJwcGEyfyck1Ax53To+n|I^OfP zKBRFoULy-=>g+t-@)6`@=5Xhq6?dm!;wmAn5yMriJyKa>78=OfxQi$bxgvX`xQgA| zI4&|Fl5g(P#EHw?#IB$UM*f7HRMB+qW-oi)08yr) z*+^8AEo@K+ZfC{wTHVgfS^o6Xzw254(?1~uG`thAriDY>p60F7*%WUO*EE`ZVZ~T* z*(If^ROn>Hgie~|LJz8?xyz-n%19mN`+}ts*X{rTxFn$`s1F&tSl&AubZoaY>^5<) zp!fTSI!YGynX1EW3xq1@rohB3pc~PGmMth(pSwG%`Bzt4IJvr-BuMBRa)49b2%8kh z9(xbR#OGFFe`~TV(VF>UE6suKT8s|<7OfS7&h%?<>@T$&nurS`Ex7p>X$kHTL|v>E zC-I{$HtW0D>T3KEm?!BGNJiJIMMy*X3`SrhFcQ{qhYyo!(wN6Cm*q;zFD@ZIpYN%> zll}-zk23}>@L_6NqA}(#u@WI@t@*^&%^)fxF%EYFFUn4QWCEgb6BiV@gxb&qP=9*Vt7YR5kiVY)Hls1 zM*{QdYeZ9dp!GtG4KL(?MEWbQRR5 zN_PLV+M+;H^zgo&X^J$A{KRo;ihV_}2d)cz#lP?#>xOGg?6_{(lXc>7Wf=1JSOKUd zsoAu%UhiLEXmOKX!ysQsPmDG$1v$%TI@71jz#aRcpJb``)7G1aRo~W~%!+SYI3}8H zbpIS-*P_U1)-=Dn<4VDC!nLni`v>f*GhEg6=>S)W<1+jpBwe)GGg#X`)usI)DzeG6 z?*|<)=^D5?^n@t+82%A}B6C-W>JoKkA^J0CF~I4>qe%a7t;%{T0~r~vRU5Uv#HX^$ zew^*62uu9XKle-~6GP%tS(E3Q1bvB@O~Ec9ON*4`Zyfh8GO0eSkd*ivo)~RZXWkES zS&-P5R-2hadi}p8qX(+9!`K@-Q(1Sm@)Or1cT~i-CZ1q_AQxXCjV4CoB}Ry6vb%Mf z_s1HIeVkY??;0JhGQBd)qHY=(x~kPH!+;wk<_KIewDm*+mkeBUOUag}JxFWRTX(Ho z>&A1Tut~^q%;gJO6LM%lh!KduHAuan#Vuk@`-T*0Qkw?e^izB2X702OU{eSnxGM17 zFpD;#&JBljBI+Qbg;THj+FUpB1QS#d+f@d(F+t$u)6L9J9VA7Rkk;q-k*XO*+b z`QMpXq;+S`4-4a4a?|hSTjC!aFZohqXGZ`B9ZP0c+>KaYx3U0FskMUH)Fi*Mr1ih! zzmRy8DQ>^XsA2(#5TLpGWK9Y&>gqN=7xTXYaubh|;{{MsdEMwHaT4tz$D*l2zr6__ zgd2LtP`&mWKdv8I8EWRQ!^=+|YOQ8ACdexidp~ixMjLC*+41v6jPYH0=xtflgN=Ya zm*Pa9cGXr@GI#GnxZbl=%WPn*8hBnM3tLOfy1Vx&oG80J z-mX_`Oy3%_&Vg4z$%!Yx6Tf{N^pjwR7|2S=t|5Ka#qzjEcwY5uBRu2Ft#%NjOEx5D zCT`%}#E*GE1Bqh$naM50BfYKkl3unuPN2*G@S6A8qix4G?G|D|5AQgAkcqh-%msL z+0EcsjGlM&P`qA_5az(?4H4|41^clUc0*#)>=h;6^dU)S4)G7ClNOLe<6nNEbOGj-1YwTh(S(r7Jy_PFztM+PSpF0t<#E_#5Vd#C(n??*b1OVvw$bw ztmEy$G}*sh(}t;><(Il~AO5?3Cy6{$k8omzj+)m?y@;X^Uv?{ zR}qv1sL2U*yBM^xPSJ=8EYtDkdp>7{`;$vOofz}GC~r5P>HTg=)VhY?0J74Mfi9$# zlq9iWw?pv|&fwY@r0Cl-1NWL=`UY-q0oT^~r&eR#t~Nd%Q@kSXmBh#6n17i0F^M!f z<{rPKsgBRfH&6mU^3H3<=Ogo9Mt+UD^^?N#`XDUznjG(Vl8=-6Gi*`{R1c02pcng3 zB=#@vZ%$_!ILT?xa%2G*qd}#opUFa3divga zgvHKejej;8Yw`Apao(+4J}Ki&pLR8DBAw*(=Dx3S?%ega@uKnz#&#kCje6pB*vlur zUU|EY(@lgwo4sJ0*Rv5lTf9ej-f1B$ZKHaIxrf5Xu<^f~OU7$@To#TuusvdyH4)AsoC$TU9|;hBu)K4w z!ygEbO=COKO=Y=>pO_wp%gGY%KBa&=#+>@U({41jL53^ein7Uj|6|{Z@`5Q;BsKHM zW^kO2XYR^Txxma@8@+)A_B^b%NZD+zIiaXlYZ7xH-bNqfM4L{?CNLDWin0yYEz3bK zC#CX%2uZ5vYS&)KTSC_$ZRHF25s96@BQOleps6iil}NImOYUeIEQr)C9~4RbtL9-D zdJ1&DYNmo(fmUp7p9$I~)sHyi(?$GA&877Sa_i^5BjkIeYk0ypLsa6OuCNAquM z>lnp5u4#{A3HsnF@MRz&{YWV6Ois?A&s$~c6OyhIpiT|UWwvwcrF`QOuTo-f%bi74 z;j&m^VVSe&U(nvIoNUA<7XYxr@4jCsv&b&t zwm?U#RaA?_ZkbJ?K@RKf7S)WzF5uNiT3vpHfaE;It;7#>O@ zK1WrLAl#MN=F~KIxz=e0?-6#&=T(LO$r!T|g;X*c#>9oj=NidAepS9V?-yONN>-Pw zNnFpdILfd@E%pWw&A0bbvU*qloC_r^YG3Jguzg0*?< zxw+oJpkTZA0#DGVdv`9`4__*tx6O}a`Ok|oz{hqPF4Qz|84;gulO@D<<&_j@}Gn}KSJDE5vpGwD<5zD$#)(u4SB=Aj*lCa1R}(Tdm(?}gc|1R9M` zYfqp(ZfE8FH|ng2P49p@pTBJnsdGvubsk!iL7gR%3+^)Hr;E3-3`=9#$OCp56qV^a zgI!&`{gRX{d104)|OucGm?JK@Qagqb&vQ(fjXZdX7Tf@ zfn;Ti7JHg!7)q@)w9Aw*FVJl;ACEIePy~vZ2U5dy%pLsM7??R5A@9R$>}(_#F&kI? z#m+{%`N*ez;w8APG!on8EDHZO6zj;a@tu?yKxM zz3|G+t#7XBRnnZysr#x+P1nW|!)5B4%-%4ya4POx_~b_FzUe|)FxDXk%^*K|+9*ZEP5wBFPL2!mqquo8Lm;Ov7 zWFYeD!W^_dW|0Z@+HbO*TTTXEQb=%Bcmb9Em0Df5Iy?4)^Y9nW!!J7zYoqbu_1>7e zx6uX*IMmrb$X{y(BRv?kXKbWV^XSN?>GAj!h_u`Xxx#`dJSC>mYcw{bP=kG5wUJ8} z@>xFb`odme((33`z`2J<5@y!lnVVJLJm+c^A8d+$AcsK{?yNfAbEbk5d(3a+=+;Us z4BL?RCtIme`9GMmF4d-y;&l1Vw*1!KtlVgPNMWMCxRJByMT3+uBB=B5mN45xH*gac za*(=^jl3tX*c*^0&$+5P*p5L!M(%!a? z@0kr-4XxhC5QAxH-JV!y;?2y^nIc$S-rJ{p;(olNN`r+FW|E72bes^NV~|0I2*!Kl zvP_gX4LgmtR?{>3%I`Bh_Wtnz9o+#xF$4@J4@l-E_e=IkI?3M2y^}pTm?n#~oOD7( z#Ia#7`x}K5QDx|xaD*FDn94i1v6U6f9*Vkx?V|W^`(?E`-${0k#9nk`@UWfk(`*O& zSL<``uJQ6xyz1PhS>L!Nq$>*o)Z7k!UH9|74y<`93#GP=0ppJRXMLCqa(i+l{Hou9_>6Z*E zWrf|H$JqO-Vr7Nhe6tRs`hVamf?=*$bZn~5z^{IeS7E5iIkwrE_v=trR+Tf6hK_9s zJHJ>_<&4kyBJZ_SmE>LmKR&%>f69wi@&CDnmHb`yxpQvI=gwI2JozNd{ZEdlY&+YxZLm|&zc3Zw0<{tj6+jD72 zvkwE98NtAgJ><`Ozs4F5 z0#nbF#k?gwG&|12FVS6by1QgoYR&z|&eRlEMpf9E_Ah4R8O;WBv2QRJxozh{hQyG$ zmj~85YB+KPB1m&}pZYa5y-U_0g6!y0(=FUMakzAE1sqg&MVclefrM*uxdtyr0vQH* z@n)FCp$MQ5Qb^Bm%>NOIZ77|0rIkerwDCZ1X}OxERYvli2CPeo@rEY_k%J>@-HhvncrJ&s?6D&|#u8uOh+72zoAjLA5`cqQ{B71SUU z?1H;gVUhkqd|@(6a*BxlN+CKI)K3TX`*u17f6q>Az$9VtMpFnr&#@|S&^3Zj)2vk8 z3)#-YuR9OFz{XD6P>Ub$!=H$uTR{w&$45~Q_=RL1ofE(^%mQ>t*fHqZVR161Kv-bs z#o z{@nTID?Hw?<*^XZP>#ssmm~2=A@Z0lZ>*!-h&#MngS4Zv-`KKSuY-o8Oi*QFHDnQO zy4MU5a#>Ocbl&{oU;j5=jAU+k@kMQTG3j?{pp_l}EW=CHWg^6aFA@ueb0G(dEq9aG zj^47IT$Crz*2HnRBP=X*7QK`Kp7(Y5ze1K9K(=oi$T-8df)y>CZkDFN**6Uiix+V0 z-tY*$Yk!$8(VH!W?PW5v#$J=STgFDVmr!C3LIMl>1z%7+$%qIOeKGMgq(t9DF#kf4 zlT|I@>#o6OMV<EHw0ojnoNP2y-svA9 zw5;W=4E)TpBIQJ1qC5?O(g*G8$^RWe4ex6|GoXF>lkWtY(-yQvA0l45wx#>OTT9$g zmpRC(w4^D!&0xnc1XvU}iWbf=oU@h!u}ATQF}eKdn)nF9$`CATtXw(47b`1}DlJY7 zRd{D#@NI~38lLkd&0=ruMc)Z0`?MX&J?oe*sa)bHz@kkyfh&Air?8t()tW2Us=l!t z!K?zgtVUwl1S6HP-X=&WW4TR`OjdzN*2)Gdv@>LKfzvhqw#zQD70$5mh(s=woF=xF zzENf6$Pi%hJSX=Yz5 zBo9g+*eYvFXNd}BS@P)Mo84yH#F(?|`Z4Aq@+@92dz85avC<0-uv*RLKem&%wTl>i z)xWHY#I5_92)YIa7M^!*VOV})i#1A3!bWc{?A#?>f>Z|!z zm{L?RLr}$>;4C87?o_#>Zt_mLiBrc7z1Z~?!Kqll0B4R5-6NOVnB%=#$P+oF4_|-M?It(-CDE^$w)XUEEJ&p3qg9Vj%_wU=en_`S%z} zPtTC_KH@_Z(ri9|=4+ki`xG<2aJ;rWR8D1uCqOElX`7rz!;k$8Gq2FCQCx1h2Epzb zeu3B8uaLKXXG%!M=M~_$?(3NlwzfJCw>S?!8^DV4Z`#>b(ImJKx_oGjyEi;ma+W>3 z*Bd>D6isjP3=lg|G>xEFjqwR;=v-5vHPx$jXP4?eV*CZ-Yq!=L?b1|y<;v$xm4XS~ z&;h=JNt%u;O$8_R0F9^yqE=AD$XW&77+a%J`eGw%nb(c5Rp1?K3vYdwLgJ+p_rj|o z^l#TH6?>PSC6f|Vkz&5HVHlS*WSc;*-Er(+Q8AVHmTUVW>VYHp7I?= zE2PfQ1_ZZw}N%2Jqj$V|Vifz#ib5Wrz1M4|ERFHm?;?AlzFu(H6F>jNQC5 zH4#?le|xubgKfsdHrRyBpL$1qFVHb$7!8*J{lmAxd8xKZQ1SZN-vZFq4rwbBk6fh@5HycjdP zciyF9$K}j@xv@qR%&YLXwzm8j&x(jRaDjt5JC|V?#te~YzqPIhBe7EWWxmQ=#caRb z!;NF}lXLWj?IYcg_Op2-hVNQ6}@PhSu4Ct z`y-(2ro<9oHn@Wi2okUIZo`%Jj6Fo$Sp0RB`Lvu^OT;|KVzH-t$Sl#UzlU7Gce95) zc(tz_*h6cDA7$i2>>V}U?jwSYeWaNWAl?osOIF{^&tM;UiSJtAYx&fg*1~RUuy}*F zq+!)qC2X0!q}5u{x|xJ;G@Hrgt)`01o#aSU>csv=6RKhD6sCs1lVsZ(jj{;uwv&8x zgHZ{zS||ouHveBN6vf^_<1$%}bk(gEiapv-CbaFS^Zn#+XSDAruuzOT)3PIDp=bsH z-_1f{_*>W4VMcpsp(ytH?FNgJVWD_z!uNqEZJ{vmT>V3*~6{JSSa>AJ#%_8Efn{S|6b^5v;AEBD$_HB<=c8{`i>TgCDU6i6t5TB{o>ZU z+V2!Gkhf) z+u}X&2@g{vLe{|z=jtUgU~g^2IfbWq`FRIscKTiVTN~}Dzw6$xcw17&mus(9I3w}%A-wm| z{Fbaq<^5V?z(R2JZe#tIQJ{CN;r5sJ({HEx&80`3Xa;!~G;LJA2X21*_Mt|aMuyrB zmoP#+bX@%MvV3EGGOnTC(ED448uEwg&2ODxvpUxgVyJHHL*RV83sdEF$ALf@)PC$X zNyy1%%cZZ}%Jyguujr1K^728<-!l1RAZcz_IP%OZ#k+*;4}2WFWpSXIseW^=kV7s8 z(A}rwVv1zzEc0R94L-~YSzZ;!_5TliuQR@Hf$#mxJB4pKMS}0%UsxRO246S9w*rIv z{|CMkza73|ox@k?!`H1d_+YeI-ckQg`0g~$4V}*K?=I^UfAtgze;5Bx$M`E*?Zq(7 z|9_D8mGO4y6u2&(1NZ3^3*5@v(+kA#102-YwT$Pt_s@DrhnsS=JK@&2)ce|a5~#b7 zrSbr#G2EFh{0Bj zMPF0>e$;s?nx)lT-xbK?x#pIJFiVALHj4{S^JlC-u`I6 z{U5b$U-E^WAND4%qW$bd17f%)m=&8o5l{VKcD7V?I;Pht(wG+gJV0Cr^V2iE7y<(5 zaDL`>-pzEso72+W1k+>V3)170Z{*u8X76n!z*sQE&Ixdz&inr25?R zi9I2W`)Q~XBLBJH$8_6AdT@N{pufxZtiO{x@9!|bzf@B&ZRsvE*0V3m%xi9k&%~#} zc#U5Uxi*oU17cZz@&2gX6>HJSSpPr;kxZTKJEK3Zv>)!CnXF?@x~G700wPWKH=gD? z>1nXv(}9_z^!s}O9^w^mlU=2I+Rd=Ll0a-vLi#kRB5{fj@zs_hqpy%hjN50&n_G>zC|7^eglRId?&HfPCv#$2) zysJ$Y+M&ESuN6`LiqZUqCxpk3tBAc=5qrjPqW}0Sr}9aE?*x zAJfiQn=xgK=LIt!g^~H=spU=p)~7;vDvfD!n|CFT=)eq0!DKp-zV&%P#yZSE#{RPU z%jEWhDol@KSu{TIEy~03?pU!F^6NSMigi!k+jh7Y^B634w7?=1X@T`;MCq0Ax(~t& zW@R5mmE^KCvlD;S{EZ*S6=ExF$ecgc`Tz9ij@e>hOEs`82G({~dRgh>T*L4HG~;Kg z-{Ti_x;B1Gk=DkIjct&h0S~$WAD*V6pZ@CI)Kf;T-?hY_fo=Fp2~{-*Bni`PInt7PkW zcA{Rp*`KIZdQn(L>)N>Zai3mNUeD`xAHXx4Iv&6swErE@Uq$s!7W){AIvvKb{xJ3l zhLK(ZWlzPlTW((`iwedq&@MA6@l%>&wDdSLQX64 zbgI>3%i*?f=y)-$JSUjVwrZS*dG0s9#54|!48(1EP;fg9QJD(74Lr>o zA!Tf(GZYJL-0v%;@tG_=56T{V?#!Ff*ep~a{F2HC)yF7QAEy=QMf@5@6`T0RB)4In zs|Y*AeCbVnqahjp(>-*wv^SltxqB~phr!~vzn{30!KB%5+a2J~v}38g2)2x~arFVo zL(_Hpl8PqSFyN)ByxCM2=a^L2$|ZyK7mYnoj>3ljA!>&fYaR-( z0EOAfKcQJ2cjvn}BINb?{eD?b6){8J)1!khq4atZe8>XYOz=7P9(>}Plv{U7Dme3o zYlmf5537jJ2_Q;&XB&t{0nlk_ct+(Cjf?_qo9u)A$xWd)YMuzM7zHSg0?Mj83@A4* z2tYZ(2c^~jy|VUHXx;jHfGZ&4iu6?NjoBnfs0vk|Y@)(JiK`fKVv@;rhD`kY3+Q}B zBLicP%Zp zVtfS%H;vf$Nk0s_+rFAuRR#=ALqD2t#yIbH!5AweJu>|J?f8DfJQx$J2*D2S#!z*C zzjp}nUvBI*Z`;2#s?VYtjxasTAIvDmQdX$JF!#H>)9BdHQ73~*c@NT%ZQ?YV&`?I@ z@-jL-5l$NnBo6nOx2B6LX_+g2LkXS7yKLK7GubJEF&Y zdHN)rwqL}BDm1IYI8xp6kYN_G0b(!3Sp8;2$tzJ}yS9JmmMo2CuXamt6>2%aox3GP z9pjMC?6&A}Y*hq*^OBd`SDKg6SnjOc=<)kUk1yMQM>IwQ>yl57gE#EIIa=}xtbnI9 z8+*lV-*S9^m)KpUtB%wyqw*T+;q~wLUDBfNBXv7-XT5e#LatGC)pcgCviPC2`JY4u zPs*If4#mX1e=0GIU*+6e(wtBvUa)}n2p{JPA2Ua(b?0VrbH9i0hYzPgDb{?HCjY5% zgQ1yK<3`8FAF4r)j+Y%Oj3~aL4We7o5ske=#Cm5KQ6Wfq@f?$tt`!C1`^>}GI zhlEnLTC5yru+qAo-8!p=ZVGqB^N8z{hm<UYO@ z?Eq{z(ZM^S&hQ--v7-p!4`IW{{ZD%Gpz5-JN)cOL@=;<8%^B6AR_LI87+F)!C%;m1 zNX5|0!y{*Vgv^i%f^8al%R8@$N54h|Z}Y$&L~yMJl>y$+e`t6q>Zk>$B5~9eU7D^GeiHCSDhVe+5T4D2VJZ8k7jQ!S>q0Vqxy;! z-ExPzsip4VmuogDTLZQO|K#W$FyteQE<*~lYR-(r4y$16Cq!QeEKVbEnN0+eY{HeK z2-6LQCzuqR-8*>%32!E(({y~&OBl^tk3GQ!!H1qi=}B%AA^D20abrJ-`q`^UQ-!^I z=n2QmgR*xS>@3=p(|~R9sa}lF8+XyC1UIvpDPX4wZWHDdM2INi2+`OGxG;fBvFi%l*wsbO#Af23irtkXN&(FvS*F!z zy%+ZDX6UBJitZ_6lhZssu7~mKirtn^2f2G+H^_~TL#7&&@0NUpup$S@_|+k|Wod6W z`vulNJTBKQ+2Xb|7r5E4a}^gweOv%)X~}b2Rus6f!IB;B+--&l^EPkkW&cgR#@oE9 z*Ld51Q_Pc>|KIgn+ZH^^lB*71(iLnan<0_Pb9O)f8v2htr~Egh-g(0$j%lUiuSlLI z171{`gx0Jvm!Gb=+-RuM((_O@S*99_*`B7uRKI&FIgOe{k$gSKMLfO*BYby7JWK2p;LwB4E6jvK4&MnNfsY6uk-N9JRh9kBz;JhRf zGWyS%zH(Q)mdbu)6{o}+vH}ugP*->X0-oW&6Da+W#_KyXk0{>u@?94bvaE=#Sb}&(&G-eebI-(*KV@ zb{NSCvMZhi-Qg=!w6>-9mzn**eQ}~_8k%#q_KLj9$Jrz#V|lj@HBysgMpuNgo zXaoK(qbUQaB&&QKL60tQ>smPR=~{G#P(+Axkpbk^w*?5ACU&p)$tU3*6M!N8MFtq; z-~2q4_r@3!`ec7;z#vazC^C3MO`{ot;lJLdX20j*E4me&=U*X^uj+V_uq31kC>8_- z(b#19PB5=-nrEYjXd3#TlbE_$7b7HeNrHV26K1#Pj!-a?%6oJ)3yCrQ@oImApP&U9 zcicFq&Yv=?{+e#C9xB53Dv(gs3Ttmrd_;aja}8NnpmohcNmjS4*fV66*_-$f+I)FJ zG8Jw-mPKeFxk`|1_=zE?Pq3DIAMo9*z9iz%3eD3#tuN2#Wv#|u0OtMTk~G)Ipuf56 zm4lf(^qhL#X=KFeoo<}`Us@*dg;L76+^Od_S*K7p_9Jr=B6>(Tp5fJ=zs^kT3=QXW zlXqD0m66!H(wlHO=y~AU-v6Kl9X;g~JFr309YTX+V<+q&WmPnG9eKgZ3rOGy=SF#`lcf}D$WbJ5H6sG3%q>_{a~@+x^8 zypk+ZLP@S%Gnmv`sEo#@8&b^`kApVdT<-{86k2$$K^><-QOMHHt~o;NgD|t3N1|xX z^S-z+-KPO%)J~EHvv^ON&f+?$_`}*e2mS$US<^^YY$Dtg zNdKp}b;Gi%L*8M>dw_IGGjvs%x6A z!s9DcpIVQ>9Y6L6cqVyEE;(?_;UAG?~M@hL>a4bYuC+h)56`ahU*! zXFszdderRA{oiG6>>hAU)=JkJco-Vw6IIyTkT0r#FSWzcQI9L3qgyW!9ohM^$WwFID;tOydT|FM zJCczxH`NP`w|0ll^NU58OCx zZ5+s9d2Wfsn!P9MlLV>d997g8dg|@)A@Z8x^mo@f{Yy8KWMX;`{Xy03%u&t&H`hqz zBy)G+@3YzFqD_w!DsV>8qO0^fwoB(j23)(Hr-VPK7W$Tt8J&sYWNu*lWD%8_#>CtV z-dJ;hX6&I$K1@ZLMzOeeTwb#%@ekoci_hEo(+w#<{u7qJ&AiK$id7@;vYERvX}>@7 zuK$BEgjt^N)aP`ih1i=Y;08+?tW+4M+0IC|GOfAFncV!jGozV-%~(}N{^Ql|;jbt} zzwg0>+mjNcx}~bjdBZDLLe1O2A7xKG<7U6<9*(Z*&FB@Ir;Ise>IwJNR8?euqMMBd zamU^Qq(MNzaHC+|QqJeV1?GNc;&Mnw#&?_0B9(V)Scy)i+n**d3q=zTY+Y2;3c)Tl zya*BH!f;c0s;ca8FC2TuX)qUN)a^n}W35*oQ02U_R4T+WaP~!+^8~kPy%jn9oQu#YU)9{_Q_9l&A!BH~Tr%poniRxe4WHB#3^YMRQXSQjT~dbf+iIpJh@l22ZsE zH)Gw?_nIX#py zm+9;8#NV@OVOxoR@`y`y-eN3T{M`zno@PT-nvldznk#WPQn4`+-i`~oInz!%X9s0_ zI{#Go_$cq4vm|uD5xaw6I|M`A3m6Mu+7DuqavxPHQGu&O1z809>2(9TH)1v72ux*X zm5$V=bFmKZIyz6j>&>7mNg1u@_1W4Xw!iH*bvpw~%^)Uxh3Cdgv^yXpZ?}%&8;0&} zwuqW3|7Ba1MwfMRN>+6*n5x-cF8mz6ZgZ@VbD$e}@z`~h&r@FgB;-Uk%vW9-Bdg2~ zj@#ObT*K5@Sl%JS@IC0jDeah{+)xJN%dWn8URhz!JVn;omP2F;px@AwcpeY%BsmJZJZHW2AvG8uV=Hm;LNt0Re)ck z-ZKdKb{shz!d7#)Zdg1`Vn(m?Y@2yJT2elQ2lhG6W zn<^sEg?!2oF@H!RMcxzrL=?v#l`Z)4r=}SMVY)|kPdSTC`ss;;>PU{b3B1R)KVb+aGO5;e5agD4XEc(pBxPe z{R=mCw?G>QG^f!->>4LDr{M&uK|ZOxhf$a%j#4L0L$4mE*<@bW$h`ONSx1ep6J>^5 z1F`q+J9}jr)1X=BW=i@Sg6mc&X94q65@25$w5+q6y}4@)eP})Z_$R*R!P2DF2WmdF zd?i0U&V`Y>k~yB!NZxa8U((e;KtJUthe3? z;5ch>xCxMB8uy;qwj*UEn&jb;CX8C*4ohaxK`Ji{gprju*YZREN}8iF>e$$qpNeH3}G^x9;Yb`gt^nDOc>S-IO$A*WX^JBc~1=WNkavvNl&QE6`7j{U29 z*6ql58tw!qYDWU$zn1C{Dxcc6=cV4X!U=G4>zb2zS1gb?*MH(|-P?{X*JSU=uRcQ! zDkn>tWt3;h&5`5zQuI=mnK+HIUHa7PG@NRd1NUSsphlvYUobAGojmAHqs1*7x%+W|f}auEfTJYJR8nD5DK z{YSg25Z=DyM8B{jjJ-pl_J)66u-kgWP;DqYmf9y z!VmNoh+f*~lm<34OpW*{j@+3p&`2^ioXU>?>7uKv=Y?~JbgMxF5H6TknmZ)BW*=UJ zvfuFj-3(Db$uGuuW+?d&2_&|GRKEimfjL(0P7b>UYH-`V_s(xKxM06B)?#A9(8}(_ zr0exiC~Az9qKi(9$Vf}qOTC*WVRndL8mhqC1do&aaNV%%ntnzo3mAyD^@3;&{eJ9f zRP9&iTh4K$y58@0e9V}a)bo+L|9msc+E33ka9wBo#Jbvn1WNa1ZEGG)O|ip++l`=A zo?(u5N}+C5FuI_a)yO+xvk(iEy}uwUi#6`Rd%nR1%O$73w|?)9DN@{=t%C$+38>6y z#h=dS-BjM|C(x@-7SY%s)M1PZHL{GcU9rV#6Qq$59I$fE!}!D3f|VnRI8kZo8QZ_H zA2bd9@)UC>E~qtU;$Q7AdLCcc<0&0Oz0XFVR&cDBWwm}M&<}N0Y12#Sh z3Kfe%%H^h3?*Nkgv?@@y(O_&tWbR7cFkCZVOCP%tcM}W7xUO#jVy&G1Nw+20)m^-0 zv;Bv^)0-Oe6rFZwXkfG5{=3|kja@0(>~c4^<~z&e^cN@w9@Y&CUawmLX9ngZ zpiygQ_^pkmwN%~>yqp|Hp=lwl{F&lC|A{s*6axLfaa%TYb)U*W-d1ndp#c^idCu?!>pnk|4@N1nw&o4q-V^ItOk5&iuEG+LY8g_&r-7zLp*%~c)1 zQPo^K^hBaNeCUxq5^a@K15KwO*{%%iNp>rtYBrcEEy|vj?&$3 zVZM(8ckT}T11==NE0>Pn`1W zHorR`-$i$9NqOJ!$H;JS5_WCKvjHz~@2FSz;)i*L?mW}D!-Y_BWGQ3d$zp&;{~s83 zCLz(x&c%=fx0-fFaKPPUS}^zRnEQq#F|!jh99gvB zo@7br>(+ z(FRe5H~8ES{g>e{h#i7Y{xt2ZZ0|CC5(2Pn<2#bm`{4A#Sn>f217DD5*NVu}K;9_m zF!jZMWTB&LmX5L~C?i{z0l_R73qqy$^|hJwQt4g(TIO%#w~0Ea@EA3hpSFp?T|moe zY`*MUw*4MXe6tozJjRwDd5oF`^AeNoc+pS0rp6SUUXbFgnynGBBZ~ltxm+;SBbO z56!8to&hc5%_G^9hu(gh_T;=b7lN~7j~@1PC|-2zes;FHpXMw5bzn%mjibW{-i_hF zxPUai#)s-zBaLtBhcy1Q&nGH9H_H8v3%v?n@Lc|UJ3Vzc-vj4%La#s573}b!i^mG~ z(zcCjz70Q~1V4`Fgyu+pSu>2mZ@m$`#fw|jU^+d)twBd~#D5WDRfDDaecu1geeE5H*_ct2HGCBaIhg{CvO}!uJYBi1pzQ*x&SSln^Ah&P& zD?%=6q>9xzp7n!3<5-lKWKK{}nGnB#E7X(uUJj!a<;fVr>H0c0hiQc(gYDk=6>T<8 zpWekYD_ePTJSTO7K?K=&a@O;;%|38&p|@&I2C^&t4ceqE(a;BF41MG&!O$PMJ3aJ> znrzBD;xaSzg_a#+1ZXU?w&&i(m)ZI9>ofusN1{9afZ4DxsPqz74O=XYq88RTgiqzEUx z_y?>uZ(GT3^Lw;LX$r5&?__?P9W%fEPTg&OZ#}}!?~P;jXnx;so!{p>m|yRPJ)PgG zVZqSvC5X=_?f!OthhJibK0e!@UyV)k`*m@<`5izFJMuXPbUMGw_p$SP_h{z#NZek1 zCSl}F=ywJ(XFTVqT5Ewg9tjQNb@jp}{MZ@vupm7<+Zh2b1cP|;#(*lq0?1Hyd-r>P%<2HWv&@W>6>!b0ZI}23O0}XdA zzc%PstViOf@B=oj_xNd4O)-AF%#Tt5re#Wy;wCNZ_~+XJB;hi)HA6##S~+`NJRu;hFwT&71i4BKb7&E zE2kUQ@k5B}Y`(T3DmdcJCquY_xJpDwdp=k-FhJxGlHK`;Y?)^G;IA(uGXYl4tUSrc7A;c3YRJ@Wkb8z%CIkT?0hO31OhM#&m-etqn0k|K^3d#frV z1vTpvDX0{112HS`T?za_0*kP5I>~)nCdE|VfJ2x@sgP&Uo00f(CjOXvielX(D@TS3 z)GYh~I}KI(3!x;KcN)w$hL-Owd71mqbu)VS(d@*J%p$F~Vpu%5=E1*l77pXzFHlzK z>TtSam&r`x-Qw*<&&I7C5l*)5vc_Xe8>e+CYpm*8(%d*QyK!VUu_g4(UrWh;Vsl9G ziIW(=?k^XBvt4G`ih^NWJf@?R){%CK(?25LG7P3>9^@GB{rT;lhRaRznwEWH+-YE% z^~NeMWpsg*o5nP*lQLH?VdGW#X4BR6(x4+0dvjlcW8x_zJBIN;QMvIy(QC;P^_cI) z|ITLAlyf(Bmnv62VG(EA3suh4RVGWmyu`R-%IdnHE+m7ib;r<{0ay6E4w`Be88peq&CCGNuSCSBp5@Ak~HWcd#& zl+C-C3UN6ZwF>E?d|_7;oG8x!~8DP*lTqDSw-*QDdzquyU<<4xA?QPss%O`PE~ z8xfNCi1Obsy7g1o)T8mUk-N{vEH<(r8b1?-$&L65jV*FUn z3nC@YL|%C&%6((FERsVb8o!ZC({^)JSQgD*8$F!izUek~D|K7eqHPmd4xXP= zNsXEd-E2?n4{hCI*UU3&GGl5|I0LH*fVf|(*XeWfl{ zFVL$+4b6u2*{lgoBT`j|zZqL*o&L=gbX=%>kYc<^X8_=4GSYw({)x-!+mYBiZu|!d zXNxvn>qp7IVyb@FuIkq&P<~C~WXTqFJG;*89ggqEWwHnTC((yTTt>4WGhcR4D$zw2 z{A}#N%b`&`D<>Lh1fSP0qOld;vwO+X^Il@6YAKy;Y^I{HK`|3!6olyPGbbU@xO82L zU8Onk7uLOY0Kb|yodT`sPlrL|(*}shEq!C~j=cg!7e%@DoJe&Al%|PUQPQo1N0x!5 z?kmKDuZgsL2E{RNV?*q}y6UghJGQy3ykrgYu$pN5$l=e4=K5+nAhGH<LZe;P#u@lH$Ed#4W0o|Wc4UFc9I*L z$kMtXH@R;#8v+}}k6F3y${xaruc0_^S-5GMoL{$wV;gIJnOszn{R%k^n6ag~iOXqS zI^h_}ueL{HFAx_V#iCzOEQZU2b?AbVzcd`c*WdcqGkfSB_{#$%DY5@}SN@dU0QBaw zd*x==3=r9s2A3DJ?{N86+JDGia>sfy?}og&T@d=Xo@qude#Ek%sREZ9*ZJlfSQ&kU zytAk$0j%UyW^HkCnl%~t%>3!VJSnD2FylGnerhDcGWMuazM?en7C*$*$0)o5wU4&U zM`kF+&8U#9f7L&YO))S8{ZBGy=<|%&SehY!|8PJcHs-X7jq_$0v2ol4BQ_rYifkRkdhhn0O;iL z#&sp<`M!)EwK+%r3+crywL0ac`4J)J1x)J{>1A>i_2Y8weW`1fu)lnLR~I1z!}Zu= zZGE<9SZt8m-)4|DWD^UVTN01Hj1gSMxA(pK`6@K;I|TCh)v;~K<9WAf)Syfo+QRJ8 z`czH!GGeDzvLDuTL%R4JBCnLU3;CDQ3ib}1s8;O@Jq`ZCxuY2x4S}}g;^z@{Yr0pl z^s;fv__}+|L5nY(I_tvYxhrpMx4B!cxjHMWXG_gQRmf6>oSMFir(H7h5-Kbj+pTWP zRXtm(TgXRH_w~LtB}jR^HxltqPSw>pYwv%R3p=ZO4|-6a@9^x6mZ2%a?ro1 z@me>=1XOaolmC%1;62kLuv5Ssng+i3pbj(m@~rfp>yt>~j>!lL6e*uRudA4=Pt6Io z3jwHDYX)zx9>KZq2b}vjaM$c>5`w*v%4_Z;?FND?7Il7}wI6{z9LXW18;-h2M3r}8&=EL7RKh(>=ono(|9h&dXMNU z3i3?B-ZjL$ydPVZ%A2k-S!+V)oVN_*>je;Jd}nY1O)M+r}IWCFX@Plp;To~lt!a2i*47} zptgdO*3T+UPP|qsac9ZegRh!^`$JFlj3%SHON^6XpN2JxfqT}C^{M$GaGCZE2|`Ax zyzAASP`wR@#*C&8xw>Bv`<%oyzuR~NkkaFQfQB;0d-S&dI^Jt|BbB#vpSI)uMQVF0 z`TO*GC=GTzR2}#60%Bpq&lqjMRJVDbpOi>d#GOcdA}(;F@Nb%vj~iS8X|9UcSc)Uu z_Eue85qmaL_gR#MO#!1-m{YYB1;kdf11D%$V?|1exl|(Vgrx47tYjVmo+*Fb7FlA9_PneRp9T5VA?Uj? zP835QR9RE+X{d0B`burj%d!#Lhe&%{x4bBMpWkJh^Tlj8_6`0Qp}HGzIpN#!4vX1!Yi(;j%&;6Z?Yu?rliQJcWeo_(oL}?#inGC zQ@>SFPIX^(b?V33l2TLRI`!|^67Ix4!Io5-l1WZ|i!I@fZ0QDoV6rKh;?)1ymUMUO zbxx*ahAElt)Hm6Z9!~uy%#J(w(ON!ObA#__b?E$?aL zA$fm6P;M4p{V}$DFB^_exx`1){$lffZ(F{1_2rZ`2W6{F*%k-}9Q3LlOW8|7nN&UG zX0T*`o4^h~hnn{g>BdgTPI_jsjpyJ`1Q@I}=c(C{k4|D|&|(xfgt%N6`aR5JaveGK zi^6Q+bE&?Kk%W0mz!0+mgjM8|yWv zw!nO!Q=995s?6|AU=|BHjKT4ld$9e?=Oasdm9LQLGYUV~(>Ms%a9Ep=@4fZBvJli1 z@Pp+d33jD@LX`<99`xi<`=pd7u6^OzN;@Lwmk6=Ka2wLDUpo#z_RWDO5y_y1h*^G9OUeBhOhhT{pz`H{Du%&t>9FfQ+a;~ z;q0z^u#!*~%5bqqUOJ-POSl~}n)F*&@)p~lcV0<515sOks9@avIoOGB!!|S5PL!ks z2nQ(To3RQHiVpT>z8;OwEFy6RNxO0czjoWLVdG;~&B^wX0>gtPb9FzA+2FMa>UL zO<~-`XVI`yis}U;vMob2Ps!*lLg_3oLD za})Zq*!F}@^HRV}mSVe+?s>>L$eed(bJQ7GAa*iE-)y*WLRm2kMyz-@g}LNvPMxna zMa}Kbd>c?@g2s>Wh3tM%3OXsSgg5{M7!iF@4=bYYYeaPWj;+KQ*G%qqZ_QD@96m(A z43Zq~N)Dg2r*b%_isWA;i0}9lg7_PDLfg`_xm3sIwH;FEEgX(8Ah-69sz*m!KI&Rt zvdvr_I3_-RAaI+k;!o5njGIM;f`RD1Qd*QouK=UT| zC+8FLA1YJ1Ngqz4haQ_Fsq(BFFVdfoQ1u&~!9VqGJ(@Fk-eDPM@XYZ{rs2A;a-3VHYJ-jKgsnF9KK?lpM*O7PTvElQ z*0S|q2hFDCd8;zg5Uj;OEwqBhkzJ;w#VT%^Z*ss0uD7;-Wt_U5hWAwx&nfDpN#1Ry zhPUc56j8r57OoXSLBkrS{z<-QY0O}RHuUxLE`I3iDEZvYZkJI4st7z5MK+l`Qbru4 zaV5w8kvN9+EqezNFYz?nyz*`x$F)xALR_oVDfi=kl8tEARRG3w&SUBly8u2Kzt;>x zx~&<)g0^sLSo2=m<|CqhUND*pc8y4U0v6p93ezLY4@OprZ3C4UK2!v9A-Ycr4tWYvPS@~$-7ddaImgJcE-0r=y37g`|kvo`45y1F%qvvo( zf!1Tl1pJq`z9qPJ@1F)CF$L+EN{YgcnfJg-dDY zrkqhpk}z%?W{*T*%8v|Q$vt5W;}?1^*Kk(oE*OWlvA0`&8aLyYlRjgd`nVyF*~EVw3C?(mY6} zKp~G_Tmwr?g+MIt{NL?FEGjh8=%NFd=(-}tbrj1}d0(m< zzyP2Qy!Y>KF%M>6FXD@_4`69g?T^&TY-HbPb*^!sqnnv+CZGXjwd^&+_@GF8my z>ykoERoktbylte28BIY&e7eo27coEPn3>>2ddxS%8p)QglY+x?sR8rq;6$_KN)YD_eX@HgV$C^!tq{(sTKwQ_u|0Y zs}M~dA*~phdKK36HhX%ZX*S5DR8VuY^iu}mg6_915Yse6Oc_sS-w6{lo{Nx}jneH( z6qw#BFT1BQwreR-VRwvC{?*c{{oLoGdgD3LY{XFXVUY$G_)_P7n*n@ISgZn@$3CTqxOB zYX1X>`3xb+z{HGV4cd_{h4Y7^lDsvaY0d60^=2eK7R%<>sp`YDNd^+<7`9e|MPnGh zWq2Bsn|w0;?XLmNyG^&$LK$fj2EXMtk^YV0a_7@hP^9t(f6Yt~oO&Se7?p*Qo<`(S zn6+X=e)c&wDeY4#^IrUiJ$D)TjQe4*f7-=VJBJ919^n-u^RtqNSH!Dw(}%{}rz|)doYDO>8)nKR}Z|QC1An zpdR8Z>Rz|w$JM>-b{yk09LX?CHYB^2KAMdhxn{o=J+ew4?NZt}U6&vffavp<%^OJ( ziT`&EsjNAYZ&EjNJj)gL827c4HLq*!b-lXOoCuWUaY!~34m=n~yO%*g>AWG`OKU%U zpW}0BZK|y16KB!t^t;=)J6Xx4&Z21Hek~uEoZx+WzQ7@*FPeya=dtSx52->?)vI*g z^@WF(HeO$-aPqldmkxKbt~xv%d#U2G=DPO|8WCyn29#yDI5+*7{>m?FR(VZu;($1cTZf@H=Ui?cUhbS+VcrLMA zsjTqA!tmU$R{#2xteMA^HTFoXXKjF<#MfG87?+%zPNZ7qNd9-LlauthC?zN3Dca+T86GTv zOfiU{62Kdsy~Qv?a>J<}sWa~a)nHW_U#?ny@WpyJ8Q&oOD8cm=A!BHi4Y<|Y-d7ch zzav^1H;)edJ7jBLBZkG|J-RS*_=Yb=IMWY4Htpnr#eGLPK8gd3<3xdRNimKSbh}Mi zsy0QlH@HV0ZE|9Hi&MmaJN5Mdnmh~(oE$@*TbPYHe7{KcYcOUgd1-~l>KyepSJsH zpl?|SOe`ewW7Xt`V`p{?`zG4C%T;0(E0~jVE|kERcj$^&kzjI)cSxvamwjA*hv6U$ z(|dyuK78{-avR4EEFW~=x@&n~=GHqhL{}{JtmH3a=ymK7ztRJnW`kqZd*0j`3J`pvu$G2E$87eazp72>@jgE7 zK4bMU3TVHJXRUydu|ELJ)$Z*yZqXt$$@iRwkM&&%_#XW-FDs!N=M5T!<#--hY{-ge zvaX2T`@0Al1mn|;SyM-({@O9kwh4Ns1n8Lr09F~~{vUO30^U@$wU4)@g@QoB5UmPQ zutF;iML|HO1Sma$6pA2JWpYA5lme}Q0~Fd`8bYoU&J$j*!&Owg4h$-`fKYItIO1?G z-~i_sKtQCRNPh3T_BqK(+B$sS_dNgS&!bJw&OUosd#$zCUV9D3*Ju@d1wyJ`+nC1* zgoSZbh+Tjge}?AvptrE=LXP5cu6(dx;B*2DCn){uaga4bGB)nO*W3rK%u;Nn%F0)T z!mv`Q?f>a_HqsjWh>_?k+r{KB68Q^Bk|X+@U9cp_icz0)HT5~&_CqOuK1KrxhtoKC zGZzFZ2&K!pD)K9(44OeMfR|Z)N0t#70N!yY7U9O5VSo1(;~w)*sCk-$o;@*Y9xwKC z4~SkIUj^;{&(u8sI*g63{zxN#$4?T5L~toCHp@)>NVYlhOvouVep|XPZ7_Ij+rd0c z_}}yJrW#}g6E}pTF%i*+k;F7h&eXhQ!(Na zPem@YW-4lu*Pn~%%^TBfXCyAMLoX~j5Ect)8V{F%oG9O-iOt$-ib?oaqV<0F_Ldsc zZb>Ye$%kALx*Rt+b;G_~fgdSQq}2zszW9+qYj=iCxRd<~4n$C$p);|Dp$i&8@4SQI&!^FZGf8*e)LdvQS~4q9TsW4Z~=d*7w{sU}7e=`)OfU^^d3qmbN-A z3S*JilzKh_U+l{Q-+CS)#|T3HM;tg2Zg>$(0XM3E&3|?EzzW} zOX?x7b4gxjkh+>#)MY0w-rk$Um5gFqR_h+*5uc^IUqSAF=ShuJ>Y)01@WYtCj9<~$Q_;El zi(^UsFHJcE!-!7#!w)!R6{QI$&p{B!M4}QNhaRc^FTsb!HioHj&gm&IIru@$I6WAr zZ0sA297^7H+2Qq^j+Q8}l+rT$` zI(BqTM6cy{IUkkM^L`N+%FG;uw`!?Kr);p7+r|J%Q8w( z9b4k)jPCgB%fPiG1T=gd1>BV=sZpV%3(y-=g8u?{RO~BCHx51fa%lw5Ji+0)5+8!$ zA%1bZ@h-0#mg75yBig!Fz#IL{nFpz(6Xr^@_TeY6TsU4&+KT1cisjk@tNkG-v1To@ zZxtedfx3%Z=yu0g?xxic0gmBuYjhDOxO%7^jn!lk^Fa#cBGxA-6~yw=iI^ zh0`%opy!GMvPe5Fl0_Q1MJ7p?FPXK2ih*L29&}PB#VM=~9CxLsBD1I;8NIbMq{O0`vy@z3fg2O?Z z>KN!<_cPpy5MZ{SrfLHpR5YhyaDnP-GK#U`x!fULu_`_SKysS>87pA=bJ6VU^(z+3QMMd|;DS+3!!e&H0pTWFQLg_7 zcdY;qT(#)|;V2h7M-v9o-4OGPk=g`Yu`FO5Xk4)Tly?;iI8U*FfBhh{{PY5uJ$(P+XrocLfqGDAX=AR?HvO#B9UyF}`%p*=I z$OgKZG5Dc(NA_dzsGWMpDe7voP(LjhG1ea@VR77gDj&}jIs=4Q(o$TWQV2%aHy@Yf#O>?`{f8mAO7!nA#3VWp zy{Q}keb#?>x}wHEbsQBc@oU&M5PxwE1v~g-Nwd!4g%r~=g`h$*%Z5bC+%yWK>83Bp z#1ea{nJmQIq4VdgSK?Ade3gWlQ&AaK`x|R`hxTb`Xg%+CkG{LH@@Mrfl9XYFvG3wO zD6C&}`7uBt^gZ~zTnwsfFaDCIez}wPE10wwwmg9rqwv?Xx7Xxr9eevM6gOmV@8WO4 z7AK*p0omS(y2f6Z zqds7n`fBtqqRSYrqTxV+Odg??xPs6hDxv8J5GnvE4TZ}oOMpOIu`=i^t1&2LCMi(gokT?eF##jXWpOl^?Pn;E|<1XZ1*E7`-{3rCy_uz&FH{XSf6^uk&D>5(zREBBS z0sYF$m{|{dqull**nW`{c`?oso7*2?hx#8XG9jP(0^KuA%_ss_`@TkTVh9#3yg!+Q zOMb~L=JWsTC}*B&_5}4VMw*8|PDYzdV@_+VTAjNy-c5j7cR~jbUnk~?eFMilnyq@+ zxSL#0^U`(&4TsmIVeDcG&Gwr2_4?a(4?TlK*84+Cyp*-j4BPm}Vwf2%l?Hr44;(_q zQNhJd=yG`7Q7 zW$0S4dEs5_oE%>&{utviT(DL6bw>f$<}1RpR&SI{#Ro(ihCkUwsT6USj(!O}{Kup_ z>mTSL-*RR|M9|zcjP2R z!7Ns@t=*T;yJc&gU2 zkR7?k?YMsv`A$|X(k8nd_aM+=Ev~E+i#vO>fE=Ts&Fa2&Xt3`uV07^RUmtd@mi}&Y zn)@5F`{L)LpwLEA5niuW&-8chQLn_;&u3?!e_N;ioek8dD5XDJxBkQi>Mv*gId$t_*g$*v<3AHKW( z@fWiGX?5#wYoI=fOW*rVo%udt)>r%%{_+d=9Yj@NG8|c(Yr&D&>u?Q{1j<+s6mpbR z;8!^ZP=l@o8YBH{Kx-Fprz18@#bRK-|8V(Hx8tEr{lspfJ(gi=m}V1N)sGh?9(OF- zge_)jm_KG6TX=i{>>+Mx=ila8O+2&nBs3~+K$f(n5P_n7#S-6p7H!V@dBMgKyWi(CY!Kx$)O93iFA%nd+kHvDy zoQC0G7Z{9!m_T%xT134dh=!I+fRRkY(&2N;U>kV@Mv#bQS3MV9g`e>j3~o*R0Tv!r z((yj{s6HSCT5igpnK+=OLjyiqIEE7BvoUPkDdR6#IMqVw_%li!KGcPkd1c&!RAOEk zC*nJpN!WGbQ(PJU1Oc{Nm_s`qR28mTE6`q_Qu+2lmTK#{nR0i$CIE2K}t{Zl)P5$%GP( zO>RpyZ}kqqTvlC)w^vXqb^$`@2HOtu|9s*?-`s*GJ1(enEUCo`OopNhPgQQmz3)zT zj82(y9d$jb{y40qQVeH8fWSB0&y0f(^NN&EkWO$iOSOk1;RsDD;tk_uwGB7jBJ56-FUxrm;u&0*IjtUg;n|JCR}K4I{YR|$j+nLqbQ+fjNis((?32z+iKfacfiAeSs=MULa zx2n#zy#kY^6GEAPdlU;ptp~3+A#G&hO)L}*?tt?Vm7mXl3FvHkCv|>xym4Gl-N}Qo zqx=BsGs;^!#VI&6U6+w<=4I&rF^-YM<3p?x&CP&00#b4shXI^)HwY3*N`KsG0Yx%5 z56b3tB63Bj)nNa%$%BCy!Z&VocB_P;ehpK5RT@7bsE-!B4LekizAF)pp&Q=P-SB!a z-T?aG+?)YJee#b2*-1C)-(AX3BS+=^m7ORi7E~}v>7g`9{qSyk5!9b?Tj>yw?B0WB zOe5Jx;Qcq=AX#7|3UmitO4V;Kl?Wk%?4*dDRL z!UaE1kh^hl4tPt*CB@7$bcu=c7YJ9_vmNr$+4zxh^v+~W?8BnSvt10nf=b+KpZuk@ znJ-7SgXaXi*batZJID_srU&>Y&~q!@;kwHO-hHeBet9i|eO#O0PP^8f4jdz*Xo=gk zsoRNQj*_idC@pb)Xkg&f!2D!}qW0H#Yj=44$B|Y}^B>Y`zj!WDbL4#JbL4Ep|LeU| zE7^uGv09s2quRJz+Sp1J>w4bhzD^pl%P>(PnK}S)my}!Kq#W4+G}!?l45Z9vvFrfj z*=8_h8Vc&$0W_-f;&*`dfK_A%C>p7jBGw*%7OrE3`%4;C5uo)U;U5)Ga#To=CzE>* zvAB1Cykqpj6VD==e%c}7xy+pPIY2BtHy?j-a8T9_kh#GQVR)3T_!Ox~6pNAUS@I5U z7r<`GetD?HkwIM|7&+_-oOL;Wu{di99>AiM8K1TPD9&mMddB@gLM{RL-?`PHX8bA_ z3*b8wT67xEB`E;^X*Dd>xK1{Zekn)QB4{QVJ=Rl^QNY|^ocbe$ppCv9kcHWq3bW(W zXPq=LTV$dt?i$s&sexmm&yGf;O`jR$oy~dx0|#P#owF8)xlqm*D|Ih z{(cD~FygOR$wl$^V-^ek;&z_+yA=h08h^**YC3|yj(78kmJ7`}r@ zT*b060{})Nyk*jov&94{zJhdBgKBcE7WzDvzAlwI7JY40+tjxruuZr}mfVYX$FyL0?Oc)TOUc;!}ixLE(3JDhRvoWM!N)hcQNHX=N`RSg^bWa^vQRH-DpBffy?uCN3 z+EcO%$z6tG8>K!v$8hp0!TQA}_Hf zb_9&v#Zl}riUADVvCF_JIi_lkMoz=ZKF42!bD5<0!1)=c?T(+Li{##%NM#PiBnH{! zia)n5yla{F_|61f^89^?wiKGVE0z;lJBAG z>Dx+MxS6>S*H)q_D2l_bOL0feTV-XPy(y&%_{XUYv!*r-Qujea%*#P8X$x9~J?_cUO-uoW< zx{WHkbiYGL+J$74-{7OJML!(_m!k>(6HE6%3lHv|&G?P&Is=7N_(tILLB`U%gI4^T zB2g86H|kS{_8E7_0t=x2hxxx1VD$rhSDAssFlLyczH&0$ zwKTuM0iaw}C;c$?s3$mtR{8MX*i>9pvt;+irzVKfOt`(jQ+I_TfSOYdRMs3Y8_#h;TijK*E5;V_2SD!5mf0yz- zJ}8=|iA#WIjROtot?oLGvGcY8O6N>UnAuPiq``~!YTo_9@$*)ZM?C9h*+oT z@@Ug;)%1gaqe2nYG^6e6XT>%Bw#-O1eUUMeO`9_+FnA$vJ#{tSi$&zOTmz^1$kRCnEEehx$@Kxo z5uLX_t~|Eu_b?#R2Z7ncm}u+zLSr|7t24)DXGKnj@F59TjG*)v)bpW-yT?9~X3>QFkS-~4TvMB{9UTW&o0u7D-JX@EY z40uOJ7Tam$)Yqk}Zv-^L0e`%=p{BRvcMCLw3`C5NG<}}&1G}v=n>Nwee7Ql0b^S(b z9TY`ju@dx0mo(Jn1Y4IajZbU~-O-pMGgZr;ZA`U2U20ra?{Lb_i~#ppHJn+OS->S} zE15`d(co~lA#Jqt)WX(N~n3ln0vroWG$tPqTG$im?l8MyEx@ z?&}GMUaunuQG?pAJ%cl8$KC8ds*}$nfK@Y*wH$;_cqN<8Ee*TbbZa*&pCo|A8H;qB zZ#f_#*1jj*=bs9Je5BKOwrO;QyBVqG8zlN<;};pE0)D2kk5BQd@2ZN-Tgc@8yBnJE zTnyO)YhUAlZ6)2t-L{UJ8>P0Vrbe;t>2%`;Jk^0z%3Y^N*8J)!S&rENn0+}A^)x|0 zy~2c)sBL)*ZteT`15ssg5$LCki?(@zYO_OqZT>7v4Ct#psQf!~VzDr%Bn9U~9IKSu zmj>_~KiOuMWCR613fK-~f$eF4F_Ta6pig-iH$j?Tq@6L9GV4|tsG2nypl1!x3OP|0 zH?$<*qn5QKjf|^oYv05;30_^d%P!F_-#jXk!M*5Nb*W?=;k+yV)=-zTB3*_z8U_In zKP}fO5ikqi7~G&J(>c;s>Be!!qc&(>V+^Qw_!Xx`Aa>90=8&Q{J|P2v}k1vu6J5@pBkA~XQ<~Od43z27SIuWgUA!~Gh~OaZwo`F zf(Rl^FfOy zg1)w-4(vY1rOBUzU0WknR#8E+pK+E@yn0G8ob^ufL}V1Qc553HTpq=)Z4r{kXw6BQ zOV;0bodAf3U&>jo$dX2W@UV1wM`Tl0)FEiJV}70K z{){92pPO!LqjSBWp4}!g-6n^HXZ`x71!~2!giW3xW!8HrT-P`{-DXC28{(uIpA!^y zrkft^@~gEn-D8n16@gW>B1wC z&D7{6(^5n4ZMbd2JJ-0VzTvq}U}d74rT(=r{rb2gO$;rF^)b3*&~+t{maQVovU9bp z`0Z|Mu4=_)t`C5oMOHH@s0q=E8 zO~3|ak@$-iXbTWG(N=?>JIvsmXSff z+*|q?66uH7;8}ySVuD_ZPU;*MDre;H!e{UFXCOgCcYt%9mQeGSyW(p9XN?8+kTDl(253B2WgfuR7N8!7Bqrm zMLWn?eXVj+jTgbPEfk$%yv|X@V@S%$77;Y8d0o0aYn8PIYC*AyCg=|c8b?uEaPjd>?LH!Y=E~#vSeCO4Z4P ze2e-?0p^+0D?4g*Hd6#pYBtv!C%8m)ntr``1W;c1(EwRXuuN)w)cA$p_it$Y<+sVo z!_C<1pCc{=y|_y0xVpmK(g^GNO4PZgYF6L@S3dR zp2)n_D$2G#QZ^%N-bF>0TIo82G3u;Nt~8bis1?dy5n52Uzv@#Wz_>|KZp#QTqLiy& z%^fAGMJs;@nBfhMfUX$k#W?k*izS;Nu^h>8zXz*YV6M7IRRg#-&)@kkTY-5FEoT%j zj=bJo;A%OsgX%4chY7c%YzS{ip+qk*F8b4=QX4h5OrrzVJ!bI1l-!s_Fq){I~+fNO!9X57YxUDIB~{X|%doS=aVOiUJx zR0G4Ug6lFhs6I`T6XYNTYbt#>P|W0tiGp3Z@Tvob+c~3gWvvNa@Tb87avRP0=cF6U zdD(61Sg)1}yztF+8jJaZe_6x=CJH7|2mKe8U*H7QSRVx@3hWBG2&Qhb-_|3_lrw@G z*Za?c38tVA$QYG9SlHEn1z=SsMIaMv@wi*C6DL~L=f`9mu21^ds+yo=1qiT_frKuEI#8XZ(`0i zUkf7a-R}^;#!w8K8j6idLx?p{1-Bi2)wYtX8bd7D}6(n55_2W z$$WC5q??0Y#-f)IFoDW-qc_c%j>b3_ZhG*(!X2N_-&yn1{(lHsxETv^3&uAAZz3n2 z|K?uCrSgW_W=`X)c%zfgKMgaQg&9r5jE3TkEAhs_Y@@l#Es|$F~%xU&ose; zmsmJ-Vd#9Z&HJth4O+O->3P`fH3_u|wUXcV7j+Q66lxJlFbf!-F6{c{UyMP7BF)-x z3P1RUnOLuXw=rw-EnX`Yx#UXGp0j5gUgah7%OAxWci=ugkQA;&fIWI)A^u~xZn*z! zjBiD!96hbhngu$xjron!={3L|d z@tQyKPsJyb`)~{kx6k3CZh3+EP6UQ6LI9~DXwi%bYi5~>hJr;1FVh9$ok>{Quq%zz zz}U`@rli6igs8fWxl4G(r*?=F*qabSNc>v;;FEyQBetNY4_~7UOC;~qzv03ca_U_+ zHkMm=fM+>M_+G_!+_5`Qj#)(gOUyys`@Muu^{gy6z2pFL0IWTV zVatygi*PX1vu=bRa%an}Z2}O-Oof!@Zxm{a@~)(-&HBtKj7bCU3^?1t^Y2UD-Go6z z8^P+77LW*o%@Cq+RV+k*-74vJS*-j8i~cEZY|z)W6koy6vIabBF2S3G_^CA(VhX(F za=Pdg4jDEHLsCQVl#-Bz!G3Q&gHXk_+gihXL4_)wp9iZHI-o>T7v+O%xj~*g5tI`% z8RZnu$+fteP6)v&SnE0@RYHQVB?r{}$-r!6sZlOKFnQ>Rq~CfOf}?Xi;8Ce9p?smr-U|0H~kXO&#WK%F-o!o z+S5wENCk&LbM1t@2r}NMN1vx%2}NBPW)duAuU<4kM?_P)*U>J) zi*IQjVyL5hoX9+{Ngf9zGsgRlvNh-eZPfnL1#_4ce2CJYqnsNHsLa5xQ5tl8iARbN zsru@>;n*1Lan%cyE8bG3H&9lmuBG6oe|awgm}7f-PFhjckw8owDwN42teOD;73Blp zu@n*Kb8q+qZ|QHpITlmG2JphJpPzyt!RUpONFWJ0k^M(B07QnkxzYp(avHI-K0P|i zgv2meMmk|U9UTF7ZlKr(A?!%_;-Xt+Ch$zo)`Ck-yA3wQKvnIbLs;RtV9e~N`^CdSAGdTKaMOJ{NcG5iNH zTo{~VDcfSyg_vZ~DS?*Qev%OP$$v<4m(W5-TuuX!$i>x5R7-+`g?c&q%0Lf=dy~Mv&tue zPGV}BLYx98%*CHE%=R(70Dp#P*fbHsh-m?aK?#3j!t>)?c~18HmT(1n<&?cLb7D3`=J^GCL@Z-ITahkjBo0<5hXsYaiNn1 zR~M-Mv+LAb-NHUdypGG*2snRugu1n-hl5xcPeeHG?StTlozL zaZ4}ZS)Z|Ab9DOkn~s2xR*2Oe%(OXToFP>5<3Apv79AoSM;v9N6^$a_!4qIN^jaW2 zf#eS8`(C5R_jI^hL)@H#vkD!>j&ZsmmO{?Ggb%H(;Mg|;n{KmWZ+j&IxufC;k1MqQ z&H+E(E4&TCz_Zxd7kKi#Z3D{LC>5aG484s7k?FXx_u~o|P{}59=#|4*rMI{RFydrq z0mk=keSlHgoxcQ_oU;8|pl^nw{7Z~5?3(^K2D=Sk0kC zj{b(H7+hV7Qt5#aEUjgch&NEfu>E{*a7bFWqn?ua!xP<(WiV^)my8&QPz=2B&rdO? z8t5+&N8o4**(3-QgMvIYGc^YeNE%KcUjKF<{DZuu2T|j-3@ZJ6ew>7cu*Pt2UOA%X ze}o#JdrJ?cQ1+OM8hL&vejPJ3ulyqWy`?{)#xhB=ljpxQ&wnLr%=ck&nOoVBv)5Z%iyDtguAMyp*?Dj?LycSVkgiLU zL2x3n>ZjrSiR9YYax}E4c*jM)V2^u(1^_w>KS@fiTfrS?A?*QR=JVg0jt8LhKx`T* z#$*O67>HeJs2h)K?-r9&u;^LX`38at2V&nFIK}55id}EuT%Z3QlAPvWRDlnl|6!2@ z{EN7!YW}s$)o&aJHk=!im5jnVdd)~k10Z2rJeT_(!Lp(#(+u&F9d<1;i)?{KXRrvY zPqocxTk7;}bI>xJI1p1|gUp*d%4bp;K-w9@?ypsln3oA@6FW8` z(P}gx@ir#uVP+NNpTh{{UE>l|E}Fr9)lZROw!tt#a7Ay^8#yvSNaVtuYeD*5GTxhjqb(7E_`ixPH6Ks!@@CZjmzM*~}fr3cP zSs;+;d=L<5G+GaJfq)W12E7fT5%^Po-ibb_Xkr>dj3c-r&i8z`eS>c_HQxXt${UDq zyXQgk4Yjk(MaEv)Rf<)3;?MCj^&YFLtmCD5z6LSH$vYX3QQjFIk#`s;#FP@#DFS9& z+d0pa0y)TgHhD)2%!J%KGE)n9vbEAG2oJQbt|q2C^~GHk&Zm_wz>)TJ$aoO%oXF4w zaXA`dKJ=Xa_a{{tSj3%KUY~pfwL0#OC`%PR8b96!q*`;VJP7}Z@se+Wz##vf3*@Bi zcNX_A9H?z#GxJ^mD3C}(kEscMww&Xx!m#hN3wQV)_0OvY?wDXt7k^rI^Wr1NAyOe! zJG<)5Uclp&a1IF_dQS`NbojP|ec?v7XZg>m#JyuP^MW^ILt+N>x4;_kea;4)75Nf5 z8^#Pf4}vv>T6ibn*3CI4lUL#r%|v3mqc_`f+{Mr#QeT4UfPFxD$RlJ~Ij0h|G>+*= z0L2O66B*W8JinOydMKcHE5x>;I6Mu+d{e$%jANjGU?!OGDL?XBvxp&UYV~10oq{&1 zLY6^qjb%tG?1_Z(g-==dKHxDhDP6zm2@65gtqXF8tDfPToRTd)4>Ws*-&L^3wJoXo zMT8c1wQCsiq}@yUlAtP9>rb+EP|4lvKqU>yzUiLp9gaPOox42_ZDh zT%1x1o%&S=_t3YQhwPXGi;1@l^_TqD`vX5H%+y0a{%(H^#8ILsgDZ)X0;EI5Eu8v~ z=#;wZH0;PuGrJ9@spuninoMhBo-$M{L{0Db6LukBO}=oQvl`$!LR6ts^fr%Km_I$GIU78CW6pD%T_k$par!msF{1s2*Tcw!_^dS7s{CTjW1>7jRKiFw_#b z8FqhR)zpsEqpRI`H=MAL8-pP++>T7>He^^bK)yMN0~eg|!W|w3g;6wMRHM?EB(@lJ zFWwf=!sLMm<45d{jJS+xO;FiwRi0U=a+_%7j+DWI{amG=gq5)I?7lsa!#8__cckgJ zO>4xnF%cUSjIV@d$xXx2XUgg5GnMOdvFg)Z@>^0du9wdF3iUncAzWG16_4-ZF?5#u=(~wX zg%CJr{5^PVf-hzGVpc*G5$G|sLKjI&L2oJ}!K96E9|K)dGy7PNVp zNBsB*`D4rp@iLAT;lb*Y&1_-}nO2N*A(mSII~Jjl{LIi8u^Cd{vwl=m!5_isilJV_4aQ5+ALB5-R=;&s zlpDMc{#Lrr4KYUZe-pz52AeKOCKG@h$PC1y=CzoBCCbR&qx|7R7i+RV0X#^pp{3zM zC6LmJs0A8Y1+e--)NoC(0G@LD+@##K^Z1a z`%~j>rw& zd!UYvF+pC8|KOI#9~b21L3Nwv1RV5DxpD@nGwoge`j&=UZ^r~n1|%8oInc}Ct+aX1bW5y3Uf2{ z(t$WkgV;0mE%&LN2iq~13%Pft8Fg4-fO2@do9BKUix2Db=8-2ff$WFdq%286m5aC@ z6gNfrOTz$wI2xT1mjuKma%cXMZSDJyQPPtMj(H5pMg#Q1A7V8*#A|gAMDW->%)0W@yIn7HKfBoC zuTlu&i!#fo*DIFCN^UL?>haa49+l?NFnPyiYq@AWy|}HUnye8Lpi~r@@`=@KmFVjq0jA#>xEVUTrVJ`4@R#4cJ8;zb$1Gd#<^yQ6}S;N zLrodu$jRoHl-^E21nw>12ZY#E3bDAGXyyxE1;hxHpxhTMeGnh+C9mEpA8#_<>fj~! z&d0}O&2clloeQf6Pj-CL!k_U8`kY@{h+pt|?80Z5Uo}2g*D^uJ8fK=P! zqs}I|dc)KC*Gwpn?29mQLIC{I<@lNZjQ60z;UKe7ph4$fiNbKvBBbub#Q31s3^B8X z;#|HiN=jeqO^WRt2ZA7ZkMM_li{(%bOqKO>%lhT3!Ki^n1Vv*2wMvK_I)w+wlBaOQ z4Zw~A%qmM{Qm6*;1tRIN%+SBEF^3l54+4>nzy~2PNyd&?l}N~02~!4)d_%d}YI006B=|IgLdksaMS+EklchoqM3MRtq7hk`g##n9#ANn@y5gYTp0F2LxfA&u};~Y+Hq!R-N)9gn<|{2VJZ@Olz7Pr z@je>ovAfu6pOml5Xc|z;hk%xPbm0s5mW~7mffhgDm#FQD>nl8RAI80uTz)<>Q;Y*j z0vwgH`Lb?&nKJLK+1#md=c}%H6(K^s#xF>fsLTN*7kg9^tYSme7y!52Q*bCi19^cP z%-q{g$QYMGVL%+s|>nGU{)E=p8!LeV_of9w=*Ln)!I1$Yz49XJvxnEP$E{`NDxt(Mzy*0zl% z3tC1>KR*Apza#3b#yrqbBjY$v1!xjyA;5ZVK8nMx1*O!5Ukhn8gqYAUlw+4e(IvUl zzh3~k^nN^+TpHAOWt0(T%(TL|{|2lmY7uejDqgHn+4aHb8?lD%C3f5OzeG_gdNIV)F+@w%%UdhVHPV(% z)%$Nw!>NasaGaX};^#TcD81{lGEl2?!^6!NSDy&_CCvBpKz%}a2v}`e!U!-Gr4d(% zQq}=UtSRi2&ZaF&m-f*v%+fIS@&De3#&1xK_a|Q2QHpB?yaIA_`66ow)kiv29}%5C zaV8X$H%S$^nS&J(rwg^|QQg>%;QE2LGDuA7sB~-y zMB1l>ikA}-{K@Cq#vX?&G*s5=v z-g49@hq&w6)(H*if7`-~HkRK08b9C?1FvfJN47<%4Y0x0DJG@iE+`)i*>?Hx7ST10 z=VcHs&)1=s!IQ^eq_Pi$@ZiM*l;yi@+#;S|$f=cNu8)Qb9j+PFMav)S%g+Gkj|_Rr zi_9)js~`Lu?RPkwdR6B#j)vg(30#u?LjRCMdg&{xNe#H|{7ip(M*~`Pb-rJ?FJE>$ zhTRIJ)YQ0W&rtr1m|~=?!6P@a0K&iat}SXAcFnj$DwO>sN5w%*MS&BDxOnp54{>i; zui_uH01}JPIDJ~1) zm|KcSVBk=wCHj8-`}UAk1GBMyZ)GeeVU+#jh%lk&@Bm?-Wr@YI^^z`l^x!#w^g+H$ zj#|mjtfg|w;NeB&0noMWw*T4N2pRP%4%xa7ZnvPGq+IoIOZQUq|jGeX)f!XN- zpi5Dr0Mx$huK_3rR%lTGb%3K<85VAttc$6}E{p(Zk_|u`+X;X&rT+sMtLp!;(!bXK zyIbu2KhZ<=e`&OT)38CUkuq?#jiNtC0WvP&hPNC5SA2TT8%Kms^CveLHI^~u-W!GU z;p8BK78tjmmw}eFJrtW1Og@4=c6_DSVK2-{zaU$eRp$fO*3HkzTBc77=&Q93>Q?8S5u)PiTcv8|gx-MOZZ8z8=ajZH}EN2I+>F`BiYd=`Dr(^(* zDr017$`lYUe>4V0yW&92~joXb&4rf!b8xNGM zeHKtg$TtDXQpxP-I_GTx%D&6%1Imta6DZ}9O&tu6T-0a=z-ut+A_TepcdW3fFU%Em zQiGvZnMw@9#doX*o;}W+38W~o2r)NGh`w7OgY?9&Mk$)dXXsr1nJD#R?5jGVrj4b9 zP6JC(6pUjBbd+IN0^2&L?wfjX%$u+9&3Xxa8!IZ--;*_9r?Ub@YDo1od}nOK1!&l$ z_FDbM$L;Fk_w!*h?$mnsEJ7-dI(a%KmS6*?%g?vwHh%hramTO7`^9J0dApT;n4PO*v9^=Uwb}m!BR1q(4p1xVRP~NVC6FIS9%ZX#M*H0rm{WZK#*AEE1eKW*@9jXoM z1P^f=2dw&zo25)~r80d<`lplnjcAC%TB@`I6D2uM(tQI5#h7+PFjmJ_NXxh>x0*7V z?5%|W%_BJUIqFs@v<&AH3e}-KwE*%?z0D&+S2lYCl@Ckv|0Xids~88=X}&;zU!Q)% zXHgrqoJCx}KK-trjXMoqQ;)+Jq^1hH0;s~h_W)!W>Q0@oFm+i;D)m_49($Gt$GOkd>`_hBrXN6l{uWCpEnOO1<|>W7}}@S~P$tq=RZgGvsP7CjmkNd9Lkh2e%y``GWm!Py8g@?JMIh{K!lf zReC>ISYycEs=bZ0HTPzC@8N$c35GZ8bMN*ay@{WDtA0%KhPQbgZ*QyJu5Dh=OB(It zAGGj#U+}t&e8G4k!JTU`NSpzowMNVZcsN4Jzn-!xCIoSaYU|SVtpJ^MVe}7$ep^_3 z{!qx=8Z+8vh^C)YmfHs^DByn!J0tuRH5r6;d>xHb8j^QqdIS9fO+ex3mKPkyiU(06+T}6rjN8ipRM-(F!!Yqrhkd*a2gVe)t5k0EIq3$i?Og8Us27rrg&D``vbgrY5dk$Z@)^H-FhPT=X&_=pB*n zq^|KsOH5TXI`zTf&~!T-aBoY-iXj};?+hv4y6V1&%o4+2(*OtD=gv#f@9V;QBvWX832Q8`|6LIUXnTbGe;69KUgjg5&o=|TBYZ%zA}Uoq z<6+les{F@83AI@K+{Mp6xlTuU2u?q~py|pNXnz}K#q&-&UEZLfcuT5+ff=Yra|?Ac zRjN(A#>Sze=kd}Vc8$l|ELn@RIfdud`JmW0l zPlPVj@<4W!9X2%I+#M(lBcPEiVJ%GTQaWjv&p#_I0=-3ZjM-drsrnbL510W zIOWfP3Q#sd`?%C6odwz_0Vo!vcvu3?$LUQ{$Y`r!R%2A_1TjbQ*A9J(G5WDff>zp{@`r*kf!5 z8{GBw)FLrWC*t~-a8SS-{Fb6Myp?7_+UwWz{D%HzXA9V* zfnEfnSds&u#@;}%N6AuLJ0?FI536oEtt@cHDwpPPY zHXXYS1yKS{-+rbZHm*d8$_Q)B`-MCHF`xgARGWrwA7Fycys0_ML zaziA6ph+xgzb7V(NbvTntrOObM6v$y5GaN6;%bdlwH8Eby~tW!@cz})MK2XxDH^B7 zxm>Q%89mqaB!;pLQo&=W#^asxqgue1aB`Wk zG$Kb?C-_m=aaxvrRD8y!+{C1Al@(23i0c2f?4u$i;@r7uP-0@}2mI0~^qpx1IvPz; z2|+8+7jBGLfqDUZ92N0SJ%*s!&rnGpF$7(i7_wV|R<^h61Z?tM={~JwL0UpFV|&0S zeVk`JO)tl9z;U|xG$f5K-!iW~gmi8@{txx}?L;^YoF!EM4ML&(*CX;@(O^lk-WP|^ zca@`@6l?x%UjGOB?YKPm;lzb0y@3^kV2IN<(ktT}c@2Sv!?Mn6NRJ3tkhg%B&`OwL zlMrwS=Z4`Rz+2MsnF;sSUV0YsPy<=8J!o)1n#ljsf~k&b^?geqUd+BDGG(Pd^8dt{ z77h0yy}Yl_fMO(1I;k(j=|{vbhV5aHoyJzk8s{h+W3IyW_qbI28J&uQOf>9{&%eOR zJnY{odMIPn@SkKb7{>~H#{pRbv z$FYb};WRU#M(N3<+4)j!1R|kfs94us8q(53HRqOmJKG?`gR%F~ z961(Kw;(*U7k)R}45fH`*A};?$XL2D&5oRrcbO@%YIibnHhHz)n{G+Q6>tp)fuZ=3 z5a%~j%TcQzU%8L^1X0bAW}ml>PLLZz8!ug}&A{is9td#^TNN^b-~+knneDCoA)4UP4r*&?>hzNl1n?PK6MnsIrk_tMU z!lwK?W7j==&Y5_@+Z&MyCHzd}71$q!q26^YZq4yhwWCmi!_fSFGiF~D!Gl9DnTJ#& z91x-&G#Gj`@-3$(tnEKuE8Ys>|HZImo9h|W>=GOGq~TG=e837>xw@MkXY z=Q){P90CXXJ^qZ4@4`%rLc7cbg$DZ_oF=Ft<>_cs@4#cfj6tD>mRKKZ%zsKy1XS!~P8Z^nX(D=Q2nUxaqw1 zYzu!p(*%DGJ|(?Lx!{ia#$z)E?@NpZcNQ{4BV$7N3jwz@*IOs_+SCza}2EYfiEn&khLLZ%<%Pw zlIj=I-;ZDUxrJ>zN`rVZuYn-6Y|}SCZ?5z}REMH&XfWA) zqiv;VqY*@|>y;4r7ve=}V$l*dsID$zYolrcsv;;uesnzE-Wwf@@5d{YKVtYp_?(My z8!W%S$i|`O9~SH$7S@Bx99{1bM4gSodY)9>Vwmg!Z0A~>>(En7n-m$&{fDe#iwp~A zUY#vCbNgh$87WUkEBXswZb$4j8Qi1JKGf<7L6&p=Dadk3M+;fnP7!3;@T7Dj<$^5Z z(42`ZC-oj}Vvz;gRxH0!_>%tr8NOVu{vlLJ{rKXoA737Lu0ecpTln(p*gt_Us11Cn zK~=0~y0+RH&+p+&5^Bfe%K|&TG|l@Xd`Yj1FTXq?3;7=|uq&`1@MZU-f-gTmDfrU3gM}~OT`%}@uj)q1rJM86Tm)ZITGhc9$j^&Kvr~Gk z)n5{!FCKJ6?%GWe`V7_aZ|Ti z;8@g-&z8XT4U(BA^YWTfKZLCXmvggxmP7Ma?Mc?E_V;y^XYq~I$9UujhZlHzZ*nX? zl|^+$ujQlhdheeRNC_j+)~Gka4lU?`=(XOlxMfUBdHx@P56L1#9pMWY-|TKtfjq2F zdDuarJ(fMq=Aq?Q z;ch%M;R16A>y7R={Xr1zb+8I9m`PO|lvYtQS)U&|mK~sOIp5QkW=#l8*1K-qnd*Qy77^a#~ zAZ6E6%9`wc;z=-N3m#!_>P1)+)7~_EnYxYPrVS(5G$kT*l{*mSXgWNt_y?F5!%z^0 z*ZKo}or!3=4oYdRUvWPlP{lW~n1 zqa@|CAUcqPSC6OH6CGe@q*pc3(JRcr<5i+}jpT%2f5)zoMa1llL)CEAO54CsuZ*z; zhkxmCC?R)1?@B-^YnDLDs(&azea^uKQf-tA!ThR zMwE1lr5cuD4CpIkdBsk`!dYIi%HSTiVpDAPb(1SCQ?l1K@tc^ERWUMR&~@o-F(o_u z0tRWph&-!l%|MjAYocXbCxnO}v0goXIscQe7(D3CAD)k1L<)~9wp zpqzd?5kE{~0;Rg`lqyyLA*V-36Kb%=w1?qUTO&ol`3gsD{y1L$9?rJUAy}OTF7XD& zh_CilT5zZnRvW;sUGyLiws<%XE~<#~ruh-~7fQvO>71=WQ`BP;Y#s@ZHV%*E@ zWwo}U<0glA6u1Z+pulqGLMKz`v@g+%i%$)m3Wu_p!%c@W1OsSs9UlBp1-rWDqx7Qi zCK#w*BwPZdhe+I*_E@KW>W#Fnx5YqKv_DF?5Me#SV=>M?( z>2rwqVR375R{)5W(G^@Ka6xSuZ>d(AA(DUw=+bG=?w;T_u}YRo{xlR1;h#RqOpuzW z;m(_mDV05}pOl!l>Vrx{4mxB?V2~KP&FrL&jh3D~s z8c@7hKdm^TSGV>T@^zjTu#g30+`UL?@3?KQROdu*ewAMu*fYKT%nd*h+ye0~QgGEv zMnh4kVjdLTLBdEUHB3V(dnoYvF9lP6q_GNa04V@7l^{~3kE<=htv{Z~ErLb~*k&{J z0sCv^F_n)_J)4ghuv_0Wnx^7#5;Ftis;z)?QVU}1udCS~Fsa~EtDj5IPv~i3U6IZ{ zf_;nW)r0w{9@n9a+VRh3TL6Skd5UB4RjIPU1lpp(Yn!js605?ywbfh`{3|hDf)Y3S zsFhZaHrn%zNDUN?GMdE~U1b!aeUE0qj!8!zDh)8pLVX%Ccf4=MnZg1591S9p~S%JLgUN$qFzQ$ ze9Ng(?~L&i*LbU+!tRoz*rPt)X3P+L#TZkO^k7|wZfG~b$q39 z#_RD#*BBYG@0C_}FpkC63Tmy4$0*v{JDgxljjdH$on`EZFY+0KVvB-WTVrH=Tm6hD zVr!LFrx;7)i#$dx4-ED}^k=A8dr?qx8HWM$m|882b@4AYHqMWKv9%#V@a@evGs@#% zOf`fQ#7?M-F(bApsI_4V2OyrH zAIT>(7T0>KG;j71ooi&pwo+Q%$5Hm6a{+MJ860E5_^OYb-nqahQ<_tMVzEdKrW z#)kN!&c@34qBD#$+~o}rd8Yu(*8T#KnV6$OGib0Ns&X2(M20;5xW zqh7-iUo_S@5sy|wjhgtPDaL2Rr(UAfd@?zM3xYjm;4Q4(pE8YcV%1Nd?9C+g{ zz>Z>DCMC8HrW{dcBZ&%_O{ucLk}5SzssxLVl`7|X7j9b4C4g9#sRejJ%AkwP!T{Mn zrJyslbtv`YC=^U-I{yd{^E~lPY)&g0oJ;j1wKOFYK`G99ZM{dG=F=gmLYBrk5#3W) zfJK2aYvUwSMB}-!zV{dLeaKwbOry+Y(+@7(hhRYogQ2EybL{xs#TNY^ONtN`*#*-6 zJuC1&3}r_=BG;H>ZXW6@ z8xqryc(0y!x2Oh-kf;YXM!zN&ccxL#F81v3^GX_aDNs-bUXwDNLXUAb+YP>EMp#19 zhnullL!5kvYn>*JQ?UBiS5AfK4h&0kFM({oWN=1Dn3Za!upF!yoH5Vm|7S)CJB2Zyd}2&&8UDLC zE{H39v`>h#zoT_GH;^1-4s zuvRzb$i}h0$`sLbb3KTnuTH%`Jq{x2<=tex^q z=5+?*U-To{Tex1^|*T%=V?1vMvQVxM4a0p(ANry4vF2_5dEn_xQrLK{ry z#t#ZH?b%^LX>m= z{VmSLR7-<+oSTwU&+~>s|B>Gd;(xzQ3s-qT8!(uJCR5D-?@zFPWavk(*qnKr<{85!JD3Xfjbi5d^KTvm zZ!9xo&&fcOu|$M#V)6A_aBv0`S?-ev)X@@wI?i%rEz3yffU=gVa0ywaI{}uDqam{< z5cL@+kWdcmCWWA{2l*q$$sL3gx?G;2SPxw%7NJCkOrk@!S`7b>7ABm1=BI)QZ|@=| z0J{YZ%FabE1Sfcp)hhfrxO+_zTUCf4VOLdeT(^=~yrr88S0<@9_tO~tnidHOw$*{= z?xt&%DLAOdnlvU?f^HPvCEyJ*UcnJelfUSzaV9XH0Sy!O8cH0i%1qW(mhm;_h^fjd znI`cVFgA<=CyW~%Wn}wD%j7i>_ZhfK65X{gP?(C?ySTK#WKHy?K=uAhq}5!I>Ijok zbCHbqKQJ&$8B}`v1-l?tT#puq1x8<>E4K`N>Ld)0g$P+yLL@ILlrG?{IEA2sl{g@X za?H#WH&B|nCPhlDxhjf${B-6n(RG)sLzE(m+H*aLchQw76XY;%24K*$8^6IrZ>dxf z6uaARqL`zcK!`&8ucBG%FMo_?#$Mb7fZ20-u$d!)cagcel}W{I*=e;1613wEPDn}!oyM{n4rE8>OHNa`ar%GaxOLgf?5F|!5MouV96n&!_XXpPet;4AIh>#Rfz7WI8?-16jvf>%P!Sznbo(B9iWOr4UJJwNl#wp;Ovdyj~ zrDK~_;85Ev_tCzINTuRD3 zH2zUc5hln@@VUgIPUh0@)%QIgw-+~4itJ9*Vc@;J`qr2llQ(0#ZpPz6g0~U)ikFf* z9ltZd0I>(5JP%wIe#}@qIy2L(HmeG^?{m(FkY04U7r&-ziLjPDsri2hyDshla}(iE ziSWc?i{TH8H-*N*Hqo)@C_-av!FHEuy?4ML9~aNRHWjm5+KG~zReZ_{j7|$fdh|uzx|B9jIX5MhFGn8(wW>`P*T=ZwP zmfq4_XA%O&aRH0^BHV8pa;~L=_tRDB1F62iiOfPpZM}^cy8v#OShm|S6!^kJApFq_ z19mRj`>|pT=g374x;}0Lv1ZVX1hKg{%k*}G_#)%FE^b_xrpvg@jiVRD8?kr^Xr_3> zgBTgo`_VHPpv*HExA0DZQ*oXubgUW!;bwG3k@6mt^VbJhZyp1RC^b+(nCu_Z80WS^ z{}{+LO1yDbD3>P)`46Fn=2xDIvBU2~-XVw^EJ*Wg%FRx6ya8$y9H8iR5td#_G`H2e z)vQFzlxUXAr|Bq(X%%u{1fIV9Ck7aqjuK$yT)Od9r`;} zYlHw|AVmlbK)6%7;XK2i60w=zCJ49HSOuBEvC5ZGL=jdb9~_|Zm7A&%t1mDUxC_RV zj_%wQw`YuTmxRINeX@8$&E8a41i`kOb_9tZ3cCe|RHqdl9=1NsG38(=d6a-m{-`L5 zzdvvL-NqfY#2g$qt_M|pSJXobjK>!ERZ+e#a1%Cm5l3dpdvF(TMAraByT#eJGoY&_ zj>qiYFWvzuc~@y4n5rt?T@3CuMmN#xfZpb6?8KeXR=1;i7c|9J4u#%Bor5?89E;R@ z?*^=k$Ow+|I{<`DIm8q%&KtcEkHJySh}$cZ+)D@=z$XpD%J0c3^o~xCt|QzP^(+I6 zxQqLzCGSl$$@b65d&G4M8((tJgaGoAzTuNtcE~i_mj9{>{bo#th-FE7NQfm^4Z`~u zBESgYIm)R6H?G4U*>z0O`wKlc<8avc3ekjY(uk0jGy#;WE06qhIOP%99C&)P_k^UX#{~z^*MkUVjWDeQX}v|OfHz1rLA*gQiOn#MwH527YH4fVrL9#| z6tJiPk>It6idL)Ql`{@1q5@WBzR%a%=S(IccxgYszkWO(VxoLm90j=}o$p3p&Nzhl93z$E$xt=aG)@aqXLVOoJWFx7TEFjcIDVQQzL zg_rPn6^`C+DnThVw{o9&IH~#8xPS2?4V?oyP`AbcTY2;euY57Sa8WNY!qfBo=2|pu z@sZD;_gd=FVm|lE_u_!<%j$@z#VGyo2QT!kgQrH%wUOhOlwAooY=Tq6wo&lHDhtkV z{C1~|h`uSm!8`iBlWH7}BEh;##6%ln;ix4fcPdmDr19-P`&N|rkXvtZjwc1)BX215 z04v>?WD(fn#|mgBmH*pf=0FU5o1lnd-5~`^v|7eB!7_y&hWZ_sYyL7*! z#cjux7|n|Al!P^3>QDVbn|iOU5x*fMO;wT+M#h3M<*W12Es0)SG4|9=ReepyRx#i; z=lTOK7{qFMPZw|^`fR4;cuFRwh?j|v97Zu7?YDx{)iynUQmNtQuKTF^=Uwr34)Ne9 zx{E9N83F!W(JNGx4QQ!JZ{j3Rek+IYe7C9@aRdQYtZU0PJ1y?dWg4Z4s%1`RIb=k;%b{KTt6Jx_&@% za`ME)^&Os#P0Z##c|x)xIW{?(vSJoXZLu#>JwyCQPH%b_kHivP$rvXuOy(ysHS)#g zx?}B&W_^KC6?mK?$Tvd>ty1}ud7EChbwf2q)x1a^=zk!D&8ma+EH#`>k|3MY#~=E~ z$_J=!#AA-H_?C=&pOhEvn_jOIIb3^vnOvv?e>-g2co<52ogn9@$81@1*mHlP)|lyW zZCPq9?)`g)WB<4X7?4HW1B?}oR~B}w-znU5IyB3*8fy_7^YL^TwM{nb`{My?d)<*K#(#=kCigVIWt##uf8o5L^AwNY3QyS zq#^JV3T-5Hju1PZ+Pwd9kd0U*ro*3fc91^u#=t>(e6Wf@EuH6D zdXx%;Tp2C>cCc&7xnd8s*cHMQITd>!9r;a|l6Xhd7oKToq7T0eK|0vWrMA*B7WS|L z%{B}2?vs@A@yKxOG?(RQA9jt7S&oDXq2}p4myQ-*!$pZ!1>Tv5Z)E%W<2-)*QNTbI zaw@n-5d`^l8bEr;aNTWs(n9_BT?i3NhwEoUqp+r550=qC#cJb6{)bQw^LI%!Wp%Kn73M+=PxCe#2hjn!( z#&C?tCvb*%u4n6ovLIDP-|O-yL~~(A>shp}JTsOa!ju{)^~MrKn>v7IY++?|nw?On z)g5m1IyIh^m`LB)lN{Vl$LWr8ycO7qVca|LKpcbwgG=#Ue8>{lQA!%1R$b#ce>(^q zgCSVOZK!yadN_|xhx(z(v8&@!$$~VW)|KQ*#F*)y>t+(a0oYVGYc^r^r`Y5f4Ep6- z_C*$;@pD9}dGDj=-}a{|)bfmw-R0v$JmdytE%~7LgBMkTMM*&=QYD!tM<954_kJkB z7#wMSh1%K?=bPJBQjeTI>r?*8j)guN<8uG1cNov1g!0+X4GnN|q;ufsW*&`*f=jKo zK)-PqGZvZOiq)+5HdFjLkzL!xQrDCQQ}<_yJsGR@`X6@)8LS_-+dSe04cqhAgF zF!3}4fPaBTzQn88ndC+}$vy0WpU&t{tCgRCCrJ)o>>#~i?;nU?&{we@9MXYwTZ%&$ zS1_9mp0hit{CD=vz|b?7v72VDi7npW#=u(~F)TRb7wlI8-Tck{{k~}2f4kp*@T$h> zyYBb5AN)P{`xAEhAGf05R8;$ZUp(lWsJP3PC$b_}{fkC--0#03-)-2N6>|A|6~->? z=kJ{XcVoe0gNRKh6gu}W!o&K93Qi4UKd(DZgGdUQ!F~u$@8=_>@ihg$wyZTUy! z_^xyZ>nxaZc%P{3+!Kpsj<=PE^16YFjCv$*#7eC9EOAo0nCM>|4l?@ThW6z?tP`?A zh!Tm9{MmHnHmWNsMbkAjtDYSg9d<=@j2(J&M_3>W-mtn|9h}Cnx%BS+$Ci|K%dF%oWBcW(_gkK6+-fC!MY4sa`P<|?;jW6 z-<}-0*gK%FL#`6gq1Z>R>HxWhs&yO;w@0qghFtj!@kWb~C>(pzJFmxvR1%G*Jh@IS zFlcpxY1W?;63pi?vivg*W0;sN1?SH){NiJKJCd?t(zy8SvPldzNl_z^$*5?{&C0%9YDtU zqK-$JB>n`XU@yzJ`a|-q=6QpMu-WY3bP*uv7%ZoY$WZr^Z3#gtScC4tQhyRU@SnNh zA|YGDaI&8rf?mPJ$8jo*(CAg+xX(LCuS(duGSNC#RP{UQR1fK?C;f`mCXyJ z+t&KMGHBs3vg^+{j~v+@|tR+=I0zU5d=a;wk5=)WiJIKPohrjAA_V zsncJ)oacm**5VOU+F(}~k=j?eh#01D1r0J!ZM7Dj<_kPD2d`-uvHQVwdlDi#JZyFS zCU?k}=wF-*gi}oR<5*#Kc)+SiylD4|)C!ASvZn5l!L1D=dX6NKV5*gq;Pso#hj26r z4EsymRj~H>K0U*!$14cy5nV0>n&Q2B2U-t?YB3->>!jDFN3g|HFgD=E8zLNO7s|nS>AYr3&6{1)nhNBxoR{6628VEyFP_=y5?L zettH|?&3XqR}6ciA~Y7?)vfK3=r%9+VEnSPX^ ze|h6~-lTZ+p{C;u0LZP3+O{%E{b?V#N^B$a8Id9}Kny0(4AsjTZ7q;~@J#q11Tuug z{<2!_)lC#9EVfc*N~JRQbmI#EP;o|CES_|+vh&+cQ04Xc%@)+Ad|@Tv$WF(1z(4q! zc#IkZ0ZrnXp((7Xi1&F@E@ln9(zQiJV8+>-U1Xtv4-MTItT()c&qzI~CCpT@pNUZ}Kr#_dLtC=zE%GR7%@*&fwL{$E zP|F`xfn@{_HQ%h?(KnORs3KTB_DNwXzurDcS351U+H-{Pc?#r+r$?|p%lW`nvh7lm z-?6zR4>!<83#`Mf&Cyx7fy)$j2!)e->ovQ?l&qNmFAaEps-NTh+cfaS-jo|T33&>| zBrLQ!#g9vN-cy;-x1{plX#c>WrgzspNBnXKa?Gk@VDX*1pW zS))nQ`ti)|7FZv;$Dt} zpx*!_&C7kS83@T&0^UZ~li_W=%X(?^SwqOn#{Xp3_iY$@cztfel_c6DqU32hWzqhx z!~P}oi$tG|5bzs%xzXm0bLX<1!=gO_ONOAmxqe_pTbq6drWf?R^@EtA%PXA+zbyT; zo&xn}YCDQ8HN%3E1w?O!GI^Ijox{_+O=U0JXY^*C2EP9vd874ZIbViR#}tNHc_nUl zsXH{o`Jegqs?LUihnKic(T$h`Y~J!DSe8dJ2P{a^XvoJkkE>KWRSLX|usT8BKFCv| zf>ZPi0*HTzZf8gl&|stBD`vPC>5>1zEp}}xx{a&&Ajaiw#{x~xNwD!*0`u3F$n=5! znL^%UPbjdh6O>U9hX(WvgkbX@2l=YJ3qRj%p{)lQg}>b#VMV@9SH27!aLkV89n>sE z&_YYB%!@D{o5!u}G4$|?6pmJS>7Y~WMiJq+{2}CA0bgX><)&2ry&)}3UPZFO9IhhY zB@D~<4J~bQ4T&?zXz19ChHjvg3wc-(|ZViHJZ# zHSii;%dx8g7ZNeaCEnTN2y9?ue)GLXxP|T+guDJ=lO?np7Ax7nz9=W^$ETkSg-=QB zE`^2gvLgDK&5UTksxu7_{oJBq>#HrMOs#Dt6N>hGbbn#refx9>(fi>_ zHUfs`apV#hOVY3SIn8o8|IvrqZD_87uCWP-0>C@4XlG*AfdW3G5{Okxhsa(g8<6v& zqgz8~zC!*Z-X~W-^Gxi-fkIBjU?39|0;I7(Y;ko8<|EAEbN(8 zzk$fE-$0LU0XLkGj6O0Fcg|a7p#f#60|#U)eulBM@ga|%>qouObPRY04YQ)s94(&4 zmj#HHz_G9$h|6jx0}&*CgG-JPphm5(9-k-Mv###1ov;+y!4wZ2RRt1YlfMtMRz)`y z^oHd)I6QpF2RoBerZ^Hmmt~0CWn(otxT%Ik3IkNuz;s|a01!v)RDlQ%+QG6#*{WmT z2p$uB`mvYW$4iwpTn%+=mLyR==c*ziTKK5nq2wDor%S%1%H~|;N{YQ(V72a(uJ!)* zvTyMkSG#_phgzdOib(R_Rvvoj*$5i$t-JvQL+-c5091L$KPlDnXaWIUO$tRstLuC! zrSKBIM+fN>3+P%PaXNKMw{&ocL_Mr%r^yO4-6Bz;0pklp11j<~;qf7ha5a?LeF|?L z#cZK&Veq6VHMegVZ0CylLZj0%q_R?k{_MWpaTJ>YZ}3Uf$QRhY;mE_Tl8cra19WtSf-%|<1c&wX<1G#=FbU0oEE8_!bvS|V_S=ay zB*!TNPZL)b(&^IA7kURgvOZOL;riO}Vn3--wnB(qJDSf2e`wO%``#DJ;3dAo5a374 zJ~$WhBN6G>JcDqacnaJyQE%ExbN2xhp1gScu33}9p{dLCXVs+8MXMIWijbpa>grH& z&bHfMP#zlj_XFNACN7ups30ZK+VRZmkmLJ_9>ekl=;;mI(i^&s4M@FWX>8TiBCj+R zdHiN13#BvH7dEOKA`Mh|s))9|DWAPhCK^d=@gZM1``Q^Nnegz@^)K*{!C4}lF0(vq z-jk_qzJFZPQcy^=sxTugRC;X3Q>{i63Yjs{Gnweb-s0|jNd%o@?fqNOPpqd734?=zP+fZ3N};oQ_X10yZD%0 zorO;Kc80b|yRrD%8m_X^okfRZeaHPw`(w_rT*yn){Dxv2C?c77ESCcJqMiXA+M+P#Xzp~wO;I-|sf z%jzoj>ne72A*$Cvnfg`dk?3m{;)g@eFk<&Bstc8np))+OLt%`7JZBML0HkuQaZS07 z2ufrnQx#*bU*5$7B{n$BsJL)jE$-z@IF7*pk#UDQJ`Mk=BDGQizAA7Q%TP;&rZX^w zjo`*iVHG_vg$?4a%rH_c+bqaog+=C)C{~e9`Sb&diY5sLA@eI-g`n%~>W%_y2dx5n z9XDvQaOJpR^>ydJ3zl$BAj_Mz*&Pg;r_W;N`X>ntheOT%0bj@}Vi_@F>FBhQp~Dn# zwy`@U=&3IT-am&7Q3diUW0%x^CL~wQx}V|S`%3`P-+$0bf#hYeoTUUHXVo?DFF`4u z^C!h4&&aq6!zr@h#rtcaLEsHCwUAy^rMgpfdIes&#=ABWztK$rAwTPCXdky%>l0_w zlSurabG;WiCu2KT%+U{xYjrTLzoHusvQgbVBkS0&pWv;S7<_FUd})kx+W;K!Chy3@ zyUS^|fHip^KpXWC3tPtR&yI;$;LZGS8(is3mxa7EJsbkC>*288*l_f>;Ybui>9ulZ+p4+} z@214@BL46wHB3uJjKAA{AopjOu$&u8^~+-Xy?%xWWB&X5p^cCC{pC6*{BES*WsAk0 zd3T3Cln=L_uzg%;ogFfna>l)dW4^uipv~x>PIaoYJbm}$e;}=lHq^{yLBy4-E^-T= zRLGy>;R`WBjQr~u3$D41-5V(*MHXro?*8u~$v|E7=9zti-Yh>h-J6i>O@ZspvNyNu z%^SO9^rl%c`ZYIO0VpxkR&vHhDvn94-VO8_NXHA@fQ>!6x8oDE?>uazrN_s;ZQ<() z9d^Ep{BYq9#9!*nI?Tp(MLn&^thq%BzuJ)}OWcfGsiG*no%l))rU7s#;tQW}dN}ir z6aDiBUkd?}j!@ztD`7R&d0!D@yK1A?Nu=Q<_5W><7?;jrTV1X;pVkc+T6_pItx^H#!pZN}da5+f=3iOfuK| zyQ|2$qWTA`D~PPUF~xW{@KTJj)3-HlDD{o=h+l7u?JZiLWak*;RuYoy4y{Qpns{>m z&_m%u7LJxP;5oec3hgt>!s-hRjA? zHfQRTvN>bUuZ&HtDT`HR;Z4}1ELsUrTfG`aD+o*}zb3_>Y+@jjz4-Are#H8vmJ@#x zV;RszqK8MKlflQaa9k%Act`9hkC9!PpPaErIQ3*jbeDRpg9LP6iMu9Ze?ZG)Ij>f_IekQ{G@kP~x0xJ*`_^@Gm3to<&Q zPNGIT1cFaZ#-1<^dB^Pu{Rz3~?+LxtQat~h5v+lD-)mn@M`M+YA_dJYy`2kS-7NKh zH8A9C3O%gX-aZ?Vmw4LCd;5)KDpA-)qyNea8vR{ey3x52YxKk6)@Z-&8$Hl(v_2+o zJ1?=3n%%EmO{Yhm%&t7>-u*&2V8#We0hSWug3Ds{6mQJkxGU88yM4Aj-MWeAqDl1! z`1a!+(Sx~fXV3!+*!fNL08eOHw9ndorwsR$cH)ph0Xpah=EFRq$Ry2*uU~6m{dc8b zTYHj>RPIEBz+d@KJk5q@*N+mfs_id?h9_5RF>kJEdXOGYE#}WSTt;AOD%!MZ8P1Zp zm{v1Zw!{Hz*C`8FJ)}Vjm7>!Y5RbsN9q^l>3|1HMT%Xp+`df=cyG!5G zMmA(|cDqEb-B>%1u^!&9*E`8v+g>13%cD#PohZ{tzaxtf$aL9s$DmpPIIQA z)Oe05sED446?H1!k2a*XIfh!4cF0LQq2?O#Z&6Mz6>sUEl{iUn;`=`H?-x^#h%Gn8 zqJyq(P%vQLgM_#8*)$mP1-Ta7K>=`dWGj~Q+*U`maz5vW6qY5jmW12;%mm@~BJQk) zeppcKg{A?DM2{g67gP;Tn5aBqd_JQ*jDLfSV-(+3AC`-QZ{+p$1%N<3PACb32Bm^o zoIt4MHZ>vRB58@Q=XWaqn9cOG(ON!T{wWv9$^KmI%KU;&uTzRqY2AJN2>5LiJrOw{ zYqeT(sl`+ohts$MO2M)VJ}ZXSlRcioQvTGC*-xtHNc4P^M`d{wGVV=4YAHyL3=Igw zoVqYckJPF#t>=OJ(qC$tNfG`7T4bsMc)URz2hymh*tWVFzhPMYZEAQp_VN0GcFNH- zJ!Okkt*B*_?lMAEf6paRoL6}E!*z4<0-%Rl<5ZyeaTYC@7R5%)>?U{H7K>n7zn}C z+(fY$Y^9pL-2l~!y@gU~m|)q3RyqhKUL=ish;5S#k!6FmPQ+%XS62;Ley;?r?(_V6 zwJ+ETtwsl5e@&d>1!Qk56&C%u+|L`AFkFmmD6+7se^ zMp&>V{h8u$191S=&N?-T<#$FnUS0%`;p?>M&O8GG3->QHVo-x(R*fySP*YA0Up2pG zYcA9@-|D#Co!5?!V!Uu+s%TtMi!CkKPqZ9XQ=@cZH#lWb^i9y+nCdsYA1-z$8byTz zf&qy-%Fsbg!{r_y9q2`dU4(m}gs4xkma6^(5-)c-}J=DLFWcc7FM@)r6i>!3@X z2}tSJ!|$?htXSQ#711{<7z6O1Dk@@xnP^;*tI-$O4^N?wSm{#v<2NxHjbCmHHUHj# zGa~e5GRNA93`>TZH-nplU(@no(Ol$QWNN(guiKJpdaZ7pAZ^u`47Fje)SBE2{}$-l z37aAP4`hoTeyCA4byuiKXHOD3DIa?1s-pe8*P)eI$1PbRJ1b{zGIm*!ohcgDwlUhn z=>@cUDvanPXy(*{utnkLc|#b8s|G)r%3t{j+z^D3R_8t*Y8t3%>q0uaccWI4F-^F7 zL8xJxoWImfyy=?Jy3)SE))0=-sTq5cxrp4x_I0*6F7~r(iX^-9v@4ElI4>E+os2Fe zj*>P?6iQ2#ty0}fT&+XV@Br)7=U7>x&L`waB=^Ue@zpqM{5215MbLF{%pd8i^`-4R zh8pcN8EP(ppG@UH_%R#NL1J2MIYApFE)!5GF;843IJ1#^Z+ag5lTQFb&Am0bEcUJ# zDd~GR(yAt3a0^(Wowz1l^_`Z6o(Dw3^Y2?}N=UVp`v9p7T^wmwY zO*>7r+I);^^dU$hm<@})I~Hy;eWl)LqpP(mrY>Cpq14CID!alBa1{tQs3yj>R`>K= z<+??pUxu3AVWu=Ldg8rtia9a;dZ;-uZN=8?oS1ee0(4>>P}s019@aN<_*m=hF`qXp zd9$Md)Py^zGVO>DZINz=jnipgu6zyXnTYfzrVEIgxolrnz`3BFcV?Nx`f-B-p*9&eZ`vz9d>J7DQ5J2EIs)rK1 zx{JK>Y-FluW$E)mSclW?R!A|HanS z!k6uj{q5^7mj>I{ER{JoqfDYQ^XB->n4t!1k&?HkE(AT0GhZ z-in{-7Z-jQFPzD<{g~p0(q8o?)XE~$BF(BZb(OvL-EOf5=iqzZpp67Bvw&QbgwnA-?^UpWT^&F{U z$mH|gf)0Df&kK5a!>2IB+dFvYl0KqEE7fV4%*(!yd7tY|)V*o**6b<~eMkN4@&A+l zJ%__+M*lv3J>9=wSguB~uNS0ealxklrGK0HsejUkmYq^ILH&fUU2Cz0IUSL6?MenT zinBicpt*+%nd2jW>GjX@p5nVmd|n}sDq{nS~jm{xh=5GW_z z-5s;u?z>g2b1FlXrHrFDJMi67n`t~D89CNQwaSM3*2mI3;>y27>>r}A_ZWt_%Gi0i zm9eX7Mea)bXxFEOh#l@JM%js9hwQai<|S`YU1Hy;EC2Zy{JNaj|FL%|bydVJ#zA+q zU)O%y*F|nk26$9nqQaI&AWOSr!{|J4)|!QD*gxOvpH(;AU=^4{Kkv<+J({Xd$umE% zx>ICkVEk|v;twY-VQOvxvQWQ@Lh~NNE*BlIF^ydELOS`UckheaJ1WU}=j7r9d>m_a zf@0@5^EW>7&6~xdwNP)}*+4Z+P*ta)`om{}>J;m+B%xXd+R@(%8op^JJek4ps7qf+ zB~G)^a7>ok*XE|N=u4}Qzl-Xjxj=lPC=YL-h>#(Q8Mm5tPp5n>B^C9|iBx@&I2#Q>wa0oP!LAd@M24P%!5VmY`gHV}9pd-Gm z>xzYM2z2B5Owhv!E0Or!7CaG*bnbp+Pb5@p1Sh5&fTZlCs#G1$^mvJ;oSO$fOZi`7 z*M%mH@MaZd+b`?5^ID!~BpX-MgyW-fZA?NQ3G!e#T zTD(vF^V_c+qUZ}cgn|OQIzLA>GL-woPtD-!x`0oaG@9KL)jX6b{{Z3eB)%6q<|YO) zzK)J|(8sSrKafE`n@s%!)ud}fUK=4|NxW~`DqEs01ghyBR^%TIEtUKuS}3V(t6k@s zr_T-vryA=(I9+o>F7;2OK%>pNw5{fVNF1dIFXX&>?OW>^d2?C4611GtRP>gbd}t#| zl))))%e@#c@X6;mXyeMfmAD59UTh2!5mkq#y2R?bykuqBaY)MpCbgB7s`B%PilA{V zHM2nTQlG7p7(IiU2x&M~6(eiT*Hr{cL!x&Yk`}wp zExJY50TZOzjF9AT02auK7&#gn+w#1IRWcZxSlK)r-?+Hb;E`MtdX>sJ{j-k7)df{< zhF>LVThm>!6I?)cn+yu6zYV$u(mnTDJOWcISc5#z?vVj>&)`qt>W#)BMJ&7qE4vB@OyD)52;&Q0zle?3Qn5 zWm4eVvcSp)4yr*4NMGTI!}DSq0_^UIMbc-`NP}9AOPv<&sR=6N-dp?XXGSY^6OPSw z4#AMh(PA)4y_cVMo`)c<@7&j*X1O6aLNG!`gZ)nMRiSq_UnSN+g(I;8D$wmf-Y3wk z)%d3aILxeVd<1{X@u!A&sc8vw)qXDgk9i z=*Lm~7#faYftRu*EKOb2Xi&UGb*RU>x(I>pObo|7(UTT%M3C-knN-_4jug$W#Oko1 z5+lUo(d@OYqfx!DpoI}-G_i^wL-pgCNo80lR`d6&qBZCiB1JEjQTkm?**di)uVN1X zHtMFOylCra{uEZgBxjtg8!Zqt7=_-@r-ZzB`^JX5ij;{%NK$IE;bYi42(X*oYRp!| zjqihCkNvwpQ00x*pGwo8H2|7WO32NA2QmaR$9XB5UqU!r7Wey7E-~t4Z2b=_cB1LT zpr_jHMS_Epz8VUk=J6frC%0~gzx~1& zPeQ19xvFCh6+BEZ+R|Wg%HSe0fnwgpx-4g^29`4oCFKnEZj+cB{JQFj6nFM0^>hJ^ z2n%b4h3LqI*ZUO;?d8-E;B~8p9LY!MRA7o+9`M0Y!o}T%iv7z$)!iIEmGh>gTnHIz zTFBU_)2hM96f`CreIju?&$U=_)T%d^qpr!mHp9}68{NO(6+i5F&xf7g#uo3or@Gqc zdTKb>=zgTe**(YDb#BqAToZp)U`?GM!5c5DZkDNL|NbhviaI^*jAvIi{r7k_ky`y` zTy(K9Jkb6#ec`4Q0nGZVK|}e`ZSTtk=&zqke%>C4&5i#(5NrMg5C}=jyV=PXn_s3h zo6~iOw{z8g*lVt({TBB-dOfjJE@#K^_6D4e;!=kHk5g;7GyCGs*z>k{m1`tb_-;tw zZuT!}n8B$&juY2b$HKL24yr_f25$NzE>Y4}$%lt?gn8ZrN4?)UYbi;d&+K^mX2Lt6&%Wfmspn0;{36-$ z!;3GTcJ9=(FPU~OcX{E(m!4O5`8nsFSI1oejEc;Bh5AFNnlYvH0kqrf{jRrMa%Pr< zm#rUKvGdHK1i#U-j)L&ut;BK*XLH7wth&pV^$lk)4-ft%ysR}ZJa~0@*~-Fj_EX{P zmAvW~9{fDd^TW%Q7lsFK3=iHGp1mnW{d}#j^s)b?KI3b?)MtF{f5}(+_q*#%`M;82dJ;%`N;6@B`_nLj;X9{>K0Lz3}&}9pUdw^L+ee zhhehfViO1p8|Un%J97Ei(;h^~j$A%;wdk6^fFjosaFT^I_stER(S3^WVn_ZqFFyBQ zoK<>p7KU^PBiC^g?Uj62q+v(!l>e{r zeEK*umjTZMC7JM?kqJ-LcYtT%vl^dMzw>%LxqUs__=FZ+a%k*|VsFE>pQk2?dhUhK z&dV<{D%}_rd`$A6;wH)g<>d0{%iibjdQhi8t@ zNI@3NSBW6|mie0dOa|gZuQJGEq4-j0q>CNnN7vx|R7d|!LIkz0)W&M^M-I^7yZN%O zUqd}RdxO}&=(Ff(jaahlnCoiF+moi9&J0hT$l46As0`gVyHu6;@h?z~;}$l1h3b;< zhg0eq9QBm503`zQ%L>};Eq~fo>)6`HuX94bh(OJa{6`b$#0K9f-DRISmM^Z1j1Vc}bF5(tgnsBrC38C??c5BcWr9_skr%*!nMp*XI* z@bId<`pIg{sz~J@u|_Vc^%D}muxf)MS7j6lS&_QI$;sc`?6IAiMHiFG^ReX0N-=*Eu+9xDY2RZdmrQPs6ql2o~LgAtm9`l-1?{+F}Z~7vxLVJ?M z;~Sf&9TksHc>SEo{l$`uEo>WG48xYSa_m;LMmZJ2-CP_|yHQ6*i(ebJ&E~C>2YDz} z@~V)Yt}ANb(+o~gEMhB<&^cVQ_7$gg5=A|y6{QlM0@i*k=bf(mMajfm8p?3xpBBsD zf;#9sBW(;vn5;3WCQP&9HzM3$xk`%S$xu6v5g#gnp@7dF1JcP(?=Ndy2LB4nkVsL8!ua!rG#w>U%4tbQV$PLlG*!-!EL&UA22n|+gk5syD_bf=k*sCk zQUY6V&j=oRczooQ0*( z=%Yo4%&BA--xi8P+8NLF&l=s7QpO(BioyvNOU^2m633qc$8@rT1TnOPJ$C&xE2~cvNJ<9B^o+YBW<*q{gtBI&oLYb8ei|2sgl2hRD+nWy%6R zWsZt8XS+zC>mz|~XG?1&d9G0M+&*sHLrvEJl16K_bsXuAD`&)E)Dx3=<%?A%S#^Qg zdBU?YJDW^{%Guecy9~ZEoPrWl_TJntQ|8#w{`u|`|0BQi!0R3N&y$NY_s_4N$=E+P za`SEb=Y;Slo-1v(%b$etoVS~~@JqsWB%F`Kx z^fWiYAZ5smLA<~Q5M?_dX+HyUx?{?Yc9LnALQNYF%N$*0R}I!O>Jlh==e6vwV`rwXO%w0O#j2E0ohbFv7y4zDH5{8&KUVZ+s92d& zI$}oUx4mQLWo0$B*8NZ>0}Oi@GO#tj?X~?zw(EMSuSVyF2K2z8Z(FMVoJ2E&tWkKm z)!`E7W7c9_4K-cM3!?n^p*psBYxlzP4s(6EwA_mIArp2gf9z9IPn;`SgIPq~D-1__ zK&s_h0-Z*XG02%Jo)Wc5Z`h;9=6Ua~*&s(Bqu&eM3?%7510LKZ0e5WwSyEwse`^@6qX5w#{2RG31Z2G zK8|Gi82_m`iER~;Z>yM%$`4>oS#}{jOVfvqqBCL*oF?R`}w_NDG<2ilK^4T6859 z(I17+fAWb3{_v~tvP5BaBKnj*`(o$p=c7+;d3E;JpM1iGQTaTKSFUC}d`tNJRjv_A zFN;36>?2C&kWP-uiZ6U}#DG=NWn2Cg3a^Upt`$5G7LdhPYKgAXf< zJTehPqURJKM}x8F6vOfD{5-5DNSfz$zj}SDe8AUrM@GFZuY|%+h|MsiVk9~^5foDSzWhG1jOvf~F(2yz3mfBI_i*D1TfZi5lszgQrz zm8IQAO=`ZVt|)oZcT3 z8}Ov;9?Cm`Q99WutIo50p^>}nIEjijyYWb zae6J(tnk=#=9*5sbPiTMM!a;+Qqy%4TwI4@#W{~|nQe@-lwJd}N6*1Frg?^3R`|BL z?9!IY%gS5Iz@oCD{AUrJ&+D?nma^gn-CD{9l(w9IXiM1-%Ui||EN%JuVJ+haX?Vge zIQCL^svdq@9IAKPiZ9`*%&E2xk@WPb&d?=Dd_$L@*`c9Js~~OYI(kKaotcrdDW@K; z&?|hBm7z=EMeSF$hA<4^c$Co)~^v1d4UVCQ~Xa z49s$!XgchwP`Z6wSIUbH71jE&7|aF=8E?-t)l7ozJXe)W zl0{*vVAcjB8;mN`m(x|zBt=@7uP5-9Q`*N8j*4r3!xIxzlefhmOYPVxMB~k51f`AD8X! zBdFGe$ZGO?EC@H$k~}qWZZ+KWzE*>O{((_9j6|d>Wb}hoq42~ROGC|SvwnCwN0DDJ zFJeVJIBgjxnOvLz`NC^33!MT6H=@!22|@!V7KR3#i0ujnMxeZ6BSuWAGDl~@a!E-# ze5T~^g;`lOaz~8kyn|~Or5`N-ZL~F#0JrhON;gJuo zdR3lx@Aom{c-9|j%ZQ_rW_t@(zn4meoFrbL2k&95_aix`7vO6bm}$hYziygvFj#-* zbTTxbB(&(T{uZ?&oD5gs#2@j8m|*n<$^8@!k>#Wz$*SuYj0zhv=S3)=?)W+Nrl~db z@jkC};S|qE^vm+zeXX6P=|G?7GaKd6XDbQP7=4aRPQ*4+xLpu@o#u&!u#QF}EC5Y_ zsZ_3EFfA;#GkR`fX5|2bO!leBE7X#Lj;@h(vv*XUbh+)}N78JP>U{$c+n6dkPfKS-2hj5G)1 z^v#b{1yLW|V%N$aq!qrHT6j^yPjhME`B8fQs6plgNv(V>Tb}I;B+A+SkSg%v$|uGh~<6`p0$|1aa;1{KunmIzPq>T|g=#r5az5 zn!{$p;IbWUWvU`TCZ7;(M;_O*IrTNTiHIHqZX%kI%GmCsV>^|h%IY~fx)XO1c2m8u zbI6s^pOlozdt~(B*D9lXPAY3FE7krzekgD9Dx+luTno$Cq$o82%lY|-mbF~|!?Kp2 z4=igLe^^;d1>018dY3ZHj{7JScPJEze&X$PbvJD?dX33C2N3xxW9x6SLk;b_f2B76 z(QfZYStH`2Z;1}D;4Klk4)ll-W-s9{8?KEuyOyv0VvhvLTp%28$Yi%o8lF0TkSZ$O z;Wio8%fKHb?-5PM_J@&k?fEg@lqqkqA#NYQ)LY7O<-9Ik&fq}A9@coD{lmy?4U47^ zZK+#RL}q755vS#%buMVPqqH0K675(gN~>MFBc;83XGdvuC=GTHhY#F#g=FSVB?w22azip{&4dK~Q)XgaQ#E2UF`_foB+!c#g^;VGiR z`=ubv8B{n+#1|A6rL@%%ga%HGL5Tx>K0DFJl&vH8dfe#q7y`1wygqh^qtAOhYV#B9ye5f+fV9& zLEXsAo*1cP*F7|r zSD{snu0wK@>(wD&zvnC<2M7=0r_B)%YMH4Gc0mU@ZJARg)QFW>CDb54kq7g2CX_4) zQuvzP9nn((4C#WZON*YamYvw9!x|g;WMr6f5JO#0o=weGrI7tavd6fo1gH>@OMH-U=AgDxj6f!H+%+Z|X;|4?NWM zxPr%R-j=u0Vo=8Z+PGng^ZsXGA!k-&e8{H=d6HCfo#r9PO0mVe|4R)zfdXxmb};CX z=z$K7DVY=`b`)|^{#he}AR+|gv&sM6A3jA~zo-ZYZJ0Zy7%yh0)|Dc9O;1CCPI&{hFF2dtS3ngT5nu?1Tq0 z6f@uM_z@!B1Iwv4&wFjxZ}jVM?Nx85I(+y3@73O5v6bKsKA1Us&QF`($DEmAdVl^R zXL{eWbvx6$xn$Uy2-Y)WhPOFRA23GS+kM{P=uxmdy`RK=qtD^ru)2fjYKHVxZW&q) z2Dq*A&ECBWeM_m~)3>d;z?`A}YDTfB=O?Qn!B`O84xypAOqOc9hjgC3Y3<|+dE8!2RD zz4=>w@@x5N!lIYeIP=+;LV{yt)UY>Q4KRx!#iZHHfqk1 zvcTZvd^p92L#~43`tW1gMCa3jEOu}Sqiod^o=DpW1XyZE(G9(7cYsy&FMz))fLYtf z%-?Nm-$oA6gw$G{Lfk5iON}IfLW3aro57nCl}0U;o>AC_y-w_+cy=8BQ6Y#fF_1N( ze&g8+Dsnf4`VoK)U#IwxlON?sfC#7e;1p*PjI+n0{0gm zINTY$)HJ&t<4d*ccV};C1-bx-IAF8=GT(wMt>H7R>?KiuS#*xfyF)Be{poGRtOAJD z9ilcrx*$WN%mRUy2b+km6iAzIiQ4=JSr5YELZ+Yev6)Pr^q6z_{h367S^qXNaHSK;oOgnQA7TC_@-E`;sWU2eyO}Vx;wwWp+98>N5 zM9f^HO-|0%eS{|Qk$3-to!{pCy*^T5qaHOS$iWz4bHk=dVMrR-;&oX6zWZSNqvT%E zdHuTMyE-)AQ$@Ov3_e=Go<#?9y$yE&X!EaepgpPXmKW}N+IYZy95OEo- z5*SPT*11LV^w@U_4h?XNP}-6PJ!k!yRIM?|T#PkZu5K|hf{8J-=k+@NV;IP)T=Ny` z7VRc7CRD_s*oy%m%VD>_zJjtAXJhKNfiRN)iFfz!dLu?24R2ShnHNbBQ-!`2+LFkY z&DH$RI4&=|q}~5< zT-W}OF%Y7zs7JJC`i#uaYrBCw|9|8S*$TGE8*=5~Clhlz(A(|#tMa=u=I`72xlI15 zcPa<+Z?27hnV7*}{rqQ+zgqIpxAIrBH{8HF_(t0MG}3jN_HJ(UX|L_zKJQ@5ct^)B zRew8|1>Gflxh=WPUd7+k^-Qh=qU&U-jzm{GZSpTMOi|cU6iYF>#RzI~T*udZCuppv zPX89v;j0;ZGU>uGswQGBCKUS0XUw|h&tf^F2my{-pjj$&nAw4f2p%g@5Y-AIIrpOv zsr=vFEmyL-ato~*o0-=h=gNDgO^%6eUeO{kP8b=Fl^xfs$6=_GEa)?#v7G07xfYG6 z#d99!HX{&Ug(@*q_Oe?nF42y|@HyF&Jd5TlRhCB&)P>)#dXc?AfmvtaF69T|>!DWS z`OhW+Gv4>_b5vw~*jLVd$+eS zkC@lAalUJ#qH`PfEpcts->z*gH_=P0$9}~`c12{j*Gbj=)k#YeuE(% zWsVHp+qBcmMw8BZN0=pz2PAgYd}M2)(~W?CAMyA0tsCEN7+DPgVEch*|9z$w)kf4@ zsyxk2U}%fqRn$t!#;<#Z8k4-!&ZP&XEq52~&prCeLM}*&DQ{9A$1fb)O|f3{a;D3p zkJHs0`#v4rsnn=Q8#&YT*y2|9%CV`N!~+E#630h4u(rR*=HI8t1(D=jxy?B58c?H% z{DS1i5S|DAZ+y14_~-b5{au`ZR9)+V#}D@5_M#p|#NLjLoJO%!{+|3rzzsG15GW(V zNB)F+&fxeUzq48cp9$?-dScK{;{Yt^^@<)?_%VSLi4}JYCKQ18u^>CjAj3IADeOW` zKcW@R1+l7TC?b%BQDj#oM^oc`K?Q?xB}IgcaLjLbr@RdRFP35kOjT{RtOyz-l1Zr) z9Kt;Aqb8`R94lsTt2DT`Xt)^Mn#4U)W3pyzY^*0`YC{-iLu@R;0e~82 zH@t}z{0_(VeFQX!bvJ)V9FI=#*b!U*p_bpMs0&}!Jcr*#f-m|%Vy0ZBH^x1UZcBHx zSC<_PPIOu)N~PH?RTnLDz(&Bbp{eGrvoWeqQ)DlZ3O8|%_0ru09rfKyi+%S}VU_D{ zdpGzr=TFrJ;vjf--0SR({s~e-qB$lzMyEve50V$^E(ft~I$Am$|LU-MHM; zn(V{n&emiOmpfYVdcvuG-+bCpxY>P2@T2RA=!yz|bQkWHa!Y(uT42#tKaNZ*zr6WB zA@fG_yLC=02Nsh`fU$OL16GW2g_HO@CeK8eBo3LCQFhm8&%}-Y>EIZA>RD2EBiBsC zAV}}iAz^*7Az%_)YI0wzty5fB2)rZZ-r^fL47Q&)yPEjc1xX0>%Jxx&g0J@`^G4d2X`C7HHa{B30^09Pem3`_>UQ?6 z3k})noJJG-Mtv#o=qr5oZE$A-&^7zkxB?l$oc|vec?@fQt+Gru?wa3c_&}TNoL0d4 z3}RY##`XF4Qsk7He#zIkZSmI4_0Np`K!PNvOwp_E7V)yya9J`ff2_UfX>ff<*Hl zYI{P?w0c)&$&@~*u8J8_YV!g2P+4F68eT4`v&Nhqg+p!%n* zH{;b`lKsGroa4Xl=LglVULdC{ZS5c+>+ckuDtXiU{gYsG@zP9eZnxj~`q5a<&%Uxq z;>}-Zg5o(5ZsEUm)X&ePa=`Dcfb+SGjj2iRma%bFvUlbxYIgnZBq@va{mne6nu2IU z>-t8yA(nP5zv>S>JtDOdC;TIn!%ow3VlFv$^SqIdNH!T~by(zWy(al5Ed2dgWOl^D z-$TG{2@O6Ae>1mTvhdrk`%Z(u9Sc9{2V&gC!q3IO&1d1?`j4n${$A^ih5wpUZpOj~ zQM6CGr!x!xDn(or?X`2aXW_f0+bC&o<7(H&L%837ptp8z7|c+P)r zXSDh#4uPgX9KZTh67)%f;)Zh1Gjo;M1w~@h8T4H#Tv){mEvib{!fs`Yy4fK7Rv!!> z@<*x-HOWuTef{O_{zTNxuwH%tNjSU6CDE$3Ov>IBF(yIh(@6JN&z3SLQq(VTG3ag` z2B}-sb~GZ#?ZJuelt?GwlS$lQRcLNt-SS((s>B@*))NC*Lrv$a#D9l0H~n9LG^PrE zYL1ItSuJw`$`PUwi0xcUt3p2QXo^uID7w(3o8~gq@_;-V#Dn(?HUF94Y&@xa?>2bw zTXh$A`c}CnRe5{1h{*MXjIwoEx&V$$JC*8~+%$^(l<$~5u?1D;2+D$I8(o2a?8{^m zd|hs`p)lBC-V1Wg-xPsCz;7o}Rd!O@$=*3H0#f6OLITO=wx<@Hp>Z>QptF}&#_>vc z&cH68_!n%W5(4#0{G6$3=TkLM?6uBEvg4|}aCR`jeHk?G{Aia0+yW#T;9Km9qbAqH zZGmQEd-d^cw?fX@Ca+kYHoj-@d$Tv(0`7Mpo((iEmt38P;~nTSWYAaIiqUe@mKc{~ zYJJ9UqzQ3?1Tokk!VO0dbus1c0En9Ff(cC5En4~UMMf*-lP|PxKACT{G6fkA>J9_P zccWW%uy1$yK&|)Azcn2k=rlf<(^NDYK$6`SfDFzzh}p61#KZGnx`nTe%?gwJux!q$ zwWw8YP;cdkBb$MG8h0XTB}vQ5R+b(|hMS6L3I1NCr5du@q5RLQh=%c0t3~u^DK41vX-iWdUja1Zg70nflspNIxblklQ0JfM|U`PS@craLfZk%uN%)oU}<;m z8uxQ>c+4fy9yl;SvV=c=O)vaInMPPA4#kkHF>7${Lo#-a&-x;KE173(sWWgelB=oR zt1ffSUFxgv1APNOcj(+D%uBoU9C>rb$vAW;JG3Q95DQMmePIG`dWWeyL%H3w5aG{= z@hDd3Ks5q?#x1OlqhG0pZFa0L&yMxs>}>WldZnKFy4|#)%S>X45Q~oUD zaoDcUw)cwDZfM><7D_o$TA-$mieBea(Ycm`DKQTc$BGrBIhcs8nKixpnZYrJcN{FXViP@u>B8M0Ba{On~<_9QrN#v4XybK*h< z&86~1P_f)inme!b8aDdQ$o1th<}zlu<>LH&cieh;t|M7(kHFcFTOiK91Hb3dY6p^4 z!UOSp*x54UJ;L;r(#L@5tNlV$j6RC#>+M~B;eW&QsqOE~^c_6KCuEZyA-mh>_YB?+ z{N7Ni?Z92VA-K^aGZY!z)nOVLx=`iqJev$-pg*f!)?0R!T4^7L`g%xHiv+q6f6p;* zqs(a3Kfg^IjtgYw0#bi|jrN=!g)j5DF|>N~fKH~?1-fo8?EAa>Q`(jM-ThH5IPLB` z-N^2~fV+U&88&)5@0OHfnz*r1tX<(8jtJ@j)HqM019M%-H3FuUa&6aCYHJ9q1Y5&o zwuY_0hPa>Us-19SnqTgrU1WRKXF}0*jhQLgPVKlM$L?_BBYD?x$}i1^Nz)d#vb<;) zW0tG@hG)|7EHzx;VH$7O>sU@bZ!)HF61NV%@>#|tA7U*ruLhvwkk6+r4FjrCWkc|l z5jeLvAHC`{%Tun71^N^XMs>zuB!AUD7-N5(9*jLz4j)oR=}^-O-GJeF-mSk% zL#rr?-w)azdy34tTpo_U-b>KFPDOLbFwJr7T@oXOo)FPi)ed6~D=;{*l!wN856})0 z4-Ecqd$(QvUD(gn#`gJ=M6H{LP}3`FVfc`c)Dw=!SF;73u2x^|0q}Gv>oM z@}aZb;uX4zADd^_V3B?g)_i;O*eSmRVOe-uh~9!9qZZwhO~_`kqH#r@q-vc!%ZJN; z2`>BeqCNN!R+ozPBOw`U=@A~JA=SCgVA)og;4T{fn zxAI$^TCJuGOD6x=qY*Zl(*O#1t;b(E%D8;CQp17>B=GSPEYce8h z7r<*0Y$@GIwOpi&8ax8PH}2tIm@c=2?YuCTmS$Ah+wVnQP2mYorKXDw1Y10$u_(Ik9^*1%ecY4H~ZeC*4 z;@RKJ?es22@Qls=7-M6}spiHut==FH@m=&z6VoOH$x6)7`ihTydp%?Q>|GgSErbsA z;bIVcC*Tr|cU?h8jri|*UlF@@KA6bdA`6M*wP@`Xq5H1aySdF{%Bn{7!mO6M76+C7KOa<+$SH-`c@y^A_IkNYIYPxBnjh+xRvW>~MU) zn3*2m2Q~%cJK@-G8sBSw{k_Nc$m##j$2ae`?>@d0?%U4)gYyaD#zz~#hE)A-5b}&8 z1&IfzqveTB9~i-opd&1U!WgA%QI#m8XFW<$V2s%Q_z;`vHg z7^q~CetR$Hm3b@>g0WXKHnNPhH!#)rF;&*Cb*rxicw5b&niNgEh ztG5xk1<7!ZQYg?Gu!iGD6^CPrK9P;d>p!Xd-~Ix>i|nrqWQ%KI-+N2#W6F(M+2fFb z6{!_gKtVW5vu5_TL@&#(#bVlsjjQqT`E?@`BOyNxSLJ6tHgk{7K#JUO2~Un|xazR1 z$3nlH#BYp8uW!(z! z7O4D1eEsM^I_izQOeW*{cLi*o+&}vmy!12Dozo&G#77K_L_dN)a83y@(;+|b8`o|2 zJF?yvs*xH_gW=-MeCpIK{VUF@+k?65h*+tEUT792&O|m6U)_oFfnHs9jhcXRk^5H@ zcjB!%zC%FWfQTm04J;hXpVlTVV93Eiz>tr^(N|OXy91Q@6KIsN3j$l>4(hgm2J(X$ zdMtz0Etvze;-Z~qPQ*|H%^*iNz?`M>5Aq*n#6H+nj{u?DJz7y61{NI^k)xQCMcDKd!tYO?^Hd)Xw=vKh6%%0r9pvh;E~2)$S> zz^`fpkptB&S_R0pS{AmLB(Ti0%2{LK*xn>iOOdG})TC_HmA${N&ky6WbW`i3(fA16 zv@Ca7sOf9o_}ta0P4rFvMfp8}FW$HBwZ>sB8Dcetb78UMiQrNKliU*x;TSPlgWCGh z(J{qkZDWkfBD=0oAY;`2-Kc5*GF5*pu3;Ld3|)f`Iv?dj@S@5If*Z}Ft8X_Sf*%5b z1%cJXguR=35+CJ3BNQwMyeEiP@Hw^WiBhnG93PSh%+wML2yZH>G`bHD5aqORR(b^TT-#fd4{y!16xH!mRg1{d!_6o$F1y9c(@UT$*jI@ z-t`nx2Mg&CdaLfzTS2qHCn(G?4UJw#vRNX!Qr!&eTB;7(tQ8!a<~LVv%{e789`i-^hps|;?sBd?J>`wR!}rmzn6Y$H%ZlpCh=1uGQ#m61z+6B?O};P-ttMC3GNbVrWaX} zVQhPK#DO6;(M3gt>HQgW3-vftG+wCNEBOjq`mO&E1KliBT z$;2+&;@8l$$dt8h`0m;Uu{@Q3YXj8VFA`eB(fQ0SvmwDma?DOaBcc8~!h&MoA6q)9JUTf%DLVFeH)Ov&&mXdkn!UYPbBSL7O{n>wKr9Lg zCWsRjE#M|A@v*W-SZ1~K+o47~?Cq<(Wt7_efD(}Lx%6S<)_60C&13%XQE78!@Xw2p#zKE z(D<+aO#1to$YgZ`sZ1QVy^Xlrtzm;!Fyfdkb8Ei)l1QpL} zB=%Q0%BIS^E&~>;={{<5Ybrx#erqT@DnphrZZI0zS7|HjdnYa|?CbwjEMFwk(4+e^ zVBVBC=d_1V>a{Da)C^Z@S;tbxsgxgWBTt`QMoWseu`(flN=rz`2Dc#FQo-@K0}ReT zEg0|3KVZ8UOPOE^dhhbY&A^$u5nxr&jZDx3vT9etUq+ey(H4uGroM4{H1A2 zI`9*j{P}SWGYL$-cQ}4#b!<#6`j6ejSHOjQHAaCxw&-BYr=dLLGa|Z#+vFPFiSv3q zHr2R!HpcoxRU3we`cNc3-BlQB-V@3gj-S!JGB!zmcbEUbD?B;}D97Z5hk2oEWqKq< z$>ER9TAnzC-+tsCaJbAUg{`c*!{rj@6OHv=>KWtGLQQM!11QC2!o@KHsr-xRG=AdZ z)1U|Nx%v~$U~dgvN$A{E0n zhkoJlBRuTWx`MKXtM<)m4PEy#4@NayHAKIk)=QQ$6zwDLxs6U#D5x0rM%^A2*-&Zi z$`TP+OCO~2>#u~@&)#62aZ6F3dcU#nE-K0!wX*!6tUydCfTCANhQWx2nondx6My;+ zP!A8FKEj8(k3s!d=z2NXry(u+Hb|eoqDx3Oe5@XR6QrjBsceLA$>vg}hYHVVR_cGoAKqr6EL0_=?=OtJtD z%jA&j2TLPeK=)%2{OR--@92l#%W$`> zzoa5|ZG$G$6ibVQ6!CEOMk$u`7{!u2E}^%jPQ(abYL1Zz9z&MzC5j7a^DZ5v2p#&h zWcGH-46EH#q=cDM1crzke@M+H@BH)rA89h~kfz8wI0l!HZ_^YxnA*HK^D@Uw;}yim zge_{%x48Q$+NFDR$hWxPW#n7@Dc^sWe2XVtX!#aT2*(1{N6gQoQ z&fv4kaM$3k9K&ao<>_yBC!_Ev;nY#8*L$glc z*(_5V(heA^$fg1!-36BrP*9*oSUt->P3I>B+~VCc#kqsxa7+?ES}L@bimj!gYJi`! zMirnUhhC1#OWvf|N(HJ8E2y@0ZQ`7$xXUEo3YQPajQG0=7<7Qb4Y$~?RI$XkzzFD=;X1X0s%+E9`I z=Tl-nr&Z3PCOLMw@hA*aLsh7$j;EZS%6$TA6ED~4sV4IR4B>%MszHzS{c45Y<$SFR zww_S)t2^nrDbLVWeB>p|#P~B#qUng7Y|vtQNN>l+6>6$>P2_w-6JNL{{*!LvhE7ei z(1b`dXrWUi{GtO;Y&Gi|3pHiAcFwT6y6(z&*Um}lcFH=nQ>d=^Y8mMR=@PP(?N!#L zP}6%L4Fk5vH?*>|Yo$-R71B7i4;W)qm~R&yOac(Xj@ zn*LAl3?H(MPeV<&8gPuOHwhO4%^Q*<$l~05F4t<#gVJyyJr9co)N&plD5WPfM?p3R z``I7oO$_{i-l*wK@QZ1%m`0&cN)zNrWC{n&lZ{l#Dg->}48BG-awln)8t7iX&o-wL zuSjNdXiIWaO3G7UbKQ9WT>;Q_ryEq>gSLV}xeS0|h`tfvaCCqV@Wog7=_bdGSLrjK!cGiMC2y<=L><$y2eTSY+y|C@^bpa;H--z2yTc*pmu zoa;#*4LUcv-<@I0r>RJfsPj4trK=O9CH8=NUUd~-SM-6kFt_MGcD2QILV`Rt`VXhI3aLiGp%IGIb z_PWpt;U=PduZsbSOM|-z#mXjfzgj;g`0r2gA9yY6!NkTDwc#M&Yuz|eJGIRuWb?lQ zNe72Gvb{2yVTju-rx!~e(Y}jog+l8fenXkya;N0ZO`J+Cf>gDo)2?p%Je9KfT?Ihe zR$A@Keq-0W{G;NSjS|wKVpOlY$hWa8X-X{rJZ^1Gilr$2iTo-dx`x9>$3>&%qg&wA5`#Kc?aH}&TrHPzTmrpDD*uoUm8Bc&A7%tZ2UGbu?ImEjax0^sRYpHb zEVoe!wkJ_dV{OGdW%MbWdN$nn_1AuzA-Kv^{(~2E1mA%rW~C|()vr2~381oF`LYbq zE=U(sR6^o1y3m)&Beag5;OO?$e@+Trv`T!X`eGwh$?-m*oFXV|tVU}Z&Qd4Me_-4F z=qzkV(T{@x-!0vY+x6Y^&Zp8pJYVzgGas*P*qpMX&o)PhrMMH|_7I8wJeNr5Y}A(* z;I&v*2+g^&-uV^J148p2)XFXXiN&+PF`?6m30CE_o*=uNY(^C%hJ1<Pz%ok01G10x)x+LR^3-#jv+>2D^i<9)?Q(l;I z6kUY(^Z_|p8Jf~X2j*yfvK`5_)%iGu<3U&-cTkYgBP86&AKq&x1!p~A>eGfJcJ)sR z4w|8pf(cO<=@}q2;^th)9Ai-IpbU@2TM6$(NfPh!$BH}aljrr8#@v7Cknl1WJm5!D z=&7w6e_fd!l$Efr|02M)%Mgp*8b}UT)m?p)nCvP`f3ruj4`nM-|HR$>Yqf~i>>%cUhgvzs|}y`-*qj2b#~JZM0*rPqU#g`mYOq!>Waq48hC<{;wCO-4YNww!jEMR z4SiDik4|DJwKx71s;mH1FjFNm7=B&i$mCGOjS}QQ7bf6zv?>tFu;8&kjJD8fgb-@R zD9s5}X^>T50|Q2=m5gk)26LgPf{I$V634=DR>XcMWI{pudM;OA5Z>bLy~r1YwQ&HN zRGU-6DeT{;OD8HS4~tg7CrIqSP!)7ULWPJ>k>22rC1MVlxnk;McOcn?k#D=I2V z6ih);Q%ErGp-D8uI998+R;ki{{Is-n*D5GV0?1Yu#9gc42JdkIQIt(_e$Usv@0mp;owfr$wC=?6ZMQh=a$`)lsqYKRog_KiQqB{KXGc+2Li<g%NY`_8={Im;vx@O<^|^O_wmlv@b{}PXwk_LrkL5q> z!l|lCqv37USI*w_xU^U%Y$rBENsW)wO-_0MjKOcN7VBSRj^nhZr@#Gwy~vQK{m19i z)L4?^z_4v=BDnLs+iMYPM;-H(|lH)N}gp=obR65-jviZq!;DwE-ET-vNmz zCUT7_PUfX|1IV8;fxhi-Ui3Meg9eko+B=n&l9zs*TA=@?Cvr-Xzw)V#I+*s5Io_p~ zCzzJtbGn)8-53U1tIz2mjLoL87qopmbf4)atFN8i|M-O3ofURnEf7DSCuqaB@sNOv z`3EF&z$G~SWIQ(QwUVoe{kA%8COm~wf^e?U4infK`GI8*GBa7|oB7bK`o%ZA^s*U- z@3w~@V2EZ*UF@D!uF$~P^R(;`D8_&U>yNI0N2!&@SxCi|J`0k3{xic)PE4F3)cF&4 z=%WO6FhyD@vKQoTKz7;AfPkWxX8jI9nK%YVwTsrBt#6z3asUYwR&0%DPnZPYko?xr zjuSq2WiVX1hHc!tUROuEUQb8ww6g~JjRWNuqTx+5J|4=ku8eaI7_&e%Q(3YE7^OmC z&Z!JlUluEjmTO<)z_BFj9F#vIZCbm3mY;UzrBXMl`52&V~}e;_rmc7{6>4x z4<$)t!5GEmzW9NJ>*B;lUWZ>JgY%}QoYhO@Eq}9o@3VRw^izxbIQ$&F6TbTbcD6|d+S-6*)b?nlK zCK1=;f|!)jiRWW^t`VQwn7T;q>pa0jXM5)fj#Ix;sO|Hh14FXX?oY~Bo?`E+--JYu z(USoQWa9*~<7qaT!mLP54@rQ`+eIaV=CsYoS8qe|Tx2uyre-e}ywEA7WG^4nCVTmq zHrdNjCL5o}F%ss-kiC3NG2DRFOeyi)k8V@<{#?hC!sbBz_i;QcozMoDra7CX5!`<$ zQ9bphQJmjlx`rs-xwAh8VL=g4iai$YbdcD6%0iB=GVA|ONzapEK7|>us|#RP08O%N zdH5MENq{U!-Zss=J=0c+uekCWH@vK}S8SP3xLKPpCXPcB)dQ6Pb|6%+!yQh+@_Bb2!*Fmk!cb)- zrKL}OE}@C;ttDXBm2@bX&%1(~M5@hw^=Ha|+n;T}fH9}^=cG3M`S84y{;c8V$NKZ; z8G?@&7VG~Yem9_SD=@@((D~mdbzrJ(esO8(6ZyrJ6boTg{ul^^96v}HcjN9@dSU{r zpNiV_!}C+rrjUzwCP_=;d(vi=a;VI(JIu~Sr*K5toO{{t6o`X|U%cj$!4;bkUexp|0ms48# zfSaGz%CwYLa8W4nKe#M9IJMq8QtPeP4c*OghSFz$;{__o7#NLA0NG2&%Wt8?fA_NJ z$ka+sPpxD`qLPxQ)4h7K+tqWuSI<4mqB6B4LD@OAp6&nqse^2QmJ*;egM46F?CfNv zk5W%^e*XBAEB#sfN`H^na>_J4b~cUjz-Q(SE#U(^C~NpkVaYOo!yGCEW9C9Gl4s9b zX(jqE^t|%Sw>26@3w$qZt@9rS?y>n!#B3gssT0ZD%@!&dNgx>Ud^sY6S58RD+&+IK z`sWqN%3=FBn-B|-t<4>b%#$F=Zw$njO z1ItcSzjgI;JT(xDc_`*zV2?qzGdsg5kKtDv1!QeMX8f7Mo`Tnq(y`*KxOB zsmJSxUAVxwE9two zN#bpZ9+}g(sbP$i75Lw+pHDmg<@)*QC2iNM`iE23&*RTZS+8=rNv>BWKhx|@b#&fy z0ZeQlcDVgbr~Yr|r;ZFkN%~*sr%u`Lh&_Wc@Kw%#j!BWKessUnMyg8L@4zC3I-jnU z)Od_G1A*{0Jlf$F{9U`975MHWU?&U;GtV^sqwX6QB*dvdLuhTwoJkoG+G(||gqDyG zQ~U{wliLxSPkG+x6#O3|4svFd`^&!c&b@@M@&){*oA7J9Hq#xl zUuHrN*>Emh_x!iNbWeNG)9v>*CV8SyBMNdF5J%>RX;m&@1=9C(Rs#t(P=8Yn3X(&q z0quB>1RWg7<0xieO9d~YN=S1bS!$2706q9c<%$g7sku%)8)2+o6n7$4M}=hv5xOo< zQ&_@oaPSLrp{7W7%RDPd7r50ID>bse@fKthjPgTRo2tufL&vJ2(l!m@(>3n=H{+ON zd*xSOqYN;DQ^ush7W{@~8q;ZqJn-KN(J3S#&- z%Kgaj=TGDa{ekMhUGqinm_xpFSEgfZ>MQpZ1&&c~WB18G(zW3jp4MC4u<0O zc|{`W>j}ZoRZJ<3xUXTZ)Fd85g~rezp^gnP&N`wJ$56=+?vS%%W{gK`Qfx*s^z(C0 zr#p<;w2J;Dp>x#YUMn?a9ldjhZQjnosGAC~r^UJFoGloOX)J+h@^^}4F5fK=X)rA` z4IIq8b(r>UCB%#}GW%HowIm-bJmo%vg%xiluyD(T77L$b>LhQZ9C(b4rF%T8@VvgK z#isoW-5~G%DStN7bP%}&>!wwUi(wGO2lN=w(UiRC>FuU4e zHXLL`_DmmU>F9Fm_nhB_VCtPpS|4 za;PnJ)H8{`$Y;piFhM7fa1J`k^l^CI*{1N9cPC06sZz}<<+r^MINjZyWIFeK7tel* zLi*0}<`et(JUwcI)s-@Ew?(e&z3)=+V5%OmGEDd-!%FtX2*mVetf{pl?oiAd%N-uY z;{#<`&7V!z@_8P+pPG`{+7kMQe5+5Z3&FfC^g8iqNEz+?oQfAu5)(*IHLrq zPAEYZkI|Tywpxz_vqIde_g+~PS8=OJwZ?5B;g-3fD=&fHt2yG}PY zb00+FlyY9C6>Ci3fVaxkZ^~7D9D&csb0XI0<1YLs%UJ!g+&b$vg_V9CI3k688%Y(T zm8<8(7JbP4-j;W_`EAH+;1~6y$z|U@Yc~?V!y=2dL(z?T8W)|eHC^J_*NwJV!-?3A zUSG&-G1G%PcGewcUXw=R6)~HzLbm&xTEymr5ySv#e3}~=H0(;#(8{jjN2T$tF|V6r zPFl5^832KkDm&wjb5*)y@+6_>PpmQ}Xj=Ynb-HB0{23My0JJo7u(i|IBuFJChU zlyl7QZFxTP3uZ8&!saIL;3{^PcX=R1#{e(-F)sb zKA!g+H?Y*(Od4iRvOb(Qfg&X>o3l!r9?rXfYrekFe6`4UP#W(BMJf2p5ue0$l#NBw zEL6>=#rNHxE&CL_=7^&BLwd~^tr@ie&dX}`o1iV&RM6y1qpBu==Ong?UFjXn)uNue zMX|5jPZ$Pn>$)tLjUlE{H~USKAA&{-1CcR4)jv-4S7;YmCC5U4FE-5_XH2w!UfcB- zVxReq*D&p-#Tt>%RpStMTLJ8H1PFl6ur67T*?6IOHJE7?{ zhlv5hHS;JN1GbFHgXw+5`ql>J>nn&CbnV3{wjgaO+Q{R=JUFGX_TOfM{Snu(LctyJ z7#dJgtUr6ldaM#CMJKGy%ZNH5RXBU{9hdvv$U!N`dQQ%we-=grKhTN zl__-mz+>LTr(7N*B`@f2AhgM}D4_$v=d*H219Wp?Pae4MowU=~we4{c@Q;ShRRJ(?blOZL!2R6d0sdIwrKqhov6fA1cW+Ls>A%!-~*5 zW|l@1$t>%RYzYrtz(W(SRX2}wqi!{M-8z$Q-55;Fg{<&yc?aEUn5N-?v-9*l^~~ot zc7mRm8og#>57BPXQIbJykp&#wG3Cv7w0nnbmko|C44!T#43rm3U55TSgjfXgDnu#w zst|+Jav-^!02)Ix&p8c3>Cs9kyw-^3C2Bq}S@T`3H5atjJVB-BCrT^EI3E3JRBD4M z+fGgJKIP#`Qy=S0`;fgIEpBby04^M3AzSs_K{VsOalC>on!O`IfO(>&(=4H^ZE`Es z@qoVO_wKx-&2MXXJ`d-`BMAr#TK^zlTS+ATrfs_P(0U`+@$B`(L2GGgfnEhIr9~gM zC^Es^?BYhTt!+?`GJNdt?tlyR*vWTrA?2s&6zUZStwun2SK%2aC?;ctcv6L~rs`@c zFTq74LrfI2USL4QkqsKr7IR!Mv`c}}$01DQw))<$c}aaYY}oqGXapMA%%^rg*1KK zCgSpU%hnnuRb?%veFowwH{&OL`PWg2i8mzm{&9SXcK9c>`J3dIhDXff%YCAZ;3$+4 zASG=HlBo+)^i78RlUlvSN%YsmCOlUCZTd-H#@|Z7D2vwJt;ha{{f*k_8lIZIdVm-r z^eo}vFi$vu^QG4yT!8rT?5;x*4&*YpPv-ymsaAv;=ZPib+KMIPl41$lzJ)5w#^?8w zQ?!(A`4!m8!U2X_Ng0|-h5;47cW%%k>T&(^nN^c zC@*R@2aCR#NqfC$@5S@%+bC~Yt!5G6!(E7s68$r+))0L_wsS%8Zt5Q!8F-{D8;Fl% zvZOLaEyE#wg19*YUKh`D1RijJ^Oc4}=vlu0U@v@_hU}!cQy;ZT)Lbb&Pp~3tdJ9g} zhW&=VE}k>!l;WmAy`0Dljx&E#v&l(c+vCO)o6k6U3g=pb^_h71hMmF|Ix*STysM2IYnz` z8q+!<1ldVW2PDOF3f0RTy4Tf-t1Iyqx`uk*DOytVuExsvw@4rx@T!hAA?>>p&a+|i zhiJ-h;{2$OVA1FPhW=DPr=0!iOV|f|P2IbgdhzC=;*ZSOgP~8I0kLbd zP>G|!(MD^)S70*=9pzSU_#6n^SSCr-9?@h_yLyc}QsspDW8TIPK1S>Wr2NSJ@L^5G zL=>jbO&t#dMVkbWsnrMCzKm?@ew?B<6@6XYiRfslxopw4VTuoJ);vS+{jb|S~ z{U-QMY$7jXr7B_ZNxM~xPjOON02L-o0UpAW2?n{Ly0;T1(|Y<3iHM26q#_eBak7V2 z27jwjT|73}a!EFC32oI}9!b4)+r=r&FuA`n2B=~}CBOvTg)?L}Kt~sMZ$Co;cU~tu zhT|{AF+cmpC3Z#dnPY&AI1p-f9gcQ_*S_?cGK0g~=;oTEz+m&a`TRK}hd(CSshEjl z(%vxxE79Bf8xH0fl0dPzDX}u}#-Qc#V{FTj?B6Wypvkx1@S3cSsPr?(B}#wa-zr^w z3o*F}#ni#SBue`m6kVmn|Lir#mV|Exd3L+84d28|Ld!y+!thZCz7c;>-?`a$7}HqE z_GRp_Zs!RK%dbXbwhoz4Dn2Ua<6!7x_lo6|47W?k#{z=Be^5dV*o&b`4QL$-59hfB z*M)(|Xrmi|_7fmW(G5i9y#*Gf0w;ddCnqtJ;iHbDmJ-^HH*;8(LGdU@k3t!FW`DwJ zl}IideSms|YaON!G<}UwsoiX~b>gq#xsBA+L8`(D>IpbCWMV5$wOLQPazf|h^oC{~!@_NO1**}D z@EiIi@6TdMEXn0J-&w#Zjx_z}39j-((kn^xkZulHM;4hc-A9j;x4rVu`x`d1+NuZj zyEA5VE17*`TJ2TGA76dG*&@hpK61Vy^`KeNnHA0j!gUE8Xm~o&JU5*v;=_rN0+!v0 zQMf($NR+E^b3;!s$Nwo1y3d?NCL!|Ep3@^4r)UA1inC3d1&pL5FMk#TG4c6Xau zk?}=niT|11p`AN6`0GSQ=`H?WJ;Cp&NJg)+q9xBA%y<4#OUjDAcuwT(AHAe#r~lS_ z7?!DWz>?6`9iRB?Zqi&8eduqf;UcuWq<%>rjmPeZj9Xl{``{UKGad{r8FrBW)^m9s zyPd>^o#1jaSk{(1p+TKEqasFKvoU%b6^E8M{>R>NTE55)Eg$gq>s!*_ZrPGqQvXuk z@bgCScI!1CMeh(;+4SVA*$9d~;&BY~*Dp3YBTUUwrdnYjkp8MQxD{*v=@^#8#RSFz z?x3mD>>yTbcSro$PA6g}D~pk$bmcfu8B-!J88|e@J&inolSp~d@|lM!f3pIgq^}GP z&Gk3lOSK#sDh*Hdu^trd@Had{lSITPa^(sW`>SO3o;nK6==TDhP2)~F(ivI0VB_)v z1A;+*Xe0$N;$5fcCI7ASY{@!)X0kG5GH|aJ)3+=AG8Pt~3;FiFWa- zoY}8#RkIWBlh@S!;HJ`p(_^oxJB><26N-@h2b9#kvQ@8Xy?@hq-Us`4qD*I#-O7n%u${x* z#)%Bu&nepJ_{Z#Y>f`&(%rs6t>~wXwtHR&ZM{_2gm{v2`V5FN-XP81e@cJ9pYnFk& zrlG=2NOU{g%^;!^+NG}O8=w0|-dFM13$Y)h1tZKQzV>1&^;^~KQ zOCPzNAM)4-L@DcnWglR9o{6;kFdqjbBElZ*$o&mZ>p%blh-Ys(UOZl$W1e}|V44&t zYfYjdcIhX@>vk=^`3e;MC;d>jo5;qaz#acH)hF$#-_W&XLzntbPTTM6Xdw@&#}{8g z1Y52{D@zBwTh{o2@g{g~kv=K?8hNg8?T+m_phI_jJ9eaR9WKSlj1jz9{8q_fZ$@uG z+fe^;|7cW0WK&^?tbXS(|F3L58YLpZ*dxF=5zg#K|HV~kc_iZ>{H8@Rn(LPzUAVSV zjf7Ux7&C;>SdgBPH{$|ucW~OfX=yO9FXO}0d|$?AjIM-Tc@&#yEz}~j7*xG;*bI`0 zr?gm#NLZk_rB;*G@^J=U(hm!89ZlPB1_F7wqEJAPPZ5%?;T2muEn6vDJ15k#V5k|` z(;jnCH^^$-V0;H@E*Q$|#wbFi-8ie;#s4harX>9(x>$g8Ui6_v)_i~CO^UsNdde~= z8QJT9Fhc=e39RB#C;zVoo4)^$?XQ1R?Y3;lK4}`~M1%_tL z99$MICYJD$k;q>MZXJpF?7%?%?yTzG<&m*l#||BT;QI2=>KPvg(syYw-xUb;Dl>i| zXCXN@BcrZV#O}wUFVMsKPy8*PbgBRNwEbRJJfmN&m-=ai@j%;R8Zy4Bj!n)iL$66Cl0sz^Gq-txI`U+B{KYqZEXGe zkw7ALgpsdBkZe()bS@mx4|ml>{QSpf+H=IZ#!L|EBM}&41g1&o7)nJzv6J)wV)j_J z;Vf1ZcH-H09xJ*{5H!3qLD03lFzSbPXi=dL*r<;?8#{3Qa=6G3ov)dUHnct$VRLf# z$DQ<+_{WvAPrGJjEO+*4Q>&}1s-4-VRZg3JSuAUTZcpm!f9A}L`mbj0rv%wc{m*tC ze9cUe>zSQ+Sh-(Ib&j4@RwtfS@htWx&f;%84wv?PtMp_28S6KVLuq0B8Fy+o&+Z2N zula?v78iim=o_Y!T@7A@)}pHnO68$znCD3#$rw1?q!ek1CuFf3gSb?(Vhr+<ZzSBq7zTBiBW^inaOGS#0r98qA3uz;ar@Y@GFfB#;U{K#>qV z$|w?64@))a)c+7is(De=WYs+c5G-`bwE1_v}$bXwUgiw9NGr| z0BLFmD1(Cj>n5Ma``BgFD@eKw;v3yAt9@y))q-Ce`P7I?p=}7J4r1)b%YBGqSX@BN zDql%!8ZN+yvU9tewgRsuuG4F7E?F$Yf%y~9uE+;Jj7TZ&xbT{*a?57SxOxV$$}^pX z=UjEgRaf%}5AgEPusp3UTxgL{weAfM;$IWqJ3Hg|$5@}@@;0VbX`~0YJn{w$;zsx352-&< z!Iux<76GN9qcf^!lPSkjJ)b9jnSB}EiUu{mP>s^{k{v2l$&mmh^KXY5j|Vx@1gdN&yQ-6on{^-y=d0I`_Vz0NCPnqM zdnJ202J&ZW2fnl zWA>BY^!@S=oRB_4j|2RP{)+zT<}#IOyH33ZWwpYig*&@I17q1o~5 z2YDkEgxSlEb9c_|7zb-r0W|5n&%so1WgOZ7_nqQYa!&H2DnrDBFWaSHL7;>Qa3of; z|C}#D@JaSqra2k}y^k&sc|+O3ya`edh=fPOpUjpOB7)5>^CD-WbXfBk8i3Hogv!C4 zPnDVypAKedc35Z$rf=%BJL%LqlWK<;a5p#94`4c@g}&G7AZqTgyKLKJ{HUArfT+|m zDkGqxr;z90x_I^!UTM!;T5k8eZTJa74BveNC;|pExUG{1VAsaA{)Rtshs#;mxSLLg zbrIVl2RHmVdZ3_$jen689Lb!m2jQG>=Xf)An$B7@(RLn9^QasOSH-iZn(oslZqQ%$X`;K3s@L6xG!CwbwTel;K*JsT%=jp1G@ZRc z0o0UUG{y{n!#`k|3!9?Gp^ebKqnh5fiFHcQ4cu zZoq*nfxR9I7ddKNAq>nlWaMvJCfFF2jlXdL*M_ZJegtggZ+c^(Hfogd@E}HEqfQ2? z!4#X5av;v5>|O`T!&cZZ$BoTz21E@zml=%>la(=8h(xEs~+mc_SyR|-{z@H z!FW5&@(>y9*?KU{y|MU#!-3rFWy05#RYiW`l5PBrXMk0K@YOkXdOI__oU8^q(438s z$(($u?u9d#QdP>FJgu7ToNRD!?)hVLVk0A^*zU{HNb76VUSDdp$BgrJF4kKnc3gC* zo*UpVFG&Jlc_e-!@b@~&pYKhQDACK0iQAN+Bw9CEa|3IS9;Sz+0xDX`9(`r(Z>(bn;00@l*%(#a zr*2(OhcT~2Gt7=4$wG#&3U~$GUsEPpqRk8IYaI}DBh9|FXjfIPd3z2*NpnNJ6^c)l zBuf24r7mW6m3qfYHA%lpC2E)Al!f2zml#Fu)!qndD(QXf!o+u8psk|BgdkG#-Q#>0 zBfNp+Awvu-vLD3|R0uX|p2l($6?8OjzvOc%<8lHW$Z6wwX%<=cM5D28)Bjbbm-N4x z{>T2Ym;AXBaA@5O^+9QIfDzZVWcvQNv31GhR3i+`kbIKGq+kY1W{D+u=vnop(6dno zzRoiNA93-c!nMXM=02N~EZ5 z9Eo`27U%G3JbUtC06={GR7fTm$_<8Uagv#ug_D+8Dmv)Vv}TxAE(^z$3Tf(FGuA5Hud4Yc0MT4}}Hy;jU!)=&VkBO1)_&<-HKKA{ZV~Jm)I% ziXy?f+e&}%j1t$0Jy^NG7$sy)f0_?vU4O{@Hsr}ul_(}`M#Q)_fTNs>NFyeN>muf44eF7ijB zP!5G+M@fO-SAP!Sj|@!Kny~Z`QJz*_JWTxCOMW3n zJ17~PTzP0<+On6P`qQ0Gi}(9xmOR%YSbRT}za!0KtMLrw8` zOEfF}b^o)g{EJ_2iTYc1XQr?AFJ6r~GB+^oolhYEVnvX-PTfXSuvMV$F^($5l zD;e-|DO%aQ@Kw3mDumC-;e&y=!v#aA@sLt{f{JuxS<>!Q!9EI`>vwUsrN^V^z3(ag z{AI5zY5?W}s2y{G&byT64HQNfd-2<+XIhL7jnxJtkd@qE-1Lk^@Cx^#HEc1EaR>f2 z%HD?fR-SZF2I5%h00~DTmT=jo0)Z|M72@B;lfqTRx}fd@Q@XW={7~u&-O93gtAcrl zdfn>A5T3X~-5LwonSIZb{$#f%ylcBv>-L~q!J)(Q2t7>aem&po9EO0KrR#2@=|Cv> zlIdhE2weISs%Byi12MXntM2_SrF*sKwnD9=?m?jjYUfVqa>0W+H_ts8p)4ex(B)eByZM)a3?j6^rdyo9N9sDHkCA+5&QoCm~-E?be)!Sx) zEiPGr5*32k?N;xH28W3l2eUQUQ4Dr;(G*?x`;OVfoC9Gbd&z`00$j8YOE^wBHIc<~ z`io~@slsgP%O%w>D9D|8+2pIQnu4wgO_Fb>Ih{~r5aM6|s{yg)_PhnV1SOZ!r*_0- zHtcpgtrpzZ)_6=1-W$6Tjwg*>Gj9|nIlRcY{>RSoo@?6Ds(-HMk8>3p?mZXRO{-=F zwW+2I57kz>HjP7dJgnn&(nMd8M$#Epx2f^$tNSLbp1^DDy&c2r0t$((o_boV^|OtB zseV(f$4n!5VQ39`?YwRAlDg9nai64RNmB(5@8Av}xihy&e*%Ni{w2pK|K-PnmrjUG zidc=ijfJK9Jv@!@voYRE zWJ&AIuy7wCcz>)h5gQmyO0-6cum<9;x=jGN(AT;_<*A0S{wZG?&YrlJm)MdInv#3> zxxe}x$y|5jn@D^{M94Z2fOyVT(c{$=pa3|s9qBBiIj{#;%KU!ZwuB06=o=y<>__g# z)i7^9&~7ftue%tr%+q8oNi5m;20z0!`6l}yOZ=Tn;R@4kbzZf-&BETbX8(BhwUkJ) zefO|SKE}Q3zOf_uiIH!3|Hf6d2RiXpBqb*FUuYeA=XiE8AL>*%AubLZo{AhSx(WSl zu|*9p*F8#k&a*PGkKE@EWm*_-K`?YG@6r;S9dpK*SB)FEVepYGv>ti=ktBaINRzws;NX+K7N=Ti27e*+(i&5ze86r6z5v4 za$SuiZ31?(D;%t+MyVmcE5|6A#|s)$pbb!Q z!rN0Pfjyf5o@X{NQ6i~IKF2|Q#QnHL(I09qp{3PaVt1`U3Z04PKx}n5bFq2rZ~PzI zm-*b%mqe&)CvrVyx4VUJqa^+vJD=JSc1Y~2wky5cg6q~Jk!+6+18=frE&H7 zxo{W^%^Vq$WNS{_?x;`&*;VJ`NE7L?>mlpFl3QZTH|~JLQE>xtZ^f#E-v(jJPl{h+1N|4#F8nX?tz z-_RD`S(mGChfJ|VRptI^IYb4yR0-YR`c~uuYi{+Rx_|~r*qcV$6a26^|EK%e%LJ1Y z-b>1R#xS6rP;m#}x*z;|YGO_H)IKUtVBrKDp^Nea$oXpN%NX zZGyPyY+!4i24Q2?+JJ4#+a!n|0*>wOduOs_MS7fik*EM)d5xDzWWL54^FoCvG)Ki@ zdx*{^iejJxU4z?$0cl+fKxEP&a7G>v%mz(z66*=7Z~3d*$vHvT z35=4`dmeb&SC%I1^DJCMt!E{|}u5PWCPsK$v zkj--6L|>Px3Qa)SGNe{0W7e=x&J~oI1EwPGo-5cHC5!Un_Oqw;m>w7}3e9!*+E9p1Y-mw5q zTbOae)d~xiOF)R|7Q+rHB#!VkATjJx_R?H3XYgeoeF>HVW2;P}NjE@`OG3*DEYfg` z+NEartfs#w-9zNl>G+9stK%V!G;d^UFcaxzvdGAj5+4qEB(KXF2)|y9Q%6IYXxus* zoGM|&GrCFpD-_HAwhN=r)f*IqwPFSELmTB@lUYaq+yOErfHMj3@6dEcJof}~FtA#g zFk9}G$t7u6aExKWFppo;N=KUiYj}>@K`4{1-FlUpsr5HTfosxY$I&#&pgQg+T~g{9 zt(0SZS?xuBd`^l zwh#^cO{KP{MvXs2*P(UMWBE<$4op|G4InzBt{T+C-)%dP1Z} zmp(dz3P_55xJ!BIqsx58vH?HF!>J4rEAxJ1jw#D8Sy86*p@6czx#B#|k_N;Q(MTas>%`uV&mZrChClBU0{x5oaw^oY0}seRSizOfn#f74xx z5MnUL-*_w6#A~EP^aefFVr4Pa+ex>@C7obS;?mxIxYcXPh*hZGrwOAyuH*o|xa zozz_1@RsaNXGy9Z-kiatz@jTu;Kj25v->rEda?ezyFu?F*?*&C>;r4((0EWEYt3cCPt3h#k)! zqnApPZR!@Swnu@ZD6vlz@bS{{OfNS#%b+>3(J@-QpRUqL3`}8X&AgF>H1Al>FSd)v z<`C0%`>lTm2*@ISQDit%?Y5fm;Sf7e4j_x5)$$oxWFr;Ev#0S_=ct^a!{6qMYLt|N zU*UpEmtM>!@e_ZNxlN{4jHrZ0u)Gb%gTOILylwGFZ9zumuNY-m z8_LJ%4bWW*ZH4i_Li~#z!k>aCgx2QQlJM+gH@pc zidR=@1DY?{5S`5W-~d;?vMte0_3P13Vh5~$k3G(=3}x9(bNr*CI#bD^%$5zA&H~t` z{&kfD`R|&Yg*)y2%}QwVyB1$d^|i+SiTJbKUHvSIBc1fCaF>J zk=ipnebHs~6|ib%rmCu1WE84Hd%YnLLU$ndz0t-(YJ338Lq97Ik&wY`=U&KFZILN* z3q{xcgZm`hN8-8@uRc3CbYNbM7t`%HcY1z^W&yQH}U?)4=E1Tp}4vMJ{j`}bG z$DQNoM20yg3KVc*dMP({pM$IveHCaM*cEP$j;8aHIe`{s(8JE7X!Yq3g6s?a&~0=Tnjoep-pnWt zFf@F}2GA{7|FznVJr?rC7KHYXz38#*7mQEI3gVx9*IN@9dzc5P>L1S+wVLn6Lp}e) zzv-#^H5tzGzq$#N8O}tL&vHMUWnC@ha8z@QJZ5rYM_PM_zj3NThjlqUwU35hnZ*Y zrb}e6>|D4Ru3c>x_v*>9%QbSKGTL*0%knq;Q>5BN7o)sH%Duz>|~ zfxG)rqt~MTKEcp7Z(*>`rCs@!Xx_%eVNSw|VdenK{i_E`!l~cst6655=)y~DrcJM& zcGXO$$X7koSvcjA>dUI9U3nR|OpxKT3nyPaefnjStEV|9`JCs>)zy?gX`mGX+T`;=j9yw? z=ZQvG=*OoBTO2jOx5cv|D(4vB3@t;R+9Bw#rziAyl;mY@XTs*M&qaXufS@KMbR>*n zLo|xNE$iyPzZeSo6Egf>&c1K&mB_F9#O?SNwCR(`r5$1;PaNRT5$)%d)N zf)r}w!jFza&H%chOWn*!y={C~orh0S%tx=gAj=W4SeSbWWyBSSUV){=5MvtGZu)2yF4p`C%y8m_bax0)=_p|66R zIEEBi7iSz4h_9@iT{LNu6A7eOKO6g^rfcQw5tAlWKP=5;t`mAI5c*a}ftft^G|*?U zv4{pk6&N4#@<H}ZLsKDlPfN_Zdl(*_)C!XuxJgv3@wR8 z7f)hZxpIFd2x%pqQXa|c%gNqA`rCn`Ei-+i>TVdEHmSOo^34`~K674dl(CP;){>$( zcpQd(t#3l-8>e~a(St(=5p!}l(-urectBz_WeT^u7f{43+fFFv9CxVwR%>GkFU*SX zAf2(>BP>m4POpLoS){r*r&u>^V;hl9C{&*h5#hCe(Q9RMChnJBQup1Y z>h6`#{}8WyV`=5#>uNsN6Ea4$(8}SamA`>Ff%+v`v{e14=v?mTLu`E^M&zqAOVlC_ zj^NMu5pCNm^}n;ajF>uk!APGG7@`-g;uwFo^hy4PO^l_oM2(ivYT4oM)vTvZstArC zuQV0)YSVElT3cBLT6foI8>ERVc|s|vgCodAP4UD3UGZmAiYv|Y_z{I27awF`sr4fm z={_P*-%_AXucp)csnZX(>-77k)4|Aj#m?*%v-MTc3V;11CM_6x$5bVs{pd&hp|{a~ zP?}e7R-1YYd65bXTW|ER*7CV+$}7i72jvgtv4zUWFB#?7txQk$pTfrGzk~s=1_xGF z0?OBcWQqToU1rzhFMX|gAf2r_#;ITOrD?~^5p?cv_z+EKCFrnNRb0DNfesAj`=-`CyzU z>x4%rWu5y>XbWzhxi!ZSnqj-fiRqC%o^C z^b4}^$`Xhqp8PC&CPsmF`;#{NUukIV`6VRkkvMisP199dOLls8MMX|5lE=64?YThR ziewh(fi?}mMzWTqkcTc$IrfDIo^{SLMl>W50?naM?%>$h>}BdhDuWg$6F0gmeLwlE z6J+KzF&MZ^LIp%kseaquF&`^^K5AB>&NY7q81d}CY+*INpS^o`#`h=uv)d2t0iM~R z-2d&s5$n=W#QYHdtt8qaLJ=_g_;rUUuz2ZM>DfsLmgIkf<8uuzj_eU!G5dO9Wxw+B^t{;N?vFtWXl^>xa^IAA z*-@V_;iWc)C4FFNZTN?VVfY6|rOZp|kN5}PWj3^z@UDr$fp_PsuLkd)vvgLj2MHF! zR$KL7QYjX~`4-vXP42?t0B6;OM<}!G0jZQ&%^Y7RSTkb1deM%9IN~6)ANe9)DTPyd zO}Q$ud`QB5m4y3267KUP-1lL+Q)7jDHJk11gFsQIL4Ri$%DG;`%UQ<k{v5ggYrm3@wtll;EuG>^zorfqkfZHCAg zmm#t?X}QMxhI_Zgii%RKz+lu^Trl{ytGy0Vxc%Qr+xj>P0HOhUOYzq6Zzr z0ID4=CY;-`AlCkM$N^iVwA0bs5qyhm!4@5@G1ELIUsnTlb*Qcm)m8VB&=_B=R>l;L zV$B2WjP-xygAVpSu3PX#v%z5J8h3h~#@=m(o4fSD4%T$UU42O#Vl9^hu+Nc-SQ8@^ z|L`|ynYKK{-)L;85=?q-0HMAz2nBx-JK=NrFAo&3dTQn_en>znBoo|QaUaM9& zS8s3_g1#m}&~rbhMRAd@Rehi6Cp7NSw&aDQj0^i-(CMeg1{J=wd^=kYQlay3#eYiM zXQ$Hkjaw4Kp3=dv9dFo@5jE_5e)lzOD>6t7O49FEZVdfC_!)yw8F3~fK3m@M;Dc5u z)qRJ>hoByt5tD~j$UjOCQb+vUB&o=MBJ&Q2c~3};Sh+TQZfNtr8}r+yKey#A_xfda zgl*TSB!Wp)whEZXb3d73n;se=-a4G3{o#^PU* z9#8KyPd$O^X}$QyzQ{>^alc;dvVvKE?}c#4{gqy3AI_^un>}ct@k(XLJF6!30beNrE zoAu*ep-0G`qgtE`zl>*(=R;$A{H5H@B3?SO73os|iGw?y5dd{cVud|IVG|QO@*T<1 zq&bnfgauPs>`GhQ9=}z3l11hbZhie}!>UJ-?bn+sKT^{81@a!}U!7A#ju9?u4w3Y) zEBDw84pzlq!r^UN%^#y5LdEVohskJXK%2-=>E(yLC@U5>kwaNsMby}TvwOXwm?kzJ z1NpGN(AwkRJa;Lbal&3JpAlJ7%FNK43w4w!QO09@MjT5f@lvw#YmTe4&7NlBs{$3iF|8qY4E?}nxyrWoiV7wjP344ng!(K`!Q zkzgS7suS+Me;|A#9xB~Wkup1ShR-S5THUGUQ(`~ji?PUSb3At0qOJbM->NEH9vUl6 z)0V>Bp4V(A4YY<(r}4b39td@`N)Q6fZ2aVVz*T{GW39$t96Mdsy$McuY_14Hgkl{Y zI{CB45-$vQhXH9Z;sRJHFBqP>(+NAd@}MXdaVdT60QQrn0VkYTMN{2fulyGvNN|*Q zGT~nC3;QMCZbHPf|eBEY?15lRh(rskiHvqL48AEDM7MqqOkAV7GKee6+3&;>7Ol_uv79^WD=JCx3AxC)=)om7RRF zany<9F{1$(mZ5cT;fFxlJ>&t3l{%4({fP=lM;q*%g^MxldF9;s>f__afugSI@Q7p^VI~VE(41dSpHGs2%Cuo`MD5(LdSJ9aGiT_mfmL z%@gKoDvTiaHg96*&`i?Zdf+Yi6pV5Uw_E?Gvw254J6V}JT4;Z(?>S0=TZM;#w^ifg zaf+UVJHms@_#goccg>y@Jb3Ct@Bl^cah(D9lSKKqiquttE)D zbNGko><=A)&VDJn`WETw-7-$vH(o^7c=A5ho27DJs-=VEo`gah7Hj8eQ3=$M!+O{; z7qEe1JfIAcWgascIZj{xf#Sh%zC*}e4ou{j$Am_{Lyr-#&cXO~dae`Z(COK%@N+#r zxK6RcuRl1dt?*|r^kUT=wUw@BuH>47iKEuDKU`MkH8H166aO%eY2wC?n~?9g;>$O? zhuHcXy!vTsn!Q}lR!zrF0*AjQi&n-Ez_3Pv!)5~(MHt54l7R=|{v3b;2{3G}4W{pQ z4qr`#`>f)I?f%d+hM8Ws)j9mN(xyD}q)i!;|4 z(~YG*opB8M*6??{Z#{n}`nCq*oG;?24K=4QP%s+Xt=5b3ll-TjRNa546WSWs@v(=- zg)PxS)<)TUUUJf1=kRwG>?o2^Oq^y8l`-g|yVEsjP7tTB6guV0w(B_I1r{tiwkNa$ z4Pfg0oogb2;P>=)Z*YS?XVD?SGGAye=HZxOfuDRPIuTxK4_Oi^i&vH&?v{jJ@;6>i zn`YUjF!j8{P!}m-K~{7y8-&xt;YTzIKq~aFqd1 zM>9J156Efm{on40M^6V9JaHdb!4cX)>>}OLYw+hdUsv5~@x}-(jZW6)lHnpkz2RPV zv!ZQ1CE9XkFBR!2GVqKc!Y0_-Z1W@>5-nngkDcOvGmHABtG?%`S@q50rf@Bh8;(+d zUB*EN?=TgHwwl9$Cd0^9e}f{Z8CsxmMnnv_P<2Zd!|KXNGLSMmMZ?0Gmd`T-^)JB$ zTS26t;VB?GA_>8Lfe4vGlSsu@d!va20nEuPGrI#9?xC}Ye3Dxy2ocWR7b3jg6GT8! z$@ePCx>#YR-y(;H5b^AhZ!{)X8wg5>} zq@CrCyTWJEZLj2GH8{ipo$I)f(4H@8ylQNy^!O~|ZWBeY~3 zdbv0eW350j)|hp}J|>8lZg|0-x2|vQ=@Yo$b{I!y0>YRy zGzIbO?AJt$hJtpuTgO?EdFPI-1p2hKCpOVbgEq>WX9G_-EuUmKk%2#ld~SB1=Wmo2GqMm7uZN;QedwTh^(pOg2}8Ugo;K%pI$&T2`th-W|j3TnEf2+}L9B!17ms3-$uNVMeO$oCwlIH^c ziQ6@c3IEsnO^%(g#WR3LJbRc*;rsdvIR-}tABo3q$s)aaPJi&TiD&O zf*8*gulh*xHiF|!A~K(Q;cUEmBRy^hRwkHM>~J{~q_aJ8>bGXn^{XD%DVH8s3Yf}^ zRQ4(kx;_D$6FN-tC_?eFaiNR#%ZA8hzm3OD!rxgc8qc{^DwaP$7hlWZR$%_($jie! zcqq11%rh=<-z7poFfx4pBb&j4>sX2gzfJ^tZy=x0@k;OogN_kVPgq&g#UFl59TAT+ zNXbRMx@L?%#g+aOn*H}TS33Ti2=%_oe{V~}%9?C2^e;#26q2w}ADA!c#*kzeOxp%o zP2{?r%^N8`k{#xZT)qx1GPj`m;72c%A1bo2TPm;;ui0Y-#82t=PeupIvvR{1E5#xa znFp}+@lbFi#08EXy*k6b1TD|oTlkk+&C=CW0|Gp?%`g#zf25g|1F^m;C&;ylXh;w> zsf%vQtK+G{y?+ha8Dx~4563vbZ#jmO=5KgOWwf>%3Qtu8O`$pQo2>Hi&%&9@k20s; z8h05?&3ueoC(M5QMwDMWs(Z$>Kc~1>HJzlzF9f}c<3v0)o{eio+lp)T%}vRuoAr(b zn$NxZE*L&=NpVAl^>^g#1OWbY6A(^-DtQo%r0Mr-0&N%kS)7%?i#_Y?+>R@Xy%5g) zD$fq8$qwp$ZvUOD+0R!Qmlr48W9!SBQ4-YEn&EegXK&ygL_bAXTr2cpw4B_^T>hd# z5n*uW%MzoV{TmJ%^bj3^06-pgyBuhVD3|x|lopu1EQKL#bU&$tU3=~_#@v-?!)M#L zG|>k844S-avWYPQl@H!FCV`bbX)*;ShS>c4n{E?J;tN^akGV%|9s zg@ihbw2NnQJ(&abgvs+Fi()oS@ zl!tGGfUfkFhfi=K=kzjC^%n9GtN{6TycuZuETcSq6GE=DgDg=S$-M+e`oahcxbw1N z#d}9Y&DnVb-}QXV2#U>AAtsP@RnCgb5qoHvZx8QyA{E=dO)&(0DohZ{;ub zn_$P^aVjzxo|*3sn&X{gy+>ov;g^~4LWC1{^$Xf3OhHbs|2|%Qqx9JYBI+R~k%hRP z5e$>8Ft;QBvCS_@Zrb7gp=djHm!su{mdt?xC2LT)Q>u-WeJ2Up0S%Pmd&FqYkpM2?0XhzsEbW0ZO)brxsVnl|nHLR@2 z9z&=t_JL--^MO!w2IF&n&Pou3VG?V;l48r@&c8(RSxwmzm9?J9voTd`x-h>Nap5BRHR#fb*CF zopg(j%87O6LRr7s0K8R}u}&Co8Q^rOdBrU5htN`tGX}uq41+a>e(h5#LTgDc&%l{Uf2b!&|hqC_-I8UZ$pn|*M{ z$*1u9+2qkRL>(mcrV~CTh>B)DWG=o|_6ovSxQo0_YJ8lfiONzvDZ1DtbzSPUc=5!DNE#X1PE1(H*;u>sNX@$gwKEGp0 zM|#iU1;_LxW$>>qfULb!`#aouf{}-<)|xFAS_8r@eC1v_|6BIJSCa1GGExhbu|)-7 ztd(WC298{n0}S>T{sGR(Ndy@_yG)umTjVVomb2VvdgzLtBtkCg=P zcIIiS{4{%$k%!TyuoCtQhG+SLMce!hBPpzNr{U50W@p6(yD9c@Tp)*O+s4GNp++9$ z>H$wDqRgmYN<6dvk|E58;}Br`Jta9^do+Y=gA5fsb?=g|3sk1XcL)OOfqf;;qHcFD znu)B4uroxux1ry%)$Hr>EVEM1T!>&GbxWZ=pE+ zAYL7C!sW#>9?a7df_;OIh;116%aF&x$E%#8yv8twB;0r*3Sj;&TC(Oo}Un%Gy;4(kT>dRQpckIyM%l>J}98KLSdp2R{<+Wks&g@yxiU`5*)2)aA`#8M~9{96HS>jJ> zGWI?H=L$lN3Sbq3UZzNqxY4~}plF}dux)f9P&)_^%u`H4jJQr1J=DIbAA@m+#6QCq zTcbJsvFg2c`ol~Q|DW;je_aX` zQpRuPN5wV?J*huK>uEhIJ{WZ(18jqc2E^2nP6!1Qy}*qHR}W1BJf%%GJ#jSP)qm! zqjy@}ck${HbP1rlDL=Y^O@9F0f|3m+0t_QG@RrcMqlc6(@9ki1}MGU$2*%kK3#rb@IdxxvsC1y99ej|D>y8INH3wMttngWA1jSefB`;0G##ig2#y8q0RCccIlfl#8>-|!x;4AD+T z^?A4TMsHlDiAD&1IB%W?)$obNpmrUgC$tQLC_+oTyPeQKRU4%n%rrvVzsHMD@-ejS z%}XmBB6?@wFj(#*k<11?&?+c{OT%ilq^t;qc6M*S?F;FFi|NDzhL52gR8MMCVABCW zv>cptkvvA|*;XfRIzErOEs%_3#nNUME$&8lf6AG-SQzH92?jCuy0^a17A)z4_z*1< zepk-W<)KY%RJ(;bYv!9wXWK&rqdFT98y6ltsH4zRh~}C9^X|T(@;kjVP#LXJMlx^L zg9Kt2A|5o4*j5b34&PGpgdc$dv!v$T{E7b_6blwxP^3{Vx>RmT9U{-QkINg*p85 z1u+L%FU>KU9OM$w-w+&-Ym8UIka+g5AMKsi@If`>5U+Q=)l&^(7L<^670eyZHkR^8o+l|O*nFV2^F3k*%jp`Dxg z+?ce9mHw*;ZGqd=9U{;0;Gs0{Jhv0H&cT;WBE8@4_4c@djSxRp+Bv2}Pl!hiF?i&IcJYI{AyZ~(~RAP`Trh9vBe|IYY`y2M} z!V%RThbm}$B(n!UF#g7B)71hk%eFRaGR0#2)Wgnbk?OFS$d#%m+@sjM%q-E5naEY@fn5&FL~cBm2!ddwok)M9glumz zrG@g4lgR`l6Udo5nWAe8=C0lln9inh@lelMriANgU&vKzfs;8lvXy;c_mlm-MsCGv z`0CP=(K2<@2JvJZBX8~mxvj@K{r{16F7Qzn*WXWoK#}C^IYdTt8~8zHY)@11KWmtnRrA;tdC{TJd|aX2m+?RKx!H(>+b)K;(&jREs*prM zJH{ivf|80B3Tna{gvk6fhjP%%Mhn8D{|X{eTUn0Fh;pH%lOHH)#9LOdbfVKKPW7)|M-PO zMh$lX^rD(j358^JF3&Pqojb$bKtAg>b|OAFIJ1`^%G2CznxB^^!(AM80AX68ct9>M zNjOS?W04bNqv2`sE9qh)f5yY~_CPbyO={c45+4g~5@x`zZx}*oG)A(WH#Y^O?Aq7u ziBl}$WpR5hl)6Y1sDZ|iTiSPTla4ePJtOvj!Z9-tkwD$V0YMB2ELhNtdNs#F00LIR zsrIq6p(q>qIudM(O%{#8v&1~*)Fs}j@gHdE&O%?3Z`j_Sbe8)2E(%TLJw6BcN_7c? z<5H2>ym|3okQVDQhA8bYh@t$5oek?GIKDp|(Xs!xZ<5WNz@w4WrTWI$%(c4iGGH_P z06d+){5_tTzr+tkH0sA^pZO0?h8BiUn^)5h3J?O_5*1iEZ}Xr2>XU>i(rLJY>sK%d z;(#8eg^fTW{}3RO`7RfqaQlROZU}kwY)F_(Vk{hEu)(6RrnC~nmcyF%uw#RFVNKY2 z+}<75ZGipFcXJbxU^ab7?}wnKj|tfRzi=_dk%P-gjAM7lc+azu&DIzE*8SV1Sy z6Y&~Jkz7MTLA$a$9IFyb@|JHpz`IeC!+eX{V0RST2NQrp%miSc%KeGH|K;!Y#aQnK z{+}WSYJ0F}}Q?krqb;76ds1 zq(Qg`&n*0l+@fZ@5Cb}fDP;4s!GLaF0c%3*ND(UBA_xoDd-ZoYrFbjyoj3d=rk6$N zj{4z7f3SB)hS=O*jc(pZEkZ|4g7K_Eykkzo&WZmIwDDhj)fxeqSeaB}bKy;z)7(Ns z7+h=x!)c#FMC9bmi1_rkKN1lYS0|CMX)h%Bt&p(G-lgcM-qnnWO-W3AKN_~Dqakz- zXn2+xAsc9?S<*bprA)4dinKhQ-BdRs@#@T=+Z}m(wH?W|)7}nrGX9MXZ!QMx>MPuO5!suv>8ozHBM(Bt~p`qGEKOWfFn zlc+Fa#=nnQl|?m<(*%55L@IPeI8tY|nyb?gp;Dfg8{!rFqfo%CEhmz_10i%fo_sm| zcE(3C>BJgTo2h*tG&a_nd%5c(yt-n^F{n!={Bnj`dkpW1{OEmP|4<$SCa1+l75e_+ zxPCm^5^EQ253ojTe^d+(Yoa(|P2}-ISkr1Mw@nkg2CXARexs>_Zd7!9$Br#rye+%2 zl7drX{WoP`8im6$&y|MX1al>fW#&YXO{`8(-5_F#l`|L9*~SQ(98+H*3vVPwG1DZM zs9zK+(tETN>*Qu$k{uZg9cZ*GEzou@kzH3%wIcnadoyLmK!5d-#FUPq$}@6Oy+TZ1 zezl7@PGK=`Xm^|ziLkgqD_p#QMa388gVuP}4}sqJ7r^Lf{wS@5kYMg})Ra~FY@yl( zosf{9mjOlJ6=z1#uYdhNpy*Id!1^(e4D>3Dq%gENl&g0xFi*!&oA6*1EDk$`;XeM} z*mHkZiop>Blw_ zk4sv&B2nu;IfzDIZfkKJ#&r{5QTvk{VNe^uS(>@->&uhoy189bx2xtWRCj&;%y&`G z*LUfEopkZY>7~!?%g6pDkD4j%ScI%K8i4u%-6^qLd10pU!vf>OTZw4>kmVLDUYOu( z;MKph9q{%3TqrGG0l)HhFTw5ph76DmOhGoYOA4}Uzc$GJ{*FO*_q8n{d*zWNWVKU4 zkPtU9e&H7_kTL5lF6QxEsDL~{bRG#P5UuPbAg<|9f;?#Ui){T%f5z;;)Ze&NYB@rM zd>U7%4LxeT_Ud-hTNBR+FZGE~ER)3Id*CJi;w`92L+lr-rdj?SK}{K!`}Tb1CcV^d zidW+{YPw4xrpp39x?8=M7G&I^l7>Q|_${uLOwz;CDs9Z>d#bxLRb9JebqaZ;&S9+U z)tt(U5HXKm|NTR-PanclBpO$@lIL43H?%l`-~v30c{J(W}ZMdp{u_V`Axq9qr2P(O-D9GnoiLjMK4%|f+o-{ zWL0o3>S9_F@04$J3Wob?&2xMj7DK|XL{h`N$1K>fUT*2MjTkqn)7_~BF$h7kx zs>h2>Gs`;B>LhamWizQBmywQHoByjuCRrg(=tRARe)cU@$MFT+ms3vI>O5yX5d>d} zaVxI7A|S#g(^B`>S^HRtC->ZL@hTs*+N-VuHRxCiPKh18iK7$kBw1Vu+AVf@3m*~> z9HnRS@R>S_uL44^_7(DM=b7n7oG*SUoS9efXa2^`=uvbC$r(`rU!F~q?sgUK{iIFi zOvhkRuNW?^3g?f=&Nc6PwZa^3&c+dPaazKf4W1hDM(pJOuXTf|6gcXichdo4tsn3x z86he~$v=dMDpC^pQv?t)iQZ&lk0K?#rOJ^_cSY(sPD7y6<~-8#6ZDd(f+YFlGy~u+ zUjH@XH;7ZZWdV^&fI4WK_EDPz3pXRSNsLMJx$=t9X^N!F(B#aub7h<3T#Y0^#&W(~ zq`GkxOImMfoYS;Oc49Rqx{V8UtY9QsgieUsW(UhKilHVr4?>=nJZ%{SBcTOZ))aQH zK`9*anfNIsJ?|2Em+;Gw7?CT@?<#ncqqpF97WIr9F-Is3`?ph+JK*p4Iv!rI{Cs_L zHvwg&JVS@iNJ~vYcVuyy)a^}vB0Js{i9i4rN*pA>gNHGpi3IT-CXcO7ai<@^k}em6 zI#V8x5(X==#lRx%`a3jtKK9SW2_vvX+shth!KV}HETiOZm$_{npVSBOqA^T0p(bY$ zscylpkglpeznX+{8UJ473{}thihIF07!Iy+C`rziatp(YDo2t*6^KD@$`~+OK%@;W zM~_8<1lb`4#1SbVat(-_-bzqFyOT5$ll_qwev$yklZDc0LiB9yiThG>_3rFSJkVVn zv-0Sv3`0#4oRJWmD+O#LF{YEZa(g2H7whpnEy3dAZN1tv^c>xo$Uk&3+_y|`wryQP z`D8Uh8YHJ32L747o1Ol6y&bz?vlOUTHWC+U2iIB}M#2MbeP3RQ&zfe+f3sYCg1Ml& zW@}cI2#Y0Z3L7W5Tuq>|ayAKS7em@WZ+5Vr=IK+6!dz$df~8_ z;oCk!TrS@hcuz+{y%vrS^%nIWT(a=G&=F;%7nLdF=rVFJ$C?y6PWNJ*q{gpcnk`_A zry`oy@>{n!bQ3?~I$}vBbuKnm8O5}KPA#LHP8-W8_)C5x@aDU$pgY4?53m4sGg6FO zv+;RN6VYxUhG{OaH+`kue1FAm1= zuxTu+le2YWm1FHcK&%!6{39xH9>Um^GBIeG*1(jJpKP$6e1r4u`Y!qJb6O*SWKIi5 zO89?!RrkkM&R3UgjT&oc7QZYpPa&`FHG!zjG+w_t&Nk{hKW|b_{b><@iu= zh4?>~$a|R6GBdi#;x0R|6i(zH1{6&v=yVome#=a|T0ED`OwLYOq`L*3+dDLSxO-hQ z$G?TjtPu{T|APsyw(oyk#_E3ZV@a+dJ*{}f2JIWcwOshV<&=XRAV!RuB5VcKX||B^+4PlH z-{tL>3?s|0QAu6QWqN1-^*_qAXJb>f*C~yIwva!xQ7DhT>Ov&A5WGjPRh?!ihWVc6 zhI(_jQf=F_9)RJZ2a%w7`(YUFG&r`uxe@EU*qGev>xpF!_MHe*9>mL@r|GYm1fxoY z%svfnMZ|3CTd-P?q%l!#RwSfVPmd(z2;F-IEoiyGfFObP$%ZeR=wKW zg}VPf1ac!u4uP%0Ufngx6+>zn-G^kW@wR%}aF8*d|hU}+&V>4rU_qR>D7UeLr18j7Cv z5YBBa0Q;R1jDRN?OgZ-|A${c9dhW130PBXNh+Q5%%|xG!Bs?k!RG`z$B~935PMNmiHN?QR`tv!`k3>F5cv|y{cL;sfJ&lke zbx<=KB7gIVXemx(Jzz9<;Si_MoF*W}KEG0ejpkEMp88A)I=q2p^7 zwlEKVn%962Z1Hcqid#n+EaXQ-EL{g4Fx>R31cK@A_Qzh`h~&!6E~s{(E!~)AXHjkZ zNZ!)VQKWr_(YdhJgB_bFkLo+!t7z);by2=6)ElObOq!e<8Z~hDn#qv%D|ZQlv7C8I zw&6PzwG7lcO9{^20xrMB|G1q(S||CLWRD-QoTPYJ=FR_600&bp;+|%Ble-(T$iIHO zpJ*P96HWebgX3RFRy?GX<~_3wLMb(+*=Qfns||w13%>Hl4?>a?L>w|5Cm5y|ae`~> zK&I|1YTnB`bMcJ(r7@Jw-0u^}Y3{dITV*1dsCdCPI(UV>7LUN;&sG+H^!AMaurl5o z(=Md0&T>oClH(swM%>dS-}S{Ori%9piucmtMtyN{DxKz4l(2x4^E{vDs{F?b?~7Kfr9*pmGQCzJd!GYn^J#4ahdr$B*_UtXstZP zP+D{o@*BEEZZa@mzcAS%;mTn~z8#g_zd5^mG8-2WX2mBz2NS|%R)y!-K*?vm*&eQy z^2;VPw-hHQ^G}p{cGF4JhbiI7O?`N1D(6oC+l(Y^Qw+96)ZR2vWs3C&Tf((X=kZ6I z;5yDfq+k(We7WDI1g3(+ZNX{fJRYVFxwLe%wb7Ayp?|;~ZZjsqBB1-peol~xD3oqs zD529?B^D&|ch_ngoABTMBNFc9-=Zfwhd*huq#j$ylSSfLQM`{ZQ~pNtAMZ&mT?nq) zmBGCWnf_NR)uw-eoBp$v!1U*uO2o;D(wRNA;w#iPm2Ao-PY$*vOKU@Lt9-!Yf?E}X zYp`itqNIRG6D4K;LQo4_#3E6b5;a_btbw+{J3k< z7IC+F4|-jzH)>P=#-FBbs*e+=FA+u$PA%G0!giQNd)o2JHGEIkI?X|bHq<;Frxm*j z$jqLA-(XML8_;cq{vB!BD1onu%`5Z`WCutlKPyg9bU40LX;nAm6;}36br{0)9NiW8 z_usY!i@Zcrj!Lp}?0vX?SG5_wcr|~gzViAT^8BtdJ|fUX{GYZe7LS!jCgf9KVLI0M zk2h_k*`4wAOnn9SnwG{@4j5`&h2UQ-v8!~a=L1aBG5+1Zu~1w;8LIn#Mm zkG-3lAPN!$Z&M#0j-z>NH{pWp6M7Px9+2sj}$WBFObjeD8 zsn2M@6jJcW1&A=T{$m2tF8ni3L#1rAIo`OskSm4+1m_ z-IQwBSZUbE&s73JqXSU=OSnn01j%7qUS#@rw(omp_|;uL8nF1ytni>0 zuB;?}24ah}iqVre_r8L2X)P#yBhjHr*wN)khg0M~cDuAW&NeOC2d{Rs)GI%_6Y+Tf zW`^hQ@m=Y<g}Nlkf+>8W@V$m1VSv;nM{u&>nLpSgePeLc)bKoQZ$?dR3ICG--oCS?TcEC<$v6j)PRf%T6+ zNFCT}SZnSM`a4@DFatqW3O4k8dN&o{`~EL){YZQF0K)qW!oal;$Yd2@+`DRC-Z9)* zj$D&hHSY|fXgu7-U|#o33YADZjH>pYrtye%dDilBp3{%n`oCbF5T-g%d!pL9Gx35; zHUBQndrKD^=ZdcHpI!BJ8?zMk$~JKHrij|!(si1GSzg&X`X!+j#7+4DASO5Qm zdv73yKPfetV|wXvBBXdH`U%kqchuLnl~&HLNHxI5;;UzEx$q4u|cOJp(wMSQG8y(a<{2Zkkt zXm|U40|SE60Ei<{gLZGqA1f3U1!F^z65b=xGf^{*V9rpE>U3wov`GD8Q!L>X(MH6% z-6}|S;#p_W3Q08B2X3WGcFtM-(9`W?YJTtHSFAw=vZzQ@o@>9D{@Cwg=SM7pQf3{6 z8OdelgdO--wj!rLSYFN_^<(5D5)4!s@H_5vA7>tweWA`=tdNOEa8amVY1OxFOl&Xn z$~Mu$RX@yts~t$SrBxqiFDwi73uQB_Mf7!xLX%nJ#l_JUa=6Ef##BQTu3r=i>%Cic zS>1!73wSK!2u(_{We}N7`}NczHNPgEVwX@4NXPJ>LUlEvDg4NkTueDK_*rAt&a3V% zQvBcjhG6Z}6SnxYbrvJb?S&dub0Yt5SD_Ih{4wlUb%;l!I>dBClS+&_-F&z!g~PN~ zCE#2k$HmhN#jjMMOsCbaS&j}i6OG=|8e;+F+3fV~tYK7MWYDH^Z}{r)AOaM+C1viZ z@i(MOf%&svai(X12=OWQyGapZ6VG;bYXiMo@X=Ri$gbyHr zbDsoeCug;0g*m4y&lZ)Ta)qeR2`j;*tt4OeuOHjY3MhqsgLYhEy-0#^U*SnRXdLE(8&r4pflQ*`| z*k!;t;gIpOB&xvxMIGjKWE{l zv#=zVr+F(d#S^vaVT|#ZQ?_F-vqXtxswTIM;iWEkL2TwTdx6pE7sdv)xj71PRN4b80h%cr|s1O$+a}5v}^BO=X)W zvT0{x#&*s~wX=_Fr##ut4Ef2g%MrjW+uAlJ)fR^)zo)IVEk*a{R?rsHU2(f5*6p13 zskZP{R-eB6v-QcVnVzAUy0m7@62_~2OZ{?`D(cW6Y1(QL71K*H*SC0Y;YOlD&ycvr ztx@guaTV`MU&pUjzevylqK#s{vS+uExm0Tl;fLrF-%c8&x7U9DR zJsY_D2F#_1#JYRUoMd4nbOfBcA1NhukA;p`PEF_pegaKUk2#FK&T1aiM38lYW6{mZ zpgELCH&F0)XddMZC%IW_$nURunCzMWS_i*4Pm1v$wWDe}QiQvS5C7Z#<;oWOm-wly z87)O6$v;k1V#a6QxEWiDyIbjgT&pd2P4Pd9)Y3wMi3?PLP_K`8j@|vG_0Z-o9HB%M zspI=DrK7ZAKZO}-#x!#}rDAW4AgZ?XR(<{A+1iLophIg@BCXBX%-s;K)v9&J-|sLn zmE?-&)$OB3r3+_Ux`$GU{9dzJQ2rw@f80jD$&(pRnq2ukV8CMXq-cI3+aU33ub>S9 zR|p9H&Frh==Uc1n_|>Pd`hjDR##l#y48CxNVa+?tu|F;X!0TTpN`&X zzuXYb?~m{3=+;e^qb@%@)#_vWZwk%|oV1fJz!c4F4l^Kf^lzYW3$Z7?^w*c`NJ(Oa z3sKvll5-HW86S`?yrKXg)2r*FgQ9@84&phH-$03YcODf;vxwi4r`p7S#!=AYZH%49 zm)T)au%^|ciF8Y3-!e@I-6S+1G`LwM;}5+2`?WFg3U>}v^N9EjN(O)7KR5?kyH)2v z+rFQ;7l;10ktdd8L&d(LY)5q488rX-YZ-oy4+?^)@X zr%&U`@c)S*GD0$7Z%B?zLE>(|n3u@!sU#+emMeeG=SW~@e5w=n?*r|}sQOH%$bg#% zuGymaYR-xzK3Bq4eeuxLC~baYBV)ZXel!E6OWEp+_u-as|MJ;*EtCKr2^$_x4(ZcD z;kGyjknvV3<2OOZ0++GTGMvYxeyXy{;Qg#8Uckv8v>&Q+ot$Zs|wB`5Oc7?f`J3Tp9Q#0htX=yWL>}Sjn&Xptw#ZB_(_cQCG zUDznu#((r2E}`iy5+-vqUx8gyAuiA?T^;IW~2c`OTPOEN#mu;<~85{!`aE@{)Fx<_fH3dnBlYA(?7d1_1U-G_^j&tKbw^P*|5}S zFYsA>Buv$PS-Ldae7)RTd^KHd;#kvYQZK>d7KegB(QpwRPAVEE@@%VnyQv`W6nitg z4Fq{kM3#e)UN}+wDhE%b!+7`07Z|>z7St?t^1lB|@-^rt2?CqLo=Jd((2>VSP{mbt0T6qlGK<(Nc%DW7N7(;Q(r zI_+!GctNUhtRC8`3>`5o#i^fsi4qoRvguHx>7iY7I8;rP(#y78fXP|?naj_WV6bP}E_ z=KK=jp$7%_sT;SizQ~;#9Y=uR;kk9Aabl7Cm+UG8Y}$!lS!_mVh+ITUPz#3Z%0l~j zPnW4N<~mJ}u8V~B(MvBLdZPsR4<7m%y7j4&>6U^=i3q(~-t08>l$>gbG#Q5hmwHL3K)Q&p8~&g0Df12UkLbz0{$2GX9Rz%k^vtS_m^II ztaaf<_#Y$m7MbZ?sKV>QjnD;qcOft6LiZo)LieBxdGWLDbgp=e+OL1oh{eCE?&SsD>#pvF=pKRHa|UGY-m%TyLq>nnMQf;S@4B~ttM2`Fc(Qxg^tL3x z#i0v9jP-DFNPOq}JL&SRpYE&pOf&bmC^WE?TH68i(PkH^B1RAVrCTg449|`4!l;b;_v_yV)a6%w-X^z^*B<@baPo4ENoxHB(U8WTH zLL_uGDf^Ietx}5QFcXD8ka#3|r5KNa{tH(%X}3$TM+zTN7M&4_NcW{FuH>kD2buH8Jeo|*OE`S6Os86tUP~$g%Jl>! z`MRRws^=$AarHZ&Awn9#yv_`r1~%)q?j$SS&?)B|B-i@l4)>)E>XB>RpemRSd7aYp zx(0b4S>B{jI87>_x4)!vwaI$$)E*WVR?_QlVqIu=O|yZKv)`HM>@#rLsW(Mmc6e>6 z)&tNZ4-k0(tR0zGsGI%d9FcS0AJ9JI{-vsq+}%Of`JJpeSg5ikWQ+(p?8;FY)&_K{@zSZyb|GId?>h^aq{JX(@oQU zfpbmTwS14BOIa$6QK5Qz`_Jj=0arKo)R|O;qdUUSz)$qAitEYRga@^k=RPX2*eTp( zw-OqKsZF43qu8;WRqd{x2LSMXOV*TC4C+V%PYZo50wxS@oOlQGr<)WY>Y5nG}S7w4Tq^o4Ha1#|_wC1(0O zoe9qtxn?#=UUH6^B+uqd^bIW~)vI=SwP!NUP3%umT4Ljejb=C+_ix@R3l}?bd(w1F z*z!JV_Og?xqiG4&X~Z6_JynZg3_HI>et**ALwV<5+?zY6EV`+B6X9hVxXkw3cFPrO zhcFrIO(helAM$VBn@vUX9t%uG1Ql1Ig9VN}gl>A|gin9k0lDXSxHfRZiC-D4lGNYETXMHpG`t^Ao?0nT&$_mnGF^zX|)hn%nk zEzc$}ss^z{rmlqgIBPu}dyCejl)s?^r>OGXN7c+Ws@^s|lduG;pTACoI5~0@`qT2p zZEeHPJbn4QOZ8vG`_nERs%rBau~V`bxeIc318~k>SB6HR z-`4U&z9h27tRBY^pnzba6^&ENyf-(E(A8`5q6E6PbVWLp$Q9|tmf6%6L)~y6?3qe; zg$Iw#tGuv0Hh;amO{9L1K+>S!*z8Q|k?7xec9vR*)`|S1&K67GL5s=6w|RDj zrL#~C$%y|f3e!trCb}PeQ)zUyQ(l$hgR9-e!<4Mpk4w^5>U^XU`sT9qU6Jf<;X}US z(sepqv0k~QwgT2RD2{G!L7B&_y_I)Sf|l z{B{bLE^IffhO1qB(h8wr>QCDqKIC(OE9{om^&eJRhiVxjLG$7*rRkaLrh03-Tpr($ zU`Bq^Xl$h~H_^2Xf3?wC8WX)}7)TUBiy>e)qp9W}-Ow2Xiozim*o2FI7LIm)E1clc z=6gd`G#LMxm~g6;>MN8cw@8#TJIh<#ps#a{ZN)FLHIo{Fjj-geUY@UC7q|Jm_1xDfvrH zB`#(M@ZF$M5WeDXkm?`!qLj#74e%z+w>)}QZt0qldD-!qsGMyv7Txd2Qv?zu^oKs6 zT@s20yR~_3{7zcO>^@*R$0eE0;l^}6J`1LEpt7ys6(@@6pjUlf=`!#S_}viOR^wQ3 z0!$kFKV=u`KEt(5hgjvw`QnfH$CnB75wNcM=XKhWF$~#EYA{}BT&|LUXAx4^u=_)9 zU|C&tMQT}PSu854NmL9d@s_Tw<_LTu()};*)Vdwm;bRG8JK&sKmCD|w@)9J7MZ7ef zMcGF)mi=9_Y#C*jsO*uHJwIdFvy){Hq3n3Qa1TNC>LSS#2kBEJm|~?jadl(yQ7V9x zlIL%DZeyb9jg+OeduXvUfFp0n@!+n-Y?>KUP+N$xfJfhNnFokPpbcK_!_)HpU?V-291dutrc z&9KJB3zE&Djj-kx(41IB(A>};Y%XvB1iM)%ILBmFE>wL*{-O(UQj$}Jq@|K@{q=eN z)gRCe7Me|zmD<49l%;TBNAx?>Os>?NsY`=_ooO>=b~B#~m!4w{k>j-ZKJM$<$sJ8p~E^Vxa_Wqk^;5 z-=4~trl*7TgfM}4q(lEIzI^^J{v`5$dj_<_(u4PpxkiSaC6lhCZV!gjTqEOi;Bd^D zoX zz7`c0*BgAO)Dpk5Qs4A1xLhH4);1AjVy#`I0%P;XlILin&z z&h>tpd(%mxkBKPUIOR_rP-paQ5(Fvk!&$~oIh?^e1J@?%HrJ*O%Qf>5>fkL!>`ETv zvmb1um0!~xZmL(-vvEu0e|{RQ`bK}{md}_9Ik8zuua5_)H4-bnhJ@5aC=!+TWg-kb zSOR28K;kQ?LL`2Eu;nglCh?z)ZMo&%kGbxM>X877`wfcA1jR3*@$R=%7mFFBxKn$) zyPw_&bJ!XG6>~#AF9Xvkz1=>dbcqAT!diO#?5`S=9zQkbiK%S#KfMatoO@|%J#Df6 zNb1D7EfsR+>DwGAE&bd6tW+a_Ul`xdc~}WDWg_a#3~^)DpI)EP%gfn-olE)%ViL*E zZJ^A6Cc7vv@RQ&Wi;K3R=P9~NK{C3_g4Kc~MF{7z8U8L&aT$%a^=i%&)e%p#a=&M$ z&X{$<32nWlquW(~UeU49tGUG}a=?+Z1N)NYS5S}t)|ek_WP)?yjTSYGlYJ8?%qtj4 z;FVkHB14~Y@_ShchJ+>7X8tM?z<{_)U;oZGwGu%k5NKbE7m?O)r=Fwpsc<`~xHfEv zDyBOAbiQiJ^Jh$gKaET2occe|!2nUS;B#G`v0FlHnEsf2DcsJSd z5dp~{g_Dt2!0LD2O*f0@D*VUW5th3u-n^&V4wycZHDKxJHXwFt$Ht1Ql{U8`nKp+s zul6>|`hOd$pjSCha@Htz=H2`pl}BQSJwQTS@g@x;@_NpGU8ejgq;Tx|Uyu^NSPi^$ zxixUqoPb|Wrt;pr#LrRXF`XA?&mSF$6~<4o){46k#zcKD@XvpeL*xtH(s5uawVYI~ zDcV&>voY7)ikSUT=P=X`msh!awr(A* z8UK~Ppn|EEOYwA(ubJO+zqMnwF1*ua24BEz!&-jFg4TT8;FUPH5*P4a$&LC#UAus#sfdr9hQJ=r!0_PcDVSP<=+@ zE?rVXUdK|rjCBh$0loIVgW~a10%OBZ7fhF3BV>v{)~+Sx@a( z_!dT4^9$7(*xaUe3-gs~WW3VIIHytxS~6_QQm8Gu>zoN$XDA=hgNQAV1Uy*QzCbp=Bht*l49g zjMAg_e^G(z=^zLeqE>){xp&VvF2QnIuPvi%ihq65MdiZo0415I1X+h z4i#}0gPcAZ;htIOnl=XH)#i)VsVUb#_bj#x?Ri~JLkyQ9*zu=`6`^krwKz}+j_28Wy>=v%BV@o7KU%MWmW;mp zk8s)J_*BwK-!x`AH9IAp2!n$H4ED3SuBEOf)DEj0lkMgDcm0_#**yRC3+&ikT=Z|G zNN_n}7E^6G>FM0`<(I`z$AzPBAhSe}Ke(4S`cMDkzbY#4e0bTr6+Oz^&W9HEgrn~y z^6#Wk%gEk{@l0O7295zr&u`YAzx;AF&Y?L~L$fMR_Lh$7JiQ?ge-3ZyXj(zvL|)naViTW#INQvTJGfy0SqlyxQubfQmmw~ z>0@{Pf*AXsaP_c+Y@gV9qn`uQryuk_RL0?AB+7MZIftI8tt6ZyMtFj`P;&k$t6op| z_ne7CWA%_w)(t00>EX^%q;QEsdhcsvTAy>tfnpu$pL+UqGM_fRBo$AtnBep>0*=4c zvLcy2D z3oS68*c>bYzH>J2tlwyZ98Pm*U3KNYa$a-ptjoV`n-!l{AQw@B^ZuTqt(;9?z1^Yt zHDhHFT@H#0b(*zN<06`Ikf4KR{iE++{)w(iCLK!GBQc~x-{?`+Q>C&a)jkD z>h(x{@p-Rrz*<=PflhICC&KwzqhIXRK0&+X(jG6n-Oe#?ud9!@Ow({&Z zITUD9o_MX?d+xQp&NSSxtpHD1{)~lMR$K}rB5_+D=ky^Owk*4dxjfl-y29e3lg|UW#@m z?Bf9;H|Uo+XjrKxy7SF1$U|L+2jryi3n$R#PXZ`BlQV;Gi~|h&cCqto0&0zy4pyg0 zl~)Cf{<2ltK0f|iGYz4>tIXgbWX z#`bXbXOTnpv^ZQcSGC%PN){CNRV4dMyGp%!OcFVLtG&l4#r&;BXWIC#>#PfNnJ0{?rk2KZ z3BS!m8-f&J8YSN17c{r4$neCluT`IATcUcO(#jpAy zcV(T_j#W8?l!^Ac$oV+azbfAQp>HH0uu8HB+`@0JdQIA0O5>{~_PZ$bu>Iox$*;zK zz1|rct^DD^P9pGXwxMVW2OU(%SZo6qC1z0l3K`+<>&63yY zM%{{eimc~pox<9xbY-i8Gnoz|-xvglFjs?5j84YG8fA3{kJ(#55njqwgW8l=6Cb46 zg?4NFCsvZV&Tlh|@Z+0NBh&}04g3+Eo{nz1=SgTb@1UVUuxSyWf54zEy5iAA2;>3m zlgtA*nQD0GB1h3TjKx~zhOmrOO4zt&(Ii=zG4SADMT-tq!PPm6LvHGhF9&KvWYOYU zg@b#SoXi+$R1Om}44VCyU-**Fu*|8Q^Pl4-g+;G!`j=oeaGg4rXX1bIZTt)#L0P;f z?j7df9bgv%yM<~rg;kx$RH))tOl0c~ZbO}7!8uK&ICl3UG70$mKnc1BOGbKj9^t%r z4T*PjH_uu0Hq0`NI(Ai)qu!DbEtE_@++(S)hsUDEH&nnX2Qw#JrrL|T6 z1*m`ivz+0}XlCKPpE!#RsIl}szLf3yDd4xb54yu{|4Jw(XGQ5jIa^~cr zCbUHl{}rki|LTUw#;ezAK%A(3esrsxiv^|-{1`EOB*Qc#_z_YZg7X}Lf2#x{d@>mx zRxe_GlO03FQXXCBPsTkx*&VO8(4d5Fm$)XJ%-jxTw&%VCx~ zS*baXnugT>cy<)a*OI5&_G^d_mJ6X%VV)xEk>Ff=sGg;HpEZD4(U&*Y&oh9f167qS z9Mu;&=Z?ncJ3C+BXMCu0?n^sYW>*xEw)9=CFj?M+x8nCu^UhU#G64iWkxl!ZX}?zO z?ag5x@08*&eHXezV4EDz^#4H)^S#4?=Ejo*Pz5l70|`+0(cwB%PI7XuZYh#sk_$Y- zGxs0%r@!~{i1`>7F_kTRGDU}F1R~N(BLT!{d_50r2Zku!q?^06rK-<4K?y%ZjjunH zPK}F1SK^{e0G5ZnsS#&D8YJ)+e~J91UZYsk4=NG;aPD2cwp~c57ung2zx){p@jk3! zqq*^H!+O99H~;LrL_DFCfd7SAVc>r#S>wf8Y?7Mi5xf{HzEoK!C9~QQcy_2|VPJEb zvid5kKIf(JZ)iDyb}MrJghb18IER-mxA8L7dlx&YH(y*pSqP+d95{w1WVv~UdlY$$ za*v|aAv_Yfv0no+Npfq4T$7dc=WIm7iueLpHCyWb^3bc^o$J+{sEJX%ySG>SZ$3=| zvUH6Dq^khg{cGK$bYX1vsTI)0=NkT4 zPDe_moq&9;YJ(L)yMyJuKl-8deec=VM2w0bs~;K@<#g4>K#TVP9BP}@L4QuOZSRCa zSRg_$e@!5kc)E9k$qJUSUK2GkUnppVqf1plE%JvA4lxV zSxHj7XVnG{FvA$&&3sYR_~`m{YHXLB8T$gEaqGunp7)rC>s}33H8=Rt(zFKaXwYa+ zM9D)diEM8K#-&pXFT3)BIp<$6=aRYMLBx*#6=WGq&C4COI)kkq1h?nS7LPpK%9|%< zeCOxF{*NDcJL%Q*iGLw6>_>l@rcyLD;8MO04h0@nMPgipS-6j9Q{?~USeVnT%3;Ws zIE)A@DZ5CweSyTrirO?XH!uO5E=4h9HrWJK#0W1(Bb)@*k=xL$CFKWc0KLT~Nm z#Xn5wSwa~Or#N81!w2e-hL%ZhCq8Lz{H9lH-dx8Y5p446=g`VkA|<7omREnU)k_-j zt3qwcBoZ|H^*25GeV=LH0aT0_)d5CMYd=jYlyp`!(4SxgL2p3H=Bi~orxg3?mW_?ut-Qi9+6 zB>QF5737)FJMRw=tG2mTRs7rLPc8dwvYRT&i{G3oqiv>@){;{D5^wRt)p~FKq*r~A zz8#dF(n%>tkkWK${7S*9^6{OnzId+tUPovruQP~GB*njNxIv8a&3SEWq4wWj`=vs^ zdQSxY+Tv{fzfRO<#cWv9{k72m2madA68YAO zpva^idy)@z0K51!XU5XPKEwz9s`({Z6+dM!eKH%DaD7>*Fz{sC%{eWeY~?Yi{56@^ zY*@G>!6BwTN;|}iL|?(i99u}#@d(<{@2cjXjEpE#qeu)xkk~mK>weSDt1X9YOBW2A zGiz1_`x;)bWaM;d@M-E3@6-cj3sS#;a9G44Ksw$z%v`Xe{Hw z?V0lb98(}HvmJ6Bir=Bmu*;pTQPh$IigSJd#k&<<$WT1abVWJal_10CAkvc*VnE^N z-uD^&ct+B(@X{aCd)-wPj^S-&3TUrxhky%I2U~bfddpeJcg@?+Tw=x7%~nnVFF*Dn79}HAd=aG*`CAU9jWfvYhbt!sR&p^~ zJ5o%R@gJEwjtQ?Fl~$YHvS{KKjA_>v<#+yXM@hiVdk#6 zrq8nph~F;>CE;ac>0gzGp-^clM?^KLS!Q1c^C7+2=JtMS?b+Pr2nN-H#>0IU+(XVn zDw3Gz_2EpsyF?$R!8ZSjjtk!N|Z1!M-?WoZW0@a z&Vm_EFjw7q{@GpFxotuO*Zjn)cyDf=Q1l;WrVeTCBp#^|_U6@koDsnbKURLLiRxHv z>66)|Ph}Ir#UFRiXG!HX%Zsc7$xCwLpv-YM*}YgxRGnK=_Ts~f15mu$zZg@@iCNo0 ze8kxPfWc|Kp@&LkO)5t0*S6o8ITSSWBMu)|`j;+#?ske9|Ev6U7q1amiAXbA5GUQGcLD_$*(XE0$t>mZ4Bd*3WGlytfn zpT);A-nP21`Qb+I^H~u(Xh9HN19r;oy$Hbkj= zT&cCLR7uNHw^GXMWV5cHj_3BdJS?IXzOyF(?!z~T_HvMV7+Bpl9v_^xGXgeaAs6_kd5XIEaR()jp;GrUBZ$WGMN`{o_|a}48acR)2q3CRG@?z};a z@7iC<5PW!U_26v9FhM&80}MyUu<)V@P@UYzvfb()!**o^s2IV4zLQzm9to!O?GZRx zM`?7ju+xZFwhK6iL7y2w94N9io_4tfM9)8tgk-R5Nece4*9y2rb`uU8UZrJMPLV+6 zpwt%O`=Dgsl7uqmU?L);S5pov3f7gOdJJURTc15aFt0N@kS02Y+k!Sw{-UIDgt^K7t+&Y;;ocU5=heO|^7>H&cy4L{o8h`#UqfOB@?^C9@pFRu z%me_5eXJ^%c0%Gig5JGm{zPBinVfMb-yqpx<~~P+FOiVMj1l40;SA$A^2hZdjR;{4 zW9d0c3$JzwNQ(bfm_p$?P)Kzf4q^*A;voWqJjnMPky4g~_cUu&C$bM@=ciOM+S{Z}0 zW*Y0%nuwDQk-MF(f*|$(eW+dHCt;{a;!j~_LHgBw1-A%_SRkdjYfGyV*%eq&p_F)l zERAQC-~h>RJrw`bZ7e1oBkki%YMEq^tPHpjlLmkHIRP+@!-;>OMz zJD&y(k5P!lAJl$uZbsC;OR_`l9l5G6|8){t%&YfDFt6$zCUtuR_uQ!cJpR-54vOaP zE_CqvINFh#TSO!MNo#bP_5Q=!5ui}&xdQp;9+P1Oc>+`b=>7qq8pt%(*gXYkt^u0U zQRQNVrLoQ-tSD>thrUarokQ~I>>^GZv&$z0%q9>fB9rc27*oyo5h{F2|N4#Ez8TR} z66fRl31*4$RyJe-kFB!by?dwz)S&;XWAM4^3?wGrlr4PF#>B~3@H}%>o9q-C&=~Va z9)mDNgAx@+mHLl;gDR8#(QI&2On5D=&{+Wxx%|TDPbAq5VvbWW9ixO8dNF6q<~sbf zjIEx)yhX-0Em_rVwDn^+Wh8oiira@{h*_|liX8vcXE#D3$Y{+I!oT}yWCCcP0KJ^i zUPow;b>9)Sil-8Pg`ScV%Uz5)(2pKWq`s%KORK)h<^Un1P`zDu~|-4-0ezj(F(7hu;)6uDDnh!uhz0Yj=} zIL^eIE)buZdwS7d_wMQAN44(hd*3E|`gc90dfEj^TNoJV-`m?dD;!RYe`vico=r$5 zEi||A>c4vxb3-Ta+Vwjo?63Xy+eFzy_aau})&5PrpnrGSZ_;MXS$K-eWeVn=XbfQ|pFi`sS*!4?8$L&>rLgZ`a;TH|f?*GarB*HaR2UhM|DA82?6`ty5n68yaI zRA0P&Vj5MvP)XGs$6OMQp%t?J^l>_}#4LUY zSwDK^G-SC@+Z+}BrE@c;K+=KFB$0GQQEMdKw>ycXJM@%9QZsY$YVSvQNTKVr13}j< z5+~}5N1v63t~)E3M4g4J@u3r|KFAJGhW|%!(k9#a*&6XeF;bQY8IPxo$Ak$JPWZ)m zY!g2ngqi&V?)$#-si`RVczf`!O7xw$j%i8tk_AmUr6w;@jmx|~FGw^Qs33Tmtm1{i z3yg>cf)@lVK;%W&hYjSnZgFUkeriHLb4d@<%OmZVO+Ab^!dL(3?Jl> zUXujt)!uBAP7MFi0%-IGy~>3veOdhT&Lp+}A5Tq<6iBOeT!vZ)rfNM?wf4zW>p7`f zPfynBB+=A_JftHd1SA9}U2H7Ozv)RLjn&b9Tw#gzt5be{S+<(a;n#JvAw)+{Quc_T z*deK6X??##v%nU+KlKF4pWCEp)%T~q+?*J}`Hx8j5A)KrLd~?~9P@IMfO<6wvgLq% z=Lv@AGQ9#wA6GeW#!qpNamD8j>Y|7HxQ~9vN3Ij!{G>J4=|l4lkc0J<97O7bJF7D5 z%ZK~X7mG%aM8}`0$pUBY)!Ip^*6R0a?XO=XTl=$~TC`?+WoxZctwn;Kv?wEWzk}#> zl~FL%p#5fnYeK4xF+8PE+l-Do|B^(v{yy}=+(*OLB&xS7HX?Z_+uCq@c{M3EWVJj!Gwptv_%8*nwaI(loMO3 zDJSY%^CzE}$j{^3e(yHjQ@=04zVd5oDOIRRPCLF4rA+p(!9-e5 z)2eRRl~vKtU%2ce&KeRGGqLgb&5_Q=W3t(JI0Fw91z2||O!@X{I}%L;h+v=q7cuT7 zAFepy6$-RnIW;;ue_GL)v(Y8}~HU4ewDm8ZCsm=cD)(FlmZU!obpSf1r0` zXK`QjxL~yTgp=d)dHL?B9IZjD_*`;{hspP{Xv+d5JO141hpyP1;AU~Q^9uzBnGy~B z%b)qkY~LD43`$;l{MMjkXG*B#Ix_v?l#DM!RE!AALD`}E=-{|Rd29k(z|$~vksZkm zFh=5za-hxMMRwFpeB#kX{80cAh-MtaJ~}VHR)Qy+Dkr3T9{%d>uor$cy!`1?qI24h zICf5%1{uj<9z$v0xir;YnTA$H*jYL%4DGu<#)-g*&e7*APGg3Wwt% zee6Mx-n1c6zIH9^RwCk!+!bDy#HtGmi8gg;h6^LgcoUl9qs2_?AmWsGY!Qh zCwp0QMsctC^cSn&J8*coF@Ah$_G{B$RC=Fvr3(@okU58!5(Ukxkx*Kic%dx1dwB;9 zqW34@{G{*nmsF^<&ugU%zDvBwVBRzV@?uK0sf&c#drx;J@O~uJPLb;K%GiweV5|ys z+j%dIM?1yfKZpTo&p;j=FBTobXji-}3+xSqDlw6P10J2yHg!%<@UL#P1JGPx%Q1?R zPK3xkMx(j>MK#D@oN1uYafPB)Y{0vfkdEoq;|OSORc(0n;Zsx-;QIj8-Y@NVN^58jcQ*UxA4Ec*tA2UT4`%R4#(w z=|A%xNE~e=uNl z^mK=R)D*0+yYZci!xJWG$<76jQns-25ZGt0ME6$gGuN@t3a?)SlWbSaOEkipb60V2 zQ2ZGuw2A!L{KX`wdUft9i|12%X6g8G;RT+>^PH>AVwAvQ1mSf< zN7{{Ej$?|R5I;mviCjoqGrTCfX^X337F9&*oh2hj&Ot}ZANdfAx{I@jAdk2F143>L znTTI`Q)+>=uPN>C`OAkgQz-x!FOsfF-4YiS+(?|ngH*&fp9&}}W?r8jp+x>w-*(T6 z4z3%yIe!d|Qmmt9Na-N$WpoTxcnX!iC`WayP9;z7= zJBe8aLvaiP#OSHWkQ;wYJga`dl+3lM>&XEdOI82FfL##`m_V&%Fek6qmB23*uWPW3x8Tg)>+M)YE~1q|l>{CPGi*nFNx; z*NF-<92+bCJGq(u_m$Ws@c{a7U<_RZEX~pC-R-=aDySFnaO=(uIKFmX7|!01cz

      dy>da75eeLXF;&bh#=-NM9L7;e)#XNFh%vgNdGoii7^ zE9I25s}Db4wVQSt8{W^!ZLHdTu~&N+IsF>yhUcys-jN$eOt6f9$?z}Ct3M^J^oFY4 zzGun&UhbX?bTn5lcg-m(BC;;?N0ENp}&fBbgZSzpB7q{g~y|{G1Hy$4swQhhqy%vRl?tMGtE>gNCMSmh8$869srpT3MjANi^)sN*h|9yqvN=_ zYc!jveUO}!blmg^V|U*HZtVJ|VX%4ob*ukHqN%#k$GnnVv^99%x7?1PDEj-AcuO&I zdDEX1@0|5;cEwGu7_z~;_r9Gd^_IR8jTG(j+vR?-Bna)=TI;b#WZ zMgCQVqlggB1;Se0;pYMfyb8I9fM>B$`)JU*CdaXN%W-7;{WUA>*TFa*(0Uwulh8FB z-8aBUdqDI zX-O8nXq}Vn%3wk~ZDF0N&R8eGiLq;CD@r*bG0Bwu+kS)mK!ueShn~aW;RT`!)?_gt zF8K)p&;5mg`{(`|IJe|y9J_yPVeIOXMTGf*P5(^wFDWpsYt_ejP>`s#B%s!9-+Vu{ zPE=2)Wu{iuyEnBSvJ*3RWG3dqHYTV4e*9xLw#0e%YULWKEE-Nq84o1(B&Cc*#VHZw zwXiuuXajtUiX&d!M-2)}p?7vkE|i0GPx%be4zC+{PUIi|MR#TLj1yDE^<|8b=p-d+bA0yI3(8Lh0xl2ePa}fo`Nfc1! z8e&2tLecfk;l8Zy>dt}tSxMdWT#iQ!P&Eo{G@~ zD_z0Vw1K|%WEWC#Xex50MJoOD^X?4xdEDc5WHixbwBSY6VWc3`wtWGYrp+v zI1|9(vMNTZ-mw2AaeK{)zSU*(mG<#@d1GS7j@i32Hx^5>YcJ?92^xzRY|cd;Q1~Jw zp*>~VnKLylcRAORbI#Kb0qJmnvybrD0c?>)#ibYr!V{N>h?qKg{*9M^rlV&iaGl<8 zjAwq!V^#&B2XlV2gYg-Z_e6oa^t? z(Of4pjr_HIBNf{@`=y&72m8J1PZ_jt6vTJ%S-BP56Lm7KBJI7UZE70kO-shls3T-c zsqqo}qsopQ8r<;KpW!!)>55Qi)bJJz_g8}Q862ea55|Z*Iv08LTBv?5#J)N&*a`-6 z$<}CN_4@~h>#xDBW+)23le0^!Hw_!IX$~Q~uVLvJ>MgydO=;t%_SGK`E9AH=f9tL>sH#A6E5Z zRdi+JC+&-~a9pV+M5ib$G=oRwdA0I4F0Y=CN~C7E9_z2nMJlM* z!mF@uQ1<`h?n~gCDz^Wdu3;$&OQ8alq6Jz6ZG~zP3Jptp0|~V3C<+Q9izrLVq7NvB zB9{;q#eLsUpBrv~pwhCmfT%2jh(1|`8v+W*rU?0e&zXCZdy^D>@Av-8=kMn|n!C-M zbLQ-GW(G_ZNU3|Q0p_<{)9e9QC)j4ICy{q)P2^$-{T`{rK$%MX4}T)pa5vQtvNsCG zC!Z+~n`#DJIFSyE;%QM8VhkjR*kx9i|JpH|MC&F?3*Zq1QX2W8t#aXOlFay>+&HQC zj#~TFR5k&@O_$zeuik(+;S&GM(&mt_Ar~jeCh~-I;T<8K0?&*!xP{1NMT3mADO$Ls z1YW>dj`9&|c%=VztSq!rR}i)Ryn#eYAkT_(y><6r7Wcow{Vz%|M#{x6<6t%6a;q)A zix&N9xT9hpwuxQiqhNV>Q)e4!LZ9^1>8ZnM%Q{k^!Y-fYvq(v?lWP6Fn<<8bAATGSaL$eVEg z*YH-=Wb5_x%1X+6<3EUGB5jb1{)FCE);LdLAOcF87ch$il;LI}mrg^D+?85bh>JYB zAXVv4ft$bs-B+EOpbwB}C6#pr7z09Iij%MRTCz}UnQ~rffWpMO8BVz?7Vh*lQ%<}L z&5(+u=5Vu+*39zz(C>vusG2tMnw&d9HvjIl#TuNQpoA+2rm`r1h{B{C!B8SMJAg9asd{v)*|+Z1fz?llxY3SDr6D24c7F zwi78?cx+I{R)Uj)tScl;@Gnx12{Y@E)A=cMny}Sa_=T8=k}dU%It+fYCT!{&*0_I-?llA#`E76938_yxF%V+i0qrZTH&Pi6Sy$Rw-i6_Xe8ay) zgMO@O!)^43(vSNo{=-e;DV$mkM_1@)#7FL9*)lR17cghZMFeYVqv1eG2HxhvsWpTL z&^6P2<}tcT#RVJr)|f;;aW;;OCdF8gVMIo|l;>~R56X_tNF@$wL||DRCZr6+_VNUu z({!5Zf|1D`#ZeG^i8!E}9So+{)Ik@4lxKftKwNgwc6AcnmiWxCA|3)Z;z~PoNE~df zifPXP68+Ep%QqCf!p7+ff?u(|7#AZhsTswDOHzwaL#P_zx(6(rGEhJ%8HpVU=J$n;b77cBeV*X+gTk=F%`D4_IVBw#X&3<2i zJQ6;z99bvhLE8{={XyGja%e3-Od)-(eDgdx^F{Ok}0NDKGk!hff<`E_-c(Z{^Bmrg@uO7N8~>Jgd=^%(*v}_qWAD z`xvL^IyxV=R}7ypY&-X@6DLP5GmXJn!=)|7$+2|wux&01HDMm+ZlH6$?CxqSUU2Qj zj$5B?p>hy!U8tkFUxD%ghsj6lRj^$jDEKZ2DNdNN^xAwD=aW>p_nAx;^a9Kdr)8i! z=~pIf^3YwV5XWy=P$(|?m4~~rR}(8E;Ry;+-GDcxxD(~+;1Mf>PaXnem0oMZRiJ0f z{W%pjc?(X_vXtKhP(YUsnIXCakm}={+cJ~yAkYwmRsa19`W|f)YUlqU`Z|?=hrZ{( zjYi+?EyL-1;zo_WXMg<*`tE2QqRZc;FEk9c;n~H91OAB(tdbnwdl9XFxAELIyZcwu zl%g>>sj7v_mAE|@`xO%Ftrx7f!3xJ@zjqw=hWo6tt$; zW6MKuKPS1=xZW_{fZ~KiY5J@Av>6n)(7E{uD%lCm!@W*F>YHLN%e zrJ>jSxASX$dX4m!|2t|J+7nIwhTNFsnFEh=nmN!AaNwXBg5fsA6|>XP47mCy<&k%e z1#mI}oT}NGv|gs6`apfxHwn*kD*Ws90HY*qWqtIvDv30urPo$S*9rg(0eOr5Sb9}* zQ66^Jqew%p3hdW^uKG7>LBvXud~#4OmCY`Rabfe7++(#xF4d~brDARc%7{G8*|t-Z zD539k>ck0Iqp6RbbP5oa19}GFBrYeL3?PbW042ruCqN`=#^K{-P>5|w{}(|2XH)o* zPH{yxg$A_lzfjv8(JoIj`yb{F;|W{OASA~49B#CVbTplSL2-q0<9)o#gH_#P1ttYb zfl~TpSE3&O#ukQGowO$fLAn=vP*R;kASLHVR25Ki0LK(%Yr8NZf)djQ*rLHHpLb$$ zXU?+(6XS$}HAEEw7pgX~g`{>MWdv4qz&0={Bj`s`geVTSi!a5VUkPo|ZKzN%r5P^C zz*!aFM(i_yoK$)dzN5?W02K-@gZ` zz5DyexJtDqXjLx_9BuFOgA1Gis-?nI)4sw~2lDrL11A-U{Y9=Ml+9KANMZ;Axy_1!%QZZM1lUUV*NCvpo^aJPo}`Vd3c;AbfPRG}ti3*bIl5<7MJu`q z!;s~m8SEAD1!KC)J-b|j7leJPHsbTz7B>xP-R$lQdUgrmv?ol`SQb2pwpUX~;K)J- z7Wug`V5v$+)_$qem(yqA7^+6DwBFwME_A+{!?Yha>X&9MERJ1J5^GrzGe$PqO+Pv? zYa@wmSYRA7b-EX?H*lez8X$ZFQwsX?bkD`_$bm#udCp$}3o)(F_t?ZZ-WGz`HxlE9 zCF+vtd&>i-Xym+&kfPrvS&FvNmi4wTkTs2QSbCg7q-t5P6&Khm50P&vs?E;?6U51x zYJ!-y-r{-NUnJ}=frUdcTs4Mwp&QJ?_oFP&N#*DkY_{Z;D{DuuaXV;4Y?VhF+9vE7ZOi%rRh&N* zp}4VROrbom%b)af82_YE`BTE?%=^xuw!U)uYrZt_UH2-COM48AZvw7zC~2ZJ#|xMOqC z;27y04#^we4D1o2=?SLk0;VZO4F@EHvOknwtEcQot;Iavc%Jg6W2z-NMB9lZbq3l( zNu5+4`VzF=1T)M7#9Xmg$?AgumXz2z3HyXlPNyo~e5(||f}%b+ve4HBZ7Fm-3zLCp z68ms)&QBkori%z4(;%}ew7u3&%s~M!)ii_gDi7CnT`zUoTsn(0Oj_o_9I^Nv(b|j9FhUshdab$@v`p~%@9Igcy`2>G|BB;?t^OWVp#Tm%qU`%*AMKz6&>UHK z@0`*?{o0vz#Fe5pL0LMyjYc+oOO0H_7Uvj8u}Z+bK0PRFVo`&h9@!{mCYJ~K9US~* zkxqf&w$Dh^q50w@F!bC@#Jy97hgh9Ld@y+B(K_SS3eG-h%c``Et7KiHH0(KH>*!ut z+rZeU(upr3fz62Tj-UPbXQJJ`9(;XC@b#|g%ScA*Qtlw)pFz8+r#-+x$-XrkS-MG8st_ znJrFe>2AG4 z9?~~Rx@6kruR#muDdZFwF0yEMp&$I!i7&Q6V)1prlT7XBZFeKB25}KbB@)0;VM@f z_l4n>^5^l9zqz-^qwe!bmIs$HPbc5<6;*M@&y`FY1N+1*8c(Hh22QCgq(m8cOqdHt z9XF|&;R}YFO%Bs^%n2U$-9t)?Ts^hlaxxk!k{6T*`17EG0){=%66FS}$!A3_$6)x} z7w)jk6V6Be(YlZ|Z_0uc8Ec?F)+C_#c7AgU+eEiJ^o66 zulnlW*Wd7vGOG%+g;2Bo@2=yYFg@-{tw~GUy;RA5R(ZemACv&uty7q6e^LLW*WVGn z-e~MKx*m638QHyFOKU)EZo@!q7eM?ieZ9i=_w;p}hW~r@^_SI`)7SM0%KuznZ!e(F z|08{UQxfaz-I#F``g-Z=8ufLv376N`eHaX#)%l<6>y5krr}}z6TF~_Mo_gW>dhEYg zU%#b)0DWD8+xqw;=oLlq_mFOvk*bz8v$dK4g#ylWdhbN(#F$K5+3akjG=eVBpIr@2 z*ABWshg>C2WO?8VxjNBggWbJ>!b?gBZRBr+Q!a&^@|l|ugPJZXLzNYVDo&TISV)r|6J<_P_?!m+WC#-mZ1|aq=a|aNq~#W zp5W`GOL0_eI>RiPaAf#EEF4Q|SWPo(G;tJ1Q%Gj=@3x2)BvM|NbX+6WXlr=00b<4zgILb$P};aJ#e!YcoYSY)j6!cpHZaK@-$ z$}DB=1j@ zYCA87s=Y|AG1h_`UE^hUlB#W|y2h#O6bC7C@TL$&szDLB#6%SGiBlI0G$nvIiN2qN zi+ZFMsk|;2De#gq6KBT4JzW*NiQxygD7WLj!9N|T&N*YA0HO7y^OB6UDr)IlZK=9D ztvg4CuQw8$qE_3Qj!okwxiQ9aQA2deX9^LkAXd$jWR(6CnUy_rlBghc4wYS?$QOmU zydTpVD%C)JJWc9iqlkGA@ED~#t%2iEaf#8xr{ znlfXyTEl``n$iaTE7ZwkR7BSkSkQEHDfJVj|B1LyeC#}C(N}M8*}{b_o}yIDNj3cd z=k%ShEbEtE+D!5mrFyVAL21*Riupw}L)CmCs&Y_vLiIK0V!jXff2HTHeW*-mPV|SI zcGU^&AqLP>k+|XHdk3G*U)=Bhj4Gyj0g8kF*6gyWHd&i*luShqoPO zqtl*g4B_J>54Zwu<>(C9uJzfV4r~`?N9DeJ~ zJyS~uhao34uVR_WwatGth!JK#Bsb=_+7$CdAtt{Q#=S_!7P=jTn!A?Dmkbhr6gb0mC zS>$-U5Usf!(cCi?wG6|%P~V)u*Hn5ZwD(l z=^VZM9aXynqC9;ymb_3Mf$#cHVxanI{Gz=7YVduJ_Wl8^_*LI8uzI9Ss8N`O{F!)j zC0RPHGn|$+gue0M@9Zye_*?w*F`RIo0*&xvH2y(mI?Z-hG}tK|Q5}_R0sD!XVRz^|`b*e}gGe6C zACTmW|LA)6iqN$oo`e%71SC5o8%@`$rDu#=^9;CXX1Hjz5LS;tmGdFXyq6%kSdSL0 z>WxKUK?AkLjgK1 zF3iGAd&PMw1k@5~}lIm7$3%KG0cVlc-h2+MgB4TF$omv@m8C#j+|t9}My{*UQEuLW$p?AQE?&6eClAcplU8`OCCHeZ2;z zp7ezdEu8Q$CNP-_l1Z{x>W8KVSyZSIdOSa|FK5&vnGS zEWVHbNBCmf?kM;YCyc8UbF6i-8AN3<=Wgc3(IO3fjdT$A<#&**5bleLq59gqAH;pW z!2M@X1DtQfoix0G|0D7L?C;|LpN%*0iGn|3_277;7?-qrl<{7ByN2_|ofz*9?*(yI z$NMCx5P>sQN3aWw!qZgWwK~oZ*}I`LL-Igddpv@%rLthEH7&Va@=lf{@62L{*EZDQ zEg9+X4g*iyvn5)d;gIV%P;(ArRv#?+O&>}Q!P}K5BOQ{mtSet4bu<&Hqm*spX{HmW z^5XL5Zu}HET6+PU+)@0pU2@7L#dz9Cd^^-B4;zU$#@gj!lknD{Qx^1K$FYX-See64 z@&JXZw38o0>#LG+OB`m5q>B=Ra01o3gw8Em{PjP=?|mbFTk{S0o$Sq*8h-Z)3^e@Q z{BjV#j^f*J{7O$o;5YRMQGM*MOB0k~Hizg6O?hTpo*^fZW{i!V#U z@%!Z02>d?!neqEgiokCq5^v$-C+g=ZY(&V2fjD57u}bF{_6kX}@%iCtYd*o0gg18` zDpU|6Zal!Pzlxiy>N58ykyyypwgFh{lr+FLSjj@v2)%#|`EC0B0C`Qk8lT3Zv+(s+ z{U>pJI&>{{m!I)EIp?jMeARwAuF&~o*w_=Ix8xZ$q`G8Zd zZFg6qG@Zwrs__vP#m=IXK<bd`IW2;xotz8oNu0t}Lz$2*?JyA#6f;CP4Ar-{?s z8|0Z1Z};{FdmXaNby2xS{k5OFD+zIb> z-BITE>+y#dr`T4iOH_3DBTNtCPh25+ns6oyCMx$cdZSZ(A>52a1F;$n)74O5vN!b4@iAHC^ z9Z^Js;f?TDaP<3RxKA_l;E#2JKh_!kSQq$Xm_9N1W3@oFqE2kHAm=4kTn-hNsc_HI zartyEKh1=Dh6a;g>ByIPaL)=thAw#&_KLt|xS{*=2EMI##1i(fXf{AEs~RvJROO&d zCy5Mm#27o|UpT8kzNYF&65P{|LefYvd2{R1R=VEgX85xT6Imdxwj}Kp;o|EzTSuGv ze3Zz)lE%x1wu93O0)^HSUj_9-eD)ZLbN;|z*uH(cgJi1xm?b>2AK?m}w|pC&H{{L} z@Gp!jttXCG^RKlz|GGp3TM_o{@5A#bb6Rdg0nhs53{Ou1&o0!7gBS$@p2h$CYk1;o zfCu!R5%lfBGsFoqTY{Ia0uNp7pgBxfAsP#?35~^<-Fcuj9_n}#Uurxw@p``0c<8L) z3g#hv+eTcfK7H~_Dl3umPF1JCND;$3ADyV`lOI5n^$=1$Lv!3!elg0gc{{z0{HYo>g0nv0N*M1U z=hAE5r@7n!n#|$-bRIvD%lQv#6r7NJ9Rs!%Or$Yj=WGK5&J$WoW55mKX}A)rx{g0G zC@~5no$?1|3{UbQR)#Y1k5m3sa8vSK9q2Qeyf>%(@=M~)J>tzb=?aX@=FXe@_%2oz z|H4C+kySgW+(!&DcRi7Z+#h{14?Jz;XNQNh71<*K1onu{lHMLIdaV|y*#5Z{)Lr|& z*k}UwDE1q=N{cznquN4fiOrZwT1EQGXpa(wJ*pM5NAF<+9kNFyKH}%M;S6D*YvO05 z2M9ES3V}(QnTb(`Nh*O!vSUzDOyv}*0cZ+J4J_h;38n_l7*hjZUrU4zhF(p?B}TCX zrl>^1PyxW?0=_Lw5iaEe9BYlGQDCRboBQc*9)%TX-RO-er-^^(t|!d%8Q=vG9;&)cZ^05t(J9-JcLoeYjZCWLhDCiwKAKyV3L5I_GxTK&x%8a+ z2|bTy->YA)1rB2Set;EovX4xf08ldkYu{ve!tA@=el30pJ*g(F0Q@)7;g!p9E6j=! z`)#;}84OCqPM%O-p;Oq3;TCHT{0&zdMdG!gdV|HADknSfWK|RNWm~Di`=~mG2KFNV zCS-350BjzF#R_24At<&ekTwfK$~m-;#U&uMrvvcUu@y%+z_{I--_nv3$uEjaJ>2bB zMI@Kw`!G815%UbHp@n}A5r2~it7ZTfe@qwN$wMXYr1ML(g}jYR3oSCBaWZDo{;6-2)P*lZTz#0_=|xF;xBT7D*J`-7q^4> zi$q%l{@k4>tNatphAU8Yd4tsXtZo?1hk`-&*QT&09tu?_QHJAGpUrvT#%mimlhD6W=L-O)WRuBfg42OV40gsFJM0fx* zH}eo&#D^-2sQDP>l)xd(1BjB3(DF|vtQ!RjK7dpk#(mU-Ow&bG-2NjQf>p&1wz~)bfFe#y~rQg z_4gFmmu`XvM{b>l zpcw2zT0I9C6e|}5_BF*T26{k>bn_`Ke`5K5WiHFN8z+Jg8(@M10=1R=Q9%zi<-_#g z{QCDV=;&c+-$?KMVmy05p<+DUUvm3f1-*ZNG1$I_GNlKTiQY5y?T71EAU?SyC=dspsAHum)~8=)h8K#J z^aFX2!`=#{du1=C_E=8#8%7Gs_A zxp0HW*A>YL?2n(Y9*!mn`;t3J*z3`zk~JqMpkTx3y_j4U zTZ4#6)=>U3M%^L~PD-u^o+a{^4XP_?)`2p6)DWos$0#V^_3GGAU9MnDtT!UWMFpT`o&_1^y zY#j~`xRpxt!eZ8^n}t*-aNW$l6}hG?dRJc=P4r5jYf6eW*OZhD6|9hw38ffoHK#Ab z!?RUzu`mYn(2JT-&c;|z2>;s{FI=$-Eul72m;Z~p9%mMu3C>Li_Cdj@i%cfsCbY$U zUqM?4rwc1atCVNF`YCN4eKr4Cn?JVUL-7B7@UTdKjAs;Y75>&J{88f`Ee0lki~ZYL zkL&0g#oqNE4P$pFBAhV>WA`D>0R<^ry+8xle#z%-?2hwQTI)I7`S)UQ>pr1UC73K^ zV^?2f;xV;Epin_ci%*5I8&XNeuB9Nk(X%zglQawg;m^S`!Y$PF}_A)ci9yAC3R zh9gk|cCo6vKE(D2~ai2e@LM=gztmD ztcUT|BJt4-^5n=ALG)Btye*|fMPiH}z>}*c%GWqw9m?m1;bw>aGSHv&)^7|?(4QDC zF2ixUQ$P*%Wg|zTug;OcaIx%$n#t+k|rwuA)lI;}PkH8>!Z=zStdmB6mB@RPu1MS`(nZ@I4 zbFEa&Hx#sCrW~x@#f3>z;&YU`Crte1TU;mwOPI`2vPu*wi~kJ#{&(o@#x6kMbI>%nUdU60<^7)_EZ~z0dPmVuT0ZH6Z&*KF zKb7_WW3!o}=ds5dM!4Xkpo)mdCyjfAJGhK}o=z=``IJvZd*xSRgh&zFR+3_;YS<~* z)DCcl`GZmXC5_66)F{(mk^}3ERn5aXKx(m7p}}7w4RcZmAZr+0HekCd6b&vr2uf#) zDwC8${IW=OLp(L9ZG{6xG^xc$?+Izugm9LHeW(>EnlE+c zQD!xxFGU;{E+5^T-iL`Ho!%jshJEo7{IttIJLOr}dAWK4krIg{==;~!^I%T-fQ?Pn zKS1fvxHFXKL5l;2AAf+$MYn<_D}!u<#y5t?MREcuaNt`CZR{=<6TVleT7V7679iij zqGOsY>J4mIpjfQbftwB8RFlv|^|#PVux1GU6$PEckV&CB?#U$>)&5cZt;ei-Im&H^ z6Gvb=SdO4OckT8G?K5cNz_-Qa4%@LQ{;Ev~}g7X-5c`=bW zGzq_*pNG3-jaM^~&ma(1hgx&VY6}8|TryRYh(A&3V+DPN!j6)SBKnL2eMW*lV?m$s zpwEOT^y!21)pUBMc@w?_eK<kI*L z0=`%IRkPPOKg4=jwI6^tb!CAGM2|!IgLeu+S#-jkGf0WsunrB=?bu=5o01&Z7Eo?m ze25l!>2$gQ-#p+8-sZd;_&Vx*^J77Ld1kz)U^?JCIUNWxqCjv1&g;@jONvH-9vgCcKp6 zNG`!kX^rV;Xr-?>)s+0)LKss~fvAgTjPnVHWQHOlo(Z=H>U;ubrI0Q%=C@0}Q0Ee0 z4yN2raHQQfiJ;2816KfNA{0DmxA0+1DKr8@+E!|@2W?15({Dq_8o(=}wD!ktF@Ml@ zp`cILM4Kw1(cnw9dxz0{2dHMxGx~J5eojQo|70l2iJPPv@2G9lmegu<87OFOWFTj)qO%vWrpx11h2n8*l zq?Nc``949GaAqxnKFSA@r}E~UP{c?2+Q=U@t*4*D$mJ&T^htgrfCr3!d7Js;2@wo# z#uWynWG*lk?yH*Ir+Bv^8)hKH@$UKuqw_~Fe|7;UKB)OKGY-Y5DSsAx|F_WlF@NWM zf9U=5^s|QioI&2nbDIHq9|}7*67oJNN<4CqU0w2zS>8_z&zI#Lq)Ff$RZ#2;jbeYK zHfsS*?3K?ruc;UN4e(>p4EfVxZt_$iaH^UM*&BU*3}RWHCxGaa9j1xnh;!+QP`y|eYyoV?10tZb^f3!e|rLnvxdj0Z| zbwPjpskfLQui}rYlE^D3Eh3QC|rugX+0Z z!Gd_Y77;f08PVOw>F5qg?2vCv5}2e)pq0`iO80q8pP|Njv|?VsfD+lwl4aE&-LN)@ zcc{Yd)7XOh9PDC~Y3N8Cs2WX^Dvb{)WfX#pBg&@R-yBok<(o zQYClgZT$7IN^IZXNXuE}zPys}KJhgMhB!qzc3(($(Rk|gH6~B&9vuEz3CMp3qG0$bf$7#1)cmAsHqD)obin;qViDd-uIc$Sz>Y%~_1qQV7N`1->+prfnJl-|YQ{W%MtOn}vk`pHY;lePB~4RgDTPu`9EoAwGXfe141g+y|t66Y)s|%>Vp^VO|N4(Ee_8vnq|+za2D* zczKq1xeH9WuTl^#68@Ec#uEHX1OR*PWcZf~&Y3~&3tuUWbL#qhm~e^cv5x3bq8^7w zW38hfGyHSuh0f7l*d$)Kl3rLD4XHQ93;X}v8t{z}{1%Cnn_o)1@ILcff)|uQ=ZVT`aq#Xyv>#(RTl4y8CYoEcPgD9l8|A~!I*}w&K4J>o zN$rn`#+KFM1to4jnUt3IsC*0B_7hn;kGw5EbTr;*%rqF-=a6 zVwl?jX5URvco9QcAi#JDUbAl^5_wVEyzm)=@vVvJ@VscV>j*ZJox#NFL3?4$V`g!P z=<(|hnKHGh#}+kFUKTyJ6j)p%dh8CwF|wP03@bX{P0?iM9?^bBYX4cF92KK1(f;Xa zEY4rv!BpA_i-h*aQTrqgzJEcTN5EfCwErl4Oy9+5ynXxwMsOd!&@~$GZ4oa#9)qEG zgEyi=_~2@$`FjGwECJz^1g3d42%%2agwZ_Nmxpvy)CO-54VpxQyKiTdx8MpWPooAY zPvtubvxmPqZj57pg(TS^EB8n&Va zK^z$O5QNBm(L4vOsG)-x2dcF^UzUPU7W5uL>Q|RBC0~Kd?i&^Dg$Kk7{r-s;VjvL_ zE!-|%h!al#!}yjkJZmGbYhgWBZma8t=5;NafpDJHk6_%J&lLU>Lv(6UZ&2G4u6{hNM;W`uiV1 zvN{^Ye|?Xs(1^fV1gjqb_t)YD6UGeP{Rz?vHCC=Q*7LzRmQlw!!x|qFCfjo>W5aB^;kSG?>U~S*|XmZq4pm5zj3B2)w!jUrd z#6v7oDfcpXyKiQKTqD|_M(tDTiO)oh3f?((l+xsHd1d<3;`1c&`Hl3sm_80!J074U z-<#3A!_99oz|RoCpGH%&Z;2PizRu(I9r%C?E`1}Tc_jZ3FRw>YukWj99C(X(p@V2m zrq-GgvJIlOcCC1M6SX#_rm>!Rg2y`kUY1ACFeYZ*b6bhKvZ#HGLL_&^`mk0pQb0a? zlc_=Q336Y9F>H5$%rtGlV)w6ha+HuZhJm(cw*Q=|!X89@=+ zE+csmWq4f5$gU_P0HmcyH#lqyu$QdG=%B94KVw!h44hm-kzn* zF8#&(!^Qh8CvtaxU|59g(SdXk*uBV~Cd8s5(3d83M;;9cUQCzdgN|TsWH4ZYZFm?= z2&ZPjdz^9_btg%C`=f&y!q0hBk{3{qksLtFGHG6R!1&s}!I$gl7B-~NZ~HRQQybCKmDH0+`|B0MfbsRzp3J^u(In!Zuk(;DKv6sfWH$&ULe1NwX}?+G z<>TVzx9MfJh8?55Tr6JhE{1wGz1$oS_>%B44IM~}lPcCCyQL$oA1DCfMgrk~4Peq< z7{{c2co36z{{#lLJvB&*)M#0dgHjO|E1$+sVumjEy%CKa-+7I(PZcok0V##2tV#F+R)hQP`_M^!2hJ-aYg(afa_4{)uV_er5kH zt-k1MvFPih=MuUOfFuAwJpmd<59{jrZWj%v3;EEw zq9X)6=U!k@G>Hb=2zXwk2FWh@toS@aw0geEbpGT7E2$~;a)grVuXLTrV}%`w3@1oO z#jgKR#;&oz&ILw+4tqYHv1_1V=bL{n3NR~PVPMX4@m%uHKtMzx_wass6wc^UmkY(q zpNN-N(#tfL!80V-y40tDicX^6cZTcGp8Uvfnco|NM3jT$B(jLHRa;x_JcnmAagGXDd4b7 z2o`KIO&;j$Gvj!^s*xC}i1|!iJyQ67J~nF0n-&lD2OJ&l;x2!Dk?C>>f7BSBs6&&2 zRJ>(@#ZtbXz)T_Pk#y~c*JHLUXSz#Ia{KFE=k}Z93UtrJA9Vsi-+moxf2O{D1WRe{_5b_rwF$L1;bCr%d>%E8thE;#wLKlbpw8P+A3aw%3Y{Nfe(7;F^Glj& z|AD*EzTV3g{K)mYcF|Fd{HWF6<*@gd_F*3mbARJFGIu+A13&J@A2lkX%$3IPyxz+< zmI?ir?QdgGDy_e0|1r`2s3qL~3~HYeKDLz+?aPMtX}(*VUyHuq!#MNpzXpU%}`w*=l&c zhQ23;sNwn0$MBrAcksDxzKj=ew7~v8C{yG0;&!93FAXl`A!)t%0PI%B6&T}DCzJ60g{@r2@P;7Gj3^}- zQRS13UyJfoVqibyhhp!9(1-9#%(^Pz)?-yugYxUqd!PFG=`yxuouSh?X9&G9G|H87wrw=-&%n14!i)>egyF! z9Toq<1E?e<+J2WGJWWb9?V5$G4|Yhb4|amE7}AGE1W`n&7L-@k2b~0=g}g?E_r{-s z@E#ZNCWhc8f06WS_o(n1`BU9*5_wmg*+u(JX7aWMZLr;B7JA0CZTr>48{YO^idgH+ zS_~DSu8GaPN3iGG+k&*xa6vEQv0Dt~$*DBxQAE|n(46B@ZktequP8jc9)Y*EBsNJF z_uea_kWrzrt)UDj9Dd?9te2ib6;}j&Xy?0F01o)wg+jj4iQm$iU@$NyRX4L$JST`3 zATA+J3vK?V$rpCM!*-D5Iy3~xUPPA!diBc$rcI2KQOXSV0aYEk^-Yu6^-4R{iz(S5 zkNKgUun*6pWy73+BuBs-p7Mbg#VK-GX8?W!tmGY|6r+;p}yiRP#Q3} z;d{byT-}Qm!J7aK`afCt^VzUEYBZs`SEK<%9M&H@QBZxwfjgKiLyh$n(dC6jg7@qB z8IBO-FA<%q_8ys1mX`*%N0aYh{ZriSprcrC*byg8)L74CI4`J=W|l+x$MF0P!jp7* z4bMM$@bb?uEx_~3*e5rAPg4vvwC{>|Zsf1a?RWCZi!5JP_hA0&Sx6j}_9_6v*j6D| zhS9tmS0MH@f|8)HtyGm$kiRghVmI^;YH%FH}H9}vR@2{k-s9==VYrju@C~T zea4!+VG?Suus$zhea;()sNhRmTao(+Z@@)Wy<8jnve=IcT4W}YWm>VbSQ!Z{+MX5F zVrsE-2X*%@S|^F8$Hb+6ea<2{2Y9mfyhSTvrU;c(a~qQA=<9Q$;s=MG_sc9mZTIEy zTeDxok88`e@}+Uf6aaepAS05euGP8fXTH>m%6gnJpy?28j8)N0h(z;o1JGEp^ zL$iP+Gz`tC@>%q3(4PG^kBN5n0k8~BLuKO5)dZ1;np8 zBN#vNS z%Grj)38KS2Iu@cgZ_2Dk`BIX9Qm(=sJ};z*;m8&d<$t^X=3p)A<>Ox5zq1sZg46kZ zKPj)^4n5gSkkLtrytUzfqyGXO{#{5*68@t9iO+=aSNrd6=pXjx6iV1p3+UVbAN1j?%?Ym-1ef-nc zK#H|L&c~#)N8uD>#MVjjyo{&lXZ5^{NAQ>abK;O#JD)R)Q&&(bMRpM@&_IPi$}+&h z-xpIRSzb>k;#%$18v^(baN(Ggz#tsKblmc=2^nt5Q>T0rPVxzClH@wB22iX7jxNMQ zdPZIsNVy)Z%Der0i3y<^_A0d|9SyiUn=Iw8p%sg@XGXfk>d45pSO;blSh5CYOtNG- zGDcdmdS;+F75~sHLnZHLjEkjyk(q9c#Se_1BV&dn_sf*zB&oXSJiw+yW1KiD*2zc3 zesLlZga9eM#dNOeEoM(#pu!a^<9Ick-APh+?0jO38@~ZgSA0%~x@OaPu6fjT0iB=& z?UDQ2Qmj3r)Dx0Zw!q+2c>_+OawR+DU&WEMH*7l&XDqI~Vn%%_uu+oZN^5bqH}nPW zif4Yn22wd&%ivi2LhnbE^ zDmr#Ksk9cia+i~+hy#gz$1f5~9FaE!Qo7?NaHKob4#WUlBgwIpze6aBHM>+7JN!{BKjp+%HPFr!0l)d<9mf}gBIqPnJG9p zI!N`m6Cvg@V09JRKBuu~vp@}+mG#g2aL_@8Ydh5k%OJ?2j0HS?hY4-0lg8=DnSk8k zd5s_V>Y_W_XVeP1kRTl7HN^PNs6$t*tUaC>1WictAYk2tptG&GCRgUwQB@93UrG`8&`**Ww?XVTCU<@Ffwx zITQYuKF|d9xryVmF&0MxDPQ7NG?rV3`=mr(b@55P?BCFVHCWY;>T4Xrc&#KKpe^$4 z>KK{D7<~k6jVq!qY}yv^7wHyFS+An=cJ+&<=Eq^0GQ-%=_=twioWRnmxZ&YTt5~6F z@P(FU_3m;wtd}VOL|J!B^zUIxGOr71c-6nL%fI7bVK@f*c=sh5yR<9Hd3I+MG$SPG zVlnTxA6J6?_Q?~mt<+pB3bJ_?yOT&UtNso88w$ImX=OSOK+zc`w%3;BmYfQ7^&)ah zsGavnI7V;3*nO9*c-vK;u3b+*cHeQX=2JV78BKw?^9`!Erzfs<`O637dIZYbn zRQLx=o)K1uXL>3frPwPc;OunCrS$f6=}ez0yCF5?mf;lbYy5|zy!v_YRnh|DRoCHV zCgBpH4Kx4p%_$d?MA~5BufaaD@xy`9?rs5B3LOa*k;HL$M&V3$av`DC(rH<0Is{HR zyy#@WM#{MhnW2&Vv)Hx}KXDvkG2JV$SyuGS$QwgSlYibsKWp2d0Uh|!oPK2DM_u~S z4nM5)BO5;&(T|S!fj+NudZwG5o_npfh4WYqq4^}6XI@4b4PkXPs2L!GPQq!!={B$! zndqAUNCz~CANHVb4inBZ#z_mMnp%RS3N}O+5HNjy}|Up3>!BrvT|krw}a^*)?ISO^~N zYpsem-)avOTBYhZ;tMf{d>fsoe$xX?{L~=vm)@XhsE|BRH`0_-WhPpV=`@Jv$IX5lY$U*HbPLFARt55*Xfy^?ko?uZlHrXaSSc=Q2SlI*!bXl zQ6-MQn{Bqo&BoN<1=fFF+7JQ?ioOS*G8jDx5C z0CC$~M!dy$8rQv>t0AuH1lGqy;5kg)D+pb?XPVXC=?2#o)K67>wo26`qN=K5yzw`H zEo-eNCqT0F*e#X+Fk_HihD&j_^eTpx#BRjn!pSIr&alfECHYEf+y6GSuXz>u5|aGA zV!!FvfPXijeXNY3oxDqfHqbFHM)~7XY|I+*?oZ0@i?Kn|!We)*U?Sn?3xFmZu&0@ot<<|C{u3> zj$(*^K?aG*aF)h_^ob-RC>vrXQ>!lQuC|#4C2dv;YqF*4LTh?V%t%SD2RC%(Vo(Od zq!bNEih=RDSGa`3|-flJ9ngO}%?M zRlWP{7wSi+7-Bs3!cmZ9_!Sby3CHxx+Ym82<&DZqH~kjydBB+5?xUZpKQ>Xf(4;sZ zYA8R+WCC5Tr9$g(0e??^`5KKZv8$*(@fA9S01rfXiqrb!?hwH#xbB%@!3ALJ4JWO8 zrgCC7ydIzkMgg9um|FPpG$^HNf98+OvN_fmS1XGZX9MrE)Q7|+x88*^Em=aFd@v~O z2=VGJ=%Zv_h}sF486Cr;kYk@A3d!%sQAlQR)$#zzGz1BQeg#g1R&B*una-?@_D);v z@(!n^`)<4YLcHaHy`Wl8Pve!SIgRmshkttIR5-HM+T?9E_kKv=f%Euc>g{wysHX_0 z#g9N>KE&GF(>&3h^Mk{*&0e`S*j$jWhPWjv+qbYd^2nyO2nQiXhMI*DfF4z|8Y{vmdt?iO~V{Fe(8>cq3n<~0nmUm37+!u$addFd@)+s39 zJcrz`;Ffhc6}@se+D2oJPTx;Wv8-sGsJ0{RIB2i6huU#;+CA0U)3Us|XvDtbptIJV z?%ujzY2DSK_VE8sYo{jIP22phfFP-koUNbTbQ%&Y65n2+Q#}u`6MzX!7bTR6mJw3)q(`FVX?9y@`?`8etkFjYNF zAVIp#-8JB9Oyfks5WNtzPwO0>IjMF)A>)sHQ9@)w=PhG2jwnlulHkk(912Dr$5-z2 zv93?aKPVvo04chG86zd{#~BrPX2}{14*^NyEU4wt88fJX@&=azb|h8Eti?zxo6?_{ zm@+$D`tx>AFN`b*c!X^BB&q{DeD!G$IR(kSq?)X5(oiMxE_%AAK%o2M^@w;F4O*8(SD$S+m93N zn??HvakHlO$LZTAMy7fZVqrV6aB|yu09zE_R8M4JH{*}GW+p)ZtCV(ExsUv7QC~&V zGj`9Kt@H-Mg4&X2syWaQ36Bm4a0!0Z1p zXkA2oDtYLWG>E3u-vOpy@v>FUEDRa_3@DBu>PR{_p~1yccN9|DvG;Zw{N#Q2Y6 zzNc@2)VZ%T6*EtTl%(I7>ahmaBByVa0?73CE%3*ZP1E3&JoPki6^;741@U`kY?S22 z6c7-!rAeX-+DO8(1VH04MK`;N&Wfe}5YV|F=uEQ?gNq&B?k0y^SX?%HDASmMZc?yd zI)LtH4SEOB=y~*y|Ci{g<}11)Q7P=-!}~6)@5KAF=_T>L=ko6(53b*#gGP~e=zuJ? z0AHI*uh)cFR7j>LhpeKZH09Z*P(l>w!d$Y>+9%1FR1fax^;n(oH#_AGn2Uqdz`N<&$+EogCbr+XLmHA2g-Te}4A499E%wLWstjljcrpLif#&~i z)rahPXit)p=ZYC( z8c6BakwU`H#r5+uaN8k&QpSJY#qy3APr|$N8^nOm%lFWDcoUw$rQ|`EWQRSuLvkrD zrSw+&hYtoQN-n_kOP7y{*m1Mm;3Y10T`IKk}y6cp`_WRUXujY%>7(PY)q?bSApVS#2p`*!4M$lD+E zI>qfYBbD2`oRCfFP;wUIk^EMDb+l|NX}FYs*f<@M7voALiWK03`FMrLQVFz4LVQku z7Wh7=JSa^RGlu;%3=0{9s^o zOrc_2$d7_X8-V}!Nd;ZaDk+7|6-O)DJzvmlFlF>gEc*hM<&Yi>>>m#Kr0zA}&SmP6 z$eeEz*294$nDXQ1V*y9!8L6ddHcz79_S>0*mG9M!M8RYNOchnSR3V8FF57|6#E__$|F% zzTGmfA->D0DC?4Vt!3UfbTd#Pby{ngcLBfsN|Y~K-~;~hHr8AQ+A%3f0Qg9B{ zN=_H_Y32zqEM*ZOG1-uqZnL4^yea>D7gmNGP33I2Lp)Qp4=rGNXCI3YeS%T|c>C-k z_3_r7hWKC$`S#%F7;1>8zJ&8Uaq^H~hR zoLw3OE35i z7LoOQrpv*Ar4DC3DHzyw7|Y&BBdWtWN$t%>X+ZS0qa9RfN5dQbR=D)1t2sjhY_H>O zhb&}^8knTqPa!2l)IEqJKk|3y9@7NhRZo)72PGeVKZ0Q7q^w9BsdKeI-baG`8wIC1 z-%(44SMkSGg|Qo*p=rt8IZ(O+mgv>7gm#K=la}wdr14z8;iFd>!gI=R0~wyOZZUk~ zyV$Yc(rYW|Hf$8xqy#7ZvGl5BhY8h39-L7wR|WPPG#c9j+71)-ay&O&go)V-7h0Kal1u^w!9wf5z!(yU zzx}$8J*9LAN2-bD6Reii1#u>0v=b7h~nC%(NjRr|IVeG6@pTcYNXbpDuK{!TbTnj40=cC$m? zq-;D+Q=Eug*dudg+G!)h8|*YmdQQ3J>Vr%H*Y)fk>6|R~h@q~9M+}`!Q*W9_jB)li zyNqkcBIbXO^MjPHD6q@tpdXYinC>H*5C}-CdWulCA*eyh__pc`G#O|{g_YflgayV# z?H8_NwxxbC0FbQ6sjJg{64$`B0^O+wE{&Dp`T})F{Dhe@)AGl*+=N`i<|pX|IRA(`${y5?r+Z8I+XZSijP z^l0x^(p`G@M!fqOU3g5K%Sb>j!(#$)nHX|7jGpN*K$!VkpXr-5_aIC`{!+Z{N1;Lf zEN&SEoJzxoe!@Uj`d1mufi55HK9=s3zlQo1Q7UGf9A2mZ#3v5XXnLhV37U}gCU<%#Fi)=EEAs}(f3I6eT8)qELm z1P}3)?{i$*Yg+C1=@bQ180k!^b)5n$Z+rLkr7O^$Z=Wxy$(b~U5pOQ}hK7HD6sEI!A zA^%nS47~b3pidyC2KrR>`w!@ollSk_CwYBM^ohIWze=BuSN#X{*&EnP5qG3~O}o2B z`q27MPr}8kNu8ty%blUi8#F;w#%dOGO{AY)G(QYY2{)GuH0WobmAfTr>8J{MEFO`G zl6r>}GDJCS{^027;QT?mVdS_b7vC5@8KLC1rH~1;SEzH8yp5bR4@T;YKS+2INx!Nu^h;95?meybg(<=G~B;)1hx%t;*7jG1ZtzL1^+vLTT#CF?Zj4dxu2i z;o{vVU3i*EPfhE{@TJ3-=h^LIxK>)Fazbun3VJZn?1jGd=3ePRhz180Gen)!e-2c| zkv2}h1!+NpKRd%If8(IE-x*2nk|BAX%UA|H$e$_D+|KWnJv;Y8ts%*bP>>y1s+S@k z$1?9YVNH>|1GxZ+g8O3J!L8vLLv3ZV5Ym+gaE+fPlhZQ`(@S5w($q?+fb#O=+UJA0tWYOCsHLe>Kz9}FJiJ?LY_=fr@(|FQ;LokUH_O=XP1G-U$x0gTuyU^X?`n^w4@sW*45>N>9%sP+ z1obqDUV{$D90Jt)NGNm|P67b4G0^G`c?_&ymkeb}#if7`Q(R>4hTX!ERNziEk^&)= zwU#(azQIq61pmD&0Y1#b3q>JL6?QQcAHfGAKOQjyY7vR{*+hE>Zsl>M+;UvONdg-< zJa-`HGv0~{G85I01;^l=lD34#AXuM=F(||s6q#amrU-s5`OSAYRD}}Nz`_+$DZNf5 z^f{&CF+<}ZbfJ~oB?*!4Uj~eEg1ASTwwIQggPmq+p&3%ug)x z@bupU(In!*;(uQvZfPDV5j2}Y6Man{4N2md>Ui@_*jlK_D&#OI6xTNm3WWzOk`1v7 zNe0B^?@Pu|r`5}*;b&?ZpNS)efKHuScz zByi2yl3*TISQ1nKbjb*$Ty+IFP8`4+)N!}20~{#-{plef8Q9`_$p32)v(0o*HEY_K ztHP8{V~%0?L&fE!+LW6q7Za~uP;+iKEDZjoZv#`BmVBM>dC$ImZ6^feq(=; z7A@%D0PmCi8Sn2t)bPGFNv|wG0kWT%LKf?b;E?Io7yU2d-UL3%B6;{vNCH8@CmeyO zpi!e6R1}n~35RA#0y8i{yiq}MR}mEvVZtE_NoInX4C9F|x}K}gww17cLiFrT4GrD1V&0 zH;AWm(bv480^b(V_hABK|%dB|g`uM=M=e`}>@STSNAq>SrjL=_%s{4~V@P zRpWTd3uK3zaCCrCM&$>(gx{`0len-ja9Vf;si&#EC7ciN$jcMcQHM*H`MZR^WHFH6 zqib69TeMnnSqtPILaO;?JFHth#sAE{2L+v%EyNY(*B#}^-bQUUdNF2Gh@UTTPC+_E z!PQ$#5s;0#Sx7c#;4-wkG8?0O!*?W!kyQz1oBY`RwmUGP&?TeKIcUgqVDof$2l`&m z12)!h?gP29VeRSbV8H6#Z^SLeq)PuBw$nL)5H%`sa5|z%C2W-ka)l1K@USgyZcE24 zK*l~2tWZ0OiPT0ks2wPd^k8QYM;6<#mCCGnad)ay3o5@}P*v6Fg;WfJ@bLpwp{xh_ ziFAQ0h$%jh+dz^z4mj*4tWqVhvTlkiO0nyBC2oL{3169gr92zEfwL9VxZ(`gP|H&c zYEB@~h~1?t%%0iohA(7QmkN!$x<$}PJiB@m>9X3pWN^F=t;WBsqr^oBM||_h7vy|& zB}elG$o*#Md^sW=IUfz!X2;R-N2EXR3feuWv$Z4A@6t;NN2H&UFTUpL3;PQJYB{g6 zCqgaHBh*UuXU^AEh@@z-_a1J=LaAaVv7>*e;z#8Nm zC-Xuu_r;5~a(4))Oa+b85Cv)#sLtg_Mnt0b${DOv)Xq&bzDd&I_c#8mPQ6dyiewHB zUcMknx`_P|lhq#(G1^5X>*k#j3N>pR)*9t3YCDv!@1`y*O7M_*ifCK5Lumv$RbN_s zeJAVsE*O(oUtNm&E(=#MH8!!n zCsNcmD^-0H#PE93XyypEgKZw%yF>MHmn#zMJSRn+$0yh6J*!>S;faGJJys^h=L>Wj zw_}%RbqV~V{b@C z_vw`NCHKe4y27kEi51qRsPN)c6{g_7{;_f~^1WjzLJXOk*iLWNPKrD|_)mln^uT~k!|%@4^K+xnAHyOpT4 zDu7U}i_@Xjf=jjPME|FGN@W)!c7!2o`(>=e{Al;VtQ`x)*}t>zLISvmOOj);Y(Cqg z=U>cVY8N7LBosaZ6gd<_i;KhyiUkY0cB2&u7DPA4;3K%09jvIBaHj^ritYeLHe)&% zi{zwPZpmS6D#YES$i4|ZDBh^gRVY8?@hl*%k2zvNY=~Iqh5uIMdyL@SR_El*Q}JkJ zR+`87wjR)#gqydky#w6IoOLsqM)H@lKU0}Yu_IcG*nUZ9^LwYN_Eb*qT0?YZmuR*7 z2#rg%$KpL_otxa|+OJi$KV3)W<@(DQKr=R}%w@#N{%cfZa7R=Z+_HN^<64UFSB;Mfy&aOOxSxwM?PATY&yD z8Kmb7mHBZUnZ1%TyA4;F_X!mbVd;?o)h&mr%$w0Ctk04&AKf7_IkUn*rS9=b`0@|B z+CRbM){t_4>P@;*`4- zUmXppLxih|8y}f|m2(e6K+OlC$q7~a^j50pW38YV;bA?`tA-0&hBj746|R4rDI@eWxTLhtR$AWQP*)QU9F5tRuLtX zl7m9D%NgitEE>TSS9E5!n&NJArhhM&1;4GKz^l0E{Gg)yvs`{<)ha<5mwA?6td%}N z=3~j34`nO5?0$+&&gRf1Z|l)0)n0I>Li=7q8S6kev>lJ^;HGHW4 z{0t(%TZbptz3Nj1@-GjQ**Uq|zYkFjcjm?rYn}cwhU~v|X7%66%ulZNN}ajvNixfm z0h+11@xog0QMYj1m;Cu`{rTha`5*M>F>)NLGym}zng2-6{AREMc_3jvt%l@G?^lXT zo_&hnBb>GXI-g z?XnJve6Mpqnzd19#t7e6FFQVv9^ah&HtIiN6R4>RzD#D47{Y(oYCch*ZmE_=#MK%NfEk2y$L0M@yaOlD{3P+y9jILmUH$ z`*xttxt;ze)>wSb*=cf%T2>ZJu1*VvE+sqGPY>29d?!e@EC)h^6TZ&X_5Oh%tx8&l zdMA86e2x0LkdCxhGR@{l!uQ0T7mTh4?w%D{uk4${dgUG4Ln2}iCU~j@Lw#d5D-bNf zSIyMFZ*Zh2ws_=8+uKKrhY@}#GjeM7R|EF6QynT~klHO4N0)nU6u0oQ?4k81_p3}N zROjp*_JF*~y-Q+`)^J8CJ?%}T7z636G+x2p@fM>a&1DS5$z`K?E>-x=g0nhR`>iI6 zoze5Mb+KuORj+CsTHookq4njbrH3A=-h5W|s%rmtP2Y8@`7Mlt(v04v)gNpcT0eji z?$gqxSUbmC2(B~>eI#63{moevsBZeUYiafBU4TeAkCbzt)=mm%INlP#tTGBG(Wep} zR_IePL(}KM9;xWVUAP>0sM#?F{#1U=L@$VJOSLn6%K#;|&%|kTPH*ioeB2O(!C%hv z_ETrc+R1isHbl zbM+2Vr3iiLN$9ES@ICRM|N zf?fQ!!Zs410@)m^X<|i0lBKBKnV#d#;ZltBnYx1R2h;VHSmmj0uR9#YVg%P z!84>F{;|L>2Z1Ojy&kIMfpeZ!oHg5M-u&oS3@B1Fs>^1~Wlq_ZQoMCBw)m%T~uXc~GG);ALV> z!u%Y%*!x@687;%cT_lq1Y+)^YS(`h+3*s*%ZN*6~XJCH8O4XDKH{&Z1F{8(nckh0~ z_aMauobkd+{<6JE%@CoCqcS+Vo=3Dg;q5MEcrU@}lr80iMxB#QaHJ5y3ViBlxzWW} z@VsKntXY!BISr#usq4YqDI{=UM}%TEP?!@>*rN{c*7M@kY3WtxidcW16qkQE2N@!> z!u*0qNE3wf1z~&_W<-(ZTancW)wiW(s+U*unw}fO>MmVzV;b-FM;j)HvGVWjNM|D5 z5}Lp8V4J@o(mZ?Li0XP4#xek1{`N-QwLB|#;K{q;;j!wCBO?+7z})(|oJ5(g!w+D^ zqIJszFkP11GEOx5l$t`6e^JOCd|bB?==&#Ndu<}$;MWmeznDx&F3urL zYYsxcf22k2J-~6W?25^@vT$xt-N_y1^GK{m$x6-zSLq~9OkF-!% zenThnM+Wx#JAVxK|5ib%LXy*+5^MqJ9{avaTB+|_&#}%3yHyclZKGKRpu|6mFx`*c zH;N=T#~uO9TiKj2zv54lJg8Ul0DqzH2^i(}FV!P7KuC{>8imKtp%~l=P2lveclsA7 z6-a!nvmF6P;b5?yU(g7S#v;F0ekxXyhuwaxoJ-#50AoOp$2so%_Rh&cNY;LzPz+CjuoN{xLcpK3lA!kKpKz z%ns+CvP&kZUG9K*z7vYOWP|5A3gd9I%IVLRVDYe6M+(W*nh#V4GrDLT1~Ymozu=Zy z;ma%#KI|G9v_#0N%TnW%$dHS7!iYaJbGB&eA#x&^nb$lnzEF&o24^2 z&bCgHsPO+Rm40rn0bo!h$>Q3S4LG|$lzZs znuO?YqK~BU8_w+w0D_~u3C@!1w^WUU+(c0L3O3LgPX7a1f$1{8z~sHW{^f$b{MOGe z5XbM`BBg&(=}Qat^D9EHQT;j*I9h3R28dyJ&B}$6Op>&SPU<;d8Y48xOjLRr4D_x2 zjy^(+N&$D^Wd%}Y$=|E_u8PBvmm!GgQ4UpX39lEO_9#f<(J9t7DcQp@J`ZRL^W-`rD5(grm*rbGo;J(3LLpU3cd{I!*3qUmmGJGX2 z{(IlC5b$({kBBXAFq{OR4XeY5M)xT;v;=oYSMdTugg%ssK zzP0N}0gk|-o4$pneU0iO2%~OdeA9^jO$r3@{ z5HNfNSwgK9%$5KCgZ?C+mLs1CkHE1})m9kIRP+@_+e^zfcG8Di%)@`-j2lJLgb1or zI+XpF6bY{rESg3G2~#ekMhg0!gvnz0#WNG{N_m$4mZi`x`R!7=iPhUKRpD!bgPL8| zhvY19gG*Uu~3Yzt{^^*cd2SmBCpA>GBWl=;9J zux0mc_0mULLMa(ub-H{|oX|%yJ5=PW$wHo@Qv@JoTX(Ce*=DwXE%;F>ayhgit6Ui< zSX0b@a6gQ#6-Ymzg1Pk2FqYOAOebgHPyinGny{a@PM zo`R`WF_=2|N=v4ei8p~@rO9)u&D4>RZEoNFZP>b4)=7aXO#<`$b}~Z~h02~v|0p2S z6^xX&ChDqeYrsBXSuGb$Kefw?OaNxDyML4u=pt4B1oyZDMWq|GcaUBKVL< zcPK(}{==cftsG5=R2vbu5(qVz_3RnwsS=EbAca`Ea?Ay9iJ&v;UZ)1>dZ|f*?})e* zc6&sArL)C*xMv2jqL4BXWM5MhJP2f6{&Cq7GhJWdk!|W(SRvYN{noHG;%A{Lr?7M1 zXHZ0`E2H?a^bQh4LDUop!JEWjFm`JFK&h$grCM7}UB$B+s`qb4J9wS97(g>fauUEQ zIyg0VcW|>vaS}__ye)GN13?>{M9f(C?UCAa7q|ji8M#qLxwIzA$d%G*5~lhjY3@SF z3JzKD-6#BXZahuJgDF`hWQaz=ZrHOWjMX+cWU?-Gzb@4+vDB4Psz@uzG9JwP9%ZeL z<~ZaG{n?-OXJ4#LsJt(qsY8QWHJ+=fQZ++Sr2ZQg*^@X?C{dW|?x$AkA^u=t_RDz{ zbIM1u_APNX- zR#z7%T=cnye8cy3hM>q*PZCORjGVyCm*ZABZe*YIrd}Lye)k%(&eyAg@vJI1($wgw zmWFqAL0X`n>(s8}e+?2}p zA;M)m=WNeYa#Y|5WCzk!^e~heKyo6~#)yQ?V}cTdVnzw;te1#ZQoXc5&R8L!J`;d~ zMaSgpDSJGHqf>Tp$d;{L(#+nSkvq}g{3kQbR|c*um=b@g!R>#%z{#g>|38)1Br+V(ObI8&zs4GHu*UJQd%D*d-0g;;CJg0~;` z{(@r2eSSR)t@^PAE>@i71tUu9Cl!p6!=6f?^K=kZju(*<`K~}EM`J3AW%w$w9?Z&H zt<^Xsu#j+%&;c${Wu+tR6^iD5%Ut>+S{!3Zby;1bXc;-4LbWX+Qbx?6G6d{Fs0EYx z>T|#1IH9sNBSFiQT9EQvn zzUU_upZgMbSO82ZFBnP*80phi2^}kviqk@;Mn}F1Or#-~5vm8jURNo*tFpglNaaEo z^KX`@c{djnn#KMf>h+ht41>LU&!NRF_(kSn3c;alEsqJ(DWd8+JDn z_R*w-pp=^C6$%^82ntp8Q500C3#);G4@4CTeL*2KODg!3KX72ENGd|1E3^aY^$X|j z{Zezg^u0MPoymK6tk7T?i4^*XLJ(al*>0ZcmxZjBex^gd$Tk1C&kmqxC!a_%>|);4 z9?Bg~X54J8;vHdTx#9AAF#oJGp68CS|cW6Fd2{s=)|5vkP6L6{^S3k<; zG%HI+&d=secWh(N_|AZ>Z1KV935{b4TfJCJ z!@R{WNnsM?-3k>)VV`-#n%&F~B*~|x5<^=aM(ZKX(|EBqRnw#}SB`n4kM1nw2y>7K z+3Z+)PFCYwj89U?-hqTck$Zy>OPffHPVsD(0t@l2R+JT{g+9|YuJUfdO8c@l7^rJ8 zMM6J@U8pi}3KuBu=jIqj_gX5F@wY*K1r&)&H14h~VrwuS0d+Wc$7irP*Kyb-E~wq2n0R$Y{9!~mS)cc-*`Y>VaH#CyW*WCX zCju+j`LQiHf9u%&;Y|&PRqyL(_*O#ppyREveT8Xb+BvK-kfD~v@e%l#|8E3>_O zCmX&eDDr%I^}hawPddp_z1O3?1-Lz9mf@=>O?l%qv=2Jps@`{maaU90=B(_d>U|T8 zy3=X8VOV-{&J{-8;VP$Ha?T_j zh~^H^Q}$hj4mzZ6!(j?dums8Mm4ktNoD8@{jo!UC=tX1-I44w9H4JM3;{?xw(72Z9 zda9f$s+d}JT8b*Fs(Q6RQHXpMasbfPolaRty#mAex7ve$qf26SuTU(E5)NOePzCGU z{X)$+6|rwiei(Ex{Cob1-dsFJ`cmi8kjnpt`c5vK@q`yn&BHH zpN9F!nXT`X z6>0X?7l+EuXnIwTQezPwN}rf-tU5I9$#l;{x)>A6mA7u-CdEa>?ay4v8Hju8Ibg5P zKoAwtg(pBh^TOT-S<&&j$HhwT4-1HkW!^s7553tAKW^Gz1T5Ug((^JIs^#Grj zHsJTdt>E12h`{!6&Cd28j4m)!IJanhmo$}=EqjbNGb0UpQD!6>v1g?1_KZYr%t(>m ztZ0_rtVAuY$o_#&yFm4vOiQ{uWnO}KGN3(l8*C#gJNmi4`hpv%(ND91;=G(tF9m># zfnX;ka&&~=H>ffkfC`(uUc9_vFiS7cw`Q9^VcXaJ`);dI6}gT`xhXf1|9t{UdwnyVJ_Jt5aAaZqP|f(LqOyH1K6Q z+snVZ$+?67RNL(d-U z;qmzHrTGr~kZubPecP zf3SxUqc9U|f%lj8RppDP%<@bmOxvrYGHbrSVRBkp$0kpo#nU`fuZbj1zFHEij*#$e z?UvP?dF`|tCRcUR!Q6Dfx7I_t{b{A`co4+Q8!Xz~AXAG9=~npHALB#1MaPmn#EmC8 zQx-VW9hl4p#&?x{_Rq>PM+HT<{?+i^3OR|RX-Dh%*}UL5oX0RP%~CtdjHWY`b-7uG zddFae9ceO}%^ou}Ts$@D8^W1;RQ!o-;#M^b=;;_Zpr9(Vw4o}kw0=Ok#8?l%?JD`W zYOAc(S$0VD7j#_}jx#UH9OIUWO)4$ap!`9lfqMd4|4+C)@4uhL#^2r@ z$R!16-lAS(@uc3m$3j8cC#z%2N3VOt5auhSZt+Bo`a644X zz(BB`WjyATDsJH*{=@pUsEKd0r2A0<@d7S{+AU%(vqW4f2yFDWH4fHOrXcw|F~-Hc zd`=_g^nDSs*zz6L{gv4FguPXhDN(c617(^D@XrW0uR2EecZu77x=0>2@a?_f+z(Zq z(-v%t>L>@8VVda!MGt~g7Hb?&xna>L>IaeTP$6bKY?K1y(c(~8`?`Q zr#UEHvn=gLD1|`+M&4Q;oEhG2EM4h1rrG)Pr_Nxei}2yZ#psmbtZ6ERq|Tr(V~qSN z83T_ZqHs!)0T9exf1D^R7M|FHI8|bP{BFCnaw4mTS69`kQs#p9;ZpBAh0#tQr|(=z z7=JDC|KwotSL=b_jlb;D9SHv{g}=Ay5m+r_aZ1dO>>0uQMovwcUvTQd#yp@gzyH0| zm}?%0;SURP=c@#1=6-G`?ud@?Cv=Pv;VXOka{GTHpd^<*EY&Mc*iid#_aSiZ-u2@!A!2l zY6M>-hth(+gL%i~(sA9I?T&k|>IqbF@t&;W&Z$g9b}=p`GNn|kkAVug;)Sxm>G^cu zD$knG_6XwkuVBrQsn}uV&X*7s&*>*3XRzq|Y%$<>-ouZ5d0U2(7tLlCN0+1tOh(Dy zKixh0edQtQ`+Lvk`&_q?nr>m|nmmmB7H`_N)T~?PV!K->{z;y5`a7^f5xc1k#N&z99JNP{&AlbIyvQSoI zW%)+VNbdPS4-&;f4jZVeM&^+#vO0`R$2O+qt@&iP?aIbbC_Cr<+=1g z{#`$BFq|uf%snSPZEiRJ4DQ?HZX2)MX=dNA~A*DhvC<}PAJX5DwB?6*lQ+M?fX z(dHcB{Mk&e{u*0xTG_Z2JU!Q#koSRKzZPM_JUfn71cu5VA`_*}&(=sTKZ)aU zcw2?^%^kT;Y%iS}oayU03K%T<*YlXG>Hvl3J5Kv|*t$+XkNR{yC&l&itLJm@UOLRW zLMJq?T^F`a($7VV3QL^5sNlobsH|A0-<$jIFlO0c(H07auyGgtaSh`#OR70S7pawM zzSf^!^iMwhO+QcKNS8i58Y~JdB3;ZaRPfe=Jb$X6A71xKIOHVp*dDZV77q*fD&*ne z@kc54qAqs*Q#5`Ii3O4?P@KtwKIgkY7x~jlz>)!Nd3A!(of@yE=nV@o-%a8nT|PdO zhaK&C5TuTbRCl6OCugh_FgwXtLp(H)LU*jOF(2~;x2H*%xzKSWPke@Ib9uPvIg&*b zgy6HH&Cl9F7EoHO2Of%#W}xHS$&}-5&N0*0h+|-ui@q0+fU0Ahf!>2PBQQajO-pxb zootpJa{sbr{_N1_wtlw585m*+Z>o8Oz|to+v&kkqa-xRi+NC;E%3_N?oO>wQ!eODE z2^_|S4HB>}$K3rACTRc0ORW))?u=WI+xbrO^oeTA`cmr`&UVEZ(mFDsxNR?#vs47W z3=XMW!KQ3IO$ubuec8W3DzzbDZ%1_y-&tJwucoxqJ3Ej4;`tP*3@*y&#~GNNFB9kC zE-x30+$Jsq`WT3gv)#cniW2IY6uX27xx^B4AoCUopvXMb9T>8n7qFH6&`Vz5iAK%t z$gIBFuouqVxE!tbX+SbNU(-HK4PR$)cAmNBMSMsmFqr9w*Pt+a5LNF%;ajOqeH%Xh zaXvLa!IRIrnsVl9o+56AZ}@l%{^t#4bh zGfZg2;Yu$TXW94PQ3SfwdXJn~cfTLyhpjKbox(3qCls(g=e%L6@)@Qq7$|>JLis3s zf3C6Nd-tLE24nd?JOAl~d;s1RiPTbbdxknLxwjMN2M-e_AinsaD-zBR#_UUKfd%si zvPSo3Z6kAMcM)d+ZoCku)glMU>L8mOnQ(+J%5w!rq~=m>vWdtHq#S2EY1A&%lM_3;u3w|^w^3om4 zOXut4v90@n_1z?IseMxsUVHA4>y=^w_g#TE#l=IUM(m#4Eu@Zak@`NVYO|KI7!fj* z$C@ouMJfMh95eISLjN)r4dvon!zUL7VXE~o9*4@6P)1!YZB_K&Q`#_@mA!<(y^sYW z>jgSnR?t7}5+aFVupA%cg3tDcORIlNuNt6rVDw=p>&_f%l@kfF?K1Tw?0-!ROEKok zEFQUkH`G;ypHIU`yj-2!Gb&7F0+E%lstyjpP>{`gc4<8;*hE##hPbN3^XV1+!y(+4 zM!=yZVtMAKR&mz4ugSO4Gu!p^Mzrom&r~-{&AtFo?QAmhtNxsbA=~K?0`u!gF?zua5u{hn)He|9$Q%y)KNWBAsp)dU7_u4x|%48^MP#!!R4 zyocqQIq0nR`1G8@Y6>lFLLQo0zN2Ay-r)4AV=<~`PCbnKF4=Ha>K2+MwBwj!=CsoV zvu?7JM*LjFFuYZ5^^dr#d{BxhHhy98dLeJr;7 zvB+?FeK_|-*)|u>5^V+(52_~q;Ub_~+F4EkLOOL~oPG_Lg>%0nohojV<8e417E67% zJuLMFGCT0%xz(x69i&wA0h)gQRpGT74oo||z`HGcK_^_M7w{! zCegg>*+~EF9e05K@h*+_&-iVJr6sSIOYQaYf_?jCz5GhKS}*@yWM#0(`c?MJJNueZ zx4Xj{(e<}lFK5eodB<|K5Ra~x8#?S?$tTB8*&u`7o?}kst(7^(>Hh)MQD4iLXFc~_ zf-;jV|FJZ1EBhId=w`v9H{OY}SonLzj4Mi1)qQRF9sz8`m)KaeAw^cw*JEV)M&<@( zWH|z(V!V;XyS&=AuzV97qilx9ENj}FA{YvJI`Mh4BUkhFSS^apOpkKLa*HH>8Gt}!j z&Px9|qp5@I4KE%~scKznqRfBF023^lv`cZuJaSa@o+xLS&tPY=)fusX{*UqbGdI!2 z;p5S-5q#?OYXqNr^=ky5f2h|M_>{K9=YgFHpGAC-gwN;bvvK$+{Ws9lJFs09+wpHR z#S@%PBKMS4s8|}E+C?I9aAMBRDm2CFk=1|C{@AtLUlY4o!feQeXl`z)a|YP9mOH?( zyRWc%bch%sBv{0gSeqfG`WL^yk*|gW4vv8v_+E!f4HjLUM$BfJ-mt05H4WKV9CNTZ z;z-QYd!?&sTLuHYfIWI~tie{Mj>cg~ccFzb{|Z<8KQp(!$l}Mld~elO#n3rvRVr*h zYE{Hs7!D_JbbfR)To$z!nsNSB>Z&4!Z!)~E##hrSyuSTyzwTdu`aZn>|C+vBuovZri{h(Ef_IPS`pRp*Q!9{Q@AS?sLDtUY zF|Jrmz<|i&++j8CBC);!jH)}ndHgvcRm>SPl#`^HAXpT_&@n? z95oIEe-}=@wgrDBN?DuqpAg^T{}}$B@wK&pf3mCTo2;{gCoe*#ti_YBB?6DgTon~7 z^Pf`)j7Jl#YL$VW_%)7X2Sy;ZJdEd`i{dM50e>9-AA@?_5_}mPG4NNTbhSzUZ+1&FXUnShmXZyZ5>|4Nl z8L;MgM0-h`d%|pUM5dmJ#0PM(wYse}0aF*>L~D@h0UEa+A>IemqPi{gX1NJ`I$rLw zNx?agYC4$(jrrzJyVz#nu>8sV#q-0_fF~~Vr}D-v#WjoNY=!ZvyWm7ez*8{T!TwEN z1y8*ySm@?g;M~sE57wb_aV}sBC~#>`MFVa{;xjYF@rD@7UCoW~KGqY%H&V_Y=vO&r z!fdU5c;#rMRstVTuH|^%3m2AiE=~M5%Q-;vi28k?Ku%&!;QdMYE$92Ec`!I#{!e}> zzf@ke4~tKE&NmQUpnksES}m_%pq9x_&RB>-Ddol+9KG1YOF511;@8C~scL?4HIq$^ z$^b{Bd94)q`w9HG&tMqP&i|FyZ5k7CDRBFjnMS(uDlmLKDajH~c7`Uhsk7JZFRV=e zvHvQUf1}I4!7Vo!qR6`aR~F{Bju&?aN{Fta6Bdvf(?GlQMF;Na!hOjmIv;CcD*BolO=NXim$f z84Ddr@6(Cj$g@{-=Aj3xkfygdQzjezax5#y{Nheo=Mo1*dE2LXDkTrsy!)SJ)1Xws z6*UVJj2Ci&9WJu(YpgzfIf2l6H=F9PXiL^2Apd3~h)A=#B(lslUlAR#m zlHFB0{S*^za-JrpS~~+H^Kl|;Hx=_IH7I=^si=o2`rK`X6IJV1tTNyM2w%r+e0g{$r~q>WAfhA^W6% zA^@{&$+Ey`=WHIDeLCcqV-m<57B5-t|CW4AqW)@*NgVx#Iwn!5U0LGmt2l6diylp` zuUP6^v$VDP3X|$9N`!Ahi~7t7)Hk=)`Z^!Dz8)>=TPXFN+Oj_32ig6Gv)Hy2o#;XT0C2BMh&nd2W zN(i#i{QHNIEw+UF#QH}%pz1=NTHGfF&P2)_4$fyw^hmiu3=FnVXADzv1G#HdGs>6p zfqTI>a!=U%>LM}bE`W$!B=*+_f%nVk5R20<)E!bkisQfcOs319Ro5USl$Ig-j%Z`% zrQhyS=W1k!0@2T9i*j0x?yW@H;oGzaC(7WEx+kH1q{aDE#6GM{dv}OP$16@mB0V8H5i%``&lDE^uRX`o!g12VWpORcnG}C&x6;o+ zH~~)u6#zUQB)C^Um;VNI8>%EBpF5`ti6T`DD=7~U+lR~5yj*k~tB*`_`k9b|!66T` zF>QYKPYB4q{g6B5?S0;qbPx3uK^|W1^#1nSjEJOO^bfIG?D2FJ${lkaTeaEd3Coa> z-1;6~&HjU3G$))Jpr{D**=r-LqWVb2F7*9g-I82PAV!&Z5Pe0nEr=V;om7ut#CAPk z@zyZ=BZ3%yPDf*CmY`Haa<|I)yWEHF>XP>6vwUdoAOe$dsK3d(Im5dz-IEPpdEd!_ zv2ZU8kM0@TDPuO<|E_mShW8iprEYVLG&M{1C&K6S#8@7(%<&vP6#&(Iqy1|Xk8Nss zm-96bL>zyMz8fT#B>Gq|Z5k{7Gk+ldCkoiyi2uxEe`mgx~1JvI}YQ#f}5wYt(T zi^Y0f=HI0vxPDIr*P8vJHB9SD^wxTJK_+T>*6T7hLr>WeTz_c#Pp2C8k%-{hqx#)V zXhNA3%%WiX*9E&!b@i6Bs^6_{`i{V@AM8?KiMm9g_7v*yxV{r+=N8sDni# z+1#)WTeLMUPfEq~g_<3Y@Hr*#^ebCp_}Nc%U)io}0;+V|z@;Wf28U1NmBqmDDdN~R z!O=W?X1eTNie7+0k6@k3eQ&?{`eIW8h7jv;xH>#5EXn}XaRr=x-gBknIjq$-PVV1F zW$CzgS1sia4q{LhrdS80gA?^$y zfp0_4GYqSq6S=X2QM=-eh(!_}dJ}wAY+_~a4Q5q&r`E^5 zm)W*vhb%`H3&UvPC2|rAX5Nu@XuG!_(>#u(M7~CX+NtfRg2#m~H-NO%!6eAYM9I?3 zEEaUL^fIka62Wbwc}p1)a*!<*?~5$r%FzS1pKrH+R_pCQE?Ea`zj0h#`@apyu4U2+ZT&Rf4V!dK|Ao zGkmfG{Qm#5vrV^9J+1|P2`l?BuYx+*S zfsla*$1wx`Z#m|+hg+r3ZplhPAA#RI{Nhyf*-vVeK7(+$fn)AKp|$DbpQP#YeRJFN z`RO4AnBfz@g#Q)#w8BA?G$5W7V``mbwML50GE^!R@xZzA+LN`sM#K3>U6K_4Y=o;p7jeQtwlQTn_$P|+uUQItN1 zPt^3OS=Kgv>h8Dc^Z!cTL@4y%`xGFlD0GFu*cydyC9qY?IeZdyi&E&R5=Ei?FGnf# z^8`(y%inHA-lWhsmA=&}0&b-ZZVHX_Mafd&wx)4@0L&`Ny66#y0-emOA2p$GT>^{| zO-ui3`IiD7(SN%~^xuV=cqyPMXcL;!cxY}Zw)J0u=KYrrp#Lg*WTykh5fMGCxOFfd zl&k|1Wy!g5MA>tO2II{}z^DL>C{bFahk~a#0?M<0X_X>f+XUs5cu=mhK{;JOc@3w6 zC@AWo4R|8_(z|tdY9;G{q>`9T1wF zcxWnZXmSOb2XJA~^jL`YVz1Y*T8hDm=5q?(l63q-?dFeVJ@A?&VH8n|wHeXIB{i~G z%hAfYB$;=Qjw40CC%#cbXW^SPel(5KBL`~#2)q3|?$PMCX#Z!)P{_B|ez*AcpMPAp zpC|1bX+86fB>D11K;IP&psA>~}JI{`zz$rEa_r3uHy#<2S@Yn69+3nx9pcM-I zBpC;!K$rOTpLy|F_nDRh#YKSs9PN-Tu9=3;u1lAEEzk*e}H>*kT0y zBpCZ{DU_B(*DCwDg2}M@sqy9KK|W9DedF-{)Tr>UU;!Oacxu#W3Q@n*1cHDjfzqE zYU=|p2?7?eEvAnSpN469vNyW*vHRG#t&bIDskT0z3~D?NZtLS(Hj3Kb`snJE4nSLp zZG9Xg&7jG5StRQ%_J`%NHa7nRiD1?<_sND5p1&$;w;XV_@!_hXtcPl&_#79H&z_;F z@Yyi`_uzBC>@u~vl{0jB3w+LzX28esN-BH;$8hdBijVS3(fuR%d{7g`=e%R$`saj{ z_+w%jI$FleAK2_44?hgQGC4larj*5NYy{Z($GO~ zwf(aCVDR}{MGJghXwdjP`cf)-d}!!{?==( zCp{%TWtYW|AK77ylLxoWiQ>~O9-nW{Ooh+N`rm_30~KbMrOgkKt}Y>4Q_DG)CGw=<##JL80_^X$zFr)oGNPo@?1Z!K~vhJODnUW=Ff| zqa)(*`TL+$_|!{72aV5&l?T&BKb+M9pL83a@1ISD&tnr0fX|$pqWEOQ#qxk$eFAkqSmZa*Ryx)b-XKeVi zjZf{67Wmv*tMRFMCKW!z*Tm}wN&RzJ44=Du#^E!eI2ArlY3QKG&mjke&x?aw;L}v2 z@p<9tRQP;I{LL7@CH2plGot;otVbL^_nwgopPACoLE|%!?WeZ;XUm`#_5>wkBZz^e3 z?V+kDKF7u5v!^H(J{#u#9(?X+bEj>5h7N4eKj%m@$OFfdsrn~$RXjfW_-j-}_`nmz z=e+K5{c}P}e6oKRKJT(6(>6X+OIqMlGe_fd<3Cd2bM3qF@*oMH{nMiOc)P{nbK!tg z{ZlLr9W=lF!iGxQ`24N71wJp_qVak3@2T)Py;J;rD&C!O^Uo@e%7=sXnVi zfMazj26v~(Asfyl45}x7jl?AqZ{u+8mGZGTwrii-lf+#c%U$G%1xNo13D1--M=X@T zV(3u$&deQXh5N4pT%4y5#Y?(W9j_qblH9EpsXN;SZ11Crb!2&_)@KSn3BBy!=QLj1 zcNU-E?}MN+oJ8c=n^DzM&V@+za#leCqT1CH{fY5g#hEccxT{1!z;z%*Y@gi{ET{@M z`Ptc~bq@~p+Z4j$Sv}%b8)3-|=T4iMfbbg%VQO*tN7=_p1ZRmAqk|YLtgRdI^CYsA zLQdCn67`7R!jW;v#o;&Fj`NaL_O1%CQdg};M%Kx^%57eOq7M~ywwq6X#C0Qbgo}XA z>7IVB;M|#PqLkPnZ@Hui;Q{c9N z7dC&I4Scm19U>YKo$G3Lh}Dv5A!`Oc+%62W_`UCxC+>v_77bhlgu&cyf8lPRVCP8} z$#B^2SS)VY=BRmAnAq}Z9`2L@VoJNoR}S6ghm+*wf;ur^9iho3&7VZ`_ybnoC8rdW zkMZHQN5STYF`G{$T``9J2i6_q^yBOLgUi2{ShK;RyGF=B;}C%zV1A7{|3_Ge4mQq!_G_0W#bQ3{D%ffy3NPWH z`#7r4I@NQU)B9`2)ZUKjx#@4s=^-zk4!mSE-rRA5qh@aUz*9X2p6kL~f1+cENaZAW z?X1H%)<@_fN&fy+MybyS$s8)qlZqoQ)acxd=M7WPCvx4WiYcx9{O3%UV?!H5m%077 ztgVE*iPysMPdNl<;=a#-C3H(I55C65V^yuE^0%BgTf+xV`UAzn1TH8!!5z3|t>Jrx ztYP&h|G^c0r_w(mCv=fxsjv@$qc~C|jdNEYx0^OsD6Vn_D;q<^eXd+7M}i3Sb<4^$ zf{1xd)*h3F>$$U4dJ7 z4n%VYhK*Lol4p`r9(Z#h#gSheJ_dM4aCmsoJVC(lvTd$l|7fSn+YI2t0KD1oehiSj z)d#+jR!H>4N~t0YR(ODRAGdijFD{bgyw^`slOHsC`{Xt3l+rnFjGI znu|j9DKCOd-4(zZ58h0ojK#o{Ya{av?++{lp|1pf`^Y5bkfN_s=zE-QJ0Gx00aMX; zm(;<@+c$!QA&Q zBF@zDU}L7A-;P1V$z5a-9AtQZ6dVKB=C}jr5;^hwf^^rPOgu?oN4 z&adLMX()!exPuZaT|VvdWlu5y`w1 zR|GQsF8{j9K21g~kxs&uC7X>~Z{i`wXmtbVi%S0*IV+737`!dHBuC-s_Ma-er*sE7 zWvm3he|Vnt4EF{rE`1W50`r9J)R=h$TYq`rHha*N1B&+r&;p<2E*-5YlhCEpfP^k? zvTD?|gF^Ic^PF<#nC>0p3^)OxG+%;VPk5~W&H5cGvj;o~6nD;iOCSJJ8CbQb^@6PrO5KWex zTa|wPRXz%qhAT=|PTP`#GJg~*AWY(!{bDK>$|Q}+uq4As^mJfAjciNz`QE545bDK- zrPF^=jwM1kuAlZQadB_7pJ3y5di14`Zs$uYNz!d49UYNw!gs^qJ4WB-ngGIg^_Bju z4mI>D`z$kRZ--+nuJ;vz0RfO{$g?Yn)i04I^Cd;Ps!)cS&^xZzN87#ruG70kdYzeO z1*1>(y6W)pbht1sM>Qi|UMyWMy)CE8@;tp%mwzCQNSC|(7w9fWiQ*n)e`T8WnOt7Y zc~PgkWVe*bHoPXlx=TWacP6+pzvA3&Mj+wC z&X0By5gOSxwa{7ev*Deg0fFfU$VBwL$hIpLbvk{oWLpVEk?>HwREknxU<4E+Hc6n< z64WtgA5=xT?X&iHm`W*$!V~!}{}$ou#(!08X&x^X=_BQ|lxBU*J=!Qx zYV5C9ymAQ=Xhc-(SNgZPxt*?3W~6MsDCbU}ZsC-IK-y0d1YIkGnLS+kMi|yHo>`$6 zQPZYrNw9X>W+n4mXcik3Q4=)_H)$!x-d5eF8hbAPM{3j^4qNL%=<=_(MDPm|{kC>v8zHt6Gr6)q!CHe!8T%@^Fqk=)0e^osOxpgZ0BsnRz_ z?p2VIN545~bxe+bW}bDF0$2pR#=`0>3BlZ-ZX~9LtO`Cb=i|^=S+b?l7`}y!_jBZu zUKH7n&1qzi(sinl)<4{TkNIc){+j-juyp1*I%NYXZvUFl3zU9Y<*s3MVxF!l-b}^B z$IqRnE0%?6?hN%o*z7_HcgbeAE^&@7p#pbPs8$tfR_AYdJ)K-;vCyqNpG{V1D-TEM zM7RGtb2)yAqzusQt4ncsJ)Tz`^EQ~R%JuLGDhTO;0S{ zoT#5A-72Go*oy5uMvRP*aPGisSU1A9ne};>+NTU9!`yUS{0c8YA4gwCO>HN!c16PX zW1^hi!xh!bXU44=s^6R`eaoPT>f|D`-TuJ^N?Q)xHi`W5z`Y)R91KMf`Z5~3^Nxyu zL|$vu7I)*5KCF?BB77&~L{3emIWtCO8;eSuHF8p#(C_y!_8Fj~QRCZLf8oVetE=u3 zwW+dhmEr5AbeZR-sJ1H5q@{7gdk)Ez;p!*LsQtDpx>Fy^@V!W*L>X-7&X~;QTZ<~v zoI`X&Yt(E$Y&808J4;@o^*>Fk=ulOEEf2J4BwJ}mf{!pOrdJN9ZIAF zPE^a7FIjGQ@1ntS|2n}^X_ErLP-D^geVItc_88;l@(M>_aGk z&(M@J{Znb*ExO-kKCB3I4>$-5pf0m6H_F$Aj%wPOU0VFBQTGi5CAeohB~jm0WzP>} zmk+vkA{o=Wxx&lcgSafj@X7kxk~Ks{-G_$nU%WZczCk5t+Gnodxb$-Whn4=7E;_yT z6n4i9-*Hq{8SHg8?H{FPaNL2GaOC-0saq- z+IkY*>FWfak-_fXQNhf+SYZ2qku&QhZQt8YcliLYdO2ZJ{79k!6OcFbq`I zvVml^w@XCr9V7BEvet3aQ7leAl%B(w1P*Sf*-zlk7af>8lZnlS#6A+8!>Hr1J;ZTy z&AESsQh~=CT|_Rovu;Fds@X1mZT*X0i^^R0AY``Iff3;>5Y<9zC>_bdN&=5%y9W`* z%<$d~&Thib`}et6D9tMnip#1C!I7EA$ePq1!7)LWM)L>n_nc%bTC1f-mD3fhXy*=Q zvff^6cyHsovcO=UHw?HtAZn-+_mDb@mm59-XD zKUBlHJ?}KS(!r>5G+7Mica7S)c&3gF_VSGgW(N8*FUmN^v?b%%^Y_3>j^b}Ur4Ij2 zhGlj|@o%0A{hTAul?>YvYS{LAsp;E1idMZ@cK6vp%{(xsC9qD5 zsS?vVU(7*lHn+3r_hKzm zMv+5EQzNt!mZU~!pOr>!2O=h*6UdO0;5(Jr8XW$M@~qEM$z_39Du7u8YT(1Mggq1D zNIbhj!z%_Sd4~lr0}B@mvvLfyvQk(;t%?VQ1zEL^Z8yfnQms6YxrFWoZ+DV7<&i>1Bb@N`x3Vp<5?yd;z6W;|&X zNPEHI?Id`L%qcg}Lp0my@HQ%$#++f)9!esC(P~BoJJktRmFX6X4lag;87oUxJA@e@ zt_WO}R#CjwQ(Erd*7PmxAMy-Sk2&&qc18XEQ844#!AY;AG1=r%wCW9adZRNq71s54!8EkrP0A^G4@~5z<)`_pr;i-Vy|NPwt z^I^!)#0o+y|Jf0&2s;MVD&44dyt2vNj8R3cXXzk}E(j)xcPL_sRc*d37soI~Pmr<* zi1E%6GU>|c_Yo3HgD|xQe*S6#3hGC=HrnD^h!vI6R?|=6a7#uELEJ$1TbUmTs%Nv{ zbg&7We`}^S3%iJ(&aBBi_77V*=yJhX8BIIs`h7B%gg?DCe86aIkm+VF!$o9{nuok9 z@9z@x2P@*0c+ZoqF@jYi+FdN_ z#Go}E>&9@b8y&2BxDrxL8pK|tYf70TpttTz?=%@yx@Q?eN1{T;5217HUdn5G2)W{i zkVM3c4IwdkwKjx$P|_Yk#=I@)y`jIwkD-%DX)%W6k_tVB2HRt3XN7DNzRSi1SF$pO znmi9V0@tU>Xc_A8f9GiWj?uf@(_ef%79KB3x+&G$XF(bzCwL^f!jhdi|)*)Bv^m$YZ4SC1@?7YH~yz5*4Y>UZeI}2xs`RWOWhjz9fF_@L!o| z{v(rv>poEdYJM#bgs8&)BI_1H$^=ys-PN4~? z!ZPL9fGPyoFJNXaMAX`$thUMn?j@P!Ty_~5t3eW@1GPyHRJ|+UG-|5_R|Yp?7ai4B zea5O;r-ka{U#`_H(X^Z_Qy4sVC{6CdoC-{Mi28ZiybEqJcnY-&#MCRBKGoIxln%5m zrUO;BbEk`nfSsSu$^*UX9o}DKI*`RAu-fn~f_Yp@vQh9uz#SGSug;{k8BbaF@md)i zqjjLqjM~rXOf}0sAWt#F9W=tC<%S7t78dRza;H&OU%TvFIoSs zHN1Z&ZCIdJb@`x&v=ZbDFBiI^1Z_loSPS9p3b{UX9dC}{NLl_BPWy~a&2&+I^UM98 zRr=SeHQ-2aG<-)Z#?8FLSd?uq0jmg9s+WJE&Mg;LZpsI`*E4sxqid`4B<=kA_@&h; zB%yQ{)06Ofy=p(oKsXY|F}ziRK5Z|c-jLOdAX>}avSOVHUyi!=t?;YjpnzT=F&xyo z$f*omi1U1VfmCdL_5-%On$1c@Kamk+U)5v1%Kag(@G`kseyvlMz#QKMeX$z5g54Ly z2Dv-Xsi3MNN&=@VaFbT*Ix@6^H)b?_*A4}uzld1TzXX|UJBg9!9YR= zeDWHi95tI15xLYj32i0&?u2kk z_RYkh#+G}JN}9;Mn9Qpc`iji!j?4ptwNoK2%dKXS?+{FuRhQ(j%(8k!5eU77x5d4e ziLFtLhd*-eiG(^kVTHL>B@8+3d9^E9G$^twc^wXD6dY?8{MdX=fB9z;+;YR<$EX8cD@_UVbAI(?RWIaU7rG{!g7$k`fop?JRi)toS zngjGlM@m7_Sx@8v6s;;<_EIXBdqi_TBweAn!c5nnj3G-B2^;Xr>xyP#9 zX6r~@&)vF!uutyM`a=~*n%BMMs<*8SUGf-8T7MBWAej5xr921pb4Sw6dAjn|l0HqR zf6B8tS*JfJ>6hyCrzHJCon9x;BlL5VlsQ|MQRU0@^DId}LqA_2&nM~U8v)O{Qa?*Q z))@VKg*?0U^ALG1)z62^v(jjSxxE!?YpfnR>oBS65dD0FJb$jAr}K&V3{H)p+>Z3n zdkOYu;-4ZNkVp8Uu@hfevSxZ06~Hthc&pqH|BJqx61#@%WiM!I7?z*iw5KWEbB)70 zryoxb5ZK|(a=u5U|VIMGdLxwA>0H8*PyuRy|jV)^I~VXks8=UX0N45Z6dD{ z@z&g4LpX|M#IPJotj64dcdjGwns~|7g{v-P5jCHZ6@jN0lEP&>hEKNgZ2ea4a(bT- z@P%ZaiIo^ALs#MaRBUku0{0;v9+vFDYx2DqIg0rlBL{0r{q?V;+XNSThSXqPs~+YQ zyTZ-*$`xDN6W>F_xZJK4g2|4jh;67d7X@!+&NMEN%3NucOBK}RXdc#&N6fa92lQ_Q z?R-4(U>c0sq+(@c7i<(3H}*GOlKKs3l%d}hV@vS0s}@|+xpq%>hrcuC5&lhDV|V!E zCs|G3LCw>90yRD^R9!6L+DleWU1ZhCcX2JNg~EkQ^6`YM6*Q@hCES!8XZQoB_nTd^ z@tfmJ|5zIbaf09q0=NHdm;e1rY@+_v;n8Zr&26{74od4rTXmPvxP@bkT9$)|F;6a! zwq&C=9tdl_*gd)IdavU0Bo^J|PUbtj6Gk%1^5o5+_AF9QSW(savkg*>b zkM=(H5xNP*URXMmLzNhigvZnv_bkV})+h%bA3@)E1|NnGA+}^$(>}Y(6cbQ}o1r5sA6>e3?I1nAi4K zudBENojpVIQvLcOxkw$;tzVzfxw4}=P^Uaa0rM37yp3m326Depbt-)$cQMauXSJg) zbccNK8%~;(^T`K~B;9v9CMK_Cu_Sh8cBPu9i;M7>xXnVRAD>PU*~L<%pAy-P4Wsf2 zY@Cz5@<|p2V&h;jm+iU6J6puJFiT+efa=*Iyv5dtbY_E#WpS|>4p|@jI%1l12hM|Q zWv?vY7|k+SD2-9{oNU%oN4RQ!4fAT$)$%Wp3c!hQiQw?!fF~ z>kCS$hfB!q|Dhs)JK)gt$pdOdABzVei`yoP8?s=XiIL?GR1+afZGZKW``}&<-G ze^rzYYs6$Gboh%@t!SV(HC-9!3Jnf%MK(1rVu})jkkFv^3iXmZQfhphFIfkQE!rK~ zbEGeBBstKjp>CB!oG@4byH-_-=a$%vT)~?#HjG3iC{uH<(?7dVM0v3z(yh5-8j-Eq zqj+G8IfJbzclugw>82BomfACG>Kdc9uavC??<_GZ1c#=(6KXGm0afkx{^%*Hc9vJg zs`eJJzXDYpNx)P6w3D0ycpT7nwKgxF7Xf-K58NzUOk{Jx-9H;~iHA!*w>P^7;s3~v z8B$x!|9Z@De}FvXiRTdeILZt2ZDj$R!ak0(c(p)In zZV!Bz?kQ7SIta_7Xj5(L?5Ay`?o?j&){ProxzMPqmbQblw2iqJY~~2uJU`o7OF4U2 z=nt`7p;EM&KFS)s00=P0E>$~1k5M?3t*iCCNNxXzx_1GOs=6BfXTktME@x08Q9;K# zwn@DO1xpN<88RU=FaxNl)N9_VlzK%-5bK4&1jxy8lzQ)5FI26sRjXJnA|ND?8=ycy z1*OVO@C+jgTIC`z|KHl@%wz)5+V}fE&-Z*hWX|6E?6a?Huf5jVYpso33bgN3c{mNC z&3FDi-iSO()g*%WgPd~^2dLT#;tw%coDnY`&B<=RO=v2kcwe}lTX@P}EHN%98ThSM zwTF(B=zBRpLVAew<=b=|2_o^s#H+bJy-yYeMG-P06#2H|&9IZ(Sq420BQ276ZN@IL z#h;Zn;kR6nw@63n(kpan0q-1IV1IlCPbGquHm|gXY{tX1@tB4elNgE(x_?xx&umNV z*{?QSxLKs0TGc5GP{8P2GVp`)^8@;NTZ}VE1(g^l6sT?v$GQotKbwPYTKqx9VtAAI zaN!_e!|cY(u&$)0#CaKswzzYNq~p{-ojE0Qe4Q6ER|=r~MGHidBPTX_Q+g??=Wc{* z0*5mngcwO&-wLO)*`C4?q{3yDg3BhaR(qfYzQuWbE~+e+7;_n`O{)@UN5ZkVRl=do z+z42OjH#Af<0B%iRm2ye3R^wx$mB#` zo-M1;pRo#MaU&)4rx4XJ!A&AN5m89SDh%j1AF~X9nXwFWS&wQNx@Bx2-aUe;GLEr6 zp&Lq!m|B8i>l`Z*yErS5I?KYEC3Tin0*i5xI-YuuFI%PXyMeHj6dp*4$=sw4vSyMq zb&&OP{AQ^!;~;ArJvv4RzgW5%>oc8;@a*-oJA%3->*uc}#u+68x0Vkp(RW&s_r2w% zR+x3Ow|q2rRDD11Ca6dpLw6~mqc(fTaA;99|4AF)anJ`6w*KqonxpU5VolFp2KBbCm zsUZsiUVzr(aVZKM!C>mxOGt1L;n_s^Kw$P)a-a#e^+ANI=4H^{mPi|XAs*);k3Ja* zskH7FS()vMe}`_H?9=vgip!$Oh_~W<0oizrWp?y3$~X@AJfaHwrr z0W@cD=mTx^N0%dgPp}_uOz(%ee2esbhLXO&DG=p^rD>8bW^2(L>+Qk->gC2nI9ARI z=2NHWzoW^mL}$%PW{HImn!zFhbTBzkeIwm*Q34F;AEq>NIDW@YrwKv;zW48x5w!VW{QGFN91#|_@>RL!@DrOvFXI1A)qd{Z-fUo zb5scfzFV;d+qUl0`cX6nBm?1wR+tHvH6N^#BL2WyuPbG(??j7|@L|FQQ$`4{g0B__1f#Cl|8g%eB$!a!$E!w#>d2D|4%yBJO3SFQ zpOESpQRejC-otT|^E!BKnh4ouUY>3u_gzDhYYVrWq|KyL>QqONJBZ|=4QoUg8PtZ?1qVC9#FK{z z{CVDX5cd7UiDU;mJHKCh2r<`3=I4~?tJ+;*U3JuNFp9p@>pfH_JU5-gq)*I2G0#Ol zpe__`G>iGhvgHdIovk~WO5JEm&O(Y9=1^>AtxtQTA@L~s1+7JYIEbP#lWe>(WihPg zCmb8}57jHWQ)dpr$S?RdyO;c%CX%*?>Z+P6I+}C#IT4wDhZ6r1x@9P` z`UPt9Xey@J%D1vy>11U)V*0;x+E%C;^5N-UC^HZ105RYl8`4**2@7FujGd#R&MC^* zZ(V2~_QwaYo!kf+$^ksbRtN)})HJy-q75)`q-(OIZInxPDjAxh&X%{fbB{V#5!~N8?h)oVESdDfTpsN@juR1|r_u z7|ySiBSZHTZWLM19x+QyZbc_di$2H}ggWO~xGy&}kl=Cn+kIRq8q|vS2c3ZK76mH@ zf-Q08$$^>@%5Z++_RE6WYc2fM1^cb_zdemUglV)tx_2n7Q6d|NwWUi3v$PpQsfZ6} zl8d?IGEX8*x^*R!R6CA@N_jIuL@>TE13Wb_@cv$p@_{x(wAzBnm0ZE}{zek$K&a(Q zv4d>+3Tkplr0|0~bM(4Em#vIfMc0UPcSQdpF2Zvq-F(Gc$w%S*1S%j;zv$GeR`bUH zT|FVNs%8J!l_YL&va~HCh1jBg8`6e-6)N1N%}~N|#ydDF=2ajUaefgg1gyUdX{G;y z5>mn#`^L@Yi-1<4W`eP^UnG|{YYml4iYI9B6e$sZcOZfcdnXw89#R|dV1Q1n1rG%b z=#@romWPC3wBZn(*R)YaxY-TY=_~2Cso$niMd7t>zxMcY?Xl&4j<)o|aLoJPBVxBa zg~h@bEgaVx^ zmtCnri+RP$m8KkYYO`+^!uNLK!Mg2P+-Z%{?Wf_Qa__|QCt5p5A4OHyN0C$wbLUmE z)C#6BfN`*xyI8S6ETs#;XX`mLjDbgV@>R_9ke8@}JK-wV+6e;PR^eEOFh+p@L; z)hi=0?<3)&=e^Z5tm5hTsiev+UMw3R5T1R{&=RLS?z0-DyRZiM3O5I`X6Pg6HH_-B z{+=LJKTScnt$MD;z`lQ0jf<@`I555j#KOu^lOJ|c*8U%_?MO&}|EP*K3W;S`gmGZI z)l8xqY`H?wBUzINEA6Be@%41lwt;?L0e_(S{$7uf7%5z?&3Z{D1A{&q)MAF5wITgb zTu$fh>Bu%pT|uL#7@q|Ns=5f}q$xQ~cYcv1P6`$Mop*gLM@cLAd_1nuhqT?^>0*VTDO6L7Jo z0-|8hWi$rJOM!E|n1WNSJ|VN!IqkMun|&=%q*~rm0r{~qK8iRK;ZZkBhPC278Nl>i zYHryQ1&9vGaIwM_$g`eOa1#J3V}sNJivJzHOK?v4@obZ_hh&JRMWf+Ipf@O{@t?NV zxxzH4F!2@#$IuCD{@KH#on9qiu0M&ZKhCh;{3G?|5dvUD%SIB?>QypnUHSHIUI^v* z6bVGDRCJB`08!Z_(zxSuZ1|Eny9Zd_Ee2nk+K6qFpN#zx7r%nLJxae^iQK;x2OZHP zr)yCW^Kl&|+rbVA#YzB522GnW3z7;8T=p1VYw{^Z2iHPTvCu( zsdqs7=k@EIl@|s270Q1%sNcfq7rr;Szuf8R=9`zv^eUNT+9rx~4N-eIVxEpXR>`W- z7Q(U}_=#71AbB`{+cNngkha0c+1y5qin(_>z6y#B*AhQCq_rT{|4wrwqE~q8P_!Ox zs>2n^(2{zfF{y`J1-~|xWqF&k6*TJ_Xs;Z4PNa8Y7LS>45Z1D8i!1B|SbDAC?~<_d z>!5RGD0;|;f~DG*MFZdH;+G@oE+N@GWMdI+IVzO3i2oL_tF?99N|-#XY>s!0dyc4; zO`liu)f&OCqgk{gjPgd}`+VBtO@V?nL99R@uL~5cz|-_HUsW=sl{6;bV^I49(Ob)B z4&x!@=Egua=d(p4mlK14Jt81`HaFSZx~P3k5KU*=pxU@tH9w@#4EgG4OfNZfZgFd~ z3Izof-XIWAMK(?~p0kToGy)_9RyunGoC<{fj+!0h2n)m00uc=D z2W$&+>=|9BHmZnm&j*rsf7`r_J$e7ye%^nz&D%}oz1PYs1{f4A?P0s#Lq|sz1`f;S z2P%gGFI}z=niF!a3q@-=214;(E{Po->+=AS$-ims@6_Kk6$;%!^_#`)1Y!$<` zz-=HIWs?6Tuo~+F_+0%F=w-s8Na4p}ZFqtk@85A4zqg=f4VgF+2t_x;z_;ez-!`uW zHP5x5_g`)ET2OPRl{cb)ABt|G=(B;ETA(I5x@c^i$$YFS#45E~0~P4p9E>glpJ6;O z1h}Eo4-lDrb-Nu-FcR%`xP#qcY7(%arjMkih7kG!+VD-q`k+M-CpOv3T$DX&B^ImY zCrMu8{9$_kMPNpG6#-Z(EMQTmqA6f`?mTfIvm=s!xct)5vHnY7Gs5~_V{G&gmr+OS zfR|=g5AafWNI+pyf5le`d*HFaU_QHPd>$fsRbr!Tz7x$HkWPF!u%Sh(cn|0Q@F@b6 zWa8TRZRS5&R1ZBwDOw!XoC6H1HOV2%ENgMbTv2JQdsOV6mp$p?kC;Cb>O;_#${KA- zRZ@_u#A#QOE+2B$ZLVT6)UFlpPM>9qV>>7zN!l#Fg;vse*5jF2t;lUr=tgd=K<7BRS z#<&#!C-}u+Oh=FhqQe|(eNv=KSYwu0(OyIof0O&D#o|@9I4lIkljo@EF~7L1EkV&r zPmEE5g9FAi$XKCaS&8EqA^hVgE@_GiU)(KR_@Opyl8S_~!?Ga`Ardq$QR^6V1XmMS zhNQuD3CzzjH#*F61Qs~x_5sph!&=Z#sNbe=(b$7-SS#b6KU%9)R!5+^7DPS0#OST6 z5!+#XV{}gkIm;+9u)$=%`;>fP-Rt#Ne>p1F|Me21hiZkIgjkUcnsTR~ZB}~tC#u9U9=)sva(>DO zer-7V4S}yg_uWG5u`7WNwVCia^hr0bUT8RUzsu-=x~yM*yCI6o&LBjY$qC#dZ^o=y zEhmi5p?RMbji_jodAk+8oT!q_4Um9nEe2GE4dy5-gQO$jGlvpwH4Z1#I=_gd23qnc zM)R#ubon99d1i-WV`n4S5IGn!47$_n?_d*^k}C{?-~lW*1lQ+bt!VVK3@LFsbgoQ0 zG)e)?f*8Bb>Z#yhN;Z774?cP|>}G%X=-nVs_|5Os{6hmZGIq6!gV#GVGGU`%L>V(v z!Y0PK#6T6B@NzZH?A;KK)PhH@QIy=@H`*xQ3v>;lXeji1k?{Te|jG zoxgfFyt=BP07mjP#i$YWu^Vfxv@5;93L2@Zelq2v{6&JG1Wu2U# z*{>F>mBJ0$!?lRF#EFGAY@czV;tX`I0>OBfV`VZ_1XWBFNOSs zRJ(6<(bfCicdqp7r>2|-ZcKE5U586SC>+#RntQw1%*zsWm&az+g_SC-G-6wL&*#F{ zJaVyxS6bn1i~w8oK=x$lq5?w;8z;)asaj7v=u!Y8QkJuj2Lakqr!kHz zfXqj=Q0Svr|Fby3J{M`a@>sOrJYBtM2s^h&oNRJ1 zYIvK1^ue9ce$yqpKcWGV!RSzyX1tSRkL5(wwIOTFzjRf=a6eJO-j7+)dsTFeIh&|j zw`%;_ktQRy{;8s51ny(Kx$TIO&D$AYCG3TBO6J6WuH?wMN{+0g$RY6x_dUBtNH&f} zGZ~k$fXPC)ty2is0%&-$jrL;0&6FWO2?N_&>_Zew5$2510uin7AlIm~w+6r{0YtgD zLCF;12KRlJDZ*92GyO1(D$* zhrL?P1qA;Is^LrMT&(j^tqG&=p?C96!LAkgyybZaF>U}cZVw^*Auv3_!euZ@YlBWC z!qz0Uz+c0WBgXAwiE#y-y<;-OxR3^mM39U0d1LgOp^47@HYw3l2qBO*BikaiEwK#E zD3f}EG^$z}HBRvLKrz{xIBejPO46&%_<*quC7VYWRrSrXjP&|Y%NK}NgDtxwu|a1? z3O87C+r75j7HB;Z7frh`&WPys)Nuaykh{-_(Dn+F{ogebdPZ=%Fwv_hQ+YvLMj%|c z1Bq~08+JHShzieZl0>^Eupj@0Fl6zUp+YJbq3w6Ti%pOMb2(=M91KM+L-RIy@LflK z>D@SE#38>i`n`1cZw8#S>8n`U=*+_P%}p4 zx;mK8Qv52J^M+SykV!>0lq<;Jtu`C6uo2pIf}rq$QsY#%6HDSs&WQ{>V%JxopyO52 zX(e|346*A!#U7*R22K_Du%P@ABm)Rnl{6~AarZ+YribeS+OVb)y+mZF4_GqP549@M z+^ueo(D+E@3t)>e*)PYB|uejQ_#xCU|27YhvmQL3rUA!466QjMt}rco*y>$KwIL2hzla!Q>itH@2w* zB2DaN&p_rhq5B;FJGEG3^Ca&+}Ha>tTOzyo8Mwy4M@yIn0{+ zP(G_TPHa~XDvJ)i#s0W(<)pa%T|&L)%lN0(fLTIJg$|go0^FX`Bx~$xfGxzFEv*;3 z>-Gmfz&>IRO#CHyENRu9v`Utwl4%Ma%_Jpdqdi6+pPae1o1Gh;lhIzOQ6apUpz9_Z3)w}DAr#UYz+FVKIkPZOkd*5HIsiH z()SG4yJfM+DRj6I&JqtM@@f*I{I!V=ocsDY7sjknfo21x%D%^X{MtMqcs^R6moeh_ zWK{CS9fBI;AZrn+{-}KMF!IGD)8;pN7zGx3Lx>oFz|R%B!@xLRd`#iU#4Pw~3o|5Jth_%fWoQwhgj zU}laIj=d|wvCql}MhbUW2AOaZFW9VlHvE1sTO8&!H-k}-odDB_!+Ofr@QolpYq;Ia zCb)*-1|6#5j_yiJO}~b8oF6P~nap;>K?y*9p~2yy?+|C1TJds3ItxT}W!%Lm`}QB5 z$N>BPb#$T{*FuiFYBNi)#hH-5pN4l!7$dSH?I2^!+5W<8VchC?-)wZzN4Z#d zwaB2k@6yQ9hj)V|yhhwOTl>Sy{PL_?6 zjPnrruqX->5JrvKFdh#z>Ay5s1bL(_W+d4q-se4EzYT}}mR6crB&orZHi;y&SU;OH zcGuiU%=JVliFoFtioc3P+$Y=LnNl{4d6SRAWjJ6ZX!?c{xcYB@p701&+ z0KKlFiy&^r-`6riy2Q#nnS zaGE~FX}aJvAq2$y3kkAW#S#Ox17T-D3ZJW}zpbViw~Bn(`F+GGx;!ZsbE`R4coV2ZMh)55Q`qN>3NIbK!H%{uK_wC0oe8?E$ zPrgrjZYa5?Vi)EodGrJAv*H4&KC|gY?Nm%MTZ#YgcV;UI*=YjM^8sD#6U7= zjOWPyzC08R^tI6~L*;BRV%*Z`=CG>#tPr7W#Ma3BK0-rHoACx+3ORR6`QgIL9Ob`8 zO9x5N?uxy%4xuq;l4bN3As5C!v<4k~NIdPeHJHO7>RX93#xXDniHAyzKHfmlsoKoJ zik7W+36&Qv^5Sz#r1^=>itP^=*JOv-tv%twPqkTZ2w^48#3c#cE(|3`$Gk}3uHK1Q zZPk?X)2e>Ln913OyWe+eVM<%Is$#yE_OcW0srVv3f`)PsyfZr#{hkg|`Dh^j2$B9quTH0#_robS@VGZdmW*m8A-O ztj$!uD~$eL<3hzC`iuG(NdSY6OQ<{Xto9aexnPOM`-?8nW)30EzlcF|B&vDC)Q!vX z*KK$EyL=;k$@Ob*_4i^|aD$iR&q)4PN#XYL@ohSdr$y;@{6;7vUyW6|{~`+CN`ik8 z1K^0~Q4g0${Np*LXgfu2!9h9&QwWPY;}9!5);&a`Xio7LwC?tHjxu(d2aGYIFw8{KbB%k`K{R zh~+F*SJyD>pPD^*k-0=#`JpkQOI@{&hEy(Xp)Xh|zDp#SoIO`f?b2EvFb;>bS>H2` zl}krTri#0dHp!JiSSyP<^%hv(Ek_-2gBLb;6JHEkix}^1wjz&JF=RF|7LPp`Mc1bxZw~ z-=93WONoBiU-_OVaUx021oZDKw_hhO_%uCAloB>k!g-z&{d;UC zI{2g8_e7lQ`7pY@j5q|`cBZ!d{<_ay zv|;`B@9KPEt>hahl#OU>UZgjB%dkDFGo@2`+I(bH&n=&nH@a*2McE^}_PHpeUjtEJ zkqwp%>k4ccs6N@_1I}ker87`-wYM`v3FwzXtOsJhRwJ%O#UP<_g-36WTQ2vI8cObS zF?8a7hRt#i@g?Mrd4yyOh7qFpD;IlLl0a!|Ao{W1Svu%sEm}>IOkV)TL+qYH&PKNH z6JoW&X--0LFon0f?0VMl;X4_RA3I4o+*GwG}n-2yMu0)8Mvka?lzr`Xzw- zBW-FeZ*}}I>+jfA*&o{>#`l@ZtqOL5GDvm3t~M_7`w^Jgg?G%8QM-&oyf^=1|$_uJ@drJ-TcElhMJ(oF!wj#b~X|c;{@H z>-ddiWlo;)SMIoO(8c180Z~*;NBC_w8&bV8;5F0!fg3TP6XVYqOxz%0G zZL#UQ?@|EDZ6E?r_s@dH=dIxRx zd=B;*f>Tb!YT|mF;yRm?TVS1(cJyY!y3*)}YdvzS7w$KZx1p0EDOGs8yp5=k2p+Ym zbsX`g3|lEO;wo>Yv{^58?+GQf3TROD7|OjqbB)*GAgPDM$|_D^Y#`w+djCL6g3mq>O?ZZrNb>_GEhJBVxu;wzsP`{~m95W+>pr zZO#0!SL1iAx0^Ca7Z+dn)6(*2vX<}jNT7^BftF{DDq)|5=Ta@JkZ zA-4k6<0eSJMc{XJ+p@cSUH7@W%LZU2*WYD-K=<9m33PTzmzCoK`k33KD1j`BLe1n6 zuhL@B=TuT+pr+j0Ay7T9nsCinZ_nyEauO`vI7!;uTe>06djsBHsv9S&ZshQLwfE$9 zDz2>I^VYiOh@qNPU!bb5oI_MvP%BS;&RiZ~9XunC_4f65Suf91>bAK9T|Sm3^r_pK z+vP)=b$s=l7s*QKgz7nRRG`m$iC@WnDvgl5r*-*yyguhuNu@fODlNZq9#N@IR7|L@ z*8XO&{msxWU(2V1>UO%jd?00duwE@w7}gi$sn`=TqC%l^P6vhB@eXw{Czc3!O^g4D-6L$wny0eN zTEGKz1k!s2T#8@=*9uaLR&^yP7Adp1@U1!nRxpA^UUB81fzFD5axO7Vn|&b}aI~#N zIHj%MWwG)iI=T&f_oXJ^g}w5j$62unSsWi8MqjI)4{yqr58qQC{zH8jk?-+E)z;JB46HUAqAvrhmA`f@R*PTACl;2MlML!xGKQ3-HuGH6()w)zgQoF+!1I0l zAlg=PZP(3hi$1BHqSM$>o4J?%zTp%M`NU~#kK2ew3U^KVtuafs%V_QS;|pi8-8rUQ z#-$z7VxPjkHshWysNxza;xdXzTfsS_&;Ys?bby z?x0Yl6|jt+Aaa7^_XNTA-Qc!{zRJeD?Nn=kAE~YU#+kibo9UqkvLR?QPgGNBZwd>^ z7k7~Y!k*#`#Lgb&U(7;rD06~f;rjBPyl|a3Ja+bk66a?eyd-u3um6~|K3U^B@gi4G zEqX55v0p&?SE6t5>tDxzP6CJIF5s9OHdsY!n%;26YZkep0c<>z6Tb^%`1ats72dR}r{M_%=CqlQ5CZO+xbfY*sSofJC80eC1_r{s z;zkdUou9)1E_c*s=yVq#8%s(&7cTs=*Elj6FCHgAhsv0G&_*2r;R+8rm z>N}d`i5IGt(+72kd3dRePBN#D%budL<7A2&ZQ$vIcrv@B`aTrjI=+spcNq%?T+9xv zaabpI-ve6$)f8BMDs5|$hVlHylAZ*#;!l~813dSa=%B>QJ1h|!7602H8+MD06e!*` zWqqryIWM4-dHw;6Y9cz4Q*Mwrk}UtN;QpBFRMGf)w6=Vlzq$_TRhNjfPMhDQ#?{k* zk?Vv>rw0apRNh3e_vE_J^!;k1hY zY(;u?DjB#+uS1U#nh(0KtX7-9SI%mJg{aOA|K@9LVy$DmHgRKsFS`vPQ=Mc=C2t7; z2^_Lr&#o{&sNJ@DymouXvOld!j@LFdlX)$lt_zIUHdAzhFQ;AY^^v9f;HOj;Qf}KY zUYmTd3t3i@rCH|FwCPQ<-{39d_kM3BlOj_g!xf*&+$sbVjLnh_gngup2N3uWk`BR6 z(Iu56WN8m$VEd*TCMC~pGZR7R$~#dCGT!tK6vPJ+>fORN;}vh2{eG(bzLxi4;|@>IxEK|mv7-8OaZmz2?w#;RAWta@1@%WP0+;6m zDU$~C`c1F2I4I_x>UqC+t`w-h;(bw`#`E5Zc7+q{3g?l&bRy%D%-QF#=e-VuEyy4* zShv%Ka5ka^c7!`n0cRCcgtRH+c7^-JSPa6xTT9T%`KL9wLB^?!65sAYiL#n#QxiAF zw&Iug@05Nt{ZL~Z(o;+Hu2k*su#2~|L`$m23(7iwLF+PA2rGUGG!;;_0uGFMve<(( z*I-$ujo`nmphoZ;E7*hJ*H*AQLHUHdZi1qxLa?h;``a-gV|1Aelu-HpnrRcL z^>@7OscOAR)q0y%>lSkG`3~#z9D<)&!4nB?w}QP0ZnJ{91h-hhlL&6Lg1x2I>n4Vb z2P;XCifegFWwUFnK>h3o2xR$d9<1g`Q;sL7Tfq}l_tz3(v}VuY38(s0+@+}Q4~W)0 z;(eb-fC|^E=ObQ`mIm0y!nri>tL4Aqoh!8g`OQ3Kj}z$Q z>5|3ntG-7iE7qSL{(J z;M0EV%z416wR!SUft9S*rumq>VVR&YUWbVhZ~28*hxxU#K|`CbZ*nPIw@eToNbVN? zrt!@;+I{33AJT3Em)ePC0RGl5YL;jJHMjNukWj`5R` zV>7s&%ShBjN*N5~79uyuu5n9?FoTt(3J3~dllgwdn3Cmw#U|3lz6|S7o+tAh%<~kU zgLwAgS;X@+o_K52^KI)eGXEkzDjaQyugn8cv8wql+u@H zZ=NUf%;k9s&t5$H@H~;{X*_dyo+`Bo4w2ew?eaW!c~UO<+~hlnXIGxRd3NWS%d-d1 zUOY9PC-UsZGe<}&AjK+FamsdKQYgz=e1?JG!f-V2qU#|Wxkl1D-2 zoLv+tL!qi!B7~>;8>vPxYA|N)*Ns`6OAX#NRKD&0^s^jK#X7!5{Y%c0?7OqKk)G2- z%4B8H-zM|sPn?cKsO|SJS>Io4eSZbtC(u{}!>kd#?LzsYcQE#(qDHLNOqAl^=TuYc znm$@@AWChuc&nizWmod93V&*ThjkuSeTl#Ee&a_JFHGNQG)vL73#4s{KP0jem#Ond zkOI7(!uEoYU<$Ienaia8u>pVQnt8z@9&?Nv%=C(Uc^Y2{hpf$%;gaPHu~BB8Cm9S< zcrCI4n{}8`3X{`h(qn_YWdRQCb)#Fw=}u}0%L$P-QZ`)fV|s$%L89CgbLn$cMNof+%`O` zl4e45s8gU>)kFd{-Fo=-=7G&xX)~F^v5Pq;UWagGU47kMx7F2eyLW0W{7ok`wmj%x zK@_iSIB?r)Nng=$U|MMzKcgpx^~a^;K=o`XvwF6GPQ&48o%tK>;l$7vs4fjwmxjhQ z?7wq4@bAL2j+%9j?3S6nP3lCovr2@9C2^&B7K!O2PC3)8q)fF>p^j=D)AFhkzC-txOJeY$Ap|dORi#Sl5v(ICv*GpQ4#5`==rnDJ8 zMezm(6m5s>5i!?p#)q}g$EVcJ1Zt~>+lQ-Nx(bZl;2jfYyGD+2i---`c$tS=i*2(W7v2Yg|_U1-7#!agOeO6+(?+W;36qUdan1LuM{KelwM!@0hk>Vh7 zP_nn$P(w+fRfy8_2ejUx-S$4;H zQYOS%El=^Y3CRrP8JFjoZy@Z-++}4qk*!L;kS}FRk*k%)36qseM7#=42NfTJ#nf4NL=U zjiSQu%TLEJaEOS5$BB;vaEqD0lFof5UvXV0+;KQ|0}X*Mk|w@Qg5VTbB3lFz@a_@y zq5Vt8@g|uw`5T)^lk1Hj(!{^jxVM=w#ziqw(W!!Kzu|4f81D<~+Y#$J%TH0p8DGmc zv4A(JPKkrgO<4C<>=($&1^0E*9=M}}OmRZq>c66#0t+u0ctms@j`l1z; z`H-S&t>{`iy3vZ7c65&wbwDae=4_rcBiD|4tZ0E96(Im`h4+`tW2~sK{1O!ooVUXH zOSIC8&atCUSkV{l=sYW0Ye$={=teub#ft8+qx-F>m=Q_IZk|-6oE8ujZ-_+2o4>sE zSgZ?{CHF*8a;_cqSW$5YA{D6m*ejb8ya)oc2__mJ)qcD~19%T}mAUn!bL4K9$9YRKN2QpTq zF~_O0?`yLKmIBai1^rg^+oa9!g;i#sE0t#7 zyA^w|%C^+^u%T+83T5(T+=9AW(Jc)QOH0&w3PY#d#A6$=6{WX6*#Z5Y>}+udqu=I^ zPZhl&g|XeVSaWkCm)Zifd`niL!G&l=3u;H@?iOzEO6>r7_6K>^ z2U^cdJzCF^ZmlO4tvAEl6c3cFV_3Xe&te}wOvmsyE?y+EC@Bc^SmMwgxP{qAI$IXz zXX;2_&4iGQsV8Doc(8CR58$TAH)Ti=KD$7A%~uh%(PV2?(9&ugmAm_@W~qtJ4U{fP zwX#zN<6-(7GD>_L|GO4Z7xsU{HU^FEf4NE|Z`^EM%i{REbDnej%oS7FSUcXYUU2B~ zCNJvDF3~McJa}Qg;PzvaQ*mPUTCGa_c_vO2^@r;T^;?%Xu4>)i(WbhLSP2J1J^fx{OF3JRJ6ItjAC09v@e!(_{9>S;6l34dQzFmVJLjOMoovV{OL(zLZ9PYTK@RO}< zZ&}&y$;?&-LHPjvlj?EwKrv~^T6>aoo2iP6N%K6XWUWJ|FEK+xA}f-QZj!-i{ix_? z_D6{;CD$f9*EMZ(eem;CuKtqiGdq_W=+?5P^-bmKk)ATuAT@8=%m|G^*l%t)0lve! z<)-`OM}?C_{%`JuZjN6iU22jWeBjF#E4skUcH1+r&HNq_vXt>Dz(PnwkO zVEi=I*7PjA)Y~2e+afvrV!9{wVz($-whmj~nW-1=w|%jh6>UxEBKyTSyFa-Ww2#x& zQqD&Tqvf+k;t#hi;I?#Ie$R_EA36-DyKxbfTKqX`nFXX+eCs%p%|3r2gHQ`Fq0e%g z@e*1{c<^~=whbJKIAiR9Cw<^Dk^6mva|KDz5| zS&OJPVv}V|0#zMMnWB~Gt|68wT8R-D(rStpcJ32n`F)(y#&AiaER~unYU3KR0rM@c zJcb*OUx3)me2GYWmW8R7{lgBM(^2+RZ;Q_B^6%awYlh?oZe*EH;gy9?0^J(#%O z{%9UOPYh0=Ilo-J;M*P*!-bHo<-^1vNrwmCE)jgkEyv_qYE#FB$dp9Q$ZVw41bd5B zf_iCgv6=86`1SX(y~^5j|~FC`~VuN4pv$?wp9GZ1Y-|o@d#lQri1yTU$85l zv+=K-KP+NT=5^o3vs!Q)bmsHegN9=R{z43q!gK1;eGU&4lA#?I$cZ=v{bl~k{Fh$p zAB!2lrT)u#UgEzLuKsc|q6*jXOLC1dn^A-dM(d|$u$eY@+NQk`abLSeoM+51_>OCH zwAnKVg!B)TYnSgw#LhlHQ3uDW+E%Pe&jDQ>V6~72Im1YZr648I_ zULXNt_4oL0*Y{%DE%-Zd*dhdLf7~mS_k~KP;WEfQBdnxR|~H zf6r%Dko1VBVF6uFP(Q7@G`q313vC?GZRdwfWXDH%FK&ag7qSmK%nGot%4;Uz55!Ab zwxe8=_2$->CvzUy;l^f#$tSDg@*b&GF$U`uB^yzUm|u0$ z?EN0tBf39Xku`2PK!aSz)Sj^<7n$Ql!%^P*X*O*2ZaXJQr$t_>q zA9;Z;>exf0y^<$uru%cBeVAG-GUW8zyl%Hz2)SwLOdI%bvtC)K%D)rrv5ucsS*Lvq zsKdWR)@e94xGS}=P7i%7>-3x*zmPi5xew$^3;wBM-M8{s2oh>tu9vD+dWBl2m-{cf z%#3`gS~M=*S7kJpUY%{)mtLQf?qhAjj!S zdW_8F_%9r|gI_OKwpAd)AR1^PeOm|yg5eCu`YLg6tnaJC*9)e5(wd;uiCs;rxT*F;lW5Q=p?<>;|}X>Dq3Wm)_P zJpJKWS$usbd8O+EuHT^GNhby}DB-aXB7>!v2~Qmbo({y1f~QpfMo9lkj_ThOZkg(M zxnH0Oj}NS@pW3ls{_!ZFX<0+ZYH5hp2N$()bj z(q4a?_R`jee9~5|L4o|A+Sc(;9M#q{rLFQWZa|=_ko6-}P7vp);--JV>ok@ZQDQB2#Ni7vM&L zWuN}1`cH`-Wpo57I9%vGt*V;u=yEt8&x%hFW@xn84-yC#T|Q>gq_A40?Z%C}BV9PL-UExn&;_*j^IxFxupmr;EoN)f0aQgU@aRo&@UiZ*u3wW}DD;sM%}{LEz%l;Igxb91CU)MA zf1?1QHGjs!8e?8<0cN|jrZl+qK7>iftGf`Q$JNm*V`x0<*EqQ1dFB4h^)7a8<-Y*R zED-B>jcR0w7e z#GWzd55fLHnQR;^P;^dUi?qM*IjY5d=Tju@e?`6P{=|PV+cHqrY==?8g`v2q3j~V) z@|&_@Fvi@3*<;69WS5y9NXy2UldK*cHPf;l;Yq~cABO5WXvt}uXC=$e2*<7`a?YC{ zyCDPb;hd?wbI2Iv^(XOXTd&NJO%&oB_@|-IDatQ-W)=CK`PcCK21Vo}GFLpbGvmcAM+suv;A_(G|w?=u7M3U13mt_3bs;)(M~ zA!uGH*idmof=gxm+P&{3wH? zkcP5cM`j}&0Zx-=ezpPlOl4+%CBL~(q&3mIa~)jqVBGB?+dHXj8SB?#W8|Da91D#J z$9|m`j{VMuC@2`xKMM&jqu7pfR*1HJY`}Sg6e7C&pGT6mtYE$dm= zlUYmT5yTa?x-eoueny4jrmvNIm&5yO+1ajqTxJ5{M>xhghC1sFC867)fzT2-XubsL zhqS+9#}D!CO@01@K56qce3M0_ACNfr0+#^ZgkP;s&a_-_3O*TyP$0xM*qGdE^-uZd z_#QQc^5KwqaCi9of0Pm&_B}zLn-ym&bp!Fzc7eJlNU0m(NjjOc?R__RWU`y3t&G(L zi*SB{oT;fe+gdNh?!;F6E}@;~x3Nt6V@%LEQ3*nXSS)Owd;u46w69oQNP(=<jN^Jxi)BHx z+~S@@C}v*zOm`d8sv`yg0H{)J#-{G*ep$4ow1o0Pc6mLOCjXz1v$s>6D_tD9f~nG~ zZzXqPZAOJ z8W|)~Q_T~GBeJ}LroCyK5Q;v>a1VcOEx(iG$yF9h=7IVc41_ioXP@gt z*}nktNGLDk%|XIr1mz;4l>{*498}2@XPIws1D9{z4!=kUC!(u`Cv3StK~C`U)FE9= zJ~Spmqz)24(?@{!@*{4Mo_jdy>=btHjl@Rz{O<_!(=VxR!QDX^Pn!|lL}oE)kY7I# z{ao{BpFPB%eajFxcEhgX>|1(x14}%qY#sEGZ|KGIuseT?MZDA~o`_Ouy1Z4-w_9FS`{g}F?l$GM!55+%lg1Zv zJ%ucA@Wo=KL2PdEr%^^3Lj~}!|aX0cw3Y)j{NPRj2C6jGf~D|652-@xBs7_ zj9d!%e*k54&}Kf(X#EtFQRS^cAe84pC@+9e z{>MTnucZ*mJW(LA+FM*Ji4%Vu%lK$+GUxeK7M8g+1Iq|7DwhQc%Vg223@o$#_ieEZ zpea~JK)o%N8Fq(YnI|n!FMZ8MG`&bom=>au7MNRSrVx!(+ZNH>&{H9rCnhUIQ#Ub% zXny-~2BMMAY(yhlLo(;}m1#s{)&7IHW;Qv&=H^>|3)kHKO&eTe(~3s2id;XQ8V~ z&{b8Sdh#sL)ocr0J(xmQa|B(@Rh=lFE8#g-_&-Hsviy@dpEPEovCkB-Brv{EUMnw^(RQt)R-6Y%~@jHHF5c3iIUYDKsY4wnbx4 zbyH}pqKx6WmjmD}8CUbT*WS}vr{Rh!lEja~^?HOdDu@}E=MPuNb z_yw8x>#72pcP##T{txZquXD)V2H#NLAKR2yBm;MBd1KozPx$gS<+bNONt8*`WYbuQ zKsF5&vPsa8`BzdJ_Fth`EeA-h;ShWlKQ@yk7!2bRa~nMI+qp!PazPklz5Prs>Y4cJ zdBj`E3uTTax7QkP_LnhNh-?M{y{>X=Xa7H({&hRT#^PQwHC#XVmVcg8uk)|l0&C0# z^>0vu-x$huVHOK^9Tf}10t?3ZP?WbJ<6>B_{?h=vuZ0Es8Wv1cTuGZ*7k@_!m(;m+Y2o^4INv z@%jXhC6SqU(S5Wr>LWi^1@y!SFP6YS>#=TVHqJwiWf;?s9Z| z;?gzAhWO+ITEl_FvWC5rTe9o7-#f6*N$~s55?tYIIDC7KfAyMV{q~A*t%tP2I%oa% zJ3K2iJL_S~sn(NTk3hA(bQj8GTI{px!~f6+_7O?tkRrX0aFitbh{>bj5QMCcA&okK z3Sy~A$d7ug1T_!&QD5q{PYrZ_R6MV${2nWzxKhO&c5JSS*@ItPt70+(R8_nMMqJty zvd~%z@htK1exVpRsK%dP?{>_rttbaWD7+-6P`?!)+QO&{UQ$_=mETe{6=m-kXff&= z+uM7Na%>jMIe)yh@hF_vne$V{sK3w6=WIOElqJ#>^UuFeZ9GzE+l|NDNo_m>C#a2Q z1)o}s`Y+aGY&`Orz42rdOy=AHb#622PpY2%;Kox*PT6>Vp)l7z^E|V4~W{@{%E+%)!?XOslemYVuGoQeVU`9L3Xs#olHnSy2f1U$MLL zuaS-2&;N$NVNP@~*{R;Ue*tq*W#8L4X7)o*l}&Q9Z#E z>N$pkoP#bg89_zAc&+)Fv|G?IH`p>df<4{pqNli--$zQUt%%@3bl>{uc0^yUtGG(1 zo}&cZ8{dfE>>HIy#8+kyF9!^GvmLGvnu}6mM8DA*Y~|#27k-b;#S|7F#@Z6Sx@Zy? zIIl|+xX=#si+V1%^M#G;-Ql7$Dv%a!Hs3h|;V^29c7b92dbhf+M^-b^on(&d9k(O? zwJdm<=!Mm)bL{rXoEqM!nKmcLBu}pw=*ghX@YTBE_8y!mm#PMIpOIXfO!Ol4Bb9oE zmHHs5oJ9X^_!>){+x(lXq^l8mZ6h0V1rWV7m!yy-Y!vViyNDFT2((zBI?OGkt4GUc zfe&7prB>FG8`R30CPkekMZLF5R+g=R>@!DUVUQS-$gy-QQD^L-I;}016=vtkHmk)B z0hsog%Fcmd+xb~{hk2{$a4KEt9u+9r?K9VIN0)j_hOnEUI)75<7wau=>f9Fw66&N* zOhqqxQ8(-4qFl_c#ZnNV-ld>dT&=o0^EVo2LGCL&{9IR{_53w|7h{D+AIlg}vRWdQjoIk0wMRSN) z$xo={Dl1v!W>)e%m3*s}T$@f7MmL#rxs|*zoxDXQ54Do_q?7lnlaXgE#SVJCS2n(RanC;um(x ztXKwYiZWpCLmO)OO%HMboKeze#nNn82?MBDOhHp2mtlxHxqorZ@ruFsPE^}NQTwPz z!;Ves>bGB`tgT|~%*_8;-!Rhhh&0?1(_}3@oKqba(n7xU~`*xbAe_HpY zOVX>k0JERU5H{|q%ZBxMT#B885=ZVkic!t~w#4|=$e3$N#0X&1R%lM?VUy1lJL8X2 z7FRtt;L3f!YjR&E@VUk{$r0Dv{#*Su9WKh!s@}y?II%LKa|L*>4svIP+&s_WC)Ycd zpI~Gc^{Dupx}ZWl(HE|rwA*iF4J&dTr&aw~KKujz*E@_aqMZ9BIzyry9F5GX+v@I8 zr@fV>&A%iIcbr|86}D(q`wEvnY#q-)3GOlO*EOQ+|G+BuobL>_^mK1{usybe~pY^!Lh0a`##T7i{mB zk(7Jfzo^)uMv^(o7|Gu?96ORTP;L5OjpP;bVe3c^ljy%0$sXisXCxDhWW#|8bpnu_ zxIsN+!Xh4$|C0gy>9E+9p$`6su=uO`V@J>jtNy2*9-tz$0im36#@5z$xGB>=s0?_91CJ5>UJ zUU?&+H|Q}bxf)(4HyHh(kara~Ow_Z6KM}}l1oDoshGlc&N`ZRT@L{!vbF}4Z z++GSg*Cx04Yn&H#(yEH+OM?3!ce94`tu@>%LJibf%5%8DG*FaP!M)X7GsCqtvWgR| z;v(0%T9qbW&SBL$#}`r1F7SF{xI=9t&} z2Y|JIbMMrS_t(L6`p=oNuHJv<6#P4fy$c$Sz-w;dH|(vg_uqT_cKO*QKYRJ)%H!(m z&bgz-MG>3!*AKhbv4;4j+WOyAIMz}S=ziF(jt%v{VYi`3_JU#8I5x{x)7)_8rjP2E z571V3uP;7F+uft#QOO)}d{tk3ruLau@9(>5M?>FDTkC&Q;xH+>_YTZQA;{H>`r>;F zcR1_)CzX9$|6d30`xdHKjG^b?Emxo_Htetr)QbX4AIM!JnVUjbHU(^LKWA9{I%n$% zSGdE~-WL@pVc*z@DvisqK`E$?&*z5oKMELU08TdmPIZ9OdsDD1lZ$_s15Qs-5*$pO z1x}~3wU4P4a2oV#(77-9xxeND-$eylRRyh2aG&5;z|&a*PZ9Bz&v9-O@Z>js zlG9j#x?xg6t~Dy^HBhSx%BK$iK^KfKqNFp3#_s{+OA0V`cb0gW-p5TI+I(MD-4=J3 zJ={%M)lITpW^D`~$PgjEn1kF#7UT5?PW+a|$OU$Pg79a=@OEL3Sc6^{-O7l`Exc;^ zm9J#PP?U(P5nG-yV(RtPD`mvqu=Z9_{eeYd#5SuD>n0<%f)P8MIbzRHQp6}SBCLsue+ zq79`uA4g)*57qjf{RwxOtLnz(CRX_^`!dw{u`P?}$AzZXDMr9DF&jlyD4X`$yH+%4 zebfwU?MV!x``{k9CTUwcCP6#@q1Y$O#4OF5NkHji4pn-Gg3KIk^h@FGkJi8Z>o*vB zNzavTG-me<;9u(`I` zB+B9gZL`T>Mhy(VCoO_eTFDvX6AO9T*x&i7mcd#6l^UGoDmGy5GfJiS;A`(E7lQm5 z9GNayN@ahSCH7L{`HqUL!GS*wT8hlU*d2(>?m{3n7WtM~`PE^V(DAv85y9xgNSTDn z_b`~*-+OrGp{s-{-7t=g2Ao9;lmWePu8Uq*r3Y=DYAzTsXHnwz`XkYxe;KsA$8mGM>=D>GA9=<9QcKUajK^ zd1wq(aGy{AX24e){a(2~E^X}q^iQH*QIeynH;CE&)%--4qwtHM zZzqRZW*zPgeq4L`lRd4KwFR{d3*9!;A@)A;=9X3gM^Nl}kQ{O2)0r>6=yqhN&Z`gG ztf#bnN2Y%H6`74VN?+TuN9LgM2kenqSSkJT_0Ou_rWRH^_Q+p-^%Ht4{gW9@^}1Ew zfSI{!Wq>E=kt8Z(Z6TID={L;f#9*wHgn)Sey2b0m znCDXiP>J=u6X<6~yMD2j%g&iTM3aIVCx)H-gZkNCaXG_!6M?vzWhQ;9k`Qk*ueoM> zGF*g`TSYICXa>!H4%n%-4WvT|Pq}_k4)Lm`-Rw7>5qjWsw}@M(4%2$NPM4a-Nlm_B z2WeG%buCtk0(Ny@UcH^WSWq)fgmiY8TR0^yy2YD^@dTCUnb+Bs7eFfBN}Z0NGafV^ z@y?Z?KDL>vZM}n@u4cJhnT`#F{YNm6WZmu#>7Rr#S;ysKVlB5fd?R}!{$k2nZSxQA z0?CWV1ZBMbc^k|86JLIxU7_R2vVvo1XYln!df)W*@`@8j{IuU6Vtf`F9xTs?5sTY<53@fil)3J3~lE)*^-k zT9vq`R5qhr%!t5Gh&9%f*YdC^g883)`?*}ssa362Inmhf&-H(tJcNu0tjCSn5#v_3 zB5H7qm2))oe^<3RQ%u9l55VJ_eD zMK+d`T%akE36IP~o^bPwzdD^{aZ7ZJr2@_&A=@8^KqJXn%!F`N!{9zvcf?Q5Nr=tV zAamH?M<&Fr+>b?ZJ?1Fi#2s7EUjF2U#9Bta%(7d@#aV6Q1=$0n|Ca(_m zqZ2qI6U2)5TdbC%q97&+7B!fQoQ$K?qNRP+@+w-j*5VD3qD~+o0R#ewpa_Kf48tWT za#NV^dDcE>=1ejPNs4d#{(ql8$(+mH`|PvMT6?d()_T_N*EOeTo0c;f0OTmPM_5$2 zJ<>tAO0{fyXpV+%yIDLmVmzd-mcZC}pC$4TcojX`2mj#yA2JKLxgDz7Q&u+yf^QBn zX@~9$Agam_8}`+33GMdw{v2t@WqCqRrScf zInY@!7inwp8s|njaI^*G(J)pU;GW&iu@_)y+t35g4|6kOp<^Irjox84zZ0ZA_A$w- z_&>74nmXk-;k8C$Gg)~pdSn47RbM>9mcXsh*a}=aGsIzY+quH5NZ(0`5e~=)A>LMm zz>wp{Mg)3w6}kj(06rF1Q}2!01z{#k;vZYptQ(8 zN4Sd*o~V`OqL5yEq=QzB$T){v)-8S4N`84HH3ktgu|*Zz<$q?QU>(fVa65ibs>t_^ zeqg2UoIk>ie1PgoJz}I%ynbH?dzyAZM>yCcT=OLcp40L?r8CaC`+r_7m5`lrcf^xVA zTjU}c*d~-#?3AUIlw)a%FV|5k<&jG4@vgJ)uJC2la*Pna06)HT!fW7Dp#2WuL&yXN ztv>ER4(RcuJPn^tzGZj=6V${j17+F~)jFm|;gWcPA7F%0P7?aE4n5cbCB}UYap;Mg+jY%@ z6(MIje>aT8AUC|KO1Hx!Hx4+NLN zx6z>h*)NWCEIc2fmG~a+kGO{AXV1Z}Bb<*?)_0Om7al70s<2TyKBQF%1DGRB#BYpY z;?Lr$0G*PKfV)DZl44>g#z{Uow#id82?1uQmC$+bHU1*>aaYS;UA!RC4!*2W0B)6j zgQt&}?F9XVS#$%bJS6022zXhRTz-*A<7IvcF9tc)no;5+y~BTlWv%a8%#-0t+SrP# z4!J+(8(}Z1cX@${J$5G}{S;Qfp$SqpRqesi+!siSmbs2UOQPw&W#>50%WiX{IqR%9XB|CouM=4YIrESSnN1BXPzp1m=|3lp zP_IXxQL>)5^RRG2c+(Z_yjj)b&hiGHB2_S@gfW*?U;@#5e~FO`^VYY2#Md$2Tu+Wh z1D!E2mdQw&b>u-8(A-{s$$Eyh_>7rk_P~&KBaF#1Kyx+nRpADxYQ1bqNK8kI({Gq% zib7l?}M-dKADZX6bX$6QBPRKAqFALH(?7H&V8; zc;psuU=Zp*ihqc2E?rpAS@#QvB0*%~J~WC>V90os>CUy2kxp<63^L)Xak1G<|fJ#X;*AFmd{5{Pa))QsiRs?sVUqSz77|n=?^~(CJJ2g?&E2W zPQt=NoV_7A0e5seB&NsQk# zD&=Du$2tik-*5(L%5?SKKxY0H*Whx{hZySDZ~+lD@2c>AJBIo&zM$@ZQf*8||LgBj z1)G{l3_m72GlpOHKd<&M1LRqEe&GxJE-{RM5}L_F-W-G3-z1J7q4A#7^Rqpvqq2dd z-kmZib=1Wf{DUBQY*1Q*Ao*&yK&cTVUyHrc5hPzN5&eWxGos&zxr!0}D+-@iQ0mQE zsT&`SVe&N2O^OE5R|%7U2;NO%8k~#FtGebnpj@h?5{E4shl=FaeA(hd2$nw+{kA|$ zr%_PB>+qkOOZ455*8n-`@XFT+DWySbjgNvji zu1;IStAwJ1D2M zavHQw>*RF0bz08=U2?EW4Uh#b#^Tt}VVqbzO=h?8H0G-qLtp%PLx#@8i#KNI$#{w| zG-EC#DF7}Iap!&yc$F=7hQ0_Ap)?S3b2-Y#xp`C!kphE|N(z7t9&b!!g9xcr=qLPLp=!Y0Mvts4?sPL_-GpHK~|69JaT>*oX7Q$vGW1!c-}=e z!l2d1g9*KtKt1yDO?}3bV$Bt>!Mdk8iyfYQtH2D9Kt=>MD`Igr}yQM{8(hI{k;AIMe6 zuy{}XWt1X#9y7RX>XYZcKf@Q8;hGK^nlns@vOT(dHV(j-*bRk?0sN-oR}dW2aig+g zA_paPN#vgAIo3I3pXXdzNEJR$T`ICJW#AH|^ok-W;4sgo%UKtvoR|;gp z4uuBl(D+B_fvM^%C1iv6WaZ~vdwkPhLg9O&stSdl_x#4F${@i}FA>3o-~0e*0d1G$C4m2Qq~1?rE6w+9j_Kmf6ZQ=twk3UT6zLI7zZ=zKqd3PGe3#IZ@{4?8$bfD>mn`lm*ksMB*x#7X zU7_@)xIRmN9ZDWI{0mei;9s_L#fYI03I1A-e@R7u=1fOBz`yWi;rMwz#C3VA@Gr4e zWMQ|`556_tWveZ~zp$=}f0;$CbgnFkMSrFlmiQMbg6Xvfi$a5;JYpWpX@GxWzq!&( zf`1{h#)f}Es=+4lFMIKUn#aGOF&q8`IMBDzPqg@0a{Nm@JKG%or91)uLLG)v8}To= zqhmdm8XC!u43{5X+_q#Q{$-#Y|MIDYf03&e{smX*ZagK1e}TX&{0oZ7c3+`45Ea#0 z{L3;C`j7jH&_Bkeeul1xmP|{;zib0yB?$P zlA~YYUuHJOznFNEASx<6$)DJS4Nvm&WROvE<(YVrXVir_o@A1`5XX~@Q5W)Kc#_-I zg#MSpoV?XXPOb*7V>xggxR7IB2;rn`n4C-iu46B89d`?^ z;|}6FHWJryBXJ#jf$Inp*D>K#;5znT;KZe%9(aya=W=l}u&<8>^Jry&7Yvttz$6q` zAYzwL7EJB0>HeoONC;e*NzG)6?#GG8RrF1sHn-km)EC!rSjnMAIvIb=2;Qxry~p^v zVh7x*1!yYJ6Up8R7y*74!3<{4k&iy|b|f2lirK;fGV zM@4*Zik`J#>`uSKot<(D^bl73J#iiGY_#(bPansr6^l9#E)jw}9*oC?-;6R6OrNK{ zTTcTLOm7S-Iv#NU zGW+iLnF04GmVVn*p{*5g?{E*mmPLn822tQ$-GOh^i^R=i7Uv~G-0r#lAA7QIbrilX zq%E#W@n+2%yF2^%g8ajexf&-^c7t%3;W zf2$6(WCZ;}K)X!5Rbl21;KT3JRsnTYm>I$GZ?tuSy#nGY$ZMbC8c|q8UsY%&-VP>r zunikFASSAcVQOL$t`yrjO3 zGT~dmL3T;yXr<&*6JD}OXQm?QRuMoONvBgR1;&Ss@x`q`^?{S5a%rv8QB7pZzx zO&ATtj+{S7WlIk{rPL-WI!&oYmF~X8YfTv6VV$3Nt=`0IolU&fMBud!J(l9aA0I$l zhp^>+5Pv7SYGv@QbWb3DYr^OqRTCcjmIr&Q9v%${S8suE^(BOB0wG+z3E_Hx5U$=t zW!*>!mzNN(vkBpH6T)=|AY5k?!qpcLF1*IKl~?p8jO+KTa5Z6EXA6w$G{Cq{BaG{A z!nh_7#`Pdx6tIT1TPxj%9^J+`rIMdwK>Wt5&BYS4NtNUvxC5%4s|dzLY+5w-h}XH# z)b{||f=VL1Hq+-l~*P!CJx1nPA-9@P79H0mXa+KY47#EaL#&^dkL~DsoE=LXC+l6k^4Mdbvy>{cZ-|?S)pe%$h*rNX&x0&}yQ>j~xa* zu`KGlv)^p5bAda$&0XG($lecVlY~}t1cSx^=tR(Juu0y2nL*Mqfw;3fk{_|efPU!9 zIznXc&o9qDA2Y}#R;4tz6KL-UoLVz+JILl+=b4dlju=Dy~oz z%YX#C%0zeh*c|^rjRDBUQ{v!@qhCj`@cp?O0Cyvp&q70Y&jlFsHMR1EP8}Nn&(}&8 z4Ny)VwU27Y;o@dPjay^PGEhX0wmQ6}7(hr6eOPS`>0gKE}%&DU_9G8Ba zNw}goDG9l+aN9_DBWos*FdJ7|NCu`$J#1FTSzjm3m#NQTjP5GY0%We)$974KuC;CjXaLneX>`i>?05l zy%nTsq{Byil6rzw0hpf~&{+ab$Mgsfr5Yrq8pBj28heV*$N?=zrs36;$#$;vzN>q# zJgK95Zu~9OGxD6D`V1YF^3%dhJQ0h2LVSO-c+>R=Fo(%^#w>+5W!D4!-@h5m8R$}u zizcM918H>_W|g5cJd|HMc4zhu=4KCJ4%(kAhS zC)gh*@j{o0pCLS@y0JaGsL}JP-^QoJu%U+d*$&C@vl;LN%I+nbLObu_!{^sEjh{`mJpnAA5p&@HZ4#qD@x=iz z;`eO(SGq}>z!}Bw2|bGCtbhJpLXSBGP2*>c33hsjRllCthB$5(QR4mY?M^51STH(r z`Wx7UA<%!_JAkH&JOC&AhjG$MFX?5RWxyM~h{uiNUeQ>WGo`UB(b&Ui>`FE^#opMU zSYx)>Fx&oGcKqe)S@AEDd_P!3gB=@xdClF&!e5TIKPchD*sxyzyZFo7eg&dq&%9ku zc&7XNLBdwzFV~&h0DpPQ_gh6T8OCMnamQcYkH>t||~|w&!b8l8hzpJi#zbhiMH?zC~Ku-I%V-lx@Gl z;Wygovqxy7zZ#)EurdV)9lrQ(X>^3PwhqS^;@@>?_%kj8e}?uMp=COD;@%n_ti-`8 z9_-_v#W-7vLigvGg+>n=#-sVTUd8MA*7Xr%c(i$hHg4?*ZGg723;!h!Ra)h>L;RvmuW`wqS;iSFMD54-ssGpMEr@?PfBm}_3KSI~c)L6g3w9FYFZyZn4 zmcxsv6BL_PVZ8}%mG_(brQ#`|1`l%0# zdE#-?p4gr??sOUz;L@9SRiHC+wN9abftZt%SY|;;E9u=Pyu8Qwyka-Jqja=7_tK9y#p}N%h;?;$pb(h6Xw# zVO9lvqcu7(yL7m~FblhEuEU~al~8hrP_nyLvVv8ofLOAsev4;tj)HVeS!Gcod@Ga~ z(<&>pGjrZ4EilZqxx%Ml|DWKWNYWrm(*2O6(T_q>Mh}IMAR8k7+y*2^oSjY6YmC&h zN91bbq9Z)o==7|EkWZYg<)1CIY|I>?!Ooh7zujE;Gs;zuzgQUH?=7xc6dS#de+gt=TiQWp{Ax>zrvR53@mAwKY zJzU)M<@|WFecbj{7`1me*MAYrtVq8&F$jAtEIf4i=4I^wBPx;h1YvQ6h36~`%dT-` z#DTC^AlFt-d7(p+ZKa}{k(xZ?ySzZ>pDSLBV5o-Sm(IV7vwulOoDY$%1|u$J0>-S% zvj@Uly9#d^X|X7aR%r`oJX#46D!&DOIhqC}b!MdMDm4&n@&kJ-9=gjW-j z7+(!ZEKfG+B_^@SHj^0WWtqeXSd7yP>3*E%O2|LFhG7lwB&SzD(yP89y`B-lomj8v zg>;o2QVL10ezSGwg6OvLTn7!bU!oLUDv8uOYEr8`%wceql3E-9g<5?t&+Z2U?O$0D zQ4KKd&_4S(Pa(Lupq6RVNi@zD+#6=fyxuEM)+a~)+VpxYJW6yCmEY&uBzTd0%s?@`NE%OIUe07FCOxU4*I$N} z+uZ*l2q8i^?w}0(!Lk5>kYcugF(I_+)o3(v{|BZTYHI%n9W6Jt{{wY{WAFcPI!ANJ zSDW{LsKht?-`)RVBsD#=%dOr2p*!mSNALfDeZOA92X7t}aGdskaDYP+_J62@IP$`D z`9-{W5C;Ufv~YKaUAHsdA1G^hfR6L-4s-S{ZOQHqcaCZ{(w{kc5a!RQYQ|7gFdOdf zun_N%WOoNfHDY&%Uid)_J=%fj#(8@BrR-VGd6q^QKYRpuz_xrk8vG;dK>^%bD zu$=tOnwVARR&K&NE(N7P9vQEOT#oQsZnD?|SFODp*p<-M9=Ic$Eb^I&A@U<2AjPkc$%oBU~zAN<-8jn|u!9vu5fV#bWEH5YSqM|$u&t@u40 zBKYejC;p7@^6I^aR@;T(Qi&mJDm}Pl>uync@UrQk6k4_=0Po5mG)eot2yVqs8F*HM zcp{l^JTB%Q4?^P(qMj@alc)WzkEdG3TLqDR!sDvp5=cI%$5k6!O2#t02IDKB&1gK9 z_PfSP`;En;E$ugg8jH%$Be7}Iq_k7{+=@8PT%Pqlm*Pmhsm`6QHS zm}5;Id{q6%<5mhLi~VLg-oRGN|vpr!gt}!Nk%gQl7wyaZ>JM z_{A|u8AO>TNSQqEHz|m0ML!G$@m*U@!B6gPOu?^Vo@x^XxiOE8g75J37!-UIWtyO1 zEbNi2w?>8f(3Vkm*e1v|6y(Ib-xOps@Ap;;@={=XX~C$&imne2f(fRK8fD6WE$0}f z47Gx^Oc_`ar9U%Lh-XDUO7icJX%uRG^6$B<8BhNGN1h%d`FAnOSVkc$`S%*Flv^}e zenkyM$Z%^~5P@PJS82(pw-dUmYFw0aK>wG1!;q6p#sxWN9AqR(ZPg>A5!v;~O#`Yv zdSG=*RqooQmGd5P9ICox?Y7Fx3muhJAFYitp?5{)<-c+4taPU%Tm%Wd!-e1bY;y%-zff4&Ue^_(uEYf61h_>zKP17=hYY=I*0> z%MjTiF>^QA!7>qU$2YcR?hbL~hua7OL%fItfq@xR^g~^1Gk13%L0)K(x%+O~qY%H; zhRodqS(Wi3Ds%U#IJM$Mn#tVFV2g&CyKCc_yVt4A-A_Y3M92&#eUoB|iK#)7CNg(} zVlWDUVv9&I$=nT!sm$G=SnD!(?}N{*QRePnqHCmB>oa#VWds7R8#)-2EvF zHpsgSnn~vF-{2lu>fb`3&37gtP&bN}RWdK!0PwCJ1x~?)}>cwBpxE z2=pz4yln(p$eOm??=R!LMFc8m!G;9l>f~TT=5DQQ83R5zo0+3C2cY`!Gm@>l@5n_Q z*p^t?x;u(=h95PvbuY29bssF43E4eS-JOJyKDi0W%+}2(;S<4v5zp2gUld7nM{}9F zkz|1N5;Jvw($o{hXoV__p-41ZC5fL1qF1KLYA6rkJbqS8R#RXhg30O*oWX~EC4QR9 z*Zqr|Y$hw4bu5;z8$*I4JZwfZn$(`fnbB`<%ls_#5PSZU98_ig6A~}9bbj2l<$(NQ zwQHHS%r!P2MC(?{)Q0III3hPr7cq>@Gk$qFDl%P!jtj~2pNy4mKIu}Xux9h0&?3g9 z5y|qO9Kr(XKR5pgSLB2l%NzL3mn}X7W6^WycboE`)X68YaBfH6TWH?TZM z0)t8$^OukVRsNE_V5OM3bwEX&C)pDlPcnZAt_VXu`1^(oc@XV2X2_VKwHg)4ko*$K z^Ox*E+Z^07BoQmezE)dmU&vnq?(?Cm&6_HZNB$Ci;+EMdo6Am;fmRZ-lUz2W zL3R?BIG))_I<9Mx&GH}DH*2#r1rc_+3^2H5wnTQ4v(W!zWGCThj717xtWkCn2S$!L zG+i)pT|7GpQ;v9z5|@r&u~<$A2Pb47iDf4-Q;#TPXltyU4fBq0cvH4c2N+6ho#lCn zc}G}8Vw0`BBQm_OxY#>Sxw6T;BR535V5)Ls&Q*CwlG{G7+=HFOVG?Gup{p*4=N;*5 z-r$fI`UP(o6zM>^12-h^$N_9zZsi?eheDO@VIY;fBSQa#yd#6376a+;0NaCsbOx#_ z1L>7FSb0a-gG8h1DXPw3RcB1BPIuIa7JHwVcZ6Lt%hRWe z{2%u6Y%P{|gr2RC_Y+uL(Gr<3S>BPogJGF9ZR(+(ER4J(-Q@Q`=+iN=yd(UOX5Nt; z97fY;qoS2}#8OfuKLYlAB+Y9-hQ2dteh}4Q`Mo(D#JQ<2#o|Awqa{;Wdb=CH&KX|6 zC`+fL^Q`}jL#pj6wk?X9S0a*Upat6R)0uZe-3O5Tx=4OzIK;-?`aV?XW zGhhKQjLa|V?0^cXn0e1OCji7BVlGm@}Xs?!|Hj+-V8kT8vJKIRnoA)p5xg5QIta z)#;!;H)~DE3b0AC0({n$o4_&)z+%Y^&?pN)t(gTN$nOVHiV2_M0ZLme3joq9(}94U zS0UUyhOD$$__p8yEfl_U*q7F30XXfN#=_?%4jnF;)@A|tFV>4^0XUJT$H)SJ2`_mT z03~TnWdYbmG6roVt)nF-F$;iA%7~bY1xN<107(pBwgAaG$pV0ly%h~xfn48qH6l#n zGN!Ts+=CZu8*=>$*0f~-xR4|=cP_L=Ny0wbAPd0JB*=A(jLl>L5D(!GLCe@=&I26O$6J@ z0dQO|roXVzSe8lflrY7}VP@TU>O^O;;o%(%?N)k~2 zO7Zc*yWNy>LxrvX?je{mD&WC!XVGyp(FLs!<8h^X0=zd9MsI*-H=yc6I&a)`-b{e= zCX3FS2jINAbmv&YP3zyt$Fio2%)(LBuJXH(BDm=}qTNZ#r)#(0QZq`pg6X zNZV4u>n9-2n@|Vp!4$;n2Ti>GQ4?{Fp$c4K;q~h+SIwFh;q@CM&hJ7@TmoL70gVx; zGSmuMjW}maza4S@49|~=I4?k{7~(vLz{UmPRalo2__x%;=^t#6<)8_w9c)0gj>m&) zFQZXxW^Us2&%#RMQeOkANtT26V5DqYmV+YJv}ZZE5f@sR<=_`A8q=kOdNrV)9j~vI zb>rR_qH0v*Wgs&!U8zAV?D_^KfMWym0mKiYB4O!ZK~Z3MjJeVgbBaEt$DE?nYD5PX zfuyKeKGJ1S<6mSb*T_XWKhZ_HmM+pQ+yeQl$~*fHS_V*kuC}l%FTf>w!Jt}P z5XULpr9cTNM16mxaf8Htnt-UUk0I)Vw(wz$v{v|Vgzrc#+(gtv>;zHI!8nen$6G58 zDa5XIi24F=5=8x*Ty3`vQ9q7VeAnL8@OZk-T6l)!#{#Rfs=u{06^?T8^w&9xzc}>JOzlbX>#W&x} zvKB;~q_ZLFr(sFmT5@$g&g8mya8h#3L)Y3yt^jK$z`;l3N=wN#kY$sS%UtH(J1T*R)qf-7n_2Z|6-ucq-i}$ejC_NugW)#ryejAo^*JeJn6Zh zJn1C$q&i$|>Pep>4+Ov-3LJqan0R&!h>ma{_P4k?Kiui{*b6s~&wT@$o^D8dZf`sY zZ&p-@=Rxzg;X&UYAdgAFgC>j5_29u~eC`D}1QzrJpk0;&3%Vi&2WKp)5G*Lboq}My z9~d)*1s&9fAWp!tfD*&O4jcd&n(5ffKl5<503~k&!c7oh0&~lB0ARBgO^sVYoaYW8 zJ_l&?Y-rEMNY6iEmtq9n5p4TeRB*m}da?x3p&xfe6wGHNZ zC9B3@o}y-X?-uIfw$6S);Vxqb4pBGHAnP zLIxEsvrca%F0=Ec6ILpSx#95UNer%+&Pf+O2lQp zf>JbcwGx+EFfQ_}iODRuHd5Xk9`n-hNN5DqWEF*EgepedHFFhwXF@Ek;ffBU`tX&9 zph7eUv9yBK>=4Vi9yPyNcxBQ^wRy?)8xvl+rb&2Z5`1Nar9wCX6om@$!Tq8_Tr-wGq+&M$6<*ph#RdyPyXX4tw2wXKtO{q)jFDvy`Bqqm#g^pK7PN_iPqSj2f)Dfb7!(|YGEGo07FQ))X@fmtv+tN7A2-+| zhOc8R?WeJX%B_zKPJ}(4-dBicg;NRaaVFh($c5E<*kcK6#$k`Q^Yj?7$079l-NfaG z_HGlf$JHF7xw=o{-?Jrb3R=s0YlN(+S~YGLVUFj0bUy5lT+O3}BOKy?TD1f#_^NBy zR?>49s#>ykU*)e09ZRd;U%QLo#$e^9-#GSHZoXEFY65r!aviDIKY=D+Rkap39?3f3 ztn%hp6XsLZ2)~GjnP|L!3x4tQ3;9tS;1@@t@AQVZ0l%2ds&V{ccbr<@xn}T-QK(+c z;1{bB@QX;0XHx9n0?&Kz0#d9q#9(=Jqr3bh_kgZi$uIB%Z9|`($eK3v*%r*%7R8#y zFD_=mhUl~Z1pMO5kf25cN=I+oMxZbz6FY(CXIuiAZ6ex-Czb(h+SuIQvBjx;1{bFjy%A5|62>b*hz#l{22Xj zn-6vWHV$8W8}P-G)ZNGFl4~N1^Eyi_!xzH3=HCimOkxiT7nv?4H@XLV&|hy6d(cXl zUtkZKfit*x0{CePyg1=(n?1<%CqXtG;pz7#$16_flxE=-yFh`k;}z>rm3YMr6-~hshj|fI3H-lAkc`_ zKqF$W9iS0|aWooSM8u-6}Hw5>jpsUBvbY~jta`3GL!kx231`n}kqz&TvzoQx#nFUfST@-gXu{>_|1r>n94ooVlAoLm&QY!&2Z;v8$aPZZ zELBI3)!BWP&A`ZNrh$=@R5U#^&4v?X?-Ox??3!7=28Yq~RC{^07Q+cn2M>hKenQ~{ z$zI8Df(tc;6O>VNUzx%Q?v&pHp&6MmoFMO;I6*R8G<^yxS~x)yA2=O1LNifUFOC!m zIPhhhz{c4izUAqB6g2gbjo5b(`bh6x;kxkHRLDxb^TOXTT0>ZavKYF?fB9`hBZN{mz<#-)6QRj%^<- z+XcfYDzLvl@KI{3U=oOFfMUp__*TJ${lNfggZ<^>Tk^sW1p8A)(N@C#9?ReoAQATW z6SUMO*k5~AjKlu60Zw)-*xw?;(Vzq-Y(N^{D%gta;{2h%pK^g8`TmkEz zlqgd~#=89Y!v2(zuXV7$i!oDxww9er!T#YoS@=fFE zF@Ss%Q6}kjz7}eVTSMC?^mqaJPP1s(3h>zrr%MR1B{d4jcd*Ui zv*oO51MC3wT+e9&lGnd!NZ!nEu#RpF$pZwh2=8q{ z@Hi;NAb6I;uFJ`k5~`!3ipJ1)^xr{|YMJ{EjyuRq?w}*s$(D{h#$jL|){R*C!Qpp+ zQnT-0gVjNFjw`J0g;W0XVRew518s-ZL2QmItnPO|l3DrxRal*NoXK?y<*G3X@&9F5 z-Koc!guT;}lJGwpR#$0*)!l<_WEjA(-^mg1fP&SDRR905I_JLuR%hD(xId|}DbG03 z8{hxuZR|=2``@WKV*h*B5PxK^tz!Q>a#_>y>ERTc{jY(2@v0otxai@6GH}Kmw1b^6 zuTzaL-Xe`pZ>I4l?TyFrbI?T{;d-`GT%8lHexSMdO{itMir)-hD$dm${4~JN6(TWR z3*tA=p#@WIZ^5k5jo@=nl_$XG1`!!_KaoM>65(?M%vBOA7v`U@arP}>a@hEAfL1|( z9KdwVgX3~UUr7#*iwAGYLID=F;|Y#atJ&6p<4)-;dS(JRZZPz{wt?eLXU#Y`Za*}v zV}awC-N1_bY6Cd#faTkvh3mM1#-jE>?92CW8#pe7Rb$||I&gIJ z;JBqIaSU+Wt&|XuDH%9U4-8U#8;hN@7!=IEA5wDO&?f{DhXnlu!vUwZ03tSk2g?Y9 z!w!bp+V6SF-Ptl7tMPa3r>M9WcZo$sN|~>DdqwQ_XzrRwOe%0}U!vqulo_BM)L8U8 z7Olpgf-0P@4w|^OK^R=PiQe~Z#kEC`Gp_BuRDSe^xV9A_UYl@je__Qqt_{0w9}CxZ zJBlR3wP|CbvfUslrJ{b?0&DAZoMCOxb|Sg{qhM`)&2_64E3RN|@BANtwKdikDy%8} z0flGV{!5wCizkV`aPTXc(wE?3Q+T!yzsC?^LE@9)*>W%}#p0Eo;)#W4n}#7XG~wcS zKuHFTQt==q>=*b?@T!U-VN}WAe_?{!e2BH_fx^JEt>7-?`5a<$5Q)?6HIxSmLMwR! zHI0g*jh)=@JKZa`BDSR4blgL*(m&lZokoRwMV(%JFjXsl2Up$xY_I=;3_a_pR`wT; zc`+p0N`(yUAZ&c4ZpcOMMEs$(^ z#@E`cfmv?jsJnQZHaIoqmlb_Xb-765 zP`Uzl7UVfU_Zk~~1|S_P3SYxUn%KW|vsOyuZTL-8viEowC=u`RB;57-uSSpivBzJt z$6q(-@!%Y{1m>7Mehv))%?2ZpHmh5fvATG>mYX{2vb2gF=+o=Nn3*YtLcM7-|f*5 zc46)K$9oKU>5SLv20QF6t{mJ;t2%W5{L1+gGFpdOtC`fIc$WvhUy7wyp)Z)BFh7-> zAIN|MZ}TIW!2cY1%*3n}fkwovQM4Lj)>h*k8e`UmOxKMeuf@@7!8ksxuJLYtY}d?S zjVB3dYQEMGnNnE5s1)8#K&0`T&2g|((C*W(MGyEvO+?!M8CE2ULZrcuid98JL|P3t zTPGq-MvE6#V0zb-VChK%{+ikwT(i%>lMy`c_y!&m=H`$zE^E zfG>Cv&lb|ISpye7TTq?_@k9_X!43Arcxvi-cB~l||FwAtM=D_+KMHF|_ZJ0uOv5XI z@N0}U#dUUcnU%O>GYHA_qbZy<4_b*kf(eN`0Gh|P;vbP8yuGc(2~rJIr}?sWaX05` zjE38>oAYxhfw84JRWDZCig)=uiW%$9l-J|%vclT%Uh&6-vGLc>)c)+qLd$4{?+dU$ zdv{NETH%}Ani%LLY)`z@+@JkKt)vR|Vu+r?$>Eo9&NLn{eGgGvvTGl-(`NmuUB#xf z6Xs0Ey5Cf#OYZ( z-M5gEZ=s%@lGAYB0!rSEVhEDpB2O!=XKY;puB@+(fRe}(jFZTV%@c4-iwTH+9D{%y zAmRiBKB~*TM;a1PE15#y6Yx>ZQ4kx8C*j3WtZA;30hzp>r&bb~(GY1~QP;ws2=q;PAbP&alD@sC;tnLgb9q0{p2>^vpUS>cXuEI)a`wHRQ&EnFEc zgD1*=a<)3H4F4LZ+6O0(FfY6tE|3dOn-@3N;n8O0wR2Z&Omm-5;mKO0-X5)$hA%^D zpY|@%vs&qoAi-8{m>DuGf(kKLlpYwGLtQh-^zky@`CPRaM8~K9aX$tgE|t}w$-$IE z@sF$4J+LyRYU|oBapqWCwQlXE%1wnx<%ofIvsUto=)>4y6*ty$V*konwK0DuAr!j+ zq0maw@DKu1RvDx{$P3y_kjTWEG#Ny;fvCpk*xOKVU%+@A+(drVnpAI~=RbKSV=2E^ zjoy22uK(Pt0x5S5oetM)o7)NB#(xf z>ktFMs_=G`gLf$iSh1sq0O0A<%s|$u)c)$yJ_&T<0J= z@LfI|x#odfUxHk8T4NK*IJwf#KP2LA8goD`hgNbCy2qF!JGp#DP{`HI?LU<>52?l8 zlUh67e&-e0DSfn(uB-`T4ylEP4nZS{Ov0%)>pC^tfL0FBD#xOoCu^QovIxb*X$^Mf z)`(i^F3>A{D=z=r=;Auqm@Yr&>$Hh3`ymfDx@_d>vFY*-iY1{7wn6^)(WU2s#&l`N z*J%@7)`K5ybXmyLW7Fl&C}yV%B|rsNNis@`N1aML&t$rK)?uyezrKr&k20!+AO9B9 z^2U*0am*smQH54e?^F@U@Z%=-OLm=1_Jo3$00rx;3f~8Qb*l`9UELo+2po})3K}N9 zICf9%WTzWr%>@99Q6E2j8ej@gkmwzetmI9nXbGQ{hP2t775l+%(3PKYv#{P%Lz~Gt8{*sVS z=ow6PcDz^-1d)n=56)U?p`BQ+R~@`Qs0ZG2ajkAM#>{oi##0jQF=w1-qI`6JiR>r@ zfRAO5DWE;(y>3(Z03ya}QQPOA+Kt&h@&Y~IQDzype}L{EqYN+iakhnFr-qavVr&Wz z{P7p{5Vag#88P3{UF$*`Cx<*=cSJ{ex0R zU7W!`FlEdb8#D*lGXu{$mka*s_*%e*Z3Z^14%o2mz=rJ+Y*?LC z%aJb%(#Nr3HE6+(0rQa!YydG#j$jD|0b^2SLcrMdP&G1!#+U?6+L#0en?w%z?i?G3 zj7J|EbBOxf;E)AqoE$>B2#34}!`&7;hYXk59#$A(4+G`m>@g~4nqv|w@P^M>;SJo7 zXqw|R3bUHxjfs~yjPJzM<;u)Wy(=@VA_8;QT|F}Rr%&It-mGQXv-2&+SY5FhO@5ca z7XnNazWARQUog{e>-d6GG=~~|?TP3*zGxq1@Ol@$J?;jttHD>WR6Pcp6#x@GJkXg2 z;`B+^bdWOv>D6f+ZC)ny>(FRbf@ZIQVEP{as@ZG#{Vg(kJsfU{*{cqeq7;xnf$`e) zm3AzQ7e_bv0qan~+A%II&wqc0FEGOu1e?vN7jjrT#_7ft)A7%4C!^iDhs{{l5X8m4 zC{tMug@hok7a(%92|UZTF#@oNfVfI<5R*_A7jxN9@EX4Mqg-j;img~jJt-zIpOFRK zy#4RHVBC&x_C`}lW7FBKle#!U_h5Av=0p#xnU5E4E435cvvse$0a{whT|( z(Mbi`5>h3Aw(dDw>}f9+i#@Hn$g-#1x1%oFR92{8s5G*UH4v1S;IgVx&ued9(7v#7!-@2!%Y4yYQbjm_qtern>ea`5m_2Ae9L zpCfpzQ*eTE4dNx9&LEc+@5C{5ak#9-~?bQSOxE(RZsv{ zH?q0{Sn-Wx0IP~T&dxW;rHO=5VGT_E0hEjFLxN?nEK^a-#d>%)Gh)qye3)xD{%R39VhNq!5tbk3MAQRQRv{P(?=E@96 zhW6Ot11&|M%I$!g1YdNF%;P$lKlH@8QY5)lvAmEZSlC@nr?a?r{4ZAn?gr3AaC!T=DHdVYJni z)HB15xub(=Zp8xFi3PAbVF3(Zgd;qZCLFxs>=?dkH7Fgv&W^95K~iL-0P12QzG^Ar zn2v2SXBKB_&KCRQ3yI0xw3Z8Wih?47p_K^4$HWvvB4lk5G`Ac)e&Ug#zF)3?ple7V z<*}BD$GMndW9XD}B_5v&Sjw9q9zNqs2!j$2k0l=XqLz5TZ~^gng*D^iQO?t2h{t_| zOWlNzW)}~U1FiHcd^wvmC^FKjRUAYh6u+^JsIjzmo%BFT4#mkf%3$3T-}h{`Wi5wk z(v~rNjqH2Y!=hpu*Qgpw00r|XY=J1#77M>J_GB?MU)469@0G7KPr4f34xu8 z;Q7O_*xTV!TZw{d30&%Z7EFNnU^r1gPMQ~k&UjWfJ1xP*KMXA)yBtw+{jH$oJKK`b zaupn9ZKLH|tZ9Ru{R!tSqUGHz*c2^eNU0-01nI?K$%8gloSh`D%*Kmq#fDuKI%Z_Kmc+Pk_Ds3)4s7f;R=X?qwD+~2$YG^`L(ixMQ0;mKaMR&+ zMmXn$sHVt7?(2QXk8LPRt3|Jd?@8X%%}Z7 z+bkdNDcxDm1eu-0kX%c559ZUwLjwIYsw+O@V4eXa{(Sj*8M)c#sF5U5UFo5fJkOf^ zc%76b`B6HB%#oxMX48k1nt}oi%*hM1k}Fwu7zSo|Gd~Zn;82WU@AV4)G@Mkx{HK-l zmrr&%jA9H#>7R>|M>Ki z8L@>6L7P@i`GAUZ3|CZ`HXi0s5LXmL<12}nJR2XEPY6*yDs^LC@(&xqhc#AlCjcy1 zm3YWDeekRJ`B~S*SeTp^7N}5OnEQ^^5ChX8>(}e*SQx? zz?||zN6r8^NWMmQBS?X?02*vB@B=(iySzq)xK_Hm{e@5_`xgF{Zbi7MurxR_c1NyX z8CoeKIlUa3!GCY)Vs3~?r;}1A%~o*H0@sh!+%CV6FoK!KT*WiqH>(2%6Vs6~@Mt6cF`5s{eaFoSb2O*E*=WHO4t>mZlEf`_IPgeN9#ZPO|r#2DkHC9X@ z(qvp|1(C3!y&{rKACSyyFcpuXC0Gk;`^Y;_jl3C3er4!gZ^Jlk+p926YX#%9f#Gc8 z(V{@73BkkH(xZi$P(;4TCl&k|ZY?-gFe!$I;+gIb!AJBneTc70x0Y-M7OM`62{s)& zn%=I=dWLPgG7oFbMlG@WH4`sA zX$$6W?Ei71*z>M|jv4&JsAfHDF{7H@ACjScTJBUwTwYqWZYM)WK!Jk`;fu@@WD$Hk|^51;!^WV3+ zJa@xnkLx5Kzo?n=ZjaA68ckn<<`4-S6#Cwfp~fL24~^xm!6UjEd37T^M&TCEHL7(+e8G84rkTUrx=|fX zzZK8pSPZq5&Wi=3l=DJ2ZcNjw-95xcFsYLK7$3FfLzRDFBnk#bfgfLa6~h{`S2zGTwxDzgzJ_Cp|CV+Zh06sS_-@VHYG3QFWZ|{!c z>@Vto!2&B``~H86@FtDpeZe7hF(dyzii!d+uEQaaRhUw*ZK7lBP2 zeI{Xvgm4kTxE9;^WjZQwFh3bA@%L;N;{fIqD(!(m89b;Zf+{Exzr9Ii({YA7HC&&| zp28CG8#BDYj%}@-x8mIx@!Ot@=8$E0!!}_y!y8r%EsOY_hQ`pe&AOkmD$!a*^E0>4 z6YG9Fsz!&`S{-G}0fg?Nn_@(bhhVXDP(IN}x>I<1tZw3A~wO1e3z-4uOD^fFw*$9+u!(M$f8?_dWxM-zlc6K;o z8sEQdaKz2jnqdfbj>zta5K*2ryI0@eQQ{bIL}qXmz639;z4~GdDr{(@2{{KBvCkzp;M3M_!bv@4VINMg1LkOKhneZvij!@sSV3fjwz|rM5sraePzbi> zF)Fhcgn(<6D*0%(6|s%&5wp*gn5%}y4zKewvITC7$*7xYGTOmu0Sur_Ms?W1-h-7Z z*2d!?9b6kPvus7H;Mtl%E>Uaas9GC`mP?4{$6jYWLNwjw{ams(mLNGSSiVD?_COW! zzS+yLLs*Nt`7d^7_u<+Ok)JSj__7v{-H9O0LD?y=7R|$piSMPKOP0pZSvIk)z;N*#krjMfP+#iJ_Yd3N8)bfDwf3Py?^k{BSKt z515B!dE!nAI6Qg?x^2>Z^bo(qmaI@YrE!m!s5jdLs}=(-j+3iOu5~xNiCz-@*-~-u zK-eJT-=auc6X<`6muLMaBlj=k-*B-h{n=XyA+Ypky;yV*N5QE$QWJR>-Tw(y(CB%C z=V*@k=0t4%48vrs8yj^_#r-qRT!BY-Sc4BX2eUFpmg>;ya~+Nw={I2N~N{?U8)nV5eDpv@dJ#SZ|(D?Q_n9VUAtU11O;z2fWaLVW&bs zTJ)I^A5?tMS$L+;dD!dxeC#Eb$JCpLKXLHlQ!;a+`qaf^&0nep#}5!4)I-(<22U&mxV(Z z$gL|0^!{KFpVNVFDZvh;_umj+Wuv#0_d~_KI<+{k?N_Y?a6gzAIzAFgEKmk3r4 zw*Kq>PTDNcw9DzEpn3YcRp2m(hYCld`!Ch~LsNCX7h2(h=*CYI)?+lId5u-Zw`8us zJ5%_Gz+BfCn0e+zaS}~WpRGA^%U^jKyp`vFBrT_8SHbTvknHnnA3?X-d)e$9*6Cfd z{|l9NedVUU3v)~M17KRC>;{?#UihOl4eR>KZ4`#ywc6v)cSWsBFyK5kZb?-)g7IG~d4UfL^t=_VMn|rc2>++08L%g1e>-AjS>0V>#LARDxIt33wSHw91BLWZkT(WDQ9Boz=hCetu zU1JI#=^Kpv&i#=P7^7(pdlddFI77%3-iaf{w=3&NjEp>gp?rT1**;@`XqWJk;u@Z> z<2l}P8VQC9u!IIRqY!6(@rgI^o27+LxgQU?vx~zq6KecHJup?c%xCNl4gC?TE3RXB zUJfeyvW|`$%80N`oRHy5GU&Ce*w*gKK+liZVYhIL3Jy2E2pxKTXOxdE`4*md9Vy{i z(Pzw6yv*0;Bl39>t&XujVx;wmC6K{p9`T&@h-b`4up%G9R)w-8g3gP0#0~t-Iymk+ zzQr({$Xh%tkEm;p@TVNOD39<>AVvt6#SLp9{UY=;>rww@K8g+SQEXj33XItYCv#ro z6=Op*ee}DUBfJza0j=aGa05#~u(C=*`AZ9pe1_#bE*OMBrQhHiE9RNR5#cfIiK(a~ zUrIc)d*E%;KNL}pMlXZ7rb0WOg^2JnsQ!S^JgXi%RTARk^iAo-R97$Q-&9u}-^-Zl zn$BPUR96VUK2T>SfAMvundh_R9HGN`{@h`_QG*LOzJbR>Z(V1oQ}xn>2OyngN9LfB&Hi4Vf7CRPDUX%Uc}#QG^LgN z60GGlKEvehEk4@rK`&Gat?U}1huY8Ja--i&Usi#umsa*u^DY1 z%*)GyV{DwW@Rjg%%-_E3_k=*~9Oo503bP8Yl1^GlZ=9in6GhGg=Xb==HC!Hk2bmq@ znr=SDeE3dWhUgEsf>JLxQr?!YsILs^*$_Ofc)is0xo%jH;&i%;C%RG{1tVF#hgSCA zxHlxwa~2;r5)sAIQX!cWIkJX&Yy`V zcrxp>sTJ;$Wre51M){dFpBcNw3>Weu=)_~x>47|_`va$*^+jQx*Z7J%qwdTpf3qiB zaPO~n7IetT3>BP);dE83h4tv=uuv)*FhX9K&Da1gWir-~PRnpHUdI=>GwLaS^Zd7^ zE1`m(fkMV{#9C3km=ErP6JL*3c@b2(3_Vao@&q(vd}Faw;V5B}T)ux}CK+H}77ndW zp~N}DW%#2{IwG^y6I}9p1Gl)^nOEG})M_yAx!3AI-1(F%mu7OwCa zhlBwxFMo5OV!`>sf_nS|PkzhV#fP0xzrjD6XNAY;HXF~5R^ZXOlZdPo^a21z3?cX7Na zkFna`);w>(>%;}KrFm#+VQy;e{&~)Vw?suk__`mXJ|^JFd}X{`5q>$)aWoF+!2KxG zB*qANnZCO)!Xz6V2A{Cz0Lxp$ifgzybcYJ(~Hnj>OwAgDbLt`>rV8AIz z9BS4pAzu%!Lu1}aQIje;sXM%ZtMDdKHifrXhUOOJq<-r&zT?Zh(cD{r%Q;+zAB0&V zn!e}_%`qDUbA%7>=lPu2`H%xVe}m^3AROUWaZVAL2C^%8C0y(~oDqCdha#j`NPefv zyiMld7u5}zRsP9`cvo(QU*XIfINxH;?F(E|j$>cof_vrXJRk1_I$R(>7j(sssSwKW zuwBo-1yfeZLX0$=bSSJG%Wo(e_+v*wt`0HneOP;(DY_`H8QK#}x}{faZ>P6ciecY{ z9)Ca0m(|aum7R%JuJCtz$LNMYtqQ<}7Z-RUbyg!q@kZ`Q+DKkjy;imnx6sDh@iq!K z>(Tjo);C(I2jml3?#=bG2nsB7FiDg8BGqdpv-jOeD>Xk0$t4dGq14B<2I6NgX7+rr4P_*wv0&YXuL zflD6Z@sHH;H9YR9j{o>893QSgrBXE37wC?Iu%nXYqK39Cx_yVw$JkGuNMRgLa6#c?7GcV&)7yOr$QLo=*Pt!a&eR^HFAOv?5ji5g7pU}3HxDqfT|e!CreeL zl-Ky2v;I;JAUR}pJkAGINH{#Qn8PftTyzyVyUP{)(LB&YpOlA13|52B3F(zmT#*-e z*2`?<1H4h>L)3ka2eR^mIYQbmz*g#!7g^Z4^7u8l@}#}`Yp4}|2%m+Gqab0Sdq4q{D3|&lS z!UJ%b<8G+B9XcBm7+b4ltcS z#^>CV=iKLwep-#03mu78`V2JTGww{&(lAtOC%1 zhy@1PR_KP?6y?-v0=$KRCz^iy3`M4^mRMx6%#X^xcFizt)(XMba!7)S&acDn1WkS^ zPJRBXQoVjR?CdpK*&$rW^Ix5c7{K*V=nW=?@c6Gtf#b8F{}tM-Cr{&a4Pa@W-<{*j zs?dtRV2c$S+j-l2GyNyvA%&0nhjd0`4}B8;8}9i}DqUEx3&ndG3lZt4m6gaN9^l7Y zI3&>d(ksf(zceRv_qY@M-VTT`_#zT4{21y|-8gIA~SzIt@!3L}HfFfd-h%0ymsNDPBw?Y2NIfu7b0?7&cNp z#=vQqF1;{7ruht2xpY@yWuzNso=|lvxd2VU4}@_TprlG$1_4m!l4l3wjb{FnG`Zw& zn`K!46)t`3#Y020i)DS46&%+Ybm8?-C#-64{JB?X#0e)g^i3%Ul3?E@_vK8U=<2BZ zL5hHk>JT;$Rw!6I^g)iCG-_UA1i2oHw212rs5jJ#`sn_1V@%0Q)745inj3 zclCmqODn0yv*0GAx3ot&R<;~iU?s-WF&lVXV~lE4>Q+1<6=MSIep>18+Vj0Vcq5#T z=iF1oo`I}=xSpQO6Vu|rV%>O=pPnapX=PUMW<|BKseDbmoyUJmDHckw6JLY2a}h_h z-(zg>W__=feJ>9i7=>`AWcxkYPL$2Y>S)1(H|<9k;PrnTO?%3xUR1>2%;nHstKB7s z3V#AcdJ%?-ZVb)wUkQm=rWJ2zYyK-!t5aaXry30V&7)5D+gKn~Yo%Ejml0mi`SmsUmImMX#wUuBBEkIg&9VD*7~y+ znRE8p*Jtnj?B~84U&)jjT}Q&S;pa<5`5~?TH#~Sk)1-*>xBeOc8(m1En^osRsQw#Y;$gQ?4v-d9&d@gP8>&|w5}_Z!jzLf>y0^{t-A$YFm%h^#)o>mS;4AV ztMARgffcjCIV%cZ)&kkK`$7{CG(3FaJch|^_)j_wx2Og>O+&od<2)Q#O_eTVmF&>y z@2C{`Y?ISzRz-uqxVzhE7WSDIy{z7%$SX2Fwseu|g>3G@Ea2|Z8|0Wru&6*kySRMD zd3vZiUmrf3eWSTsWN1_M;S#PPbT<(uk8ol|MIz=4RU(s6<=_m%Ud`QH*;v;{hEg8Z z>RV;z<{gvMTl+(k+tEsd&QJw>)3F5K)RbH_ES11%iFAKZHrGhWGGkM8I$-NGs3HcX z_%hjCYQs4qAJc+tCx@V_LRkmp$-x!H7R!c_&FVm0Q4b~o-@~-XpvFa}iA5{6>%Xi^7_^8CR;FhgzWos(x;#yT$b00Elg$FcV z7NY~SO@c2|bb>e18`G=bp$P83XwC6!qF3X|P`Vsn`9Hd(`X5hB08~7!(pY|20}L z^M=Sx>QnYJgM^Ov3(68A{=BDBMEn<5Ds1nSvK!~9vbR)n1U_bw6w3cQI4Z;6LpSer z#0x(EGo(l8-oi-M@pfpqdrPe^4F3q-9Lub6%CqrTV!97z7YaZNewjh9pi#&$ST}QIW45^s z%&~(VXS-SLuxK1VJ|biDQuK`|$^H|4GxQ|%&GdVcw2j+DhI@=HavRGwLE*d=(-nDh zFh$mz5&4$1*FWniNHQ>~~qT$0E{G zq@8-;)Wf(G1@Fu}z2uYg6;8fEQRSD;lep`KH?l6j-20^p8Z|R9>Dm{YhDtmp?=-GB2PE3hMW~ms_qQW z@OaJP>Wy$~D|P3l3hhzi>c+h#M|I~171~2B6^^47HE~@nIA zcqxO?vLo?=FCNoS0K1Lj;b>NHSDtSB&~2Ou?!E;ZLNm9ATl?Gb>D@-e{in4zjc#yX zX7j{b5+bX>x}>ed$gmJ*U%u37`a08NVsGkE+V+aZ7euEn6qsPYslsbK_%+9x8JK!y zs914XGO1m4%ft?{bjzpGdzoc$(<@iOzn_mHQsU`M5FI$`q$$PaKJ&Mel|xkpKy)dV zCc%d7jl3FBY?%K|*h0ca!vgsWVEoWYdgWS=58?%<0}-EbLU^!pk6DF&8Ch}`HGx_( zvn0-rG!HE{J3nOUBf z`HbtDh#b^P*vZ&Wh;~wjtp`UGXHFZ9?nMjw z;a>?63;z0uNq4nW+vybMv$Uzz{S`5&9{es-o9~lsp>fcuNadAz6e|B%p{k-xzR}4F zRZm?&24Y%jcS&|w1{8<}*;BeRrp+Hr4wva;Mdd$FV-W1hQf;znU#Mp9a(ZGkmwjX$ z@i>oY^G((E&?E3IF4I3W8#ee0;UpmN^B+|-dhmEAJUu;~tNn4M1H;n-fvivm`f!V` z4)oHQT%oWdy8*cLZ;`YtM|g|9L6Jcr7ls81a{=?l+>;djN7tgp#0CO;UJrWui<0WG zw%#m0K;vw@WP`G0_9tLswRykFOS1~p@vtYpF>pwDgvHV&tTKWn0xJ4H*p#R^b@xEg zVx;J7wiJY{3f9lkTswSs?m;PI`%q+QR`JbRZ~?`=wl;H|&8)~439__nuW-alf*h|^lo#Oqe__P7b)*Hj_FR=4v?qn4M&3891?b$vvFBX z*4@W4JxSt4acNIZr`s4JVxnXNvA=UGgEoIuvMzH#*w}uq3_-fD)yqjK1~t<4lYn_D zdailvBzv;{uG8lnf_kVw)k`hvh!Vu?GIC!;&o02MkOPn-O#C`-fk9P3pP<#3sXc2i z_J!;Vd`5e$R4KjS*`u3*S2QoNWNK(!9W5`YHWYuO3SleL>!nLYA$IOV>gT7Y50|%I zL)1^fZ`IEkSMq~B=+F4!DhC%L#2|z!F@l@%pKcE9kNzA~-hqNqi8(}yf^Mwt0$`I= zh%KTUX7>^8{s3#;VxqPBe@NeuQ{ahDR`V`=iUk^COd+T{!e^Ihf6=HW7VgS+-MLL$ za0s-foW|~D0g5?PS(7=XyTdB@H(GX?`7avdNl`xg&4FD}qHsaVN-NiQy=1jkJ6HPY{8p=V z^B}s*b;21lRnp}x<`DQc8R`kXy37$T8YA);BIDl{_$<08!9FCm*Gsru{h%28a5f*lhVQFZCgp4@%t%#JxaX zt!C#D5$unfF6 zzs@68y~}t}^{(XMr1id4o2YlEbdq|dh}0|fiQ-M_SJzr74Pv(tJT|(3sTuzM5Tl3; zI=hg?&voBVj;_hD;aD-kh*4RFfi9q>!m@Rh-AHg(i44m!UOSu(bH zjm66!v>gm32L=TF0bTY3 zh%qnnv{-G5eSzgJ{Fznp+NfN(ppumR1Odkqw+;_LH&_s&H_=g@a*%qnq?X8x(K+5* zxbV-$K=;`=BoIFcdSf2ka&)ild&u`1~ zPps#4@_Z)GmQ^u8ts9+Gla`x{6%Ghx-$*VC1TFSry2Is&G!Yw^uAWRT&JsSy9Fd*O zxYACl?Vwa+v*HDAgY}OFap=pIYOJgLs#v}U?=7^%Rz>lGQzgM1T`p&Ty4b25u~o$l z(RaaD=@JV>9^5>~tG2m-Noi0eZ zsbt}KwmgeGpXXU(ll7ITCU4QfHw~&miwAYX45BweWb8A3@RfX`)m72**pU5kcj)%G z%XDZdjBqIEep+(SP zErXy@LL9fIpQt(BE`r!n|If6gYb=YR0Lrf)P?~*4c2DRU>u}6eFS8sjbAsKqBr|q9 zd2HJJrIIYU>mKDP997?|Ox@vHVvD(~JWul_G&L){KQmR^KcORyCOvc|RNFqi1hcf2 zTJ7^BO7))5EW+dGHz1mX0c=vBv0|6H8|oAt({O+BgCx6Q?jGh>hZPV^Es$KKeiK|9 zGa{J09zbLF;Rf0x{1*Fx7$s*o{nfo$N|hgS!>nq$P8Z z@T=J7cpS3{SrC>=2R)U{{3hDL{tr;HimX?8sbD|;@z>Hd(LjZiW(#q-ykhB#8HOJ- ziBQ4PH6jK^wjJ5`=&ra_-Y6#>du}21q7j!#9vlfVx$^P1d{i?iRfLA!*8F~|Q$Obu z$IS>t4f$G7$ivtBs47%Ono0J)gp5k#cR!z{dIZ0jAw4S`&9rm|pmIkhL?JHZYW0Y% zooRm^wzlCp1)XYiR}n3Elcc*}w=&scmv9>>Ajr9qtb3yuP z^^dbV(gtR(?ikoTWJ0G}A#PBGWCJ>B4PA7ShJMQASwMXx(aL$S+cZTwR;KJ2{ajq&I~IA6ttl{Nk6D%?O9 zITQ87P6<^CRfqYuN_1o1HDY>ys}F%+dYx0S_6m+v1mgH5j@WMy^AQ)`)~bhwbSH=x z`}h;B_7Pbd^L_wDi}^Y)9wX+F4ZaRZO7uDT8XERyWOF=vl`!U^VK2yY70+C?wo;)5 zboEKB&`f?P+huaC+G9-+v!cgzJ6hzN&j{4SSAtujGdM!ji6>dAEJ)Hg9{~p0>62njMoZYf{;5beiNV@1US;q_ov^n=LuXOa36M zDKK6X@y<`RdZLEMqc1XOvGkc6y^$vmJ98Gp(nD61Y26T$ra{slVjHs$zl}gE8AnCz zIaoY2CaOC9{Wtm%(EwbK)ovMwvEn!j2m#Ez=D&q1qZD($W+ zrAlrtA#Z6~Z!jdxS?~j0xJP<(FUle54P~}IWNj6h2QfJqEO01IY_rboCJH~dE7jnm ziNa1P37 zR0~;&0)LkRjOP{@oC&FtYFe74Q44r?5$rP2(%J_tK*+rfItOv7p5Mi96{=bPinB`Ju~SRJ*iFTHBdhg>AuKrb5)W${SuR9Qy7 zu2yfNM7mogjQkohJMzWj@=^F}<0oR$0e&X$z!KqsvzL*>3JdYV@7pB(1EI_fiIf4K z6)92m6#V*bQ9bUD47g3IDwxhI{H1Ka;5!r2_8z$}Sp}_jRw8$&ukkh_s<<1b6!*e?-rrA6DRe1i<}FZI zCJ#*UFF`K7q#2Iv?56^?#7#O#;aBof>Jn3?<>Uq{D_?Fr~Z$Zkf-yg5N_X$h9?!v;UHZvL@){iX*FS%8o^=t6_h80w6~X=h&kp--J^K?RlouaYC;%Bj4SJl;An;R4K`s_MP*l#{P)|@1^Or5; zd6CRZwsaqalf7HY@C@az))4d^sUz?_kR<-a8A!Z<3- zLuMa=h5uYx4dMMoPWUAR&076tKmds!-sSL})#Az72+(2!(DD|M=rY!GA*{ob^S&o% zJ>XVFFt-Kl{(gWwQ>*_Y#c6Q*c;X4uN^FSg`}C^xev5v{W#%qt`snwe;4b=|t0P;e z#5_IKpTOzq-C!`W$B2Gp{1B~XD7;#I3cHNesXnddu#67o^DMjvAv zrSt)wqTR^B>~v>$b<9xr#0>SSpsef{HA8CNCdlh8sR^6Rgqd@#37gt!!mgA{9@$fR zjQTU`ymX#4+jq-d21c-P95xesVy^m&oEaauF>Id*{>5a-zJ;55WkS4W)4xxz3ha zG6ml$?1(iWTN(d(lL%X{x1Bbv4}bf!7LSt;uln8JTECZ~^yt|1R&)ZU^l)SM5k-L_ z-5d_z%)+h!g$}E|2b=*hB@O8)#^Y^*7V~)L2i8Rv;IT-<;QU{N;3;wbFKFw6P-Quom+0no4(2R+%GkYKz9-@< zc#PwE2s>h9x5wy_2;t_Eeud8X)ywa*h=#42%{mSZtKg0GP{~gs~F>HnnIhd!xo`KrkAbQwFr1RN>fRbD#u(!g5d6PLINoq`A3CRcoA zmGea45@UUHb)K!F;jZ2dH}`S9OquOQH1;@&7z`|JBDSi9esaRRuFPpo*e6S&hMN;* zV(%xGd>Z{S?@LQw^n=$tFHK&wVmUMjs&uf@URl*eNs1-^WDEm#1sG*u1&bI-t2+nk z0ONvL!Cj+VX1y4!QNakh^~hYFF}q+DSSnYZIan>R0?+Ij5j%t`l>&H?n$m}hYvlJR zB2UYmRXA2}@hoAZI7}_Ao5;4CBpZ8f>u!wcv!-3EqJ#W`NCwo&=_G%6s$k-GvexAp zev7eTpRFO+7btJ*?z3{t+(c zBabme@k@0+BIb9YpU0Ij21V2eEm#Q>QT5TVaNJMx&T3w|G))?_mxT8|RMMCtIkZC{ ze>ciS5d_I_m&q{UUDR)4K)rr6pnj6cp1bJ zX=C`)#WnnD^TCiAvVO7b01zV8!}H;Y|BMukQA$^H<|w*Tb@eNFvi2g(wpEod^!P=e#z8p~5s$T%UWSuPsx$t1arU62pj zYim4b9fg8moKa!a>GVJ$Xj2^@nCN(~^`b`eb}a zLRl2fgGnX6FyOPa+80FZbgfKBXjs)YL`{=vh38A;c_Pn3zJ0|aP9e(BuxDRUqDZwL zwkV4eOT??HRDK(HX<#=!RSP~SyPw8IDyQzw3gymaxyyaDANlW51w327!eOJ`i%^#W zcT<2FMp;E~ZBcJ%Xsai9UtWe*cPn26&N#XJ2+9Ys)a(l7ZU>T3{`ou$%I8U6G4~0a zn~+lq1V3AngrM4nT73q&qN`YQRG^c;CHQ6@+k4w`WwAun8L9$`h{+9_;B!<_JU z!5gaZ9O6$W3QtQE9-|tpnyd;~t<6*{rz#K~p6a11QJ{bVUL(Rq53=CR3c6TVTm$42 z5KgsQ+EL9Z8>QU?(&-a(t$}X9ra(kZHJwNL-SkvvYfhK8RiV|1LSic;g~a45t;5Y7 zh3?#vYH4Aj&~2)aIzLkYeYm4U?CexCHzi73NC{UXOI@)aTidLqlN#8diK#w5{#vTJ zvl4~B#bQDYOh6*DU;%aa{?rsc_?{G+BHK}oZtr~-NZyc=FnxpNG|A@nB;i%;6*_28 z;Oof}ZW}XQ5?6Y%1U=Xeb_Mzy(^7rAsXu2or$nhp00fIf?n^ZEa~fh5kJy|Levv`& z0W5#HbisMdqg5Z{V0pAaWKzwM224(Q9TgA}lfQUsWTutS?w9WeV*ARDAbuf7HaSR$ zT*vngdNAowNTi>mE_MY-5U(0-zThlmLU$Nccf>-h;I;a0WHHwJ zLe~}g%$b7;=|Mvr%3pcr2_K9!{80+{hF|Evjf#pq1SIhoGm#<;DKw@O+FIO&pnG&+ zu(d6z0HmR~g^n#8^cLp_^k*Q5jvt3+y>EOBdb7 z(1kIA6c7p*WUbs8bR)kwlDn0yNAGkqzc}T{kQcp+GuI`df;nsqm)+Cia!7Z5#@%_b z?tG9lS(vj8h3BA6>O8KRg5?RG-x_oZlmm;iHj+?VZUNL_exUx}qaI&9bKCxJE zFkD;(c`}Hxr1ch22MIbSS4P>Enpr(;fzyQKOm2SbuuwZjqRV+gsjJ$i$~Hh)Wb>IX z3>H$zoL|I`EM07k=ZhtYRMSMoyyhidg|1UJ_L8p@#CglU1WF1KoJvlD{WE^tFu>f}k z23umqFE~3T4bo33o*BI412qVdsNln8I}+%^lE{gd4hRB0UfXgRi$@#%E@9iGic(|9 zJgIaRvgZ3B2G!6Q)+wBp5|&(dS|qhLe=ai(FrH5V<9;3Xxo7 zMCb4<>a;vmjMkZ0_iI@~q3jP&OH7;aB8$i?%A_L2%Q&|SvCgClDXWcMr5{E0wMns} z3=?}^5xcS5#Liv1ZstBHnI&lz9y4pIc!bL{e7ytskxURDR!Jc?KW%9Zx*DCpR1blL)vS1Uu+ze01YiGWybNh z^Pe+(%7ZfFO|F{l%s6-Fv@qkxtQkLuxpg+Ocgz`NwtF+4&E>IW3i{ETqy`4aybFqV zt`!n&5o1Wr|9Z)we6N!8FZnyoKX5~Hrv$Re=|=)8@EWY5rRZ8EVJ3dG27ad~(WSEM z)GF{_sO-bW@Sfb8q1?n8hz4gj5M>Es)!vYt`2K7l=?gK4HfZxt?^Mh%XE)%h+^)^v zO)j4~zg&HOpn@N)&fmrtaiI$*L}`BNp{TeY{-Dj5zikdHdd8Mfx;Ni&_b56raBaj zXyg=RUI{;YE*<$>vYzPGP=gA%$$3>fL~R#;PtnQOM>1(S+o z&HnYVE39>+e5J0kMJKBDgVZ@`SH|{^+%5e@`dyLXcgynEQD+Lq?>KYf=hojY);I~C znMu3_IuW;diwV|xL#|3qgQzL?%8!b#LS4m~f7)%FK9kUe#K!XW5rOYwP$gK373`Jg z&&30VI2Mo+5>s=%_4KAi# zvQv^S)=4I7u*x(^j~6_98)L&X>G4o5cd6D`1j#s&x8cj>Y@Sgr>uLaK6T(8?k-~93 z0=CYgeGfKe6FV|wuTfr8S=A0RudJzl3xOYzfQ1UyE1cF6xl5P66Il{)uBU>D6k#Yr2!{ks7 z8uXlV%L#B0II3u$c+4RO*F%)>#5ZWKRbT9JzBBD~ulX|-IeNZIZy`?q9Yf<=g*xM! zrMUmR%R~0P468ys_{;TBbvd4L1aSx)T7u6`oSK!xDB%;-yNa*5*yiseh^-&qXj0Wt zx*9l~T0hLc>ff$Z|6+L1j=cU#EhF;YY>8TN-mOeQXynb~NLfjW)>G@55VR$J(&TNy zFUy0Y(DkUP6c4yN95VXrkT-)iApv~G9#7~_N0s*4eHV+ChM)*7t1aZa#$Qx9-2c2C zzm=LDfCZv1{C&*{oBwm+FJ$w()c`D*M_dFOBYT*DbWbTrE z(C6av)l8h4UuhY}epjg4HrnvN;F#nx##|hG1{0}lG-gk$@#{M{03!W{S73ZWCET6# z0;6`A-A*$8Uo!qG#t%I2x>yfggTm$qfVf(^E`xHHM4X$ndZ|Z`6Q49Rmr!d%_fua* zcz0I3;QL#|VNetpPV~~7I2y-qEcY6hPBJbZsyn08vq_)P26QEK0de}>M4Uj&04#* z;7R~U!7Tc|Dz})$TQh6i0JJb{1THJP`*v*}Lc=GJAbPxKDn zVSh@_k>g_9>!R4eE@R)7oIKZ({?gf2y3nJfZ;|xNNI#xPPvn1H((%$CIR~N|-2D)r zR}7|1WGW1jApMbJNs9EDCHSf%-&)C6D*1HsaWqMY+^U;29%EKOA0|Fta1kkT>YTGc z8N_zNZx;W{fs^2W#nKsOSNKbhId*O^cnzR+Dd#udyuT=8NOh>ha>Qkx%^;sc_-;kRe_$Kx=vtFpzt zOE4BeI8@n zw$KsV&JokW6nhPr;z92SFObd<%kT(Oe^SOb!6$d{$iK`}7sfx8C!Fk_NKcmxwqPZ% z5C~!rQ?Q5U$l;1qdV=BIWu=T$1<`<7uXju4W}fB98TWR1hMY|Qn#eT4rDa~f>TSU{ zD7F7KwT5=gvp1>k@3UMn#qcIU!J%j95mV=|CNJhe`>>#G! zNXJZxsO;WZ0gAg1YT&Es{fTysBxxrCFv8{mP>WtU519=;{EW6+4ON zeDGv4B)mB15f18K#WExxY`Toe0}EBbuaGpL^15Q-bL9ouMcmlQXzLEMBQ}d|+O1I4 ze=|0UD02Q^S#L6G=frHAe}KxXMjN??>}qq&fWF1=W+TCvS}N!}C(lw*Yrkn1PMO$e zqB3zz|BbbL?8_uaY^kjG5mHi`nK3HaM4(4UHEE4S2t=S7%dr|;1AM=C$h!J8^1yJl z%(8Q2)g6h0sVXzie)~-VgE`;HIAgO_N;O z-1!H2RS#`E=q*h$0*}$n6S@ys=2x#@NUB7o7)$j8+`pXHB{qWKU%>-HORp5-te&{M zfX*F$#%H{+h@|DJP2&Oa&GQ*6mPlsf0g=Cwp@|=ev-z$3GKPk~ujPTCP5e;vW`4*e z3tDj?9z#iCQyrH5;%QM*TB+c$3_>k*Ly2(ISY*LdZX7@A`vmKKviyWr$nsR#rt+YN ztdN!pknw^SuVGe_P?*1vjVKMPN*?2dj>)!lHN3EdACK{bY*nNWvYgV8t7Wz-K!`kb zilWtwRaJGLv&fl9M`X)vWag~kKg~%G+Sds`lzYt;GE!m9>kKMV@`(8Y71_M7=?W@X z`iCAZB@v4@kNJr72EkR$ScG5*bqRs_PKxfDDsWX~6*hF!dV8IFwD}K_R%JT8&K@&+ zlRw{QeB*PrPg@u5CoP)w3UQ3I=(f{HQg}m7-ofni=YKC_N68DvRD}9LhZvr`oYiCg zx8N9|pMB=@QblEp{hyRp%x`>s05OLh$GF9+c5`u&jLEE#Ih6VxA`l{c-X2g>6vdPv zV*L9A5d%AI{#R5aSc9u|vnj{j6-(B*5^W5<>ekf``tTJ7V2qNTfR5m0b>+JsvH z9*wbf0!J!!3PB|EVmp8amvD?!f3<3);Fw|QSV@IO7C)|xp&t7#SIn^PwkOT72K`FR zunT69fHE}l9GoSu^LVw8+T&J2gCxjhIQt_Dtds{xiKU~vbbSi;&Zau=%ms4NI#+AK zZ8CX)yA&QcORN8sSBOEc`452$*E>7|K5{zsy>`7S&*Uz(J=0V#| zzt(F+L4wwjmizv^q5rZ4%K>slzJI3>CSv)%+hs%|UkZc}*I+iwEK1e%nwzh{=!KHP zygi$RN8=6D;^O}8(2dL-U9)OX@ei=~iaaBb#U6lGrIZ%jO#ZZtjMY&^b91CQ@m`xR zf#*V1Ke&wfVrx{DKsm+}GIa@R^kY?r{cUKH1<(oIUB(m2E(ut&z||BfDZXS=LcH7s7_%i;{{RVh$7Mj^cS!wKn4>!kU{+1wR~1* z7cpGhp~|h*7=4*l*E#DdB(0%d!@ofayy7y%2>CLWwDnbHW1ELY9(`CLi{Bj0wTv~D zDkk#%jcxJhZU!O}Z6bDsdi9{9*sBy+zR;2%WPnzFMvh47D4G9Z&wjLC8eGF?oHnvl z?Vu#rGD2jDVB&lWmu#UP!RA9Qq)#={0({6}No$T2k`}v*gy$2Px=X@MO31^GxP&I7 z9^gbTZs0jG=?*@RQW3@WM?Na!<-(NvZ+&;}QI+i~xGgU-gVz}GhYrNVn>w4)f+PMx z8RQseiOdI(qm;3u1kHX>9Rs{myiGf zA31GC+5vnG2CZ&qIFJo*LBu_bs>HT*o3Ykd?>53!j2$+IK>CeW6pBrdIh{M@h!Gl* zAhZ1>K<$}CM01$=%gv$ljG@bo{CP4L1w5&oIX?5HY0iI}5ZDd$BqG_wxLEt+#!F!8dk!p5Z2Ku<%3n-wQt=qW>Ln zt9rlH+B)^RF><@Kmh_KM;gj>Yyw^fT4GQ`>Cn>%AM$?LYQXy z#`zCQct?6`Uh5beDt>#6>HRB_MA!Jw#Z-6m7;WjpeHT)b&xRuN$_gKMmHbX^<{j4NKW5cegcR(^m7&}|m6zuBnKmNOt;%rOV!v}6--6VR zxJ`d%wv@Y1mAQa2T%UM^GpGmod(7NEZL-^_u*EKyY7^kr7KnsZAAS?}-#ji)=Cwu8 zZy$L>SHoalJGinTx5pU6-NQD<@b@6xD`OMC2AKrJWs6eqO*hsM=M`%*XAYB^{WGLS zgf&Pf#&oICh{|bRyH=VeHjptfGduR&NmjsL^w1cNa1b7=w@S{5ZxNN}N1k0mKtvuu z793%+>!9AM@}ff(0_apk+1I=qnMnyuH#sAd1w7_;MbYb3fr1<+nx!DNSWA8?eJXhI z2T6fiZjL-*rM#+AFm~Axx!+28gOnJ=Rlx~)kh_RJxIN|mFD=r67q8fQqB(`{IvNZbR_YZ9R+MGVcRqFr{3W+bpJ%;l?MfX zak5m?L3QnViU$se(ocm=pJx z9n|Av9f6;y5e1LsEEnv6{Y0yb%+g+J`q2;d`c{9p__c+BY_0AuXZU};}!J$QnG0~sN?Sg`uhV^(3%ds3<#equPDez3V z$>C}kljms>JEauP=&k2@68{{f4^V$H-Jb@CZlWIy{83W<58aSxc;RjB$r zgD(YF{S!Zt9@i;9k-@93(Ty*lj|iCG9rO~3&=%(fiAfN1SEpA_M7o5^n!`%hs=0OX zc#d^tnpYcrNI8mx=AZ`W&^;8nfI5P6w%bH}SJfu8zt^}Z1z2c}23fl1oHpGIL?W_| zReN&h=r~$(DHfWTTC)bpH4vcH5(z6|Ac`0;MhQ;*=Sii@@@Pk5Oq{DOQ~~+LPG=h9 z1(T{&uD}jh4hMtEP&vKE&@8Vp+}eIhV5f#oEG^5AWU{S;AW&aIBd>Ts+?Wc^e4PqgDzSq1RQ@S~e zGW>(Nxqg{Q-7Zoz%2K!LuU02+eL~rstz6s@KFRv^8IxrF0;PDgj0`R%MB;k-CTeNb zTdD+&W%y94ED$jw01^Fk9yTYJflOg&;sx*10C(ehjX9fqB|o5egVPXtb9A%&vdp(8 zjc&1DcHnJDUEnhZMyqPE*1LWd?M>1K)=A~8U>VS>k`~$YN0zdAdjqX#bs_m^-nh_f z{&o?Q-Q+DHG})?|RWe}J1NIwkUKrGD%^-+h+1{0jXjk14{_mtPK=VaNoKuvwjhp_GCp(dw=5pHdi$5$*w5fR?$#~9fY`7 za>G{KwpmiU3tpYm>5s8J*fx;FYi+^ZqiVkUbcT30U6~o)-3_0ooXs`g9keJRQg6zVxNlr- z9&YOs-qkJm*{Ga#IjiPy|Oh@~n(N6}C^`BlC z{Oo4en{2cUZlsG{-tpboZY3M5M%Ktz;v-Kx-}NTka0WMAac)jKgI|P*t~Z6o@B}}m z_O$v1Hr^6$gm_0=Fhn*zp~Te{Yn2THeiju3K_9ciZMivNW1ZD^t@aLfuP7NpbDmcI zIZuMtB46JO(_8hlgo?h?ZO&P&f(+KvCNb!%{$*6Xi9vv|$Lg(r*1Yd(_%v;x^gpe$ z8fu>OzNUAtn$B3owBRpzriT|q#fHvGl%XT-O0P}}igQp@1TB1tZeiQ~U$ol?p+mCW zb9q+n*79Is6^Sq$5uX9hp;iH3eVBHV`^VT`JSw+F+@iW!^D+I5nl(+33N_vF~VAjU-9EkpJH|T z0;<2j7OVP?y(EM80_o)inX!Rgddau(^38jJ^zwo%pY2Ppar-89Lb>L})p|Jd4OtAl zsim7I53C0jtWifIYb}R1i88rh8yN-UiK5fHjcFJ$DE3=C+y&yw%e`BoqUnk552D>c zwwTB2KITl}eYs>w2Qyi`gJb}MGGk|118{{8^l{Z}JSg=u1o`S6BtsaK<+XhV(%EGB z#F$lYsy#SufJ?z;SSkX$L=m~zJhM<=ae0259^Uc7U^V((H(=V%N7&_2n`y@IR z@LRJZr(NVNRJ_r?^ia~&A-pg0ENL?EROx9eje}~H9g1HBNv15x^ck_iypI8XfiY)La=6+glc@U)1X$rh0ZA^i-;DIiyC`V>F+RO+} zx{!KX`@mXA(I?4vvb7{|Wy_|mrKn%BD!Bd+%PD##xe~LF6x=`Q~4_FT$a@lRX;42ko}{?y*z$3OvIx7g;^hR3+AMq@#)4E^fW+Kb|f&-5H@^a)MU&a1G|%N6w>)RGL$}`P7^6gD(|%Sj6)qrC5d@*Yt}Y3 z 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

      GsCLjm& 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%0D`fcMNe?D&caB=HfEPIH&{KdtAD^Y zhcW3e%D?Xaa+*Vo3mZn7v3E)sacE(kL1Nu~Mui_~_vd8Llp3P;Ta?CHjl zZW5a-hGRxi{DI^554j)jl|0sAdrP~pQIam5J9bc}N~7$WgI837!?rioC)Rjlh|LHk zS_E7uarJ0^I1tT=ABYyoRp>QpJjul`Cb5vj#TwBOkB5^>3}Ct>K*{0cBEjn>2R{ST z3la3=R&T6vuIQ{S?__ML(M0Sfi&mNdm}k`W^y6-NmAQVmTs0)>IliWj+g*QRF9z`c zMkcQ1Y~(tD-DATo1#0 z+8cwPGQ@poPV7vIAar&hSgFic6m`=%m4%Jly3Oa5G|@+=_1BX4oUnzKxBro4_((Zp z>1y5Pt&JA97A`I*C@*lGx}}Mw(YLGI4sU?V(OGWv6=+M-VWbl$DvHc&22idX$Rf!F zV(j%gn5T}15zmJ=tP^V8=xXB8I-S<^*u)nW*JpM4CWpU8UO z5W1F0drf|gh=jy*gb2-re-_o#1&J>I6QI@&y>$%1a*=$_xnoqh_J_!pFQ>yYKzD9i zi{hrOhxRsYy-v1lTZ@i(E$wXMcD5s4(*7d?G&QF6I-{Tcp@NKi(~Q?%PNg^%)W8li zzDjq|>6Ogtbm<$1;R%HoJabCkVQ+oSPp(l8C!Pr>UXDIyCT8Q=ZnCv|Qm&z)Na`<| zlx}lpJD7Ac({Numd8n?uW*UCWA&lPLcL#IOoOH+GcN>Ai9*oCfdt7gBkG;#skpHk9 z4@2jzy-xIxp9KPFF`)BvL{ZJ10u(y2l>G|}4oAx&mU? zSY?R4_aKFuE)wa7n=cATe;XPl)~TF{zW+3l{u6HUn*WIOhX_zZ`q%U%{mo#s2kCP# z{UPq70){S1LX+x{b*>vAi}})LaKQU8pTM zBie68%=joTA?KkryE+SgN9COKz{_sVf)t$@@wl&>DTtKhJW-^7i;fwU9)m)8$zq

      l92L?ISBJF$F1a`1I^ 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 R|!h4FO=zu^pJd{%1clZ+g}o`kx6N4E15}i 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 literal 0 HcmV?d00001 diff --git a/source/target-vendors/cp312/pydantic_core/_pydantic_core.pyi b/source/target-vendors/cp312/pydantic_core/_pydantic_core.pyi new file mode 100644 index 0000000..122c86f --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core/_pydantic_core.pyi @@ -0,0 +1,1056 @@ +import datetime +from collections.abc import Mapping +from typing import Any, Callable, Generic, Literal, TypeVar, final + +from _typeshed import SupportsAllComparisons +from typing_extensions import LiteralString, Self, TypeAlias + +from pydantic_core import ErrorDetails, ErrorTypeInfo, InitErrorDetails, MultiHostHost +from pydantic_core.core_schema import CoreConfig, CoreSchema, ErrorType, ExtraBehavior + +__all__ = [ + '__version__', + 'build_profile', + 'build_info', + '_recursion_limit', + 'ArgsKwargs', + 'SchemaValidator', + 'SchemaSerializer', + 'Url', + 'MultiHostUrl', + 'SchemaError', + 'ValidationError', + 'PydanticCustomError', + 'PydanticKnownError', + 'PydanticOmit', + 'PydanticUseDefault', + 'PydanticSerializationError', + 'PydanticSerializationUnexpectedValue', + 'PydanticUndefined', + 'PydanticUndefinedType', + 'Some', + 'to_json', + 'from_json', + 'to_jsonable_python', + 'list_all_errors', + 'TzInfo', +] +__version__: str +build_profile: str +build_info: str +_recursion_limit: int + +_T = TypeVar('_T', default=Any, covariant=True) + +_StringInput: TypeAlias = 'dict[str, _StringInput]' + +@final +class Some(Generic[_T]): + """ + Similar to Rust's [`Option::Some`](https://doc.rust-lang.org/std/option/enum.Option.html) type, this + identifies a value as being present, and provides a way to access it. + + Generally used in a union with `None` to different between "some value which could be None" and no value. + """ + + __match_args__ = ('value',) + + @property + def value(self) -> _T: + """ + Returns the value wrapped by `Some`. + """ + @classmethod + def __class_getitem__(cls, item: Any, /) -> type[Self]: ... + +@final +class SchemaValidator: + """ + `SchemaValidator` is the Python wrapper for `pydantic-core`'s Rust validation logic, internally it owns one + `CombinedValidator` which may in turn own more `CombinedValidator`s which make up the full schema validator. + """ + + # note: pyo3 currently supports __new__, but not __init__, though we include __init__ stubs + # and docstrings here (and in the following classes) for documentation purposes + + def __init__(self, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> None: + """Initializes the `SchemaValidator`. + + Arguments: + schema: The `CoreSchema` to use for validation. + config: Optionally a [`CoreConfig`][pydantic_core.core_schema.CoreConfig] to configure validation. + _use_prebuilt: Whether to use pre-built validators (False during rebuilds to avoid stale references). + """ + + def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> Self: ... + @property + def title(self) -> str: + """ + The title of the schema, as used in the heading of [`ValidationError.__str__()`][pydantic_core.ValidationError]. + """ + def validate_python( + self, + input: Any, + *, + strict: bool | None = None, + extra: ExtraBehavior | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + self_instance: Any | None = None, + allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Any: + """ + Validate a Python object against the schema and return the validated object. + + Arguments: + input: The Python object to validate. + strict: Whether to validate the object in strict mode. + If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. + extra: Whether to ignore, allow, or forbid extra data during model validation. + If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. + from_attributes: Whether to validate objects as inputs to models by extracting attributes. + If `None`, the value of [`CoreConfig.from_attributes`][pydantic_core.core_schema.CoreConfig] is used. + context: The context to use for validation, this is passed to functional validators as + [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. + self_instance: An instance of a model set attributes on from validation, this is used when running + validation from the `__init__` method of a model. + allow_partial: Whether to allow partial validation; if `True` errors in the last element of sequences + and mappings are ignored. + `'trailing-strings'` means any final unfinished JSON string is included in the result. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Raises: + ValidationError: If validation fails. + Exception: Other error types maybe raised if internal errors occur. + + Returns: + The validated object. + """ + def isinstance_python( + self, + input: Any, + *, + strict: bool | None = None, + extra: ExtraBehavior | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + self_instance: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> bool: + """ + Similar to [`validate_python()`][pydantic_core.SchemaValidator.validate_python] but returns a boolean. + + Arguments match `validate_python()`. This method will not raise `ValidationError`s but will raise internal + errors. + + Returns: + `True` if validation succeeds, `False` if validation fails. + """ + def validate_json( + self, + input: str | bytes | bytearray, + *, + strict: bool | None = None, + extra: ExtraBehavior | None = None, + context: Any | None = None, + self_instance: Any | None = None, + allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Any: + """ + Validate JSON data directly against the schema and return the validated Python object. + + This method should be significantly faster than `validate_python(json.loads(json_data))` as it avoids the + need to create intermediate Python objects + + It also handles constructing the correct Python type even in strict mode, where + `validate_python(json.loads(json_data))` would fail validation. + + Arguments: + input: The JSON data to validate. + strict: Whether to validate the object in strict mode. + If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. + extra: Whether to ignore, allow, or forbid extra data during model validation. + If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. + context: The context to use for validation, this is passed to functional validators as + [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. + self_instance: An instance of a model set attributes on from validation. + allow_partial: Whether to allow partial validation; if `True` incomplete JSON will be parsed successfully + and errors in the last element of sequences and mappings are ignored. + `'trailing-strings'` means any final unfinished JSON string is included in the result. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Raises: + ValidationError: If validation fails or if the JSON data is invalid. + Exception: Other error types maybe raised if internal errors occur. + + Returns: + The validated Python object. + """ + def validate_strings( + self, + input: _StringInput, + *, + strict: bool | None = None, + extra: ExtraBehavior | None = None, + context: Any | None = None, + allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> Any: + """ + Validate a string against the schema and return the validated Python object. + + This is similar to `validate_json` but applies to scenarios where the input will be a string but not + JSON data, e.g. URL fragments, query parameters, etc. + + Arguments: + input: The input as a string, or bytes/bytearray if `strict=False`. + strict: Whether to validate the object in strict mode. + If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. + extra: Whether to ignore, allow, or forbid extra data during model validation. + If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. + context: The context to use for validation, this is passed to functional validators as + [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. + allow_partial: Whether to allow partial validation; if `True` errors in the last element of sequences + and mappings are ignored. + `'trailing-strings'` means any final unfinished JSON string is included in the result. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Raises: + ValidationError: If validation fails or if the JSON data is invalid. + Exception: Other error types maybe raised if internal errors occur. + + Returns: + The validated Python object. + """ + def validate_assignment( + self, + obj: Any, + field_name: str, + field_value: Any, + *, + strict: bool | None = None, + extra: ExtraBehavior | None = None, + from_attributes: bool | None = None, + context: Any | None = None, + by_alias: bool | None = None, + by_name: bool | None = None, + ) -> dict[str, Any] | tuple[dict[str, Any], dict[str, Any] | None, set[str]]: + """ + Validate an assignment to a field on a model. + + Arguments: + obj: The model instance being assigned to. + field_name: The name of the field to validate assignment for. + field_value: The value to assign to the field. + strict: Whether to validate the object in strict mode. + If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. + extra: Whether to ignore, allow, or forbid extra data during model validation. + If `None`, the value of [`CoreConfig.extra_fields_behavior`][pydantic_core.core_schema.CoreConfig] is used. + from_attributes: Whether to validate objects as inputs to models by extracting attributes. + If `None`, the value of [`CoreConfig.from_attributes`][pydantic_core.core_schema.CoreConfig] is used. + context: The context to use for validation, this is passed to functional validators as + [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. + by_alias: Whether to use the field's alias when validating against the provided input data. + by_name: Whether to use the field's name when validating against the provided input data. + + Raises: + ValidationError: If validation fails. + Exception: Other error types maybe raised if internal errors occur. + + Returns: + Either the model dict or a tuple of `(model_data, model_extra, fields_set)` + """ + def get_default_value(self, *, strict: bool | None = None, context: Any = None) -> Some | None: + """ + Get the default value for the schema, including running default value validation. + + Arguments: + strict: Whether to validate the default value in strict mode. + If `None`, the value of [`CoreConfig.strict`][pydantic_core.core_schema.CoreConfig] is used. + context: The context to use for validation, this is passed to functional validators as + [`info.context`][pydantic_core.core_schema.ValidationInfo.context]. + + Raises: + ValidationError: If validation fails. + Exception: Other error types maybe raised if internal errors occur. + + Returns: + `None` if the schema has no default value, otherwise a [`Some`][pydantic_core.Some] containing the default. + """ + +# In reality, `bool` should be replaced by `Literal[True]` but mypy fails to correctly apply bidirectional type inference +# (e.g. when using `{'a': {'b': True}}`). +_IncEx: TypeAlias = set[int] | set[str] | Mapping[int, _IncEx | bool] | Mapping[str, _IncEx | bool] + +@final +class SchemaSerializer: + """ + `SchemaSerializer` is the Python wrapper for `pydantic-core`'s Rust serialization logic, internally it owns one + `CombinedSerializer` which may in turn own more `CombinedSerializer`s which make up the full schema serializer. + """ + + def __init__(self, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> None: + """Initializes the `SchemaSerializer`. + + Arguments: + schema: The `CoreSchema` to use for serialization. + config: Optionally a [`CoreConfig`][pydantic_core.core_schema.CoreConfig] to to configure serialization. + _use_prebuilt: Whether to use pre-built validators (False during rebuilds to avoid stale references). + """ + + def __new__(cls, schema: CoreSchema, config: CoreConfig | None = None, _use_prebuilt: bool = True) -> Self: ... + def to_python( + self, + value: Any, + *, + mode: str | None = None, + include: _IncEx | None = None, + exclude: _IncEx | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + context: Any | None = None, + ) -> Any: + """ + Serialize/marshal a Python object to a Python object including transforming and filtering data. + + Arguments: + value: The Python object to serialize. + mode: The serialization mode to use, either `'python'` or `'json'`, defaults to `'python'`. In JSON mode, + all values are converted to JSON compatible types, e.g. `None`, `int`, `float`, `str`, `list`, `dict`. + include: A set of fields to include, if `None` all fields are included. + exclude: A set of fields to exclude, if `None` no fields are excluded. + by_alias: Whether to use the alias names of fields. + exclude_unset: Whether to exclude fields that are not set, + e.g. are not included in `__pydantic_fields_set__`. + exclude_defaults: Whether to exclude fields that are equal to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + round_trip: Whether to enable serialization and validation round-trip support. + warnings: How to handle invalid fields. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered, + if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + context: The context to use for serialization, this is passed to functional serializers as + [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. + + Raises: + PydanticSerializationError: If serialization fails and no `fallback` function is provided. + + Returns: + The serialized Python object. + """ + def to_json( + self, + value: Any, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: _IncEx | None = None, + exclude: _IncEx | None = None, + by_alias: bool | None = None, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, + exclude_computed_fields: bool = False, + round_trip: bool = False, + warnings: bool | Literal['none', 'warn', 'error'] = True, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + context: Any | None = None, + ) -> bytes: + """ + Serialize a Python object to JSON including transforming and filtering data. + + Arguments: + value: The Python object to serialize. + indent: If `None`, the JSON will be compact, otherwise it will be pretty-printed with the indent provided. + ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. + If `False` (the default), these characters will be output as-is. + include: A set of fields to include, if `None` all fields are included. + exclude: A set of fields to exclude, if `None` no fields are excluded. + by_alias: Whether to use the alias names of fields. + exclude_unset: Whether to exclude fields that are not set, + e.g. are not included in `__pydantic_fields_set__`. + exclude_defaults: Whether to exclude fields that are equal to their default value. + exclude_none: Whether to exclude fields that have a value of `None`. + exclude_computed_fields: Whether to exclude computed fields. + round_trip: Whether to enable serialization and validation round-trip support. + warnings: How to handle invalid fields. False/"none" ignores them, True/"warn" logs errors, + "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. + fallback: A function to call when an unknown value is encountered, + if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + context: The context to use for serialization, this is passed to functional serializers as + [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. + + Raises: + PydanticSerializationError: If serialization fails and no `fallback` function is provided. + + Returns: + JSON bytes. + """ + +def to_json( + value: Any, + *, + indent: int | None = None, + ensure_ascii: bool = False, + include: _IncEx | None = None, + exclude: _IncEx | None = None, + # Note: In Pydantic 2.11, the default value of `by_alias` on `SchemaSerializer` was changed from `True` to `None`, + # to be consistent with the Pydantic "dump" methods. However, the default of `True` was kept here for + # backwards compatibility. In Pydantic V3, `by_alias` is expected to default to `True` everywhere: + by_alias: bool = True, + exclude_none: bool = False, + round_trip: bool = False, + timedelta_mode: Literal['iso8601', 'float'] = 'iso8601', + temporal_mode: Literal['iso8601', 'seconds', 'milliseconds'] = 'iso8601', + bytes_mode: Literal['utf8', 'base64', 'hex'] = 'utf8', + inf_nan_mode: Literal['null', 'constants', 'strings'] = 'constants', + serialize_unknown: bool = False, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + context: Any | None = None, +) -> bytes: + """ + Serialize a Python object to JSON including transforming and filtering data. + + This is effectively a standalone version of [`SchemaSerializer.to_json`][pydantic_core.SchemaSerializer.to_json]. + + Arguments: + value: The Python object to serialize. + indent: If `None`, the JSON will be compact, otherwise it will be pretty-printed with the indent provided. + ensure_ascii: If `True`, the output is guaranteed to have all incoming non-ASCII characters escaped. + If `False` (the default), these characters will be output as-is. + include: A set of fields to include, if `None` all fields are included. + exclude: A set of fields to exclude, if `None` no fields are excluded. + by_alias: Whether to use the alias names of fields. + exclude_none: Whether to exclude fields that have a value of `None`. + round_trip: Whether to enable serialization and validation round-trip support. + timedelta_mode: How to serialize `timedelta` objects, either `'iso8601'` or `'float'`. + temporal_mode: How to serialize datetime-like objects (`datetime`, `date`, `time`), either `'iso8601'`, `'seconds'`, or `'milliseconds'`. + `iso8601` returns an ISO 8601 string; `seconds` returns the Unix timestamp in seconds as a float; `milliseconds` returns the Unix timestamp in milliseconds as a float. + + bytes_mode: How to serialize `bytes` objects, either `'utf8'`, `'base64'`, or `'hex'`. + inf_nan_mode: How to serialize `Infinity`, `-Infinity` and `NaN` values, either `'null'`, `'constants'`, or `'strings'`. + serialize_unknown: Attempt to serialize unknown types, `str(value)` will be used, if that fails + `""` will be used. + fallback: A function to call when an unknown value is encountered, + if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + context: The context to use for serialization, this is passed to functional serializers as + [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. + + Raises: + PydanticSerializationError: If serialization fails and no `fallback` function is provided. + + Returns: + JSON bytes. + """ + +def from_json( + data: str | bytes | bytearray, + *, + allow_inf_nan: bool = True, + cache_strings: bool | Literal['all', 'keys', 'none'] = True, + allow_partial: bool | Literal['off', 'on', 'trailing-strings'] = False, +) -> Any: + """ + Deserialize JSON data to a Python object. + + This is effectively a faster version of `json.loads()`, with some extra functionality. + + Arguments: + data: The JSON data to deserialize. + allow_inf_nan: Whether to allow `Infinity`, `-Infinity` and `NaN` values as `json.loads()` does by default. + cache_strings: Whether to cache strings to avoid constructing new Python objects, + this should have a significant impact on performance while increasing memory usage slightly, + `all/True` means cache all strings, `keys` means cache only dict keys, `none/False` means no caching. + allow_partial: Whether to allow partial deserialization, if `True` JSON data is returned if the end of the + input is reached before the full object is deserialized, e.g. `["aa", "bb", "c` would return `['aa', 'bb']`. + `'trailing-strings'` means any final unfinished JSON string is included in the result. + + Raises: + ValueError: If deserialization fails. + + Returns: + The deserialized Python object. + """ + +def to_jsonable_python( + value: Any, + *, + include: _IncEx | None = None, + exclude: _IncEx | None = None, + # Note: In Pydantic 2.11, the default value of `by_alias` on `SchemaSerializer` was changed from `True` to `None`, + # to be consistent with the Pydantic "dump" methods. However, the default of `True` was kept here for + # backwards compatibility. In Pydantic V3, `by_alias` is expected to default to `True` everywhere: + by_alias: bool = True, + exclude_none: bool = False, + round_trip: bool = False, + timedelta_mode: Literal['iso8601', 'float'] = 'iso8601', + temporal_mode: Literal['iso8601', 'seconds', 'milliseconds'] = 'iso8601', + bytes_mode: Literal['utf8', 'base64', 'hex'] = 'utf8', + inf_nan_mode: Literal['null', 'constants', 'strings'] = 'constants', + serialize_unknown: bool = False, + fallback: Callable[[Any], Any] | None = None, + serialize_as_any: bool = False, + polymorphic_serialization: bool | None = None, + context: Any | None = None, +) -> Any: + """ + Serialize/marshal a Python object to a JSON-serializable Python object including transforming and filtering data. + + This is effectively a standalone version of + [`SchemaSerializer.to_python(mode='json')`][pydantic_core.SchemaSerializer.to_python]. + + Args: + value: The Python object to serialize. + include: A set of fields to include, if `None` all fields are included. + exclude: A set of fields to exclude, if `None` no fields are excluded. + by_alias: Whether to use the alias names of fields. + exclude_none: Whether to exclude fields that have a value of `None`. + round_trip: Whether to enable serialization and validation round-trip support. + timedelta_mode: How to serialize `timedelta` objects, either `'iso8601'` or `'float'`. + temporal_mode: How to serialize datetime-like objects (`datetime`, `date`, `time`), either `'iso8601'`, `'seconds'`, or `'milliseconds'`. + `iso8601` returns an ISO 8601 string; `seconds` returns the Unix timestamp in seconds as a float; `milliseconds` returns the Unix timestamp in milliseconds as a float. + + bytes_mode: How to serialize `bytes` objects, either `'utf8'`, `'base64'`, or `'hex'`. + inf_nan_mode: How to serialize `Infinity`, `-Infinity` and `NaN` values, either `'null'`, `'constants'`, or `'strings'`. + serialize_unknown: Attempt to serialize unknown types, `str(value)` will be used, if that fails + `""` will be used. + fallback: A function to call when an unknown value is encountered, + if `None` a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. + serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. + polymorphic_serialization: Whether to use model and dataclass polymorphic serialization for this call. + context: The context to use for serialization, this is passed to functional serializers as + [`info.context`][pydantic_core.core_schema.SerializationInfo.context]. + + Raises: + PydanticSerializationError: If serialization fails and no `fallback` function is provided. + + Returns: + The serialized Python object. + """ + +class Url(SupportsAllComparisons): + """ + A URL type, internal logic uses the [url rust crate](https://docs.rs/url/latest/url/) originally developed + by Mozilla. + """ + + def __init__(self, url: str) -> None: ... + def __new__(cls, url: str) -> Self: ... + @property + def scheme(self) -> str: ... + @property + def username(self) -> str | None: ... + @property + def password(self) -> str | None: ... + @property + def host(self) -> str | None: ... + def unicode_host(self) -> str | None: ... + @property + def port(self) -> int | None: ... + @property + def path(self) -> str | None: ... + @property + def query(self) -> str | None: ... + def query_params(self) -> list[tuple[str, str]]: ... + @property + def fragment(self) -> str | None: ... + def unicode_string(self) -> str: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + def __deepcopy__(self, memo: dict) -> str: ... + @classmethod + def build( + cls, + *, + scheme: str, + username: str | None = None, + password: str | None = None, + host: str, + port: int | None = None, + path: str | None = None, + query: str | None = None, + fragment: str | None = None, + ) -> Self: ... + +class MultiHostUrl(SupportsAllComparisons): + """ + A URL type with support for multiple hosts, as used by some databases for DSNs, e.g. `https://foo.com,bar.com/path`. + + Internal URL logic uses the [url rust crate](https://docs.rs/url/latest/url/) originally developed + by Mozilla. + """ + + def __init__(self, url: str) -> None: ... + def __new__(cls, url: str) -> Self: ... + @property + def scheme(self) -> str: ... + @property + def path(self) -> str | None: ... + @property + def query(self) -> str | None: ... + def query_params(self) -> list[tuple[str, str]]: ... + @property + def fragment(self) -> str | None: ... + def hosts(self) -> list[MultiHostHost]: ... + def unicode_string(self) -> str: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + def __deepcopy__(self, memo: dict) -> Self: ... + @classmethod + def build( + cls, + *, + scheme: str, + hosts: list[MultiHostHost] | None = None, + username: str | None = None, + password: str | None = None, + host: str | None = None, + port: int | None = None, + path: str | None = None, + query: str | None = None, + fragment: str | None = None, + ) -> Self: ... + +@final +class SchemaError(Exception): + """ + Information about errors that occur while building a [`SchemaValidator`][pydantic_core.SchemaValidator] + or [`SchemaSerializer`][pydantic_core.SchemaSerializer]. + """ + + def error_count(self) -> int: + """ + Returns: + The number of errors in the schema. + """ + def errors(self) -> list[ErrorDetails]: + """ + Returns: + A list of [`ErrorDetails`][pydantic_core.ErrorDetails] for each error in the schema. + """ + +class ValidationError(ValueError): + """ + `ValidationError` is the exception raised by `pydantic-core` when validation fails, it contains a list of errors + which detail why validation failed. + """ + @classmethod + def from_exception_data( + cls, + title: str, + line_errors: list[InitErrorDetails], + input_type: Literal['python', 'json'] = 'python', + hide_input: bool = False, + ) -> Self: + """ + Python constructor for a Validation Error. + + Arguments: + title: The title of the error, as used in the heading of `str(validation_error)` + line_errors: A list of [`InitErrorDetails`][pydantic_core.InitErrorDetails] which contain information + about errors that occurred during validation. + input_type: Whether the error is for a Python object or JSON. + hide_input: Whether to hide the input value in the error message. + """ + @property + def title(self) -> str: + """ + The title of the error, as used in the heading of `str(validation_error)`. + """ + def error_count(self) -> int: + """ + Returns: + The number of errors in the validation error. + """ + def errors( + self, *, include_url: bool = True, include_context: bool = True, include_input: bool = True + ) -> list[ErrorDetails]: + """ + Details about each error in the validation error. + + Args: + include_url: Whether to include a URL to documentation on the error each error. + include_context: Whether to include the context of each error. + include_input: Whether to include the input value of each error. + + Returns: + A list of [`ErrorDetails`][pydantic_core.ErrorDetails] for each error in the validation error. + """ + def json( + self, + *, + indent: int | None = None, + include_url: bool = True, + include_context: bool = True, + include_input: bool = True, + ) -> str: + """ + Same as [`errors()`][pydantic_core.ValidationError.errors] but returns a JSON string. + + Args: + indent: The number of spaces to indent the JSON by, or `None` for no indentation - compact JSON. + include_url: Whether to include a URL to documentation on the error each error. + include_context: Whether to include the context of each error. + include_input: Whether to include the input value of each error. + + Returns: + a JSON string. + """ + + def __repr__(self) -> str: + """ + A string representation of the validation error. + + Whether or not documentation URLs are included in the repr is controlled by the + environment variable `PYDANTIC_ERRORS_INCLUDE_URL` being set to `1` or + `true`; by default, URLs are shown. + + Due to implementation details, this environment variable can only be set once, + before the first validation error is created. + """ + +class PydanticCustomError(ValueError): + """A custom exception providing flexible error handling for Pydantic validators. + + You can raise this error in custom validators when you'd like flexibility in regards to the error type, message, and context. + + Example: + ```py + from pydantic_core import PydanticCustomError + + def custom_validator(v) -> None: + if v <= 10: + raise PydanticCustomError('custom_value_error', 'Value must be greater than {value}', {'value': 10, 'extra_context': 'extra_data'}) + return v + ``` + + Arguments: + error_type: The error type. + message_template: The message template. + context: The data to inject into the message template. + """ + + def __init__( + self, error_type: LiteralString, message_template: LiteralString, context: dict[str, Any] | None = None, / + ) -> None: ... + @property + def context(self) -> dict[str, Any] | None: + """Values which are required to render the error message, and could hence be useful in passing error data forward.""" + + @property + def type(self) -> str: + """The error type associated with the error. For consistency with Pydantic, this is typically a snake_case string.""" + + @property + def message_template(self) -> str: + """The message template associated with the error. This is a string that can be formatted with context variables in `{curly_braces}`.""" + + def message(self) -> str: + """The formatted message associated with the error. This presents as the message template with context variables appropriately injected.""" + +@final +class PydanticKnownError(ValueError): + """A helper class for raising exceptions that mimic Pydantic's built-in exceptions, with more flexibility in regards to context. + + Unlike [`PydanticCustomError`][pydantic_core.PydanticCustomError], the `error_type` argument must be a known `ErrorType`. + + Example: + ```py + from pydantic_core import PydanticKnownError + + def custom_validator(v) -> None: + if v <= 10: + raise PydanticKnownError('greater_than', {'gt': 10}) + return v + ``` + + Arguments: + error_type: The error type. + context: The data to inject into the message template. + """ + + def __init__(self, error_type: ErrorType, context: dict[str, Any] | None = None, /) -> None: ... + @property + def context(self) -> dict[str, Any] | None: + """Values which are required to render the error message, and could hence be useful in passing error data forward.""" + + @property + def type(self) -> ErrorType: + """The type of the error.""" + + @property + def message_template(self) -> str: + """The message template associated with the provided error type. This is a string that can be formatted with context variables in `{curly_braces}`.""" + + def message(self) -> str: + """The formatted message associated with the error. This presents as the message template with context variables appropriately injected.""" + +@final +class PydanticOmit(Exception): + """An exception to signal that a field should be omitted from a generated result. + + This could span from omitting a field from a JSON Schema to omitting a field from a serialized result. + Upcoming: more robust support for using PydanticOmit in custom serializers is still in development. + Right now, this is primarily used in the JSON Schema generation process. + + Example: + ```py + from typing import Callable + + from pydantic_core import PydanticOmit + + from pydantic import BaseModel + from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue + + + class MyGenerateJsonSchema(GenerateJsonSchema): + def handle_invalid_for_json_schema(self, schema, error_info) -> JsonSchemaValue: + raise PydanticOmit + + + class Predicate(BaseModel): + name: str = 'no-op' + func: Callable = lambda x: x + + + instance_example = Predicate() + + validation_schema = instance_example.model_json_schema(schema_generator=MyGenerateJsonSchema, mode='validation') + print(validation_schema) + ''' + {'properties': {'name': {'default': 'no-op', 'title': 'Name', 'type': 'string'}}, 'title': 'Predicate', 'type': 'object'} + ''' + ``` + + For a more in depth example / explanation, see the [customizing JSON schema](../concepts/json_schema.md#customizing-the-json-schema-generation-process) docs. + """ + + def __new__(cls) -> Self: ... + +@final +class PydanticUseDefault(Exception): + """An exception to signal that standard validation either failed or should be skipped, and the default value should be used instead. + + This warning can be raised in custom validation functions to redirect the flow of validation. + + Example: + ```py + from pydantic_core import PydanticUseDefault + from datetime import datetime + from pydantic import BaseModel, field_validator + + + class Event(BaseModel): + name: str = 'meeting' + time: datetime + + @field_validator('name', mode='plain') + def name_must_be_present(cls, v) -> str: + if not v or not isinstance(v, str): + raise PydanticUseDefault() + return v + + + event1 = Event(name='party', time=datetime(2024, 1, 1, 12, 0, 0)) + print(repr(event1)) + # > Event(name='party', time=datetime.datetime(2024, 1, 1, 12, 0)) + event2 = Event(time=datetime(2024, 1, 1, 12, 0, 0)) + print(repr(event2)) + # > Event(name='meeting', time=datetime.datetime(2024, 1, 1, 12, 0)) + ``` + + For an additional example, see the [validating partial json data](../concepts/json.md#partial-json-parsing) section of the Pydantic documentation. + """ + + def __new__(cls) -> Self: ... + +@final +class PydanticSerializationError(ValueError): + """An error raised when an issue occurs during serialization. + + In custom serializers, this error can be used to indicate that serialization has failed. + + Arguments: + message: The message associated with the error. + """ + + def __init__(self, message: str, /) -> None: ... + +@final +class PydanticSerializationUnexpectedValue(ValueError): + """An error raised when an unexpected value is encountered during serialization. + + This error is often caught and coerced into a warning, as `pydantic-core` generally makes a best attempt + at serializing values, in contrast with validation where errors are eagerly raised. + + Example: + ```py + from pydantic import BaseModel, field_serializer + from pydantic_core import PydanticSerializationUnexpectedValue + + class BasicPoint(BaseModel): + x: int + y: int + + @field_serializer('*') + def serialize(self, v): + if not isinstance(v, int): + raise PydanticSerializationUnexpectedValue(f'Expected type `int`, got {type(v)} with value {v}') + return v + + point = BasicPoint(x=1, y=2) + # some sort of mutation + point.x = 'a' + + print(point.model_dump()) + ''' + UserWarning: Pydantic serializer warnings: + PydanticSerializationUnexpectedValue(Expected type `int`, got with value a) + return self.__pydantic_serializer__.to_python( + {'x': 'a', 'y': 2} + ''' + ``` + + This is often used internally in `pydantic-core` when unexpected types are encountered during serialization, + but it can also be used by users in custom serializers, as seen above. + + Arguments: + message: The message associated with the unexpected value. + """ + + def __init__(self, message: str, /) -> None: ... + +@final +class ArgsKwargs: + """A construct used to store arguments and keyword arguments for a function call. + + This data structure is generally used to store information for core schemas associated with functions (like in an arguments schema). + This data structure is also currently used for some validation against dataclasses. + + Example: + ```py + from pydantic.dataclasses import dataclass + from pydantic import model_validator + + + @dataclass + class Model: + a: int + b: int + + @model_validator(mode="before") + @classmethod + def no_op_validator(cls, values): + print(values) + return values + + Model(1, b=2) + #> ArgsKwargs((1,), {"b": 2}) + + Model(1, 2) + #> ArgsKwargs((1, 2), {}) + + Model(a=1, b=2) + #> ArgsKwargs((), {"a": 1, "b": 2}) + ``` + """ + + def __init__(self, args: tuple[Any, ...], kwargs: dict[str, Any] | None = None) -> None: + """Initializes the `ArgsKwargs`. + + Arguments: + args: The arguments (inherently ordered) for a function call. + kwargs: The keyword arguments for a function call + """ + + def __new__(cls, args: tuple[Any, ...], kwargs: dict[str, Any] | None = None) -> Self: ... + @property + def args(self) -> tuple[Any, ...]: + """The arguments (inherently ordered) for a function call.""" + + @property + def kwargs(self) -> dict[str, Any] | None: + """The keyword arguments for a function call.""" + +@final +class PydanticUndefinedType: + """A type used as a sentinel for undefined values.""" + + def __copy__(self) -> Self: ... + def __deepcopy__(self, memo: Any) -> Self: ... + +PydanticUndefined: PydanticUndefinedType + +def list_all_errors() -> list[ErrorTypeInfo]: + """ + Get information about all built-in errors. + + Returns: + A list of `ErrorTypeInfo` typed dicts. + """ +@final +class TzInfo(datetime.tzinfo): + """An `pydantic-core` implementation of the abstract [`datetime.tzinfo`][] class.""" + + def __init__(self, seconds: float = 0.0) -> None: + """Initializes the `TzInfo`. + + Arguments: + seconds: The offset from UTC in seconds. Defaults to 0.0 (UTC). + """ + + def __new__(cls, seconds: float = 0.0) -> Self: ... + + # Docstrings for attributes sourced from the abstract base class, [`datetime.tzinfo`](https://docs.python.org/3/library/datetime.html#datetime.tzinfo). + + def tzname(self, dt: datetime.datetime | None) -> str | None: + """Return the time zone name corresponding to the [`datetime`][datetime.datetime] object _dt_, as a string. + + For more info, see [`tzinfo.tzname`][datetime.tzinfo.tzname]. + """ + + def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta | None: + """Return offset of local time from UTC, as a [`timedelta`][datetime.timedelta] object that is positive east of UTC. If local time is west of UTC, this should be negative. + + More info can be found at [`tzinfo.utcoffset`][datetime.tzinfo.utcoffset]. + """ + + def dst(self, dt: datetime.datetime | None) -> datetime.timedelta | None: + """Return the daylight saving time (DST) adjustment, as a [`timedelta`][datetime.timedelta] object or `None` if DST information isn’t known. + + More info can be found at[`tzinfo.dst`][datetime.tzinfo.dst].""" + + def fromutc(self, dt: datetime.datetime) -> datetime.datetime: + """Adjust the date and time data associated datetime object _dt_, returning an equivalent datetime in self’s local time. + + More info can be found at [`tzinfo.fromutc`][datetime.tzinfo.fromutc].""" + + def __deepcopy__(self, _memo: dict[Any, Any]) -> TzInfo: ... diff --git a/source/target-vendors/cp312/pydantic_core/core_schema.py b/source/target-vendors/cp312/pydantic_core/core_schema.py new file mode 100644 index 0000000..6ff202c --- /dev/null +++ b/source/target-vendors/cp312/pydantic_core/core_schema.py @@ -0,0 +1,4461 @@ +""" +This module contains definitions to build schemas which `pydantic_core` can +validate and serialize. +""" + +from __future__ import annotations as _annotations + +import sys +import warnings +from collections.abc import Generator, Hashable, Mapping +from datetime import date, datetime, time, timedelta +from decimal import Decimal +from re import Pattern +from typing import TYPE_CHECKING, Any, Callable, Literal, Union + +from typing_extensions import TypeVar, deprecated + +if sys.version_info < (3, 12): + from typing_extensions import TypedDict +else: + from typing import TypedDict + +if sys.version_info < (3, 11): + from typing_extensions import Protocol, Required, TypeAlias +else: + from typing import Protocol, Required, TypeAlias + +if TYPE_CHECKING: + from pydantic_core import PydanticUndefined +else: + # The initial build of pydantic_core requires PydanticUndefined to generate + # the core schema; so we need to conditionally skip it. mypy doesn't like + # this at all, hence the TYPE_CHECKING branch above. + try: + from pydantic_core import PydanticUndefined + except ImportError: + PydanticUndefined = object() + + +ExtraBehavior = Literal['allow', 'forbid', 'ignore'] + + +class CoreConfig(TypedDict, total=False): + """ + Base class for schema configuration options. + + Attributes: + title: The name of the configuration. + strict: Whether the configuration should strictly adhere to specified rules. + extra_fields_behavior: The behavior for handling extra fields. + typed_dict_total: Whether the TypedDict should be considered total. Default is `True`. + from_attributes: Whether to use attributes for models, dataclasses, and tagged union keys. + loc_by_alias: Whether to use the used alias (or first alias for "field required" errors) instead of + `field_names` to construct error `loc`s. Default is `True`. + revalidate_instances: Whether instances of models and dataclasses should re-validate. Default is 'never'. + validate_default: Whether to validate default values during validation. Default is `False`. + str_max_length: The maximum length for string fields. + str_min_length: The minimum length for string fields. + str_strip_whitespace: Whether to strip whitespace from string fields. + str_to_lower: Whether to convert string fields to lowercase. + str_to_upper: Whether to convert string fields to uppercase. + allow_inf_nan: Whether to allow infinity and NaN values for float fields. Default is `True`. + ser_json_timedelta: The serialization option for `timedelta` values. Default is 'iso8601'. + Note that if ser_json_temporal is set, then this param will be ignored. + ser_json_temporal: The serialization option for datetime like values. Default is 'iso8601'. + The types this covers are datetime, date, time and timedelta. + If this is set, it will take precedence over ser_json_timedelta + ser_json_bytes: The serialization option for `bytes` values. Default is 'utf8'. + ser_json_inf_nan: The serialization option for infinity and NaN values + in float fields. Default is 'null'. + val_json_bytes: The validation option for `bytes` values, complementing ser_json_bytes. Default is 'utf8'. + hide_input_in_errors: Whether to hide input data from `ValidationError` representation. + validation_error_cause: Whether to add user-python excs to the __cause__ of a ValidationError. + Requires exceptiongroup backport pre Python 3.11. + coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode). + regex_engine: The regex engine to use for regex pattern validation. Default is 'rust-regex'. See `StringSchema`. + cache_strings: Whether to cache strings. Default is `True`, `True` or `'all'` is required to cache strings + during general validation since validators don't know if they're in a key or a value. + validate_by_alias: Whether to use the field's alias when validating against the provided input data. Default is `True`. + validate_by_name: Whether to use the field's name when validating against the provided input data. Default is `False`. Replacement for `populate_by_name`. + serialize_by_alias: Whether to serialize by alias. Default is `False`, expected to change to `True` in V3. + polymorphic_serialization: Whether to enable polymorphic serialization for models and dataclasses. Default is `False`. + url_preserve_empty_path: Whether to preserve empty URL paths when validating values for a URL type. Defaults to `False`. + """ + + title: str + strict: bool + # settings related to typed dicts, model fields, dataclass fields + extra_fields_behavior: ExtraBehavior + typed_dict_total: bool # default: True + # used for models, dataclasses, and tagged union keys + from_attributes: bool + # whether to use the used alias (or first alias for "field required" errors) instead of field_names + # to construct error `loc`s, default True + loc_by_alias: bool + # whether instances of models and dataclasses (including subclass instances) should re-validate, default 'never' + revalidate_instances: Literal['always', 'never', 'subclass-instances'] + # whether to validate default values during validation, default False + validate_default: bool + # used on typed-dicts and arguments + # fields related to string fields only + str_max_length: int + str_min_length: int + str_strip_whitespace: bool + str_to_lower: bool + str_to_upper: bool + # fields related to float fields only + allow_inf_nan: bool # default: True + # the config options are used to customise serialization to JSON + ser_json_timedelta: Literal['iso8601', 'float'] # default: 'iso8601' + ser_json_temporal: Literal['iso8601', 'seconds', 'milliseconds'] # default: 'iso8601' + ser_json_bytes: Literal['utf8', 'base64', 'hex'] # default: 'utf8' + ser_json_inf_nan: Literal['null', 'constants', 'strings'] # default: 'null' + val_json_bytes: Literal['utf8', 'base64', 'hex'] # default: 'utf8' + # used to hide input data from ValidationError repr + hide_input_in_errors: bool + validation_error_cause: bool # default: False + coerce_numbers_to_str: bool # default: False + regex_engine: Literal['rust-regex', 'python-re'] # default: 'rust-regex' + cache_strings: Union[bool, Literal['all', 'keys', 'none']] # default: 'True' + validate_by_alias: bool # default: True + validate_by_name: bool # default: False + serialize_by_alias: bool # default: False + polymorphic_serialization: bool # default: False + url_preserve_empty_path: bool # default: False + + +IncExCall: TypeAlias = 'set[int | str] | dict[int | str, IncExCall] | None' + +ContextT = TypeVar('ContextT', covariant=True, default='Any | None') + + +class SerializationInfo(Protocol[ContextT]): + """Extra data used during serialization.""" + + @property + def include(self) -> IncExCall: + """The `include` argument set during serialization.""" + ... + + @property + def exclude(self) -> IncExCall: + """The `exclude` argument set during serialization.""" + ... + + @property + def context(self) -> ContextT: + """The current serialization context.""" + ... + + @property + def mode(self) -> Literal['python', 'json'] | str: + """The serialization mode set during serialization.""" + ... + + @property + def by_alias(self) -> bool: + """The `by_alias` argument set during serialization.""" + ... + + @property + def exclude_unset(self) -> bool: + """The `exclude_unset` argument set during serialization.""" + ... + + @property + def exclude_defaults(self) -> bool: + """The `exclude_defaults` argument set during serialization.""" + ... + + @property + def exclude_none(self) -> bool: + """The `exclude_none` argument set during serialization.""" + ... + + @property + def exclude_computed_fields(self) -> bool: + """The `exclude_computed_fields` argument set during serialization.""" + ... + + @property + def serialize_as_any(self) -> bool: + """The `serialize_as_any` argument set during serialization.""" + ... + + @property + def polymorphic_serialization(self) -> bool | None: + """The `polymorphic_serialization` argument set during serialization, if any.""" + ... + + @property + def round_trip(self) -> bool: + """The `round_trip` argument set during serialization.""" + ... + + def mode_is_json(self) -> bool: ... + + def __str__(self) -> str: ... + + def __repr__(self) -> str: ... + + +class FieldSerializationInfo(SerializationInfo[ContextT], Protocol): + """Extra data used during field serialization.""" + + @property + def field_name(self) -> str: + """The name of the current field being serialized.""" + ... + + +class ValidationInfo(Protocol[ContextT]): + """Extra data used during validation.""" + + @property + def context(self) -> ContextT: + """The current validation context.""" + ... + + @property + def config(self) -> CoreConfig | None: + """The CoreConfig that applies to this validation.""" + ... + + @property + def mode(self) -> Literal['python', 'json']: + """The type of input data we are currently validating.""" + ... + + @property + def data(self) -> dict[str, Any]: + """The data being validated for this model.""" + ... + + @property + def field_name(self) -> str | None: + """ + The name of the current field being validated if this validator is + attached to a model field. + """ + ... + + +ExpectedSerializationTypes = Literal[ + 'none', + 'int', + 'bool', + 'float', + 'str', + 'bytes', + 'bytearray', + 'list', + 'tuple', + 'set', + 'frozenset', + 'generator', + 'dict', + 'datetime', + 'date', + 'time', + 'timedelta', + 'url', + 'multi-host-url', + 'json', + 'uuid', + 'any', +] + + +class SimpleSerSchema(TypedDict, total=False): + type: Required[ExpectedSerializationTypes] + + +def simple_ser_schema(type: ExpectedSerializationTypes) -> SimpleSerSchema: + """ + Returns a schema for serialization with a custom type. + + Args: + type: The type to use for serialization + """ + return SimpleSerSchema(type=type) + + +# (input_value: Any, /) -> Any +GeneralPlainNoInfoSerializerFunction = Callable[[Any], Any] +# (input_value: Any, info: FieldSerializationInfo, /) -> Any +GeneralPlainInfoSerializerFunction = Callable[[Any, SerializationInfo[Any]], Any] +# (model: Any, input_value: Any, /) -> Any +FieldPlainNoInfoSerializerFunction = Callable[[Any, Any], Any] +# (model: Any, input_value: Any, info: FieldSerializationInfo, /) -> Any +FieldPlainInfoSerializerFunction = Callable[[Any, Any, FieldSerializationInfo[Any]], Any] +SerializerFunction = Union[ + GeneralPlainNoInfoSerializerFunction, + GeneralPlainInfoSerializerFunction, + FieldPlainNoInfoSerializerFunction, + FieldPlainInfoSerializerFunction, +] + +WhenUsed = Literal['always', 'unless-none', 'json', 'json-unless-none'] +""" +Values have the following meanings: + +* `'always'` means always use +* `'unless-none'` means use unless the value is `None` +* `'json'` means use when serializing to JSON +* `'json-unless-none'` means use when serializing to JSON and the value is not `None` +""" + + +class PlainSerializerFunctionSerSchema(TypedDict, total=False): + type: Required[Literal['function-plain']] + function: Required[SerializerFunction] + is_field_serializer: bool # default False + info_arg: bool # default False + return_schema: CoreSchema # if omitted, AnySchema is used + when_used: WhenUsed # default: 'always' + + +def plain_serializer_function_ser_schema( + function: SerializerFunction, + *, + is_field_serializer: bool | None = None, + info_arg: bool | None = None, + return_schema: CoreSchema | None = None, + when_used: WhenUsed = 'always', +) -> PlainSerializerFunctionSerSchema: + """ + Returns a schema for serialization with a function, can be either a "general" or "field" function. + + Args: + function: The function to use for serialization + is_field_serializer: Whether the serializer is for a field, e.g. takes `model` as the first argument, + and `info` includes `field_name` + info_arg: Whether the function takes an `info` argument + return_schema: Schema to use for serializing return value + when_used: When the function should be called + """ + if when_used == 'always': + # just to avoid extra elements in schema, and to use the actual default defined in rust + when_used = None # type: ignore + return _dict_not_none( + type='function-plain', + function=function, + is_field_serializer=is_field_serializer, + info_arg=info_arg, + return_schema=return_schema, + when_used=when_used, + ) + + +class SerializerFunctionWrapHandler(Protocol): # pragma: no cover + def __call__(self, input_value: Any, index_key: int | str | None = None, /) -> Any: ... + + +# (input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any +GeneralWrapNoInfoSerializerFunction = Callable[[Any, SerializerFunctionWrapHandler], Any] +# (input_value: Any, serializer: SerializerFunctionWrapHandler, info: SerializationInfo, /) -> Any +GeneralWrapInfoSerializerFunction = Callable[[Any, SerializerFunctionWrapHandler, SerializationInfo[Any]], Any] +# (model: Any, input_value: Any, serializer: SerializerFunctionWrapHandler, /) -> Any +FieldWrapNoInfoSerializerFunction = Callable[[Any, Any, SerializerFunctionWrapHandler], Any] +# (model: Any, input_value: Any, serializer: SerializerFunctionWrapHandler, info: FieldSerializationInfo, /) -> Any +FieldWrapInfoSerializerFunction = Callable[[Any, Any, SerializerFunctionWrapHandler, FieldSerializationInfo[Any]], Any] +WrapSerializerFunction = Union[ + GeneralWrapNoInfoSerializerFunction, + GeneralWrapInfoSerializerFunction, + FieldWrapNoInfoSerializerFunction, + FieldWrapInfoSerializerFunction, +] + + +class WrapSerializerFunctionSerSchema(TypedDict, total=False): + type: Required[Literal['function-wrap']] + function: Required[WrapSerializerFunction] + is_field_serializer: bool # default False + info_arg: bool # default False + schema: CoreSchema # if omitted, the schema on which this serializer is defined is used + return_schema: CoreSchema # if omitted, AnySchema is used + when_used: WhenUsed # default: 'always' + + +def wrap_serializer_function_ser_schema( + function: WrapSerializerFunction, + *, + is_field_serializer: bool | None = None, + info_arg: bool | None = None, + schema: CoreSchema | None = None, + return_schema: CoreSchema | None = None, + when_used: WhenUsed = 'always', +) -> WrapSerializerFunctionSerSchema: + """ + Returns a schema for serialization with a wrap function, can be either a "general" or "field" function. + + Args: + function: The function to use for serialization + is_field_serializer: Whether the serializer is for a field, e.g. takes `model` as the first argument, + and `info` includes `field_name` + info_arg: Whether the function takes an `info` argument + schema: The schema to use for the inner serialization + return_schema: Schema to use for serializing return value + when_used: When the function should be called + """ + if when_used == 'always': + # just to avoid extra elements in schema, and to use the actual default defined in rust + when_used = None # type: ignore + return _dict_not_none( + type='function-wrap', + function=function, + is_field_serializer=is_field_serializer, + info_arg=info_arg, + schema=schema, + return_schema=return_schema, + when_used=when_used, + ) + + +class FormatSerSchema(TypedDict, total=False): + type: Required[Literal['format']] + formatting_string: Required[str] + when_used: WhenUsed # default: 'json-unless-none' + + +def format_ser_schema(formatting_string: str, *, when_used: WhenUsed = 'json-unless-none') -> FormatSerSchema: + """ + Returns a schema for serialization using python's `format` method. + + Args: + formatting_string: String defining the format to use + when_used: Same meaning as for [general_function_plain_ser_schema], but with a different default + """ + if when_used == 'json-unless-none': + # just to avoid extra elements in schema, and to use the actual default defined in rust + when_used = None # type: ignore + return _dict_not_none(type='format', formatting_string=formatting_string, when_used=when_used) + + +class ToStringSerSchema(TypedDict, total=False): + type: Required[Literal['to-string']] + when_used: WhenUsed # default: 'json-unless-none' + + +def to_string_ser_schema(*, when_used: WhenUsed = 'json-unless-none') -> ToStringSerSchema: + """ + Returns a schema for serialization using python's `str()` / `__str__` method. + + Args: + when_used: Same meaning as for [general_function_plain_ser_schema], but with a different default + """ + s = dict(type='to-string') + if when_used != 'json-unless-none': + # just to avoid extra elements in schema, and to use the actual default defined in rust + s['when_used'] = when_used + return s # type: ignore + + +class ModelSerSchema(TypedDict, total=False): + type: Required[Literal['model']] + cls: Required[type[Any]] + schema: Required[CoreSchema] + + +def model_ser_schema(cls: type[Any], schema: CoreSchema) -> ModelSerSchema: + """ + Returns a schema for serialization using a model. + + Args: + cls: The expected class type, used to generate warnings if the wrong type is passed + schema: Internal schema to use to serialize the model dict + """ + return ModelSerSchema(type='model', cls=cls, schema=schema) + + +SerSchema = Union[ + SimpleSerSchema, + PlainSerializerFunctionSerSchema, + WrapSerializerFunctionSerSchema, + FormatSerSchema, + ToStringSerSchema, + ModelSerSchema, +] + + +class InvalidSchema(TypedDict, total=False): + type: Required[Literal['invalid']] + ref: str + metadata: dict[str, Any] + # note, we never plan to use this, but include it for type checking purposes to match + # all other CoreSchema union members + serialization: SerSchema + + +def invalid_schema(ref: str | None = None, metadata: dict[str, Any] | None = None) -> InvalidSchema: + """ + Returns an invalid schema, used to indicate that a schema is invalid. + + Args: + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + """ + + return _dict_not_none(type='invalid', ref=ref, metadata=metadata) + + +class ComputedField(TypedDict, total=False): + type: Required[Literal['computed-field']] + property_name: Required[str] + return_schema: Required[CoreSchema] + alias: str + serialization_exclude_if: Callable[[Any], bool] + metadata: dict[str, Any] + + +def computed_field( + property_name: str, + return_schema: CoreSchema, + *, + alias: str | None = None, + serialization_exclude_if: Callable[[Any], bool] | None = None, + metadata: dict[str, Any] | None = None, +) -> ComputedField: + """ + ComputedFields are properties of a model or dataclass that are included in serialization. + + Args: + property_name: The name of the property on the model or dataclass + return_schema: The schema used for the type returned by the computed field + alias: The name to use in the serialized output + metadata: Any other information you want to include with the schema, not used by pydantic-core + """ + return _dict_not_none( + type='computed-field', + property_name=property_name, + return_schema=return_schema, + alias=alias, + serialization_exclude_if=serialization_exclude_if, + metadata=metadata, + ) + + +class AnySchema(TypedDict, total=False): + type: Required[Literal['any']] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def any_schema( + *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None +) -> AnySchema: + """ + Returns a schema that matches any value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.any_schema() + v = SchemaValidator(schema) + assert v.validate_python(1) == 1 + ``` + + Args: + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='any', ref=ref, metadata=metadata, serialization=serialization) + + +class NoneSchema(TypedDict, total=False): + type: Required[Literal['none']] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def none_schema( + *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None +) -> NoneSchema: + """ + Returns a schema that matches a None value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.none_schema() + v = SchemaValidator(schema) + assert v.validate_python(None) is None + ``` + + Args: + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='none', ref=ref, metadata=metadata, serialization=serialization) + + +class BoolSchema(TypedDict, total=False): + type: Required[Literal['bool']] + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def bool_schema( + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> BoolSchema: + """ + Returns a schema that matches a bool value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.bool_schema() + v = SchemaValidator(schema) + assert v.validate_python('True') is True + ``` + + Args: + strict: Whether the value should be a bool or a value that can be converted to a bool + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='bool', strict=strict, ref=ref, metadata=metadata, serialization=serialization) + + +class IntSchema(TypedDict, total=False): + type: Required[Literal['int']] + multiple_of: int + le: int + ge: int + lt: int + gt: int + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def int_schema( + *, + multiple_of: int | None = None, + le: int | None = None, + ge: int | None = None, + lt: int | None = None, + gt: int | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> IntSchema: + """ + Returns a schema that matches a int value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.int_schema(multiple_of=2, le=6, ge=2) + v = SchemaValidator(schema) + assert v.validate_python('4') == 4 + ``` + + Args: + multiple_of: The value must be a multiple of this number + le: The value must be less than or equal to this number + ge: The value must be greater than or equal to this number + lt: The value must be strictly less than this number + gt: The value must be strictly greater than this number + strict: Whether the value should be a int or a value that can be converted to a int + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='int', + multiple_of=multiple_of, + le=le, + ge=ge, + lt=lt, + gt=gt, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class FloatSchema(TypedDict, total=False): + type: Required[Literal['float']] + allow_inf_nan: bool # whether 'NaN', '+inf', '-inf' should be forbidden. default: True + multiple_of: float + le: float + ge: float + lt: float + gt: float + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def float_schema( + *, + allow_inf_nan: bool | None = None, + multiple_of: float | None = None, + le: float | None = None, + ge: float | None = None, + lt: float | None = None, + gt: float | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> FloatSchema: + """ + Returns a schema that matches a float value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.float_schema(le=0.8, ge=0.2) + v = SchemaValidator(schema) + assert v.validate_python('0.5') == 0.5 + ``` + + Args: + allow_inf_nan: Whether to allow inf and nan values + multiple_of: The value must be a multiple of this number + le: The value must be less than or equal to this number + ge: The value must be greater than or equal to this number + lt: The value must be strictly less than this number + gt: The value must be strictly greater than this number + strict: Whether the value should be a float or a value that can be converted to a float + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='float', + allow_inf_nan=allow_inf_nan, + multiple_of=multiple_of, + le=le, + ge=ge, + lt=lt, + gt=gt, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class DecimalSchema(TypedDict, total=False): + type: Required[Literal['decimal']] + allow_inf_nan: bool # whether 'NaN', '+inf', '-inf' should be forbidden. default: False + multiple_of: Decimal + le: Decimal + ge: Decimal + lt: Decimal + gt: Decimal + max_digits: int + decimal_places: int + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def decimal_schema( + *, + allow_inf_nan: bool | None = None, + multiple_of: Decimal | None = None, + le: Decimal | None = None, + ge: Decimal | None = None, + lt: Decimal | None = None, + gt: Decimal | None = None, + max_digits: int | None = None, + decimal_places: int | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> DecimalSchema: + """ + Returns a schema that matches a decimal value, e.g.: + + ```py + from decimal import Decimal + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.decimal_schema(le=0.8, ge=0.2) + v = SchemaValidator(schema) + assert v.validate_python('0.5') == Decimal('0.5') + ``` + + Args: + allow_inf_nan: Whether to allow inf and nan values + multiple_of: The value must be a multiple of this number + le: The value must be less than or equal to this number + ge: The value must be greater than or equal to this number + lt: The value must be strictly less than this number + gt: The value must be strictly greater than this number + max_digits: The maximum number of decimal digits allowed + decimal_places: The maximum number of decimal places allowed + strict: Whether the value should be a float or a value that can be converted to a float + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='decimal', + gt=gt, + ge=ge, + lt=lt, + le=le, + max_digits=max_digits, + decimal_places=decimal_places, + multiple_of=multiple_of, + allow_inf_nan=allow_inf_nan, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class ComplexSchema(TypedDict, total=False): + type: Required[Literal['complex']] + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def complex_schema( + *, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> ComplexSchema: + """ + Returns a schema that matches a complex value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.complex_schema() + v = SchemaValidator(schema) + assert v.validate_python('1+2j') == complex(1, 2) + assert v.validate_python(complex(1, 2)) == complex(1, 2) + ``` + + Args: + strict: Whether the value should be a complex object instance or a value that can be converted to a complex object + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='complex', + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class StringSchema(TypedDict, total=False): + type: Required[Literal['str']] + pattern: Union[str, Pattern[str]] + max_length: int + min_length: int + strip_whitespace: bool + to_lower: bool + to_upper: bool + regex_engine: Literal['rust-regex', 'python-re'] # default: 'rust-regex' + strict: bool + coerce_numbers_to_str: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def str_schema( + *, + pattern: str | Pattern[str] | None = None, + max_length: int | None = None, + min_length: int | None = None, + strip_whitespace: bool | None = None, + to_lower: bool | None = None, + to_upper: bool | None = None, + regex_engine: Literal['rust-regex', 'python-re'] | None = None, + strict: bool | None = None, + coerce_numbers_to_str: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> StringSchema: + """ + Returns a schema that matches a string value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.str_schema(max_length=10, min_length=2) + v = SchemaValidator(schema) + assert v.validate_python('hello') == 'hello' + ``` + + Args: + pattern: A regex pattern that the value must match + max_length: The value must be at most this length + min_length: The value must be at least this length + strip_whitespace: Whether to strip whitespace from the value + to_lower: Whether to convert the value to lowercase + to_upper: Whether to convert the value to uppercase + regex_engine: The regex engine to use for pattern validation. Default is 'rust-regex'. + - `rust-regex` uses the [`regex`](https://docs.rs/regex) Rust + crate, which is non-backtracking and therefore more DDoS + resistant, but does not support all regex features. + - `python-re` use the [`re`](https://docs.python.org/3/library/re.html) module, + which supports all regex features, but may be slower. + strict: Whether the value should be a string or a value that can be converted to a string + coerce_numbers_to_str: Whether to enable coercion of any `Number` type to `str` (not applicable in `strict` mode). + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='str', + pattern=pattern, + max_length=max_length, + min_length=min_length, + strip_whitespace=strip_whitespace, + to_lower=to_lower, + to_upper=to_upper, + regex_engine=regex_engine, + strict=strict, + coerce_numbers_to_str=coerce_numbers_to_str, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class BytesSchema(TypedDict, total=False): + type: Required[Literal['bytes']] + max_length: int + min_length: int + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def bytes_schema( + *, + max_length: int | None = None, + min_length: int | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> BytesSchema: + """ + Returns a schema that matches a bytes value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.bytes_schema(max_length=10, min_length=2) + v = SchemaValidator(schema) + assert v.validate_python(b'hello') == b'hello' + ``` + + Args: + max_length: The value must be at most this length + min_length: The value must be at least this length + strict: Whether the value should be a bytes or a value that can be converted to a bytes + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='bytes', + max_length=max_length, + min_length=min_length, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class DateSchema(TypedDict, total=False): + type: Required[Literal['date']] + strict: bool + le: date + ge: date + lt: date + gt: date + now_op: Literal['past', 'future'] + # defaults to current local utc offset from `time.localtime().tm_gmtoff` + # value is restricted to -86_400 < offset < 86_400: + now_utc_offset: int + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def date_schema( + *, + strict: bool | None = None, + le: date | None = None, + ge: date | None = None, + lt: date | None = None, + gt: date | None = None, + now_op: Literal['past', 'future'] | None = None, + now_utc_offset: int | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> DateSchema: + """ + Returns a schema that matches a date value, e.g.: + + ```py + from datetime import date + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.date_schema(le=date(2020, 1, 1), ge=date(2019, 1, 1)) + v = SchemaValidator(schema) + assert v.validate_python(date(2019, 6, 1)) == date(2019, 6, 1) + ``` + + Args: + strict: Whether the value should be a date or a value that can be converted to a date + le: The value must be less than or equal to this date + ge: The value must be greater than or equal to this date + lt: The value must be strictly less than this date + gt: The value must be strictly greater than this date + now_op: The value must be in the past or future relative to the current date + now_utc_offset: The value must be in the past or future relative to the current date with this utc offset + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='date', + strict=strict, + le=le, + ge=ge, + lt=lt, + gt=gt, + now_op=now_op, + now_utc_offset=now_utc_offset, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class TimeSchema(TypedDict, total=False): + type: Required[Literal['time']] + strict: bool + le: time + ge: time + lt: time + gt: time + tz_constraint: Union[Literal['aware', 'naive'], int] + microseconds_precision: Literal['truncate', 'error'] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def time_schema( + *, + strict: bool | None = None, + le: time | None = None, + ge: time | None = None, + lt: time | None = None, + gt: time | None = None, + tz_constraint: Literal['aware', 'naive'] | int | None = None, + microseconds_precision: Literal['truncate', 'error'] = 'truncate', + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> TimeSchema: + """ + Returns a schema that matches a time value, e.g.: + + ```py + from datetime import time + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.time_schema(le=time(12, 0, 0), ge=time(6, 0, 0)) + v = SchemaValidator(schema) + assert v.validate_python(time(9, 0, 0)) == time(9, 0, 0) + ``` + + Args: + strict: Whether the value should be a time or a value that can be converted to a time + le: The value must be less than or equal to this time + ge: The value must be greater than or equal to this time + lt: The value must be strictly less than this time + gt: The value must be strictly greater than this time + tz_constraint: The value must be timezone aware or naive, or an int to indicate required tz offset + microseconds_precision: The behavior when seconds have more than 6 digits or microseconds is too large + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='time', + strict=strict, + le=le, + ge=ge, + lt=lt, + gt=gt, + tz_constraint=tz_constraint, + microseconds_precision=microseconds_precision, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class DatetimeSchema(TypedDict, total=False): + type: Required[Literal['datetime']] + strict: bool + le: datetime + ge: datetime + lt: datetime + gt: datetime + now_op: Literal['past', 'future'] + tz_constraint: Union[Literal['aware', 'naive'], int] + # defaults to current local utc offset from `time.localtime().tm_gmtoff` + # value is restricted to -86_400 < offset < 86_400 by bounds in generate_self_schema.py + now_utc_offset: int + microseconds_precision: Literal['truncate', 'error'] # default: 'truncate' + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def datetime_schema( + *, + strict: bool | None = None, + le: datetime | None = None, + ge: datetime | None = None, + lt: datetime | None = None, + gt: datetime | None = None, + now_op: Literal['past', 'future'] | None = None, + tz_constraint: Literal['aware', 'naive'] | int | None = None, + now_utc_offset: int | None = None, + microseconds_precision: Literal['truncate', 'error'] = 'truncate', + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> DatetimeSchema: + """ + Returns a schema that matches a datetime value, e.g.: + + ```py + from datetime import datetime + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.datetime_schema() + v = SchemaValidator(schema) + now = datetime.now() + assert v.validate_python(str(now)) == now + ``` + + Args: + strict: Whether the value should be a datetime or a value that can be converted to a datetime + le: The value must be less than or equal to this datetime + ge: The value must be greater than or equal to this datetime + lt: The value must be strictly less than this datetime + gt: The value must be strictly greater than this datetime + now_op: The value must be in the past or future relative to the current datetime + tz_constraint: The value must be timezone aware or naive, or an int to indicate required tz offset + TODO: use of a tzinfo where offset changes based on the datetime is not yet supported + now_utc_offset: The value must be in the past or future relative to the current datetime with this utc offset + microseconds_precision: The behavior when seconds have more than 6 digits or microseconds is too large + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='datetime', + strict=strict, + le=le, + ge=ge, + lt=lt, + gt=gt, + now_op=now_op, + tz_constraint=tz_constraint, + now_utc_offset=now_utc_offset, + microseconds_precision=microseconds_precision, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class TimedeltaSchema(TypedDict, total=False): + type: Required[Literal['timedelta']] + strict: bool + le: timedelta + ge: timedelta + lt: timedelta + gt: timedelta + microseconds_precision: Literal['truncate', 'error'] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def timedelta_schema( + *, + strict: bool | None = None, + le: timedelta | None = None, + ge: timedelta | None = None, + lt: timedelta | None = None, + gt: timedelta | None = None, + microseconds_precision: Literal['truncate', 'error'] = 'truncate', + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> TimedeltaSchema: + """ + Returns a schema that matches a timedelta value, e.g.: + + ```py + from datetime import timedelta + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.timedelta_schema(le=timedelta(days=1), ge=timedelta(days=0)) + v = SchemaValidator(schema) + assert v.validate_python(timedelta(hours=12)) == timedelta(hours=12) + ``` + + Args: + strict: Whether the value should be a timedelta or a value that can be converted to a timedelta + le: The value must be less than or equal to this timedelta + ge: The value must be greater than or equal to this timedelta + lt: The value must be strictly less than this timedelta + gt: The value must be strictly greater than this timedelta + microseconds_precision: The behavior when seconds have more than 6 digits or microseconds is too large + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='timedelta', + strict=strict, + le=le, + ge=ge, + lt=lt, + gt=gt, + microseconds_precision=microseconds_precision, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class LiteralSchema(TypedDict, total=False): + type: Required[Literal['literal']] + expected: Required[list[Any]] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def literal_schema( + expected: list[Any], + *, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> LiteralSchema: + """ + Returns a schema that matches a literal value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.literal_schema(['hello', 'world']) + v = SchemaValidator(schema) + assert v.validate_python('hello') == 'hello' + ``` + + Args: + expected: The value must be one of these values + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='literal', expected=expected, ref=ref, metadata=metadata, serialization=serialization) + + +class EnumSchema(TypedDict, total=False): + type: Required[Literal['enum']] + cls: Required[Any] + members: Required[list[Any]] + sub_type: Literal['str', 'int', 'float'] + missing: Callable[[Any], Any] + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def enum_schema( + cls: Any, + members: list[Any], + *, + sub_type: Literal['str', 'int', 'float'] | None = None, + missing: Callable[[Any], Any] | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> EnumSchema: + """ + Returns a schema that matches an enum value, e.g.: + + ```py + from enum import Enum + from pydantic_core import SchemaValidator, core_schema + + class Color(Enum): + RED = 1 + GREEN = 2 + BLUE = 3 + + schema = core_schema.enum_schema(Color, list(Color.__members__.values())) + v = SchemaValidator(schema) + assert v.validate_python(2) is Color.GREEN + ``` + + Args: + cls: The enum class + members: The members of the enum, generally `list(MyEnum.__members__.values())` + sub_type: The type of the enum, either 'str' or 'int' or None for plain enums + missing: A function to use when the value is not found in the enum, from `_missing_` + strict: Whether to use strict mode, defaults to False + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='enum', + cls=cls, + members=members, + sub_type=sub_type, + missing=missing, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class MissingSentinelSchema(TypedDict, total=False): + type: Required[Literal['missing-sentinel']] + metadata: dict[str, Any] + serialization: SerSchema + + +def missing_sentinel_schema( + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> MissingSentinelSchema: + """Returns a schema for the `MISSING` sentinel.""" + + return _dict_not_none( + type='missing-sentinel', + metadata=metadata, + serialization=serialization, + ) + + +# must match input/parse_json.rs::JsonType::try_from +JsonType = Literal['null', 'bool', 'int', 'float', 'str', 'list', 'dict'] + + +class IsInstanceSchema(TypedDict, total=False): + type: Required[Literal['is-instance']] + cls: Required[Any] + cls_repr: str + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def is_instance_schema( + cls: Any, + *, + cls_repr: str | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> IsInstanceSchema: + """ + Returns a schema that checks if a value is an instance of a class, equivalent to python's `isinstance` method, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + class A: + pass + + schema = core_schema.is_instance_schema(cls=A) + v = SchemaValidator(schema) + v.validate_python(A()) + ``` + + Args: + cls: The value must be an instance of this class + cls_repr: If provided this string is used in the validator name instead of `repr(cls)` + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='is-instance', cls=cls, cls_repr=cls_repr, ref=ref, metadata=metadata, serialization=serialization + ) + + +class IsSubclassSchema(TypedDict, total=False): + type: Required[Literal['is-subclass']] + cls: Required[type[Any]] + cls_repr: str + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def is_subclass_schema( + cls: type[Any], + *, + cls_repr: str | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> IsInstanceSchema: + """ + Returns a schema that checks if a value is a subtype of a class, equivalent to python's `issubclass` method, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + class A: + pass + + class B(A): + pass + + schema = core_schema.is_subclass_schema(cls=A) + v = SchemaValidator(schema) + v.validate_python(B) + ``` + + Args: + cls: The value must be a subclass of this class + cls_repr: If provided this string is used in the validator name instead of `repr(cls)` + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='is-subclass', cls=cls, cls_repr=cls_repr, ref=ref, metadata=metadata, serialization=serialization + ) + + +class CallableSchema(TypedDict, total=False): + type: Required[Literal['callable']] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def callable_schema( + *, ref: str | None = None, metadata: dict[str, Any] | None = None, serialization: SerSchema | None = None +) -> CallableSchema: + """ + Returns a schema that checks if a value is callable, equivalent to python's `callable` method, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.callable_schema() + v = SchemaValidator(schema) + v.validate_python(min) + ``` + + Args: + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='callable', ref=ref, metadata=metadata, serialization=serialization) + + +class UuidSchema(TypedDict, total=False): + type: Required[Literal['uuid']] + version: Literal[1, 3, 4, 5, 7] + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def uuid_schema( + *, + version: Literal[1, 3, 4, 5, 6, 7, 8] | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> UuidSchema: + return _dict_not_none( + type='uuid', version=version, strict=strict, ref=ref, metadata=metadata, serialization=serialization + ) + + +class IncExSeqSerSchema(TypedDict, total=False): + type: Required[Literal['include-exclude-sequence']] + include: set[int] + exclude: set[int] + + +def filter_seq_schema(*, include: set[int] | None = None, exclude: set[int] | None = None) -> IncExSeqSerSchema: + return _dict_not_none(type='include-exclude-sequence', include=include, exclude=exclude) + + +IncExSeqOrElseSerSchema = Union[IncExSeqSerSchema, SerSchema] + + +class ListSchema(TypedDict, total=False): + type: Required[Literal['list']] + items_schema: CoreSchema + min_length: int + max_length: int + fail_fast: bool + strict: bool + ref: str + metadata: dict[str, Any] + serialization: IncExSeqOrElseSerSchema + + +def list_schema( + items_schema: CoreSchema | None = None, + *, + min_length: int | None = None, + max_length: int | None = None, + fail_fast: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: IncExSeqOrElseSerSchema | None = None, +) -> ListSchema: + """ + Returns a schema that matches a list value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.list_schema(core_schema.int_schema(), min_length=0, max_length=10) + v = SchemaValidator(schema) + assert v.validate_python(['4']) == [4] + ``` + + Args: + items_schema: The value must be a list of items that match this schema + min_length: The value must be a list with at least this many items + max_length: The value must be a list with at most this many items + fail_fast: Stop validation on the first error + strict: The value must be a list with exactly this many items + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='list', + items_schema=items_schema, + min_length=min_length, + max_length=max_length, + fail_fast=fail_fast, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +# @deprecated('tuple_positional_schema is deprecated. Use pydantic_core.core_schema.tuple_schema instead.') +def tuple_positional_schema( + items_schema: list[CoreSchema], + *, + extras_schema: CoreSchema | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: IncExSeqOrElseSerSchema | None = None, +) -> TupleSchema: + """ + Returns a schema that matches a tuple of schemas, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.tuple_positional_schema( + [core_schema.int_schema(), core_schema.str_schema()] + ) + v = SchemaValidator(schema) + assert v.validate_python((1, 'hello')) == (1, 'hello') + ``` + + Args: + items_schema: The value must be a tuple with items that match these schemas + extras_schema: The value must be a tuple with items that match this schema + This was inspired by JSON schema's `prefixItems` and `items` fields. + In python's `typing.Tuple`, you can't specify a type for "extra" items -- they must all be the same type + if the length is variable. So this field won't be set from a `typing.Tuple` annotation on a pydantic model. + strict: The value must be a tuple with exactly this many items + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + if extras_schema is not None: + variadic_item_index = len(items_schema) + items_schema = items_schema + [extras_schema] + else: + variadic_item_index = None + return tuple_schema( + items_schema=items_schema, + variadic_item_index=variadic_item_index, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +# @deprecated('tuple_variable_schema is deprecated. Use pydantic_core.core_schema.tuple_schema instead.') +def tuple_variable_schema( + items_schema: CoreSchema | None = None, + *, + min_length: int | None = None, + max_length: int | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: IncExSeqOrElseSerSchema | None = None, +) -> TupleSchema: + """ + Returns a schema that matches a tuple of a given schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.tuple_variable_schema( + items_schema=core_schema.int_schema(), min_length=0, max_length=10 + ) + v = SchemaValidator(schema) + assert v.validate_python(('1', 2, 3)) == (1, 2, 3) + ``` + + Args: + items_schema: The value must be a tuple with items that match this schema + min_length: The value must be a tuple with at least this many items + max_length: The value must be a tuple with at most this many items + strict: The value must be a tuple with exactly this many items + ref: Optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return tuple_schema( + items_schema=[items_schema or any_schema()], + variadic_item_index=0, + min_length=min_length, + max_length=max_length, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class TupleSchema(TypedDict, total=False): + type: Required[Literal['tuple']] + items_schema: Required[list[CoreSchema]] + variadic_item_index: int + min_length: int + max_length: int + fail_fast: bool + strict: bool + ref: str + metadata: dict[str, Any] + serialization: IncExSeqOrElseSerSchema + + +def tuple_schema( + items_schema: list[CoreSchema], + *, + variadic_item_index: int | None = None, + min_length: int | None = None, + max_length: int | None = None, + fail_fast: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: IncExSeqOrElseSerSchema | None = None, +) -> TupleSchema: + """ + Returns a schema that matches a tuple of schemas, with an optional variadic item, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.tuple_schema( + [core_schema.int_schema(), core_schema.str_schema(), core_schema.float_schema()], + variadic_item_index=1, + ) + v = SchemaValidator(schema) + assert v.validate_python((1, 'hello', 'world', 1.5)) == (1, 'hello', 'world', 1.5) + ``` + + Args: + items_schema: The value must be a tuple with items that match these schemas + variadic_item_index: The index of the schema in `items_schema` to be treated as variadic (following PEP 646) + min_length: The value must be a tuple with at least this many items + max_length: The value must be a tuple with at most this many items + fail_fast: Stop validation on the first error + strict: The value must be a tuple with exactly this many items + ref: Optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='tuple', + items_schema=items_schema, + variadic_item_index=variadic_item_index, + min_length=min_length, + max_length=max_length, + fail_fast=fail_fast, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class SetSchema(TypedDict, total=False): + type: Required[Literal['set']] + items_schema: CoreSchema + min_length: int + max_length: int + fail_fast: bool + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def set_schema( + items_schema: CoreSchema | None = None, + *, + min_length: int | None = None, + max_length: int | None = None, + fail_fast: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> SetSchema: + """ + Returns a schema that matches a set of a given schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.set_schema( + items_schema=core_schema.int_schema(), min_length=0, max_length=10 + ) + v = SchemaValidator(schema) + assert v.validate_python({1, '2', 3}) == {1, 2, 3} + ``` + + Args: + items_schema: The value must be a set with items that match this schema + min_length: The value must be a set with at least this many items + max_length: The value must be a set with at most this many items + fail_fast: Stop validation on the first error + strict: The value must be a set with exactly this many items + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='set', + items_schema=items_schema, + min_length=min_length, + max_length=max_length, + fail_fast=fail_fast, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class FrozenSetSchema(TypedDict, total=False): + type: Required[Literal['frozenset']] + items_schema: CoreSchema + min_length: int + max_length: int + fail_fast: bool + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def frozenset_schema( + items_schema: CoreSchema | None = None, + *, + min_length: int | None = None, + max_length: int | None = None, + fail_fast: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> FrozenSetSchema: + """ + Returns a schema that matches a frozenset of a given schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.frozenset_schema( + items_schema=core_schema.int_schema(), min_length=0, max_length=10 + ) + v = SchemaValidator(schema) + assert v.validate_python(frozenset(range(3))) == frozenset({0, 1, 2}) + ``` + + Args: + items_schema: The value must be a frozenset with items that match this schema + min_length: The value must be a frozenset with at least this many items + max_length: The value must be a frozenset with at most this many items + fail_fast: Stop validation on the first error + strict: The value must be a frozenset with exactly this many items + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='frozenset', + items_schema=items_schema, + min_length=min_length, + max_length=max_length, + fail_fast=fail_fast, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class GeneratorSchema(TypedDict, total=False): + type: Required[Literal['generator']] + items_schema: CoreSchema + min_length: int + max_length: int + ref: str + metadata: dict[str, Any] + serialization: IncExSeqOrElseSerSchema + + +def generator_schema( + items_schema: CoreSchema | None = None, + *, + min_length: int | None = None, + max_length: int | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: IncExSeqOrElseSerSchema | None = None, +) -> GeneratorSchema: + """ + Returns a schema that matches a generator value, e.g.: + + ```py + from typing import Iterator + from pydantic_core import SchemaValidator, core_schema + + def gen() -> Iterator[int]: + yield 1 + + schema = core_schema.generator_schema(items_schema=core_schema.int_schema()) + v = SchemaValidator(schema) + v.validate_python(gen()) + ``` + + Unlike other types, validated generators do not raise ValidationErrors eagerly, + but instead will raise a ValidationError when a violating value is actually read from the generator. + This is to ensure that "validated" generators retain the benefit of lazy evaluation. + + Args: + items_schema: The value must be a generator with items that match this schema + min_length: The value must be a generator that yields at least this many items + max_length: The value must be a generator that yields at most this many items + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='generator', + items_schema=items_schema, + min_length=min_length, + max_length=max_length, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +IncExDict = set[Union[int, str]] + + +class IncExDictSerSchema(TypedDict, total=False): + type: Required[Literal['include-exclude-dict']] + include: IncExDict + exclude: IncExDict + + +def filter_dict_schema(*, include: IncExDict | None = None, exclude: IncExDict | None = None) -> IncExDictSerSchema: + return _dict_not_none(type='include-exclude-dict', include=include, exclude=exclude) + + +IncExDictOrElseSerSchema = Union[IncExDictSerSchema, SerSchema] + + +class DictSchema(TypedDict, total=False): + type: Required[Literal['dict']] + keys_schema: CoreSchema # default: AnySchema + values_schema: CoreSchema # default: AnySchema + min_length: int + max_length: int + fail_fast: bool + strict: bool + ref: str + metadata: dict[str, Any] + serialization: IncExDictOrElseSerSchema + + +def dict_schema( + keys_schema: CoreSchema | None = None, + values_schema: CoreSchema | None = None, + *, + min_length: int | None = None, + max_length: int | None = None, + fail_fast: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> DictSchema: + """ + Returns a schema that matches a dict value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.dict_schema( + keys_schema=core_schema.str_schema(), values_schema=core_schema.int_schema() + ) + v = SchemaValidator(schema) + assert v.validate_python({'a': '1', 'b': 2}) == {'a': 1, 'b': 2} + ``` + + Args: + keys_schema: The value must be a dict with keys that match this schema + values_schema: The value must be a dict with values that match this schema + min_length: The value must be a dict with at least this many items + max_length: The value must be a dict with at most this many items + fail_fast: Stop validation on the first error + strict: Whether the keys and values should be validated with strict mode + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='dict', + keys_schema=keys_schema, + values_schema=values_schema, + min_length=min_length, + max_length=max_length, + fail_fast=fail_fast, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +# (input_value: Any, /) -> Any +NoInfoValidatorFunction = Callable[[Any], Any] + + +class NoInfoValidatorFunctionSchema(TypedDict): + type: Literal['no-info'] + function: NoInfoValidatorFunction + + +# (input_value: Any, info: ValidationInfo, /) -> Any +WithInfoValidatorFunction = Callable[[Any, ValidationInfo[Any]], Any] + + +class WithInfoValidatorFunctionSchema(TypedDict, total=False): + type: Required[Literal['with-info']] + function: Required[WithInfoValidatorFunction] + field_name: str # deprecated + + +ValidationFunction = Union[NoInfoValidatorFunctionSchema, WithInfoValidatorFunctionSchema] + + +class _ValidatorFunctionSchema(TypedDict, total=False): + function: Required[ValidationFunction] + schema: Required[CoreSchema] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +class BeforeValidatorFunctionSchema(_ValidatorFunctionSchema, total=False): + type: Required[Literal['function-before']] + json_schema_input_schema: CoreSchema + + +def no_info_before_validator_function( + function: NoInfoValidatorFunction, + schema: CoreSchema, + *, + ref: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> BeforeValidatorFunctionSchema: + """ + Returns a schema that calls a validator function before validating, no `info` argument is provided, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: bytes) -> str: + return v.decode() + 'world' + + func_schema = core_schema.no_info_before_validator_function( + function=fn, schema=core_schema.str_schema() + ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) + + v = SchemaValidator(schema) + assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} + ``` + + Args: + function: The validator function to call + schema: The schema to validate the output of the validator function + ref: optional unique identifier of the schema, used to reference the schema in other places + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='function-before', + function={'type': 'no-info', 'function': function}, + schema=schema, + ref=ref, + json_schema_input_schema=json_schema_input_schema, + metadata=metadata, + serialization=serialization, + ) + + +def with_info_before_validator_function( + function: WithInfoValidatorFunction, + schema: CoreSchema, + *, + field_name: str | None = None, + ref: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> BeforeValidatorFunctionSchema: + """ + Returns a schema that calls a validator function before validation, the function is called with + an `info` argument, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: bytes, info: core_schema.ValidationInfo) -> str: + assert info.data is not None + assert info.field_name is not None + return v.decode() + 'world' + + func_schema = core_schema.with_info_before_validator_function( + function=fn, schema=core_schema.str_schema() + ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) + + v = SchemaValidator(schema) + assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} + ``` + + Args: + function: The validator function to call + field_name: The name of the field this validator is applied to, if any (deprecated) + schema: The schema to validate the output of the validator function + ref: optional unique identifier of the schema, used to reference the schema in other places + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + if field_name is not None: + warnings.warn( + 'The `field_name` argument on `with_info_before_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', + DeprecationWarning, + stacklevel=2, + ) + + return _dict_not_none( + type='function-before', + function=_dict_not_none(type='with-info', function=function, field_name=field_name), + schema=schema, + ref=ref, + json_schema_input_schema=json_schema_input_schema, + metadata=metadata, + serialization=serialization, + ) + + +class AfterValidatorFunctionSchema(_ValidatorFunctionSchema, total=False): + type: Required[Literal['function-after']] + + +def no_info_after_validator_function( + function: NoInfoValidatorFunction, + schema: CoreSchema, + *, + ref: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> AfterValidatorFunctionSchema: + """ + Returns a schema that calls a validator function after validating, no `info` argument is provided, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: str) -> str: + return v + 'world' + + func_schema = core_schema.no_info_after_validator_function(fn, core_schema.str_schema()) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) + + v = SchemaValidator(schema) + assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} + ``` + + Args: + function: The validator function to call after the schema is validated + schema: The schema to validate before the validator function + ref: optional unique identifier of the schema, used to reference the schema in other places + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='function-after', + function={'type': 'no-info', 'function': function}, + schema=schema, + ref=ref, + json_schema_input_schema=json_schema_input_schema, + metadata=metadata, + serialization=serialization, + ) + + +def with_info_after_validator_function( + function: WithInfoValidatorFunction, + schema: CoreSchema, + *, + field_name: str | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> AfterValidatorFunctionSchema: + """ + Returns a schema that calls a validator function after validation, the function is called with + an `info` argument, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: str, info: core_schema.ValidationInfo) -> str: + assert info.data is not None + assert info.field_name is not None + return v + 'world' + + func_schema = core_schema.with_info_after_validator_function( + function=fn, schema=core_schema.str_schema() + ) + schema = core_schema.typed_dict_schema({'a': core_schema.typed_dict_field(func_schema)}) + + v = SchemaValidator(schema) + assert v.validate_python({'a': b'hello '}) == {'a': 'hello world'} + ``` + + Args: + function: The validator function to call after the schema is validated + schema: The schema to validate before the validator function + field_name: The name of the field this validator is applied to, if any (deprecated) + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + if field_name is not None: + warnings.warn( + 'The `field_name` argument on `with_info_after_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', + DeprecationWarning, + stacklevel=2, + ) + + return _dict_not_none( + type='function-after', + function=_dict_not_none(type='with-info', function=function, field_name=field_name), + schema=schema, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class ValidatorFunctionWrapHandler(Protocol): + def __call__(self, input_value: Any, outer_location: str | int | None = None, /) -> Any: # pragma: no cover + ... + + +# (input_value: Any, validator: ValidatorFunctionWrapHandler, /) -> Any +NoInfoWrapValidatorFunction = Callable[[Any, ValidatorFunctionWrapHandler], Any] + + +class NoInfoWrapValidatorFunctionSchema(TypedDict): + type: Literal['no-info'] + function: NoInfoWrapValidatorFunction + + +# (input_value: Any, validator: ValidatorFunctionWrapHandler, info: ValidationInfo, /) -> Any +WithInfoWrapValidatorFunction = Callable[[Any, ValidatorFunctionWrapHandler, ValidationInfo[Any]], Any] + + +class WithInfoWrapValidatorFunctionSchema(TypedDict, total=False): + type: Required[Literal['with-info']] + function: Required[WithInfoWrapValidatorFunction] + field_name: str # deprecated + + +WrapValidatorFunction = Union[NoInfoWrapValidatorFunctionSchema, WithInfoWrapValidatorFunctionSchema] + + +class WrapValidatorFunctionSchema(TypedDict, total=False): + type: Required[Literal['function-wrap']] + function: Required[WrapValidatorFunction] + schema: Required[CoreSchema] + ref: str + json_schema_input_schema: CoreSchema + metadata: dict[str, Any] + serialization: SerSchema + + +def no_info_wrap_validator_function( + function: NoInfoWrapValidatorFunction, + schema: CoreSchema, + *, + ref: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> WrapValidatorFunctionSchema: + """ + Returns a schema which calls a function with a `validator` callable argument which can + optionally be used to call inner validation with the function logic, this is much like the + "onion" implementation of middleware in many popular web frameworks, no `info` argument is passed, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn( + v: str, + validator: core_schema.ValidatorFunctionWrapHandler, + ) -> str: + return validator(input_value=v) + 'world' + + schema = core_schema.no_info_wrap_validator_function( + function=fn, schema=core_schema.str_schema() + ) + v = SchemaValidator(schema) + assert v.validate_python('hello ') == 'hello world' + ``` + + Args: + function: The validator function to call + schema: The schema to validate the output of the validator function + ref: optional unique identifier of the schema, used to reference the schema in other places + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='function-wrap', + function={'type': 'no-info', 'function': function}, + schema=schema, + json_schema_input_schema=json_schema_input_schema, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +def with_info_wrap_validator_function( + function: WithInfoWrapValidatorFunction, + schema: CoreSchema, + *, + field_name: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> WrapValidatorFunctionSchema: + """ + Returns a schema which calls a function with a `validator` callable argument which can + optionally be used to call inner validation with the function logic, this is much like the + "onion" implementation of middleware in many popular web frameworks, an `info` argument is also passed, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn( + v: str, + validator: core_schema.ValidatorFunctionWrapHandler, + info: core_schema.ValidationInfo, + ) -> str: + return validator(input_value=v) + 'world' + + schema = core_schema.with_info_wrap_validator_function( + function=fn, schema=core_schema.str_schema() + ) + v = SchemaValidator(schema) + assert v.validate_python('hello ') == 'hello world' + ``` + + Args: + function: The validator function to call + schema: The schema to validate the output of the validator function + field_name: The name of the field this validator is applied to, if any (deprecated) + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + if field_name is not None: + warnings.warn( + 'The `field_name` argument on `with_info_wrap_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', + DeprecationWarning, + stacklevel=2, + ) + + return _dict_not_none( + type='function-wrap', + function=_dict_not_none(type='with-info', function=function, field_name=field_name), + schema=schema, + json_schema_input_schema=json_schema_input_schema, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class PlainValidatorFunctionSchema(TypedDict, total=False): + type: Required[Literal['function-plain']] + function: Required[ValidationFunction] + ref: str + json_schema_input_schema: CoreSchema + metadata: dict[str, Any] + serialization: SerSchema + + +def no_info_plain_validator_function( + function: NoInfoValidatorFunction, + *, + ref: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> PlainValidatorFunctionSchema: + """ + Returns a schema that uses the provided function for validation, no `info` argument is passed, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: str) -> str: + assert 'hello' in v + return v + 'world' + + schema = core_schema.no_info_plain_validator_function(function=fn) + v = SchemaValidator(schema) + assert v.validate_python('hello ') == 'hello world' + ``` + + Args: + function: The validator function to call + ref: optional unique identifier of the schema, used to reference the schema in other places + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='function-plain', + function={'type': 'no-info', 'function': function}, + ref=ref, + json_schema_input_schema=json_schema_input_schema, + metadata=metadata, + serialization=serialization, + ) + + +def with_info_plain_validator_function( + function: WithInfoValidatorFunction, + *, + field_name: str | None = None, + ref: str | None = None, + json_schema_input_schema: CoreSchema | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> PlainValidatorFunctionSchema: + """ + Returns a schema that uses the provided function for validation, an `info` argument is passed, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: str, info: core_schema.ValidationInfo) -> str: + assert 'hello' in v + return v + 'world' + + schema = core_schema.with_info_plain_validator_function(function=fn) + v = SchemaValidator(schema) + assert v.validate_python('hello ') == 'hello world' + ``` + + Args: + function: The validator function to call + field_name: The name of the field this validator is applied to, if any (deprecated) + ref: optional unique identifier of the schema, used to reference the schema in other places + json_schema_input_schema: The core schema to be used to generate the corresponding JSON Schema input type + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + if field_name is not None: + warnings.warn( + 'The `field_name` argument on `with_info_plain_validator_function` is deprecated, it will be passed to the function through `ValidationState` instead.', + DeprecationWarning, + stacklevel=2, + ) + + return _dict_not_none( + type='function-plain', + function=_dict_not_none(type='with-info', function=function, field_name=field_name), + ref=ref, + json_schema_input_schema=json_schema_input_schema, + metadata=metadata, + serialization=serialization, + ) + + +class WithDefaultSchema(TypedDict, total=False): + type: Required[Literal['default']] + schema: Required[CoreSchema] + default: Any + default_factory: Union[Callable[[], Any], Callable[[dict[str, Any]], Any]] + default_factory_takes_data: bool + on_error: Literal['raise', 'omit', 'default'] # default: 'raise' + validate_default: bool # default: False + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def with_default_schema( + schema: CoreSchema, + *, + default: Any = PydanticUndefined, + default_factory: Union[Callable[[], Any], Callable[[dict[str, Any]], Any], None] = None, + default_factory_takes_data: bool | None = None, + on_error: Literal['raise', 'omit', 'default'] | None = None, + validate_default: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> WithDefaultSchema: + """ + Returns a schema that adds a default value to the given schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.with_default_schema(core_schema.str_schema(), default='hello') + wrapper_schema = core_schema.typed_dict_schema( + {'a': core_schema.typed_dict_field(schema)} + ) + v = SchemaValidator(wrapper_schema) + assert v.validate_python({}) == v.validate_python({'a': 'hello'}) + ``` + + Args: + schema: The schema to add a default value to + default: The default value to use + default_factory: A callable that returns the default value to use + default_factory_takes_data: Whether the default factory takes a validated data argument + on_error: What to do if the schema validation fails. One of 'raise', 'omit', 'default' + validate_default: Whether the default value should be validated + strict: Whether the underlying schema should be validated with strict mode + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + s = _dict_not_none( + type='default', + schema=schema, + default_factory=default_factory, + default_factory_takes_data=default_factory_takes_data, + on_error=on_error, + validate_default=validate_default, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + if default is not PydanticUndefined: + s['default'] = default + return s + + +class NullableSchema(TypedDict, total=False): + type: Required[Literal['nullable']] + schema: Required[CoreSchema] + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def nullable_schema( + schema: CoreSchema, + *, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> NullableSchema: + """ + Returns a schema that matches a nullable value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.nullable_schema(core_schema.str_schema()) + v = SchemaValidator(schema) + assert v.validate_python(None) is None + ``` + + Args: + schema: The schema to wrap + strict: Whether the underlying schema should be validated with strict mode + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='nullable', schema=schema, strict=strict, ref=ref, metadata=metadata, serialization=serialization + ) + + +class UnionSchema(TypedDict, total=False): + type: Required[Literal['union']] + choices: Required[list[Union[CoreSchema, tuple[CoreSchema, str]]]] + # default true, whether to automatically collapse unions with one element to the inner validator + auto_collapse: bool + custom_error_type: str + custom_error_message: str + custom_error_context: dict[str, Union[str, int, float]] + mode: Literal['smart', 'left_to_right'] # default: 'smart' + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def union_schema( + choices: list[CoreSchema | tuple[CoreSchema, str]], + *, + auto_collapse: bool | None = None, + custom_error_type: str | None = None, + custom_error_message: str | None = None, + custom_error_context: dict[str, str | int] | None = None, + mode: Literal['smart', 'left_to_right'] | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> UnionSchema: + """ + Returns a schema that matches a union value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.union_schema([core_schema.str_schema(), core_schema.int_schema()]) + v = SchemaValidator(schema) + assert v.validate_python('hello') == 'hello' + assert v.validate_python(1) == 1 + ``` + + Args: + choices: The schemas to match. If a tuple, the second item is used as the label for the case. + auto_collapse: whether to automatically collapse unions with one element to the inner validator, default true + custom_error_type: The custom error type to use if the validation fails + custom_error_message: The custom error message to use if the validation fails + custom_error_context: The custom error context to use if the validation fails + mode: How to select which choice to return + * `smart` (default) will try to return the choice which is the closest match to the input value + * `left_to_right` will return the first choice in `choices` which succeeds validation + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='union', + choices=choices, + auto_collapse=auto_collapse, + custom_error_type=custom_error_type, + custom_error_message=custom_error_message, + custom_error_context=custom_error_context, + mode=mode, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class TaggedUnionSchema(TypedDict, total=False): + type: Required[Literal['tagged-union']] + choices: Required[dict[Hashable, CoreSchema]] + discriminator: Required[Union[str, list[Union[str, int]], list[list[Union[str, int]]], Callable[[Any], Hashable]]] + custom_error_type: str + custom_error_message: str + custom_error_context: dict[str, Union[str, int, float]] + strict: bool + from_attributes: bool # default: True + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def tagged_union_schema( + choices: dict[Any, CoreSchema], + discriminator: str | list[str | int] | list[list[str | int]] | Callable[[Any], Any], + *, + custom_error_type: str | None = None, + custom_error_message: str | None = None, + custom_error_context: dict[str, int | str | float] | None = None, + strict: bool | None = None, + from_attributes: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> TaggedUnionSchema: + """ + Returns a schema that matches a tagged union value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + apple_schema = core_schema.typed_dict_schema( + { + 'foo': core_schema.typed_dict_field(core_schema.str_schema()), + 'bar': core_schema.typed_dict_field(core_schema.int_schema()), + } + ) + banana_schema = core_schema.typed_dict_schema( + { + 'foo': core_schema.typed_dict_field(core_schema.str_schema()), + 'spam': core_schema.typed_dict_field( + core_schema.list_schema(items_schema=core_schema.int_schema()) + ), + } + ) + schema = core_schema.tagged_union_schema( + choices={ + 'apple': apple_schema, + 'banana': banana_schema, + }, + discriminator='foo', + ) + v = SchemaValidator(schema) + assert v.validate_python({'foo': 'apple', 'bar': '123'}) == {'foo': 'apple', 'bar': 123} + assert v.validate_python({'foo': 'banana', 'spam': [1, 2, 3]}) == { + 'foo': 'banana', + 'spam': [1, 2, 3], + } + ``` + + Args: + choices: The schemas to match + When retrieving a schema from `choices` using the discriminator value, if the value is a str, + it should be fed back into the `choices` map until a schema is obtained + (This approach is to prevent multiple ownership of a single schema in Rust) + discriminator: The discriminator to use to determine the schema to use + * If `discriminator` is a str, it is the name of the attribute to use as the discriminator + * If `discriminator` is a list of int/str, it should be used as a "path" to access the discriminator + * If `discriminator` is a list of lists, each inner list is a path, and the first path that exists is used + * If `discriminator` is a callable, it should return the discriminator when called on the value to validate; + the callable can return `None` to indicate that there is no matching discriminator present on the input + custom_error_type: The custom error type to use if the validation fails + custom_error_message: The custom error message to use if the validation fails + custom_error_context: The custom error context to use if the validation fails + strict: Whether the underlying schemas should be validated with strict mode + from_attributes: Whether to use the attributes of the object to retrieve the discriminator value + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='tagged-union', + choices=choices, + discriminator=discriminator, + custom_error_type=custom_error_type, + custom_error_message=custom_error_message, + custom_error_context=custom_error_context, + strict=strict, + from_attributes=from_attributes, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class ChainSchema(TypedDict, total=False): + type: Required[Literal['chain']] + steps: Required[list[CoreSchema]] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def chain_schema( + steps: list[CoreSchema], + *, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> ChainSchema: + """ + Returns a schema that chains the provided validation schemas, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: str, info: core_schema.ValidationInfo) -> str: + assert 'hello' in v + return v + ' world' + + fn_schema = core_schema.with_info_plain_validator_function(function=fn) + schema = core_schema.chain_schema( + [fn_schema, fn_schema, fn_schema, core_schema.str_schema()] + ) + v = SchemaValidator(schema) + assert v.validate_python('hello') == 'hello world world world' + ``` + + Args: + steps: The schemas to chain + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='chain', steps=steps, ref=ref, metadata=metadata, serialization=serialization) + + +class LaxOrStrictSchema(TypedDict, total=False): + type: Required[Literal['lax-or-strict']] + lax_schema: Required[CoreSchema] + strict_schema: Required[CoreSchema] + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def lax_or_strict_schema( + lax_schema: CoreSchema, + strict_schema: CoreSchema, + *, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> LaxOrStrictSchema: + """ + Returns a schema that uses the lax or strict schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + def fn(v: str, info: core_schema.ValidationInfo) -> str: + assert 'hello' in v + return v + ' world' + + lax_schema = core_schema.int_schema(strict=False) + strict_schema = core_schema.int_schema(strict=True) + + schema = core_schema.lax_or_strict_schema( + lax_schema=lax_schema, strict_schema=strict_schema, strict=True + ) + v = SchemaValidator(schema) + assert v.validate_python(123) == 123 + + schema = core_schema.lax_or_strict_schema( + lax_schema=lax_schema, strict_schema=strict_schema, strict=False + ) + v = SchemaValidator(schema) + assert v.validate_python('123') == 123 + ``` + + Args: + lax_schema: The lax schema to use + strict_schema: The strict schema to use + strict: Whether the strict schema should be used + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='lax-or-strict', + lax_schema=lax_schema, + strict_schema=strict_schema, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class JsonOrPythonSchema(TypedDict, total=False): + type: Required[Literal['json-or-python']] + json_schema: Required[CoreSchema] + python_schema: Required[CoreSchema] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def json_or_python_schema( + json_schema: CoreSchema, + python_schema: CoreSchema, + *, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> JsonOrPythonSchema: + """ + Returns a schema that uses the Json or Python schema depending on the input: + + ```py + from pydantic_core import SchemaValidator, ValidationError, core_schema + + v = SchemaValidator( + core_schema.json_or_python_schema( + json_schema=core_schema.int_schema(), + python_schema=core_schema.int_schema(strict=True), + ) + ) + + assert v.validate_json('"123"') == 123 + + try: + v.validate_python('123') + except ValidationError: + pass + else: + raise AssertionError('Validation should have failed') + ``` + + Args: + json_schema: The schema to use for Json inputs + python_schema: The schema to use for Python inputs + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='json-or-python', + json_schema=json_schema, + python_schema=python_schema, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class TypedDictField(TypedDict, total=False): + type: Required[Literal['typed-dict-field']] + schema: Required[CoreSchema] + required: bool + validation_alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] + serialization_alias: str + serialization_exclude: bool # default: False + metadata: dict[str, Any] + serialization_exclude_if: Callable[[Any], bool] # default None + + +def typed_dict_field( + schema: CoreSchema, + *, + required: bool | None = None, + validation_alias: str | list[str | int] | list[list[str | int]] | None = None, + serialization_alias: str | None = None, + serialization_exclude: bool | None = None, + metadata: dict[str, Any] | None = None, + serialization_exclude_if: Callable[[Any], bool] | None = None, +) -> TypedDictField: + """ + Returns a schema that matches a typed dict field, e.g.: + + ```py + from pydantic_core import core_schema + + field = core_schema.typed_dict_field(schema=core_schema.int_schema(), required=True) + ``` + + Args: + schema: The schema to use for the field + required: Whether the field is required, otherwise uses the value from `total` on the typed dict + validation_alias: The alias(es) to use to find the field in the validation data + serialization_alias: The alias to use as a key when serializing + serialization_exclude: Whether to exclude the field when serializing + serialization_exclude_if: A callable that determines whether to exclude the field when serializing based on its value. + metadata: Any other information you want to include with the schema, not used by pydantic-core + """ + return _dict_not_none( + type='typed-dict-field', + schema=schema, + required=required, + validation_alias=validation_alias, + serialization_alias=serialization_alias, + serialization_exclude=serialization_exclude, + serialization_exclude_if=serialization_exclude_if, + metadata=metadata, + ) + + +class TypedDictSchema(TypedDict, total=False): + type: Required[Literal['typed-dict']] + fields: Required[dict[str, TypedDictField]] + cls: type[Any] + cls_name: str + computed_fields: list[ComputedField] + strict: bool + extras_schema: CoreSchema + # all these values can be set via config, equivalent fields have `typed_dict_` prefix + extra_behavior: ExtraBehavior + total: bool # default: True + ref: str + metadata: dict[str, Any] + serialization: SerSchema + config: CoreConfig + + +def typed_dict_schema( + fields: dict[str, TypedDictField], + *, + cls: type[Any] | None = None, + cls_name: str | None = None, + computed_fields: list[ComputedField] | None = None, + strict: bool | None = None, + extras_schema: CoreSchema | None = None, + extra_behavior: ExtraBehavior | None = None, + total: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, + config: CoreConfig | None = None, +) -> TypedDictSchema: + """ + Returns a schema that matches a typed dict, e.g.: + + ```py + from typing_extensions import TypedDict + + from pydantic_core import SchemaValidator, core_schema + + class MyTypedDict(TypedDict): + a: str + + wrapper_schema = core_schema.typed_dict_schema( + {'a': core_schema.typed_dict_field(core_schema.str_schema())}, cls=MyTypedDict + ) + v = SchemaValidator(wrapper_schema) + assert v.validate_python({'a': 'hello'}) == {'a': 'hello'} + ``` + + Args: + fields: The fields to use for the typed dict + cls: The class to use for the typed dict + cls_name: The name to use in error locations. Falls back to `cls.__name__`, or the validator name if no class + is provided. + computed_fields: Computed fields to use when serializing the model, only applies when directly inside a model + strict: Whether the typed dict is strict + extras_schema: The extra validator to use for the typed dict + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + extra_behavior: The extra behavior to use for the typed dict + total: Whether the typed dict is total, otherwise uses `typed_dict_total` from config + serialization: Custom serialization schema + """ + return _dict_not_none( + type='typed-dict', + fields=fields, + cls=cls, + cls_name=cls_name, + computed_fields=computed_fields, + strict=strict, + extras_schema=extras_schema, + extra_behavior=extra_behavior, + total=total, + ref=ref, + metadata=metadata, + serialization=serialization, + config=config, + ) + + +class ModelField(TypedDict, total=False): + type: Required[Literal['model-field']] + schema: Required[CoreSchema] + validation_alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] + serialization_alias: str + serialization_exclude: bool # default: False + serialization_exclude_if: Callable[[Any], bool] # default: None + frozen: bool + metadata: dict[str, Any] + + +def model_field( + schema: CoreSchema, + *, + validation_alias: str | list[str | int] | list[list[str | int]] | None = None, + serialization_alias: str | None = None, + serialization_exclude: bool | None = None, + serialization_exclude_if: Callable[[Any], bool] | None = None, + frozen: bool | None = None, + metadata: dict[str, Any] | None = None, +) -> ModelField: + """ + Returns a schema for a model field, e.g.: + + ```py + from pydantic_core import core_schema + + field = core_schema.model_field(schema=core_schema.int_schema()) + ``` + + Args: + schema: The schema to use for the field + validation_alias: The alias(es) to use to find the field in the validation data + serialization_alias: The alias to use as a key when serializing + serialization_exclude: Whether to exclude the field when serializing + serialization_exclude_if: A Callable that determines whether to exclude a field during serialization based on its value. + frozen: Whether the field is frozen + metadata: Any other information you want to include with the schema, not used by pydantic-core + """ + return _dict_not_none( + type='model-field', + schema=schema, + validation_alias=validation_alias, + serialization_alias=serialization_alias, + serialization_exclude=serialization_exclude, + serialization_exclude_if=serialization_exclude_if, + frozen=frozen, + metadata=metadata, + ) + + +class ModelFieldsSchema(TypedDict, total=False): + type: Required[Literal['model-fields']] + fields: Required[dict[str, ModelField]] + model_name: str + computed_fields: list[ComputedField] + strict: bool + extras_schema: CoreSchema + extras_keys_schema: CoreSchema + extra_behavior: ExtraBehavior + from_attributes: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def model_fields_schema( + fields: dict[str, ModelField], + *, + model_name: str | None = None, + computed_fields: list[ComputedField] | None = None, + strict: bool | None = None, + extras_schema: CoreSchema | None = None, + extras_keys_schema: CoreSchema | None = None, + extra_behavior: ExtraBehavior | None = None, + from_attributes: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> ModelFieldsSchema: + """ + Returns a schema that matches the fields of a Pydantic model, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + wrapper_schema = core_schema.model_fields_schema( + {'a': core_schema.model_field(core_schema.str_schema())} + ) + v = SchemaValidator(wrapper_schema) + print(v.validate_python({'a': 'hello'})) + #> ({'a': 'hello'}, None, {'a'}) + ``` + + Args: + fields: The fields of the model + model_name: The name of the model, used for error messages, defaults to "Model" + computed_fields: Computed fields to use when serializing the model, only applies when directly inside a model + strict: Whether the model is strict + extras_schema: The schema to use when validating extra input data + extras_keys_schema: The schema to use when validating the keys of extra input data + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + extra_behavior: The extra behavior to use for the model fields + from_attributes: Whether the model fields should be populated from attributes + serialization: Custom serialization schema + """ + return _dict_not_none( + type='model-fields', + fields=fields, + model_name=model_name, + computed_fields=computed_fields, + strict=strict, + extras_schema=extras_schema, + extras_keys_schema=extras_keys_schema, + extra_behavior=extra_behavior, + from_attributes=from_attributes, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class ModelSchema(TypedDict, total=False): + type: Required[Literal['model']] + cls: Required[type[Any]] + generic_origin: type[Any] + schema: Required[CoreSchema] + custom_init: bool + root_model: bool + post_init: str + revalidate_instances: Literal['always', 'never', 'subclass-instances'] # default: 'never' + strict: bool + frozen: bool + extra_behavior: ExtraBehavior + config: CoreConfig + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def model_schema( + cls: type[Any], + schema: CoreSchema, + *, + generic_origin: type[Any] | None = None, + custom_init: bool | None = None, + root_model: bool | None = None, + post_init: str | None = None, + revalidate_instances: Literal['always', 'never', 'subclass-instances'] | None = None, + strict: bool | None = None, + frozen: bool | None = None, + extra_behavior: ExtraBehavior | None = None, + config: CoreConfig | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> ModelSchema: + """ + A model schema generally contains a typed-dict schema. + It will run the typed dict validator, then create a new class + and set the dict and fields set returned from the typed dict validator + to `__dict__` and `__pydantic_fields_set__` respectively. + + Example: + + ```py + from pydantic_core import CoreConfig, SchemaValidator, core_schema + + class MyModel: + __slots__ = ( + '__dict__', + '__pydantic_fields_set__', + '__pydantic_extra__', + '__pydantic_private__', + ) + + schema = core_schema.model_schema( + cls=MyModel, + config=CoreConfig(str_max_length=5), + schema=core_schema.model_fields_schema( + fields={'a': core_schema.model_field(core_schema.str_schema())}, + ), + ) + v = SchemaValidator(schema) + assert v.isinstance_python({'a': 'hello'}) is True + assert v.isinstance_python({'a': 'too long'}) is False + ``` + + Args: + cls: The class to use for the model + schema: The schema to use for the model + generic_origin: The origin type used for this model, if it's a parametrized generic. Ex, + if this model schema represents `SomeModel[int]`, generic_origin is `SomeModel` + custom_init: Whether the model has a custom init method + root_model: Whether the model is a `RootModel` + post_init: The call after init to use for the model + revalidate_instances: whether instances of models and dataclasses (including subclass instances) + should re-validate defaults to config.revalidate_instances, else 'never' + strict: Whether the model is strict + frozen: Whether the model is frozen + extra_behavior: The extra behavior to use for the model, used in serialization + config: The config to use for the model + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='model', + cls=cls, + generic_origin=generic_origin, + schema=schema, + custom_init=custom_init, + root_model=root_model, + post_init=post_init, + revalidate_instances=revalidate_instances, + strict=strict, + frozen=frozen, + extra_behavior=extra_behavior, + config=config, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class DataclassField(TypedDict, total=False): + type: Required[Literal['dataclass-field']] + name: Required[str] + schema: Required[CoreSchema] + kw_only: bool # default: True + init: bool # default: True + init_only: bool # default: False + frozen: bool # default: False + validation_alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] + serialization_alias: str + serialization_exclude: bool # default: False + metadata: dict[str, Any] + serialization_exclude_if: Callable[[Any], bool] # default: None + + +def dataclass_field( + name: str, + schema: CoreSchema, + *, + kw_only: bool | None = None, + init: bool | None = None, + init_only: bool | None = None, + validation_alias: str | list[str | int] | list[list[str | int]] | None = None, + serialization_alias: str | None = None, + serialization_exclude: bool | None = None, + metadata: dict[str, Any] | None = None, + serialization_exclude_if: Callable[[Any], bool] | None = None, + frozen: bool | None = None, +) -> DataclassField: + """ + Returns a schema for a dataclass field, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + field = core_schema.dataclass_field( + name='a', schema=core_schema.str_schema(), kw_only=False + ) + schema = core_schema.dataclass_args_schema('Foobar', [field]) + v = SchemaValidator(schema) + assert v.validate_python({'a': 'hello'}) == ({'a': 'hello'}, None) + ``` + + Args: + name: The name to use for the argument parameter + schema: The schema to use for the argument parameter + kw_only: Whether the field can be set with a positional argument as well as a keyword argument + init: Whether the field should be validated during initialization + init_only: Whether the field should be omitted from `__dict__` and passed to `__post_init__` + validation_alias: The alias(es) to use to find the field in the validation data + serialization_alias: The alias to use as a key when serializing + serialization_exclude: Whether to exclude the field when serializing + serialization_exclude_if: A callable that determines whether to exclude the field when serializing based on its value. + metadata: Any other information you want to include with the schema, not used by pydantic-core + frozen: Whether the field is frozen + """ + return _dict_not_none( + type='dataclass-field', + name=name, + schema=schema, + kw_only=kw_only, + init=init, + init_only=init_only, + validation_alias=validation_alias, + serialization_alias=serialization_alias, + serialization_exclude=serialization_exclude, + serialization_exclude_if=serialization_exclude_if, + metadata=metadata, + frozen=frozen, + ) + + +class DataclassArgsSchema(TypedDict, total=False): + type: Required[Literal['dataclass-args']] + dataclass_name: Required[str] + fields: Required[list[DataclassField]] + computed_fields: list[ComputedField] + collect_init_only: bool # default: False + ref: str + metadata: dict[str, Any] + serialization: SerSchema + extra_behavior: ExtraBehavior + + +def dataclass_args_schema( + dataclass_name: str, + fields: list[DataclassField], + *, + computed_fields: list[ComputedField] | None = None, + collect_init_only: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, + extra_behavior: ExtraBehavior | None = None, +) -> DataclassArgsSchema: + """ + Returns a schema for validating dataclass arguments, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + field_a = core_schema.dataclass_field( + name='a', schema=core_schema.str_schema(), kw_only=False + ) + field_b = core_schema.dataclass_field( + name='b', schema=core_schema.bool_schema(), kw_only=False + ) + schema = core_schema.dataclass_args_schema('Foobar', [field_a, field_b]) + v = SchemaValidator(schema) + assert v.validate_python({'a': 'hello', 'b': True}) == ({'a': 'hello', 'b': True}, None) + ``` + + Args: + dataclass_name: The name of the dataclass being validated + fields: The fields to use for the dataclass + computed_fields: Computed fields to use when serializing the dataclass + collect_init_only: Whether to collect init only fields into a dict to pass to `__post_init__` + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + extra_behavior: How to handle extra fields + """ + return _dict_not_none( + type='dataclass-args', + dataclass_name=dataclass_name, + fields=fields, + computed_fields=computed_fields, + collect_init_only=collect_init_only, + ref=ref, + metadata=metadata, + serialization=serialization, + extra_behavior=extra_behavior, + ) + + +class DataclassSchema(TypedDict, total=False): + type: Required[Literal['dataclass']] + cls: Required[type[Any]] + generic_origin: type[Any] + schema: Required[CoreSchema] + fields: Required[list[str]] + cls_name: str + post_init: bool # default: False + revalidate_instances: Literal['always', 'never', 'subclass-instances'] # default: 'never' + strict: bool # default: False + frozen: bool # default False + ref: str + metadata: dict[str, Any] + serialization: SerSchema + slots: bool + config: CoreConfig + + +def dataclass_schema( + cls: type[Any], + schema: CoreSchema, + fields: list[str], + *, + generic_origin: type[Any] | None = None, + cls_name: str | None = None, + post_init: bool | None = None, + revalidate_instances: Literal['always', 'never', 'subclass-instances'] | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, + frozen: bool | None = None, + slots: bool | None = None, + config: CoreConfig | None = None, +) -> DataclassSchema: + """ + Returns a schema for a dataclass. As with `ModelSchema`, this schema can only be used as a field within + another schema, not as the root type. + + Args: + cls: The dataclass type, used to perform subclass checks + schema: The schema to use for the dataclass fields + fields: Fields of the dataclass, this is used in serialization and in validation during re-validation + and while validating assignment + generic_origin: The origin type used for this dataclass, if it's a parametrized generic. Ex, + if this model schema represents `SomeDataclass[int]`, generic_origin is `SomeDataclass` + cls_name: The name to use in error locs, etc; this is useful for generics (default: `cls.__name__`) + post_init: Whether to call `__post_init__` after validation + revalidate_instances: whether instances of models and dataclasses (including subclass instances) + should re-validate defaults to config.revalidate_instances, else 'never' + strict: Whether to require an exact instance of `cls` + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + frozen: Whether the dataclass is frozen + slots: Whether `slots=True` on the dataclass, means each field is assigned independently, rather than + simply setting `__dict__`, default false + """ + return _dict_not_none( + type='dataclass', + cls=cls, + generic_origin=generic_origin, + fields=fields, + cls_name=cls_name, + schema=schema, + post_init=post_init, + revalidate_instances=revalidate_instances, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + frozen=frozen, + slots=slots, + config=config, + ) + + +class ArgumentsParameter(TypedDict, total=False): + name: Required[str] + schema: Required[CoreSchema] + mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] # default positional_or_keyword + alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] + + +def arguments_parameter( + name: str, + schema: CoreSchema, + *, + mode: Literal['positional_only', 'positional_or_keyword', 'keyword_only'] | None = None, + alias: str | list[str | int] | list[list[str | int]] | None = None, +) -> ArgumentsParameter: + """ + Returns a schema that matches an argument parameter, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + param = core_schema.arguments_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + schema = core_schema.arguments_schema([param]) + v = SchemaValidator(schema) + assert v.validate_python(('hello',)) == (('hello',), {}) + ``` + + Args: + name: The name to use for the argument parameter + schema: The schema to use for the argument parameter + mode: The mode to use for the argument parameter + alias: The alias to use for the argument parameter + """ + return _dict_not_none(name=name, schema=schema, mode=mode, alias=alias) + + +VarKwargsMode: TypeAlias = Literal['uniform', 'unpacked-typed-dict'] + + +class ArgumentsSchema(TypedDict, total=False): + type: Required[Literal['arguments']] + arguments_schema: Required[list[ArgumentsParameter]] + validate_by_name: bool + validate_by_alias: bool + var_args_schema: CoreSchema + var_kwargs_mode: VarKwargsMode + var_kwargs_schema: CoreSchema + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def arguments_schema( + arguments: list[ArgumentsParameter], + *, + validate_by_name: bool | None = None, + validate_by_alias: bool | None = None, + var_args_schema: CoreSchema | None = None, + var_kwargs_mode: VarKwargsMode | None = None, + var_kwargs_schema: CoreSchema | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> ArgumentsSchema: + """ + Returns a schema that matches an arguments schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + param_a = core_schema.arguments_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + param_b = core_schema.arguments_parameter( + name='b', schema=core_schema.bool_schema(), mode='positional_only' + ) + schema = core_schema.arguments_schema([param_a, param_b]) + v = SchemaValidator(schema) + assert v.validate_python(('hello', True)) == (('hello', True), {}) + ``` + + Args: + arguments: The arguments to use for the arguments schema + validate_by_name: Whether to populate by the parameter names, defaults to `False`. + validate_by_alias: Whether to populate by the parameter aliases, defaults to `True`. + var_args_schema: The variable args schema to use for the arguments schema + var_kwargs_mode: The validation mode to use for variadic keyword arguments. If `'uniform'`, every value of the + keyword arguments will be validated against the `var_kwargs_schema` schema. If `'unpacked-typed-dict'`, + the `var_kwargs_schema` argument must be a [`typed_dict_schema`][pydantic_core.core_schema.typed_dict_schema] + var_kwargs_schema: The variable kwargs schema to use for the arguments schema + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='arguments', + arguments_schema=arguments, + validate_by_name=validate_by_name, + validate_by_alias=validate_by_alias, + var_args_schema=var_args_schema, + var_kwargs_mode=var_kwargs_mode, + var_kwargs_schema=var_kwargs_schema, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class ArgumentsV3Parameter(TypedDict, total=False): + name: Required[str] + schema: Required[CoreSchema] + mode: Literal[ + 'positional_only', + 'positional_or_keyword', + 'keyword_only', + 'var_args', + 'var_kwargs_uniform', + 'var_kwargs_unpacked_typed_dict', + ] # default positional_or_keyword + alias: Union[str, list[Union[str, int]], list[list[Union[str, int]]]] + + +def arguments_v3_parameter( + name: str, + schema: CoreSchema, + *, + mode: Literal[ + 'positional_only', + 'positional_or_keyword', + 'keyword_only', + 'var_args', + 'var_kwargs_uniform', + 'var_kwargs_unpacked_typed_dict', + ] + | None = None, + alias: str | list[str | int] | list[list[str | int]] | None = None, +) -> ArgumentsV3Parameter: + """ + Returns a schema that matches an argument parameter, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + param = core_schema.arguments_v3_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + schema = core_schema.arguments_v3_schema([param]) + v = SchemaValidator(schema) + assert v.validate_python({'a': 'hello'}) == (('hello',), {}) + ``` + + Args: + name: The name to use for the argument parameter + schema: The schema to use for the argument parameter + mode: The mode to use for the argument parameter + alias: The alias to use for the argument parameter + """ + return _dict_not_none(name=name, schema=schema, mode=mode, alias=alias) + + +class ArgumentsV3Schema(TypedDict, total=False): + type: Required[Literal['arguments-v3']] + arguments_schema: Required[list[ArgumentsV3Parameter]] + validate_by_name: bool + validate_by_alias: bool + extra_behavior: Literal['forbid', 'ignore'] # 'allow' doesn't make sense here. + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def arguments_v3_schema( + arguments: list[ArgumentsV3Parameter], + *, + validate_by_name: bool | None = None, + validate_by_alias: bool | None = None, + extra_behavior: Literal['forbid', 'ignore'] | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> ArgumentsV3Schema: + """ + Returns a schema that matches an arguments schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + param_a = core_schema.arguments_v3_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + param_b = core_schema.arguments_v3_parameter( + name='kwargs', schema=core_schema.bool_schema(), mode='var_kwargs_uniform' + ) + schema = core_schema.arguments_v3_schema([param_a, param_b]) + v = SchemaValidator(schema) + assert v.validate_python({'a': 'hi', 'kwargs': {'b': True}}) == (('hi',), {'b': True}) + ``` + + This schema is currently not used by other Pydantic components. In V3, it will most likely + become the default arguments schema for the `'call'` schema. + + Args: + arguments: The arguments to use for the arguments schema. + validate_by_name: Whether to populate by the parameter names, defaults to `False`. + validate_by_alias: Whether to populate by the parameter aliases, defaults to `True`. + extra_behavior: The extra behavior to use. + ref: optional unique identifier of the schema, used to reference the schema in other places. + metadata: Any other information you want to include with the schema, not used by pydantic-core. + serialization: Custom serialization schema. + """ + return _dict_not_none( + type='arguments-v3', + arguments_schema=arguments, + validate_by_name=validate_by_name, + validate_by_alias=validate_by_alias, + extra_behavior=extra_behavior, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class CallSchema(TypedDict, total=False): + type: Required[Literal['call']] + arguments_schema: Required[CoreSchema] + function: Required[Callable[..., Any]] + function_name: str # default function.__name__ + return_schema: CoreSchema + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def call_schema( + arguments: CoreSchema, + function: Callable[..., Any], + *, + function_name: str | None = None, + return_schema: CoreSchema | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> CallSchema: + """ + Returns a schema that matches an arguments schema, then calls a function, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + param_a = core_schema.arguments_parameter( + name='a', schema=core_schema.str_schema(), mode='positional_only' + ) + param_b = core_schema.arguments_parameter( + name='b', schema=core_schema.bool_schema(), mode='positional_only' + ) + args_schema = core_schema.arguments_schema([param_a, param_b]) + + schema = core_schema.call_schema( + arguments=args_schema, + function=lambda a, b: a + str(not b), + return_schema=core_schema.str_schema(), + ) + v = SchemaValidator(schema) + assert v.validate_python((('hello', True))) == 'helloFalse' + ``` + + Args: + arguments: The arguments to use for the arguments schema + function: The function to use for the call schema + function_name: The function name to use for the call schema, if not provided `function.__name__` is used + return_schema: The return schema to use for the call schema + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='call', + arguments_schema=arguments, + function=function, + function_name=function_name, + return_schema=return_schema, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class CustomErrorSchema(TypedDict, total=False): + type: Required[Literal['custom-error']] + schema: Required[CoreSchema] + custom_error_type: Required[str] + custom_error_message: str + custom_error_context: dict[str, Union[str, int, float]] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def custom_error_schema( + schema: CoreSchema, + custom_error_type: str, + *, + custom_error_message: str | None = None, + custom_error_context: dict[str, Any] | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> CustomErrorSchema: + """ + Returns a schema that matches a custom error value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.custom_error_schema( + schema=core_schema.int_schema(), + custom_error_type='MyError', + custom_error_message='Error msg', + ) + v = SchemaValidator(schema) + v.validate_python(1) + ``` + + Args: + schema: The schema to use for the custom error schema + custom_error_type: The custom error type to use for the custom error schema + custom_error_message: The custom error message to use for the custom error schema + custom_error_context: The custom error context to use for the custom error schema + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='custom-error', + schema=schema, + custom_error_type=custom_error_type, + custom_error_message=custom_error_message, + custom_error_context=custom_error_context, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class JsonSchema(TypedDict, total=False): + type: Required[Literal['json']] + schema: CoreSchema + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def json_schema( + schema: CoreSchema | None = None, + *, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> JsonSchema: + """ + Returns a schema that matches a JSON value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + dict_schema = core_schema.model_fields_schema( + { + 'field_a': core_schema.model_field(core_schema.str_schema()), + 'field_b': core_schema.model_field(core_schema.bool_schema()), + }, + ) + + class MyModel: + __slots__ = ( + '__dict__', + '__pydantic_fields_set__', + '__pydantic_extra__', + '__pydantic_private__', + ) + field_a: str + field_b: bool + + json_schema = core_schema.json_schema(schema=dict_schema) + schema = core_schema.model_schema(cls=MyModel, schema=json_schema) + v = SchemaValidator(schema) + m = v.validate_python('{"field_a": "hello", "field_b": true}') + assert isinstance(m, MyModel) + ``` + + Args: + schema: The schema to use for the JSON schema + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none(type='json', schema=schema, ref=ref, metadata=metadata, serialization=serialization) + + +class UrlSchema(TypedDict, total=False): + type: Required[Literal['url']] + max_length: int + allowed_schemes: list[str] + host_required: bool # default False + default_host: str + default_port: int + default_path: str + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def url_schema( + *, + max_length: int | None = None, + allowed_schemes: list[str] | None = None, + host_required: bool | None = None, + default_host: str | None = None, + default_port: int | None = None, + default_path: str | None = None, + preserve_empty_path: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> UrlSchema: + """ + Returns a schema that matches a URL value, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.url_schema() + v = SchemaValidator(schema) + print(v.validate_python('https://example.com')) + #> https://example.com/ + ``` + + Args: + max_length: The maximum length of the URL + allowed_schemes: The allowed URL schemes + host_required: Whether the URL must have a host + default_host: The default host to use if the URL does not have a host + default_port: The default port to use if the URL does not have a port + default_path: The default path to use if the URL does not have a path + preserve_empty_path: Whether to preserve an empty path or convert it to '/', default False + strict: Whether to use strict URL parsing + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='url', + max_length=max_length, + allowed_schemes=allowed_schemes, + host_required=host_required, + default_host=default_host, + default_port=default_port, + default_path=default_path, + preserve_empty_path=preserve_empty_path, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class MultiHostUrlSchema(TypedDict, total=False): + type: Required[Literal['multi-host-url']] + max_length: int + allowed_schemes: list[str] + host_required: bool # default False + default_host: str + default_port: int + default_path: str + strict: bool + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def multi_host_url_schema( + *, + max_length: int | None = None, + allowed_schemes: list[str] | None = None, + host_required: bool | None = None, + default_host: str | None = None, + default_port: int | None = None, + default_path: str | None = None, + preserve_empty_path: bool | None = None, + strict: bool | None = None, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> MultiHostUrlSchema: + """ + Returns a schema that matches a URL value with possibly multiple hosts, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.multi_host_url_schema() + v = SchemaValidator(schema) + print(v.validate_python('redis://localhost,0.0.0.0,127.0.0.1')) + #> redis://localhost,0.0.0.0,127.0.0.1 + ``` + + Args: + max_length: The maximum length of the URL + allowed_schemes: The allowed URL schemes + host_required: Whether the URL must have a host + default_host: The default host to use if the URL does not have a host + default_port: The default port to use if the URL does not have a port + default_path: The default path to use if the URL does not have a path + preserve_empty_path: Whether to preserve an empty path or convert it to '/', default False + strict: Whether to use strict URL parsing + ref: optional unique identifier of the schema, used to reference the schema in other places + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='multi-host-url', + max_length=max_length, + allowed_schemes=allowed_schemes, + host_required=host_required, + default_host=default_host, + default_port=default_port, + default_path=default_path, + preserve_empty_path=preserve_empty_path, + strict=strict, + ref=ref, + metadata=metadata, + serialization=serialization, + ) + + +class DefinitionsSchema(TypedDict, total=False): + type: Required[Literal['definitions']] + schema: Required[CoreSchema] + definitions: Required[list[CoreSchema]] + metadata: dict[str, Any] + serialization: SerSchema + + +def definitions_schema(schema: CoreSchema, definitions: list[CoreSchema]) -> DefinitionsSchema: + """ + Build a schema that contains both an inner schema and a list of definitions which can be used + within the inner schema. + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema = core_schema.definitions_schema( + core_schema.list_schema(core_schema.definition_reference_schema('foobar')), + [core_schema.int_schema(ref='foobar')], + ) + v = SchemaValidator(schema) + assert v.validate_python([1, 2, '3']) == [1, 2, 3] + ``` + + Args: + schema: The inner schema + definitions: List of definitions which can be referenced within inner schema + """ + return DefinitionsSchema(type='definitions', schema=schema, definitions=definitions) + + +class DefinitionReferenceSchema(TypedDict, total=False): + type: Required[Literal['definition-ref']] + schema_ref: Required[str] + ref: str + metadata: dict[str, Any] + serialization: SerSchema + + +def definition_reference_schema( + schema_ref: str, + ref: str | None = None, + metadata: dict[str, Any] | None = None, + serialization: SerSchema | None = None, +) -> DefinitionReferenceSchema: + """ + Returns a schema that points to a schema stored in "definitions", this is useful for nested recursive + models and also when you want to define validators separately from the main schema, e.g.: + + ```py + from pydantic_core import SchemaValidator, core_schema + + schema_definition = core_schema.definition_reference_schema('list-schema') + schema = core_schema.definitions_schema( + schema=schema_definition, + definitions=[ + core_schema.list_schema(items_schema=schema_definition, ref='list-schema'), + ], + ) + v = SchemaValidator(schema) + assert v.validate_python([()]) == [[]] + ``` + + Args: + schema_ref: The schema ref to use for the definition reference schema + metadata: Any other information you want to include with the schema, not used by pydantic-core + serialization: Custom serialization schema + """ + return _dict_not_none( + type='definition-ref', schema_ref=schema_ref, ref=ref, metadata=metadata, serialization=serialization + ) + + +MYPY = False +# See https://github.com/python/mypy/issues/14034 for details, in summary mypy is extremely slow to process this +# union which kills performance not just for pydantic, but even for code using pydantic +if not MYPY: + CoreSchema = Union[ + InvalidSchema, + AnySchema, + NoneSchema, + BoolSchema, + IntSchema, + FloatSchema, + DecimalSchema, + StringSchema, + BytesSchema, + DateSchema, + TimeSchema, + DatetimeSchema, + TimedeltaSchema, + LiteralSchema, + MissingSentinelSchema, + EnumSchema, + IsInstanceSchema, + IsSubclassSchema, + CallableSchema, + ListSchema, + TupleSchema, + SetSchema, + FrozenSetSchema, + GeneratorSchema, + DictSchema, + AfterValidatorFunctionSchema, + BeforeValidatorFunctionSchema, + WrapValidatorFunctionSchema, + PlainValidatorFunctionSchema, + WithDefaultSchema, + NullableSchema, + UnionSchema, + TaggedUnionSchema, + ChainSchema, + LaxOrStrictSchema, + JsonOrPythonSchema, + TypedDictSchema, + ModelFieldsSchema, + ModelSchema, + DataclassArgsSchema, + DataclassSchema, + ArgumentsSchema, + ArgumentsV3Schema, + CallSchema, + CustomErrorSchema, + JsonSchema, + UrlSchema, + MultiHostUrlSchema, + DefinitionsSchema, + DefinitionReferenceSchema, + UuidSchema, + ComplexSchema, + ] +elif False: + CoreSchema: TypeAlias = Mapping[str, Any] + + +# to update this, call `pytest -k test_core_schema_type_literal` and copy the output +CoreSchemaType = Literal[ + 'invalid', + 'any', + 'none', + 'bool', + 'int', + 'float', + 'decimal', + 'str', + 'bytes', + 'date', + 'time', + 'datetime', + 'timedelta', + 'literal', + 'missing-sentinel', + 'enum', + 'is-instance', + 'is-subclass', + 'callable', + 'list', + 'tuple', + 'set', + 'frozenset', + 'generator', + 'dict', + 'function-after', + 'function-before', + 'function-wrap', + 'function-plain', + 'default', + 'nullable', + 'union', + 'tagged-union', + 'chain', + 'lax-or-strict', + 'json-or-python', + 'typed-dict', + 'model-fields', + 'model', + 'dataclass-args', + 'dataclass', + 'arguments', + 'arguments-v3', + 'call', + 'custom-error', + 'json', + 'url', + 'multi-host-url', + 'definitions', + 'definition-ref', + 'uuid', + 'complex', +] + +CoreSchemaFieldType = Literal['model-field', 'dataclass-field', 'typed-dict-field', 'computed-field'] + + +# used in _pydantic_core.pyi::PydanticKnownError +# to update this, call `pytest -k test_all_errors` and copy the output +ErrorType = Literal[ + 'no_such_attribute', + 'json_invalid', + 'json_type', + 'needs_python_object', + 'recursion_loop', + 'missing', + 'frozen_field', + 'frozen_instance', + 'extra_forbidden', + 'invalid_key', + 'get_attribute_error', + 'model_type', + 'model_attributes_type', + 'dataclass_type', + 'dataclass_exact_type', + 'default_factory_not_called', + 'none_required', + 'greater_than', + 'greater_than_equal', + 'less_than', + 'less_than_equal', + 'multiple_of', + 'finite_number', + 'too_short', + 'too_long', + 'iterable_type', + 'iteration_error', + 'string_type', + 'string_sub_type', + 'string_unicode', + 'string_too_short', + 'string_too_long', + 'string_pattern_mismatch', + 'string_not_ascii', + 'enum', + 'dict_type', + 'mapping_type', + 'list_type', + 'tuple_type', + 'set_type', + 'set_item_not_hashable', + 'bool_type', + 'bool_parsing', + 'int_type', + 'int_parsing', + 'int_parsing_size', + 'int_from_float', + 'float_type', + 'float_parsing', + 'bytes_type', + 'bytes_too_short', + 'bytes_too_long', + 'bytes_invalid_encoding', + 'value_error', + 'assertion_error', + 'literal_error', + 'missing_sentinel_error', + 'date_type', + 'date_parsing', + 'date_from_datetime_parsing', + 'date_from_datetime_inexact', + 'date_past', + 'date_future', + 'time_type', + 'time_parsing', + 'datetime_type', + 'datetime_parsing', + 'datetime_object_invalid', + 'datetime_from_date_parsing', + 'datetime_past', + 'datetime_future', + 'timezone_naive', + 'timezone_aware', + 'timezone_offset', + 'time_delta_type', + 'time_delta_parsing', + 'frozen_set_type', + 'is_instance_of', + 'is_subclass_of', + 'callable_type', + 'union_tag_invalid', + 'union_tag_not_found', + 'arguments_type', + 'missing_argument', + 'unexpected_keyword_argument', + 'missing_keyword_only_argument', + 'unexpected_positional_argument', + 'missing_positional_only_argument', + 'multiple_argument_values', + 'url_type', + 'url_parsing', + 'url_syntax_violation', + 'url_too_long', + 'url_scheme', + 'uuid_type', + 'uuid_parsing', + 'uuid_version', + 'decimal_type', + 'decimal_parsing', + 'decimal_max_digits', + 'decimal_max_places', + 'decimal_whole_digits', + 'complex_type', + 'complex_str_parsing', +] + + +def _dict_not_none(**kwargs: Any) -> Any: + return {k: v for k, v in kwargs.items() if v is not None} + + +def iter_union_choices(union_schema: UnionSchema) -> Generator[CoreSchema]: + """Iterate over the choices of a `'union'` schema.""" + for choice in union_schema['choices']: + if isinstance(choice, tuple): + yield choice[0] + else: + yield choice + + +############################################################################### +# All this stuff is deprecated by #980 and will be removed eventually +# They're kept because some code external code will be using them + + +@deprecated('`field_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.') +def field_before_validator_function(function: WithInfoValidatorFunction, field_name: str, schema: CoreSchema, **kwargs): + warnings.warn( + '`field_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.', + DeprecationWarning, + ) + return with_info_before_validator_function(function, schema, field_name=field_name, **kwargs) + + +@deprecated('`general_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.') +def general_before_validator_function(*args, **kwargs): + warnings.warn( + '`general_before_validator_function` is deprecated, use `with_info_before_validator_function` instead.', + DeprecationWarning, + ) + return with_info_before_validator_function(*args, **kwargs) + + +@deprecated('`field_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.') +def field_after_validator_function(function: WithInfoValidatorFunction, field_name: str, schema: CoreSchema, **kwargs): + warnings.warn( + '`field_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.', + DeprecationWarning, + ) + return with_info_after_validator_function(function, schema, field_name=field_name, **kwargs) + + +@deprecated('`general_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.') +def general_after_validator_function(*args, **kwargs): + warnings.warn( + '`general_after_validator_function` is deprecated, use `with_info_after_validator_function` instead.', + DeprecationWarning, + ) + return with_info_after_validator_function(*args, **kwargs) + + +@deprecated('`field_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.') +def field_wrap_validator_function( + function: WithInfoWrapValidatorFunction, field_name: str, schema: CoreSchema, **kwargs +): + warnings.warn( + '`field_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.', + DeprecationWarning, + ) + return with_info_wrap_validator_function(function, schema, field_name=field_name, **kwargs) + + +@deprecated('`general_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.') +def general_wrap_validator_function(*args, **kwargs): + warnings.warn( + '`general_wrap_validator_function` is deprecated, use `with_info_wrap_validator_function` instead.', + DeprecationWarning, + ) + return with_info_wrap_validator_function(*args, **kwargs) + + +@deprecated('`field_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.') +def field_plain_validator_function(function: WithInfoValidatorFunction, field_name: str, **kwargs): + warnings.warn( + '`field_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.', + DeprecationWarning, + ) + return with_info_plain_validator_function(function, field_name=field_name, **kwargs) + + +@deprecated('`general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.') +def general_plain_validator_function(*args, **kwargs): + warnings.warn( + '`general_plain_validator_function` is deprecated, use `with_info_plain_validator_function` instead.', + DeprecationWarning, + ) + return with_info_plain_validator_function(*args, **kwargs) + + +_deprecated_import_lookup = { + 'FieldValidationInfo': ValidationInfo, + 'FieldValidatorFunction': WithInfoValidatorFunction, + 'GeneralValidatorFunction': WithInfoValidatorFunction, + 'FieldWrapValidatorFunction': WithInfoWrapValidatorFunction, +} + +if TYPE_CHECKING: + FieldValidationInfo = ValidationInfo + + +def __getattr__(attr_name: str) -> object: + new_attr = _deprecated_import_lookup.get(attr_name) + if new_attr is None: + raise AttributeError(f"module 'pydantic_core' has no attribute '{attr_name}'") + else: + import warnings + + msg = f'`{attr_name}` is deprecated, use `{new_attr.__name__}` instead.' + warnings.warn(msg, DeprecationWarning, stacklevel=1) + return new_attr diff --git a/source/target-vendors/cp312/pydantic_core/py.typed b/source/target-vendors/cp312/pydantic_core/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/METADATA b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/METADATA new file mode 100644 index 0000000..52926c2 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/METADATA @@ -0,0 +1,70 @@ +Metadata-Version: 2.4 +Name: pydantic-settings +Version: 2.15.0 +Summary: Settings management using Pydantic +Project-URL: Homepage, https://github.com/pydantic/pydantic-settings +Project-URL: Funding, https://github.com/sponsors/samuelcolvin +Project-URL: Source, https://github.com/pydantic/pydantic-settings +Project-URL: Changelog, https://github.com/pydantic/pydantic-settings/releases +Project-URL: Documentation, https://docs.pydantic.dev/dev-v2/concepts/pydantic_settings/ +Author-email: Samuel Colvin , Eric Jolibois , Hasan Ramezani +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Environment :: MacOS X +Classifier: Framework :: Pydantic +Classifier: Framework :: Pydantic :: 2 +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: Information Technology +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Unix +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Topic :: Internet +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.10 +Requires-Dist: pydantic>=2.7.0 +Requires-Dist: python-dotenv>=0.21.0 +Requires-Dist: typing-inspection>=0.4.0 +Provides-Extra: aws-secrets-manager +Requires-Dist: boto3>=1.35.0; extra == 'aws-secrets-manager' +Provides-Extra: azure-key-vault +Requires-Dist: azure-identity>=1.16.0; extra == 'azure-key-vault' +Requires-Dist: azure-keyvault-secrets>=4.8.0; extra == 'azure-key-vault' +Provides-Extra: gcp-secret-manager +Requires-Dist: google-cloud-secret-manager>=2.23.1; extra == 'gcp-secret-manager' +Provides-Extra: toml +Requires-Dist: tomli>=2.0.1; extra == 'toml' +Provides-Extra: yaml +Requires-Dist: pyyaml>=6.0.1; extra == 'yaml' +Description-Content-Type: text/markdown + +# pydantic-settings + +[![CI](https://github.com/pydantic/pydantic-settings/actions/workflows/ci.yml/badge.svg?event=push)](https://github.com/pydantic/pydantic-settings/actions/workflows/ci.yml?query=branch%3Amain) +[![Coverage](https://codecov.io/gh/pydantic/pydantic-settings/branch/main/graph/badge.svg)](https://codecov.io/gh/pydantic/pydantic-settings) +[![pypi](https://img.shields.io/pypi/v/pydantic-settings.svg)](https://pypi.python.org/pypi/pydantic-settings) +[![license](https://img.shields.io/github/license/pydantic/pydantic-settings.svg)](https://github.com/pydantic/pydantic-settings/blob/main/LICENSE) +[![downloads](https://static.pepy.tech/badge/pydantic-settings/month)](https://pepy.tech/project/pydantic-settings) +[![versions](https://img.shields.io/pypi/pyversions/pydantic-settings.svg)](https://github.com/pydantic/pydantic-settings) + +Settings management using Pydantic. + +See [documentation](https://pydantic.dev/docs/validation/latest/concepts/pydantic_settings/) for more details. + +## Part of the Pydantic Stack + +The Pydantic Stack is everything you need to ship production-grade AI agents: + +- [Pydantic AI](https://pydantic.dev/pydantic-ai?utm_source=github&utm_medium=readme&utm_campaign=pydantic-settings) - Type-safe agent framework +- [Pydantic Logfire](https://pydantic.dev/logfire?utm_source=github&utm_medium=readme&utm_campaign=pydantic-settings) - AI-first, full-stack observability +- [Logfire AI Gateway](https://pydantic.dev/ai-gateway?utm_source=github&utm_medium=readme&utm_campaign=pydantic-settings) - Unified LLM proxy diff --git a/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/RECORD b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/RECORD new file mode 100644 index 0000000..ebd1905 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/RECORD @@ -0,0 +1,27 @@ +pydantic_settings/__init__.py,sha256=F24B0u2U_vPocmZwgqpN83JtwfFSAbsl3VePWAJCBbE,1781 +pydantic_settings/exceptions.py,sha256=o9WAppV9m_8334HP2LqxzbrVfM4WHV56Cqit57tgL4A,426 +pydantic_settings/main.py,sha256=HxKWdFB6duziUY4ezxTt5BS2Hlb-880pxsMO1H-GC_I,47390 +pydantic_settings/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pydantic_settings/utils.py,sha256=ZPXGoD5MU3QLl6TlT_P2VqP11kMqb9rqp0nc3nsCLRc,1703 +pydantic_settings/version.py,sha256=jSdrSRDnJmdDSOi5UEA39d_r3Ov1jn5kIrqsZnD1-Po,19 +pydantic_settings/sources/__init__.py,sha256=sOdQuzLbpBvJWKWGUyIK_ZeLvJnAvFiFNARE_PVHXJ4,2404 +pydantic_settings/sources/base.py,sha256=5X-IrXve090QH-u39NRVcVB5E3hUsNuxqTOOA3h-_4Q,26340 +pydantic_settings/sources/types.py,sha256=6XH_-XSRVb78LbDFSDIAcfA7GqP2237ozUlwZqUjTaQ,2617 +pydantic_settings/sources/utils.py,sha256=1xhDF5cG-JZxYjUf_xDTZmioM-LOoRGWhBuk7v3ci3Q,14570 +pydantic_settings/sources/providers/__init__.py,sha256=gE6XLz6hbKpc_sSidAQ-UM001uWUXg7xGU-IRHrC6Ug,1281 +pydantic_settings/sources/providers/aws.py,sha256=jielh-5n_kl8b8gGOd3kq3Mr1UkwW5JjUCqqtcOzw4s,2729 +pydantic_settings/sources/providers/azure.py,sha256=ljAhpbQ2CENyBBm8StZBXVhEhZN4rDqBcRP4Ji8kdYA,5689 +pydantic_settings/sources/providers/cli.py,sha256=e_LHvvyQyRXmp4s2pLJdVDCvMsR46LlayMrSJAzFGO4,79106 +pydantic_settings/sources/providers/dotenv.py,sha256=oul0VHKUS0UFvr5eFcR5gPDIP77QHMpH6963RFDzuak,8328 +pydantic_settings/sources/providers/env.py,sha256=vyV26JsO5LhLOhPX86k6pEK1ZQetSjHQH5kIrNTQYV4,16235 +pydantic_settings/sources/providers/gcp.py,sha256=ykP5sLd6l95eyAh3oHz7Me0tnlqNZnYm_YRuwyxPrpM,15238 +pydantic_settings/sources/providers/json.py,sha256=9rohQV_nK0z-Xn2n6dLU63-Kx3O7rxSkaykkMVUdgos,1673 +pydantic_settings/sources/providers/nested_secrets.py,sha256=k6pntQ_8GGfpRzZTMNAt3F7RaAN64Xjkv08b2iNRkOM,9260 +pydantic_settings/sources/providers/pyproject.py,sha256=-NYo0pHE0LuebcCHu5e2x5uYPYjT5Cch9W5nD23wwmo,2153 +pydantic_settings/sources/providers/secrets.py,sha256=8c3tV9FyW36P5TTjiWU4sF7XIYObkLMgxj7a8WL-pns,5188 +pydantic_settings/sources/providers/toml.py,sha256=FCLO4KuuvhDPm4cjEy18DGPghg6AQzq8sHzwmYudTio,3351 +pydantic_settings/sources/providers/yaml.py,sha256=rKkIPx2DF-3-prmoniU13GrxRYFjsEx84EvTbLjiZD4,5726 +pydantic_settings-2.15.0.dist-info/METADATA,sha256=WsEuQI32Lx1MdkMUbZ3wSs50nx_lzyizt5S-Cyg0ym0,3885 +pydantic_settings-2.15.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87 +pydantic_settings-2.15.0.dist-info/licenses/LICENSE,sha256=6zVadT4CA0bTPYO_l2kTW4n8YQVorFMaAcKVvO5_2Zg,1103 +pydantic_settings-2.15.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/WHEEL b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/WHEEL new file mode 100644 index 0000000..7401812 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.31.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..d90598f --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings-2.15.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2022 Samuel Colvin and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/source/target-vendors/cp312/pydantic_settings/__init__.py b/source/target-vendors/cp312/pydantic_settings/__init__.py new file mode 100644 index 0000000..8cdd40c --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/__init__.py @@ -0,0 +1,70 @@ +from .exceptions import IncompleteFieldDefinitionWarning, SettingsError +from .main import BaseSettings, CliApp, SettingsConfigDict +from .sources import ( + CLI_SUPPRESS, + AWSSecretsManagerSettingsSource, + AzureKeyVaultSettingsSource, + CliDualFlag, + CliExplicitFlag, + CliImplicitFlag, + CliMutuallyExclusiveGroup, + CliPositionalArg, + CliSettingsSource, + CliSubCommand, + CliSuppress, + CliToggleFlag, + CliUnknownArgs, + DotEnvSettingsSource, + EnvSettingsSource, + ForceDecode, + GoogleSecretManagerSettingsSource, + InitSettingsSource, + JsonConfigSettingsSource, + NestedSecretsSettingsSource, + NoDecode, + PydanticBaseSettingsSource, + PyprojectTomlConfigSettingsSource, + SecretsSettingsSource, + TomlConfigSettingsSource, + YamlConfigSettingsSource, + get_subcommand, +) +from .version import VERSION + +__all__ = ( + 'CLI_SUPPRESS', + 'AWSSecretsManagerSettingsSource', + 'AzureKeyVaultSettingsSource', + 'BaseSettings', + 'CliApp', + 'CliDualFlag', + 'CliExplicitFlag', + 'CliImplicitFlag', + 'CliMutuallyExclusiveGroup', + 'CliPositionalArg', + 'CliSettingsSource', + 'CliSubCommand', + 'CliSuppress', + 'CliToggleFlag', + 'CliUnknownArgs', + 'DotEnvSettingsSource', + 'EnvSettingsSource', + 'ForceDecode', + 'GoogleSecretManagerSettingsSource', + 'IncompleteFieldDefinitionWarning', + 'InitSettingsSource', + 'JsonConfigSettingsSource', + 'NestedSecretsSettingsSource', + 'NoDecode', + 'PydanticBaseSettingsSource', + 'PyprojectTomlConfigSettingsSource', + 'SecretsSettingsSource', + 'SettingsConfigDict', + 'SettingsError', + 'TomlConfigSettingsSource', + 'YamlConfigSettingsSource', + '__version__', + 'get_subcommand', +) + +__version__ = VERSION diff --git a/source/target-vendors/cp312/pydantic_settings/exceptions.py b/source/target-vendors/cp312/pydantic_settings/exceptions.py new file mode 100644 index 0000000..dab7c71 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/exceptions.py @@ -0,0 +1,10 @@ +class SettingsError(ValueError): + """Base exception for settings-related errors.""" + + +class IncompleteFieldDefinitionWarning(UserWarning): + """Warning emitted when a field with an incomplete definition is used during settings resolution. + + A field definition is incomplete when its annotation contains unresolved forward references, + in which case settings sources may fail to correctly resolve its value. + """ diff --git a/source/target-vendors/cp312/pydantic_settings/main.py b/source/target-vendors/cp312/pydantic_settings/main.py new file mode 100644 index 0000000..3366241 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/main.py @@ -0,0 +1,978 @@ +from __future__ import annotations as _annotations + +import asyncio +import inspect +import logging +import re +import threading +import warnings +from argparse import Namespace +from collections.abc import Mapping +from types import SimpleNamespace +from typing import Any, ClassVar, Literal, TextIO, TypeVar, cast + +from pydantic import ConfigDict +from pydantic._internal._config import config_keys +from pydantic._internal._signature import _field_name_for_signature +from pydantic._internal._utils import deep_update, is_model_class +from pydantic.dataclasses import is_pydantic_dataclass +from pydantic.main import BaseModel + +from .exceptions import SettingsError +from .sources import ( + ENV_FILE_SENTINEL, + CliSettingsSource, + ConfigFileSourceType, + DefaultSettingsSource, + DotenvFiltering, + DotEnvSettingsSource, + DotenvType, + EnvPrefixTarget, + EnvSettingsSource, + InitSettingsSource, + JsonConfigSettingsSource, + PathType, + PydanticBaseSettingsSource, + PydanticModel, + PyprojectTomlConfigSettingsSource, + SecretsSettingsSource, + TomlConfigSettingsSource, + YamlConfigSettingsSource, + get_subcommand, +) +from .sources.utils import InitState, _get_alias_names, _warn_if_field_info_incomplete +from .utils import _settings_debug_enabled, logger + +T = TypeVar('T') + + +class SettingsConfigDict(ConfigDict, total=False): + case_sensitive: bool + nested_model_default_partial_update: bool | None + env_prefix: str + env_prefix_target: EnvPrefixTarget + env_file: DotenvType | None + env_file_encoding: str | None + dotenv_filtering: DotenvFiltering | None + env_ignore_empty: bool + env_nested_delimiter: str | None + env_nested_max_split: int | None + env_parse_none_str: str | None + env_parse_enums: bool | None + cli_prog_name: str | None + cli_parse_args: bool | list[str] | tuple[str, ...] | None + cli_parse_none_str: str | None + cli_hide_none_type: bool + cli_avoid_json: bool + cli_enforce_required: bool + cli_use_class_docs_for_groups: bool + cli_show_env_vars: bool + cli_exit_on_error: bool + cli_prefix: str + cli_flag_prefix_char: str + cli_implicit_flags: bool | Literal['dual', 'toggle'] | None + cli_ignore_unknown_args: bool | None + cli_kebab_case: bool | Literal['all', 'no_enums'] | None + cli_shortcuts: Mapping[str, str | list[str]] | None + secrets_dir: PathType | None + json_file: ConfigFileSourceType | None + json_file_encoding: str | None + yaml_file: ConfigFileSourceType | None + yaml_file_encoding: str | None + yaml_config_section: str | None + """ + Specifies the section in a YAML file from which to load the settings. + Supports dot-notation for nested paths (e.g., 'config.app.settings'). + If provided, the settings will be loaded from the specified section. + This is useful when the YAML file contains multiple configuration sections + and you only want to load a specific subset into your settings model. + """ + + pyproject_toml_depth: int + """ + Number of levels **up** from the current working directory to attempt to find a pyproject.toml + file. + + This is only used when a pyproject.toml file is not found in the current working directory. + """ + + pyproject_toml_table_header: tuple[str, ...] + """ + Header of the TOML table within a pyproject.toml file to use when filling variables. + This is supplied as a `tuple[str, ...]` instead of a `str` to accommodate for headers + containing a `.`. + + For example, `toml_table_header = ("tool", "my.tool", "foo")` can be used to fill variable + values from a table with header `[tool."my.tool".foo]`. + + To use the root table, exclude this config setting or provide an empty tuple. + """ + + toml_file: ConfigFileSourceType | None + + toml_table_header: tuple[str, ...] + """ + Header of the TOML table in a TOML file to use when filling variables. + Similar to `pyproject_toml_table_header`, but for generic TOML file handling. + + Default is to use the root table, i.e. no table header. + """ + enable_decoding: bool + + +# Extend `config_keys` by pydantic settings config keys to +# support setting config through class kwargs. +# Pydantic uses `config_keys` in `pydantic._internal._config.ConfigWrapper.for_model` +# to extract config keys from model kwargs, So, by adding pydantic settings keys to +# `config_keys`, they will be considered as valid config keys and will be collected +# by Pydantic. +config_keys |= set(SettingsConfigDict.__annotations__.keys()) + + +class BaseSettings(BaseModel): + """ + Base class for settings, allowing values to be overridden by environment variables. + + This is useful in production for secrets you do not wish to save in code, it plays nicely with docker(-compose), + Heroku and any 12 factor app design. + + All the below attributes can be set via `model_config`. + + Args: + _case_sensitive: Whether environment and CLI variable names should be read with case-sensitivity. + Defaults to `None`. + _nested_model_default_partial_update: Whether to allow partial updates on nested model default object fields. + Defaults to `False`. + _env_prefix: Prefix for all environment variables. Defaults to `None`. + _env_prefix_target: Targets to which `_env_prefix` is applied. Default: `variable`. + _env_file: The env file(s) to load settings values from. Defaults to `Path('')`, which + means that the value from `model_config['env_file']` should be used. You can also pass + `None` to indicate that environment variables should not be loaded from an env file. + _env_file_encoding: The env file encoding, e.g. `'latin-1'`. Defaults to `None`. + _env_ignore_empty: Ignore environment variables where the value is an empty string. Default to `False`. + _env_nested_delimiter: The nested env values delimiter. Defaults to `None`. + _env_nested_max_split: The nested env values maximum nesting. Defaults to `None`, which means no limit. + _env_parse_none_str: The env string value that should be parsed (e.g. "null", "void", "None", etc.) + into `None` type(None). Defaults to `None` type(None), which means no parsing should occur. + _env_parse_enums: Parse enum field names to values. Defaults to `None.`, which means no parsing should occur. + _cli_prog_name: The CLI program name to display in help text. Defaults to `None` if _cli_parse_args is `None`. + Otherwise, defaults to sys.argv[0]. + _cli_parse_args: The list of CLI arguments to parse. Defaults to None. + If set to `True`, defaults to sys.argv[1:]. + _cli_settings_source: Override the default CLI settings source with a user defined instance. Defaults to None. + _cli_parse_none_str: The CLI string value that should be parsed (e.g. "null", "void", "None", etc.) into + `None` type(None). Defaults to _env_parse_none_str value if set. Otherwise, defaults to "null" if + _cli_avoid_json is `False`, and "None" if _cli_avoid_json is `True`. + _cli_hide_none_type: Hide `None` values in CLI help text. Defaults to `False`. + _cli_avoid_json: Avoid complex JSON objects in CLI help text. Defaults to `False`. + _cli_enforce_required: Enforce required fields at the CLI. Defaults to `False`. + _cli_use_class_docs_for_groups: Use class docstrings in CLI group help text instead of field descriptions. + Defaults to `False`. + _cli_show_env_vars: Show resolved environment variable names in CLI help text. Defaults to `False`. + _cli_exit_on_error: Determines whether or not the internal parser exits with error info when an error occurs. + Defaults to `True`. + _cli_prefix: The root parser command line arguments prefix. Defaults to "". + _cli_flag_prefix_char: The flag prefix character to use for CLI optional arguments. Defaults to '-'. + _cli_implicit_flags: Controls how `bool` fields are exposed as CLI flags. + + - False (default): no implicit flags are generated; booleans must be set explicitly (e.g. --flag=true). + - True / 'dual': optional boolean fields generate both positive and negative forms (--flag and --no-flag). + - 'toggle': required boolean fields remain in 'dual' mode, while optional boolean fields generate a single + flag aligned with the default value (if default=False, expose --flag; if default=True, expose --no-flag). + _cli_ignore_unknown_args: Whether to ignore unknown CLI args and parse only known ones. Defaults to `False`. + _cli_kebab_case: CLI args use kebab case. Defaults to `False`. + _cli_shortcuts: Mapping of target field name to alias names. Defaults to `None`. + _secrets_dir: The secret files directory or a sequence of directories. Defaults to `None`. + _build_sources: Pre-initialized sources and init kwargs to use for building instantiation values. + Defaults to `None`. + """ + + # Note: when adding new parameters, make sure to use `object` instead of `Any` to avoid issues with the Mypy plugin + # when used with `--disallow-any-explicit`. If `Any` needs to be used as a generic parameter for variance (e.g. in `_build_sources`), + # make sure to update the Pydantic Mypy plugin accordingly. + def __init__( + __pydantic_self__, + _case_sensitive: bool | None = None, + _nested_model_default_partial_update: bool | None = None, + _env_prefix: str | None = None, + _env_prefix_target: EnvPrefixTarget | None = None, + _env_file: DotenvType | None = ENV_FILE_SENTINEL, + _env_file_encoding: str | None = None, + _env_ignore_empty: bool | None = None, + _env_nested_delimiter: str | None = None, + _env_nested_max_split: int | None = None, + _env_parse_none_str: str | None = None, + _env_parse_enums: bool | None = None, + _cli_prog_name: str | None = None, + _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, + _cli_settings_source: CliSettingsSource[Any] | None = None, + _cli_parse_none_str: str | None = None, + _cli_hide_none_type: bool | None = None, + _cli_avoid_json: bool | None = None, + _cli_enforce_required: bool | None = None, + _cli_use_class_docs_for_groups: bool | None = None, + _cli_show_env_vars: bool | None = None, + _cli_exit_on_error: bool | None = None, + _cli_prefix: str | None = None, + _cli_flag_prefix_char: str | None = None, + _cli_implicit_flags: bool | Literal['dual', 'toggle'] | None = None, + _cli_ignore_unknown_args: bool | None = None, + _cli_kebab_case: bool | Literal['all', 'no_enums'] | None = None, + _cli_shortcuts: Mapping[str, str | list[str]] | None = None, + _secrets_dir: PathType | None = None, + _build_sources: tuple[tuple[PydanticBaseSettingsSource, ...], dict[str, Any]] | None = None, + **values: Any, + ) -> None: + sources, init_kwargs = ( + _build_sources + if _build_sources is not None + else __pydantic_self__.__class__._settings_init_sources( + _case_sensitive=_case_sensitive, + _nested_model_default_partial_update=_nested_model_default_partial_update, + _env_prefix=_env_prefix, + _env_prefix_target=_env_prefix_target, + _env_file=_env_file, + _env_file_encoding=_env_file_encoding, + _env_ignore_empty=_env_ignore_empty, + _env_nested_delimiter=_env_nested_delimiter, + _env_nested_max_split=_env_nested_max_split, + _env_parse_none_str=_env_parse_none_str, + _env_parse_enums=_env_parse_enums, + _cli_prog_name=_cli_prog_name, + _cli_parse_args=_cli_parse_args, + _cli_settings_source=_cli_settings_source, + _cli_parse_none_str=_cli_parse_none_str, + _cli_hide_none_type=_cli_hide_none_type, + _cli_avoid_json=_cli_avoid_json, + _cli_enforce_required=_cli_enforce_required, + _cli_use_class_docs_for_groups=_cli_use_class_docs_for_groups, + _cli_show_env_vars=_cli_show_env_vars, + _cli_exit_on_error=_cli_exit_on_error, + _cli_prefix=_cli_prefix, + _cli_flag_prefix_char=_cli_flag_prefix_char, + _cli_implicit_flags=_cli_implicit_flags, + _cli_ignore_unknown_args=_cli_ignore_unknown_args, + _cli_kebab_case=_cli_kebab_case, + _cli_shortcuts=_cli_shortcuts, + _secrets_dir=_secrets_dir, + _init_kwargs=values, + ) + ) + + super().__init__(**__pydantic_self__.__class__._settings_build_values(sources, init_kwargs)) + + @classmethod + def settings_customise_sources( + cls, + settings_cls: type[BaseSettings], + init_settings: PydanticBaseSettingsSource, + env_settings: PydanticBaseSettingsSource, + dotenv_settings: PydanticBaseSettingsSource, + file_secret_settings: PydanticBaseSettingsSource, + ) -> tuple[PydanticBaseSettingsSource, ...]: + """ + Define the sources and their order for loading the settings values. + + Args: + settings_cls: The Settings class. + init_settings: The `InitSettingsSource` instance. + env_settings: The `EnvSettingsSource` instance. + dotenv_settings: The `DotEnvSettingsSource` instance. + file_secret_settings: The `SecretsSettingsSource` instance. + + Returns: + A tuple containing the sources and their order for loading the settings values. + """ + return init_settings, env_settings, dotenv_settings, file_secret_settings + + @classmethod + def _settings_init_sources( + cls, + _case_sensitive: bool | None = None, + _nested_model_default_partial_update: bool | None = None, + _env_prefix: str | None = None, + _env_prefix_target: EnvPrefixTarget | None = None, + _env_file: DotenvType | None = ENV_FILE_SENTINEL, + _env_file_encoding: str | None = None, + _env_ignore_empty: bool | None = None, + _env_nested_delimiter: str | None = None, + _env_nested_max_split: int | None = None, + _env_parse_none_str: str | None = None, + _env_parse_enums: bool | None = None, + _cli_prog_name: str | None = None, + _cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, + _cli_settings_source: CliSettingsSource[Any] | None = None, + _cli_parse_none_str: str | None = None, + _cli_hide_none_type: bool | None = None, + _cli_avoid_json: bool | None = None, + _cli_enforce_required: bool | None = None, + _cli_use_class_docs_for_groups: bool | None = None, + _cli_show_env_vars: bool | None = None, + _cli_exit_on_error: bool | None = None, + _cli_prefix: str | None = None, + _cli_flag_prefix_char: str | None = None, + _cli_implicit_flags: bool | Literal['dual', 'toggle'] | None = None, + _cli_ignore_unknown_args: bool | None = None, + _cli_kebab_case: bool | Literal['all', 'no_enums'] | None = None, + _cli_shortcuts: Mapping[str, str | list[str]] | None = None, + _secrets_dir: PathType | None = None, + _init_kwargs: dict[str, Any] | None = None, + ) -> tuple[tuple[PydanticBaseSettingsSource, ...], dict[str, Any]]: + # Determine settings config values + case_sensitive = _case_sensitive if _case_sensitive is not None else cls.model_config.get('case_sensitive') + env_prefix = _env_prefix if _env_prefix is not None else cls.model_config.get('env_prefix') + env_prefix_target = ( + _env_prefix_target if _env_prefix_target is not None else cls.model_config.get('env_prefix_target') + ) + nested_model_default_partial_update = ( + _nested_model_default_partial_update + if _nested_model_default_partial_update is not None + else cls.model_config.get('nested_model_default_partial_update') + ) + env_file = _env_file if _env_file != ENV_FILE_SENTINEL else cls.model_config.get('env_file') + env_file_encoding = ( + _env_file_encoding if _env_file_encoding is not None else cls.model_config.get('env_file_encoding') + ) + env_ignore_empty = ( + _env_ignore_empty if _env_ignore_empty is not None else cls.model_config.get('env_ignore_empty') + ) + env_nested_delimiter = ( + _env_nested_delimiter if _env_nested_delimiter is not None else cls.model_config.get('env_nested_delimiter') + ) + env_nested_max_split = ( + _env_nested_max_split if _env_nested_max_split is not None else cls.model_config.get('env_nested_max_split') + ) + env_parse_none_str = ( + _env_parse_none_str if _env_parse_none_str is not None else cls.model_config.get('env_parse_none_str') + ) + env_parse_enums = _env_parse_enums if _env_parse_enums is not None else cls.model_config.get('env_parse_enums') + + cli_prog_name = _cli_prog_name if _cli_prog_name is not None else cls.model_config.get('cli_prog_name') + cli_parse_args = _cli_parse_args if _cli_parse_args is not None else cls.model_config.get('cli_parse_args') + cli_settings_source = ( + _cli_settings_source if _cli_settings_source is not None else cls.model_config.get('cli_settings_source') + ) + cli_parse_none_str = ( + _cli_parse_none_str if _cli_parse_none_str is not None else cls.model_config.get('cli_parse_none_str') + ) + cli_parse_none_str = cli_parse_none_str if not env_parse_none_str else env_parse_none_str + cli_hide_none_type = ( + _cli_hide_none_type if _cli_hide_none_type is not None else cls.model_config.get('cli_hide_none_type') + ) + cli_avoid_json = _cli_avoid_json if _cli_avoid_json is not None else cls.model_config.get('cli_avoid_json') + cli_enforce_required = ( + _cli_enforce_required if _cli_enforce_required is not None else cls.model_config.get('cli_enforce_required') + ) + cli_use_class_docs_for_groups = ( + _cli_use_class_docs_for_groups + if _cli_use_class_docs_for_groups is not None + else cls.model_config.get('cli_use_class_docs_for_groups') + ) + cli_show_env_vars = ( + _cli_show_env_vars if _cli_show_env_vars is not None else cls.model_config.get('cli_show_env_vars') + ) + cli_exit_on_error = ( + _cli_exit_on_error if _cli_exit_on_error is not None else cls.model_config.get('cli_exit_on_error') + ) + cli_prefix = _cli_prefix if _cli_prefix is not None else cls.model_config.get('cli_prefix') + cli_flag_prefix_char = ( + _cli_flag_prefix_char if _cli_flag_prefix_char is not None else cls.model_config.get('cli_flag_prefix_char') + ) + cli_implicit_flags = ( + _cli_implicit_flags if _cli_implicit_flags is not None else cls.model_config.get('cli_implicit_flags') + ) + cli_ignore_unknown_args = ( + _cli_ignore_unknown_args + if _cli_ignore_unknown_args is not None + else cls.model_config.get('cli_ignore_unknown_args') + ) + cli_kebab_case = _cli_kebab_case if _cli_kebab_case is not None else cls.model_config.get('cli_kebab_case') + cli_shortcuts = _cli_shortcuts if _cli_shortcuts is not None else cls.model_config.get('cli_shortcuts') + + secrets_dir = _secrets_dir if _secrets_dir is not None else cls.model_config.get('secrets_dir') + + # Configure built-in sources, sharing the same init state so that incomplete + # fields are only warned about once per settings resolution. + init_state: InitState = {'field_info_ids': set()} + default_settings = DefaultSettingsSource( + cls, nested_model_default_partial_update=nested_model_default_partial_update, _init_state=init_state + ) + init_settings = InitSettingsSource( + cls, + init_kwargs=_init_kwargs if _init_kwargs is not None else {}, + nested_model_default_partial_update=nested_model_default_partial_update, + _init_state=default_settings._init_state, + ) + env_settings = EnvSettingsSource( + cls, + case_sensitive=case_sensitive, + env_prefix=env_prefix, + env_prefix_target=env_prefix_target, + env_nested_delimiter=env_nested_delimiter, + env_nested_max_split=env_nested_max_split, + env_ignore_empty=env_ignore_empty, + env_parse_none_str=env_parse_none_str, + env_parse_enums=env_parse_enums, + _init_state=init_settings._init_state, + ) + dotenv_settings = DotEnvSettingsSource( + cls, + env_file=env_file, + env_file_encoding=env_file_encoding, + case_sensitive=case_sensitive, + env_prefix=env_prefix, + env_prefix_target=env_prefix_target, + env_nested_delimiter=env_nested_delimiter, + env_nested_max_split=env_nested_max_split, + env_ignore_empty=env_ignore_empty, + env_parse_none_str=env_parse_none_str, + env_parse_enums=env_parse_enums, + _init_state=env_settings._init_state, + ) + + file_secret_settings = SecretsSettingsSource( + cls, + secrets_dir=secrets_dir, + case_sensitive=case_sensitive, + env_prefix=env_prefix, + env_prefix_target=env_prefix_target, + _init_state=dotenv_settings._init_state, + ) + # Provide a hook to set built-in sources priority and add / remove sources + sources = cls.settings_customise_sources( + cls, + init_settings=init_settings, + env_settings=env_settings, + dotenv_settings=dotenv_settings, + file_secret_settings=file_secret_settings, + ) + (default_settings,) + custom_cli_sources = [source for source in sources if isinstance(source, CliSettingsSource)] + if not any(custom_cli_sources): + if isinstance(cli_settings_source, CliSettingsSource): + sources = (cli_settings_source,) + sources + elif cli_parse_args is not None: + cli_settings = CliSettingsSource[Any]( + cls, + _init_state=file_secret_settings._init_state, + cli_prog_name=cli_prog_name, + cli_parse_args=cli_parse_args, + cli_parse_none_str=cli_parse_none_str, + cli_hide_none_type=cli_hide_none_type, + cli_avoid_json=cli_avoid_json, + cli_enforce_required=cli_enforce_required, + cli_use_class_docs_for_groups=cli_use_class_docs_for_groups, + cli_show_env_vars=cli_show_env_vars, + cli_exit_on_error=cli_exit_on_error, + cli_prefix=cli_prefix, + cli_flag_prefix_char=cli_flag_prefix_char, + cli_implicit_flags=cli_implicit_flags, + cli_ignore_unknown_args=cli_ignore_unknown_args, + cli_kebab_case=cli_kebab_case, + cli_shortcuts=cli_shortcuts, + case_sensitive=case_sensitive, + _env_settings_source=env_settings, + ) + sources = (cli_settings,) + sources + # We ensure that if command line arguments haven't been parsed yet, we do so. + elif cli_parse_args not in (None, False) and not custom_cli_sources[0].env_vars: + custom_cli_sources[0](args=cli_parse_args) + + cls._settings_warn_unused_config_keys(sources, cls.model_config) + + return sources, _init_kwargs if _init_kwargs is not None else {} + + @classmethod + def _settings_build_values( + cls, sources: tuple[PydanticBaseSettingsSource, ...], init_kwargs: dict[str, Any] + ) -> dict[str, Any]: + if sources: + state: dict[str, Any] = {} + defaults: dict[str, Any] = {} + states: dict[str, dict[str, Any]] = {} + for source in sources: + if isinstance(source, PydanticBaseSettingsSource): + source._set_current_state(state) + source._set_settings_sources_data(states) + + source_name = source.__name__ if hasattr(source, '__name__') else type(source).__name__ + source_state = source() + + if isinstance(source, DefaultSettingsSource): + defaults = source_state + + states[source_name] = source_state + state = deep_update(source_state, state) + + # Strip any default values not explicitly set before returning final state + state = {key: val for key, val in state.items() if key not in defaults or defaults[key] != val} + + if _settings_debug_enabled() and logger.isEnabledFor(logging.DEBUG): + cls._settings_log_debug(states) + # The last source is the `DefaultSettingsSource` instance created in `_settings_init_sources()`, + # holding the init state shared by all built-in sources: + last_source = sources[-1] + init_state = last_source._init_state if isinstance(last_source, PydanticBaseSettingsSource) else InitState() + cls._settings_restore_init_kwarg_names(cls, init_kwargs, state, init_state) + + return state + else: + # no one should mean to do this, but I think returning an empty dict is marginally preferable + # to an informative error and much better than a confusing error + return {} + + @classmethod + def _settings_log_debug(cls, states: dict[str, dict[str, Any]]) -> None: + """Log the data collected by each settings source in priority order. + + Enabled by setting the ``PYDANTIC_SETTINGS_DEBUG`` environment variable to a truthy value. + This is emitted at ``DEBUG`` level on the ``pydantic_settings`` logger. + + Warning: the output may contain sensitive values loaded from the environment, dotenv + files, or secret files. Only enable it in a trusted debugging context. + """ + lines = [f'Resolving settings for {cls.__name__!r} (sources in priority order, highest first):'] + for name, source_state in states.items(): + lines.append(f' {name}: {source_state!r}') + logger.debug('\n'.join(lines)) + + @staticmethod + def _settings_restore_init_kwarg_names( + settings_cls: type[BaseSettings], + init_kwargs: dict[str, Any], + state: dict[str, Any], + init_state: InitState, + ) -> None: + """ + Restore the init_kwarg key names to the final merged state dictionary. + + This function renames keys in state to match the original init_kwargs key names, + preserving the merged values from the source priority order. + """ + if init_kwargs and state: + state_kwarg_names = set(state.keys()) + init_kwarg_names = set(init_kwargs.keys()) + for field_name, field_info in settings_cls.model_fields.items(): + _warn_if_field_info_incomplete(field_info, field_name, init_state) + alias_names, *_ = _get_alias_names(field_name, field_info) + matchable_names = set(alias_names) + include_name = settings_cls.model_config.get( + 'populate_by_name', False + ) or settings_cls.model_config.get('validate_by_name', False) + if include_name: + matchable_names.add(field_name) + init_kwarg_name = init_kwarg_names & matchable_names + state_kwarg_name = state_kwarg_names & matchable_names + if init_kwarg_name and state_kwarg_name: + # Use deterministic selection for both keys. + # Target key: the key from init_kwargs that should be used in the final state. + target_key = next(iter(init_kwarg_name)) + # Source key: prefer the alias (first in alias_names) if present in state, + # as InitSettingsSource normalizes to the preferred alias. + # This ensures we get the highest-priority value for this field. + source_key = None + for alias in alias_names: + if alias in state_kwarg_name: + source_key = alias + break + if source_key is None: + # Fall back to field_name if no alias found in state + source_key = field_name if field_name in state_kwarg_name else next(iter(state_kwarg_name)) + # Get the value from the source key and remove all matching keys + value = state.pop(source_key) + for key in state_kwarg_name - {source_key}: + state.pop(key, None) + state[target_key] = value + + @staticmethod + def _settings_warn_unused_config_keys(sources: tuple[object, ...], model_config: SettingsConfigDict) -> None: + """ + Warns if any values in model_config were set but the corresponding settings source has not been initialised. + + The list alternative sources and their config keys can be found here: + https://docs.pydantic.dev/latest/concepts/pydantic_settings/#other-settings-source + + Args: + sources: The tuple of configured sources + model_config: The model config to check for unused config keys + """ + + def warn_if_not_used(source_type: type[PydanticBaseSettingsSource], keys: tuple[str, ...]) -> None: + if not any(isinstance(source, source_type) for source in sources): + for key in keys: + if model_config.get(key) is not None: + warnings.warn( + f'Config key `{key}` is set in model_config but will be ignored because no ' + f'{source_type.__name__} source is configured. To use this config key, add a ' + f'{source_type.__name__} source to the settings sources via the ' + 'settings_customise_sources hook.', + UserWarning, + stacklevel=3, + ) + + warn_if_not_used(JsonConfigSettingsSource, ('json_file', 'json_file_encoding')) + warn_if_not_used(PyprojectTomlConfigSettingsSource, ('pyproject_toml_depth', 'pyproject_toml_table_header')) + warn_if_not_used(TomlConfigSettingsSource, ('toml_file', 'toml_table_header')) + warn_if_not_used(YamlConfigSettingsSource, ('yaml_file', 'yaml_file_encoding', 'yaml_config_section')) + + model_config: ClassVar[SettingsConfigDict] = SettingsConfigDict( + extra='forbid', + arbitrary_types_allowed=True, + validate_default=True, + case_sensitive=False, + env_prefix='', + env_prefix_target='variable', + nested_model_default_partial_update=False, + env_file=None, + env_file_encoding=None, + env_ignore_empty=False, + env_nested_delimiter=None, + env_nested_max_split=None, + env_parse_none_str=None, + env_parse_enums=None, + cli_prog_name=None, + cli_parse_args=None, + cli_parse_none_str=None, + cli_hide_none_type=False, + cli_avoid_json=False, + cli_enforce_required=False, + cli_use_class_docs_for_groups=False, + cli_show_env_vars=False, + cli_exit_on_error=True, + cli_prefix='', + cli_flag_prefix_char='-', + cli_implicit_flags=False, + cli_ignore_unknown_args=False, + cli_kebab_case=False, + cli_shortcuts=None, + json_file=None, + json_file_encoding=None, + yaml_file=None, + yaml_file_encoding=None, + yaml_config_section=None, + toml_file=None, + secrets_dir=None, + protected_namespaces=('model_validate', 'model_dump', 'settings_customise_sources'), + enable_decoding=True, + ) + + +class CliApp: + """ + A utility class for running Pydantic `BaseSettings`, `BaseModel`, or `pydantic.dataclasses.dataclass` as + CLI applications. + """ + + _subcommand_stack: ClassVar[dict[int, tuple[CliSettingsSource[Any], Any, str]]] = {} + _ansi_color: ClassVar[re.Pattern[str]] = re.compile(r'\x1b\[[0-9;]*m') + + @staticmethod + def _get_base_settings_cls(model_cls: type[Any]) -> type[BaseSettings]: + if issubclass(model_cls, BaseSettings): + return model_cls + + class CliAppBaseSettings(BaseSettings, model_cls): # type: ignore + __doc__ = model_cls.__doc__ + model_config = SettingsConfigDict( + nested_model_default_partial_update=True, + case_sensitive=True, + cli_hide_none_type=True, + cli_avoid_json=True, + cli_enforce_required=True, + cli_implicit_flags=True, + cli_kebab_case=True, + ) + + return CliAppBaseSettings + + @staticmethod + def _run_cli_cmd(model: Any, cli_cmd_method_name: str, is_required: bool) -> Any: + command = getattr(type(model), cli_cmd_method_name, None) + if command is None: + if is_required: + raise SettingsError(f'Error: {type(model).__name__} class is missing {cli_cmd_method_name} entrypoint') + return model + + # If the method is asynchronous, we handle its execution based on the current event loop status. + if inspect.iscoroutinefunction(command): + # For asynchronous methods, we have two execution scenarios: + # 1. If no event loop is running in the current thread, run the coroutine directly with asyncio.run(). + # 2. If an event loop is already running in the current thread, run the coroutine in a separate thread to avoid conflicts. + try: + # Check if an event loop is currently running in this thread. + loop = asyncio.get_running_loop() + except RuntimeError: + loop = None + + if loop and loop.is_running(): + # We're in a context with an active event loop (e.g., Jupyter Notebook). + # Running asyncio.run() here would cause conflicts, so we use a separate thread. + exception_container = [] + + def run_coro() -> None: + try: + # Execute the coroutine in a new event loop in this separate thread. + asyncio.run(command(model)) + except Exception as e: + exception_container.append(e) + + thread = threading.Thread(target=run_coro) + thread.start() + thread.join() + if exception_container: + # Propagate exceptions from the separate thread. + raise exception_container[0] + else: + # No event loop is running; safe to run the coroutine directly. + asyncio.run(command(model)) + else: + # For synchronous methods, call them directly. + command(model) + + return model + + @staticmethod + def run( + model_cls: type[T], + cli_args: list[str] | Namespace | SimpleNamespace | dict[str, Any] | None = None, + cli_settings_source: CliSettingsSource[Any] | None = None, + cli_exit_on_error: bool | None = None, + cli_show_env_vars: bool | None = None, + cli_cmd_method_name: str = 'cli_cmd', + **model_init_data: Any, + ) -> T: + """ + Runs a Pydantic `BaseSettings`, `BaseModel`, or `pydantic.dataclasses.dataclass` as a CLI application. + Running a model as a CLI application requires the `cli_cmd` method to be defined in the model class. + + Args: + model_cls: The model class to run as a CLI application. + cli_args: The list of CLI arguments to parse. If `cli_settings_source` is specified, this may + also be a namespace or dictionary of pre-parsed CLI arguments. Defaults to `sys.argv[1:]`. + cli_settings_source: Override the default CLI settings source with a user defined instance. + Defaults to `None`. + cli_exit_on_error: Determines whether this function exits on error. If model is subclass of + `BaseSettings`, defaults to BaseSettings `cli_exit_on_error` value. Otherwise, defaults to + `True`. + cli_show_env_vars: Show resolved environment variable names in CLI help text. Defaults to `False`. + cli_cmd_method_name: The CLI command method name to run. Defaults to "cli_cmd". + model_init_data: The model init data. + + Returns: + The ran instance of model. + + Raises: + SettingsError: If model_cls is not subclass of `BaseModel` or `pydantic.dataclasses.dataclass`. + SettingsError: If model_cls does not have a `cli_cmd` entrypoint defined. + """ + + if not (is_pydantic_dataclass(model_cls) or is_model_class(model_cls)): + raise SettingsError( + f'Error: {model_cls.__name__} is not subclass of BaseModel or pydantic.dataclasses.dataclass' + ) + + cli_settings = None + cli_parse_args = True if cli_args is None else cli_args + if cli_settings_source is not None: + if isinstance(cli_parse_args, (Namespace, SimpleNamespace, dict)): + cli_settings = cli_settings_source(parsed_args=cli_parse_args) + else: + cli_settings = cli_settings_source(args=cli_parse_args) + elif isinstance(cli_parse_args, (Namespace, SimpleNamespace, dict)): + raise SettingsError('Error: `cli_args` must be list[str] or None when `cli_settings_source` is not used') + + if not issubclass(model_cls, BaseSettings): + base_settings_cls = CliApp._get_base_settings_cls(model_cls) + sources, init_kwargs = base_settings_cls._settings_init_sources( + _cli_parse_args=cli_parse_args, # type: ignore[arg-type] + _cli_exit_on_error=cli_exit_on_error, + _cli_show_env_vars=cli_show_env_vars, + _cli_settings_source=cli_settings, + _init_kwargs=model_init_data, + ) + model = base_settings_cls(**base_settings_cls._settings_build_values(sources, init_kwargs)) + model_init_data = {} + for field_name, field_info in base_settings_cls.model_fields.items(): + model_init_data[_field_name_for_signature(field_name, field_info)] = getattr(model, field_name) + command = model_cls(**model_init_data) + else: + sources, init_kwargs = model_cls._settings_init_sources( + _cli_parse_args=cli_parse_args, # type: ignore[arg-type] + _cli_exit_on_error=cli_exit_on_error, + _cli_show_env_vars=cli_show_env_vars, + _cli_settings_source=cli_settings, + _init_kwargs=model_init_data, + ) + command = model_cls(_build_sources=(sources, init_kwargs)) + + subcommand_dest = ':subcommand' + cli_settings_source = next(source for source in sources if isinstance(source, CliSettingsSource)) + CliApp._subcommand_stack[id(command)] = (cli_settings_source, cli_settings_source.root_parser, subcommand_dest) + try: + data_model = CliApp._run_cli_cmd(command, cli_cmd_method_name, is_required=False) + finally: + del CliApp._subcommand_stack[id(command)] + return data_model + + @staticmethod + def run_subcommand( + model: PydanticModel, + cli_exit_on_error: bool | None = None, + cli_show_env_vars: bool | None = None, + cli_cmd_method_name: str = 'cli_cmd', + ) -> PydanticModel: + """ + Runs the model subcommand. Running a model subcommand requires the `cli_cmd` method to be defined in + the nested model subcommand class. + + Args: + model: The model to run the subcommand from. + cli_exit_on_error: Determines whether this function exits with error if no subcommand is found. + Defaults to model_config `cli_exit_on_error` value if set. Otherwise, defaults to `True`. + cli_show_env_vars: Show resolved environment variable names in CLI help text. Defaults to `False`. + cli_cmd_method_name: The CLI command method name to run. Defaults to "cli_cmd". + + Returns: + The ran subcommand model. + + Raises: + SystemExit: When no subcommand is found and cli_exit_on_error=`True` (the default). + SettingsError: When no subcommand is found and cli_exit_on_error=`False`. + """ + + if id(model) in CliApp._subcommand_stack: + cli_settings_source, parser, subcommand_dest = CliApp._subcommand_stack[id(model)] + else: + cli_settings_source = CliSettingsSource[Any]( + CliApp._get_base_settings_cls(type(model)), + cli_show_env_vars=cli_show_env_vars, + ) + parser = cli_settings_source.root_parser + subcommand_dest = ':subcommand' + + cli_exit_on_error = cli_settings_source.cli_exit_on_error if cli_exit_on_error is None else cli_exit_on_error + + errors: list[SettingsError | SystemExit] = [] + subcommand = get_subcommand( + model, is_required=True, cli_exit_on_error=cli_exit_on_error, _suppress_errors=errors + ) + if errors: + err = errors[0] + if err.__context__ is None and err.__cause__ is None and cli_settings_source._format_help is not None: + error_message = f'{err}\n{cli_settings_source._format_help(parser)}' + raise type(err)(error_message) from None + else: + raise err + + subcommand_cls = cast(type[BaseModel], type(subcommand)) + subcommand_arg = cli_settings_source._parser_map[subcommand_dest][subcommand_cls] + subcommand_dest = f'{subcommand_arg.dest}.:subcommand' + subcommand_parser = subcommand_arg.parser + CliApp._subcommand_stack[id(subcommand)] = (cli_settings_source, subcommand_parser, subcommand_dest) + try: + data_model = CliApp._run_cli_cmd(subcommand, cli_cmd_method_name, is_required=True) + finally: + del CliApp._subcommand_stack[id(subcommand)] + return data_model + + @staticmethod + def serialize( + model: PydanticModel, + list_style: Literal['json', 'argparse', 'lazy'] = 'json', + dict_style: Literal['json', 'env'] = 'json', + positionals_first: bool = False, + ) -> list[str]: + """ + Serializes the CLI arguments for a Pydantic data model. + + Args: + model: The data model to serialize. + list_style: + Controls how list-valued fields are serialized on the command line. + - 'json' (default): + Lists are encoded as a single JSON array. + Example: `--tags '["a","b","c"]'` + - 'argparse': + Each list element becomes its own repeated flag, following + typical `argparse` conventions. + Example: `--tags a --tags b --tags c` + - 'lazy': + Lists are emitted as a single comma-separated string without JSON + quoting or escaping. + Example: `--tags a,b,c` + dict_style: + Controls how dictionary-valued fields are serialized. + - 'json' (default): + The entire dictionary is emitted as a single JSON object. + Example: `--config '{"host": "localhost", "port": 5432}'` + - 'env': + The dictionary is flattened into multiple CLI flags using + environment-variable-style assignment. + Example: `--config host=localhost --config port=5432` + positionals_first: Controls whether positional arguments should be serialized + first compared to optional arguments. Defaults to `False`. + + Returns: + The serialized CLI arguments for the data model. + """ + + base_settings_cls = CliApp._get_base_settings_cls(type(model)) + serialized_args = CliSettingsSource[Any](base_settings_cls)._serialized_args( + model, + list_style=list_style, + dict_style=dict_style, + positionals_first=positionals_first, + ) + return CliSettingsSource._flatten_serialized_args(serialized_args, positionals_first) + + @staticmethod + def format_help( + model: PydanticModel | type[T], + cli_settings_source: CliSettingsSource[Any] | None = None, + strip_ansi_color: bool = False, + ) -> str: + """ + Return a string containing a help message for a Pydantic model. + + Args: + model: The model or model class. + cli_settings_source: Override the default CLI settings source with a user defined instance. + Defaults to `None`. + strip_ansi_color: Strips ANSI color codes from the help message when set to `True`. + + Returns: + The help message string for the model. + """ + model_cls = model if isinstance(model, type) else type(model) + if cli_settings_source is None: + if not isinstance(model, type) and id(model) in CliApp._subcommand_stack: + cli_settings_source, *_ = CliApp._subcommand_stack[id(model)] + else: + cli_settings_source = CliSettingsSource(CliApp._get_base_settings_cls(model_cls)) + help_message = cli_settings_source._format_help(cli_settings_source.root_parser) + return help_message if not strip_ansi_color else CliApp._ansi_color.sub('', help_message) + + @staticmethod + def print_help( + model: PydanticModel | type[T], + cli_settings_source: CliSettingsSource[Any] | None = None, + file: TextIO | None = None, + strip_ansi_color: bool = False, + ) -> None: + """ + Print a help message for a Pydantic model. + + Args: + model: The model or model class. + cli_settings_source: Override the default CLI settings source with a user defined instance. + Defaults to `None`. + file: A text stream to which the help message is written. If `None`, the output is sent to sys.stdout. + strip_ansi_color: Strips ANSI color codes from the help message when set to `True`. + """ + print( + CliApp.format_help( + model, + cli_settings_source=cli_settings_source, + strip_ansi_color=strip_ansi_color, + ), + file=file, + ) diff --git a/source/target-vendors/cp312/pydantic_settings/py.typed b/source/target-vendors/cp312/pydantic_settings/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/pydantic_settings/sources/__init__.py b/source/target-vendors/cp312/pydantic_settings/sources/__init__.py new file mode 100644 index 0000000..a9afe6e --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/__init__.py @@ -0,0 +1,88 @@ +"""Package for handling configuration sources in pydantic-settings.""" + +from .base import ( + ConfigFileSourceMixin, + DefaultSettingsSource, + InitSettingsSource, + PydanticBaseEnvSettingsSource, + PydanticBaseSettingsSource, + get_subcommand, +) +from .providers.aws import AWSSecretsManagerSettingsSource +from .providers.azure import AzureKeyVaultSettingsSource +from .providers.cli import ( + CLI_SUPPRESS, + CliDualFlag, + CliExplicitFlag, + CliImplicitFlag, + CliMutuallyExclusiveGroup, + CliPositionalArg, + CliSettingsSource, + CliSubCommand, + CliSuppress, + CliToggleFlag, + CliUnknownArgs, +) +from .providers.dotenv import DotEnvSettingsSource, read_env_file +from .providers.env import EnvSettingsSource +from .providers.gcp import GoogleSecretManagerSettingsSource +from .providers.json import JsonConfigSettingsSource +from .providers.nested_secrets import NestedSecretsSettingsSource +from .providers.pyproject import PyprojectTomlConfigSettingsSource +from .providers.secrets import SecretsSettingsSource +from .providers.toml import TomlConfigSettingsSource +from .providers.yaml import YamlConfigSettingsSource +from .types import ( + DEFAULT_PATH, + ENV_FILE_SENTINEL, + ConfigFileSourceType, + DotenvFiltering, + DotenvType, + EnvPrefixTarget, + ForceDecode, + NoDecode, + PathType, + PydanticModel, +) + +__all__ = [ + 'CLI_SUPPRESS', + 'DEFAULT_PATH', + 'ENV_FILE_SENTINEL', + 'AWSSecretsManagerSettingsSource', + 'AzureKeyVaultSettingsSource', + 'CliDualFlag', + 'CliExplicitFlag', + 'CliImplicitFlag', + 'CliMutuallyExclusiveGroup', + 'CliPositionalArg', + 'CliSettingsSource', + 'CliSubCommand', + 'CliSuppress', + 'CliToggleFlag', + 'CliUnknownArgs', + 'ConfigFileSourceMixin', + 'ConfigFileSourceType', + 'DefaultSettingsSource', + 'DotEnvSettingsSource', + 'DotenvFiltering', + 'DotenvType', + 'EnvPrefixTarget', + 'EnvSettingsSource', + 'ForceDecode', + 'GoogleSecretManagerSettingsSource', + 'InitSettingsSource', + 'JsonConfigSettingsSource', + 'NestedSecretsSettingsSource', + 'NoDecode', + 'PathType', + 'PydanticBaseEnvSettingsSource', + 'PydanticBaseSettingsSource', + 'PydanticModel', + 'PyprojectTomlConfigSettingsSource', + 'SecretsSettingsSource', + 'TomlConfigSettingsSource', + 'YamlConfigSettingsSource', + 'get_subcommand', + 'read_env_file', +] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/base.py b/source/target-vendors/cp312/pydantic_settings/sources/base.py new file mode 100644 index 0000000..9d73d14 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/base.py @@ -0,0 +1,639 @@ +"""Base classes and core functionality for pydantic-settings sources.""" + +from __future__ import annotations as _annotations + +import json +from abc import ABC, abstractmethod +from collections.abc import Sequence +from dataclasses import asdict, is_dataclass +from pathlib import Path +from typing import TYPE_CHECKING, Any, cast, get_args + +from pydantic import AliasChoices, AliasPath, BaseModel, TypeAdapter +from pydantic._internal._typing_extra import ( # type: ignore[attr-defined] + get_origin, +) +from pydantic._internal._utils import deep_update, is_model_class +from pydantic.fields import FieldInfo +from typing_inspection.introspection import is_union_origin + +from ..exceptions import SettingsError +from ..utils import _lenient_issubclass +from .types import ( + ConfigFileSourceType, + EnvNoneType, + EnvPrefixTarget, + ForceDecode, + NoDecode, + PydanticModel, + _CliSubCommand, +) +from .utils import ( + InitState, + _annotation_is_complex, + _get_alias_names, + _get_field_metadata, + _get_model_fields, + _resolve_type_alias, + _strip_annotated, + _union_is_complex, + _warn_if_field_info_incomplete, +) + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + from .types import Traversable + + +def get_subcommand( + model: PydanticModel, + is_required: bool = True, + cli_exit_on_error: bool | None = None, + _suppress_errors: list[SettingsError | SystemExit] | None = None, +) -> PydanticModel | None: + """ + Get the subcommand from a model. + + Args: + model: The model to get the subcommand from. + is_required: Determines whether a model must have subcommand set and raises error if not + found. Defaults to `True`. + cli_exit_on_error: Determines whether this function exits with error if no subcommand is found. + Defaults to model_config `cli_exit_on_error` value if set. Otherwise, defaults to `True`. + + Returns: + The subcommand model if found, otherwise `None`. + + Raises: + SystemExit: When no subcommand is found and is_required=`True` and cli_exit_on_error=`True` + (the default). + SettingsError: When no subcommand is found and is_required=`True` and + cli_exit_on_error=`False`. + """ + + model_cls = type(model) + if cli_exit_on_error is None and is_model_class(model_cls): + model_default = model_cls.model_config.get('cli_exit_on_error') + if isinstance(model_default, bool): + cli_exit_on_error = model_default + if cli_exit_on_error is None: + cli_exit_on_error = True + + subcommands: list[str] = [] + for field_name, field_info in _get_model_fields(model_cls).items(): + if _CliSubCommand in field_info.metadata: + if getattr(model, field_name) is not None: + return getattr(model, field_name) + subcommands.append(field_name) + # TODO: we could warn if no sub command was found and one of `field_info`s + # isn't complete. + + if is_required: + error_message = ( + f'Error: CLI subcommand is required {{{", ".join(subcommands)}}}' + if subcommands + else 'Error: CLI subcommand is required but no subcommands were found.' + ) + err = SystemExit(error_message) if cli_exit_on_error else SettingsError(error_message) + if _suppress_errors is None: + raise err + _suppress_errors.append(err) + + return None + + +class PydanticBaseSettingsSource(ABC): + """ + Abstract base class for settings sources, every settings source classes should inherit from it. + """ + + def __init__(self, settings_cls: type[BaseSettings], _init_state: InitState | None = None): + self._init_state: InitState = {} if _init_state is None else _init_state + self.settings_cls = settings_cls + self.config = settings_cls.model_config + self._current_state: dict[str, Any] = {} + self._settings_sources_data: dict[str, dict[str, Any]] = {} + + def _set_current_state(self, state: dict[str, Any]) -> None: + """ + Record the state of settings from the previous settings sources. This should + be called right before __call__. + """ + self._current_state = state + + def _set_settings_sources_data(self, states: dict[str, dict[str, Any]]) -> None: + """ + Record the state of settings from all previous settings sources. This should + be called right before __call__. + """ + self._settings_sources_data = states + + @property + def current_state(self) -> dict[str, Any]: + """ + The current state of the settings, populated by the previous settings sources. + """ + return self._current_state + + @property + def settings_sources_data(self) -> dict[str, dict[str, Any]]: + """ + The state of all previous settings sources. + """ + return self._settings_sources_data + + @abstractmethod + def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + """ + Gets the value, the key for model creation, and a flag to determine whether value is complex. + + This is an abstract method that should be overridden in every settings source classes. + + Args: + field: The field. + field_name: The field name. + + Returns: + A tuple that contains the value, key and a flag to determine whether value is complex. + """ + + def field_is_complex(self, field: FieldInfo) -> bool: + """ + Checks whether a field is complex, in which case it will attempt to be parsed as JSON. + + Args: + field: The field. + + Returns: + Whether the field is complex. + """ + return _annotation_is_complex(field.annotation, field.metadata, self._init_state) + + def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any: + """ + Prepares the value of a field. + + Args: + field_name: The field name. + field: The field. + value: The value of the field that has to be prepared. + value_is_complex: A flag to determine whether value is complex. + + Returns: + The prepared value. + """ + if value is not None and (self.field_is_complex(field) or value_is_complex): + return self.decode_complex_value(field_name, field, value) + return value + + def decode_complex_value(self, field_name: str, field: FieldInfo, value: Any) -> Any: + """ + Decode the value for a complex field + + Args: + field_name: The field name. + field: The field. + value: The value of the field that has to be prepared. + + Returns: + The decoded value for further preparation + """ + if field and ( + NoDecode in _get_field_metadata(field) + or (self.config.get('enable_decoding') is False and ForceDecode not in field.metadata) + ): + return value + + return json.loads(value) + + @abstractmethod + def __call__(self) -> dict[str, Any]: + pass + + +class ConfigFileSourceMixin(ABC): + def _read_files(self, files: ConfigFileSourceType | None, deep_merge: bool = False) -> dict[str, Any]: + if files is None: + return {} + if not isinstance(files, Sequence) or isinstance(files, str): + files = [files] + vars: dict[str, Any] = {} + for file in files: + file_path: Path | Traversable = Path(file) if isinstance(file, str) else file + if isinstance(file_path, Path): + file_path = file_path.expanduser() + + if not file_path.is_file(): + continue + + updating_vars = self._read_file(file_path) + if deep_merge: + vars = deep_update(vars, updating_vars) + else: + vars.update(updating_vars) + return vars + + @abstractmethod + def _read_file(self, path: Path | Traversable) -> dict[str, Any]: + pass + + +def _unwrap_optional_annotation(annotation: Any) -> Any: + """Return the inner type of an ``Optional[T]`` annotation, otherwise the annotation unchanged.""" + if is_union_origin(get_origin(annotation)): + args = get_args(annotation) + if len(args) == 2 and type(None) in args: + for arg in args: + if arg is not type(None): + return arg + return annotation + + +def _has_discriminator(field_info: FieldInfo) -> bool: + """Check if a field uses a discriminated union (via Annotated or Field(discriminator=...)).""" + if field_info.discriminator is not None: + return True + from pydantic import Discriminator + + return any(isinstance(m, Discriminator) for m in field_info.metadata) + + +class DefaultSettingsSource(PydanticBaseSettingsSource): + """ + Source class for loading default object values. + + Args: + settings_cls: The Settings class. + nested_model_default_partial_update: Whether to allow partial updates on nested model default object fields. + Defaults to `False`. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + nested_model_default_partial_update: bool | None = None, + _init_state: InitState | None = None, + ): + super().__init__(settings_cls, _init_state) + self.defaults: dict[str, Any] = {} + self.nested_model_default_partial_update = ( + nested_model_default_partial_update + if nested_model_default_partial_update is not None + else self.config.get('nested_model_default_partial_update', False) + ) + if self.nested_model_default_partial_update: + for field_name, field_info in settings_cls.model_fields.items(): + _warn_if_field_info_incomplete(field_info, field_name, self._init_state) + if _has_discriminator(field_info): + continue + alias_names, *_ = _get_alias_names(field_name, field_info) + preferred_alias = alias_names[0] + if is_dataclass(type(field_info.default)): + self.defaults[preferred_alias] = asdict(field_info.default) + elif is_model_class(type(field_info.default)): + self.defaults[preferred_alias] = field_info.default.model_dump() + + def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + # Nothing to do here. Only implement the return statement to make mypy happy + return None, '', False + + def __call__(self) -> dict[str, Any]: + return self.defaults + + def __repr__(self) -> str: + return ( + f'{self.__class__.__name__}(nested_model_default_partial_update={self.nested_model_default_partial_update})' + ) + + +class InitSettingsSource(PydanticBaseSettingsSource): + """ + Source class for loading values provided during settings class initialization. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + init_kwargs: dict[str, Any], + nested_model_default_partial_update: bool | None = None, + _init_state: InitState | None = None, + ): + super().__init__(settings_cls, _init_state) + case_sensitive = self.config.get('case_sensitive', False) + include_name = self.config.get('populate_by_name', False) or self.config.get('validate_by_name', False) + + def normalize(name: str) -> str: + # When case_sensitive is False, matching is done on lower-cased names. + return name if case_sensitive else name.lower() + + self.init_kwargs = {} + init_kwarg_names = set(init_kwargs.keys()) + # Map each normalized name to all provided keys sharing it, so field aliases can + # be matched without losing the original key used to look up the value. A 1-to-many + # mapping is required because case_sensitive=False can collapse distinct keys + # (e.g. ``TeSt`` and ``TEST``) onto the same normalized name. + normalized_provided: dict[str, list[str]] = {} + for key in init_kwargs: + normalized_provided.setdefault(normalize(key), []).append(key) + for field_name, field_info in settings_cls.model_fields.items(): + _warn_if_field_info_incomplete(field_info, field_name, self._init_state) + # Canonical (case-preserving) alias names determine the output key, so the value + # still matches pydantic's validation aliases, which are always case-sensitive. + canonical_alias_names, *_ = _get_alias_names(field_name, field_info) + # Match alias names respect case_sensitive when matching against provided keys. + match_alias_names, *_ = _get_alias_names(field_name, field_info, case_sensitive=case_sensitive) + # When populate_by_name is True, allow using the field name as an input key, + # but normalize to the preferred alias to keep keys consistent across sources. + matchable_names = list(match_alias_names) + if include_name: + name = normalize(field_name) + if name not in matchable_names: + matchable_names.append(name) + # All provided keys matching this field, in matchable_names preference order + # (aliases first, then the field name). Only keys not yet consumed by an + # earlier field are considered. + matched_keys = [ + original + for name in matchable_names + if name in normalized_provided + for original in normalized_provided[name] + if original in init_kwarg_names + ] + if matched_keys: + preferred_alias = canonical_alias_names[0] if canonical_alias_names else field_name + # Prefer the first match in preference order; drop the remaining matches + # so they are not re-added as extras. + init_kwarg_names.difference_update(matched_keys) + self.init_kwargs[preferred_alias] = init_kwargs[matched_keys[0]] + # Include any remaining init kwargs (e.g., extras) unchanged + # Note: If populate_by_name is True and the provided key is the field name, but + # no alias exists, we keep it as-is so it can be processed as extra if allowed. + self.init_kwargs.update({key: val for key, val in init_kwargs.items() if key in init_kwarg_names}) + + self.nested_model_default_partial_update = ( + nested_model_default_partial_update + if nested_model_default_partial_update is not None + else self.config.get('nested_model_default_partial_update', False) + ) + + def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + # Nothing to do here. Only implement the return statement to make mypy happy + return None, '', False + + def __call__(self) -> dict[str, Any]: + return ( + TypeAdapter(dict[str, Any]).dump_python(self.init_kwargs) + if self.nested_model_default_partial_update + else self.init_kwargs + ) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(init_kwargs={self.init_kwargs!r})' + + +class PydanticBaseEnvSettingsSource(PydanticBaseSettingsSource): + def __init__( + self, + settings_cls: type[BaseSettings], + case_sensitive: bool | None = None, + env_prefix: str | None = None, + env_prefix_target: EnvPrefixTarget | None = None, + env_ignore_empty: bool | None = None, + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + _init_state: InitState | None = None, + ) -> None: + super().__init__(settings_cls, _init_state) + self.case_sensitive = case_sensitive if case_sensitive is not None else self.config.get('case_sensitive', False) + self.env_prefix = env_prefix if env_prefix is not None else self.config.get('env_prefix', '') + self.env_prefix_target = ( + env_prefix_target if env_prefix_target is not None else self.config.get('env_prefix_target', 'variable') + ) + self.env_ignore_empty = ( + env_ignore_empty if env_ignore_empty is not None else self.config.get('env_ignore_empty', False) + ) + self.env_parse_none_str = ( + env_parse_none_str if env_parse_none_str is not None else self.config.get('env_parse_none_str') + ) + self.env_parse_enums = env_parse_enums if env_parse_enums is not None else self.config.get('env_parse_enums') + + def _apply_case_sensitive(self, value: str) -> str: + return value.lower() if not self.case_sensitive else value + + def _extract_field_info(self, field: FieldInfo, field_name: str) -> list[tuple[str, str, bool]]: + """ + Extracts field info. This info is used to get the value of field from environment variables. + + It returns a list of tuples, each tuple contains: + * field_key: The key of field that has to be used in model creation. + * env_name: The environment variable name of the field. + * value_is_complex: A flag to determine whether the value from environment variable + is complex and has to be parsed. + + Args: + field (FieldInfo): The field. + field_name (str): The field name. + + Returns: + list[tuple[str, str, bool]]: List of tuples, each tuple contains field_key, env_name, and value_is_complex. + """ + _warn_if_field_info_incomplete(field, field_name, self._init_state) + field_info: list[tuple[str, str, bool]] = [] + if isinstance(field.validation_alias, (AliasChoices, AliasPath)): + v_alias: str | list[str | int] | list[list[str | int]] | None = field.validation_alias.convert_to_aliases() + else: + v_alias = field.validation_alias + + if v_alias: + env_prefix = self.env_prefix if self.env_prefix_target in ('alias', 'all') else '' + if isinstance(v_alias, list): # AliasChoices, AliasPath + for alias in v_alias: + if isinstance(alias, str): # AliasPath + field_info.append((alias, self._apply_case_sensitive(env_prefix + alias), len(alias) > 1)) + elif isinstance(alias, list): # AliasChoices + first_arg = cast(str, alias[0]) # first item of an AliasChoices must be a str + field_info.append( + ( + first_arg, + self._apply_case_sensitive(env_prefix + first_arg), + len(alias) > 1, + ) + ) + else: # string validation alias + field_info.append((v_alias, self._apply_case_sensitive(env_prefix + v_alias), False)) + + if not v_alias or self.config.get('populate_by_name', False) or self.config.get('validate_by_name', False): + annotation = _strip_annotated(_resolve_type_alias(field.annotation)) + env_prefix = self.env_prefix if self.env_prefix_target in ('variable', 'all') else '' + if is_union_origin(get_origin(annotation)) and _union_is_complex( + annotation, field.metadata, self._init_state + ): + field_info.append((field_name, self._apply_case_sensitive(env_prefix + field_name), True)) + else: + field_info.append((field_name, self._apply_case_sensitive(env_prefix + field_name), False)) + + return field_info + + def _replace_field_names_case_insensitively(self, field: FieldInfo, field_values: dict[str, Any]) -> dict[str, Any]: + """ + Replace field names in values dict by looking in models fields insensitively. + + By having the following models: + + ```py + class SubSubSub(BaseModel): + VaL3: str + + class SubSub(BaseModel): + Val2: str + SUB_sub_SuB: SubSubSub + + class Sub(BaseModel): + VAL1: str + SUB_sub: SubSub + + class Settings(BaseSettings): + nested: Sub + + model_config = SettingsConfigDict(env_nested_delimiter='__') + ``` + + Then: + _replace_field_names_case_insensitively( + field, + {"val1": "v1", "sub_SUB": {"VAL2": "v2", "sub_SUB_sUb": {"vAl3": "v3"}}} + ) + Returns {'VAL1': 'v1', 'SUB_sub': {'Val2': 'v2', 'SUB_sub_SuB': {'VaL3': 'v3'}}} + """ + values: dict[str, Any] = {} + + for name, value in field_values.items(): + sub_model_field: FieldInfo | None = None + + annotation = _unwrap_optional_annotation(field.annotation) + + # This is here to make mypy happy + # Item "None" of "Optional[Type[Any]]" has no attribute "model_fields" + if not annotation or not hasattr(annotation, 'model_fields'): + values[name] = value + continue + else: + model_fields: dict[str, FieldInfo] = annotation.model_fields + + # Find field in sub model by looking in fields case insensitively + field_key: str | None = None + for sub_model_field_name, sub_model_field in model_fields.items(): + _warn_if_field_info_incomplete(sub_model_field, sub_model_field_name, self._init_state) + aliases, _ = _get_alias_names(sub_model_field_name, sub_model_field) + _search = (alias for alias in aliases if alias.lower() == name.lower()) + if field_key := next(_search, None): + break + + if not field_key: + values[name] = value + continue + + if ( + sub_model_field is not None + and _lenient_issubclass(_unwrap_optional_annotation(sub_model_field.annotation), BaseModel) + and isinstance(value, dict) + ): + values[field_key] = self._replace_field_names_case_insensitively(sub_model_field, value) + else: + values[field_key] = value + + return values + + def _replace_env_none_type_values(self, field_value: dict[str, Any]) -> dict[str, Any]: + """ + Recursively parse values that are of "None" type(EnvNoneType) to `None` type(None). + """ + values: dict[str, Any] = {} + + for key, value in field_value.items(): + if not isinstance(value, EnvNoneType): + values[key] = value if not isinstance(value, dict) else self._replace_env_none_type_values(value) + else: + values[key] = None + + return values + + def _get_resolved_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + """ + Gets the value, the preferred alias key for model creation, and a flag to determine whether value + is complex. + + Note: + In V3, this method should either be made public, or, this method should be removed and the + abstract method get_field_value should be updated to include a "use_preferred_alias" flag. + + Args: + field: The field. + field_name: The field name. + + Returns: + A tuple that contains the value, preferred key and a flag to determine whether value is complex. + """ + field_value, field_key, value_is_complex = self.get_field_value(field, field_name) + if not ( + value_is_complex + or ( + (self.config.get('populate_by_name', False) or self.config.get('validate_by_name', False)) + and (field_key == field_name) + ) + ): + field_infos = self._extract_field_info(field, field_name) + preferred_key, _, preferred_is_complex = field_infos[0] + # Only normalize to preferred_key when it's a simple string alias. + # When the preferred key comes from an AliasPath (complex entry), skip normalization + # to avoid using the AliasPath's first element as the key (see #766). + if not preferred_is_complex: + return field_value, preferred_key, value_is_complex + return field_value, field_key, value_is_complex + + def __call__(self) -> dict[str, Any]: + data: dict[str, Any] = {} + + for field_name, field in self.settings_cls.model_fields.items(): + _warn_if_field_info_incomplete(field, field_name, self._init_state) + try: + field_value, field_key, value_is_complex = self._get_resolved_field_value(field, field_name) + except Exception as e: + raise SettingsError( + f'error getting value for field "{field_name}" from source "{self.__class__.__name__}"' + ) from e + + try: + field_value = self.prepare_field_value(field_name, field, field_value, value_is_complex) + except ValueError as e: + raise SettingsError( + f'error parsing value for field "{field_name}" from source "{self.__class__.__name__}"' + ) from e + + if field_value is not None: + if self.env_parse_none_str is not None: + if isinstance(field_value, dict): + field_value = self._replace_env_none_type_values(field_value) + elif isinstance(field_value, EnvNoneType): + field_value = None + if ( + not self.case_sensitive + # and _lenient_issubclass(field.annotation, BaseModel) + and isinstance(field_value, dict) + ): + data[field_key] = self._replace_field_names_case_insensitively(field, field_value) + else: + data[field_key] = field_value + + return data + + +__all__ = [ + 'ConfigFileSourceMixin', + 'DefaultSettingsSource', + 'InitSettingsSource', + 'PydanticBaseEnvSettingsSource', + 'PydanticBaseSettingsSource', + 'SettingsError', +] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/__init__.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/__init__.py new file mode 100644 index 0000000..b55a2ed --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/__init__.py @@ -0,0 +1,45 @@ +"""Package containing individual source implementations.""" + +from .aws import AWSSecretsManagerSettingsSource +from .azure import AzureKeyVaultSettingsSource +from .cli import ( + CliDualFlag, + CliExplicitFlag, + CliImplicitFlag, + CliMutuallyExclusiveGroup, + CliPositionalArg, + CliSettingsSource, + CliSubCommand, + CliSuppress, + CliToggleFlag, +) +from .dotenv import DotEnvSettingsSource +from .env import EnvSettingsSource +from .gcp import GoogleSecretManagerSettingsSource +from .json import JsonConfigSettingsSource +from .pyproject import PyprojectTomlConfigSettingsSource +from .secrets import SecretsSettingsSource +from .toml import TomlConfigSettingsSource +from .yaml import YamlConfigSettingsSource + +__all__ = [ + 'AWSSecretsManagerSettingsSource', + 'AzureKeyVaultSettingsSource', + 'CliDualFlag', + 'CliExplicitFlag', + 'CliImplicitFlag', + 'CliMutuallyExclusiveGroup', + 'CliPositionalArg', + 'CliSettingsSource', + 'CliSubCommand', + 'CliSuppress', + 'CliToggleFlag', + 'DotEnvSettingsSource', + 'EnvSettingsSource', + 'GoogleSecretManagerSettingsSource', + 'JsonConfigSettingsSource', + 'PyprojectTomlConfigSettingsSource', + 'SecretsSettingsSource', + 'TomlConfigSettingsSource', + 'YamlConfigSettingsSource', +] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/aws.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/aws.py new file mode 100644 index 0000000..848c2d0 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/aws.py @@ -0,0 +1,87 @@ +from __future__ import annotations as _annotations # important for BaseSettings import to work + +import json +from collections.abc import Mapping +from typing import TYPE_CHECKING + +from ..utils import InitState, parse_env_vars +from .env import EnvSettingsSource + +if TYPE_CHECKING: + from types_boto3_secretsmanager.client import SecretsManagerClient + + from pydantic_settings.main import BaseSettings + + +boto3_client = None + + +def import_aws_secrets_manager() -> None: + global boto3_client + + try: + from boto3 import client as boto3_client + except ImportError as e: # pragma: no cover + raise ImportError( + 'AWS Secrets Manager dependencies are not installed, run `pip install pydantic-settings[aws-secrets-manager]`' + ) from e + + +class AWSSecretsManagerSettingsSource(EnvSettingsSource): + _secret_id: str + _secretsmanager_client: SecretsManagerClient + + def __init__( + self, + settings_cls: type[BaseSettings], + secret_id: str, + region_name: str | None = None, + endpoint_url: str | None = None, + case_sensitive: bool | None = True, + env_prefix: str | None = None, + env_nested_delimiter: str | None = '--', + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + version_id: str | None = None, + _init_state: InitState | None = None, + ) -> None: + import_aws_secrets_manager() + self._secretsmanager_client = boto3_client('secretsmanager', region_name=region_name, endpoint_url=endpoint_url) # type: ignore + self._secret_id = secret_id + self._version_id = version_id + super().__init__( + settings_cls, + case_sensitive=case_sensitive, + env_prefix=env_prefix, + env_nested_delimiter=env_nested_delimiter, + env_ignore_empty=False, + env_parse_none_str=env_parse_none_str, + env_parse_enums=env_parse_enums, + _init_state=_init_state, + ) + + def _load_env_vars(self) -> Mapping[str, str | None]: + request = {'SecretId': self._secret_id} + + if self._version_id: + request['VersionId'] = self._version_id + + response = self._secretsmanager_client.get_secret_value(**request) + + return parse_env_vars( + json.loads(response['SecretString']), + self.case_sensitive, + self.env_ignore_empty, + self.env_parse_none_str, + ) + + def __repr__(self) -> str: + return ( + f'{self.__class__.__name__}(secret_id={self._secret_id!r}, ' + f'env_nested_delimiter={self.env_nested_delimiter!r})' + ) + + +__all__ = [ + 'AWSSecretsManagerSettingsSource', +] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/azure.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/azure.py new file mode 100644 index 0000000..7bda681 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/azure.py @@ -0,0 +1,162 @@ +"""Azure Key Vault settings source.""" + +from __future__ import annotations as _annotations + +from collections.abc import Iterator, Mapping +from typing import TYPE_CHECKING + +from pydantic.alias_generators import to_snake +from pydantic.fields import FieldInfo + +from ..utils import InitState +from .env import EnvSettingsSource + +if TYPE_CHECKING: + from azure.core.credentials import TokenCredential + from azure.core.exceptions import ResourceNotFoundError + from azure.keyvault.secrets import SecretClient + + from pydantic_settings.main import BaseSettings +else: + TokenCredential = None + ResourceNotFoundError = None + SecretClient = None + + +def import_azure_key_vault() -> None: + global TokenCredential + global SecretClient + global ResourceNotFoundError + + try: + from azure.core.credentials import TokenCredential + from azure.core.exceptions import ResourceNotFoundError + from azure.keyvault.secrets import SecretClient + except ImportError as e: # pragma: no cover + raise ImportError( + 'Azure Key Vault dependencies are not installed, run `pip install pydantic-settings[azure-key-vault]`' + ) from e + + +class AzureKeyVaultMapping(Mapping[str, str | None]): + _loaded_secrets: dict[str, str | None] + _secret_client: SecretClient + _secret_names: list[str] + + def __init__( + self, + secret_client: SecretClient, + case_sensitive: bool, + snake_case_conversion: bool, + env_prefix: str | None, + ) -> None: + self._loaded_secrets = {} + self._secret_client = secret_client + self._case_sensitive = case_sensitive + self._snake_case_conversion = snake_case_conversion + self._env_prefix = env_prefix if env_prefix else '' + self._secret_map: dict[str, str] = self._load_remote() + + def _load_remote(self) -> dict[str, str]: + secret_names: Iterator[str] = ( + secret.name for secret in self._secret_client.list_properties_of_secrets() if secret.name and secret.enabled + ) + + if self._snake_case_conversion: + name_map: dict[str, str] = {} + for name in secret_names: + if name.startswith(self._env_prefix): + name_map[f'{self._env_prefix}{to_snake(name[len(self._env_prefix) :])}'] = name + else: + name_map[to_snake(name)] = name + return name_map + + if self._case_sensitive: + return {name: name for name in secret_names} + + return {name.lower(): name for name in secret_names} + + def __getitem__(self, key: str) -> str | None: + new_key = key + + if self._snake_case_conversion: + if key.startswith(self._env_prefix): + new_key = f'{self._env_prefix}{to_snake(key[len(self._env_prefix) :])}' + else: + new_key = to_snake(key) + + elif not self._case_sensitive: + new_key = key.lower() + + if new_key not in self._loaded_secrets: + if new_key in self._secret_map: + self._loaded_secrets[new_key] = self._secret_client.get_secret(self._secret_map[new_key]).value + else: + raise KeyError(key) + + return self._loaded_secrets[new_key] + + def __len__(self) -> int: + return len(self._secret_map) + + def __iter__(self) -> Iterator[str]: + return iter(self._secret_map.keys()) + + +class AzureKeyVaultSettingsSource(EnvSettingsSource): + _url: str + _credential: TokenCredential + + def __init__( + self, + settings_cls: type[BaseSettings], + url: str, + credential: TokenCredential, + dash_to_underscore: bool = False, + case_sensitive: bool | None = None, + snake_case_conversion: bool = False, + env_prefix: str | None = None, + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + _init_state: InitState | None = None, + ) -> None: + import_azure_key_vault() + self._url = url + self._credential = credential + self._dash_to_underscore = dash_to_underscore + self._snake_case_conversion = snake_case_conversion + super().__init__( + settings_cls, + case_sensitive=True if snake_case_conversion else case_sensitive, + env_prefix=env_prefix, + env_nested_delimiter='__' if snake_case_conversion else '--', + env_ignore_empty=False, + env_parse_none_str=env_parse_none_str, + env_parse_enums=env_parse_enums, + _init_state=_init_state, + ) + + def _load_env_vars(self) -> Mapping[str, str | None]: + secret_client = SecretClient(vault_url=self._url, credential=self._credential) + return AzureKeyVaultMapping( + secret_client=secret_client, + case_sensitive=self.case_sensitive, + snake_case_conversion=self._snake_case_conversion, + env_prefix=self.env_prefix, + ) + + def _extract_field_info(self, field: FieldInfo, field_name: str) -> list[tuple[str, str, bool]]: + if self._snake_case_conversion: + field_info = [(x[0], x[1], x[2]) for x in super()._extract_field_info(field, field_name)] + return field_info + + if self._dash_to_underscore: + return [(x[0], x[1].replace('_', '-'), x[2]) for x in super()._extract_field_info(field, field_name)] + + return super()._extract_field_info(field, field_name) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(url={self._url!r}, env_nested_delimiter={self.env_nested_delimiter!r})' + + +__all__ = ['AzureKeyVaultMapping', 'AzureKeyVaultSettingsSource'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/cli.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/cli.py new file mode 100644 index 0000000..1064759 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/cli.py @@ -0,0 +1,1700 @@ +"""Command-line interface settings source.""" + +from __future__ import annotations as _annotations + +import copy +import json +import re +import shlex +import sys +import typing +from argparse import ( + SUPPRESS, + ArgumentParser, + BooleanOptionalAction, + Namespace, + RawDescriptionHelpFormatter, + _SubParsersAction, +) +from collections import defaultdict +from collections.abc import Callable, Mapping, Sequence +from enum import Enum +from functools import cached_property +from itertools import chain +from textwrap import dedent +from types import SimpleNamespace +from typing import ( + TYPE_CHECKING, + Annotated, + Any, + Generic, + Literal, + NoReturn, + TypeVar, + cast, + get_args, + get_origin, + overload, +) + +from pydantic import AliasChoices, AliasPath, BaseModel, Field, PrivateAttr, TypeAdapter +from pydantic._internal._repr import Representation +from pydantic._internal._utils import is_model_class +from pydantic.dataclasses import is_pydantic_dataclass +from pydantic.fields import FieldInfo +from pydantic_core import PydanticUndefined +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from ...exceptions import SettingsError +from ...utils import _lenient_issubclass, _typing_base, _WithArgsTypes +from ..types import ( + ForceDecode, + NoDecode, + PydanticModel, + _CliDualFlag, + _CliExplicitFlag, + _CliImplicitFlag, + _CliPositionalArg, + _CliSubCommand, + _CliToggleFlag, + _CliUnknownArgs, +) +from ..utils import ( + InitState, + _annotation_contains_types, + _annotation_enum_val_to_name, + _get_alias_names, + _get_model_fields, + _is_function, + _strip_annotated, + parse_env_vars, +) +from .env import EnvSettingsSource + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + +class _CliInternalArgParser(ArgumentParser): + def __init__(self, cli_exit_on_error: bool = True, **kwargs: Any) -> None: + super().__init__(**kwargs) + self._cli_exit_on_error = cli_exit_on_error + + def error(self, message: str) -> NoReturn: + if not self._cli_exit_on_error: + raise SettingsError(f'error parsing CLI: {message}') + super().error(message) + + +class CliMutuallyExclusiveGroup(BaseModel): + pass + + +def _get_model_description(model_cls: type[Any]) -> str | None: + """Get model description from json_schema_extra or __doc__ fallback. + + ``json_schema_extra.description`` takes precedence over ``__doc__`` to + match pydantic's own behaviour. When neither is available (e.g. under + ``python -OO`` where docstrings are stripped), returns ``None``. + """ + config: Any = {} + if is_model_class(model_cls): + config = model_cls.model_config + elif is_pydantic_dataclass(model_cls): + config = getattr(model_cls, '__pydantic_config__', {}) + json_schema_extra = config.get('json_schema_extra') + if isinstance(json_schema_extra, dict): + desc = json_schema_extra.get('description') + if desc is not None: + return desc + elif callable(json_schema_extra): + try: + desc = None + if is_model_class(model_cls): + desc = model_cls.model_json_schema().get('description') + elif is_pydantic_dataclass(model_cls): + desc = TypeAdapter(model_cls).json_schema().get('description') + if desc is not None: + return desc + except Exception: + pass + if model_cls.__doc__ is not None: + return dedent(model_cls.__doc__) + return None + + +def _collect_sub_models(type_: Any, sub_models: list[type[BaseModel]]) -> None: + """Recursively collect BaseModel subclasses from possibly nested union types.""" + stripped = _strip_annotated(type_) + if is_model_class(stripped) or is_pydantic_dataclass(stripped): + sub_models.append(stripped) # type: ignore[arg-type] + elif is_union_origin(get_origin(stripped)): + for arg in get_args(stripped): + _collect_sub_models(arg, sub_models) + + +class _CliArg(BaseModel): + model: Any + parser: Any + field_name: str + arg_prefix: str + case_sensitive: bool + populate_by_name: bool + hide_none_type: bool + kebab_case: bool | Literal['all', 'no_enums'] | None + enable_decoding: bool | None + env_prefix_len: int + args: list[str] = [] + kwargs: dict[str, Any] = {} + + _alias_names: tuple[str, ...] = PrivateAttr(()) + _alias_paths: dict[str, int | None] = PrivateAttr({}) + _is_alias_path_only: bool = PrivateAttr(False) + _field_info: FieldInfo = PrivateAttr() + + def __init__( + self, + field_info: FieldInfo, + parser_map: defaultdict[str | FieldInfo, dict[int | None | str | type[BaseModel], _CliArg]], + **values: Any, + ) -> None: + super().__init__(**values) + self._field_info = field_info + self._alias_names, self._is_alias_path_only = _get_alias_names( + self.field_name, + self.field_info, + alias_path_args=self._alias_paths, + case_sensitive=self.case_sensitive, + populate_by_name=self.populate_by_name, + ) + + alias_path_dests = {f'{self.arg_prefix}{name}': index for name, index in self._alias_paths.items()} + if self.subcommand_dest: + for sub_model in self.sub_models: + subcommand_alias = self.subcommand_alias(sub_model) + parser_map[self.subcommand_dest][subcommand_alias] = self.model_copy(update={'args': [], 'kwargs': {}}) + parser_map[self.subcommand_dest][sub_model] = parser_map[self.subcommand_dest][subcommand_alias] + parser_map[self.field_info][subcommand_alias] = parser_map[self.subcommand_dest][subcommand_alias] + elif self.dest not in alias_path_dests: + parser_map[self.dest][None] = self + parser_map[self.field_info][None] = parser_map[self.dest][None] + for alias_path_dest, index in alias_path_dests.items(): + parser_map[alias_path_dest][index] = self.model_copy(update={'args': [], 'kwargs': {}}) + parser_map[self.field_info][index] = parser_map[alias_path_dest][index] + + @classmethod + def get_kebab_case(cls, name: str, kebab_case: bool | Literal['all', 'no_enums'] | None) -> str: + return name.replace('_', '-') if kebab_case not in (None, False) else name + + @classmethod + def get_enum_names( + cls, annotation: type[Any], kebab_case: bool | Literal['all', 'no_enums'] | None + ) -> tuple[str, ...]: + enum_names: tuple[str, ...] = () + annotation = _strip_annotated(annotation) + for type_ in get_args(annotation): + enum_names += cls.get_enum_names(type_, kebab_case) + if annotation and _lenient_issubclass(annotation, Enum): + enum_names += tuple(cls.get_kebab_case(name, kebab_case == 'all') for name in annotation.__members__) + return enum_names + + def subcommand_alias(self, sub_model: type[BaseModel]) -> str: + return self.get_kebab_case( + sub_model.__name__ if len(self.sub_models) > 1 else self.preferred_alias, self.kebab_case + ) + + @cached_property + def field_info(self) -> FieldInfo: + return self._field_info + + @cached_property + def subcommand_dest(self) -> str | None: + return f'{self.arg_prefix}:subcommand' if _CliSubCommand in self.field_info.metadata else None + + @cached_property + def dest(self) -> str: + if ( + not self.subcommand_dest + and self.arg_prefix + and self.field_info.validation_alias is not None + and not self.is_parser_submodel + ): + # Strip prefix if validation alias is set and value is not complex. + # Related https://github.com/pydantic/pydantic-settings/pull/25 + return f'{self.arg_prefix}{self.preferred_alias}'[self.env_prefix_len :] + return f'{self.arg_prefix}{self.preferred_alias}' + + @cached_property + def preferred_arg_name(self) -> str: + return self.args[0].replace('_', '-') if self.kebab_case else self.args[0] + + @cached_property + def sub_models(self) -> list[type[BaseModel]]: + field_types: tuple[Any, ...] = ( + (self.field_info.annotation,) + if not get_args(self.field_info.annotation) + else get_args(self.field_info.annotation) + ) + if self.hide_none_type: + field_types = tuple([type_ for type_ in field_types if type_ is not type(None)]) + + sub_models: list[type[BaseModel]] = [] + for type_ in field_types: + if _annotation_contains_types(type_, (_CliSubCommand,), is_include_origin=False): + raise SettingsError( + f'CliSubCommand is not outermost annotation for {self.model.__name__}.{self.field_name}' + ) + elif _annotation_contains_types(type_, (_CliPositionalArg,), is_include_origin=False): + raise SettingsError( + f'CliPositionalArg is not outermost annotation for {self.model.__name__}.{self.field_name}' + ) + _collect_sub_models(type_, sub_models) + return sub_models + + @cached_property + def alias_names(self) -> tuple[str, ...]: + return self._alias_names + + @cached_property + def alias_paths(self) -> dict[str, int | None]: + return self._alias_paths + + @cached_property + def preferred_alias(self) -> str: + return self._alias_names[0] + + @cached_property + def is_alias_path_only(self) -> bool: + return self._is_alias_path_only + + @cached_property + def is_append_action(self) -> bool: + return not self.subcommand_dest and _annotation_contains_types( + self.field_info.annotation, (list, set, dict, Sequence, Mapping), is_strip_annotated=True + ) + + @cached_property + def is_parser_submodel(self) -> bool: + return not self.subcommand_dest and bool(self.sub_models) and not self.is_append_action + + @cached_property + def is_no_decode(self) -> bool: + return self.field_info is not None and ( + NoDecode in self.field_info.metadata + or (self.enable_decoding is False and ForceDecode not in self.field_info.metadata) + ) + + +T = TypeVar('T') +CliSubCommand = Annotated[T | None, _CliSubCommand] +CliPositionalArg = Annotated[T, _CliPositionalArg] +_CliBoolFlag = TypeVar('_CliBoolFlag', bound=bool) +CliImplicitFlag = Annotated[_CliBoolFlag, _CliImplicitFlag] +CliExplicitFlag = Annotated[_CliBoolFlag, _CliExplicitFlag] +CliToggleFlag = Annotated[_CliBoolFlag, _CliToggleFlag] +CliDualFlag = Annotated[_CliBoolFlag, _CliDualFlag] +CLI_SUPPRESS = SUPPRESS +CliSuppress = Annotated[T, CLI_SUPPRESS] +CliUnknownArgs = Annotated[list[str], Field(default=[]), _CliUnknownArgs, NoDecode] + + +class CliSettingsSource(EnvSettingsSource, Generic[T]): + """ + Source class for loading settings values from CLI. + + Note: + A `CliSettingsSource` connects with a `root_parser` object by using the parser methods to add + `settings_cls` fields as command line arguments. The `CliSettingsSource` internal parser representation + is based upon the `argparse` parsing library, and therefore, requires the parser methods to support + the same attributes as their `argparse` library counterparts. + + Args: + cli_prog_name: The CLI program name to display in help text. Defaults to `None` if cli_parse_args is `None`. + Otherwise, defaults to sys.argv[0]. + cli_parse_args: The list of CLI arguments to parse. Defaults to None. + If set to `True`, defaults to sys.argv[1:]. + cli_parse_none_str: The CLI string value that should be parsed (e.g. "null", "void", "None", etc.) into `None` + type(None). Defaults to "null" if cli_avoid_json is `False`, and "None" if cli_avoid_json is `True`. + cli_hide_none_type: Hide `None` values in CLI help text. Defaults to `False`. + cli_avoid_json: Avoid complex JSON objects in CLI help text. Defaults to `False`. + cli_enforce_required: Enforce required fields at the CLI. Defaults to `False`. + cli_use_class_docs_for_groups: Use class docstrings in CLI group help text instead of field descriptions. + Defaults to `False`. + cli_show_env_vars: Show resolved environment variable names in CLI help text. Defaults to `False`. + cli_exit_on_error: Determines whether or not the internal parser exits with error info when an error occurs. + Defaults to `True`. + cli_prefix: Prefix for command line arguments added under the root parser. Defaults to "". + cli_flag_prefix_char: The flag prefix character to use for CLI optional arguments. Defaults to '-'. + cli_implicit_flags: Controls how `bool` fields are exposed as CLI flags. + + - False (default): no implicit flags are generated; booleans must be set explicitly (e.g. --flag=true). + - True / 'dual': optional boolean fields generate both positive and negative forms (--flag and --no-flag). + - 'toggle': required boolean fields remain in 'dual' mode, while optional boolean fields generate a single + flag aligned with the default value (if default=False, expose --flag; if default=True, expose --no-flag). + cli_ignore_unknown_args: Whether to ignore unknown CLI args and parse only known ones. Defaults to `False`. + cli_kebab_case: CLI args use kebab case. Defaults to `False`. + cli_shortcuts: Mapping of target field name to alias names. Defaults to `None`. + case_sensitive: Whether CLI "--arg" names should be read with case-sensitivity. Defaults to `True`. + Note: Case-insensitive matching is only supported on the internal root parser and does not apply to CLI + subcommands. + root_parser: The root parser object. + parse_args_method: The root parser parse args method. Defaults to `argparse.ArgumentParser.parse_args`. + add_argument_method: The root parser add argument method. Defaults to `argparse.ArgumentParser.add_argument`. + add_argument_group_method: The root parser add argument group method. + Defaults to `argparse.ArgumentParser.add_argument_group`. + add_parser_method: The root parser add new parser (sub-command) method. + Defaults to `argparse._SubParsersAction.add_parser`. + add_subparsers_method: The root parser add subparsers (sub-commands) method. + Defaults to `argparse.ArgumentParser.add_subparsers`. + format_help_method: The root parser format help method. Defaults to `argparse.ArgumentParser.format_help`. + formatter_class: A class for customizing the root parser help text. Defaults to `argparse.RawDescriptionHelpFormatter`. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + cli_prog_name: str | None = None, + cli_parse_args: bool | list[str] | tuple[str, ...] | None = None, + cli_parse_none_str: str | None = None, + cli_hide_none_type: bool | None = None, + cli_avoid_json: bool | None = None, + cli_enforce_required: bool | None = None, + cli_use_class_docs_for_groups: bool | None = None, + cli_show_env_vars: bool | None = None, + cli_exit_on_error: bool | None = None, + cli_prefix: str | None = None, + cli_flag_prefix_char: str | None = None, + cli_implicit_flags: bool | Literal['dual', 'toggle'] | None = None, + cli_ignore_unknown_args: bool | None = None, + cli_kebab_case: bool | Literal['all', 'no_enums'] | None = None, + cli_shortcuts: Mapping[str, str | list[str]] | None = None, + case_sensitive: bool | None = True, + root_parser: Any = None, + parse_args_method: Callable[..., Any] | None = None, + add_argument_method: Callable[..., Any] | None = ArgumentParser.add_argument, + add_argument_group_method: Callable[..., Any] | None = ArgumentParser.add_argument_group, + add_parser_method: Callable[..., Any] | None = _SubParsersAction.add_parser, + add_subparsers_method: Callable[..., Any] | None = ArgumentParser.add_subparsers, + format_help_method: Callable[..., Any] | None = ArgumentParser.format_help, + formatter_class: Any = RawDescriptionHelpFormatter, + _env_settings_source: EnvSettingsSource | None = None, + _init_state: InitState | None = None, + ) -> None: + self.cli_prog_name = ( + cli_prog_name if cli_prog_name is not None else settings_cls.model_config.get('cli_prog_name', sys.argv[0]) + ) + self.cli_hide_none_type = ( + cli_hide_none_type + if cli_hide_none_type is not None + else settings_cls.model_config.get('cli_hide_none_type', False) + ) + self.cli_avoid_json = ( + cli_avoid_json if cli_avoid_json is not None else settings_cls.model_config.get('cli_avoid_json', False) + ) + if not cli_parse_none_str: + cli_parse_none_str = 'None' if self.cli_avoid_json is True else 'null' + self.cli_parse_none_str = cli_parse_none_str + self.cli_enforce_required = ( + cli_enforce_required + if cli_enforce_required is not None + else settings_cls.model_config.get('cli_enforce_required', False) + ) + self.cli_use_class_docs_for_groups = ( + cli_use_class_docs_for_groups + if cli_use_class_docs_for_groups is not None + else settings_cls.model_config.get('cli_use_class_docs_for_groups', False) + ) + self.cli_show_env_vars = ( + cli_show_env_vars + if cli_show_env_vars is not None + else settings_cls.model_config.get('cli_show_env_vars', False) + ) + self.cli_exit_on_error = ( + cli_exit_on_error + if cli_exit_on_error is not None + else settings_cls.model_config.get('cli_exit_on_error', True) + ) + self.cli_prefix = cli_prefix if cli_prefix is not None else settings_cls.model_config.get('cli_prefix', '') + self.cli_flag_prefix_char = ( + cli_flag_prefix_char + if cli_flag_prefix_char is not None + else settings_cls.model_config.get('cli_flag_prefix_char', '-') + ) + self._cli_flag_prefix = self.cli_flag_prefix_char * 2 + if self.cli_prefix: + if cli_prefix.startswith('.') or cli_prefix.endswith('.') or not cli_prefix.replace('.', '').isidentifier(): # type: ignore + raise SettingsError(f'CLI settings source prefix is invalid: {cli_prefix}') + self.cli_prefix += '.' + self.cli_implicit_flags = ( + cli_implicit_flags + if cli_implicit_flags is not None + else settings_cls.model_config.get('cli_implicit_flags', False) + ) + self.cli_ignore_unknown_args = ( + cli_ignore_unknown_args + if cli_ignore_unknown_args is not None + else settings_cls.model_config.get('cli_ignore_unknown_args', False) + ) + self.cli_kebab_case = ( + cli_kebab_case if cli_kebab_case is not None else settings_cls.model_config.get('cli_kebab_case', False) + ) + self.cli_shortcuts = ( + cli_shortcuts if cli_shortcuts is not None else settings_cls.model_config.get('cli_shortcuts', None) + ) + self._env_settings_source: EnvSettingsSource | None = None + if self.cli_show_env_vars: + self._env_settings_source = _env_settings_source or EnvSettingsSource(settings_cls) + self._env_var_names: dict[str, tuple[str, ...]] = {} + + case_sensitive = case_sensitive if case_sensitive is not None else True + if not case_sensitive and root_parser is not None: + raise SettingsError('Case-insensitive matching is only supported on the internal root parser') + + super().__init__( + settings_cls, + env_nested_delimiter='.', + env_parse_none_str=self.cli_parse_none_str, + env_parse_enums=True, + env_prefix=self.cli_prefix, + case_sensitive=case_sensitive, + env_nested_max_split=0, + _init_state=_init_state, + ) + + root_parser = ( + _CliInternalArgParser( + cli_exit_on_error=self.cli_exit_on_error, + prog=self.cli_prog_name, + description=_get_model_description(settings_cls), + formatter_class=formatter_class, + prefix_chars=self.cli_flag_prefix_char, + allow_abbrev=False, + add_help=False, + ) + if root_parser is None + else root_parser + ) + self._connect_root_parser( + root_parser=root_parser, + parse_args_method=parse_args_method, + add_argument_method=add_argument_method, + add_argument_group_method=add_argument_group_method, + add_parser_method=add_parser_method, + add_subparsers_method=add_subparsers_method, + format_help_method=format_help_method, + formatter_class=formatter_class, + ) + + if cli_parse_args not in (None, False): + if cli_parse_args is True: + cli_parse_args = sys.argv[1:] + elif not isinstance(cli_parse_args, (list, tuple)): + raise SettingsError( + f'cli_parse_args must be a list or tuple of strings, received {type(cli_parse_args)}' + ) + self._load_env_vars(parsed_args=self._parse_args(self.root_parser, cli_parse_args)) + + @property + def env_var_names(self) -> Mapping[str, tuple[str, ...]]: + """Resolved environment variable names for CLI arguments.""" + return self._env_var_names.copy() + + @overload + def __call__(self) -> dict[str, Any]: ... + + @overload + def __call__(self, *, args: list[str] | tuple[str, ...] | bool) -> CliSettingsSource[T]: + """ + Parse and load the command line arguments list into the CLI settings source. + + Args: + args: + The command line arguments to parse and load. Defaults to `None`, which means do not parse + command line arguments. If set to `True`, defaults to sys.argv[1:]. If set to `False`, does + not parse command line arguments. + + Returns: + CliSettingsSource: The object instance itself. + """ + + @overload + def __call__(self, *, parsed_args: Namespace | SimpleNamespace | dict[str, Any]) -> CliSettingsSource[T]: + """ + Loads parsed command line arguments into the CLI settings source. + + Note: + The parsed args must be in `argparse.Namespace`, `SimpleNamespace`, or vars dictionary + (e.g., vars(argparse.Namespace)) format. + + Args: + parsed_args: The parsed args to load. + + Returns: + CliSettingsSource: The object instance itself. + """ + + def __call__( + self, + *, + args: list[str] | tuple[str, ...] | bool | None = None, + parsed_args: Namespace | SimpleNamespace | dict[str, list[str] | str] | None = None, + ) -> dict[str, Any] | CliSettingsSource[T]: + if args is not None and parsed_args is not None: + raise SettingsError('`args` and `parsed_args` are mutually exclusive') + elif args is not None: + if args is False: + return self._load_env_vars(parsed_args={}) + if args is True: + args = sys.argv[1:] + return self._load_env_vars(parsed_args=self._parse_args(self.root_parser, args)) + elif parsed_args is not None: + return self._load_env_vars(parsed_args=copy.copy(parsed_args)) + else: + return super().__call__() + + @overload + def _load_env_vars(self) -> Mapping[str, str | None]: ... + + @overload + def _load_env_vars(self, *, parsed_args: Namespace | SimpleNamespace | dict[str, Any]) -> CliSettingsSource[T]: + """ + Loads the parsed command line arguments into the CLI environment settings variables. + + Note: + The parsed args must be in `argparse.Namespace`, `SimpleNamespace`, or vars dictionary + (e.g., vars(argparse.Namespace)) format. + + Args: + parsed_args: The parsed args to load. + + Returns: + CliSettingsSource: The object instance itself. + """ + + def _load_env_vars( + self, *, parsed_args: Namespace | SimpleNamespace | dict[str, list[str] | str] | None = None + ) -> Mapping[str, str | None] | CliSettingsSource[T]: + if parsed_args is None: + return {} + + if isinstance(parsed_args, (Namespace, SimpleNamespace)): + parsed_args = vars(parsed_args) + + selected_subcommands = self._resolve_parsed_args(parsed_args) + for arg_dest, arg_map in self._parser_map.items(): + if isinstance(arg_dest, str) and arg_dest.endswith(':subcommand'): + for subcommand_dest in [arg.dest for arg in arg_map.values()]: + if subcommand_dest not in selected_subcommands: + parsed_args[subcommand_dest] = self.cli_parse_none_str + + parsed_args = { + key: val + for key, val in parsed_args.items() + if not key.endswith(':subcommand') and val is not PydanticUndefined + } + if selected_subcommands: + last_selected_subcommand = max(selected_subcommands, key=len) + if not any(field_name for field_name in parsed_args if f'{last_selected_subcommand}.' in field_name): + parsed_args[last_selected_subcommand] = '{}' + else: + last_selected_subcommand = '' + + # When using parse_known_args due to a subcommand's CliUnknownArgs, reject + # unknown args if the selected subcommand does not accept them. + if not self.cli_ignore_unknown_args and self._cli_unknown_args: + has_unknown = any(args for args in self._cli_unknown_args.values()) + if has_unknown: + selected_accepts_unknown = any( + dest.rsplit('.', 1)[0] in last_selected_subcommand for dest in self._cli_unknown_args + ) + if not selected_accepts_unknown: + unknown = next(args for args in self._cli_unknown_args.values() if args) + if isinstance(self.root_parser, ArgumentParser): + self.root_parser.error(f'unrecognized arguments: {" ".join(unknown)}') + raise SystemExit(2) + + parsed_args.update(self._cli_unknown_args) + + self.env_vars = parse_env_vars( + cast(Mapping[str, str], parsed_args), + self.case_sensitive, + self.env_ignore_empty, + self.cli_parse_none_str, + ) + + return self + + def _resolve_parsed_args(self, parsed_args: dict[str, list[str] | str]) -> list[str]: + selected_subcommands: list[str] = [] + for field_name, val in list(parsed_args.items()): + if isinstance(val, list): + if self._is_nested_alias_path_only_workaround(parsed_args, field_name, val): + # Workaround for nested alias path environment variables not being handled. + # See https://github.com/pydantic/pydantic-settings/issues/670 + continue + + cli_arg = self._parser_map.get(field_name, {}).get(None) + if cli_arg and cli_arg.is_no_decode: + parsed_args[field_name] = ','.join(val) + continue + + parsed_args[field_name] = self._merge_parsed_list(val, field_name) + elif field_name.endswith(':subcommand') and val is not None: + selected_subcommands.append(self._parser_map[field_name][val].dest) + elif self.cli_kebab_case == 'all' and isinstance(val, str): + snake_val = val.replace('-', '_') + cli_arg = self._parser_map.get(field_name, {}).get(None) + if ( + cli_arg + and cli_arg.field_info.annotation + and (snake_val in cli_arg.get_enum_names(cli_arg.field_info.annotation, False)) + ): + if '_' in val: + raise ValueError(f'Input should be kebab-case "{val.replace("_", "-")}", not "{val}"') + parsed_args[field_name] = snake_val + + return selected_subcommands + + def _is_nested_alias_path_only_workaround( + self, parsed_args: dict[str, list[str] | str], field_name: str, val: list[str] + ) -> bool: + """ + Workaround for nested alias path environment variables not being handled. + See https://github.com/pydantic/pydantic-settings/issues/670 + """ + known_arg = self._parser_map.get(field_name, {}).values() + if not known_arg: + return False + arg = next(iter(known_arg)) + if arg.is_alias_path_only and arg.arg_prefix.endswith('.'): + del parsed_args[field_name] + nested_dest = arg.arg_prefix[:-1] + nested_val = f'"{arg.preferred_alias}": {self._merge_parsed_list(val, field_name)}' + parsed_args[nested_dest] = ( + f'{{{nested_val}}}' + if nested_dest not in parsed_args + else f'{parsed_args[nested_dest][:-1]}, {nested_val}}}' + ) + return True + return False + + def _get_merge_parsed_list_types(self, parsed_list: list[str], field_name: str) -> tuple[type | None, type | None]: + merge_type = self._cli_dict_args.get(field_name, list) + if ( + merge_type is list + or not is_union_origin(get_origin(merge_type)) + or not any( + type_ + for type_ in get_args(merge_type) + if type_ is not type(None) and get_origin(type_) not in (dict, Mapping) + ) + ): + inferred_type = merge_type + else: + inferred_type = list if parsed_list and (len(parsed_list) > 1 or parsed_list[0].startswith('[')) else str + + return merge_type, inferred_type + + def _merged_list_to_str(self, merged_list: list[str], field_name: str) -> str: + decode_list: list[str] = [] + is_use_decode: bool | None = None + cli_arg_map = self._parser_map.get(field_name, {}) + try: + list_adapter: Any = TypeAdapter(next(iter(cli_arg_map.values())).field_info.annotation) + is_num_type_str = type(next(iter(list_adapter.validate_python(['1'])))) is str + except Exception: + is_num_type_str = None + for index, item in enumerate(merged_list): + cli_arg = cli_arg_map.get(index) + is_decode = cli_arg is None or not cli_arg.is_no_decode + if is_use_decode is None: + is_use_decode = is_decode + elif is_use_decode != is_decode: + raise SettingsError('Mixing Decode and NoDecode across different AliasPath fields is not allowed') + if is_use_decode: + item = item.replace('\\', '\\\\') + try: + unquoted_item = item[1:-1] if item.startswith('"') and item.endswith('"') else item + float(unquoted_item) + item = f'"{unquoted_item}"' if is_num_type_str else unquoted_item + except ValueError: + pass + elif item.startswith('"') and item.endswith('"'): + item = item[1:-1] + decode_list.append(item) + merged_list_str = ','.join(decode_list) + return f'[{merged_list_str}]' if is_use_decode else merged_list_str + + def _merge_parsed_list(self, parsed_list: list[str], field_name: str) -> str: + try: + merged_list: list[str] = [] + is_last_consumed_a_value = False + merge_type, inferred_type = self._get_merge_parsed_list_types(parsed_list, field_name) + for val in parsed_list: + if not isinstance(val, str): + # If val is not a string, it's from an external parser and we can ignore parsing the rest of the + # list. + break + val = val.strip() + if val.startswith('[') and val.endswith(']'): + val = val[1:-1].strip() + while val: + val = val.strip() + if val.startswith(','): + val = self._consume_comma(val, merged_list, is_last_consumed_a_value) + is_last_consumed_a_value = False + else: + if val.startswith(('{', '[')): + val = self._consume_object_or_array(val, merged_list) + else: + try: + val = self._consume_string_or_number(val, merged_list, merge_type) + except ValueError: + if merge_type is inferred_type: + raise + merge_type = inferred_type + val = self._consume_string_or_number(val, merged_list, merge_type) + is_last_consumed_a_value = True + if not is_last_consumed_a_value: + val = self._consume_comma(val, merged_list, is_last_consumed_a_value) + + if merge_type is str: + return merged_list[0] + elif merge_type is list: + return self._merged_list_to_str(merged_list, field_name) + else: + merged_dict: dict[str, str] = {} + for item in merged_list: + merged_dict.update(json.loads(item)) + return json.dumps(merged_dict) + except Exception as e: + raise SettingsError(f'Parsing error encountered for {field_name}: {e}') + + def _consume_comma(self, item: str, merged_list: list[str], is_last_consumed_a_value: bool) -> str: + if not is_last_consumed_a_value: + merged_list.append('""') + return item[1:] + + def _consume_object_or_array(self, item: str, merged_list: list[str]) -> str: + count = 1 + close_delim = '}' if item.startswith('{') else ']' + in_str = False + for consumed in range(1, len(item)): + if item[consumed] == '"' and item[consumed - 1] != '\\': + in_str = not in_str + elif in_str: + continue + elif item[consumed] in ('{', '['): + count += 1 + elif item[consumed] in ('}', ']'): + count -= 1 + if item[consumed] == close_delim and count == 0: + merged_list.append(item[: consumed + 1]) + return item[consumed + 1 :] + raise SettingsError(f'Missing end delimiter "{close_delim}"') + + def _consume_string_or_number(self, item: str, merged_list: list[str], merge_type: type[Any] | None) -> str: + consumed = 0 if merge_type is not str else len(item) + is_find_end_quote = False + while consumed < len(item): + if item[consumed] == '"' and (consumed == 0 or item[consumed - 1] != '\\'): + is_find_end_quote = not is_find_end_quote + if not is_find_end_quote and item[consumed] == ',': + break + consumed += 1 + if is_find_end_quote: + raise SettingsError('Mismatched quotes') + val_string = item[:consumed].strip() + if merge_type in (list, str): + try: + float(val_string) + except ValueError: + if val_string == self.cli_parse_none_str: + val_string = 'null' + if val_string not in ('true', 'false', 'null') and not val_string.startswith('"'): + val_string = f'"{val_string}"' + merged_list.append(val_string) + else: + key, val = (kv for kv in val_string.split('=', 1)) + if key.startswith('"') and not key.endswith('"') and not val.startswith('"') and val.endswith('"'): + raise ValueError(f'Dictionary key=val parameter is a quoted string: {val_string}') + key, val = key.strip('"'), val.strip('"') + merged_list.append(json.dumps({key: val})) + return item[consumed:] + + def _verify_cli_flag_annotations(self, model: type[BaseModel], field_name: str, field_info: FieldInfo) -> None: + if _CliImplicitFlag in field_info.metadata: + cli_flag_name = 'CliImplicitFlag' + elif _CliExplicitFlag in field_info.metadata: + cli_flag_name = 'CliExplicitFlag' + elif _CliToggleFlag in field_info.metadata: + cli_flag_name = 'CliToggleFlag' + if not isinstance(field_info.default, bool): + raise SettingsError( + f'{cli_flag_name} argument {model.__name__}.{field_name} must have a default bool value' + ) + elif _CliDualFlag in field_info.metadata: + cli_flag_name = 'CliDualFlag' + else: + return + + if field_info.annotation is not bool: + raise SettingsError(f'{cli_flag_name} argument {model.__name__}.{field_name} is not of type bool') + + def _sort_arg_fields(self, model: type[BaseModel]) -> list[tuple[str, FieldInfo]]: + positional_variadic_arg: list[tuple[str, FieldInfo]] = [] + positional_args, subcommand_args, optional_args = [], [], [] + for field_name, field_info in _get_model_fields(model).items(): + if _CliSubCommand in field_info.metadata: + if not field_info.is_required(): + raise SettingsError(f'subcommand argument {model.__name__}.{field_name} has a default value') + else: + alias_names, *_ = _get_alias_names(field_name, field_info) + if len(alias_names) > 1: + raise SettingsError(f'subcommand argument {model.__name__}.{field_name} has multiple aliases') + field_types = [type_ for type_ in get_args(field_info.annotation) if type_ is not type(None)] + for field_type in field_types: + if not (is_model_class(field_type) or is_pydantic_dataclass(field_type)): + raise SettingsError( + f'subcommand argument {model.__name__}.{field_name} has type not derived from BaseModel' + ) + subcommand_args.append((field_name, field_info)) + elif _CliPositionalArg in field_info.metadata: + alias_names, *_ = _get_alias_names(field_name, field_info) + if len(alias_names) > 1: + raise SettingsError(f'positional argument {model.__name__}.{field_name} has multiple aliases') + is_append_action = _annotation_contains_types( + field_info.annotation, (list, set, dict, Sequence, Mapping), is_strip_annotated=True + ) + if not is_append_action: + positional_args.append((field_name, field_info)) + else: + positional_variadic_arg.append((field_name, field_info)) + else: + self._verify_cli_flag_annotations(model, field_name, field_info) + optional_args.append((field_name, field_info)) + + if positional_variadic_arg: + if len(positional_variadic_arg) > 1: + field_names = ', '.join([name for name, info in positional_variadic_arg]) + raise SettingsError(f'{model.__name__} has multiple variadic positional arguments: {field_names}') + elif subcommand_args: + field_names = ', '.join([name for name, info in positional_variadic_arg + subcommand_args]) + raise SettingsError( + f'{model.__name__} has variadic positional arguments and subcommand arguments: {field_names}' + ) + + return positional_args + positional_variadic_arg + subcommand_args + optional_args + + @property + def root_parser(self) -> T: + """The connected root parser instance.""" + return self._root_parser + + def _connect_parser_method( + self, parser_method: Callable[..., Any] | None, method_name: str, *args: Any, **kwargs: Any + ) -> Callable[..., Any]: + if ( + parser_method is not None + and self.case_sensitive is False + and method_name == 'parse_args_method' + and isinstance(self._root_parser, _CliInternalArgParser) + ): + + def parse_args_insensitive_method( + root_parser: _CliInternalArgParser, + args: list[str] | tuple[str, ...] | None = None, + namespace: Namespace | None = None, + ) -> Any: + insensitive_args = [] + for arg in shlex.split(shlex.join(args)) if args else []: + flag_prefix = rf'\{self.cli_flag_prefix_char}{{1,2}}' + matched = re.match(rf'^({flag_prefix}[^\s=]+)(.*)', arg) + if matched: + arg = matched.group(1).lower() + matched.group(2) + insensitive_args.append(arg) + return parser_method(root_parser, insensitive_args, namespace) + + return parse_args_insensitive_method + + elif parser_method is None: + + def none_parser_method(*args: Any, **kwargs: Any) -> Any: + raise SettingsError( + f'cannot connect CLI settings source root parser: {method_name} is set to `None` but is needed for connecting' + ) + + return none_parser_method + + else: + return parser_method + + def _connect_group_method(self, add_argument_group_method: Callable[..., Any] | None) -> Callable[..., Any]: + add_argument_group = self._connect_parser_method(add_argument_group_method, 'add_argument_group_method') + + def add_group_method(parser: Any, **kwargs: Any) -> Any: + if not kwargs.pop('_is_cli_mutually_exclusive_group'): + kwargs.pop('required') + return add_argument_group(parser, **kwargs) + else: + main_group_kwargs = {arg: kwargs.pop(arg) for arg in ['title', 'description'] if arg in kwargs} + main_group_kwargs['title'] += ' (mutually exclusive)' + group = add_argument_group(parser, **main_group_kwargs) + if not hasattr(group, 'add_mutually_exclusive_group'): + raise SettingsError( + 'cannot connect CLI settings source root parser: ' + 'group object is missing add_mutually_exclusive_group but is needed for connecting' + ) + return group.add_mutually_exclusive_group(**kwargs) + + return add_group_method + + def _connect_root_parser( + self, + root_parser: T, + parse_args_method: Callable[..., Any] | None, + add_argument_method: Callable[..., Any] | None = ArgumentParser.add_argument, + add_argument_group_method: Callable[..., Any] | None = ArgumentParser.add_argument_group, + add_parser_method: Callable[..., Any] | None = _SubParsersAction.add_parser, + add_subparsers_method: Callable[..., Any] | None = ArgumentParser.add_subparsers, + format_help_method: Callable[..., Any] | None = ArgumentParser.format_help, + formatter_class: Any = RawDescriptionHelpFormatter, + ) -> None: + self._cli_unknown_args: dict[str, list[str]] = {} + + def _parse_known_args(*args: Any, **kwargs: Any) -> Namespace: + args, unknown_args = ArgumentParser.parse_known_args(*args, **kwargs) + for dest in self._cli_unknown_args: + self._cli_unknown_args[dest] = unknown_args + return cast(Namespace, args) + + self._root_parser = root_parser + _is_default_parse_args = parse_args_method is None + if parse_args_method is None: + parse_args_method = _parse_known_args if self.cli_ignore_unknown_args else ArgumentParser.parse_args + self._parse_args = self._connect_parser_method(parse_args_method, 'parse_args_method') + self._add_argument = self._connect_parser_method(add_argument_method, 'add_argument_method') + self._add_group = self._connect_group_method(add_argument_group_method) + self._add_parser = self._connect_parser_method(add_parser_method, 'add_parser_method') + self._add_subparsers = self._connect_parser_method(add_subparsers_method, 'add_subparsers_method') + self._format_help = self._connect_parser_method(format_help_method, 'format_help_method') + self._formatter_class = formatter_class + self._cli_dict_args: dict[str, type[Any] | None] = {} + self._parser_map: defaultdict[str | FieldInfo, dict[int | None | str | type[BaseModel], _CliArg]] = defaultdict( + dict + ) + self._add_default_help() + self._add_parser_args( + parser=self.root_parser, + model=self.settings_cls, + added_args=[], + arg_prefix=self.env_prefix, + subcommand_prefix=self.env_prefix, + group=None, + alias_prefixes=[], + model_default=PydanticUndefined, + model_path=set(), + env_prefixes=self._root_env_prefixes(), + ) + + # If subcommands registered CliUnknownArgs fields but root does not have + # cli_ignore_unknown_args=True, upgrade to parse_known_args so that argparse + # does not error on unknown arguments destined for a subcommand. + if self._cli_unknown_args and not self.cli_ignore_unknown_args and _is_default_parse_args: + self._parse_args = self._connect_parser_method(_parse_known_args, 'parse_args_method') + + def _add_default_help(self) -> None: + if isinstance(self._root_parser, _CliInternalArgParser): + if not self.cli_prefix: + for field_name, field_info in _get_model_fields(self.settings_cls).items(): + alias_names, *_ = _get_alias_names(field_name, field_info, case_sensitive=self.case_sensitive) + if 'help' in alias_names: + return + + self._add_argument( + self.root_parser, + f'{self._cli_flag_prefix[:1]}h', + f'{self._cli_flag_prefix[:2]}help', + action='help', + default=SUPPRESS, + help='show this help message and exit', + ) + + def _add_parser_args( # noqa: C901 + self, + parser: Any, + model: type[BaseModel], + added_args: list[str], + arg_prefix: str, + subcommand_prefix: str, + group: Any, + alias_prefixes: list[str], + model_default: Any, + is_model_suppressed: bool = False, + discriminator_vals: dict[str, set[Any]] | None = None, + is_last_discriminator: bool = True, + model_path: set[type[BaseModel]] | None = None, + env_prefixes: tuple[tuple[str, bool], ...] = (), + ) -> ArgumentParser: + if discriminator_vals is None: + discriminator_vals = {} + if model_path is None: + model_path = set() + model_path = model_path | {model} + subparsers: Any = None + alias_path_args: dict[str, int | None] = {} + # Ignore model default if the default is a model and not a subclass of the current model. + model_default = ( + None + if ( + (is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default))) + and not issubclass(type(model_default), model) + ) + else model_default + ) + for field_name, field_info in self._sort_arg_fields(model): + arg = _CliArg( + parser=parser, + field_info=field_info, + parser_map=self._parser_map, + model=model, + field_name=field_name, + arg_prefix=arg_prefix, + case_sensitive=self.case_sensitive, + populate_by_name=self.config.get('populate_by_name', False) + or self.config.get('validate_by_name', False), + hide_none_type=self.cli_hide_none_type, + kebab_case=self.cli_kebab_case, + enable_decoding=self.config.get('enable_decoding'), + env_prefix_len=self.env_prefix_len, + ) + alias_path_args.update(arg.alias_paths) + + if arg.subcommand_dest: + for sub_model in arg.sub_models: + subcommand_alias = arg.subcommand_alias(sub_model) + subcommand_arg = self._parser_map[arg.subcommand_dest][subcommand_alias] + subcommand_arg.args = [subcommand_alias] + subcommand_arg.kwargs['allow_abbrev'] = False + subcommand_arg.kwargs['formatter_class'] = self._formatter_class + subcommand_arg.kwargs['description'] = _get_model_description(sub_model) + subcommand_arg.kwargs['help'] = None if len(arg.sub_models) > 1 else field_info.description + if self.cli_use_class_docs_for_groups: + subcommand_arg.kwargs['help'] = _get_model_description(sub_model) + + subparsers = ( + self._add_subparsers( + parser, + title='subcommands', + dest=f'{arg_prefix}:subcommand', + description=field_info.description if len(arg.sub_models) > 1 else None, + ) + if subparsers is None + else subparsers + ) + + if hasattr(subparsers, 'metavar'): + subparsers.metavar = ( + f'{subparsers.metavar[:-1]},{subcommand_alias}}}' + if subparsers.metavar + else f'{{{subcommand_alias}}}' + ) + + subcommand_arg.parser = self._add_parser(subparsers, *subcommand_arg.args, **subcommand_arg.kwargs) + self._add_parser_args( + parser=subcommand_arg.parser, + model=sub_model, + added_args=[], + arg_prefix=f'{arg.dest}.', + subcommand_prefix=f'{subcommand_prefix}{arg.preferred_alias}.', + group=None, + alias_prefixes=[], + model_default=PydanticUndefined, + model_path=model_path, + env_prefixes=self._nested_env_prefixes( + self._get_field_env_var_names(field_name, field_info, env_prefixes) + ), + ) + else: + flag_prefix: str = self._cli_flag_prefix + env_var_names = self._get_field_env_var_names(field_name, field_info, env_prefixes) + arg.kwargs['dest'] = arg.dest + arg.kwargs['default'] = CLI_SUPPRESS + arg.kwargs['help'] = self._help_format( + field_name, + field_info, + model_default, + is_model_suppressed, + env_var_names, + ) + arg.kwargs['metavar'] = self._metavar_format(field_info.annotation) + arg.kwargs['required'] = ( + self.cli_enforce_required and field_info.is_required() and model_default is PydanticUndefined + ) + + arg_names = self._get_arg_names( + arg, + subcommand_prefix, + alias_prefixes, + added_args, + discriminator_vals, + is_last_discriminator, + ) + if not arg_names or (arg.kwargs['dest'] in added_args): + continue + + self._convert_append_action(arg.kwargs, field_info, arg.is_append_action) + + if _CliPositionalArg in field_info.metadata: + arg_names, flag_prefix = self._convert_positional_arg( + arg.kwargs, field_info, arg.preferred_alias, model_default + ) + + self._convert_bool_flag(arg.kwargs, field_info, model_default) + + non_recursive_sub_models = [m for m in arg.sub_models if m not in model_path] + if ( + arg.is_parser_submodel + and not getattr(field_info.annotation, '__pydantic_root_model__', False) + and non_recursive_sub_models + ): + self._add_parser_submodels( + parser, + model, + non_recursive_sub_models, + added_args, + arg_prefix, + subcommand_prefix, + flag_prefix, + arg_names, + arg.kwargs, + field_name, + field_info, + arg.alias_names, + model_default=model_default, + is_model_suppressed=is_model_suppressed, + model_path=model_path, + env_var_names=env_var_names, + ) + elif _CliUnknownArgs in field_info.metadata: + self._cli_unknown_args[arg.kwargs['dest']] = [] + elif not arg.is_alias_path_only: + if isinstance(group, dict): + group = self._add_group(parser, **group) + context = parser if group is None else group + if arg.kwargs.get('action') == 'store_false': + flag_prefix += 'no-' + arg.args = [f'{flag_prefix[: 1 if len(name) == 1 else None]}{name}' for name in arg_names] + self._add_env_var_names(arg.dest, arg.kwargs['help'], env_var_names) + self._add_argument(context, *arg.args, **arg.kwargs) + added_args += list(arg_names) + + self._add_parser_alias_paths(parser, alias_path_args, added_args, arg_prefix, subcommand_prefix, group) + return parser + + def _convert_append_action(self, kwargs: dict[str, Any], field_info: FieldInfo, is_append_action: bool) -> None: + if is_append_action: + kwargs['action'] = 'append' + if _annotation_contains_types(field_info.annotation, (dict, Mapping), is_strip_annotated=True): + self._cli_dict_args[kwargs['dest']] = field_info.annotation + + def _convert_bool_flag(self, kwargs: dict[str, Any], field_info: FieldInfo, model_default: Any) -> None: + if kwargs['metavar'] == 'bool': + meta_bool_flags = [ + meta + for meta in field_info.metadata + if isinstance(meta, type) and issubclass(meta, _CliImplicitFlag | _CliExplicitFlag) + ] + if not meta_bool_flags and self.cli_implicit_flags: + meta_bool_flags = [_CliImplicitFlag] + if meta_bool_flags: + bool_flag = meta_bool_flags.pop() + if bool_flag is _CliImplicitFlag: + bool_flag = ( + _CliToggleFlag + if self.cli_implicit_flags == 'toggle' and isinstance(field_info.default, bool) + else _CliDualFlag + ) + if bool_flag is _CliDualFlag: + del kwargs['metavar'] + kwargs['action'] = BooleanOptionalAction + elif bool_flag is _CliToggleFlag: + del kwargs['metavar'] + kwargs['action'] = 'store_false' if field_info.default else 'store_true' + + def _convert_positional_arg( + self, kwargs: dict[str, Any], field_info: FieldInfo, preferred_alias: str, model_default: Any + ) -> tuple[list[str], str]: + flag_prefix = '' + arg_names = [kwargs['dest']] + kwargs['default'] = PydanticUndefined + kwargs['metavar'] = _CliArg.get_kebab_case(preferred_alias.upper(), self.cli_kebab_case) + + # Note: CLI positional args are always strictly required at the CLI. Therefore, use field_info.is_required in + # conjunction with model_default instead of the derived kwargs['required']. + is_required = field_info.is_required() and model_default is PydanticUndefined + if kwargs.get('action') == 'append': + del kwargs['action'] + kwargs['nargs'] = '+' if is_required else '*' + elif not is_required: + kwargs['nargs'] = '?' + + del kwargs['dest'] + del kwargs['required'] + return arg_names, flag_prefix + + def _get_arg_names( + self, + arg: _CliArg, + subcommand_prefix: str, + alias_prefixes: list[str], + added_args: list[str], + discriminator_vals: dict[str, set[Any]], + is_last_discriminator: bool, + ) -> list[str]: + arg_names: list[str] = [] + for prefix in [arg.arg_prefix] + alias_prefixes: + for name in arg.alias_names: + arg_name = _CliArg.get_kebab_case( + f'{prefix}{name}' + if subcommand_prefix == self.env_prefix + else f'{prefix.replace(subcommand_prefix, "", 1)}{name}', + self.cli_kebab_case, + ) + if arg_name not in added_args: + arg_names.append(arg_name) + + if self.cli_shortcuts: + for target, aliases in self.cli_shortcuts.items(): + if target in arg_names: + alias_list = [aliases] if isinstance(aliases, str) else aliases + arg_names.extend(alias for alias in alias_list if alias not in added_args) + + tags: set[Any] = set() + discriminators = discriminator_vals.get(arg.dest) + if discriminators is not None: + _annotation_contains_types( + arg.field_info.annotation, + (Literal,), + is_include_origin=True, + collect=tags, + ) + discriminators.update(chain.from_iterable(get_args(tag) for tag in tags)) + if not is_last_discriminator: + return [] + arg.kwargs['metavar'] = self._metavar_format(Literal[tuple(sorted(discriminators))]) + + return arg_names + + def _add_parser_submodels( + self, + parser: Any, + model: type[BaseModel], + sub_models: list[type[BaseModel]], + added_args: list[str], + arg_prefix: str, + subcommand_prefix: str, + flag_prefix: str, + arg_names: list[str], + kwargs: dict[str, Any], + field_name: str, + field_info: FieldInfo, + alias_names: tuple[str, ...], + model_default: Any, + is_model_suppressed: bool, + model_path: set[type[BaseModel]] | None = None, + env_var_names: tuple[str, ...] = (), + ) -> None: + if issubclass(model, CliMutuallyExclusiveGroup): + # Argparse has deprecated "calling add_argument_group() or add_mutually_exclusive_group() on a + # mutually exclusive group" (https://docs.python.org/3/library/argparse.html#mutual-exclusion). + # Since nested models result in a group add, raise an exception for nested models in a mutually + # exclusive group. + raise SettingsError('cannot have nested models in a CliMutuallyExclusiveGroup') + + model_group_kwargs: dict[str, Any] = {} + model_group_kwargs['title'] = f'{arg_names[0]} options' + model_group_kwargs['description'] = field_info.description + model_group_kwargs['required'] = kwargs['required'] + model_group_kwargs['_is_cli_mutually_exclusive_group'] = any( + issubclass(model, CliMutuallyExclusiveGroup) for model in sub_models + ) + if model_group_kwargs['_is_cli_mutually_exclusive_group'] and len(sub_models) > 1: + raise SettingsError('cannot use union with CliMutuallyExclusiveGroup') + if self.cli_use_class_docs_for_groups and len(sub_models) == 1: + model_group_kwargs['description'] = _get_model_description(sub_models[0]) + + if model_default is not PydanticUndefined: + if is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)): + model_default = getattr(model_default, field_name) + else: + if field_info.default is not PydanticUndefined: + model_default = field_info.default + elif field_info.default_factory is not None: + model_default = field_info.default_factory + if model_default is None: + desc_header = f'default: {self.cli_parse_none_str} (undefined)' + if model_group_kwargs['description'] is not None: + model_group_kwargs['description'] = dedent(f'{desc_header}\n{model_group_kwargs["description"]}') + else: + model_group_kwargs['description'] = desc_header + + preferred_alias = alias_names[0] + is_model_suppressed = self._is_field_suppressed(field_info) or is_model_suppressed + if is_model_suppressed: + model_group_kwargs['description'] = CLI_SUPPRESS + added_args.append(arg_names[0]) + kwargs['required'] = False + kwargs['nargs'] = '?' + kwargs['const'] = '{}' + kwargs['help'] = ( + CLI_SUPPRESS + if is_model_suppressed or self.cli_avoid_json + else self._help_format_env_vars(f'set {arg_names[0]} from JSON string (default: {{}})', env_var_names) + ) + self._add_env_var_names(kwargs['dest'], kwargs['help'], env_var_names) + model_group = self._add_group(parser, **model_group_kwargs) + self._add_argument(model_group, *(f'{flag_prefix}{name}' for name in arg_names), **kwargs) + discriminator_vals: dict[str, set[Any]] = ( + {f'{arg_prefix}{preferred_alias}.{field_info.discriminator}': set()} if field_info.discriminator else {} + ) + for sub_model in sub_models: + self._add_parser_args( + parser=parser, + model=sub_model, + added_args=added_args, + arg_prefix=f'{arg_prefix}{preferred_alias}.', + subcommand_prefix=subcommand_prefix, + group=model_group, + alias_prefixes=[f'{arg_prefix}{name}.' for name in alias_names[1:]], + model_default=model_default, + is_model_suppressed=is_model_suppressed, + discriminator_vals=discriminator_vals, + is_last_discriminator=sub_model is sub_models[-1], + model_path=model_path, + env_prefixes=self._nested_env_prefixes(env_var_names), + ) + + def _add_parser_alias_paths( + self, + parser: Any, + alias_path_args: dict[str, int | None], + added_args: list[str], + arg_prefix: str, + subcommand_prefix: str, + group: Any, + ) -> None: + if alias_path_args: + context = parser + if group is not None: + context = self._add_group(parser, **group) if isinstance(group, dict) else group + for name, index in alias_path_args.items(): + arg_name = ( + f'{arg_prefix}{name}' + if subcommand_prefix == self.env_prefix + else f'{arg_prefix.replace(subcommand_prefix, "", 1)}{name}' + ) + kwargs: dict[str, Any] = {} + kwargs['default'] = CLI_SUPPRESS + kwargs['help'] = 'pydantic alias path' + kwargs['action'] = 'append' + kwargs['metavar'] = 'list' + if index is None: + kwargs['metavar'] = 'dict' + self._cli_dict_args[arg_name] = dict + args = [f'{self._cli_flag_prefix}{arg_name}'] + for arg in self._parser_map[arg_name].values(): + arg.args, arg.kwargs = args, kwargs + self._add_argument(context, *args, **kwargs) + added_args.append(arg_name) + + def _get_modified_args(self, obj: Any) -> tuple[str, ...]: + if not self.cli_hide_none_type: + return get_args(obj) + else: + return tuple([type_ for type_ in get_args(obj) if type_ is not type(None)]) + + def _metavar_format_choices(self, args: list[str], obj_qualname: str | None = None) -> str: + if 'JSON' in args: + args = args[: args.index('JSON') + 1] + [arg for arg in args[args.index('JSON') + 1 :] if arg != 'JSON'] + metavar = ','.join(args) + if obj_qualname: + return f'{obj_qualname}[{metavar}]' + else: + return metavar if len(args) == 1 else f'{{{metavar}}}' + + def _metavar_format_recurse(self, obj: Any) -> str: + """Pretty metavar representation of a type. Adapts logic from `pydantic._repr.display_as_type`.""" + obj = _strip_annotated(obj) + if _is_function(obj): + # If function is locally defined use __name__ instead of __qualname__ + return obj.__name__ if '' in obj.__qualname__ else obj.__qualname__ + elif obj is ...: + return '...' + elif isinstance(obj, Representation): + return repr(obj) + elif isinstance(obj, typing.ForwardRef) or typing_objects.is_typealiastype(obj): + return str(obj) + + if not isinstance(obj, (_typing_base, _WithArgsTypes, type)): + obj = obj.__class__ + + origin = get_origin(obj) + if is_union_origin(origin): + return self._metavar_format_choices(list(map(self._metavar_format_recurse, self._get_modified_args(obj)))) + elif typing_objects.is_literal(origin): + return self._metavar_format_choices(list(map(str, self._get_modified_args(obj)))) + elif _lenient_issubclass(obj, Enum): + return self._metavar_format_choices( + [_CliArg.get_kebab_case(name, self.cli_kebab_case == 'all') for name in obj.__members__] + ) + elif isinstance(obj, _WithArgsTypes): + return self._metavar_format_choices( + list(map(self._metavar_format_recurse, self._get_modified_args(obj))), + obj_qualname=obj.__qualname__ if hasattr(obj, '__qualname__') else str(obj), + ) + elif obj is type(None): + return self.cli_parse_none_str + elif is_model_class(obj) or is_pydantic_dataclass(obj): + return ( + self._metavar_format_recurse(_get_model_fields(obj)['root'].annotation) + if getattr(obj, '__pydantic_root_model__', False) + else 'JSON' + ) + elif isinstance(obj, type): + return obj.__qualname__ + else: + return repr(obj).replace('typing.', '').replace('typing_extensions.', '') + + def _metavar_format(self, obj: Any) -> str: + return self._metavar_format_recurse(obj).replace(', ', ',') + + def _root_env_prefixes(self) -> tuple[tuple[str, bool], ...]: + if self._env_settings_source is None: + return () + return ((self._env_settings_source.env_prefix, False),) + + def _nested_env_prefixes(self, env_var_names: tuple[str, ...]) -> tuple[tuple[str, bool], ...]: + if self._env_settings_source is None or not self._env_settings_source.env_nested_delimiter: + return () + return tuple( + (f'{env_name}{self._env_settings_source.env_nested_delimiter}', True) for env_name in env_var_names + ) + + def _display_env_var_name(self, env_name: str) -> str: + if self._env_settings_source is not None and not self._env_settings_source.case_sensitive: + return env_name.upper() + return env_name + + def _get_field_env_var_names( + self, + field_name: str, + field_info: FieldInfo, + env_prefixes: tuple[tuple[str, bool], ...], + ) -> tuple[str, ...]: + if ( + self._env_settings_source is None + or self._is_field_suppressed(field_info) + or _CliPositionalArg in field_info.metadata + or _CliUnknownArgs in field_info.metadata + ): + return () + + env_var_names: list[str] = [] + env_settings_source = copy.copy(self._env_settings_source) + for env_prefix, force_env_prefix in env_prefixes: + env_settings_source.env_prefix = env_prefix + normalized_env_prefix = env_settings_source._apply_case_sensitive(env_prefix) + for _, env_name, _ in env_settings_source._extract_field_info(field_info, field_name): + if force_env_prefix and normalized_env_prefix and not env_name.startswith(normalized_env_prefix): + env_name = f'{normalized_env_prefix}{env_name}' + display_env_name = self._display_env_var_name(env_name) + if display_env_name and display_env_name not in env_var_names: + env_var_names.append(display_env_name) + + return tuple(env_var_names) + + def _help_format_env_vars(self, help_text: str, env_var_names: tuple[str, ...]) -> str: + if not env_var_names: + return help_text + env_help = f'[env: {" | ".join(env_var_names)}]' + return f'{help_text} {env_help}' if help_text else env_help + + def _add_env_var_names(self, dest: str, help_text: str, env_var_names: tuple[str, ...]) -> None: + if env_var_names and help_text != CLI_SUPPRESS: + self._env_var_names[dest] = env_var_names + + def _help_format( + self, + field_name: str, + field_info: FieldInfo, + model_default: Any, + is_model_suppressed: bool, + env_var_names: tuple[str, ...] = (), + ) -> str: + _help = field_info.description if field_info.description else '' + if is_model_suppressed or self._is_field_suppressed(field_info): + return CLI_SUPPRESS + + if field_info.is_required() and model_default in (PydanticUndefined, None): + if _CliPositionalArg not in field_info.metadata: + ifdef = 'ifdef: ' if model_default is None else '' + _help += f' ({ifdef}required)' if _help else f'({ifdef}required)' + else: + default = f'(default: {self.cli_parse_none_str})' + if is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)): + default = f'(default: {getattr(model_default, field_name)})' + elif model_default not in (PydanticUndefined, None) and _is_function(model_default): + default = f'(default factory: {self._metavar_format(model_default)})' + elif field_info.default not in (PydanticUndefined, None): + enum_name = _annotation_enum_val_to_name(field_info.annotation, field_info.default) + default = f'(default: {field_info.default if enum_name is None else enum_name})' + elif field_info.default_factory is not None: + default = f'(default factory: {self._metavar_format(field_info.default_factory)})' + + if _CliToggleFlag not in field_info.metadata: + _help += f' {default}' if _help else default + _help = self._help_format_env_vars(_help, env_var_names) + return _help.replace('%', '%%') if issubclass(type(self._root_parser), ArgumentParser) else _help + + def _is_field_suppressed(self, field_info: FieldInfo) -> bool: + _help = field_info.description if field_info.description else '' + return _help == CLI_SUPPRESS or CLI_SUPPRESS in field_info.metadata + + def _update_alias_path_only_default( + self, arg_name: str, value: Any, field_info: FieldInfo, alias_path_only_defaults: dict[str, Any] + ) -> list[Any] | dict[str, Any]: + alias_path: AliasPath = next( + alias if isinstance(alias, AliasPath) else cast(AliasPath, alias.choices[0]) + for alias in (field_info.alias, field_info.validation_alias) + if isinstance(alias, (AliasPath, AliasChoices)) + ) + + alias_nested_paths: list[str] = alias_path.path[1:-1] # type: ignore + if not alias_nested_paths: + alias_path_only_defaults.setdefault(arg_name, []) + alias_default = alias_path_only_defaults[arg_name] + else: + alias_path_only_defaults.setdefault(arg_name, {}) + current_path = alias_path_only_defaults[arg_name] + + for nested_path in alias_nested_paths[:-1]: + current_path.setdefault(nested_path, {}) + current_path = current_path[nested_path] + current_path.setdefault(alias_nested_paths[-1], []) + alias_default = current_path[alias_nested_paths[-1]] + + alias_path_index = cast(int, alias_path.path[-1]) + alias_default.extend([''] * max(alias_path_index + 1 - len(alias_default), 0)) + alias_default[alias_path_index] = value + return alias_path_only_defaults[arg_name] + + def _coerce_value_styles( + self, + model_default: Any, + value: str | list[Any] | dict[str, Any], + list_style: Literal['json', 'argparse', 'lazy'] = 'json', + dict_style: Literal['json', 'env'] = 'json', + ) -> list[str | list[Any] | dict[str, Any]]: + values = [value] + if isinstance(value, str): + if isinstance(model_default, list): + if list_style == 'lazy': + values = [','.join(f'{v}' for v in json.loads(value))] + elif list_style == 'argparse': + values = [f'{v}' for v in json.loads(value)] + elif isinstance(model_default, dict) and dict_style == 'env': + values = [f'{k}={v}' for k, v in json.loads(value).items()] + return values + + @staticmethod + def _flatten_serialized_args( + serialized_args: dict[str, list[str]], + positionals_first: bool, + ) -> list[str]: + return ( + serialized_args['optional'] + serialized_args['positional'] + if not positionals_first + else serialized_args['positional'] + serialized_args['optional'] + ) + serialized_args['subcommand'] + + def _serialized_args( + self, + model: PydanticModel, + list_style: Literal['json', 'argparse', 'lazy'] = 'json', + dict_style: Literal['json', 'env'] = 'json', + positionals_first: bool = False, + _is_submodel: bool = False, + ) -> dict[str, list[str]]: + alias_path_only_defaults: dict[str, Any] = {} + optional_args: list[str | list[Any] | dict[str, Any]] = [] + positional_args: list[str | list[Any] | dict[str, Any]] = [] + subcommand_args: list[str] = [] + for field_name, field_info in _get_model_fields(type(model) if _is_submodel else self.settings_cls).items(): + model_default = getattr(model, field_name) + if field_info.default == model_default: + continue + if _CliSubCommand in field_info.metadata and model_default is None: + continue + arg = next(iter(self._parser_map[field_info].values())) + if arg.subcommand_dest: + subcommand_args.append(arg.subcommand_alias(type(model_default))) + sub_args = self._serialized_args( + model_default, + list_style=list_style, + dict_style=dict_style, + positionals_first=positionals_first, + _is_submodel=True, + ) + subcommand_args += self._flatten_serialized_args(sub_args, positionals_first) + continue + if is_model_class(type(model_default)) or is_pydantic_dataclass(type(model_default)): + sub_args = self._serialized_args( + model_default, + list_style=list_style, + dict_style=dict_style, + positionals_first=positionals_first, + _is_submodel=True, + ) + optional_args += sub_args['optional'] + positional_args += sub_args['positional'] + subcommand_args += sub_args['subcommand'] + continue + + matched = re.match(r'(-*)(.+)', arg.preferred_arg_name) + flag_chars, arg_name = matched.groups() if matched else ('', '') + value: str | list[Any] | dict[str, Any] = ( + json.dumps(model_default) if isinstance(model_default, (dict, list, set)) else str(model_default) + ) + + if arg.is_alias_path_only: + # For alias path only, we won't know the complete value until we've finished parsing the entire class. In + # this case, insert value as a non-string reference pointing to the relevant alias_path_only_defaults + # entry and convert into completed string value later. + value = self._update_alias_path_only_default(arg_name, value, field_info, alias_path_only_defaults) + + if _CliPositionalArg in field_info.metadata: + for value in model_default if isinstance(model_default, list) else [model_default]: + value = json.dumps(value) if isinstance(value, (dict, list, set)) else str(value) + positional_args.append(value) + continue + + # Note: prepend 'no-' for boolean optional action flag if model_default value is False and flag is not a short option + if arg.kwargs.get('action') == BooleanOptionalAction and model_default is False and flag_chars == '--': + flag_chars += 'no-' + + for coerced_value in self._coerce_value_styles( + model_default, value, list_style=list_style, dict_style=dict_style + ): + optional_args.append(f'{flag_chars}{arg_name}') + + # If implicit bool flag, do not add a value + if arg.kwargs.get('action') not in (BooleanOptionalAction, 'store_true', 'store_false'): + optional_args.append(coerced_value) + + return { + 'optional': [json.dumps(value) if not isinstance(value, str) else value for value in optional_args], + 'positional': [json.dumps(value) if not isinstance(value, str) else value for value in positional_args], + 'subcommand': subcommand_args, + } diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/dotenv.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/dotenv.py new file mode 100644 index 0000000..d4b7848 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/dotenv.py @@ -0,0 +1,210 @@ +"""Dotenv file settings source.""" + +from __future__ import annotations as _annotations + +import logging +import os +import warnings +from collections.abc import Mapping +from pathlib import Path +from typing import TYPE_CHECKING, Any + +from dotenv import dotenv_values +from pydantic._internal._typing_extra import ( # type: ignore[attr-defined] + get_origin, +) +from typing_inspection.introspection import is_union_origin + +from ...utils import _settings_debug_enabled, logger +from ..types import ENV_FILE_SENTINEL, DotenvFiltering, DotenvType, EnvPrefixTarget +from ..utils import ( + InitState, + _annotation_is_complex, + _union_is_complex, + parse_env_vars, +) +from .env import EnvSettingsSource + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + +class DotEnvSettingsSource(EnvSettingsSource): + """ + Source class for loading settings values from env files. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + env_file: DotenvType | None = ENV_FILE_SENTINEL, + env_file_encoding: str | None = None, + dotenv_filtering: DotenvFiltering | None = None, + case_sensitive: bool | None = None, + env_prefix: str | None = None, + env_prefix_target: EnvPrefixTarget | None = None, + env_nested_delimiter: str | None = None, + env_nested_max_split: int | None = None, + env_ignore_empty: bool | None = None, + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + _init_state: InitState | None = None, + ) -> None: + self.env_file = env_file if env_file != ENV_FILE_SENTINEL else settings_cls.model_config.get('env_file') + self.env_file_encoding = ( + env_file_encoding if env_file_encoding is not None else settings_cls.model_config.get('env_file_encoding') + ) + self.dotenv_filtering = ( + dotenv_filtering if dotenv_filtering is not None else settings_cls.model_config.get('dotenv_filtering') + ) + super().__init__( + settings_cls, + case_sensitive, + env_prefix, + env_prefix_target, + env_nested_delimiter, + env_nested_max_split, + env_ignore_empty, + env_parse_none_str, + env_parse_enums, + _init_state, + ) + + def _load_env_vars(self) -> Mapping[str, str | None]: + return self._read_env_files() + + @staticmethod + def _static_read_env_file( + file_path: Path, + *, + encoding: str | None = None, + case_sensitive: bool = False, + ignore_empty: bool = False, + parse_none_str: str | None = None, + ) -> Mapping[str, str | None]: + file_vars: dict[str, str | None] = dotenv_values(file_path, encoding=encoding or 'utf8') + return parse_env_vars(file_vars, case_sensitive, ignore_empty, parse_none_str) + + def _read_env_file( + self, + file_path: Path, + ) -> Mapping[str, str | None]: + return self._static_read_env_file( + file_path, + encoding=self.env_file_encoding, + case_sensitive=self.case_sensitive, + ignore_empty=self.env_ignore_empty, + parse_none_str=self.env_parse_none_str, + ) + + def _read_env_files(self) -> Mapping[str, str | None]: + env_files = self.env_file + if env_files is None: + return {} + + if isinstance(env_files, (str, os.PathLike)): + env_files = [env_files] + + debug = _settings_debug_enabled() and logger.isEnabledFor(logging.DEBUG) + + dotenv_vars: dict[str, str | None] = {} + for env_file in env_files: + env_path = Path(env_file).expanduser() + if env_path.is_file() or env_path.is_fifo(): + if debug: + logger.debug('Loading env file: %s', env_path.resolve()) + dotenv_vars.update(self._read_env_file(env_path)) + elif debug: + logger.debug('Env file not found, skipping: %s', env_path.resolve()) + + return dotenv_vars + + def __call__(self) -> dict[str, Any]: # noqa: C901 + data: dict[str, Any] = super().__call__() + if self.dotenv_filtering == 'only_existing': + # This case behaves like the EnvSettingsSource, only return existing fields + return data + if self.dotenv_filtering == 'match_prefix': + # In this case add all env vars that match the prefix, stripping the prefix. + prefix = self._apply_case_sensitive(self.env_prefix) + for env_name, env_value in self.env_vars.items(): + if env_name.startswith(prefix): + normalized_env_name = env_name[len(self.env_prefix) :] + if ( + self.env_nested_delimiter + and self.env_nested_delimiter in normalized_env_name + and normalized_env_name.partition(self.env_nested_delimiter)[0] in data + ): + continue + if normalized_env_name not in data: + data[normalized_env_name] = env_value + return data + + is_extra_allowed = self.config.get('extra') != 'forbid' + + # As `extra` config is allowed in dotenv settings source, We have to + # update data with extra env variables from dotenv file. + for env_name, env_value in self.env_vars.items(): + if not env_value or env_name in data or (self.env_prefix and env_name in self.settings_cls.model_fields): + continue + env_used = False + for field_name, field in self.settings_cls.model_fields.items(): + for _, field_env_name, _ in self._extract_field_info(field, field_name): + if env_name == field_env_name or ( + ( + _annotation_is_complex(field.annotation, field.metadata, self._init_state) + or ( + is_union_origin(get_origin(field.annotation)) + and _union_is_complex(field.annotation, field.metadata, self._init_state) + ) + ) + # A var only belongs to a complex field when it sits at the nested + # delimiter boundary (`db...`, matching what explode_env_vars + # consumes). A bare name-prefix match (e.g. `dbx_token` vs field `db`) + # must not claim the var, otherwise it is silently dropped instead of + # being kept as an extra. + and self.env_nested_delimiter + and env_name.startswith(f'{field_env_name}{self.env_nested_delimiter}') + ): + env_used = True + break + if env_used: + break + if not env_used: + if is_extra_allowed and env_name.startswith(self.env_prefix): + # env_prefix should be respected and removed from the env_name + normalized_env_name = env_name[len(self.env_prefix) :] + data[normalized_env_name] = env_value + else: + data[env_name] = env_value + return data + + def __repr__(self) -> str: + return ( + f'{self.__class__.__name__}(env_file={self.env_file!r}, env_file_encoding={self.env_file_encoding!r}, ' + f'env_nested_delimiter={self.env_nested_delimiter!r}, env_prefix_len={self.env_prefix_len!r})' + ) + + +def read_env_file( + file_path: Path, + *, + encoding: str | None = None, + case_sensitive: bool = False, + ignore_empty: bool = False, + parse_none_str: str | None = None, +) -> Mapping[str, str | None]: + warnings.warn( + 'read_env_file will be removed in the next version, use DotEnvSettingsSource._static_read_env_file if you must', + DeprecationWarning, + ) + return DotEnvSettingsSource._static_read_env_file( + file_path, + encoding=encoding, + case_sensitive=case_sensitive, + ignore_empty=ignore_empty, + parse_none_str=parse_none_str, + ) + + +__all__ = ['DotEnvSettingsSource', 'read_env_file'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/env.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/env.py new file mode 100644 index 0000000..e6c3993 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/env.py @@ -0,0 +1,382 @@ +from __future__ import annotations as _annotations + +import json +import os +from collections.abc import Mapping +from typing import ( + TYPE_CHECKING, + Any, + get_args, + get_origin, +) + +from pydantic import AliasChoices, AliasPath, Json, TypeAdapter, ValidationError +from pydantic._internal._utils import deep_update, is_model_class +from pydantic.dataclasses import is_pydantic_dataclass +from pydantic.fields import FieldInfo +from typing_inspection.introspection import is_union_origin + +from ...utils import _lenient_issubclass +from ..base import PydanticBaseEnvSettingsSource +from ..types import EnvNoneType, EnvPrefixTarget +from ..utils import ( + InitState, + _annotation_contains_types, + _annotation_enum_name_to_val, + _annotation_is_complex, + _get_model_fields, + _literal_has_numeric_enum, + _union_has_strict_types, + _union_is_complex, + parse_env_vars, +) + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + +def _environ_is_case_insensitive() -> bool: + """Whether ``os.environ`` is the OS-backed, case-insensitive mapping (i.e. on Windows). + + When ``os.environ`` has been replaced (e.g. patched to a plain ``dict`` in tests), the + requested case sensitivity is honored as-is. + """ + return os.name == 'nt' and isinstance(os.environ, os._Environ) + + +class EnvSettingsSource(PydanticBaseEnvSettingsSource): + """ + Source class for loading settings values from environment variables. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + case_sensitive: bool | None = None, + env_prefix: str | None = None, + env_prefix_target: EnvPrefixTarget | None = None, + env_nested_delimiter: str | None = None, + env_nested_max_split: int | None = None, + env_ignore_empty: bool | None = None, + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + _init_state: InitState | None = None, + ) -> None: + super().__init__( + settings_cls, + case_sensitive, + env_prefix, + env_prefix_target, + env_ignore_empty, + env_parse_none_str, + env_parse_enums, + _init_state, + ) + self.env_nested_delimiter = ( + env_nested_delimiter if env_nested_delimiter is not None else self.config.get('env_nested_delimiter') + ) + self.env_nested_max_split = ( + env_nested_max_split if env_nested_max_split is not None else self.config.get('env_nested_max_split') + ) + self.maxsplit = (self.env_nested_max_split or 0) - 1 + self.env_prefix_len = len(self.env_prefix) + + self.env_vars = self._load_env_vars() + + def _load_env_vars(self) -> Mapping[str, str | None]: + # On Windows, ``os.environ`` is case-insensitive: variable names are normalized to + # upper-case and looked up regardless of case. Matching environment variables + # case-sensitively is therefore impossible, so we fall back to case-insensitive + # matching to avoid spurious "field required" errors (see #295). ``.env`` files do + # preserve case and are handled by ``DotEnvSettingsSource``, which overrides this method. + if self.case_sensitive and _environ_is_case_insensitive(): + self.case_sensitive = False + return parse_env_vars(os.environ, self.case_sensitive, self.env_ignore_empty, self.env_parse_none_str) + + def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + """ + Gets the value for field from environment variables and a flag to determine whether value is complex. + + Args: + field: The field. + field_name: The field name. + + Returns: + A tuple that contains the value (`None` if not found), key, and + a flag to determine whether value is complex. + """ + + env_val: str | None = None + for field_key, env_name, value_is_complex in self._extract_field_info(field, field_name): + env_val = self.env_vars.get(env_name) + if env_val is not None: + break + + return env_val, field_key, value_is_complex + + def prepare_field_value(self, field_name: str, field: FieldInfo, value: Any, value_is_complex: bool) -> Any: + """ + Prepare value for the field. + + * Extract value for nested field. + * Deserialize value to python object for complex field. + + Args: + field: The field. + field_name: The field name. + + Returns: + A tuple contains prepared value for the field. + + Raises: + ValuesError: When There is an error in deserializing value for complex field. + """ + is_complex, allow_parse_failure = self._field_is_complex(field) + if self.env_parse_enums: + enum_val = _annotation_enum_name_to_val(field.annotation, value) + value = value if enum_val is None else enum_val + + if is_complex or value_is_complex: + if isinstance(value, EnvNoneType): + return value + elif value is None: + # field is complex but no value found so far, try explode_env_vars + env_val_built = self.explode_env_vars(field_name, field, self.env_vars) + if env_val_built: + return env_val_built + else: + # field is complex and there's a value, decode that as JSON, then add explode_env_vars + try: + value = self.decode_complex_value(field_name, field, value) + except ValueError: + if not allow_parse_failure: + raise + + if isinstance(value, dict): + return deep_update(value, self.explode_env_vars(field_name, field, self.env_vars)) + else: + return value + elif value is not None: + # simplest case, field is not complex, we only need to add the value if it was found + return self._coerce_env_val_strict(field, value) + + def _matches_alias_path_head(self, field: FieldInfo | Any | None, key: str) -> bool: + """ + Whether ``key`` matches the first element of a multi-part ``AliasPath`` on ``field``. + + When a nested field is aliased via e.g. ``AliasPath('path', 0)``, the env value found + under ``path`` is a container that must be JSON-decoded before pydantic can navigate + into it (see #670). This mirrors the complexity that ``_extract_field_info`` already + reports for top-level ``AliasPath`` fields. + + Args: + field: The field (or raw type) matched for ``key``. + key: The (case-normalized) env name segment matched for the field. + + Returns: + Whether ``key`` is the head of a multi-element ``AliasPath``. + """ + if not isinstance(field, FieldInfo): + return False + v_alias = field.validation_alias + paths: list[tuple[str | int, ...]] = [] + if isinstance(v_alias, AliasPath): + paths.append(tuple(v_alias.path)) + elif isinstance(v_alias, AliasChoices): + paths.extend(tuple(choice.path) for choice in v_alias.choices if isinstance(choice, AliasPath)) + for path in paths: + head = path[0] + if len(path) > 1 and isinstance(head, str) and self._apply_case_sensitive(head) == key: + return True + return False + + def _field_is_complex(self, field: FieldInfo) -> tuple[bool, bool]: + """ + Find out if a field is complex, and if so whether JSON errors should be ignored + """ + if self.field_is_complex(field): + allow_parse_failure = False + elif is_union_origin(get_origin(field.annotation)) and _union_is_complex( + field.annotation, field.metadata, self._init_state + ): + allow_parse_failure = True + else: + return False, False + + return True, allow_parse_failure + + # Default value of `case_sensitive` is `None`, because we don't want to break existing behavior. + # We have to change the method to a non-static method and use + # `self.case_sensitive` instead in V3. + def next_field( + self, field: FieldInfo | Any | None, key: str, case_sensitive: bool | None = None + ) -> FieldInfo | None: + """ + Find the field in a sub model by key(env name) + + By having the following models: + + ```py + class SubSubModel(BaseSettings): + dvals: Dict + + class SubModel(BaseSettings): + vals: list[str] + sub_sub_model: SubSubModel + + class Cfg(BaseSettings): + sub_model: SubModel + ``` + + Then: + next_field(sub_model, 'vals') Returns the `vals` field of `SubModel` class + next_field(sub_model, 'sub_sub_model') Returns `sub_sub_model` field of `SubModel` class + + Args: + field: The field. + key: The key (env name). + case_sensitive: Whether to search for key case sensitively. + + Returns: + Field if it finds the next field otherwise `None`. + """ + if not field: + return None + + annotation = field.annotation if isinstance(field, FieldInfo) else field + for type_ in get_args(annotation): + type_has_key = self.next_field(type_, key, case_sensitive) + if type_has_key: + return type_has_key + if _lenient_issubclass(get_origin(annotation), dict): + # get value type if it's a dict + return get_args(annotation)[-1] + elif is_model_class(annotation) or is_pydantic_dataclass(annotation): # type: ignore[arg-type] + fields = _get_model_fields(annotation) + # `case_sensitive is None` is here to be compatible with the old behavior. + # Has to be removed in V3. + for field_name, f in fields.items(): + for _, env_name, _ in self._extract_field_info(f, field_name): + if case_sensitive is None or case_sensitive: + if field_name == key or env_name == key: + return f + elif field_name.lower() == key.lower() or env_name.lower() == key.lower(): + return f + return None + + def explode_env_vars(self, field_name: str, field: FieldInfo, env_vars: Mapping[str, str | None]) -> dict[str, Any]: # noqa: C901 + """ + Process env_vars and extract the values of keys containing env_nested_delimiter into nested dictionaries. + + This is applied to a single field, hence filtering by env_var prefix. + + Args: + field_name: The field name. + field: The field. + env_vars: Environment variables. + + Returns: + A dictionary contains extracted values from nested env values. + """ + if not self.env_nested_delimiter: + return {} + + ann = field.annotation + is_dict = ann is dict or _lenient_issubclass(get_origin(ann), dict) + + prefixes = [ + f'{env_name}{self.env_nested_delimiter}' for _, env_name, _ in self._extract_field_info(field, field_name) + ] + result: dict[str, Any] = {} + for env_name, env_val in env_vars.items(): + try: + prefix = next(prefix for prefix in prefixes if env_name.startswith(prefix)) + except StopIteration: + continue + # we remove the prefix before splitting in case the prefix has characters in common with the delimiter + env_name_without_prefix = env_name[len(prefix) :] + *keys, last_key = env_name_without_prefix.split(self.env_nested_delimiter, self.maxsplit) + env_var = result + target_field: FieldInfo | None = field + for key in keys: + target_field = self.next_field(target_field, key, self.case_sensitive) + if isinstance(env_var, dict): + env_var = env_var.setdefault(key, {}) + + # get proper field with last_key + target_field = self.next_field(target_field, last_key, self.case_sensitive) + + # check if env_val maps to a complex field and if so, parse the env_val + if (target_field or is_dict) and env_val: + if isinstance(target_field, FieldInfo): + is_complex, allow_json_failure = self._field_is_complex(target_field) + if not is_complex and self._matches_alias_path_head(target_field, last_key): + # The env value sits under an AliasPath head (e.g. AliasPath('path', 0)); + # decode it so pydantic can navigate into the container (see #670). + is_complex, allow_json_failure = True, True + if self.env_parse_enums: + enum_val = _annotation_enum_name_to_val(target_field.annotation, env_val) + env_val = env_val if enum_val is None else enum_val + elif target_field: + # target_field is a raw type (e.g. from dict value type annotation) + is_complex = _annotation_is_complex(target_field, [], self._init_state) + allow_json_failure = True + else: + # nested field type is dict + is_complex, allow_json_failure = True, True + if is_complex: + try: + field_info = target_field if isinstance(target_field, FieldInfo) else None + env_val = self.decode_complex_value(last_key, field_info, env_val) # type: ignore + except ValueError: + if not allow_json_failure: + raise + if isinstance(env_var, dict) and ( + last_key not in env_var or not isinstance(env_val, EnvNoneType) or env_var[last_key] == {} + ): + env_var[last_key] = self._coerce_env_val_strict(target_field, env_val) + return result + + def _coerce_env_val_strict(self, field: FieldInfo | None, value: Any) -> Any: + """ + Coerce environment string values based on field annotation if model config is `strict=True` + or if the field annotation contains strict-annotated types (e.g. Optional[StrictBool]). + + Args: + field: The field. + value: The value to coerce. + + Returns: + The coerced value if successful, otherwise the original value. + """ + try: + should_coerce = self.config.get('strict') + if not should_coerce and isinstance(field, FieldInfo): + should_coerce = ( + is_union_origin(get_origin(field.annotation)) and _union_has_strict_types(field.annotation) + ) or _literal_has_numeric_enum(field.annotation) + if should_coerce and isinstance(value, str) and isinstance(field, FieldInfo): + if value == self.env_parse_none_str: + return value + if not _annotation_contains_types(field.annotation, (Json,), is_instance=True): + try: + return TypeAdapter(field.annotation).validate_python(value) + except ValidationError: + # Try JSON decoding as fallback (e.g. 'true' -> True for StrictBool) + decoded = json.loads(value) + if not isinstance(decoded, str): + return TypeAdapter(field.annotation).validate_python(decoded) + raise + except (ValidationError, json.JSONDecodeError): + # Allow validation error to be raised at time of instantiation + pass + return value + + def __repr__(self) -> str: + return ( + f'{self.__class__.__name__}(env_nested_delimiter={self.env_nested_delimiter!r}, ' + f'env_prefix_len={self.env_prefix_len!r})' + ) + + +__all__ = ['EnvSettingsSource'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/gcp.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/gcp.py new file mode 100644 index 0000000..f3a9261 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/gcp.py @@ -0,0 +1,349 @@ +from __future__ import annotations as _annotations + +import warnings +from collections.abc import Iterator, Mapping +from functools import cached_property +from typing import TYPE_CHECKING, Any + +from pydantic.fields import FieldInfo + +from ...exceptions import SettingsError +from ..types import SecretVersion +from ..utils import InitState +from .env import EnvSettingsSource + +if TYPE_CHECKING: + from google.auth import default as google_auth_default + from google.auth.credentials import Credentials + from google.cloud.secretmanager import SecretManagerServiceClient + + from pydantic_settings.main import BaseSettings +else: + Credentials = None + SecretManagerServiceClient = None + google_auth_default = None + + +def import_gcp_secret_manager() -> None: + global Credentials + global SecretManagerServiceClient + global google_auth_default + + try: + from google.auth import default as google_auth_default + from google.auth.credentials import Credentials + + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', category=FutureWarning) + from google.cloud.secretmanager import SecretManagerServiceClient + except ImportError as e: # pragma: no cover + raise ImportError( + 'GCP Secret Manager dependencies are not installed, run `pip install pydantic-settings[gcp-secret-manager]`' + ) from e + + +def _is_not_found_error(exc: Exception) -> bool: + try: + from google.api_core.exceptions import NotFound + + return isinstance(exc, NotFound) + except ImportError: + return False + + +class GoogleSecretManagerMapping(Mapping[str, str | None]): + _loaded_secrets: dict[str, str | None] + _secret_client: SecretManagerServiceClient + + def __init__(self, secret_client: SecretManagerServiceClient, project_id: str, case_sensitive: bool) -> None: + self._loaded_secrets = {} + self._secret_client = secret_client + self._project_id = project_id + self._case_sensitive = case_sensitive + + @property + def _gcp_project_path(self) -> str: + return self._secret_client.common_project_path(self._project_id) + + def _select_case_insensitive_secret(self, lower_name: str, candidates: list[str]) -> str: + if len(candidates) == 1: + return candidates[0] + + # Sort to ensure deterministic selection (prefer lowercase / ASCII last) + candidates.sort() + winner = candidates[-1] + warnings.warn( + f"Secret collision: Found multiple secrets {candidates} normalizing to '{lower_name}'. " + f"Using '{winner}' for case-insensitive lookup.", + UserWarning, + stacklevel=2, + ) + return winner + + @cached_property + def _secret_name_map(self) -> dict[str, str]: + mapping: dict[str, str] = {} + # Group secrets by normalized name to detect collisions + normalized_groups: dict[str, list[str]] = {} + + secrets = self._secret_client.list_secrets(parent=self._gcp_project_path) + for secret in secrets: + name = self._secret_client.parse_secret_path(secret.name).get('secret', '') + mapping[name] = name + + if not self._case_sensitive: + lower_name = name.lower() + if lower_name not in normalized_groups: + normalized_groups[lower_name] = [] + normalized_groups[lower_name].append(name) + + if not self._case_sensitive: + for lower_name, candidates in normalized_groups.items(): + mapping[lower_name] = self._select_case_insensitive_secret(lower_name, candidates) + + return mapping + + @property + def _secret_names(self) -> list[str]: + return list(self._secret_name_map.keys()) + + def _secret_version_path(self, key: str, version: str = 'latest') -> str: + return self._secret_client.secret_version_path(self._project_id, key, version) + + def _get_secret_value(self, gcp_secret_name: str, version: str = 'latest') -> str | None: + try: + return self._secret_client.access_secret_version( + name=self._secret_version_path(gcp_secret_name, version) + ).payload.data.decode('UTF-8') + except Exception: + return None + + def _get_secret_value_or_raise(self, gcp_secret_name: str) -> str | None: + try: + return self._secret_client.access_secret_version( + name=self._secret_version_path(gcp_secret_name) + ).payload.data.decode('UTF-8') + except Exception as e: + if _is_not_found_error(e): + raise KeyError(gcp_secret_name) from e + return None + + def __getitem__(self, key: str) -> str | None: + if key in self._loaded_secrets: + return self._loaded_secrets[key] + + if self._case_sensitive: + self._loaded_secrets[key] = self._get_secret_value_or_raise(key) + return self._loaded_secrets[key] + + gcp_secret_name = self._secret_name_map.get(key) + if gcp_secret_name is None: + gcp_secret_name = self._secret_name_map.get(key.lower()) + + if gcp_secret_name: + self._loaded_secrets[key] = self._get_secret_value(gcp_secret_name) + else: + raise KeyError(key) + + return self._loaded_secrets[key] + + def __len__(self) -> int: + return len(self._secret_names) + + def __iter__(self) -> Iterator[str]: + return iter(self._secret_names) + + +class GoogleSecretManagerSettingsSource(EnvSettingsSource): + _credentials: Credentials | None + _secret_client: SecretManagerServiceClient | None + _project_id: str | None + _explicit_project_id: str | None + + def __init__( + self, + settings_cls: type[BaseSettings], + credentials: Credentials | None = None, + project_id: str | None = None, + env_prefix: str | None = None, + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + secret_client: SecretManagerServiceClient | None = None, + case_sensitive: bool | None = True, + project_id_field: str = 'project_id', + _init_state: InitState | None = None, + ) -> None: + """Settings source that reads secrets from Google Cloud Secret Manager. + + Args: + project_id: The GCP project to read secrets from. If not provided, it is + resolved lazily (see below). + project_id_field: The key, populated by a previous (higher priority) + settings source, to use as the ``project_id`` when one is not passed + explicitly. This must match the key used in ``current_state`` by the + previous source (typically the field name or its preferred alias). + For example, with ``some_field: str = Field(alias='GCP_PROJECT')``, + previous env sources will expose the value under ``'GCP_PROJECT'``. + Defaults to ``'project_id'``. + + The ``project_id`` is resolved lazily in :meth:`__call__` rather than at + construction time so that it can be sourced from settings resolved by previous + sources (only available via ``current_state`` once the source is called). + Resolution order is: + + 1. the explicit ``project_id`` argument + 2. the ``project_id_field`` value from previous settings sources + 3. ``google.auth.default()`` + """ + # Import Google Packages if they haven't already been imported + if SecretManagerServiceClient is None or Credentials is None or google_auth_default is None: + import_gcp_secret_manager() + + # Resolution is deferred to __call__ (see _resolve_gcp_project / _load_env_vars). + # _explicit_project_id is the immutable user input; _project_id is the resolved + # value and is written exclusively by _resolve_gcp_project. + self._explicit_project_id = project_id + self._project_id = None + self._credentials = credentials + self._secret_client = secret_client + self._project_id_field = project_id_field + self._env_vars_loaded = False + + super().__init__( + settings_cls, + case_sensitive=case_sensitive, + env_prefix=env_prefix, + env_ignore_empty=False, + env_parse_none_str=env_parse_none_str, + env_parse_enums=env_parse_enums, + _init_state=_init_state, + ) + # __init__ is past; subsequent _load_env_vars() calls may now resolve the project. + self._env_vars_loaded = True + + def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + """Override get_field_value to get the secret value from GCP Secret Manager. + Look for a SecretVersion metadata field to specify a particular SecretVersion. + + Args: + field: The field to get the value for + field_name: The declared name of the field + + Returns: + A tuple of (value, key, value_is_complex), where `key` is the identifier used + to populate the model (either the field name or an alias, depending on + configuration). + """ + + secret_version = next((m.version for m in field.metadata if isinstance(m, SecretVersion)), None) + + # If a secret version is specified, try to get that specific version of the secret from + # GCP Secret Manager via the GoogleSecretManagerMapping. This allows different versions + # of the same secret name to be retrieved independently and cached in the GoogleSecretManagerMapping + if secret_version and isinstance(self.env_vars, GoogleSecretManagerMapping): + for field_key, env_name, value_is_complex in self._extract_field_info(field, field_name): + if self.case_sensitive: + gcp_secret_name: str | None = env_name + else: + gcp_secret_name = self.env_vars._secret_name_map.get(env_name) + if gcp_secret_name is None: + gcp_secret_name = self.env_vars._secret_name_map.get(env_name.lower()) + + if gcp_secret_name: + env_val = self.env_vars._get_secret_value(gcp_secret_name, secret_version) + if env_val is not None: + # If populate_by_name is enabled, return field_name to allow multiple fields + # with the same alias but different versions to be distinguished + if self.settings_cls.model_config.get('populate_by_name'): + return env_val, field_name, value_is_complex + return env_val, field_key, value_is_complex + + # If a secret version is specified but not found, we should not fall back to "latest" (default behavior) + # as that would be incorrect. We return None to indicate the value was not found. + return None, field_name, False + + val, key, is_complex = super().get_field_value(field, field_name) + + # If populate_by_name is enabled, we need to return the field_name as the key + # without this being enabled, you cannot load two secrets with the same name but different versions + if self.settings_cls.model_config.get('populate_by_name') and val is not None: + return val, field_name, is_complex + return val, key, is_complex + + def _resolve_gcp_project(self) -> None: + """Resolve the credentials, project_id and Secret Manager client. + + ``project_id`` is resolved, in order of precedence, from: the explicit + ``project_id`` argument, the ``project_id_field`` value from previous settings + sources (``current_state``), and finally ``google.auth.default()``. + """ + if self._project_id is not None: + return + + project_id = self._explicit_project_id + credentials = self._credentials + + # Fall back to a value resolved by a previous (higher priority) settings source. + if project_id is None: + state_project_id = self.current_state.get(self._project_id_field) + if isinstance(state_project_id, str): + project_id = state_project_id + + # Fall back to google.auth.default for whatever is still missing. + # Credentials are only needed if we have to build a client ourselves — if the + # caller supplied a pre-built secret_client we can skip the auth call entirely + # when project_id is also known, avoiding an unnecessary RPC / file read. + need_credentials = self._secret_client is None and credentials is None + need_project = project_id is None + if need_credentials or need_project: + _creds, _project_id = google_auth_default() + if need_credentials: + credentials = _creds + if need_project and isinstance(_project_id, str): + project_id = _project_id + + if project_id is None: + raise AttributeError( + 'project_id is required to be specified either as an argument, via a previous ' + 'settings source, or from google.auth.default. See ' + 'https://google-auth.readthedocs.io/en/master/reference/google.auth.html#google.auth.default' + ) + + self._credentials = credentials + self._project_id = project_id + if self._secret_client is None: + self._secret_client = SecretManagerServiceClient(credentials=self._credentials) + + def _load_env_vars(self) -> Mapping[str, str | None]: + # During __init__ the previous sources have not run yet, so defer building the + # mapping until __call__, where current_state (and thus project_id) is available. + if not self._env_vars_loaded: + return {} + + self._resolve_gcp_project() + if self._project_id is None or self._secret_client is None: + raise SettingsError( + 'GoogleSecretManagerSettingsSource: could not determine GCP project_id or initialize the Secret Manager client. ' + 'Pass project_id explicitly or ensure it is available via application default credentials or a previous settings source.' + ) + return GoogleSecretManagerMapping( + self._secret_client, project_id=self._project_id, case_sensitive=self.case_sensitive + ) + + def __call__(self) -> dict[str, Any]: + # current_state is populated by previous sources right before __call__; (re)build + # the mapping now so project_id can be sourced from them. + self._env_vars_loaded = True + self.env_vars = self._load_env_vars() + return super().__call__() + + def __repr__(self) -> str: + # Prefer the resolved project_id, falling back to the explicit constructor + # arg so the repr is informative before the source has been called. + project_id = self._project_id if self._project_id is not None else self._explicit_project_id + return ( + f'{self.__class__.__name__}(project_id={project_id!r}, env_nested_delimiter={self.env_nested_delimiter!r})' + ) + + +__all__ = ['GoogleSecretManagerMapping', 'GoogleSecretManagerSettingsSource'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/json.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/json.py new file mode 100644 index 0000000..872917c --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/json.py @@ -0,0 +1,53 @@ +"""JSON file settings source.""" + +from __future__ import annotations as _annotations + +import json +from typing import ( + TYPE_CHECKING, + Any, +) + +from ..base import ConfigFileSourceMixin, InitSettingsSource +from ..types import DEFAULT_PATH, ConfigFileSourceType +from ..utils import InitState + +if TYPE_CHECKING: + from pathlib import Path + + from pydantic_settings.main import BaseSettings + + from ..types import Traversable + + +class JsonConfigSettingsSource(InitSettingsSource, ConfigFileSourceMixin): + """ + A source class that loads variables from a JSON file + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + json_file: ConfigFileSourceType | None = DEFAULT_PATH, + json_file_encoding: str | None = None, + deep_merge: bool = False, + _init_state: InitState | None = None, + ): + self.json_file_path = json_file if json_file != DEFAULT_PATH else settings_cls.model_config.get('json_file') + self.json_file_encoding = ( + json_file_encoding + if json_file_encoding is not None + else settings_cls.model_config.get('json_file_encoding') + ) + self.json_data = self._read_files(self.json_file_path, deep_merge=deep_merge) + super().__init__(settings_cls, self.json_data, _init_state=_init_state) + + def _read_file(self, file_path: Path | Traversable) -> dict[str, Any]: + with file_path.open(encoding=self.json_file_encoding) as json_file: + return json.load(json_file) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(json_file={self.json_file_path})' + + +__all__ = ['JsonConfigSettingsSource'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/nested_secrets.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/nested_secrets.py new file mode 100644 index 0000000..e25df06 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/nested_secrets.py @@ -0,0 +1,214 @@ +import os +import warnings +from collections.abc import Iterator +from functools import reduce +from pathlib import Path +from typing import TYPE_CHECKING, Any, Literal, Optional + +from ...exceptions import SettingsError +from ...utils import path_type_label +from ..base import PydanticBaseSettingsSource +from ..utils import InitState, parse_env_vars +from .env import EnvSettingsSource +from .secrets import SecretsSettingsSource + +if TYPE_CHECKING: + from ...main import BaseSettings + from ...sources import PathType + + +SECRETS_DIR_MAX_SIZE = 16 * 2**20 # 16 MiB seems to be a reasonable default + + +class NestedSecretsSettingsSource(EnvSettingsSource): + def __init__( + self, + file_secret_settings: PydanticBaseSettingsSource | SecretsSettingsSource, + secrets_dir: Optional['PathType'] = None, + secrets_dir_missing: Literal['ok', 'warn', 'error'] | None = None, + secrets_dir_max_size: int | None = None, + secrets_case_sensitive: bool | None = None, + secrets_prefix: str | None = None, + secrets_nested_delimiter: str | None = None, + secrets_nested_subdir: bool | None = None, + # args for compatibility with SecretsSettingsSource, don't use directly + case_sensitive: bool | None = None, + env_prefix: str | None = None, + _init_state: InitState | None = None, + ) -> None: + # We allow the first argument to be settings_cls like original + # SecretsSettingsSource. However, it is recommended to pass + # SecretsSettingsSource instance instead (as it is shown in usage examples), + # otherwise `_secrets_dir` arg passed to Settings() constructor will be ignored. + settings_cls: type[BaseSettings] = getattr( + file_secret_settings, + 'settings_cls', + file_secret_settings, # type: ignore[arg-type] + ) + # config options + conf = settings_cls.model_config + self.secrets_dir: PathType | None = first_not_none( + getattr(file_secret_settings, 'secrets_dir', None), + secrets_dir, + conf.get('secrets_dir'), + ) + self.secrets_dir_missing: Literal['ok', 'warn', 'error'] = first_not_none( + secrets_dir_missing, + conf.get('secrets_dir_missing'), + 'warn', + ) + if self.secrets_dir_missing not in ('ok', 'warn', 'error'): + raise SettingsError(f'invalid secrets_dir_missing value: {self.secrets_dir_missing}') + self.secrets_dir_max_size: int = first_not_none( + secrets_dir_max_size, + conf.get('secrets_dir_max_size'), + SECRETS_DIR_MAX_SIZE, + ) + self.case_sensitive: bool = first_not_none( + secrets_case_sensitive, + conf.get('secrets_case_sensitive'), + case_sensitive, + conf.get('case_sensitive'), + False, + ) + self.secrets_prefix: str = first_not_none( + secrets_prefix, + conf.get('secrets_prefix'), + env_prefix, + conf.get('env_prefix'), + '', + ) + + # nested options + self.secrets_nested_delimiter: str | None = first_not_none( + secrets_nested_delimiter, + conf.get('secrets_nested_delimiter'), + conf.get('env_nested_delimiter'), + ) + self.secrets_nested_subdir: bool = first_not_none( + secrets_nested_subdir, + conf.get('secrets_nested_subdir'), + False, + ) + if self.secrets_nested_subdir: + if secrets_nested_delimiter or conf.get('secrets_nested_delimiter'): + raise SettingsError('Options secrets_nested_delimiter and secrets_nested_subdir are mutually exclusive') + else: + self.secrets_nested_delimiter = os.sep + + # ensure valid secrets_path + if self.secrets_dir is None: + paths = [] + elif isinstance(self.secrets_dir, (Path, str)): + paths = [self.secrets_dir] + else: + paths = list(self.secrets_dir) + self.secrets_paths: list[Path] = [Path(p).expanduser().resolve() for p in paths] + for path in self.secrets_paths: + self.validate_secrets_path(path) + + # construct parent, inheriting the init state of the wrapped source if not provided + super().__init__( + settings_cls, + case_sensitive=self.case_sensitive, + env_prefix=self.secrets_prefix, + env_nested_delimiter=self.secrets_nested_delimiter, + env_ignore_empty=False, # match SecretsSettingsSource behaviour + env_parse_enums=True, # we can pass everything here, it will still behave as "True" + env_parse_none_str=None, # match SecretsSettingsSource behaviour + _init_state=_init_state if _init_state is not None else getattr(file_secret_settings, '_init_state', None), + ) + self.env_parse_none_str = None # update manually because of None + + # update parent members + if not len(self.secrets_paths): + self.env_vars = {} + else: + secrets = reduce( + lambda d1, d2: dict((*d1.items(), *d2.items())), + (self.load_secrets(p) for p in self.secrets_paths), + ) + self.env_vars = parse_env_vars( + secrets, + self.case_sensitive, + self.env_ignore_empty, + self.env_parse_none_str, + ) + + def validate_secrets_path(self, path: Path) -> None: + if not path.exists(): + if self.secrets_dir_missing == 'ok': + pass + elif self.secrets_dir_missing == 'warn': + warnings.warn(f'directory "{path}" does not exist', stacklevel=2) + elif self.secrets_dir_missing == 'error': + raise SettingsError(f'directory "{path}" does not exist') + else: + raise ValueError # unreachable, checked before + else: + if not path.is_dir(): + raise SettingsError(f'secrets_dir must reference a directory, not a {path_type_label(path)}') + secrets_dir_size = sum(f.stat().st_size for f in self._iter_secret_files(path)) + if secrets_dir_size > self.secrets_dir_max_size: + raise SettingsError(f'secrets_dir size is above {self.secrets_dir_max_size} bytes') + + @staticmethod + def _iter_secret_files(path: Path) -> Iterator[Path]: + """Yield the secret files contained in ``path``. + + ``path`` is expected to already be resolved. The directory tree is walked + explicitly so that symbolic links are handled safely: + + * a file is only yielded if its real location stays within ``path``; entries + that resolve outside of it (e.g. through a symbolic link) are skipped, so + they neither contribute to the ``secrets_dir_max_size`` accounting nor get + loaded; + * each real directory is visited at most once, so cyclic or repeated + symlinks cannot make the walk loop and inflate the size accounting or the + number of loaded secrets. + + Because the size check and the loader share this iterator, they always see + the same set of files. + """ + seen_dirs: set[Path] = set() + + def walk(directory: Path) -> Iterator[Path]: + # Guard against symlink loops / a directory reachable through multiple + # links being traversed more than once. + resolved_dir = directory.resolve() + if resolved_dir in seen_dirs: + return + seen_dirs.add(resolved_dir) + try: + entries = sorted(directory.iterdir()) + except OSError: + return + for entry in entries: + resolved = entry.resolve() + if resolved.is_dir(): + # Only descend into directories that stay within secrets_dir. + # A symlinked directory pointing outside of ``path`` is not + # followed at all, so we never walk (potentially large) external + # trees and never read files from outside secrets_dir. + if resolved == path or path in resolved.parents: + yield from walk(entry) + elif resolved.is_file() and path in resolved.parents: + # Defense in depth: a file whose real location escapes + # secrets_dir (e.g. a symlink pointing outside of ``path``) is + # skipped from both the size accounting and the load. + yield entry + + yield from walk(path) + + @classmethod + def load_secrets(cls, path: Path) -> dict[str, str]: + # Explicit encoding, matching SecretsSettingsSource: the locale default would + # corrupt UTF-8 secrets on a non-UTF-8 Windows code page. + return {str(p.relative_to(path)): p.read_text(encoding='utf-8').strip() for p in cls._iter_secret_files(path)} + + def __repr__(self) -> str: + return f'NestedSecretsSettingsSource(secrets_dir={self.secrets_dir!r})' + + +def first_not_none(*objs: Any) -> Any: + return next(filter(lambda o: o is not None, objs), None) diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/pyproject.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/pyproject.py new file mode 100644 index 0000000..309b6b6 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/pyproject.py @@ -0,0 +1,64 @@ +"""Pyproject TOML file settings source.""" + +from __future__ import annotations as _annotations + +from pathlib import Path +from typing import ( + TYPE_CHECKING, +) + +from ..utils import InitState +from .toml import TomlConfigSettingsSource + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + +class PyprojectTomlConfigSettingsSource(TomlConfigSettingsSource): + """ + A source class that loads variables from a `pyproject.toml` file. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + toml_file: Path | None = None, + _init_state: InitState | None = None, + ) -> None: + self.toml_file_path = self._pick_pyproject_toml_file( + toml_file, settings_cls.model_config.get('pyproject_toml_depth', 0) + ) + self.toml_table_header: tuple[str, ...] = settings_cls.model_config.get( + 'pyproject_toml_table_header', ('tool', 'pydantic-settings') + ) + self.toml_data = self._read_files(self.toml_file_path) + for key in self.toml_table_header: + self.toml_data = self.toml_data.get(key, {}) + super(TomlConfigSettingsSource, self).__init__(settings_cls, self.toml_data, _init_state=_init_state) + + @staticmethod + def _pick_pyproject_toml_file(provided: Path | None, depth: int) -> Path: + """Pick a `pyproject.toml` file path to use. + + Args: + provided: Explicit path provided when instantiating this class. + depth: Number of directories up the tree to check of a pyproject.toml. + + """ + if provided: + return provided.resolve() + rv = Path.cwd() / 'pyproject.toml' + count = 0 + if not rv.is_file(): + child = rv.parent.parent / 'pyproject.toml' + while count < depth: + if child.is_file(): + return child + if str(child.parent) == rv.root: + break # end discovery after checking system root once + child = child.parent.parent / 'pyproject.toml' + count += 1 + return rv + + +__all__ = ['PyprojectTomlConfigSettingsSource'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/secrets.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/secrets.py new file mode 100644 index 0000000..df22acf --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/secrets.py @@ -0,0 +1,143 @@ +"""Secrets file settings source.""" + +from __future__ import annotations as _annotations + +import logging +import os +import warnings +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Any, +) + +from pydantic.fields import FieldInfo + +from pydantic_settings.utils import _settings_debug_enabled, logger, path_type_label + +from ...exceptions import SettingsError +from ..base import PydanticBaseEnvSettingsSource +from ..types import EnvPrefixTarget, PathType +from ..utils import InitState + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + +class SecretsSettingsSource(PydanticBaseEnvSettingsSource): + """ + Source class for loading settings values from secret files. + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + secrets_dir: PathType | None = None, + case_sensitive: bool | None = None, + env_prefix: str | None = None, + env_prefix_target: EnvPrefixTarget | None = None, + env_ignore_empty: bool | None = None, + env_parse_none_str: str | None = None, + env_parse_enums: bool | None = None, + _init_state: InitState | None = None, + ) -> None: + super().__init__( + settings_cls, + case_sensitive, + env_prefix, + env_prefix_target, + env_ignore_empty, + env_parse_none_str, + env_parse_enums, + _init_state, + ) + self.secrets_dir = secrets_dir if secrets_dir is not None else self.config.get('secrets_dir') + + def __call__(self) -> dict[str, Any]: + """ + Build fields from "secrets" files. + """ + secrets: dict[str, str | None] = {} + + if self.secrets_dir is None: + return secrets + + secrets_dirs = [self.secrets_dir] if isinstance(self.secrets_dir, (str, os.PathLike)) else self.secrets_dir + secrets_paths = [Path(p).expanduser() for p in secrets_dirs] + self.secrets_paths = [] + + for path in secrets_paths: + if not path.exists(): + warnings.warn(f'directory "{path}" does not exist') + else: + self.secrets_paths.append(path) + + if not len(self.secrets_paths): + return secrets + + for path in self.secrets_paths: + if not path.is_dir(): + raise SettingsError(f'secrets_dir must reference a directory, not a {path_type_label(path)}') + + return super().__call__() + + @classmethod + def find_case_path(cls, dir_path: Path, file_name: str, case_sensitive: bool) -> Path | None: + """ + Find a file within path's directory matching filename, optionally ignoring case. + + Args: + dir_path: Directory path. + file_name: File name. + case_sensitive: Whether to search for file name case sensitively. + + Returns: + Whether file path or `None` if file does not exist in directory. + """ + for f in dir_path.iterdir(): + if f.name == file_name or (not case_sensitive and f.name.lower() == file_name.lower()): + return f + return None + + def get_field_value(self, field: FieldInfo, field_name: str) -> tuple[Any, str, bool]: + """ + Gets the value for field from secret file and a flag to determine whether value is complex. + + Args: + field: The field. + field_name: The field name. + + Returns: + A tuple that contains the value (`None` if the file does not exist), key, and + a flag to determine whether value is complex. + """ + + debug = _settings_debug_enabled() and logger.isEnabledFor(logging.DEBUG) + + for field_key, env_name, value_is_complex in self._extract_field_info(field, field_name): + # paths reversed to match the last-wins behaviour of `env_file` + for secrets_path in reversed(self.secrets_paths): + path = self.find_case_path(secrets_path, env_name, self.case_sensitive) + if not path: + # path does not exist, we currently don't return a warning for this + if debug: + logger.debug('Secret file not found, skipping: %s', (secrets_path / env_name).resolve()) + continue + + if path.is_file(): + if debug: + logger.debug('Loading secret file: %s', path.resolve()) + # Explicit encoding: `read_text()` would otherwise decode with the + # locale encoding, so a UTF-8 secret is corrupted on a non-UTF-8 + # Windows code page (silently, when every byte happens to map). + return path.read_text(encoding='utf-8').strip(), field_key, value_is_complex + else: + warnings.warn( + f'attempted to load secret file "{path}" but found a {path_type_label(path)} instead.', + stacklevel=4, + ) + + return None, field_key, value_is_complex + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(secrets_dir={self.secrets_dir!r})' diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/toml.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/toml.py new file mode 100644 index 0000000..9147adc --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/toml.py @@ -0,0 +1,100 @@ +"""TOML file settings source.""" + +from __future__ import annotations as _annotations + +import sys +from collections.abc import Sequence +from pathlib import Path +from typing import ( + TYPE_CHECKING, + Any, +) + +from ..base import ConfigFileSourceMixin, InitSettingsSource +from ..types import DEFAULT_PATH, ConfigFileSourceType +from ..utils import InitState + +if TYPE_CHECKING: + from pydantic_settings.main import BaseSettings + + from ..types import Traversable + + if sys.version_info >= (3, 11): + import tomllib + else: + tomllib = None + import tomli +else: + tomllib = None + tomli = None + + +def import_toml() -> None: + global tomli + global tomllib + if sys.version_info < (3, 11): + if tomli is not None: + return + try: + import tomli + except ImportError as e: # pragma: no cover + raise ImportError('tomli is not installed, run `pip install pydantic-settings[toml]`') from e + else: + if tomllib is not None: + return + import tomllib + + +class TomlConfigSettingsSource(InitSettingsSource, ConfigFileSourceMixin): + """ + A source class that loads variables from a TOML file + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + toml_file: ConfigFileSourceType | None = DEFAULT_PATH, + toml_table_header: tuple[str, ...] = (), + deep_merge: bool = False, + _init_state: InitState | None = None, + ): + self.toml_file_path = toml_file if toml_file != DEFAULT_PATH else settings_cls.model_config.get('toml_file') + self.toml_table_header = ( + toml_table_header if toml_table_header else settings_cls.model_config.get('toml_table_header', ()) + ) + self.toml_data = self._read_files(self.toml_file_path, deep_merge=deep_merge) + + if self._any_file_exists(self.toml_file_path): + for key in self.toml_table_header: + if key not in self.toml_data: + raise KeyError(f'toml_table_header key "{key}" not found in {self.toml_file_path}') + self.toml_data = self.toml_data[key] + + super().__init__(settings_cls, self.toml_data, _init_state=_init_state) + + def _read_file(self, file_path: Path | Traversable) -> dict[str, Any]: + import_toml() + with file_path.open(mode='rb') as toml_file: + if sys.version_info < (3, 11): + return tomli.load(toml_file) + return tomllib.load(toml_file) + + @staticmethod + def _any_file_exists(paths: ConfigFileSourceType | None) -> bool: + """Check if any of the given file paths exist.""" + if paths is None: + return False + if isinstance(paths, str) or not isinstance(paths, Sequence): + paths = [paths] + + def _exists(path: Path | str | Traversable) -> bool: + if isinstance(path, (str, Path)): + return Path(path).exists() + # Non-`Path` `Traversable` (e.g. a resource inside a zip/wheel) is not + # `os.PathLike`, so it can't be wrapped in `Path`; query it directly. + return path.is_file() + + return any(_exists(path) for path in paths) + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(toml_file={self.toml_file_path}, toml_table_header={self.toml_table_header})' diff --git a/source/target-vendors/cp312/pydantic_settings/sources/providers/yaml.py b/source/target-vendors/cp312/pydantic_settings/sources/providers/yaml.py new file mode 100644 index 0000000..b3aa64e --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/providers/yaml.py @@ -0,0 +1,147 @@ +"""YAML file settings source.""" + +from __future__ import annotations as _annotations + +from typing import ( + TYPE_CHECKING, + Any, +) + +from ..base import ConfigFileSourceMixin, InitSettingsSource +from ..types import DEFAULT_PATH, ConfigFileSourceType +from ..utils import InitState + +if TYPE_CHECKING: + from pathlib import Path + + import yaml + + from pydantic_settings.main import BaseSettings + + from ..types import Traversable +else: + yaml = None + + +def import_yaml() -> None: + global yaml + if yaml is not None: + return + try: + import yaml + except ImportError as e: + raise ImportError('PyYAML is not installed, run `pip install pydantic-settings[yaml]`') from e + + +class YamlConfigSettingsSource(InitSettingsSource, ConfigFileSourceMixin): + """ + A source class that loads variables from a yaml file + """ + + def __init__( + self, + settings_cls: type[BaseSettings], + yaml_file: ConfigFileSourceType | None = DEFAULT_PATH, + yaml_file_encoding: str | None = None, + yaml_config_section: str | None = None, + deep_merge: bool = False, + _init_state: InitState | None = None, + ): + self.yaml_file_path = yaml_file if yaml_file != DEFAULT_PATH else settings_cls.model_config.get('yaml_file') + self.yaml_file_encoding = ( + yaml_file_encoding + if yaml_file_encoding is not None + else settings_cls.model_config.get('yaml_file_encoding') + ) + self.yaml_config_section = ( + yaml_config_section + if yaml_config_section is not None + else settings_cls.model_config.get('yaml_config_section') + ) + self.yaml_data = self._read_files(self.yaml_file_path, deep_merge=deep_merge) + + if self.yaml_config_section is not None: + section_data = self._traverse_nested_section( + self.yaml_data, self.yaml_config_section, self.yaml_config_section + ) + # An empty section (`section:` with no children) parses to `None`; treat it as an + # empty mapping so it falls back to defaults, mirroring `_read_file`'s `or {}` for + # an empty whole file. A non-mapping section (e.g. a scalar) is a user error, so + # raise a clear message instead of letting `InitSettingsSource` choke on `.keys()`. + if section_data is None: + section_data = {} + elif not isinstance(section_data, dict): + raise TypeError( + f'yaml_config_section "{self.yaml_config_section}" in {self.yaml_file_path} ' + f'must be a mapping, got {type(section_data).__name__}.' + ) + self.yaml_data = section_data + super().__init__(settings_cls, self.yaml_data, _init_state=_init_state) + + def _read_file(self, file_path: Path | Traversable) -> dict[str, Any]: + import_yaml() + with file_path.open(encoding=self.yaml_file_encoding) as yaml_file: + return yaml.safe_load(yaml_file) or {} + + def _traverse_nested_section( + self, data: dict[str, Any], section_path: str, original_path: str | None = None + ) -> dict[str, Any]: + """ + Traverse nested YAML sections using dot-notation path. + + This method tries to match the longest possible key first before splitting on dots, + allowing access to YAML keys that contain literal dot characters. + + For example, with section_path="a.b.c", it will try: + 1. "a.b.c" as a literal key + 2. "a.b" as a key, then traverse to "c" + 3. "a" as a key, then traverse to "b.c" + 4. "a" as a key, then "b" as a key, then "c" as a key + """ + # Track the original path for error messages + if original_path is None: + original_path = section_path + + # Only reject truly empty paths + if not section_path: + raise ValueError('yaml_config_section cannot be empty') + + # Try the full path as a literal key first (even with leading/trailing/consecutive dots) + try: + return data[section_path] + except KeyError: + pass # Not a literal key, try splitting + except TypeError: + raise TypeError( + f'yaml_config_section path "{original_path}" cannot be traversed in {self.yaml_file_path}. ' + f'An intermediate value is not a dictionary.' + ) + + # If path contains no dots, we already tried it as a literal key above + if '.' not in section_path: + raise KeyError(f'yaml_config_section key "{original_path}" not found in {self.yaml_file_path}') + + # Try progressively shorter prefixes (greedy left-to-right approach) + parts = section_path.split('.') + for i in range(len(parts) - 1, 0, -1): + prefix = '.'.join(parts[:i]) + suffix = '.'.join(parts[i:]) + + if prefix in data: + # Found the prefix as a literal key, now recursively traverse the suffix + try: + return self._traverse_nested_section(data[prefix], suffix, original_path) + except TypeError: + raise TypeError( + f'yaml_config_section path "{original_path}" cannot be traversed in {self.yaml_file_path}. ' + f'An intermediate value is not a dictionary.' + ) + + # If we get here, no match was found + raise KeyError(f'yaml_config_section key "{original_path}" not found in {self.yaml_file_path}') + + def __repr__(self) -> str: + return f'{self.__class__.__name__}(yaml_file={self.yaml_file_path})' + + +__all__ = ['YamlConfigSettingsSource'] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/types.py b/source/target-vendors/cp312/pydantic_settings/sources/types.py new file mode 100644 index 0000000..29f449f --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/types.py @@ -0,0 +1,108 @@ +"""Type definitions for pydantic-settings sources.""" + +from __future__ import annotations as _annotations + +import sys +from collections.abc import Sequence +from pathlib import Path +from typing import TYPE_CHECKING, Any, Literal + +if sys.version_info >= (3, 11): + from importlib.resources.abc import Traversable as Traversable # noqa: PLC0414 (explicit re-export) +else: + from importlib.abc import Traversable as Traversable # noqa: PLC0414 (explicit re-export) + +if TYPE_CHECKING: + from pydantic._internal._dataclasses import PydanticDataclass + from pydantic.main import BaseModel + + PydanticModel = PydanticDataclass | BaseModel +else: + PydanticModel = Any + + +class EnvNoneType(str): + pass + + +class NoDecode: + """Annotation to prevent decoding of a field value.""" + + +class ForceDecode: + """Annotation to force decoding of a field value.""" + + +EnvPrefixTarget = Literal['variable', 'alias', 'all'] +DotenvType = Path | str | Sequence[Path | str] +PathType = Path | str | Sequence[Path | str] +# Config file sources (json/toml/yaml) additionally accept packaged resources exposed as a +# `Traversable` (e.g. `importlib.resources.files(...).joinpath(...)`), including non-filesystem +# ones such as a file inside a zip/wheel. +# See https://github.com/pydantic/pydantic-settings/issues/299 +ConfigFileSourceType = Path | str | Traversable | Sequence[Path | str | Traversable] +DotenvFiltering = Literal['match_prefix', 'only_existing'] +DEFAULT_PATH: PathType = Path('') + +# This is used as default value for `_env_file` in the `BaseSettings` class and +# `env_file` in `DotEnvSettingsSource` so the default can be distinguished from `None`. +# See the docstring of `BaseSettings` for more details. +ENV_FILE_SENTINEL: DotenvType = Path('') + + +class _CliSubCommand: + pass + + +class _CliPositionalArg: + pass + + +class _CliImplicitFlag: + pass + + +class _CliToggleFlag(_CliImplicitFlag): + pass + + +class _CliDualFlag(_CliImplicitFlag): + pass + + +class _CliExplicitFlag: + pass + + +class _CliUnknownArgs: + pass + + +class SecretVersion: + def __init__(self, version: str) -> None: + self.version = version + + def __repr__(self) -> str: + return f'{self.__class__.__name__}({self.version!r})' + + +__all__ = [ + 'DEFAULT_PATH', + 'ENV_FILE_SENTINEL', + 'ConfigFileSourceType', + 'DotenvType', + 'EnvNoneType', + 'EnvPrefixTarget', + 'ForceDecode', + 'NoDecode', + 'PathType', + 'PydanticModel', + 'SecretVersion', + '_CliDualFlag', + '_CliExplicitFlag', + '_CliImplicitFlag', + '_CliPositionalArg', + '_CliSubCommand', + '_CliToggleFlag', + '_CliUnknownArgs', +] diff --git a/source/target-vendors/cp312/pydantic_settings/sources/utils.py b/source/target-vendors/cp312/pydantic_settings/sources/utils.py new file mode 100644 index 0000000..d4bec22 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/sources/utils.py @@ -0,0 +1,376 @@ +"""Utility functions for pydantic-settings sources.""" + +from __future__ import annotations as _annotations + +import warnings +from collections import deque +from collections.abc import Mapping, Sequence +from dataclasses import is_dataclass +from enum import Enum +from typing import Any, TypedDict, TypeVar, cast, get_args, get_origin + +from pydantic import BaseModel, Json, RootModel, Secret +from pydantic._internal._utils import is_model_class +from pydantic.dataclasses import is_pydantic_dataclass +from pydantic.fields import FieldInfo +from pydantic.types import Strict +from typing_inspection import typing_objects +from typing_inspection.introspection import is_union_origin + +from ..exceptions import IncompleteFieldDefinitionWarning, SettingsError +from ..utils import _lenient_issubclass +from .types import EnvNoneType + + +class InitState(TypedDict, total=False): + """State shared between settings sources during a single settings resolution.""" + + field_info_ids: set[int] + """The `id()`s of the incomplete `FieldInfo` instances that were already warned about.""" + + +def _warn_if_field_info_incomplete(field_info: FieldInfo, field_name: str, init_state: InitState) -> None: + """Warn if the field is incomplete, i.e. its annotation contains unresolved forward references. + + An incomplete `FieldInfo` instance is unsafe to inspect — any of its attributes (annotation, + aliases, metadata, default) may rely on the unresolved annotation, so settings sources may + silently fail to resolve the field's value. Each instance is only warned about once per + `init_state`, so that a field accessed by multiple sources during a single settings + resolution doesn't emit duplicate warnings. + """ + if getattr(field_info, '_complete', True): + return + warned_ids = init_state.setdefault('field_info_ids', set()) + if id(field_info) in warned_ids: + return + warned_ids.add(id(field_info)) + warnings.warn( + f'Field {field_name!r} has an incomplete definition: its annotation contains an unresolved ' + 'forward reference, so settings sources may fail to correctly resolve its value. ' + 'Call `model_rebuild()` on the model where the field is defined, once all the referenced ' + 'types are defined.', + IncompleteFieldDefinitionWarning, + ) + + +def _get_env_var_key(key: str, case_sensitive: bool = False) -> str: + return key if case_sensitive else key.lower() + + +def _parse_env_none_str(value: str | None, parse_none_str: str | None = None) -> str | None | EnvNoneType: + return value if not (value == parse_none_str and parse_none_str is not None) else EnvNoneType(value) + + +def parse_env_vars( + env_vars: Mapping[str, str | None], + case_sensitive: bool = False, + ignore_empty: bool = False, + parse_none_str: str | None = None, +) -> Mapping[str, str | None]: + return { + _get_env_var_key(k, case_sensitive): _parse_env_none_str(v, parse_none_str) + for k, v in env_vars.items() + if not (ignore_empty and v == '') + } + + +def _substitute_typevars(tp: Any, param_map: dict[Any, Any]) -> Any: + """Substitute TypeVars in a type annotation with concrete types from param_map.""" + if isinstance(tp, TypeVar) and tp in param_map: + return param_map[tp] + args = get_args(tp) + if not args: + return tp + new_args = tuple(_substitute_typevars(arg, param_map) for arg in args) + if new_args == args: + return tp + origin = get_origin(tp) + if origin is not None: + try: + return origin[new_args] + except TypeError: + # types.UnionType and similar are not directly subscriptable, + # reconstruct using | operator + import functools + import operator + + return functools.reduce(operator.or_, new_args) + return tp + + +def _resolve_type_alias(annotation: Any) -> Any: + """Resolve a TypeAliasType to its underlying value, substituting type params if parameterized.""" + if typing_objects.is_typealiastype(annotation): + return annotation.__value__ + origin = get_origin(annotation) + if typing_objects.is_typealiastype(origin): + type_params = getattr(origin, '__type_params__', ()) + type_args = get_args(annotation) + value = origin.__value__ + if type_params and type_args: + return _substitute_typevars(value, dict(zip(type_params, type_args))) + return value + return annotation + + +def _annotation_is_complex(annotation: Any, metadata: list[Any], init_state: InitState | None = None) -> bool: + # If the model is a root model, the root annotation should be used to + # evaluate the complexity. + annotation = _resolve_type_alias(annotation) + if annotation is not None and _lenient_issubclass(annotation, RootModel) and annotation is not RootModel: + annotation = cast('type[RootModel[Any]]', annotation) + root_field = annotation.model_fields['root'] + if init_state is not None: + _warn_if_field_info_incomplete(root_field, f'{annotation.__name__}.root', init_state) + root_annotation = root_field.annotation + if root_annotation is not None: # pragma: no branch + annotation = root_annotation + + if any(isinstance(md, Json) for md in metadata): # type: ignore[misc] + return False + + origin = get_origin(annotation) + + # Check if annotation is of the form Annotated[type, metadata]. + if typing_objects.is_annotated(origin): + # Return result of recursive call on inner type. + inner, *meta = get_args(annotation) + return _annotation_is_complex(inner, meta, init_state) + + if _lenient_issubclass(origin, Secret): + return False + + return ( + _annotation_is_complex_inner(annotation) + or _annotation_is_complex_inner(origin) + or hasattr(origin, '__pydantic_core_schema__') + or hasattr(origin, '__get_pydantic_core_schema__') + ) + + +def _get_field_metadata(field: FieldInfo) -> list[Any]: + annotation = _resolve_type_alias(field.annotation) + metadata = field.metadata + origin = get_origin(annotation) + if typing_objects.is_annotated(origin): + _, *meta = get_args(annotation) + metadata += meta + return metadata + + +def _annotation_is_complex_inner(annotation: type[Any] | None) -> bool: + if _lenient_issubclass(annotation, (str, bytes)): + return False + + return _lenient_issubclass( + annotation, (BaseModel, Mapping, Sequence, tuple, set, frozenset, deque) + ) or is_dataclass(annotation) + + +def _union_is_complex(annotation: type[Any] | None, metadata: list[Any], init_state: InitState | None = None) -> bool: + """Check if a union type contains any complex types.""" + for arg in get_args(annotation): + if _annotation_is_complex(arg, metadata, init_state): + return True + # _annotation_is_complex doesn't handle bare Union types, so when an arg + # is Annotated[Union[X, Y], ...], stripping Annotated yields a bare Union + # that _annotation_is_complex can't evaluate. Recurse into it, but only + # if the Annotated metadata doesn't suppress complexity (e.g. Json). + inner = _strip_annotated(arg) + if inner is not arg: + _, *inner_meta = get_args(arg) + if any(isinstance(md, Json) for md in inner_meta): # type: ignore[misc] + continue + if is_union_origin(get_origin(inner)) and _union_is_complex(inner, metadata, init_state): + return True + return False + + +def _union_has_strict_types(annotation: type[Any] | None) -> bool: + """Check if a union type contains any strict-annotated types.""" + for arg in get_args(annotation): + if typing_objects.is_annotated(get_origin(arg)): + _, *meta = get_args(arg) + if any(isinstance(m, Strict) for m in meta): + return True + return False + + +def _annotation_contains_types( + annotation: type[Any] | None, + types: tuple[Any, ...], + is_include_origin: bool = True, + is_strip_annotated: bool = False, + is_instance: bool = False, + collect: set[Any] | None = None, +) -> bool: + """Check if a type annotation contains any of the specified types.""" + if is_strip_annotated: + annotation = _strip_annotated(annotation) + if is_include_origin is True: + origin = get_origin(annotation) + if origin in types: + if collect is None: + return True + collect.add(annotation) + if is_instance and any(isinstance(origin, type_) for type_ in types): + if collect is None: + return True + collect.add(annotation) + for type_ in get_args(annotation): + if ( + _annotation_contains_types( + type_, + types, + is_include_origin=True, + is_strip_annotated=is_strip_annotated, + is_instance=is_instance, + collect=collect, + ) + and collect is None + ): + return True + if is_instance and any(isinstance(annotation, type_) for type_ in types): + if collect is None: + return True + collect.add(annotation) + if annotation in types: + if collect is not None: + collect.add(annotation) + return True + return False + + +def _strip_annotated(annotation: Any) -> Any: + if typing_objects.is_annotated(get_origin(annotation)): + return annotation.__origin__ + else: + return annotation + + +def _annotation_enum_val_to_name(annotation: type[Any] | None, value: Any) -> str | None: + for type_ in (annotation, get_origin(annotation)): + if _lenient_issubclass(type_, Enum): + enum_type = cast('type[Enum]', type_) + if value in enum_type.__members__.values(): + return enum_type(value).name + for arg in get_args(annotation): + enum_name = _annotation_enum_val_to_name(arg, value) + if enum_name is not None: + return enum_name + return None + + +def _annotation_enum_name_to_val(annotation: type[Any] | None, name: Any) -> Any: + for type_ in (annotation, get_origin(annotation)): + if _lenient_issubclass(type_, Enum): + enum_type = cast('type[Enum]', type_) + if name in enum_type.__members__: + return enum_type[name] + for arg in get_args(annotation): + enum_val = _annotation_enum_name_to_val(arg, name) + if enum_val is not None: + return enum_val + return None + + +def _literal_has_numeric_enum(annotation: type[Any] | None) -> bool: + """Check if annotation is a Literal type containing numeric Enum members (IntEnum, (int, Enum), (float, Enum)).""" + if typing_objects.is_literal(get_origin(annotation)): + return any(isinstance(arg, (int, float)) and isinstance(arg, Enum) for arg in get_args(annotation)) + # Handle Annotated wrapping, e.g. Annotated[Literal[IntEnum.member], Field(...)] + if typing_objects.is_annotated(get_origin(annotation)): + inner = get_args(annotation)[0] + return _literal_has_numeric_enum(inner) + # Handle Union/Optional wrapping, e.g. Optional[Literal[IntEnum.member]] + if is_union_origin(get_origin(annotation)): + return any(_literal_has_numeric_enum(arg) for arg in get_args(annotation)) + return False + + +def _get_model_fields(model_cls: type[Any]) -> dict[str, FieldInfo]: + """Get fields from a pydantic model or dataclass.""" + + if is_pydantic_dataclass(model_cls) and hasattr(model_cls, '__pydantic_fields__'): + return model_cls.__pydantic_fields__ + if is_model_class(model_cls): + return model_cls.model_fields + raise SettingsError(f'Error: {model_cls.__name__} is not subclass of BaseModel or pydantic.dataclasses.dataclass') + + +def _get_alias_names( + field_name: str, + field_info: FieldInfo, + alias_path_args: dict[str, int | None] | None = None, + case_sensitive: bool = True, + populate_by_name: bool = False, +) -> tuple[tuple[str, ...], bool]: + """Get alias names for a field, handling alias paths and case sensitivity.""" + from pydantic import AliasChoices, AliasPath + + alias_names: list[str] = [] + is_alias_path_only: bool = True + if not any((field_info.alias, field_info.validation_alias)): + alias_names += [field_name] + is_alias_path_only = False + else: + new_alias_paths: list[AliasPath] = [] + for alias in (field_info.alias, field_info.validation_alias): + if alias is None: + continue + elif isinstance(alias, str): + alias_names.append(alias) + is_alias_path_only = False + elif isinstance(alias, AliasChoices): + for name in alias.choices: + if isinstance(name, str): + alias_names.append(name) + is_alias_path_only = False + else: + new_alias_paths.append(name) + else: + new_alias_paths.append(alias) + for alias_path in new_alias_paths: + name = cast(str, alias_path.path[0]) + name = name.lower() if not case_sensitive else name + if alias_path_args is not None: + alias_path_args[name] = ( + alias_path.path[1] if len(alias_path.path) > 1 and isinstance(alias_path.path[1], int) else None + ) + if not alias_names and is_alias_path_only: + alias_names.append(name) + if populate_by_name and field_name not in alias_names: + alias_names.append(field_name) + is_alias_path_only = False + if not case_sensitive: + alias_names = [alias_name.lower() for alias_name in alias_names] + return tuple(dict.fromkeys(alias_names)), is_alias_path_only + + +def _is_function(obj: Any) -> bool: + """Check if an object is a function.""" + from types import BuiltinFunctionType, FunctionType + + return isinstance(obj, (FunctionType, BuiltinFunctionType)) + + +__all__ = [ + 'InitState', + '_annotation_contains_types', + '_annotation_enum_name_to_val', + '_annotation_enum_val_to_name', + '_annotation_is_complex', + '_annotation_is_complex_inner', + '_get_alias_names', + '_get_env_var_key', + '_get_model_fields', + '_is_function', + '_literal_has_numeric_enum', + '_parse_env_none_str', + '_resolve_type_alias', + '_strip_annotated', + '_union_has_strict_types', + '_union_is_complex', + '_warn_if_field_info_incomplete', + 'parse_env_vars', +] diff --git a/source/target-vendors/cp312/pydantic_settings/utils.py b/source/target-vendors/cp312/pydantic_settings/utils.py new file mode 100644 index 0000000..7bd6fe8 --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/utils.py @@ -0,0 +1,55 @@ +import logging +import os +import types +from pathlib import Path +from typing import Any, _Final, _GenericAlias, get_origin # type: ignore [attr-defined] + +logger = logging.getLogger('pydantic_settings') + +_DEBUG_ENV_VAR = 'PYDANTIC_SETTINGS_DEBUG' + + +def _settings_debug_enabled() -> bool: + """Whether settings source debugging is enabled via the `PYDANTIC_SETTINGS_DEBUG` env var.""" + return os.environ.get(_DEBUG_ENV_VAR, '').strip().lower() in ('1', 'true', 'yes', 'on') + + +_PATH_TYPE_LABELS = { + Path.is_dir: 'directory', + Path.is_file: 'file', + Path.is_mount: 'mount point', + Path.is_symlink: 'symlink', + Path.is_block_device: 'block device', + Path.is_char_device: 'char device', + Path.is_fifo: 'FIFO', + Path.is_socket: 'socket', +} + + +def path_type_label(p: Path) -> str: + """ + Find out what sort of thing a path is. + """ + assert p.exists(), 'path does not exist' + for method, name in _PATH_TYPE_LABELS.items(): + if method(p): + return name + + return 'unknown' # pragma: no cover + + +# TODO remove and replace usage by `isinstance(cls, type) and issubclass(cls, class_or_tuple)` +# once we drop support for Python 3.10. +def _lenient_issubclass(cls: Any, class_or_tuple: Any) -> bool: # pragma: no cover + try: + return isinstance(cls, type) and issubclass(cls, class_or_tuple) + except TypeError: + if get_origin(cls) is not None: + # Up until Python 3.10, isinstance(, type) is True + # (e.g. list[int]) + return False + raise + + +_WithArgsTypes = (_GenericAlias, types.GenericAlias, types.UnionType) +_typing_base: Any = _Final # pyright: ignore[reportAttributeAccessIssue] diff --git a/source/target-vendors/cp312/pydantic_settings/version.py b/source/target-vendors/cp312/pydantic_settings/version.py new file mode 100644 index 0000000..b4e42de --- /dev/null +++ b/source/target-vendors/cp312/pydantic_settings/version.py @@ -0,0 +1 @@ +VERSION = '2.15.0' diff --git a/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/METADATA b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/METADATA new file mode 100644 index 0000000..0db0043 --- /dev/null +++ b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/METADATA @@ -0,0 +1,93 @@ +Metadata-Version: 2.4 +Name: PyJWT +Version: 2.14.0 +Summary: JSON Web Token implementation in Python +Author-email: Jose Padilla +License-Expression: MIT +Project-URL: Homepage, https://github.com/jpadilla/pyjwt +Keywords: json,jwt,security,signing,token,web +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Topic :: Utilities +Requires-Python: >=3.9 +Description-Content-Type: text/x-rst +License-File: LICENSE +License-File: AUTHORS.rst +Requires-Dist: typing_extensions>=4.0; python_version < "3.11" +Provides-Extra: crypto +Requires-Dist: cryptography>=3.4.0; extra == "crypto" +Dynamic: license-file + +PyJWT +===== + +.. image:: https://github.com/jpadilla/pyjwt/workflows/CI/badge.svg + :target: https://github.com/jpadilla/pyjwt/actions?query=workflow%3ACI + +.. image:: https://img.shields.io/pypi/v/pyjwt.svg + :target: https://pypi.python.org/pypi/pyjwt + +.. image:: https://codecov.io/gh/jpadilla/pyjwt/branch/master/graph/badge.svg + :target: https://codecov.io/gh/jpadilla/pyjwt + +.. image:: https://readthedocs.org/projects/pyjwt/badge/?version=stable + :target: https://pyjwt.readthedocs.io/en/stable/ + +A Python implementation of `RFC 7519 `_. Original implementation was written by `@progrium `_. + +Sponsor +------- + +.. |auth0-logo| image:: https://github.com/user-attachments/assets/ee98379e-ee76-4bcb-943a-e25c4ea6d174 + :width: 160px + ++--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| |auth0-logo| | If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at `auth0.com/signup `_. | ++--------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Installing +---------- + +Install with **pip**: + +.. code-block:: console + + $ pip install PyJWT + + +Usage +----- + +.. code-block:: pycon + + >>> import jwt + >>> encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256") + >>> print(encoded) + eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg + >>> jwt.decode(encoded, "secret", algorithms=["HS256"]) + {'some': 'payload'} + +Documentation +------------- + +View the full docs online at https://pyjwt.readthedocs.io/en/stable/ + + +Tests +----- + +You can run tests from the project root after cloning with: + +.. code-block:: console + + $ tox diff --git a/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/RECORD b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/RECORD new file mode 100644 index 0000000..478b91f --- /dev/null +++ b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/RECORD @@ -0,0 +1,19 @@ +jwt/__init__.py,sha256=BWR5W0NaQShI2w1ngQD9E4qjCWB16MzjZHUcfkJ9YP0,1805 +jwt/algorithms.py,sha256=vsUpnHXbHUvXpfnxw4LIX8ZIAlcVt-UisyDhYdOutVo,40244 +jwt/api_jwk.py,sha256=XfmRO9SEb-fSV7nADDn4vGEcdfgydMmK5QM4p8sgxj8,6328 +jwt/api_jws.py,sha256=oMV41OCcgjr-AZ7T4LBvsYTGZf80z-QExoIprjJyJp0,17421 +jwt/api_jwt.py,sha256=iP4AZ7WXxyarU6SZYyB4IqGo79vBOGAxRr1DJGAM2hg,22244 +jwt/exceptions.py,sha256=NUD0h2A0MiHV6U-TPt_Ar0prnAHxyJJ0i6LHIWzd8VQ,2375 +jwt/help.py,sha256=HB3ZsrJVclR0XY-sDH-Lvl5K7ae5QidGiU6WyTAnYhs,1784 +jwt/jwk_set_cache.py,sha256=A395RCkJUDxKLj_M6RZUkS405AeDepEwztU4k4xDSoU,961 +jwt/jwks_client.py,sha256=ALpi3iPIyA2Q-x9zU5qPvzLEepWdjQ-69R5GgAxBmrc,11764 +jwt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jwt/types.py,sha256=R46Bkno1V08fquxnVr71AvW6uEPilHJlqkgX6ObZFnw,3174 +jwt/utils.py,sha256=5OPU-vCxXEegSZQAiOJWQ0tlZpIOxxY8FyzkdoTCmsA,4067 +jwt/warnings.py,sha256=iQTvP-NPDQA-tuhPhjifEkYRqMUgte99iOPMJc_DLJk,330 +pyjwt-2.14.0.dist-info/licenses/AUTHORS.rst,sha256=klzkNGECnu2_VY7At89_xLBF3vUSDruXk3xwgUBxzwc,322 +pyjwt-2.14.0.dist-info/licenses/LICENSE,sha256=eXp6ICMdTEM-nxkR2xcx0GtYKLmPSZgZoDT3wPVvXOU,1085 +pyjwt-2.14.0.dist-info/METADATA,sha256=uFTrRhqu74BGlhIhB4asH79tEGTx1Rr17iYZt7vdsbo,3449 +pyjwt-2.14.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91 +pyjwt-2.14.0.dist-info/top_level.txt,sha256=RP5DHNyJbMq2ka0FmfTgoSaQzh7e3r5XuCWCO8a00k8,4 +pyjwt-2.14.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/WHEEL b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/WHEEL new file mode 100644 index 0000000..13013d7 --- /dev/null +++ b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (84.0.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/AUTHORS.rst b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/AUTHORS.rst new file mode 100644 index 0000000..88e2b6a --- /dev/null +++ b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/AUTHORS.rst @@ -0,0 +1,7 @@ +Authors +======= + +``pyjwt`` is currently written and maintained by `Jose Padilla `_. +Originally written and maintained by `Jeff Lindsay `_. + +A full list of contributors can be found on GitHub’s `overview `_. diff --git a/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..fd0ecbc --- /dev/null +++ b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-2022 José Padilla + +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/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/top_level.txt b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/top_level.txt new file mode 100644 index 0000000..27ccc9b --- /dev/null +++ b/source/target-vendors/cp312/pyjwt-2.14.0.dist-info/top_level.txt @@ -0,0 +1 @@ +jwt diff --git a/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/METADATA b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/METADATA new file mode 100644 index 0000000..9bc77db --- /dev/null +++ b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/METADATA @@ -0,0 +1,820 @@ +Metadata-Version: 2.4 +Name: python-dotenv +Version: 1.2.3 +Summary: Read key-value pairs from a .env file and set them as environment variables +Author-email: Saurabh Kumar +License: BSD-3-Clause +Project-URL: Source, https://github.com/theskumar/python-dotenv +Keywords: environment variables,deployments,settings,env,dotenv,configurations,python +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: Operating System :: OS Independent +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities +Classifier: Environment :: Web Environment +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-File: LICENSE +Provides-Extra: cli +Requires-Dist: click>=5.0; extra == "cli" +Dynamic: license-file + +# python-dotenv + +[![Build Status][build_status_badge]][build_status_link] +[![PyPI version][pypi_badge]][pypi_link] + +python-dotenv reads key-value pairs from a `.env` file and can set them as +environment variables. It helps in the development of applications following the +[12-factor](https://12factor.net/) principles. + +- [Getting Started](#getting-started) +- [Other Use Cases](#other-use-cases) + - [Load configuration without altering the environment](#load-configuration-without-altering-the-environment) + - [Parse configuration as a stream](#parse-configuration-as-a-stream) + - [Load .env files in IPython](#load-env-files-in-ipython) +- [Command-line Interface](#command-line-interface) +- [File format](#file-format) + - [Multiline values](#multiline-values) + - [Variable expansion](#variable-expansion) +- [Related Projects](#related-projects) +- [Acknowledgements](#acknowledgements) + +## Getting Started + +```shell +pip install python-dotenv +``` + +If your application takes its configuration from environment variables, like a +12-factor application, launching it in development is not very practical because +you have to set those environment variables yourself. + +To help you with that, you can add python-dotenv to your application to make it +load the configuration from a `.env` file when it is present (e.g. in +development) while remaining configurable via the environment: + +```python +from dotenv import load_dotenv + +load_dotenv() # reads variables from a .env file and sets them in os.environ + +# Code of your application, which uses environment variables (e.g. from `os.environ` or +# `os.getenv`) as if they came from the actual environment. +``` + +By default, `load_dotenv()` will: + +- Look for a `.env` file in the same directory as the Python script (or higher up the directory tree). +- Read each key-value pair and add it to `os.environ`. +- **Not override** existing environment variables (`override=False`). Pass `override=True` to override existing variables. + +To configure the development environment, add a `.env` in the root directory of +your project: + +``` +. +├── .env +└── foo.py +``` + +The syntax of `.env` files supported by python-dotenv is similar to that of +Bash: + +```bash +# Development settings +DOMAIN=example.org +ADMIN_EMAIL=admin@${DOMAIN} +ROOT_URL=${DOMAIN}/app +``` + +If you use variables in values, ensure they are surrounded with `{` and `}`, +like `${DOMAIN}`, as bare variables such as `$DOMAIN` are not expanded. + +You will probably want to add `.env` to your `.gitignore`, especially if it +contains secrets like a password. + +See the section "[File format](#file-format)" below for more information about what you can write in a `.env` file. + +## Other Use Cases + +### Load configuration without altering the environment + +The function `dotenv_values` works more or less the same way as `load_dotenv`, +except it doesn't touch the environment, it just returns a `dict` with the +values parsed from the `.env` file. + +```python +from dotenv import dotenv_values + +config = dotenv_values(".env") # config = {"USER": "foo", "EMAIL": "foo@example.org"} +``` + +This notably enables advanced configuration management: + +```python +import os +from dotenv import dotenv_values + +config = { + **dotenv_values(".env.shared"), # load shared development variables + **dotenv_values(".env.secret"), # load sensitive variables + **os.environ, # override loaded values with environment variables +} +``` + +### Parse configuration as a stream + +`load_dotenv` and `dotenv_values` accept [streams][python_streams] via their +`stream` argument. It is thus possible to load the variables from sources other +than the filesystem (e.g. the network). + +```python +from io import StringIO + +from dotenv import load_dotenv + +config = StringIO("USER=foo\nEMAIL=foo@example.org") +load_dotenv(stream=config) +``` + +### Load .env files in IPython + +You can use dotenv in IPython. By default, it will use `find_dotenv` to search for a +`.env` file: + +```python +%load_ext dotenv +%dotenv +``` + +You can also specify a path: + +```python +%dotenv relative/or/absolute/path/to/.env +``` + +Optional flags: + +- `-o` to override existing variables. +- `-v` for increased verbosity. + +### Disable load_dotenv + +Set `PYTHON_DOTENV_DISABLED=1` to disable `load_dotenv()` from loading .env +files or streams. Useful when you can't modify third-party package calls or in +production. + +## Command-line Interface + +A CLI interface `dotenv` is also included, which helps you manipulate the `.env` +file without manually opening it. + +```shell +$ pip install "python-dotenv[cli]" +$ dotenv set USER foo +$ dotenv set EMAIL foo@example.org +$ dotenv list +USER=foo +EMAIL=foo@example.org +$ dotenv list --format=json +{ + "USER": "foo", + "EMAIL": "foo@example.org" +} +$ dotenv run -- python foo.py +``` + +Run `dotenv --help` for more information about the options and subcommands. + +## File format + +The format is not formally specified and still improves over time. That being +said, `.env` files should mostly look like Bash files. Reading from FIFOs (named +pipes) on Unix systems is also supported. + +Keys can be unquoted or single-quoted. Values can be unquoted, single- or +double-quoted. Spaces before and after keys, equal signs, and values are +ignored. Values can be followed by a comment. Lines can start with the `export` +directive, which does not affect their interpretation. + +Allowed escape sequences: + +- in single-quoted values: `\\`, `\'` +- in double-quoted values: `\\`, `\'`, `\"`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v` + +### Multiline values + +It is possible for single- or double-quoted values to span multiple lines. The +following examples are equivalent: + +```bash +FOO="first line +second line" +``` + +```bash +FOO="first line\nsecond line" +``` + +### Variable without a value + +A variable can have no value: + +```bash +FOO +``` + +It results in `dotenv_values` associating that variable name with the value +`None` (e.g. `{"FOO": None}`. `load_dotenv`, on the other hand, simply ignores +such variables. + +This shouldn't be confused with `FOO=`, in which case the variable is associated +with the empty string. + +### Variable expansion + +python-dotenv can interpolate variables using POSIX variable expansion. + +With `load_dotenv(override=True)` or `dotenv_values()`, the value of a variable +is the first of the values defined in the following list: + +- Value of that variable in the `.env` file. +- Value of that variable in the environment. +- Default value, if provided. +- Empty string. + +With `load_dotenv(override=False)`, the value of a variable is the first of the +values defined in the following list: + +- Value of that variable in the environment. +- Value of that variable in the `.env` file. +- Default value, if provided. +- Empty string. + +## Related Projects + +- [environs](https://github.com/sloria/environs) +- [Honcho](https://github.com/nickstenning/honcho) +- [dump-env](https://github.com/sobolevn/dump-env) +- [dynaconf](https://github.com/dynaconf/dynaconf) +- [parse_it](https://github.com/naorlivne/parse_it) +- [django-dotenv](https://github.com/jpadilla/django-dotenv) +- [django-environ](https://github.com/joke2k/django-environ) +- [python-decouple](https://github.com/HBNetwork/python-decouple) +- [django-configuration](https://github.com/jezdez/django-configurations) + +## Acknowledgements + +This project is currently maintained by [Saurabh Kumar][saurabh-homepage] and +[Bertrand Bonnefoy-Claudet][gh-bbc2] and would not have been possible without +the support of these [awesome people][contributors]. + +[gh-bbc2]: https://github.com/bbc2 +[saurabh-homepage]: https://saurabh-kumar.com +[pypi_link]: https://badge.fury.io/py/python-dotenv +[pypi_badge]: https://badge.fury.io/py/python-dotenv.svg +[python_streams]: https://docs.python.org/3/library/io.html +[contributors]: https://github.com/theskumar/python-dotenv/graphs/contributors +[build_status_link]: https://github.com/theskumar/python-dotenv/actions/workflows/test.yml +[build_status_badge]: https://github.com/theskumar/python-dotenv/actions/workflows/test.yml/badge.svg + +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this +project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.2.3] - 2026-08-16 + +### Fixed + +- Strip a leading UTF-8 BOM from `.env` file contents so the first variable is no longer silently lost when the file is saved with BOM (e.g. by some JetBrains IDEs on Windows) by [@h1whelan] in [#640] +- `set_key` now escapes backslashes, so values containing them (Windows paths, regular expressions) survive a write/read round-trip. Quoted values ending in an escaped backslash are no longer mis-parsed as an escaped quote, which used to swallow the following lines by [@dchaudhari7177] in [#680] +- `dotenv run` now prints a friendly error instead of a traceback when no command is given by [@bbc2] in [#606] +- Cache the parsed result for empty `.env` files so repeated `dotenv_values`/`load_dotenv` calls no longer re-read the file by [@ReinerBRO] in [#638] + +## [1.2.2] - 2026-03-01 + +### Added + +- Support for Python 3.14, including the free-threaded (3.14t) build. (#588) + +### Changed + +- The `dotenv run` command now forwards flags directly to the specified command by [@bbc2] in [#607] +- Improved documentation clarity regarding override behavior and the reference page. +- Updated PyPy support to version 3.11. +- Documentation for FIFO file support. +- Dropped Support for Python 3.9. + +### Fixed + +- Improved `set_key` and `unset_key` behavior when interacting with symlinks by [@bbc2] in [790c5c0] +- Corrected the license specifier and added missing Python 3.14 classifiers in package metadata by [@JYOuyang] in [#590] + +### Breaking Changes + +- `dotenv.set_key` and `dotenv.unset_key` used to follow symlinks in some + situations. This is no longer the case. For that behavior to be restored in + all cases, `follow_symlinks=True` should be used. + +- In the CLI, `set` and `unset` used to follow symlinks in some situations. This + is no longer the case. + +- `dotenv.set_key`, `dotenv.unset_key` and the CLI commands `set` and `unset` + used to reset the file mode of the modified .env file to `0o600` in some + situations. This is no longer the case: The original mode of the file is now + preserved. Is the file needed to be created or wasn't a regular file, mode + `0o600` is used. + +## [1.2.1] - 2025-10-26 + +- Move more config to `pyproject.toml`, removed `setup.cfg` +- Add support for reading `.env` from FIFOs (Unix) by [@sidharth-sudhir] in [#586] + +## [1.2.0] - 2025-10-26 + +- Upgrade build system to use PEP 517 & PEP 518 to use `build` and `pyproject.toml` by [@EpicWink] in [#583] +- Add support for Python 3.14 by [@23f3001135] in [#579] +- Add support for disabling of `load_dotenv()` using `PYTHON_DOTENV_DISABLED` env var. by [@matthewfranglen] in [#569] + +## [1.1.1] - 2025-06-24 + +### Fixed + +- CLI: Ensure `find_dotenv` work reliably on python 3.13 by [@theskumar] in [#563] +- CLI: revert the use of execvpe on Windows by [@wrongontheinternet] in [#566] + +## [1.1.0] - 2025-03-25 + +### Added + +- Add support for python 3.13 +- Enhance `dotenv run`, switch to `execvpe` for better resource management and signal handling ([#523]) by [@eekstunt] + +### Fixed + +- `find_dotenv` and `load_dotenv` now correctly looks up at the current directory when running in debugger or pdb ([#553] by [@randomseed42]) + +### Misc + +- Drop support for Python 3.8 + +## [1.0.1] - 2024-01-23 + +### Fixed + +- Gracefully handle code which has been imported from a zipfile ([#456] by [@samwyma]) +- Allow modules using `load_dotenv` to be reloaded when launched in a separate thread ([#497] by [@freddyaboulton]) +- Fix file not closed after deletion, handle error in the rewrite function ([#469] by [@Qwerty-133]) + +### Misc + +- Use pathlib.Path in tests ([#466] by [@eumiro]) +- Fix year in release date in changelog.md ([#454] by [@jankislinger]) +- Use https in README links ([#474] by [@Nicals]) + +## [1.0.0] - 2023-02-24 + +### Fixed + +- Drop support for python 3.7, add python 3.12-dev (#449 by [@theskumar]) +- Handle situations where the cwd does not exist. (#446 by [@jctanner]) + +## [0.21.1] - 2023-01-21 + +### Added + +- Use Python 3.11 non-beta in CI (#438 by [@bbc2]) +- Modernize variables code (#434 by [@Nougat-Waffle]) +- Modernize main.py and parser.py code (#435 by [@Nougat-Waffle]) +- Improve conciseness of cli.py and **init**.py (#439 by [@Nougat-Waffle]) +- Improve error message for `get` and `list` commands when env file can't be opened (#441 by [@bbc2]) +- Updated License to align with BSD OSI template (#433 by [@lsmith77]) + +### Fixed + +- Fix Out-of-scope error when "dest" variable is undefined (#413 by [@theGOTOguy]) +- Fix IPython test warning about deprecated `magic` (#440 by [@bbc2]) +- Fix type hint for dotenv_path var, add StrPath alias (#432 by [@eaf]) + +## [0.21.0] - 2022-09-03 + +### Added + +- CLI: add support for invocations via 'python -m'. (#395 by [@theskumar]) +- `load_dotenv` function now returns `False`. (#388 by [@larsks]) +- CLI: add --format= option to list command. (#407 by [@sammck]) + +### Fixed + +- Drop Python 3.5 and 3.6 and upgrade GA (#393 by [@eggplants]) +- Use `open` instead of `io.open`. (#389 by [@rabinadk1]) +- Improve documentation for variables without a value (#390 by [@bbc2]) +- Add `parse_it` to Related Projects (#410 by [@naorlivne]) +- Update README.md (#415 by [@harveer07]) +- Improve documentation with direct use of MkDocs (#398 by [@bbc2]) + +## [0.20.0] - 2022-03-24 + +### Added + +- Add `encoding` (`Optional[str]`) parameter to `get_key`, `set_key` and `unset_key`. + (#379 by [@bbc2]) + +### Fixed + +- Use dict to specify the `entry_points` parameter of `setuptools.setup` (#376 by + [@mgorny]). +- Don't build universal wheels (#387 by [@bbc2]). + +## [0.19.2] - 2021-11-11 + +### Fixed + +- In `set_key`, add missing newline character before new entry if necessary. (#361 by + [@bbc2]) + +## [0.19.1] - 2021-08-09 + +### Added + +- Add support for Python 3.10. (#359 by [@theskumar]) + +## [0.19.0] - 2021-07-24 + +### Changed + +- Require Python 3.5 or a later version. Python 2 and 3.4 are no longer supported. (#341 + by [@bbc2]). + +### Added + +- The `dotenv_path` argument of `set_key` and `unset_key` now has a type of `Union[str, +os.PathLike]` instead of just `os.PathLike` (#347 by [@bbc2]). +- The `stream` argument of `load_dotenv` and `dotenv_values` can now be a text stream + (`IO[str]`), which includes values like `io.StringIO("foo")` and `open("file.env", +"r")` (#348 by [@bbc2]). + +## [0.18.0] - 2021-06-20 + +### Changed + +- Raise `ValueError` if `quote_mode` isn't one of `always`, `auto` or `never` in + `set_key` (#330 by [@bbc2]). +- When writing a value to a .env file with `set_key` or `dotenv set ` (#330 + by [@bbc2]): + - Use single quotes instead of double quotes. + - Don't strip surrounding quotes. + - In `auto` mode, don't add quotes if the value is only made of alphanumeric characters + (as determined by `string.isalnum`). + +## [0.17.1] - 2021-04-29 + +### Fixed + +- Fixed tests for build environments relying on `PYTHONPATH` (#318 by [@befeleme]). + +## [0.17.0] - 2021-04-02 + +### Changed + +- Make `dotenv get ` only show the value, not `key=value` (#313 by [@bbc2]). + +### Added + +- Add `--override`/`--no-override` option to `dotenv run` (#312 by [@zueve] and [@bbc2]). + +## [0.16.0] - 2021-03-27 + +### Changed + +- The default value of the `encoding` parameter for `load_dotenv` and `dotenv_values` is + now `"utf-8"` instead of `None` (#306 by [@bbc2]). +- Fix resolution order in variable expansion with `override=False` (#287 by [@bbc2]). + +## [0.15.0] - 2020-10-28 + +### Added + +- Add `--export` option to `set` to make it prepend the binding with `export` (#270 by + [@jadutter]). + +### Changed + +- Make `set` command create the `.env` file in the current directory if no `.env` file was + found (#270 by [@jadutter]). + +### Fixed + +- Fix potentially empty expanded value for duplicate key (#260 by [@bbc2]). +- Fix import error on Python 3.5.0 and 3.5.1 (#267 by [@gongqingkui]). +- Fix parsing of unquoted values containing several adjacent space or tab characters + (#277 by [@bbc2], review by [@x-yuri]). + +## [0.14.0] - 2020-07-03 + +### Changed + +- Privilege definition in file over the environment in variable expansion (#256 by + [@elbehery95]). + +### Fixed + +- Improve error message for when file isn't found (#245 by [@snobu]). +- Use HTTPS URL in package meta data (#251 by [@ekohl]). + +## [0.13.0] - 2020-04-16 + +### Added + +- Add support for a Bash-like default value in variable expansion (#248 by [@bbc2]). + +## [0.12.0] - 2020-02-28 + +### Changed + +- Use current working directory to find `.env` when bundled by PyInstaller (#213 by + [@gergelyk]). + +### Fixed + +- Fix escaping of quoted values written by `set_key` (#236 by [@bbc2]). +- Fix `dotenv run` crashing on environment variables without values (#237 by [@yannham]). +- Remove warning when last line is empty (#238 by [@bbc2]). + +## [0.11.0] - 2020-02-07 + +### Added + +- Add `interpolate` argument to `load_dotenv` and `dotenv_values` to disable interpolation + (#232 by [@ulyssessouza]). + +### Changed + +- Use logging instead of warnings (#231 by [@bbc2]). + +### Fixed + +- Fix installation in non-UTF-8 environments (#225 by [@altendky]). +- Fix PyPI classifiers (#228 by [@bbc2]). + +## [0.10.5] - 2020-01-19 + +### Fixed + +- Fix handling of malformed lines and lines without a value (#222 by [@bbc2]): + - Don't print warning when key has no value. + - Reject more malformed lines (e.g. "A: B", "a='b',c"). +- Fix handling of lines with just a comment (#224 by [@bbc2]). + +## [0.10.4] - 2020-01-17 + +### Added + +- Make typing optional (#179 by [@techalchemy]). +- Print a warning on malformed line (#211 by [@bbc2]). +- Support keys without a value (#220 by [@ulyssessouza]). + +## 0.10.3 + +- Improve interactive mode detection ([@andrewsmith])([#183]). +- Refactor parser to fix parsing inconsistencies ([@bbc2])([#170]). + - Interpret escapes as control characters only in double-quoted strings. + - Interpret `#` as start of comment only if preceded by whitespace. + +## 0.10.2 + +- Add type hints and expose them to users ([@qnighy])([#172]) +- `load_dotenv` and `dotenv_values` now accept an `encoding` parameter, defaults to `None` + ([@theskumar])([@earlbread])([#161]) +- Fix `str`/`unicode` inconsistency in Python 2: values are always `str` now. ([@bbc2])([#121]) +- Fix Unicode error in Python 2, introduced in 0.10.0. ([@bbc2])([#176]) + +## 0.10.1 + +- Fix parsing of variable without a value ([@asyncee])([@bbc2])([#158]) + +## 0.10.0 + +- Add support for UTF-8 in unquoted values ([@bbc2])([#148]) +- Add support for trailing comments ([@bbc2])([#148]) +- Add backslashes support in values ([@bbc2])([#148]) +- Add support for newlines in values ([@bbc2])([#148]) +- Force environment variables to str with Python2 on Windows ([@greyli]) +- Drop Python 3.3 support ([@greyli]) +- Fix stderr/-out/-in redirection ([@venthur]) + +## 0.9.0 + +- Add `--version` parameter to cli ([@venthur]) +- Enable loading from current directory ([@cjauvin]) +- Add 'dotenv run' command for calling arbitrary shell script with .env ([@venthur]) + +## 0.8.1 + +- Add tests for docs ([@Flimm]) +- Make 'cli' support optional. Use `pip install python-dotenv[cli]`. ([@theskumar]) + +## 0.8.0 + +- `set_key` and `unset_key` only modified the affected file instead of + parsing and re-writing file, this causes comments and other file + entact as it is. +- Add support for `export` prefix in the line. +- Internal refractoring ([@theskumar]) +- Allow `load_dotenv` and `dotenv_values` to work with `StringIO())` ([@alanjds])([@theskumar])([#78]) + +## 0.7.1 + +- Remove hard dependency on iPython ([@theskumar]) + +## 0.7.0 + +- Add support to override system environment variable via .env. + ([@milonimrod](https://github.com/milonimrod)) + ([\#63](https://github.com/theskumar/python-dotenv/issues/63)) +- Disable ".env not found" warning by default + ([@maxkoryukov](https://github.com/maxkoryukov)) + ([\#57](https://github.com/theskumar/python-dotenv/issues/57)) + +## 0.6.5 + +- Add support for special characters `\`. + ([@pjona](https://github.com/pjona)) + ([\#60](https://github.com/theskumar/python-dotenv/issues/60)) + +## 0.6.4 + +- Fix issue with single quotes ([@Flimm]) + ([\#52](https://github.com/theskumar/python-dotenv/issues/52)) + +## 0.6.3 + +- Handle unicode exception in setup.py + ([\#46](https://github.com/theskumar/python-dotenv/issues/46)) + +## 0.6.2 + +- Fix dotenv list command ([@ticosax](https://github.com/ticosax)) +- Add iPython Support + ([@tillahoffmann](https://github.com/tillahoffmann)) + +## 0.6.0 + +- Drop support for Python 2.6 +- Handle escaped characters and newlines in quoted values. (Thanks + [@iameugenejo](https://github.com/iameugenejo)) +- Remove any spaces around unquoted key/value. (Thanks + [@paulochf](https://github.com/paulochf)) +- Added POSIX variable expansion. (Thanks + [@hugochinchilla](https://github.com/hugochinchilla)) + +## 0.5.1 + +- Fix `find_dotenv` - it now start search from the file where this + function is called from. + +## 0.5.0 + +- Add `find_dotenv` method that will try to find a `.env` file. + (Thanks [@isms](https://github.com/isms)) + +## 0.4.0 + +- cli: Added `-q/--quote` option to control the behaviour of quotes + around values in `.env`. (Thanks + [@hugochinchilla](https://github.com/hugochinchilla)). +- Improved test coverage. + + + +[#78]: https://github.com/theskumar/python-dotenv/issues/78 +[#121]: https://github.com/theskumar/python-dotenv/issues/121 +[#148]: https://github.com/theskumar/python-dotenv/issues/148 +[#158]: https://github.com/theskumar/python-dotenv/issues/158 +[#170]: https://github.com/theskumar/python-dotenv/issues/170 +[#172]: https://github.com/theskumar/python-dotenv/issues/172 +[#176]: https://github.com/theskumar/python-dotenv/issues/176 +[#183]: https://github.com/theskumar/python-dotenv/issues/183 +[#359]: https://github.com/theskumar/python-dotenv/issues/359 +[#469]: https://github.com/theskumar/python-dotenv/issues/469 +[#456]: https://github.com/theskumar/python-dotenv/issues/456 +[#466]: https://github.com/theskumar/python-dotenv/issues/466 +[#454]: https://github.com/theskumar/python-dotenv/issues/454 +[#474]: https://github.com/theskumar/python-dotenv/issues/474 +[#523]: https://github.com/theskumar/python-dotenv/issues/523 +[#553]: https://github.com/theskumar/python-dotenv/issues/553 +[#569]: https://github.com/theskumar/python-dotenv/issues/569 +[#583]: https://github.com/theskumar/python-dotenv/issues/583 +[#586]: https://github.com/theskumar/python-dotenv/issues/586 +[#590]: https://github.com/theskumar/python-dotenv/issues/590 +[#607]: https://github.com/theskumar/python-dotenv/issues/607 +[#588]: https://github.com/theskumar/python-dotenv/issues/588 +[#579]: https://github.com/theskumar/python-dotenv/pull/579 +[#566]: https://github.com/theskumar/python-dotenv/pull/566 +[#563]: https://github.com/theskumar/python-dotenv/pull/563 +[#497]: https://github.com/theskumar/python-dotenv/pull/497 +[#161]: https://github.com/theskumar/python-dotenv/issues/161 +[#606]: https://github.com/theskumar/python-dotenv/pull/606 +[#638]: https://github.com/theskumar/python-dotenv/pull/638 +[#640]: https://github.com/theskumar/python-dotenv/pull/640 +[#680]: https://github.com/theskumar/python-dotenv/pull/680 +[790c5c0]: https://github.com/theskumar/python-dotenv/commit/790c5c02991100aa1bf41ee5330aca75edc51311 + + + +[@23f3001135]: https://github.com/23f3001135 +[@EpicWink]: https://github.com/EpicWink +[@Flimm]: https://github.com/Flimm +[@Nicals]: https://github.com/Nicals +[@Nougat-Waffle]: https://github.com/Nougat-Waffle +[@Qwerty-133]: https://github.com/Qwerty-133 +[@ReinerBRO]: https://github.com/ReinerBRO +[@alanjds]: https://github.com/alanjds +[@altendky]: https://github.com/altendky +[@andrewsmith]: https://github.com/andrewsmith +[@asyncee]: https://github.com/asyncee +[@bbc2]: https://github.com/bbc2 +[@befeleme]: https://github.com/befeleme +[@cjauvin]: https://github.com/cjauvin +[@dchaudhari7177]: https://github.com/dchaudhari7177 +[@eaf]: https://github.com/eaf +[@earlbread]: https://github.com/earlbread +[@eekstunt]: https://github.com/eekstunt +[@eggplants]: https://github.com/eggplants +[@ekohl]: https://github.com/ekohl +[@elbehery95]: https://github.com/elbehery95 +[@eumiro]: https://github.com/eumiro +[@freddyaboulton]: https://github.com/freddyaboulton +[@gergelyk]: https://github.com/gergelyk +[@gongqingkui]: https://github.com/gongqingkui +[@greyli]: https://github.com/greyli +[@h1whelan]: https://github.com/h1whelan +[@harveer07]: https://github.com/harveer07 +[@jadutter]: https://github.com/jadutter +[@jankislinger]: https://github.com/jankislinger +[@jctanner]: https://github.com/jctanner +[@larsks]: https://github.com/larsks +[@lsmith77]: https://github.com/lsmith77 +[@matthewfranglen]: https://github.com/matthewfranglen +[@mgorny]: https://github.com/mgorny +[@naorlivne]: https://github.com/naorlivne +[@qnighy]: https://github.com/qnighy +[@rabinadk1]: https://github.com/rabinadk1 +[@randomseed42]: https://github.com/randomseed42 +[@sammck]: https://github.com/sammck +[@samwyma]: https://github.com/samwyma +[@sidharth-sudhir]: https://github.com/sidharth-sudhir +[@snobu]: https://github.com/snobu +[@techalchemy]: https://github.com/techalchemy +[@theGOTOguy]: https://github.com/theGOTOguy +[@theskumar]: https://github.com/theskumar +[@ulyssessouza]: https://github.com/ulyssessouza +[@venthur]: https://github.com/venthur +[@wrongontheinternet]: https://github.com/wrongontheinternet +[@x-yuri]: https://github.com/x-yuri +[@yannham]: https://github.com/yannham +[@zueve]: https://github.com/zueve +[@JYOuyang]: https://github.com/JYOuyang +[@burnout-projects]: https://github.com/burnout-projects +[@cpackham-atlnz]: https://github.com/cpackham-atlnz +[Unreleased]: https://github.com/theskumar/python-dotenv/compare/v1.2.3...HEAD +[1.2.3]: https://github.com/theskumar/python-dotenv/compare/v1.2.2...v1.2.3 +[1.2.2]: https://github.com/theskumar/python-dotenv/compare/v1.2.1...v1.2.2 +[1.2.1]: https://github.com/theskumar/python-dotenv/compare/v1.2.0...v1.2.1 +[1.2.0]: https://github.com/theskumar/python-dotenv/compare/v1.1.1...v1.2.0 +[1.1.1]: https://github.com/theskumar/python-dotenv/compare/v1.1.0...v1.1.1 +[1.1.0]: https://github.com/theskumar/python-dotenv/compare/v1.0.1...v1.1.0 +[1.0.1]: https://github.com/theskumar/python-dotenv/compare/v1.0.0...v1.0.1 +[1.0.0]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v1.0.0 +[0.21.1]: https://github.com/theskumar/python-dotenv/compare/v0.21.0...v0.21.1 +[0.21.0]: https://github.com/theskumar/python-dotenv/compare/v0.20.0...v0.21.0 +[0.20.0]: https://github.com/theskumar/python-dotenv/compare/v0.19.2...v0.20.0 +[0.19.2]: https://github.com/theskumar/python-dotenv/compare/v0.19.1...v0.19.2 +[0.19.1]: https://github.com/theskumar/python-dotenv/compare/v0.19.0...v0.19.1 +[0.19.0]: https://github.com/theskumar/python-dotenv/compare/v0.18.0...v0.19.0 +[0.18.0]: https://github.com/theskumar/python-dotenv/compare/v0.17.1...v0.18.0 +[0.17.1]: https://github.com/theskumar/python-dotenv/compare/v0.17.0...v0.17.1 +[0.17.0]: https://github.com/theskumar/python-dotenv/compare/v0.16.0...v0.17.0 +[0.16.0]: https://github.com/theskumar/python-dotenv/compare/v0.15.0...v0.16.0 +[0.15.0]: https://github.com/theskumar/python-dotenv/compare/v0.14.0...v0.15.0 +[0.14.0]: https://github.com/theskumar/python-dotenv/compare/v0.13.0...v0.14.0 +[0.13.0]: https://github.com/theskumar/python-dotenv/compare/v0.12.0...v0.13.0 +[0.12.0]: https://github.com/theskumar/python-dotenv/compare/v0.11.0...v0.12.0 +[0.11.0]: https://github.com/theskumar/python-dotenv/compare/v0.10.5...v0.11.0 +[0.10.5]: https://github.com/theskumar/python-dotenv/compare/v0.10.4...v0.10.5 +[0.10.4]: https://github.com/theskumar/python-dotenv/compare/v0.10.3...v0.10.4 diff --git a/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/RECORD b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/RECORD new file mode 100644 index 0000000..da675af --- /dev/null +++ b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/RECORD @@ -0,0 +1,15 @@ +dotenv/__init__.py,sha256=bhY-iK6wwHZamWII6eSCuCAWXUNdn2TQFmEOuXSU7SM,1230 +dotenv/__main__.py,sha256=N0RhLG7nHIqtlJHwwepIo-zbJPNx9sewCCRGY528h_4,129 +dotenv/cli.py,sha256=jFR-2VtVH0kthcycgcVeR2quvtADksFKT_3aO4AHy7s,6865 +dotenv/ipython.py,sha256=dHQBd9PcdCUphGb67Xwy3GkUqMSdf9XUUiNYxTZ3tYU,1326 +dotenv/main.py,sha256=aX6zPu5114tz22Hq-Wv5plR1SMGBHJNQG2fgVuVHDeo,15179 +dotenv/parser.py,sha256=YFJTOmzU4K1QUv6I5ZNoUwWcKO0_7A8JjNKafLN23KQ,5394 +dotenv/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26 +dotenv/variables.py,sha256=CD0qXOvvpB3q5RpBQMD9qX6vHX7SyW-SuiwGMFSlt08,2348 +dotenv/version.py,sha256=C-D_WWrVkBDmQmApLcm0sWNh2CgIrwWfc8_sB5vvU-Q,22 +python_dotenv-1.2.3.dist-info/licenses/LICENSE,sha256=gGGbcEnwjIFoOtDgHwjyV6hAZS3XHugxRtNmWMfSwrk,1556 +python_dotenv-1.2.3.dist-info/METADATA,sha256=I4DqlwB5a3OY_YFW4i-QKK_l7r-RjrhKa9XrsKj907U,29008 +python_dotenv-1.2.3.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91 +python_dotenv-1.2.3.dist-info/entry_points.txt,sha256=yRl1rCbswb1nQTQ_gZRlCw5QfabztUGnfGWLhlXFNdI,47 +python_dotenv-1.2.3.dist-info/top_level.txt,sha256=eyqUH4SHJNr6ahOYlxIunTr4XinE8Z5ajWLdrK3r0D8,7 +python_dotenv-1.2.3.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/WHEEL b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/WHEEL new file mode 100644 index 0000000..13013d7 --- /dev/null +++ b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (84.0.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/entry_points.txt b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/entry_points.txt new file mode 100644 index 0000000..0a86823 --- /dev/null +++ b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +dotenv = dotenv.__main__:cli diff --git a/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/licenses/LICENSE b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/licenses/LICENSE new file mode 100644 index 0000000..3a97119 --- /dev/null +++ b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/licenses/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014, Saurabh Kumar (python-dotenv), 2013, Ted Tieken (django-dotenv-rw), 2013, Jacob Kaplan-Moss (django-dotenv) + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of django-dotenv nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/top_level.txt b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/top_level.txt new file mode 100644 index 0000000..fe7c01a --- /dev/null +++ b/source/target-vendors/cp312/python_dotenv-1.2.3.dist-info/top_level.txt @@ -0,0 +1 @@ +dotenv diff --git a/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/METADATA b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/METADATA new file mode 100644 index 0000000..d00853e --- /dev/null +++ b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/METADATA @@ -0,0 +1,43 @@ +Metadata-Version: 2.4 +Name: python-multipart +Version: 0.0.32 +Summary: A streaming multipart parser for Python +Project-URL: Homepage, https://github.com/Kludex/python-multipart +Project-URL: Documentation, https://kludex.github.io/python-multipart/ +Project-URL: Changelog, https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md +Project-URL: Source, https://github.com/Kludex/python-multipart +Author-email: Andrew Dunham +Maintainer-email: Marcelo Trylesinski +License-Expression: Apache-2.0 +License-File: LICENSE.txt +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=3.10 +Description-Content-Type: text/markdown + +# [Python-Multipart](https://kludex.github.io/python-multipart/) + +[![Build Status](https://github.com/Kludex/python-multipart/workflows/CI/badge.svg)](https://github.com/Kludex/python-multipart/actions) +[![Package version](https://badge.fury.io/py/python-multipart.svg)](https://pypi.python.org/pypi/python-multipart) +[![Supported Python Version](https://img.shields.io/pypi/pyversions/python-multipart.svg?color=%2334D058)](https://pypi.org/project/python-multipart) +[![Discord](https://img.shields.io/discord/1051468649518616576?logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/RxKUF5JuHs) + +--- + +`python-multipart` is an Apache2-licensed streaming multipart parser for Python. +Test coverage is currently 100%. + +## Why? + +Because streaming uploads are awesome for large files. diff --git a/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/RECORD b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/RECORD new file mode 100644 index 0000000..2e2bab8 --- /dev/null +++ b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/RECORD @@ -0,0 +1,13 @@ +multipart/__init__.py,sha256=gbY7W9NUdsFZavp-iKQroN4FxonfZqzokkLW5B3jnZ0,1474 +multipart/decoders.py,sha256=XvkAwTU9UFPiXkc0hkvovHf0W6H3vK-2ieWlhav02hQ,40 +multipart/exceptions.py,sha256=6D_X-seiOmMAlIeiGlPGUs8-vpcvIGJeQycFMDb1f7A,42 +multipart/multipart.py,sha256=8fDH14j_VMbrch_58wlzi63XNARGv80kOZAyN72aG7A,41 +python_multipart/__init__.py,sha256=qr5CNo-H4S3lUCU61_h2_FczSuUdjzK_1E4aa06kFPo,937 +python_multipart/decoders.py,sha256=dJmwSRxowd5Xp3s86aIpU8f_Y55Kr0H4f5wgvScidEM,6676 +python_multipart/exceptions.py,sha256=U0lNBjhR4dQI97zV02aQpULQbDjjLqyWk90h5NrCxWA,954 +python_multipart/multipart.py,sha256=Ozy3ZJqDzJa6f4CgsiU4xO9DOb5PPVyUSrT72Rhfn6I,79407 +python_multipart/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +python_multipart-0.0.32.dist-info/METADATA,sha256=6dOZ196l7d8OTSS1wkaHqC5-UL8sKzD4-KBqZNiH3YY,2131 +python_multipart-0.0.32.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87 +python_multipart-0.0.32.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 +python_multipart-0.0.32.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/WHEEL b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/WHEEL new file mode 100644 index 0000000..bd84226 --- /dev/null +++ b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.30.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/licenses/LICENSE.txt b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/source/target-vendors/cp312/python_multipart-0.0.32.dist-info/licenses/LICENSE.txt @@ -0,0 +1,202 @@ + + 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/source/target-vendors/cp312/python_multipart/__init__.py b/source/target-vendors/cp312/python_multipart/__init__.py new file mode 100644 index 0000000..7b60cac --- /dev/null +++ b/source/target-vendors/cp312/python_multipart/__init__.py @@ -0,0 +1,35 @@ +# Copyright 2012, Andrew Dunham +# +# 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. + +__version__ = "0.0.32" + +from .multipart import ( + BaseParser, + FormParser, + MultipartParser, + OctetStreamParser, + QuerystringParser, + create_form_parser, + parse_form, +) + +__all__ = ( + "BaseParser", + "FormParser", + "MultipartParser", + "OctetStreamParser", + "QuerystringParser", + "create_form_parser", + "parse_form", +) diff --git a/source/target-vendors/cp312/python_multipart/decoders.py b/source/target-vendors/cp312/python_multipart/decoders.py new file mode 100644 index 0000000..c4cdfb6 --- /dev/null +++ b/source/target-vendors/cp312/python_multipart/decoders.py @@ -0,0 +1,185 @@ +import base64 +import binascii +from typing import TYPE_CHECKING + +from .exceptions import DecodeError + +if TYPE_CHECKING: # pragma: no cover + from typing import Protocol, TypeVar + + _T_contra = TypeVar("_T_contra", contravariant=True) + + class SupportsWrite(Protocol[_T_contra]): + def write(self, __b: _T_contra) -> object: ... + + # No way to specify optional methods. See + # https://github.com/python/typing/issues/601 + # close() [Optional] + # finalize() [Optional] + + +class Base64Decoder: + """This object provides an interface to decode a stream of Base64 data. It + is instantiated with an "underlying object", and whenever a write() + operation is performed, it will decode the incoming data as Base64, and + call write() on the underlying object. This is primarily used for decoding + form data encoded as Base64, but can be used for other purposes:: + + from python_multipart.decoders import Base64Decoder + fd = open("notb64.txt", "wb") + decoder = Base64Decoder(fd) + try: + decoder.write("Zm9vYmFy") # "foobar" in Base64 + decoder.finalize() + finally: + decoder.close() + + # The contents of "notb64.txt" should be "foobar". + + This object will also pass all finalize() and close() calls to the + underlying object, if the underlying object supports them. + + Note that this class maintains a cache of base64 chunks, so that a write of + arbitrary size can be performed. You must call :meth:`finalize` on this + object after all writes are completed to ensure that all data is flushed + to the underlying object. + + :param underlying: the underlying object to pass writes to + """ + + def __init__(self, underlying: "SupportsWrite[bytes]") -> None: + self.cache = bytearray() + self.underlying = underlying + + def write(self, data: bytes) -> int: + """Takes any input data provided, decodes it as base64, and passes it + on to the underlying object. If the data provided is invalid base64 + data, then this method will raise + a :class:`python_multipart.exceptions.DecodeError` + + :param data: base64 data to decode + """ + + # Prepend any cache info to our data. + if len(self.cache) > 0: + data = bytes(self.cache) + data + + # Slice off a string that's a multiple of 4. + decode_len = (len(data) // 4) * 4 + val = data[:decode_len] + + # Decode and write, if we have any. + if len(val) > 0: + try: + decoded = base64.b64decode(val) + except binascii.Error: + raise DecodeError("There was an error raised while decoding base64-encoded data.") + + self.underlying.write(decoded) + + # Get the remaining bytes and save in our cache. + remaining_len = len(data) % 4 + if remaining_len > 0: + self.cache[:] = data[-remaining_len:] + else: + self.cache[:] = b"" + + # Return the length of the data to indicate no error. + return len(data) + + def close(self) -> None: + """Close this decoder. If the underlying object has a `close()` + method, this function will call it. + """ + if hasattr(self.underlying, "close"): + self.underlying.close() + + def finalize(self) -> None: + """Finalize this object. This should be called when no more data + should be written to the stream. This function can raise a + :class:`python_multipart.exceptions.DecodeError` if there is some remaining + data in the cache. + + If the underlying object has a `finalize()` method, this function will + call it. + """ + if len(self.cache) > 0: + raise DecodeError( + "There are %d bytes remaining in the Base64Decoder cache when finalize() is called" % len(self.cache) + ) + + if hasattr(self.underlying, "finalize"): + self.underlying.finalize() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(underlying={self.underlying!r})" + + +class QuotedPrintableDecoder: + """This object provides an interface to decode a stream of quoted-printable + data. It is instantiated with an "underlying object", in the same manner + as the :class:`python_multipart.decoders.Base64Decoder` class. This class behaves + in exactly the same way, including maintaining a cache of quoted-printable + chunks. + + :param underlying: the underlying object to pass writes to + """ + + def __init__(self, underlying: "SupportsWrite[bytes]") -> None: + self.cache = b"" + self.underlying = underlying + + def write(self, data: bytes) -> int: + """Takes any input data provided, decodes it as quoted-printable, and + passes it on to the underlying object. + + :param data: quoted-printable data to decode + """ + # Prepend any cache info to our data. + if len(self.cache) > 0: + data = self.cache + data + + # If the last 2 characters have an '=' sign in it, then we won't be + # able to decode the encoded value and we'll need to save it for the + # next decoding step. + if data[-2:].find(b"=") != -1: + enc, rest = data[:-2], data[-2:] + else: + enc = data + rest = b"" + + # Encode and write, if we have data. + if len(enc) > 0: + self.underlying.write(binascii.a2b_qp(enc)) + + # Save remaining in cache. + self.cache = rest + return len(data) + + def close(self) -> None: + """Close this decoder. If the underlying object has a `close()` + method, this function will call it. + """ + if hasattr(self.underlying, "close"): + self.underlying.close() + + def finalize(self) -> None: + """Finalize this object. This should be called when no more data + should be written to the stream. This function will not raise any + exceptions, but it may write more data to the underlying object if + there is data remaining in the cache. + + If the underlying object has a `finalize()` method, this function will + call it. + """ + # If we have a cache, write and then remove it. + if len(self.cache) > 0: # pragma: no cover + self.underlying.write(binascii.a2b_qp(self.cache)) + self.cache = b"" + + # Finalize our underlying stream. + if hasattr(self.underlying, "finalize"): + self.underlying.finalize() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(underlying={self.underlying!r})" diff --git a/source/target-vendors/cp312/python_multipart/exceptions.py b/source/target-vendors/cp312/python_multipart/exceptions.py new file mode 100644 index 0000000..2e7df21 --- /dev/null +++ b/source/target-vendors/cp312/python_multipart/exceptions.py @@ -0,0 +1,34 @@ +class FormParserError(ValueError): + """Base error class for our form parser.""" + + +class ParseError(FormParserError): + """This exception (or a subclass) is raised when there is an error while + parsing something. + """ + + def __init__(self, message: str, *, offset: int = -1) -> None: + super().__init__(message) + self.offset = offset + + +class MultipartParseError(ParseError): + """This is a specific error that is raised when the MultipartParser detects + an error while parsing. + """ + + +class QuerystringParseError(ParseError): + """This is a specific error that is raised when the QuerystringParser + detects an error while parsing. + """ + + +class DecodeError(ParseError): + """This exception is raised when there is a decoding error - for example + with the Base64Decoder or QuotedPrintableDecoder. + """ + + +class FileError(FormParserError, OSError): + """Exception class for problems with the File class.""" diff --git a/source/target-vendors/cp312/python_multipart/multipart.py b/source/target-vendors/cp312/python_multipart/multipart.py new file mode 100644 index 0000000..887cf60 --- /dev/null +++ b/source/target-vendors/cp312/python_multipart/multipart.py @@ -0,0 +1,1925 @@ +from __future__ import annotations + +import logging +import os +import shutil +import sys +import tempfile +from enum import IntEnum +from io import BufferedRandom, BytesIO +from numbers import Number +from typing import TYPE_CHECKING, cast + +from .decoders import Base64Decoder, QuotedPrintableDecoder +from .exceptions import FileError, FormParserError, MultipartParseError, QuerystringParseError + +if TYPE_CHECKING: + from collections.abc import Callable + from typing import Any, Literal, Protocol, TypeAlias, TypedDict + + class SupportsRead(Protocol): + def read(self, __n: int) -> bytes: ... + + class QuerystringCallbacks(TypedDict, total=False): + on_field_start: Callable[[], None] + on_field_name: Callable[[bytes, int, int], None] + on_field_data: Callable[[bytes, int, int], None] + on_field_end: Callable[[], None] + on_end: Callable[[], None] + + class OctetStreamCallbacks(TypedDict, total=False): + on_start: Callable[[], None] + on_data: Callable[[bytes, int, int], None] + on_end: Callable[[], None] + + class MultipartCallbacks(TypedDict, total=False): + on_part_begin: Callable[[], None] + on_part_data: Callable[[bytes, int, int], None] + on_part_end: Callable[[], None] + on_header_begin: Callable[[], None] + on_header_field: Callable[[bytes, int, int], None] + on_header_value: Callable[[bytes, int, int], None] + on_header_end: Callable[[], None] + on_headers_finished: Callable[[], None] + on_end: Callable[[], None] + + class FileConfig(TypedDict, total=False): + UPLOAD_DIR: str | bytes | None + UPLOAD_DELETE_TMP: bool + UPLOAD_KEEP_FILENAME: bool + UPLOAD_KEEP_EXTENSIONS: bool + MAX_MEMORY_FILE_SIZE: int + + class FormParserConfig(FileConfig): + UPLOAD_ERROR_ON_BAD_CTE: bool + MAX_BODY_SIZE: float + MAX_HEADER_COUNT: int + MAX_HEADER_SIZE: int + + CallbackName: TypeAlias = Literal[ + "start", + "data", + "end", + "field_start", + "field_name", + "field_data", + "field_end", + "part_begin", + "part_data", + "part_end", + "header_begin", + "header_field", + "header_value", + "header_end", + "headers_finished", + ] + +# Unique missing object. +_missing = object() + + +class QuerystringState(IntEnum): + """Querystring parser states. + + These are used to keep track of the state of the parser, and are used to determine + what to do when new data is encountered. + """ + + BEFORE_FIELD = 0 + FIELD_NAME = 1 + FIELD_DATA = 2 + + +class MultipartState(IntEnum): + """Multipart parser states. + + These are used to keep track of the state of the parser, and are used to determine + what to do when new data is encountered. + """ + + START = 0 + START_BOUNDARY = 1 + HEADER_FIELD_START = 2 + HEADER_FIELD = 3 + HEADER_VALUE_START = 4 + HEADER_VALUE = 5 + HEADER_VALUE_ALMOST_DONE = 6 + HEADERS_ALMOST_DONE = 7 + PART_DATA_START = 8 + PART_DATA = 9 + PART_DATA_END = 10 + END_BOUNDARY = 11 + END = 12 + + +# Flags for the multipart parser. +FLAG_PART_BOUNDARY = 1 +FLAG_LAST_BOUNDARY = 2 + +# Get constants. Since iterating over a str on Python 2 gives you a 1-length +# string, but iterating over a bytes object on Python 3 gives you an integer, +# we need to save these constants. +CR = b"\r"[0] +LF = b"\n"[0] +COLON = b":"[0] +SPACE = b" "[0] +HYPHEN = b"-"[0] +AMPERSAND = b"&"[0] +LOWER_A = b"a"[0] +LOWER_Z = b"z"[0] +NULL = b"\x00"[0] + +# fmt: off +# Mask for ASCII characters that can be http tokens. +# Per RFC7230 - 3.2.6, this is all alpha-numeric characters +# and these: !#$%&'*+-.^_`|~ +TOKEN_CHARS = ( + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + b"abcdefghijklmnopqrstuvwxyz" + b"0123456789" + b"!#$%&'*+-.^_`|~") +TOKEN_CHARS_SET = frozenset(TOKEN_CHARS) +# fmt: on + +DEFAULT_MAX_HEADER_COUNT = 8 +"""Default maximum number of headers allowed per multipart part.""" + +DEFAULT_MAX_HEADER_SIZE = 4096 + 128 +"""Default maximum size of a single multipart header line, including syntax overhead.""" + +MAX_BOUNDARY_LENGTH = 256 +"""Maximum allowed length of a multipart boundary. + +[RFC 2046 §5.1.1](https://datatracker.ietf.org/doc/html/rfc2046#section-5.1.1) +recommends boundaries be at most 70 bytes. 256 bytes is generous headroom over +every HTTP client. +""" + + +def _parseparam(s: str) -> list[str]: + # Vendored from the standard library's + # [`email.message._parseparam`](https://github.com/python/cpython/blob/v3.14.2/Lib/email/message.py#L73-L96) + # to split a header into its `;`-separated parts without treating a `;` inside a double-quoted string as a + # separator - and without the RFC 2231 decoding that `email.message.Message.get_params` would apply on top. + s = ";" + s + plist: list[str] = [] + start = 0 + while s.find(";", start) == start: + start += 1 + end = s.find(";", start) + ind, diff = start, 0 + while end > 0: + diff += s.count('"', ind, end) - s.count('\\"', ind, end) + if diff % 2 == 0: + break + end, ind = ind, s.find(";", end + 1) + if end < 0: + end = len(s) + i = s.find("=", start, end) + if i == -1: + f = s[start:end] + else: + f = s[start:i].rstrip().lower() + "=" + s[i + 1 : end].lstrip() + plist.append(f.strip()) + start = end + return plist + + +def parse_options_header(value: str | bytes | None) -> tuple[bytes, dict[bytes, bytes]]: + """Parses a Content-Type header into a value in the following format: (content_type, {parameters}).""" + if not value: + return (b"", {}) + + # If we are passed bytes, we assume that it conforms to WSGI, encoding in latin-1. + if isinstance(value, bytes): # pragma: no cover + value = value.decode("latin-1") + + # For types + assert isinstance(value, str), "Value should be a string by now" + + # If we have no options, return the string as-is. + if ";" not in value: + return (value.lower().strip().encode("latin-1"), {}) + + ctype, *segments = _parseparam(value) + options: dict[bytes, bytes] = {} + for segment in segments: + key, _, val = segment.partition("=") + # [RFC 7578 §4.2](https://datatracker.ietf.org/doc/html/rfc7578#section-4.2) + # forbids the RFC 5987/2231 extended syntax (`key*=`, `key*0`, ...) in + # multipart/form-data, so we ignore those parameters and keep the plain + # `key` authoritative. + if "*" in key: + continue + if len(val) >= 2 and val[0] == '"' and val[-1] == '"': + val = val[1:-1].replace("\\\\", "\\").replace('\\"', '"') + # Work around an IE6 bug where the full file path is sent instead of + # just the filename. + if key == "filename" and (val[1:3] == ":\\" or val[:2] == "\\\\"): + val = val.split("\\")[-1] + options[key.encode("latin-1")] = val.encode("latin-1") + return ctype.encode("latin-1"), options + + +class Field: + """A Field object represents a (parsed) form field. It represents a single + field with a corresponding name and value. + + The name that a :class:`Field` will be instantiated with is the same name + that would be found in the following HTML:: + + + + This class defines two methods, :meth:`on_data` and :meth:`on_end`, that + will be called when data is written to the Field, and when the Field is + finalized, respectively. + + Args: + name: The name of the form field. + content_type: The value of the Content-Type header for this field. + """ + + def __init__(self, name: bytes | None, *, content_type: str | None = None) -> None: + self._name = name + self._value: list[bytes] = [] + self._content_type = content_type + + # We cache the joined version of _value for speed. + self._cache = _missing + + @classmethod + def from_value(cls, name: bytes, value: bytes | None) -> Field: + """Create an instance of a :class:`Field`, and set the corresponding + value - either None or an actual value. This method will also + finalize the Field itself. + + Args: + name: the name of the form field. + value: the value of the form field - either a bytestring or None. + + Returns: + A new instance of a [`Field`][python_multipart.Field]. + """ + + f = cls(name) + if value is None: + f.set_none() + else: + f.write(value) + f.finalize() + return f + + def write(self, data: bytes) -> int: + """Write some data into the form field. + + Args: + data: The data to write to the field. + + Returns: + The number of bytes written. + """ + return self.on_data(data) + + def on_data(self, data: bytes) -> int: + """This method is a callback that will be called whenever data is + written to the Field. + + Args: + data: The data to write to the field. + + Returns: + The number of bytes written. + """ + self._value.append(data) + self._cache = _missing + return len(data) + + def on_end(self) -> None: + """This method is called whenever the Field is finalized.""" + if self._cache is _missing: + self._cache = b"".join(self._value) + + def finalize(self) -> None: + """Finalize the form field.""" + self.on_end() + + def close(self) -> None: + """Close the Field object. This will free any underlying cache.""" + # Free our value array. + if self._cache is _missing: + self._cache = b"".join(self._value) + + del self._value + + def set_none(self) -> None: + """Some fields in a querystring can possibly have a value of None - for + example, the string "foo&bar=&baz=asdf" will have a field with the + name "foo" and value None, one with name "bar" and value "", and one + with name "baz" and value "asdf". Since the write() interface doesn't + support writing None, this function will set the field value to None. + """ + self._cache = None + + @property + def field_name(self) -> bytes | None: + """This property returns the name of the field.""" + return self._name + + @property + def value(self) -> bytes | None: + """This property returns the value of the form field.""" + if self._cache is _missing: + self._cache = b"".join(self._value) + + assert isinstance(self._cache, bytes) or self._cache is None + return self._cache + + @property + def content_type(self) -> str | None: + """This property returns the content_type value of the field.""" + return self._content_type + + def __eq__(self, other: object) -> bool: + if isinstance(other, Field): + return self.field_name == other.field_name and self.value == other.value + else: + return NotImplemented + + def __repr__(self) -> str: + if self.value is not None and len(self.value) > 97: + # We get the repr, and then insert three dots before the final + # quote. + v = repr(self.value[:97])[:-1] + "...'" + else: + v = repr(self.value) + + return f"{self.__class__.__name__}(field_name={self.field_name!r}, value={v})" + + +class File: + """This class represents an uploaded file. It handles writing file data to + either an in-memory file or a temporary file on-disk, if the optional + threshold is passed. + + There are some options that can be passed to the File to change behavior + of the class. Valid options are as follows: + + | Name | Type | Default | Description | + |-----------------------|-------|---------|-------------| + | UPLOAD_DIR | `str` | None | The directory to store uploaded files in. If this is None, a temporary file will be created in the system's standard location. | + | UPLOAD_DELETE_TMP | `bool`| True | Delete automatically created TMP file | + | UPLOAD_KEEP_FILENAME | `bool`| False | Whether or not to keep the filename of the uploaded file. If True, then the filename will be converted to a safe representation (e.g. by removing any invalid path segments), and then saved with the same name). Otherwise, a temporary name will be used. | + | UPLOAD_KEEP_EXTENSIONS| `bool`| False | Whether or not to keep the uploaded file's extension. If False, the file will be saved with the default temporary extension (usually ".tmp"). Otherwise, the file's extension will be maintained. Note that this will properly combine with the UPLOAD_KEEP_FILENAME setting. | + | MAX_MEMORY_FILE_SIZE | `int` | 1 MiB | The maximum number of bytes of a File to keep in memory. By default, the contents of a File are kept into memory until a certain limit is reached, after which the contents of the File are written to a temporary file. This behavior can be disabled by setting this value to an appropriately large value (or, for example, infinity, such as `float('inf')`. | + + Args: + file_name: The name of the file that this [`File`][python_multipart.File] represents. + field_name: The name of the form field that this file was uploaded with. This can be None, if, for example, + the file was uploaded with Content-Type application/octet-stream. + config: The configuration for this File. See above for valid configuration keys and their corresponding values. + content_type: The value of the Content-Type header. + """ # noqa: E501 + + def __init__( + self, + file_name: bytes | None, + field_name: bytes | None = None, + config: FileConfig = {}, + *, + content_type: str | None = None, + ) -> None: + # Save configuration, set other variables default. + self.logger = logging.getLogger(__name__) + self._config = config + self._in_memory = True + self._bytes_written = 0 + self._fileobj: BytesIO | BufferedRandom = BytesIO() + + # Save the provided field/file name and content type. + self._field_name = field_name + self._file_name = file_name + self._content_type = content_type + + # Our actual file name is None by default, since, depending on our + # config, we may not actually use the provided name. + self._actual_file_name: bytes | None = None + + # Split the extension from the filename. + if file_name is not None: + # Extract just the basename to avoid directory traversal + basename = os.path.basename(file_name) + base, ext = os.path.splitext(basename) + self._file_base = base + self._ext = ext + + @property + def field_name(self) -> bytes | None: + """The form field associated with this file. May be None if there isn't + one, for example when we have an application/octet-stream upload. + """ + return self._field_name + + @property + def file_name(self) -> bytes | None: + """The file name given in the upload request.""" + return self._file_name + + @property + def actual_file_name(self) -> bytes | None: + """The file name that this file is saved as. Will be None if it's not + currently saved on disk. + """ + return self._actual_file_name + + @property + def file_object(self) -> BytesIO | BufferedRandom: + """The file object that we're currently writing to. Note that this + will either be an instance of a :class:`io.BytesIO`, or a regular file + object. + """ + return self._fileobj + + @property + def size(self) -> int: + """The total size of this file, counted as the number of bytes that + currently have been written to the file. + """ + return self._bytes_written + + @property + def in_memory(self) -> bool: + """A boolean representing whether or not this file object is currently + stored in-memory or on-disk. + """ + return self._in_memory + + @property + def content_type(self) -> str | None: + """The Content-Type value for this part, if it was set.""" + return self._content_type + + def flush_to_disk(self) -> None: + """If the file is already on-disk, do nothing. Otherwise, copy from + the in-memory buffer to a disk file, and then reassign our internal + file object to this new disk file. + + Note that if you attempt to flush a file that is already on-disk, a + warning will be logged to this module's logger. + """ + if not self._in_memory: + self.logger.warning("Trying to flush to disk when we're not in memory") + return + + # Go back to the start of our file. + self._fileobj.seek(0) + + # Open a new file. + new_file = self._get_disk_file() + + # Copy the file objects. + shutil.copyfileobj(self._fileobj, new_file) + + # Seek to the new position in our new file. + new_file.seek(self._bytes_written) + + # Reassign the fileobject. + old_fileobj = self._fileobj + self._fileobj = new_file + + # We're no longer in memory. + self._in_memory = False + + # Close the old file object. + old_fileobj.close() + + def _get_disk_file(self) -> BufferedRandom: + """This function is responsible for getting a file object on-disk for us.""" + self.logger.info("Opening a file on disk") + + file_dir = self._config.get("UPLOAD_DIR") + keep_filename = self._config.get("UPLOAD_KEEP_FILENAME", False) + keep_extensions = self._config.get("UPLOAD_KEEP_EXTENSIONS", False) + delete_tmp = self._config.get("UPLOAD_DELETE_TMP", True) + tmp_file: None | BufferedRandom = None + + # If we have a directory and are to keep the filename... + if file_dir is not None and keep_filename: + self.logger.info("Saving with filename in: %r", file_dir) + + # Build our filename. + # TODO: what happens if we don't have a filename? + fname = self._file_base + self._ext if keep_extensions else self._file_base + + path = os.path.join(file_dir, fname) # type: ignore[arg-type] + try: + self.logger.info("Opening file: %r", path) + tmp_file = open(path, "w+b") + except OSError: + tmp_file = None + + self.logger.exception("Error opening temporary file") + raise FileError("Error opening temporary file: %r" % path) + else: + # Build options array. + # Note that on Python 3, tempfile doesn't support byte names. We + # encode our paths using the default filesystem encoding. + suffix = self._ext.decode(sys.getfilesystemencoding()) if keep_extensions else None + + if file_dir is None: + dir = None + elif isinstance(file_dir, bytes): + dir = file_dir.decode(sys.getfilesystemencoding()) + else: + dir = file_dir # pragma: no cover + + # Create a temporary (named) file with the appropriate settings. + self.logger.info( + "Creating a temporary file with options: %r", {"suffix": suffix, "delete": delete_tmp, "dir": dir} + ) + try: + tmp_file = cast(BufferedRandom, tempfile.NamedTemporaryFile(suffix=suffix, delete=delete_tmp, dir=dir)) + except OSError: + self.logger.exception("Error creating named temporary file") + raise FileError("Error creating named temporary file") + + assert tmp_file is not None + # Encode filename as bytes. + if isinstance(tmp_file.name, str): + fname = tmp_file.name.encode(sys.getfilesystemencoding()) + else: + fname = cast(bytes, tmp_file.name) # pragma: no cover + + self._actual_file_name = fname + return tmp_file + + def write(self, data: bytes) -> int: + """Write some data to the File. + + :param data: a bytestring + """ + return self.on_data(data) + + def on_data(self, data: bytes) -> int: + """This method is a callback that will be called whenever data is + written to the File. + + Args: + data: The data to write to the file. + + Returns: + The number of bytes written. + """ + bwritten = self._fileobj.write(data) + + # If the bytes written isn't the same as the length, just return. + if bwritten != len(data): + self.logger.warning("bwritten != len(data) (%d != %d)", bwritten, len(data)) + return bwritten + + # Keep track of how many bytes we've written. + self._bytes_written += bwritten + + # If we're in-memory and are over our limit, we create a file. + max_memory_file_size = self._config.get("MAX_MEMORY_FILE_SIZE") + if self._in_memory and max_memory_file_size is not None and (self._bytes_written > max_memory_file_size): + self.logger.info("Flushing to disk") + self.flush_to_disk() + + # Return the number of bytes written. + return bwritten + + def on_end(self) -> None: + """This method is called whenever the Field is finalized.""" + # Flush the underlying file object + self._fileobj.flush() + + def finalize(self) -> None: + """Finalize the form file. This will not close the underlying file, + but simply signal that we are finished writing to the File. + """ + self.on_end() + + def close(self) -> None: + """Close the File object. This will actually close the underlying + file object (whether it's a :class:`io.BytesIO` or an actual file + object). + """ + self._fileobj.close() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(file_name={self.file_name!r}, field_name={self.field_name!r})" + + +class BaseParser: + """This class is the base class for all parsers. It contains the logic for + calling and adding callbacks. + + A callback can be one of two different forms. "Notification callbacks" are + callbacks that are called when something happens - for example, when a new + part of a multipart message is encountered by the parser. "Data callbacks" + are called when we get some sort of data - for example, part of the body of + a multipart chunk. Notification callbacks are called with no parameters, + whereas data callbacks are called with three, as follows:: + + data_callback(data, start, end) + + The "data" parameter is a bytestring (i.e. "foo" on Python 2, or b"foo" on + Python 3). "start" and "end" are integer indexes into the "data" string + that represent the data of interest. Thus, in a data callback, the slice + `data[start:end]` represents the data that the callback is "interested in". + The callback is not passed a copy of the data, since copying severely hurts + performance. + """ + + def __init__(self) -> None: + self.logger = logging.getLogger(__name__) + self.callbacks: QuerystringCallbacks | OctetStreamCallbacks | MultipartCallbacks = {} + + def callback( + self, name: CallbackName, data: bytes | None = None, start: int | None = None, end: int | None = None + ) -> None: + """This function calls a provided callback with some data. If the + callback is not set, will do nothing. + + Args: + name: The name of the callback to call (as a string). + data: Data to pass to the callback. If None, then it is assumed that the callback is a notification + callback, and no parameters are given. + end: An integer that is passed to the data callback. + start: An integer that is passed to the data callback. + """ + func = self.callbacks.get("on_" + name) + if func is None: + return + func = cast("Callable[..., Any]", func) + # Depending on whether we're given a buffer... + if data is not None: + # Don't do anything if we have start == end. + if start is not None and start == end: + return + func(data, start, end) + else: + func() + + def set_callback(self, name: CallbackName, new_func: Callable[..., Any] | None) -> None: + """Update the function for a callback. Removes from the callbacks dict + if new_func is None. + + :param name: The name of the callback to call (as a string). + + :param new_func: The new function for the callback. If None, then the + callback will be removed (with no error if it does not + exist). + """ + if new_func is None: + self.callbacks.pop("on_" + name, None) # type: ignore[misc] + else: + self.callbacks["on_" + name] = new_func # type: ignore[literal-required] + + def close(self) -> None: + pass # pragma: no cover + + def finalize(self) -> None: + pass # pragma: no cover + + def __repr__(self) -> str: + return "%s()" % self.__class__.__name__ + + +class OctetStreamParser(BaseParser): + """This parser parses an octet-stream request body and calls callbacks when + incoming data is received. Callbacks are as follows: + + | Callback Name | Parameters | Description | + |----------------|-----------------|-----------------------------------------------------| + | on_start | None | Called when the first data is parsed. | + | on_data | data, start, end| Called for each data chunk that is parsed. | + | on_end | None | Called when the parser is finished parsing all data.| + + Args: + callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][python_multipart.BaseParser]. + max_size: The maximum size of body to parse. Defaults to infinity - i.e. unbounded. + """ + + def __init__(self, callbacks: OctetStreamCallbacks = {}, max_size: float = float("inf")): + super().__init__() + self.callbacks = callbacks + self._started = False + + if not isinstance(max_size, Number) or max_size < 1: + raise ValueError("max_size must be a positive number, not %r" % max_size) + self.max_size: int | float = max_size + self._current_size = 0 + + def write(self, data: bytes) -> int: + """Write some data to the parser, which will perform size verification, + and then pass the data to the underlying callback. + + Args: + data: The data to write to the parser. + + Returns: + The number of bytes written. + """ + if not self._started: + self.callback("start") + self._started = True + + # Truncate data length. + data_len = len(data) + if (self._current_size + data_len) > self.max_size: + # We truncate the length of data that we are to process. + new_size = int(self.max_size - self._current_size) + self.logger.warning( + "Current size is %d (max %d), so truncating data length from %d to %d", + self._current_size, + self.max_size, + data_len, + new_size, + ) + data_len = new_size + + # Increment size, then callback, in case there's an exception. + self._current_size += data_len + self.callback("data", data, 0, data_len) + return data_len + + def finalize(self) -> None: + """Finalize this parser, which signals to that we are finished parsing, + and sends the on_end callback. + """ + self.callback("end") + + def __repr__(self) -> str: + return "%s()" % self.__class__.__name__ + + +class QuerystringParser(BaseParser): + """This is a streaming querystring parser. It will consume data, and call + the callbacks given when it has data. + + | Callback Name | Parameters | Description | + |----------------|-----------------|-----------------------------------------------------| + | on_field_start | None | Called when a new field is encountered. | + | on_field_name | data, start, end| Called when a portion of a field's name is encountered. | + | on_field_data | data, start, end| Called when a portion of a field's data is encountered. | + | on_field_end | None | Called when the end of a field is encountered. | + | on_end | None | Called when the parser is finished parsing all data.| + + Args: + callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][python_multipart.BaseParser]. + strict_parsing: Whether or not to parse the body strictly. Defaults to False. If this is set to True, then the + behavior of the parser changes as the following: if a field has a value with an equal sign + (e.g. "foo=bar", or "foo="), it is always included. If a field has no equals sign (e.g. "...&name&..."), + it will be treated as an error if 'strict_parsing' is True, otherwise included. If an error is encountered, + then a [`QuerystringParseError`][python_multipart.exceptions.QuerystringParseError] will be raised. + max_size: The maximum size of body to parse. Defaults to infinity - i.e. unbounded. + """ # noqa: E501 + + state: QuerystringState + + def __init__( + self, callbacks: QuerystringCallbacks = {}, strict_parsing: bool = False, max_size: float = float("inf") + ) -> None: + super().__init__() + self.state = QuerystringState.BEFORE_FIELD + self._found_sep = False + + self.callbacks = callbacks + + # Max-size stuff + if not isinstance(max_size, Number) or max_size < 1: + raise ValueError("max_size must be a positive number, not %r" % max_size) + self.max_size: int | float = max_size + self._current_size = 0 + + # Should parsing be strict? + self.strict_parsing = strict_parsing + + def write(self, data: bytes) -> int: + """Write some data to the parser, which will perform size verification, + parse into either a field name or value, and then pass the + corresponding data to the underlying callback. If an error is + encountered while parsing, a QuerystringParseError will be raised. The + "offset" attribute of the raised exception will be set to the offset in + the input data chunk (NOT the overall stream) that caused the error. + + Args: + data: The data to write to the parser. + + Returns: + The number of bytes written. + """ + # Handle sizing. + data_len = len(data) + if (self._current_size + data_len) > self.max_size: + # We truncate the length of data that we are to process. + new_size = int(self.max_size - self._current_size) + self.logger.warning( + "Current size is %d (max %d), so truncating data length from %d to %d", + self._current_size, + self.max_size, + data_len, + new_size, + ) + data_len = new_size + + l = 0 + try: + l = self._internal_write(data, data_len) + finally: + self._current_size += l + + return l + + def _internal_write(self, data: bytes, length: int) -> int: + state = self.state + strict_parsing = self.strict_parsing + found_sep = self._found_sep + + i = 0 + while i < length: + ch = data[i] + + # Depending on our state... + if state == QuerystringState.BEFORE_FIELD: + # If the 'found_sep' flag is set, we've already encountered + # and skipped a single separator. If so, we check our strict + # parsing flag and decide what to do. Otherwise, we haven't + # yet reached a separator, and thus, if we do, we need to skip + # it as it will be the boundary between fields that's supposed + # to be there. + if ch == AMPERSAND: + if found_sep: + # If we're parsing strictly, we disallow blank chunks. + if strict_parsing: + raise QuerystringParseError("Skipping duplicate ampersand at %d" % i, offset=i) + else: + self.logger.debug("Skipping duplicate ampersand at %d", i) + else: + # This case is when we're skipping the (first) + # separator between fields, so we just set our flag + # and continue on. + found_sep = True + else: + # Emit a field-start event, and go to that state. Also, + # reset the "found_sep" flag, for the next time we get to + # this state. + self.callback("field_start") + i -= 1 + state = QuerystringState.FIELD_NAME + found_sep = False + + elif state == QuerystringState.FIELD_NAME: + # Try and find a separator - we ensure that, if we do, we only + # look for the equal sign before it. + sep_pos = data.find(b"&", i, length) + + # See if we can find an equals sign in the remaining data. If + # so, we can immediately emit the field name and jump to the + # data state. + if sep_pos != -1: + equals_pos = data.find(b"=", i, sep_pos) + else: + equals_pos = data.find(b"=", i, length) + + if equals_pos != -1: + # Emit this name. + self.callback("field_name", data, i, equals_pos) + + # Jump i to this position. Note that it will then have 1 + # added to it below, which means the next iteration of this + # loop will inspect the character after the equals sign. + i = equals_pos + state = QuerystringState.FIELD_DATA + else: + # No equals sign found. + if not strict_parsing: + # See also comments in the QuerystringState.FIELD_DATA case below. + # If we found the separator, we emit the name and just + # end - there's no data callback at all (not even with + # a blank value). + if sep_pos != -1: + self.callback("field_name", data, i, sep_pos) + self.callback("field_end") + + i = sep_pos - 1 + state = QuerystringState.BEFORE_FIELD + else: + # Otherwise, no separator in this block, so the + # rest of this chunk must be a name. + self.callback("field_name", data, i, length) + i = length + + else: + # We're parsing strictly. If we find a separator, + # this is an error - we require an equals sign. + if sep_pos != -1: + raise QuerystringParseError( + "When strict_parsing is True, we require an " + "equals sign in all field chunks. Did not " + "find one in the chunk that starts at %d" % (i,), + offset=i, + ) + + # No separator in the rest of this chunk, so it's just + # a field name. + self.callback("field_name", data, i, length) + i = length + + elif state == QuerystringState.FIELD_DATA: + # Try finding an ampersand after this position. + sep_pos = data.find(b"&", i, length) + + # If we found it, callback this bit as data and then go back + # to expecting to find a field. + if sep_pos != -1: + self.callback("field_data", data, i, sep_pos) + self.callback("field_end") + + # Note that we go to the separator, which brings us to the + # "before field" state. This allows us to properly emit + # "field_start" events only when we actually have data for + # a field of some sort. + i = sep_pos - 1 + state = QuerystringState.BEFORE_FIELD + + # Otherwise, emit the rest as data and finish. + else: + self.callback("field_data", data, i, length) + i = length + + else: # pragma: no cover (error case) + msg = "Reached an unknown state %d at %d" % (state, i) + self.logger.warning(msg) + raise QuerystringParseError(msg, offset=i) + + i += 1 + + self.state = state + self._found_sep = found_sep + return length + + def finalize(self) -> None: + """Finalize this parser, which signals to that we are finished parsing, + if we're still in the middle of a field, an on_field_end callback, and + then the on_end callback. + """ + # If we're currently in the middle of a field, we finish it. + if self.state in (QuerystringState.FIELD_DATA, QuerystringState.FIELD_NAME): + self.callback("field_end") + self.callback("end") + + def __repr__(self) -> str: + return "{}(strict_parsing={!r}, max_size={!r})".format( + self.__class__.__name__, self.strict_parsing, self.max_size + ) + + +class MultipartParser(BaseParser): + """This class is a streaming multipart/form-data parser. + + | Callback Name | Parameters | Description | + |--------------------|-----------------|-------------| + | on_part_begin | None | Called when a new part of the multipart message is encountered. | + | on_part_data | data, start, end| Called when a portion of a part's data is encountered. | + | on_part_end | None | Called when the end of a part is reached. | + | on_header_begin | None | Called when we've found a new header in a part of a multipart message | + | on_header_field | data, start, end| Called each time an additional portion of a header is read (i.e. the part of the header that is before the colon; the "Foo" in "Foo: Bar"). | + | on_header_value | data, start, end| Called when we get data for a header. | + | on_header_end | None | Called when the current header is finished - i.e. we've reached the newline at the end of the header. | + | on_headers_finished| None | Called when all headers are finished, and before the part data starts. | + | on_end | None | Called when the parser is finished parsing all data. | + + Args: + boundary: The multipart boundary. This is required, and must match what is given in the HTTP request - usually in the Content-Type header. + callbacks: A dictionary of callbacks. See the documentation for [`BaseParser`][python_multipart.BaseParser]. + max_size: The maximum size of body to parse. Defaults to infinity - i.e. unbounded. + max_header_count: The maximum number of headers allowed per part. + max_header_size: The maximum size of a single header line (excluding the trailing CRLF). + """ # noqa: E501 + + def __init__( + self, + boundary: bytes | str, + callbacks: MultipartCallbacks = {}, + max_size: float = float("inf"), + *, + max_header_count: int = DEFAULT_MAX_HEADER_COUNT, + max_header_size: int = DEFAULT_MAX_HEADER_SIZE, + ) -> None: + # Initialize parser state. + super().__init__() + self.state = MultipartState.START + self.index = self.flags = 0 + + self.callbacks = callbacks + + if not isinstance(max_size, Number) or max_size < 1: + raise ValueError("max_size must be a positive number, not %r" % max_size) + self.max_size = max_size + self._current_size = 0 + + self.max_header_count = max_header_count + self._current_header_count = 0 + + self.max_header_size = max_header_size + self._current_header_size = 0 + + # Setup marks. These are used to track the state of data received. + self.marks: dict[str, int] = {} + + # Save our boundary. + if isinstance(boundary, str): # pragma: no cover + boundary = boundary.encode("latin-1") + if len(boundary) > MAX_BOUNDARY_LENGTH: + raise FormParserError(f"Boundary length {len(boundary)} exceeds maximum of {MAX_BOUNDARY_LENGTH}") + self.boundary = b"\r\n--" + boundary + + def write(self, data: bytes) -> int: + """Write some data to the parser, which will perform size verification, + and then parse the data into the appropriate location (e.g. header, + data, etc.), and pass this on to the underlying callback. If an error + is encountered, a MultipartParseError will be raised. The "offset" + attribute on the raised exception will be set to the offset of the byte + in the input chunk that caused the error. + + Args: + data: The data to write to the parser. + + Returns: + The number of bytes written. + """ + # Handle sizing. + data_len = len(data) + if (self._current_size + data_len) > self.max_size: + # We truncate the length of data that we are to process. + new_size = int(self.max_size - self._current_size) + self.logger.warning( + "Current size is %d (max %d), so truncating data length from %d to %d", + self._current_size, + self.max_size, + data_len, + new_size, + ) + data_len = new_size + + l = 0 + try: + l = self._internal_write(data, data_len) + finally: + self._current_size += l + + return l + + def _internal_write(self, data: bytes, length: int) -> int: + # Get values from locals. + boundary = self.boundary + boundary_length = len(boundary) + + # Get our state, flags and index. These are persisted between calls to + # this function. + state = self.state + index = self.index + flags = self.flags + current_header_count = self._current_header_count + current_header_size = self._current_header_size + + # Our index defaults to 0. + i = 0 + + def advance_header_size(amount: int = 1) -> None: + nonlocal current_header_size + current_header_size += amount + if current_header_size > self.max_header_size: + raise MultipartParseError("Maximum header size exceeded", offset=i) + + # Set a mark. + def set_mark(name: str) -> None: + self.marks[name] = i + + # Remove a mark. + def delete_mark(name: str, reset: bool = False) -> None: + self.marks.pop(name, None) + + # Helper function that makes calling a callback with data easier. The + # 'remaining' parameter will callback from the marked value until the + # end of the buffer, and reset the mark, instead of deleting it. This + # is used at the end of the function to call our callbacks with any + # remaining data in this chunk. + def data_callback(name: CallbackName, end_i: int, remaining: bool = False) -> None: + marked_index = self.marks.get(name) + if marked_index is None: + return + + # Otherwise, we call it from the mark to the current byte we're + # processing. + if end_i <= marked_index: + # There is no additional data to send. + pass + elif marked_index >= 0: + # We are emitting data from the local buffer. + self.callback(name, data, marked_index, end_i) + else: + # Some of the data comes from a partial boundary match. + # and requires look-behind. + # We need to use self.flags (and not flags) because we care about + # the state when we entered the loop. + lookbehind_len = -marked_index + if lookbehind_len <= boundary_length: + self.callback(name, boundary, 0, lookbehind_len) + elif self.flags & FLAG_PART_BOUNDARY: + lookback = boundary + b"\r\n" + self.callback(name, lookback, 0, lookbehind_len) + elif self.flags & FLAG_LAST_BOUNDARY: + lookback = boundary + b"--\r\n" + self.callback(name, lookback, 0, lookbehind_len) + else: # pragma: no cover (error case) + self.logger.warning("Look-back buffer error") + + if end_i > 0: + self.callback(name, data, 0, end_i) + # If we're getting remaining data, we have got all the data we + # can be certain is not a boundary, leaving only a partial boundary match. + if remaining: + self.marks[name] = end_i - length + else: + self.marks.pop(name, None) + + # For each byte... + while i < length: + c = data[i] + + if state == MultipartState.START: + # Skip leading newlines + if c == CR or c == LF: + i = data.find(b"-", i) + if i == -1: + # No boundary candidate in this chunk, so ignore the content after the leading CR/LF. + i = length + break + continue + + # index is used as in index into our boundary. Set to 0. + index = 0 + + # Move to the next state, but decrement i so that we re-process + # this character. + state = MultipartState.START_BOUNDARY + i -= 1 + + elif state == MultipartState.START_BOUNDARY: + # Check to ensure that the last 2 characters in our boundary + # are CRLF. + if index == boundary_length - 2: + if c == HYPHEN: + # Potential empty message. + state = MultipartState.END_BOUNDARY + elif c != CR: + # Error! + msg = "Did not find CR at end of boundary (%d)" % (i,) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + index += 1 + + elif index == boundary_length - 1: + if c != LF: + msg = "Did not find LF at end of boundary (%d)" % (i,) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + # The index is now used for indexing into our boundary. + index = 0 + + # Callback for the start of a part. + self.callback("part_begin") + current_header_count = 0 + current_header_size = 0 + + # Move to the next character and state. + state = MultipartState.HEADER_FIELD_START + + else: + # Check to ensure our boundary matches + if c != boundary[index + 2]: + msg = "Expected boundary character %r, got %r at index %d" % (boundary[index + 2], c, index + 2) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + # Increment index into boundary and continue. + index += 1 + + elif state == MultipartState.HEADER_FIELD_START: + # Mark the start of a header field here, reset the index, and + # continue parsing our header field. + index = 0 + + if c != CR: + current_header_count += 1 + if current_header_count > self.max_header_count: + raise MultipartParseError("Maximum header count exceeded", offset=i) + current_header_size = 0 + + # Set a mark of our header field. + set_mark("header_field") + + # Notify that we're starting a header if the next character is + # not a CR; a CR at the beginning of the header will cause us + # to stop parsing headers in the MultipartState.HEADER_FIELD state, + # below. + if c != CR: + self.callback("header_begin") + + # Move to parsing header fields. + state = MultipartState.HEADER_FIELD + i -= 1 + + elif state == MultipartState.HEADER_FIELD: + # If we've reached a CR at the beginning of a header, it means + # that we've reached the second of 2 newlines, and so there are + # no more headers to parse. + if c == CR and index == 0: + delete_mark("header_field") + state = MultipartState.HEADERS_ALMOST_DONE + i += 1 + continue + + # The field name runs until the colon; jump straight to it and + # validate the whole span at once instead of byte by byte. + colon = data.find(b":", i, length) + end = colon if colon != -1 else length + + # Enforce the size limit before slicing and validating, so an oversized header + # name fails fast instead of copying and scanning a potentially huge span. + advance_header_size(end - i if colon == -1 else end - i + 1) + + field = data[i:end] + if field.translate(None, TOKEN_CHARS): + bad = next(b for b in field if b not in TOKEN_CHARS_SET) + bad_i = i + field.index(bad) + msg = "Found invalid character %r in header at %d" % (bad, bad_i) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=bad_i) + + index += end - i + if colon == -1: + # Field name continues into the next chunk. + i = length + else: + # A 0-length header is an error. + if index == 0: + msg = "Found 0-length header at %d" % (i,) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + # Call our callback with the header field. + i = colon + data_callback("header_field", i) + + # Move to parsing the header value. + state = MultipartState.HEADER_VALUE_START + + elif state == MultipartState.HEADER_VALUE_START: + # Skip leading spaces. + if c == SPACE: + advance_header_size() + i += 1 + continue + + # Mark the start of the header value. + set_mark("header_value") + + # Move to the header-value state, reprocessing this character. + state = MultipartState.HEADER_VALUE + i -= 1 + + elif state == MultipartState.HEADER_VALUE: + # The value runs until the terminating CR; jump straight to it + # instead of inspecting every byte. + cr = data.find(b"\r", i, length) + end = cr if cr != -1 else length + advance_header_size(end - i) + if cr != -1: + i = cr + data_callback("header_value", i) + self.callback("header_end") + current_header_size = 0 + state = MultipartState.HEADER_VALUE_ALMOST_DONE + else: + i = length + + elif state == MultipartState.HEADER_VALUE_ALMOST_DONE: + # The last character should be a LF. If not, it's an error. + if c != LF: + msg = f"Did not find LF character at end of header (found {c!r})" + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + # Move back to the start of another header. Note that if that + # state detects ANOTHER newline, it'll trigger the end of our + # headers. + state = MultipartState.HEADER_FIELD_START + + elif state == MultipartState.HEADERS_ALMOST_DONE: + # We're almost done our headers. This is reached when we parse + # a CR at the beginning of a header, so our next character + # should be a LF, or it's an error. + if c != LF: + msg = f"Did not find LF at end of headers (found {c!r})" + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + self.callback("headers_finished") + state = MultipartState.PART_DATA_START + + elif state == MultipartState.PART_DATA_START: + # Mark the start of our part data. + set_mark("part_data") + + # Start processing part data, including this character. + state = MultipartState.PART_DATA + i -= 1 + + elif state == MultipartState.PART_DATA: + # We're processing our part data right now. During this, we + # need to efficiently search for our boundary, since any data + # on any number of lines can be a part of the current data. + + # Save the current value of our index. We use this in case we + # find part of a boundary, but it doesn't match fully. + prev_index = index + + # If our index is 0, we're starting a new part, so start our + # search. + if index == 0: + # The most common case is likely to be that the whole + # boundary is present in the buffer. + # Calling `find` is much faster than iterating here. + i0 = data.find(boundary, i, length) + if i0 >= 0: + # We matched the whole boundary string. + index = boundary_length - 1 + i = i0 + boundary_length - 1 + c = data[i] + else: + # No whole boundary, but the tail may hold a partial one + # that completes in the next chunk. Boundary starts with + # CR, which an RFC boundary contains nowhere else, so the + # last CR in the tail is the only candidate prefix start. + k = data.rfind(boundary[:1], max(i, length - boundary_length + 1), length) + if k != -1 and boundary.startswith(data[k:length]): + index = length - k + # Carry the partial via index; the end-of-chunk flush + # emits the data before it and re-marks the lookbehind. + i = length + continue + + # Now, we have a couple of cases here. If our index is before + # the end of the boundary... + if index < boundary_length: + # If the character matches... + if boundary[index] == c: + # The current character matches, so continue! + index += 1 + else: + index = 0 + + # Our index is equal to the length of our boundary! + elif index == boundary_length: + # First we increment it. + index += 1 + + # Now, if we've reached a newline, we need to set this as + # the potential end of our boundary. + if c == CR: + flags |= FLAG_PART_BOUNDARY + + # Otherwise, if this is a hyphen, we might be at the last + # of all boundaries. + elif c == HYPHEN: + flags |= FLAG_LAST_BOUNDARY + + # Otherwise, we reset our index, since this isn't either a + # newline or a hyphen. + else: + index = 0 + + # Our index is right after the part boundary, which should be + # a LF. + elif index == boundary_length + 1: + # If we're at a part boundary (i.e. we've seen a CR + # character already)... + if flags & FLAG_PART_BOUNDARY: + # We need a LF character next. + if c == LF: + # Unset the part boundary flag. + flags &= ~FLAG_PART_BOUNDARY + + # We have identified a boundary, callback for any data before it. + data_callback("part_data", i - index) + # Callback indicating that we've reached the end of + # a part, and are starting a new one. + self.callback("part_end") + self.callback("part_begin") + current_header_count = 0 + current_header_size = 0 + + # Move to parsing new headers. + index = 0 + state = MultipartState.HEADER_FIELD_START + i += 1 + continue + + # We didn't find an LF character, so no match. Reset + # our index and clear our flag. + index = 0 + flags &= ~FLAG_PART_BOUNDARY + + # Otherwise, if we're at the last boundary (i.e. we've + # seen a hyphen already)... + elif flags & FLAG_LAST_BOUNDARY: + # We need a second hyphen here. + if c == HYPHEN: + # We have identified a boundary, callback for any data before it. + data_callback("part_data", i - index) + # Callback to end the current part, and then the + # message. + self.callback("part_end") + self.callback("end") + state = MultipartState.END + else: + # No match, so reset index. + index = 0 + + # Otherwise, our index is 0. If the previous index is not, it + # means we reset something, and we need to take the data we + # thought was part of our boundary and send it along as actual + # data. + if index == 0 and prev_index > 0: + # Overwrite our previous index. + prev_index = 0 + + # Re-consider the current character, since this could be + # the start of the boundary itself. + i -= 1 + + elif state == MultipartState.END_BOUNDARY: + if index == boundary_length - 1: + if c != HYPHEN: + msg = "Did not find - at end of boundary (%d)" % (i,) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + index += 1 + self.callback("end") + state = MultipartState.END + + elif state == MultipartState.END: + # Silently discard any epilogue data (RFC 2046 section 5.1.1 allows a CRLF and optional + # epilogue after the closing boundary). Django and Werkzeug do the same. + i = length + break + + else: # pragma: no cover (error case) + # We got into a strange state somehow! Just stop processing. + msg = "Reached an unknown state %d at %d" % (state, i) + self.logger.warning(msg) + raise MultipartParseError(msg, offset=i) + + # Move to the next byte. + i += 1 + + # We call our callbacks with any remaining data. Note that we pass + # the 'remaining' flag, which sets the mark back to 0 instead of + # deleting it, if it's found. This is because, if the mark is found + # at this point, we assume that there's data for one of these things + # that has been parsed, but not yet emitted. And, as such, it implies + # that we haven't yet reached the end of this 'thing'. So, by setting + # the mark to 0, we cause any data callbacks that take place in future + # calls to this function to start from the beginning of that buffer. + data_callback("header_field", length, True) + data_callback("header_value", length, True) + data_callback("part_data", length - index, True) + + # Save values to locals. + self.state = state + self.index = index + self.flags = flags + self._current_header_count = current_header_count + self._current_header_size = current_header_size + + # Return our data length to indicate no errors, and that we processed + # all of it. + return length + + def finalize(self) -> None: + """Finalize this parser, which signals to that we are finished parsing. + + Note: It does not currently, but in the future, it will verify that we + are in the final state of the parser (i.e. the end of the multipart + message is well-formed), and, if not, throw an error. + """ + # TODO: verify that we're in the state MultipartState.END, otherwise throw an + # error or otherwise state that we're not finished parsing. + pass + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(boundary={self.boundary!r})" + + +class FormParser: + """This class is the all-in-one form parser. Given all the information + necessary to parse a form, it will instantiate the correct parser, create + the proper :class:`Field` and :class:`File` classes to store the data that + is parsed, and call the two given callbacks with each field and file as + they become available. + + Args: + content_type: The Content-Type of the incoming request. This is used to select the appropriate parser. + on_field: The callback to call when a field has been parsed and is ready for usage. See above for parameters. + on_file: The callback to call when a file has been parsed and is ready for usage. See above for parameters. + on_end: An optional callback to call when all fields and files in a request has been parsed. Can be None. + boundary: If the request is a multipart/form-data request, this should be the boundary of the request, as given + in the Content-Type header, as a bytestring. + file_name: If the request is of type application/octet-stream, then the body of the request will not contain any + information about the uploaded file. In such cases, you can provide the file name of the uploaded file + manually. + config: Configuration to use for this FormParser. The default values are taken from the DEFAULT_CONFIG value, + and then any keys present in this dictionary will overwrite the default values. + """ + + #: This is the default configuration for our form parser. + #: Note: all file sizes should be in bytes. + DEFAULT_CONFIG: FormParserConfig = { + "MAX_BODY_SIZE": float("inf"), + "MAX_HEADER_COUNT": DEFAULT_MAX_HEADER_COUNT, + "MAX_HEADER_SIZE": DEFAULT_MAX_HEADER_SIZE, + "MAX_MEMORY_FILE_SIZE": 1 * 1024 * 1024, + "UPLOAD_DIR": None, + "UPLOAD_DELETE_TMP": True, + "UPLOAD_KEEP_FILENAME": False, + "UPLOAD_KEEP_EXTENSIONS": False, + # Error on invalid Content-Transfer-Encoding? + "UPLOAD_ERROR_ON_BAD_CTE": False, + } + + def __init__( + self, + content_type: str, + on_field: Callable[[Field], None] | None, + on_file: Callable[[File], None] | None, + on_end: Callable[[], None] | None = None, + boundary: bytes | str | None = None, + file_name: bytes | None = None, + config: dict[Any, Any] = {}, + ) -> None: + self.logger = logging.getLogger(__name__) + + # Save variables. + self.content_type = content_type + self.boundary = boundary + self.bytes_received = 0 + self.parser = None + + # Save callbacks. + self.on_field = on_field + self.on_file = on_file + self.on_end = on_end + + # Set configuration options. + self.config: FormParserConfig = self.DEFAULT_CONFIG.copy() + self.config.update(config) # type: ignore[typeddict-item] + + parser: OctetStreamParser | MultipartParser | QuerystringParser | None = None + + # Depending on the Content-Type, we instantiate the correct parser. + if content_type == "application/octet-stream": + file: File | None = None + + def on_start() -> None: + nonlocal file + file = File(file_name, None, config=self.config) + + def on_data(data: bytes, start: int, end: int) -> None: + nonlocal file + assert file is not None + file.write(data[start:end]) + + def _on_end() -> None: + nonlocal file + assert file is not None + # Finalize the file itself. + file.finalize() + + # Call our callback. + if on_file: + on_file(file) + + # Call the on-end callback. + if self.on_end is not None: + self.on_end() + + # Instantiate an octet-stream parser + parser = OctetStreamParser( + callbacks={"on_start": on_start, "on_data": on_data, "on_end": _on_end}, + max_size=self.config["MAX_BODY_SIZE"], + ) + + elif content_type == "application/x-www-form-urlencoded" or content_type == "application/x-url-encoded": + name_buffer: list[bytes] = [] + + f: Field | None = None + + def on_field_start() -> None: + pass + + def on_field_name(data: bytes, start: int, end: int) -> None: + name_buffer.append(data[start:end]) + + def on_field_data(data: bytes, start: int, end: int) -> None: + nonlocal f + if f is None: + f = Field(b"".join(name_buffer)) + del name_buffer[:] + f.write(data[start:end]) + + def on_field_end() -> None: + nonlocal f + # Finalize and call callback. + if f is None: + # If we get here, it's because there was no field data. + # We create a field, set it to None, and then continue. + f = Field(b"".join(name_buffer)) + del name_buffer[:] + f.set_none() + + f.finalize() + if on_field: + on_field(f) + f = None + + def _on_end() -> None: + if self.on_end is not None: + self.on_end() + + # Instantiate parser. + parser = QuerystringParser( + callbacks={ + "on_field_start": on_field_start, + "on_field_name": on_field_name, + "on_field_data": on_field_data, + "on_field_end": on_field_end, + "on_end": _on_end, + }, + max_size=self.config["MAX_BODY_SIZE"], + ) + + elif content_type == "multipart/form-data": + if boundary is None: + self.logger.error("No boundary given") + raise FormParserError("No boundary given") + + header_name: list[bytes] = [] + header_value: list[bytes] = [] + headers: dict[bytes, bytes] = {} + + f_multi: File | Field | None = None + writer: File | Field | Base64Decoder | QuotedPrintableDecoder | None = None + is_file = False + + def on_part_begin() -> None: + # Reset headers in case this isn't the first part. + nonlocal headers + headers = {} + + def on_part_data(data: bytes, start: int, end: int) -> None: + nonlocal writer + assert writer is not None + writer.write(data[start:end]) + # TODO: check for error here. + + def on_part_end() -> None: + nonlocal f_multi, is_file + assert f_multi is not None + f_multi.finalize() + if is_file: + if on_file: + assert isinstance(f_multi, File) + on_file(f_multi) + else: + if on_field: + assert isinstance(f_multi, Field) + on_field(f_multi) + + def on_header_field(data: bytes, start: int, end: int) -> None: + header_name.append(data[start:end]) + + def on_header_value(data: bytes, start: int, end: int) -> None: + header_value.append(data[start:end]) + + def on_header_end() -> None: + headers[b"".join(header_name).lower()] = b"".join(header_value) + del header_name[:] + del header_value[:] + + def on_headers_finished() -> None: + nonlocal is_file, f_multi, writer + # Reset the 'is file' flag. + is_file = False + + # Parse the content-disposition header. + content_disp = headers.get(b"content-disposition") + disp, options = parse_options_header(content_disp) + + # Get the field and filename. + field_name = options.get(b"name") + file_name = options.get(b"filename") + # RFC 7578 §4.2: each part MUST have a Content-Disposition header with a "name" parameter. + if field_name is None: + raise FormParserError(f'Field name not found in Content-Disposition: "{content_disp!r}"') + + # Create the proper class. + content_type_b = headers.get(b"content-type") + content_type = content_type_b.decode("latin-1") if content_type_b is not None else None + if file_name is None: + f_multi = Field(field_name, content_type=content_type) + else: + f_multi = File(file_name, field_name, config=self.config, content_type=content_type) + is_file = True + + # Parse the given Content-Transfer-Encoding to determine what + # we need to do with the incoming data. + # TODO: check that we properly handle 8bit / 7bit encoding. + # RFC 2045 section 6.1: Content-Transfer-Encoding values are case-insensitive. + # https://www.rfc-editor.org/rfc/rfc2045#section-6.1 + transfer_encoding = headers.get(b"content-transfer-encoding", b"7bit").lower() + + if transfer_encoding in (b"binary", b"8bit", b"7bit"): + writer = f_multi + + elif transfer_encoding == b"base64": + writer = Base64Decoder(f_multi) + + elif transfer_encoding == b"quoted-printable": + writer = QuotedPrintableDecoder(f_multi) + + else: + self.logger.warning("Unknown Content-Transfer-Encoding: %r", transfer_encoding) + if self.config["UPLOAD_ERROR_ON_BAD_CTE"]: + raise FormParserError(f'Unknown Content-Transfer-Encoding "{transfer_encoding!r}"') + else: + # If we aren't erroring, then we just treat this as an + # unencoded Content-Transfer-Encoding. + writer = f_multi + + def _on_end() -> None: + nonlocal writer + if writer is not None: + writer.finalize() + if self.on_end is not None: + self.on_end() + + # Instantiate a multipart parser. + parser = MultipartParser( + boundary, + callbacks={ + "on_part_begin": on_part_begin, + "on_part_data": on_part_data, + "on_part_end": on_part_end, + "on_header_field": on_header_field, + "on_header_value": on_header_value, + "on_header_end": on_header_end, + "on_headers_finished": on_headers_finished, + "on_end": _on_end, + }, + max_size=self.config["MAX_BODY_SIZE"], + max_header_count=self.config["MAX_HEADER_COUNT"], + max_header_size=self.config["MAX_HEADER_SIZE"], + ) + + else: + self.logger.warning("Unknown Content-Type: %r", content_type) + raise FormParserError(f"Unknown Content-Type: {content_type}") + + self.parser = parser + + def write(self, data: bytes) -> int: + """Write some data. The parser will forward this to the appropriate + underlying parser. + + Args: + data: The data to write. + + Returns: + The number of bytes processed. + """ + self.bytes_received += len(data) + # TODO: check the parser's return value for errors? + assert self.parser is not None + return self.parser.write(data) + + def finalize(self) -> None: + """Finalize the parser.""" + if self.parser is not None and hasattr(self.parser, "finalize"): + self.parser.finalize() + + def close(self) -> None: + """Close the parser.""" + if self.parser is not None and hasattr(self.parser, "close"): + self.parser.close() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(content_type={self.content_type!r}, parser={self.parser!r})" + + +def create_form_parser( + headers: dict[str, bytes], + on_field: Callable[[Field], None] | None, + on_file: Callable[[File], None] | None, + config: dict[Any, Any] = {}, +) -> FormParser: + """This function is a helper function to aid in creating a FormParser + instances. Given a dictionary-like headers object, it will determine + the correct information needed, instantiate a FormParser with the + appropriate values and given callbacks, and then return the corresponding + parser. + + Args: + headers: A dictionary-like object of HTTP headers. The only required header is Content-Type. + on_field: Callback to call with each parsed field. + on_file: Callback to call with each parsed file. + config: Configuration variables to pass to the FormParser. + """ + content_type: str | bytes | None = headers.get("Content-Type") + if content_type is None: + logging.getLogger(__name__).warning("No Content-Type header given") + raise ValueError("No Content-Type header given!") + + # Boundaries are optional (the FormParser will raise if one is needed + # but not given). + content_type, params = parse_options_header(content_type) + boundary = params.get(b"boundary") + + # We need content_type to be a string, not a bytes object. + content_type = content_type.decode("latin-1") + + # Instantiate a form parser. + form_parser = FormParser(content_type, on_field, on_file, boundary=boundary, config=config) + + # Return our parser. + return form_parser + + +def parse_form( + headers: dict[str, bytes], + input_stream: SupportsRead, + on_field: Callable[[Field], None] | None, + on_file: Callable[[File], None] | None, + chunk_size: int = 1048576, +) -> None: + """This function is useful if you just want to parse a request body, + without too much work. Pass it a dictionary-like object of the request's + headers, and a file-like object for the input stream, along with two + callbacks that will get called whenever a field or file is parsed. + + Args: + headers: A dictionary-like object of HTTP headers. The only required header is Content-Type. + input_stream: A file-like object that represents the request body. The read() method must return bytestrings. + on_field: Callback to call with each parsed field. + on_file: Callback to call with each parsed file. + chunk_size: The maximum size to read from the input stream and write to the parser at one time. + Defaults to 1 MiB. + """ + if chunk_size < 1: + raise ValueError(f"chunk_size must be a positive number, not {chunk_size!r}") + + # Create our form parser. + parser = create_form_parser(headers, on_field, on_file) + + # Read chunks of 1MiB and write to the parser, but never read more than + # the given Content-Length, if any. + content_length: int | float | bytes | None = headers.get("Content-Length") + if content_length is not None: + content_length = int(content_length) + if content_length < 0: + raise ValueError("Content-Length must be non-negative") + else: + content_length = float("inf") + bytes_read = 0 + + while True: + # Read only up to the Content-Length given. + max_readable = int(min(content_length - bytes_read, chunk_size)) + buff = input_stream.read(max_readable) + + # Write to the parser and update our length. + parser.write(buff) + bytes_read += len(buff) + + # If we get a buffer that's smaller than the size requested, or if we + # have read up to our content length, we're done. + if len(buff) != max_readable or bytes_read == content_length: + break + + # Tell our parser that we're done writing data. + parser.finalize() diff --git a/source/target-vendors/cp312/python_multipart/py.typed b/source/target-vendors/cp312/python_multipart/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/referencing-0.37.0.dist-info/METADATA b/source/target-vendors/cp312/referencing-0.37.0.dist-info/METADATA new file mode 100644 index 0000000..9a6abbc --- /dev/null +++ b/source/target-vendors/cp312/referencing-0.37.0.dist-info/METADATA @@ -0,0 +1,64 @@ +Metadata-Version: 2.4 +Name: referencing +Version: 0.37.0 +Summary: JSON Referencing + Python +Project-URL: Documentation, https://referencing.readthedocs.io/ +Project-URL: Homepage, https://github.com/python-jsonschema/referencing +Project-URL: Issues, https://github.com/python-jsonschema/referencing/issues/ +Project-URL: Funding, https://github.com/sponsors/Julian +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-referencing?utm_source=pypi-referencing&utm_medium=referral&utm_campaign=pypi-link +Project-URL: Changelog, https://referencing.readthedocs.io/en/stable/changes/ +Project-URL: Source, https://github.com/python-jsonschema/referencing +Author-email: Julian Berman +License-Expression: MIT +License-File: COPYING +Keywords: asyncapi,json,jsonschema,openapi,referencing +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: File Formats :: JSON +Classifier: Topic :: File Formats :: JSON :: JSON Schema +Requires-Python: >=3.10 +Requires-Dist: attrs>=22.2.0 +Requires-Dist: rpds-py>=0.7.0 +Requires-Dist: typing-extensions>=4.4.0; python_version < '3.13' +Description-Content-Type: text/x-rst + +=============== +``referencing`` +=============== + +|PyPI| |Pythons| |CI| |ReadTheDocs| |pre-commit| + +.. |PyPI| image:: https://img.shields.io/pypi/v/referencing.svg + :alt: PyPI version + :target: https://pypi.org/project/referencing/ + +.. |Pythons| image:: https://img.shields.io/pypi/pyversions/referencing.svg + :alt: Supported Python versions + :target: https://pypi.org/project/referencing/ + +.. |CI| image:: https://github.com/python-jsonschema/referencing/workflows/CI/badge.svg + :alt: Build status + :target: https://github.com/python-jsonschema/referencing/actions?query=workflow%3ACI + +.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat + :alt: ReadTheDocs status + :target: https://referencing.readthedocs.io/en/stable/ + +.. |pre-commit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/referencing/main.svg + :alt: pre-commit.ci status + :target: https://results.pre-commit.ci/latest/github/python-jsonschema/referencing/main + + +An implementation-agnostic implementation of JSON reference resolution. + +See `the documentation `_ for more details. diff --git a/source/target-vendors/cp312/referencing-0.37.0.dist-info/RECORD b/source/target-vendors/cp312/referencing-0.37.0.dist-info/RECORD new file mode 100644 index 0000000..bb50514 --- /dev/null +++ b/source/target-vendors/cp312/referencing-0.37.0.dist-info/RECORD @@ -0,0 +1,19 @@ +referencing/__init__.py,sha256=5IZKXaAH_FWyCJRkaTn1XcptLfg9cveLb9u5nYUxJKs,207 +referencing/_attrs.py,sha256=bgT-KMhDVLeGtWxM_SGKYeLaZBFzT2kUVFdAkOcXi8g,791 +referencing/_attrs.pyi,sha256=g2wX-aLEqQAvWU-s0qIN2OMGAqjOA0R72R_uSffO8_M,573 +referencing/_core.py,sha256=2SPGfaTvzA3sRqbj_4R2wC--fiXolCUVpLFLJJ6zdZ8,24732 +referencing/exceptions.py,sha256=zFgaEg6WiKeT58MQuKNsgGDnHszp26c4oReC6sF9gHM,4176 +referencing/jsonschema.py,sha256=jXZ6t6x9oTvTHMIC0tRyaFjW5r2qeHObYuu7UhSfK3Q,18615 +referencing/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +referencing/retrieval.py,sha256=cn9EeAdaaTbnMDdC4JRIhiEpXDjflRdHCOLFrw1ZhLA,2729 +referencing/typing.py,sha256=WjUbnZ6jPAd31cnCFAaeWIVENzyHtHdJyOlelv1GY70,1445 +referencing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +referencing/tests/test_core.py,sha256=eap0CAaI23vjMIbVyEj92qLddp3iHH3AxC55CKUN4LU,37854 +referencing/tests/test_exceptions.py,sha256=7eOdHyobXMt7-h5AnnH7u8iw2uHPaH7U4Bs9JhLgjWo,934 +referencing/tests/test_jsonschema.py,sha256=4QnjUWOAMAn5yeA8ZtldJkhI54vwKWJWB0LDzNdx5xc,11687 +referencing/tests/test_referencing_suite.py,sha256=wD6veMfLsUu0s4MLjm7pS8cg4cIfL7FMBENngk73zCI,2335 +referencing/tests/test_retrieval.py,sha256=vcbnfA4TqVeqUzW073wO-nLeqVIv0rQZWNWv0z9km48,3719 +referencing-0.37.0.dist-info/METADATA,sha256=yTsA5qsVJP1ghIN2YEwYmhFDdHdkdcJaMdV75Hsp3mo,2845 +referencing-0.37.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 +referencing-0.37.0.dist-info/licenses/COPYING,sha256=QtzWNJX4e063x3V6-jebtVpT-Ur9el9lfZrfVyNuUVw,1057 +referencing-0.37.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/referencing-0.37.0.dist-info/WHEEL b/source/target-vendors/cp312/referencing-0.37.0.dist-info/WHEEL new file mode 100644 index 0000000..12228d4 --- /dev/null +++ b/source/target-vendors/cp312/referencing-0.37.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.27.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/referencing-0.37.0.dist-info/licenses/COPYING b/source/target-vendors/cp312/referencing-0.37.0.dist-info/licenses/COPYING new file mode 100644 index 0000000..a9f853e --- /dev/null +++ b/source/target-vendors/cp312/referencing-0.37.0.dist-info/licenses/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2022 Julian Berman + +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/source/target-vendors/cp312/referencing/__init__.py b/source/target-vendors/cp312/referencing/__init__.py new file mode 100644 index 0000000..e09207d --- /dev/null +++ b/source/target-vendors/cp312/referencing/__init__.py @@ -0,0 +1,7 @@ +""" +Cross-specification, implementation-agnostic JSON referencing. +""" + +from referencing._core import Anchor, Registry, Resource, Specification + +__all__ = ["Anchor", "Registry", "Resource", "Specification"] diff --git a/source/target-vendors/cp312/referencing/_attrs.py b/source/target-vendors/cp312/referencing/_attrs.py new file mode 100644 index 0000000..ae85b86 --- /dev/null +++ b/source/target-vendors/cp312/referencing/_attrs.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from typing import NoReturn, TypeVar + +from attrs import define as _define, frozen as _frozen + +_T = TypeVar("_T") + + +def define(cls: type[_T]) -> type[_T]: # pragma: no cover + cls.__init_subclass__ = _do_not_subclass + return _define(cls) + + +def frozen(cls: type[_T]) -> type[_T]: + cls.__init_subclass__ = _do_not_subclass + return _frozen(cls) + + +class UnsupportedSubclassing(Exception): + def __str__(self): + return ( + "Subclassing is not part of referencing's public API. " + "If no other suitable API exists for what you're trying to do, " + "feel free to file an issue asking for one." + ) + + +@staticmethod +def _do_not_subclass() -> NoReturn: # pragma: no cover + raise UnsupportedSubclassing() diff --git a/source/target-vendors/cp312/referencing/_attrs.pyi b/source/target-vendors/cp312/referencing/_attrs.pyi new file mode 100644 index 0000000..eca6db2 --- /dev/null +++ b/source/target-vendors/cp312/referencing/_attrs.pyi @@ -0,0 +1,21 @@ +from collections.abc import Callable +from typing import Any, TypeVar + +from attr import attrib, field + +class UnsupportedSubclassing(Exception): ... + +_T = TypeVar("_T") + +def __dataclass_transform__( + *, + frozen_default: bool = False, + field_descriptors: tuple[type | Callable[..., Any], ...] = ..., +) -> Callable[[_T], _T]: ... +@__dataclass_transform__(field_descriptors=(attrib, field)) +def define(cls: type[_T]) -> type[_T]: ... +@__dataclass_transform__( + frozen_default=True, + field_descriptors=(attrib, field), +) +def frozen(cls: type[_T]) -> type[_T]: ... diff --git a/source/target-vendors/cp312/referencing/_core.py b/source/target-vendors/cp312/referencing/_core.py new file mode 100644 index 0000000..4206845 --- /dev/null +++ b/source/target-vendors/cp312/referencing/_core.py @@ -0,0 +1,739 @@ +from __future__ import annotations + +from collections.abc import Callable, Iterable, Iterator, Sequence +from enum import Enum +from typing import Any, ClassVar, Generic, Protocol +from urllib.parse import unquote, urldefrag, urljoin + +from attrs import evolve, field +from rpds import HashTrieMap, HashTrieSet, List + +try: + from typing_extensions import TypeVar +except ImportError: # pragma: no cover + from typing import TypeVar + +from referencing import exceptions +from referencing._attrs import frozen +from referencing.typing import URI, Anchor as AnchorType, D, Mapping, Retrieve + +EMPTY_UNCRAWLED: HashTrieSet[URI] = HashTrieSet() +EMPTY_PREVIOUS_RESOLVERS: List[URI] = List() + + +class _Unset(Enum): + """ + What sillyness... + """ + + SENTINEL = 1 + + +_UNSET = _Unset.SENTINEL + + +class _MaybeInSubresource(Protocol[D]): + def __call__( + self, + segments: Sequence[int | str], + resolver: Resolver[D], + subresource: Resource[D], + ) -> Resolver[D]: ... + + +def _detect_or_error(contents: D) -> Specification[D]: + if not isinstance(contents, Mapping): + raise exceptions.CannotDetermineSpecification(contents) + + jsonschema_dialect_id = contents.get("$schema") # type: ignore[reportUnknownMemberType] + if not isinstance(jsonschema_dialect_id, str): + raise exceptions.CannotDetermineSpecification(contents) + + from referencing.jsonschema import specification_with + + return specification_with(jsonschema_dialect_id) + + +def _detect_or_default( + default: Specification[D], +) -> Callable[[D], Specification[D]]: + def _detect(contents: D) -> Specification[D]: + if not isinstance(contents, Mapping): + return default + + jsonschema_dialect_id = contents.get("$schema") # type: ignore[reportUnknownMemberType] + if jsonschema_dialect_id is None: + return default + + from referencing.jsonschema import specification_with + + return specification_with( + jsonschema_dialect_id, # type: ignore[reportUnknownArgumentType] + default=default, + ) + + return _detect + + +class _SpecificationDetector: + def __get__( + self, + instance: Specification[D] | None, + cls: type[Specification[D]], + ) -> Callable[[D], Specification[D]]: + if instance is None: + return _detect_or_error + else: + return _detect_or_default(instance) + + +@frozen +class Specification(Generic[D]): + """ + A specification which defines referencing behavior. + + The various methods of a `Specification` allow for varying referencing + behavior across JSON Schema specification versions, etc. + """ + + #: A short human-readable name for the specification, used for debugging. + name: str + + #: Find the ID of a given document. + id_of: Callable[[D], URI | None] + + #: Retrieve the subresources of the given document (without traversing into + #: the subresources themselves). + subresources_of: Callable[[D], Iterable[D]] + + #: While resolving a JSON pointer, conditionally enter a subresource + #: (if e.g. we have just entered a keyword whose value is a subresource) + maybe_in_subresource: _MaybeInSubresource[D] + + #: Retrieve the anchors contained in the given document. + _anchors_in: Callable[ + [Specification[D], D], + Iterable[AnchorType[D]], + ] = field(alias="anchors_in") + + #: An opaque specification where resources have no subresources + #: nor internal identifiers. + OPAQUE: ClassVar[Specification[Any]] + + #: Attempt to discern which specification applies to the given contents. + #: + #: May be called either as an instance method or as a class method, with + #: slightly different behavior in the following case: + #: + #: Recall that not all contents contains enough internal information about + #: which specification it is written for -- the JSON Schema ``{}``, + #: for instance, is valid under many different dialects and may be + #: interpreted as any one of them. + #: + #: When this method is used as an instance method (i.e. called on a + #: specific specification), that specification is used as the default + #: if the given contents are unidentifiable. + #: + #: On the other hand when called as a class method, an error is raised. + #: + #: To reiterate, ``DRAFT202012.detect({})`` will return ``DRAFT202012`` + #: whereas the class method ``Specification.detect({})`` will raise an + #: error. + #: + #: (Note that of course ``DRAFT202012.detect(...)`` may return some other + #: specification when given a schema which *does* identify as being for + #: another version). + #: + #: Raises: + #: + #: `CannotDetermineSpecification` + #: + #: if the given contents don't have any discernible + #: information which could be used to guess which + #: specification they identify as + detect = _SpecificationDetector() + + def __repr__(self) -> str: + return f"" + + def anchors_in(self, contents: D): + """ + Retrieve the anchors contained in the given document. + """ + return self._anchors_in(self, contents) + + def create_resource(self, contents: D) -> Resource[D]: + """ + Create a resource which is interpreted using this specification. + """ + return Resource(contents=contents, specification=self) + + +Specification.OPAQUE = Specification( + name="opaque", + id_of=lambda contents: None, + subresources_of=lambda contents: [], + anchors_in=lambda specification, contents: [], + maybe_in_subresource=lambda segments, resolver, subresource: resolver, +) + + +@frozen +class Resource(Generic[D]): + r""" + A document (deserialized JSON) with a concrete interpretation under a spec. + + In other words, a Python object, along with an instance of `Specification` + which describes how the document interacts with referencing -- both + internally (how it refers to other `Resource`\ s) and externally (how it + should be identified such that it is referenceable by other documents). + """ + + contents: D + _specification: Specification[D] = field(alias="specification") + + @classmethod + def from_contents( + cls, + contents: D, + default_specification: ( + type[Specification[D]] | Specification[D] + ) = Specification, + ) -> Resource[D]: + """ + Create a resource guessing which specification applies to the contents. + + Raises: + + `CannotDetermineSpecification` + + if the given contents don't have any discernible + information which could be used to guess which + specification they identify as + + """ + specification = default_specification.detect(contents) + return specification.create_resource(contents=contents) + + @classmethod + def opaque(cls, contents: D) -> Resource[D]: + """ + Create an opaque `Resource` -- i.e. one with opaque specification. + + See `Specification.OPAQUE` for details. + """ + return Specification.OPAQUE.create_resource(contents=contents) + + def id(self) -> URI | None: + """ + Retrieve this resource's (specification-specific) identifier. + """ + id = self._specification.id_of(self.contents) + if id is None: + return + return id.rstrip("#") + + def subresources(self) -> Iterable[Resource[D]]: + """ + Retrieve this resource's subresources. + """ + return ( + Resource.from_contents( + each, + default_specification=self._specification, + ) + for each in self._specification.subresources_of(self.contents) + ) + + def anchors(self) -> Iterable[AnchorType[D]]: + """ + Retrieve this resource's (specification-specific) identifier. + """ + return self._specification.anchors_in(self.contents) + + def pointer(self, pointer: str, resolver: Resolver[D]) -> Resolved[D]: + """ + Resolve the given JSON pointer. + + Raises: + + `exceptions.PointerToNowhere` + + if the pointer points to a location not present in the document + + """ + if not pointer: + return Resolved(contents=self.contents, resolver=resolver) + + contents = self.contents + segments: list[int | str] = [] + for segment in unquote(pointer[1:]).split("/"): + if isinstance(contents, Sequence): + segment = int(segment) + else: + segment = segment.replace("~1", "/").replace("~0", "~") + try: + contents = contents[segment] # type: ignore[reportUnknownArgumentType] + except LookupError as lookup_error: + error = exceptions.PointerToNowhere(ref=pointer, resource=self) + raise error from lookup_error + + segments.append(segment) + last = resolver + resolver = self._specification.maybe_in_subresource( + segments=segments, + resolver=resolver, + subresource=self._specification.create_resource(contents), + ) + if resolver is not last: + segments = [] + return Resolved(contents=contents, resolver=resolver) # type: ignore[reportUnknownArgumentType] + + +def _fail_to_retrieve(uri: URI): + raise exceptions.NoSuchResource(ref=uri) + + +@frozen +class Registry(Mapping[URI, Resource[D]]): + r""" + A registry of `Resource`\ s, each identified by their canonical URIs. + + Registries store a collection of in-memory resources, and optionally + enable additional resources which may be stored elsewhere (e.g. in a + database, a separate set of files, over the network, etc.). + + They also lazily walk their known resources, looking for subresources + within them. In other words, subresources contained within any added + resources will be retrievable via their own IDs (though this discovery of + subresources will be delayed until necessary). + + Registries are immutable, and their methods return new instances of the + registry with the additional resources added to them. + + The ``retrieve`` argument can be used to configure retrieval of resources + dynamically, either over the network, from a database, or the like. + Pass it a callable which will be called if any URI not present in the + registry is accessed. It must either return a `Resource` or else raise a + `NoSuchResource` exception indicating that the resource does not exist + even according to the retrieval logic. + """ + + _resources: HashTrieMap[URI, Resource[D]] = field( + default=HashTrieMap(), + converter=HashTrieMap.convert, # type: ignore[reportGeneralTypeIssues] + alias="resources", + ) + _anchors: HashTrieMap[tuple[URI, str], AnchorType[D]] = HashTrieMap() + _uncrawled: HashTrieSet[URI] = EMPTY_UNCRAWLED + _retrieve: Retrieve[D] = field(default=_fail_to_retrieve, alias="retrieve") + + def __getitem__(self, uri: URI) -> Resource[D]: + """ + Return the (already crawled) `Resource` identified by the given URI. + """ + try: + return self._resources[uri.rstrip("#")] + except KeyError: + raise exceptions.NoSuchResource(ref=uri) from None + + def __iter__(self) -> Iterator[URI]: + """ + Iterate over all crawled URIs in the registry. + """ + return iter(self._resources) + + def __len__(self) -> int: + """ + Count the total number of fully crawled resources in this registry. + """ + return len(self._resources) + + def __rmatmul__( + self, + new: Resource[D] | Iterable[Resource[D]], + ) -> Registry[D]: + """ + Create a new registry with resource(s) added using their internal IDs. + + Resources must have a internal IDs (e.g. the :kw:`$id` keyword in + modern JSON Schema versions), otherwise an error will be raised. + + Both a single resource as well as an iterable of resources works, i.e.: + + * ``resource @ registry`` or + + * ``[iterable, of, multiple, resources] @ registry`` + + which -- again, assuming the resources have internal IDs -- is + equivalent to calling `Registry.with_resources` as such: + + .. code:: python + + registry.with_resources( + (resource.id(), resource) for resource in new_resources + ) + + Raises: + + `NoInternalID` + + if the resource(s) in fact do not have IDs + + """ + if isinstance(new, Resource): + new = (new,) + + resources = self._resources + uncrawled = self._uncrawled + for resource in new: + id = resource.id() + if id is None: + raise exceptions.NoInternalID(resource=resource) + uncrawled = uncrawled.insert(id) + resources = resources.insert(id, resource) + return evolve(self, resources=resources, uncrawled=uncrawled) + + def __repr__(self) -> str: + size = len(self) + pluralized = "resource" if size == 1 else "resources" + if self._uncrawled: + uncrawled = len(self._uncrawled) + if uncrawled == size: + summary = f"uncrawled {pluralized}" + else: + summary = f"{pluralized}, {uncrawled} uncrawled" + else: + summary = f"{pluralized}" + return f"" + + def get_or_retrieve(self, uri: URI) -> Retrieved[D, Resource[D]]: + """ + Get a resource from the registry, crawling or retrieving if necessary. + + May involve crawling to find the given URI if it is not already known, + so the returned object is a `Retrieved` object which contains both the + resource value as well as the registry which ultimately contained it. + """ + resource = self._resources.get(uri) + if resource is not None: + return Retrieved(registry=self, value=resource) + + registry = self.crawl() + resource = registry._resources.get(uri) + if resource is not None: + return Retrieved(registry=registry, value=resource) + + try: + resource = registry._retrieve(uri) + except ( + exceptions.CannotDetermineSpecification, + exceptions.NoSuchResource, + ): + raise + except Exception as error: + raise exceptions.Unretrievable(ref=uri) from error + else: + registry = registry.with_resource(uri, resource) + return Retrieved(registry=registry, value=resource) + + def remove(self, uri: URI): + """ + Return a registry with the resource identified by a given URI removed. + """ + if uri not in self._resources: + raise exceptions.NoSuchResource(ref=uri) + + return evolve( + self, + resources=self._resources.remove(uri), + uncrawled=self._uncrawled.discard(uri), + anchors=HashTrieMap( + (k, v) for k, v in self._anchors.items() if k[0] != uri + ), + ) + + def anchor(self, uri: URI, name: str): + """ + Retrieve a given anchor from a resource which must already be crawled. + """ + value = self._anchors.get((uri, name)) + if value is not None: + return Retrieved(value=value, registry=self) + + registry = self.crawl() + value = registry._anchors.get((uri, name)) + if value is not None: + return Retrieved(value=value, registry=registry) + + resource = self[uri] + canonical_uri = resource.id() + if canonical_uri is not None: + value = registry._anchors.get((canonical_uri, name)) + if value is not None: + return Retrieved(value=value, registry=registry) + + if "/" in name: + raise exceptions.InvalidAnchor( + ref=uri, + resource=resource, + anchor=name, + ) + raise exceptions.NoSuchAnchor(ref=uri, resource=resource, anchor=name) + + def contents(self, uri: URI) -> D: + """ + Retrieve the (already crawled) contents identified by the given URI. + """ + return self[uri].contents + + def crawl(self) -> Registry[D]: + """ + Crawl all added resources, discovering subresources. + """ + resources = self._resources + anchors = self._anchors + uncrawled = [(uri, resources[uri]) for uri in self._uncrawled] + while uncrawled: + uri, resource = uncrawled.pop() + + id = resource.id() + if id is not None: + uri = urljoin(uri, id) + resources = resources.insert(uri, resource) + for each in resource.anchors(): + anchors = anchors.insert((uri, each.name), each) + uncrawled.extend((uri, each) for each in resource.subresources()) + return evolve( + self, + resources=resources, + anchors=anchors, + uncrawled=EMPTY_UNCRAWLED, + ) + + def with_resource(self, uri: URI, resource: Resource[D]): + """ + Add the given `Resource` to the registry, without crawling it. + """ + return self.with_resources([(uri, resource)]) + + def with_resources( + self, + pairs: Iterable[tuple[URI, Resource[D]]], + ) -> Registry[D]: + r""" + Add the given `Resource`\ s to the registry, without crawling them. + """ + resources = self._resources + uncrawled = self._uncrawled + for uri, resource in pairs: + # Empty fragment URIs are equivalent to URIs without the fragment. + # TODO: Is this true for non JSON Schema resources? Probably not. + uri = uri.rstrip("#") + uncrawled = uncrawled.insert(uri) + resources = resources.insert(uri, resource) + return evolve(self, resources=resources, uncrawled=uncrawled) + + def with_contents( + self, + pairs: Iterable[tuple[URI, D]], + **kwargs: Any, + ) -> Registry[D]: + r""" + Add the given contents to the registry, autodetecting when necessary. + """ + return self.with_resources( + (uri, Resource.from_contents(each, **kwargs)) + for uri, each in pairs + ) + + def combine(self, *registries: Registry[D]) -> Registry[D]: + """ + Combine together one or more other registries, producing a unified one. + """ + if registries == (self,): + return self + resources = self._resources + anchors = self._anchors + uncrawled = self._uncrawled + retrieve = self._retrieve + for registry in registries: + resources = resources.update(registry._resources) + anchors = anchors.update(registry._anchors) + uncrawled = uncrawled.update(registry._uncrawled) + + if registry._retrieve is not _fail_to_retrieve: + if registry._retrieve is not retrieve is not _fail_to_retrieve: + raise ValueError( # noqa: TRY003 + "Cannot combine registries with conflicting retrieval " + "functions.", + ) + retrieve = registry._retrieve + return evolve( + self, + anchors=anchors, + resources=resources, + uncrawled=uncrawled, + retrieve=retrieve, + ) + + def resolver(self, base_uri: URI = "") -> Resolver[D]: + """ + Return a `Resolver` which resolves references against this registry. + """ + return Resolver(base_uri=base_uri, registry=self) + + def resolver_with_root(self, resource: Resource[D]) -> Resolver[D]: + """ + Return a `Resolver` with a specific root resource. + """ + uri = resource.id() or "" + return Resolver( + base_uri=uri, + registry=self.with_resource(uri, resource), + ) + + +#: An anchor or resource. +AnchorOrResource = TypeVar( + "AnchorOrResource", + AnchorType[Any], + Resource[Any], + default=Resource[Any], +) + + +@frozen +class Retrieved(Generic[D, AnchorOrResource]): + """ + A value retrieved from a `Registry`. + """ + + value: AnchorOrResource + registry: Registry[D] + + +@frozen +class Resolved(Generic[D]): + """ + A reference resolved to its contents by a `Resolver`. + """ + + contents: D + resolver: Resolver[D] + + +@frozen +class Resolver(Generic[D]): + """ + A reference resolver. + + Resolvers help resolve references (including relative ones) by + pairing a fixed base URI with a `Registry`. + + This object, under normal circumstances, is expected to be used by + *implementers of libraries* built on top of `referencing` (e.g. JSON Schema + implementations or other libraries resolving JSON references), + not directly by end-users populating registries or while writing + schemas or other resources. + + References are resolved against the base URI, and the combined URI + is then looked up within the registry. + + The process of resolving a reference may itself involve calculating + a *new* base URI for future reference resolution (e.g. if an + intermediate resource sets a new base URI), or may involve encountering + additional subresources and adding them to a new registry. + """ + + _base_uri: URI = field(alias="base_uri") + _registry: Registry[D] = field(alias="registry") + _previous: List[URI] = field(default=List(), repr=False, alias="previous") + + def lookup(self, ref: URI) -> Resolved[D]: + """ + Resolve the given reference to the resource it points to. + + Raises: + + `exceptions.Unresolvable` + + or a subclass thereof (see below) if the reference isn't + resolvable + + `exceptions.NoSuchAnchor` + + if the reference is to a URI where a resource exists but + contains a plain name fragment which does not exist within + the resource + + `exceptions.PointerToNowhere` + + if the reference is to a URI where a resource exists but + contains a JSON pointer to a location within the resource + that does not exist + + """ + if ref.startswith("#"): + uri, fragment = self._base_uri, ref[1:] + else: + uri, fragment = urldefrag(urljoin(self._base_uri, ref)) + try: + retrieved = self._registry.get_or_retrieve(uri) + except exceptions.NoSuchResource: + raise exceptions.Unresolvable(ref=ref) from None + except exceptions.Unretrievable as error: + raise exceptions.Unresolvable(ref=ref) from error + + if fragment.startswith("/"): + resolver = self._evolve(registry=retrieved.registry, base_uri=uri) + return retrieved.value.pointer(pointer=fragment, resolver=resolver) + + if fragment: + retrieved = retrieved.registry.anchor(uri, fragment) + resolver = self._evolve(registry=retrieved.registry, base_uri=uri) + return retrieved.value.resolve(resolver=resolver) + + resolver = self._evolve(registry=retrieved.registry, base_uri=uri) + return Resolved(contents=retrieved.value.contents, resolver=resolver) + + def in_subresource(self, subresource: Resource[D]) -> Resolver[D]: + """ + Create a resolver for a subresource (which may have a new base URI). + """ + id = subresource.id() + if id is None: + return self + return evolve(self, base_uri=urljoin(self._base_uri, id)) + + def dynamic_scope(self) -> Iterable[tuple[URI, Registry[D]]]: + """ + In specs with such a notion, return the URIs in the dynamic scope. + """ + for uri in self._previous: + yield uri, self._registry + + def _evolve(self, base_uri: URI, **kwargs: Any): + """ + Evolve, appending to the dynamic scope. + """ + previous = self._previous + if self._base_uri and (not previous or base_uri != self._base_uri): + previous = previous.push_front(self._base_uri) + return evolve(self, base_uri=base_uri, previous=previous, **kwargs) + + +@frozen +class Anchor(Generic[D]): + """ + A simple anchor in a `Resource`. + """ + + name: str + resource: Resource[D] + + def resolve(self, resolver: Resolver[D]): + """ + Return the resource for this anchor. + """ + return Resolved(contents=self.resource.contents, resolver=resolver) diff --git a/source/target-vendors/cp312/referencing/exceptions.py b/source/target-vendors/cp312/referencing/exceptions.py new file mode 100644 index 0000000..3267fc7 --- /dev/null +++ b/source/target-vendors/cp312/referencing/exceptions.py @@ -0,0 +1,165 @@ +""" +Errors, oh no! +""" + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +import attrs + +from referencing._attrs import frozen + +if TYPE_CHECKING: + from referencing import Resource + from referencing.typing import URI + + +@frozen +class NoSuchResource(KeyError): + """ + The given URI is not present in a registry. + + Unlike most exceptions, this class *is* intended to be publicly + instantiable and *is* part of the public API of the package. + """ + + ref: URI + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return NotImplemented + return attrs.astuple(self) == attrs.astuple(other) + + def __hash__(self) -> int: + return hash(attrs.astuple(self)) + + +@frozen +class NoInternalID(Exception): + """ + A resource has no internal ID, but one is needed. + + E.g. in modern JSON Schema drafts, this is the :kw:`$id` keyword. + + One might be needed if a resource was to-be added to a registry but no + other URI is available, and the resource doesn't declare its canonical URI. + """ + + resource: Resource[Any] + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return NotImplemented + return attrs.astuple(self) == attrs.astuple(other) + + def __hash__(self) -> int: + return hash(attrs.astuple(self)) + + +@frozen +class Unretrievable(KeyError): + """ + The given URI is not present in a registry, and retrieving it failed. + """ + + ref: URI + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return NotImplemented + return attrs.astuple(self) == attrs.astuple(other) + + def __hash__(self) -> int: + return hash(attrs.astuple(self)) + + +@frozen +class CannotDetermineSpecification(Exception): + """ + Attempting to detect the appropriate `Specification` failed. + + This happens if no discernible information is found in the contents of the + new resource which would help identify it. + """ + + contents: Any + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return NotImplemented + return attrs.astuple(self) == attrs.astuple(other) + + def __hash__(self) -> int: + return hash(attrs.astuple(self)) + + +@attrs.frozen # Because here we allow subclassing below. +class Unresolvable(Exception): + """ + A reference was unresolvable. + """ + + ref: URI + + def __eq__(self, other: object) -> bool: + if self.__class__ is not other.__class__: + return NotImplemented + return attrs.astuple(self) == attrs.astuple(other) + + def __hash__(self) -> int: + return hash(attrs.astuple(self)) + + +@frozen +class PointerToNowhere(Unresolvable): + """ + A JSON Pointer leads to a part of a document that does not exist. + """ + + resource: Resource[Any] + + def __str__(self) -> str: + msg = f"{self.ref!r} does not exist within {self.resource.contents!r}" + if self.ref == "/": + msg += ( + ". The pointer '/' is a valid JSON Pointer but it points to " + "an empty string property ''. If you intended to point " + "to the entire resource, you should use '#'." + ) + return msg + + +@frozen +class NoSuchAnchor(Unresolvable): + """ + An anchor does not exist within a particular resource. + """ + + resource: Resource[Any] + anchor: str + + def __str__(self) -> str: + return ( + f"{self.anchor!r} does not exist within {self.resource.contents!r}" + ) + + +@frozen +class InvalidAnchor(Unresolvable): + """ + An anchor which could never exist in a resource was dereferenced. + + It is somehow syntactically invalid. + """ + + resource: Resource[Any] + anchor: str + + def __str__(self) -> str: + return ( + f"'#{self.anchor}' is not a valid anchor, neither as a " + "plain name anchor nor as a JSON Pointer. You may have intended " + f"to use '#/{self.anchor}', as the slash is required *before each " + "segment* of a JSON pointer." + ) diff --git a/source/target-vendors/cp312/referencing/jsonschema.py b/source/target-vendors/cp312/referencing/jsonschema.py new file mode 100644 index 0000000..93e77a7 --- /dev/null +++ b/source/target-vendors/cp312/referencing/jsonschema.py @@ -0,0 +1,642 @@ +""" +Referencing implementations for JSON Schema specs (historic & current). +""" + +from __future__ import annotations + +from collections.abc import Iterable, Sequence, Set +from typing import Any + +from referencing import Anchor, Registry, Resource, Specification, exceptions +from referencing._attrs import frozen +from referencing._core import ( + _UNSET, # type: ignore[reportPrivateUsage] + Resolved as _Resolved, + Resolver as _Resolver, + _Unset, # type: ignore[reportPrivateUsage] +) +from referencing.typing import URI, Anchor as AnchorType, Mapping + +#: A JSON Schema which is a JSON object +ObjectSchema = Mapping[str, Any] + +#: A JSON Schema of any kind +Schema = bool | ObjectSchema + +#: A Resource whose contents are JSON Schemas +SchemaResource = Resource[Schema] + +#: A JSON Schema Registry +SchemaRegistry = Registry[Schema] + +#: The empty JSON Schema Registry +EMPTY_REGISTRY: SchemaRegistry = Registry() + + +@frozen +class UnknownDialect(Exception): + """ + A dialect identifier was found for a dialect unknown by this library. + + If it's a custom ("unofficial") dialect, be sure you've registered it. + """ + + uri: URI + + +def _dollar_id(contents: Schema) -> URI | None: + if isinstance(contents, bool): + return + return contents.get("$id") + + +def _legacy_dollar_id(contents: Schema) -> URI | None: + if isinstance(contents, bool) or "$ref" in contents: + return + id = contents.get("$id") + if id is not None and not id.startswith("#"): + return id + + +def _legacy_id(contents: ObjectSchema) -> URI | None: + if "$ref" in contents: + return + id = contents.get("id") + if id is not None and not id.startswith("#"): + return id + + +def _anchor( + specification: Specification[Schema], + contents: Schema, +) -> Iterable[AnchorType[Schema]]: + if isinstance(contents, bool): + return + anchor = contents.get("$anchor") + if anchor is not None: + yield Anchor( + name=anchor, + resource=specification.create_resource(contents), + ) + + dynamic_anchor = contents.get("$dynamicAnchor") + if dynamic_anchor is not None: + yield DynamicAnchor( + name=dynamic_anchor, + resource=specification.create_resource(contents), + ) + + +def _anchor_2019( + specification: Specification[Schema], + contents: Schema, +) -> Iterable[Anchor[Schema]]: + if isinstance(contents, bool): + return [] + anchor = contents.get("$anchor") + if anchor is None: + return [] + return [ + Anchor( + name=anchor, + resource=specification.create_resource(contents), + ), + ] + + +def _legacy_anchor_in_dollar_id( + specification: Specification[Schema], + contents: Schema, +) -> Iterable[Anchor[Schema]]: + if isinstance(contents, bool): + return [] + id = contents.get("$id", "") + if not id.startswith("#"): + return [] + return [ + Anchor( + name=id[1:], + resource=specification.create_resource(contents), + ), + ] + + +def _legacy_anchor_in_id( + specification: Specification[ObjectSchema], + contents: ObjectSchema, +) -> Iterable[Anchor[ObjectSchema]]: + id = contents.get("id", "") + if not id.startswith("#"): + return [] + return [ + Anchor( + name=id[1:], + resource=specification.create_resource(contents), + ), + ] + + +def _subresources_of( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + """ + Create a callable returning JSON Schema specification-style subschemas. + + Relies on specifying the set of keywords containing subschemas in their + values, in a subobject's values, or in a subarray. + """ + + def subresources_of(contents: Schema) -> Iterable[ObjectSchema]: + if isinstance(contents, bool): + return + for each in in_value: + if each in contents: + yield contents[each] + for each in in_subarray: + if each in contents: + yield from contents[each] + for each in in_subvalues: + if each in contents: + yield from contents[each].values() + + return subresources_of + + +def _subresources_of_with_crazy_items( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + """ + Specifically handle older drafts where there are some funky keywords. + """ + + def subresources_of(contents: Schema) -> Iterable[ObjectSchema]: + if isinstance(contents, bool): + return + for each in in_value: + if each in contents: + yield contents[each] + for each in in_subarray: + if each in contents: + yield from contents[each] + for each in in_subvalues: + if each in contents: + yield from contents[each].values() + + items = contents.get("items") + if items is not None: + if isinstance(items, Sequence): + yield from items + else: + yield items + + return subresources_of + + +def _subresources_of_with_crazy_items_dependencies( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + """ + Specifically handle older drafts where there are some funky keywords. + """ + + def subresources_of(contents: Schema) -> Iterable[ObjectSchema]: + if isinstance(contents, bool): + return + for each in in_value: + if each in contents: + yield contents[each] + for each in in_subarray: + if each in contents: + yield from contents[each] + for each in in_subvalues: + if each in contents: + yield from contents[each].values() + + items = contents.get("items") + if items is not None: + if isinstance(items, Sequence): + yield from items + else: + yield items + dependencies = contents.get("dependencies") + if dependencies is not None: + values = iter(dependencies.values()) + value = next(values, None) + if isinstance(value, Mapping): + yield value + yield from values + + return subresources_of + + +def _subresources_of_with_crazy_aP_items_dependencies( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + """ + Specifically handle even older drafts where there are some funky keywords. + """ + + def subresources_of(contents: ObjectSchema) -> Iterable[ObjectSchema]: + for each in in_value: + if each in contents: + yield contents[each] + for each in in_subarray: + if each in contents: + yield from contents[each] + for each in in_subvalues: + if each in contents: + yield from contents[each].values() + + items = contents.get("items") + if items is not None: + if isinstance(items, Sequence): + yield from items + else: + yield items + dependencies = contents.get("dependencies") + if dependencies is not None: + values = iter(dependencies.values()) + value = next(values, None) + if isinstance(value, Mapping): + yield value + yield from values + + for each in "additionalItems", "additionalProperties": + value = contents.get(each) + if isinstance(value, Mapping): + yield value + + return subresources_of + + +def _maybe_in_subresource( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + in_child = in_subvalues | in_subarray + + def maybe_in_subresource( + segments: Sequence[int | str], + resolver: _Resolver[Any], + subresource: Resource[Any], + ) -> _Resolver[Any]: + _segments = iter(segments) + for segment in _segments: + if segment not in in_value and ( + segment not in in_child or next(_segments, None) is None + ): + return resolver + return resolver.in_subresource(subresource) + + return maybe_in_subresource + + +def _maybe_in_subresource_crazy_items( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + in_child = in_subvalues | in_subarray + + def maybe_in_subresource( + segments: Sequence[int | str], + resolver: _Resolver[Any], + subresource: Resource[Any], + ) -> _Resolver[Any]: + _segments = iter(segments) + for segment in _segments: + if segment == "items" and isinstance( + subresource.contents, + Mapping, + ): + return resolver.in_subresource(subresource) + if segment not in in_value and ( + segment not in in_child or next(_segments, None) is None + ): + return resolver + return resolver.in_subresource(subresource) + + return maybe_in_subresource + + +def _maybe_in_subresource_crazy_items_dependencies( + in_value: Set[str] = frozenset(), + in_subvalues: Set[str] = frozenset(), + in_subarray: Set[str] = frozenset(), +): + in_child = in_subvalues | in_subarray + + def maybe_in_subresource( + segments: Sequence[int | str], + resolver: _Resolver[Any], + subresource: Resource[Any], + ) -> _Resolver[Any]: + _segments = iter(segments) + for segment in _segments: + if segment in {"items", "dependencies"} and isinstance( + subresource.contents, + Mapping, + ): + return resolver.in_subresource(subresource) + if segment not in in_value and ( + segment not in in_child or next(_segments, None) is None + ): + return resolver + return resolver.in_subresource(subresource) + + return maybe_in_subresource + + +#: JSON Schema draft 2020-12 +DRAFT202012 = Specification( + name="draft2020-12", + id_of=_dollar_id, + subresources_of=_subresources_of( + in_value={ + "additionalProperties", + "contains", + "contentSchema", + "else", + "if", + "items", + "not", + "propertyNames", + "then", + "unevaluatedItems", + "unevaluatedProperties", + }, + in_subarray={"allOf", "anyOf", "oneOf", "prefixItems"}, + in_subvalues={ + "$defs", + "definitions", + "dependentSchemas", + "patternProperties", + "properties", + }, + ), + anchors_in=_anchor, + maybe_in_subresource=_maybe_in_subresource( + in_value={ + "additionalProperties", + "contains", + "contentSchema", + "else", + "if", + "items", + "not", + "propertyNames", + "then", + "unevaluatedItems", + "unevaluatedProperties", + }, + in_subarray={"allOf", "anyOf", "oneOf", "prefixItems"}, + in_subvalues={ + "$defs", + "definitions", + "dependentSchemas", + "patternProperties", + "properties", + }, + ), +) +#: JSON Schema draft 2019-09 +DRAFT201909 = Specification( + name="draft2019-09", + id_of=_dollar_id, + subresources_of=_subresources_of_with_crazy_items( + in_value={ + "additionalItems", + "additionalProperties", + "contains", + "contentSchema", + "else", + "if", + "not", + "propertyNames", + "then", + "unevaluatedItems", + "unevaluatedProperties", + }, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={ + "$defs", + "definitions", + "dependentSchemas", + "patternProperties", + "properties", + }, + ), + anchors_in=_anchor_2019, + maybe_in_subresource=_maybe_in_subresource_crazy_items( + in_value={ + "additionalItems", + "additionalProperties", + "contains", + "contentSchema", + "else", + "if", + "not", + "propertyNames", + "then", + "unevaluatedItems", + "unevaluatedProperties", + }, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={ + "$defs", + "definitions", + "dependentSchemas", + "patternProperties", + "properties", + }, + ), +) +#: JSON Schema draft 7 +DRAFT7 = Specification( + name="draft-07", + id_of=_legacy_dollar_id, + subresources_of=_subresources_of_with_crazy_items_dependencies( + in_value={ + "additionalItems", + "additionalProperties", + "contains", + "else", + "if", + "not", + "propertyNames", + "then", + }, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), + anchors_in=_legacy_anchor_in_dollar_id, + maybe_in_subresource=_maybe_in_subresource_crazy_items_dependencies( + in_value={ + "additionalItems", + "additionalProperties", + "contains", + "else", + "if", + "not", + "propertyNames", + "then", + }, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), +) +#: JSON Schema draft 6 +DRAFT6 = Specification( + name="draft-06", + id_of=_legacy_dollar_id, + subresources_of=_subresources_of_with_crazy_items_dependencies( + in_value={ + "additionalItems", + "additionalProperties", + "contains", + "not", + "propertyNames", + }, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), + anchors_in=_legacy_anchor_in_dollar_id, + maybe_in_subresource=_maybe_in_subresource_crazy_items_dependencies( + in_value={ + "additionalItems", + "additionalProperties", + "contains", + "not", + "propertyNames", + }, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), +) +#: JSON Schema draft 4 +DRAFT4 = Specification( + name="draft-04", + id_of=_legacy_id, + subresources_of=_subresources_of_with_crazy_aP_items_dependencies( + in_value={"not"}, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), + anchors_in=_legacy_anchor_in_id, + maybe_in_subresource=_maybe_in_subresource_crazy_items_dependencies( + in_value={"additionalItems", "additionalProperties", "not"}, + in_subarray={"allOf", "anyOf", "oneOf"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), +) +#: JSON Schema draft 3 +DRAFT3 = Specification( + name="draft-03", + id_of=_legacy_id, + subresources_of=_subresources_of_with_crazy_aP_items_dependencies( + in_subarray={"extends"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), + anchors_in=_legacy_anchor_in_id, + maybe_in_subresource=_maybe_in_subresource_crazy_items_dependencies( + in_value={"additionalItems", "additionalProperties"}, + in_subarray={"extends"}, + in_subvalues={"definitions", "patternProperties", "properties"}, + ), +) + + +_SPECIFICATIONS: Registry[Specification[Schema]] = Registry( + { + dialect_id: Resource.opaque(specification) + for dialect_id, specification in [ + ("https://json-schema.org/draft/2020-12/schema", DRAFT202012), + ("https://json-schema.org/draft/2019-09/schema", DRAFT201909), + ("http://json-schema.org/draft-07/schema", DRAFT7), + ("http://json-schema.org/draft-06/schema", DRAFT6), + ("http://json-schema.org/draft-04/schema", DRAFT4), + ("http://json-schema.org/draft-03/schema", DRAFT3), + ] + }, +) + + +def specification_with( + dialect_id: URI, + default: Specification[Any] | _Unset = _UNSET, +) -> Specification[Any]: + """ + Retrieve the `Specification` with the given dialect identifier. + + Raises: + + `UnknownDialect` + + if the given ``dialect_id`` isn't known + + """ + resource = _SPECIFICATIONS.get(dialect_id.rstrip("#")) + if resource is not None: + return resource.contents + if default is _UNSET: + raise UnknownDialect(dialect_id) + return default + + +@frozen +class DynamicAnchor: + """ + Dynamic anchors, introduced in draft 2020. + """ + + name: str + resource: SchemaResource + + def resolve(self, resolver: _Resolver[Schema]) -> _Resolved[Schema]: + """ + Resolve this anchor dynamically. + """ + last = self.resource + for uri, registry in resolver.dynamic_scope(): + try: + anchor = registry.anchor(uri, self.name).value + except exceptions.NoSuchAnchor: + continue + if isinstance(anchor, DynamicAnchor): + last = anchor.resource + return _Resolved( + contents=last.contents, + resolver=resolver.in_subresource(last), + ) + + +def lookup_recursive_ref(resolver: _Resolver[Schema]) -> _Resolved[Schema]: + """ + Recursive references (via recursive anchors), present only in draft 2019. + + As per the 2019 specification (§ 8.2.4.2.1), only the ``#`` recursive + reference is supported (and is therefore assumed to be the relevant + reference). + """ + resolved = resolver.lookup("#") + if isinstance(resolved.contents, Mapping) and resolved.contents.get( + "$recursiveAnchor", + ): + for uri, _ in resolver.dynamic_scope(): + next_resolved = resolver.lookup(uri) + if not isinstance( + next_resolved.contents, + Mapping, + ) or not next_resolved.contents.get("$recursiveAnchor"): + break + resolved = next_resolved + return resolved diff --git a/source/target-vendors/cp312/referencing/py.typed b/source/target-vendors/cp312/referencing/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/referencing/retrieval.py b/source/target-vendors/cp312/referencing/retrieval.py new file mode 100644 index 0000000..ac5a65b --- /dev/null +++ b/source/target-vendors/cp312/referencing/retrieval.py @@ -0,0 +1,94 @@ +""" +Helpers related to (dynamic) resource retrieval. +""" + +from __future__ import annotations + +from functools import lru_cache +from typing import TYPE_CHECKING +import json + +try: + from typing_extensions import TypeVar +except ImportError: # pragma: no cover + from typing import TypeVar + +from referencing import Resource + +if TYPE_CHECKING: + from collections.abc import Callable + + from referencing.typing import URI, D, Retrieve + +#: A serialized document (e.g. a JSON string) +_T = TypeVar("_T", default=str) + + +def to_cached_resource( + cache: Callable[[Retrieve[D]], Retrieve[D]] | None = None, + loads: Callable[[_T], D] = json.loads, + from_contents: Callable[[D], Resource[D]] = Resource.from_contents, +) -> Callable[[Callable[[URI], _T]], Retrieve[D]]: + """ + Create a retriever which caches its return values from a simpler callable. + + Takes a function which returns things like serialized JSON (strings) and + returns something suitable for passing to `Registry` as a retrieve + function. + + This decorator both reduces a small bit of boilerplate for a common case + (deserializing JSON from strings and creating `Resource` objects from the + result) as well as makes the probable need for caching a bit easier. + Retrievers which otherwise do expensive operations (like hitting the + network) might otherwise be called repeatedly. + + Examples + -------- + + .. testcode:: + + from referencing import Registry + from referencing.typing import URI + import referencing.retrieval + + + @referencing.retrieval.to_cached_resource() + def retrieve(uri: URI): + print(f"Retrieved {uri}") + + # Normally, go get some expensive JSON from the network, a file ... + return ''' + { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "foo": "bar" + } + ''' + + one = Registry(retrieve=retrieve).get_or_retrieve("urn:example:foo") + print(one.value.contents["foo"]) + + # Retrieving the same URI again reuses the same value (and thus doesn't + # print another retrieval message here) + two = Registry(retrieve=retrieve).get_or_retrieve("urn:example:foo") + print(two.value.contents["foo"]) + + .. testoutput:: + + Retrieved urn:example:foo + bar + bar + + """ + if cache is None: + cache = lru_cache(maxsize=None) + + def decorator(retrieve: Callable[[URI], _T]): + @cache + def cached_retrieve(uri: URI): + response = retrieve(uri) + contents = loads(response) + return from_contents(contents) + + return cached_retrieve + + return decorator diff --git a/source/target-vendors/cp312/referencing/tests/__init__.py b/source/target-vendors/cp312/referencing/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/referencing/tests/test_core.py b/source/target-vendors/cp312/referencing/tests/test_core.py new file mode 100644 index 0000000..3edddbc --- /dev/null +++ b/source/target-vendors/cp312/referencing/tests/test_core.py @@ -0,0 +1,1057 @@ +from rpds import HashTrieMap +import pytest + +from referencing import Anchor, Registry, Resource, Specification, exceptions +from referencing.jsonschema import DRAFT202012 + +ID_AND_CHILDREN = Specification( + name="id-and-children", + id_of=lambda contents: contents.get("ID"), + subresources_of=lambda contents: contents.get("children", []), + anchors_in=lambda specification, contents: [ + Anchor( + name=name, + resource=specification.create_resource(contents=each), + ) + for name, each in contents.get("anchors", {}).items() + ], + maybe_in_subresource=lambda segments, resolver, subresource: ( + resolver.in_subresource(subresource) + if not len(segments) % 2 + and all(each == "children" for each in segments[::2]) + else resolver + ), +) + + +def blow_up(uri): # pragma: no cover + """ + A retriever suitable for use in tests which expect it never to be used. + """ + raise RuntimeError("This retrieve function expects to never be called!") + + +class TestRegistry: + def test_with_resource(self): + """ + Adding a resource to the registry then allows re-retrieving it. + """ + + resource = Resource.opaque(contents={"foo": "bar"}) + uri = "urn:example" + registry = Registry().with_resource(uri=uri, resource=resource) + assert registry[uri] is resource + + def test_with_resources(self): + """ + Adding multiple resources to the registry is like adding each one. + """ + + one = Resource.opaque(contents={}) + two = Resource(contents={"foo": "bar"}, specification=ID_AND_CHILDREN) + registry = Registry().with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/foo/bar", two), + ], + ) + assert registry == Registry().with_resource( + uri="http://example.com/1", + resource=one, + ).with_resource( + uri="http://example.com/foo/bar", + resource=two, + ) + + def test_matmul_resource(self): + uri = "urn:example:resource" + resource = ID_AND_CHILDREN.create_resource({"ID": uri, "foo": 12}) + registry = resource @ Registry() + assert registry == Registry().with_resource(uri, resource) + + def test_matmul_many_resources(self): + one_uri = "urn:example:one" + one = ID_AND_CHILDREN.create_resource({"ID": one_uri, "foo": 12}) + + two_uri = "urn:example:two" + two = ID_AND_CHILDREN.create_resource({"ID": two_uri, "foo": 12}) + + registry = [one, two] @ Registry() + assert registry == Registry().with_resources( + [(one_uri, one), (two_uri, two)], + ) + + def test_matmul_resource_without_id(self): + resource = Resource.opaque(contents={"foo": "bar"}) + with pytest.raises(exceptions.NoInternalID) as e: + resource @ Registry() + assert e.value == exceptions.NoInternalID(resource=resource) + + def test_with_contents_from_json_schema(self): + uri = "urn:example" + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + registry = Registry().with_contents([(uri, schema)]) + + expected = Resource(contents=schema, specification=DRAFT202012) + assert registry[uri] == expected + + def test_with_contents_and_default_specification(self): + uri = "urn:example" + registry = Registry().with_contents( + [(uri, {"foo": "bar"})], + default_specification=Specification.OPAQUE, + ) + assert registry[uri] == Resource.opaque({"foo": "bar"}) + + def test_len(self): + total = 5 + registry = Registry().with_contents( + [(str(i), {"foo": "bar"}) for i in range(total)], + default_specification=Specification.OPAQUE, + ) + assert len(registry) == total + + def test_bool_empty(self): + assert not Registry() + + def test_bool_not_empty(self): + registry = Registry().with_contents( + [(str(i), {"foo": "bar"}) for i in range(3)], + default_specification=Specification.OPAQUE, + ) + assert registry + + def test_iter(self): + registry = Registry().with_contents( + [(str(i), {"foo": "bar"}) for i in range(8)], + default_specification=Specification.OPAQUE, + ) + assert set(registry) == {str(i) for i in range(8)} + + def test_crawl_still_has_top_level_resource(self): + resource = Resource.opaque({"foo": "bar"}) + uri = "urn:example" + registry = Registry({uri: resource}).crawl() + assert registry[uri] is resource + + def test_crawl_finds_a_subresource(self): + child_id = "urn:child" + root = ID_AND_CHILDREN.create_resource( + {"ID": "urn:root", "children": [{"ID": child_id, "foo": 12}]}, + ) + registry = root @ Registry() + with pytest.raises(LookupError): + registry[child_id] + + expected = ID_AND_CHILDREN.create_resource({"ID": child_id, "foo": 12}) + assert registry.crawl()[child_id] == expected + + def test_crawl_finds_anchors_with_id(self): + resource = ID_AND_CHILDREN.create_resource( + {"ID": "urn:bar", "anchors": {"foo": 12}}, + ) + registry = resource @ Registry() + + assert registry.crawl().anchor(resource.id(), "foo").value == Anchor( + name="foo", + resource=ID_AND_CHILDREN.create_resource(12), + ) + + def test_crawl_finds_anchors_no_id(self): + resource = ID_AND_CHILDREN.create_resource({"anchors": {"foo": 12}}) + registry = Registry().with_resource("urn:root", resource) + + assert registry.crawl().anchor("urn:root", "foo").value == Anchor( + name="foo", + resource=ID_AND_CHILDREN.create_resource(12), + ) + + def test_contents(self): + resource = Resource.opaque({"foo": "bar"}) + uri = "urn:example" + registry = Registry().with_resource(uri, resource) + assert registry.contents(uri) == {"foo": "bar"} + + def test_getitem_strips_empty_fragments(self): + uri = "http://example.com/" + resource = ID_AND_CHILDREN.create_resource({"ID": uri + "#"}) + registry = resource @ Registry() + assert registry[uri] == registry[uri + "#"] == resource + + def test_contents_strips_empty_fragments(self): + uri = "http://example.com/" + resource = ID_AND_CHILDREN.create_resource({"ID": uri + "#"}) + registry = resource @ Registry() + assert ( + registry.contents(uri) + == registry.contents(uri + "#") + == {"ID": uri + "#"} + ) + + def test_contents_nonexistent_resource(self): + registry = Registry() + with pytest.raises(exceptions.NoSuchResource) as e: + registry.contents("urn:example") + assert e.value == exceptions.NoSuchResource(ref="urn:example") + + def test_crawled_anchor(self): + resource = ID_AND_CHILDREN.create_resource({"anchors": {"foo": "bar"}}) + registry = Registry().with_resource("urn:example", resource) + retrieved = registry.anchor("urn:example", "foo") + assert retrieved.value == Anchor( + name="foo", + resource=ID_AND_CHILDREN.create_resource("bar"), + ) + assert retrieved.registry == registry.crawl() + + def test_anchor_in_nonexistent_resource(self): + registry = Registry() + with pytest.raises(exceptions.NoSuchResource) as e: + registry.anchor("urn:example", "foo") + assert e.value == exceptions.NoSuchResource(ref="urn:example") + + def test_init(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + registry = Registry( + { + "http://example.com/1": one, + "http://example.com/foo/bar": two, + }, + ) + assert ( + registry + == Registry() + .with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/foo/bar", two), + ], + ) + .crawl() + ) + + def test_dict_conversion(self): + """ + Passing a `dict` to `Registry` gets converted to a `HashTrieMap`. + + So continuing to use the registry works. + """ + + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + registry = Registry( + {"http://example.com/1": one}, + ).with_resource("http://example.com/foo/bar", two) + assert ( + registry.crawl() + == Registry() + .with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/foo/bar", two), + ], + ) + .crawl() + ) + + def test_no_such_resource(self): + registry = Registry() + with pytest.raises(exceptions.NoSuchResource) as e: + registry["urn:bigboom"] + assert e.value == exceptions.NoSuchResource(ref="urn:bigboom") + + def test_combine(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + three = ID_AND_CHILDREN.create_resource({"baz": "quux"}) + four = ID_AND_CHILDREN.create_resource({"anchors": {"foo": 12}}) + + first = Registry({"http://example.com/1": one}) + second = Registry().with_resource("http://example.com/foo/bar", two) + third = Registry( + { + "http://example.com/1": one, + "http://example.com/baz": three, + }, + ) + fourth = ( + Registry() + .with_resource( + "http://example.com/foo/quux", + four, + ) + .crawl() + ) + assert first.combine(second, third, fourth) == Registry( + [ + ("http://example.com/1", one), + ("http://example.com/baz", three), + ("http://example.com/foo/quux", four), + ], + anchors=HashTrieMap( + { + ("http://example.com/foo/quux", "foo"): Anchor( + name="foo", + resource=ID_AND_CHILDREN.create_resource(12), + ), + }, + ), + ).with_resource("http://example.com/foo/bar", two) + + def test_combine_self(self): + """ + Combining a registry with itself short-circuits. + + This is a performance optimization -- otherwise we do lots more work + (in jsonschema this seems to correspond to making the test suite take + *3x* longer). + """ + + registry = Registry({"urn:foo": "bar"}) + assert registry.combine(registry) is registry + + def test_combine_with_uncrawled_resources(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + three = ID_AND_CHILDREN.create_resource({"baz": "quux"}) + + first = Registry().with_resource("http://example.com/1", one) + second = Registry().with_resource("http://example.com/foo/bar", two) + third = Registry( + { + "http://example.com/1": one, + "http://example.com/baz": three, + }, + ) + expected = Registry( + [ + ("http://example.com/1", one), + ("http://example.com/foo/bar", two), + ("http://example.com/baz", three), + ], + ) + combined = first.combine(second, third) + assert combined != expected + assert combined.crawl() == expected + + def test_combine_with_single_retrieve(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + three = ID_AND_CHILDREN.create_resource({"baz": "quux"}) + + def retrieve(uri): # pragma: no cover + pass + + first = Registry().with_resource("http://example.com/1", one) + second = Registry( + retrieve=retrieve, + ).with_resource("http://example.com/2", two) + third = Registry().with_resource("http://example.com/3", three) + + assert first.combine(second, third) == Registry( + retrieve=retrieve, + ).with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/2", two), + ("http://example.com/3", three), + ], + ) + assert second.combine(first, third) == Registry( + retrieve=retrieve, + ).with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/2", two), + ("http://example.com/3", three), + ], + ) + + def test_combine_with_common_retrieve(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + three = ID_AND_CHILDREN.create_resource({"baz": "quux"}) + + def retrieve(uri): # pragma: no cover + pass + + first = Registry(retrieve=retrieve).with_resource( + "http://example.com/1", + one, + ) + second = Registry( + retrieve=retrieve, + ).with_resource("http://example.com/2", two) + third = Registry(retrieve=retrieve).with_resource( + "http://example.com/3", + three, + ) + + assert first.combine(second, third) == Registry( + retrieve=retrieve, + ).with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/2", two), + ("http://example.com/3", three), + ], + ) + assert second.combine(first, third) == Registry( + retrieve=retrieve, + ).with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/2", two), + ("http://example.com/3", three), + ], + ) + + def test_combine_conflicting_retrieve(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + three = ID_AND_CHILDREN.create_resource({"baz": "quux"}) + + def foo_retrieve(uri): # pragma: no cover + pass + + def bar_retrieve(uri): # pragma: no cover + pass + + first = Registry(retrieve=foo_retrieve).with_resource( + "http://example.com/1", + one, + ) + second = Registry().with_resource("http://example.com/2", two) + third = Registry(retrieve=bar_retrieve).with_resource( + "http://example.com/3", + three, + ) + + with pytest.raises(Exception, match="conflict.*retriev"): + first.combine(second, third) + + def test_remove(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + registry = Registry({"urn:foo": one, "urn:bar": two}) + assert registry.remove("urn:foo") == Registry({"urn:bar": two}) + + def test_remove_uncrawled(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + registry = Registry().with_resources( + [("urn:foo", one), ("urn:bar", two)], + ) + assert registry.remove("urn:foo") == Registry().with_resource( + "urn:bar", + two, + ) + + def test_remove_with_anchors(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"anchors": {"foo": "bar"}}) + registry = ( + Registry() + .with_resources( + [("urn:foo", one), ("urn:bar", two)], + ) + .crawl() + ) + assert ( + registry.remove("urn:bar") + == Registry() + .with_resource( + "urn:foo", + one, + ) + .crawl() + ) + + def test_remove_nonexistent_uri(self): + with pytest.raises(exceptions.NoSuchResource) as e: + Registry().remove("urn:doesNotExist") + assert e.value == exceptions.NoSuchResource(ref="urn:doesNotExist") + + def test_retrieve(self): + foo = Resource.opaque({"foo": "bar"}) + registry = Registry(retrieve=lambda uri: foo) + assert registry.get_or_retrieve("urn:example").value == foo + + def test_retrieve_arbitrary_exception(self): + foo = Resource.opaque({"foo": "bar"}) + + def retrieve(uri): + if uri == "urn:succeed": + return foo + raise Exception("Oh no!") + + registry = Registry(retrieve=retrieve) + assert registry.get_or_retrieve("urn:succeed").value == foo + with pytest.raises(exceptions.Unretrievable): + registry.get_or_retrieve("urn:uhoh") + + def test_retrieve_no_such_resource(self): + foo = Resource.opaque({"foo": "bar"}) + + def retrieve(uri): + if uri == "urn:succeed": + return foo + raise exceptions.NoSuchResource(ref=uri) + + registry = Registry(retrieve=retrieve) + assert registry.get_or_retrieve("urn:succeed").value == foo + with pytest.raises(exceptions.NoSuchResource): + registry.get_or_retrieve("urn:uhoh") + + def test_retrieve_cannot_determine_specification(self): + def retrieve(uri): + return Resource.from_contents({}) + + registry = Registry(retrieve=retrieve) + with pytest.raises(exceptions.CannotDetermineSpecification): + registry.get_or_retrieve("urn:uhoh") + + def test_retrieve_already_available_resource(self): + foo = Resource.opaque({"foo": "bar"}) + registry = Registry({"urn:example": foo}, retrieve=blow_up) + assert registry["urn:example"] == foo + assert registry.get_or_retrieve("urn:example").value == foo + + def test_retrieve_first_checks_crawlable_resource(self): + child = ID_AND_CHILDREN.create_resource({"ID": "urn:child", "foo": 12}) + root = ID_AND_CHILDREN.create_resource({"children": [child.contents]}) + registry = Registry(retrieve=blow_up).with_resource("urn:root", root) + assert registry.crawl()["urn:child"] == child + + def test_resolver(self): + one = Resource.opaque(contents={}) + registry = Registry({"http://example.com": one}) + resolver = registry.resolver(base_uri="http://example.com") + assert resolver.lookup("#").contents == {} + + def test_resolver_with_root_identified(self): + root = ID_AND_CHILDREN.create_resource({"ID": "http://example.com"}) + resolver = Registry().resolver_with_root(root) + assert resolver.lookup("http://example.com").contents == root.contents + assert resolver.lookup("#").contents == root.contents + + def test_resolver_with_root_unidentified(self): + root = Resource.opaque(contents={}) + resolver = Registry().resolver_with_root(root) + assert resolver.lookup("#").contents == root.contents + + def test_repr(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + registry = Registry().with_resources( + [ + ("http://example.com/1", one), + ("http://example.com/foo/bar", two), + ], + ) + assert repr(registry) == "" + assert repr(registry.crawl()) == "" + + def test_repr_mixed_crawled(self): + one = Resource.opaque(contents={}) + two = ID_AND_CHILDREN.create_resource({"foo": "bar"}) + registry = ( + Registry( + {"http://example.com/1": one}, + ) + .crawl() + .with_resource(uri="http://example.com/foo/bar", resource=two) + ) + assert repr(registry) == "" + + def test_repr_one_resource(self): + registry = Registry().with_resource( + uri="http://example.com/1", + resource=Resource.opaque(contents={}), + ) + assert repr(registry) == "" + + def test_repr_empty(self): + assert repr(Registry()) == "" + + +class TestResource: + def test_from_contents_from_json_schema(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + resource = Resource.from_contents(schema) + assert resource == Resource(contents=schema, specification=DRAFT202012) + + def test_from_contents_with_no_discernible_information(self): + """ + Creating a resource with no discernible way to see what + specification it belongs to (e.g. no ``$schema`` keyword for JSON + Schema) raises an error. + """ + + with pytest.raises(exceptions.CannotDetermineSpecification): + Resource.from_contents({"foo": "bar"}) + + def test_from_contents_with_no_discernible_information_and_default(self): + resource = Resource.from_contents( + {"foo": "bar"}, + default_specification=Specification.OPAQUE, + ) + assert resource == Resource.opaque(contents={"foo": "bar"}) + + def test_from_contents_unneeded_default(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + resource = Resource.from_contents( + schema, + default_specification=Specification.OPAQUE, + ) + assert resource == Resource( + contents=schema, + specification=DRAFT202012, + ) + + def test_non_mapping_from_contents(self): + resource = Resource.from_contents( + True, + default_specification=ID_AND_CHILDREN, + ) + assert resource == Resource( + contents=True, + specification=ID_AND_CHILDREN, + ) + + def test_from_contents_with_fallback(self): + resource = Resource.from_contents( + {"foo": "bar"}, + default_specification=Specification.OPAQUE, + ) + assert resource == Resource.opaque(contents={"foo": "bar"}) + + def test_id_delegates_to_specification(self): + specification = Specification( + name="", + id_of=lambda contents: "urn:fixedID", + subresources_of=lambda contents: [], + anchors_in=lambda specification, contents: [], + maybe_in_subresource=( + lambda segments, resolver, subresource: resolver + ), + ) + resource = Resource( + contents={"foo": "baz"}, + specification=specification, + ) + assert resource.id() == "urn:fixedID" + + def test_id_strips_empty_fragment(self): + uri = "http://example.com/" + root = ID_AND_CHILDREN.create_resource({"ID": uri + "#"}) + assert root.id() == uri + + def test_subresources_delegates_to_specification(self): + resource = ID_AND_CHILDREN.create_resource({"children": [{}, 12]}) + assert list(resource.subresources()) == [ + ID_AND_CHILDREN.create_resource(each) for each in [{}, 12] + ] + + def test_subresource_with_different_specification(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + resource = ID_AND_CHILDREN.create_resource({"children": [schema]}) + assert list(resource.subresources()) == [ + DRAFT202012.create_resource(schema), + ] + + def test_anchors_delegates_to_specification(self): + resource = ID_AND_CHILDREN.create_resource( + {"anchors": {"foo": {}, "bar": 1, "baz": ""}}, + ) + assert list(resource.anchors()) == [ + Anchor(name="foo", resource=ID_AND_CHILDREN.create_resource({})), + Anchor(name="bar", resource=ID_AND_CHILDREN.create_resource(1)), + Anchor(name="baz", resource=ID_AND_CHILDREN.create_resource("")), + ] + + def test_pointer_to_mapping(self): + resource = Resource.opaque(contents={"foo": "baz"}) + resolver = Registry().resolver() + assert resource.pointer("/foo", resolver=resolver).contents == "baz" + + def test_pointer_to_array(self): + resource = Resource.opaque(contents={"foo": {"bar": [3]}}) + resolver = Registry().resolver() + assert resource.pointer("/foo/bar/0", resolver=resolver).contents == 3 + + def test_root_pointer(self): + contents = {"foo": "baz"} + resource = Resource.opaque(contents=contents) + resolver = Registry().resolver() + assert resource.pointer("", resolver=resolver).contents == contents + + def test_opaque(self): + contents = {"foo": "bar"} + assert Resource.opaque(contents) == Resource( + contents=contents, + specification=Specification.OPAQUE, + ) + + +class TestResolver: + def test_lookup_exact_uri(self): + resource = Resource.opaque(contents={"foo": "baz"}) + resolver = Registry({"http://example.com/1": resource}).resolver() + resolved = resolver.lookup("http://example.com/1") + assert resolved.contents == resource.contents + + def test_lookup_subresource(self): + root = ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/", + "children": [ + {"ID": "http://example.com/a", "foo": 12}, + ], + }, + ) + registry = root @ Registry() + resolved = registry.resolver().lookup("http://example.com/a") + assert resolved.contents == {"ID": "http://example.com/a", "foo": 12} + + def test_lookup_anchor_with_id(self): + root = ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/", + "anchors": {"foo": 12}, + }, + ) + registry = root @ Registry() + resolved = registry.resolver().lookup("http://example.com/#foo") + assert resolved.contents == 12 + + def test_lookup_anchor_without_id(self): + root = ID_AND_CHILDREN.create_resource({"anchors": {"foo": 12}}) + resolver = Registry().with_resource("urn:example", root).resolver() + resolved = resolver.lookup("urn:example#foo") + assert resolved.contents == 12 + + def test_lookup_unknown_reference(self): + resolver = Registry().resolver() + ref = "http://example.com/does/not/exist" + with pytest.raises(exceptions.Unresolvable) as e: + resolver.lookup(ref) + assert e.value == exceptions.Unresolvable(ref=ref) + + def test_lookup_non_existent_pointer(self): + resource = Resource.opaque({"foo": {}}) + resolver = Registry({"http://example.com/1": resource}).resolver() + ref = "http://example.com/1#/foo/bar" + with pytest.raises(exceptions.Unresolvable) as e: + resolver.lookup(ref) + assert e.value == exceptions.PointerToNowhere( + ref="/foo/bar", + resource=resource, + ) + assert str(e.value) == "'/foo/bar' does not exist within {'foo': {}}" + + def test_lookup_non_existent_pointer_to_array_index(self): + resource = Resource.opaque([1, 2, 4, 8]) + resolver = Registry({"http://example.com/1": resource}).resolver() + ref = "http://example.com/1#/10" + with pytest.raises(exceptions.Unresolvable) as e: + resolver.lookup(ref) + assert e.value == exceptions.PointerToNowhere( + ref="/10", + resource=resource, + ) + + def test_lookup_pointer_to_empty_string(self): + resolver = Registry().resolver_with_root(Resource.opaque({"": {}})) + assert resolver.lookup("#/").contents == {} + + def test_lookup_non_existent_pointer_to_empty_string(self): + resource = Resource.opaque({"foo": {}}) + resolver = Registry().resolver_with_root(resource) + with pytest.raises( + exceptions.Unresolvable, + match="^'/' does not exist within {'foo': {}}.*'#'", + ) as e: + resolver.lookup("#/") + assert e.value == exceptions.PointerToNowhere( + ref="/", + resource=resource, + ) + + def test_lookup_non_existent_anchor(self): + root = ID_AND_CHILDREN.create_resource({"anchors": {}}) + resolver = Registry().with_resource("urn:example", root).resolver() + resolved = resolver.lookup("urn:example") + assert resolved.contents == root.contents + + ref = "urn:example#noSuchAnchor" + with pytest.raises(exceptions.Unresolvable) as e: + resolver.lookup(ref) + assert "'noSuchAnchor' does not exist" in str(e.value) + assert e.value == exceptions.NoSuchAnchor( + ref="urn:example", + resource=root, + anchor="noSuchAnchor", + ) + + def test_lookup_invalid_JSON_pointerish_anchor(self): + resolver = Registry().resolver_with_root( + ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/", + "foo": {"bar": 12}, + }, + ), + ) + + valid = resolver.lookup("#/foo/bar") + assert valid.contents == 12 + + with pytest.raises(exceptions.InvalidAnchor) as e: + resolver.lookup("#foo/bar") + assert " '#/foo/bar'" in str(e.value) + + def test_lookup_retrieved_resource(self): + resource = Resource.opaque(contents={"foo": "baz"}) + resolver = Registry(retrieve=lambda uri: resource).resolver() + resolved = resolver.lookup("http://example.com/") + assert resolved.contents == resource.contents + + def test_lookup_failed_retrieved_resource(self): + """ + Unretrievable exceptions are also wrapped in Unresolvable. + """ + + uri = "http://example.com/" + + registry = Registry(retrieve=blow_up) + with pytest.raises(exceptions.Unretrievable): + registry.get_or_retrieve(uri) + + resolver = registry.resolver() + with pytest.raises(exceptions.Unresolvable): + resolver.lookup(uri) + + def test_repeated_lookup_from_retrieved_resource(self): + """ + A (custom-)retrieved resource is added to the registry returned by + looking it up. + """ + resource = Resource.opaque(contents={"foo": "baz"}) + once = [resource] + + def retrieve(uri): + return once.pop() + + resolver = Registry(retrieve=retrieve).resolver() + resolved = resolver.lookup("http://example.com/") + assert resolved.contents == resource.contents + + resolved = resolved.resolver.lookup("http://example.com/") + assert resolved.contents == resource.contents + + def test_repeated_anchor_lookup_from_retrieved_resource(self): + resource = Resource.opaque(contents={"foo": "baz"}) + once = [resource] + + def retrieve(uri): + return once.pop() + + resolver = Registry(retrieve=retrieve).resolver() + resolved = resolver.lookup("http://example.com/") + assert resolved.contents == resource.contents + + resolved = resolved.resolver.lookup("#") + assert resolved.contents == resource.contents + + # FIXME: The tests below aren't really representable in the current + # suite, though we should probably think of ways to do so. + + def test_in_subresource(self): + root = ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/", + "children": [ + { + "ID": "child/", + "children": [{"ID": "grandchild"}], + }, + ], + }, + ) + registry = root @ Registry() + + resolver = registry.resolver() + first = resolver.lookup("http://example.com/") + assert first.contents == root.contents + + with pytest.raises(exceptions.Unresolvable): + first.resolver.lookup("grandchild") + + sub = first.resolver.in_subresource( + ID_AND_CHILDREN.create_resource(first.contents["children"][0]), + ) + second = sub.lookup("grandchild") + assert second.contents == {"ID": "grandchild"} + + def test_in_pointer_subresource(self): + root = ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/", + "children": [ + { + "ID": "child/", + "children": [{"ID": "grandchild"}], + }, + ], + }, + ) + registry = root @ Registry() + + resolver = registry.resolver() + first = resolver.lookup("http://example.com/") + assert first.contents == root.contents + + with pytest.raises(exceptions.Unresolvable): + first.resolver.lookup("grandchild") + + second = first.resolver.lookup("#/children/0") + third = second.resolver.lookup("grandchild") + assert third.contents == {"ID": "grandchild"} + + def test_dynamic_scope(self): + one = ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/", + "children": [ + { + "ID": "child/", + "children": [{"ID": "grandchild"}], + }, + ], + }, + ) + two = ID_AND_CHILDREN.create_resource( + { + "ID": "http://example.com/two", + "children": [{"ID": "two-child/"}], + }, + ) + registry = [one, two] @ Registry() + + resolver = registry.resolver() + first = resolver.lookup("http://example.com/") + second = first.resolver.lookup("#/children/0") + third = second.resolver.lookup("grandchild") + fourth = third.resolver.lookup("http://example.com/two") + assert list(fourth.resolver.dynamic_scope()) == [ + ("http://example.com/child/grandchild", fourth.resolver._registry), + ("http://example.com/child/", fourth.resolver._registry), + ("http://example.com/", fourth.resolver._registry), + ] + assert list(third.resolver.dynamic_scope()) == [ + ("http://example.com/child/", third.resolver._registry), + ("http://example.com/", third.resolver._registry), + ] + assert list(second.resolver.dynamic_scope()) == [ + ("http://example.com/", second.resolver._registry), + ] + assert list(first.resolver.dynamic_scope()) == [] + + +class TestSpecification: + def test_create_resource(self): + specification = Specification( + name="", + id_of=lambda contents: "urn:fixedID", + subresources_of=lambda contents: [], + anchors_in=lambda specification, contents: [], + maybe_in_subresource=( + lambda segments, resolver, subresource: resolver + ), + ) + resource = specification.create_resource(contents={"foo": "baz"}) + assert resource == Resource( + contents={"foo": "baz"}, + specification=specification, + ) + assert resource.id() == "urn:fixedID" + + def test_detect_from_json_schema(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + specification = Specification.detect(schema) + assert specification == DRAFT202012 + + def test_detect_with_no_discernible_information(self): + with pytest.raises(exceptions.CannotDetermineSpecification): + Specification.detect({"foo": "bar"}) + + def test_detect_with_non_URI_schema(self): + with pytest.raises(exceptions.CannotDetermineSpecification): + Specification.detect({"$schema": 37}) + + def test_detect_with_no_discernible_information_and_default(self): + specification = Specification.OPAQUE.detect({"foo": "bar"}) + assert specification is Specification.OPAQUE + + def test_detect_unneeded_default(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + specification = Specification.OPAQUE.detect(schema) + assert specification == DRAFT202012 + + def test_non_mapping_detect(self): + with pytest.raises(exceptions.CannotDetermineSpecification): + Specification.detect(True) + + def test_non_mapping_detect_with_default(self): + specification = ID_AND_CHILDREN.detect(True) + assert specification is ID_AND_CHILDREN + + def test_detect_with_fallback(self): + specification = Specification.OPAQUE.detect({"foo": "bar"}) + assert specification is Specification.OPAQUE + + def test_repr(self): + assert ( + repr(ID_AND_CHILDREN) == "" + ) + + +class TestOpaqueSpecification: + THINGS = [{"foo": "bar"}, True, 37, "foo", object()] + + @pytest.mark.parametrize("thing", THINGS) + def test_no_id(self, thing): + """ + An arbitrary thing has no ID. + """ + + assert Specification.OPAQUE.id_of(thing) is None + + @pytest.mark.parametrize("thing", THINGS) + def test_no_subresources(self, thing): + """ + An arbitrary thing has no subresources. + """ + + assert list(Specification.OPAQUE.subresources_of(thing)) == [] + + @pytest.mark.parametrize("thing", THINGS) + def test_no_anchors(self, thing): + """ + An arbitrary thing has no anchors. + """ + + assert list(Specification.OPAQUE.anchors_in(thing)) == [] + + +@pytest.mark.parametrize( + "cls", + [Anchor, Registry, Resource, Specification, exceptions.PointerToNowhere], +) +def test_nonsubclassable(cls): + with pytest.raises(Exception, match="(?i)subclassing"): + + class Boom(cls): # pragma: no cover + pass diff --git a/source/target-vendors/cp312/referencing/tests/test_exceptions.py b/source/target-vendors/cp312/referencing/tests/test_exceptions.py new file mode 100644 index 0000000..85cf99e --- /dev/null +++ b/source/target-vendors/cp312/referencing/tests/test_exceptions.py @@ -0,0 +1,34 @@ +import itertools + +import pytest + +from referencing import Resource, exceptions + + +def pairs(choices): + return itertools.combinations(choices, 2) + + +TRUE = Resource.opaque(True) + + +thunks = ( + lambda: exceptions.CannotDetermineSpecification(TRUE), + lambda: exceptions.NoSuchResource("urn:example:foo"), + lambda: exceptions.NoInternalID(TRUE), + lambda: exceptions.InvalidAnchor(resource=TRUE, anchor="foo", ref="a#b"), + lambda: exceptions.NoSuchAnchor(resource=TRUE, anchor="foo", ref="a#b"), + lambda: exceptions.PointerToNowhere(resource=TRUE, ref="urn:example:foo"), + lambda: exceptions.Unresolvable("urn:example:foo"), + lambda: exceptions.Unretrievable("urn:example:foo"), +) + + +@pytest.mark.parametrize("one, two", pairs(each() for each in thunks)) +def test_eq_incompatible_types(one, two): + assert one != two + + +@pytest.mark.parametrize("thunk", thunks) +def test_hash(thunk): + assert thunk() in {thunk()} diff --git a/source/target-vendors/cp312/referencing/tests/test_jsonschema.py b/source/target-vendors/cp312/referencing/tests/test_jsonschema.py new file mode 100644 index 0000000..c80714d --- /dev/null +++ b/source/target-vendors/cp312/referencing/tests/test_jsonschema.py @@ -0,0 +1,382 @@ +import pytest + +from referencing import Registry, Resource, Specification +import referencing.jsonschema + + +@pytest.mark.parametrize( + "uri, expected", + [ + ( + "https://json-schema.org/draft/2020-12/schema", + referencing.jsonschema.DRAFT202012, + ), + ( + "https://json-schema.org/draft/2019-09/schema", + referencing.jsonschema.DRAFT201909, + ), + ( + "http://json-schema.org/draft-07/schema#", + referencing.jsonschema.DRAFT7, + ), + ( + "http://json-schema.org/draft-06/schema#", + referencing.jsonschema.DRAFT6, + ), + ( + "http://json-schema.org/draft-04/schema#", + referencing.jsonschema.DRAFT4, + ), + ( + "http://json-schema.org/draft-03/schema#", + referencing.jsonschema.DRAFT3, + ), + ], +) +def test_schemas_with_explicit_schema_keywords_are_detected(uri, expected): + """ + The $schema keyword in JSON Schema is a dialect identifier. + """ + contents = {"$schema": uri} + resource = Resource.from_contents(contents) + assert resource == Resource(contents=contents, specification=expected) + + +def test_unknown_dialect(): + dialect_id = "http://example.com/unknown-json-schema-dialect-id" + with pytest.raises(referencing.jsonschema.UnknownDialect) as excinfo: + Resource.from_contents({"$schema": dialect_id}) + assert excinfo.value.uri == dialect_id + + +@pytest.mark.parametrize( + "id, specification", + [ + ("$id", referencing.jsonschema.DRAFT202012), + ("$id", referencing.jsonschema.DRAFT201909), + ("$id", referencing.jsonschema.DRAFT7), + ("$id", referencing.jsonschema.DRAFT6), + ("id", referencing.jsonschema.DRAFT4), + ("id", referencing.jsonschema.DRAFT3), + ], +) +def test_id_of_mapping(id, specification): + uri = "http://example.com/some-schema" + assert specification.id_of({id: uri}) == uri + + +@pytest.mark.parametrize( + "specification", + [ + referencing.jsonschema.DRAFT202012, + referencing.jsonschema.DRAFT201909, + referencing.jsonschema.DRAFT7, + referencing.jsonschema.DRAFT6, + ], +) +@pytest.mark.parametrize("value", [True, False]) +def test_id_of_bool(specification, value): + assert specification.id_of(value) is None + + +@pytest.mark.parametrize( + "specification", + [ + referencing.jsonschema.DRAFT202012, + referencing.jsonschema.DRAFT201909, + referencing.jsonschema.DRAFT7, + referencing.jsonschema.DRAFT6, + ], +) +@pytest.mark.parametrize("value", [True, False]) +def test_anchors_in_bool(specification, value): + assert list(specification.anchors_in(value)) == [] + + +@pytest.mark.parametrize( + "specification", + [ + referencing.jsonschema.DRAFT202012, + referencing.jsonschema.DRAFT201909, + referencing.jsonschema.DRAFT7, + referencing.jsonschema.DRAFT6, + ], +) +@pytest.mark.parametrize("value", [True, False]) +def test_subresources_of_bool(specification, value): + assert list(specification.subresources_of(value)) == [] + + +@pytest.mark.parametrize( + "uri, expected", + [ + ( + "https://json-schema.org/draft/2020-12/schema", + referencing.jsonschema.DRAFT202012, + ), + ( + "https://json-schema.org/draft/2019-09/schema", + referencing.jsonschema.DRAFT201909, + ), + ( + "http://json-schema.org/draft-07/schema#", + referencing.jsonschema.DRAFT7, + ), + ( + "http://json-schema.org/draft-06/schema#", + referencing.jsonschema.DRAFT6, + ), + ( + "http://json-schema.org/draft-04/schema#", + referencing.jsonschema.DRAFT4, + ), + ( + "http://json-schema.org/draft-03/schema#", + referencing.jsonschema.DRAFT3, + ), + ], +) +def test_specification_with(uri, expected): + assert referencing.jsonschema.specification_with(uri) == expected + + +@pytest.mark.parametrize( + "uri, expected", + [ + ( + "http://json-schema.org/draft-07/schema", + referencing.jsonschema.DRAFT7, + ), + ( + "http://json-schema.org/draft-06/schema", + referencing.jsonschema.DRAFT6, + ), + ( + "http://json-schema.org/draft-04/schema", + referencing.jsonschema.DRAFT4, + ), + ( + "http://json-schema.org/draft-03/schema", + referencing.jsonschema.DRAFT3, + ), + ], +) +def test_specification_with_no_empty_fragment(uri, expected): + assert referencing.jsonschema.specification_with(uri) == expected + + +def test_specification_with_unknown_dialect(): + dialect_id = "http://example.com/unknown-json-schema-dialect-id" + with pytest.raises(referencing.jsonschema.UnknownDialect) as excinfo: + referencing.jsonschema.specification_with(dialect_id) + assert excinfo.value.uri == dialect_id + + +def test_specification_with_default(): + dialect_id = "http://example.com/unknown-json-schema-dialect-id" + specification = referencing.jsonschema.specification_with( + dialect_id, + default=Specification.OPAQUE, + ) + assert specification is Specification.OPAQUE + + +# FIXME: The tests below should move to the referencing suite but I haven't yet +# figured out how to represent dynamic (& recursive) ref lookups in it. +def test_lookup_trivial_dynamic_ref(): + one = referencing.jsonschema.DRAFT202012.create_resource( + {"$dynamicAnchor": "foo"}, + ) + resolver = Registry().with_resource("http://example.com", one).resolver() + resolved = resolver.lookup("http://example.com#foo") + assert resolved.contents == one.contents + + +def test_multiple_lookup_trivial_dynamic_ref(): + TRUE = referencing.jsonschema.DRAFT202012.create_resource(True) + root = referencing.jsonschema.DRAFT202012.create_resource( + { + "$id": "http://example.com", + "$dynamicAnchor": "fooAnchor", + "$defs": { + "foo": { + "$id": "foo", + "$dynamicAnchor": "fooAnchor", + "$defs": { + "bar": True, + "baz": { + "$dynamicAnchor": "fooAnchor", + }, + }, + }, + }, + }, + ) + resolver = ( + Registry() + .with_resources( + [ + ("http://example.com", root), + ("http://example.com/foo/", TRUE), + ("http://example.com/foo/bar", root), + ], + ) + .resolver() + ) + + first = resolver.lookup("http://example.com") + second = first.resolver.lookup("foo/") + resolver = second.resolver.lookup("bar").resolver + fourth = resolver.lookup("#fooAnchor") + assert fourth.contents == root.contents + + +def test_multiple_lookup_dynamic_ref_to_nondynamic_ref(): + one = referencing.jsonschema.DRAFT202012.create_resource( + {"$anchor": "fooAnchor"}, + ) + two = referencing.jsonschema.DRAFT202012.create_resource( + { + "$id": "http://example.com", + "$dynamicAnchor": "fooAnchor", + "$defs": { + "foo": { + "$id": "foo", + "$dynamicAnchor": "fooAnchor", + "$defs": { + "bar": True, + "baz": { + "$dynamicAnchor": "fooAnchor", + }, + }, + }, + }, + }, + ) + resolver = ( + Registry() + .with_resources( + [ + ("http://example.com", two), + ("http://example.com/foo/", one), + ("http://example.com/foo/bar", two), + ], + ) + .resolver() + ) + + first = resolver.lookup("http://example.com") + second = first.resolver.lookup("foo/") + resolver = second.resolver.lookup("bar").resolver + fourth = resolver.lookup("#fooAnchor") + assert fourth.contents == two.contents + + +def test_lookup_trivial_recursive_ref(): + one = referencing.jsonschema.DRAFT201909.create_resource( + {"$recursiveAnchor": True}, + ) + resolver = Registry().with_resource("http://example.com", one).resolver() + first = resolver.lookup("http://example.com") + resolved = referencing.jsonschema.lookup_recursive_ref( + resolver=first.resolver, + ) + assert resolved.contents == one.contents + + +def test_lookup_recursive_ref_to_bool(): + TRUE = referencing.jsonschema.DRAFT201909.create_resource(True) + registry = Registry({"http://example.com": TRUE}) + resolved = referencing.jsonschema.lookup_recursive_ref( + resolver=registry.resolver(base_uri="http://example.com"), + ) + assert resolved.contents == TRUE.contents + + +def test_multiple_lookup_recursive_ref_to_bool(): + TRUE = referencing.jsonschema.DRAFT201909.create_resource(True) + root = referencing.jsonschema.DRAFT201909.create_resource( + { + "$id": "http://example.com", + "$recursiveAnchor": True, + "$defs": { + "foo": { + "$id": "foo", + "$recursiveAnchor": True, + "$defs": { + "bar": True, + "baz": { + "$recursiveAnchor": True, + "$anchor": "fooAnchor", + }, + }, + }, + }, + }, + ) + resolver = ( + Registry() + .with_resources( + [ + ("http://example.com", root), + ("http://example.com/foo/", TRUE), + ("http://example.com/foo/bar", root), + ], + ) + .resolver() + ) + + first = resolver.lookup("http://example.com") + second = first.resolver.lookup("foo/") + resolver = second.resolver.lookup("bar").resolver + fourth = referencing.jsonschema.lookup_recursive_ref(resolver=resolver) + assert fourth.contents == root.contents + + +def test_multiple_lookup_recursive_ref_with_nonrecursive_ref(): + one = referencing.jsonschema.DRAFT201909.create_resource( + {"$recursiveAnchor": True}, + ) + two = referencing.jsonschema.DRAFT201909.create_resource( + { + "$id": "http://example.com", + "$recursiveAnchor": True, + "$defs": { + "foo": { + "$id": "foo", + "$recursiveAnchor": True, + "$defs": { + "bar": True, + "baz": { + "$recursiveAnchor": True, + "$anchor": "fooAnchor", + }, + }, + }, + }, + }, + ) + three = referencing.jsonschema.DRAFT201909.create_resource( + {"$recursiveAnchor": False}, + ) + resolver = ( + Registry() + .with_resources( + [ + ("http://example.com", three), + ("http://example.com/foo/", two), + ("http://example.com/foo/bar", one), + ], + ) + .resolver() + ) + + first = resolver.lookup("http://example.com") + second = first.resolver.lookup("foo/") + resolver = second.resolver.lookup("bar").resolver + fourth = referencing.jsonschema.lookup_recursive_ref(resolver=resolver) + assert fourth.contents == two.contents + + +def test_empty_registry(): + assert referencing.jsonschema.EMPTY_REGISTRY == Registry() diff --git a/source/target-vendors/cp312/referencing/tests/test_referencing_suite.py b/source/target-vendors/cp312/referencing/tests/test_referencing_suite.py new file mode 100644 index 0000000..4b8ae91 --- /dev/null +++ b/source/target-vendors/cp312/referencing/tests/test_referencing_suite.py @@ -0,0 +1,66 @@ +from pathlib import Path +import json +import os + +import pytest + +from referencing import Registry +from referencing.exceptions import Unresolvable +import referencing.jsonschema + + +class SuiteNotFound(Exception): + def __str__(self): # pragma: no cover + return ( + "Cannot find the referencing suite. " + "Set the REFERENCING_SUITE environment variable to the path to " + "the suite, or run the test suite from alongside a full checkout " + "of the git repository." + ) + + +if "REFERENCING_SUITE" in os.environ: # pragma: no cover + SUITE = Path(os.environ["REFERENCING_SUITE"]) / "tests" +else: + SUITE = Path(__file__).parent.parent.parent / "suite/tests" +if not SUITE.is_dir(): # pragma: no cover + raise SuiteNotFound() +DIALECT_IDS = json.loads(SUITE.joinpath("specifications.json").read_text()) + + +@pytest.mark.parametrize( + "test_path", + [ + pytest.param(each, id=f"{each.parent.name}-{each.stem}") + for each in SUITE.glob("*/**/*.json") + ], +) +def test_referencing_suite(test_path, subtests): + dialect_id = DIALECT_IDS[test_path.relative_to(SUITE).parts[0]] + specification = referencing.jsonschema.specification_with(dialect_id) + loaded = json.loads(test_path.read_text()) + registry = loaded["registry"] + registry = Registry().with_resources( + (uri, specification.create_resource(contents)) + for uri, contents in loaded["registry"].items() + ) + for test in loaded["tests"]: + with subtests.test(test=test): + if "normalization" in test_path.stem: + pytest.xfail("APIs need to change for proper URL support.") + + resolver = registry.resolver(base_uri=test.get("base_uri", "")) + + if test.get("error"): + with pytest.raises(Unresolvable): + resolver.lookup(test["ref"]) + else: + resolved = resolver.lookup(test["ref"]) + assert resolved.contents == test["target"] + + then = test.get("then") + while then: # pragma: no cover + with subtests.test(test=test, then=then): + resolved = resolved.resolver.lookup(then["ref"]) + assert resolved.contents == then["target"] + then = then.get("then") diff --git a/source/target-vendors/cp312/referencing/tests/test_retrieval.py b/source/target-vendors/cp312/referencing/tests/test_retrieval.py new file mode 100644 index 0000000..d0a8f8a --- /dev/null +++ b/source/target-vendors/cp312/referencing/tests/test_retrieval.py @@ -0,0 +1,106 @@ +from functools import lru_cache +import json + +import pytest + +from referencing import Registry, Resource, exceptions +from referencing.jsonschema import DRAFT202012 +from referencing.retrieval import to_cached_resource + + +class TestToCachedResource: + def test_it_caches_retrieved_resources(self): + contents = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + stack = [json.dumps(contents)] + + @to_cached_resource() + def retrieve(uri): + return stack.pop() + + registry = Registry(retrieve=retrieve) + + expected = Resource.from_contents(contents) + + got = registry.get_or_retrieve("urn:example:schema") + assert got.value == expected + + # And a second time we get the same value. + again = registry.get_or_retrieve("urn:example:schema") + assert again.value is got.value + + def test_custom_loader(self): + contents = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + stack = [json.dumps(contents)[::-1]] + + @to_cached_resource(loads=lambda s: json.loads(s[::-1])) + def retrieve(uri): + return stack.pop() + + registry = Registry(retrieve=retrieve) + + expected = Resource.from_contents(contents) + + got = registry.get_or_retrieve("urn:example:schema") + assert got.value == expected + + # And a second time we get the same value. + again = registry.get_or_retrieve("urn:example:schema") + assert again.value is got.value + + def test_custom_from_contents(self): + contents = {} + stack = [json.dumps(contents)] + + @to_cached_resource(from_contents=DRAFT202012.create_resource) + def retrieve(uri): + return stack.pop() + + registry = Registry(retrieve=retrieve) + + expected = DRAFT202012.create_resource(contents) + + got = registry.get_or_retrieve("urn:example:schema") + assert got.value == expected + + # And a second time we get the same value. + again = registry.get_or_retrieve("urn:example:schema") + assert again.value is got.value + + def test_custom_cache(self): + schema = {"$schema": "https://json-schema.org/draft/2020-12/schema"} + mapping = { + "urn:example:1": dict(schema, foo=1), + "urn:example:2": dict(schema, foo=2), + "urn:example:3": dict(schema, foo=3), + } + + resources = { + uri: Resource.from_contents(contents) + for uri, contents in mapping.items() + } + + @to_cached_resource(cache=lru_cache(maxsize=2)) + def retrieve(uri): + return json.dumps(mapping.pop(uri)) + + registry = Registry(retrieve=retrieve) + + got = registry.get_or_retrieve("urn:example:1") + assert got.value == resources["urn:example:1"] + assert registry.get_or_retrieve("urn:example:1").value is got.value + assert registry.get_or_retrieve("urn:example:1").value is got.value + + got = registry.get_or_retrieve("urn:example:2") + assert got.value == resources["urn:example:2"] + assert registry.get_or_retrieve("urn:example:2").value is got.value + assert registry.get_or_retrieve("urn:example:2").value is got.value + + # This still succeeds, but evicts the first URI + got = registry.get_or_retrieve("urn:example:3") + assert got.value == resources["urn:example:3"] + assert registry.get_or_retrieve("urn:example:3").value is got.value + assert registry.get_or_retrieve("urn:example:3").value is got.value + + # And now this fails (as we popped the value out of `mapping`) + with pytest.raises(exceptions.Unretrievable): + registry.get_or_retrieve("urn:example:1") diff --git a/source/target-vendors/cp312/referencing/typing.py b/source/target-vendors/cp312/referencing/typing.py new file mode 100644 index 0000000..a614464 --- /dev/null +++ b/source/target-vendors/cp312/referencing/typing.py @@ -0,0 +1,61 @@ +""" +Type-annotation related support for the referencing library. +""" + +from __future__ import annotations + +from collections.abc import Mapping as Mapping +from typing import TYPE_CHECKING, Any, Protocol + +try: + from typing_extensions import TypeVar +except ImportError: # pragma: no cover + from typing import TypeVar + +if TYPE_CHECKING: + from referencing._core import Resolved, Resolver, Resource + +#: A URI which identifies a `Resource`. +URI = str + +#: The type of documents within a registry. +D = TypeVar("D", default=Any) + + +class Retrieve(Protocol[D]): + """ + A retrieval callable, usable within a `Registry` for resource retrieval. + + Does not make assumptions about where the resource might be coming from. + """ + + def __call__(self, uri: URI) -> Resource[D]: + """ + Retrieve the resource with the given URI. + + Raise `referencing.exceptions.NoSuchResource` if you wish to indicate + the retriever cannot lookup the given URI. + """ + ... + + +class Anchor(Protocol[D]): + """ + An anchor within a `Resource`. + + Beyond "simple" anchors, some specifications like JSON Schema's 2020 + version have dynamic anchors. + """ + + @property + def name(self) -> str: + """ + Return the name of this anchor. + """ + ... + + def resolve(self, resolver: Resolver[D]) -> Resolved[D]: + """ + Return the resource for this anchor. + """ + ... diff --git a/source/target-vendors/cp312/rpds/__init__.py b/source/target-vendors/cp312/rpds/__init__.py new file mode 100644 index 0000000..257da6a --- /dev/null +++ b/source/target-vendors/cp312/rpds/__init__.py @@ -0,0 +1,5 @@ +from .rpds import * + +__doc__ = rpds.__doc__ +if hasattr(rpds, "__all__"): + __all__ = rpds.__all__ \ No newline at end of file diff --git a/source/target-vendors/cp312/rpds/__init__.pyi b/source/target-vendors/cp312/rpds/__init__.pyi new file mode 100644 index 0000000..51f03b0 --- /dev/null +++ b/source/target-vendors/cp312/rpds/__init__.pyi @@ -0,0 +1,79 @@ +from collections.abc import ( + ItemsView, + Iterable, + Iterator, + KeysView, + Mapping, + ValuesView, +) +from typing import ( + TypeVar, +) + +_T = TypeVar("_T") +_KT_co = TypeVar("_KT_co", covariant=True) +_VT_co = TypeVar("_VT_co", covariant=True) +_KU_co = TypeVar("_KU_co", covariant=True) +_VU_co = TypeVar("_VU_co", covariant=True) + +class HashTrieMap(Mapping[_KT_co, _VT_co]): + def __init__( + self, + value: Mapping[_KT_co, _VT_co] | Iterable[tuple[_KT_co, _VT_co]] = {}, + **kwds: Mapping[_KT_co, _VT_co], + ): ... + def __getitem__(self, key: _KT_co) -> _VT_co: ... + def __iter__(self) -> Iterator[_KT_co]: ... + def __len__(self) -> int: ... + def discard(self, key: _KT_co) -> HashTrieMap[_KT_co, _VT_co]: ... + def items(self) -> ItemsView[_KT_co, _VT_co]: ... + def keys(self) -> KeysView[_KT_co]: ... + def values(self) -> ValuesView[_VT_co]: ... + def remove(self, key: _KT_co) -> HashTrieMap[_KT_co, _VT_co]: ... + def insert( + self, + key: _KT_co, + val: _VT_co, + ) -> HashTrieMap[_KT_co, _VT_co]: ... + def update( + self, + *args: Mapping[_KU_co, _VU_co] | Iterable[tuple[_KU_co, _VU_co]], + ) -> HashTrieMap[_KT_co | _KU_co, _VT_co | _VU_co]: ... + @classmethod + def convert( + cls, + value: Mapping[_KT_co, _VT_co] | Iterable[tuple[_KT_co, _VT_co]], + ) -> HashTrieMap[_KT_co, _VT_co]: ... + @classmethod + def fromkeys( + cls, + keys: Iterable[_KT_co], + value: _VT_co = None, + ) -> HashTrieMap[_KT_co, _VT_co]: ... + +class HashTrieSet(frozenset[_T]): + def __init__(self, value: Iterable[_T] = ()): ... + def __iter__(self) -> Iterator[_T]: ... + def __len__(self) -> int: ... + def discard(self, value: _T) -> HashTrieSet[_T]: ... + def remove(self, value: _T) -> HashTrieSet[_T]: ... + def insert(self, value: _T) -> HashTrieSet[_T]: ... + def update(self, *args: Iterable[_T]) -> HashTrieSet[_T]: ... + +class List(Iterable[_T]): + def __init__(self, value: Iterable[_T] = (), *more: _T): ... + def __iter__(self) -> Iterator[_T]: ... + def __len__(self) -> int: ... + def push_front(self, value: _T) -> List[_T]: ... + def drop_first(self) -> List[_T]: ... + +class Queue(Iterable[_T]): + def __init__(self, value: Iterable[_T] = (), *more: _T): ... + def __iter__(self) -> Iterator[_T]: ... + def __len__(self) -> int: ... + def enqueue(self, value: _T) -> Queue[_T]: ... + def dequeue(self, value: _T) -> Queue[_T]: ... + @property + def is_empty(self) -> _T: ... + @property + def peek(self) -> _T: ... diff --git a/source/target-vendors/cp312/rpds/py.typed b/source/target-vendors/cp312/rpds/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/rpds/rpds.cpython-312-x86_64-linux-gnu.so b/source/target-vendors/cp312/rpds/rpds.cpython-312-x86_64-linux-gnu.so new file mode 100644 index 0000000000000000000000000000000000000000..6d5f769f98b2fb498a5e973eaf53be1835d1d143 GIT binary patch literal 966896 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
      ^vX9@;L1%D~nqUTEUdOok&^jyfW5m74Uv`fzq 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⪼{ZIi=WENgQE&*YUbQ6wbbfTgvOOZ3GDQpk|= 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 AYOE*V!oCGJsw_epvH7O5W)g-L2K;vdW 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�qTqq>foTRi3w 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

      <0ou;Sq z<-?u7KF$a3Q{PL&$*(7T{jArCztZr|Un)LnSm&>|^MU&>TAog?(WI7_ieK07RKF*+ z{;BQvMe*x;>+6@rr_2A}!Y32O`Aco@)OOYVlM2^3PBwl{Hl9=aBlTIg$ElY8KRtf_ zxA3KYU+QyD?XBVZ`enzT#-p!a7N71vjZft9&Yyn&dB0bu*EpOsSYZ17sp6A;rStb? z@i}qH{eTp}>GpH#yi7@!mO9UdrQ}P^pE^!c@#*K(e5vzKr%SzRx{wM_t>@Wxf_bS4 zQ=U`vrGB3~C4FkWC#SrhlJb0Y%JVfT&pkb+wg;wV>X%x6YX0mLfL{A`zMk4Ib=;n5 z<2hOTrRLM)SeKXDekW@Wolk$p$=X+^)ARe+G@PD0`knK7s_mLuFTK8Kcu(z`TAncH z^3(15W!oopyrs5RPxVTr2YISi$$IsaFLi!vI-;7Lx=S%uzdFyZSU0dU(*e0U%%}86m*HllhNIt`Y&~SoMB@W zNs;_|%9lzPM_b9$PL?lqyq;_4n`d8px}?tg&r82k`JTac0jc#!EjM*uo|clYr*=tg z&(!(cQ@+%C>UpZ$<@4rCrH3+xyZfbO6^Hk}u=4W&RkNKSCrOuE4sd4^A z$KA=sS?ahNtv}ShruMI%cRJbm`o_Mdj$8d&ua`raK;5ky|I_Qh$<`5FFU?n_ey4t~ z=SAxK)MuSOwY@c5Uv)d^XH9=TFFu`K=hyVCr~F^E{;70Im!q#5pMKW$>8bowd^)|( zpW0sf{i)*9^-Im4`mD=Ot)GVLYwG)x)i1RionGVnqWk!h;nU+uOwLE>Lb!g>dZ+R$ zU$)*S!>8+ggnH{SEY;U=(Glkf!2W6YUwVN5x(7Vr9^eJw)jW$XL$0act>2~6^VH|m zah&>I^9?=WqncfQdK_zDPw!L5hfc4{>*>A5_hsMf@>193RJ^I zTS~dQZasako3bqG+f4zv)?rQ2H?65QkHH;8%15-;mjL z-0Sqe0q&f~8ZPzi4t_0g=UV+`+f`TfI{W4x2(5E|>i2wBx4)D1%gNsBw(qIE^XyW4 zdauVRTK6vV>122{K7CF7I1Sg=)c0Q&e^34PW!vjy_43sTXCp+Qd%sfD!|&zZ$w!>5y?PoyJ;6_gPk*nzO5M8q>F@r3tKD_| z^tHP>3QX5CwSP`FzrO5yO^+r}2Q8zL`e^vw+&g6r8a^Mmb3SUgj1T8H((wC%pT$4@ z)9?oX4Anrc8Xn}nyZVS6#YyjV`T&#MiRYU(&OdRz(!Q6AhCju8C&{yvU#oZW%B)>hi}m9!-b?DqYL4x;e%4z@!NJ9 z>3b*r>WL1WtbKHQ>#L&*U2dsHx4)C&KUsU-Yh#U4fOFny__^u$5j#rO@ZSS>j$cQT zZf{Rk5B>f6nubV$?&J9KUMxukBi@d@CpY~4gU{d&T*mn+h=KC=YBU}=e-E{ zWCtFIS%f$Q#5hCAd#Ab zTkQLPGWneKcfvz%1IuIo`i0 zp8xIiXWI32t{no>^}mGrJLNEicKV*$&wibz=ShTpn{!-`u@mg>otCC`OajvI7l1q0 zcP$fejtNPx$C1njXZ)=6yxBEmF7){#NofBx{K6DG`WuH(e`mYtvX%gM&QT2){z$i>6mg$jPA6CA{MT^l zcPGED;nEIHI;!hg1%7Ay*yy{gMH+T0S3TEGHl9B(?o*ww_t*t|pYN46(!UY*jg!_1 zD9?tUtlkqoXS#3L>8_^yZ2Mj=8o$0eUUhq`)9Gusi5x(d5B1Ym$18QKX|Nuj`n{IJ z)B?C%1G#Fr&0#F0tE|I!2e zcfg(WS*Mq1(N2Cy!$0T&Pg@W0H+#Sz1Ac*{p4Zv;9wxeT9nt+T1Ndl1dY^rNZJ(}i zN0R^l_J5!SbRRtpE+@Uz@c#zx>=!K;+Ydb8C||=f=tt-Jq2Yts$90G2Ci<6GiQirJ z-9qN2ru_o?iVeRQxD&sI{~5TGf6(Q&QlE3}ymHa-|Aaqu;?eM>J;22W)|pyL)dC%v;inhxo!qe|*l&x0?!Ki1_x4pt|<*6`b?uXFv=@NvMMa!w7u9Qd`4%4+x~ z=J&-8xTZ0813R-D_zYl!9dLaM`fh(3uCLuD0(h$L^>?VV<{Zd1Ts%~r>$QfTO}{$% zS`8O@*g4(ckvOf+eW6Z&fN|+;KMfZdv9p~tTxfoGaB27M;6iVm@@$RgJHW^APyh5B zD+Zu>O?ju`qRa0m0Q;xmSMl5(Tx4I}!5;*!X^NoIcpl>3xgXH*65yjGq5X5hy&A|> z!%Mk$j%y7s1MZ}28ZLZYcjdkS{Qt0b?{PAh|Nr=3&Q>cUht{bkN$Wh$r^U!=3mKxE z8!RbH<4lQ3OHS2@P_|4(A!Q1sNJCCZnM8v~ zLG@~Us`_*8`#0lR%5%>v<4+6!Z`Ug-?pSK@Z}+MBpL?F0L{lEV!ltF z-+c_~^GojIzx@9H>3=u-o!(Zt_d5?)Y`Qu=sz z-G1)lgV`Pz)$u#`dCT|}<@H%pzZfr~j#s&_lTCkyss7~N?{a(Y=itWst9)MLFj`#) zw9M76$sbal`#Qt;EY+Xf{Wm^ax#_bmm)mncS2F(eHR{Yzo>zag=T)b&^3r+q|90iM zpLd#e8!69yem36t8s1cS?(>VuH&b3Uk9M`^RloT)^4jyt>+AL0*H5Nh?KkGpZu@K0 z>2M8CSDx2;Y0s-aovz`Xui^JzqrUdM>UU9|*LZ5rD_>K&d^V$pMIAo>m&>)jZq6ky zsDQo}FpH0W(C6sf$IJiS<9j;mJg1I3xwoG=ew$a*u6Z?XUX7dA|J{C=ee@x9JjlI2 z8Gqp#zTg@@Mh!};>5O_cb+qT+|2i{sRK4aNN8=}j_h7!5dNt=pO~&=HFZXfoLH$Lw z^i{{vyz1-gg53L)X*WxG?)v6A(9g=NssGGk{D6Wx464_T{PVOMob%WCv&wTHr*nO) z{YNt&Kjj8CfB#kdy$DY-=IizNcXO>^=EvoK{&`dvHaT?|x0eaLIWRf*6gbQL=e>_h z{QghW{-qbQk1cu$e^=AjUP63T!)-6o6?#kkdn`8Xs%c{{F@B>O4tp{4)@&;eCkv{m zdmnb}+*PcPi(fa_lsSu#H1|9%)-_`t=hw}(wOQ|E=3INwA#-f0$-gJK{%#gjzYg3U z&otgts$X4W|DD6bYXARzasLlrwemzV|1g?+3^%1x}0@p|2|DF*T`hR#; z{r`vSUoU@s1g?+3|2-pck@wqjjTf}Refk@GeV?z}`T7lCPw-WKzqxOh{@?y?o=cdV z{JZh%^)V9H$H&ZwyvO7E_*@?!=Lr0-|0d^){JZ(?|LMmcvmWMov-$h~saO50#PwpH zL;tsS{@eKew>tmr`~Tb5&2#W;_0v4>mS4Zte7RQc8si_7`RjkbJ_6TA;Q9z$AA##5 zaD4=>kHGa2$a@6xsSB$AFV|ol+O%orPVI1Sk819^p4#( zhSjW2504l&cvLfYr%r9%^;G5B_1vj-1`QoNXxO7;$J7};YEYfb%yGkO1x7vk$lyU^ z?7z6{4jR~CaQ!Cr>kq2iv~JTu^#(T@GO%IerUUBLA27%>xZc2e^%^#5Jh1WLYU&df z|Mt8=?IyJws(*PpYDOgyrSuEzDQ+=V-MDgtw+ggg>A>pZetV`dzq!HrKy{Y%gt@&wr@D+RH5Ue_cNz z>MT&6Pkj<9A)a4dZKVDQyZogrS9j+X`Z|@*Ykl{!zQqr^n9n5YpVQRsy6L@CPA}8# z4kuZui}82!|3%CPnJ>#P{7Dbf&F7c&&)e!xpn63ezjAwhnQy~78<_7Y@?S9T{mKsf z=d+)w_D+yw1w_7?a$P^fy!l+sSbCUlJ|`2QN9g9hN&mc(t`imcs_GlH$LJN<|99yL zdRKZ-eO^fCeS6XWR`d#L^V$8Ro6jA6N{`T|F+a-wfKrk*L#(gP8MTK+op$yIk&>*fqE1hGT=+273GG9F7P3F@GoKLo&zSe@ zN4^5{)zya)b$@*Hsq|;*ae5#6Is3zlNtP>{z?Y&WI6mK?zR3ra>-kwxZw^V1tIuia{s-u7O}EtNwX{d+d+1Z_&v7ML4MhFt>0aT>=-q{{rw4_9 zPTwm0dwNm*0|&X5)AY8&3)-J|OR~lYznQ*Vcy;<&;VtNyujFb}{n1Cy5;xTHBcSiu^%(K=`lprNXb$j|nenpHPyl zlvgdsQboD$f1)1xbA=S*GRr(EQ{dV-gn@;aZPhRfyVf608 zC(|bhpG#jPd>MVG@DJ(7gnvO#Ug7M|QF@l}bM*Pblk5*1Cs|8{SE5IS*QGaE>1?+h zJt({veYx=A^sU05q<4SIS^ow4D&Z^WQQ;rcPYM5up0dhW|2REe_$B&!;l=F>n3y~sy?MV+mz|8y64@OQu!9T+&&T|EXMaYiUv#a<({%yfh5cMh_tX0n#TWLgUkt7DQNE+Il>NE6hu*#w ztn^Qc*+D<+thBwDyZ@f)U)DPsxhI)bZr_o)7;6>@(dLi#F z0zbm~XXuvxSK-xiEAyYJe(3(Yi@~>ZeC}00@U1=Jg7;(o?S61yDfn(~mp|$5GVqH0 z!HC=Z$a~Af+c2M_enFD1A92G+(mxvn_f&?Tp=V^!tH8~6Uq-j?gs*42odzQxtqFey zFV=Z_qAun`S9<>;$oo71GtOaptReh4_U9+MU;knywU}{!O8p`py}SDDxYY`7#=j%o z=Y^Z`f1Vy|?ewGcXgfH+Y*iVK`mVd-<~Z{ZJxs62^*u?Cc0}GBHy#>+I-$<+1h?a( zs$+UQgZII`_VtQo#mB;<_CMLIex?auwj$#&o~aw0<5_Dw#xtb$1HHKI|6A5_+e=x? zhdKAVzbBx6Vi*dW`d>_hyB~$G<9d~R3?3f|?|Taxc;gAUH{`4{VKVwTL-g~!?ZvE! z=;x>@*zP+;KX<7EqaL5YJZJrE^$W1HhZn#<<_YHQsc`>l`1_nEPd^2Bzw7h?S@5|2 z1&?Ym`R3DDe=X~?PMPVf|32ItKfBN)^v+2bpFJ~?x1z}3!Ra1 z;T<^suh7Fg;YrNTe+K!;XK-_Sd6Mqi1^=G;s?TD(nCE_ebko|Pc6_}*dc<~V5W;pz z7u#j}T=suA>i^Cje%CzY6ZF;e{PW@Ay~z9M zE$9jQY98k=nEWB+i*X#DdjWMK-@*^DPSOH+=rFuEUaYU_;qL)oGQW2r@_`@Vk8yjo zUj$Dag*Rq?D&6xV+>Be<7m;`W1UK99UV4;n#&Zijd<^++T;IRxmVR)j7Bk#Dcxc>KW^wNGY^43|n*vA=(8doe543j^=AtE+#@ z<5kS795JuvzlL_>g>e2-yNSJgNe}2BxL1q0KD^;|W_=K3&5kKF)&lXW)JgTz8G5dU~e^6d6W_|Ca zyQ;(QXZ}0odOt1B@#JQ=+OL3@qTgs&v#go6m$FiL9qy*@qPsZ$=K8$(Tc|UrDH=4- z!za-vdf@7DrM+yTH|PX6KmTd1LY+is_zle8MgRUTxP7~%zLrHlQx|U5Ydd{sH#iTU zR?)Xne^p~={d?%=Sf8gUYYu&LduRSjdP3c==*9HM^^UHuu2*|wf~(7Edug{CzP^w1 z{QF%5{kf+df~KFhz6H}%)dqN!hYJ1aa23M*{3&-+>!WpO*Hs(! z&Gx-Q-_3Ex>{Y)rLY-Lkysg<0dG%P>UV`-LoL6Stw$S@?+|2we_yPJ8=!brq#~cOL z!&CY@x69%W(e7xDgPFJA(HE%uLcO@{|Ev3kkC6AM`&zx2c{qSRG7WC#`RlfqvL>+I z0PD=yfd1qNAM`Oi@F4nW^68u4apAW|;X`?#^{{@)&G1EZH~kCxdf_v-Ab(JJyHB+j zv+m^tH}h%+{fll`U-NU@pVOQ5fSY-H<5tv(al2Pxf4b5eaXig@m`|_C`FuO`2k24m z7iK<`--i0LIZw=f)Q^6#F8X6W&ljc-;ykw>+p0Exq8H)*VzzJ9?Wpgk+mEkR{$YA~ z^*lf?W_(uB+i)DreE5UDk;hNdpL#n`Uq2_%%dPhR)xTp!ugv-;zn4%6ZK2AfmdezCv7ifUF3Ej%Jb2#&vm|({W06U;+ODI93OL> zd5~V5Zt}0uw~6EPar%(9=%+b8r|v=hEV?=F4Wp;=xRJ_!zC)kg+&P}7Z7*fTxn39X zW$Vmdtnb0WSltc}NZo+wd_d&Cv%QoxL*!rm0r`Z;-x}9m$|@?J5BzF-G0WB4*`G&_ zBA+VqO@2gukH~*udnqejo##%H*59`4M+b*6k?TI^)r-kI*_^Un~sZ|EBNeRTO;vFtCX?-%#W zUFq^U@H5x&UCQ<~aPKIxyz-d5`y%>-TY7`WHm0#T>6%s{^%m58XVko@pPz z)%&^ca7FpDnE5#Kex5MSGM^>#MbrUM*Y|qS?wdS;`RxN^k`)vA(R8=D!DYMC>0aS4 z(*45wsNT_?ag=DK1x^E*ZU2l_$bJ9}b2 zxHHh7Z@FJIdk`LCeY1bHOu&7d52rb9JB{~2oqIUnx~YKue6Jr||9hr-IYPJmaCJJf zmmz16j}L%1X8w};V3w|9Wx_||v4!>2S$ObK_*1M?{2W~N^NbpYyykfc`$8_s$`Rvp z8~uv#`gGTO=(qWQJ9-u2573(kf0&*w{Be3;;m^n^65H3z!;o@a-!1a5(>=o9r*{(m z8GWemBlIlcf6x~R&wrbxmLzMH@H_i)K2Jsed0B5Y?GFz;4_Ak4dwGMN7z_UmY-MwQ z^iObl>LApK>R%YC7E`C!!|>oVxM_FDqi}1kGv6=(kBo=E&UQbd`zAWQ$5`Y&kHhb0 zzU<@h5dC5LH}v>8Fy`smAGA|XCogBI{lWH;npOlzfbp1ar(WlAn%>*^eRhOhvP7u>-7#j zGzNJ;`{Q1YylV!$DZRx?cv%0#MQZ88<7C1dSLZR$`Ww#U`g7;~D1fh8)(aQlu0C+{ zT<8G30^Qu#FIP8c`o6#|eBvee9iq+#+e=yA5xBlJ=dZSZq5rYz=t*6!SHUZ&BcErM zxh?PGc|GNNe>^4j$F}t3wHyGx+)uA5d?>w>@W<$x!sjU0=VgBc{a=_54IE*9j>!Mc zeDob>zGY?oeM#0?k@wO2u4BjfGKiind>s9V@R@Y?`_4Mq^bFyvO?}~8==+54r(YDF zL$7FdbT)sPo+kXp+jStx>MQ&)`6Kt-a{y@A~>D@By9O^7!D^d+;mted@Wh zoqrKtf_1{`0HQsy0saR49No1N{w7|mz5`f)4d6KIe?(8vO+Q@&k@qh`-n3hc_bI`J z@K&sIMD5qQKhlGL!=ubEWWMuN=3hdcY4o@Lfx8wvy?259cKtB@TYTBtZ2V(@8Hb4l zkq?I9Cf}wI+`kNN#^+h}ffjq5KZ2XxY@WJt)9&Fo8(&l`zkQr+$P?5c_WzLbJjX%J z!@RCnUskS-vzumkZ2C*w0h+ zE_dobBw3wAet>d4Zeg~2iTR_<&k*@P=^KR?vL9fo`&Qv8^ozo4(2IV=2KmyGo+`X6 zJzaPPy|3``^nmbL^eo{o)5F3e^o_zlr5_aj4gIX}lk|!koa=jq-d1>tYC4x>WeBfK zpCerT+?JhRB|M!T6W&lgU(@@S_fyQP&H45BTh_e3JZ@}&8z5AWMg&scu&&PavapV(+ocS;5p(Dr0QR9=>@nnK>yRmUXNdf3^hLtg(U%L~NnbDguyWmQC7-O_l5ZM}J4YB=cjK_lf+|^pNnE=wab+(<8#8^r-N!=`rCa=yBnf z=n3J;wXnX{C(iY~mF^N=kM0)Uj_wiOlkOEhjP4UYneG=pmmUzllpYlR0X-yq7d?F1#8&Av}$4MV;f{h3*nQknR>fmhKTggYFf+nC=t)4&5(& zGd)}QKKd%*Khrk~|BJp`c=0-xT9T|I!rk;!!t2wo2yahM-mJ>yT6)nd3eTk16h4KX zCj5DNC*jNJeTA>5XA1wEK1ulZ^f|&$)3b#a^yrmT&+CNWOy4NHI(@hB7W5;+ee_ep z2hpzxA4gB#l56nQA7|1l3eTq36uz3CCVUIMlkolYzQS|pnZhsACkel?F2-|?@Z0Fw z!W+<63GYDPD7-g)xA5WgBf^99Q^M!buLysGp8TnE{6C~u6uz5YQ}_?`G~s9HorD*v zhjHsGJcXVqyas)e@RsyB!n@M5g=f%L2_H}2D10`3x9}zOBf{6vPYK^azasoFJ$b8h z{Qsa=6keb{#;vCCo9Su7YtTCh@AeL^=cE4=v>Q%g^E2q?UpX?AzmT2m%lsy~Hy_;O&(ZyboL(!!`hTL`KCJUF-CNL^f7N)xxn6bFppIYk zb1*$Bd@Eym zbhlXF6CWX;xajO>;|=iGC8vK*_wv4@Gv`m?jmU>ZKkuTuML#FfEzzHM>5&s?*VI2n zj~;jWogbs!px9n-7#Hhxf$lr+T(8-iP{;SPv;KCvU#wUDPuQ+lucq{<*p4IVZqff$ zbiY{NpG_UMYxdJ2QI50NA77)#MSl*_y<(iZtIvh%{VVZ;FG>T&jn{!FENInGJ>up<@UjeJ}jAKKCrVt!7cTVk9y z&;w$=ou@~|IMh;~^VIzei+MYkZgG2=dH5>bE%FUw?7tYdN9Z20y*AKYVn0p(3Uwl4 zocqyTtZ%maJM@4U|9|LFvA_G&=RfuOhQ#stReDsMmm7Y~@e${vOygp^yh-}!891rWN&&TTV zw8U}aUAkA~f1`)RabWlXj)NGt6?DJIS38J&P~-<27x`A|`Yo^LmVJ3$*LN#VXnYw# z&lDb{PZIt-eU9*@^lafD(6WxvM&X<3apC*uSA_peZ?ePLpTFp1gcom! z@mwn0P2VcKK0PkHJ^hOCUi6fm&i-W5(}Yi<`-Sglf&C&@wvb)OJSI4D58QtP{2Mlt z#m~cdOT$mnYt2O7n*?t~KQjmJcER7HTl}1iHyK`%=e7LvkPouXH0JB6H!SS)V;SU4 zKilVrTcZDKitv4klE~l9`gimF)5J|q-|S+Z*FVp&-4{!;-NMLc(VO1{j|%^e?kj@4 zsWYV%@^Shq*14@TJX92UZp&w*vkOpCE#Ye zyg`qP?e!~NZr|bMP(Lijtwi~}{oQN$eHHS~pSy-HR6jVc=Yt&Qrj_!pbC~WC+v^GS z576s6ayve+_Lsbl|ErbT?~mM!af@-gJlaVALA_5c_OGeRbv}^d%nxgfd|2cs(>DsA zOW!SgDgBi259qGX*g?MRqBju!9lfXU1bve50!`5WY~f|;8--V+UlE>0Puu0}XBYY; z;R8*5;l0}7xDmPqf5c-hYt9PY7dJoB38&vTq(Vw{)K6T;u8yFPbr$DMSK@Nelp;iu@C!mrX7 z33oNs?Wxbt3$IL12yZ~IxZBy!4)k>4z3D;W!|AJp2k8fe&!ZRo!rAT{bdT^4>3xOo zrq2-m1AVRVGxUAJ3pK;ISzkK)lcHQ7uOe+Rf6Qf2f97k7{7AZAcosb%d?7t3d?h_3 z{9}4pc#Iwq{u4ba{5(A-JgGUxAuhZkJt4df{Xf5eio^lqKu{(4To`(7UBo5J~VXRAzC zc%+##|3WW#@Ghrk4uZSVoOP=5{1s^7%xBC%K2{q(jpOs>Y`Dh@@6PpV{0ux=AFfu@ zUM9?k$J@ZSu}-}g;Gx#=pXg&3!UK)q&$7;kJa1Y};HLiAmyi$Fft&t3r#|4S&r`9M za5Mg1H_l&v=Iza=+OB;YKHr$p4-FP)f2_*zk@OqsZRl6~BA-N`Mwg#U-$D03fP7Kr z7u}Bf4~TXT(=V|;*21zXRYAT1^Ea@LpI(GsjQ$$EmB^3119eIYZ(kLD58aGIxjW&h z^kmlWLq99}Su+*+iXuNkx!x|pc37hn)>%dm3qL}S3NKX+b>hPBpg|DZ3 zh5teK3$I$8{TJSk9u_{I9u@vMJuWa-OUf0h%d4BPV^UJsN?!r&eGlXBIj}h)_ zp(lpA-xOY%9unSw9ueMw9uwZ1eoXjqy7d(&CSQW|io!>Z!tva9FUJ2M^QSqU9&Q)& zd}dNz&bN-ve35z_|4#5Vtn)5C&>3!?JKazpc{jZi^Xupl`a*i22FQE5pw8d)m~kKc zTY9^O$h*42f2V&$m;ITi#wV|N5>cK{{gioxKc60CogX-!X<|H2E7#ZO?rv!JcIKDj_Z()S5}ik`fe9pTFYx?lJT`g-9T={dsp&{My5*8h>- zQ}{XMdVD;?F+OT{wwEUM#8AKgU*tQ|cM9)MFSyUy?nt^zcow~)@P+gy!dKGU3jdfs zRCtU&M)*(kpz!nbY~e{>y*}#SH4t7=xt@ofD6T-%Hga(7`_RYWme4*@WfEK zd0xHpQP$`FqApYIWyA!y$M3A)EC>%}IQ@JG9_SA@{oKXtVb4SGcUiv#uZR7Q!VA); zzlb`qhv7HV3%&;T^@N-CEq9UmfpF9AFZ4)Xr+5Dc`6$QVY?s4ouh8S{9)-Ml47Z5S z)kEAaX8Zm@k8!)-%k8o%Kk9_J-A%p#f4(Wf`X+yw&$V2cXtx~Kw=thnB_4755?<%W z`oPUNj8xb8y8oemPES(T+uA+7oPJzgKWk46aQX-8`q_3duV$+2XYG+e&iu>jI$66* z)M=@HQGot^GOT4^SBJb&eyqd=L zGPM~ze81DPn!{b3KlbjgzT>qtT+erFf&veqjMdef_xWgqa{Kr>7WGRrzk?o_0$)Kd z(HePw5MGTwTe4hmKBC$19!RB=Q^7aYnnme|%aU zXSAUg5-f5!UezOw6|$osf` z#}q)FA?kRd^O?+}nq@UsZy0G`D7?>Q)JZ&v*Gdn8oUvG*){sPMY-Nj19OnC!|{L2KH(-= zHO&c-K8Kzrd@y<&hD0Q zKlAviWwmZap9|T`?YM~^W_|_hxV<=!1h~Gb^p35uAAO;oBkIK*w@bFmd*0Sou8)T~ zVm!Tc*8%&i9!FSR4^{vqk9uuCa zT(=uyoz+~g8tvgRu5W+i9WW2?Qs+Ir)SzeDUdmd;`fmE$boWT-{`&{(jAosZ%-2mv zKbwgB%XFXcA8apX<*<%v_qMxHXQ;>zvb~tqhi~wXW4lY~FYtl%{qz&c_4vqfeyLsF z``xo?YCfyua4?MRg8y6A&-(el@(7*N%}VV84~YDidb_B6Ncdm$u<*6l=+8do`Z$mf z`{N0ELGu8H>w8AO-=W%#vcCP;L4EDwHR_jXkNPR1&YkpB;Z5mHgmxC7SLI%GHdpZ}GkyM))IyM?!+w-w%v z?iW6oK416*`f}m3>1&0*Lcb{dU3vraK#Oa(mF^dQfWA-oFZ3pd|1&i9AO5Dd6<#u3 ze>utOF8mI9KzLL74B?&Wi-ZrLFBd+RzFzoD`c~mD)AtE~mwrX~HhPsK&T%+I??iHxBgLQJWtMgj?Blw&2=G~A_ zFkhKbuzssv$a_S)VeR^OF8W!qci#CY zuHoO)<$AU5gF4dJsri}LecxW?_IBs|tj+!xxCd@+#QK&o>qU3dZ{)bWLic=(d?xdk z>0!FL|83n-2h``TzhjUu_tCoxA56~_KAxT>d?r0xcs6~l@YVF)!ne?m3Exk@B0Ps) z`g`YkU8dI*exv;cjT#5xx6%6wZ$KX-yaRoX@ZR*L!iUp03J=ov37W%Jj`adMl(NO@Eh*c-45tE#==wR$As6QCm+?{ z_wUk@?h)RV?h~Ft_X{6S-zj_+Jt6#My8Fj}`=b98q5Fh?N}nM78~SqLC+RzdU!flq zUZSgRT|EyGUYUMTctiTZpY-?ryQI_43hzUA9s4({|1^T`5&k6ICwx9VB>YX~dOk<@ zV7|3uGn4i6L**gPs|EC}>i4^84}XSy%Y67k(GI-c*yZ#Ky#5L8fOls8_OZxYpTZwu z{hXC>_ilK00eoS(7w2)$7Wg*i|LKVPanGn?wz%mtJK?+>h$6p`{;YaHs-GKo;Ppc) zeUI&>)bGtk9kX9A<@w#kacIT-t$k5H!t<&YYZkT}jP?ay}UC0M8V0Ib&=T(4U6Cu}ce`Na5?9i-~0?HJ(r?=bz*uCCv_TQP3w z9RGI)BOl)h|A6_k%Jp-hkf=XsDEc#8%?rKsW&Stiy1pFGM<34Hi*(ETI;x6t-G5gM z{dt4+r_f_x!Oix{QLgvXV`BbarWZZV0(`mgKIE$izfHMrH_CQTFh7a;G?9OfdDmX_ zr#JJ(yQ6-F$h+wQ;q~bu;qB=W;l1cF;hFSP!l%%a%?h!f&(muPUq(+CzMh^T{BwFx z`1kbX!cWsT3NP3L;}#QsGyRzG>hz1k^Do75Ccy1-3)i=_3-dfgSGODXvY5x2p`)G0 zhaDMeo?8{I=q|X6b?$ux^EtwKXpSe{hGV~w&)Z*6uJ;R>Z=w31*L_59<$4|__7$>Q zEX{V;&|UlC=6dW#_25zGgWtf-elgyDAem$}`I!ayGLzn2_+r+Hu)bNZHV^1;OtLaX zzK3#qe_^|Ka6C8A13#ia{O5J8LOoGulBknH&lX;TzFv4s`aa=Z=~skj&@1L}0QfSV z?h!sqx&9oBPkfH$C+6FV{CWBW;Ys!hLS5GhuSkywuS4G|{4V+t;XUZqN#}Z1)t@uh z^WiwgU%fqQFPZxN6g{sF!qtyS+RM$S;GQ3xo<$FR3xAqS8t9p06A62jdV*K~fL&BH#Kt3Y;3irDh=d(Hg z4prlp*M2vRx5TlgIMDd9`#$-g@L{~o=j@NM)?!Vl6jh5t&QBm63T zmGF{%bU%`;-NLKTty9i^Hm19U-$U;yydOPN_}}NTA4NI;qujq*^ZGXOEB1?7Z2pRR zj;HsFn3(7L)bls(3E`deb)7ozcv$BN)(K|9qko|OhxBc97d=7`1a$pk){_I#!7B9k zY*+uj8_%0=`dNBhoKG8#M7zOX(C!N67a2bZPtfleg?xbdV)U2j!36R@aNMemR(W+i z@t%Tj;c@R1<@!3-GX@n>SttJ(cu(Ool+`#<{}dI$z8>#P|0*v)z95s`aq}Gw4g`@;d*BnkRW3 z2QDes`>BufB%5`*_lLXw!nm2^z{kq<{``!SjUXpga?s7Ci1iBXN70etv}ci zzPv+E7QUJ87QT<(MEK8ipYXrv6NDG{qyIC6yXo_V*QbYtx2H#i_oC+rU&{9leH{NE zEiC&U#Qcehd2;j`+dWg&&uhESRBj)iFJt?f`S}w)LC@lOs?h-C&A)W3<|Vj$b4n|2q`BlNb+R~@APpni|NsNYn%eg5LVMC@h$1?ICvemQ-< z@D23k!oQ?%6@HW+7k-wWdYT>KOA&j=OtO5!%hTrzuSMS|+)F z`R^XU@!3@vu2$b(I`Dno{uzKYur_F_NUXfp-T%Q*_ z`Ot2d^`{JjhdBRB(M$5W*Lx%Kt+>8}^!22w6XCeokFC`ARG!2-+<)!Ewenjh<2>@E z`gv=;)Uf|=S#K)0&zszjTGL;h0uNrr{#%KDV~}~ess9w+V*krCf06DJ^>;ssIx&ue znI~PQ!d>~XzI#|_KRr%=l0M=otXDQSV0HRt<@Wiv2dz4QC+X{jZ?(OcRcA2TZOJ-CW};3^xqsP*P34E_vv@sYU)Cz0qmEa3oxfHn*T;ZkmPX!OM|B;7b`OethH_m$!un@* zOfAJ8(*IZgPMOG8qL=rmY{_3sLq6=GL2=n>)L>AQu`q9=sEZ0eu;cMSBOBJ?W4Kc%M$|Aw9+{3LyX z@HDl5+S{ut*0(5|Z^`#1{q#EY$?cI3(Ql&9dH`mIgX5csfS@fqh^R=FZ z`?Qs*Ymt~gHR#KQx1g^V-i00)K7f8v_-K03^XxcZrqfe|zex8AUq$x`|Ag)rzL%aU z{5XAr@IHK>%iRFmx3=l$L)cyxy)=FK2yVyf$bZRsnD!_SF`;vTY&ei9BByS%mrQdCa+g-EDg@Yur63 zU_a(nl`g9B$!q?Uc|#P@b{-MW&-!u&E z<_N!oeo=T6deIB)2wytVJ;M9bGlY+%PZFL*pD+B7`hi3}4*teiUtV5VZ;gT{IDh7{ zKl?|+ee?zNX?!2n(+G7;exdrHsjeSt2!E0JR6Y-nG5-v`m%1O($JKPP-IHI!JdwwZ zg=)R>+U{$W>vjX&j@4K{DH9&1o9l`UdZf8?yMLiv&!3HA++9B=E4K)VT1=Pu>Cj+^=CSZ5_YL4T57?NQXRE)w{XMt2GC zLQfMukUl~9Sb9|W4Ehz}iA^H-zVQplM_a(v zZMeM@P{%`key{it3fqSf^_BLvtM@M+FJ|Xb5V!7C^WQ$+a{id(@CEJ{PYpqx8q8OD z8TDV|FG{gbAL?uM)cEAJzjWcabr<6{fSw_Iv~oS3!GTyWvmbp)_h!INKO2wK9aHaj zh&p%EmkRGg-za>9a(n&{LVdGe7aIi+(N}OBy3u`fGoF9Z1N2*%e`hrMxlgpanSM<8 zKDzfZ3-IM<`YPdn(WAnPk3qY~guCep;q~dBE6#S?)5i$!MPDR5lfG8?06vcjayvd& z1nrdZt9huldu%l4Gxv)|LonZ_b3U7Ko=6Y!LfFOb-lOh+^?del{@hJ}NX=Va-^xUN zwR_sj*YwZ`wp$3^>J_vruOFtU^~!6W7w6C4xyGW7IsV*xKluu!;;h*T^jPfwo z%k-z&;=Fw_-6Qf_=q^#ea5nqH^%{!Rv+kqII=j?%(c|VHkKk&KL-sYc%ZHqYJHg$LT=*IKdf|n} z>4wz%S;AB32Zh(5=Ll~}zbL#bz34yA^~#{92p>;xD|{Bcuke@Y0pSsPmheyMG2!3P zBac@D=)nay+7|a{d7}*Dvu9w*00L^uvbyv z#k}z~baxQ#n)*qvA@8M|pR1Zm_p!cx8L!&-UOl+h`}I!l*B-X(UWz(?j)OUW9aXNc z(_%cYHD>M z)qj27oPqH%&zB~tcD1{nhUc)|hpy4?)5>)|Ium)b-M?kKV??{B=re@x8-{j0vrwlj z+ij;mZ=>qRS-&;?z3FhD$X~riKg&%(KLgCSV4cMi;lU(au$b$OuO5R(n7@zt`zFC% zv(e95d=R<#3AnE@>ZEfZs!xV{79n_o*CCtf@$<+Z=l<1q3i4Je{4M(5^w8h%O(oHx z4}!=?9)W+te!8Z@LtHQOeAxAr4yd3172{u7xgKZlJgnE58&T+yEO@vh>c7kWU!q$} zuwMI_UoZ`Ms~GZTJQq%9{o-)bpNF4@`)`7q^S*xuJXiv5jvL))qW`-^|A#2I`~MpH z-@uLjFP;T={e^y-&)YmO8y>wC^_vz%{sP_Nc)kj@+N%c+y1q-S*F}2Fg*qYTXQ>N6 zJ6{T}Hix|wdJZ0^FQ6Zxds$}=y}Mmd9nbS|BG88@*Y(G2!TPG{YA^Zc;`7P#`8gu2 zwWWUV6Y_5M-#kxPr(Dm68KV9U=6`4X1b3K*&-3%oe4p2wgmzz1uKN>MgBG{5yGQ7e zvKWU|h+7TkAs;-3e9Z#*!d$xV8@RfywwJHyk=gL}C}-U{A9X?t;Lo$&AU&D`Z_N68 zP5u}Pj7moR8ZV$u;vn*Cz}7%|_%i$h`bN5S3hraOF111RICzeteowYLnx54M`5|>s zXbat69{KNBzu7|6iB*6XVg1!~>j>P#{c+eLPW?fTbFehLBYj919x4g%OK<(E{)76wy_o0SmFqeQ<{xIh`fJEn zEWm-Mx1cu=?xXvK526Q!kE4f$&s47aW93KxKj%2#`8xU&75Qe$bv{-I`GM@`WqR-i zxS3a5mm=>^cKS2RP(LQ>hn4I4agP5xtiSyY z;T|5B{$#$v3et(ikiIvEEM7}aTO?X3kPvPnGF~a*O*X>4l{@Tud zwtEZh21UN7a-9#}i1j_k{9X0|P@R88zK3$1_j4Ya>&Xx4LAp7g_IMllXbS3^?Hg0B z=lOb3|0nuB;pgdb;Ys#}PO?r3uc%!2GtBc>L#|hX`HLc7U^VhF?x$vdT&rC7vtS|T z_T52u3;&j0Q}}PJ?mUH$en;xZCL3yi$I#BC;f_^vsN&5hvWGxl-=QHo+`R-Qc zZ&;81L`42p<+{F?=fUC3&tZP2$cLGaFrQ-bAEN#~nWvu>zE-(z*W&rho_?xC@<(uA zCC<0}XrLQC!t-fsj{hops9usCoR7Hmk8(X9Di(Im|56*+ZWYwO!1?w*J#-Fkt~dIr z3uC*VF?dbZpG^;c1y`qCd-;?es|G*G{`)>gooG$?0(95wID|^6xXhVJq@Mk>8_S=OfdQk1}7&J`p5Y^F_Y3a-ENVf_#O7 zx~^rpcfe!&;O4o?1IqO{EEjc#(Kia8!aBiTsH1jsd-;v|n8@ebiFUockynR1dl{`< zw|h+FpQc|FzL=hDE=Wo6Nm-qE#>k#XQMg8CC5#jj`bA0xq-P3H>XZ&k;dHNi> zdoRZ42l{rppZQMgP{AWQpgvzA+D%ce*EhoBsu>?YJt}-9>%>HzP4u(E_tITSW@OOO z6Rhw02J3Z+{V)DK`q@_GZ&R-O={kTs4=2`Mx|{wC>tx#lqJAHdsH1<6lD)p7PQN%j zN;l*1D?KLs@uTQxhN%A>JxloO^lafDDA)b*Mz9@gah~`35%t%K{BY$uANU&ilKFH_ zeLj%+9FhN!ent2f^ajOP0A;MBtnWIFaZb>i{-pn)ex6t4JJaLB2hfY&;H*EEUQ_r? zdPQ?V#CBh%cNhLH-7kC_eUb1(^oa1^=v#&7JBIZ=D7*|kA-o#BU~%XAwxFj7?@F&J zd@$WFd?Gz4{2AqXK3F{d&*Zp$MGqXtJh{05zEDs-Sg_~YX?T0)yW0;O)P0AjKa{>+ z_$1Z|l}DWstn(W^Q4XF>?{fm}MtOa^ihi0Ne;axA@c?_7`Llje_tB!=mzC@Ohgu>3 zDD!DK$Op_DQ+5^0@+r5+htJs_rEg$K9FA2PFCUOtaOrfI>ATd#ac%Xb_Y~o z{ukxC|JkDcRr)F6H~qr;?j*Zi{NJ+h`vTPcZwcqTnxyi&ekb7})`{;%f9|rYS=MIe zmy7&<`c{{-{z-a{@W1I-gqQpk{YfzgB({5pay|Z$pV1$4yEvZt1|mP3enj{ZdP4Xb zdcm8V{og@vBK$DDlkh+28Nv&k!g>XT->h7(m-`j0R|eO2Jv~Ivr1$;}`EW68*-rEd zzoUM(s9%Sk5Z;E~wv=;yAD}N1K8(If_!Rn1;q&PGguh9T3*SIb2;W05SlZdopXe#V zFDTdJ>D!F)tif-q^#`usJmR`^FujTJmzC?E2W-OeHP8JD+b1&h?=OgU%hNN3*H&)N z+e7HjM)t?g{0xyFL(djIgT7vPHoa&W=lDdF>+98Yu9x}hKg?GY`BLgaQTH?a8Tx7N zPunTib#nNAmZ>v_`Ox>s7vng+qg)?P8i@K^=;^}0VVx+i|6Qz;b_R9)BJZPT3C~cj z`&m@1?-J#DJEpR(seg`jR*5=Ef1=%}@Jh<{_$0o-`c~rkVj%M|ksn95%9;^F2WHW$ z2!Dm1F8n=uU*X%8>;8oJK8}66q?%}V7X4o<^1YPnyytiHe;2xAEoT0R$gifK75*vf z_=@BBQ-tGC;T+mcx!JkCb?6&~x1k>t{s6s6inGozdQag~=*xxAQ?BPjK+K2lnBOY$ zr|CJu3!TS$C7XZPisM#JxgO6L=l|=4@P)3*^?h7O>@Tm;=L)}Idqr!c=;vJ*(5_pw zdq2Iq@JHw~giltk$6=JHf712}RyyxDF)J+Vwu^dyDap08EI0r3h;qGOuafnZ>-7zD zz0Cf#llhGze}rDNymR{|=rx5Gv~TFt?~@mvLXQcrNxvxEOYdnethiqIoVxn`y26Jt zzg+kv)2{FkJ-MQDy_V9w!q?OL3g1niAUv+z-rsq>Z6ChWI;8%E?J`H?)0FFc9EqDO__M?WU~A$rkD&hdGio+|t~dK2NV(*wdkpl1pH zT)AFf*LjS?B924%D_E~ZB0p5QJ#NgK>#o1(?hB|hg>|O>jXJADodxub!dEKS^~0>A zZd>f7*;UlpE%Nu$3Gug~Sy0@rv zdlgX6@paxu@6CLG9!YZM_t2yC0Q*^6J)hNeJiHGz$H}?&b6fTAR*QZvW8QTG>fg>f z-_gDFw)E!eIis#0qMO^-m*|mX)G_T|pu2fpYUxkV!cv14!79PH`V*IB43~G7oJWJ2=7OqBYYG+TlmxT zRl>9BapCXMPYK^nFId?*4u|P3;R$*Z;f3tyq)FCL;pOQQgx8_Z5Z;!)RCq7?df_AJ z`-DG5PYBn~i|zeF?AL!VU*&e^IN&+2x?dJv&VF8*q<-&&GhdtT6W&I-Za18Y`7@vM zXA$##MgDE(gEf#htI^PYo~W*eMgAV;x_+c4^5*;-qsQp>V_wzv0QG!O=cBcp`2;;q zw-1jhKi+;0sLq3;-8ss2okVSCos#zRJN16O$X8Xa^R7C`zsPY|M~~1=|L;-<7M+jL z&3SD-JudRMspnI6zAoy2%=%;O=T_={G0~ry%zJpBUYz+6>N$?Cq9@1K*bBck1^jggP@{icp=x3hNrb9@K!zDz&*IC_X)nEom~On;NU zoArH%P$!3eneP1-UWs0<3EK73=g@m;SL>Can>x?Y4^I2uAoJDxzgsUud zrO_010u8WTmhgVOe>ePIuXMJT!q>U?As^=byN7CTZ zp7-IM*zPR4bq4i+rhiM1??>Kjmw}T}C&7Gq=AYI-U!&R$7evp^bDnSc^C=;|Ph_sQ zyS<5gjQuo^^;gopJe*cO5*8X04`c;X%$5GtM8<;}+_h z%hn6V#kggyL!CJ5-^==i--k!eqRs)jpPtOm>6v-^3EjUF{lq9)R_PB|ho6fxK9L?3 zo@4Ue(5{(R4L;=h-tY8P>H{izK1Uybo98FvH^KvR;Dz}hd)>#Zv%u+pZi0ux@DJJ1 z7E!owCHx!uw9RnOTKKE1|Hl@1d=p$fR<)OJKh1AHuO7<3W0cg-k8DN$#4gBL&XdXX za4+~*{J!GbkhjEkoUB|QXX1QbXX?Mk{Pb;*p{#${)Zym@2C;t9cJ$LP`q^B$9%t`a z)Y-;5=jg6KvA!?RJM2LIVa|t!^c;F(JL;I@QpKIf2YbWq+e6idp7aFg`62Evi|BDa z*D~j|-{`KJv7!ECe!^#{@8kQ<4{`l=(PLu2dvzDrR~)YIAo-&et60DBZsmUX}g} z-Ock?Gx{wt)bVp3PG|kDbPwMjSxuvPSAZk4;ruf725UO zg6;Jg`*Vh#;Py4=@teLzK19EX{mGz5`MhE;xBC~y`8>_ct8)8LCrmf=M?i z5$jj@1|H<|E^}VKasVFTb0Kp*GwLAR#r||=oiFJ@dJFpP-y(07!8p7?f1MttoB5D> z82KpgE6Xt7=6iTToPUe|khhPb%k%QFYvlXIQAeJC57K43{g39I|CKKDJ%2=A9^Vep z<#~DZPsq#j=0&>P-@iMScYeZgxU7HM&H3{Dx!|_S_3_Zv4BN|muIw}A`uW&daov8H z`7rYjb9*&ULEfsuiBIpWT-SG}p}yH)o>QLBDrU`p9(nU!AG1!fsI!M&Q+Op_SG$^{ z{;Q^4dX(OcepJ=T>*u5YVf_Z8{!Qg{&(!lS;djt8gg2p&5#DMwwu_hJ(3Sn^sPcLB z=V9e~+yX7JUaL7kwK8?_b|Wq8uj-V>G{r6iVU!VE8%!ft(1h1n`GXEy~vyImSPq5vl^kwY-{q#Fo|8-SAuknep-Swi~ zz4V>JkI@ebKTkg^yr}*DS&~)y4t9|JsX(tHyf(e9@YeM1!n@P`!XKhf5dIi_j__yb zVc}u=D&cGB8-;JD$AllE=LkPVzasn}y33rXIc_)E@3$pcRfOL`Zz8-2y_4{cbieTa z^fAIm(q{(3Xjlt3g1dUBK#mdA^a4*XsUDEEc-%K z{hXBW(sYmT>hIt<8G8W7u{6%lUwAzn?*cc+rCPim?oXe}{78Dny~vyUanH}FpWG8} zdb@-kWxMA6#4G%Bsf8uWV z9D4Nxd`EkDd0r29J`KNoKYSb8Jx_1d9d2L7sIP50gM1SEIf40fbz`N^Ydh%8=pWPb zbwVBEX=jmdPXC4Z1@!eC=VkO;&mmuqBwc{Z_0sQu=XHL( zSGiuVHt(SSBlrM!3H>R~&)?Z@e)WJw=T|+B{ABuF^y-t~{IN;vY5K@sa8u_Lz55LK z3f|DxbEE!)z2Qe$KSXc$6ubnVi|(g;`@k16-(0r z`C${`=KcLH^dIP7F#im_TYuzVX8lw2Kj^(V5B2*Ty8hVt$ai3!74*9Yz}wMFsOt=! zuRH-BX8rr2K1X9SFalo~+Khy3R5BJFLH$KJOvqH!+`}Kc4}Aig|s0)pfcK zh0ozUSx7H41U{MhbMz$(;l1fS)$v-_xnn&1Z??OPzJ=?%g8mEr(jw$*&~H)4Yh7pK z3-F&tLQ^R@QUpJRr;Gt;p%qSUN%=l{pacCe)G2K@Dgt$Z+tqvitsJ; zN%VH?f0-JnQ=9vpsgug*C*KW2{T|GRdEY(fEqEcW*M9Er#krr3W4^{k90%Td6ZxZD z-t(|KY%-=`Xzc(|lacKV!>Ua*K{z3Nhm22cTu%E6Y z$eZygRSWCop^sv_GwGopkbi-`SGm5wPFMSD?&TQWFZ?_`AiQX8)R`f?JbkI~n)Kbm zThVibccZ)1@gw&#m|ju%1bR*3v*|wJuh6rEze`^vd@Fsu@B{Q?!hfNk75+CpSsl-E zFRnTmPq*;f={1EnqNfSJo8Db`UwWqSN9mJ^WP`t&qK=f^VChNBv3HK$#8_+9re+h8>i*bF6uS7n=ym?-I>J+>c+co=3tKXTw8TEIv zer@h|A=W8J_m{vteEmje|Far#KG%T{VEz;19;feY%=~4{x2?<{OXEDh1$i(1@s`Xt zf%l;&^EeQ^f;!cB{quTzFr%5mN} zg!waQ*E~PDOn04vPiNly5c1*Q;O6@31l@fR-i-O!qsWIiZoEvh$_3bN0(t!3vX(ps zkCefBU0|KP^ynW*mZX=Qj(ji$`2!rE0t?|ju2*Bam!4p|H?huCx{G-;KW8sOolrg0 zFU|bt^x$3a2U)-Hi^#`?w>I7kdGljhPtx6DUTrkab_cM2OUcPB&2zStH{ok|erd=$3;8_LTM_*+`}|z?z(8#{_z&|J$?4TT^!E}tTUePgGcT}{xqKpZK6kc zy#0XrgX)cMy^Ai0jJe-jl4Sf*-P~U$Ol`)2eSTPdP4Z{L&(R)e(^S4?iV@6#eVU^VbqE8 zc$mTGW(Vkgo?pyyaweY}_&Fagv7d*HmqY*8@_gOq66(w2?XUDiY2?lJs?O&I9-ar+ zvpz?zFJ z{`rrsMZyAvx19ddj7}p z{J~HD&IiBxC$`7=CD7r)Pk!OS|7q~9^;mz9@JPV%-WdA|7M1$%hR!>l{~`0d=Ffit zbQ!++5I{9o&M{(DpR=l`LF`}sc&``I=B*Z;GdZV&$#_w&E<8}4zu z|J(iif6veV#K~8`{(FDood0LO`}sczyV|whf9vdcybC3UfI-cKlJpUsd&;R?5=l^TR^S|Mldp^Ijv;b8 zbN77yK*#fW$MgT@%stNUJ9j^Sd*OcmPk!Nk{zp5W|C=w}pa0)Fp8x!p?$7^i9nY^i zp8qEu&;LTl^U*8!d&O7o=f9A-pa1cTIxIh0p;fK2P+9jU5=AU*v|Lt@4=l_m{`}r@!kaLayE5GD^{=fgT?&rS^{;zBP z|J1+e{``}F+5P-C{uTH0zwwW{pZ_1f?0){QBd+LL*PrTm{=5Ed_ve2J{+(-_f1~61 zKk%pAbok31&;R*<&;9v-;@@{a{}X@O{rpdMJpV8MQ}^fJ!GHW|(||HR|NMXM{`{~0 zIrsDbw&VF_EpTE81c?J8~HUDR@ z%U#dE=y?7gc0B*b{%iL*MaT0=$MY4QyY}}V?|A;tbv*xfI>!H%j_3bb$Mc{5CHK1i zp8wAM{2%Rj{&~mqtB&VyJD&ef|D*f8KlkhI=TrDouKm63c>Z8Coh{|)^>j7LSK~?f zi{tXasJxvnZm%Dxr*GwaF`iAgeo5#0*Q;!Cr9ZvIlewH^^i}iI4X$z=y)KGWzAxm> zGF@i*MB?9OWwy*7jO0~X&9iHnUX}Q6{o8}lcsj=SD*W|ew3P4hvl?irzqQO43%n5{ z(CaXm{%D%b=h?0Pa{V)Al3kAr%wa|onJx7|_}YAy-ehGtp1#H_uG3;No6356`Zek; z#q9c8PVrsP0+YwzSBvFb|D^wZP|TN$<*KSi#e+1xe0H2ZJ-xV0(+8!T%h%(@QqI%* z1&arcM`>El($|w&o=wtnIh!xiZ1w&DUVJl=OIeOQ4D0wrO61Y&Ofkdx?E_89a&>)u zi?1|(ONpLaAD!Qni%~8DA>t@1Gv*~;5dC8DdNuO!y7T96UoE~(pD&LWufL4t;+txG z^Y%>|WRuCP2(f-p?fLR3NW%;BGkugtFW)EP$?Ws+yVNgcb1ACpW%PKwxS3?P^z(!C z>*x9(W;cttT1|^3m@0fSeK9Sh?-dw6o#Drat0;e{{&=hS1vDRD;^yJ9p8;_Mx(FC zH=EhEKXIMm6VI}qPZU?#7|T1Rzi1pKhDH+z$fm&j~{09;!4i(aB-E*Wtra0##6O|H{)rEbP2N1EI@=CtD8!;vBz{X|o2 zv*qp`(u>q={#%TrkL|up{Qn!qF(M7(46-bXlcMru7)uB*OPpEKOtY$-Lztc2p3q-Y z`EGM~v|$RV3lVpA`?50Qj9@DAHdWiKM1AIy{PiT z#EaWPU-12=b_t%T=cWuXh&p9`jYirE8#+%Jd$|-DD+1=1rD$seky!I=ifNLK8|r;% zxd^gWzAuAVMnw=LJa?HbtYNp1di7by3XHJ-oMiq-T?1$;!n}Z)7s84pu5H_^tYHqR zHAL1LwCtSA#cBdocCP+*t>S0~4t^(XD*^iX29`VVIkYtWsAT%Fk>=`%6xm{#;-?wT z$uWM`9Je`t6)%G@iu0lXpL<2q7{;`PZA@t1Q6z_w&?iO6A`6N{<`Sl8={d}I7TXj` zHl`b1<$D%^^sAt_uV0SkJG^pUzc3VqmsOtdBfrdK=CHFl+@9Jy!RTSvVZFI6bJ5Ojb6%v2JbxQhLCZ>@p z#5^b^YnrIEh}e3E7KU4kc(zjKS+C#(Z$u>hJ_GS!*z*c(N(43~0xge8ZZPpFf`FIvv4s3M zyJcQEt|~;o;IU%Q;wltz5Qk+}B9aoiLIGO%x`yJ)i(7z8V4`8Lz~d~D8RS6`h`509 z($=IQQ=-T*Sg@MvL1Yo*Jab-&B=(tr*t7<*$r;+@3~h3THaWwnYeL*ZRPkEEiYwAB zl2v}hqM(XPOpYvG#{}&S32kMLC84E3np34p}`!l(l+P;-o>H_d6O_=AyNWx79H<$aFm0gY<|Kq z>tP8bOg>cF$GI_JI%Om3?cKx?+yU-Zq>K#3Y|$_+t*G!bxxAW{3*{$ql}mu0#S;(v znFM*kIXFj@kZ*n~hV-$G_%?Oy!)%LId%tb*78CnNOc7ao0+gvm(1_yrWUuM?_J#5= z8U$^A)_e>$c<^qHs4a+>1+geXL^7&a1~9@M4C)Z)4hiZImW?>h;WLCy_rB9f-0mIzL^Ux-+r^+?;DwMIUu8gys^dokG7_M9B16}K0I5J>xru$OvR z#3qsbYWp+xi|zMrY6WURWZ$lIP#ICDYWf!Vbf#jT)JR8YW+{+z$hhWDL;`FG4)C zEl3(59tvlFppbd{t=pmO#9j#H={Jk1W43oO9ZX;oLCQnM=OR^}85}q(e=wv(Q9t@i0hGdYs=1nYPRRwdr$cxYmyujvxhD`__ zNCv&B?Nbc0<;;vC7;z#N%twl}j0=Z|wiS;AU2N{c>Bu+WPfyW=oqI+RPZV zxDYw2f{+JQ6mTzh#KUdP%^d5s7mO$$3G_j;@OYLa3{spSa#0kn2#J=e!$ymvB*uaw z?gv#7I}`&Vi-YIp%LK+&Qk9;UM_J(zW_L2t2dw}hYM)8Zud3WDMDC);9rn1)M8GMA z%!9081b=KZ%)pawZ}PyyZ`>m z32l*rsBL?VzD;}Ip1mu(XwTla6_sy`haXoCvQ4kh7H-H0TA#9MAKJ9vC*^0o(Wd=D z6L$9OT{%3Pb0XWE8J6jbY|hyy`PZgbZ1a6=&)%KFv&OP%AKSBcrQvMONo>wZY}zOG z>=S$TA3n=x&)=Q-vsb`8dkM_5*Wk_?+Omgv_9jqvvB!P42XXMKb+ql**jqi&0&-Bm zK>&MF%$~U;k~&an+he)oAZ@01o7C2)Y<51V3bl9R!|Tf)meN*N9cE=gXd&br?zMJY zRrqErq&OO#P~Fv+76^$M8bqA_}4?k4pkRI847*E;q3= zsE1n;8NbbHl--W?9&0Zcp*M=C5Ufa;D_H6RA~+=358@cx^SXC@9aeP@i`&x9wuo%C zU{BAcnl1Zm(Pv95TLRcK94L=%S>=jx+Y=w`;I*aW{iU`(m2PK|vrVibT}=_`T~Jvp zqJd0AF|q?0*qsSD!1i(fEr+eHBK|Fht)|3ahpk&`xDKFYS=q;Lh}5uUge?(VNHJU5 zxKdTNyuq36S?2~E8qufHo7*Hk`|5>AAD=wI0gOcGg}GpvkRtcF;{ev>(O;uHy0hw8 zOjp<6ph7xIgU2#oy;jxFZQ){*(_XSoJbS^mI2{&t*~dVn=o`_`LBu!(QD-8(o|P-0 zsN{QDfUsd$#32y3c~VITHb=?FurQ5pum1-e)#xTuaPjoT{g?nowtVZ&=sV24Au1^7J5w#< zAz3uEHeVy4Rloy0l0%?8wQo1WjWd)c+!i+pv0tuUI$jSZKZ~w zMvwfm72FWt#5U;dacoA49`HAl?Cm?j$FIN1Jpd>O?NzSi2<0DM z5@#MmTZt_5Gu;AZkmaL%Va^5TXhsqgv5#^jziy#ok;NL)=3Cd!*xC*RZi?99qB;pZ zA!QcE3CdmoGIsbDHlZCEmP2MAT(wR1B<@|c9hYS9 z7JgI)IS?5f@OxJ}-aZBPzB!5iJnsC5T2Fqp!C+$@yx!9A6)% z3rNV((<}jDqdWqB&yiUe>{mC}=%}pF;=pcgS5bpLD6&b z-Lc*GLz8y{&2(26k#w4=QgmwUaEafVb~nPYaa;rmx?UiF;VAGJSVC>bX&m;+K&*mo zBn_-ZwgsmPg3#brv_3vyUj`{c{PD52I>UHo{dHr=X(LgT{GNa<_( zcZ%dei)EpZSrwM(C?YE_gE8G>Q5-PnkfCzT4}ub9@UaBsZo3DB^SPC z_nxx0=n|^zmzLqO;<@R|cb(1O5Saf$qWRuNLh+23r5A{ZWl}G0 z!nF^oOYzx<%VAPGENU03%oZT~K*)Md4P^U=D&9C4M{=GN0?B!xaG`uWsHpYO(Dxtp zINDs*3T*vg$_^383NjdVILQcRWsV9`3*0@da+`m~cfA#%RaQxSt1Embm%=+DgDSRc+)TKLpQ->1I%ELe9^Ptju!?abq}r*q#axgzj*&Ng)^`qxt~QzQvmgpNTFyqMYaqE>s{atPbFNqjT9sfWqY*lJ zFQ_T{^$J%(pn{tI`ec>ORfE$mXI_1Oc{PWH2EZ!*cd33pUAu4O#$mAux;9Z~AMVH8 zOSmJt({L&GRVtZ4D5>xn^-zK1&?LjYL!;*~nnNNxTnLH4UaQ+EK>C&^+(kKkz&9Z? zN5r5zUS_C@T0}oWO(GgKOD-~3!_aNma$uvD>v_QLo@VH{iVpa=qhxfkTHL@3f3#d? z#Z|qDvdDQD6$J}K9#@V6IhVz18&&sLPPRI9xYLgOl%t)O%jvfDXkd#wq)B_^1CZ~^ zolZJ&YslyX2t?23Dn*riv8-Z~vBHBSrN~zU&9=!~?T3Q1tzA@4G>sdy2C#Uy?v$^2 zxT?mZQITT)=vjR;9%kw{$f*-FOr03A`H-8JPR{dy)bN~^$hntxVy6( zt&Bf&v{rB+{68Ft%%MZ$2_CQ{Mr*ws!4F3?&Xt_9ovwY#$Y~d7tF;3kp|9~ITP#>O z$-cWyRnAd|^*MVt&(wt*bDcubUN7W7gJBVe9vV@jrzom*+d+ZuFnV8YzJWh(-K)1`oEmI?yZlPO0;*i?;n_G zrxdWVeW-SiErb(j2rjWyk81U*(hcWJ(k=)T8$(5+H zST~C*kT*f%f6C8jxcP`G#*x5UTwmKAxPSv$Zu`GSWl+iA% z2!)^Uj&cjzQDcggQ;PHe=FM|Ihh-BB6fy*6jHWPh)bJ2Ds;`e!uAe$!PhabpurXK! z@Laf4Bo}nK9K3P|+|Y7PqX!gc4gi!&aHSP)_>#C^O4KttKYjl8Sx1$qPxMex`cwE4 zB8@3le~f4N6%V2`)H*EG_k69NY8YjxF9=mnU9fSDQx||YnU7S*7Z;22^;aw4wG&)> zJm=IX&j)@TH}t-neSyE#Cn=T}7n4`V*NY49(N!9}9$!z!K84Y7-|n;=XVY{s86&O0 zPSkG~^oyD@zf2STiShE5@u%bEaw7GIPVgTV#m`fXfj>Ek>-fm?V-V?xr;M4v2?6S# zAA@j5JV`Mp`YQqvXo^StS$e|!5{>z*6ixaGf4^LKsdwUicXGUlg10}rJpJk-<3CF& zUja7{gS*3%%1hX?9@P4e{1)NQPmeyOX<#Dwrynr&&vsJ(c}@MxBgWGsCQ@um7u9}? zZ^7yxmT!4K-yU)Yju&nLu)c<}nvaTMCFCKBUvkYAzfi0~TOYsiXk@f=ofcwVvn^ z`!YQVb9L9@j`QCm)RY8d0T5mbnPyAW1?EUE*5`ef$b&5Hlz7gA1+lisP1LDF%&Hk- z0=Qj0L6WOEp$H_<@9UDmNza6Wx0HS_D!Y$=&Aivv+CLKT@<|Np`deuw51HR+j+z^?GAR(nAbB?=4*~Ft`HHzJ#5aI zE7Fo?b85&ysd;}fn=eCsrFOEoMu>C-@-!o-VG&)iRyP%8a&SyEs3clKoNE zhxrjK61i9?V*ql`Y0{|qTpY3MG*a)(ZB8y!2j>R=0IU-v8+;)uPf1@{i~q3sh8jvK7@QPtV{UZ=&r@__sOWZ}Ff z%Mg9m)Mlco%@#!8gQ>H{oAJ#?n`s)reBCAc?xoI(e!UUTr>_Y$O_P91W9)qTy1wdF zGyi@XMBRkYE#8h7c0KOhP5+&z@PPc*C)Vj0epU0^j$?Rt-)HA4w+*m;PZoRJbFvO2 zSe<%AmHv=xe4$qGkyp*jzEyv?WeZ#@EpV&!_p;{fu4``V5TrZ~s6({Hkx%BWiHtxo8o{KHn*uS)XCr?f*P~`)a|+JSBsqV<~FM zn8*?2|C2GrY!IB$6N`7wt7mJ!LCnW#2L;7s1|lD;Kh@8D0=#FR7=vw#jAvS5+G@r< z%iN{?&U=`&dw#S;_aYB(KdX(R$l4V5EPuPA>y-yu%#0b6IejB0}Q_F69QocH#= zcL(mA%-H35>`;(2siUW9sQvR0&`P-J2YPkSNmYCv6PusU-Wlul=}t-XyqoPvxcw~U z>~vb7?b8IMd^GskeD)fJeMjuu^qZ4!4zw&6MVos(jGS%#M;DoGe5iJuTOs}vm1O}` zz%BzL1q&xE{#6Hd@^hi?r>pk~Lh|}| zZ~Y-Yo@r#1QGm!)U~U-2jAKj6o?*ksCofNr0ZiFHPQTJKv|rzz@W~NNQY(>zrdo=? zNG5a*#CV<+Z>Vfirt?LDo7;2THuRm;DH5eVgJWRQks5i2j^OF*$t=$%L}4h_2;q&{ zepp{OI^oA}xvfap$UNcZfBRNqLVo1gT;Y zBs%0YE$+54U4(1zz|k|ae#Lks2igqXPipQ>#`z*GC#k+1Po_6l}tW&>%$F)`%)xLsY!$ z?yQ#|J>YeU)CSDNycuI}Z;o0%yPwv9p;fs(NyIVg@>B0Z_! zbwQ{Q*?5;4Fi~xP$ZFEBpkS{$i4ma@&Sj;?S0mAnDj}i1xn`sAvo#;74_oL39~OZ& z5@4ZrbA$d6Ic<^3bwp`>g!QmY^AYXV!aHFe3Ehd>_D()B^5cGz535{jI3^Z=%@$WF zY@%hBn{y4bLvyO_^hERQU5bDdQ6C`&cAmYX&=eKW+?XXOlyJk-w$>~RIt zbfU2)nem>&Pn416b|{sPdtafkR%1qsM+;dH-_RK(bP7?;eFWEA@2_`WaSwf?BLcH4 zH1S2ZYje`aGo4!>s=e==&w2?#%6)YPPN&t3c>YrWf#iI#76{ zj-fK7qBB@BN2}@t5ALR)HSwJosUFT(u6~DOu193M_Y)3XCk_LCy<0lm!Sq;fVaM^+ zjM!koy@C}VG7_O81@WV~mbJsy)kJ$BV7TkJBbw5=8ScGk2RjJme;3P8EyERe*`OdF zf8uEnpHf@GI(Sc+{%8A0!Fz)r!o(T<^(ho8Ny4WdLFaD57pvvXYNut z;XV9$>R+IN!O2s6_=sKFK?iqZ7mFM=TG|C#N2L}K?HO=PS~zqtt2%L*UYN3A9qoTI zn_p+kM*Nr5@(!#~PvqZq;;dy+LHgYeVVB0OEumffylX{(mh`Z$%^P=Kzz(A!KG!f; z9rEmvnmZS=`kohZvAQ9J{P7pk<}&n7yDOI|5#jQQoVu-F?ikV3V<;XBef?SAmMir2 zX^k8hay(JXawx)e9ox0Lb~y9|d)Y$;Y%HX3owz;7akg?$TJ(18H-hSSNi82_hF!#0 zCVq{p-&=4ld&oY7+t54v?%dYDG$Vq(|E1YwjD!0C-iIc(w_T^71_&dgfc7OC?*lP8 z?eVtU#;xZceenn4m;)@{r2EJMu)W3(_?k-*)jNOXr1@b8tXv8~E(OUxE&tm29QBz{ z_wfo;8?Qih@lszwMzk?cGL@%ybUo|Wc38Y&mgjT%mc@_M-(wa3Td3UG5ZUDJwA5x; zN6B1ZO!7NzBYoIOK87MJq&AR`1<)F4T?T8>{EnFB8`Tg^)6-8?aT$brwJsN{D}{epVmlMT&5JIi4jK%W}3_B0@*SFc`v0oua_+ z?wr(P+-h&S>2>bqPCHq@y?dcu1L^8Lavz&$=!sz7rm>yc#~lay8~o$wUW!7eT(n2^7c> zgOFHpjBYS93WVO=+$f}*avUhOpeo`0$7nsTeoE*kML&b8gCl{sHdeS*-1#zHi&CO< z&k3mon%EL(WaEpfwr|x|y=;ZaUE)py1irf;6@m>F^x7N>%eB`00Bhwzy;h_<%3E+F zu4H=e5TADwPZZtP)Nk`9MOTwG1_bpt=?(Bu%M=U>P{)fqo<{u++gfXZt!!;z3E=pS z<^sLhrDiDT9L^S0jTOIGAnXj1o)B20EiGfaP(C&Q8X9+q$x_c@hsthoxPur6W8Z-@ z;>|O+i}Bio!^J0e5>fS>Y%bX(2;%3fiE35kKHPVRu<5tCIHLuGSf7CeK%CX|9WvPd z(d;_E-yxva+8f(?WeaT;Jss!sY<{cWXi@o&c2~XbyHA6XgeE_zum$azFz@b1)2S9W z8kY%D9Vm9xbWhGJSHL{ z8q&lDnn$g$ILda{VR2=V;9K>0J~dfWU%P07PW=l1#F&vv)TPwL@Ad}R-Z!I;TM89N z`9+u7uhY|5k*ZkQWT(;U2jEFu3GsS9b7u+7d28zqvTKssuAy!U>2j7LPoPqMpuifP ziJ#4mIT@jA92V+q-_3lM1D=Q%=#j(5$RUmV{OwmYzuSk7G@Lg3DLnKZfL|ng(GC`b z$jEol_Y0Z}0HO9MA!(5uy>iw<&K(F_2mSz40A2xfs0$8gKRQ&xu9$aUj@(|U;Q%k~ z3L+6}2WyOlV$?k*_o630mMG)~=%rc!-)k1c#>-R7ZNOn9xg>EiXM(MBppuCbwut1Qgokg6<^xTD%MO| z@6*1bd;moUbLiS#xF0<)wQ#UaxDbU`*Rv_p7YGoB=7rKBIIdr(ELIr9M~H2|mJ9t4 zz{EmoE10Fj3o*SwT5Nk{5V(Yl@3QOG&_)qkV&VvuvV&Tk;d9+mRrBy*imx-DLnt1v zrU21HLnXN1u6RRQWb>0AK<_}?|LAw8$&aPNh=nXKZm%`vfdE3Y71WJ+N>|k{PV-w+ zL#jnCuy@!){JB-_f~G7)fFpLbF-qMNBbP(S>09k^px_KYd+4og`xTC?DZ}*{4ZUO= z$@d3DVo}<6B1cFU&JiTilIiIE_%UV>6I6@ZK`CISJqx?RB|{3;{+t6#hMVLXE7+~u zajU#6gPZZ&*^;qqNi6{dJkCPz??EjkhMpyEQ;89R`3Qd=)L6ReIo6%V(uXJB-3=rM z;mmOjm5Btx9n3}&eL%onHqr+t-hOsb2OVJ;fr4af;;#dmM$;bt+hH1gJVNec4uPI_ z^R6`|57x^{>?UM~em)o(wKBFf(tQ;%LWDaMaV-(uidfcRMdiQUU&`Od!XpU(eNDXf z2|Qvb<)Q+dVMg9JmYgG7WtfrI6Cye3HS+GxM4Q%njFY+LBMC=lUY|}~OSZiZB%14* zScIl3b<@kWXv+`SO>ePNvK{O|wrLp~THcFui#<3u**0E|SauiAMK8k^9GsfR4dYz- zy-+*WDG0?*uO({v(EY$j8tw}DZpxPWgt=YJqIoZsrgwa&_cHqUqil#-?j^7RiMF@ z@LB^;Oeg||O{NhVouECSFSby70N}WiL6J!Yy@I&j;mzM9NQt2+6xXIvJwGyU9*Wc{ z&4}92Q2!fI4)4*qkN)CM-Q%e4YTIT$wPMwN9Rs5F&3RL59fH6cx4WxALaKi41ddWu zDmH1hj`k`AI+E{fuYzG(?NuNZsa=T0oH5ZAK$SsI6`#Od{?ix7pE(Ai$Sw_}S{B%+ zG}P?K$0Z2mr*VCaDwRn_$1lF1Yvb=fLL%Q^WyoO3(lIlNmZ~iv5_irl0u~Hiz?Ll1 zwT=3>loE^3XexPz4Q}MWc%6p50(Q;wR-mw|b?l<0p#Xf{Y&=ahInZV0^!bQtOH_k3 zYOmr*EYOXa=g{HQ|K;&`aWlzo>5;vZA>(MFfvLjuKq(s9Lg+&Fbw&G-_t<S}G; zx#qHMI|mAVrMQwsM|Eo+)vw^m^^!9U&Z0_l%^0)E>UwIkSz=#V!4h-2l=iZ>i)gZr zS;Z&MU#9M}l~80wn^l7w@I<-+k53JFyrXgxKC`FM$OVFBb-nyF?3_3_$w z9Gaygq{?x#tTl7j6>JL9@%)0YBX>}%<*LK1XzA z!Wyf$)w3)_m>=ECT#HbF0<+g$DzSB#wve!Qoa^UmrnrlQG-IOckf9prDOLdYYik7o z-FmoyxW8Q@Q8fQ@Tw*tLQ$l+?9Ci~|iR}BY4hQLu>r*f+$4WN49VnIM+6vt#&hU=1 z^tyOwwX?^6?zeOH-?9P`7C#O?hQ4%1V>^t3rsJ5E8 z6pWf{R<@PyqmI8#7N6^ToOPcdS6HLQ@#3sfIHB2Q%1s{=SGc%^M|zEm#t7w`X4eSF z6722hOJ$8iYU~0I-}i-0baDN*kB{`@3Qo70$ei)m-c2nJ7Sz(5#6g$jq~bzNhjvqO zWCM1z7U_w+e`7-Lj(J%OqR;^(<##laiZYEnG26y95Jk7T!ZUEs$D1+*32DmuZgQ8r zwTo%>yc;F8uEWrX)~R^VQEpqSzA9Oz*T*WNVMWcT&!s+0h|QU1n+vX!A*%Wc&YgLj z(lIxSq0xGH1-A*6l5Q%*DOEtgQ}g@2l<(#hP2|UFm9_(b>)&r#NEHWZwkXEqbe@&t z_qGIbgns=a>QUpVfO4!C{V z0>>rGxMbGmGsi8)fy3$z9QPOp4m@4pu!IALB^(4QHt()bsutYWJqFSuL&svowg3+U zUJtc%8ijoP4 z=stR?1EHx(b9iuCxk%IW{0l@#FD@S=NsipdbA0OMqo?-PI8us1ptXCK7;GBXF&Sa7 zq2AadJKT`Kk*o|H$;tp4ONnCV)@k#X`*ngud1}TppkxV)&(2R?rjMS2IO&r|r%%5) zcU+Qe6rjs=X;52il`$H=u#GyM>|p-Ir!T&E`WQX!&o1eu8+BrTg{X)^rHS@${0vuw zE|FTGd_y*|sp-(7LA=iFeABJOKYvX7xK7A0enxqjv+R}{cBAPZ{%vR8#}W{+9bymG zI^9K5a_3Z|4wk(5;_~c^%bG^%7Z)dw2b_S-0RHv>xTX6J>>fKbBW#9xqwH;3zgL({ z4Kln&Y>X?C9Lv=lRjz;}+k56PJOb2KThw$o)1f1Y5$YrcqT9Vewz|KoPd=|w&$Jhn&OvYl;R+fxrcZ9(+Qylt>R@OqWaOMx4HLOCV$kVTNt5%3Rna358_M$g&{ zYNT+$)O3&FF+jiF>YAG*V|7K!Z=q6cQ+3)9e)FO05ctT;@XrZt{#BOqQ49LYN=g&#eU7Q?4>>g%NCcZFpJU@B# z_$wEY9nF+NhdvE!eY&4(Vc+4vqQ@skUwi`ffB9*8^6K>B@`A{yYHbm*g(lHCWzx?; z=A^LASR#uo%nRw48HvquF*7B$4L<1Ngza<8m;(B&sEl-h8pFjhczpTd{K96&Iw0J$ zeq#3R;Vm)IIlAM(IXvDlbQ}rbeypPt*@kWyIRt_ud>Tf!lNCBbsv$JD^8-SP8Nr~frV3ECuo~?N!+|@*S!4yRVK5Ad4!y7^pT?=25#V(0tPsX!q>ej1ePqJz&Nf zin;H)DFL!S^#F}Oz$mz*_yD7j?%uH?i{g$*VT^#2-UW_I2Zs*bT-8P=aX!8|o6Bna ze$5sR0Y$lx&4yVLA$FuHVn_*Vx(*vKcG!Ti!v>5U(T3QO=7^Je`9gWpE((w}-q0JM zdyqD}EajUnODqC5R?E*?b{gs)WcZ+(tQNM1o-o^5N`L`r6EtDAl?ETk{+z=iOB@zi z;(#3{j%axTHEzwtf$2yPp|(C}vYT~kuG6rtw}pUZ9U6l8vWe-oUluwh3eQF#5GtB? z@dpLP=q56Kal%d^jw?V_&tB$lGYWw{Kg^44ru=a4a#;@_YGL{~e6Y0yYJWc1@TMah z>@0eP#rFoz{%Y~LVLPWEB9Qeatpui8TLy-U&{spTt9@cN5lwYy*3Bq;j*T_?*BIT! z>c-6-cpA+~@bpP25TG=ZKjiR+(D2e4gVXFgDT-Sww<+4*9p(vJ<%Uzz8~=-{C( zozeEu7JtlhC^F`m2*<1Sy+Q5dJjoc-eY%P~D$JCeuddQeV@8F?> zFwCKO(B{#O1>vFV?T!#MKIxz<08!TQ!Y6IL$Cx8rjiuWT9v<3(3_Ntr(-9ZNCtdRl zbo$`cVt$yzwUG$+hPoJ#If8=NPuGr^e4)m-~+PTL0G$K)DxGx~L}S@iGW?jT8uVYLB^X6UZ^M{SF?@OwBI2ci^o}y?uD<0MpqfSpQ@iF)fzM z*Qh~NkuB6vDx|@=>^f1d;GT&i)t0CV@wv`xJH^mx<7`E*;S|}Cb7d**9ZNJ6BNNvV zL4>Z?3Xk4%#|GA@%&r?)JM1_sbcNn;?by}rCU&J!d-#mq(pv6rX^jSUD*0C+HbR#T z_Ym_(y~vd=;w&*=s>*gS3knlE<*U8tfDZg;_w%X z*DHlkP%U~L=TF?>x~om#nMCyQf?b_nzJC45>E-hbn3d)<2wIq&yf36WX6RkPzOfBP zO8wqpT6cWs(P#D>HFR93Hu@)TWP2p*HKfHvX4BP;lD4}SA09t?{^MLDL zP+OPIXS1a>T>Rkm_}~MmeP_tHqdrF?H#qfV0(*kjkCoYcBDht9ETd+ z_7@#EXNQ07+mmqMMjWsa2Wlj?r|Q6F0-D*Lsw30jfF?SSiHW^zN0A?TO0?hT08ubU zkppuSIWPwr60s-i6?BnF`?ZKXIiA_Pg1D38bM{stv}1n`eH5(sI=~>z0R};2#PMCn zoSk7N$DAE$3+6~$I73VbCJ}n9NK1K*F2@r&N&+GC67{W2da+;B;#7z2-*yIS5qhkf zsi=6Ix)P-ZU#cf-D5g)<#af5eC5y$2Z{JV8nOt5!&Qs=Z&xpVE@O?m*&ye>3#tpYU z&<{$)AWuil3xIWDo_EDcbdf#1%%C&>hjMaD_zgDIojc-+T0K_${M?Ik2xA@(m;Dm(bxR3kT)qo z7i+d@5`Y@Nn5j~aZ&OaYo1P8c9P$?GL9JUmeaN?n^;_3lxChZ%X6oT)6hGtTdZXx7VVB>1tlch3e<0TKN@l z=~Pp&NWGU?QK2dakLM8~^<+K^|7X3)#*7T!)8ZHqdOBbrK zba?NcN40mF+bX~Ao?>l_fSIDUh5)kEJLTdAJ+4ko5ms@cOp~2-CQ1NnH_)nJ-ly{Y z^Kp*Cmj&~wH-)~DX@!GzU#ZI2l|-$y9#jo7U^dLlv&FbbjUv6ver{}=M4tzkS!V8c zmj=w7DP_W>4Kmz)C~j;)Jrp(oT!rNc>tvG`!?ct%PZRZ|U`4xgaB{>fDH z`_NscPSVY7R^>Z-n`u%?Tqx^8&j{9Rs1(a0R?`InHKrSTGyI@fkeWenmf%>xnvucB z=wL&2Pr%%*M_23Xd_|yYN%i>XsL;>v`k=%Y=rrZ3`Kv{f5ufX|c9} zKC8wL4Au^3(t=^smEiWb0Ssv%0GLqbI}Y<2xCeRToDP+gxrmDC5aw`e5{PD8<>_5d>Gv!+M!3;$cs~g_p61cOYOKK@0~Z=KfJRn+~qt19oW8 z0fKQLD1jAehl3*RGQC>dPxe{EIkwgm1}zSWBx@$573aP>=s`6Z*784#!PfAmshiLQ844MAbyyyUZ*;+N9mAf3yrn6 zzHfAXg!^e`b7%^fJ(L5ZF3a#UVY)G{p_1sS0}#I9K`3mu%0^GrKy}F?>kUO)=X6)w zHwt=ym27MOdTFSX=_^!0|Ackf0s18zy;sA~m)pFg@A=x~eyqht#(!hn{E(K}GGhVO zd2=P{ieXgkPD|8yfBNG5GJWyn$;HVfI(a<5Q0t~eJC{9h+(-|o2Ya>nvXhE1doKwj^Ji(;)KF_bf1}w)$##u0@vmd$;cQ_3jS6t63B>a8v13?yo)RTpd;xO=r{Z zlSNh4*7f0w)W0?MungZb8=pu7`;quvW{pHikXAm!Q zK#b7-aE^bN%%<{EHIhi_-`xMQRq37{`PqB$?3`a z^H=fB$weBWNM0o%n5XLMReHYfV~oB~PEuvj_I;4b@9Bfcb577Df5=DCY-iU;>-nbT ze0HNDSbZZ$YEc@mrJ)afpN^YrOX(n(UP*3}ao-Rxt)Q01ucwf22FuX%79Q5$Qj4t{ z`@pgW->dIwIY=j}4FadarR~m4EI@0fm*@>~dYL{tKY#R>gDvb*m9;9DCk68Nf>E%PE)<@)fjz){|&1m!~ zew1_ir;CT5Tt0lb;@-n-q5f)q)_e?~(4`$Ly2{X~rwGwXu8MJibWxm)CX=_;jtt}(>#HL0qjY7Nf{ezyGrx%Z*FITF$7p}QAPf@`73iZa zJPv?>K$|7Zi&jk_oXAs*Pw>MDy0j97^fVwVml@ikk49&=o2L}~T8u{MVnEN)oj_5O z-Wy%v4TTJWLXcHeWEtzBRQkpA9YUt*xm>JtmwpA@wlrM>BpGV{z(i{n(d7P2-fC*= zUsaR6ZSw2x;x*0BZZ)y!rV~t>dtMx7=u{YIK^0(o%`U#cepQp%yY)~(qBiT{)3b*U z&+)$o2kqE5=dM(FRDxP1vc>dYRKNF>dSsfHp53O8cT2Ff&{zvb!*(&5gw!1ixMYMz z7=Ltm`RMpl-S>=RIjbngI`D^z|7Fu9ektim`H;uWf1b=1=-SlySIA;#zcdh3dXg1! z7FAv*syIl%Zs~HeKtg4i5_`f4Zvf-v!uAo8Pxl7_>F zMQ|vI3LNhU(KX1b9mB5Azlaq5?DH?@b2{Q+MWPQ@9Y=yyfei963d6t`eaHLj=SirJ zi{9d!+d@tzqY+8EbTm4eK|H=YzLLco$YkpvwLX1zdkhfNV*5)pCG^q*I1U9)Xaz?d zov&AD@OPC&r7uKKdb}vSAPY|(WH3TUCAdKptSHNhNfG%Bzs9-8!`x3~#Ih0Zmg^)h zX(3vWsMbB<*)8#q5h5s&E}{r}!Y`5}^dLlbeSiL9{#bus zU>lfMAe^Z6I?y@WIzwwOtuw&b6n)=FYqf`)FONpY7zjHGB?1C&DHOd?>I>^l_bIYZ z{LTXqPB6bL^CFA11_7R^vBMi}afC*T zOX*io3B2$aAa!Wf5wf`Qlaa4kgoPfCSrW!j>_Oo9h#R2DXCrjA-UQBu8V9B@+^4I_ z1XJKLiQX;tX0YuyiumCw$SrL=jJ|>-J8T?|F(A_Q3HGGSqk^Lv z-pfVBvRX!Tt%oEg^OQziyd2ASWUJlW>evOWHqaJ-rdXL52e2?GJk2TqNts&NN00y> zr33Zp$1G?9czslfB=KX<(3coH)FK5?xjP)5S`3}tYSDA|a|2hi;AI$OkoA5pjOArf z6&_H7s+7?(WX*Gt=OIwlV9G>FO;&ADa?FmTqVffKWMm}yWn<-}DN|QzQkE2OgO(Cz z6McSd7K)<8Im%0(7_7$S&lv z&MflIee$^kMWgsR?BL#u6Dc z{7UZ?rtz=h1e9B8qN_5b6#n+`+bq0jz}h>3SoK= zYE)B6EoV>i3lt2nB!j@MIBXp)tA~<53W^974YH74#FH?p6>Eo0Z^%yuWC!_)2aOUa zg9x6fFG`LrsB#!CWNPRQ>=~i4ff*WDGU-Pd((YAK%FPJMltokQwl~CdP@o#m7s{lD z{Z|!*6fmC%0BZ$^ zhp-4BQZ_roT7*TIa&04^6YxS&HVOr7RRKd)%0kp%r|BRiw6A>t+n_>ONt9&1=O+~r zwC20k+z|0w&kc-wttZFhLS$eVPbQT_g^K?EfhHGn#2CP(p3Ec+tGIh|Npo^jfDSZM z7D94S`JCgt#(8YalKYEs_&*pLEK)GE8Lt?rag^lb4Oj30dy>f{lzy1W!ixnQ$6?FX zDn=XX5CDFKX$b@@;nrb*&H%m$Ac0i4dpgt6`E+qLzE07_B0gMgKpm%|)C zEHCF-1%J4rC|wdK6sPHsFP&Z|4+;nXgl`ItNPJ-wi-TEOBhVc=_>Yu^&x$-uIGpuq{9y-HVyA7lhO+%Tx8#m3qK-pMSh9Cz@ml=?{L6CGS3%b0mnJ>i#$i9%#h4v^xL$e zJl0mTbCwYGV3DIjlxUWc(o`H)$6HtuT9MB>go^~n9N87ba8GGEG-YBdx1aGG0Q1c! zU{k}K|@j~#}DyJq^OWrSpXpdko*lCT;-V1?R{!Si0@%am!A>k>i-cJvpk9l z5oO>mxJkA3=_59Uz#Iz-f>Plm`|egjs_V!EyZq|xBzV94}zak0uNY)Feb0ltFvLaKnJ}WB&cJXYqr`ZBJD24?&@4$*Dz~J9?vEd)rWV(hW3a=ZSMx? zQXNh<_>P*hPI!NuTNRW)qd$V?gVC>=o}YS-K3dIp0Qrgv7ti!FH(z$i7rcOO{| zn7FXFkT(fMQU)=C^b)~rM3qa%Ml3X;RgZ&T6A$-(dQt2PMDcvZv_u2dLNQ&>%4VJ9 zDVT|vqn0)#N&@mja0e!Zm&TAk*g^y;eVO^87X&%ntA<|N^$IQ;G*H9A2LZkW5TvUd zhBEWBqU6W~paNH&744{P8_Zj$tsJ8!28G_Fju2r(3JBK(cu-4;N}Y9_*X>Xgi8`av z5(ZxpAqp-sFP2j4L`+68rp^@*V?&&nxSNq_CO&Zr+4V$;mPUlW`L+HaNlZkpW)mWZ ztP)VJ=YJ}J)`8f+ zz+nTlPYKo7-FY!k6G2^AsS)rR)!_4vdHuE zu=0Y~M4~=kx<@gQSq(S<>L0W55n;)=agdcTpo6%n|6sxy+Sk0^!?X@LyT(1ZGc7cv z4i5qcWqz)ALKUBY_Y=g-3+zOhOVVCFyoE&i+INPxCCe3V%GJiHkDzi@l$DrSE9dZ)bhz5C~39x(DhQ3iL;Gzp)Vgh&oQO`-)9%Vi*u8Qj$GfGi1 z1j4{KLKWDnTt(T2v)v5D>%lFSV_U#Ae8W0FEF-q{b7d*wvEE zB*0u@29|Xc3;*yWn=Bept&evyx%?K)?Lom6ewFhGUK3NyjY(b3SB*Ix4qm`~!4kOG zB8*vrcGAe8qK^s=!beL#^C^YrJqa6HNMFJb4ZS*?<#IL=Hfiu2xPF;|6KZzhh=$?l z_&$(Q+&3zXG^}#>7&{_#D_L)Hj&KO{IwF|#`YNmv1b}%`<~*0$5Qn7ff}F(H*&F0R z6e1!9Dx|8sDg!Qp(o`lo-RB=Tf*73Dj?N~Dfz!E3U?8C^ssb1@6hfijczM6q>`s}q zVkI%cJRVy7pg#vNRZX+Yv54KHn@BHXl5+fsL~lMcHaD?_weJ`NAI^7NBh2=23BxdA zei)ZPDTP>uH()O|RvB`h2<11UxfC}YM<`WMAZ_{tsPTZ5%z(;-jcqK@d!&qZ#pQs( z3Sz@ zk8|esR`du>vpz*_<=Qm_OZs6_uqMi6NNU`T!nsZ*~L?!IAJ;B#c@72MA!}?Cl*i)Z7H!qd4ji zLBq|6q|sbKLj>~*I01lzh&bVi5%ILE>+qZ_K)bxT?=|rma25dfhb3w* z7($%GhEcKp1){jMr3I8K5O4?{ggg>r3skl}8_|?Wi`#1ic;TX^t;Hp|2X8IPiv;UK zY_K^igfXrM0D%O+f^hvHDnlS$VAwQFtIt<*B{7Z)jkF?W4F!@!IiT-3;9LPhZ^n%= zG19&v8fcanNl{`L4=zRsQ*<+n;9Hsmi`77NluV)faTTooH&|!bTyzG_Ly7;2T7_v& zL1L|V)3J!g401B=e4vTL5Q)R0!6#H`QQ$sxHPF@!#Lesmwqc%7H4b({qC6sG%^0!o z44T+F!Ac&e<)TLC5E7s{mhd?9LfF}j6u;VQ6nSLdjVHI~k}9ucS!1QPwxy|r$xP7bzoA$_k>O_2 zikC2W5#TlunU5HlP~jNhu`=KW<6HnIENi9zk)tD`0v0dvbH8G740s+kmJ-}9U_yw- zc#v^S$oB|sFHQbrBTD@HCeh%5DU|v_4#L)8?vv0e-dnqY>q+z;g&+$MdGtKMJSyDP z-Y}(2x!U!tTuo$rcKb~I5JD2n6vBvLiWNXSr6f>nuAP>T$8`~+sAxMdUq>$?#=|Tr z$^;NWfFB_aYs?ICw5KKp`f)>c0;LI%w#Z`u2^0g*3G)0!% zlEj>VR2*&y3oBt3s?`3EMc^c;aYRc|qy(^@fFWh+Lxlo@USdUR<3cSuTau`e$)(L& zSK&1P32P*Q3Srra^%f>0=jh^vvJ?b-akv5wAxK9~FGA{RJjDT5*q~TEasjg=0^`3r|hoeN@v4k1oApnU0 zV#7dZzOH85ZRAHuj*G>304pD1)WHbZ4|BQ z)-%_%m853=@g~vKf`F=&Rf$qU zz(W#XRt6C4As!eYVWl}u-_QI}?cgc@8MlZ4P}Yp2|9B4NmL7-G2D3`QiOkTr zAk^NhX^+r8t%q0SSyDogA|6p9LlNXUEP1H6@6hCk@Q0x<3m-Aj0!90p7nLUe@$4l8 z6B?+XDiK*3iIj0}U^*&Sbq`%$MJQi@&XK4dK{jNtE@$2j{N#^}u3Kj$N|4Mz?O~B2 z|0!5Abot{8o(mnQYN=!bd{CL_I`ZDDmPw(Y*f>JDF>u|7g&?nIu(y3;tw}i-RyJX4 zt5J@HdJG@gJ0C$l(`iD-hktxqy|prdk}ZU-eUzx`=<~I+ z*8>~haDmgV+*(-xpm#|beb+%j1}YxnUes1uGdgeAw`qVZnx6)&4w72 zU*?r4DlcSt5yg#spZlAek|bFLXrTq%CyL6v(qxf80Q3O?ABL_StSka#jScL-&J`Pv zW(N{hl{isJhw7uU4!fGRYI+QX(nUO-IiUd0D2iWcA%M=0lZ}rop^Gzwg#3c%vfMpa6@T|<(dTXR4Ls@!TDs;4GkiScalPNl8=yHv!SQanhgL)KnFw4gq~ta0^Vc zn_#2j)r03KOO&ezWrT1)`Cdrz=oXDT`rFdAoYZ$VX|-!KDI&Wbxb7p*xTy%;FFO3#^sl2Opo?- z39_JiQ+MN&sP+M|-UtbJWUWnq7-bf@UP)0C^w-yg?j8X0EDX?{DFpZrXoUVYXLLk5 zrLFEzrMf~GNgJXO0uVJY)(SYWwa7jYp;2dm!UvAqJ1bODm|E_wRinUsool95>!}fn zGeNH+l=u_sK_K5!3olpK&Ke(Dld=h?Xq99j^#K5phnAo)deGuh?VnK>T2^bjpqW-S z@~ztp8y0g1Dh|Z~3@}A1(=*u5T3?&<`>|_{B$~|t4+6w3XK2jQ6;5)i({)GGo-U_r zwc1w=5(BWyQ6fZ`j$9fxImo8$j9?(Jh*SjXZc#j5HjpUHZ#7BkVuIQdT33P^{vj3D z6wqDY@3Z9_LphCjoD#spfqL~S4?+?>5lx_+UUrYzMGO!CnK#f|DC(@>;S7Xvi2<<- z*WpxF#^%Ta^N2EGSR^H|NvNpN!nLXMnW`DaWHc>3m8|KMhTdif z3?MT!YeR)Hpw*~Wt{TixPrVly!(kgn5$?T-V)SrooTTAZL;}EW4-L%=A!sulKF2m} zZEk=u2HT5vRt1XfahQ^d=(o{L`mXLDhjrR#`b7q&gxjVzYU4)AHwyg+GzB`Z!mh== zt*G;9Y+(JpPHzvna~K&3AW4!MEj4NmI=;Gb_keiJ@+1k+6+)sfO9M!G2TKKDD!avB zI;&J&J$MuGU1Y)ly~5lGJF?4?r!(W6xq;CsdZ8*S$xy^pAjyyXn1Qm9?6||syP6YL zP}yFV!$*_oe$^DM&UwkHf_!Ndrxz4n0*o*9PAsBEprr>NXa)eSI1)vuUZTDyWfo92 zwYCq|Z|-y*(DDcgC;Sin;oyMkv~Jz8wFxiV6kp>uknt3KS?MoAraeOG<5Am{Zhp0= zmX+M;W&yS+(Y6Z#WfWl`z}~19=~zj_fJVQ`81Pldqy#x56ZzOGj4&8Gb)I%AW z0BfYbXla3Z09t3T8zLXJ150qjRlUmxVj%!CVUvJ0{S4k)(STZZEWcr=qmDC1Jtsgz z5rhBRkcItCDcM6O?Q3<*d{s%HD1Pt?L<6i|#I*nqK=HOo z$+JLVi0OUQ6lr0uKXA7J(C|zO2x@$0TW0G~O!%|?;o9tnFig-BU$^GPyr|a^x};P^ zkRhqaG~Ll;`um=j%tF{VXh-HzCqL8A;0G`-4;{Ns(L`vNMK?kx;A;I7dhF|agTS3xg?=d!E;~V4 zaVSi6-N%cJ*1%)TBu13HG=!ss*@6<`M}`J(BeDv5S)t* zjCRXh+B8xB0I?xL^&py93N(e3q3Y_0mRQZEhx@#KM-&9zqS5CvN24$lU6&p$x z0eztX5-*axLZ=vX2+=g$Z8`V=>EoLvH3Z|L8NArMbUS=egS$=mBB98-h%=T^Cp-i7 zQvn?J09L&n5V;AOYyfD2M%P=$hm~-lJNrUsgl|xfo3Y?3=4r#cPM6wk3)C39261w8pY_u%LuJjeSIu2UL0ieW@8?`>WkN zh&@0PbXe6A^^a(Oy*Y{p2rj^#2{D8c|{+Mrq$t87-)np%Uy;aB4B9^g2u1i6pW zJ&vjtPkV@4VxBgIF6w|+KEJgU zO_Mvfa)FSDjZ7akq4QAMh?^S{SbGiW(J@o&EG1}v<)f(@%Ib4uyEG#kR3EXxXhiKY z8hAz>;Xqd<7}U7r5O-Ldd`o9UBWUTq5>&YrxV8oLWi=L?1atd}EB0uK3e2ldR%odg zqDl!rLp=jB%7Yw`S0s^2ByNl>-gzYuGJO5nGBXA3DKMr}@%q+{wuum-l_|O|qk}lW zZ1C|n9IZ_+=H;{5L^nYVwZXr}h-tmqxqHn-0S!WgYiuWKb4#1V48+Lt@0YKh= z0K_wUHoLQ$5sB8-WXS|BgT$q@&1%MN=GfH(EXdKr7}yu8;}8J{>DD%Qs$}g3szQ8` z;>Hs6?87_MHGd-9RA1G-h;;{IgX9&84ydj=Y>GT!*+~ylY7_zVX*fIrtRqcxh9PE zoo+N!wLP0l~Ww^X5Lrw2wJeA>e zhHE0|+9SYUxd=08i5P9HVq<*o`c{ZKbQYI!gsUJJfLRUYqJ>4{T_`>^w`Qb8Wvq3x;OYZa6`>1H%z(RA8gt0xi?E_81R00tP?F&=kZ3)}u=~9c0=TpQ zq8j4HF>nBA8U;OH2XNg~i%=VEzJ|6x3EDRz<%&id=$F<8m| z>b3uMjF}b)=DX-x2?Qdpf)j8yqZ-uWo~mj9XucQYqAo;k(7hw{k)SqlX7~3P0~m(l z%;vj3Qdz*EB1sn`IhNE7R(9Gy(cZ!>+FQ6qdkeRCZ{Zg2E!^V0g>U7$yHt!RODEUHd4gAk2KtD!v|5S${9VFav-)9U@yNo5nRUunZP)k~F zBr`A(=tT{>(2a06O9$d9QG9N({tc0$low`|!{~7#HyM zNw>Dd$f&_9?);3(5;xm53zY4hY6w(xLBR!WNV}sY3GUkL6;e%sD%F)OCGJ5gk-V!b ze7c0&wm{9$`UGVo2y3I&IASg(573=0YI!&W^s|Bh6ER#4-w{A|D;UfW3}-DUaCVc$&>`YxkwBaGxKr zrnuk_@Vefaw!Vr>b#s(4!W62ITFM%T6d( zT-&qlBmy*z;vU>=1TbD4m}X5KW_E*raj7S+48~yvei})6Q=IKq!%hB0rdr~55svO0 zz)IGQeB9q_F(F#0;=)V1d>6ZiMi70Q*7_>J7m%k$li?h=_x|uon|}p*%onkM^Mage zMoHD7{M)05dbYOZ#0N-xfM95Tf{a?hdR1>@e=1aHpfn={5Hv&dp!aLd{h==YIYPxS z5zr%oF4`Ts+8(7je6@gOF>(`OnxJ!U*~?apQ>=p;bQ%FyfIcBm)eJ`#mq^_~()6h7 z;dA#zgvPH)2E2>_;--NkaGb*S+)*NqQ-qrgDu%ME>JD`8F%*W+J&XXGM!^^%#$%NC z^q#Hu+!KHe(ZClqYUtO1NZ??esoPiFKMs#dsBZl~kaOAIK^ox3_n$?NA{e@m9*<<` z5Ir($=ny@EVCWD%=W*x|J;!3;5WL5J9y-MS+{yRnPQE{P^8LA!@6Vllf9~Y_b0^=Q zJNf?HDSEiGTkdb-C`B0MG2IpDq3uu-_nP#BOklKVD{yHCAb}n#Z<{4ew)z`1ARvuM ziNiWYtd=0@eL88-fT)TQ9^i4foDFf&8f@maJvW3xKosDUqQdPpfF|X=CduYoz|Um3 z4--uvkZ=$4UT16bErecyZKZZGfM4MzxxJT+s5`)1Xi9;*HDT2Cnt_98h+eAb*biVM zz;fthyZ?ajeu0px5aTBIvY&0xFPTg|)hoZ9x)gAL&>IQ0pfJ7AuVAndB6?(W_d#mJ z@dO-Ov}~X99oMV%G2U zZASuphC7x+98`v)RUkL}Ufb{~(Cf#K(FFwct{EEF^%}TMp8}vVG;W7gE@0>((cSmD zw)cfnE_6=_kR9+4DJ}bRwN#&Dd;ug(K$Q~WO#)gpoB#8@Pyu(DIBOC#!>tZdpHXAe` zM|^}@y_6`O#9hq2!f4Qdki=z%%a>51<72A5f^pD*619l9V3o4~_t1#CR(+2pX9xzN z;u!ZA;9`@!Ke#ezhSZ`OHAw+V{1A$(%L4b9A%H5V>PM6vCD(x{dxKtsW|#y12l~ah zNHz4(xnZzi^!L@1xOEjFH0T?2#--4A-w9~xN!UWmDPV`bAt6&qKNlutbBZzSlLgdbqv|vqO{| zWo;da!a)HXRy7dq>QW6*@fFncY=aNO*+= zV!;YoHVeeYzyh(bkYyH_orQ#$Ejx=1UZGhbuNZ#kdqhTNMC7Zgy4&6A&dRKeFTVI5 z=R1%8`JZ7=NboWw{n{B@?R!7#r9yd2^$IE)isODuh00%}hiu>X{s3?xP#a>FS-vT{2dPj1JkQkhB;W zP*^W}q_`N!L8#?b$lkw)f)6?9gvdt-N|7Ow7*xlX?rqY$AK=~;h$R@z5k*uLPDefA zeO>Kc=aN8H3PN609(#cMr`XLfueo4Lg$q$XdtYZZR=F(Y19rfNN`(4>a4|xPK$&AT z_)8rSrl$w&00rOrSfx_3A_r`v#l=$bL~gz)Aol=s5VF&;{$NGrbQ%oI9O$eCJqK#- zKj0Wp2slE?MqKx(Dq(Z4>OD|9-~oF8RaY;kJZcdWf44d1eVv7<$3UmKK42F>1yX^b zFLlPq$usVPB{8tK2-=WjjM)H!nOnm(6gpO&md6IRt=JJnH&QFFOXM|@jBQ`ZWKkDd zF4wLG)^V-X+oHYJ^x|P3_l^gfDy*q^r?kefGTaWF z`+6UvS8uCx^bmnLc1k2Qb5M`96uh@%V8aN8y}l3f4alL_AClalPi{4WL2DwgQq>O* zYBiP`>#u%n-ODJ}jzMX!Yb43ZgaeH7nJ`RKNTuaGk?ivQ#mI)CgeMJxE-J_e6zH)P zFI4s|*65yFd8xzqF_w)6y9N^o7L}&KqELGoB5mykzsJLQ!(ci?SPOkIB4C|>e5$@K z_Z`e7ZQ?!#v(aGJVD>oHhGGh0(2;YlP3HSlG&YQ8gv|}ta&H)uq7zw2vEJqTa`dy0 zYO2wF3}>^&uJLq1Bf>Zi=`h4SxnOv(RhGu{j%w3}@r3Ri>@K)a0$EgvHm;1jjpuTY z?_)fhEq0CPASZ>t54w*vO7&}V2Hm3)xM4g=;vT@q1|G`qf%>d*6FPfWT3A+F?_)fh zEq0A3fcw7VL#G|WF9(y8UZ3}=(ry?~wtA0Z)&X_GfW|EiXt-~Yw-qh?K1Q^q$*v(K zh=_j%~?Md8#qZ!0;-_QFQysoveSgxSH zLJUZPs3DapAkYb@c`jU8L23!&{n!-HutJeba*gfA|VYsz6uMT*hv zcEKs2i0VRJ0H7bYs$n%kyyLDhY@RD*r-i!ty%+_C6%$ zkh%`YOcVDfoy#EoSad^sxI;@}KvMMlsu<6l_^Ao^KPk$5I#Ly+-ToZRr__)x1~zv& zsjlc>I9>qV2CN@=!~wr*=@KZa^s2r0{|_^oFNP;3}oRgscz{!1ANq z0gllO)@|2S&s!7%q2#gdI;}w&!zqs$xx2l0!!KMW^Qx^BgKe&(I)u=4#4h0Uro{y$2GcO}4WG`7NJm9d95@*sINY<)B zVr(~(UcYg-+C18&CO0IFiU5d5D3W}bz9Mf`L)uyaJt!|nV6sQ!L2=`R>J3$2c%#@u z_S_8dY%)o%((!Gr=1eu|(!~%qT(oLj5Ryo1ma;7%V0<36EzT@A_P3f?AqROS<$Toc zZupuv75s^%PJ?=8nWrFwxB#Dogs%&yzA98Z{$P~P!qeL)yqJ=nfL!_rR>+$?XGp4$ znpz46?Ld(!jmlF33f-Mz2ZXe%oa)D}6Zd?-&DHmDK!AB_tgg&C@Iqg>UD^z$o1Ec?ZSgQw%?^O_`jap;P%To+FUF8~2^2yH2c3)v#Gzul7= z_u32r3^KM9<%HNDOY|z8^@;IBM@v3@{^~GqoU`jSpmyoXC`YAIN}7 zS|4b;IktW1SpOP^q}5Q_iKwBnV~rY$yQ=69yqGx}x=?-B4wNH~l9%J+@$^ll$}i~a zJ2@h${Bz;Dq)fnR9!HXdXJ~sP9phROR)(fquAj<_uO^xuP^s*<*Tu0&e73F>p{@Z`JZJ%9{$a<%5b5+3K_I@IS<#nLa~zjk z-pAS8Baa$+gzrZ7tNL2Vr(XZIacs19=*EfVk*4r+u6lr zEY|T=DhIIOY62%k4wBo9u7^j#tT zh6EpnnAPe@iyqG2FoZ`HWNKXKDBXTdkx+oHN#GJ3Ng7#{zfvr&@yhhPUCMQe^UGK- zIA*4tt;g~r`i}k;UPjCrsoZ93p{hepmL0ru0{p}uM@7bQx+LzZo=fqMz>9n- zX-zdQHDOgBDX6nr8+A=d(JlM9s^@O5q{>6o9)^H)kPQps!E$OwwzT4=hau&?@i4l_ z`oI?{vlvcgC#rfQJaB=9kJ+e3{D)BXeUChc#aCBGe&@2UJ71vZ6o&JG4@fBz@aT|T zzjjWkP&9(K6xPsmO6t(#sd2v1maZ^XUQXV#Qm|uv-!GsB5WZwLvO68XFc?0-bKt9k zzAuo5rKLi---jIC-Pg>{qq_42dKxJHHbitsfQI3o_nrHh22#*L=fWBbQWaTbTXj07 zVF{PFyqsSl6;4<6-I@UV!o^96m-;s^0C4mhvi z%fF{FL26S0HW-l5;*cJeZD>}-lRSi(<1NWH*Lg7+6e7|-XSsZ7mrRI}S4`!M=G+(} zHmGPvC^V%K&A!4Wx=P<7PL<^i8;uLPlw6XCj2x(Y);8MJcPA>Z(`i}Yb)BZS$-EqW zQ@Fvo`s}fM^o4vP&!+q+9$rKqCq-TOXjoDC0=k5 zNrVpM9=cdCcgh93t0C; zpAv*UCZ6(fel50B9d8L z80&^o+QKELjv~MZ#^1Ba7U}mI%JS|SuGT-PUYV1dNYs@QB`LCTt-xN6!@E5lhd&vQ zi>aKD$~YF!g4o8cGnhz0du1o5<3V!4f0rVU@#mu#!jnXjWfoz9$&nLls2-N~BtJMn z4jvpJ0;_Ykz5?stDM1p5Xt+vrsP3HiQY7Vsc%8oZh(I0BD*xi@i}V74JVX?MRdF(~ zVLG4j!}lVl06O*;sGo>35?Yb?;JqLrk7G&*)qA9tV&H$28G#OgYS`=$*d$03)Id(>|LWvN=c)Vs z#4Bfm8rp><;aPrRZrRT-i*!7%;gl2>#_>-D9dmq>7h1=QlvL0-nd|iSa*~SAl7KH& zUcs<|xar%FyfKuGur(F&q&0lC^74veGIdF{(NLyzOcteBrA6w&zoVBtrPOM;2$B)- zs8;EKg3?N7qg>^+=wN88kkox_TwJ^CFfEH`>Fq>^J#~~=4u#(AIvEs7$cmUmHG+&h zN@G0c)Mr)OL3!Cj-FU^4Qojn!3g;T=J-p&TKMaiEQ+h5Bq!Hd|xEWFXC@ia<>ysM! zen!ST5D1)Q9_}H1Kz&j@#2x_qmQgpFybn#__fuMjWWr}* zm`Uk8snu%?tjdMnqUu>!EV!g8f(Ku0rGRO5UwiPZU9r1nxQ{DS)GMR~JBey>A z-)^85F|qrc=`Gx45w4bi;}XJzfF1nPJCATy=YUAa2hX8{wzXnErSpiI z@l=h4CuK;mVPNR+KB-ww`>_LOA2Bn+OC+d$db3R40T^ci&SOOoH~$2CICSBa6fzuA zYydBPdOghHUy6V+k`M*3(r`w7QtJ@ohBV>9UCNeUfJnkT903X<)ThsxTK!Ru5u@j18E(D+ z)_w{d`d(_IK@hRxY@%oZo|YbQCpT2u;Iebk*_7l%5SMe=qw1&^vZzk zfkO0!eWC}%iL6nGG4V@nhe9+Aj@_U=e4u3g`9*Jt)!xHsCy^W9Y=$Sj$YLiya4Zb* zo}Z{MF@gXuunX1+Ubtxxe@y7*!8~urn7>mZCLN{L@IvLw{Y7WZMXETaBgei4zrxaKx-pFGGPRxs-$XeHzs#q zwia-{?t!!qygJmEJ?K5^6+{2!!GT1!sT|yP9M)dOx!5C(0PKZN+F;NZIYU8-=@Eiq984 z!UK>wY&#@m!jK)DNt_?xYNR!8jrdn7=pA>9JtuM6eoM*AYTlwn=t&nhe=sMZ< zY>ddTqP0w7`{jL*Qa$p~DKjRd{<}WA)b9ZKRd_>~odF1SZjbi6XH*lV06VrCX%-Ye z+4XX~xX|}P8w2bjXflRxn0E-fsN&9|p^Ty*sIc@d%LZPGoW083nL03uJ9ZxM{g8(S zP?WNM*9fHcp(75KQUn`j4Gd>0E9`jpp$IbyxgcnAF#IMEY;9$~2}!Ei%7Vs8NjEZn z0SLtNg0glF{8p45+h{S{o50GlYLLsatqA*67Lue*Y0^hhl131we4~*-weFBIvT#xq zU_x0Cg;+cR*iI8Y=v3;e&V={Vnfln6@qxM(P#BrK8DXN{(A&@@a)A_HppJ_gjbU%m zkf;-Wtiz!e3C?M$zzXt2;0qMh!S;x-FV@nI;!~!Nmjpi$<@mEq{bj~rM^96LWm)7Zw9<;#{j!@ zb&pF{+F~56$8nKCzBvQzjI=gAenE^Q5}-Y5Q%2Enw>dvbL>0d%cjWIPRy^==zY z5f8{iHuGkP3B_rTTy@`)R`pi5lyK)F+tYWVDdxs)(ABYjE5GRRcYQ9z7r)vOcJ%f~M`n}>tK2|8V*JZTjrC&fPu(%+~}u!kY1_35IK> z9l@%n5*9#1Odm4oB?*Nwd|sw1Pr~hgc@uk2CqD?kNqn_LXoSHFlK8300!9FXl`OLP z8zC&4=j2I@ipzn^%Xm~?DAT|$Er&$?RRN=g%W~qIRxEZAGW#GHSU+q!z?DK$&!LcI zmHyE+y48bF#i9K{zMdCz4s;czkVEZ*Jqklh8TLHrITS8VDH5;Nju*&4oL6HeJ9=r*F zq=)I~vT~ZNqO!g7IhhsX!Qc?bHDCM=U^ET{aL=;0(d2pZz zC&(zOH`6=})~G@QSov6Q(V$1dC{~8LnP#03JhX?y&*{H}aN>w}mFn*F8%AF@?y z{iK;V8=*4B;+DnRf=&M~bF;9F4AzD{WsJ{`+bQ{x>i zR55ORcitCsh5z2ogs9`7yck{aUJMuhlVJdYjYuZv4tEpWuIq*YEqA9;cA5XG10<=H z^J%ek^Fk6_LRhl$A!J34%`l=iOmhyz4Q9_bbgEU+sTbKY)PTo}$bDm<22`2|L!u_@ z9#01`NM^)|2^R@uBoJ!C?Bh_k3s-jNuu-cF&aOVL3=o^guDJxx&iCm^@sju{ByHrh zz|%%XF}no@Mv*>C#3mk3<1m*(@(Mre)aI;-Kf7j}SI`T|ZCae^YA6;L9~>Ofkl6dj z(w2yB)y8s-40VyBc#$voA|)8a0DLZ#RFIZL5`VISiaMd|hswrVH%%vWyp8#++fgRj z3rO=tA^areMJha@*AqM$Vp*T7_ow=;jDSAlx77lyd_pd$9H4cbhw!9OGaUxXJ%&c4sGg9Ylgmq( zB}bF-V@X6sj5d{)Rtpv}PaaWB0ya^l1)Waou3rp`DolmR93ZyL!nXMq&ReuYcKSR8ZD?p z$|`#NRRO6TBtK9m5r)bLNn`pHg<_(pg5BqYvKFCl$ody=gi>tr?yR_$-x1cx;pIt0 zXXM-PuRk6SmK*u3m|@}>S>VSIy#f3TU|*ujb?%37tAx-dLH|Y$qI(dSbwxU;=bY)h5AHoBvhuL@gkmh2%lWsr-XL(*yWTJx##N@)K z=utI}pnsntv!H#0#S`i_YXfjnzM9SpeGh`;JcToi2UPvyK0?VyW=Pl%gzszshpJgx zR0k8{M5j-78vHOW)f*~{c!lNA)vn(zhC@g=GN@&V38S14*HqSOWy*w2>bROIv#P%< z-5nlERYRdP8X|=}0lE>m4~CQx?O7A9?FlqRdZG)JT`^|Lu6?ZNXL+Ys;1fG3wfE=3 zZ(mzB%1&9VqQ~VIubxJB1<59H^y#_XCeglhQM|P~UFq0eTV?gjwGD%ZMhN&Zz;lue zQ-}+ISYwITF+@tC4|OAG46?zJ=;Xz#~*hQ!cprvh~XMXEIxSGq*YCHtMoB1$&pp@(phU{)Kq74@`XDoOhS00BQj zX;sW{u$OEUqTTh~muD zn50Z29LB>quHkZ4e1rb!%a_k&6A>Ho0K`xfJA-z~ zN>h$^Rt$@2fkl2gnOr)-w0MILj&S;*z&AVOE|j{!j{*?}9wY~kpc1UY`miFOwJ-1) ze6(^rt4Ck)1$vNdlb?~3oJEic3O$BZcD0DY7wMH6Qpedarh2fId^tFfmu0HnwUgic zdVTt}wBm`W0Uvr43WL}z#d&FP6(74}b@Ay7iZyVcI|jiJW&p?*Bl&}QdRdL8yGwl! zkS8$xgXELFB#=J!X8nlTZ!KL?AJvK_7$`OFzRc-G1@1yyN99xLV10B+MFQP{>KCVw zRg*L&yT|zyd+H7ek)X3trj{6{;1DaFPuR3yOi*G4QQEMO`&- zZK%8_3}u7%D43xGa;I)=Qv=MO2eP zM`Am$Kwvq6I3ZE}ffElx@4z!gZ-^ca*pYlNu$OKOv7^VsSnJ|(c{~;~V_+XkJQD5n zhUUyC*5M|h{yH@ou}&a*97g)Mre&;!DRG#anHjQ|c|M=w46crmRb56X${{09zmdb9 zi9^`|p9vmJ^f{~CwVg}Vl$=QmgGztX1B3|_4mgN$i^nW-io%7xkSc9{N(mM?Y7ac? z{BCPoscxH_sB*Ykj!o4>ua}3^Q-Ep(9mRp>Jf}b%Q`bu&4#|e@fp4a%Rh?lnIzcFb z@&z%-haA3DSmHj*$-sO`+9K>GFenX#%D0-rWhGGK7ps`Zs!G%1tS{TtE}ZELH7bPJ zIwvy|EI!3-Oqt62d^m{DNlvCx8D9Gc1y?=XecmAB^dBHTC`yQO9hw_#&`@^N`W#6q z6$6<-E4iNf8SeEKLkcY8btz&5W^qho)}w1n!zOuVMK$m z_e0#1Sieec2T&^O#D-hejxC6u?Sr@2;;>M5hf)XrCBG3!_mP(F3xdiS?8Dfx2&;)gEb*;vj~C9QGHs< z@c2aVfNpO29Kl-O(B|h56UIJ9Z2&eqm9}{($|b{31ag1`Do4upt$nC%RHe=Apiq%Q z+C_bKGAt+}fO?}(QmkR}-eJ~&^&5j;DpLkNg^_xZ?+(45MI}a*z!eA~ZXD1bxGo%J z)JJtwq!8J%VT2m4DRq&Wk0sw+oLWyEl88c1B-Vrw1`_v=bB&Ox+%GC`uZ&s`ySCP) z3pRAWVTCUBBFM2HN!3CDg11>C55#eGev55=r51~5R(x_cAJ0Zt#*ww1ugOMZ+9bf1 zEtt?iTMN2d!c4fUE@pkYt^NnSf;Oph?mBf&15$em-lKuNt2~rmd0Q&4gfCv=V2FqC zMxj)F1=tZkzfynf(Fcvg8h{H6qIvXbqBni&!7YBW+lpk_idWQvERGRT*HfibiAMe`=Edo2cEqPaDN16Y%R za>IaBZBiYB6n<0R$t^0VZB59?zb;QZLf#9TBCs|E4C<{qZ{MJ3d@+U8m%v|#*+l9h zdq=>qkB=1^Mun2w=hz)h0-R5y32tSAEMm>7;nbGx@r}8(Nm8mKfQ~2JDp!(zqDWEo zwG8j7{lQrF>k># z1PyK{bj8)SAr#_Al6jm`cLcQ?%z-t00oGM}TB_hYndH?S#GupbGA^P0&(pbr)_Vks z0EK5P6@pTZwxR7QE&+}s`Qo--_Dybf$XWmcO7S}Q+u>sdwUvR)?hWB`?`IJ_C>4W2 zFQ85tF^ov3_p6#C+=Z&)Y=yCwRosvtA zqp*e;;y~sD1)0BNBjEyYA8Ouvb8hKPCin`akR7hN^+YBf9B5=k!{OnjFuGHqET>rS zAR}GS^m2#nfIyFwDut|*0~QDh3#j7mfvS0CFcQWu?hxCc6g`o`FaX?c)RE0GnGG?< z-J!%V>Y^%>Lh2I6jslbVYEP4U1X_pCzmerCWd%skr;fo|t*?r5c4lX`Cs7o3BP(@$ z>Bv{BL!WY#*Fc;USUwo@A*Dpu_eIOhrL>cpQmn*nxArCh2Ui8Q!8v1eYYAuv*zuZJ z{?)eES{yGSmK;(hODSLrqr-YK*oFj>3pse$xV31{`G&%bYe5bmAG5m~bSJHbuBe&uf?VLNeCG zOR&#^yg+AhrII19gu_%7!&euez$9)-3Y$25hD4np$qaSyL@D6wLr-{WMHizA0w)o$ zQ-V)AE=Bd3iyr>%exG6iR9?bQVs(|SzOJByH-glu0-NH=!{-8_x5g z6oe%jM-@oDc6S#tz}I5xol25_ioCNhV9F3~fNj`vifs!}6bZYH{HDEY&WPqlVC?%T zt|K1Ep=uVDJFQub%cY49so&<#4hVFZh}va-fKCjoBZxvjR?B-Im%ZzeHW3jeC2wE+ zl4^DcZ8p-jcQ1L7jM)Ok0DyF@^2H1FnT~{Z)xXFHa^OsINHdQaVeR_+$bE|Zw4Vjp zfV#&6Hk$NFDgTlX*#fYW(6!QJ;!3EixBVwthfrA*EGzO}jLP73Yeynm#Py?1wj;!` z_>%bm4gblAoI=SAvFH_&L6Z|u|61*H$J}WEJOOr{(Bs(hzVu?^v=d={hm?D6Qd=ZEb$V=!!7=)v{x^neI4M@h#MkZwp zRmRWAFr$SW0CSI^B4|PAkNXz7)_Qzyw;6m(o!B_`-*O0y%GK5a zBT#{ClsilLu&C~8RXC}?oKwzuL-LnbkR3q^kwlO&qU;7~1CZX=EumV2Djk3d!EDCN zZj0@2xzJNLJ{}lW*t1B91^XHM6_HKby-shFlTwZhot#K8`|PA6HoL%$ucT~TULH3+ zOZo`fh~0Hel(?;LYQ1c3!TN1m(7*R4-f=#nWCQeaVX4X^>(y-Q^}XFw%G8nAjI)ZG z$XE~7#(c=u)?k!9;h{obH+Jp1dlL4#AMLqoG{wkr9h{oQ^m@`v3%iI74Iufq0IQ+}-glmz8ytbUgZ+PPv}sT8b!A%ui}(Q5$I@_#3#c zdK4jwV<5uBt}uwU?2gHNXd9#LTJYAO)5v(JOI@i>j+=cHS87%Ws3udO zAbVVG`}`J5+%g?oKL4F1O<)|YopV5q&Go@RBdR)rf%kH>Wrz*U{0;crUDQr)!vZa) zeKlxQll6`cljP)>%$(@6XD<&QKTA#@zc@Kcj$VH8;+0wn?O};c}y0<{0kwzf?<-D|8XSIV}W7r>+D%UTOE)j&9UFbcq5tL=~ zr&?81=?C~W{kJ(MF&P7SP)rKe*LHBQKsTF8b9g7M zbJo5hYm3mO*c-O4PfUai@(s?smhHEL&NU=$Bcp&i#dI-Swux9{@O{VIRtsA?*BH-BcD-(Bx42B$f+Hg}i_PFrOeKqy{rY z#mLbrHSO&2Ob;L4SigXz3tdn(>L6ZHpBqR?gHJ|~Mv9D5U^ApOVQ2x2+H1msRjuhes&{8^x(- zT~BS3tV7`RM2}A8T~LRU+avKs&=X4}FTU_?Foe#4IwD?(XFimKLhZp+&i)mK>`r`Qe3FfOQ+wSO>9A23BviuX0M}uAG*h)!xk~r6q(X&5Iq7jzvrt3K#;_15q zv07{^ulEMPZfS)c+)`IMR0=WQHIu^y5No8nbT%dYWa!@OTMNRtC|GPB zv;z)kbuoUl=~!btF&{iBE*H!*o8_m`aohIZb`sbcx@|3p+wgVi8vMzs3)6>8{34tJ zk)K>ChpgjanWvQD6lR|SP)aKRMqj4CqO&=TX4$koNjO^NJ#fDS^|gRa9Eb z)9Wp{DqP37Szx%;Yi}mFy^x=YSh3y!i&JBWoJ_PJ$doFoV&C;i4F+b%Kdj7{9#r0j zd$>QwroKOM#3*%1KL$>k4XCqX=Hy}T?|2LVeULHH{YVka-T*>>Bscj$6~yub^`jaO zinI#zRsoEcEZ{1<3N1|QeC#NwKUV zC?;2iq?0PSy|o)^yKip78Z8}9q7Ff|MIGl*fcJW%MzYso?p4JDqzDcGbNtz$6>w%7 zf5lPRBzIJP6wierRTUc{-~Dzn*U?Xv#$!IvftMYq^Ig>r145oGbws_4V)8O@&-7SGJdtxY_d3FP6$ksB`M8 z?Rq`x>UDq9t>w!0Uh4ttKzqsqn@g8^UFiU4qx|A%az)vl!Z?IBQC8Vy)J0ik?L`2= z4Ndl=sN8MRW;=mZRkm$w0_Ao`(OXasjG`5gZWojsa`)0R9jYag%j@RYYq;~Z%YDaw zgash+91eqwAerlF?@BCEHY2ld>`l}6u5*^YetQ!Figdd@eMzWW13dP{RC_n=gJT*?adXa(7dr1(E()5#hUZf7DbleLH zGt$ffZThS~u=z%J*qp_;aHzLr@$Ka|jf0F_14=LrB+|m&qHa~4cgL{P zytqC-3!Wv*yAj#%CXVwIY{DoTU5;k(_T=exn)6dKF=66_Tg4dWjp)MrCz=F1`YKQC|AV^c6 zC|@t79tDEMmU?)7;rPl?XoQjTfBV8*h8jJ&MK3*y;UYVN8wSXk9tI;L@;7 zIW0D=aJjO5bG+H|(&pxfAjD$jKsV}VFy!?qONOtEx`$LMOJNy0ux457vZzG>?gvZ@ zXJpsvvs&<~w?|k6)JD=%VpewN`d_jNlziAY1U4?;*0=3isCby~(1Z;dw>6=yn=MtG zAc-s=&zfzzG)~ff=ZHFeP;~-xPT1W>{B1WZ_T+DUBsf_$xl2V8O|;?)1jp_e4-it+ z6eNy12vTyeMGaLCWcTapk`mY<^(!uY3Y!`*rPEUsB-Eo3z~S!M248)3Op&7MzD=m3 zL4?Lbpbvt&E`7|dx2T)V)LcHSC~P&J!S<+QJ~cMOFR8zYtQN)HAw_pIoXIE26@fK< z;qd7Eyd1pw(cBA@81T;2y&R3NDl30I3)FAiSXg0en^p}p0VGWsGZN4=8Il1+Q=Rrk{P>fRT>UPtX~U-e%${kX8WfseK{ zTl%t{lw4htB3VndCbg&x@9bV8w4jm^j;002J;^$;UxQtvPkMci{w-jf{e3s(eB-( zf5r!Akf+4zH#+Mmo#B9*Nrg$}PZmwMd6u}t@=Oh_FI!k{i?M)m>`RN{o8v|moBtyz zE~woLueI8!`?;zKQThX_>6vg&C(|-6Z?Ce6lr_+2vcqt5q*6p`Owso@$rW*GVMC%C z<8yveVno`N?lz`M4B?QLN3*i8ylG@?DSsQEKj67Y%FU7vbJtDeJYTbkHpm|dVoPwK zIhiPbGg%O_QN#m}_As8AjnX=rK41YmoKRU!<|ugyst`O1@e}n9HK-T}8+1CGOye<( z(22~g8EQ=mu{!~+77Q&Xp%iON-)uF4*QtfLwmhTkQ#q~m9(pp~Y0 z=$0nutK2f*ta_@B!#xlXt6BY3^i%+5hRk+>39P3J%t0Xpw%jD8;bt* zbdqDY5)i@ut-iKKtE4;7R9w%g3ugM<)~*P>xH>PfFLilE5yMG&A*OcqOEH4=;!`g6 zNXjrKlgU-@n`2hwecz-$npzRM033B$OjmCwPt_2McQew&hcb()ZvZXl_)W2&7F;R8 ztXAbPK=?|Ncel$>RhS-J3Y`uEU}g)$?By1k@ZAjFS0YNSSy}c<){hQ-G2K&%~l~;La)Jfg3CuB}#D!f4wtxUxs#YDIA)$qMd zLtl-%dwGB39?b=_i+a=_U5~{9pk=on_SKVOz5eSJm&5o}RN%q+?Uf#Fw(t4jtHkXo z--5lD*a!=vfXfrZV4dwksCN__x z2>%Bg$Gy~wXn(b0b)6oH>A$^R@wOoj4xMyMy&~PXX74`Il@bwM6nMHgc&Z=t;ipfZ zdr&7L)CmT2gFeCL*XK{WMlnRA_(HMdt6H_EwX?su;#T-?+|j^2d19_;F%SH_xV*Fq zL3$~s*lnUI$}6Io=1poQ335byvx-{jVlsLANI>@^%~6Bzd$*Bf6nsh-C_kk?R+T7~ z0ZlVqF*9YHtLyaP?Ra3Z1`9KCa$Sr=Uk$*Hp}O|2FHA(oKeXP}r&Id6a0nd!K(xc1fo%TwUcUUinw9qNK*X%`UUWGScuOcQ1u}A4W>1C*9>xjs=z3C)Zm5PXm5ASr9}TBP@rdoIey6L|iHAulM<_Hzvx9o2Rn7?- zr0R;g(hO7A?lh~yyr{hu>MT>SPV^9$lqGCg-PRY(u`Ise!}$gUwnRa_#!!;t5`#G5$N4)`Q;X|2J3HlUP^Rk%{+F+Z++t!6^qWg+&h-SQWI|7 zqhAvYQcPjnZY)OyLMQ@&;+nnOl^@#W)InrOyiF?)Qg?Zc;8;Fqke^3o{_^Xa%dak9 zT|LPX&Hy~RIk}WqIOM=vxl+{DzSI4a*4rfDvhZ{wovNRRGNZy`<2OpSIYy#NN6%Hp zg4wZ+(_*PqlfGxun`A(|rjqPR?WXpQ$|=r+DYitVE?qj#0J40kfHRqvP7g23{07?7 zw*_%-U5s2kx^6DG8IGQRHN3w0(!;HC1^)e;WO6ftFKRR%;!h&UkU}<+P>1J}NMI=e z1Kj4UGK~do8$9V#I4NbI0u?-GtnkVxh#1MP7X>tk*91pVI5W5*2kG=SUN9O;`?@+- zYuhA>n6}kYv1>p-PGi^=*ttSiKe{Z7;w|ESIq1;1s-_fh6pCUzrk|?7Ro5}?p|-%v zDrJ4C4>lN0MT5@YTb9SBBv`(nxY0m>wnx^wxf9diB6z{z-d=WJv-||NmlJ>oM2wk{ z+T^b)ta5I{5HXs#YNyC~Pd+AbR|wRvXV87Exwdx03iL4_&)}MpT`LcT5D>*s+qS+p=mTD--e_VfoE6oLJ4Z$?M5su0IFP#a^5?YMXE5l za-9rw^JWCrRZSTG39KOMr$>SnVK<0AD#11RVSv1Ns|MjlRq=}I-NQE0n zik1KR+I)szJ<(b0kLn){ic1vw>LXT^xWA!v6Mc8*xZ~~Z0>7(PNc$j(`0*)XSt{tT zY9s9kx=bFb(>hPQXs9oMSRv5Dkg(o@){Dp+T+EZTB*;cmP>qA z$b*B!=;*W&IIdb%r>T-2(M-a}AUM>0pYM{5&3Pn6-BhVEbG6k9nyZxYTB+&QQ{wy8 z{2I>gdP%oE+psCw`j}xVSV_&PsE?pN0Zg=3uYg#C2iW*PuFME^3}%N&uxp?>0*ICX zU|1<>SY!#Qr&lX4PNc2IY9ifjpGQCl5-!Slg!TQu-^JiI>(;rHuamSpy`WVUuQfwy zEpCChtytW8Mg{QFE&v%kxmvDl&)~7gM{`b=FI~#u(RX!{^}45;OTxoi6J688=1CwF zD-Sur9Sc;BKHbk%=_2w~>j_H0szDP_ArW zf={=+v}FnIu}TO|?;y$AB!O_Wm{I#E_g_AiRJ4ARIA^XG1#6iIAP}1l#MUkHyqtGV z7R#}ZMupFbtR7Jr9OUdd^@lKirj?cby3A;yO;Ytop5KhJ%1Y)im57>Dz`|Pa#?nFl_)Y!f*hvu1^n@htx zt(}V;Z6m!b>o_JD&O9}uatj6B8bRv}N#0|GzCYfZ}dZ1I4@t_L(L3nirXfNqAd+qFM=u=Q^^v$C_(j>0RDjoua~0%%(W`Y909EP911_;`Lo<&5~Ip$kclF z!w=juUz{-hbN;(?C-A5!)2DrN)^^B!r{AniQm9tl{fOFE`Wc(&(i&{;X*-5yG2r*u zwYIg{wi_i%wCDh6)k^0&OGjmKY>SCkAH)5LFRk{u^25t$$Sw2FuZH1ce_m!cC>g2% z06wt%BD{g%6)td76QE~m0+2TCK7FB%Ix#NyZ39Nu8KxcWh%=9%fH-B^EU$W=Hi#x6 zuaZRVG2Btt$9-ddxemn#%+Cqn_(c0$q;sT%n9$j0my;}&vVrZZ+!!O1j($kCIlBav zTyoAYRFqD7+%)-{?$S18$lOjShc-QSm7ac2cYWSj@Z1izdd{V>c6^lwpI!l$B7<aZ@%Z%&JXdS_*j{A3I`?k=v;}!lUt_^IlE>*7NgnL3P+Pce=VGorhXR zIz$So>AO+;gO~4NZrH1zv5ZdUf$=JA68>7v`KmzcOCQadn%!3-2`}~TkSpkZbE_k1X1#^Rv}6V+E0zthI#ogV6{_E7w+9?I$I5I&As9`*ax)JVd_ABU-NKmYPL zD6gSm+cYnmjw_~GOzhfeC82OD;yUD;5*^P!;jvmskv*33z7O^xmh$q0ZCcJh{9`ml z+bwCe@?LzxkJS{Qj*+0~eSjxQ%+$6$t5NGZKzkS^9@dg3XBJ`a9kE5fO!IU+Q)~yf zht6@r0cnI7c#P?-q;yr%_}!i(^dJH_t{v(M#AOr^(LcV}yQ3fW*pSufXo;I#azrLV zH&8!01kt&}$szNrkMZd66?)$D^m?yT`&hygfCe1F-eWH9d@@w?T%G|w^lV#IQ zUAJ<*T6e!n{;OG(m5)cDd~Mp_8Z*H%p^CN8))h0Fdrm9lcXyjsz4s5D!cMD}3_Gr{ zg#?i^zAixQV%^D*SQa>k&eyhcI!x3)2kWee2NE}020NhuMoq$p(wi%}^Sa#5dfsl7 zI#;T_d>hmI@R=RVPgx|csvn!gV!Pu(LfHULr=u&P+C=8y2AmN#EFs2Nk1E(?2|lwzShi1Qb-Cl?W78K)I~vaWx^&j? z?EXL{vcu6*;b_;7fmw%+5aM<$tTSNU!uqmXi@gmX8&Mg^(sRynZ9N-Zf$JPRy_!89 z0A4MoKj<1+*7+jLu8ez7S9P!*V@I?0sdREmQ)to5*{0PYHIOs{=v>gdY7FXo?C`d_ z&AP$UyHNCC;7mG z9pcV4SRZ&bxj$n4tnbI2m)4KX%BnMO+qLxpZ@+*$>zj++*g8&zIrc)-6sl86dgy4( zFv(voRosAz?ZojFv&_jjznqtl=EFL9RCXp8Fx=d-V?*kD1}x*^CQyyr8$uQ*DsS0taCASc@Q8MkL732bsUXXD}~xtEsEA*si8xo<@^AlUpA6L zd`qoYD_Ookcsji=X2a;{Vm^Lbk;{QAtCPufWv_`%Be!UJO090+Rfa&T3GLnE5mq6% zr|H0mQHE;;i;Q?wPpm@*TQ;ega=;pCCEPTSc1sMk-WGD&f&4^h{$~XmhNV$yJ8bBk zLvjhzX)Rt2Ech{KXMvrnN(=sSIq@NfL@DppD++YF>bH;Pzrz8zQH5 zv=*z&4OdpznAn%0f;8Rf#u0BjjdfWBnsRu9)~Qk=lj^4@KYH=_`N`3vd;0SyXy?!H z@8?W=|JM9qU%$I@pFg?s{;%-<&-2e-{}c0reLejP`hq{ri`?s5`t75?W?p}Z*Ps3D zXA^tHBK`BR>1Twd=qA zm-Pkq^*j1)b${D`^YNoYe)xI**?#rR_4f6%KWo3KU(MrGAAX;oq)+zxo4=udWnaJZ zkM(=|dwYL7ey_~+(hvFb>%X!5`Y-fb)xKP_di_7(GwG9U|8M`MzQDdlwgLTdWBjho z^{)B-Km29=g!c9NADLg6mv1k>eRRY7`u%_MTl#wY`b#pwwLh!#_fPm;{raE&L|<=T zzw>`;7xSZie*39Bo?Id8L;igGf9R3;_J7f@zowm>u|10MDmFaJc z-@jV9{#VWQziO`k`!m^{i$AO5_iy-B{rdJcKY#G+`o4c~qhD9QZ{OS3|IRgkk$*q`=sW!X=+PgV>;KSPzdBy_I`w7#`=9)i zwPWx9N9OuJGS{2sSgkL6y>0h@ac%wifB!dhzkmN5{rX4Jx!NClz5VEa^F#gm-}`s^ zy5IY!`t^JEi{^Fp`k(T-d}jOqt$(kt`_?}*_y1GN4amLfe}2ZB`u)H4yUW+tzbikl z-v1Z4c-{5?(GHYpX!ZKP%Ek5m|IUBY_x~L;j{kY31FP5nqPc%><$Lye8Q=OJ>8t#) zuYZdlw4~6V+yDRdZ|Z*h>R;F2{0_hPWe!Sve=EO5T-vd>*UIZ3{I;B`j~@L!dn5I3 babNTHQP6Sy-~3Pd`hWg&%dM|8_vrrv|3OVR literal 0 HcmV?d00001 diff --git a/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/METADATA b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/METADATA new file mode 100644 index 0000000..bcf64a4 --- /dev/null +++ b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/METADATA @@ -0,0 +1,99 @@ +Metadata-Version: 2.4 +Name: rpds-py +Version: 2026.6.3 +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Rust +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +License-File: LICENSE +Summary: Python bindings to Rust's persistent data structures (rpds) +Keywords: data structures,rust,persistent +Author-email: Julian Berman +License-Expression: MIT +Requires-Python: >=3.11 +Description-Content-Type: text/x-rst; charset=UTF-8 +Project-URL: Documentation, https://rpds.readthedocs.io/ +Project-URL: Funding, https://github.com/sponsors/Julian +Project-URL: Homepage, https://github.com/crate-py/rpds +Project-URL: Issues, https://github.com/crate-py/rpds/issues/ +Project-URL: Source, https://github.com/crate-py/rpds +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-rpds-py?utm_source=pypi-rpds-py&utm_medium=referral&utm_campaign=pypi-link +Project-URL: Upstream, https://github.com/orium/rpds + +=========== +``rpds.py`` +=========== + +|PyPI| |Pythons| |CI| + +.. |PyPI| image:: https://img.shields.io/pypi/v/rpds-py.svg + :alt: PyPI version + :target: https://pypi.org/project/rpds-py/ + +.. |Pythons| image:: https://img.shields.io/pypi/pyversions/rpds-py.svg + :alt: Supported Python versions + :target: https://pypi.org/project/rpds-py/ + +.. |CI| image:: https://github.com/crate-py/rpds/workflows/CI/badge.svg + :alt: Build status + :target: https://github.com/crate-py/rpds/actions?query=workflow%3ACI + +.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat + :alt: ReadTheDocs status + :target: https://referencing.readthedocs.io/en/stable/ + + +Python bindings to the `Rust rpds crate `_ for persistent data structures. + +What's here is quite minimal (in transparency, it was written initially to support replacing ``pyrsistent`` in the `referencing library `_). +If you see something missing (which is very likely), a PR is definitely welcome to add it. + +Installation +------------ + +The distribution on PyPI is named ``rpds.py`` (equivalently ``rpds-py``), and thus can be installed via e.g.: + +.. code:: sh + + $ pip install rpds-py + +Note that if you install ``rpds-py`` from source, you will need a Rust toolchain installed, as it is a build-time dependency. +An example of how to do so in a ``Dockerfile`` can be found `here `_. + +If you believe you are on a common platform which should have wheels built (i.e. and not need to compile from source), feel free to file an issue or pull request modifying the GitHub action used here to build wheels via ``maturin``. + +Usage +----- + +Methods in general are named similarly to their ``rpds`` counterparts (rather than ``pyrsistent``\ 's conventions, though probably a full drop-in ``pyrsistent``\ -compatible wrapper module is a good addition at some point). + +.. code:: python + + >>> from rpds import HashTrieMap, HashTrieSet, List + + >>> m = HashTrieMap({"foo": "bar", "baz": "quux"}) + >>> m.insert("spam", 37) == HashTrieMap({"foo": "bar", "baz": "quux", "spam": 37}) + True + >>> m.remove("foo") == HashTrieMap({"baz": "quux"}) + True + + >>> s = HashTrieSet({"foo", "bar", "baz", "quux"}) + >>> s.insert("spam") == HashTrieSet({"foo", "bar", "baz", "quux", "spam"}) + True + >>> s.remove("foo") == HashTrieSet({"bar", "baz", "quux"}) + True + + >>> L = List([1, 3, 5]) + >>> L.push_front(-1) == List([-1, 1, 3, 5]) + True + >>> L.rest == List([3, 5]) + True + diff --git a/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/RECORD b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/RECORD new file mode 100644 index 0000000..40f3721 --- /dev/null +++ b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/RECORD @@ -0,0 +1,9 @@ +rpds/__init__.py,sha256=w3MgXW7lpTCICw0KXbw20QX573_kbsEnWIeMsCAugvM,99 +rpds/__init__.pyi,sha256=am7x6oMa_pu_kv1NlolqJbPr6_UvCvoyxGKrDGSMKEk,2602 +rpds/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +rpds/rpds.cpython-312-x86_64-linux-gnu.so,sha256=gCKJWrgLJvnkD9UWAiPP37QdQh1v7LyT70kZnHUKRas,966896 +rpds_py-2026.6.3.dist-info/METADATA,sha256=-L57F9o5gLLEhZaUFBGkPHCsQbHi1TCqUx8sFeqy6xw,4147 +rpds_py-2026.6.3.dist-info/WHEEL,sha256=xePaIXZtDnKvRf8NMrO2enfKl7aJHT-f4ydLBaOLZ8E,147 +rpds_py-2026.6.3.dist-info/licenses/LICENSE,sha256=MU5Okb47qpPA-0vMyeTpfNZD64ObBlr5IXgsIXX-mQk,1057 +rpds_py-2026.6.3.dist-info/sboms/rpds-py.cyclonedx.json,sha256=gKO_uuFgflGyVpVmpGm4ptmphNSSPAgkCGQYpsij52M,20594 +rpds_py-2026.6.3.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/WHEEL b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/WHEEL new file mode 100644 index 0000000..4898fa8 --- /dev/null +++ b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: maturin (1.14.1) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 diff --git a/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/licenses/LICENSE b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/licenses/LICENSE new file mode 100644 index 0000000..119a1f2 --- /dev/null +++ b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/licenses/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2023 Julian Berman + +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/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/sboms/rpds-py.cyclonedx.json b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/sboms/rpds-py.cyclonedx.json new file mode 100644 index 0000000..87f246b --- /dev/null +++ b/source/target-vendors/cp312/rpds_py-2026.6.3.dist-info/sboms/rpds-py.cyclonedx.json @@ -0,0 +1,680 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "version": 1, + "serialNumber": "urn:uuid:db798bf9-1726-4cb1-82cb-2a13771d0822", + "metadata": { + "timestamp": "2026-06-30T07:08:42.115208144Z", + "tools": [ + { + "vendor": "CycloneDX", + "name": "cargo-cyclonedx", + "version": "0.5.9" + } + ], + "component": { + "type": "library", + "bom-ref": "path+file:///home/runner/work/rpds/rpds#rpds-py@2026.6.3", + "name": "rpds-py", + "version": "2026.6.3", + "scope": "required", + "purl": "pkg:cargo/rpds-py@2026.6.3?download_url=file://.", + "components": [ + { + "type": "library", + "bom-ref": "path+file:///home/runner/work/rpds/rpds#rpds-py@2026.6.3 bin-target-0", + "name": "rpds", + "version": "2026.6.3", + "purl": "pkg:cargo/rpds-py@2026.6.3?download_url=file://.#src/lib.rs" + } + ] + }, + "properties": [ + { + "name": "cdx:rustc:sbom:target:all_targets", + "value": "true" + } + ] + }, + "components": [ + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#archery@1.2.2", + "author": "Diogo Sousa ", + "name": "archery", + "version": "1.2.2", + "description": "Abstract over the atomicity of reference-counting pointers", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "70e0a5f99dfebb87bb342d0f53bb92c81842e100bbb915223e38349580e5441d" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/archery@1.2.2", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/archery" + }, + { + "type": "website", + "url": "https://github.com/orium/archery" + }, + { + "type": "vcs", + "url": "https://github.com/orium/archery" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "name": "heck", + "version": "0.5.0", + "description": "heck is a case conversion library.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/heck@0.5.0", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/withoutboats/heck" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.177", + "author": "The Rust Project Developers", + "name": "libc", + "version": "0.2.177", + "description": "Raw FFI bindings to platform libraries like libc.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/libc@0.2.177", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/rust-lang/libc" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "author": "Aleksey Kladov ", + "name": "once_cell", + "version": "1.21.3", + "description": "Single assignment cells and lazy values.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/once_cell@1.21.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/once_cell" + }, + { + "type": "vcs", + "url": "https://github.com/matklad/once_cell" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103", + "author": "David Tolnay , Alex Crichton ", + "name": "proc-macro2", + "version": "1.0.103", + "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/proc-macro2@1.0.103", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/proc-macro2" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/proc-macro2" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-build-config", + "version": "0.29.0", + "description": "Build configuration for the PyO3 ecosystem", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-build-config@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-ffi", + "version": "0.29.0", + "description": "Python-API bindings for the PyO3 ecosystem", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-ffi@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "other", + "url": "python" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-macros-backend", + "version": "0.29.0", + "description": "Code generation for PyO3 package", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-macros-backend@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3-macros", + "version": "0.29.0", + "description": "Proc macros for PyO3 package", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3-macros@0.29.0", + "externalReferences": [ + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "author": "PyO3 Project and Contributors ", + "name": "pyo3", + "version": "0.29.0", + "description": "Bindings to Python interpreter", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/pyo3@0.29.0", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/crate/pyo3/" + }, + { + "type": "website", + "url": "https://github.com/pyo3/pyo3" + }, + { + "type": "other", + "url": "pyo3-python" + }, + { + "type": "vcs", + "url": "https://github.com/pyo3/pyo3" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42", + "author": "David Tolnay ", + "name": "quote", + "version": "1.0.42", + "description": "Quasi-quoting macro quote!(...)", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/quote@1.0.42", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/quote/" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/quote" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#rpds@1.2.1", + "author": "Diogo Sousa ", + "name": "rpds", + "version": "1.2.1", + "description": "Persistent data structures with structural sharing", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "e025feb26210bc196b908e72deb063b1b4000754304341cbc168a1e72c857ebc" + } + ], + "licenses": [ + { + "expression": "MIT" + } + ], + "purl": "pkg:cargo/rpds@1.2.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/rpds" + }, + { + "type": "website", + "url": "https://github.com/orium/rpds" + }, + { + "type": "vcs", + "url": "https://github.com/orium/rpds" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1", + "author": "The Servo Project Developers", + "name": "smallvec", + "version": "1.15.1", + "description": "'Small vector' optimization: store up to a small number of items on the stack", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/smallvec@1.15.1", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/smallvec/" + }, + { + "type": "vcs", + "url": "https://github.com/servo/rust-smallvec" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.111", + "author": "David Tolnay ", + "name": "syn", + "version": "2.0.111", + "description": "Parser for Rust source code", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/syn@2.0.111", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/syn" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/syn" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.3", + "author": "Dan Gohman ", + "name": "target-lexicon", + "version": "0.13.3", + "description": "LLVM target triple types", + "scope": "excluded", + "hashes": [ + { + "alg": "SHA-256", + "content": "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" + } + ], + "licenses": [ + { + "expression": "Apache-2.0 WITH LLVM-exception" + } + ], + "purl": "pkg:cargo/target-lexicon@0.13.3", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/target-lexicon/" + }, + { + "type": "vcs", + "url": "https://github.com/bytecodealliance/target-lexicon" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#triomphe@0.1.15", + "author": "Manish Goregaokar , The Servo Project Developers", + "name": "triomphe", + "version": "0.1.15", + "description": "A fork of std::sync::Arc with some extra functionality and without weak references (originally servo_arc)", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" + } + ], + "licenses": [ + { + "expression": "MIT OR Apache-2.0" + } + ], + "purl": "pkg:cargo/triomphe@0.1.15", + "externalReferences": [ + { + "type": "vcs", + "url": "https://github.com/Manishearth/triomphe" + } + ] + }, + { + "type": "library", + "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.22", + "author": "David Tolnay ", + "name": "unicode-ident", + "version": "1.0.22", + "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31", + "scope": "required", + "hashes": [ + { + "alg": "SHA-256", + "content": "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + } + ], + "licenses": [ + { + "expression": "(MIT OR Apache-2.0) AND Unicode-3.0" + } + ], + "purl": "pkg:cargo/unicode-ident@1.0.22", + "externalReferences": [ + { + "type": "documentation", + "url": "https://docs.rs/unicode-ident" + }, + { + "type": "vcs", + "url": "https://github.com/dtolnay/unicode-ident" + } + ] + } + ], + "dependencies": [ + { + "ref": "path+file:///home/runner/work/rpds/rpds#rpds-py@2026.6.3", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#archery@1.2.2", + "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#rpds@1.2.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#archery@1.2.2", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#triomphe@0.1.15" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.177" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.22" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.3" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.177", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0", + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.111" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42", + "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.111" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.177", + "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.3", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0", + "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#rpds@1.2.1", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#archery@1.2.2", + "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#smallvec@1.15.1" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.111", + "dependsOn": [ + "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.103", + "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.42", + "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.22" + ] + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.3" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#triomphe@0.1.15" + }, + { + "ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.22" + } + ] +} \ No newline at end of file diff --git a/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/METADATA b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/METADATA new file mode 100644 index 0000000..f461f39 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/METADATA @@ -0,0 +1,493 @@ +Metadata-Version: 2.4 +Name: sse-starlette +Version: 3.4.11 +Summary: SSE plugin for Starlette +Author-email: sysid +License-Expression: BSD-3-Clause +Project-URL: Homepage, https://github.com/sysid/sse-starlette +Project-URL: Repository, https://github.com/sysid/sse-starlette +Project-URL: Issues, https://github.com/sysid/sse-starlette/issues +Project-URL: Source, https://github.com/sysid/sse-starlette +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-File: LICENSE +License-File: AUTHORS +Requires-Dist: starlette>=0.49.1 +Requires-Dist: anyio>=4.7.0 +Provides-Extra: examples +Requires-Dist: uvicorn>=0.34.0; extra == "examples" +Requires-Dist: fastapi>=0.115.12; extra == "examples" +Requires-Dist: pydantic>=2; extra == "examples" +Provides-Extra: examples-db +Requires-Dist: sqlalchemy[asyncio]>=2.0.41; extra == "examples-db" +Requires-Dist: aiosqlite>=0.21.0; extra == "examples-db" +Provides-Extra: uvicorn +Requires-Dist: uvicorn>=0.34.0; extra == "uvicorn" +Provides-Extra: granian +Requires-Dist: granian>=2.3.1; extra == "granian" +Provides-Extra: daphne +Requires-Dist: daphne>=4.2.0; extra == "daphne" +Dynamic: license-file + +# Server-Sent Events for [Starlette](https://github.com/encode/starlette) and [FastAPI](https://fastapi.tiangolo.com/) + +[![Downloads](https://static.pepy.tech/badge/sse-starlette/week)](https://pepy.tech/project/sse-starlette) +[![PyPI Version][pypi-image]][pypi-url] +[![Build Status][build-image]][build-url] + +> Background: https://sysid.github.io/server-sent-events/ + +Production ready Server-Sent Events implementation for Starlette and FastAPI following the [W3C SSE specification](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). + +## Installation + +```bash +pip install sse-starlette +uv add sse-starlette + +# To run the examples (fastapi, uvicorn, pydantic) +uv add sse-starlette[examples] + +# Example 03 also needs the DB extras (sqlalchemy, aiosqlite) +uv add sse-starlette[examples,examples-db] + +# Recommended ASGI server +uv add sse-starlette[uvicorn,granian,daphne] +``` + +## Quick Start + +```python +import asyncio +from starlette.applications import Starlette +from starlette.routing import Route +from sse_starlette import EventSourceResponse + +async def generate_events(): + for i in range(10): + yield {"data": f"Event {i}"} + await asyncio.sleep(1) + +async def sse_endpoint(request): + return EventSourceResponse(generate_events()) + +app = Starlette(routes=[Route("/events", sse_endpoint)]) +``` + +## Core Features + +- **Standards Compliant**: Full SSE specification implementation +- **Framework Integration**: Native Starlette and FastAPI support +- **Async/Await**: Built on modern Python async patterns +- **Connection Management**: Automatic client disconnect detection +- **Graceful Shutdown**: Proper cleanup on server termination with cooperative shutdown support +- **Thread Safety**: Context-local event management for multi-threaded applications +- **Multi-Loop Support**: Works correctly with multiple asyncio event loops + +For a detailed look at the internal task coordination, shutdown detection, and cancellation +flows, see [ARCHITECTURE.md](ARCHITECTURE.md). + +## Key Components + +### EventSourceResponse + +The main response class that handles SSE streaming: + +```python +from sse_starlette import EventSourceResponse + +# Basic usage +async def stream_data(): + for item in data: + yield {"data": item, "event": "update", "id": str(item.id)} + +return EventSourceResponse(stream_data()) +``` + +### ServerSentEvent + +For structured event creation: + +```python +from sse_starlette import ServerSentEvent + +event = ServerSentEvent( + data="Custom message", + event="notification", + id="msg-123", + retry=5000 +) +``` + +### JSONServerSentEvent + +For an easy way to send json data as SSE events: + +```python +from sse_starlette import JSONServerSentEvent + +event = JSONServerSentEvent( + data={"field":"value"}, # Anything serializable with json.dumps +) +``` + +## Advanced Usage + +### Custom Ping Configuration + +```python +from sse_starlette import ServerSentEvent + +def custom_ping(): + return ServerSentEvent(comment="Custom ping message") + +return EventSourceResponse( + generate_events(), + ping=10, # Ping every 10 seconds + ping_message_factory=custom_ping +) +``` + +### Multi-Threaded Usage + +sse-starlette now supports usage in multi-threaded applications and with multiple asyncio event loops: + +```python +import threading +import asyncio +from sse_starlette import EventSourceResponse + +def run_sse_in_thread(): + """SSE streaming works correctly in separate threads""" + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + + async def thread_events(): + for i in range(5): + yield {"data": f"Thread event {i}"} + await asyncio.sleep(1) + + # This works without "Event bound to different loop" errors + response = EventSourceResponse(thread_events()) + loop.close() + +# Start SSE in multiple threads +for i in range(3): + thread = threading.Thread(target=run_sse_in_thread) + thread.start() +``` + +### Database Streaming (Thread-Safe) + +```python +async def stream_database_results(request): + # CORRECT: Create session within generator context + async with AsyncSession() as session: + results = await session.execute(select(User)) + for row in results: + if await request.is_disconnected(): + break + yield {"data": row.name, "id": str(row.id)} + +return EventSourceResponse(stream_database_results(request)) +``` + +### Error Handling and Timeouts + +```python +async def robust_stream(request): + try: + for i in range(100): + if await request.is_disconnected(): + break + yield {"data": f"Item {i}"} + await asyncio.sleep(0.5) + except asyncio.CancelledError: + # Client disconnected - perform cleanup + raise + +return EventSourceResponse( + robust_stream(request), + send_timeout=30, # Timeout hanging sends + headers={"Cache-Control": "no-cache"} +) +``` + +### Memory Channels Alternative + +For complex data flows, use memory channels instead of generators: + +```python +import anyio +from functools import partial + +async def data_producer(send_channel): + async with send_channel: + for i in range(10): + await send_channel.send({"data": f"Item {i}"}) + await anyio.sleep(1) + +async def channel_endpoint(request): + send_channel, receive_channel = anyio.create_memory_object_stream(10) + + return EventSourceResponse( + receive_channel, + data_sender_callable=partial(data_producer, send_channel) + ) +``` + +### Cooperative Shutdown + +By default, generators receive `CancelledError` immediately when the server shuts down. With +cooperative shutdown, generators can detect the shutdown signal, send farewell events to clients, +and exit gracefully within a configurable grace period. + +```python +import anyio +from sse_starlette import EventSourceResponse + +async def graceful_stream(request): + shutdown_event = anyio.Event() + + async def generate(): + try: + while not shutdown_event.is_set(): + yield {"data": "tick"} + # Check for shutdown between iterations + with anyio.move_on_after(1.0): + await shutdown_event.wait() + # Shutdown detected — send farewell event + yield {"event": "shutdown", "data": "Server is shutting down"} + except anyio.get_cancelled_exc_class(): + # Grace period expired — generator force-cancelled + raise + + return EventSourceResponse( + generate(), + shutdown_event=shutdown_event, # Library sets this on shutdown + shutdown_grace_period=5.0, # Seconds to wait before force-cancel + ) +``` + +**How it works:** + +1. On server shutdown, the library sets your `shutdown_event` +2. Your generator sees the event and can yield final events +3. If the generator exits within `shutdown_grace_period`, shutdown is clean (no `CancelledError`) +4. If the generator doesn't exit in time, it is force-cancelled as before + +**Important:** `shutdown_grace_period` should be less than your ASGI server's graceful shutdown +timeout (e.g. uvicorn's `--timeout-graceful-shutdown`), otherwise the process is killed before the +grace period expires. + +Without `shutdown_event` (the default), behavior is identical to previous versions: immediate +cancellation on server shutdown. + +## Configuration Options + +### EventSourceResponse Parameters + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `content` | `ContentStream` | Required | Async generator or iterable | +| `ping` | `int` | 15 | Ping interval in seconds (`0` disables keep-alive pings) | +| `sep` | `str` | `"\r\n"` | Line separator (`\r\n`, `\r`, `\n`) | +| `send_timeout` | `float` | `None` | Send operation timeout in seconds | +| `headers` | `dict` | `None` | Additional HTTP headers | +| `ping_message_factory` | `Callable` | `None` | Custom ping message creator | +| `shutdown_event` | `anyio.Event` | `None` | Event set by library on server shutdown | +| `shutdown_grace_period` | `float` | `0` | Seconds to wait after setting `shutdown_event` before force-cancel | + +### Client Disconnection + +```python +async def monitored_stream(request): + events_sent = 0 + try: + while events_sent < 100: + if await request.is_disconnected(): + print(f"Client disconnected after {events_sent} events") + break + + yield {"data": f"Event {events_sent}"} + events_sent += 1 + await asyncio.sleep(1) + + except asyncio.CancelledError: + print("Stream cancelled") + raise +``` + +## Testing + +sse-starlette includes now comprehensive test isolation without manual setup. The library automatically handles event loop contexts, eliminating the need for manual state resets: + +```python +# this is deprecated and not needed since version 3.0.0 +import pytest +from sse_starlette import EventSourceResponse + +@pytest.fixture +def reset_sse_app_status(): + AppStatus.should_exit_event = None + yield + AppStatus.should_exit_event = None +``` + +## Production Considerations + +### Performance Limits + +- **Memory**: Each connection maintains a buffer. Monitor memory usage. +- **Connections**: Limited by system file descriptors and application design. +- **Network**: High-frequency events can saturate bandwidth. + +### Error Recovery + +Implement client-side reconnection logic: + +```javascript +function createEventSource(url) { + const eventSource = new EventSource(url); + + eventSource.onerror = function() { + setTimeout(() => { + createEventSource(url); // Reconnect after delay + }, 5000); + }; + + return eventSource; +} +``` + +## Learning Resources + +### Examples Directory + +The `examples/` directory contains production-ready patterns: + +- **`01_basic_sse.py`**: Fundamental SSE concepts +- **`02_message_broadcasting.py`**: Multi-client message distribution +- **`03_database_streaming.py`**: Thread-safe database integration +- **`04_advanced_features.py`**: Custom protocols and error handling + +### Demonstrations Directory + +The `examples/demonstrations/` directory provides educational scenarios: + +**Basic Patterns** (`basic_patterns/`): +- Client disconnect detection and cleanup +- Graceful server shutdown behavior + +**Production Scenarios** (`production_scenarios/`): +- Load testing with concurrent clients +- Network interruption handling + +**Advanced Patterns** (`advanced_patterns/`): +- Memory channels vs generators +- Error recovery and circuit breakers +- Custom protocol development + +Run any demonstration: +```bash +python examples/demonstrations/basic_patterns/client_disconnect.py +python examples/demonstrations/production_scenarios/load_simulations.py +python examples/demonstrations/advanced_patterns/error_recovery.py +``` + +## Troubleshooting + +### Common Issues + +**Database session errors with async generators** +- Create database sessions inside generators, not as dependencies + +**Hanging connections after client disconnect** +- Always check `await request.is_disconnected()` in loops +- Use `send_timeout` parameter to detect dead connections + +If you are using Postman, please see: https://github.com/sysid/sse-starlette/issues/47#issuecomment-1445953826 + +### Performance Optimization + +```python +# Connection limits +class ConnectionLimiter: + def __init__(self, max_connections=100): + self.semaphore = asyncio.Semaphore(max_connections) + + async def limited_endpoint(self, request): + async with self.semaphore: + return EventSourceResponse(generate_events()) +``` + +## Network-Level Gotchas + +Network infrastructure components can buffer SSE streams, breaking real-time delivery. Here are the most common issues and solutions: + +### Reverse Proxy Buffering (Nginx/Apache) + +**Problem**: Nginx buffers responses by default, delaying SSE events until ~16KB accumulates. + +**Solution**: Add the `X-Accel-Buffering: no` header. + +**Nginx Configuration** (if you can't modify app headers): +```nginx +location /events { + proxy_pass http://localhost:8000; + proxy_http_version 1.1; + proxy_set_header Connection ''; + proxy_buffering off; # Disable for this location + chunked_transfer_encoding off; +} +``` + +### CDN Issues + +**Cloudflare**: Buffers ~100KB before flushing to clients, breaking real-time delivery. +**Akamai**: Edge servers buffer by default. + +### Load Balancer Problems + +**HAProxy**: Timeout settings must exceed heartbeat frequency. +```haproxy +# Ensure timeouts > ping interval +timeout client 60s # If ping every 45s +timeout server 60s +``` + +**F5 Load Balancers**: Buffer responses by default. + +## Contributing + +See examples and demonstrations for implementation patterns. Run tests with: + +```bash +make test-unit # Unit tests only (default dev install) +make test # Unit + docker integration tests +make test-experimentation # Optional experimentation tests (multi-consumer load tests) + # Requires the `experimentation` dependency group: + # uv sync --group experimentation +``` + +The `experimentation` group is opt-in (kept out of the default `dev` install) to keep the +contributor footprint small. See `tests/experimentation/` for the tests it enables. + + +[pypi-image]: https://badge.fury.io/py/sse-starlette.svg +[pypi-url]: https://pypi.org/project/sse-starlette/ +[build-image]: https://github.com/sysid/sse-starlette/actions/workflows/build.yml/badge.svg +[build-url]: https://github.com/sysid/sse-starlette/actions/workflows/build.yml +[coverage-image]: https://codecov.io/gh/sysid/sse-starlette/branch/master/graph/badge.svg + + diff --git a/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/RECORD b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/RECORD new file mode 100644 index 0000000..7892a92 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/RECORD @@ -0,0 +1,11 @@ +sse_starlette/__init__.py,sha256=9ixg0ov-gHr8LSSotykb6kDhX4WqNrT_0-TD1rLkgF0,219 +sse_starlette/_utils.py,sha256=c1971mx2Wlr_MN7ekij6JYN-e3i9IQbY3l4MqDQ_VEA,1439 +sse_starlette/event.py,sha256=wePjktO-n0jsguXGmlu3hQooQWfJYNrUa8iD_RDe2K0,2801 +sse_starlette/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +sse_starlette/sse.py,sha256=M7qzZzruHeJQLoLoCTQ4f7oJXu5_XaA4RTawayI4bV0,21365 +sse_starlette-3.4.11.dist-info/licenses/AUTHORS,sha256=wv9j0uzxKLvairGyAWgwpdoSQgL7uXFoaFu5lGrtPxo,395 +sse_starlette-3.4.11.dist-info/licenses/LICENSE,sha256=gK9r_Mvr0sFNSquWaVyrmVDhdxkMyA9e-BnpmZaIPo4,1511 +sse_starlette-3.4.11.dist-info/METADATA,sha256=DSt-l025V8pKogBTkYUWpvKKhDPv9AFyhIPLsjXkg6Q,15343 +sse_starlette-3.4.11.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91 +sse_starlette-3.4.11.dist-info/top_level.txt,sha256=-WvV5NMWkq_J766sZPusKqv8pESM-Dxugi96Lp9oer4,14 +sse_starlette-3.4.11.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/WHEEL b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/WHEEL new file mode 100644 index 0000000..13013d7 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (84.0.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/AUTHORS b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/AUTHORS new file mode 100644 index 0000000..26fddfc --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/AUTHORS @@ -0,0 +1,10 @@ +sysid +synodriver +Skyler Lewis +Margret `Pax` Williams +nekonoshiri +justindujardin +Håvard Thom <34199185+havardthom@users.noreply.github.com> +Vaibhav Mule +issmirnov +Cyprien diff --git a/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/LICENSE b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/LICENSE new file mode 100644 index 0000000..3d12971 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/licenses/LICENSE @@ -0,0 +1,27 @@ +Copyright © 2020, [sysid](https://sysid.github.io/). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/top_level.txt b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/top_level.txt new file mode 100644 index 0000000..a0dde6f --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette-3.4.11.dist-info/top_level.txt @@ -0,0 +1 @@ +sse_starlette diff --git a/source/target-vendors/cp312/sse_starlette/__init__.py b/source/target-vendors/cp312/sse_starlette/__init__.py new file mode 100644 index 0000000..207a327 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette/__init__.py @@ -0,0 +1,5 @@ +from sse_starlette.event import ServerSentEvent, JSONServerSentEvent +from sse_starlette.sse import EventSourceResponse + +__all__ = ["EventSourceResponse", "ServerSentEvent", "JSONServerSentEvent"] +__version__ = "3.4.11" diff --git a/source/target-vendors/cp312/sse_starlette/_utils.py b/source/target-vendors/cp312/sse_starlette/_utils.py new file mode 100644 index 0000000..c7e03d4 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette/_utils.py @@ -0,0 +1,37 @@ +import sys +from contextlib import contextmanager +from typing import Generator + +# Divergence #3 (see sse_starlette/sse.py module docstring): vendored copy of +# starlette._utils.collapse_excgroups. We do not import the upstream version +# because it lives in a private (underscore-prefixed) Starlette module, and +# the pinned floor (starlette>=0.41.3) makes that import surface unstable. +# +# Behaviour: AnyIO v4 wraps task-group failures in an ExceptionGroup; this +# helper unwraps single-exception groups so user middleware sees the bare +# exception (matching pre-v4 anyio and Starlette's StreamingResponse). +# Solution per https://anyio.readthedocs.io/en/stable/migration.html + +has_exceptiongroups = True +if sys.version_info < (3, 11): + try: + from exceptiongroup import BaseExceptionGroup # noqa: F401 + except ImportError: + has_exceptiongroups = False + + +@contextmanager +def collapse_excgroups() -> Generator[None, None, None]: + try: + yield + except BaseException as exc: + if has_exceptiongroups: + # `ty` does not narrow BaseExceptionGroup.exceptions; the runtime + # contract is identical to starlette._utils.collapse_excgroups. + while isinstance(exc, BaseExceptionGroup) and len(exc.exceptions) == 1: # ty: ignore[unresolved-attribute] + exc = exc.exceptions[0] # ty: ignore[unresolved-attribute] + + raise exc + + +__all__ = ["collapse_excgroups"] diff --git a/source/target-vendors/cp312/sse_starlette/event.py b/source/target-vendors/cp312/sse_starlette/event.py new file mode 100644 index 0000000..d72cfd5 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette/event.py @@ -0,0 +1,96 @@ +import io +import re +import json +from typing import Optional, Any, Union + + +class ServerSentEvent: + """ + Helper class to format data for Server-Sent Events (SSE). + """ + + _LINE_SEP_EXPR = re.compile(r"\r\n|\r|\n") + DEFAULT_SEPARATOR = "\r\n" + + def __init__( + self, + data: Optional[Any] = None, + *, + event: Optional[str] = None, + id: Optional[str] = None, + retry: Optional[int] = None, + comment: Optional[str] = None, + sep: Optional[str] = None, + ) -> None: + self.data = data + self.event = event + self.id = id + self.retry = retry + self.comment = comment + self._sep = sep if sep is not None else self.DEFAULT_SEPARATOR + + def encode(self) -> bytes: + buffer = io.StringIO() + if self.comment is not None: + for chunk in self._LINE_SEP_EXPR.split(str(self.comment)): + buffer.write(f": {chunk}{self._sep}") + + if self.id is not None: + # Clean newlines in the event id + buffer.write("id: " + self._LINE_SEP_EXPR.sub("", self.id) + self._sep) + + if self.event is not None: + # Clean newlines in the event name + buffer.write( + "event: " + self._LINE_SEP_EXPR.sub("", self.event) + self._sep + ) + + if self.data is not None: + # Break multi-line data into multiple data: lines + for chunk in self._LINE_SEP_EXPR.split(str(self.data)): + buffer.write(f"data: {chunk}{self._sep}") + + if self.retry is not None: + if not isinstance(self.retry, int): + raise TypeError("retry argument must be int") + buffer.write(f"retry: {self.retry}{self._sep}") + + buffer.write(self._sep) + return buffer.getvalue().encode("utf-8") + + +class JSONServerSentEvent(ServerSentEvent): + """ + Helper class to format JSON data for Server-Sent Events (SSE). + """ + + def __init__( + self, + data: Optional[Any] = None, + *args, + **kwargs, + ) -> None: + super().__init__( + json.dumps( + data, + ensure_ascii=False, + allow_nan=False, + indent=None, + separators=(",", ":"), + ) + if data is not None + else None, + *args, + **kwargs, + ) + + +def ensure_bytes(data: Union[bytes, dict, ServerSentEvent, Any], sep: str) -> bytes: + if isinstance(data, (bytes, memoryview)): + return bytes(data) + if isinstance(data, ServerSentEvent): + return data.encode() + if isinstance(data, dict): + data["sep"] = sep + return ServerSentEvent(**data).encode() + return ServerSentEvent(str(data), sep=sep).encode() diff --git a/source/target-vendors/cp312/sse_starlette/py.typed b/source/target-vendors/cp312/sse_starlette/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/sse_starlette/sse.py b/source/target-vendors/cp312/sse_starlette/sse.py new file mode 100644 index 0000000..c096b66 --- /dev/null +++ b/source/target-vendors/cp312/sse_starlette/sse.py @@ -0,0 +1,531 @@ +"""Server-Sent Events response for Starlette / FastAPI. + +Intentional divergence from ``starlette.responses.StreamingResponse`` +-------------------------------------------------------------------- + +``EventSourceResponse`` is modelled on Starlette's ``StreamingResponse`` and +re-syncs most of its behaviour (WebSocket denial, ``collapse_excgroups()`` +around the task group, ``memoryview`` chunk handling). The following points +are deliberate divergences — DO NOT "fix" them without reading the rationale: + +1. ASGI ``spec_version >= 2.4`` fast path is NOT adopted. + Upstream short-circuits to ``await stream_response(send)`` and converts + ``OSError`` into ``ClientDisconnect``, skipping ``listen_for_disconnect``. + We keep ``_listen_for_disconnect`` running because it + (a) invokes ``client_close_handler_callable`` on disconnect, + (b) flips ``self.active = False`` so ``_ping`` and the cooperative + shutdown grace loop exit promptly. + Adopting the upstream fast path would regress both features. + +2. ``_wrap_websocket_denial_send`` is inlined in this module rather than + inherited from ``starlette.responses.Response``. The helper landed on + Starlette ``main`` after our minimum pin (``starlette>=0.41.3``); inline + until the floor moves past the release that contains it. + +3. ``collapse_excgroups()`` is vendored in ``sse_starlette._utils`` rather + than imported from ``starlette._utils`` (private module). +""" + +import asyncio +import logging +import signal +import threading +from dataclasses import dataclass, field +from datetime import datetime, timezone +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Coroutine, + Iterator, + Mapping, + Optional, + Set, + Union, +) + +import anyio +from starlette.background import BackgroundTask +from starlette.concurrency import iterate_in_threadpool +from starlette.datastructures import MutableHeaders +from starlette.responses import Response +from starlette.types import Receive, Scope, Send, Message + +from sse_starlette._utils import collapse_excgroups +from sse_starlette.event import ServerSentEvent, ensure_bytes + + +logger = logging.getLogger(__name__) + + +@dataclass +class _ShutdownState: + """Per-thread state for shutdown coordination. + + Issue #152 fix: Uses threading.local() instead of ContextVar to ensure + one watcher per thread rather than one per async context. + """ + + events: Set[anyio.Event] = field(default_factory=set) + watcher_started: bool = False + + +# Each thread gets its own shutdown state (one event loop per thread typically) +_thread_state = threading.local() + + +def _get_shutdown_state() -> _ShutdownState: + """Get or create shutdown state for the current thread.""" + state = getattr(_thread_state, "shutdown_state", None) + if state is None: + state = _ShutdownState() + _thread_state.shutdown_state = state + return state + + +def _get_uvicorn_server(): + """ + Try to get uvicorn Server instance via signal handler introspection. + + When uvicorn registers signal handlers, they're bound methods on the Server instance. + We can retrieve the Server from the handler's __self__ attribute. + + Returns None if: + - Not running under uvicorn + - Signal handler isn't a bound method + - Any introspection fails + """ + try: + handler = signal.getsignal(signal.SIGTERM) + if hasattr(handler, "__self__"): + server = handler.__self__ + if hasattr(server, "should_exit"): + return server + except Exception: + pass + return None + + +async def _shutdown_watcher() -> None: + """ + Poll for shutdown and broadcast to all events in this context. + + One watcher runs per thread (event loop). Checks two shutdown sources: + 1. AppStatus.should_exit - set when our monkey-patch works + 2. uvicorn Server.should_exit - via signal handler introspection (Issue #132 fix) + + When either becomes True, signals all registered events. + """ + state = _get_shutdown_state() + uvicorn_server = _get_uvicorn_server() + + try: + while True: + # Check our flag (monkey-patch worked or manually set) + if AppStatus.should_exit: + break + # Check uvicorn's flag directly (monkey-patch failed - Issue #132) + if ( + AppStatus.enable_automatic_graceful_drain + and uvicorn_server is not None + and uvicorn_server.should_exit + ): + AppStatus.should_exit = True # Sync state for consistency + break + await anyio.sleep(0.5) + + # Shutdown detected - broadcast to all waiting events + for event in list(state.events): + event.set() + finally: + # Allow watcher to be restarted if loop is reused + state.watcher_started = False + + +def _ensure_watcher_started_on_this_loop() -> None: + """Ensure the shutdown watcher is running for this thread (event loop).""" + state = _get_shutdown_state() + if not state.watcher_started: + state.watcher_started = True + try: + loop = asyncio.get_running_loop() + loop.create_task(_shutdown_watcher()) + except RuntimeError: + # No running loop - shouldn't happen in normal use + state.watcher_started = False + + +def _wrap_websocket_denial_send(send: Send) -> Send: + """Mirror of ``starlette.responses.Response._wrap_websocket_denial_send``. + + Divergence #2 (see module docstring): inlined because the helper landed + on Starlette ``main`` (commit 9ee9519) after our minimum pin + ``starlette>=0.41.3``. Drop this once the floor moves past the release + that contains it. + """ + + async def wrapped(message: Message) -> None: + message_type = message["type"] + if message_type in {"http.response.start", "http.response.body"}: + message = {**message, "type": "websocket." + message_type} + await send(message) + + return wrapped + + +class SendTimeoutError(TimeoutError): + pass + + +class AppStatus: + """Helper to capture a shutdown signal from Uvicorn so we can gracefully terminate SSE streams.""" + + should_exit = False + enable_automatic_graceful_drain = True + original_handler: Optional[Callable] = None + + @staticmethod + def disable_automatic_graceful_drain(): + """ + Prevent automatic SSE stream termination on server shutdown. + + WARNING: When disabled, you MUST set AppStatus.should_exit = True + at some point during shutdown, or streams will never close and the + server will hang indefinitely (or until uvicorn's graceful shutdown + timeout expires). + """ + AppStatus.enable_automatic_graceful_drain = False + + @staticmethod + def enable_automatic_graceful_drain_mode(): + """ + Re-enable automatic SSE stream termination on server shutdown. + + This restores the default behavior where SIGTERM triggers immediate + stream draining. Call this to undo a previous call to + disable_automatic_graceful_drain(). + """ + AppStatus.enable_automatic_graceful_drain = True + + @staticmethod + def handle_exit(*args, **kwargs): + if AppStatus.enable_automatic_graceful_drain: + AppStatus.should_exit = True + if AppStatus.original_handler is not None: + AppStatus.original_handler(*args, **kwargs) + + +try: + from uvicorn.main import Server + + AppStatus.original_handler = Server.handle_exit + Server.handle_exit = AppStatus.handle_exit # type: ignore +except ImportError: + logger.debug( + "Uvicorn not installed. Graceful shutdown on server termination disabled." + ) + +Content = Union[str, bytes, dict, ServerSentEvent, Any] +SyncContentStream = Iterator[Content] +AsyncContentStream = AsyncIterable[Content] +ContentStream = Union[AsyncContentStream, SyncContentStream] + + +class EventSourceResponse(Response): + """Streaming response implementing the SSE (Server-Sent Events) specification. + + Args: + content: Async iterable or sync iterator yielding SSE event data. + status_code: HTTP status code. Default: 200. + headers: Additional HTTP headers. + media_type: Response media type. Default: "text/event-stream". + background: Background task to run after response completes. + ping: Ping interval in seconds. Default: 15. Set to 0 to disable + keep-alive pings entirely (no ping task is started). + sep: Line separator for SSE messages ("\\r\\n", "\\r", or "\\n"). + ping_message_factory: Callable returning custom ping ServerSentEvent. + data_sender_callable: Async callable for push-based data sending. + send_timeout: Timeout in seconds for individual data or heartbeat sends. + client_close_handler_callable: Async callback on client disconnect. + shutdown_event: Optional ``anyio.Event`` set by the library when server + shutdown is detected. Generators can watch this event to send farewell + messages and exit cooperatively instead of receiving CancelledError. + shutdown_grace_period: Seconds to wait after setting ``shutdown_event`` + before force-cancelling the generator. Must be >= 0. Should be less + than your ASGI server's graceful shutdown timeout. Default: 0 + (immediate cancel, identical to pre-v3.3.0 behavior). + """ + + DEFAULT_PING_INTERVAL = 15 + DEFAULT_SEPARATOR = "\r\n" + + def __init__( + self, + content: ContentStream, + status_code: int = 200, + headers: Optional[Mapping[str, str]] = None, + media_type: str = "text/event-stream", + background: Optional[BackgroundTask] = None, + ping: Optional[Union[int, float]] = None, + sep: Optional[str] = None, + ping_message_factory: Optional[Callable[[], ServerSentEvent]] = None, + data_sender_callable: Optional[ + Callable[[], Coroutine[None, None, None]] + ] = None, + send_timeout: Optional[float] = None, + client_close_handler_callable: Optional[ + Callable[[Message], Awaitable[None]] + ] = None, + shutdown_event: Optional[anyio.Event] = None, + shutdown_grace_period: float = 0, + ) -> None: + # Validate separator + if sep not in (None, "\r\n", "\r", "\n"): + raise ValueError(f"sep must be one of: \\r\\n, \\r, \\n, got: {sep}") + self.sep = sep or self.DEFAULT_SEPARATOR + + # If content is sync, wrap it for async iteration + if isinstance(content, AsyncIterable): + self.body_iterator = content + else: + self.body_iterator = iterate_in_threadpool(content) + + self.status_code = status_code + self.media_type = self.media_type if media_type is None else media_type + self.background = background + self.data_sender_callable = data_sender_callable + self.send_timeout = send_timeout + + # Build SSE-specific headers. + _headers = MutableHeaders() + if headers is not None: # pragma: no cover + _headers.update(headers) + + # "The no-store response directive indicates that any caches of any kind (private or shared) + # should not store this response." + # -- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + # allow cache control header to be set by user to support fan out proxies + # https://www.fastly.com/blog/server-sent-events-fastly + + _headers.setdefault("Cache-Control", "no-store") + # mandatory for servers-sent events headers + _headers["Connection"] = "keep-alive" + _headers["X-Accel-Buffering"] = "no" + self.init_headers(_headers) + + self.ping_interval = self.DEFAULT_PING_INTERVAL if ping is None else ping + self.ping_message_factory = ping_message_factory + + self.client_close_handler_callable = client_close_handler_callable + + # Cooperative shutdown (Issue #167): Allow generators to send farewell + # events before force-cancellation. The grace period should be less than + # your ASGI server's graceful shutdown timeout (e.g. uvicorn's + # --timeout-graceful-shutdown), otherwise the process is killed before + # the grace period expires. + if shutdown_grace_period < 0: + raise ValueError("shutdown_grace_period must be >= 0") + self._shutdown_event = shutdown_event + self._shutdown_grace_period = shutdown_grace_period + + self.active = True + # https://github.com/sysid/sse-starlette/pull/55#issuecomment-1732374113 + self._send_lock = anyio.Lock() + + @property + def ping_interval(self) -> Union[int, float]: + return self._ping_interval + + @ping_interval.setter + def ping_interval(self, value: Union[int, float]) -> None: + if not isinstance(value, (int, float)): + raise TypeError("ping interval must be int or float") + if value < 0: + raise ValueError("ping interval must be >= 0 (0 disables ping)") + self._ping_interval = value + + def enable_compression(self, force: bool = False) -> None: + raise NotImplementedError("Compression is not supported for SSE streams.") + + async def _send_with_timeout(self, send: Send, message: Message) -> None: + """Send one ASGI message, applying the response's per-send timeout.""" + with anyio.move_on_after(self.send_timeout) as cancel_scope: + await send(message) + + if cancel_scope and cancel_scope.cancel_called: + raise SendTimeoutError() + + async def _stream_response(self, send: Send) -> None: + """Send out SSE data to the client as it becomes available in the iterator.""" + await send( + { + "type": "http.response.start", + "status": self.status_code, + "headers": self.raw_headers, + } + ) + + async for data in self.body_iterator: + chunk = ensure_bytes(data, self.sep) + logger.debug("chunk: %s", chunk) + try: + await self._send_with_timeout( + send, + {"type": "http.response.body", "body": chunk, "more_body": True}, + ) + except SendTimeoutError: + aclose = getattr(self.body_iterator, "aclose", None) + if aclose is not None: + await aclose() + raise + + async with self._send_lock: + self.active = False + await send({"type": "http.response.body", "body": b"", "more_body": False}) + + async def _listen_for_disconnect(self, receive: Receive) -> None: + """Watch for a disconnect message from the client. + + Divergence #1 (see module docstring): kept unconditionally instead of + adopting Starlette's ASGI 2.4 ``OSError → ClientDisconnect`` fast path, + because this loop drives ``client_close_handler_callable`` and flips + ``self.active = False`` for ``_ping`` and the shutdown grace loop. + """ + while self.active: + message = await receive() + if message["type"] == "http.disconnect": + self.active = False + logger.debug("Got event: http.disconnect. Stop streaming.") + if self.client_close_handler_callable: + await self.client_close_handler_callable(message) + break + + @staticmethod + async def _listen_for_exit_signal() -> None: + """Wait for shutdown signal via the shared watcher.""" + if AppStatus.should_exit: + return + + _ensure_watcher_started_on_this_loop() + + state = _get_shutdown_state() + event = anyio.Event() + state.events.add(event) + + try: + # Double-check after registration + if AppStatus.should_exit: + return + await event.wait() + finally: + state.events.discard(event) + + async def _listen_for_exit_signal_with_grace(self) -> None: + """Wait for shutdown signal, then optionally give generator a grace period. + + Issue #167: When a shutdown_event is provided, the library sets it before + returning, giving the generator a chance to send farewell events and exit + cooperatively. The shutdown_grace_period controls how long to wait before + force-cancelling via task group cancellation. + """ + await self._listen_for_exit_signal() + + # Signal the user's generator that shutdown is happening + if self._shutdown_event: + self._shutdown_event.set() + + # Grace period: let generator finish naturally before force-cancel + if self._shutdown_grace_period > 0: + with anyio.move_on_after(self._shutdown_grace_period): + while self.active: + await anyio.sleep(0.1) + + async def _ping(self, send: Send) -> None: + """Periodically send ping messages to keep the connection alive on proxies. + - frequency ca every 15 seconds. + - Alternatively one can send periodically a comment line (one starting with a ':' character) + + Invariant (Issue #206): must NOT be started when ``ping_interval == 0`` + (ping disabled), because ``anyio.sleep(0)`` is a bare checkpoint and the + loop would busy-spin, flooding the client with pings and contending for + ``_send_lock`` with the data stream. ``__call__`` skips the task instead + of returning early here, since ``_ping`` runs under ``cancel_on_finish`` + and any return would tear down the whole response. + """ + while self.active: + await anyio.sleep(self._ping_interval) + sse_ping = ( + self.ping_message_factory() + if self.ping_message_factory + else ServerSentEvent( + comment=f"ping - {datetime.now(timezone.utc)}", sep=self.sep + ) + ) + ping_bytes = ensure_bytes(sse_ping, self.sep) + logger.debug("ping: %s", ping_bytes) + + async with self._send_lock: + if self.active: + # A SendTimeoutError raised here deliberately does NOT + # aclose() the body iterator, unlike _stream_response. When a + # heartbeat times out, _stream_response is normally suspended + # inside body_iterator.__anext__(), where ag_running_async is + # set, so aclose() would raise "RuntimeError: aclose(): + # asynchronous generator is already running" (verified). + # Propagating instead lets the task group cancel + # _stream_response, which throws into the suspended + # __anext__ and runs the generator's finally block -- see + # test_ping_whenSendTimesOut_thenTearsDownResponseAndRunsCleanup. + await self._send_with_timeout( + send, + { + "type": "http.response.body", + "body": ping_bytes, + "more_body": True, + }, + ) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + """Entrypoint for Starlette's ASGI contract. We spin up tasks: + - _stream_response to push events + - _ping to keep the connection alive + - _listen_for_exit_signal to respond to server shutdown + - _listen_for_disconnect to respond to client disconnect + """ + # WebSocket denial parity with Starlette's StreamingResponse: a + # streaming response on a websocket scope must wrap send so message + # types become ``websocket.http.response.*``. + if scope["type"] == "websocket": + send = _wrap_websocket_denial_send(send) + + # collapse_excgroups parity with Starlette's StreamingResponse: anyio + # v4 wraps task-group failures in ExceptionGroup; user middleware + # expects the bare exception. + with collapse_excgroups(): + async with anyio.create_task_group() as task_group: + # https://trio.readthedocs.io/en/latest/reference-core.html#custom-supervisors + async def cancel_on_finish(coro: Callable[[], Awaitable[None]]): + await coro() + task_group.cancel_scope.cancel() + + task_group.start_soon( + cancel_on_finish, lambda: self._stream_response(send) + ) + # ping_interval == 0 disables keep-alive pings entirely (#206) + if self._ping_interval > 0: + task_group.start_soon(cancel_on_finish, lambda: self._ping(send)) + task_group.start_soon( + cancel_on_finish, self._listen_for_exit_signal_with_grace + ) + + if self.data_sender_callable: + task_group.start_soon(self.data_sender_callable) + + # Wait for the client to disconnect last + task_group.start_soon( + cancel_on_finish, lambda: self._listen_for_disconnect(receive) + ) + + if self.background is not None: + await self.background() diff --git a/source/target-vendors/cp312/starlette-1.7.0.dist-info/METADATA b/source/target-vendors/cp312/starlette-1.7.0.dist-info/METADATA new file mode 100644 index 0000000..714e2cf --- /dev/null +++ b/source/target-vendors/cp312/starlette-1.7.0.dist-info/METADATA @@ -0,0 +1,182 @@ +Metadata-Version: 2.5 +Name: starlette +Version: 1.7.0 +Summary: The little ASGI library that shines. +Project-URL: Homepage, https://github.com/Kludex/starlette +Project-URL: Documentation, https://starlette.dev/ +Project-URL: Changelog, https://starlette.dev/release-notes/ +Project-URL: Funding, https://github.com/sponsors/Kludex +Project-URL: Source, https://github.com/Kludex/starlette +Author-email: Tom Christie +Maintainer-email: Marcelo Trylesinski +License-Expression: BSD-3-Clause +License-File: LICENSE.md +Classifier: Development Status :: 3 - Alpha +Classifier: Environment :: Web Environment +Classifier: Framework :: AnyIO +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.10 +Requires-Dist: anyio<5,>=4.0.0 +Requires-Dist: typing-extensions>=4.10.0; python_version < '3.13' +Provides-Extra: full +Requires-Dist: httpx2>=2.0.0; extra == 'full' +Requires-Dist: httpx<0.29.0,>=0.27.0; extra == 'full' +Requires-Dist: itsdangerous; extra == 'full' +Requires-Dist: jinja2; extra == 'full' +Requires-Dist: opentelemetry-api; extra == 'full' +Requires-Dist: python-multipart>=0.0.18; extra == 'full' +Requires-Dist: pyyaml; extra == 'full' +Description-Content-Type: text/markdown + +

      + + + + starlette-logo + +

      + +

      + ✨ The little ASGI framework that shines. ✨ +

      + +--- + +[![Build Status](https://github.com/Kludex/starlette/workflows/Test%20Suite/badge.svg)](https://github.com/Kludex/starlette/actions) +[![Package version](https://badge.fury.io/py/starlette.svg)](https://pypi.python.org/pypi/starlette) +[![Supported Python Version](https://img.shields.io/pypi/pyversions/starlette.svg?color=%2334D058)](https://pypi.org/project/starlette) +[![Discord](https://img.shields.io/discord/1051468649518616576?logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/RxKUF5JuHs) + +--- + +**Documentation**:
      https://starlette.dev + +**Source Code**: https://github.com/Kludex/starlette + +--- + +# Starlette + +Starlette is a lightweight [ASGI][asgi] framework/toolkit, +which is ideal for building async web services in Python. + +It is production-ready, and gives you the following: + +* A lightweight, low-complexity HTTP web framework. +* WebSocket support. +* In-process background tasks. +* Startup and shutdown events. +* Test client built on `httpx2`. +* CORS, GZip, Static Files, Streaming responses. +* Session and Cookie support. +* 100% test coverage. +* 100% type annotated codebase. +* Few hard dependencies. +* Compatible with `asyncio` and `trio` backends. +* Great overall performance [against independent benchmarks][techempower]. + +## Installation + +```shell +$ pip install starlette +``` + +You'll also want to install an ASGI server, such as [uvicorn](https://uvicorn.dev) or any of the [other ASGI server implementations](https://asgi.readthedocs.io/en/latest/implementations.html#servers). + +```shell +$ pip install uvicorn +``` + +## Example + +```python title="main.py" +from starlette.applications import Starlette +from starlette.responses import JSONResponse +from starlette.routing import Route + + +async def homepage(request): + return JSONResponse({'hello': 'world'}) + +routes = [ + Route("/", endpoint=homepage) +] + +app = Starlette(debug=True, routes=routes) +``` + +Then run the application using Uvicorn: + +```shell +$ uvicorn main:app +``` + +## Dependencies + +Starlette only requires `anyio`, and the following are optional: + +* [`httpx2`][httpx2] - Required if you want to use the `TestClient`. +* [`jinja2`][jinja2] - Required if you want to use `Jinja2Templates`. +* [`opentelemetry-api`][opentelemetry-api] - Required for `OpenTelemetryMiddleware`. +* [`python-multipart`][python-multipart] - Required if you want to support form parsing, with `request.form()`. +* [`itsdangerous`][itsdangerous] - Required for `SessionMiddleware` support. +* [`pyyaml`][pyyaml] - Required for `SchemaGenerator` support. + +You can install all of these with `pip install starlette[full]`. + +## Framework or Toolkit + +Starlette is designed to be used either as a complete framework, or as +an ASGI toolkit. You can use any of its components independently. + +```python +from starlette.responses import PlainTextResponse + + +async def app(scope, receive, send): + assert scope['type'] == 'http' + response = PlainTextResponse('Hello, world!') + await response(scope, receive, send) +``` + +Run the `app` application in `example.py`: + +```shell +$ uvicorn example:app +INFO: Started server process [11509] +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +Run uvicorn with `--reload` to enable auto-reloading on code changes. + +## Modularity + +The modularity that Starlette is designed on promotes building reusable +components that can be shared between any ASGI framework. This should enable +an ecosystem of shared middleware and mountable applications. + +The clean API separation also means it's easier to understand each component +in isolation. + +--- + +

      Starlette is BSD licensed code.
      Designed & crafted with care.

      — ⭐️ —

      + +[asgi]: https://asgi.readthedocs.io/en/latest/ +[httpx2]: https://pypi.org/project/httpx2/ +[jinja2]: https://jinja.palletsprojects.com/ +[opentelemetry-api]: https://opentelemetry.io/docs/languages/python/api/ +[python-multipart]: https://multipart.fastapiexpert.com/ +[itsdangerous]: https://itsdangerous.palletsprojects.com/ +[sqlalchemy]: https://www.sqlalchemy.org +[pyyaml]: https://pyyaml.org/wiki/PyYAMLDocumentation +[techempower]: https://github.com/TechEmpower/FrameworkBenchmarks diff --git a/source/target-vendors/cp312/starlette-1.7.0.dist-info/RECORD b/source/target-vendors/cp312/starlette-1.7.0.dist-info/RECORD new file mode 100644 index 0000000..06c5375 --- /dev/null +++ b/source/target-vendors/cp312/starlette-1.7.0.dist-info/RECORD @@ -0,0 +1,41 @@ +starlette/__init__.py,sha256=lEEx5lwinUby-YNl7w-VFGUcjcibsJ9EuzgJ2W7ocrU,22 +starlette/_exception_handler.py,sha256=8Vm915fWYe9xLo_za5iQ5WyrAvFBu2kEEJc7XreTyOk,2257 +starlette/_utils.py,sha256=NTNRqxu24V4GwVq5gnhQ0oFBlRnrjbywbKahzeiwrw0,4211 +starlette/applications.py,sha256=gYh-C6992lgRukt6Z-Scu6t66XsyG6cuR1x5f5iWkOk,5763 +starlette/authentication.py,sha256=rJx0wvk1xsVifLsyiHV6P_b3oAherBRXW6QkXKw3APM,5341 +starlette/background.py,sha256=D-XpUpFRgUBnZeA1tHgzMOgube6ICVZFlOA4ML0q1T8,1122 +starlette/concurrency.py,sha256=Pp4kXQYO85cWxY7XVNt5lcYvhYHUquyLguCec7hKKoM,1701 +starlette/config.py,sha256=GVwko0pGSusxuQHO35tL_Nt_ApL0fmVYL3IiHHYpLW4,4426 +starlette/convertors.py,sha256=F1rse3AacN9rsfJnTeuDnjbN51r_ouHc3WLyYkjkX_o,2304 +starlette/datastructures.py,sha256=NdxfT1u9a-NIoFGoz257evM14p1sq__46iMp9Xo_-60,23200 +starlette/endpoints.py,sha256=KI-tMTdlqi4rU1eR9hnOptdyGFxc_T1adwOKIgeOBm0,5304 +starlette/exceptions.py,sha256=-0sNmNNLa46g9V6xpsqOqqPwDRJMoe4vEqDAbCVQJTU,1492 +starlette/formparsers.py,sha256=rdPatCDCwT8yj1mDeFOAHknV7O4x3wU0cCZs4GbVaOI,12374 +starlette/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +starlette/requests.py,sha256=hpGwGuSez6CF_mQZNDZ49zt3yS_GOkERBqd9jpvwrEQ,12708 +starlette/responses.py,sha256=5Ypb6Ud-MLloC7Jw4PGw_G4lKuG6ZXZecNOUZzLTJ_c,22090 +starlette/routing.py,sha256=FSFciPQYfJjPSY51exiMDgb76A2V94t2MMTlH5JhGvQ,30472 +starlette/schemas.py,sha256=e9KnCHN1KBV9F8Ml54wC55ItHE5LES5WWXLVEYUgot0,5494 +starlette/staticfiles.py,sha256=UP3kCtjzAs1ZsdluuP7NLEq55ER_FI65LMfKVbrsMBg,9071 +starlette/status.py,sha256=XYcVn-aU522TYJ8BJxl0WUnf6J_3yBTQz7Tqgye8KO4,6430 +starlette/templating.py,sha256=y-ATlQrNDoLMZs5hrHzQBTapECBDr9wAl-bs8Blk5jw,5447 +starlette/testclient.py,sha256=noWneuuRPAkTsqnel3rmF1VOzQimReyJvKLggJ__dhs,21597 +starlette/types.py,sha256=87wTuwF1036QxRse3mL5qOuS9i4a9xaIZMqTjY-lvvo,1041 +starlette/websockets.py,sha256=mflI9LUwlf93_uujI8w-tY-noS-zdREbzaUmeOVDP9c,8518 +starlette/middleware/__init__.py,sha256=BORnOj0n0mL1OWUUs1PLTu1SASmvT8kEEDA6cbuhuPo,1349 +starlette/middleware/authentication.py,sha256=-RSwwJ0pIkrM0v-2Ip8HXVB24xtSp7ObzR3OfTC8wSA,1800 +starlette/middleware/base.py,sha256=5Od_lmyCvfI0jsEDWiQTiHy9DEbAb3tKAPedJ24tils,10500 +starlette/middleware/body_limit.py,sha256=L12EvFC-9ryO_A_2ngdDpt6WaVkwhAtqiuJPhyhqyA8,4609 +starlette/middleware/cors.py,sha256=_OnWebUt2WcPOCFtqs3KsVnGmVzbUlbuUWLcWNJaXE8,7688 +starlette/middleware/errors.py,sha256=E14AZhjybcfRH72ByiaQ7Mdt0AwnYZqiv6zGtC0F0xM,8126 +starlette/middleware/exceptions.py,sha256=7OgSUiBgwHS4VMmpaWlw21uDKNDmOMzLVZrWDLDUqWo,2784 +starlette/middleware/gzip.py,sha256=7ijfBszT4h6syblkcd89ple43WqYBgH-hCycsKuWtms,8805 +starlette/middleware/httpsredirect.py,sha256=fogRKypMx3gKzoHgJpKPIITGdKxFdUCEAqskRHndZBQ,1023 +starlette/middleware/opentelemetry.py,sha256=lAP3BYvOjunvnPBK9GcQaZR7MF6wVmYLbpc75-54hwI,5719 +starlette/middleware/sessions.py,sha256=8YpoNTO02-KWaUvtJdNe7lKExKxYuZD-hIRC3TdtBf4,5175 +starlette/middleware/trustedhost.py,sha256=WkeCKP_loVg5IBpjjMyoWXEnS0URQmon8Iee-dTz46U,2456 +starlette/middleware/wsgi.py,sha256=8_xjdUNjA-DcWY0owaqyiZlGcvml4UMIB18rGxtdNvg,5536 +starlette-1.7.0.dist-info/METADATA,sha256=94cPwZq3wuNkiHBXNAuftH6b2nTSSwbFjKOZSUq_4Bk,6610 +starlette-1.7.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87 +starlette-1.7.0.dist-info/licenses/LICENSE.md,sha256=3LlWd6AiQCQxh-lk-UGEfRmxeCHPmeWvrmhPqzKMGb8,1518 +starlette-1.7.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/starlette-1.7.0.dist-info/WHEEL b/source/target-vendors/cp312/starlette-1.7.0.dist-info/WHEEL new file mode 100644 index 0000000..51abe1f --- /dev/null +++ b/source/target-vendors/cp312/starlette-1.7.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.32.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/starlette-1.7.0.dist-info/licenses/LICENSE.md b/source/target-vendors/cp312/starlette-1.7.0.dist-info/licenses/LICENSE.md new file mode 100644 index 0000000..d16a60e --- /dev/null +++ b/source/target-vendors/cp312/starlette-1.7.0.dist-info/licenses/LICENSE.md @@ -0,0 +1,27 @@ +Copyright © 2018, [Encode OSS Ltd](https://www.encode.io/). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/starlette/__init__.py b/source/target-vendors/cp312/starlette/__init__.py new file mode 100644 index 0000000..14d9d2f --- /dev/null +++ b/source/target-vendors/cp312/starlette/__init__.py @@ -0,0 +1 @@ +__version__ = "1.7.0" diff --git a/source/target-vendors/cp312/starlette/_exception_handler.py b/source/target-vendors/cp312/starlette/_exception_handler.py new file mode 100644 index 0000000..9491f8b --- /dev/null +++ b/source/target-vendors/cp312/starlette/_exception_handler.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +from typing import Any + +from starlette._utils import is_async_callable +from starlette.concurrency import run_in_threadpool +from starlette.exceptions import HTTPException +from starlette.requests import Request +from starlette.types import ASGIApp, ExceptionHandler, Message, Receive, Scope, Send +from starlette.websockets import WebSocket + +ExceptionHandlers = dict[Any, ExceptionHandler] +StatusHandlers = dict[int, ExceptionHandler] + + +def _lookup_exception_handler(exc_handlers: ExceptionHandlers, exc: Exception) -> ExceptionHandler | None: + for cls in type(exc).__mro__: + if cls in exc_handlers: + return exc_handlers[cls] + return None + + +def wrap_app_handling_exceptions(app: ASGIApp, conn: Request | WebSocket) -> ASGIApp: + exception_handlers: ExceptionHandlers + status_handlers: StatusHandlers + try: + exception_handlers, status_handlers = conn.scope["starlette.exception_handlers"] + except KeyError: + exception_handlers, status_handlers = {}, {} + + async def wrapped_app(scope: Scope, receive: Receive, send: Send) -> None: + response_started = False + + async def sender(message: Message) -> None: + nonlocal response_started + + if message["type"] == "http.response.start": + response_started = True + await send(message) + + try: + await app(scope, receive, sender) + except Exception as exc: + handler = None + + if isinstance(exc, HTTPException): + handler = status_handlers.get(exc.status_code) + + if handler is None: + handler = _lookup_exception_handler(exception_handlers, exc) + + if handler is None: + raise exc + + if response_started: + raise RuntimeError("Caught handled exception, but response already started.") from exc + + if is_async_callable(handler): + response = await handler(conn, exc) # type: ignore[arg-type] + else: + response = await run_in_threadpool(handler, conn, exc) # type: ignore[arg-type] + if response is not None: + await response(scope, receive, sender) + + return wrapped_app diff --git a/source/target-vendors/cp312/starlette/_utils.py b/source/target-vendors/cp312/starlette/_utils.py new file mode 100644 index 0000000..21bc95a --- /dev/null +++ b/source/target-vendors/cp312/starlette/_utils.py @@ -0,0 +1,155 @@ +from __future__ import annotations + +import functools +import re +import sys +from collections.abc import AsyncGenerator, Awaitable, Callable, Generator +from contextlib import AbstractAsyncContextManager, asynccontextmanager +from dataclasses import dataclass +from ipaddress import AddressValueError, IPv6Address +from typing import Any, Generic, Protocol, TypeVar, overload + +import anyio.abc + +from starlette.types import Scope + +if sys.version_info >= (3, 13): # pragma: no cover + from inspect import iscoroutinefunction + from typing import TypeIs +else: # pragma: no cover + from asyncio import iscoroutinefunction + + from typing_extensions import TypeIs + +if sys.version_info < (3, 11): # pragma: no cover + from exceptiongroup import BaseExceptionGroup + + +T = TypeVar("T") +AwaitableCallable = Callable[..., Awaitable[T]] + +# Reject characters that could make a Host header change the URL path or authority. +_HOST_RE = re.compile( + r"^(?P[a-z0-9._~%!$&'()*+,;=-]+|\[(?:(?P[a-f0-9]*:[a-f0-9.:]+)|" + r"(?-i:v)[a-f0-9]+\.[a-z0-9._~!$&'()*+,;=:-]+)\])(?::(?P[0-9]+))?$", + re.IGNORECASE, +) + + +@dataclass(frozen=True, slots=True) +class ParsedHost: + host: str + port: str | None + + @property + def authority(self) -> str: + return self.host if self.port is None else f"{self.host}:{self.port}" + + @property + def is_valid_port(self) -> bool: + if self.port is None: + return True + port = self.port.lstrip("0") + return len(port) <= 5 and int(port or "0") <= 65535 + + +@overload +def is_async_callable(obj: AwaitableCallable[T]) -> TypeIs[AwaitableCallable[T]]: ... + + +@overload +def is_async_callable(obj: Any) -> TypeIs[AwaitableCallable[Any]]: ... + + +def is_async_callable(obj: Any) -> Any: + while isinstance(obj, functools.partial): + obj = obj.func + + return iscoroutinefunction(obj) or (callable(obj) and iscoroutinefunction(obj.__call__)) + + +T_co = TypeVar("T_co", covariant=True) + + +class AwaitableOrContextManager( + Awaitable[T_co], AbstractAsyncContextManager[T_co], Protocol[T_co] +): ... # pragma: no branch + + +class SupportsAsyncClose(Protocol): + async def close(self) -> None: ... # pragma: no cover + + +SupportsAsyncCloseType = TypeVar("SupportsAsyncCloseType", bound=SupportsAsyncClose, covariant=False) + + +class AwaitableOrContextManagerWrapper(Generic[SupportsAsyncCloseType]): + __slots__ = ("aw", "entered") + + def __init__(self, aw: Awaitable[SupportsAsyncCloseType]) -> None: + self.aw = aw + + def __await__(self) -> Generator[Any, None, SupportsAsyncCloseType]: + return self.aw.__await__() + + async def __aenter__(self) -> SupportsAsyncCloseType: + self.entered = await self.aw + return self.entered + + async def __aexit__(self, *args: Any) -> None | bool: + await self.entered.close() + return None + + +@asynccontextmanager +async def create_collapsing_task_group() -> AsyncGenerator[anyio.abc.TaskGroup, None]: + try: + async with anyio.create_task_group() as tg: + yield tg + except BaseExceptionGroup as excs: + if len(excs.exceptions) != 1: + raise + + exc = excs.exceptions[0] + context = None if exc.__suppress_context__ else exc.__context__ + raise exc from exc.__cause__ or context + + +def parse_host_header(host_header: str | None) -> ParsedHost | None: + """Parse `host_header` into its host and port components. + + The host preserves brackets around IP literals. Invalid headers produce `None`. + """ + if host_header is None: + return None + + match = _HOST_RE.fullmatch(host_header) + if match is None: + return None + + ipv6 = match["ipv6"] + if ipv6 is not None: + try: + IPv6Address(ipv6) + except AddressValueError: + return None + + return ParsedHost(match["host"], match["port"]) + + +def get_route_path(scope: Scope) -> str: + path: str = scope["path"] + root_path = scope.get("root_path", "") + if not root_path: + return path + + if not path.startswith(root_path): + return path + + if path == root_path: + return "" + + if path[len(root_path)] == "/": + return path[len(root_path) :] + + return path diff --git a/source/target-vendors/cp312/starlette/applications.py b/source/target-vendors/cp312/starlette/applications.py new file mode 100644 index 0000000..a28cde4 --- /dev/null +++ b/source/target-vendors/cp312/starlette/applications.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +from collections.abc import Awaitable, Callable, Mapping, Sequence +from typing import Any, ParamSpec, TypeVar + +from starlette.datastructures import State, URLPath +from starlette.middleware import Middleware, _MiddlewareFactory +from starlette.middleware.body_limit import RequestBodyLimitMiddleware +from starlette.middleware.errors import ServerErrorMiddleware +from starlette.middleware.exceptions import ExceptionMiddleware +from starlette.requests import Request +from starlette.responses import Response +from starlette.routing import BaseRoute, Router +from starlette.types import ASGIApp, ExceptionHandler, Lifespan, Receive, Scope, Send + +AppType = TypeVar("AppType", bound="Starlette") +P = ParamSpec("P") + + +class Starlette: + """Creates a Starlette application.""" + + def __init__( + self: AppType, + debug: bool = False, + routes: Sequence[BaseRoute] | None = None, + middleware: Sequence[Middleware] | None = None, + exception_handlers: Mapping[Any, ExceptionHandler] | None = None, + lifespan: Lifespan[AppType] | None = None, + *, + max_body_size: int | None = None, + ) -> None: + """Initializes the application. + + Parameters: + debug: Boolean indicating if debug tracebacks should be returned on errors. + routes: A list of routes to serve incoming HTTP and WebSocket requests. + middleware: A list of middleware to run for every request. A starlette + application will always automatically include two middleware classes. + `ServerErrorMiddleware` is added as the very outermost middleware, to handle + any uncaught errors occurring anywhere in the entire stack. + `ExceptionMiddleware` is added as the very innermost middleware, to deal + with handled exception cases occurring in the routing or endpoints. + exception_handlers: A mapping of either integer status codes, + or exception class types onto callables which handle the exceptions. + Exception handler callables should be of the form + `handler(request, exc) -> response` and may be either standard functions, or + async functions. + lifespan: A lifespan context function, which can be used to perform + startup and shutdown tasks. This is a newer style that replaces the + `on_startup` and `on_shutdown` handlers. Use one or the other, not both. + max_body_size: Non-negative maximum total size in bytes of an HTTP request + body. The default, `None`, does not limit request body size. + """ + self.debug = debug + self.state = State() + self.router = Router(routes, lifespan=lifespan) + self.max_body_size = max_body_size + self.exception_handlers = {} if exception_handlers is None else dict(exception_handlers) + self.user_middleware = [] if middleware is None else list(middleware) + self.middleware_stack: ASGIApp | None = None + + def build_middleware_stack(self) -> ASGIApp: + debug = self.debug + error_handler = None + exception_handlers: dict[Any, ExceptionHandler] = {} + + for key, value in self.exception_handlers.items(): + if key in (500, Exception): + error_handler = value + else: + exception_handlers[key] = value + + middleware = [Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)] + if self.max_body_size is not None: + middleware.append(Middleware(RequestBodyLimitMiddleware, max_body_size=self.max_body_size)) + middleware += self.user_middleware + middleware.append(Middleware(ExceptionMiddleware, handlers=exception_handlers, debug=debug)) + + app = self.router + for cls, args, kwargs in reversed(middleware): + app = cls(app, *args, **kwargs) + return app + + @property + def routes(self) -> list[BaseRoute]: + return self.router.routes + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + return self.router.url_path_for(name, **path_params) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + scope["app"] = self + if self.middleware_stack is None: + self.middleware_stack = self.build_middleware_stack() + await self.middleware_stack(scope, receive, send) + + def mount(self, path: str, app: ASGIApp, name: str | None = None) -> None: + self.router.mount(path, app=app, name=name) # pragma: no cover + + def host(self, host: str, app: ASGIApp, name: str | None = None) -> None: + self.router.host(host, app=app, name=name) # pragma: no cover + + def add_middleware(self, middleware_class: _MiddlewareFactory[P], *args: P.args, **kwargs: P.kwargs) -> None: + if self.middleware_stack is not None: # pragma: no cover + raise RuntimeError("Cannot add middleware after an application has started") + self.user_middleware.insert(0, Middleware(middleware_class, *args, **kwargs)) + + def add_exception_handler( + self, + exc_class_or_status_code: int | type[Exception], + handler: ExceptionHandler, + ) -> None: # pragma: no cover + self.exception_handlers[exc_class_or_status_code] = handler + + def add_route( + self, + path: str, + route: Callable[[Request], Awaitable[Response] | Response], + methods: list[str] | None = None, + name: str | None = None, + include_in_schema: bool = True, + ) -> None: # pragma: no cover + self.router.add_route(path, route, methods=methods, name=name, include_in_schema=include_in_schema) diff --git a/source/target-vendors/cp312/starlette/authentication.py b/source/target-vendors/cp312/starlette/authentication.py new file mode 100644 index 0000000..317ef01 --- /dev/null +++ b/source/target-vendors/cp312/starlette/authentication.py @@ -0,0 +1,157 @@ +from __future__ import annotations + +import functools +import inspect +from collections.abc import Callable, Sequence +from typing import Any, ParamSpec +from urllib.parse import urlencode + +from starlette._utils import is_async_callable +from starlette.exceptions import HTTPException +from starlette.requests import HTTPConnection, Request +from starlette.responses import RedirectResponse +from starlette.websockets import WebSocket + +_P = ParamSpec("_P") + + +def has_required_scope(conn: HTTPConnection, scopes: Sequence[str]) -> bool: + for scope in scopes: + if scope not in conn.auth.scopes: + return False + return True + + +def requires( + scopes: str | Sequence[str], + status_code: int = 403, + redirect: str | None = None, +) -> Callable[[Callable[_P, Any]], Callable[_P, Any]]: + scopes_list = [scopes] if isinstance(scopes, str) else list(scopes) + + def decorator( + func: Callable[_P, Any], + ) -> Callable[_P, Any]: + sig = inspect.signature(func) + for idx, parameter in enumerate(sig.parameters.values()): + if parameter.name == "request" or parameter.name == "websocket": + type_ = parameter.name + break + else: + raise Exception(f'No "request" or "websocket" argument on function "{func}"') + + if type_ == "websocket": + # Handle websocket functions. (Always async) + @functools.wraps(func) + async def websocket_wrapper(*args: _P.args, **kwargs: _P.kwargs) -> None: + websocket = kwargs.get("websocket", args[idx] if idx < len(args) else None) + assert isinstance(websocket, WebSocket), ( + "Parameter with name 'websocket' is required to be of type 'WebSocket'" + f" not '{type(websocket).__name__}'" + ) + + if not has_required_scope(websocket, scopes_list): + await websocket.close() + else: + await func(*args, **kwargs) + + return websocket_wrapper + + elif is_async_callable(func): + # Handle async request/response functions. + @functools.wraps(func) + async def async_wrapper(*args: _P.args, **kwargs: _P.kwargs) -> Any: + request = kwargs.get("request", args[idx] if idx < len(args) else None) + assert isinstance(request, Request), ( + f"Parameter with name 'request' is required to be of type 'Request' not '{type(request).__name__}'" + ) + + if not has_required_scope(request, scopes_list): + if redirect is not None: + orig_request_qparam = urlencode({"next": str(request.url)}) + next_url = f"{request.url_for(redirect)}?{orig_request_qparam}" + return RedirectResponse(url=next_url, status_code=303) + raise HTTPException(status_code=status_code) + return await func(*args, **kwargs) + + return async_wrapper + + else: + # Handle sync request/response functions. + @functools.wraps(func) + def sync_wrapper(*args: _P.args, **kwargs: _P.kwargs) -> Any: + request = kwargs.get("request", args[idx] if idx < len(args) else None) + assert isinstance(request, Request), ( + f"Parameter with name 'request' is required to be of type 'Request' not '{type(request).__name__}'" + ) + + if not has_required_scope(request, scopes_list): + if redirect is not None: + orig_request_qparam = urlencode({"next": str(request.url)}) + next_url = f"{request.url_for(redirect)}?{orig_request_qparam}" + return RedirectResponse(url=next_url, status_code=303) + raise HTTPException(status_code=status_code) + return func(*args, **kwargs) + + return sync_wrapper + + return decorator + + +class AuthenticationError(Exception): + pass + + +class AuthenticationBackend: + async def authenticate(self, conn: HTTPConnection) -> tuple[AuthCredentials, BaseUser] | None: + raise NotImplementedError() # pragma: no cover + + +class AuthCredentials: + def __init__(self, scopes: Sequence[str] | None = None): + self.scopes = [] if scopes is None else list(scopes) + + +class BaseUser: + @property + def is_authenticated(self) -> bool: + raise NotImplementedError() # pragma: no cover + + @property + def display_name(self) -> str: + raise NotImplementedError() # pragma: no cover + + @property + def identity(self) -> str: + raise NotImplementedError() # pragma: no cover + + +class SimpleUser(BaseUser): + def __init__(self, username: str) -> None: + self.username = username + + @property + def is_authenticated(self) -> bool: + return True + + @property + def display_name(self) -> str: + return self.username + + @property + def identity(self) -> str: + return self.username + + +class UnauthenticatedUser(BaseUser): + @property + def is_authenticated(self) -> bool: + return False + + @property + def display_name(self) -> str: + return "" + + @property + def identity(self) -> str: + return "" diff --git a/source/target-vendors/cp312/starlette/background.py b/source/target-vendors/cp312/starlette/background.py new file mode 100644 index 0000000..55135ee --- /dev/null +++ b/source/target-vendors/cp312/starlette/background.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +from collections.abc import Callable, Sequence +from typing import Any, ParamSpec + +from starlette._utils import is_async_callable +from starlette.concurrency import run_in_threadpool + +P = ParamSpec("P") + + +class BackgroundTask: + def __init__(self, func: Callable[P, Any], *args: P.args, **kwargs: P.kwargs) -> None: + self.func = func + self.args = args + self.kwargs = kwargs + self.is_async = is_async_callable(func) + + async def __call__(self) -> None: + if self.is_async: + await self.func(*self.args, **self.kwargs) + else: + await run_in_threadpool(self.func, *self.args, **self.kwargs) + + +class BackgroundTasks(BackgroundTask): + def __init__(self, tasks: Sequence[BackgroundTask] | None = None): + self.tasks = list(tasks) if tasks else [] + + def add_task(self, func: Callable[P, Any], *args: P.args, **kwargs: P.kwargs) -> None: + task = BackgroundTask(func, *args, **kwargs) + self.tasks.append(task) + + async def __call__(self) -> None: + for task in self.tasks: + await task() diff --git a/source/target-vendors/cp312/starlette/concurrency.py b/source/target-vendors/cp312/starlette/concurrency.py new file mode 100644 index 0000000..a2c55be --- /dev/null +++ b/source/target-vendors/cp312/starlette/concurrency.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import functools +import warnings +from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Iterator +from typing import ParamSpec, TypeVar + +import anyio.to_thread + +from starlette.exceptions import StarletteDeprecationWarning + +P = ParamSpec("P") +T = TypeVar("T") + + +async def run_until_first_complete(*args: tuple[Callable, dict]) -> None: # type: ignore[type-arg] + warnings.warn( + "run_until_first_complete is deprecated and will be removed in a future version.", + StarletteDeprecationWarning, + ) + + async with anyio.create_task_group() as task_group: + + async def run(func: Callable[[], Coroutine]) -> None: # type: ignore[type-arg] + await func() + task_group.cancel_scope.cancel() + + for func, kwargs in args: + task_group.start_soon(run, functools.partial(func, **kwargs)) + + +async def run_in_threadpool(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T: + func = functools.partial(func, *args, **kwargs) + return await anyio.to_thread.run_sync(func) + + +class _StopIteration(Exception): + pass + + +def _next(iterator: Iterator[T]) -> T: + # We can't raise `StopIteration` from within the threadpool iterator + # and catch it outside that context, so we coerce them into a different + # exception type. + try: + return next(iterator) + except StopIteration: + raise _StopIteration + + +async def iterate_in_threadpool( + iterator: Iterable[T], +) -> AsyncIterator[T]: + as_iterator = iter(iterator) + while True: + try: + yield await anyio.to_thread.run_sync(_next, as_iterator) + except _StopIteration: + break diff --git a/source/target-vendors/cp312/starlette/config.py b/source/target-vendors/cp312/starlette/config.py new file mode 100644 index 0000000..56c25ca --- /dev/null +++ b/source/target-vendors/cp312/starlette/config.py @@ -0,0 +1,140 @@ +from __future__ import annotations + +import os +import warnings +from collections.abc import Callable, Iterator, Mapping, MutableMapping +from pathlib import Path +from typing import Any, TypeVar, overload + + +class undefined: + pass + + +class EnvironError(Exception): + pass + + +class Environ(MutableMapping[str, str]): + def __init__(self, environ: MutableMapping[str, str] = os.environ): + self._environ = environ + self._has_been_read: set[str] = set() + + def __getitem__(self, key: str) -> str: + self._has_been_read.add(key) + return self._environ.__getitem__(key) + + def __setitem__(self, key: str, value: str) -> None: + if key in self._has_been_read: + raise EnvironError(f"Attempting to set environ['{key}'], but the value has already been read.") + self._environ.__setitem__(key, value) + + def __delitem__(self, key: str) -> None: + if key in self._has_been_read: + raise EnvironError(f"Attempting to delete environ['{key}'], but the value has already been read.") + self._environ.__delitem__(key) + + def __iter__(self) -> Iterator[str]: + return iter(self._environ) + + def __len__(self) -> int: + return len(self._environ) + + +environ = Environ() + +T = TypeVar("T") + + +class Config: + def __init__( + self, + env_file: str | Path | None = None, + environ: Mapping[str, str] = environ, + env_prefix: str = "", + encoding: str = "utf-8", + ) -> None: + self.environ = environ + self.env_prefix = env_prefix + self.file_values: dict[str, str] = {} + if env_file is not None: + if not os.path.isfile(env_file): + warnings.warn(f"Config file '{env_file}' not found.") + else: + self.file_values = self._read_file(env_file, encoding) + + @overload + def __call__(self, key: str, *, default: None) -> str | None: ... + + @overload + def __call__(self, key: str, cast: type[T], default: T = ...) -> T: ... + + @overload + def __call__(self, key: str, cast: type[str] = ..., default: str = ...) -> str: ... + + @overload + def __call__( + self, + key: str, + cast: Callable[[Any], T] = ..., + default: Any = ..., + ) -> T: ... + + @overload + def __call__(self, key: str, cast: type[str] = ..., default: T = ...) -> T | str: ... + + def __call__( + self, + key: str, + cast: Callable[[Any], Any] | None = None, + default: Any = undefined, + ) -> Any: + return self.get(key, cast, default) + + def get( + self, + key: str, + cast: Callable[[Any], Any] | None = None, + default: Any = undefined, + ) -> Any: + key = self.env_prefix + key + if key in self.environ: + value = self.environ[key] + return self._perform_cast(key, value, cast) + if key in self.file_values: + value = self.file_values[key] + return self._perform_cast(key, value, cast) + if default is not undefined: + return self._perform_cast(key, default, cast) + raise KeyError(f"Config '{key}' is missing, and has no default.") + + def _read_file(self, file_name: str | Path, encoding: str) -> dict[str, str]: + file_values: dict[str, str] = {} + with open(file_name, encoding=encoding) as input_file: + for line in input_file.readlines(): + line = line.strip() + if "=" in line and not line.startswith("#"): + key, value = line.split("=", 1) + key = key.strip() + value = value.strip().strip("\"'") + file_values[key] = value + return file_values + + def _perform_cast( + self, + key: str, + value: Any, + cast: Callable[[Any], Any] | None = None, + ) -> Any: + if cast is None or value is None: + return value + elif cast is bool and isinstance(value, str): + mapping = {"true": True, "1": True, "false": False, "0": False} + value = value.lower() + if value not in mapping: + raise ValueError(f"Config '{key}' has value '{value}'. Not a valid bool.") + return mapping[value] + try: + return cast(value) + except (TypeError, ValueError): + raise ValueError(f"Config '{key}' has value '{value}'. Not a valid {cast.__name__}.") diff --git a/source/target-vendors/cp312/starlette/convertors.py b/source/target-vendors/cp312/starlette/convertors.py new file mode 100644 index 0000000..72b1cf9 --- /dev/null +++ b/source/target-vendors/cp312/starlette/convertors.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +import math +import uuid +from typing import Any, ClassVar, Generic, TypeVar + +T = TypeVar("T") + + +class Convertor(Generic[T]): + regex: ClassVar[str] = "" + + def convert(self, value: str) -> T: + raise NotImplementedError() # pragma: no cover + + def to_string(self, value: T) -> str: + raise NotImplementedError() # pragma: no cover + + +class StringConvertor(Convertor[str]): + regex = "[^/]+" + + def convert(self, value: str) -> str: + return value + + def to_string(self, value: str) -> str: + value = str(value) + assert "/" not in value, "May not contain path separators" + assert value, "Must not be empty" + return value + + +class PathConvertor(Convertor[str]): + regex = ".*" + + def convert(self, value: str) -> str: + return str(value) + + def to_string(self, value: str) -> str: + return str(value) + + +class IntegerConvertor(Convertor[int]): + regex = "[0-9]+" + + def convert(self, value: str) -> int: + return int(value) + + def to_string(self, value: int) -> str: + value = int(value) + assert value >= 0, "Negative integers are not supported" + return str(value) + + +class FloatConvertor(Convertor[float]): + regex = r"[0-9]+(\.[0-9]+)?" + + def convert(self, value: str) -> float: + return float(value) + + def to_string(self, value: float) -> str: + value = float(value) + assert value >= 0.0, "Negative floats are not supported" + assert not math.isnan(value), "NaN values are not supported" + assert not math.isinf(value), "Infinite values are not supported" + return ("%0.20f" % value).rstrip("0").rstrip(".") + + +class UUIDConvertor(Convertor[uuid.UUID]): + regex = "[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}" + + def convert(self, value: str) -> uuid.UUID: + return uuid.UUID(value) + + def to_string(self, value: uuid.UUID) -> str: + return str(value) + + +CONVERTOR_TYPES: dict[str, Convertor[Any]] = { + "str": StringConvertor(), + "path": PathConvertor(), + "int": IntegerConvertor(), + "float": FloatConvertor(), + "uuid": UUIDConvertor(), +} + + +def register_url_convertor(key: str, convertor: Convertor[Any]) -> None: + CONVERTOR_TYPES[key] = convertor diff --git a/source/target-vendors/cp312/starlette/datastructures.py b/source/target-vendors/cp312/starlette/datastructures.py new file mode 100644 index 0000000..d4ec95e --- /dev/null +++ b/source/target-vendors/cp312/starlette/datastructures.py @@ -0,0 +1,704 @@ +from __future__ import annotations + +from collections.abc import ItemsView, Iterable, Iterator, KeysView, Mapping, MutableMapping, Sequence, ValuesView +from shlex import shlex +from typing import Any, BinaryIO, Literal, NamedTuple, TypeVar, cast +from urllib.parse import SplitResult, parse_qsl, urlencode, urlsplit + +from starlette._utils import parse_host_header +from starlette.concurrency import run_in_threadpool +from starlette.types import Scope + + +class Address(NamedTuple): + host: str + port: int + + +_KeyType = TypeVar("_KeyType") +# Mapping keys are invariant but their values are covariant since +# you can only read them +# that is, you can't do `Mapping[str, Animal]()["fido"] = Dog()` +_CovariantValueType = TypeVar("_CovariantValueType", covariant=True) + + +class URL: + def __init__( + self, + url: str = "", + scope: Scope | None = None, + **components: Any, + ) -> None: + if scope is not None: + assert not url, 'Cannot set both "url" and "scope".' + assert not components, 'Cannot set both "scope" and "**components".' + scheme = scope.get("scheme", "http") + server = scope.get("server", None) + path = scope["path"] + query_string = scope.get("query_string", b"") + + host_header = None + for key, value in scope["headers"]: + if key == b"host": + host_header = value.decode("latin-1") + break + + parsed_host = parse_host_header(host_header) + if parsed_host is not None and parsed_host.is_valid_port: + netloc = parsed_host.authority + elif server is not None: + host, port = server + if ":" in host and not host.startswith("["): + host = f"[{host}]" + default_port = {"http": 80, "https": 443, "ws": 80, "wss": 443}[scheme] + netloc = host if port == default_port else f"{host}:{port}" + else: + netloc = None + + query = query_string.decode() + if netloc is not None: + url = SplitResult(scheme=scheme, netloc=netloc, path=path, query=query, fragment="").geturl() + else: + url = f"{path}?{query}" if query else path + elif components: + assert not url, 'Cannot set both "url" and "**components".' + url = URL("").replace(**components).components.geturl() + + self._url = url + + @property + def components(self) -> SplitResult: + if not hasattr(self, "_components"): + self._components = urlsplit(self._url) + return self._components + + @property + def scheme(self) -> str: + return self.components.scheme + + @property + def netloc(self) -> str: + return self.components.netloc + + @property + def path(self) -> str: + return self.components.path + + @property + def query(self) -> str: + return self.components.query + + @property + def fragment(self) -> str: + return self.components.fragment + + @property + def username(self) -> None | str: + return self.components.username + + @property + def password(self) -> None | str: + return self.components.password + + @property + def hostname(self) -> None | str: + return self.components.hostname + + @property + def port(self) -> int | None: + return self.components.port + + @property + def is_secure(self) -> bool: + return self.scheme in ("https", "wss") + + def replace(self, **kwargs: Any) -> URL: + if "username" in kwargs or "password" in kwargs or "hostname" in kwargs or "port" in kwargs: + hostname = kwargs.pop("hostname", None) + port = kwargs.pop("port", self.port) + username = kwargs.pop("username", self.username) + password = kwargs.pop("password", self.password) + + if hostname is None: + netloc = self.netloc + _, _, hostname = netloc.rpartition("@") + + if hostname and hostname[-1] != "]": + hostname = hostname.rsplit(":", 1)[0] + + netloc = hostname + if port is not None: + netloc += f":{port}" + if username is not None: + userpass = username + if password is not None: + userpass += f":{password}" + netloc = f"{userpass}@{netloc}" + + kwargs["netloc"] = netloc + + components = self.components._replace(**kwargs) + return self.__class__(components.geturl()) + + def include_query_params(self, **kwargs: Any) -> URL: + params = MultiDict(parse_qsl(self.query, keep_blank_values=True)) + params.update({str(key): str(value) for key, value in kwargs.items()}) + query = urlencode(params.multi_items()) + return self.replace(query=query) + + def replace_query_params(self, **kwargs: Any) -> URL: + query = urlencode([(str(key), str(value)) for key, value in kwargs.items()]) + return self.replace(query=query) + + def remove_query_params(self, keys: str | Sequence[str]) -> URL: + if isinstance(keys, str): + keys = [keys] + params = MultiDict(parse_qsl(self.query, keep_blank_values=True)) + for key in keys: + params.pop(key, None) + query = urlencode(params.multi_items()) + return self.replace(query=query) + + def __eq__(self, other: Any) -> bool: + return str(self) == str(other) + + def __str__(self) -> str: + return self._url + + def __repr__(self) -> str: + url = str(self) + if self.password: + url = str(self.replace(password="********")) + return f"{self.__class__.__name__}({repr(url)})" + + +class URLPath(str): + """ + A URL path string that may also hold an associated protocol and/or host. + Used by the routing to return `url_path_for` matches. + """ + + def __new__(cls, path: str, protocol: Literal["http", "websocket", ""] = "", host: str = "") -> URLPath: + assert protocol in ("http", "websocket", "") + return str.__new__(cls, path) + + def __init__(self, path: str, protocol: Literal["http", "websocket", ""] = "", host: str = "") -> None: + self.protocol = protocol + self.host = host + + def make_absolute_url(self, base_url: str | URL) -> URL: + if isinstance(base_url, str): + base_url = URL(base_url) + if self.protocol: + scheme = { + "http": {True: "https", False: "http"}, + "websocket": {True: "wss", False: "ws"}, + }[self.protocol][base_url.is_secure] + else: + scheme = base_url.scheme + + netloc = self.host or base_url.netloc + path = base_url.path.rstrip("/") + str(self) + return URL(scheme=scheme, netloc=netloc, path=path) + + +class Secret: + """ + Holds a string value that should not be revealed in tracebacks etc. + You should cast the value to `str` at the point it is required. + """ + + def __init__(self, value: str): + self._value = value + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + return f"{class_name}('**********')" + + def __str__(self) -> str: + return self._value + + def __bool__(self) -> bool: + return bool(self._value) + + +class CommaSeparatedStrings(Sequence[str]): + def __init__(self, value: str | Sequence[str]): + if isinstance(value, str): + splitter = shlex(value, posix=True) + splitter.whitespace = "," + splitter.whitespace_split = True + self._items = [item.strip() for item in splitter] + else: + self._items = list(value) + + def __len__(self) -> int: + return len(self._items) + + def __getitem__(self, index: int | slice) -> Any: + return self._items[index] + + def __iter__(self) -> Iterator[str]: + return iter(self._items) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + items = [item for item in self] + return f"{class_name}({items!r})" + + def __str__(self) -> str: + return ", ".join(repr(item) for item in self) + + +class ImmutableMultiDict(Mapping[_KeyType, _CovariantValueType]): + _dict: dict[_KeyType, _CovariantValueType] + + def __init__( + self, + *args: ImmutableMultiDict[_KeyType, _CovariantValueType] + | Mapping[_KeyType, _CovariantValueType] + | Iterable[tuple[_KeyType, _CovariantValueType]], + **kwargs: Any, + ) -> None: + assert len(args) < 2, "Too many arguments." + + value: Any = args[0] if args else [] + if kwargs: + value = ImmutableMultiDict(value).multi_items() + ImmutableMultiDict(kwargs).multi_items() + + if not value: + _items: list[tuple[Any, Any]] = [] + elif hasattr(value, "multi_items"): + value = cast(ImmutableMultiDict[_KeyType, _CovariantValueType], value) + _items = list(value.multi_items()) + elif hasattr(value, "items"): + value = cast(Mapping[_KeyType, _CovariantValueType], value) + _items = list(value.items()) + else: + value = cast("list[tuple[Any, Any]]", value) + _items = list(value) + + self._dict = {k: v for k, v in _items} + self._list = _items + + def getlist(self, key: Any) -> list[_CovariantValueType]: + return [item_value for item_key, item_value in self._list if item_key == key] + + def keys(self) -> KeysView[_KeyType]: + return self._dict.keys() + + def values(self) -> ValuesView[_CovariantValueType]: + return self._dict.values() + + def items(self) -> ItemsView[_KeyType, _CovariantValueType]: + return self._dict.items() + + def multi_items(self) -> list[tuple[_KeyType, _CovariantValueType]]: + return list(self._list) + + def __getitem__(self, key: _KeyType) -> _CovariantValueType: + return self._dict[key] + + def __contains__(self, key: Any) -> bool: + return key in self._dict + + def __iter__(self) -> Iterator[_KeyType]: + return iter(self.keys()) + + def __len__(self) -> int: + return len(self._dict) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, self.__class__): + return False + return sorted(self._list) == sorted(other._list) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + items = self.multi_items() + return f"{class_name}({items!r})" + + +class MultiDict(ImmutableMultiDict[Any, Any]): + def __setitem__(self, key: Any, value: Any) -> None: + self.setlist(key, [value]) + + def __delitem__(self, key: Any) -> None: + self._list = [(k, v) for k, v in self._list if k != key] + del self._dict[key] + + def pop(self, key: Any, default: Any = None) -> Any: + self._list = [(k, v) for k, v in self._list if k != key] + return self._dict.pop(key, default) + + def popitem(self) -> tuple[Any, Any]: + key, value = self._dict.popitem() + self._list = [(k, v) for k, v in self._list if k != key] + return key, value + + def poplist(self, key: Any) -> list[Any]: + values = [v for k, v in self._list if k == key] + self.pop(key) + return values + + def clear(self) -> None: + self._dict.clear() + self._list.clear() + + def setdefault(self, key: Any, default: Any = None) -> Any: + if key not in self: + self._dict[key] = default + self._list.append((key, default)) + + return self[key] + + def setlist(self, key: Any, values: list[Any]) -> None: + if not values: + self.pop(key, None) + else: + existing_items = [(k, v) for (k, v) in self._list if k != key] + self._list = existing_items + [(key, value) for value in values] + self._dict[key] = values[-1] + + def append(self, key: Any, value: Any) -> None: + self._list.append((key, value)) + self._dict[key] = value + + def update( + self, + *args: MultiDict | Mapping[Any, Any] | list[tuple[Any, Any]], + **kwargs: Any, + ) -> None: + value = MultiDict(*args, **kwargs) + existing_items = [(k, v) for (k, v) in self._list if k not in value.keys()] + self._list = existing_items + value.multi_items() + self._dict.update(value) + + +class QueryParams(ImmutableMultiDict[str, str]): + """ + An immutable multidict. + """ + + def __init__( + self, + *args: ImmutableMultiDict[Any, Any] | Mapping[Any, Any] | list[tuple[Any, Any]] | str | bytes, + **kwargs: Any, + ) -> None: + assert len(args) < 2, "Too many arguments." + + value = args[0] if args else [] + + if isinstance(value, str): + super().__init__(parse_qsl(value, keep_blank_values=True), **kwargs) + elif isinstance(value, bytes): + super().__init__(parse_qsl(value.decode("latin-1"), keep_blank_values=True), **kwargs) + else: + super().__init__(*args, **kwargs) # type: ignore[arg-type] + self._list = [(str(k), str(v)) for k, v in self._list] + self._dict = {str(k): str(v) for k, v in self._dict.items()} + + def __str__(self) -> str: + return urlencode(self._list) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + query_string = str(self) + return f"{class_name}({query_string!r})" + + +class UploadFile: + """ + An uploaded file included as part of the request data. + """ + + def __init__( + self, + file: BinaryIO, + *, + size: int | None = None, + filename: str | None = None, + headers: Headers | None = None, + ) -> None: + self.filename = filename + self.file = file + self.size = size + self.headers = headers or Headers() + + # Capture max size from SpooledTemporaryFile if one is provided. This slightly speeds up future checks. + # Note 0 means unlimited mirroring SpooledTemporaryFile's __init__ + self._max_mem_size = getattr(self.file, "_max_size", 0) + + @property + def content_type(self) -> str | None: + return self.headers.get("content-type", None) + + @property + def _in_memory(self) -> bool: + # check for SpooledTemporaryFile._rolled + rolled_to_disk = getattr(self.file, "_rolled", True) + return not rolled_to_disk + + def _will_roll(self, size_to_add: int) -> bool: + # If we're not in_memory then we will always roll + if not self._in_memory: + return True + + # Check for SpooledTemporaryFile._max_size + future_size = self.file.tell() + size_to_add + return bool(future_size > self._max_mem_size) if self._max_mem_size else False + + async def write(self, data: bytes) -> None: + new_data_len = len(data) + if self.size is not None: + self.size += new_data_len + + if self._will_roll(new_data_len): + await run_in_threadpool(self.file.write, data) + else: + self.file.write(data) + + async def read(self, size: int = -1) -> bytes: + if self._in_memory: + return self.file.read(size) + return await run_in_threadpool(self.file.read, size) + + async def seek(self, offset: int) -> None: + if self._in_memory: + self.file.seek(offset) + else: + await run_in_threadpool(self.file.seek, offset) + + async def close(self) -> None: + if self._in_memory: + self.file.close() + else: + await run_in_threadpool(self.file.close) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(filename={self.filename!r}, size={self.size!r}, headers={self.headers!r})" + + +class FormData(ImmutableMultiDict[str, UploadFile | str]): + """ + An immutable multidict, containing both file uploads and text input. + """ + + def __init__( + self, + *args: FormData | Mapping[str, str | UploadFile] | list[tuple[str, str | UploadFile]], + **kwargs: str | UploadFile, + ) -> None: + super().__init__(*args, **kwargs) + + async def close(self) -> None: + for key, value in self.multi_items(): + if isinstance(value, UploadFile): + await value.close() + + +class Headers(Mapping[str, str]): + """ + An immutable, case-insensitive multidict. + """ + + def __init__( + self, + headers: Mapping[str, str] | None = None, + raw: list[tuple[bytes, bytes]] | None = None, + scope: MutableMapping[str, Any] | None = None, + ) -> None: + self._list: list[tuple[bytes, bytes]] = [] + if headers is not None: + assert raw is None, 'Cannot set both "headers" and "raw".' + assert scope is None, 'Cannot set both "headers" and "scope".' + self._list = [(key.lower().encode("latin-1"), value.encode("latin-1")) for key, value in headers.items()] + elif raw is not None: + assert scope is None, 'Cannot set both "raw" and "scope".' + self._list = raw + elif scope is not None: + # scope["headers"] isn't necessarily a list + # it might be a tuple or other iterable + self._list = scope["headers"] = list(scope["headers"]) + + @property + def raw(self) -> list[tuple[bytes, bytes]]: + return list(self._list) + + def keys(self) -> list[str]: # type: ignore[override] + return [key.decode("latin-1") for key, value in self._list] + + def values(self) -> list[str]: # type: ignore[override] + return [value.decode("latin-1") for key, value in self._list] + + def items(self) -> list[tuple[str, str]]: # type: ignore[override] + return [(key.decode("latin-1"), value.decode("latin-1")) for key, value in self._list] + + def getlist(self, key: str) -> list[str]: + get_header_key = key.lower().encode("latin-1") + return [item_value.decode("latin-1") for item_key, item_value in self._list if item_key == get_header_key] + + def mutablecopy(self) -> MutableHeaders: + return MutableHeaders(raw=self._list[:]) + + def __getitem__(self, key: str) -> str: + get_header_key = key.lower().encode("latin-1") + for header_key, header_value in self._list: + if header_key == get_header_key: + return header_value.decode("latin-1") + raise KeyError(key) + + def __contains__(self, key: Any) -> bool: + get_header_key = key.lower().encode("latin-1") + for header_key, header_value in self._list: + if header_key == get_header_key: + return True + return False + + def __iter__(self) -> Iterator[Any]: + return iter(self.keys()) + + def __len__(self) -> int: + return len(self._list) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Headers): + return False + return sorted(self._list) == sorted(other._list) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + as_dict = dict(self.items()) + if len(as_dict) == len(self): + return f"{class_name}({as_dict!r})" + return f"{class_name}(raw={self.raw!r})" + + +class MutableHeaders(Headers): + def __setitem__(self, key: str, value: str) -> None: + """ + Set the header `key` to `value`, removing any duplicate entries. + Retains insertion order. + """ + set_key = key.lower().encode("latin-1") + set_value = value.encode("latin-1") + + found_indexes: list[int] = [] + for idx, (item_key, item_value) in enumerate(self._list): + if item_key == set_key: + found_indexes.append(idx) + + for idx in reversed(found_indexes[1:]): + del self._list[idx] + + if found_indexes: + idx = found_indexes[0] + self._list[idx] = (set_key, set_value) + else: + self._list.append((set_key, set_value)) + + def __delitem__(self, key: str) -> None: + """ + Remove the header `key`. + """ + del_key = key.lower().encode("latin-1") + + pop_indexes: list[int] = [] + for idx, (item_key, item_value) in enumerate(self._list): + if item_key == del_key: + pop_indexes.append(idx) + + for idx in reversed(pop_indexes): + del self._list[idx] + + def __ior__(self, other: Mapping[str, str]) -> MutableHeaders: + if not isinstance(other, Mapping): + raise TypeError(f"Expected a mapping but got {other.__class__.__name__}") + self.update(other) + return self + + def __or__(self, other: Mapping[str, str]) -> MutableHeaders: + if not isinstance(other, Mapping): + raise TypeError(f"Expected a mapping but got {other.__class__.__name__}") + new = self.mutablecopy() + new.update(other) + return new + + @property + def raw(self) -> list[tuple[bytes, bytes]]: + return self._list + + def setdefault(self, key: str, value: str) -> str: + """ + If the header `key` does not exist, then set it to `value`. + Returns the header value. + """ + set_key = key.lower().encode("latin-1") + set_value = value.encode("latin-1") + + for idx, (item_key, item_value) in enumerate(self._list): + if item_key == set_key: + return item_value.decode("latin-1") + self._list.append((set_key, set_value)) + return value + + def update(self, other: Mapping[str, str]) -> None: + for key, val in other.items(): + self[key] = val + + def append(self, key: str, value: str) -> None: + """ + Append a header, preserving any duplicate entries. + """ + append_key = key.lower().encode("latin-1") + append_value = value.encode("latin-1") + self._list.append((append_key, append_value)) + + def add_vary_header(self, vary: str) -> None: + existing = self.get("vary") + if existing is not None: + vary = ", ".join([existing, vary]) + self["vary"] = vary + + +class State: + """ + An object that can be used to store arbitrary state. + + Used for `request.state` and `app.state`. + """ + + _state: dict[str, Any] + + def __init__(self, state: dict[str, Any] | None = None): + if state is None: + state = {} + super().__setattr__("_state", state) + + def __setattr__(self, key: Any, value: Any) -> None: + self._state[key] = value + + def __getattr__(self, key: Any) -> Any: + try: + return self._state[key] + except KeyError: + message = "'{}' object has no attribute '{}'" + raise AttributeError(message.format(self.__class__.__name__, key)) + + def __delattr__(self, key: Any) -> None: + del self._state[key] + + def __getitem__(self, key: str) -> Any: + return self._state[key] + + def __setitem__(self, key: str, value: Any) -> None: + self._state[key] = value + + def __delitem__(self, key: str) -> None: + del self._state[key] + + def __iter__(self) -> Iterator[str]: + return iter(self._state) + + def __len__(self) -> int: + return len(self._state) diff --git a/source/target-vendors/cp312/starlette/endpoints.py b/source/target-vendors/cp312/starlette/endpoints.py new file mode 100644 index 0000000..9b2032c --- /dev/null +++ b/source/target-vendors/cp312/starlette/endpoints.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +import json +from collections.abc import Callable, Generator +from typing import Any, Literal + +from starlette import status +from starlette._utils import is_async_callable +from starlette.concurrency import run_in_threadpool +from starlette.exceptions import HTTPException +from starlette.requests import Request +from starlette.responses import PlainTextResponse, Response +from starlette.types import Message, Receive, Scope, Send +from starlette.websockets import WebSocket + + +class HTTPEndpoint: + def __init__(self, scope: Scope, receive: Receive, send: Send) -> None: + assert scope["type"] == "http" + self.scope = scope + self.receive = receive + self.send = send + self._allowed_methods = [ + method + for method in ("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "QUERY") + if getattr(self, method.lower(), None) is not None + ] + + def __await__(self) -> Generator[Any, None, None]: + return self.dispatch().__await__() + + async def dispatch(self) -> None: + request = Request(self.scope, receive=self.receive) + handler_name = "get" if request.method == "HEAD" and not hasattr(self, "head") else request.method.lower() + + handler: Callable[[Request], Any] + if request.method in self._allowed_methods or (request.method == "HEAD" and "GET" in self._allowed_methods): + handler = getattr(self, handler_name) + else: + handler = self.method_not_allowed + is_async = is_async_callable(handler) + if is_async: + response = await handler(request) + else: + response = await run_in_threadpool(handler, request) + await response(self.scope, self.receive, self.send) + + async def method_not_allowed(self, request: Request) -> Response: + # If we're running inside a starlette application then raise an + # exception, so that the configurable exception handler can deal with + # returning the response. For plain ASGI apps, just return the response. + headers = {"Allow": ", ".join(self._allowed_methods)} + if "app" in self.scope: + raise HTTPException(status_code=405, headers=headers) + return PlainTextResponse("Method Not Allowed", status_code=405, headers=headers) + + +class WebSocketEndpoint: + encoding: Literal["text", "bytes", "json"] | None = None + + def __init__(self, scope: Scope, receive: Receive, send: Send) -> None: + assert scope["type"] == "websocket" + self.scope = scope + self.receive = receive + self.send = send + + def __await__(self) -> Generator[Any, None, None]: + return self.dispatch().__await__() + + async def dispatch(self) -> None: + websocket = WebSocket(self.scope, receive=self.receive, send=self.send) + await self.on_connect(websocket) + + close_code = status.WS_1000_NORMAL_CLOSURE + + try: + while True: + message = await websocket.receive() + if message["type"] == "websocket.receive": + data = await self.decode(websocket, message) + await self.on_receive(websocket, data) + elif message["type"] == "websocket.disconnect": # pragma: no branch + close_code = int(message.get("code") or status.WS_1000_NORMAL_CLOSURE) + break + except Exception as exc: + close_code = status.WS_1011_INTERNAL_ERROR + raise exc + finally: + await self.on_disconnect(websocket, close_code) + + async def decode(self, websocket: WebSocket, message: Message) -> Any: + if self.encoding == "text": + if message.get("text") is None: + await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA) + raise RuntimeError("Expected text websocket messages, but got bytes") + return message["text"] + + elif self.encoding == "bytes": + if message.get("bytes") is None: + await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA) + raise RuntimeError("Expected bytes websocket messages, but got text") + return message["bytes"] + + elif self.encoding == "json": + if message.get("text") is not None: + text = message["text"] + else: + text = message["bytes"].decode("utf-8") + + try: + return json.loads(text) + except json.decoder.JSONDecodeError: + await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA) + raise RuntimeError("Malformed JSON data received.") + + assert self.encoding is None, f"Unsupported 'encoding' attribute {self.encoding}" + return message["text"] if message.get("text") is not None else message["bytes"] + + async def on_connect(self, websocket: WebSocket) -> None: + """Override to handle an incoming websocket connection""" + await websocket.accept() + + async def on_receive(self, websocket: WebSocket, data: Any) -> None: + """Override to handle an incoming websocket message""" + + async def on_disconnect(self, websocket: WebSocket, close_code: int) -> None: + """Override to handle a disconnecting websocket""" diff --git a/source/target-vendors/cp312/starlette/exceptions.py b/source/target-vendors/cp312/starlette/exceptions.py new file mode 100644 index 0000000..37bdae1 --- /dev/null +++ b/source/target-vendors/cp312/starlette/exceptions.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +import http.client +from collections.abc import Mapping + + +class HTTPException(Exception): + def __init__(self, status_code: int, detail: str | None = None, headers: Mapping[str, str] | None = None) -> None: + if detail is None: + detail = http.client.responses.get(status_code, "") + self.status_code = status_code + self.detail = detail + self.headers = headers + + def __str__(self) -> str: + return f"{self.status_code}: {self.detail}" + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + return f"{class_name}(status_code={self.status_code!r}, detail={self.detail!r})" + + +class WebSocketException(Exception): + def __init__(self, code: int, reason: str | None = None) -> None: + self.code = code + self.reason = reason or "" + + def __str__(self) -> str: + return f"{self.code}: {self.reason}" + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + return f"{class_name}(code={self.code!r}, reason={self.reason!r})" + + +class StarletteDeprecationWarning(UserWarning): + """A custom deprecation warning for Starlette. + + Unlike the built-in DeprecationWarning, this inherits from UserWarning to ensure it is visible by default, helping + users discover deprecated features without needing to enable warnings explicitly. + + Reference: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries + """ diff --git a/source/target-vendors/cp312/starlette/formparsers.py b/source/target-vendors/cp312/starlette/formparsers.py new file mode 100644 index 0000000..e3cdc85 --- /dev/null +++ b/source/target-vendors/cp312/starlette/formparsers.py @@ -0,0 +1,301 @@ +from __future__ import annotations + +from collections.abc import AsyncGenerator +from dataclasses import dataclass, field +from enum import Enum +from tempfile import SpooledTemporaryFile +from typing import TYPE_CHECKING +from urllib.parse import unquote_plus + +from starlette.datastructures import FormData, Headers, UploadFile + +if TYPE_CHECKING: + import python_multipart as multipart + from python_multipart.exceptions import FormParserError + from python_multipart.multipart import MultipartCallbacks, QuerystringCallbacks, parse_options_header +else: + try: + try: + import python_multipart as multipart + from python_multipart.exceptions import FormParserError + from python_multipart.multipart import parse_options_header + except ModuleNotFoundError: # pragma: no cover + import multipart + from multipart.exceptions import FormParserError + from multipart.multipart import parse_options_header + except ModuleNotFoundError: # pragma: no cover + multipart = None + parse_options_header = None + + +class FormMessage(Enum): + FIELD_START = 1 + FIELD_NAME = 2 + FIELD_DATA = 3 + FIELD_END = 4 + END = 5 + + +@dataclass +class MultipartPart: + content_disposition: bytes | None = None + field_name: str = "" + data: bytearray = field(default_factory=bytearray) + file: UploadFile | None = None + item_headers: list[tuple[bytes, bytes]] = field(default_factory=list) + + +def _user_safe_decode(src: bytes | bytearray, codec: str) -> str: + try: + return src.decode(codec) + except (UnicodeDecodeError, LookupError): + return src.decode("latin-1") + + +class MultiPartException(Exception): + def __init__(self, message: str) -> None: + self.message = message + + +class FormParser: + def __init__( + self, + headers: Headers, + stream: AsyncGenerator[bytes, None], + *, + max_fields: int | float = 1000, + max_part_size: int = 1024 * 1024, # 1MB + ) -> None: + assert multipart is not None, "The `python-multipart` library must be installed to use form parsing." + self.headers = headers + self.stream = stream + self.max_fields = max_fields + self.max_part_size = max_part_size + self.messages: list[tuple[FormMessage, bytes]] = [] + self._current_field_size = 0 + self._current_fields = 0 + + def on_field_start(self) -> None: + self._current_field_size = 0 + message = (FormMessage.FIELD_START, b"") + self.messages.append(message) + + def on_field_name(self, data: bytes, start: int, end: int) -> None: + self._current_field_size += end - start + if self._current_field_size > self.max_part_size: + raise MultiPartException(f"Field exceeded maximum size of {int(self.max_part_size / 1024)}KB.") + message = (FormMessage.FIELD_NAME, data[start:end]) + self.messages.append(message) + + def on_field_data(self, data: bytes, start: int, end: int) -> None: + self._current_field_size += end - start + if self._current_field_size > self.max_part_size: + raise MultiPartException(f"Field exceeded maximum size of {int(self.max_part_size / 1024)}KB.") + message = (FormMessage.FIELD_DATA, data[start:end]) + self.messages.append(message) + + def on_field_end(self) -> None: + self._current_fields += 1 + if self._current_fields > self.max_fields: + raise MultiPartException(f"Too many fields. Maximum number of fields is {self.max_fields}.") + message = (FormMessage.FIELD_END, b"") + self.messages.append(message) + + def on_end(self) -> None: + message = (FormMessage.END, b"") + self.messages.append(message) + + async def parse(self) -> FormData: + # Callbacks dictionary. + callbacks: QuerystringCallbacks = { + "on_field_start": self.on_field_start, + "on_field_name": self.on_field_name, + "on_field_data": self.on_field_data, + "on_field_end": self.on_field_end, + "on_end": self.on_end, + } + + # Create the parser. + parser = multipart.QuerystringParser(callbacks) + field_name = bytearray() + field_value = bytearray() + + items: list[tuple[str, str | UploadFile]] = [] + + # Feed the parser with data from the request. + async for chunk in self.stream: + if chunk: + parser.write(chunk) + else: + parser.finalize() + messages = list(self.messages) + self.messages.clear() + for message_type, message_bytes in messages: + if message_type == FormMessage.FIELD_START: + field_name = bytearray() + field_value = bytearray() + elif message_type == FormMessage.FIELD_NAME: + field_name.extend(message_bytes) + elif message_type == FormMessage.FIELD_DATA: + field_value.extend(message_bytes) + elif message_type == FormMessage.FIELD_END: + name = unquote_plus(field_name.decode("latin-1")) + value = unquote_plus(field_value.decode("latin-1")) + items.append((name, value)) + + return FormData(items) + + +class MultiPartParser: + spool_max_size = 1024 * 1024 # 1MB + """The maximum size of the spooled temporary file used to store file data.""" + max_part_size = 1024 * 1024 # 1MB + """The maximum size of a part in the multipart request.""" + + def __init__( + self, + headers: Headers, + stream: AsyncGenerator[bytes, None], + *, + max_files: int | float = 1000, + max_fields: int | float = 1000, + max_part_size: int = 1024 * 1024, # 1MB + ) -> None: + assert multipart is not None, "The `python-multipart` library must be installed to use form parsing." + self.headers = headers + self.stream = stream + self.max_files = max_files + self.max_fields = max_fields + self.items: list[tuple[str, str | UploadFile]] = [] + self._current_files = 0 + self._current_fields = 0 + self._current_partial_header_name: bytes = b"" + self._current_partial_header_value: bytes = b"" + self._current_part = MultipartPart() + self._charset = "" + self._file_parts_to_write: list[tuple[MultipartPart, bytes]] = [] + self._file_parts_to_finish: list[MultipartPart] = [] + self._files_to_close_on_error: list[SpooledTemporaryFile[bytes]] = [] + self.max_part_size = max_part_size + + def on_part_begin(self) -> None: + self._current_part = MultipartPart() + + def on_part_data(self, data: bytes, start: int, end: int) -> None: + message_bytes = data[start:end] + if self._current_part.file is None: + if len(self._current_part.data) + len(message_bytes) > self.max_part_size: + raise MultiPartException(f"Part exceeded maximum size of {int(self.max_part_size / 1024)}KB.") + self._current_part.data.extend(message_bytes) + else: + self._file_parts_to_write.append((self._current_part, message_bytes)) + + def on_part_end(self) -> None: + if self._current_part.file is None: + self.items.append( + ( + self._current_part.field_name, + _user_safe_decode(self._current_part.data, self._charset), + ) + ) + else: + self._file_parts_to_finish.append(self._current_part) + # The file can be added to the items right now even though it's not + # finished yet, because it will be finished in the `parse()` method, before + # self.items is used in the return value. + self.items.append((self._current_part.field_name, self._current_part.file)) + + def on_header_field(self, data: bytes, start: int, end: int) -> None: + self._current_partial_header_name += data[start:end] + + def on_header_value(self, data: bytes, start: int, end: int) -> None: + self._current_partial_header_value += data[start:end] + + def on_header_end(self) -> None: + field = self._current_partial_header_name.lower() + if field == b"content-disposition": + self._current_part.content_disposition = self._current_partial_header_value + self._current_part.item_headers.append((field, self._current_partial_header_value)) + self._current_partial_header_name = b"" + self._current_partial_header_value = b"" + + def on_headers_finished(self) -> None: + disposition, options = parse_options_header(self._current_part.content_disposition) + try: + self._current_part.field_name = _user_safe_decode(options[b"name"], self._charset) + except KeyError: + raise MultiPartException('The Content-Disposition header field "name" must be provided.') + if b"filename" in options: + self._current_files += 1 + if self._current_files > self.max_files: + raise MultiPartException(f"Too many files. Maximum number of files is {self.max_files}.") + filename = _user_safe_decode(options[b"filename"], self._charset) + tempfile = SpooledTemporaryFile(max_size=self.spool_max_size) + self._files_to_close_on_error.append(tempfile) + self._current_part.file = UploadFile( + file=tempfile, # type: ignore[arg-type] + size=0, + filename=filename, + headers=Headers(raw=self._current_part.item_headers), + ) + else: + self._current_fields += 1 + if self._current_fields > self.max_fields: + raise MultiPartException(f"Too many fields. Maximum number of fields is {self.max_fields}.") + self._current_part.file = None + + def on_end(self) -> None: + pass + + async def parse(self) -> FormData: + # Parse the Content-Type header to get the multipart boundary. + _, params = parse_options_header(self.headers["Content-Type"]) + charset = params.get(b"charset", "utf-8") + if isinstance(charset, bytes): + charset = charset.decode("latin-1") + self._charset = charset + try: + boundary = params[b"boundary"] + except KeyError: + raise MultiPartException("Missing boundary in multipart.") + + # Callbacks dictionary. + callbacks: MultipartCallbacks = { + "on_part_begin": self.on_part_begin, + "on_part_data": self.on_part_data, + "on_part_end": self.on_part_end, + "on_header_field": self.on_header_field, + "on_header_value": self.on_header_value, + "on_header_end": self.on_header_end, + "on_headers_finished": self.on_headers_finished, + "on_end": self.on_end, + } + + try: + parser = multipart.MultipartParser(boundary, callbacks) + # Feed the parser with data from the request. + async for chunk in self.stream: + parser.write(chunk) + # Write file data, it needs to use await with the UploadFile methods + # that call the corresponding file methods *in a threadpool*, + # otherwise, if they were called directly in the callback methods above + # (regular, non-async functions), that would block the event loop in + # the main thread. + for part, data in self._file_parts_to_write: + assert part.file # for type checkers + await part.file.write(data) + for part in self._file_parts_to_finish: + assert part.file # for type checkers + await part.file.seek(0) + self._file_parts_to_write.clear() + self._file_parts_to_finish.clear() + parser.finalize() + except BaseException as exc: + # Close all the files if parsing or reading the request stream fails. + for file in self._files_to_close_on_error: + file.close() + if isinstance(exc, FormParserError): + raise MultiPartException("Invalid multipart data.") from exc + raise + + return FormData(self.items) diff --git a/source/target-vendors/cp312/starlette/middleware/__init__.py b/source/target-vendors/cp312/starlette/middleware/__init__.py new file mode 100644 index 0000000..f8d47d7 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/__init__.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from collections.abc import Awaitable, Callable, Iterator +from typing import Any, ParamSpec, Protocol + +P = ParamSpec("P") + + +_Scope = Any +_Receive = Callable[[], Awaitable[Any]] +_Send = Callable[[Any], Awaitable[None]] +# Since `starlette.types.ASGIApp` type differs from `ASGIApplication` from `asgiref` +# we need to define a more permissive version of ASGIApp that doesn't cause type errors. +_ASGIApp = Callable[[_Scope, _Receive, _Send], Awaitable[None]] + + +class _MiddlewareFactory(Protocol[P]): + def __call__(self, app: _ASGIApp, /, *args: P.args, **kwargs: P.kwargs) -> _ASGIApp: ... # pragma: no cover + + +class Middleware: + def __init__(self, cls: _MiddlewareFactory[P], *args: P.args, **kwargs: P.kwargs) -> None: + self.cls = cls + self.args = args + self.kwargs = kwargs + + def __iter__(self) -> Iterator[Any]: + as_tuple = (self.cls, self.args, self.kwargs) + return iter(as_tuple) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + args_strings = [f"{value!r}" for value in self.args] + option_strings = [f"{key}={value!r}" for key, value in self.kwargs.items()] + name = getattr(self.cls, "__name__", "") + args_repr = ", ".join([name] + args_strings + option_strings) + return f"{class_name}({args_repr})" diff --git a/source/target-vendors/cp312/starlette/middleware/authentication.py b/source/target-vendors/cp312/starlette/middleware/authentication.py new file mode 100644 index 0000000..935385f --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/authentication.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +from collections.abc import Callable + +from starlette.authentication import ( + AuthCredentials, + AuthenticationBackend, + AuthenticationError, + UnauthenticatedUser, +) +from starlette.requests import HTTPConnection +from starlette.responses import PlainTextResponse, Response +from starlette.types import ASGIApp, Receive, Scope, Send + + +class AuthenticationMiddleware: + def __init__( + self, + app: ASGIApp, + backend: AuthenticationBackend, + on_error: Callable[[HTTPConnection, AuthenticationError], Response] | None = None, + ) -> None: + self.app = app + self.backend = backend + self.on_error: Callable[[HTTPConnection, AuthenticationError], Response] = ( + on_error if on_error is not None else self.default_on_error + ) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] not in ["http", "websocket"]: + await self.app(scope, receive, send) + return + + conn = HTTPConnection(scope) + try: + auth_result = await self.backend.authenticate(conn) + except AuthenticationError as exc: + response = self.on_error(conn, exc) + if scope["type"] == "websocket": + await send({"type": "websocket.close", "code": 1000}) + else: + await response(scope, receive, send) + return + + if auth_result is None: + auth_result = AuthCredentials(), UnauthenticatedUser() + scope["auth"], scope["user"] = auth_result + await self.app(scope, receive, send) + + @staticmethod + def default_on_error(conn: HTTPConnection, exc: Exception) -> Response: + return PlainTextResponse(str(exc), status_code=400) diff --git a/source/target-vendors/cp312/starlette/middleware/base.py b/source/target-vendors/cp312/starlette/middleware/base.py new file mode 100644 index 0000000..a7ecb80 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/base.py @@ -0,0 +1,248 @@ +from __future__ import annotations + +from collections.abc import AsyncGenerator, AsyncIterable, Awaitable, Callable, Mapping, MutableMapping +from typing import Any, TypeVar + +import anyio + +from starlette._utils import create_collapsing_task_group +from starlette.requests import ClientDisconnect, Request +from starlette.responses import Response +from starlette.types import ASGIApp, Message, Receive, Scope, Send + +RequestResponseEndpoint = Callable[[Request], Awaitable[Response]] +DispatchFunction = Callable[[Request, RequestResponseEndpoint], Awaitable[Response]] +BodyStreamGenerator = AsyncGenerator[bytes | MutableMapping[str, Any], None] +AsyncContentStream = AsyncIterable[str | bytes | memoryview | MutableMapping[str, Any]] +T = TypeVar("T") + + +class _CachedRequest(Request): + """ + If the user calls Request.body() from their dispatch function + we cache the entire request body in memory and pass that to downstream middlewares, + but if they call Request.stream() then all we do is send an + empty body so that downstream things don't hang forever. + """ + + def __init__(self, scope: Scope, receive: Receive): + super().__init__(scope, receive) + self._wrapped_rcv_disconnected = False + self._wrapped_rcv_consumed = False + self._wrapped_rc_stream = self.stream() + + async def wrapped_receive(self) -> Message: + # wrapped_rcv state 1: disconnected + if self._wrapped_rcv_disconnected: + # we've already sent a disconnect to the downstream app + # we don't need to wait to get another one + # (although most ASGI servers will just keep sending it) + return {"type": "http.disconnect"} + # wrapped_rcv state 1: consumed but not yet disconnected + if self._wrapped_rcv_consumed: + # since the downstream app has consumed us all that is left + # is to send it a disconnect + if self._is_disconnected: + # the middleware has already seen the disconnect + # since we know the client is disconnected no need to wait + # for the message + self._wrapped_rcv_disconnected = True + return {"type": "http.disconnect"} + # we don't know yet if the client is disconnected or not + # so we'll wait until we get that message + msg = await self.receive() + if msg["type"] != "http.disconnect": # pragma: no cover + # at this point a disconnect is all that we should be receiving + # if we get something else, things went wrong somewhere + raise RuntimeError(f"Unexpected message received: {msg['type']}") + self._wrapped_rcv_disconnected = True + return msg + + # wrapped_rcv state 3: not yet consumed + if getattr(self, "_body", None) is not None: + # body() was called, we return it even if the client disconnected + self._wrapped_rcv_consumed = True + return { + "type": "http.request", + "body": self._body, + "more_body": False, + } + elif self._stream_consumed: + # stream() was called to completion + # return an empty body so that downstream apps don't hang + # waiting for a disconnect + self._wrapped_rcv_consumed = True + return { + "type": "http.request", + "body": b"", + "more_body": False, + } + else: + # body() was never called and stream() wasn't consumed + try: + stream = self.stream() + chunk = await stream.__anext__() + self._wrapped_rcv_consumed = self._stream_consumed + return { + "type": "http.request", + "body": chunk, + "more_body": not self._stream_consumed, + } + except ClientDisconnect: + self._wrapped_rcv_disconnected = True + return {"type": "http.disconnect"} + + +class BaseHTTPMiddleware: + def __init__(self, app: ASGIApp, dispatch: DispatchFunction | None = None) -> None: + self.app = app + self.dispatch_func = self.dispatch if dispatch is None else dispatch + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http": + await self.app(scope, receive, send) + return + + request = _CachedRequest(scope, receive) + wrapped_receive = request.wrapped_receive + response_sent = anyio.Event() + app_exc: Exception | None = None + exception_already_raised = False + + async def call_next(request: Request) -> Response: + async def receive_or_disconnect() -> Message: + if response_sent.is_set(): + return {"type": "http.disconnect"} + + async with anyio.create_task_group() as task_group: + + async def wrap(func: Callable[[], Awaitable[T]]) -> T: + result = await func() + task_group.cancel_scope.cancel() + return result + + task_group.start_soon(wrap, response_sent.wait) + message = await wrap(wrapped_receive) + + if response_sent.is_set(): + return {"type": "http.disconnect"} + + return message + + async def send_no_error(message: Message) -> None: + try: + await send_stream.send(message) + except anyio.BrokenResourceError: + # recv_stream has been closed, i.e. response_sent has been set. + return + + if message["type"] == "http.response.pathsend" or ( + message["type"] == "http.response.body" and not message.get("more_body", False) + ): + await response_sent.wait() + + async def coro() -> None: + nonlocal app_exc + + with send_stream: + try: + await self.app(scope, receive_or_disconnect, send_no_error) + except Exception as exc: + app_exc = exc + + task_group.start_soon(coro) + + try: + message = await recv_stream.receive() + info = message.get("info", None) + if message["type"] == "http.response.debug" and info is not None: + message = await recv_stream.receive() + except anyio.EndOfStream: + if app_exc is not None: + nonlocal exception_already_raised + exception_already_raised = True + # Prevent `anyio.EndOfStream` from polluting app exception context. + # If both cause and context are None then the context is suppressed + # and `anyio.EndOfStream` is not present in the exception traceback. + # If exception cause is not None then it is propagated with + # reraising here. + # If exception has no cause but has context set then the context is + # propagated as a cause with the reraise. This is necessary in order + # to prevent `anyio.EndOfStream` from polluting the exception + # context. + raise app_exc from app_exc.__cause__ or app_exc.__context__ + raise RuntimeError("No response returned.") + + assert message["type"] == "http.response.start" + + async def body_stream() -> BodyStreamGenerator: + async for message in recv_stream: + if message["type"] == "http.response.pathsend": + yield message + break + assert message["type"] == "http.response.body", f"Unexpected message: {message}" + body = message.get("body", b"") + if body: + yield body + if not message.get("more_body", False): + break + + response = _StreamingResponse(status_code=message["status"], content=body_stream(), info=info) + response.raw_headers = message["headers"] + return response + + send_stream, recv_stream = anyio.create_memory_object_stream[Message]() + with recv_stream, send_stream: + async with create_collapsing_task_group() as task_group: + response = await self.dispatch_func(request, call_next) + await response(scope, wrapped_receive, send) + response_sent.set() + recv_stream.close() + if app_exc is not None and not exception_already_raised: + raise app_exc + + async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: + raise NotImplementedError() # pragma: no cover + + +class _StreamingResponse(Response): + def __init__( + self, + content: AsyncContentStream, + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + info: Mapping[str, Any] | None = None, + ) -> None: + self.info = info + self.body_iterator = content + self.status_code = status_code + self.media_type = media_type + self.init_headers(headers) + self.background = None + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if self.info is not None: + await send({"type": "http.response.debug", "info": self.info}) + await send( + { + "type": "http.response.start", + "status": self.status_code, + "headers": self.raw_headers, + } + ) + + should_close_body = True + async for chunk in self.body_iterator: + if isinstance(chunk, dict): + # We got an ASGI message which is not response body (eg: pathsend) + should_close_body = False + await send(chunk) + continue + await send({"type": "http.response.body", "body": chunk, "more_body": True}) + + if should_close_body: + await send({"type": "http.response.body", "body": b"", "more_body": False}) + + if self.background: + await self.background() diff --git a/source/target-vendors/cp312/starlette/middleware/body_limit.py b/source/target-vendors/cp312/starlette/middleware/body_limit.py new file mode 100644 index 0000000..159c70d --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/body_limit.py @@ -0,0 +1,132 @@ +from __future__ import annotations + +from typing import cast + +from starlette.datastructures import Headers +from starlette.exceptions import HTTPException +from starlette.responses import PlainTextResponse +from starlette.types import ASGIApp, Message, Receive, Scope, Send + +MAX_BODY_SIZE_SCOPE_KEY = "starlette.max_body_size" +_BODY_LIMIT_RESPONDER_SCOPE_KEY = "starlette._body_limit_responder" + + +class _Missing: + __slots__ = () + + +_MISSING = _Missing() + + +class _RequestBodyTooLarge(HTTPException): + def __init__(self) -> None: + super().__init__(status_code=413, detail="Content Too Large") + + +class _RequestBodyLimitResponseSent(Exception): + pass + + +class RequestBodyLimitMiddleware: + """Limit the total size of an HTTP request body.""" + + def __init__(self, app: ASGIApp, max_body_size: int) -> None: + self.app = app + self.max_body_size = max_body_size + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http": + return await self.app(scope, receive, send) + + responder = RequestBodyLimitResponder(self.app, self.max_body_size) + await responder(scope, receive, send) + + +class RequestBodyLimitResponder: + def __init__(self, app: ASGIApp, max_body_size: int) -> None: + self.app = app + self.max_body_size = max_body_size + self._scope: Scope | None = None + self._receive: Receive | None = None + self._send: Send | None = None + self.content_length: int | None = None + self.total_size = 0 + self.response_started = False + + @property + def scope(self) -> Scope: + assert self._scope is not None + return self._scope + + @property + def receive(self) -> Receive: + assert self._receive is not None + return self._receive + + @property + def send(self) -> Send: + assert self._send is not None + return self._send + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + previous_scope_limit = cast(int | _Missing, scope.get(MAX_BODY_SIZE_SCOPE_KEY, _MISSING)) + scope[MAX_BODY_SIZE_SCOPE_KEY] = self.max_body_size + + active_responder = cast(RequestBodyLimitResponder | None, scope.get(_BODY_LIMIT_RESPONDER_SCOPE_KEY)) + if active_responder is not None: + active_responder.max_body_size = self.max_body_size + if active_responder.total_size > active_responder.max_body_size: + raise _RequestBodyTooLarge + return await self.app(scope, receive, send) + + self._scope = scope + self._receive = receive + self._send = send + self.content_length = _get_content_length(scope) + scope[_BODY_LIMIT_RESPONDER_SCOPE_KEY] = self + + try: + await self.app(scope, self.receive_with_limit, self.send_with_limit) + except _RequestBodyTooLarge: + if self.response_started: + raise + response = PlainTextResponse("Content Too Large", status_code=413) + await response(scope, receive, send) + except _RequestBodyLimitResponseSent: + pass + finally: + scope.pop(_BODY_LIMIT_RESPONDER_SCOPE_KEY, None) + if isinstance(previous_scope_limit, _Missing): + scope.pop(MAX_BODY_SIZE_SCOPE_KEY, None) + else: + scope[MAX_BODY_SIZE_SCOPE_KEY] = previous_scope_limit + + async def receive_with_limit(self) -> Message: + if self.content_length is not None and self.content_length > self.max_body_size: + raise _RequestBodyTooLarge + + message = await self.receive() + if message["type"] == "http.request": + self.total_size += len(message.get("body", b"")) + if self.total_size > self.max_body_size: + raise _RequestBodyTooLarge + return message + + async def send_with_limit(self, message: Message) -> None: + if message["type"] == "http.response.start": + self.response_started = True + if self.content_length is not None and self.content_length > self.max_body_size: + response = PlainTextResponse("Content Too Large", status_code=413) + await response(self.scope, self.receive, self.send) + raise _RequestBodyLimitResponseSent + await self.send(message) + + +def _get_content_length(scope: Scope) -> int | None: + content_length = Headers(scope=scope).get("content-length") + if content_length is None: + return None + try: + return int(content_length) + except ValueError: + return None diff --git a/source/target-vendors/cp312/starlette/middleware/cors.py b/source/target-vendors/cp312/starlette/middleware/cors.py new file mode 100644 index 0000000..fe4c234 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/cors.py @@ -0,0 +1,177 @@ +from __future__ import annotations + +import functools +import re +from collections.abc import Collection + +from starlette.datastructures import Headers, MutableHeaders +from starlette.responses import PlainTextResponse, Response +from starlette.types import ASGIApp, Message, Receive, Scope, Send + +ALL_METHODS = ("DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT", "QUERY") +SAFELISTED_HEADERS = {"Accept", "Accept-Language", "Content-Language", "Content-Type"} + + +class CORSMiddleware: + def __init__( + self, + app: ASGIApp, + allow_origins: Collection[str] = (), + allow_methods: Collection[str] = ("GET",), + allow_headers: Collection[str] = (), + allow_credentials: bool = False, + allow_origin_regex: str | None = None, + allow_private_network: bool = False, + expose_headers: Collection[str] = (), + max_age: int = 600, + ) -> None: + if "*" in allow_methods: + allow_methods = ALL_METHODS + + compiled_allow_origin_regex = None + if allow_origin_regex is not None: + compiled_allow_origin_regex = re.compile(allow_origin_regex) + + allow_all_origins = "*" in allow_origins + allow_all_headers = "*" in allow_headers + preflight_explicit_allow_origin = not allow_all_origins or allow_credentials + + simple_headers: dict[str, str] = {} + if allow_all_origins: + simple_headers["Access-Control-Allow-Origin"] = "*" + if allow_credentials: + simple_headers["Access-Control-Allow-Credentials"] = "true" + if expose_headers: + simple_headers["Access-Control-Expose-Headers"] = ", ".join(expose_headers) + + preflight_headers: dict[str, str] = { + "Vary": "Origin, Access-Control-Request-Method, Access-Control-Request-Headers, Access-Control-Request-Private-Network" # noqa: E501 # fmt: skip + } + if not preflight_explicit_allow_origin: + preflight_headers["Access-Control-Allow-Origin"] = "*" + preflight_headers.update( + { + "Access-Control-Allow-Methods": ", ".join(allow_methods), + "Access-Control-Max-Age": str(max_age), + } + ) + allow_headers = sorted(SAFELISTED_HEADERS | set(allow_headers)) + if allow_headers and not allow_all_headers: + preflight_headers["Access-Control-Allow-Headers"] = ", ".join(allow_headers) + if allow_credentials: + preflight_headers["Access-Control-Allow-Credentials"] = "true" + + self.app = app + self.allow_origins = allow_origins + self.allow_methods = allow_methods + self.allow_headers = [h.lower() for h in allow_headers] + self.allow_all_origins = allow_all_origins + self.allow_all_headers = allow_all_headers + self.allow_credentials = allow_credentials + self.preflight_explicit_allow_origin = preflight_explicit_allow_origin + self.allow_origin_regex = compiled_allow_origin_regex + self.allow_private_network = allow_private_network + self.simple_headers = simple_headers + self.preflight_headers = preflight_headers + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http": # pragma: no cover + await self.app(scope, receive, send) + return + + method = scope["method"] + headers = Headers(scope=scope) + origin = headers.get("origin") + + if origin is not None and method == "OPTIONS" and "access-control-request-method" in headers: + response = self.preflight_response(request_headers=headers) + await response(scope, receive, send) + return + + await self.simple_response(scope, receive, send, request_headers=headers) + + def is_allowed_origin(self, origin: str) -> bool: + if self.allow_all_origins: + return True + + if self.allow_origin_regex is not None and self.allow_origin_regex.fullmatch(origin): + return True + + return origin in self.allow_origins + + def preflight_response(self, request_headers: Headers) -> Response: + requested_origin = request_headers["origin"] + requested_method = request_headers["access-control-request-method"] + requested_headers = request_headers.get("access-control-request-headers") + requested_private_network = request_headers.get("access-control-request-private-network") + + headers = dict(self.preflight_headers) + failures: list[str] = [] + + if self.is_allowed_origin(origin=requested_origin): + if self.preflight_explicit_allow_origin: + # The "else" case is already accounted for in self.preflight_headers + # and the value would be "*". + headers["Access-Control-Allow-Origin"] = requested_origin + else: + failures.append("origin") + + if requested_method not in self.allow_methods: + failures.append("method") + + # If we allow all headers, then we have to mirror back any requested + # headers in the response. + if self.allow_all_headers and requested_headers is not None: + headers["Access-Control-Allow-Headers"] = requested_headers + elif requested_headers is not None: + for header in [h.lower() for h in requested_headers.split(",")]: + if header.strip() not in self.allow_headers: + failures.append("headers") + break + + if requested_private_network is not None: + if self.allow_private_network: + headers["Access-Control-Allow-Private-Network"] = "true" + else: + failures.append("private-network") + + # We don't strictly need to use 400 responses here, since its up to + # the browser to enforce the CORS policy, but its more informative + # if we do. + if failures: + failure_text = "Disallowed CORS " + ", ".join(failures) + return PlainTextResponse(failure_text, status_code=400, headers=headers) + + return PlainTextResponse("OK", status_code=200, headers=headers) + + async def simple_response(self, scope: Scope, receive: Receive, send: Send, request_headers: Headers) -> None: + send = functools.partial(self.send, send=send, request_headers=request_headers) + await self.app(scope, receive, send) + + async def send(self, message: Message, send: Send, request_headers: Headers) -> None: + if message["type"] != "http.response.start": + await send(message) + return + + message.setdefault("headers", []) + headers = MutableHeaders(scope=message) + origin = request_headers.get("Origin") + if origin is not None: + headers.update(self.simple_headers) + + # If credentials are allowed, then we must respond with the specific origin instead of '*'. + if origin is not None and self.allow_all_origins and self.allow_credentials: + self.allow_explicit_origin(headers, origin) + + # If we only allow specific origins, then we have to mirror back the Origin header in the response. + elif origin is not None and not self.allow_all_origins and self.is_allowed_origin(origin=origin): + self.allow_explicit_origin(headers, origin) + else: + headers["Vary"] = ", ".join([*headers.getlist("Vary"), "Origin"]) + + await send(message) + + @staticmethod + def allow_explicit_origin(headers: MutableHeaders, origin: str) -> None: + headers["Access-Control-Allow-Origin"] = origin + headers["Vary"] = ", ".join([*headers.getlist("Vary"), "Origin"]) diff --git a/source/target-vendors/cp312/starlette/middleware/errors.py b/source/target-vendors/cp312/starlette/middleware/errors.py new file mode 100644 index 0000000..e0ebd65 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/errors.py @@ -0,0 +1,259 @@ +from __future__ import annotations + +import html +import inspect +import sys +import traceback + +from starlette._utils import is_async_callable +from starlette.concurrency import run_in_threadpool +from starlette.requests import Request +from starlette.responses import HTMLResponse, PlainTextResponse, Response +from starlette.types import ASGIApp, ExceptionHandler, Message, Receive, Scope, Send + +STYLES = """ +p { + color: #211c1c; +} +.traceback-container { + border: 1px solid #038BB8; +} +.traceback-title { + background-color: #038BB8; + color: lemonchiffon; + padding: 12px; + font-size: 20px; + margin-top: 0px; +} +.frame-line { + padding-left: 10px; + font-family: monospace; +} +.frame-filename { + font-family: monospace; +} +.center-line { + background-color: #038BB8; + color: #f9f6e1; + padding: 5px 0px 5px 5px; +} +.lineno { + margin-right: 5px; +} +.frame-title { + font-weight: unset; + padding: 10px 10px 10px 10px; + background-color: #E4F4FD; + margin-right: 10px; + color: #191f21; + font-size: 17px; + border: 1px solid #c7dce8; +} +.collapse-btn { + float: right; + padding: 0px 5px 1px 5px; + border: solid 1px #96aebb; + cursor: pointer; +} +.collapsed { + display: none; +} +.source-code { + font-family: courier; + font-size: small; + padding-bottom: 10px; +} +""" + +JS = """ + +""" + +TEMPLATE = """ + + + + Starlette Debugger + + +

      500 Server Error

      +

      {error}

      +
      +

      Traceback

      +
      {exc_html}
      +
      + {js} + + +""" + +FRAME_TEMPLATE = """ +
      +

      File {frame_filename}, + line {frame_lineno}, + in {frame_name} + {collapse_button} +

      +
      {code_context}
      +
      +""" # noqa: E501 + +LINE = """ +

      +{lineno}. {line}

      +""" + +CENTER_LINE = """ +

      +{lineno}. {line}

      +""" + + +class ServerErrorMiddleware: + """ + Handles returning 500 responses when a server error occurs. + + If 'debug' is set, then traceback responses will be returned, + otherwise the designated 'handler' will be called. + + This middleware class should generally be used to wrap *everything* + else up, so that unhandled exceptions anywhere in the stack + always result in an appropriate 500 response. + """ + + def __init__( + self, + app: ASGIApp, + handler: ExceptionHandler | None = None, + debug: bool = False, + ) -> None: + self.app = app + self.handler = handler + self.debug = debug + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http": + await self.app(scope, receive, send) + return + + response_started = False + + async def _send(message: Message) -> None: + nonlocal response_started, send + + if message["type"] == "http.response.start": + response_started = True + await send(message) + + try: + await self.app(scope, receive, _send) + except Exception as exc: + request = Request(scope) + if self.debug: + # In debug mode, return traceback responses. + response = await run_in_threadpool(self.debug_response, request, exc) + elif self.handler is None: + # Use our default 500 error handler. + response = self.error_response(request, exc) + else: + # Use an installed 500 error handler. + if is_async_callable(self.handler): + response = await self.handler(request, exc) # type: ignore[assignment, arg-type] + else: + response = await run_in_threadpool(self.handler, request, exc) # type: ignore[arg-type] + + if not response_started: + await response(scope, receive, send) + + # We always continue to raise the exception. + # This allows servers to log the error, or allows test clients + # to optionally raise the error within the test case. + raise exc + + def format_line(self, index: int, line: str, frame_lineno: int, frame_index: int) -> str: + values = { + # HTML escape - line could contain < or > + "line": html.escape(line).replace(" ", " "), + "lineno": (frame_lineno - frame_index) + index, + } + + if index != frame_index: + return LINE.format(**values) + return CENTER_LINE.format(**values) + + def generate_frame_html(self, frame: inspect.FrameInfo, is_collapsed: bool) -> str: + code_context = "".join( + self.format_line( + index, + line, + frame.lineno, + frame.index, # type: ignore[arg-type] + ) + for index, line in enumerate(frame.code_context or []) + ) + + values = { + # HTML escape - filename could contain < or >, especially if it's a virtual + # file e.g. in the REPL + "frame_filename": html.escape(frame.filename), + "frame_lineno": frame.lineno, + # HTML escape - if you try very hard it's possible to name a function with < + # or > + "frame_name": html.escape(frame.function), + "code_context": code_context, + "collapsed": "collapsed" if is_collapsed else "", + "collapse_button": "+" if is_collapsed else "‒", + } + return FRAME_TEMPLATE.format(**values) + + def generate_html(self, exc: Exception, limit: int = 7) -> str: + traceback_obj = traceback.TracebackException.from_exception(exc, capture_locals=True) + + exc_html = "" + is_collapsed = False + exc_traceback = exc.__traceback__ + if exc_traceback is not None: + frames = inspect.getinnerframes(exc_traceback, limit) + for frame in reversed(frames): + exc_html += self.generate_frame_html(frame, is_collapsed) + is_collapsed = True + + if sys.version_info >= (3, 13): # pragma: no cover + exc_type_str = traceback_obj.exc_type_str + else: # pragma: no cover + exc_type_str = traceback_obj.exc_type.__name__ + + # escape error class and text + error = f"{html.escape(exc_type_str)}: {html.escape(str(traceback_obj))}" + + return TEMPLATE.format(styles=STYLES, js=JS, error=error, exc_html=exc_html) + + def generate_plain_text(self, exc: Exception) -> str: + return "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)) + + def debug_response(self, request: Request, exc: Exception) -> Response: + accept = request.headers.get("accept", "") + + if "text/html" in accept: + content = self.generate_html(exc) + return HTMLResponse(content, status_code=500) + content = self.generate_plain_text(exc) + return PlainTextResponse(content, status_code=500) + + def error_response(self, request: Request, exc: Exception) -> Response: + return PlainTextResponse("Internal Server Error", status_code=500) diff --git a/source/target-vendors/cp312/starlette/middleware/exceptions.py b/source/target-vendors/cp312/starlette/middleware/exceptions.py new file mode 100644 index 0000000..6c98558 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/exceptions.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any + +from starlette._exception_handler import ( + ExceptionHandlers, + StatusHandlers, + wrap_app_handling_exceptions, +) +from starlette.exceptions import HTTPException, WebSocketException +from starlette.requests import Request +from starlette.responses import PlainTextResponse, Response +from starlette.types import ASGIApp, ExceptionHandler, Receive, Scope, Send +from starlette.websockets import WebSocket + + +class ExceptionMiddleware: + def __init__( + self, + app: ASGIApp, + handlers: Mapping[Any, ExceptionHandler] | None = None, + debug: bool = False, + ) -> None: + self.app = app + self.debug = debug # TODO: We ought to handle 404 cases if debug is set. + self._status_handlers: StatusHandlers = {} + self._exception_handlers: ExceptionHandlers = { + HTTPException: self.http_exception, + WebSocketException: self.websocket_exception, + } + if handlers is not None: # pragma: no branch + for key, value in handlers.items(): + self.add_exception_handler(key, value) + + def add_exception_handler( + self, + exc_class_or_status_code: int | type[Exception], + handler: ExceptionHandler, + ) -> None: + if isinstance(exc_class_or_status_code, int): + self._status_handlers[exc_class_or_status_code] = handler + else: + assert issubclass(exc_class_or_status_code, Exception) + self._exception_handlers[exc_class_or_status_code] = handler + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] not in ("http", "websocket"): + await self.app(scope, receive, send) + return + + scope["starlette.exception_handlers"] = ( + self._exception_handlers, + self._status_handlers, + ) + + conn: Request | WebSocket + if scope["type"] == "http": + conn = Request(scope, receive, send) + else: + conn = WebSocket(scope, receive, send) + + await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) + + async def http_exception(self, request: Request, exc: Exception) -> Response: + assert isinstance(exc, HTTPException) + if exc.status_code in {204, 304}: + return Response(status_code=exc.status_code, headers=exc.headers) + return PlainTextResponse(exc.detail, status_code=exc.status_code, headers=exc.headers) + + async def websocket_exception(self, websocket: WebSocket, exc: Exception) -> None: + assert isinstance(exc, WebSocketException) + await websocket.close(code=exc.code, reason=exc.reason) # pragma: no cover diff --git a/source/target-vendors/cp312/starlette/middleware/gzip.py b/source/target-vendors/cp312/starlette/middleware/gzip.py new file mode 100644 index 0000000..4473f5a --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/gzip.py @@ -0,0 +1,222 @@ +from __future__ import annotations + +import zlib +from typing import NoReturn + +import anyio.lowlevel +import anyio.to_thread + +from starlette.datastructures import Headers, MutableHeaders +from starlette.types import ASGIApp, Message, Receive, Scope, Send + +# TODO(v2): We should rename `DEFAULT_EXCLUDED_CONTENT_TYPES` to `DEFAULT_EXCLUDE_CONTENT_TYPES`. +DEFAULT_EXCLUDED_CONTENT_TYPES = ( + "application/gzip", + "application/x-gzip", + "application/zip", + "audio/*", + "font/woff", + "font/woff2", + "image/avif", + "image/gif", + "image/jpeg", + "image/png", + "image/webp", + "text/event-stream", + "video/*", +) + +_gzip_capacity_limiter: anyio.lowlevel.RunVar[anyio.CapacityLimiter] = anyio.lowlevel.RunVar("_gzip_capacity_limiter") + + +def _get_gzip_capacity_limiter() -> anyio.CapacityLimiter: + """Return the capacity limiter used for worker-thread GZip compression.""" + try: + return _gzip_capacity_limiter.get() + except LookupError: + # Keep gzip compression isolated from AnyIO's default worker-thread + # capacity limiter while matching its default concurrency. + limiter = anyio.CapacityLimiter(40) + _gzip_capacity_limiter.set(limiter) + return limiter + + +class GZipMiddleware: + def __init__( + self, + app: ASGIApp, + minimum_size: int = 500, + compresslevel: int = 9, + thread_minimum_size: int = 128 * 1024, # 128 KiB + *, + exclude_content_types: tuple[str, ...] = DEFAULT_EXCLUDED_CONTENT_TYPES, + ) -> None: + self.app = app + self.minimum_size = minimum_size + self.compresslevel = compresslevel + self.thread_minimum_size = thread_minimum_size + self.exclude_content_types = _normalize_content_types(exclude_content_types) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http": # pragma: no cover + await self.app(scope, receive, send) + return + + headers = Headers(scope=scope) + responder: ASGIApp + if "gzip" in headers.get("Accept-Encoding", ""): + responder = GZipResponder( + self.app, + self.minimum_size, + compresslevel=self.compresslevel, + thread_minimum_size=self.thread_minimum_size, + exclude_content_types=self.exclude_content_types, + ) + else: + responder = IdentityResponder(self.app, self.minimum_size, exclude_content_types=self.exclude_content_types) + + await responder(scope, receive, send) + + +class IdentityResponder: + content_encoding: str + + def __init__( + self, + app: ASGIApp, + minimum_size: int, + *, + exclude_content_types: tuple[str, ...] = DEFAULT_EXCLUDED_CONTENT_TYPES, + ) -> None: + self.app = app + self.minimum_size = minimum_size + self.exclude_content_types = _normalize_content_types(exclude_content_types) + self.send: Send = unattached_send + self.initial_message: Message = {} + self.started = False + self.content_encoding_set = False + self.content_type_is_excluded = False + self.partial_response = False + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + self.send = send + await self.app(scope, receive, self.send_with_compression) + + async def send_with_compression(self, message: Message) -> None: + message_type = message["type"] + if message_type == "http.response.start": + # Don't send the initial message until we've determined how to + # modify the outgoing headers correctly. + self.initial_message = message + headers = Headers(raw=self.initial_message["headers"]) + self.content_encoding_set = "content-encoding" in headers + self.partial_response = message["status"] == 206 + media_type = headers.get("content-type", "").partition(";")[0].strip().lower() + media_types = {media_type, media_type.partition("/")[0] + "/*"} + self.content_type_is_excluded = not media_types.isdisjoint(self.exclude_content_types) + elif message_type == "http.response.body" and ( + self.content_encoding_set or self.partial_response or self.content_type_is_excluded + ): + if not self.started: + self.started = True + await self.send(self.initial_message) + await self.send(message) + elif message_type == "http.response.body" and not self.started: + self.started = True + body = message.get("body", b"") + more_body = message.get("more_body", False) + if len(body) < self.minimum_size and not more_body: + # Don't apply compression to small outgoing responses. + await self.send(self.initial_message) + await self.send(message) + elif not more_body: + # Standard response. + body = await self.apply_compression(body, more_body=False) + + headers = MutableHeaders(raw=self.initial_message["headers"]) + headers.add_vary_header("Accept-Encoding") + if body != message["body"]: + headers["Content-Encoding"] = self.content_encoding + headers["Content-Length"] = str(len(body)) + message["body"] = body + + await self.send(self.initial_message) + await self.send(message) + else: + # Initial body in streaming response. + body = await self.apply_compression(body, more_body=True) + + headers = MutableHeaders(raw=self.initial_message["headers"]) + headers.add_vary_header("Accept-Encoding") + if body != message["body"]: + headers["Content-Encoding"] = self.content_encoding + del headers["Content-Length"] + message["body"] = body + + await self.send(self.initial_message) + await self.send(message) + elif message_type == "http.response.body": + # Remaining body in streaming response. + body = message.get("body", b"") + more_body = message.get("more_body", False) + + message["body"] = await self.apply_compression(body, more_body=more_body) + + await self.send(message) + elif message_type == "http.response.pathsend": # pragma: no branch + # Don't apply GZip to pathsend responses + await self.send(self.initial_message) + await self.send(message) + + async def apply_compression(self, body: bytes, *, more_body: bool) -> bytes: + """Apply compression on the response body. + + If more_body is False, the compression stream is finalized. Compression + resources are only allocated once a body is actually compressed. + """ + return body + + +class GZipResponder(IdentityResponder): + content_encoding = "gzip" + + def __init__( + self, + app: ASGIApp, + minimum_size: int, + compresslevel: int = 9, + *, + thread_minimum_size: int = 128 * 1024, # 128 KiB + exclude_content_types: tuple[str, ...] = DEFAULT_EXCLUDED_CONTENT_TYPES, + ) -> None: + super().__init__(app, minimum_size, exclude_content_types=exclude_content_types) + + self.compresslevel = compresslevel + self.thread_minimum_size = thread_minimum_size + self._compressor: zlib._Compress | None = None + + @property + def compressor(self) -> zlib._Compress: + if self._compressor is None: + self._compressor = zlib.compressobj(self.compresslevel, zlib.DEFLATED, 16 + zlib.MAX_WBITS) + return self._compressor + + async def apply_compression(self, body: bytes, *, more_body: bool) -> bytes: + if len(body) >= self.thread_minimum_size: + # Compressing large chunks inline would block the event loop. + limiter = _get_gzip_capacity_limiter() + return await anyio.to_thread.run_sync(self._compress_body, body, more_body, limiter=limiter) + return self._compress_body(body, more_body) + + def _compress_body(self, body: bytes, more_body: bool) -> bytes: + if more_body: + return self.compressor.compress(body) + self.compressor.flush(zlib.Z_SYNC_FLUSH) + return self.compressor.compress(body) + self.compressor.flush() + + +async def unattached_send(message: Message) -> NoReturn: + raise RuntimeError("send awaitable not set") # pragma: no cover + + +def _normalize_content_types(content_types: tuple[str, ...]) -> tuple[str, ...]: + return tuple(content_type.partition(";")[0].strip().lower() for content_type in content_types) diff --git a/source/target-vendors/cp312/starlette/middleware/httpsredirect.py b/source/target-vendors/cp312/starlette/middleware/httpsredirect.py new file mode 100644 index 0000000..da40919 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/httpsredirect.py @@ -0,0 +1,22 @@ +from starlette.datastructures import URL +from starlette.responses import PlainTextResponse, RedirectResponse +from starlette.types import ASGIApp, Receive, Scope, Send + + +class HTTPSRedirectMiddleware: + def __init__(self, app: ASGIApp) -> None: + self.app = app + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] in ("http", "websocket") and scope["scheme"] in ("http", "ws"): + url = URL(scope=scope) + if not url.netloc: + await PlainTextResponse("Invalid host header", status_code=400)(scope, receive, send) + return + redirect_scheme = {"http": "https", "ws": "wss"}[url.scheme] + netloc = url.hostname if url.port in (80, 443) else url.netloc + url = url.replace(scheme=redirect_scheme, netloc=netloc) + response = RedirectResponse(url, status_code=307) + await response(scope, receive, send) + else: + await self.app(scope, receive, send) diff --git a/source/target-vendors/cp312/starlette/middleware/opentelemetry.py b/source/target-vendors/cp312/starlette/middleware/opentelemetry.py new file mode 100644 index 0000000..666766c --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/opentelemetry.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import re +from collections.abc import Sequence + +try: + from opentelemetry import metrics, propagate, trace + from opentelemetry.trace import SpanKind, Status, StatusCode +except ImportError: # pragma: no cover + raise ImportError("The `opentelemetry-api` package is required to use `OpenTelemetryMiddleware`.") from None + +from starlette import __version__ +from starlette.datastructures import URL +from starlette.routing import Mount +from starlette.types import ASGIApp, Message, Receive, Scope, Send + + +class OpenTelemetryMiddleware: + """Create OpenTelemetry server spans for incoming HTTP requests. + + This middleware is experimental. Its API and emitted telemetry may change in minor + releases without a deprecation period. + + Args: + app: The ASGI application to wrap. + excluded_urls: Regular expressions matched against the full request URL. + Pass a comma-separated string or a sequence. By default, exclude no URLs. + tracer_provider: Optional tracer provider. If omitted, use the global tracer provider. + meter_provider: Optional meter provider. If omitted, use the global meter provider. + """ + + def __init__( + self, + app: ASGIApp, + *, + excluded_urls: str | Sequence[str] = (), + tracer_provider: trace.TracerProvider | None = None, + meter_provider: metrics.MeterProvider | None = None, + ) -> None: + self.app = app + self._meter_provider = meter_provider + if isinstance(excluded_urls, str): + excluded_urls = [pattern.strip() for pattern in excluded_urls.split(",")] if excluded_urls else () + self._excluded_urls = tuple(re.compile(pattern) for pattern in excluded_urls) + self._tracer_provider = tracer_provider or trace.get_tracer_provider() + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] != "http" or scope.get("starlette.opentelemetry"): + return await self.app(scope, receive, send) + + scope["starlette.opentelemetry"] = True + try: + tracer_provider = self._tracer_provider + if isinstance(tracer_provider, trace.NoOpTracerProvider): + return await self.app(scope, receive, send) + + url = URL(scope=scope) + if any(pattern.search(str(url)) for pattern in self._excluded_urls): + return await self.app(scope, receive, send) + + original_method = scope.get("method", "") + method = original_method.upper() + + headers: dict[str, list[str]] = {} + for name, value in scope.get("headers", []): + headers.setdefault(name.decode("latin-1").lower(), []).append(value.decode("latin-1")) + + attributes: dict[str, str | int] = { + "http.request.method": method, + "url.path": scope.get("path", ""), + "url.scheme": scope.get("scheme", "http"), + } + if original_method != method: + attributes["http.request.method_original"] = original_method + if url.query: + attributes["url.query"] = url.query + if url.hostname is not None: + attributes["server.address"] = url.hostname + server = scope.get("server") + server_port = url.port if url.port is not None else server[1] if server is not None else None + if server_port is not None: + attributes["server.port"] = server_port + if scope.get("http_version"): + attributes["network.protocol.version"] = scope["http_version"] + if scope.get("client") is not None: + attributes["client.address"] = scope["client"][0] + if headers.get("user-agent"): + attributes["user_agent.original"] = headers["user-agent"][0] + + with tracer_provider.get_tracer("starlette", __version__).start_as_current_span( + method, + context=propagate.extract(headers), + kind=SpanKind.SERVER, + attributes=attributes, + ) as span: + + async def send_with_telemetry(message: Message) -> None: + if message["type"] == "http.response.start": + status_code = message["status"] + span.set_attribute("http.response.status_code", status_code) + if status_code >= 500: + span.set_attribute("error.type", str(status_code)) + span.set_status(Status(StatusCode.ERROR)) + await send(message) + + try: + await self.app(scope, receive, send_with_telemetry) + except Exception as exc: + span.set_attribute("error.type", type(exc).__qualname__) + raise + finally: + route = scope.get("route") + if isinstance(route, Mount): + route_path = scope.get("root_path") or "/" + else: + path_format = getattr(route, "path_format", None) + route_path = ( + scope.get("root_path", "").rstrip("/") + path_format or "/" + if isinstance(path_format, str) + else None + ) + if route_path is not None: + span.update_name(f"{method} {route_path}") + span.set_attribute("http.route", route_path) + finally: + del scope["starlette.opentelemetry"] diff --git a/source/target-vendors/cp312/starlette/middleware/sessions.py b/source/target-vendors/cp312/starlette/middleware/sessions.py new file mode 100644 index 0000000..efe5e9e --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/sessions.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +import json +import typing +from base64 import b64decode, b64encode +from typing import Literal + +import itsdangerous +from itsdangerous.exc import BadSignature + +from starlette.datastructures import MutableHeaders, Secret +from starlette.requests import HTTPConnection +from starlette.types import ASGIApp, Message, Receive, Scope, Send + + +class SessionMiddleware: + def __init__( + self, + app: ASGIApp, + secret_key: str | Secret, + session_cookie: str = "session", + max_age: int | None = 14 * 24 * 60 * 60, # 14 days, in seconds + path: str = "/", + same_site: Literal["lax", "strict", "none"] = "lax", + https_only: bool = False, + domain: str | None = None, + partitioned: bool = False, + ) -> None: + self.app = app + self.signer = itsdangerous.TimestampSigner(str(secret_key)) + self.session_cookie = session_cookie + self.max_age = max_age + self.path = path + self.security_flags = "httponly; samesite=" + same_site + if https_only: # Secure flag can be used with HTTPS only + self.security_flags += "; secure" + if domain is not None: + self.security_flags += f"; domain={domain}" + if partitioned: + self.security_flags += "; partitioned" + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] not in ("http", "websocket"): # pragma: no cover + await self.app(scope, receive, send) + return + + connection = HTTPConnection(scope) + initial_session_was_empty = True + + if self.session_cookie in connection.cookies: + data = connection.cookies[self.session_cookie].encode("utf-8") + try: + data = self.signer.unsign(data, max_age=self.max_age) + scope["session"] = Session(json.loads(b64decode(data))) + initial_session_was_empty = False + except BadSignature: + scope["session"] = Session() + else: + scope["session"] = Session() + + async def send_wrapper(message: Message) -> None: + if message["type"] == "http.response.start": + session: Session = scope["session"] + headers = MutableHeaders(scope=message) + if session.accessed: + headers.add_vary_header("Cookie") + if session.modified and session: + # We have session data to persist. + data = b64encode(json.dumps(session).encode("utf-8")) + data = self.signer.sign(data) + header_value = "{session_cookie}={data}; path={path}; {max_age}{security_flags}".format( + session_cookie=self.session_cookie, + data=data.decode("utf-8"), + path=self.path, + max_age=f"Max-Age={self.max_age}; " if self.max_age else "", + security_flags=self.security_flags, + ) + headers.append("Set-Cookie", header_value) + elif session.modified and not initial_session_was_empty: + # The session has been cleared. + header_value = "{session_cookie}={data}; path={path}; {expires}{security_flags}".format( + session_cookie=self.session_cookie, + data="null", + path=self.path, + expires="expires=Thu, 01 Jan 1970 00:00:00 GMT; ", + security_flags=self.security_flags, + ) + headers.append("Set-Cookie", header_value) + await send(message) + + await self.app(scope, receive, send_wrapper) + + +class Session(dict[str, typing.Any]): + accessed: bool = False + modified: bool = False + + def mark_accessed(self) -> None: + self.accessed = True + + def mark_modified(self) -> None: + self.accessed = True + self.modified = True + + def __setitem__(self, key: str, value: typing.Any) -> None: + self.mark_modified() + super().__setitem__(key, value) + + def __delitem__(self, key: str) -> None: + self.mark_modified() + super().__delitem__(key) + + def clear(self) -> None: + self.mark_modified() + super().clear() + + def pop(self, key: str, *args: typing.Any) -> typing.Any: + self.modified = self.modified or key in self + return super().pop(key, *args) + + def popitem(self) -> tuple[str, typing.Any]: + item = super().popitem() + self.mark_modified() + return item + + def setdefault(self, key: str, default: typing.Any = None) -> typing.Any: + if key not in self: + self.mark_modified() + return super().setdefault(key, default) + + def update(self, *args: typing.Any, **kwargs: typing.Any) -> None: + self.mark_modified() + super().update(*args, **kwargs) + + def __ior__(self, other: typing.Any, /) -> Session: # type: ignore[override,misc] + self.mark_modified() + return super().__ior__(other) diff --git a/source/target-vendors/cp312/starlette/middleware/trustedhost.py b/source/target-vendors/cp312/starlette/middleware/trustedhost.py new file mode 100644 index 0000000..c57aa9a --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/trustedhost.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from collections.abc import Sequence + +from starlette._utils import parse_host_header +from starlette.datastructures import URL, Headers +from starlette.responses import PlainTextResponse, RedirectResponse, Response +from starlette.types import ASGIApp, Receive, Scope, Send + +ENFORCE_DOMAIN_WILDCARD = "Domain wildcard patterns must be like '*.example.com'." + + +class TrustedHostMiddleware: + def __init__( + self, + app: ASGIApp, + allowed_hosts: Sequence[str] | None = None, + www_redirect: bool = True, + ) -> None: + if allowed_hosts is None: + allowed_hosts = ["*"] + + for pattern in allowed_hosts: + assert "*" not in pattern[1:], ENFORCE_DOMAIN_WILDCARD + if pattern.startswith("*") and pattern != "*": + assert pattern.startswith("*."), ENFORCE_DOMAIN_WILDCARD + self.app = app + self.allowed_hosts = list(allowed_hosts) + self.allow_any = "*" in allowed_hosts + self.www_redirect = www_redirect + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if self.allow_any or scope["type"] not in ( + "http", + "websocket", + ): # pragma: no cover + await self.app(scope, receive, send) + return + + headers = Headers(scope=scope) + parsed_host = parse_host_header(headers.get("host")) + if parsed_host is None: + await PlainTextResponse("Invalid host header", status_code=400)(scope, receive, send) + return + host = parsed_host.host + + is_valid_host = False + found_www_redirect = False + for pattern in self.allowed_hosts: + if host == pattern or (pattern.startswith("*") and host.endswith(pattern[1:])): + is_valid_host = True + break + elif "www." + host == pattern: + found_www_redirect = True + + if is_valid_host: + await self.app(scope, receive, send) + else: + response: Response + if found_www_redirect and self.www_redirect: + url = URL(scope=scope) + redirect_url = url.replace(netloc="www." + url.netloc) + response = RedirectResponse(url=str(redirect_url)) + else: + response = PlainTextResponse("Invalid host header", status_code=400) + await response(scope, receive, send) diff --git a/source/target-vendors/cp312/starlette/middleware/wsgi.py b/source/target-vendors/cp312/starlette/middleware/wsgi.py new file mode 100644 index 0000000..0871926 --- /dev/null +++ b/source/target-vendors/cp312/starlette/middleware/wsgi.py @@ -0,0 +1,157 @@ +from __future__ import annotations + +import io +import math +import sys +import warnings +from collections.abc import Callable, MutableMapping +from typing import Any + +import anyio.from_thread +import anyio.to_thread +from anyio.abc import ObjectReceiveStream, ObjectSendStream + +from starlette._utils import create_collapsing_task_group +from starlette.exceptions import StarletteDeprecationWarning +from starlette.types import Receive, Scope, Send + +warnings.warn( + "starlette.middleware.wsgi is deprecated and will be removed in a future release. " + "Please refer to https://github.com/abersheeran/a2wsgi as a replacement.", + StarletteDeprecationWarning, + stacklevel=2, +) + + +def build_environ(scope: Scope, body: bytes) -> dict[str, Any]: + """ + Builds a scope and request body into a WSGI environ object. + """ + + script_name = scope.get("root_path", "").encode("utf8").decode("latin1") + path_info = scope["path"].encode("utf8").decode("latin1") + if path_info.startswith(script_name): + path_info = path_info[len(script_name) :] + + environ = { + "REQUEST_METHOD": scope["method"], + "SCRIPT_NAME": script_name, + "PATH_INFO": path_info, + "QUERY_STRING": scope["query_string"].decode("ascii"), + "SERVER_PROTOCOL": f"HTTP/{scope['http_version']}", + "wsgi.version": (1, 0), + "wsgi.url_scheme": scope.get("scheme", "http"), + "wsgi.input": io.BytesIO(body), + "wsgi.errors": sys.stdout, + "wsgi.multithread": True, + "wsgi.multiprocess": True, + "wsgi.run_once": False, + } + + # Get server name and port - required in WSGI, not in ASGI + server = scope.get("server") or ("localhost", 80) + environ["SERVER_NAME"] = server[0] + environ["SERVER_PORT"] = server[1] + + # Get client IP address + if scope.get("client"): + environ["REMOTE_ADDR"] = scope["client"][0] + + # Go through headers and make them into environ entries + for name, value in scope.get("headers", []): + name = name.decode("latin1") + if name == "content-length": + corrected_name = "CONTENT_LENGTH" + elif name == "content-type": + corrected_name = "CONTENT_TYPE" + else: + corrected_name = f"HTTP_{name}".upper().replace("-", "_") + # HTTPbis say only ASCII chars are allowed in headers, but we latin1 just in + # case + value = value.decode("latin1") + if corrected_name in environ: + value = environ[corrected_name] + "," + value + environ[corrected_name] = value + return environ + + +class WSGIMiddleware: + def __init__(self, app: Callable[..., Any]) -> None: + self.app = app + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + assert scope["type"] == "http" + responder = WSGIResponder(self.app, scope) + await responder(receive, send) + + +class WSGIResponder: + stream_send: ObjectSendStream[MutableMapping[str, Any]] + stream_receive: ObjectReceiveStream[MutableMapping[str, Any]] + + def __init__(self, app: Callable[..., Any], scope: Scope) -> None: + self.app = app + self.scope = scope + self.status = None + self.response_headers = None + self.stream_send, self.stream_receive = anyio.create_memory_object_stream(math.inf) + self.response_started = False + self.exc_info: Any = None + + async def __call__(self, receive: Receive, send: Send) -> None: + body = b"" + more_body = True + while more_body: + message = await receive() + body += message.get("body", b"") + more_body = message.get("more_body", False) + environ = build_environ(self.scope, body) + + async with create_collapsing_task_group() as task_group: + task_group.start_soon(self.sender, send) + async with self.stream_send: + await anyio.to_thread.run_sync(self.wsgi, environ, self.start_response) + if self.exc_info is not None: + raise self.exc_info[0].with_traceback(self.exc_info[1], self.exc_info[2]) + + async def sender(self, send: Send) -> None: + async with self.stream_receive: + async for message in self.stream_receive: + await send(message) + + def start_response( + self, + status: str, + response_headers: list[tuple[str, str]], + exc_info: Any = None, + ) -> None: + self.exc_info = exc_info + if not self.response_started: # pragma: no branch + self.response_started = True + status_code_string, _ = status.split(" ", 1) + status_code = int(status_code_string) + headers = [ + (name.strip().encode("ascii").lower(), value.strip().encode("ascii")) + for name, value in response_headers + ] + anyio.from_thread.run( + self.stream_send.send, + { + "type": "http.response.start", + "status": status_code, + "headers": headers, + }, + ) + + def wsgi( + self, + environ: dict[str, Any], + start_response: Callable[..., Any], + ) -> None: + for chunk in self.app(environ, start_response): + anyio.from_thread.run( + self.stream_send.send, + {"type": "http.response.body", "body": chunk, "more_body": True}, + ) + + anyio.from_thread.run(self.stream_send.send, {"type": "http.response.body", "body": b""}) diff --git a/source/target-vendors/cp312/starlette/py.typed b/source/target-vendors/cp312/starlette/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/starlette/requests.py b/source/target-vendors/cp312/starlette/requests.py new file mode 100644 index 0000000..d4f3f4b --- /dev/null +++ b/source/target-vendors/cp312/starlette/requests.py @@ -0,0 +1,348 @@ +from __future__ import annotations + +import json +import sys +from collections.abc import AsyncGenerator, Iterator, Mapping +from http import cookies as http_cookies +from typing import TYPE_CHECKING, Any, Generic, NoReturn, cast + +import anyio + +from starlette._utils import AwaitableOrContextManager, AwaitableOrContextManagerWrapper +from starlette.datastructures import URL, Address, FormData, Headers, QueryParams, State +from starlette.exceptions import HTTPException +from starlette.formparsers import FormParser, MultiPartException, MultiPartParser +from starlette.types import Message, Receive, Scope, Send + +if TYPE_CHECKING: + from python_multipart.multipart import parse_options_header + + from starlette.applications import Starlette + from starlette.middleware.sessions import Session + from starlette.routing import Router +else: + try: + try: + from python_multipart.multipart import parse_options_header + except ModuleNotFoundError: # pragma: no cover + from multipart.multipart import parse_options_header + except ModuleNotFoundError: # pragma: no cover + parse_options_header = None + +if sys.version_info >= (3, 13): # pragma: no cover + from typing import TypeVar +else: # pragma: no cover + from typing_extensions import TypeVar + +SERVER_PUSH_HEADERS_TO_COPY = { + "accept", + "accept-encoding", + "accept-language", + "cache-control", + "user-agent", +} + + +def cookie_parser(cookie_string: str) -> dict[str, str]: + """ + This function parses a ``Cookie`` HTTP header into a dict of key/value pairs. + + It attempts to mimic browser cookie parsing behavior: browsers and web servers + frequently disregard the spec (RFC 6265) when setting and reading cookies, + so we attempt to suit the common scenarios here. + + This function has been adapted from Django 3.1.0. + Note: we are explicitly _NOT_ using `SimpleCookie.load` because it is based + on an outdated spec and will fail on lots of input we want to support + """ + cookie_dict: dict[str, str] = {} + for chunk in cookie_string.split(";"): + if "=" in chunk: + key, val = chunk.split("=", 1) + else: + # Assume an empty name per + # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 + key, val = "", chunk + key, val = key.strip(), val.strip() + if key or val: + # unquote using Python's algorithm. + cookie_dict[key] = http_cookies._unquote(val) + return cookie_dict + + +class ClientDisconnect(Exception): + pass + + +StateT = TypeVar("StateT", bound=Mapping[str, Any] | State, default=State) + + +class HTTPConnection(Mapping[str, Any], Generic[StateT]): + """ + A base class for incoming HTTP connections, that is used to provide + any functionality that is common to both `Request` and `WebSocket`. + """ + + def __init__(self, scope: Scope, receive: Receive | None = None) -> None: + assert scope["type"] in ("http", "websocket") + self.scope = scope + + def __getitem__(self, key: str) -> Any: + return self.scope[key] + + def __iter__(self) -> Iterator[str]: + return iter(self.scope) + + def __len__(self) -> int: + return len(self.scope) + + # Don't use the `abc.Mapping.__eq__` implementation. + # Connection instances should never be considered equal + # unless `self is other`. + __eq__ = object.__eq__ + __hash__ = object.__hash__ + + @property + def app(self) -> Any: + return self.scope["app"] + + @property + def url(self) -> URL: + if not hasattr(self, "_url"): # pragma: no branch + self._url = URL(scope=self.scope) + return self._url + + @property + def base_url(self) -> URL: + if not hasattr(self, "_base_url"): + base_url_scope = dict(self.scope) + # This is used by request.url_for, it might be used inside a Mount which + # would have its own child scope with its own root_path, but the base URL + # for url_for should still be the top level app root path. + app_root_path = base_url_scope.get("app_root_path", base_url_scope.get("root_path", "")) + path = app_root_path + if not path.endswith("/"): + path += "/" + base_url_scope["path"] = path + base_url_scope["query_string"] = b"" + base_url_scope["root_path"] = app_root_path + self._base_url = URL(scope=base_url_scope) + return self._base_url + + @property + def headers(self) -> Headers: + if not hasattr(self, "_headers"): + self._headers = Headers(scope=self.scope) + return self._headers + + @property + def query_params(self) -> QueryParams: + if not hasattr(self, "_query_params"): # pragma: no branch + self._query_params = QueryParams(self.scope["query_string"]) + return self._query_params + + @property + def path_params(self) -> dict[str, Any]: + path_params: dict[str, Any] = self.scope.get("path_params", {}) + return path_params + + @property + def cookies(self) -> dict[str, str]: + if not hasattr(self, "_cookies"): + cookies: dict[str, str] = {} + cookie_headers = self.headers.getlist("cookie") + + for header in cookie_headers: + cookies.update(cookie_parser(header)) + + self._cookies = cookies + return self._cookies + + @property + def client(self) -> Address | None: + # client is a 2 item tuple of (host, port), None if missing + host_port = self.scope.get("client") + if host_port is not None: + return Address(*host_port) + return None + + @property + def session(self) -> dict[str, Any]: + assert "session" in self.scope, "SessionMiddleware must be installed to access request.session" + session: Session = self.scope["session"] + # We keep the hasattr in case people actually use their own `SessionMiddleware` implementation. + if hasattr(session, "mark_accessed"): # pragma: no branch + session.mark_accessed() + return session + + @property + def auth(self) -> Any: + assert "auth" in self.scope, "AuthenticationMiddleware must be installed to access request.auth" + return self.scope["auth"] + + @property + def user(self) -> Any: + assert "user" in self.scope, "AuthenticationMiddleware must be installed to access request.user" + return self.scope["user"] + + @property + def state(self) -> StateT: + if not hasattr(self, "_state"): + # Ensure 'state' has an empty dict if it's not already populated. + self.scope.setdefault("state", {}) + # Create a state instance with a reference to the dict in which it should + # store info + self._state = State(self.scope["state"]) + return cast(StateT, self._state) + + def url_for(self, name: str, /, **path_params: Any) -> URL: + url_path_provider: Router | Starlette | None = self.scope.get("router") or self.scope.get("app") + if url_path_provider is None: + raise RuntimeError("The `url_for` method can only be used inside a Starlette application or with a router.") + url_path = url_path_provider.url_path_for(name, **path_params) + return url_path.make_absolute_url(base_url=self.base_url) + + +async def empty_receive() -> NoReturn: + raise RuntimeError("Receive channel has not been made available") + + +async def empty_send(message: Message) -> NoReturn: + raise RuntimeError("Send channel has not been made available") + + +class Request(HTTPConnection[StateT]): + _form: FormData | None + + def __init__(self, scope: Scope, receive: Receive = empty_receive, send: Send = empty_send): + super().__init__(scope) + assert scope["type"] == "http" + self._receive = receive + self._send = send + self._stream_consumed = False + self._is_disconnected = False + self._form = None + + @property + def method(self) -> str: + return cast(str, self.scope["method"]) + + @property + def receive(self) -> Receive: + return self._receive + + async def stream(self) -> AsyncGenerator[bytes, None]: + if hasattr(self, "_body"): + yield self._body + yield b"" + return + if self._stream_consumed: + raise RuntimeError("Stream consumed") + while not self._stream_consumed: + message = await self._receive() + if message["type"] == "http.request": + body = message.get("body", b"") + if not message.get("more_body", False): + self._stream_consumed = True + if body: + yield body + elif message["type"] == "http.disconnect": # pragma: no branch + self._is_disconnected = True + raise ClientDisconnect() + yield b"" + + async def body(self) -> bytes: + if not hasattr(self, "_body"): + chunks: list[bytes] = [] + async for chunk in self.stream(): + chunks.append(chunk) + self._body = b"".join(chunks) + return self._body + + async def json(self) -> Any: + if not hasattr(self, "_json"): # pragma: no branch + body = await self.body() + self._json = json.loads(body) + return self._json + + async def _get_form( + self, + *, + max_files: int | float = 1000, + max_fields: int | float = 1000, + max_part_size: int = 1024 * 1024, + ) -> FormData: + if self._form is None: # pragma: no branch + assert parse_options_header is not None, ( + "The `python-multipart` library must be installed to use form parsing." + ) + content_type_header = self.headers.get("Content-Type") + content_type: bytes + content_type, _ = parse_options_header(content_type_header) + if content_type == b"multipart/form-data": + try: + multipart_parser = MultiPartParser( + self.headers, + self.stream(), + max_files=max_files, + max_fields=max_fields, + max_part_size=max_part_size, + ) + self._form = await multipart_parser.parse() + except MultiPartException as exc: + if "app" in self.scope: + raise HTTPException(status_code=400, detail=exc.message) + raise exc + elif content_type == b"application/x-www-form-urlencoded": + try: + form_parser = FormParser( + self.headers, + self.stream(), + max_fields=max_fields, + max_part_size=max_part_size, + ) + self._form = await form_parser.parse() + except MultiPartException as exc: + if "app" in self.scope: + raise HTTPException(status_code=400, detail=exc.message) + raise exc + else: + self._form = FormData() + return self._form + + def form( + self, + *, + max_files: int | float = 1000, + max_fields: int | float = 1000, + max_part_size: int = 1024 * 1024, + ) -> AwaitableOrContextManager[FormData]: + return AwaitableOrContextManagerWrapper( + self._get_form(max_files=max_files, max_fields=max_fields, max_part_size=max_part_size) + ) + + async def close(self) -> None: + if self._form is not None: # pragma: no branch + await self._form.close() + + async def is_disconnected(self) -> bool: + if not self._is_disconnected: + message: Message = {} + + # If message isn't immediately available, move on + with anyio.CancelScope() as cs: + cs.cancel() + message = await self._receive() + + if message.get("type") == "http.disconnect": + self._is_disconnected = True + + return self._is_disconnected + + async def send_push_promise(self, path: str) -> None: + if "http.response.push" in self.scope.get("extensions", {}): + raw_headers: list[tuple[bytes, bytes]] = [] + for name in SERVER_PUSH_HEADERS_TO_COPY: + for value in self.headers.getlist(name): + raw_headers.append((name.encode("latin-1"), value.encode("latin-1"))) + await self._send({"type": "http.response.push", "path": path, "headers": raw_headers}) diff --git a/source/target-vendors/cp312/starlette/responses.py b/source/target-vendors/cp312/starlette/responses.py new file mode 100644 index 0000000..bff2467 --- /dev/null +++ b/source/target-vendors/cp312/starlette/responses.py @@ -0,0 +1,579 @@ +from __future__ import annotations + +import hashlib +import http.cookies +import json +import os +import stat +import sys +from collections.abc import AsyncIterable, Awaitable, Callable, Iterable, Mapping, Sequence +from datetime import datetime +from email.utils import format_datetime, formatdate +from functools import partial +from mimetypes import guess_type +from secrets import token_hex +from typing import Any, Literal +from urllib.parse import quote + +import anyio +import anyio.to_thread + +from starlette._utils import create_collapsing_task_group +from starlette.background import BackgroundTask +from starlette.concurrency import iterate_in_threadpool +from starlette.datastructures import URL, Headers, MutableHeaders +from starlette.requests import ClientDisconnect +from starlette.types import Message, Receive, Scope, Send + + +class Response: + media_type = None + charset = "utf-8" + + def __init__( + self, + content: Any = None, + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + background: BackgroundTask | None = None, + ) -> None: + self.status_code = status_code + if media_type is not None: + self.media_type = media_type + self.background = background + self.body = self.render(content) + self.init_headers(headers) + + def render(self, content: Any) -> bytes | memoryview: + if content is None: + return b"" + if isinstance(content, bytes | memoryview): + return content + return content.encode(self.charset) # type: ignore + + def init_headers(self, headers: Mapping[str, str] | None = None) -> None: + if headers is None: + raw_headers: list[tuple[bytes, bytes]] = [] + populate_content_length = True + populate_content_type = True + else: + raw_headers = [(k.lower().encode("latin-1"), v.encode("latin-1")) for k, v in headers.items()] + keys = [h[0] for h in raw_headers] + populate_content_length = b"content-length" not in keys + populate_content_type = b"content-type" not in keys + + body = getattr(self, "body", None) + if ( + body is not None + and populate_content_length + and not (self.status_code < 200 or self.status_code in (204, 304)) + ): + content_length = str(len(body)) + raw_headers.append((b"content-length", content_length.encode("latin-1"))) + + content_type = self.media_type + if content_type is not None and populate_content_type: + if content_type.startswith("text/") and "charset=" not in content_type.lower(): + content_type += "; charset=" + self.charset + raw_headers.append((b"content-type", content_type.encode("latin-1"))) + + self.raw_headers = raw_headers + + @property + def headers(self) -> MutableHeaders: + if not hasattr(self, "_headers"): + self._headers = MutableHeaders(raw=self.raw_headers) + return self._headers + + def set_cookie( + self, + key: str, + value: str = "", + max_age: int | None = None, + expires: datetime | str | int | None = None, + path: str | None = "/", + domain: str | None = None, + secure: bool = False, + httponly: bool = False, + samesite: Literal["lax", "strict", "none"] | None = "lax", + partitioned: bool = False, + ) -> None: + cookie: http.cookies.BaseCookie[str] = http.cookies.SimpleCookie() + cookie[key] = value + if max_age is not None: + cookie[key]["max-age"] = max_age + if expires is not None: + if isinstance(expires, datetime): + cookie[key]["expires"] = format_datetime(expires, usegmt=True) + else: + cookie[key]["expires"] = expires + if path is not None: + cookie[key]["path"] = path + if domain is not None: + cookie[key]["domain"] = domain + if secure: + cookie[key]["secure"] = True + if httponly: + cookie[key]["httponly"] = True + if samesite is not None: + assert samesite.lower() in [ + "strict", + "lax", + "none", + ], "samesite must be either 'strict', 'lax' or 'none'" + cookie[key]["samesite"] = samesite + if partitioned: + if sys.version_info < (3, 14): + raise ValueError("Partitioned cookies are only supported in Python 3.14 and above.") # pragma: no cover + cookie[key]["partitioned"] = True # pragma: no cover + + cookie_val = cookie.output(header="").strip() + self.raw_headers.append((b"set-cookie", cookie_val.encode("latin-1"))) + + def delete_cookie( + self, + key: str, + path: str = "/", + domain: str | None = None, + secure: bool = False, + httponly: bool = False, + samesite: Literal["lax", "strict", "none"] | None = "lax", + partitioned: bool = False, + ) -> None: + self.set_cookie( + key, + max_age=0, + expires=0, + path=path, + domain=domain, + secure=secure, + httponly=httponly, + samesite=samesite, + partitioned=partitioned, + ) + + def _wrap_websocket_denial_send(self, send: Send) -> Send: + async def wrapped(message: Message) -> None: + message_type = message["type"] + if message_type in {"http.response.start", "http.response.body"}: # pragma: no branch + message = {**message, "type": "websocket." + message_type} + await send(message) + + return wrapped + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] == "websocket": + send = self._wrap_websocket_denial_send(send) + await send({"type": "http.response.start", "status": self.status_code, "headers": self.raw_headers}) + await send({"type": "http.response.body", "body": self.body}) + + if self.background is not None: + await self.background() + + +class HTMLResponse(Response): + media_type = "text/html" + + +class PlainTextResponse(Response): + media_type = "text/plain" + + +class JSONResponse(Response): + media_type = "application/json" + + def __init__( + self, + content: Any, + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + background: BackgroundTask | None = None, + ) -> None: + super().__init__(content, status_code, headers, media_type, background) + + def render(self, content: Any) -> bytes: + return json.dumps( + content, + ensure_ascii=False, + allow_nan=False, + indent=None, + separators=(",", ":"), + ).encode("utf-8") + + +class RedirectResponse(Response): + def __init__( + self, + url: str | URL, + status_code: int = 307, + headers: Mapping[str, str] | None = None, + background: BackgroundTask | None = None, + ) -> None: + super().__init__(content=b"", status_code=status_code, headers=headers, background=background) + self.headers["location"] = quote(str(url), safe=":/%#?=@[]!$&'()*+,;") + + +Content = str | bytes | memoryview +SyncContentStream = Iterable[Content] +AsyncContentStream = AsyncIterable[Content] +ContentStream = AsyncContentStream | SyncContentStream + + +class StreamingResponse(Response): + body_iterator: AsyncContentStream + + def __init__( + self, + content: ContentStream, + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + background: BackgroundTask | None = None, + ) -> None: + if isinstance(content, AsyncIterable): + self.body_iterator = content + else: + self.body_iterator = iterate_in_threadpool(content) + self.status_code = status_code + self.media_type = self.media_type if media_type is None else media_type + self.background = background + self.init_headers(headers) + + async def listen_for_disconnect(self, receive: Receive) -> None: + while True: + message = await receive() + if message["type"] == "http.disconnect": + break + + async def stream_response(self, send: Send) -> None: + await send({"type": "http.response.start", "status": self.status_code, "headers": self.raw_headers}) + async for chunk in self.body_iterator: + if not isinstance(chunk, bytes | memoryview): + chunk = chunk.encode(self.charset) + await send({"type": "http.response.body", "body": chunk, "more_body": True}) + + await send({"type": "http.response.body", "body": b"", "more_body": False}) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] == "websocket": + send = self._wrap_websocket_denial_send(send) + await self.stream_response(send) + if self.background is not None: + await self.background() + return + + spec_version = tuple(map(int, scope.get("asgi", {}).get("spec_version", "2.0").split("."))) + + if spec_version >= (2, 4): + try: + await self.stream_response(send) + except OSError: + raise ClientDisconnect() + else: + async with create_collapsing_task_group() as task_group: + + async def wrap(func: Callable[[], Awaitable[None]]) -> None: + await func() + task_group.cancel_scope.cancel() + + task_group.start_soon(wrap, partial(self.stream_response, send)) + await wrap(partial(self.listen_for_disconnect, receive)) + + if self.background is not None: + await self.background() + + +class MalformedRangeHeader(Exception): + def __init__(self, content: str = "Malformed range header.") -> None: + self.content = content + + +class RangeNotSatisfiable(Exception): + def __init__(self, max_size: int) -> None: + self.max_size = max_size + + +class FileResponse(Response): + chunk_size = 64 * 1024 + max_ranges = 100 + + def __init__( + self, + path: str | os.PathLike[str], + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + background: BackgroundTask | None = None, + filename: str | None = None, + stat_result: os.stat_result | None = None, + content_disposition_type: str = "attachment", + ) -> None: + self.path = path + self.status_code = status_code + self.filename = filename + if media_type is None: + media_type = guess_type(filename or path)[0] or "application/octet-stream" + self.media_type = media_type + self.background = background + self.init_headers(headers) + self.headers.setdefault("accept-ranges", "bytes") + if self.filename is not None: + content_disposition_filename = quote(self.filename) + if content_disposition_filename != self.filename: + content_disposition = f"{content_disposition_type}; filename*=utf-8''{content_disposition_filename}" + else: + content_disposition = f'{content_disposition_type}; filename="{self.filename}"' + self.headers.setdefault("content-disposition", content_disposition) + self.stat_result = stat_result + if stat_result is not None: + self.set_stat_headers(stat_result) + + def set_stat_headers(self, stat_result: os.stat_result) -> None: + content_length = str(stat_result.st_size) + last_modified = formatdate(stat_result.st_mtime, usegmt=True) + etag_base = str(stat_result.st_mtime) + "-" + str(stat_result.st_size) + etag = f'"{hashlib.md5(etag_base.encode(), usedforsecurity=False).hexdigest()}"' + + self.headers.setdefault("content-length", content_length) + self.headers.setdefault("last-modified", last_modified) + self.headers.setdefault("etag", etag) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + scope_type = scope["type"] + send_header_only = scope_type == "http" and scope["method"].upper() == "HEAD" + send_pathsend = scope_type == "http" and "http.response.pathsend" in scope.get("extensions", {}) + if scope_type == "websocket": + send = self._wrap_websocket_denial_send(send) + + if self.stat_result is None: + try: + stat_result = await anyio.to_thread.run_sync(os.stat, self.path) + self.set_stat_headers(stat_result) + except FileNotFoundError: + raise RuntimeError(f"File at path {self.path} does not exist.") + else: + mode = stat_result.st_mode + if not stat.S_ISREG(mode): + raise RuntimeError(f"File at path {self.path} is not a file.") + else: + stat_result = self.stat_result + + headers = Headers(scope=scope) + http_range = headers.get("range") + http_if_range = headers.get("if-range") + + if ( + self.status_code != 200 + or http_range is None + or (http_if_range is not None and not self._should_use_range(http_if_range)) + ): + await self._handle_simple(send, send_header_only, send_pathsend) + else: + try: + ranges = self._parse_range_header(http_range, stat_result.st_size) + except MalformedRangeHeader as exc: + return await PlainTextResponse(exc.content, status_code=400)(scope, receive, send) + except RangeNotSatisfiable as exc: + response = PlainTextResponse(status_code=416, headers={"Content-Range": f"bytes */{exc.max_size}"}) + return await response(scope, receive, send) + + if len(ranges) == 0: + await self._handle_simple(send, send_header_only, send_pathsend) + elif len(ranges) == 1: + start, end = ranges[0] + await self._handle_single_range(send, start, end, stat_result.st_size, send_header_only) + else: + await self._handle_multiple_ranges(send, ranges, stat_result.st_size, send_header_only) + + if self.background is not None: + await self.background() + + async def _handle_simple(self, send: Send, send_header_only: bool, send_pathsend: bool) -> None: + await send({"type": "http.response.start", "status": self.status_code, "headers": self.raw_headers}) + if send_header_only: + await send({"type": "http.response.body", "body": b"", "more_body": False}) + elif send_pathsend: + await send({"type": "http.response.pathsend", "path": str(self.path)}) + else: + async with await anyio.open_file(self.path, mode="rb") as file: + more_body = True + while more_body: + chunk = await file.read(self.chunk_size) + more_body = len(chunk) == self.chunk_size + await send({"type": "http.response.body", "body": chunk, "more_body": more_body}) + + async def _handle_single_range( + self, send: Send, start: int, end: int, file_size: int, send_header_only: bool + ) -> None: + headers = MutableHeaders(raw=list(self.raw_headers)) + headers["content-range"] = f"bytes {start}-{end - 1}/{file_size}" + headers["content-length"] = str(end - start) + await send({"type": "http.response.start", "status": 206, "headers": headers.raw}) + if send_header_only: + await send({"type": "http.response.body", "body": b"", "more_body": False}) + else: + async with await anyio.open_file(self.path, mode="rb") as file: + await file.seek(start) + more_body = True + while more_body: + chunk = await file.read(min(self.chunk_size, end - start)) + start += len(chunk) + more_body = len(chunk) == self.chunk_size and start < end + await send({"type": "http.response.body", "body": chunk, "more_body": more_body}) + + async def _handle_multiple_ranges( + self, + send: Send, + ranges: list[tuple[int, int]], + file_size: int, + send_header_only: bool, + ) -> None: + # In firefox and chrome, they use boundary with 95-96 bits entropy (that's roughly 13 bytes). + boundary = token_hex(13) + content_length, header_generator = self.generate_multipart( + ranges, boundary, file_size, self.headers["content-type"] + ) + headers = MutableHeaders(raw=list(self.raw_headers)) + headers["content-type"] = f"multipart/byteranges; boundary={boundary}" + headers["content-length"] = str(content_length) + await send({"type": "http.response.start", "status": 206, "headers": headers.raw}) + if send_header_only: + await send({"type": "http.response.body", "body": b"", "more_body": False}) + else: + async with await anyio.open_file(self.path, mode="rb") as file: + for start, end in ranges: + await send({"type": "http.response.body", "body": header_generator(start, end), "more_body": True}) + await file.seek(start) + while start < end: + chunk = await file.read(min(self.chunk_size, end - start)) + start += len(chunk) + await send({"type": "http.response.body", "body": chunk, "more_body": True}) + await send({"type": "http.response.body", "body": b"\r\n", "more_body": True}) + await send( + { + "type": "http.response.body", + "body": f"--{boundary}--".encode("latin-1"), + "more_body": False, + } + ) + + def _should_use_range(self, http_if_range: str) -> bool: + return http_if_range == self.headers["last-modified"] or http_if_range == self.headers["etag"] + + @classmethod + def _parse_range_header(cls, http_range: str, file_size: int) -> list[tuple[int, int]]: + ranges: list[tuple[int, int]] = [] + try: + units, range_ = http_range.split("=", 1) + except ValueError: + raise MalformedRangeHeader() + + units = units.strip().lower() + + if units != "bytes": + raise MalformedRangeHeader("Only support bytes range") + + if range_.count(",") + 1 > cls.max_ranges: + return [] + + ranges = cls._parse_ranges(range_, file_size) + + if len(ranges) == 0: + raise MalformedRangeHeader("Range header: range must be requested") + + if any(not (0 <= start < file_size) for start, _ in ranges): + raise RangeNotSatisfiable(file_size) + + if any(start >= end for start, end in ranges): + raise MalformedRangeHeader("Range header: start must be less than end") + + if len(ranges) == 1: + return ranges + + # Merge overlapping ranges + ranges.sort() + result: list[tuple[int, int]] = [ranges[0]] + for start, end in ranges[1:]: + last_start, last_end = result[-1] + if start <= last_end: + result[-1] = (last_start, max(last_end, end)) + else: + result.append((start, end)) + + return result + + @classmethod + def _parse_ranges(cls, range_: str, file_size: int) -> list[tuple[int, int]]: + ranges: list[tuple[int, int]] = [] + + for part in range_.split(","): + part = part.strip() + + # If the range is empty or a single dash, we ignore it. + if not part or part == "-": + continue + + # If the range is not in the format "start-end", we ignore it. + if "-" not in part: + continue + + start_str, end_str = part.split("-", 1) + start_str = start_str.strip() + end_str = end_str.strip() + + try: + start = int(start_str) if start_str else max(file_size - int(end_str), 0) + end = int(end_str) + 1 if start_str and end_str and int(end_str) < file_size else file_size + ranges.append((start, end)) + except ValueError: + # If the range is not numeric, we ignore it. + continue + + return ranges + + def generate_multipart( + self, + ranges: Sequence[tuple[int, int]], + boundary: str, + max_size: int, + content_type: str, + ) -> tuple[int, Callable[[int, int], bytes]]: + r""" + Multipart response headers generator. + + ``` + --{boundary}\r\n + Content-Type: {content_type}\r\n + Content-Range: bytes {start}-{end-1}/{max_size}\r\n + \r\n + ..........content...........\r\n + --{boundary}\r\n + Content-Type: {content_type}\r\n + Content-Range: bytes {start}-{end-1}/{max_size}\r\n + \r\n + ..........content...........\r\n + --{boundary}-- + ``` + """ + boundary_len = len(boundary) + static_header_part_len = 49 + boundary_len + len(content_type) + len(str(max_size)) + content_length = sum( + (len(str(start)) + len(str(end - 1)) + static_header_part_len) # Headers + + (end - start) # Content + for start, end in ranges + ) + ( + 4 + boundary_len # --boundary-- + ) + return ( + content_length, + lambda start, end: ( + f"""\ +--{boundary}\r +Content-Type: {content_type}\r +Content-Range: bytes {start}-{end - 1}/{max_size}\r +\r +""" + ).encode("latin-1"), + ) diff --git a/source/target-vendors/cp312/starlette/routing.py b/source/target-vendors/cp312/starlette/routing.py new file mode 100644 index 0000000..9969d38 --- /dev/null +++ b/source/target-vendors/cp312/starlette/routing.py @@ -0,0 +1,765 @@ +from __future__ import annotations + +import contextlib +import functools +import inspect +import re +import traceback +import types +import warnings +from collections.abc import Awaitable, Callable, Collection, Generator, Sequence +from contextlib import AbstractAsyncContextManager, AbstractContextManager, asynccontextmanager +from enum import Enum +from re import Pattern +from typing import Any, TypeVar + +from starlette._exception_handler import wrap_app_handling_exceptions +from starlette._utils import get_route_path, is_async_callable, parse_host_header +from starlette.concurrency import run_in_threadpool +from starlette.convertors import CONVERTOR_TYPES, Convertor +from starlette.datastructures import URL, Headers, URLPath +from starlette.exceptions import HTTPException, StarletteDeprecationWarning +from starlette.middleware import Middleware +from starlette.middleware.body_limit import RequestBodyLimitMiddleware +from starlette.requests import Request +from starlette.responses import PlainTextResponse, RedirectResponse, Response +from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send +from starlette.websockets import WebSocket, WebSocketClose + + +class NoMatchFound(Exception): + """ + Raised by `.url_for(name, **path_params)` and `.url_path_for(name, **path_params)` + if no matching route exists. + """ + + def __init__(self, name: str, path_params: dict[str, Any]) -> None: + params = ", ".join(list(path_params.keys())) + super().__init__(f'No route exists for name "{name}" and params "{params}".') + + +class Match(Enum): + NONE = 0 + PARTIAL = 1 + FULL = 2 + + +def request_response( + func: Callable[[Request], Awaitable[Response] | Response], +) -> ASGIApp: + """ + Takes a function or coroutine `func(request) -> response`, + and returns an ASGI application. + """ + f: Callable[[Request], Awaitable[Response]] = ( + func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type: ignore[assignment, call-arg] + ) + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + request = Request(scope, receive, send) + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + response = await f(request) + await response(scope, receive, send) + + await wrap_app_handling_exceptions(app, request)(scope, receive, send) + + return app + + +def websocket_session( + func: Callable[[WebSocket], Awaitable[None]], +) -> ASGIApp: + """ + Takes a coroutine `func(session)`, and returns an ASGI application. + """ + # assert asyncio.iscoroutinefunction(func), "WebSocket endpoints must be async" + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + session = WebSocket(scope, receive=receive, send=send) + + async def app(scope: Scope, receive: Receive, send: Send) -> None: + await func(session) + + await wrap_app_handling_exceptions(app, session)(scope, receive, send) + + return app + + +def get_name(endpoint: Callable[..., Any]) -> str: + return getattr(endpoint, "__name__", endpoint.__class__.__name__) + + +def replace_params( + path: str, + param_convertors: dict[str, Convertor[Any]], + path_params: dict[str, str], +) -> tuple[str, dict[str, str]]: + for key, value in list(path_params.items()): + if "{" + key + "}" in path: + convertor = param_convertors[key] + value = convertor.to_string(value) + path = path.replace("{" + key + "}", value) + path_params.pop(key) + return path, path_params + + +# Match parameters in URL paths, eg. '{param}', and '{param:int}' +PARAM_REGEX = re.compile("{([a-zA-Z_][a-zA-Z0-9_]*)(:[a-zA-Z_][a-zA-Z0-9_]*)?}") + + +def compile_path( + path: str, +) -> tuple[Pattern[str], str, dict[str, Convertor[Any]]]: + """ + Given a path string, like: "/{username:str}", + or a host string, like: "{subdomain}.mydomain.org", return a three-tuple + of (regex, format, {param_name:convertor}). + + regex: "/(?P[^/]+)" + format: "/{username}" + convertors: {"username": StringConvertor()} + """ + is_host = not path.startswith("/") + + path_regex = "^" + path_format = "" + duplicated_params: set[str] = set() + + idx = 0 + param_convertors = {} + for match in PARAM_REGEX.finditer(path): + param_name, convertor_type = match.groups("str") + convertor_type = convertor_type.lstrip(":") + assert convertor_type in CONVERTOR_TYPES, f"Unknown path convertor '{convertor_type}'" + convertor = CONVERTOR_TYPES[convertor_type] + + path_regex += re.escape(path[idx : match.start()]) + path_regex += f"(?P<{param_name}>{convertor.regex})" + + path_format += path[idx : match.start()] + path_format += "{%s}" % param_name + + if param_name in param_convertors: + duplicated_params.add(param_name) + + param_convertors[param_name] = convertor + + idx = match.end() + + if duplicated_params: + names = ", ".join(sorted(duplicated_params)) + ending = "s" if len(duplicated_params) > 1 else "" + raise ValueError(f"Duplicated param name{ending} {names} at path {path}") + + if is_host: + # Align with `Host.matches()` behavior, which ignores port. + hostname = path[idx:] + if not hostname.endswith("]"): + hostname = hostname.rsplit(":", 1)[0] + path_regex += re.escape(hostname) + "$" + else: + path_regex += re.escape(path[idx:]) + "$" + + path_format += path[idx:] + + return re.compile(path_regex), path_format, param_convertors + + +class BaseRoute: + def matches(self, scope: Scope) -> tuple[Match, Scope]: + raise NotImplementedError() # pragma: no cover + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + raise NotImplementedError() # pragma: no cover + + async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: + raise NotImplementedError() # pragma: no cover + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + """ + A route may be used in isolation as a stand-alone ASGI app. + This is a somewhat contrived case, as they'll almost always be used + within a Router, but could be useful for some tooling and minimal apps. + """ + match, child_scope = self.matches(scope) + if match == Match.NONE: + if scope["type"] == "http": + response = PlainTextResponse("Not Found", status_code=404) + await response(scope, receive, send) + elif scope["type"] == "websocket": # pragma: no branch + websocket_close = WebSocketClose() + await websocket_close(scope, receive, send) + return + + scope.update(child_scope) + await self.handle(scope, receive, send) + + +class Route(BaseRoute): + def __init__( + self, + path: str, + endpoint: Callable[..., Any], + *, + methods: Collection[str] | None = None, + name: str | None = None, + include_in_schema: bool = True, + middleware: Sequence[Middleware] | None = None, + max_body_size: int | None = None, + ) -> None: + assert path.startswith("/"), "Routed paths must start with '/'" + self.path = path + self.endpoint = endpoint + self.name = get_name(endpoint) if name is None else name + self.include_in_schema = include_in_schema + + endpoint_handler = endpoint + while isinstance(endpoint_handler, functools.partial): + endpoint_handler = endpoint_handler.func + if inspect.isfunction(endpoint_handler) or inspect.ismethod(endpoint_handler): + # Endpoint is function or method. Treat it as `func(request) -> response`. + self.app = request_response(endpoint) + if methods is None: + methods = ["GET"] + else: + # Endpoint is a class. Treat it as ASGI. + self.app = endpoint + + if middleware is not None: + for cls, args, kwargs in reversed(middleware): + self.app = cls(self.app, *args, **kwargs) + if max_body_size is not None: + self.app = RequestBodyLimitMiddleware(self.app, max_body_size=max_body_size) + + if methods is None: + self.methods = None + else: + self.methods = {method.upper() for method in methods} + if "GET" in self.methods: + self.methods.add("HEAD") + + self.path_regex, self.path_format, self.param_convertors = compile_path(path) + + def matches(self, scope: Scope) -> tuple[Match, Scope]: + path_params: dict[str, Any] + if scope["type"] == "http": + route_path = get_route_path(scope) + match = self.path_regex.match(route_path) + if match: + matched_params = match.groupdict() + for key, value in matched_params.items(): + matched_params[key] = self.param_convertors[key].convert(value) + path_params = dict(scope.get("path_params", {})) + path_params.update(matched_params) + child_scope = {"endpoint": self.endpoint, "path_params": path_params} + if self.methods and scope["method"] not in self.methods: + return Match.PARTIAL, child_scope + else: + return Match.FULL, child_scope + return Match.NONE, {} + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + seen_params = set(path_params.keys()) + expected_params = set(self.param_convertors.keys()) + + if name != self.name or seen_params != expected_params: + raise NoMatchFound(name, path_params) + + path, remaining_params = replace_params(self.path_format, self.param_convertors, path_params) + assert not remaining_params + return URLPath(path=path, protocol="http") + + async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: + if self.methods and scope["method"] not in self.methods: + headers = {"Allow": ", ".join(self.methods)} + if "app" in scope: + raise HTTPException(status_code=405, headers=headers) + else: + response = PlainTextResponse("Method Not Allowed", status_code=405, headers=headers) + await response(scope, receive, send) + else: + await self.app(scope, receive, send) + + def __eq__(self, other: Any) -> bool: + return ( + isinstance(other, Route) + and self.path == other.path + and self.endpoint == other.endpoint + and self.methods == other.methods + ) + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + methods = sorted(self.methods or []) + path, name = self.path, self.name + return f"{class_name}(path={path!r}, name={name!r}, methods={methods!r})" + + +class WebSocketRoute(BaseRoute): + def __init__( + self, + path: str, + endpoint: Callable[..., Any], + *, + name: str | None = None, + middleware: Sequence[Middleware] | None = None, + ) -> None: + assert path.startswith("/"), "Routed paths must start with '/'" + self.path = path + self.endpoint = endpoint + self.name = get_name(endpoint) if name is None else name + + endpoint_handler = endpoint + while isinstance(endpoint_handler, functools.partial): + endpoint_handler = endpoint_handler.func + if inspect.isfunction(endpoint_handler) or inspect.ismethod(endpoint_handler): + # Endpoint is function or method. Treat it as `func(websocket)`. + self.app = websocket_session(endpoint) + else: + # Endpoint is a class. Treat it as ASGI. + self.app = endpoint + + if middleware is not None: + for cls, args, kwargs in reversed(middleware): + self.app = cls(self.app, *args, **kwargs) + + self.path_regex, self.path_format, self.param_convertors = compile_path(path) + + def matches(self, scope: Scope) -> tuple[Match, Scope]: + path_params: dict[str, Any] + if scope["type"] == "websocket": + route_path = get_route_path(scope) + match = self.path_regex.match(route_path) + if match: + matched_params = match.groupdict() + for key, value in matched_params.items(): + matched_params[key] = self.param_convertors[key].convert(value) + path_params = dict(scope.get("path_params", {})) + path_params.update(matched_params) + child_scope = {"endpoint": self.endpoint, "path_params": path_params} + return Match.FULL, child_scope + return Match.NONE, {} + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + seen_params = set(path_params.keys()) + expected_params = set(self.param_convertors.keys()) + + if name != self.name or seen_params != expected_params: + raise NoMatchFound(name, path_params) + + path, remaining_params = replace_params(self.path_format, self.param_convertors, path_params) + assert not remaining_params + return URLPath(path=path, protocol="websocket") + + async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: + await self.app(scope, receive, send) + + def __eq__(self, other: Any) -> bool: + return isinstance(other, WebSocketRoute) and self.path == other.path and self.endpoint == other.endpoint + + def __repr__(self) -> str: + return f"{self.__class__.__name__}(path={self.path!r}, name={self.name!r})" + + +class Mount(BaseRoute): + def __init__( + self, + path: str, + app: ASGIApp | None = None, + routes: Sequence[BaseRoute] | None = None, + name: str | None = None, + *, + middleware: Sequence[Middleware] | None = None, + max_body_size: int | None = None, + ) -> None: + assert path == "" or path.startswith("/"), "Routed paths must start with '/'" + assert app is not None or routes is not None, "Either 'app=...', or 'routes=' must be specified" + self.path = path.rstrip("/") + if app is not None: + self._base_app: ASGIApp = app + else: + self._base_app = Router(routes=routes) + self.app = self._base_app + if middleware is not None: + for cls, args, kwargs in reversed(middleware): + self.app = cls(self.app, *args, **kwargs) + if max_body_size is not None: + self.app = RequestBodyLimitMiddleware(self.app, max_body_size=max_body_size) + self.name = name + self.path_regex, self.path_format, self.param_convertors = compile_path(self.path + "/{path:path}") + + @property + def routes(self) -> list[BaseRoute]: + return getattr(self._base_app, "routes", []) + + def matches(self, scope: Scope) -> tuple[Match, Scope]: + path_params: dict[str, Any] + if scope["type"] in ("http", "websocket"): # pragma: no branch + root_path = scope.get("root_path", "") + route_path = get_route_path(scope) + match = self.path_regex.match(route_path) + if match: + matched_params = match.groupdict() + for key, value in matched_params.items(): + matched_params[key] = self.param_convertors[key].convert(value) + remaining_path = "/" + matched_params.pop("path") + matched_path = route_path[: -len(remaining_path)] + path_params = dict(scope.get("path_params", {})) + path_params.update(matched_params) + child_scope = { + "path_params": path_params, + # app_root_path will only be set at the top level scope, + # initialized with the (optional) value of a root_path + # set above/before Starlette. And even though any + # mount will have its own child scope with its own respective + # root_path, the app_root_path will always be available in all + # the child scopes with the same top level value because it's + # set only once here with a default, any other child scope will + # just inherit that app_root_path default value stored in the + # scope. All this is needed to support Request.url_for(), as it + # uses the app_root_path to build the URL path. + "app_root_path": scope.get("app_root_path", root_path), + "root_path": root_path + matched_path, + "endpoint": self.app, + } + return Match.FULL, child_scope + return Match.NONE, {} + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + if self.name is not None and name == self.name and "path" in path_params: + # 'name' matches "". + path_params["path"] = path_params["path"].lstrip("/") + path, remaining_params = replace_params(self.path_format, self.param_convertors, path_params) + if not remaining_params: + return URLPath(path=path) + elif self.name is None or name.startswith(self.name + ":"): + if self.name is None: + # No mount name. + remaining_name = name + else: + # 'name' matches ":". + remaining_name = name[len(self.name) + 1 :] + path_kwarg = path_params.get("path") + path_params["path"] = "" + path_prefix, remaining_params = replace_params(self.path_format, self.param_convertors, path_params) + if path_kwarg is not None: + remaining_params["path"] = path_kwarg + for route in self.routes or []: + try: + url = route.url_path_for(remaining_name, **remaining_params) + return URLPath(path=path_prefix.rstrip("/") + str(url), protocol=url.protocol) + except NoMatchFound: + pass + raise NoMatchFound(name, path_params) + + async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: + await self.app(scope, receive, send) + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Mount) and self.path == other.path and self.app == other.app + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + name = self.name or "" + return f"{class_name}(path={self.path!r}, name={name!r}, app={self.app!r})" + + +class Host(BaseRoute): + def __init__(self, host: str, app: ASGIApp, name: str | None = None) -> None: + assert not host.startswith("/"), "Host must not start with '/'" + self.host = host + self.app = app + self.name = name + self.host_regex, self.host_format, self.param_convertors = compile_path(host) + + @property + def routes(self) -> list[BaseRoute]: + return getattr(self.app, "routes", []) + + def matches(self, scope: Scope) -> tuple[Match, Scope]: + if scope["type"] in ("http", "websocket"): # pragma:no branch + headers = Headers(scope=scope) + parsed_host = parse_host_header(headers.get("host")) + if parsed_host is None: + return Match.NONE, {} + host = parsed_host.host + + match = self.host_regex.match(host) + if match: + matched_params = match.groupdict() + for key, value in matched_params.items(): + matched_params[key] = self.param_convertors[key].convert(value) + path_params = dict(scope.get("path_params", {})) + path_params.update(matched_params) + child_scope = {"path_params": path_params, "endpoint": self.app} + return Match.FULL, child_scope + return Match.NONE, {} + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + if self.name is not None and name == self.name and "path" in path_params: + # 'name' matches "". + path = path_params.pop("path") + host, remaining_params = replace_params(self.host_format, self.param_convertors, path_params) + if not remaining_params: + return URLPath(path=path, host=host) + elif self.name is None or name.startswith(self.name + ":"): + if self.name is None: + # No mount name. + remaining_name = name + else: + # 'name' matches ":". + remaining_name = name[len(self.name) + 1 :] + host, remaining_params = replace_params(self.host_format, self.param_convertors, path_params) + for route in self.routes or []: + try: + url = route.url_path_for(remaining_name, **remaining_params) + return URLPath(path=str(url), protocol=url.protocol, host=host) + except NoMatchFound: + pass + raise NoMatchFound(name, path_params) + + async def handle(self, scope: Scope, receive: Receive, send: Send) -> None: + await self.app(scope, receive, send) + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Host) and self.host == other.host and self.app == other.app + + def __repr__(self) -> str: + class_name = self.__class__.__name__ + name = self.name or "" + return f"{class_name}(host={self.host!r}, name={name!r}, app={self.app!r})" + + +_T = TypeVar("_T") + + +class _AsyncLiftContextManager(AbstractAsyncContextManager[_T]): + def __init__(self, cm: AbstractContextManager[_T]): + self._cm = cm + + async def __aenter__(self) -> _T: + return self._cm.__enter__() + + async def __aexit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + traceback: types.TracebackType | None, + ) -> bool | None: + return self._cm.__exit__(exc_type, exc_value, traceback) + + +def _wrap_gen_lifespan_context( + lifespan_context: Callable[[Any], Generator[Any, Any, Any]], +) -> Callable[[Any], AbstractAsyncContextManager[Any]]: + cmgr = contextlib.contextmanager(lifespan_context) + + @functools.wraps(cmgr) + def wrapper(app: Any) -> _AsyncLiftContextManager[Any]: + return _AsyncLiftContextManager(cmgr(app)) + + return wrapper + + +class _DefaultLifespan: + def __init__(self, router: Router): + self._router = router + + async def __aenter__(self) -> None: + pass + + async def __aexit__(self, *exc_info: object) -> None: + pass + + def __call__(self: _T, app: object) -> _T: + return self + + +class Router: + def __init__( + self, + routes: Sequence[BaseRoute] | None = None, + redirect_slashes: bool = True, + default: ASGIApp | None = None, + # the generic to Lifespan[AppType] is the type of the top level application + # which the router cannot know statically, so we use Any + lifespan: Lifespan[Any] | None = None, + *, + middleware: Sequence[Middleware] | None = None, + max_body_size: int | None = None, + ) -> None: + self.routes = [] if routes is None else list(routes) + self.redirect_slashes = redirect_slashes + self.default = self.not_found if default is None else default + + if lifespan is None: + self.lifespan_context: Lifespan[Any] = _DefaultLifespan(self) + + elif inspect.isasyncgenfunction(lifespan): + warnings.warn( + "async generator function lifespans are deprecated, " + "use an @contextlib.asynccontextmanager function instead", + StarletteDeprecationWarning, + ) + self.lifespan_context = asynccontextmanager(lifespan) + elif inspect.isgeneratorfunction(lifespan): + warnings.warn( + "generator function lifespans are deprecated, use an @contextlib.asynccontextmanager function instead", + StarletteDeprecationWarning, + ) + self.lifespan_context = _wrap_gen_lifespan_context(lifespan) + else: + self.lifespan_context = lifespan + + self.middleware_stack = self.app + if middleware: + for cls, args, kwargs in reversed(middleware): + self.middleware_stack = cls(self.middleware_stack, *args, **kwargs) + if max_body_size is not None: + self.middleware_stack = RequestBodyLimitMiddleware(self.middleware_stack, max_body_size=max_body_size) + + async def not_found(self, scope: Scope, receive: Receive, send: Send) -> None: + if scope["type"] == "websocket": + websocket_close = WebSocketClose() + await websocket_close(scope, receive, send) + return + + # If we're running inside a starlette application then raise an + # exception, so that the configurable exception handler can deal with + # returning the response. For plain ASGI apps, just return the response. + if "app" in scope: + raise HTTPException(status_code=404) + else: + response = PlainTextResponse("Not Found", status_code=404) + await response(scope, receive, send) + + def url_path_for(self, name: str, /, **path_params: Any) -> URLPath: + for route in self.routes: + try: + return route.url_path_for(name, **path_params) + except NoMatchFound: + pass + raise NoMatchFound(name, path_params) + + async def lifespan(self, scope: Scope, receive: Receive, send: Send) -> None: + """ + Handle ASGI lifespan messages, which allows us to manage application + startup and shutdown events. + """ + started = False + app: Any = scope.get("app") + await receive() + try: + async with self.lifespan_context(app) as maybe_state: + if maybe_state is not None: + if "state" not in scope: + raise RuntimeError('The server does not support "state" in the lifespan scope.') + scope["state"].update(maybe_state) + await send({"type": "lifespan.startup.complete"}) + started = True + await receive() + except BaseException: + exc_text = traceback.format_exc() + if started: + await send({"type": "lifespan.shutdown.failed", "message": exc_text}) + else: + await send({"type": "lifespan.startup.failed", "message": exc_text}) + raise + else: + await send({"type": "lifespan.shutdown.complete"}) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + """ + The main entry point to the Router class. + """ + await self.middleware_stack(scope, receive, send) + + async def app(self, scope: Scope, receive: Receive, send: Send) -> None: + assert scope["type"] in ("http", "websocket", "lifespan") + + if "router" not in scope: + scope["router"] = self + + if scope["type"] == "lifespan": + await self.lifespan(scope, receive, send) + return + + partial = None + + for route in self.routes: + # Determine if any route matches the incoming scope, + # and hand over to the matching route if found. + match, child_scope = route.matches(scope) + if match == Match.FULL: + scope["route"] = route + scope.update(child_scope) + await route.handle(scope, receive, send) + return + elif match == Match.PARTIAL and partial is None: + partial = route + partial_scope = child_scope + + if partial is not None: + #  Handle partial matches. These are cases where an endpoint is + # able to handle the request, but is not a preferred option. + # We use this in particular to deal with "405 Method Not Allowed". + scope["route"] = partial + scope.update(partial_scope) + await partial.handle(scope, receive, send) + return + + route_path = get_route_path(scope) + if scope["type"] == "http" and self.redirect_slashes and route_path != "/": + redirect_scope = dict(scope) + if route_path.endswith("/"): + redirect_scope["path"] = redirect_scope["path"].rstrip("/") + else: + redirect_scope["path"] = redirect_scope["path"] + "/" + + for route in self.routes: + match, child_scope = route.matches(redirect_scope) + if match != Match.NONE: + redirect_url = URL(scope=redirect_scope) + response = RedirectResponse(url=str(redirect_url)) + await response(scope, receive, send) + return + + await self.default(scope, receive, send) + + def __eq__(self, other: Any) -> bool: + return isinstance(other, Router) and self.routes == other.routes + + def mount(self, path: str, app: ASGIApp, name: str | None = None) -> None: # pragma: no cover + route = Mount(path, app=app, name=name) + self.routes.append(route) + + def host(self, host: str, app: ASGIApp, name: str | None = None) -> None: # pragma: no cover + route = Host(host, app=app, name=name) + self.routes.append(route) + + def add_route( + self, + path: str, + endpoint: Callable[[Request], Awaitable[Response] | Response], + methods: Collection[str] | None = None, + name: str | None = None, + include_in_schema: bool = True, + ) -> None: # pragma: no cover + route = Route( + path, + endpoint=endpoint, + methods=methods, + name=name, + include_in_schema=include_in_schema, + ) + self.routes.append(route) + + def add_websocket_route( + self, + path: str, + endpoint: Callable[[WebSocket], Awaitable[None]], + name: str | None = None, + ) -> None: # pragma: no cover + route = WebSocketRoute(path, endpoint=endpoint, name=name) + self.routes.append(route) diff --git a/source/target-vendors/cp312/starlette/schemas.py b/source/target-vendors/cp312/starlette/schemas.py new file mode 100644 index 0000000..484664c --- /dev/null +++ b/source/target-vendors/cp312/starlette/schemas.py @@ -0,0 +1,152 @@ +from __future__ import annotations + +import inspect +import re +from collections.abc import Callable +from typing import Any, NamedTuple + +from starlette.requests import Request +from starlette.responses import Response +from starlette.routing import BaseRoute, Host, Mount, Route + +try: + import yaml +except ModuleNotFoundError: # pragma: no cover + yaml = None # type: ignore[assignment] + + +class OpenAPIResponse(Response): + media_type = "application/vnd.oai.openapi" + + def render(self, content: Any) -> bytes: + assert yaml is not None, "`pyyaml` must be installed to use OpenAPIResponse." + assert isinstance(content, dict), "The schema passed to OpenAPIResponse should be a dictionary." + return yaml.dump(content, default_flow_style=False).encode("utf-8") + + +class EndpointInfo(NamedTuple): + path: str + http_method: str + func: Callable[..., Any] + + +_remove_converter_pattern = re.compile(r":\w+}") + + +class BaseSchemaGenerator: + def get_schema(self, routes: list[BaseRoute]) -> dict[str, Any]: + raise NotImplementedError() # pragma: no cover + + def get_endpoints(self, routes: list[BaseRoute]) -> list[EndpointInfo]: + """ + Given the routes, yields the following information: + + - path + eg: /users/ + - http_method + one of 'get', 'post', 'put', 'patch', 'delete', 'options', 'query' + - func + method ready to extract the docstring + """ + endpoints_info: list[EndpointInfo] = [] + + for route in routes: + if isinstance(route, Mount | Host): + routes = route.routes or [] + if isinstance(route, Mount): + path = self._remove_converter(route.path) + else: + path = "" + sub_endpoints = [ + EndpointInfo( + path="".join((path, sub_endpoint.path)), + http_method=sub_endpoint.http_method, + func=sub_endpoint.func, + ) + for sub_endpoint in self.get_endpoints(routes) + ] + endpoints_info.extend(sub_endpoints) + + elif not isinstance(route, Route) or not route.include_in_schema: + continue + + elif inspect.isfunction(route.endpoint) or inspect.ismethod(route.endpoint): + path = self._remove_converter(route.path) + for method in route.methods or ["GET"]: + if method == "HEAD": + continue + endpoints_info.append(EndpointInfo(path, method.lower(), route.endpoint)) + else: + path = self._remove_converter(route.path) + for method in ["get", "post", "put", "patch", "delete", "options", "query"]: + if not hasattr(route.endpoint, method): + continue + func = getattr(route.endpoint, method) + endpoints_info.append(EndpointInfo(path, method.lower(), func)) + + return endpoints_info + + def _remove_converter(self, path: str) -> str: + """ + Remove the converter from the path. + For example, a route like this: + Route("/users/{id:int}", endpoint=get_user, methods=["GET"]) + Should be represented as `/users/{id}` in the OpenAPI schema. + """ + return _remove_converter_pattern.sub("}", path) + + def parse_docstring(self, func_or_method: Callable[..., Any]) -> dict[str, Any]: + """ + Given a function, parse the docstring as YAML and return a dictionary of info. + """ + docstring = func_or_method.__doc__ + if not docstring: + return {} + + assert yaml is not None, "`pyyaml` must be installed to use parse_docstring." + + # We support having regular docstrings before the schema + # definition. Here we return just the schema part from + # the docstring. + docstring = docstring.split("---")[-1] + + parsed = yaml.safe_load(docstring) + + if not isinstance(parsed, dict): + # A regular docstring (not yaml formatted) can return + # a simple string here, which wouldn't follow the schema. + return {} + + return parsed + + def OpenAPIResponse(self, request: Request) -> Response: + routes = request.app.routes + schema = self.get_schema(routes=routes) + return OpenAPIResponse(schema) + + +class SchemaGenerator(BaseSchemaGenerator): + def __init__(self, base_schema: dict[str, Any]) -> None: + self.base_schema = base_schema + + def get_schema(self, routes: list[BaseRoute]) -> dict[str, Any]: + schema = dict(self.base_schema) + schema.setdefault("paths", {}) + openapi_version_match = re.match(r"^(\d+)\.(\d+)", str(schema.get("openapi", ""))) + supports_query = openapi_version_match is not None and tuple(map(int, openapi_version_match.groups())) >= (3, 2) + endpoints_info = self.get_endpoints(routes) + + for endpoint in endpoints_info: + if endpoint.http_method == "query" and not supports_query: + continue + parsed = self.parse_docstring(endpoint.func) + + if not parsed: + continue + + if endpoint.path not in schema["paths"]: + schema["paths"][endpoint.path] = {} + + schema["paths"][endpoint.path][endpoint.http_method] = parsed + + return schema diff --git a/source/target-vendors/cp312/starlette/staticfiles.py b/source/target-vendors/cp312/starlette/staticfiles.py new file mode 100644 index 0000000..77b62e1 --- /dev/null +++ b/source/target-vendors/cp312/starlette/staticfiles.py @@ -0,0 +1,231 @@ +from __future__ import annotations + +import errno +import importlib.util +import os +import stat +from email.utils import parsedate +from typing import Union + +import anyio +import anyio.to_thread + +from starlette._utils import get_route_path +from starlette.datastructures import URL, Headers +from starlette.exceptions import HTTPException +from starlette.responses import FileResponse, RedirectResponse, Response +from starlette.types import Receive, Scope, Send +from starlette.websockets import WebSocketClose + +PathLike = Union[str, "os.PathLike[str]"] + + +class NotModifiedResponse(Response): + NOT_MODIFIED_HEADERS = ( + "cache-control", + "content-location", + "date", + "etag", + "expires", + "vary", + ) + + def __init__(self, headers: Headers): + super().__init__( + status_code=304, + headers={name: value for name, value in headers.items() if name in self.NOT_MODIFIED_HEADERS}, + ) + + +class StaticFiles: + def __init__( + self, + *, + directory: PathLike | None = None, + packages: list[str | tuple[str, str]] | None = None, + html: bool = False, + check_dir: bool = True, + follow_symlink: bool = False, + ) -> None: + self.directory = directory + self.packages = packages + self.all_directories = self.get_directories(directory, packages) + self.html = html + self.config_checked = False + self.follow_symlink = follow_symlink + if check_dir and directory is not None and not os.path.isdir(directory): + raise RuntimeError(f"Directory '{directory}' does not exist") + + def get_directories( + self, + directory: PathLike | None = None, + packages: list[str | tuple[str, str]] | None = None, + ) -> list[PathLike]: + """ + Given `directory` and `packages` arguments, return a list of all the + directories that should be used for serving static files from. + """ + directories = [] + if directory is not None: + directories.append(directory) + + for package in packages or []: + if isinstance(package, tuple): + package, statics_dir = package + else: + statics_dir = "statics" + spec = importlib.util.find_spec(package) + assert spec is not None, f"Package {package!r} could not be found." + assert spec.origin is not None, f"Package {package!r} could not be found." + package_directory = os.path.normpath(os.path.join(spec.origin, "..", statics_dir)) + assert os.path.isdir(package_directory), ( + f"Directory '{statics_dir!r}' in package {package!r} could not be found." + ) + directories.append(package_directory) + + return directories + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + """ + The ASGI entry point. + """ + if scope["type"] == "websocket": + websocket_close = WebSocketClose() + await websocket_close(scope, receive, send) + return + + assert scope["type"] == "http" + + if not self.config_checked: + await self.check_config() + self.config_checked = True + + path = self.get_path(scope) + response = await self.get_response(path, scope) + await response(scope, receive, send) + + def get_path(self, scope: Scope) -> str: + """ + Given the ASGI scope, return the `path` string to serve up, + with OS specific path separators, and any '..', '.' components removed. + """ + route_path = get_route_path(scope) + return os.path.normpath(os.path.join(*route_path.split("/"))) + + async def get_response(self, path: str, scope: Scope) -> Response: + """ + Returns an HTTP response, given the incoming path, method and request headers. + """ + if scope["method"] not in ("GET", "HEAD"): + raise HTTPException(status_code=405) + + try: + full_path, stat_result = await anyio.to_thread.run_sync(self.lookup_path, path) + except PermissionError: + raise HTTPException(status_code=401) + except OSError as exc: + # Filename is too long, so it can't be a valid static file. + if exc.errno == errno.ENAMETOOLONG: + raise HTTPException(status_code=404) + + raise exc + except ValueError: + # Null bytes or other invalid characters in the path. + raise HTTPException(status_code=404) + + if stat_result and stat.S_ISREG(stat_result.st_mode): + # We have a static file to serve. + return self.file_response(full_path, stat_result, scope) + + elif stat_result and stat.S_ISDIR(stat_result.st_mode) and self.html: + # We're in HTML mode, and have got a directory URL. + # Check if we have 'index.html' file to serve. + index_path = os.path.join(path, "index.html") + full_path, stat_result = await anyio.to_thread.run_sync(self.lookup_path, index_path) + if stat_result is not None and stat.S_ISREG(stat_result.st_mode): + if not scope["path"].endswith("/"): + # Directory URLs should redirect to always end in "/". + url = URL(scope=scope) + url = url.replace(path=url.path + "/") + return RedirectResponse(url=url) + return self.file_response(full_path, stat_result, scope) + + if self.html: + # Check for '404.html' if we're in HTML mode. + full_path, stat_result = await anyio.to_thread.run_sync(self.lookup_path, "404.html") + if stat_result and stat.S_ISREG(stat_result.st_mode): + return FileResponse(full_path, stat_result=stat_result, status_code=404) + raise HTTPException(status_code=404) + + def lookup_path(self, path: str) -> tuple[str, os.stat_result | None]: + # Reject absolute paths so they cannot escape the served directory. + if path.startswith(("/", "\\")): + return "", None + for directory in self.all_directories: + joined_path = os.path.join(directory, path) + if self.follow_symlink: + full_path = os.path.abspath(joined_path) + directory = os.path.abspath(directory) + else: + full_path = os.path.realpath(joined_path) + directory = os.path.realpath(directory) + if os.path.commonpath([full_path, directory]) != str(directory): + # Don't allow misbehaving clients to break out of the static files directory. + continue + try: + return full_path, os.stat(full_path) + except (FileNotFoundError, NotADirectoryError): + continue + return "", None + + def file_response( + self, + full_path: PathLike, + stat_result: os.stat_result, + scope: Scope, + status_code: int = 200, + ) -> Response: + request_headers = Headers(scope=scope) + + response = FileResponse(full_path, status_code=status_code, stat_result=stat_result) + if self.is_not_modified(response.headers, request_headers): + return NotModifiedResponse(response.headers) + return response + + async def check_config(self) -> None: + """ + Perform a one-off configuration check that StaticFiles is actually + pointed at a directory, so that we can raise loud errors rather than + just returning 404 responses. + """ + if self.directory is None: + return + + try: + stat_result = await anyio.to_thread.run_sync(os.stat, self.directory) + except FileNotFoundError: + raise RuntimeError(f"StaticFiles directory '{self.directory}' does not exist.") + if not (stat.S_ISDIR(stat_result.st_mode) or stat.S_ISLNK(stat_result.st_mode)): + raise RuntimeError(f"StaticFiles path '{self.directory}' is not a directory.") + + def is_not_modified(self, response_headers: Headers, request_headers: Headers) -> bool: + """ + Given the request and response headers, return `True` if an HTTP + "Not Modified" response could be returned instead. + """ + if if_none_match := request_headers.get("if-none-match"): + if if_none_match.strip() == "*": + return True + # The "etag" header is added by FileResponse, so it's always present. + etag = response_headers["etag"] + return etag in [tag.strip().removeprefix("W/") for tag in if_none_match.split(",")] + + try: + if_modified_since = parsedate(request_headers["if-modified-since"]) + last_modified = parsedate(response_headers["last-modified"]) + if if_modified_since is not None and last_modified is not None and if_modified_since >= last_modified: + return True + except KeyError: + pass + + return False diff --git a/source/target-vendors/cp312/starlette/status.py b/source/target-vendors/cp312/starlette/status.py new file mode 100644 index 0000000..202b6b5 --- /dev/null +++ b/source/target-vendors/cp312/starlette/status.py @@ -0,0 +1,211 @@ +""" +HTTP codes +See HTTP Status Code Registry: +https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + +And RFC 9110 - https://www.rfc-editor.org/rfc/rfc9110 +""" + +from __future__ import annotations + +import warnings + +from starlette.exceptions import StarletteDeprecationWarning + +__all__ = [ + "HTTP_100_CONTINUE", + "HTTP_101_SWITCHING_PROTOCOLS", + "HTTP_102_PROCESSING", + "HTTP_103_EARLY_HINTS", + "HTTP_200_OK", + "HTTP_201_CREATED", + "HTTP_202_ACCEPTED", + "HTTP_203_NON_AUTHORITATIVE_INFORMATION", + "HTTP_204_NO_CONTENT", + "HTTP_205_RESET_CONTENT", + "HTTP_206_PARTIAL_CONTENT", + "HTTP_207_MULTI_STATUS", + "HTTP_208_ALREADY_REPORTED", + "HTTP_226_IM_USED", + "HTTP_300_MULTIPLE_CHOICES", + "HTTP_301_MOVED_PERMANENTLY", + "HTTP_302_FOUND", + "HTTP_303_SEE_OTHER", + "HTTP_304_NOT_MODIFIED", + "HTTP_305_USE_PROXY", + "HTTP_306_RESERVED", + "HTTP_307_TEMPORARY_REDIRECT", + "HTTP_308_PERMANENT_REDIRECT", + "HTTP_400_BAD_REQUEST", + "HTTP_401_UNAUTHORIZED", + "HTTP_402_PAYMENT_REQUIRED", + "HTTP_403_FORBIDDEN", + "HTTP_404_NOT_FOUND", + "HTTP_405_METHOD_NOT_ALLOWED", + "HTTP_406_NOT_ACCEPTABLE", + "HTTP_407_PROXY_AUTHENTICATION_REQUIRED", + "HTTP_408_REQUEST_TIMEOUT", + "HTTP_409_CONFLICT", + "HTTP_410_GONE", + "HTTP_411_LENGTH_REQUIRED", + "HTTP_412_PRECONDITION_FAILED", + "HTTP_413_CONTENT_TOO_LARGE", + "HTTP_414_URI_TOO_LONG", + "HTTP_415_UNSUPPORTED_MEDIA_TYPE", + "HTTP_416_RANGE_NOT_SATISFIABLE", + "HTTP_417_EXPECTATION_FAILED", + "HTTP_418_IM_A_TEAPOT", + "HTTP_421_MISDIRECTED_REQUEST", + "HTTP_422_UNPROCESSABLE_CONTENT", + "HTTP_423_LOCKED", + "HTTP_424_FAILED_DEPENDENCY", + "HTTP_425_TOO_EARLY", + "HTTP_426_UPGRADE_REQUIRED", + "HTTP_428_PRECONDITION_REQUIRED", + "HTTP_429_TOO_MANY_REQUESTS", + "HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE", + "HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS", + "HTTP_500_INTERNAL_SERVER_ERROR", + "HTTP_501_NOT_IMPLEMENTED", + "HTTP_502_BAD_GATEWAY", + "HTTP_503_SERVICE_UNAVAILABLE", + "HTTP_504_GATEWAY_TIMEOUT", + "HTTP_505_HTTP_VERSION_NOT_SUPPORTED", + "HTTP_506_VARIANT_ALSO_NEGOTIATES", + "HTTP_507_INSUFFICIENT_STORAGE", + "HTTP_508_LOOP_DETECTED", + "HTTP_510_NOT_EXTENDED", + "HTTP_511_NETWORK_AUTHENTICATION_REQUIRED", + "WS_1000_NORMAL_CLOSURE", + "WS_1001_GOING_AWAY", + "WS_1002_PROTOCOL_ERROR", + "WS_1003_UNSUPPORTED_DATA", + "WS_1005_NO_STATUS_RCVD", + "WS_1006_ABNORMAL_CLOSURE", + "WS_1007_INVALID_FRAME_PAYLOAD_DATA", + "WS_1008_POLICY_VIOLATION", + "WS_1009_MESSAGE_TOO_BIG", + "WS_1010_MANDATORY_EXT", + "WS_1011_INTERNAL_ERROR", + "WS_1012_SERVICE_RESTART", + "WS_1013_TRY_AGAIN_LATER", + "WS_1014_BAD_GATEWAY", + "WS_1015_TLS_HANDSHAKE", +] + +HTTP_100_CONTINUE = 100 +HTTP_101_SWITCHING_PROTOCOLS = 101 +HTTP_102_PROCESSING = 102 +HTTP_103_EARLY_HINTS = 103 +HTTP_200_OK = 200 +HTTP_201_CREATED = 201 +HTTP_202_ACCEPTED = 202 +HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 +HTTP_204_NO_CONTENT = 204 +HTTP_205_RESET_CONTENT = 205 +HTTP_206_PARTIAL_CONTENT = 206 +HTTP_207_MULTI_STATUS = 207 +HTTP_208_ALREADY_REPORTED = 208 +HTTP_226_IM_USED = 226 +HTTP_300_MULTIPLE_CHOICES = 300 +HTTP_301_MOVED_PERMANENTLY = 301 +HTTP_302_FOUND = 302 +HTTP_303_SEE_OTHER = 303 +HTTP_304_NOT_MODIFIED = 304 +HTTP_305_USE_PROXY = 305 +HTTP_306_RESERVED = 306 +HTTP_307_TEMPORARY_REDIRECT = 307 +HTTP_308_PERMANENT_REDIRECT = 308 +HTTP_400_BAD_REQUEST = 400 +HTTP_401_UNAUTHORIZED = 401 +HTTP_402_PAYMENT_REQUIRED = 402 +HTTP_403_FORBIDDEN = 403 +HTTP_404_NOT_FOUND = 404 +HTTP_405_METHOD_NOT_ALLOWED = 405 +HTTP_406_NOT_ACCEPTABLE = 406 +HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407 +HTTP_408_REQUEST_TIMEOUT = 408 +HTTP_409_CONFLICT = 409 +HTTP_410_GONE = 410 +HTTP_411_LENGTH_REQUIRED = 411 +HTTP_412_PRECONDITION_FAILED = 412 +HTTP_413_CONTENT_TOO_LARGE = 413 +HTTP_414_URI_TOO_LONG = 414 +HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415 +HTTP_416_RANGE_NOT_SATISFIABLE = 416 +HTTP_417_EXPECTATION_FAILED = 417 +HTTP_418_IM_A_TEAPOT = 418 +HTTP_421_MISDIRECTED_REQUEST = 421 +HTTP_422_UNPROCESSABLE_CONTENT = 422 +HTTP_423_LOCKED = 423 +HTTP_424_FAILED_DEPENDENCY = 424 +HTTP_425_TOO_EARLY = 425 +HTTP_426_UPGRADE_REQUIRED = 426 +HTTP_428_PRECONDITION_REQUIRED = 428 +HTTP_429_TOO_MANY_REQUESTS = 429 +HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 +HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 +HTTP_500_INTERNAL_SERVER_ERROR = 500 +HTTP_501_NOT_IMPLEMENTED = 501 +HTTP_502_BAD_GATEWAY = 502 +HTTP_503_SERVICE_UNAVAILABLE = 503 +HTTP_504_GATEWAY_TIMEOUT = 504 +HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505 +HTTP_506_VARIANT_ALSO_NEGOTIATES = 506 +HTTP_507_INSUFFICIENT_STORAGE = 507 +HTTP_508_LOOP_DETECTED = 508 +HTTP_510_NOT_EXTENDED = 510 +HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511 + + +""" +WebSocket codes +https://www.iana.org/assignments/websocket/websocket.xml#close-code-number +https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent +""" +WS_1000_NORMAL_CLOSURE = 1000 +WS_1001_GOING_AWAY = 1001 +WS_1002_PROTOCOL_ERROR = 1002 +WS_1003_UNSUPPORTED_DATA = 1003 +WS_1005_NO_STATUS_RCVD = 1005 +WS_1006_ABNORMAL_CLOSURE = 1006 +WS_1007_INVALID_FRAME_PAYLOAD_DATA = 1007 +WS_1008_POLICY_VIOLATION = 1008 +WS_1009_MESSAGE_TOO_BIG = 1009 +WS_1010_MANDATORY_EXT = 1010 +WS_1011_INTERNAL_ERROR = 1011 +WS_1012_SERVICE_RESTART = 1012 +WS_1013_TRY_AGAIN_LATER = 1013 +WS_1014_BAD_GATEWAY = 1014 +WS_1015_TLS_HANDSHAKE = 1015 + +__deprecated__ = { + "HTTP_413_REQUEST_ENTITY_TOO_LARGE": 413, + "HTTP_414_REQUEST_URI_TOO_LONG": 414, + "HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE": 416, + "HTTP_422_UNPROCESSABLE_ENTITY": 422, +} + + +def __getattr__(name: str) -> int: + deprecation_changes = { + "HTTP_413_REQUEST_ENTITY_TOO_LARGE": "HTTP_413_CONTENT_TOO_LARGE", + "HTTP_414_REQUEST_URI_TOO_LONG": "HTTP_414_URI_TOO_LONG", + "HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE": "HTTP_416_RANGE_NOT_SATISFIABLE", + "HTTP_422_UNPROCESSABLE_ENTITY": "HTTP_422_UNPROCESSABLE_CONTENT", + } + + deprecated = __deprecated__.get(name) + if deprecated: + warnings.warn( + f"'{name}' is deprecated. Use '{deprecation_changes[name]}' instead.", + category=StarletteDeprecationWarning, + stacklevel=3, + ) + return deprecated + + raise AttributeError(f"module 'starlette.status' has no attribute '{name}'") + + +def __dir__() -> list[str]: + return sorted(list(__all__) + list(__deprecated__.keys())) # pragma: no cover diff --git a/source/target-vendors/cp312/starlette/templating.py b/source/target-vendors/cp312/starlette/templating.py new file mode 100644 index 0000000..67872b3 --- /dev/null +++ b/source/target-vendors/cp312/starlette/templating.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +from collections.abc import Callable, Mapping, Sequence +from os import PathLike +from typing import TYPE_CHECKING, Any, overload + +from starlette.background import BackgroundTask +from starlette.datastructures import URL +from starlette.requests import Request +from starlette.responses import HTMLResponse +from starlette.types import Receive, Scope, Send + +try: + import jinja2 + + # @contextfunction was renamed to @pass_context in Jinja 3.0, and was removed in 3.1 + # hence we try to get pass_context (most installs will be >=3.1) + # and fall back to contextfunction, + # adding a type ignore for mypy to let us access an attribute that may not exist + if TYPE_CHECKING: + pass_context = jinja2.pass_context + else: + if hasattr(jinja2, "pass_context"): + pass_context = jinja2.pass_context + else: # pragma: no cover + pass_context = jinja2.contextfunction # type: ignore[attr-defined] +except ImportError as _import_error: # pragma: no cover + raise ImportError("jinja2 must be installed to use Jinja2Templates") from _import_error + + +class _TemplateResponse(HTMLResponse): + def __init__( + self, + template: Any, + context: dict[str, Any], + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + background: BackgroundTask | None = None, + ): + self.template = template + self.context = context + content = template.render(context) + super().__init__(content, status_code, headers, media_type, background) + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + request = self.context.get("request", {}) + extensions = request.get("extensions", {}) + if "http.response.debug" in extensions: # pragma: no branch + await send({"type": "http.response.debug", "info": {"template": self.template, "context": self.context}}) + await super().__call__(scope, receive, send) + + +class Jinja2Templates: + """Jinja2 template renderer. + + Example: + ```python + from starlette.templating import Jinja2Templates + + templates = Jinja2Templates(directory="templates") + + async def homepage(request: Request) -> Response: + return templates.TemplateResponse(request, "index.html") + ``` + """ + + @overload + def __init__( + self, + directory: str | PathLike[str] | Sequence[str | PathLike[str]], + *, + context_processors: list[Callable[[Request], dict[str, Any]]] | None = None, + ) -> None: ... + + @overload + def __init__( + self, + *, + env: jinja2.Environment, + context_processors: list[Callable[[Request], dict[str, Any]]] | None = None, + ) -> None: ... + + def __init__( + self, + directory: str | PathLike[str] | Sequence[str | PathLike[str]] | None = None, + *, + context_processors: list[Callable[[Request], dict[str, Any]]] | None = None, + env: jinja2.Environment | None = None, + ) -> None: + assert bool(directory) ^ bool(env), "either 'directory' or 'env' arguments must be passed" + self.context_processors = context_processors or [] + if directory is not None: + loader = jinja2.FileSystemLoader(directory) + self.env = jinja2.Environment(loader=loader, autoescape=jinja2.select_autoescape()) + elif env is not None: # pragma: no branch + self.env = env + + self._setup_env_defaults(self.env) + + def _setup_env_defaults(self, env: jinja2.Environment) -> None: + @pass_context + def url_for( + context: dict[str, Any], + name: str, + /, + **path_params: Any, + ) -> URL: + request: Request = context["request"] + return request.url_for(name, **path_params) + + env.globals.setdefault("url_for", url_for) + + def get_template(self, name: str) -> jinja2.Template: + return self.env.get_template(name) + + def TemplateResponse( + self, + request: Request, + name: str, + context: dict[str, Any] | None = None, + status_code: int = 200, + headers: Mapping[str, str] | None = None, + media_type: str | None = None, + background: BackgroundTask | None = None, + ) -> _TemplateResponse: + """ + Render a template and return an HTML response. + + Args: + request: The incoming request instance. + name: The template file name to render. + context: Variables to pass to the template. + status_code: HTTP status code for the response. + headers: Additional headers to include in the response. + media_type: Media type for the response. + background: Background task to run after response is sent. + + Returns: + An HTML response with the rendered template content. + """ + context = context or {} + + context.setdefault("request", request) + for context_processor in self.context_processors: + context.update(context_processor(request)) + + template = self.get_template(name) + return _TemplateResponse( + template, + context, + status_code=status_code, + headers=headers, + media_type=media_type, + background=background, + ) diff --git a/source/target-vendors/cp312/starlette/testclient.py b/source/target-vendors/cp312/starlette/testclient.py new file mode 100644 index 0000000..2f3f468 --- /dev/null +++ b/source/target-vendors/cp312/starlette/testclient.py @@ -0,0 +1,568 @@ +from __future__ import annotations + +import contextlib +import inspect +import io +import json +import math +import sys +import warnings +from collections.abc import Awaitable, Callable, Generator, Iterable, Mapping, Sequence +from concurrent.futures import Future +from contextlib import AbstractContextManager +from types import GeneratorType +from typing import TYPE_CHECKING, Any, Literal, TypedDict, TypeGuard, cast +from urllib.parse import unquote, urljoin + +import anyio +import anyio.abc +import anyio.from_thread +from anyio.streams.stapled import StapledObjectStream + +from starlette._utils import is_async_callable +from starlette.exceptions import StarletteDeprecationWarning +from starlette.types import ASGIApp, Message, Receive, Scope, Send +from starlette.websockets import WebSocketDisconnect + +if sys.version_info >= (3, 11): # pragma: no cover + from typing import Self +else: # pragma: no cover + from typing_extensions import Self + +if TYPE_CHECKING: + import httpx2 as httpx +else: + try: + import httpx2 as httpx + except ModuleNotFoundError: # pragma: no cover + try: + import httpx + except ModuleNotFoundError: + raise RuntimeError( + "The starlette.testclient module requires the httpx2 package to be installed.\n" + "You can install this with:\n" + " $ pip install httpx2\n" + ) from None + else: + warnings.warn( + "Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.", + StarletteDeprecationWarning, + stacklevel=2, + ) + +_PortalFactoryType = Callable[[], AbstractContextManager[anyio.from_thread.BlockingPortal]] + +ASGIInstance = Callable[[Receive, Send], Awaitable[None]] +ASGI2App = Callable[[Scope], ASGIInstance] +ASGI3App = Callable[[Scope, Receive, Send], Awaitable[None]] + + +_RequestData = Mapping[str, str | Iterable[str] | bytes] + + +def _is_asgi3(app: ASGI2App | ASGI3App) -> TypeGuard[ASGI3App]: + if inspect.isclass(app): + return hasattr(app, "__await__") + return is_async_callable(app) + + +class _WrapASGI2: + """ + Provide an ASGI3 interface onto an ASGI2 app. + """ + + def __init__(self, app: ASGI2App) -> None: + self.app = app + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + instance = self.app(scope) + await instance(receive, send) + + +class _AsyncBackend(TypedDict): + backend: str + backend_options: dict[str, Any] + + +class _Upgrade(Exception): + def __init__(self, session: WebSocketTestSession) -> None: + self.session = session + + +class WebSocketDenialResponse( # type: ignore[misc] + httpx.Response, + WebSocketDisconnect, +): + """ + A special case of `WebSocketDisconnect`, raised in the `TestClient` if the + `WebSocket` is closed before being accepted with a `send_denial_response()`. + """ + + +class WebSocketTestSession: + def __init__( + self, + app: ASGI3App, + scope: Scope, + portal_factory: _PortalFactoryType, + ) -> None: + self.app = app + self.scope = scope + self.accepted_subprotocol = None + self.portal_factory = portal_factory + self.extra_headers = None + + def __enter__(self) -> Self: + with contextlib.ExitStack() as stack: + self.portal = portal = stack.enter_context(self.portal_factory()) + fut, cs = portal.start_task(self._run) + stack.callback(fut.result) + stack.callback(portal.call, cs.cancel) + self.send({"type": "websocket.connect"}) + message = self.receive() + self._raise_on_close(message) + self.accepted_subprotocol = message.get("subprotocol", None) + self.extra_headers = message.get("headers", None) + stack.callback(self.close, 1000) + self.exit_stack = stack.pop_all() + return self + + def __exit__(self, *args: Any) -> bool | None: + return self.exit_stack.__exit__(*args) + + async def _run(self, *, task_status: anyio.abc.TaskStatus[anyio.CancelScope]) -> None: + """ + The sub-thread in which the websocket session runs. + """ + send_tx, send_rx = anyio.create_memory_object_stream[Message](math.inf) + receive_tx, receive_rx = anyio.create_memory_object_stream[Message](math.inf) + with send_tx, send_rx, receive_tx, receive_rx, anyio.CancelScope() as cs: + self._receive_tx = receive_tx + self._send_rx = send_rx + task_status.started(cs) + await self.app(self.scope, receive_rx.receive, send_tx.send) + + # wait for cs.cancel to be called before closing streams + await anyio.sleep_forever() + + def _raise_on_close(self, message: Message) -> None: + if message["type"] == "websocket.close": + raise WebSocketDisconnect(code=message.get("code", 1000), reason=message.get("reason", "")) + elif message["type"] == "websocket.http.response.start": + status_code: int = message["status"] + headers: list[tuple[bytes, bytes]] = message["headers"] + body: list[bytes] = [] + while True: + message = self.receive() + assert message["type"] == "websocket.http.response.body" + body.append(message["body"]) + if not message.get("more_body", False): + break + raise WebSocketDenialResponse(status_code=status_code, headers=headers, content=b"".join(body)) + + def send(self, message: Message) -> None: + self.portal.call(self._receive_tx.send, message) + + def send_text(self, data: str) -> None: + self.send({"type": "websocket.receive", "text": data}) + + def send_bytes(self, data: bytes) -> None: + self.send({"type": "websocket.receive", "bytes": data}) + + def send_json(self, data: Any, mode: Literal["text", "binary"] = "text") -> None: + text = json.dumps(data, separators=(",", ":"), ensure_ascii=False) + if mode == "text": + self.send({"type": "websocket.receive", "text": text}) + else: + self.send({"type": "websocket.receive", "bytes": text.encode("utf-8")}) + + def close(self, code: int = 1000, reason: str | None = None) -> None: + self.send({"type": "websocket.disconnect", "code": code, "reason": reason}) + + def receive(self) -> Message: + return self.portal.call(self._send_rx.receive) + + def receive_text(self) -> str: + message = self.receive() + self._raise_on_close(message) + return cast(str, message["text"]) + + def receive_bytes(self) -> bytes: + message = self.receive() + self._raise_on_close(message) + return cast(bytes, message["bytes"]) + + def receive_json(self, mode: Literal["text", "binary"] = "text") -> Any: + message = self.receive() + self._raise_on_close(message) + if mode == "text": + text = message["text"] + else: + text = message["bytes"].decode("utf-8") + return json.loads(text) + + +class _TestClientTransport(httpx.BaseTransport): + def __init__( + self, + app: ASGI3App, + portal_factory: _PortalFactoryType, + raise_server_exceptions: bool = True, + root_path: str = "", + *, + client: tuple[str, int], + app_state: dict[str, Any], + ) -> None: + self.app = app + self.raise_server_exceptions = raise_server_exceptions + self.root_path = root_path + self.portal_factory = portal_factory + self.app_state = app_state + self.client = client + + def handle_request(self, request: httpx.Request) -> httpx.Response: + scheme = request.url.scheme + host = request.url.raw_host.decode(encoding="ascii") + path = request.url.path + raw_path = request.url.raw_path + query = request.url.query.decode(encoding="ascii") + + default_port = {"http": 80, "ws": 80, "https": 443, "wss": 443}[scheme] + port = request.url.port + if port is None: + port = default_port + + # Include the 'host' header. + if "host" in request.headers: + headers: list[tuple[bytes, bytes]] = [] + else: # pragma: no cover + headers = [(b"host", request.url.netloc)] + + # Include other request headers. + headers += [(key.lower().encode(), value.encode()) for key, value in request.headers.multi_items()] + + scope: dict[str, Any] + + if scheme in {"ws", "wss"}: + subprotocol = request.headers.get("sec-websocket-protocol", None) + if subprotocol is None: + subprotocols: Sequence[str] = [] + else: + subprotocols = [value.strip() for value in subprotocol.split(",")] + scope = { + "type": "websocket", + "path": unquote(path), + "raw_path": raw_path.split(b"?", 1)[0], + "root_path": self.root_path, + "scheme": scheme, + "query_string": query.encode(), + "headers": headers, + "client": self.client, + "server": [host, port], + "subprotocols": subprotocols, + "state": self.app_state.copy(), + "extensions": {"websocket.http.response": {}}, + } + session = WebSocketTestSession(self.app, scope, self.portal_factory) + raise _Upgrade(session) + + scope = { + "type": "http", + "http_version": "1.1", + "method": request.method, + "path": unquote(path), + "raw_path": raw_path.split(b"?", 1)[0], + "root_path": self.root_path, + "scheme": scheme, + "query_string": query.encode(), + "headers": headers, + "client": self.client, + "server": [host, port], + "extensions": {"http.response.debug": {}, "http.response.trailers": {}}, + "state": self.app_state.copy(), + } + + request_complete = False + response_started = False + body_complete = False + trailers_expected = False + trailers: list[tuple[bytes, bytes]] = [] + response_complete: anyio.Event + raw_kwargs: dict[str, Any] = {"stream": io.BytesIO()} + debug_info: dict[str, Any] | None = None + + async def receive() -> Message: + nonlocal request_complete + + if request_complete: + if not response_complete.is_set(): + await response_complete.wait() + return {"type": "http.disconnect"} + + body = request.read() + if isinstance(body, str): + body_bytes: bytes = body.encode("utf-8") # pragma: no cover + elif body is None: + body_bytes = b"" # pragma: no cover + elif isinstance(body, GeneratorType): + try: # pragma: no cover + chunk = body.send(None) + if isinstance(chunk, str): + chunk = chunk.encode("utf-8") + return {"type": "http.request", "body": chunk, "more_body": True} + except StopIteration: # pragma: no cover + request_complete = True + return {"type": "http.request", "body": b""} + else: + body_bytes = body + + request_complete = True + return {"type": "http.request", "body": body_bytes} + + async def send(message: Message) -> None: + nonlocal raw_kwargs, response_started, debug_info, body_complete, trailers_expected + + if message["type"] == "http.response.start": + assert not response_started, 'Received multiple "http.response.start" messages.' + raw_kwargs["status_code"] = message["status"] + raw_kwargs["headers"] = [(key.decode(), value.decode()) for key, value in message.get("headers", [])] + response_started = True + trailers_expected = message.get("trailers", False) + elif message["type"] == "http.response.body": + assert response_started, 'Received "http.response.body" without "http.response.start".' + assert not response_complete.is_set(), 'Received "http.response.body" after response completed.' + assert not body_complete, 'Received "http.response.body" after body completed.' + body = message.get("body", b"") + more_body = message.get("more_body", False) + if request.method != "HEAD": + raw_kwargs["stream"].write(body) + if not more_body: + raw_kwargs["stream"].seek(0) + body_complete = True + if not trailers_expected: + response_complete.set() + elif message["type"] == "http.response.trailers": + assert trailers_expected, 'Received "http.response.trailers" without declaring trailers.' + assert body_complete, 'Received "http.response.trailers" before body completed.' + assert not response_complete.is_set(), 'Received "http.response.trailers" after response completed.' + trailers.extend(message.get("headers", [])) + if not message.get("more_trailers", False): + response_complete.set() + elif message["type"] == "http.response.debug": + debug_info = message["info"] + + try: + with self.portal_factory() as portal: + response_complete = portal.call(anyio.Event) + portal.call(self.app, scope, receive, send) + except BaseException as exc: + if self.raise_server_exceptions: + raise exc + + if self.raise_server_exceptions: + assert response_started, "TestClient did not receive any response." + elif not response_started: + raw_kwargs = { + "status_code": 500, + "headers": [], + "stream": io.BytesIO(), + } + + raw_kwargs["stream"] = httpx.ByteStream(raw_kwargs["stream"].read()) + + response = httpx.Response(**raw_kwargs, request=request) + if trailers_expected: + response.extensions["http.response.trailers"] = trailers + if debug_info is not None: + response.extensions["http.response.debug"] = debug_info + if "template" in debug_info: + response.template = debug_info["template"] # type: ignore[attr-defined] + if "context" in debug_info: + response.context = debug_info["context"] # type: ignore[attr-defined] + return response + + +class TestClient(httpx.Client): + __test__ = False + task: Future[None] + portal: anyio.from_thread.BlockingPortal | None = None + + def __init__( + self, + app: ASGIApp, + base_url: str = "http://testserver", + raise_server_exceptions: bool = True, + root_path: str = "", + backend: Literal["asyncio", "trio"] = "asyncio", + backend_options: dict[str, Any] | None = None, + cookies: httpx._types.CookieTypes | None = None, + headers: dict[str, str] | None = None, + follow_redirects: bool = True, + client: tuple[str, int] = ("testclient", 50000), + ) -> None: + self.async_backend = _AsyncBackend(backend=backend, backend_options=backend_options or {}) + if _is_asgi3(app): + asgi_app = app + else: + app = cast(ASGI2App, app) # type: ignore[assignment] + asgi_app = _WrapASGI2(app) # type: ignore[arg-type] + self.app = asgi_app + self.app_state: dict[str, Any] = {} + transport = _TestClientTransport( + self.app, + portal_factory=self._portal_factory, + raise_server_exceptions=raise_server_exceptions, + root_path=root_path, + app_state=self.app_state, + client=client, + ) + if headers is None: + headers = {} + headers.setdefault("user-agent", "testclient") + super().__init__( + base_url=base_url, + headers=headers, + transport=transport, + follow_redirects=follow_redirects, + cookies=cookies, + ) + + @contextlib.contextmanager + def _portal_factory(self) -> Generator[anyio.from_thread.BlockingPortal, None, None]: + if self.portal is not None: + yield self.portal + else: + with anyio.from_thread.start_blocking_portal(**self.async_backend) as portal: + yield portal + + def request( # type: ignore[override] + self, + method: str, + url: httpx._types.URLTypes, + *, + content: httpx._types.RequestContent | None = None, + data: _RequestData | None = None, + files: httpx._types.RequestFiles | None = None, + json: Any = None, + params: httpx._types.QueryParamTypes | None = None, + headers: httpx._types.HeaderTypes | None = None, + cookies: httpx._types.CookieTypes | None = None, + auth: httpx._types.AuthTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT, + follow_redirects: bool | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT, + timeout: httpx._types.TimeoutTypes | httpx._client.UseClientDefault = httpx._client.USE_CLIENT_DEFAULT, + extensions: dict[str, Any] | None = None, + ) -> httpx.Response: + if timeout is not httpx.USE_CLIENT_DEFAULT: + warnings.warn( + "You should not use the 'timeout' argument with the TestClient. " + "See https://github.com/Kludex/starlette/issues/1108 for more information.", + StarletteDeprecationWarning, + stacklevel=2, + ) + url = self._merge_url(url) + return super().request( + method, + url, + content=content, + data=data, + files=files, + json=json, + params=params, + headers=headers, + cookies=cookies, + auth=auth, + follow_redirects=follow_redirects, + timeout=timeout, + extensions=extensions, + ) + + def websocket_connect( + self, + url: str, + subprotocols: Sequence[str] | None = None, + **kwargs: Any, + ) -> WebSocketTestSession: + url = urljoin("ws://testserver", url) + headers = kwargs.get("headers", {}) + headers.setdefault("connection", "upgrade") + headers.setdefault("sec-websocket-key", "testserver==") + headers.setdefault("sec-websocket-version", "13") + if subprotocols is not None: + headers.setdefault("sec-websocket-protocol", ", ".join(subprotocols)) + kwargs["headers"] = headers + try: + super().request("GET", url, **kwargs) + except _Upgrade as exc: + session = exc.session + else: + raise RuntimeError("Expected WebSocket upgrade") # pragma: no cover + + return session + + def __enter__(self) -> Self: + with contextlib.ExitStack() as stack: + self.portal = portal = stack.enter_context(anyio.from_thread.start_blocking_portal(**self.async_backend)) + + @stack.callback + def reset_portal() -> None: + self.portal = None + + send = anyio.create_memory_object_stream[Message | None](math.inf) + receive = anyio.create_memory_object_stream[Message](math.inf) + for channel in (*send, *receive): + stack.callback(channel.close) + self.stream_send = StapledObjectStream(*send) + self.stream_receive = StapledObjectStream(*receive) + self.task = portal.start_task_soon(self.lifespan) + portal.call(self.wait_startup) + + @stack.callback + def wait_shutdown() -> None: + portal.call(self.wait_shutdown) + + self.exit_stack = stack.pop_all() + + return self + + def __exit__(self, *args: Any) -> None: + self.exit_stack.close() + + async def lifespan(self) -> None: + scope = {"type": "lifespan", "state": self.app_state} + try: + await self.app(scope, self.stream_receive.receive, self.stream_send.send) + finally: + await self.stream_send.send(None) + + async def wait_startup(self) -> None: + await self.stream_receive.send({"type": "lifespan.startup"}) + + async def receive() -> Any: + message = await self.stream_send.receive() + if message is None: + self.task.result() + return message + + message = await receive() + assert message["type"] in ( + "lifespan.startup.complete", + "lifespan.startup.failed", + ) + if message["type"] == "lifespan.startup.failed": + await receive() + + async def wait_shutdown(self) -> None: + async def receive() -> Any: + message = await self.stream_send.receive() + if message is None: + self.task.result() + return message + + await self.stream_receive.send({"type": "lifespan.shutdown"}) + message = await receive() + assert message["type"] in ( + "lifespan.shutdown.complete", + "lifespan.shutdown.failed", + ) + if message["type"] == "lifespan.shutdown.failed": + await receive() diff --git a/source/target-vendors/cp312/starlette/types.py b/source/target-vendors/cp312/starlette/types.py new file mode 100644 index 0000000..b767ae1 --- /dev/null +++ b/source/target-vendors/cp312/starlette/types.py @@ -0,0 +1,26 @@ +from collections.abc import Awaitable, Callable, Mapping, MutableMapping +from contextlib import AbstractAsyncContextManager +from typing import TYPE_CHECKING, Any, TypeVar + +if TYPE_CHECKING: + from starlette.requests import Request + from starlette.responses import Response + from starlette.websockets import WebSocket + +AppType = TypeVar("AppType") + +Scope = MutableMapping[str, Any] +Message = MutableMapping[str, Any] + +Receive = Callable[[], Awaitable[Message]] +Send = Callable[[Message], Awaitable[None]] + +ASGIApp = Callable[[Scope, Receive, Send], Awaitable[None]] + +StatelessLifespan = Callable[[AppType], AbstractAsyncContextManager[None]] +StatefulLifespan = Callable[[AppType], AbstractAsyncContextManager[Mapping[str, Any]]] +Lifespan = StatelessLifespan[AppType] | StatefulLifespan[AppType] + +HTTPExceptionHandler = Callable[["Request", Exception], "Response | Awaitable[Response]"] +WebSocketExceptionHandler = Callable[["WebSocket", Exception], Awaitable[None]] +ExceptionHandler = HTTPExceptionHandler | WebSocketExceptionHandler diff --git a/source/target-vendors/cp312/starlette/websockets.py b/source/target-vendors/cp312/starlette/websockets.py new file mode 100644 index 0000000..cf48e87 --- /dev/null +++ b/source/target-vendors/cp312/starlette/websockets.py @@ -0,0 +1,202 @@ +from __future__ import annotations + +import enum +import json +from collections.abc import AsyncIterator, Iterable +from typing import Any, cast + +from starlette.requests import HTTPConnection, StateT +from starlette.responses import Response +from starlette.types import Message, Receive, Scope, Send + + +class WebSocketState(enum.Enum): + CONNECTING = 0 + CONNECTED = 1 + DISCONNECTED = 2 + RESPONSE = 3 + + +class WebSocketDisconnect(Exception): + def __init__(self, code: int = 1000, reason: str | None = None) -> None: + self.code = code + self.reason = reason or "" + + +class WebSocketDisconnected(RuntimeError): + """ + Raised when attempting to use a disconnected WebSocket. + """ + + +class WebSocket(HTTPConnection[StateT]): + def __init__(self, scope: Scope, receive: Receive, send: Send) -> None: + super().__init__(scope) + assert scope["type"] == "websocket" + self._receive = receive + self._send = send + self.client_state = WebSocketState.CONNECTING + self.application_state = WebSocketState.CONNECTING + + async def receive(self) -> Message: + """ + Receive ASGI websocket messages, ensuring valid state transitions. + """ + if self.client_state == WebSocketState.CONNECTING: + message = await self._receive() + message_type = message["type"] + if message_type != "websocket.connect": + raise RuntimeError(f'Expected ASGI message "websocket.connect", but got {message_type!r}') + self.client_state = WebSocketState.CONNECTED + return message + elif self.client_state == WebSocketState.CONNECTED: + message = await self._receive() + message_type = message["type"] + if message_type not in {"websocket.receive", "websocket.disconnect"}: + raise RuntimeError( + f'Expected ASGI message "websocket.receive" or "websocket.disconnect", but got {message_type!r}' + ) + if message_type == "websocket.disconnect": + self.client_state = WebSocketState.DISCONNECTED + return message + else: + raise WebSocketDisconnected('Cannot call "receive" once a disconnect message has been received.') + + async def send(self, message: Message) -> None: + """ + Send ASGI websocket messages, ensuring valid state transitions. + """ + if self.application_state == WebSocketState.CONNECTING: + message_type = message["type"] + if message_type not in {"websocket.accept", "websocket.close", "websocket.http.response.start"}: + raise RuntimeError( + 'Expected ASGI message "websocket.accept", "websocket.close" or "websocket.http.response.start", ' + f"but got {message_type!r}" + ) + if message_type == "websocket.close": + self.application_state = WebSocketState.DISCONNECTED + elif message_type == "websocket.http.response.start": + self.application_state = WebSocketState.RESPONSE + else: + self.application_state = WebSocketState.CONNECTED + await self._send(message) + elif self.application_state == WebSocketState.CONNECTED: + message_type = message["type"] + if message_type not in {"websocket.send", "websocket.close"}: + raise RuntimeError( + f'Expected ASGI message "websocket.send" or "websocket.close", but got {message_type!r}' + ) + if message_type == "websocket.close": + self.application_state = WebSocketState.DISCONNECTED + try: + await self._send(message) + except OSError: + self.application_state = WebSocketState.DISCONNECTED + raise WebSocketDisconnect(code=1006) + elif self.application_state == WebSocketState.RESPONSE: + message_type = message["type"] + if message_type != "websocket.http.response.body": + raise RuntimeError(f'Expected ASGI message "websocket.http.response.body", but got {message_type!r}') + if not message.get("more_body", False): + self.application_state = WebSocketState.DISCONNECTED + await self._send(message) + else: + raise WebSocketDisconnected('Cannot call "send" once a close message has been sent.') + + async def accept( + self, + subprotocol: str | None = None, + headers: Iterable[tuple[bytes, bytes]] | None = None, + ) -> None: + headers = headers or [] + + if self.client_state == WebSocketState.CONNECTING: # pragma: no branch + # If we haven't yet seen the 'connect' message, then wait for it first. + await self.receive() + await self.send({"type": "websocket.accept", "subprotocol": subprotocol, "headers": headers}) + + def _raise_on_disconnect(self, message: Message) -> None: + if message["type"] == "websocket.disconnect": + raise WebSocketDisconnect(message["code"], message.get("reason")) + + async def receive_text(self) -> str: + if self.application_state != WebSocketState.CONNECTED: + raise WebSocketDisconnected('WebSocket is not connected. Need to call "accept" first.') + message = await self.receive() + self._raise_on_disconnect(message) + return cast(str, message["text"]) + + async def receive_bytes(self) -> bytes: + if self.application_state != WebSocketState.CONNECTED: + raise WebSocketDisconnected('WebSocket is not connected. Need to call "accept" first.') + message = await self.receive() + self._raise_on_disconnect(message) + return cast(bytes, message["bytes"]) + + async def receive_json(self, mode: str = "text") -> Any: + if mode not in {"text", "binary"}: + raise RuntimeError('The "mode" argument should be "text" or "binary".') + if self.application_state != WebSocketState.CONNECTED: + raise WebSocketDisconnected('WebSocket is not connected. Need to call "accept" first.') + message = await self.receive() + self._raise_on_disconnect(message) + + if mode == "text": + text = message["text"] + else: + text = message["bytes"].decode("utf-8") + return json.loads(text) + + async def iter_text(self) -> AsyncIterator[str]: + try: + while True: + yield await self.receive_text() + except WebSocketDisconnect: + pass + + async def iter_bytes(self) -> AsyncIterator[bytes]: + try: + while True: + yield await self.receive_bytes() + except WebSocketDisconnect: + pass + + async def iter_json(self) -> AsyncIterator[Any]: + try: + while True: + yield await self.receive_json() + except WebSocketDisconnect: + pass + + async def send_text(self, data: str) -> None: + await self.send({"type": "websocket.send", "text": data}) + + async def send_bytes(self, data: bytes) -> None: + await self.send({"type": "websocket.send", "bytes": data}) + + async def send_json(self, data: Any, mode: str = "text") -> None: + if mode not in {"text", "binary"}: + raise RuntimeError('The "mode" argument should be "text" or "binary".') + text = json.dumps(data, separators=(",", ":"), ensure_ascii=False) + if mode == "text": + await self.send({"type": "websocket.send", "text": text}) + else: + await self.send({"type": "websocket.send", "bytes": text.encode("utf-8")}) + + async def close(self, code: int = 1000, reason: str | None = None) -> None: + await self.send({"type": "websocket.close", "code": code, "reason": reason or ""}) + + async def send_denial_response(self, response: Response) -> None: + if "websocket.http.response" in self.scope.get("extensions", {}): + await response(self.scope, self.receive, self.send) + else: + raise RuntimeError("The server doesn't support the Websocket Denial Response extension.") + + +class WebSocketClose: + def __init__(self, code: int = 1000, reason: str | None = None) -> None: + self.code = code + self.reason = reason or "" + + async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: + await send({"type": "websocket.close", "code": self.code, "reason": self.reason}) diff --git a/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/METADATA b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/METADATA new file mode 100644 index 0000000..97fd818 --- /dev/null +++ b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/METADATA @@ -0,0 +1,73 @@ +Metadata-Version: 2.4 +Name: typing_extensions +Version: 4.16.0 +Summary: Backported and Experimental Type Hints for Python 3.9+ +Keywords: annotations,backport,checker,checking,function,hinting,hints,type,typechecking,typehinting,typehints,typing +Author-email: "Guido van Rossum, Jukka Lehtosalo, Łukasz Langa, Michael Lee" +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-Expression: PSF-2.0 +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Topic :: Software Development +License-File: LICENSE +Project-URL: Bug Tracker, https://github.com/python/typing_extensions/issues +Project-URL: Changes, https://github.com/python/typing_extensions/blob/main/CHANGELOG.md +Project-URL: Documentation, https://typing-extensions.readthedocs.io/ +Project-URL: Home, https://github.com/python/typing_extensions +Project-URL: Q & A, https://github.com/python/typing/discussions +Project-URL: Repository, https://github.com/python/typing_extensions + +# Typing Extensions + +[![Chat at https://gitter.im/python/typing](https://badges.gitter.im/python/typing.svg)](https://gitter.im/python/typing) + +[Documentation](https://typing-extensions.readthedocs.io/en/latest/#) – +[PyPI](https://pypi.org/project/typing-extensions/) + +## Overview + +The `typing_extensions` module serves two related purposes: + +- Enable use of new type system features on older Python versions. For example, + `typing.TypeGuard` is new in Python 3.10, but `typing_extensions` allows + users on previous Python versions to use it too. +- Enable experimentation with new type system PEPs before they are accepted and + added to the `typing` module. + +`typing_extensions` is treated specially by static type checkers such as +mypy and pyright. Objects defined in `typing_extensions` are treated the same +way as equivalent forms in `typing`. + +`typing_extensions` uses +[Semantic Versioning](https://semver.org/). The +major version will be incremented only for backwards-incompatible changes. +Therefore, it's safe to depend +on `typing_extensions` like this: `typing_extensions ~=x.y`, +where `x.y` is the first version that includes all features you need. +[This](https://packaging.python.org/en/latest/specifications/version-specifiers/#compatible-release) +is equivalent to `typing_extensions >=x.y, <(x+1)`. Do not depend on `~= x.y.z` +unless you really know what you're doing; that defeats the purpose of +semantic versioning. + +## Included items + +See [the documentation](https://typing-extensions.readthedocs.io/en/latest/#) for a +complete listing of module contents. + +## Contributing + +See [CONTRIBUTING.md](https://github.com/python/typing_extensions/blob/main/CONTRIBUTING.md) +for how to contribute to `typing_extensions`. + diff --git a/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/RECORD b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/RECORD new file mode 100644 index 0000000..b6d2d5e --- /dev/null +++ b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/RECORD @@ -0,0 +1,5 @@ +typing_extensions.py,sha256=QEDKGh7L7gDROFwSqTCE0cW9RvC3dPB-WufpHE9V5pY,165012 +typing_extensions-4.16.0.dist-info/licenses/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 +typing_extensions-4.16.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +typing_extensions-4.16.0.dist-info/METADATA,sha256=sFCEyh1Qh5hlF42f_5-r6rYb37HzYb-96VQh_8j5vkY,3310 +typing_extensions-4.16.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/WHEEL b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/licenses/LICENSE b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..f26bcf4 --- /dev/null +++ b/source/target-vendors/cp312/typing_extensions-4.16.0.dist-info/licenses/LICENSE @@ -0,0 +1,279 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see https://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see https://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see https://opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +Python software and documentation are licensed under the +Python Software Foundation License Version 2. + +Starting with Python 3.8.6, examples, recipes, and other code in +the documentation are dual licensed under the PSF License Version 2 +and the Zero-Clause BSD license. + +Some software incorporated into Python is under different licenses. +The licenses are listed with code falling under that license. + + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION +---------------------------------------------------------------------- + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/source/target-vendors/cp312/typing_extensions.py b/source/target-vendors/cp312/typing_extensions.py new file mode 100644 index 0000000..ced7837 --- /dev/null +++ b/source/target-vendors/cp312/typing_extensions.py @@ -0,0 +1,4422 @@ +import abc +import builtins +import collections +import collections.abc +import contextlib +import enum +import functools +import inspect +import io +import keyword +import operator +import sys +import types as _types +import typing +import warnings + +# Breakpoint: https://github.com/python/cpython/pull/119891 +if sys.version_info >= (3, 14): + import annotationlib + +__all__ = [ + # Super-special typing primitives. + 'Any', + 'ClassVar', + 'Concatenate', + 'Final', + 'LiteralString', + 'ParamSpec', + 'ParamSpecArgs', + 'ParamSpecKwargs', + 'Self', + 'Type', + 'TypeVar', + 'TypeVarTuple', + 'Unpack', + + # ABCs (from collections.abc). + 'Awaitable', + 'AsyncIterator', + 'AsyncIterable', + 'Coroutine', + 'AsyncGenerator', + 'AsyncContextManager', + 'Buffer', + 'ChainMap', + + # Concrete collection types. + 'ContextManager', + 'Counter', + 'Deque', + 'DefaultDict', + 'NamedTuple', + 'OrderedDict', + 'TypedDict', + + # Structural checks, a.k.a. protocols. + 'SupportsAbs', + 'SupportsBytes', + 'SupportsComplex', + 'SupportsFloat', + 'SupportsIndex', + 'SupportsInt', + 'SupportsRound', + 'Reader', + 'Writer', + + # One-off things. + 'Annotated', + 'assert_never', + 'assert_type', + 'clear_overloads', + 'dataclass_transform', + 'deprecated', + 'disjoint_base', + 'Doc', + 'evaluate_forward_ref', + 'get_overloads', + 'final', + 'Format', + 'get_annotations', + 'get_args', + 'get_origin', + 'get_original_bases', + 'get_protocol_members', + 'get_type_hints', + 'IntVar', + 'is_protocol', + 'is_typeddict', + 'Literal', + 'NewType', + 'overload', + 'override', + 'Protocol', + 'sentinel', + 'Sentinel', + 'reveal_type', + 'runtime', + 'runtime_checkable', + 'Text', + 'TypeAlias', + 'TypeAliasType', + 'TypeForm', + 'TypeGuard', + 'TypeIs', + 'TYPE_CHECKING', + 'type_repr', + 'Never', + 'NoReturn', + 'ReadOnly', + 'Required', + 'NotRequired', + 'NoDefault', + 'NoExtraItems', + + # Pure aliases, have always been in typing + 'AbstractSet', + 'AnyStr', + 'BinaryIO', + 'Callable', + 'Collection', + 'Container', + 'Dict', + 'ForwardRef', + 'FrozenSet', + 'Generator', + 'Generic', + 'Hashable', + 'IO', + 'ItemsView', + 'Iterable', + 'Iterator', + 'KeysView', + 'List', + 'Mapping', + 'MappingView', + 'Match', + 'MutableMapping', + 'MutableSequence', + 'MutableSet', + 'Optional', + 'Pattern', + 'Reversible', + 'Sequence', + 'Set', + 'Sized', + 'TextIO', + 'Tuple', + 'Union', + 'ValuesView', + 'cast', + 'no_type_check', +] + +# for backward compatibility +PEP_560 = True +GenericMeta = type +# Breakpoint: https://github.com/python/cpython/pull/116129 +_PEP_696_IMPLEMENTED = sys.version_info >= (3, 13, 0, "beta") + +# Added with bpo-45166 to 3.10.1+ and some 3.9 versions +_FORWARD_REF_HAS_CLASS = "__forward_is_class__" in typing.ForwardRef.__slots__ + + +def _caller(depth=1, default='__main__'): + try: + return sys._getframemodulename(depth + 1) or default + except AttributeError: # For platforms without _getframemodulename() + pass + try: + return sys._getframe(depth + 1).f_globals.get('__name__', default) + except (AttributeError, ValueError): # For platforms without _getframe() + pass + return None + + +# Placeholder for sentinel methods, because sentinels can not have their own sentinels +_sentinel_placeholder = object() + +if hasattr(builtins, "sentinel"): # 3.15+ + sentinel = builtins.sentinel +else: + class sentinel: + """Create a unique sentinel object. + + *name* should be the name of the variable to which the return value + shall be assigned. + """ + + def __init__( + self, + __name: str = _sentinel_placeholder, + __repr: typing.Optional[str] = _sentinel_placeholder, + /, + *, + repr: typing.Optional[str] = None, + name: str = _sentinel_placeholder, + ) -> None: + if name is not _sentinel_placeholder: + warnings.warn( + "Passing 'name' as a keyword argument is deprecated; " + "pass it positionally instead.", + DeprecationWarning, + stacklevel=2, + ) + __name = name + if __name is _sentinel_placeholder: + raise TypeError("First parameter 'name' is required") + if __repr is not _sentinel_placeholder: + warnings.warn( + "Passing 'repr' as a positional argument is deprecated; " + "pass it by keyword instead.", + DeprecationWarning, + stacklevel=2, + ) + repr = __repr + + self._name = __name + self._repr = repr if repr is not None else __name + + # For pickling as a singleton: + self.__module__ = _caller() + + def __init_subclass__(cls): + warnings.warn( + "Subclassing sentinel is deprecated " + "and will be disallowed in Python 3.15", + DeprecationWarning, + stacklevel=2, + ) + super().__init_subclass__() + + def __setattr__(self, attr: str, value: object) -> None: + if attr not in {"_name", "_repr", "__module__"}: + warnings.warn( + f"Setting attribute {attr!r} on sentinel objects is deprecated " + "and will be disallowed in Python 3.15.", + DeprecationWarning, + stacklevel=2, + ) + super().__setattr__(attr, value) + + @property + def __name__(self) -> str: + return self._name + + @__name__.setter + def __name__(self, value: str) -> None: + self._name = value + + def __repr__(self) -> str: + return self._repr + + if sys.version_info < (3, 11): + # The presence of this method convinces typing._type_check + # that Sentinels are types. + def __call__(self, *args, **kwargs): + raise TypeError(f"{type(self).__name__!r} object is not callable") + + # Breakpoint: https://github.com/python/cpython/pull/21515 + if sys.version_info >= (3, 10): + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __reduce__(self) -> str: + """Reduce this sentinel to a singleton.""" + return self.__name__ # Module is taken from the __module__ attribute + +Sentinel = sentinel + +_marker = sentinel("sentinel") + + +# The functions below are modified copies of typing internal helpers. +# They are needed by _ProtocolMeta and they provide support for PEP 646. + +# Breakpoint: https://github.com/python/cpython/pull/27342 +if sys.version_info >= (3, 10): + def _should_collect_from_parameters(t): + return isinstance( + t, (typing._GenericAlias, _types.GenericAlias, _types.UnionType) + ) +else: + def _should_collect_from_parameters(t): + return isinstance(t, (typing._GenericAlias, _types.GenericAlias)) + + +NoReturn = typing.NoReturn + +# Some unconstrained type variables. These are used by the container types. +# (These are not for export.) +T = typing.TypeVar('T') # Any type. +KT = typing.TypeVar('KT') # Key type. +VT = typing.TypeVar('VT') # Value type. +T_co = typing.TypeVar('T_co', covariant=True) # Any type covariant containers. +T_contra = typing.TypeVar('T_contra', contravariant=True) # Ditto contravariant. + + +# Breakpoint: https://github.com/python/cpython/pull/31841 +if sys.version_info >= (3, 11): + from typing import Any +else: + + class _AnyMeta(type): + def __instancecheck__(self, obj): + if self is Any: + raise TypeError("typing_extensions.Any cannot be used with isinstance()") + return super().__instancecheck__(obj) + + def __repr__(self): + if self is Any: + return "typing_extensions.Any" + return super().__repr__() + + class Any(metaclass=_AnyMeta): + """Special type indicating an unconstrained type. + - Any is compatible with every type. + - Any assumed to have all methods. + - All values assumed to be instances of Any. + Note that all the above statements are true from the point of view of + static type checkers. At runtime, Any should not be used with instance + checks. + """ + def __new__(cls, *args, **kwargs): + if cls is Any: + raise TypeError("Any cannot be instantiated") + return super().__new__(cls, *args, **kwargs) + + +ClassVar = typing.ClassVar + +# Vendored from cpython typing._SpecialFrom +# Having a separate class means that instances will not be rejected by +# typing._type_check. +class _SpecialForm(typing._Final, _root=True): + __slots__ = ('_name', '__doc__', '_getitem') + + def __init__(self, getitem): + self._getitem = getitem + self._name = getitem.__name__ + self.__doc__ = getitem.__doc__ + + def __getattr__(self, item): + if item in {'__name__', '__qualname__'}: + return self._name + + raise AttributeError(item) + + def __mro_entries__(self, bases): + raise TypeError(f"Cannot subclass {self!r}") + + def __repr__(self): + return f'typing_extensions.{self._name}' + + def __reduce__(self): + return self._name + + def __call__(self, *args, **kwds): + raise TypeError(f"Cannot instantiate {self!r}") + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + def __instancecheck__(self, obj): + raise TypeError(f"{self} cannot be used with isinstance()") + + def __subclasscheck__(self, cls): + raise TypeError(f"{self} cannot be used with issubclass()") + + @typing._tp_cache + def __getitem__(self, parameters): + return self._getitem(self, parameters) + + +# Note that inheriting from this class means that the object will be +# rejected by typing._type_check, so do not use it if the special form +# is arguably valid as a type by itself. +class _ExtensionsSpecialForm(typing._SpecialForm, _root=True): + def __repr__(self): + return 'typing_extensions.' + self._name + + +Final = typing.Final + +# Breakpoint: https://github.com/python/cpython/pull/30530 +if sys.version_info >= (3, 11): + final = typing.final +else: + # @final exists in 3.8+, but we backport it for all versions + # before 3.11 to keep support for the __final__ attribute. + # See https://bugs.python.org/issue46342 + def final(f): + """This decorator can be used to indicate to type checkers that + the decorated method cannot be overridden, and decorated class + cannot be subclassed. For example: + + class Base: + @final + def done(self) -> None: + ... + class Sub(Base): + def done(self) -> None: # Error reported by type checker + ... + @final + class Leaf: + ... + class Other(Leaf): # Error reported by type checker + ... + + There is no runtime checking of these properties. The decorator + sets the ``__final__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + """ + try: + f.__final__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return f + + +if hasattr(typing, "disjoint_base"): # 3.15 + disjoint_base = typing.disjoint_base +else: + def disjoint_base(cls): + """This decorator marks a class as a disjoint base. + + Child classes of a disjoint base cannot inherit from other disjoint bases that are + not parent classes of the disjoint base. + + For example: + + @disjoint_base + class Disjoint1: pass + + @disjoint_base + class Disjoint2: pass + + class Disjoint3(Disjoint1, Disjoint2): pass # Type checker error + + Type checkers can use knowledge of disjoint bases to detect unreachable code + and determine when two types can overlap. + + See PEP 800.""" + cls.__disjoint_base__ = True + return cls + + +def IntVar(name): + return typing.TypeVar(name) + + +# A Literal bug was fixed in 3.11.0, 3.10.1 and 3.9.8 +# Breakpoint: https://github.com/python/cpython/pull/29334 +if sys.version_info >= (3, 10, 1): + Literal = typing.Literal +else: + def _flatten_literal_params(parameters): + """An internal helper for Literal creation: flatten Literals among parameters""" + params = [] + for p in parameters: + if isinstance(p, _LiteralGenericAlias): + params.extend(p.__args__) + else: + params.append(p) + return tuple(params) + + def _value_and_type_iter(params): + for p in params: + yield p, type(p) + + class _LiteralGenericAlias(typing._GenericAlias, _root=True): + def __eq__(self, other): + if not isinstance(other, _LiteralGenericAlias): + return NotImplemented + these_args_deduped = set(_value_and_type_iter(self.__args__)) + other_args_deduped = set(_value_and_type_iter(other.__args__)) + return these_args_deduped == other_args_deduped + + def __hash__(self): + return hash(frozenset(_value_and_type_iter(self.__args__))) + + class _LiteralForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, doc: str): + self._name = 'Literal' + self._doc = self.__doc__ = doc + + def __getitem__(self, parameters): + if not isinstance(parameters, tuple): + parameters = (parameters,) + + parameters = _flatten_literal_params(parameters) + + val_type_pairs = list(_value_and_type_iter(parameters)) + try: + deduped_pairs = set(val_type_pairs) + except TypeError: + # unhashable parameters + pass + else: + # similar logic to typing._deduplicate on Python 3.9+ + if len(deduped_pairs) < len(val_type_pairs): + new_parameters = [] + for pair in val_type_pairs: + if pair in deduped_pairs: + new_parameters.append(pair[0]) + deduped_pairs.remove(pair) + assert not deduped_pairs, deduped_pairs + parameters = tuple(new_parameters) + + return _LiteralGenericAlias(self, parameters) + + Literal = _LiteralForm(doc="""\ + A type that can be used to indicate to type checkers + that the corresponding value has a value literally equivalent + to the provided parameter. For example: + + var: Literal[4] = 4 + + The type checker understands that 'var' is literally equal to + the value 4 and no other value. + + Literal[...] cannot be subclassed. There is no runtime + checking verifying that the parameter is actually a value + instead of a type.""") + + +_overload_dummy = typing._overload_dummy + + +if hasattr(typing, "get_overloads"): # 3.11+ + overload = typing.overload + get_overloads = typing.get_overloads + clear_overloads = typing.clear_overloads +else: + # {module: {qualname: {firstlineno: func}}} + _overload_registry = collections.defaultdict( + functools.partial(collections.defaultdict, dict) + ) + + def overload(func): + """Decorator for overloaded functions/methods. + + In a stub file, place two or more stub definitions for the same + function in a row, each decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + + In a non-stub file (i.e. a regular .py file), do the same but + follow it with an implementation. The implementation should *not* + be decorated with @overload. For example: + + @overload + def utf8(value: None) -> None: ... + @overload + def utf8(value: bytes) -> bytes: ... + @overload + def utf8(value: str) -> bytes: ... + def utf8(value): + # implementation goes here + + The overloads for a function can be retrieved at runtime using the + get_overloads() function. + """ + # classmethod and staticmethod + f = getattr(func, "__func__", func) + try: + _overload_registry[f.__module__][f.__qualname__][ + f.__code__.co_firstlineno + ] = func + except AttributeError: + # Not a normal function; ignore. + pass + return _overload_dummy + + def get_overloads(func): + """Return all defined overloads for *func* as a sequence.""" + # classmethod and staticmethod + f = getattr(func, "__func__", func) + if f.__module__ not in _overload_registry: + return [] + mod_dict = _overload_registry[f.__module__] + if f.__qualname__ not in mod_dict: + return [] + return list(mod_dict[f.__qualname__].values()) + + def clear_overloads(): + """Clear all overloads in the registry.""" + _overload_registry.clear() + + +# This is not a real generic class. Don't use outside annotations. +Type = typing.Type + +# Various ABCs mimicking those in collections.abc. +# A few are simply re-exported for completeness. +Awaitable = typing.Awaitable +Coroutine = typing.Coroutine +AsyncIterable = typing.AsyncIterable +AsyncIterator = typing.AsyncIterator +Deque = typing.Deque +DefaultDict = typing.DefaultDict +OrderedDict = typing.OrderedDict +Counter = typing.Counter +ChainMap = typing.ChainMap +Text = typing.Text +TYPE_CHECKING = typing.TYPE_CHECKING + + +# Breakpoint: https://github.com/python/cpython/pull/118681 +if sys.version_info >= (3, 13, 0, "beta"): + from typing import AsyncContextManager, AsyncGenerator, ContextManager, Generator +else: + def _is_dunder(attr): + return attr.startswith('__') and attr.endswith('__') + + + class _SpecialGenericAlias(typing._SpecialGenericAlias, _root=True): + def __init__(self, origin, nparams, *, defaults, inst=True, name=None): + assert nparams > 0, "`nparams` must be a positive integer" + assert defaults, "Must always specify a non-empty sequence for `defaults`" + super().__init__(origin, nparams, inst=inst, name=name) + self._defaults = defaults + + def __setattr__(self, attr, val): + allowed_attrs = {'_name', '_inst', '_nparams', '_defaults'} + if _is_dunder(attr) or attr in allowed_attrs: + object.__setattr__(self, attr, val) + else: + setattr(self.__origin__, attr, val) + + @typing._tp_cache + def __getitem__(self, params): + if not isinstance(params, tuple): + params = (params,) + msg = "Parameters to generic types must be types." + params = tuple(typing._type_check(p, msg) for p in params) + if ( + len(params) < self._nparams + and len(params) + len(self._defaults) >= self._nparams + ): + params = (*params, *self._defaults[len(params) - self._nparams:]) + actual_len = len(params) + + if actual_len != self._nparams: + expected = f"at least {self._nparams - len(self._defaults)}" + raise TypeError( + f"Too {'many' if actual_len > self._nparams else 'few'}" + f" arguments for {self};" + f" actual {actual_len}, expected {expected}" + ) + return self.copy_with(params) + + _NoneType = type(None) + Generator = _SpecialGenericAlias( + collections.abc.Generator, 3, defaults=(_NoneType, _NoneType) + ) + AsyncGenerator = _SpecialGenericAlias( + collections.abc.AsyncGenerator, 2, defaults=(_NoneType,) + ) + ContextManager = _SpecialGenericAlias( + contextlib.AbstractContextManager, + 2, + name="ContextManager", + defaults=(typing.Optional[bool],) + ) + AsyncContextManager = _SpecialGenericAlias( + contextlib.AbstractAsyncContextManager, + 2, + name="AsyncContextManager", + defaults=(typing.Optional[bool],) + ) + + +_PROTO_ALLOWLIST = { + 'collections.abc': [ + 'Callable', 'Awaitable', 'Iterable', 'Iterator', 'AsyncIterable', + 'AsyncIterator', 'Hashable', 'Sized', 'Container', 'Collection', + 'Reversible', 'Buffer', + ], + 'contextlib': ['AbstractContextManager', 'AbstractAsyncContextManager'], + 'io': ['Reader', 'Writer'], + 'typing_extensions': ['Buffer'], + 'os': ['PathLike'], +} + + +_EXCLUDED_ATTRS = frozenset(typing.EXCLUDED_ATTRIBUTES) | { + "__match_args__", "__protocol_attrs__", "__non_callable_proto_members__", + "__final__", +} + + +def _get_protocol_attrs(cls): + attrs = set() + for base in cls.__mro__[:-1]: # without object + if base.__name__ in {'Protocol', 'Generic'}: + continue + annotations = getattr(base, '__annotations__', {}) + for attr in (*base.__dict__, *annotations): + if (not attr.startswith('_abc_') and attr not in _EXCLUDED_ATTRS): + attrs.add(attr) + return attrs + + +# `__match_args__` attribute was removed from protocol members in 3.13, +# we want to backport this change to older Python versions. +# 3.14 additionally added `io.Reader`, `io.Writer` and `os.PathLike` to +# the list of allowed protocol allowlist. +# https://github.com/python/cpython/issues/127647 +if sys.version_info >= (3, 14): + Protocol = typing.Protocol +else: + def _allow_reckless_class_checks(depth=2): + """Allow instance and class checks for special stdlib modules. + The abc and functools modules indiscriminately call isinstance() and + issubclass() on the whole MRO of a user class, which may contain protocols. + """ + return _caller(depth) in {'abc', 'functools', None} + + def _no_init(self, *args, **kwargs): + if type(self)._is_protocol: + raise TypeError('Protocols cannot be instantiated') + + def _type_check_issubclass_arg_1(arg): + """Raise TypeError if `arg` is not an instance of `type` + in `issubclass(arg, )`. + + In most cases, this is verified by type.__subclasscheck__. + Checking it again unnecessarily would slow down issubclass() checks, + so, we don't perform this check unless we absolutely have to. + + For various error paths, however, + we want to ensure that *this* error message is shown to the user + where relevant, rather than a typing.py-specific error message. + """ + if not isinstance(arg, type): + # Same error message as for issubclass(1, int). + raise TypeError('issubclass() arg 1 must be a class') + + # Inheriting from typing._ProtocolMeta isn't actually desirable, + # but is necessary to allow typing.Protocol and typing_extensions.Protocol + # to mix without getting TypeErrors about "metaclass conflict" + class _ProtocolMeta(type(typing.Protocol)): + # This metaclass is somewhat unfortunate, + # but is necessary for several reasons... + # + # NOTE: DO NOT call super() in any methods in this class + # That would call the methods on typing._ProtocolMeta on Python <=3.11 + # and those are slow + def __new__(mcls, name, bases, namespace, **kwargs): + if name == "Protocol" and len(bases) < 2: + pass + elif {Protocol, typing.Protocol} & set(bases): + for base in bases: + if not ( + base in {object, typing.Generic, Protocol, typing.Protocol} + or base.__name__ in _PROTO_ALLOWLIST.get(base.__module__, []) + or is_protocol(base) + ): + raise TypeError( + f"Protocols can only inherit from other protocols, " + f"got {base!r}" + ) + return abc.ABCMeta.__new__(mcls, name, bases, namespace, **kwargs) + + def __init__(cls, *args, **kwargs): + abc.ABCMeta.__init__(cls, *args, **kwargs) + if getattr(cls, "_is_protocol", False): + cls.__protocol_attrs__ = _get_protocol_attrs(cls) + + def __subclasscheck__(cls, other): + if cls is Protocol: + return type.__subclasscheck__(cls, other) + if ( + getattr(cls, '_is_protocol', False) + and not _allow_reckless_class_checks() + ): + if not getattr(cls, '_is_runtime_protocol', False): + _type_check_issubclass_arg_1(other) + raise TypeError( + "Instance and class checks can only be used with " + "@runtime_checkable protocols" + ) + if ( + # this attribute is set by @runtime_checkable: + cls.__non_callable_proto_members__ + and cls.__dict__.get("__subclasshook__") is _proto_hook + ): + _type_check_issubclass_arg_1(other) + non_method_attrs = sorted(cls.__non_callable_proto_members__) + raise TypeError( + "Protocols with non-method members don't support issubclass()." + f" Non-method members: {str(non_method_attrs)[1:-1]}." + ) + return abc.ABCMeta.__subclasscheck__(cls, other) + + def __instancecheck__(cls, instance): + # We need this method for situations where attributes are + # assigned in __init__. + if cls is Protocol: + return type.__instancecheck__(cls, instance) + if not getattr(cls, "_is_protocol", False): + # i.e., it's a concrete subclass of a protocol + return abc.ABCMeta.__instancecheck__(cls, instance) + + if ( + not getattr(cls, '_is_runtime_protocol', False) and + not _allow_reckless_class_checks() + ): + raise TypeError("Instance and class checks can only be used with" + " @runtime_checkable protocols") + + if abc.ABCMeta.__instancecheck__(cls, instance): + return True + + for attr in cls.__protocol_attrs__: + try: + val = inspect.getattr_static(instance, attr) + except AttributeError: + break + # this attribute is set by @runtime_checkable: + if val is None and attr not in cls.__non_callable_proto_members__: + break + else: + return True + + return False + + def __eq__(cls, other): + # Hack so that typing.Generic.__class_getitem__ + # treats typing_extensions.Protocol + # as equivalent to typing.Protocol + if abc.ABCMeta.__eq__(cls, other) is True: + return True + return cls is Protocol and other is typing.Protocol + + # This has to be defined, or the abc-module cache + # complains about classes with this metaclass being unhashable, + # if we define only __eq__! + def __hash__(cls) -> int: + return type.__hash__(cls) + + @classmethod + def _proto_hook(cls, other): + if not cls.__dict__.get('_is_protocol', False): + return NotImplemented + + for attr in cls.__protocol_attrs__: + for base in other.__mro__: + # Check if the members appears in the class dictionary... + if attr in base.__dict__: + if base.__dict__[attr] is None: + return NotImplemented + break + + # ...or in annotations, if it is a sub-protocol. + annotations = getattr(base, '__annotations__', {}) + if ( + isinstance(annotations, collections.abc.Mapping) + and attr in annotations + and is_protocol(other) + ): + break + else: + return NotImplemented + return True + + class Protocol(typing.Generic, metaclass=_ProtocolMeta): + __doc__ = typing.Protocol.__doc__ + __slots__ = () + _is_protocol = True + _is_runtime_protocol = False + + def __init_subclass__(cls, *args, **kwargs): + super().__init_subclass__(*args, **kwargs) + + # Determine if this is a protocol or a concrete subclass. + if not cls.__dict__.get('_is_protocol', False): + cls._is_protocol = any(b is Protocol for b in cls.__bases__) + + # Set (or override) the protocol subclass hook. + if '__subclasshook__' not in cls.__dict__: + cls.__subclasshook__ = _proto_hook + + # Prohibit instantiation for protocol classes + if cls._is_protocol and cls.__init__ is Protocol.__init__: + cls.__init__ = _no_init + + +# Breakpoint: https://github.com/python/cpython/pull/113401 +if sys.version_info >= (3, 13): + runtime_checkable = typing.runtime_checkable +else: + def runtime_checkable(cls): + """Mark a protocol class as a runtime protocol. + + Such protocol can be used with isinstance() and issubclass(). + Raise TypeError if applied to a non-protocol class. + This allows a simple-minded structural check very similar to + one trick ponies in collections.abc such as Iterable. + + For example:: + + @runtime_checkable + class Closable(Protocol): + def close(self): ... + + assert isinstance(open('/some/file'), Closable) + + Warning: this will check only the presence of the required methods, + not their type signatures! + """ + if not issubclass(cls, typing.Generic) or not getattr(cls, '_is_protocol', False): + raise TypeError(f'@runtime_checkable can be only applied to protocol classes,' + f' got {cls!r}') + cls._is_runtime_protocol = True + + # typing.Protocol classes on <=3.11 break if we execute this block, + # because typing.Protocol classes on <=3.11 don't have a + # `__protocol_attrs__` attribute, and this block relies on the + # `__protocol_attrs__` attribute. Meanwhile, typing.Protocol classes on 3.12.2+ + # break if we *don't* execute this block, because *they* assume that all + # protocol classes have a `__non_callable_proto_members__` attribute + # (which this block sets) + if isinstance(cls, _ProtocolMeta) or sys.version_info >= (3, 12, 2): + # PEP 544 prohibits using issubclass() + # with protocols that have non-method members. + # See gh-113320 for why we compute this attribute here, + # rather than in `_ProtocolMeta.__init__` + cls.__non_callable_proto_members__ = set() + for attr in cls.__protocol_attrs__: + try: + is_callable = callable(getattr(cls, attr, None)) + except Exception as e: + raise TypeError( + f"Failed to determine whether protocol member {attr!r} " + "is a method member" + ) from e + else: + if not is_callable: + cls.__non_callable_proto_members__.add(attr) + + return cls + + +# The "runtime" alias exists for backwards compatibility. +runtime = runtime_checkable + + +# Our version of runtime-checkable protocols is faster on Python <=3.11 +# Breakpoint: https://github.com/python/cpython/pull/112717 +if sys.version_info >= (3, 12): + SupportsInt = typing.SupportsInt + SupportsFloat = typing.SupportsFloat + SupportsComplex = typing.SupportsComplex + SupportsBytes = typing.SupportsBytes + SupportsIndex = typing.SupportsIndex + SupportsAbs = typing.SupportsAbs + SupportsRound = typing.SupportsRound +else: + @runtime_checkable + class SupportsInt(Protocol): + """An ABC with one abstract method __int__.""" + __slots__ = () + + @abc.abstractmethod + def __int__(self) -> int: + pass + + @runtime_checkable + class SupportsFloat(Protocol): + """An ABC with one abstract method __float__.""" + __slots__ = () + + @abc.abstractmethod + def __float__(self) -> float: + pass + + @runtime_checkable + class SupportsComplex(Protocol): + """An ABC with one abstract method __complex__.""" + __slots__ = () + + @abc.abstractmethod + def __complex__(self) -> complex: + pass + + @runtime_checkable + class SupportsBytes(Protocol): + """An ABC with one abstract method __bytes__.""" + __slots__ = () + + @abc.abstractmethod + def __bytes__(self) -> bytes: + pass + + @runtime_checkable + class SupportsIndex(Protocol): + __slots__ = () + + @abc.abstractmethod + def __index__(self) -> int: + pass + + @runtime_checkable + class SupportsAbs(Protocol[T_co]): + """ + An ABC with one abstract method __abs__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __abs__(self) -> T_co: + pass + + @runtime_checkable + class SupportsRound(Protocol[T_co]): + """ + An ABC with one abstract method __round__ that is covariant in its return type. + """ + __slots__ = () + + @abc.abstractmethod + def __round__(self, ndigits: int = 0) -> T_co: + pass + + +if hasattr(io, "Reader") and hasattr(io, "Writer"): + Reader = io.Reader + Writer = io.Writer +else: + @runtime_checkable + class Reader(Protocol[T_co]): + """Protocol for simple I/O reader instances. + + This protocol only supports blocking I/O. + """ + + __slots__ = () + + @abc.abstractmethod + def read(self, size: int = ..., /) -> T_co: + """Read data from the input stream and return it. + + If *size* is specified, at most *size* items (bytes/characters) will be + read. + """ + + @runtime_checkable + class Writer(Protocol[T_contra]): + """Protocol for simple I/O writer instances. + + This protocol only supports blocking I/O. + """ + + __slots__ = () + + @abc.abstractmethod + def write(self, data: T_contra, /) -> int: + """Write *data* to the output stream and return the number of items written.""" # noqa: E501 + + +_NEEDS_SINGLETONMETA = ( + not hasattr(typing, "NoDefault") or not hasattr(typing, "NoExtraItems") +) + +if _NEEDS_SINGLETONMETA: + class SingletonMeta(type): + def __setattr__(cls, attr, value): + # TypeError is consistent with the behavior of NoneType + raise TypeError( + f"cannot set {attr!r} attribute of immutable type {cls.__name__!r}" + ) + + +if hasattr(typing, "NoDefault"): + NoDefault = typing.NoDefault +else: + class NoDefaultType(metaclass=SingletonMeta): + """The type of the NoDefault singleton.""" + + __slots__ = () + + def __new__(cls): + return globals().get("NoDefault") or object.__new__(cls) + + def __repr__(self): + return "typing_extensions.NoDefault" + + def __reduce__(self): + return "NoDefault" + + NoDefault = NoDefaultType() + del NoDefaultType + +if hasattr(typing, "NoExtraItems"): + NoExtraItems = typing.NoExtraItems +else: + class NoExtraItemsType(metaclass=SingletonMeta): + """The type of the NoExtraItems singleton.""" + + __slots__ = () + + def __new__(cls): + return globals().get("NoExtraItems") or object.__new__(cls) + + def __repr__(self): + return "typing_extensions.NoExtraItems" + + def __reduce__(self): + return "NoExtraItems" + + NoExtraItems = NoExtraItemsType() + del NoExtraItemsType + +if _NEEDS_SINGLETONMETA: + del SingletonMeta + + +# Update this to something like >=3.13.0b1 if and when +# PEP 764 is implemented in CPython +_PEP_764_IMPLEMENTED = False + +if _PEP_764_IMPLEMENTED: + # The standard library TypedDict in Python 3.9.0/1 does not honour the "total" + # keyword with old-style TypedDict(). See https://bugs.python.org/issue42059 + # The standard library TypedDict below Python 3.11 does not store runtime + # information about optional and required keys when using Required or NotRequired. + # Generic TypedDicts are also impossible using typing.TypedDict on Python <3.11. + # Aaaand on 3.12 we add __orig_bases__ to TypedDict + # to enable better runtime introspection. + # On 3.13 we deprecate some odd ways of creating TypedDicts. + # Also on 3.13, PEP 705 adds the ReadOnly[] qualifier. + # PEP 728 (Python 3.15+) adds the `extra_items` and `closed` keywords. + # PEP 764 (still pending) allows the `TypedDict` special form to be subscripted. + TypedDict = typing.TypedDict + _TypedDictMeta = typing._TypedDictMeta + is_typeddict = typing.is_typeddict +else: + # 3.10.0 and later + _TAKES_MODULE = "module" in inspect.signature(typing._type_check).parameters + + def _get_typeddict_qualifiers(annotation_type): + while True: + annotation_origin = get_origin(annotation_type) + if annotation_origin is Annotated: + annotation_args = get_args(annotation_type) + if annotation_args: + annotation_type = annotation_args[0] + else: + break + elif annotation_origin is Required: + yield Required + annotation_type, = get_args(annotation_type) + elif annotation_origin is NotRequired: + yield NotRequired + annotation_type, = get_args(annotation_type) + elif annotation_origin is ReadOnly: + yield ReadOnly + annotation_type, = get_args(annotation_type) + else: + break + + class _TypedDictMeta(type): + + def __new__(cls, name, bases, ns, *, total=True, closed=None, + extra_items=NoExtraItems): + """Create new typed dict class object. + + This method is called when TypedDict is subclassed, + or when TypedDict is instantiated. This way + TypedDict supports all three syntax forms described in its docstring. + Subclasses and instances of TypedDict return actual dictionaries. + """ + for base in bases: + if type(base) is not _TypedDictMeta and base is not typing.Generic: + raise TypeError('cannot inherit from both a TypedDict type ' + 'and a non-TypedDict base class') + if closed is not None and extra_items is not NoExtraItems: + raise TypeError(f"Cannot combine closed={closed!r} and extra_items") + + if any(issubclass(b, typing.Generic) for b in bases): + generic_base = (typing.Generic,) + else: + generic_base = () + + ns_annotations = ns.pop('__annotations__', None) + + # typing.py generally doesn't let you inherit from plain Generic, unless + # the name of the class happens to be "Protocol" + tp_dict = type.__new__(_TypedDictMeta, "Protocol", (*generic_base, dict), ns) + tp_dict.__name__ = name + if tp_dict.__qualname__ == "Protocol": + tp_dict.__qualname__ = name + + if not hasattr(tp_dict, '__orig_bases__'): + tp_dict.__orig_bases__ = bases + + annotations = {} + own_annotate = None + if ns_annotations is not None: + own_annotations = ns_annotations + elif sys.version_info >= (3, 14): + if hasattr(annotationlib, "get_annotate_from_class_namespace"): + own_annotate = annotationlib.get_annotate_from_class_namespace(ns) + else: + # 3.14.0a7 and earlier + own_annotate = ns.get("__annotate__") + if own_annotate is not None: + own_annotations = annotationlib.call_annotate_function( + own_annotate, Format.FORWARDREF, owner=tp_dict + ) + else: + own_annotations = {} + else: + own_annotations = {} + msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type" + if _TAKES_MODULE: + own_checked_annotations = { + n: typing._type_check(tp, msg, module=tp_dict.__module__) + for n, tp in own_annotations.items() + } + else: + own_checked_annotations = { + n: typing._type_check(tp, msg) + for n, tp in own_annotations.items() + } + required_keys = set() + optional_keys = set() + readonly_keys = set() + mutable_keys = set() + extra_items_type = extra_items + + for base in bases: + base_dict = base.__dict__ + + if sys.version_info <= (3, 14): + annotations.update(base_dict.get('__annotations__', {})) + base_required = base_dict.get('__required_keys__', set()) + required_keys |= base_required + optional_keys -= base_required + + base_optional = base_dict.get('__optional_keys__', set()) + required_keys -= base_optional + optional_keys |= base_optional + + readonly_keys.update(base_dict.get('__readonly_keys__', ())) + mutable_keys.update(base_dict.get('__mutable_keys__', ())) + + # This was specified in an earlier version of PEP 728. Support + # is retained for backwards compatibility, but only for Python + # 3.13 and lower. + if (closed and sys.version_info < (3, 14) + and "__extra_items__" in own_checked_annotations): + annotation_type = own_checked_annotations.pop("__extra_items__") + qualifiers = set(_get_typeddict_qualifiers(annotation_type)) + if Required in qualifiers: + raise TypeError( + "Special key __extra_items__ does not support " + "Required" + ) + if NotRequired in qualifiers: + raise TypeError( + "Special key __extra_items__ does not support " + "NotRequired" + ) + extra_items_type = annotation_type + + annotations.update(own_checked_annotations) + for annotation_key, annotation_type in own_checked_annotations.items(): + qualifiers = set(_get_typeddict_qualifiers(annotation_type)) + + if Required in qualifiers: + is_required = True + elif NotRequired in qualifiers: + is_required = False + else: + is_required = total + + if is_required: + required_keys.add(annotation_key) + optional_keys.discard(annotation_key) + else: + optional_keys.add(annotation_key) + required_keys.discard(annotation_key) + + if ReadOnly in qualifiers: + mutable_keys.discard(annotation_key) + readonly_keys.add(annotation_key) + else: + mutable_keys.add(annotation_key) + readonly_keys.discard(annotation_key) + + # Breakpoint: https://github.com/python/cpython/pull/119891 + if sys.version_info >= (3, 14): + def __annotate__(format): + annos = {} + for base in bases: + if base is Generic: + continue + base_annotate = base.__annotate__ + if base_annotate is None: + continue + base_annos = annotationlib.call_annotate_function( + base_annotate, format, owner=base) + annos.update(base_annos) + if own_annotate is not None: + own = annotationlib.call_annotate_function( + own_annotate, format, owner=tp_dict) + if format != Format.STRING: + own = { + n: typing._type_check(tp, msg, module=tp_dict.__module__) + for n, tp in own.items() + } + elif format == Format.STRING: + own = annotationlib.annotations_to_string(own_annotations) + elif format in (Format.FORWARDREF, Format.VALUE): + own = own_checked_annotations + else: + raise NotImplementedError(format) + annos.update(own) + return annos + + tp_dict.__annotate__ = __annotate__ + else: + tp_dict.__annotations__ = annotations + tp_dict.__required_keys__ = frozenset(required_keys) + tp_dict.__optional_keys__ = frozenset(optional_keys) + tp_dict.__readonly_keys__ = frozenset(readonly_keys) + tp_dict.__mutable_keys__ = frozenset(mutable_keys) + tp_dict.__total__ = total + tp_dict.__closed__ = closed + tp_dict.__extra_items__ = extra_items_type + return tp_dict + + __call__ = dict # static method + + def __subclasscheck__(cls, other): + # Typed dicts are only for static structural subtyping. + raise TypeError('TypedDict does not support instance and class checks') + + __instancecheck__ = __subclasscheck__ + + _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {}) + + def _create_typeddict( + typename, + fields, + /, + *, + typing_is_inline, + total, + closed, + extra_items, + **kwargs, + ): + if fields is _marker or fields is None: + if fields is _marker: + deprecated_thing = ( + "Failing to pass a value for the 'fields' parameter" + ) + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + + example = f"`{typename} = TypedDict({typename!r}, {{}})`" + deprecation_msg = ( + f"{deprecated_thing} is deprecated and will be disallowed in " + "Python 3.15. To create a TypedDict class with 0 fields " + "using the functional syntax, pass an empty dictionary, e.g. " + ) + example + "." + warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) + # Support a field called "closed" + if closed is not False and closed is not True and closed is not None: + kwargs["closed"] = closed + closed = None + # Or "extra_items" + if extra_items is not NoExtraItems: + kwargs["extra_items"] = extra_items + extra_items = NoExtraItems + fields = kwargs + elif kwargs: + raise TypeError("TypedDict takes either a dict or keyword arguments," + " but not both") + if kwargs: + # Breakpoint: https://github.com/python/cpython/pull/104891 + if sys.version_info >= (3, 13): + raise TypeError("TypedDict takes no keyword arguments") + warnings.warn( + "The kwargs-based syntax for TypedDict definitions is deprecated " + "in Python 3.11, will be removed in Python 3.13, and may not be " + "understood by third-party type checkers.", + DeprecationWarning, + stacklevel=2, + ) + + ns = {'__annotations__': dict(fields)} + module = _caller(depth=4 if typing_is_inline else 2) + if module is not None: + # Setting correct module is necessary to make typed dict classes + # pickleable. + ns['__module__'] = module + + td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, + extra_items=extra_items) + td.__orig_bases__ = (TypedDict,) + return td + + class _TypedDictSpecialForm(_SpecialForm, _root=True): + def __call__( + self, + typename, + fields=_marker, + /, + *, + total=True, + closed=None, + extra_items=NoExtraItems, + **kwargs + ): + return _create_typeddict( + typename, + fields, + typing_is_inline=False, + total=total, + closed=closed, + extra_items=extra_items, + **kwargs, + ) + + def __mro_entries__(self, bases): + return (_TypedDict,) + + @_TypedDictSpecialForm + def TypedDict(self, args): + """A simple typed namespace. At runtime it is equivalent to a plain dict. + + TypedDict creates a dictionary type such that a type checker will expect all + instances to have a certain set of keys, where each key is + associated with a value of a consistent type. This expectation + is not checked at runtime. + + Usage:: + + class Point2D(TypedDict): + x: int + y: int + label: str + + a: Point2D = {'x': 1, 'y': 2, 'label': 'good'} # OK + b: Point2D = {'z': 3, 'label': 'bad'} # Fails type check + + assert Point2D(x=1, y=2, label='first') == dict(x=1, y=2, label='first') + + The type info can be accessed via the Point2D.__annotations__ dict, and + the Point2D.__required_keys__ and Point2D.__optional_keys__ frozensets. + TypedDict supports an additional equivalent form:: + + Point2D = TypedDict('Point2D', {'x': int, 'y': int, 'label': str}) + + By default, all keys must be present in a TypedDict. It is possible + to override this by specifying totality:: + + class Point2D(TypedDict, total=False): + x: int + y: int + + This means that a Point2D TypedDict can have any of the keys omitted. A type + checker is only expected to support a literal False or True as the value of + the total argument. True is the default, and makes all items defined in the + class body be required. + + The Required and NotRequired special forms can also be used to mark + individual keys as being required or not required:: + + class Point2D(TypedDict): + x: int # the "x" key must always be present (Required is the default) + y: NotRequired[int] # the "y" key can be omitted + + See PEP 655 for more details on Required and NotRequired. + """ + # This runs when creating inline TypedDicts: + if not isinstance(args, dict): + raise TypeError( + "TypedDict[...] should be used with a single dict argument" + ) + + return _create_typeddict( + "", + args, + typing_is_inline=True, + total=True, + closed=True, + extra_items=NoExtraItems, + ) + + _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta) + + def is_typeddict(tp): + """Check if an annotation is a TypedDict class + + For example:: + class Film(TypedDict): + title: str + year: int + + is_typeddict(Film) # => True + is_typeddict(Union[list, str]) # => False + """ + return isinstance(tp, _TYPEDDICT_TYPES) + + +if hasattr(typing, "assert_type"): + assert_type = typing.assert_type + +else: + def assert_type(val, typ, /): + """Assert (to the type checker) that the value is of the given type. + + When the type checker encounters a call to assert_type(), it + emits an error if the value is not of the specified type:: + + def greet(name: str) -> None: + assert_type(name, str) # ok + assert_type(name, int) # type checker error + + At runtime this returns the first argument unchanged and otherwise + does nothing. + """ + return val + + +if hasattr(typing, "ReadOnly"): # 3.13+ + get_type_hints = typing.get_type_hints +else: # <=3.13 + # replaces _strip_annotations() + def _strip_extras(t): + """Strips Annotated, Required and NotRequired from a given type.""" + if isinstance(t, typing._AnnotatedAlias): + return _strip_extras(t.__origin__) + if hasattr(t, "__origin__") and t.__origin__ in (Required, NotRequired, ReadOnly): + return _strip_extras(t.__args__[0]) + if isinstance(t, typing._GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return t.copy_with(stripped_args) + if hasattr(_types, "GenericAlias") and isinstance(t, _types.GenericAlias): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return _types.GenericAlias(t.__origin__, stripped_args) + if hasattr(_types, "UnionType") and isinstance(t, _types.UnionType): + stripped_args = tuple(_strip_extras(a) for a in t.__args__) + if stripped_args == t.__args__: + return t + return functools.reduce(operator.or_, stripped_args) + + return t + + def get_type_hints(obj, globalns=None, localns=None, include_extras=False): + """Return type hints for an object. + + This is often the same as obj.__annotations__, but it handles + forward references encoded as string literals, adds Optional[t] if a + default value equal to None is set and recursively replaces all + 'Annotated[T, ...]', 'Required[T]' or 'NotRequired[T]' with 'T' + (unless 'include_extras=True'). + + The argument may be a module, class, method, or function. The annotations + are returned as a dictionary. For classes, annotations include also + inherited members. + + TypeError is raised if the argument is not of a type that can contain + annotations, and an empty dictionary is returned if no annotations are + present. + + BEWARE -- the behavior of globalns and localns is counterintuitive + (unless you are familiar with how eval() and exec() work). The + search order is locals first, then globals. + + - If no dict arguments are passed, an attempt is made to use the + globals from obj (or the respective module's globals for classes), + and these are also used as the locals. If the object does not appear + to have globals, an empty dictionary is used. + + - If one dict argument is passed, it is used for both globals and + locals. + + - If two dict arguments are passed, they specify globals and + locals, respectively. + """ + hint = typing.get_type_hints( + obj, globalns=globalns, localns=localns, include_extras=True + ) + # Breakpoint: https://github.com/python/cpython/pull/30304 + if sys.version_info < (3, 11): + _clean_optional(obj, hint, globalns, localns) + if include_extras: + return hint + return {k: _strip_extras(t) for k, t in hint.items()} + + _NoneType = type(None) + + def _could_be_inserted_optional(t): + """detects Union[..., None] pattern""" + if not isinstance(t, typing._UnionGenericAlias): + return False + # Assume if last argument is not None they are user defined + if t.__args__[-1] is not _NoneType: + return False + return True + + # < 3.11 + def _clean_optional(obj, hints, globalns=None, localns=None): + # reverts injected Union[..., None] cases from typing.get_type_hints + # when a None default value is used. + # see https://github.com/python/typing_extensions/issues/310 + if not hints or isinstance(obj, type): + return + defaults = typing._get_defaults(obj) # avoid accessing __annotations___ + if not defaults: + return + original_hints = obj.__annotations__ + for name, value in hints.items(): + # Not a Union[..., None] or replacement conditions not fullfilled + if (not _could_be_inserted_optional(value) + or name not in defaults + or defaults[name] is not None + ): + continue + original_value = original_hints[name] + # value=NoneType should have caused a skip above but check for safety + if original_value is None: + original_value = _NoneType + # Forward reference + if isinstance(original_value, str): + if globalns is None: + if isinstance(obj, _types.ModuleType): + globalns = obj.__dict__ + else: + nsobj = obj + # Find globalns for the unwrapped object. + while hasattr(nsobj, '__wrapped__'): + nsobj = nsobj.__wrapped__ + globalns = getattr(nsobj, '__globals__', {}) + if localns is None: + localns = globalns + elif localns is None: + localns = globalns + + original_value = ForwardRef( + original_value, + is_argument=not isinstance(obj, _types.ModuleType) + ) + original_evaluated = typing._eval_type(original_value, globalns, localns) + # Compare if values differ. Note that even if equal + # value might be cached by typing._tp_cache contrary to original_evaluated + if original_evaluated != value or ( + # 3.10: ForwardRefs of UnionType might be turned into _UnionGenericAlias + hasattr(_types, "UnionType") + and isinstance(original_evaluated, _types.UnionType) + and not isinstance(value, _types.UnionType) + ): + hints[name] = original_evaluated + +# Python 3.9 has get_origin() and get_args() but those implementations don't support +# ParamSpecArgs and ParamSpecKwargs, so only Python 3.10's versions will do. +# Breakpoint: https://github.com/python/cpython/pull/25298 +if sys.version_info >= (3, 10): + get_origin = typing.get_origin + get_args = typing.get_args +# 3.9 +else: + def get_origin(tp): + """Get the unsubscripted version of a type. + + This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar + and Annotated. Return None for unsupported types. Examples:: + + get_origin(Literal[42]) is Literal + get_origin(int) is None + get_origin(ClassVar[int]) is ClassVar + get_origin(Generic) is Generic + get_origin(Generic[T]) is Generic + get_origin(Union[T, int]) is Union + get_origin(List[Tuple[T, T]][int]) == list + get_origin(P.args) is P + """ + if isinstance(tp, typing._AnnotatedAlias): + return Annotated + if isinstance(tp, (typing._BaseGenericAlias, _types.GenericAlias, + ParamSpecArgs, ParamSpecKwargs)): + return tp.__origin__ + if tp is typing.Generic: + return typing.Generic + return None + + def get_args(tp): + """Get type arguments with all substitutions performed. + + For unions, basic simplifications used by Union constructor are performed. + Examples:: + get_args(Dict[str, int]) == (str, int) + get_args(int) == () + get_args(Union[int, Union[T, int], str][int]) == (int, str) + get_args(Union[int, Tuple[T, int]][str]) == (int, Tuple[str, int]) + get_args(Callable[[], T][int]) == ([], int) + """ + if isinstance(tp, typing._AnnotatedAlias): + return (tp.__origin__, *tp.__metadata__) + if isinstance(tp, (typing._GenericAlias, _types.GenericAlias)): + res = tp.__args__ + if get_origin(tp) is collections.abc.Callable and res[0] is not Ellipsis: + res = (list(res[:-1]), res[-1]) + return res + return () + + +# 3.10+ +if hasattr(typing, 'TypeAlias'): + TypeAlias = typing.TypeAlias +# 3.9 +else: + @_ExtensionsSpecialForm + def TypeAlias(self, parameters): + """Special marker indicating that an assignment should + be recognized as a proper type alias definition by type + checkers. + + For example:: + + Predicate: TypeAlias = Callable[..., bool] + + It's invalid when used anywhere except as in the example above. + """ + raise TypeError(f"{self} is not subscriptable") + + +def _set_default(type_param, default): + type_param.has_default = lambda: default is not NoDefault + type_param.__default__ = default + + +def _set_module(typevarlike): + # for pickling: + def_mod = _caller(depth=2) + if def_mod != 'typing_extensions': + typevarlike.__module__ = def_mod + + +class _DefaultMixin: + """Mixin for TypeVarLike defaults.""" + + __slots__ = () + __init__ = _set_default + + +# Classes using this metaclass must provide a _backported_typevarlike ClassVar +class _TypeVarLikeMeta(type): + def __instancecheck__(cls, __instance: Any) -> bool: + return isinstance(__instance, cls._backported_typevarlike) + + +if _PEP_696_IMPLEMENTED: + from typing import TypeVar +else: + # Add default and infer_variance parameters from PEP 696 and 695 + class TypeVar(metaclass=_TypeVarLikeMeta): + """Type variable.""" + + _backported_typevarlike = typing.TypeVar + + def __new__(cls, name, *constraints, bound=None, + covariant=False, contravariant=False, + default=NoDefault, infer_variance=False): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented (3.12+), can pass infer_variance to typing.TypeVar + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant, + infer_variance=infer_variance) + else: + typevar = typing.TypeVar(name, *constraints, bound=bound, + covariant=covariant, contravariant=contravariant) + if infer_variance and (covariant or contravariant): + raise ValueError("Variance cannot be specified with infer_variance.") + typevar.__infer_variance__ = infer_variance + + _set_default(typevar, default) + _set_module(typevar) + + def _tvar_prepare_subst(alias, args): + if ( + typevar.has_default() + and alias.__parameters__.index(typevar) == len(args) + ): + args += (typevar.__default__,) + return args + + typevar.__typing_prepare_subst__ = _tvar_prepare_subst + return typevar + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.TypeVar' is not an acceptable base type") + + +# Python 3.10+ has PEP 612 +if hasattr(typing, 'ParamSpecArgs'): + ParamSpecArgs = typing.ParamSpecArgs + ParamSpecKwargs = typing.ParamSpecKwargs +# 3.9 +else: + class _Immutable: + """Mixin to indicate that object should not be copied.""" + __slots__ = () + + def __copy__(self): + return self + + def __deepcopy__(self, memo): + return self + + class ParamSpecArgs(_Immutable): + """The args for a ParamSpec object. + + Given a ParamSpec object P, P.args is an instance of ParamSpecArgs. + + ParamSpecArgs objects have a reference back to their ParamSpec: + + P.args.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.args" + + def __eq__(self, other): + if not isinstance(other, ParamSpecArgs): + return NotImplemented + return self.__origin__ == other.__origin__ + + class ParamSpecKwargs(_Immutable): + """The kwargs for a ParamSpec object. + + Given a ParamSpec object P, P.kwargs is an instance of ParamSpecKwargs. + + ParamSpecKwargs objects have a reference back to their ParamSpec: + + P.kwargs.__origin__ is P + + This type is meant for runtime introspection and has no special meaning to + static type checkers. + """ + def __init__(self, origin): + self.__origin__ = origin + + def __repr__(self): + return f"{self.__origin__.__name__}.kwargs" + + def __eq__(self, other): + if not isinstance(other, ParamSpecKwargs): + return NotImplemented + return self.__origin__ == other.__origin__ + + +if _PEP_696_IMPLEMENTED: + from typing import ParamSpec + +# 3.10+ +elif hasattr(typing, 'ParamSpec'): + + # Add default parameter - PEP 696 + class ParamSpec(metaclass=_TypeVarLikeMeta): + """Parameter specification.""" + + _backported_typevarlike = typing.ParamSpec + + def __new__(cls, name, *, bound=None, + covariant=False, contravariant=False, + infer_variance=False, default=NoDefault): + if hasattr(typing, "TypeAliasType"): + # PEP 695 implemented, can pass infer_variance to typing.TypeVar + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant, + infer_variance=infer_variance) + else: + paramspec = typing.ParamSpec(name, bound=bound, + covariant=covariant, + contravariant=contravariant) + paramspec.__infer_variance__ = bool(infer_variance) + + _set_default(paramspec, default) + _set_module(paramspec) + + def _paramspec_prepare_subst(alias, args): + params = alias.__parameters__ + i = params.index(paramspec) + if i == len(args) and paramspec.has_default(): + args = [*args, paramspec.__default__] + if i >= len(args): + raise TypeError(f"Too few arguments for {alias}") + # Special case where Z[[int, str, bool]] == Z[int, str, bool] in PEP 612. + if len(params) == 1 and not typing._is_param_expr(args[0]): + assert i == 0 + args = (args,) + # Convert lists to tuples to help other libraries cache the results. + elif isinstance(args[i], list): + args = (*args[:i], tuple(args[i]), *args[i + 1:]) + return args + + paramspec.__typing_prepare_subst__ = _paramspec_prepare_subst + return paramspec + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") + +# 3.9 +else: + + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + class ParamSpec(list, _DefaultMixin): + """Parameter specification variable. + + Usage:: + + P = ParamSpec('P') + + Parameter specification variables exist primarily for the benefit of static + type checkers. They are used to forward the parameter types of one + callable to another callable, a pattern commonly found in higher order + functions and decorators. They are only valid when used in ``Concatenate``, + or s the first argument to ``Callable``. In Python 3.10 and higher, + they are also supported in user-defined Generics at runtime. + See class Generic for more information on generic types. An + example for annotating a decorator:: + + T = TypeVar('T') + P = ParamSpec('P') + + def add_logging(f: Callable[P, T]) -> Callable[P, T]: + '''A type-safe decorator to add logging to a function.''' + def inner(*args: P.args, **kwargs: P.kwargs) -> T: + logging.info(f'{f.__name__} was called') + return f(*args, **kwargs) + return inner + + @add_logging + def add_two(x: float, y: float) -> float: + '''Add two numbers together.''' + return x + y + + Parameter specification variables defined with covariant=True or + contravariant=True can be used to declare covariant or contravariant + generic types. These keyword arguments are valid, but their actual semantics + are yet to be decided. See PEP 612 for details. + + Parameter specification variables can be introspected. e.g.: + + P.__name__ == 'T' + P.__bound__ == None + P.__covariant__ == False + P.__contravariant__ == False + + Note that only parameter specification variables defined in global scope can + be pickled. + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + @property + def args(self): + return ParamSpecArgs(self) + + @property + def kwargs(self): + return ParamSpecKwargs(self) + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + infer_variance=False, default=NoDefault): + list.__init__(self, [self]) + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + self.__infer_variance__ = bool(infer_variance) + self.__bound__ = bound + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __repr__(self): + if self.__infer_variance__: + prefix = '' + elif self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + # Hack to get typing._type_check to pass. + def __call__(self, *args, **kwargs): + pass + + def __init_subclass__(cls) -> None: + raise TypeError(f"type '{__name__}.ParamSpec' is not an acceptable base type") + + +# 3.9 +if not hasattr(typing, 'Concatenate'): + # Inherits from list as a workaround for Callable checks in Python < 3.9.2. + + # 3.9.0-1 + if not hasattr(typing, '_type_convert'): + def _type_convert(arg, module=None, *, allow_special_forms=False): + """For converting None to type(None), and strings to ForwardRef.""" + if arg is None: + return type(None) + if isinstance(arg, str): + if sys.version_info <= (3, 9, 6): + return ForwardRef(arg) + if sys.version_info <= (3, 9, 7): + return ForwardRef(arg, module=module) + return ForwardRef(arg, module=module, is_class=allow_special_forms) + return arg + else: + _type_convert = typing._type_convert + + class _ConcatenateGenericAlias(list): + + # Trick Generic into looking into this for __parameters__. + __class__ = typing._GenericAlias + + def __init__(self, origin, args): + # Cannot use `super().__init__` here because of the `__class__` assignment + # in the class body (https://github.com/python/typing_extensions/issues/661) + list.__init__(self, args) + self.__origin__ = origin + self.__args__ = args + + def __repr__(self): + _type_repr = typing._type_repr + return (f'{_type_repr(self.__origin__)}' + f'[{", ".join(_type_repr(arg) for arg in self.__args__)}]') + + def __hash__(self): + return hash((self.__origin__, self.__args__)) + + # Hack to get typing._type_check to pass in Generic. + def __call__(self, *args, **kwargs): + pass + + @property + def __parameters__(self): + return tuple( + tp for tp in self.__args__ if isinstance(tp, (typing.TypeVar, ParamSpec)) + ) + + # 3.9 used by __getitem__ below + def copy_with(self, params): + if isinstance(params[-1], _ConcatenateGenericAlias): + params = (*params[:-1], *params[-1].__args__) + elif isinstance(params[-1], (list, tuple)): + return (*params[:-1], *params[-1]) + elif (not (params[-1] is ... or isinstance(params[-1], ParamSpec))): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable or ellipsis.") + return self.__class__(self.__origin__, params) + + # 3.9; accessed during GenericAlias.__getitem__ when substituting + def __getitem__(self, args): + if self.__origin__ in (Generic, Protocol): + # Can't subscript Generic[...] or Protocol[...]. + raise TypeError(f"Cannot subscript already-subscripted {self}") + if not self.__parameters__: + raise TypeError(f"{self} is not a generic class") + + if not isinstance(args, tuple): + args = (args,) + args = _unpack_args(*(_type_convert(p) for p in args)) + params = self.__parameters__ + for param in params: + prepare = getattr(param, "__typing_prepare_subst__", None) + if prepare is not None: + args = prepare(self, args) + # 3.9 & typing.ParamSpec + elif isinstance(param, ParamSpec): + i = params.index(param) + if ( + i == len(args) + and getattr(param, '__default__', NoDefault) is not NoDefault + ): + args = [*args, param.__default__] + if i >= len(args): + raise TypeError(f"Too few arguments for {self}") + # Special case for Z[[int, str, bool]] == Z[int, str, bool] + if len(params) == 1 and not _is_param_expr(args[0]): + assert i == 0 + args = (args,) + elif ( + isinstance(args[i], list) + # 3.9 + # This class inherits from list do not convert + and not isinstance(args[i], _ConcatenateGenericAlias) + ): + args = (*args[:i], tuple(args[i]), *args[i + 1:]) + + alen = len(args) + plen = len(params) + if alen != plen: + raise TypeError( + f"Too {'many' if alen > plen else 'few'} arguments for {self};" + f" actual {alen}, expected {plen}" + ) + + subst = dict(zip(self.__parameters__, args)) + # determine new args + new_args = [] + for arg in self.__args__: + if isinstance(arg, type): + new_args.append(arg) + continue + if isinstance(arg, TypeVar): + arg = subst[arg] + if ( + (isinstance(arg, typing._GenericAlias) and _is_unpack(arg)) + or ( + hasattr(_types, "GenericAlias") + and isinstance(arg, _types.GenericAlias) + and getattr(arg, "__unpacked__", False) + ) + ): + raise TypeError(f"{arg} is not valid as type argument") + + elif isinstance(arg, + typing._GenericAlias + if not hasattr(_types, "GenericAlias") else + (typing._GenericAlias, _types.GenericAlias) + ): + subparams = arg.__parameters__ + if subparams: + subargs = tuple(subst[x] for x in subparams) + arg = arg[subargs] + new_args.append(arg) + return self.copy_with(tuple(new_args)) + +# 3.10+ +else: + _ConcatenateGenericAlias = typing._ConcatenateGenericAlias + + # 3.10 + if sys.version_info < (3, 11): + + class _ConcatenateGenericAlias(typing._ConcatenateGenericAlias, _root=True): + # needed for checks in collections.abc.Callable to accept this class + __module__ = "typing" + + def copy_with(self, params): + if isinstance(params[-1], (list, tuple)): + return (*params[:-1], *params[-1]) + if isinstance(params[-1], typing._ConcatenateGenericAlias): + params = (*params[:-1], *params[-1].__args__) + elif not (params[-1] is ... or isinstance(params[-1], ParamSpec)): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable or ellipsis.") + return super(typing._ConcatenateGenericAlias, self).copy_with(params) + + def __getitem__(self, args): + value = super().__getitem__(args) + if isinstance(value, tuple) and any(_is_unpack(t) for t in value): + return tuple(_unpack_args(*(n for n in value))) + return value + + +# 3.9.2 +class _EllipsisDummy: ... + + +# <=3.10 +def _create_concatenate_alias(origin, parameters): + if parameters[-1] is ... and sys.version_info < (3, 9, 2): + # Hack: Arguments must be types, replace it with one. + parameters = (*parameters[:-1], _EllipsisDummy) + if sys.version_info >= (3, 10, 3): + concatenate = _ConcatenateGenericAlias(origin, parameters, + _typevar_types=(TypeVar, ParamSpec), + _paramspec_tvars=True) + else: + concatenate = _ConcatenateGenericAlias(origin, parameters) + if parameters[-1] is not _EllipsisDummy: + return concatenate + # Remove dummy again + concatenate.__args__ = tuple(p if p is not _EllipsisDummy else ... + for p in concatenate.__args__) + if sys.version_info < (3, 10): + # backport needs __args__ adjustment only + return concatenate + concatenate.__parameters__ = tuple(p for p in concatenate.__parameters__ + if p is not _EllipsisDummy) + return concatenate + + +# <=3.10 +@typing._tp_cache +def _concatenate_getitem(self, parameters): + if parameters == (): + raise TypeError("Cannot take a Concatenate of no types.") + if not isinstance(parameters, tuple): + parameters = (parameters,) + if not (parameters[-1] is ... or isinstance(parameters[-1], ParamSpec)): + raise TypeError("The last parameter to Concatenate should be a " + "ParamSpec variable or ellipsis.") + msg = "Concatenate[arg, ...]: each arg must be a type." + parameters = (*(typing._type_check(p, msg) for p in parameters[:-1]), + parameters[-1]) + return _create_concatenate_alias(self, parameters) + + +# 3.11+; Concatenate does not accept ellipsis in 3.10 +# Breakpoint: https://github.com/python/cpython/pull/30969 +if sys.version_info >= (3, 11): + Concatenate = typing.Concatenate +# <=3.10 +else: + @_ExtensionsSpecialForm + def Concatenate(self, parameters): + """Used in conjunction with ``ParamSpec`` and ``Callable`` to represent a + higher order function which adds, removes or transforms parameters of a + callable. + + For example:: + + Callable[Concatenate[int, P], int] + + See PEP 612 for detailed information. + """ + return _concatenate_getitem(self, parameters) + + +# 3.10+ +if hasattr(typing, 'TypeGuard'): + TypeGuard = typing.TypeGuard +# 3.9 +else: + @_ExtensionsSpecialForm + def TypeGuard(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type guard function. ``TypeGuard`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeGuard`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeGuard[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeGuard`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the type inside ``TypeGuard``. + + For example:: + + def is_str(val: Union[str, float]): + # "isinstance" type guard + if isinstance(val, str): + # Type of ``val`` is narrowed to ``str`` + ... + else: + # Else, type of ``val`` is narrowed to ``float``. + ... + + Strict type narrowing is not enforced -- ``TypeB`` need not be a narrower + form of ``TypeA`` (it can even be a wider form) and this may lead to + type-unsafe results. The main reason is to allow for things like + narrowing ``List[object]`` to ``List[str]`` even though the latter is not + a subtype of the former, since ``List`` is invariant. The responsibility of + writing type-safe type guards is left to the user. + + ``TypeGuard`` also works with type variables. For more information, see + PEP 647 (User-Defined Type Guards). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + +# 3.13+ +if hasattr(typing, 'TypeIs'): + TypeIs = typing.TypeIs +# <=3.12 +else: + @_ExtensionsSpecialForm + def TypeIs(self, parameters): + """Special typing form used to annotate the return type of a user-defined + type narrower function. ``TypeIs`` only accepts a single type argument. + At runtime, functions marked this way should return a boolean. + + ``TypeIs`` aims to benefit *type narrowing* -- a technique used by static + type checkers to determine a more precise type of an expression within a + program's code flow. Usually type narrowing is done by analyzing + conditional code flow and applying the narrowing to a block of code. The + conditional expression here is sometimes referred to as a "type guard". + + Sometimes it would be convenient to use a user-defined boolean function + as a type guard. Such a function should use ``TypeIs[...]`` as its + return type to alert static type checkers to this intention. + + Using ``-> TypeIs`` tells the static type checker that for a given + function: + + 1. The return value is a boolean. + 2. If the return value is ``True``, the type of its argument + is the intersection of the type inside ``TypeIs`` and the argument's + previously known type. + + For example:: + + def is_awaitable(val: object) -> TypeIs[Awaitable[Any]]: + return hasattr(val, '__await__') + + def f(val: Union[int, Awaitable[int]]) -> int: + if is_awaitable(val): + assert_type(val, Awaitable[int]) + else: + assert_type(val, int) + + ``TypeIs`` also works with type variables. For more information, see + PEP 742 (Narrowing types with TypeIs). + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + +# 3.15+? +if hasattr(typing, 'TypeForm'): + TypeForm = typing.TypeForm +# <=3.14 +else: + class _TypeFormForm(_ExtensionsSpecialForm, _root=True): + # TypeForm(X) is equivalent to X but indicates to the type checker + # that the object is a TypeForm. + def __call__(self, obj, /): + return obj + + @_TypeFormForm + def TypeForm(self, parameters): + """A special form representing the value that results from the evaluation + of a type expression. This value encodes the information supplied in the + type expression, and it represents the type described by that type expression. + + When used in a type expression, TypeForm describes a set of type form objects. + It accepts a single type argument, which must be a valid type expression. + ``TypeForm[T]`` describes the set of all type form objects that represent + the type T or types that are assignable to T. + + Usage: + + def cast[T](typ: TypeForm[T], value: Any) -> T: ... + + reveal_type(cast(int, "x")) # int + + See PEP 747 for more information. + """ + item = typing._type_check(parameters, f'{self} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + + + +if hasattr(typing, "LiteralString"): # 3.11+ + LiteralString = typing.LiteralString +else: + @_SpecialForm + def LiteralString(self, params): + """Represents an arbitrary literal string. + + Example:: + + from typing_extensions import LiteralString + + def query(sql: LiteralString) -> ...: + ... + + query("SELECT * FROM table") # ok + query(f"SELECT * FROM {input()}") # not ok + + See PEP 675 for details. + + """ + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Self"): # 3.11+ + Self = typing.Self +else: + @_SpecialForm + def Self(self, params): + """Used to spell the type of "self" in classes. + + Example:: + + from typing import Self + + class ReturnsSelf: + def parse(self, data: bytes) -> Self: + ... + return self + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, "Never"): # 3.11+ + Never = typing.Never +else: + @_SpecialForm + def Never(self, params): + """The bottom type, a type that has no members. + + This can be used to define a function that should never be + called, or a function that never returns:: + + from typing_extensions import Never + + def never_call_me(arg: Never) -> None: + pass + + def int_or_str(arg: int | str) -> None: + never_call_me(arg) # type checker error + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + never_call_me(arg) # ok, arg is of type Never + + """ + + raise TypeError(f"{self} is not subscriptable") + + +if hasattr(typing, 'Required'): # 3.11+ + Required = typing.Required + NotRequired = typing.NotRequired +else: # <=3.10 + @_ExtensionsSpecialForm + def Required(self, parameters): + """A special typing construct to mark a key of a total=False TypedDict + as required. For example: + + class Movie(TypedDict, total=False): + title: Required[str] + year: int + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + + There is no runtime checking that a required key is actually provided + when instantiating a related TypedDict. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + @_ExtensionsSpecialForm + def NotRequired(self, parameters): + """A special typing construct to mark a key of a TypedDict as + potentially missing. For example: + + class Movie(TypedDict): + title: str + year: NotRequired[int] + + m = Movie( + title='The Matrix', # typechecker error if key is omitted + year=1999, + ) + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + +if hasattr(typing, 'ReadOnly'): + ReadOnly = typing.ReadOnly +else: # <=3.12 + @_ExtensionsSpecialForm + def ReadOnly(self, parameters): + """A special typing construct to mark an item of a TypedDict as read-only. + + For example: + + class Movie(TypedDict): + title: ReadOnly[str] + year: int + + def mutate_movie(m: Movie) -> None: + m["year"] = 1992 # allowed + m["title"] = "The Matrix" # typechecker error + + There is no runtime checking for this property. + """ + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return typing._GenericAlias(self, (item,)) + + +_UNPACK_DOC = """\ +Type unpack operator. + +The type unpack operator takes the child types from some container type, +such as `tuple[int, str]` or a `TypeVarTuple`, and 'pulls them out'. For +example: + + # For some generic class `Foo`: + Foo[Unpack[tuple[int, str]]] # Equivalent to Foo[int, str] + + Ts = TypeVarTuple('Ts') + # Specifies that `Bar` is generic in an arbitrary number of types. + # (Think of `Ts` as a tuple of an arbitrary number of individual + # `TypeVar`s, which the `Unpack` is 'pulling out' directly into the + # `Generic[]`.) + class Bar(Generic[Unpack[Ts]]): ... + Bar[int] # Valid + Bar[int, str] # Also valid + +From Python 3.11, this can also be done using the `*` operator: + + Foo[*tuple[int, str]] + class Bar(Generic[*Ts]): ... + +The operator can also be used along with a `TypedDict` to annotate +`**kwargs` in a function signature. For instance: + + class Movie(TypedDict): + name: str + year: int + + # This function expects two keyword arguments - *name* of type `str` and + # *year* of type `int`. + def foo(**kwargs: Unpack[Movie]): ... + +Note that there is only some runtime checking of this operator. Not +everything the runtime allows may be accepted by static type checkers. + +For more information, see PEP 646 and PEP 692. +""" + + +# PEP 692 changed the repr of Unpack[] +# Breakpoint: https://github.com/python/cpython/pull/104048 +if sys.version_info >= (3, 12): + Unpack = typing.Unpack + + def _is_unpack(obj): + return get_origin(obj) is Unpack + +else: # <=3.11 + class _UnpackSpecialForm(_ExtensionsSpecialForm, _root=True): + def __init__(self, getitem): + super().__init__(getitem) + self.__doc__ = _UNPACK_DOC + + class _UnpackAlias(typing._GenericAlias, _root=True): + if sys.version_info < (3, 11): + # needed for compatibility with Generic[Unpack[Ts]] + __class__ = typing.TypeVar + + @property + def __typing_unpacked_tuple_args__(self): + assert self.__origin__ is Unpack + assert len(self.__args__) == 1 + arg, = self.__args__ + if isinstance(arg, (typing._GenericAlias, _types.GenericAlias)): + if arg.__origin__ is not tuple: + raise TypeError("Unpack[...] must be used with a tuple type") + return arg.__args__ + return None + + @property + def __typing_is_unpacked_typevartuple__(self): + assert self.__origin__ is Unpack + assert len(self.__args__) == 1 + return isinstance(self.__args__[0], TypeVarTuple) + + def __getitem__(self, args): + if self.__typing_is_unpacked_typevartuple__: + return args + # Cannot use `super().__getitem__` here because of the `__class__` assignment + # in the class body on Python <=3.11 + # (https://github.com/python/typing_extensions/issues/661) + return typing._GenericAlias.__getitem__(self, args) + + @_UnpackSpecialForm + def Unpack(self, parameters): + item = typing._type_check(parameters, f'{self._name} accepts only a single type.') + return _UnpackAlias(self, (item,)) + + def _is_unpack(obj): + return isinstance(obj, _UnpackAlias) + + +def _unpack_args(*args): + newargs = [] + for arg in args: + subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) + if subargs is not None and (not (subargs and subargs[-1] is ...)): + newargs.extend(subargs) + else: + newargs.append(arg) + return newargs + + +if sys.version_info >= (3, 15): + from typing import TypeVarTuple + +elif hasattr(typing, "TypeVarTuple"): # 3.11+ + + # Add default parameter - PEP 696 and bound/variance parameters + class TypeVarTuple(metaclass=_TypeVarLikeMeta): + """Type variable tuple.""" + + _backported_typevarlike = typing.TypeVarTuple + + def __new__(cls, name, *, bound=None, + covariant=False, contravariant=False, + infer_variance=False, default=NoDefault): + + if _PEP_696_IMPLEMENTED: + # can pass default argument + tvt = typing.TypeVarTuple(name, default=default) + else: + tvt = typing.TypeVarTuple(name) + _set_default(tvt, default) + + tvt.__bound__ = bound + tvt.__covariant__ = bool(covariant) + tvt.__contravariant__ = bool(contravariant) + tvt.__infer_variance__ = bool(infer_variance) + + _set_module(tvt) + + def _typevartuple_prepare_subst(alias, args): + params = alias.__parameters__ + typevartuple_index = params.index(tvt) + for param in params[typevartuple_index + 1:]: + if isinstance(param, TypeVarTuple): + raise TypeError( + f"More than one TypeVarTuple parameter in {alias}" + ) + + alen = len(args) + plen = len(params) + left = typevartuple_index + right = plen - typevartuple_index - 1 + var_tuple_index = None + fillarg = None + for k, arg in enumerate(args): + if not isinstance(arg, type): + subargs = getattr(arg, '__typing_unpacked_tuple_args__', None) + if subargs and len(subargs) == 2 and subargs[-1] is ...: + if var_tuple_index is not None: + raise TypeError( + "More than one unpacked " + "arbitrary-length tuple argument" + ) + var_tuple_index = k + fillarg = subargs[0] + if var_tuple_index is not None: + left = min(left, var_tuple_index) + right = min(right, alen - var_tuple_index - 1) + elif left + right > alen: + raise TypeError(f"Too few arguments for {alias};" + f" actual {alen}, expected at least {plen - 1}") + if left == alen - right and tvt.has_default(): + replacement = _unpack_args(tvt.__default__) + else: + replacement = args[left: alen - right] + + return ( + *args[:left], + *([fillarg] * (typevartuple_index - left)), + replacement, + *([fillarg] * (plen - right - left - typevartuple_index - 1)), + *args[alen - right:], + ) + + tvt.__typing_prepare_subst__ = _typevartuple_prepare_subst + return tvt + + def __init_subclass__(self, *args, **kwds): + raise TypeError("Cannot subclass special typing classes") + +else: # <=3.10 + class TypeVarTuple(_DefaultMixin): + """Type variable tuple. + + Usage:: + + Ts = TypeVarTuple('Ts') + + In the same way that a normal type variable is a stand-in for a single + type such as ``int``, a type variable *tuple* is a stand-in for a *tuple* + type such as ``Tuple[int, str]``. + + Type variable tuples can be used in ``Generic`` declarations. + Consider the following example:: + + class Array(Generic[*Ts]): ... + + The ``Ts`` type variable tuple here behaves like ``tuple[T1, T2]``, + where ``T1`` and ``T2`` are type variables. To use these type variables + as type parameters of ``Array``, we must *unpack* the type variable tuple using + the star operator: ``*Ts``. The signature of ``Array`` then behaves + as if we had simply written ``class Array(Generic[T1, T2]): ...``. + In contrast to ``Generic[T1, T2]``, however, ``Generic[*Shape]`` allows + us to parameterise the class with an *arbitrary* number of type parameters. + + Type variable tuples can be used anywhere a normal ``TypeVar`` can. + This includes class definitions, as shown above, as well as function + signatures and variable annotations:: + + class Array(Generic[*Ts]): + + def __init__(self, shape: Tuple[*Ts]): + self._shape: Tuple[*Ts] = shape + + def get_shape(self) -> Tuple[*Ts]: + return self._shape + + shape = (Height(480), Width(640)) + x: Array[Height, Width] = Array(shape) + y = abs(x) # Inferred type is Array[Height, Width] + z = x + x # ... is Array[Height, Width] + x.get_shape() # ... is tuple[Height, Width] + + """ + + # Trick Generic __parameters__. + __class__ = typing.TypeVar + + def __iter__(self): + yield self.__unpacked__ + + def __init__(self, name, *, bound=None, covariant=False, contravariant=False, + infer_variance=False, default=NoDefault): + self.__name__ = name + self.__covariant__ = bool(covariant) + self.__contravariant__ = bool(contravariant) + self.__infer_variance__ = bool(infer_variance) + self.__bound__ = bound + _DefaultMixin.__init__(self, default) + + # for pickling: + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + self.__unpacked__ = Unpack[self] + + def __repr__(self): + if self.__infer_variance__: + prefix = '' + elif self.__covariant__: + prefix = '+' + elif self.__contravariant__: + prefix = '-' + else: + prefix = '~' + return prefix + self.__name__ + + def __hash__(self): + return object.__hash__(self) + + def __eq__(self, other): + return self is other + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(self, *args, **kwds): + if '_root' not in kwds: + raise TypeError("Cannot subclass special typing classes") + + +if hasattr(typing, "reveal_type"): # 3.11+ + reveal_type = typing.reveal_type +else: # <=3.10 + def reveal_type(obj: T, /) -> T: + """Reveal the inferred type of a variable. + + When a static type checker encounters a call to ``reveal_type()``, + it will emit the inferred type of the argument:: + + x: int = 1 + reveal_type(x) + + Running a static type checker (e.g., ``mypy``) on this example + will produce output similar to 'Revealed type is "builtins.int"'. + + At runtime, the function prints the runtime type of the + argument and returns it unchanged. + + """ + print(f"Runtime type is {type(obj).__name__!r}", file=sys.stderr) + return obj + + +if hasattr(typing, "_ASSERT_NEVER_REPR_MAX_LENGTH"): # 3.11+ + _ASSERT_NEVER_REPR_MAX_LENGTH = typing._ASSERT_NEVER_REPR_MAX_LENGTH +else: # <=3.10 + _ASSERT_NEVER_REPR_MAX_LENGTH = 100 + + +if hasattr(typing, "assert_never"): # 3.11+ + assert_never = typing.assert_never +else: # <=3.10 + def assert_never(arg: Never, /) -> Never: + """Assert to the type checker that a line of code is unreachable. + + Example:: + + def int_or_str(arg: int | str) -> None: + match arg: + case int(): + print("It's an int") + case str(): + print("It's a str") + case _: + assert_never(arg) + + If a type checker finds that a call to assert_never() is + reachable, it will emit an error. + + At runtime, this throws an exception when called. + + """ + value = repr(arg) + if len(value) > _ASSERT_NEVER_REPR_MAX_LENGTH: + value = value[:_ASSERT_NEVER_REPR_MAX_LENGTH] + '...' + raise AssertionError(f"Expected code to be unreachable, but got: {value}") + + +# dataclass_transform exists in 3.11 but lacks the frozen_default parameter +# Breakpoint: https://github.com/python/cpython/pull/99958 +if sys.version_info >= (3, 12): # 3.12+ + dataclass_transform = typing.dataclass_transform +else: # <=3.11 + def dataclass_transform( + *, + eq_default: bool = True, + order_default: bool = False, + kw_only_default: bool = False, + frozen_default: bool = False, + field_specifiers: typing.Tuple[ + typing.Union[typing.Type[typing.Any], typing.Callable[..., typing.Any]], + ... + ] = (), + **kwargs: typing.Any, + ) -> typing.Callable[[T], T]: + """Decorator that marks a function, class, or metaclass as providing + dataclass-like behavior. + + Example: + + from typing_extensions import dataclass_transform + + _T = TypeVar("_T") + + # Used on a decorator function + @dataclass_transform() + def create_model(cls: type[_T]) -> type[_T]: + ... + return cls + + @create_model + class CustomerModel: + id: int + name: str + + # Used on a base class + @dataclass_transform() + class ModelBase: ... + + class CustomerModel(ModelBase): + id: int + name: str + + # Used on a metaclass + @dataclass_transform() + class ModelMeta(type): ... + + class ModelBase(metaclass=ModelMeta): ... + + class CustomerModel(ModelBase): + id: int + name: str + + Each of the ``CustomerModel`` classes defined in this example will now + behave similarly to a dataclass created with the ``@dataclasses.dataclass`` + decorator. For example, the type checker will synthesize an ``__init__`` + method. + + The arguments to this decorator can be used to customize this behavior: + - ``eq_default`` indicates whether the ``eq`` parameter is assumed to be + True or False if it is omitted by the caller. + - ``order_default`` indicates whether the ``order`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``kw_only_default`` indicates whether the ``kw_only`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``frozen_default`` indicates whether the ``frozen`` parameter is + assumed to be True or False if it is omitted by the caller. + - ``field_specifiers`` specifies a static list of supported classes + or functions that describe fields, similar to ``dataclasses.field()``. + + At runtime, this decorator records its arguments in the + ``__dataclass_transform__`` attribute on the decorated object. + + See PEP 681 for details. + + """ + def decorator(cls_or_fn): + cls_or_fn.__dataclass_transform__ = { + "eq_default": eq_default, + "order_default": order_default, + "kw_only_default": kw_only_default, + "frozen_default": frozen_default, + "field_specifiers": field_specifiers, + "kwargs": kwargs, + } + return cls_or_fn + return decorator + + +if hasattr(typing, "override"): # 3.12+ + override = typing.override +else: # <=3.11 + _F = typing.TypeVar("_F", bound=typing.Callable[..., typing.Any]) + + def override(arg: _F, /) -> _F: + """Indicate that a method is intended to override a method in a base class. + + Usage: + + class Base: + def method(self) -> None: + pass + + class Child(Base): + @override + def method(self) -> None: + super().method() + + When this decorator is applied to a method, the type checker will + validate that it overrides a method with the same name on a base class. + This helps prevent bugs that may occur when a base class is changed + without an equivalent change to a child class. + + There is no runtime checking of these properties. The decorator + sets the ``__override__`` attribute to ``True`` on the decorated object + to allow runtime introspection. + + See PEP 698 for details. + + """ + try: + arg.__override__ = True + except (AttributeError, TypeError): + # Skip the attribute silently if it is not writable. + # AttributeError happens if the object has __slots__ or a + # read-only property, TypeError if it's a builtin class. + pass + return arg + + +# Python 3.13.8+ and 3.14.1+ contain a fix for the wrapped __init_subclass__ +# Breakpoint: https://github.com/python/cpython/pull/138210 +if ((3, 13, 8) <= sys.version_info < (3, 14)) or sys.version_info >= (3, 14, 1): + deprecated = warnings.deprecated +else: + _T = typing.TypeVar("_T") + + class deprecated: + """Indicate that a class, function or overload is deprecated. + + When this decorator is applied to an object, the type checker + will generate a diagnostic on usage of the deprecated object. + + Usage: + + @deprecated("Use B instead") + class A: + pass + + @deprecated("Use g instead") + def f(): + pass + + @overload + @deprecated("int support is deprecated") + def g(x: int) -> int: ... + @overload + def g(x: str) -> int: ... + + The warning specified by *category* will be emitted at runtime + on use of deprecated objects. For functions, that happens on calls; + for classes, on instantiation and on creation of subclasses. + If the *category* is ``None``, no warning is emitted at runtime. + The *stacklevel* determines where the + warning is emitted. If it is ``1`` (the default), the warning + is emitted at the direct caller of the deprecated object; if it + is higher, it is emitted further up the stack. + Static type checker behavior is not affected by the *category* + and *stacklevel* arguments. + + The deprecation message passed to the decorator is saved in the + ``__deprecated__`` attribute on the decorated object. + If applied to an overload, the decorator + must be after the ``@overload`` decorator for the attribute to + exist on the overload as returned by ``get_overloads()``. + + See PEP 702 for details. + + """ + def __init__( + self, + message: str, + /, + *, + category: typing.Optional[typing.Type[Warning]] = DeprecationWarning, + stacklevel: int = 1, + ) -> None: + if not isinstance(message, str): + raise TypeError( + "Expected an object of type str for 'message', not " + f"{type(message).__name__!r}" + ) + self.message = message + self.category = category + self.stacklevel = stacklevel + + def __call__(self, arg: _T, /) -> _T: + # Make sure the inner functions created below don't + # retain a reference to self. + msg = self.message + category = self.category + stacklevel = self.stacklevel + if category is None: + arg.__deprecated__ = msg + return arg + elif isinstance(arg, type): + import functools + from types import MethodType + + original_new = arg.__new__ + + @functools.wraps(original_new) + def __new__(cls, /, *args, **kwargs): + if cls is arg: + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + if original_new is not object.__new__: + return original_new(cls, *args, **kwargs) + # Mirrors a similar check in object.__new__. + elif cls.__init__ is object.__init__ and (args or kwargs): + raise TypeError(f"{cls.__name__}() takes no arguments") + else: + return original_new(cls) + + arg.__new__ = staticmethod(__new__) + + if "__init_subclass__" in arg.__dict__: + # __init_subclass__ is directly present on the decorated class. + # Synthesize a wrapper that calls this method directly. + original_init_subclass = arg.__init_subclass__ + # We need slightly different behavior if __init_subclass__ + # is a bound method (likely if it was implemented in Python). + # Otherwise, it likely means it's a builtin such as + # object's implementation of __init_subclass__. + if isinstance(original_init_subclass, MethodType): + original_init_subclass = original_init_subclass.__func__ + + @functools.wraps(original_init_subclass) + def __init_subclass__(*args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return original_init_subclass(*args, **kwargs) + else: + def __init_subclass__(cls, *args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return super(arg, cls).__init_subclass__(*args, **kwargs) + + arg.__init_subclass__ = classmethod(__init_subclass__) + + arg.__deprecated__ = __new__.__deprecated__ = msg + __init_subclass__.__deprecated__ = msg + return arg + elif callable(arg): + import functools + import inspect + + @functools.wraps(arg) + def wrapper(*args, **kwargs): + warnings.warn(msg, category=category, stacklevel=stacklevel + 1) + return arg(*args, **kwargs) + + if inspect.iscoroutinefunction(arg): + # Breakpoint: https://github.com/python/cpython/pull/99247 + if sys.version_info >= (3, 12): + wrapper = inspect.markcoroutinefunction(wrapper) + else: + import asyncio.coroutines + + wrapper._is_coroutine = asyncio.coroutines._is_coroutine + + arg.__deprecated__ = wrapper.__deprecated__ = msg + return wrapper + else: + raise TypeError( + "@deprecated decorator with non-None category must be applied to " + f"a class or callable, not {arg!r}" + ) + +# Breakpoint: https://github.com/python/cpython/pull/23702 +if sys.version_info < (3, 10): + def _is_param_expr(arg): + return arg is ... or isinstance( + arg, (tuple, list, ParamSpec, _ConcatenateGenericAlias) + ) +else: + def _is_param_expr(arg): + return arg is ... or isinstance( + arg, + ( + tuple, + list, + ParamSpec, + _ConcatenateGenericAlias, + typing._ConcatenateGenericAlias, + ), + ) + + +# We have to do some monkey patching to deal with the dual nature of +# Unpack/TypeVarTuple: +# - We want Unpack to be a kind of TypeVar so it gets accepted in +# Generic[Unpack[Ts]] +# - We want it to *not* be treated as a TypeVar for the purposes of +# counting generic parameters, so that when we subscript a generic, +# the runtime doesn't try to substitute the Unpack with the subscripted type. +if not hasattr(typing, "TypeVarTuple"): + def _check_generic(cls, parameters, elen=_marker): + """Check correct count for parameters of a generic cls (internal helper). + + This gives a nice error message in case of count mismatch. + """ + # If substituting a single ParamSpec with multiple arguments + # we do not check the count + if (inspect.isclass(cls) and issubclass(cls, typing.Generic) + and len(cls.__parameters__) == 1 + and isinstance(cls.__parameters__[0], ParamSpec) + and parameters + and not _is_param_expr(parameters[0]) + ): + # Generic modifies parameters variable, but here we cannot do this + return + + if not elen: + raise TypeError(f"{cls} is not a generic class") + if elen is _marker: + if not hasattr(cls, "__parameters__") or not cls.__parameters__: + raise TypeError(f"{cls} is not a generic class") + elen = len(cls.__parameters__) + alen = len(parameters) + if alen != elen: + expect_val = elen + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + num_tv_tuples = sum(isinstance(p, TypeVarTuple) for p in parameters) + if (num_tv_tuples > 0) and (alen >= elen - num_tv_tuples): + return + + # deal with TypeVarLike defaults + # required TypeVarLikes cannot appear after a defaulted one. + if alen < elen: + # since we validate TypeVarLike default in _collect_type_vars + # or _collect_parameters we can safely check parameters[alen] + if ( + getattr(parameters[alen], '__default__', NoDefault) + is not NoDefault + ): + return + + num_default_tv = sum(getattr(p, '__default__', NoDefault) + is not NoDefault for p in parameters) + + elen -= num_default_tv + + expect_val = f"at least {elen}" + + # Breakpoint: https://github.com/python/cpython/pull/27515 + things = "arguments" if sys.version_info >= (3, 10) else "parameters" + raise TypeError(f"Too {'many' if alen > elen else 'few'} {things}" + f" for {cls}; actual {alen}, expected {expect_val}") +else: + # Python 3.11+ + + def _check_generic(cls, parameters, elen): + """Check correct count for parameters of a generic cls (internal helper). + + This gives a nice error message in case of count mismatch. + """ + if not elen: + raise TypeError(f"{cls} is not a generic class") + alen = len(parameters) + if alen != elen: + expect_val = elen + if hasattr(cls, "__parameters__"): + parameters = [p for p in cls.__parameters__ if not _is_unpack(p)] + + # deal with TypeVarLike defaults + # required TypeVarLikes cannot appear after a defaulted one. + if alen < elen: + # since we validate TypeVarLike default in _collect_type_vars + # or _collect_parameters we can safely check parameters[alen] + if ( + getattr(parameters[alen], '__default__', NoDefault) + is not NoDefault + ): + return + + num_default_tv = sum(getattr(p, '__default__', NoDefault) + is not NoDefault for p in parameters) + + elen -= num_default_tv + + expect_val = f"at least {elen}" + + raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments" + f" for {cls}; actual {alen}, expected {expect_val}") + +if not _PEP_696_IMPLEMENTED: + typing._check_generic = _check_generic + + +def _has_generic_or_protocol_as_origin() -> bool: + try: + frame = sys._getframe(2) + # - Catch AttributeError: not all Python implementations have sys._getframe() + # - Catch ValueError: maybe we're called from an unexpected module + # and the call stack isn't deep enough + except (AttributeError, ValueError): + return False # err on the side of leniency + else: + # If we somehow get invoked from outside typing.py, + # also err on the side of leniency + if frame.f_globals.get("__name__") != "typing": + return False + origin = frame.f_locals.get("origin") + # Cannot use "in" because origin may be an object with a buggy __eq__ that + # throws an error. + return origin is typing.Generic or origin is Protocol or origin is typing.Protocol + + +_TYPEVARTUPLE_TYPES = {TypeVarTuple, getattr(typing, "TypeVarTuple", None)} + + +def _is_unpacked_typevartuple(x) -> bool: + if get_origin(x) is not Unpack: + return False + args = get_args(x) + return ( + bool(args) + and len(args) == 1 + and type(args[0]) in _TYPEVARTUPLE_TYPES + ) + + +# Python 3.11+ _collect_type_vars was renamed to _collect_parameters +if hasattr(typing, '_collect_type_vars'): + def _collect_type_vars(types, typevar_types=None): + """Collect all type variable contained in types in order of + first appearance (lexicographic order). For example:: + + _collect_type_vars((T, List[S, T])) == (T, S) + """ + if typevar_types is None: + typevar_types = typing.TypeVar + tvars = [] + + # A required TypeVarLike cannot appear after a TypeVarLike with a default + # if it was a direct call to `Generic[]` or `Protocol[]` + enforce_default_ordering = _has_generic_or_protocol_as_origin() + default_encountered = False + + # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple + type_var_tuple_encountered = False + + for t in types: + if _is_unpacked_typevartuple(t): + type_var_tuple_encountered = True + elif ( + isinstance(t, typevar_types) and not isinstance(t, _UnpackAlias) + and t not in tvars + ): + if enforce_default_ordering: + has_default = getattr(t, '__default__', NoDefault) is not NoDefault + if has_default: + if type_var_tuple_encountered: + raise TypeError('Type parameter with a default' + ' follows TypeVarTuple') + default_encountered = True + elif default_encountered: + raise TypeError(f'Type parameter {t!r} without a default' + ' follows type parameter with a default') + + tvars.append(t) + if _should_collect_from_parameters(t): + tvars.extend([t for t in t.__parameters__ if t not in tvars]) + elif isinstance(t, tuple): + # Collect nested type_vars + # tuple wrapped by _prepare_paramspec_params(cls, params) + for x in t: + for collected in _collect_type_vars([x]): + if collected not in tvars: + tvars.append(collected) + return tuple(tvars) + + typing._collect_type_vars = _collect_type_vars +else: + def _collect_parameters(args): + """Collect all type variables and parameter specifications in args + in order of first appearance (lexicographic order). + + For example:: + + assert _collect_parameters((T, Callable[P, T])) == (T, P) + """ + parameters = [] + + # A required TypeVarLike cannot appear after a TypeVarLike with default + # if it was a direct call to `Generic[]` or `Protocol[]` + enforce_default_ordering = _has_generic_or_protocol_as_origin() + default_encountered = False + + # Also, a TypeVarLike with a default cannot appear after a TypeVarTuple + type_var_tuple_encountered = False + + for t in args: + if isinstance(t, type): + # We don't want __parameters__ descriptor of a bare Python class. + pass + elif isinstance(t, tuple): + # `t` might be a tuple, when `ParamSpec` is substituted with + # `[T, int]`, or `[int, *Ts]`, etc. + for x in t: + for collected in _collect_parameters([x]): + if collected not in parameters: + parameters.append(collected) + elif hasattr(t, '__typing_subst__'): + if t not in parameters: + if enforce_default_ordering: + has_default = ( + getattr(t, '__default__', NoDefault) is not NoDefault + ) + + if type_var_tuple_encountered and has_default: + raise TypeError('Type parameter with a default' + ' follows TypeVarTuple') + + if has_default: + default_encountered = True + elif default_encountered: + raise TypeError(f'Type parameter {t!r} without a default' + ' follows type parameter with a default') + + parameters.append(t) + else: + if _is_unpacked_typevartuple(t): + type_var_tuple_encountered = True + for x in getattr(t, '__parameters__', ()): + if x not in parameters: + parameters.append(x) + + return tuple(parameters) + + if not _PEP_696_IMPLEMENTED: + typing._collect_parameters = _collect_parameters + +# Backport typing.NamedTuple as it exists in Python 3.13. +# In 3.11, the ability to define generic `NamedTuple`s was supported. +# This was explicitly disallowed in 3.9-3.10, and only half-worked in <=3.8. +# On 3.12, we added __orig_bases__ to call-based NamedTuples +# On 3.13, we deprecated kwargs-based NamedTuples +# Breakpoint: https://github.com/python/cpython/pull/105609 +if sys.version_info >= (3, 13): + NamedTuple = typing.NamedTuple +else: + def _make_nmtuple(name, types, module, defaults=()): + fields = [n for n, t in types] + annotations = {n: typing._type_check(t, f"field {n} annotation must be a type") + for n, t in types} + nm_tpl = collections.namedtuple(name, fields, + defaults=defaults, module=module) + nm_tpl.__annotations__ = nm_tpl.__new__.__annotations__ = annotations + return nm_tpl + + _prohibited_namedtuple_fields = typing._prohibited + _special_namedtuple_fields = frozenset({'__module__', '__name__', '__annotations__'}) + + class _NamedTupleMeta(type): + def __new__(cls, typename, bases, ns): + assert _NamedTuple in bases + for base in bases: + if base is not _NamedTuple and base is not typing.Generic: + raise TypeError( + 'can only inherit from a NamedTuple type and Generic') + bases = tuple(tuple if base is _NamedTuple else base for base in bases) + if "__annotations__" in ns: + types = ns["__annotations__"] + elif "__annotate__" in ns: + # TODO: Use inspect.VALUE here, and make the annotations lazily evaluated + types = ns["__annotate__"](1) + else: + types = {} + default_names = [] + for field_name in types: + if field_name in ns: + default_names.append(field_name) + elif default_names: + raise TypeError(f"Non-default namedtuple field {field_name} " + f"cannot follow default field" + f"{'s' if len(default_names) > 1 else ''} " + f"{', '.join(default_names)}") + nm_tpl = _make_nmtuple( + typename, types.items(), + defaults=[ns[n] for n in default_names], + module=ns['__module__'] + ) + nm_tpl.__bases__ = bases + if typing.Generic in bases: + if hasattr(typing, '_generic_class_getitem'): # 3.12+ + nm_tpl.__class_getitem__ = classmethod(typing._generic_class_getitem) + else: + class_getitem = typing.Generic.__class_getitem__.__func__ + nm_tpl.__class_getitem__ = classmethod(class_getitem) + # update from user namespace without overriding special namedtuple attributes + for key, val in ns.items(): + if key in _prohibited_namedtuple_fields: + raise AttributeError("Cannot overwrite NamedTuple attribute " + key) + elif key not in _special_namedtuple_fields: + if key not in nm_tpl._fields: + setattr(nm_tpl, key, ns[key]) + try: + set_name = type(val).__set_name__ + except AttributeError: + pass + else: + try: + set_name(val, nm_tpl, key) + except BaseException as e: + msg = ( + f"Error calling __set_name__ on {type(val).__name__!r} " + f"instance {key!r} in {typename!r}" + ) + # BaseException.add_note() existed on py311, + # but the __set_name__ machinery didn't start + # using add_note() until py312. + # Making sure exceptions are raised in the same way + # as in "normal" classes seems most important here. + # Breakpoint: https://github.com/python/cpython/pull/95915 + if sys.version_info >= (3, 12): + e.add_note(msg) + raise + else: + raise RuntimeError(msg) from e + + if typing.Generic in bases: + nm_tpl.__init_subclass__() + return nm_tpl + + _NamedTuple = type.__new__(_NamedTupleMeta, 'NamedTuple', (), {}) + + def _namedtuple_mro_entries(bases): + assert NamedTuple in bases + return (_NamedTuple,) + + def NamedTuple(typename, fields=_marker, /, **kwargs): + """Typed version of namedtuple. + + Usage:: + + class Employee(NamedTuple): + name: str + id: int + + This is equivalent to:: + + Employee = collections.namedtuple('Employee', ['name', 'id']) + + The resulting class has an extra __annotations__ attribute, giving a + dict that maps field names to types. (The field names are also in + the _fields attribute, which is part of the namedtuple API.) + An alternative equivalent functional syntax is also accepted:: + + Employee = NamedTuple('Employee', [('name', str), ('id', int)]) + """ + if fields is _marker: + if kwargs: + deprecated_thing = "Creating NamedTuple classes using keyword arguments" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "Use the class-based or functional syntax instead." + ) + else: + deprecated_thing = "Failing to pass a value for the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif fields is None: + if kwargs: + raise TypeError( + "Cannot pass `None` as the 'fields' parameter " + "and also specify fields using keyword arguments" + ) + else: + deprecated_thing = "Passing `None` as the 'fields' parameter" + example = f"`{typename} = NamedTuple({typename!r}, [])`" + deprecation_msg = ( + "{name} is deprecated and will be disallowed in Python {remove}. " + "To create a NamedTuple class with 0 fields " + "using the functional syntax, " + "pass an empty list, e.g. " + ) + example + "." + elif kwargs: + raise TypeError("Either list of fields or keywords" + " can be provided to NamedTuple, not both") + if fields is _marker or fields is None: + warnings.warn( + deprecation_msg.format(name=deprecated_thing, remove="3.15"), + DeprecationWarning, + stacklevel=2, + ) + fields = kwargs.items() + nt = _make_nmtuple(typename, fields, module=_caller()) + nt.__orig_bases__ = (NamedTuple,) + return nt + + NamedTuple.__mro_entries__ = _namedtuple_mro_entries + + +if hasattr(collections.abc, "Buffer"): + Buffer = collections.abc.Buffer +else: + class Buffer(abc.ABC): # noqa: B024 + """Base class for classes that implement the buffer protocol. + + The buffer protocol allows Python objects to expose a low-level + memory buffer interface. Before Python 3.12, it is not possible + to implement the buffer protocol in pure Python code, or even + to check whether a class implements the buffer protocol. In + Python 3.12 and higher, the ``__buffer__`` method allows access + to the buffer protocol from Python code, and the + ``collections.abc.Buffer`` ABC allows checking whether a class + implements the buffer protocol. + + To indicate support for the buffer protocol in earlier versions, + inherit from this ABC, either in a stub file or at runtime, + or use ABC registration. This ABC provides no methods, because + there is no Python-accessible methods shared by pre-3.12 buffer + classes. It is useful primarily for static checks. + + """ + + # As a courtesy, register the most common stdlib buffer classes. + Buffer.register(memoryview) + Buffer.register(bytearray) + Buffer.register(bytes) + + +# Backport of types.get_original_bases, available on 3.12+ in CPython +if hasattr(_types, "get_original_bases"): + get_original_bases = _types.get_original_bases +else: + def get_original_bases(cls, /): + """Return the class's "original" bases prior to modification by `__mro_entries__`. + + Examples:: + + from typing import TypeVar, Generic + from typing_extensions import NamedTuple, TypedDict + + T = TypeVar("T") + class Foo(Generic[T]): ... + class Bar(Foo[int], float): ... + class Baz(list[str]): ... + Eggs = NamedTuple("Eggs", [("a", int), ("b", str)]) + Spam = TypedDict("Spam", {"a": int, "b": str}) + + assert get_original_bases(Bar) == (Foo[int], float) + assert get_original_bases(Baz) == (list[str],) + assert get_original_bases(Eggs) == (NamedTuple,) + assert get_original_bases(Spam) == (TypedDict,) + assert get_original_bases(int) == (object,) + """ + try: + return cls.__dict__.get("__orig_bases__", cls.__bases__) + except AttributeError: + raise TypeError( + f'Expected an instance of type, not {type(cls).__name__!r}' + ) from None + + +# NewType is a class on Python 3.10+, making it pickleable +# The error message for subclassing instances of NewType was improved on 3.11+ +# Breakpoint: https://github.com/python/cpython/pull/30268 +if sys.version_info >= (3, 11): + NewType = typing.NewType +else: + class NewType: + """NewType creates simple unique types with almost zero + runtime overhead. NewType(name, tp) is considered a subtype of tp + by static type checkers. At runtime, NewType(name, tp) returns + a dummy callable that simply returns its argument. Usage:: + UserId = NewType('UserId', int) + def name_by_id(user_id: UserId) -> str: + ... + UserId('user') # Fails type check + name_by_id(42) # Fails type check + name_by_id(UserId(42)) # OK + num = UserId(5) + 1 # type: int + """ + + def __call__(self, obj, /): + return obj + + def __init__(self, name, tp): + self.__qualname__ = name + if '.' in name: + name = name.rpartition('.')[-1] + self.__name__ = name + self.__supertype__ = tp + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + + def __mro_entries__(self, bases): + # We defined __mro_entries__ to get a better error message + # if a user attempts to subclass a NewType instance. bpo-46170 + supercls_name = self.__name__ + + class Dummy: + def __init_subclass__(cls): + subcls_name = cls.__name__ + raise TypeError( + f"Cannot subclass an instance of NewType. " + f"Perhaps you were looking for: " + f"`{subcls_name} = NewType({subcls_name!r}, {supercls_name})`" + ) + + return (Dummy,) + + def __repr__(self): + return f'{self.__module__}.{self.__qualname__}' + + def __reduce__(self): + return self.__qualname__ + + # Breakpoint: https://github.com/python/cpython/pull/21515 + if sys.version_info >= (3, 10): + # PEP 604 methods + # It doesn't make sense to have these methods on Python <3.10 + + def __or__(self, other): + return typing.Union[self, other] + + def __ror__(self, other): + return typing.Union[other, self] + + +# Breakpoint: https://github.com/python/cpython/pull/149172 +if sys.version_info >= (3, 15): + TypeAliasType = typing.TypeAliasType +# <=3.14 +else: + # Breakpoint: https://github.com/python/cpython/pull/103764 + if sys.version_info >= (3, 12): + # 3.12-3.14 + def _is_unionable(obj): + """Corresponds to is_unionable() in unionobject.c in CPython.""" + return obj is None or isinstance(obj, ( + type, + _types.GenericAlias, + _types.UnionType, + typing.TypeAliasType, + TypeAliasType, + )) + else: + # <=3.11 + def _is_unionable(obj): + """Corresponds to is_unionable() in unionobject.c in CPython.""" + return obj is None or isinstance(obj, ( + type, + _types.GenericAlias, + _types.UnionType, + TypeAliasType, + )) + + if sys.version_info < (3, 10): + # Copied and pasted from https://github.com/python/cpython/blob/986a4e1b6fcae7fe7a1d0a26aea446107dd58dd2/Objects/genericaliasobject.c#L568-L582, + # so that we emulate the behaviour of `types.GenericAlias` + # on the latest versions of CPython + _ATTRIBUTE_DELEGATION_EXCLUSIONS = frozenset({ + "__class__", + "__bases__", + "__origin__", + "__args__", + "__unpacked__", + "__parameters__", + "__typing_unpacked_tuple_args__", + "__mro_entries__", + "__reduce_ex__", + "__reduce__", + "__copy__", + "__deepcopy__", + }) + + class _TypeAliasGenericAlias(typing._GenericAlias, _root=True): + def __getattr__(self, attr): + if attr in _ATTRIBUTE_DELEGATION_EXCLUSIONS: + return object.__getattr__(self, attr) + return getattr(self.__origin__, attr) + + + class TypeAliasType: + """Create named, parameterized type aliases. + + This provides a backport of the new `type` statement in Python 3.12: + + type ListOrSet[T] = list[T] | set[T] + + is equivalent to: + + T = TypeVar("T") + ListOrSet = TypeAliasType("ListOrSet", list[T] | set[T], type_params=(T,)) + + The name ListOrSet can then be used as an alias for the type it refers to. + + The type_params argument should contain all the type parameters used + in the value of the type alias. If the alias is not generic, this + argument is omitted. + + Static type checkers should only support type aliases declared using + TypeAliasType that follow these rules: + + - The first argument (the name) must be a string literal. + - The TypeAliasType instance must be immediately assigned to a variable + of the same name. (For example, 'X = TypeAliasType("Y", int)' is invalid, + as is 'X, Y = TypeAliasType("X", int), TypeAliasType("Y", int)'). + + """ + + def __init__(self, name: str, value, *, type_params=()): + if not isinstance(name, str): + raise TypeError("TypeAliasType name must be a string") + if not isinstance(type_params, tuple): + raise TypeError("type_params must be a tuple") + self.__value__ = value + self.__type_params__ = type_params + + default_value_encountered = False + parameters = [] + for type_param in type_params: + if ( + not isinstance(type_param, (TypeVar, TypeVarTuple, ParamSpec)) + # <=3.11 + # Unpack Backport passes isinstance(type_param, TypeVar) + or _is_unpack(type_param) + ): + raise TypeError(f"Expected a type param, got {type_param!r}") + has_default = ( + getattr(type_param, '__default__', NoDefault) is not NoDefault + ) + if default_value_encountered and not has_default: + raise TypeError(f"non-default type parameter '{type_param!r}'" + " follows default type parameter") + if has_default: + default_value_encountered = True + if isinstance(type_param, TypeVarTuple): + parameters.extend(type_param) + else: + parameters.append(type_param) + self.__parameters__ = tuple(parameters) + def_mod = _caller() + if def_mod != 'typing_extensions': + self.__module__ = def_mod + # Setting this attribute closes the TypeAliasType from further modification + self.__name__ = name + + def __setattr__(self, name: str, value: object, /) -> None: + if hasattr(self, "__name__") and name != "__module__": + self._raise_attribute_error(name) + super().__setattr__(name, value) + + def __delattr__(self, name: str, /) -> Never: + self._raise_attribute_error(name) + + def _raise_attribute_error(self, name: str) -> Never: + # Match the Python 3.12 error messages exactly + if name == "__name__": + raise AttributeError("readonly attribute") + elif name in {"__value__", "__type_params__", "__parameters__"}: + raise AttributeError( + f"attribute '{name}' of 'typing.TypeAliasType' objects " + "is not writable" + ) + else: + raise AttributeError( + f"'typing.TypeAliasType' object has no attribute '{name}'" + ) + + def __repr__(self) -> str: + return self.__name__ + + if sys.version_info < (3, 11): + def _check_single_param(self, param, recursion=0): + # Allow [], [int], [int, str], [int, ...], [int, T] + if param is ...: + return ... + if param is None: + return None + # Note in <= 3.9 _ConcatenateGenericAlias inherits from list + if isinstance(param, list) and recursion == 0: + return [self._check_single_param(arg, recursion+1) + for arg in param] + return typing._type_check( + param, f'Subscripting {self.__name__} requires a type.' + ) + + def _check_parameters(self, parameters): + if sys.version_info < (3, 11): + return tuple( + self._check_single_param(item) + for item in parameters + ) + return tuple(typing._type_check( + item, f'Subscripting {self.__name__} requires a type.' + ) + for item in parameters + ) + + def __getitem__(self, parameters): + if not self.__type_params__: + raise TypeError("Only generic type aliases are subscriptable") + if not isinstance(parameters, tuple): + parameters = (parameters,) + # Using 3.9 here will create problems with Concatenate + if sys.version_info >= (3, 10): + return _types.GenericAlias(self, parameters) + type_vars = _collect_type_vars(parameters) + parameters = self._check_parameters(parameters) + alias = _TypeAliasGenericAlias(self, parameters) + # alias.__parameters__ is not complete if Concatenate is present + # as it is converted to a list from which no parameters are extracted. + if alias.__parameters__ != type_vars: + alias.__parameters__ = type_vars + return alias + + def __reduce__(self): + return self.__name__ + + def __init_subclass__(cls, *args, **kwargs): + raise TypeError( + "type 'typing_extensions.TypeAliasType' is not an acceptable base type" + ) + + # The presence of this method convinces typing._type_check + # that TypeAliasTypes are types. + def __call__(self): + raise TypeError("Type alias is not callable") + + # Breakpoint: https://github.com/python/cpython/pull/21515 + if sys.version_info >= (3, 10): + def __or__(self, right): + # For forward compatibility with 3.12, reject Unions + # that are not accepted by the built-in Union. + if not _is_unionable(right): + return NotImplemented + return typing.Union[self, right] + + def __ror__(self, left): + if not _is_unionable(left): + return NotImplemented + return typing.Union[left, self] + + +if hasattr(typing, "is_protocol"): + is_protocol = typing.is_protocol + get_protocol_members = typing.get_protocol_members +else: + def is_protocol(tp: type, /) -> bool: + """Return True if the given type is a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, is_protocol + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> is_protocol(P) + True + >>> is_protocol(int) + False + """ + return ( + isinstance(tp, type) + and getattr(tp, '_is_protocol', False) + and tp is not Protocol + and tp is not typing.Protocol + ) + + def get_protocol_members(tp: type, /) -> typing.FrozenSet[str]: + """Return the set of members defined in a Protocol. + + Example:: + + >>> from typing_extensions import Protocol, get_protocol_members + >>> class P(Protocol): + ... def a(self) -> str: ... + ... b: int + >>> get_protocol_members(P) == frozenset({'a', 'b'}) + True + + Raise a TypeError for arguments that are not Protocols. + """ + if not is_protocol(tp): + raise TypeError(f'{tp!r} is not a Protocol') + if hasattr(tp, '__protocol_attrs__'): + return frozenset(tp.__protocol_attrs__) + return frozenset(_get_protocol_attrs(tp)) + + +if hasattr(typing, "Doc"): + Doc = typing.Doc +else: + class Doc: + """Define the documentation of a type annotation using ``Annotated``, to be + used in class attributes, function and method parameters, return values, + and variables. + + The value should be a positional-only string literal to allow static tools + like editors and documentation generators to use it. + + This complements docstrings. + + The string value passed is available in the attribute ``documentation``. + + Example:: + + >>> from typing_extensions import Annotated, Doc + >>> def hi(to: Annotated[str, Doc("Who to say hi to")]) -> None: ... + """ + def __init__(self, documentation: str, /) -> None: + self.documentation = documentation + + def __repr__(self) -> str: + return f"Doc({self.documentation!r})" + + def __hash__(self) -> int: + return hash(self.documentation) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Doc): + return NotImplemented + return self.documentation == other.documentation + + +_CapsuleType = getattr(_types, "CapsuleType", None) + +if _CapsuleType is None: + try: + import _socket + except ImportError: + pass + else: + _CAPI = getattr(_socket, "CAPI", None) + if _CAPI is not None: + _CapsuleType = type(_CAPI) + +if _CapsuleType is not None: + CapsuleType = _CapsuleType + __all__.append("CapsuleType") + + +if sys.version_info >= (3, 14): + from annotationlib import Format, get_annotations +else: + # Available since Python 3.14.0a3 + # PR: https://github.com/python/cpython/pull/124415 + class Format(enum.IntEnum): + VALUE = 1 + VALUE_WITH_FAKE_GLOBALS = 2 + FORWARDREF = 3 + STRING = 4 + + # Available since Python 3.14.0a1 + # PR: https://github.com/python/cpython/pull/119891 + def get_annotations(obj, *, globals=None, locals=None, eval_str=False, + format=Format.VALUE): + """Compute the annotations dict for an object. + + obj may be a callable, class, or module. + Passing in an object of any other type raises TypeError. + + Returns a dict. get_annotations() returns a new dict every time + it's called; calling it twice on the same object will return two + different but equivalent dicts. + + This is a backport of `inspect.get_annotations`, which has been + in the standard library since Python 3.10. See the standard library + documentation for more: + + https://docs.python.org/3/library/inspect.html#inspect.get_annotations + + This backport adds the *format* argument introduced by PEP 649. The + three formats supported are: + * VALUE: the annotations are returned as-is. This is the default and + it is compatible with the behavior on previous Python versions. + * FORWARDREF: return annotations as-is if possible, but replace any + undefined names with ForwardRef objects. The implementation proposed by + PEP 649 relies on language changes that cannot be backported; the + typing-extensions implementation simply returns the same result as VALUE. + * STRING: return annotations as strings, in a format close to the original + source. Again, this behavior cannot be replicated directly in a backport. + As an approximation, typing-extensions retrieves the annotations under + VALUE semantics and then stringifies them. + + The purpose of this backport is to allow users who would like to use + FORWARDREF or STRING semantics once PEP 649 is implemented, but who also + want to support earlier Python versions, to simply write: + + typing_extensions.get_annotations(obj, format=Format.FORWARDREF) + + """ + format = Format(format) + if format is Format.VALUE_WITH_FAKE_GLOBALS: + raise ValueError( + "The VALUE_WITH_FAKE_GLOBALS format is for internal use only" + ) + + if eval_str and format is not Format.VALUE: + raise ValueError("eval_str=True is only supported with format=Format.VALUE") + + if isinstance(obj, type): + # class + obj_dict = getattr(obj, '__dict__', None) + if obj_dict and hasattr(obj_dict, 'get'): + ann = obj_dict.get('__annotations__', None) + if isinstance(ann, _types.GetSetDescriptorType): + ann = None + else: + ann = None + + obj_globals = None + module_name = getattr(obj, '__module__', None) + if module_name: + module = sys.modules.get(module_name, None) + if module: + obj_globals = getattr(module, '__dict__', None) + obj_locals = dict(vars(obj)) + unwrap = obj + elif isinstance(obj, _types.ModuleType): + # module + ann = getattr(obj, '__annotations__', None) + obj_globals = obj.__dict__ + obj_locals = None + unwrap = None + elif callable(obj): + # this includes types.Function, types.BuiltinFunctionType, + # types.BuiltinMethodType, functools.partial, functools.singledispatch, + # "class funclike" from Lib/test/test_inspect... on and on it goes. + ann = getattr(obj, '__annotations__', None) + obj_globals = getattr(obj, '__globals__', None) + obj_locals = None + unwrap = obj + elif hasattr(obj, '__annotations__'): + ann = obj.__annotations__ + obj_globals = obj_locals = unwrap = None + else: + raise TypeError(f"{obj!r} is not a module, class, or callable.") + + if ann is None: + return {} + + if not isinstance(ann, dict): + raise ValueError(f"{obj!r}.__annotations__ is neither a dict nor None") + + if not ann: + return {} + + if not eval_str: + if format is Format.STRING: + return { + key: value if isinstance(value, str) else typing._type_repr(value) + for key, value in ann.items() + } + return dict(ann) + + if unwrap is not None: + while True: + if hasattr(unwrap, '__wrapped__'): + unwrap = unwrap.__wrapped__ + continue + if isinstance(unwrap, functools.partial): + unwrap = unwrap.func + continue + break + if hasattr(unwrap, "__globals__"): + obj_globals = unwrap.__globals__ + + if globals is None: + globals = obj_globals + if locals is None: + locals = obj_locals or {} + + # "Inject" type parameters into the local namespace + # (unless they are shadowed by assignments *in* the local namespace), + # as a way of emulating annotation scopes when calling `eval()` + if type_params := getattr(obj, "__type_params__", ()): + locals = {param.__name__: param for param in type_params} | locals + + return_value = {key: + value if not isinstance(value, str) else eval(value, globals, locals) + for key, value in ann.items() } + return return_value + + +if hasattr(typing, "evaluate_forward_ref"): + evaluate_forward_ref = typing.evaluate_forward_ref +else: + # Implements annotationlib.ForwardRef.evaluate + def _eval_with_owner( + forward_ref, *, owner=None, globals=None, locals=None, type_params=None + ): + if forward_ref.__forward_evaluated__: + return forward_ref.__forward_value__ + if getattr(forward_ref, "__cell__", None) is not None: + try: + value = forward_ref.__cell__.cell_contents + except ValueError: + pass + else: + forward_ref.__forward_evaluated__ = True + forward_ref.__forward_value__ = value + return value + if owner is None: + owner = getattr(forward_ref, "__owner__", None) + + if ( + globals is None + and getattr(forward_ref, "__forward_module__", None) is not None + ): + globals = getattr( + sys.modules.get(forward_ref.__forward_module__, None), "__dict__", None + ) + if globals is None: + globals = getattr(forward_ref, "__globals__", None) + if globals is None: + if isinstance(owner, type): + module_name = getattr(owner, "__module__", None) + if module_name: + module = sys.modules.get(module_name, None) + if module: + globals = getattr(module, "__dict__", None) + elif isinstance(owner, _types.ModuleType): + globals = getattr(owner, "__dict__", None) + elif callable(owner): + globals = getattr(owner, "__globals__", None) + + # If we pass None to eval() below, the globals of this module are used. + if globals is None: + globals = {} + + if locals is None: + locals = {} + if isinstance(owner, type): + locals.update(vars(owner)) + + if type_params is None and owner is not None: + # "Inject" type parameters into the local namespace + # (unless they are shadowed by assignments *in* the local namespace), + # as a way of emulating annotation scopes when calling `eval()` + type_params = getattr(owner, "__type_params__", None) + + # Type parameters exist in their own scope, which is logically + # between the locals and the globals. We simulate this by adding + # them to the globals. + if type_params is not None: + globals = dict(globals) + for param in type_params: + globals[param.__name__] = param + + arg = forward_ref.__forward_arg__ + if arg.isidentifier() and not keyword.iskeyword(arg): + if arg in locals: + value = locals[arg] + elif arg in globals: + value = globals[arg] + elif hasattr(builtins, arg): + return getattr(builtins, arg) + else: + raise NameError(arg) + else: + code = forward_ref.__forward_code__ + value = eval(code, globals, locals) + forward_ref.__forward_evaluated__ = True + forward_ref.__forward_value__ = value + return value + + def evaluate_forward_ref( + forward_ref, + *, + owner=None, + globals=None, + locals=None, + type_params=None, + format=None, + _recursive_guard=frozenset(), + ): + """Evaluate a forward reference as a type hint. + + This is similar to calling the ForwardRef.evaluate() method, + but unlike that method, evaluate_forward_ref() also: + + * Recursively evaluates forward references nested within the type hint. + * Rejects certain objects that are not valid type hints. + * Replaces type hints that evaluate to None with types.NoneType. + * Supports the *FORWARDREF* and *STRING* formats. + + *forward_ref* must be an instance of ForwardRef. *owner*, if given, + should be the object that holds the annotations that the forward reference + derived from, such as a module, class object, or function. It is used to + infer the namespaces to use for looking up names. *globals* and *locals* + can also be explicitly given to provide the global and local namespaces. + *type_params* is a tuple of type parameters that are in scope when + evaluating the forward reference. This parameter must be provided (though + it may be an empty tuple) if *owner* is not given and the forward reference + does not already have an owner set. *format* specifies the format of the + annotation and is a member of the annotationlib.Format enum. + + """ + if format == Format.STRING: + return forward_ref.__forward_arg__ + if forward_ref.__forward_arg__ in _recursive_guard: + return forward_ref + + # Evaluate the forward reference + try: + value = _eval_with_owner( + forward_ref, + owner=owner, + globals=globals, + locals=locals, + type_params=type_params, + ) + except NameError: + if format == Format.FORWARDREF: + return forward_ref + else: + raise + + if isinstance(value, str): + value = ForwardRef(value) + + # Recursively evaluate the type + if isinstance(value, ForwardRef): + if getattr(value, "__forward_module__", True) is not None: + globals = None + return evaluate_forward_ref( + value, + globals=globals, + locals=locals, + type_params=type_params, owner=owner, + _recursive_guard=_recursive_guard, format=format + ) + if sys.version_info < (3, 12, 5) and type_params: + # Make use of type_params + locals = dict(locals) if locals else {} + for tvar in type_params: + if tvar.__name__ not in locals: # lets not overwrite something present + locals[tvar.__name__] = tvar + if sys.version_info < (3, 12, 5): + return typing._eval_type( + value, + globals, + locals, + recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, + ) + else: + return typing._eval_type( + value, + globals, + locals, + type_params, + recursive_guard=_recursive_guard | {forward_ref.__forward_arg__}, + ) + + +if sys.version_info >= (3, 14, 0, "beta"): + type_repr = annotationlib.type_repr +else: + def type_repr(value): + """Convert a Python value to a format suitable for use with the STRING format. + + This is intended as a helper for tools that support the STRING format but do + not have access to the code that originally produced the annotations. It uses + repr() for most objects. + + """ + if isinstance(value, (type, _types.FunctionType, _types.BuiltinFunctionType)): + if value.__module__ == "builtins": + return value.__qualname__ + return f"{value.__module__}.{value.__qualname__}" + if value is ...: + return "..." + return repr(value) + + +# Aliases for items that are in typing in all supported versions. +# We use hasattr() checks so this library will continue to import on +# future versions of Python that may remove these names. +_typing_names = [ + "AbstractSet", + "AnyStr", + "BinaryIO", + "Callable", + "Collection", + "Container", + "Dict", + "FrozenSet", + "Hashable", + "IO", + "ItemsView", + "Iterable", + "Iterator", + "KeysView", + "List", + "Mapping", + "MappingView", + "Match", + "MutableMapping", + "MutableSequence", + "MutableSet", + "Optional", + "Pattern", + "Reversible", + "Sequence", + "Set", + "Sized", + "TextIO", + "Tuple", + "Union", + "ValuesView", + "cast", + "no_type_check", + # This is private, but it was defined by typing_extensions for a long time + # and some users rely on it. + "_AnnotatedAlias", +] + +# Breakpoint: https://github.com/python/cpython/pull/133602 +if sys.version_info < (3, 15, 0): + _typing_names.append("no_type_check_decorator") + __all__.append("no_type_check_decorator") + +globals().update( + {name: getattr(typing, name) for name in _typing_names if hasattr(typing, name)} +) +# These are defined unconditionally because they are used in +# typing-extensions itself. +Generic = typing.Generic +ForwardRef = typing.ForwardRef +Annotated = typing.Annotated diff --git a/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/METADATA b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/METADATA new file mode 100644 index 0000000..886db47 --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/METADATA @@ -0,0 +1,49 @@ +Metadata-Version: 2.5 +Name: typing-inspection +Version: 0.4.4 +Summary: Runtime typing introspection tools +Project-URL: Homepage, https://github.com/pydantic/typing-inspection +Project-URL: Documentation, https://pydantic.github.io/typing-inspection/dev/ +Project-URL: Source, https://github.com/pydantic/typing-inspection +Project-URL: Changelog, https://github.com/pydantic/typing-inspection/blob/main/HISTORY.md +Author-email: Victorien Plot +License-Expression: MIT +License-File: LICENSE +Classifier: Development Status :: 3 - Alpha +Classifier: Intended Audience :: Developers +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: 3.15 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Typing :: Typed +Requires-Python: >=3.10 +Requires-Dist: typing-extensions>=4.15.0 +Description-Content-Type: text/markdown + +# typing-inspection + +[![CI](https://img.shields.io/github/actions/workflow/status/pydantic/typing-inspection/ci.yml?branch=main&logo=github&label=CI)](https://github.com/pydantic/typing-inspection/actions?query=event%3Apush+branch%3Amain+workflow%3ACI) +[![Coverage](https://coverage-badge.samuelcolvin.workers.dev/pydantic/typing-inspection.svg)](https://coverage-badge.samuelcolvin.workers.dev/redirect/pydantic/typing-inspection) +[![PyPI](https://img.shields.io/pypi/v/typing-inspection.svg)](https://pypi.org/project/typing-inspection/) +[![Versions](https://img.shields.io/pypi/pyversions/typing-inspection.svg)](https://github.com/pydantic/typing-inspection) +[![License](https://img.shields.io/github/license/pydantic/typing-inspection.svg)](https://github.com/pydantic/typing-inspection/blob/main/LICENSE) +[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) + +`typing-inspection` provides tools to inspect type annotations at runtime. + +## Installation + +From [PyPI](https://pypi.org/project/typing-inspection/): + +```bash +pip install typing-inspection +``` + +The library can be imported from the `typing_inspection` module. diff --git a/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/RECORD b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/RECORD new file mode 100644 index 0000000..cd59891 --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/RECORD @@ -0,0 +1,9 @@ +typing_inspection/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +typing_inspection/introspection.py,sha256=WIjEW9Yn2mktlSdpnj9Umt81ZRWWsWVncjEOEhgbQ5Y,22550 +typing_inspection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +typing_inspection/typing_objects.py,sha256=p3jWKQ1RWBycmiPgJjrypGBMdt71xNQKfNGjdbAEb_Y,17838 +typing_inspection/typing_objects.pyi,sha256=O9JN2S0CcNMdZP1Aq8HvhpP1Miqrmnius8W2L5kvhL4,9635 +typing_inspection-0.4.4.dist-info/METADATA,sha256=utPZ5jQu9nUM9RKOyUIye4vr3OC25Nb2fLFbJ65RGNo,2554 +typing_inspection-0.4.4.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87 +typing_inspection-0.4.4.dist-info/licenses/LICENSE,sha256=gEtZsl8sMb0nj5ICoZrkmjlFqiZkOH4tChKMfKzGHsM,1090 +typing_inspection-0.4.4.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/WHEEL b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/WHEEL new file mode 100644 index 0000000..51abe1f --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.32.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/licenses/LICENSE b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/licenses/LICENSE new file mode 100644 index 0000000..e825ad5 --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection-0.4.4.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Pydantic Services Inc. 2025 to present + +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/source/target-vendors/cp312/typing_inspection/__init__.py b/source/target-vendors/cp312/typing_inspection/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/typing_inspection/introspection.py b/source/target-vendors/cp312/typing_inspection/introspection.py new file mode 100644 index 0000000..458c4ee --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection/introspection.py @@ -0,0 +1,587 @@ +"""High-level introspection utilities, used to inspect type annotations.""" + +from __future__ import annotations + +import sys +import types +from collections.abc import Generator +from dataclasses import InitVar +from enum import Enum, IntEnum, auto +from typing import Any, Literal, NamedTuple, TypeAlias, cast + +from typing_extensions import assert_never, get_args, get_origin # noqa: UP035 + +from . import typing_objects + +__all__ = ( + 'AnnotationSource', + 'ForbiddenQualifier', + 'InspectedAnnotation', + 'Qualifier', + 'get_literal_values', + 'inspect_annotation', + 'is_union_origin', +) + +if sys.version_info >= (3, 14): + + def is_union_origin(obj: Any, /) -> bool: + """Return whether the provided origin is the union form. + + ```pycon + >>> is_union_origin(typing.Union) + True + >>> is_union_origin(get_origin(int | str)) + True + >>> is_union_origin(types.UnionType) + True + ``` + + !!! note + Since Python 3.14, both `Union[, , ...]` and ` | | ...` forms create instances + of the same [`typing.Union`][] class. As such, it is recommended to not use this function + anymore (provided that you only support Python 3.14 or greater), and instead use the + [`typing_objects.is_union()`][typing_inspection.typing_objects.is_union] function directly: + + ```python + from typing import Union, get_origin + + from typing_inspection import typing_objects + + typ = int | str # Or Union[int, str] + origin = get_origin(typ) + if typing_objects.is_union(origin): + ... + ``` + """ + return typing_objects.is_union(obj) + + +else: + + def is_union_origin(obj: Any, /) -> bool: + """Return whether the provided origin is the union form. + + ```pycon + >>> is_union_origin(typing.Union) + True + >>> is_union_origin(get_origin(int | str)) + True + >>> is_union_origin(types.UnionType) + True + ``` + + !!! note + Since Python 3.14, both `Union[, , ...]` and ` | | ...` forms create instances + of the same [`typing.Union`][] class. As such, it is recommended to not use this function + anymore (provided that you only support Python 3.14 or greater), and instead use the + [`typing_objects.is_union()`][typing_inspection.typing_objects.is_union] function directly: + + ```python + from typing import Union, get_origin + + from typing_inspection import typing_objects + + typ = int | str # Or Union[int, str] + origin = get_origin(typ) + if typing_objects.is_union(origin): + ... + ``` + """ + return typing_objects.is_union(obj) or obj is types.UnionType + + +_literal_allowed_types = int | bytes | str | bool | Enum | typing_objects.NoneType + + +def _literal_type_check(value: Any, /) -> None: + """Type check the provided literal value against the legal parameters.""" + if not isinstance(value, _literal_allowed_types) and value is not typing_objects.NoneType: + raise TypeError(f'{value} is not a valid literal value, must be one of: int, bytes, str, Enum, None.') + + +def get_literal_values( + annotation: Any, + /, + *, + type_check: bool = False, + unpack_type_aliases: Literal['skip', 'lenient', 'eager'] = 'eager', +) -> Generator[Any]: + """Yield the values contained in the provided [`Literal`][typing.Literal] [special form][]. + + Args: + annotation: The [`Literal`][typing.Literal] [special form][] to unpack. + type_check: Whether to check if the literal values are [legal parameters][literal-legal-parameters]. + Raises a [`TypeError`][] otherwise. + unpack_type_aliases: What to do when encountering [PEP 695](https://peps.python.org/pep-0695/) + [type aliases][type-aliases]. Can be one of: + + - `'skip'`: Do not try to parse type aliases. Note that this can lead to incorrect results: + ```pycon + >>> type MyAlias = Literal[1, 2] + >>> list(get_literal_values(Literal[MyAlias, 3], unpack_type_aliases="skip")) + [MyAlias, 3] + ``` + + - `'lenient'`: Try to parse type aliases, and fallback to `'skip'` if the type alias can't be inspected + (because of an undefined forward reference). + + - `'eager'`: Parse type aliases and raise any encountered [`NameError`][] exceptions (the default): + ```pycon + >>> type MyAlias = Literal[1, 2] + >>> list(get_literal_values(Literal[MyAlias, 3], unpack_type_aliases="eager")) + [1, 2, 3] + ``` + + Note: + While `None` is [equivalent to][none] `type(None)`, the runtime implementation of [`Literal`][typing.Literal] + does not de-duplicate them. This function makes sure this de-duplication is applied: + + ```pycon + >>> list(get_literal_values(Literal[NoneType, None])) + [None] + ``` + + Example: + ```pycon + >>> type Ints = Literal[1, 2] + >>> list(get_literal_values(Literal[1, Ints], unpack_type_alias="skip")) + ["a", Ints] + >>> list(get_literal_values(Literal[1, Ints])) + [1, 2] + >>> list(get_literal_values(Literal[1.0], type_check=True)) + Traceback (most recent call last): + ... + TypeError: 1.0 is not a valid literal value, must be one of: int, bytes, str, Enum, None. + ``` + """ + # `literal` is guaranteed to be a `Literal[...]` special form, so use + # `__args__` directly instead of calling `get_args()`. + + if unpack_type_aliases == 'skip': + _has_none = False + # `Literal` parameters are already deduplicated, no need to do it ourselves. + # (we only check for `None` and `NoneType`, which should be considered as duplicates). + for arg in annotation.__args__: + if type_check: + _literal_type_check(arg) + if arg is None or arg is typing_objects.NoneType: + if not _has_none: + yield None + _has_none = True + else: + yield arg + else: + # We'll need to manually deduplicate parameters, see the `Literal` implementation in `typing`. + values_and_type: list[tuple[Any, type[Any]]] = [] + + for arg in annotation.__args__: + # Note: we could also check for generic aliases with a type alias as an origin. + # However, it is very unlikely that this happens as type variables can't appear in + # `Literal` forms, so the only valid (but unnecessary) use case would be something like: + # `type Test[T] = Literal['a']` (and then use `Test[SomeType]`). + if typing_objects.is_typealiastype(arg): + try: + alias_value = arg.__value__ + except NameError: + if unpack_type_aliases == 'eager': + raise + # unpack_type_aliases == "lenient": + if type_check: + _literal_type_check(arg) + values_and_type.append((arg, type(arg))) + else: + sub_args = get_literal_values( + alias_value, type_check=type_check, unpack_type_aliases=unpack_type_aliases + ) + values_and_type.extend((a, type(a)) for a in sub_args) # pyright: ignore[reportUnknownArgumentType] + else: + if type_check: + _literal_type_check(arg) + if arg is typing_objects.NoneType: + values_and_type.append((None, typing_objects.NoneType)) + else: + values_and_type.append((arg, type(arg))) # pyright: ignore[reportUnknownArgumentType] + + try: + dct = dict.fromkeys(values_and_type) + except TypeError: + # Unhashable parameters, the Python implementation allows them + yield from (p for p, _ in values_and_type) + else: + yield from (p for p, _ in dct) + + +Qualifier: TypeAlias = Literal['required', 'not_required', 'read_only', 'class_var', 'init_var', 'final'] +"""A [type qualifier][].""" + +_all_qualifiers: set[Qualifier] = set(get_args(Qualifier)) + + +# TODO at some point, we could switch to an enum flag, so that multiple sources +# can be combined. However, is there a need for this? +class AnnotationSource(IntEnum): + # TODO if/when https://peps.python.org/pep-0767/ is accepted, add 'read_only' + # to CLASS and NAMED_TUPLE (even though for named tuples it is redundant). + + """The source of an annotation, e.g. a class or a function. + + Depending on the source, different [type qualifiers][type qualifier] may be (dis)allowed. + """ + + ASSIGNMENT_OR_VARIABLE = auto() + """An annotation used in an assignment or variable annotation: + + ```python + x: Final[int] = 1 + y: Final[str] + ``` + + **Allowed type qualifiers:** [`Final`][typing.Final]. + """ + + CLASS = auto() + """An annotation used in the body of a class: + + ```python + class Test: + x: Final[int] = 1 + y: ClassVar[str] + ``` + + **Allowed type qualifiers:** [`ClassVar`][typing.ClassVar], [`Final`][typing.Final]. + """ + + DATACLASS = auto() + """An annotation used in the body of a dataclass: + + ```python + @dataclass + class Test: + x: Final[int] = 1 + y: InitVar[str] = 'test' + ``` + + **Allowed type qualifiers:** [`ClassVar`][typing.ClassVar], [`Final`][typing.Final], [`InitVar`][dataclasses.InitVar]. + """ # noqa: E501 + + TYPED_DICT = auto() + """An annotation used in the body of a [`TypedDict`][typing.TypedDict]: + + ```python + class TD(TypedDict): + x: Required[ReadOnly[int]] + y: ReadOnly[NotRequired[str]] + ``` + + **Allowed type qualifiers:** [`ReadOnly`][typing.ReadOnly], [`Required`][typing.Required], + [`NotRequired`][typing.NotRequired]. + """ + + NAMED_TUPLE = auto() + """An annotation used in the body of a [`NamedTuple`][typing.NamedTuple]. + + ```python + class NT(NamedTuple): + x: int + y: str + ``` + + **Allowed type qualifiers:** none. + """ + + FUNCTION = auto() + """An annotation used in a function, either for a parameter or the return value. + + ```python + def func(a: int) -> str: + ... + ``` + + **Allowed type qualifiers:** none. + """ + + ANY = auto() + """An annotation that might come from any source. + + **Allowed type qualifiers:** all. + """ + + BARE = auto() + """An annotation that is inspected as is. + + **Allowed type qualifiers:** none. + """ + + @property + def allowed_qualifiers(self) -> set[Qualifier]: + """The allowed [type qualifiers][type qualifier] for this annotation source.""" + # TODO use a match statement when Python 3.9 support is dropped. + if self is AnnotationSource.ASSIGNMENT_OR_VARIABLE: + return {'final'} + elif self is AnnotationSource.CLASS: + return {'final', 'class_var'} + elif self is AnnotationSource.DATACLASS: + return {'final', 'class_var', 'init_var'} + elif self is AnnotationSource.TYPED_DICT: + return {'required', 'not_required', 'read_only'} + elif self in (AnnotationSource.NAMED_TUPLE, AnnotationSource.FUNCTION, AnnotationSource.BARE): + return set() + elif self is AnnotationSource.ANY: + return _all_qualifiers + else: # pragma: no cover + assert_never(self) + + +class ForbiddenQualifier(Exception): + """The provided [type qualifier][] is forbidden.""" + + qualifier: Qualifier + """The forbidden qualifier.""" + + def __init__(self, qualifier: Qualifier, /) -> None: + self.qualifier = qualifier + + +class _UnknownTypeEnum(Enum): + UNKNOWN = auto() + + def __str__(self) -> str: + return 'UNKNOWN' + + def __repr__(self) -> str: + return '' + + +UNKNOWN = _UnknownTypeEnum.UNKNOWN +"""A sentinel value used when no [type expression][] is present.""" + +_UnknownType: TypeAlias = Literal[_UnknownTypeEnum.UNKNOWN] +"""The type of the [`UNKNOWN`][typing_inspection.introspection.UNKNOWN] sentinel value.""" + + +class InspectedAnnotation(NamedTuple): + """The result of the inspected annotation.""" + + type: Any | _UnknownType + """The final [type expression][], with [type qualifiers][type qualifier] and annotated metadata stripped. + + If no type expression is available, the [`UNKNOWN`][typing_inspection.introspection.UNKNOWN] sentinel + value is used instead. This is the case when a [type qualifier][] is used with no type annotation: + + ```python + ID: Final = 1 + + class C: + x: ClassVar = 'test' + ``` + """ + + qualifiers: set[Qualifier] + """The [type qualifiers][type qualifier] present on the annotation.""" + + metadata: list[Any] + """The annotated metadata.""" + + +def inspect_annotation( # noqa: PLR0915 + annotation: Any, + /, + *, + annotation_source: AnnotationSource, + unpack_type_aliases: Literal['skip', 'lenient', 'eager'] = 'skip', +) -> InspectedAnnotation: + """Inspect an [annotation expression][], extracting any [type qualifier][] and metadata. + + An [annotation expression][] is a [type expression][] optionally surrounded by one or more + [type qualifiers][type qualifier] or by [`Annotated`][typing.Annotated]. This function will: + + - Unwrap the type expression, keeping track of the type qualifiers. + - Unwrap [`Annotated`][typing.Annotated] forms, keeping track of the annotated metadata. + + Args: + annotation: The annotation expression to be inspected. + annotation_source: The source of the annotation. Depending on the source (e.g. a class), different type + qualifiers may be (dis)allowed. To allow any type qualifier, use + [`AnnotationSource.ANY`][typing_inspection.introspection.AnnotationSource.ANY]. + unpack_type_aliases: What to do when encountering [PEP 695](https://peps.python.org/pep-0695/) + [type aliases][type-aliases]. Can be one of: + + - `'skip'`: Do not try to parse type aliases (the default): + ```pycon + >>> type MyInt = Annotated[int, 'meta'] + >>> inspect_annotation(MyInt, annotation_source=AnnotationSource.BARE, unpack_type_aliases='skip') + InspectedAnnotation(type=MyInt, qualifiers={}, metadata=[]) + ``` + + - `'lenient'`: Try to parse type aliases, and fallback to `'skip'` if the type alias + can't be inspected (because of an undefined forward reference): + ```pycon + >>> type MyInt = Annotated[Undefined, 'meta'] + >>> inspect_annotation(MyInt, annotation_source=AnnotationSource.BARE, unpack_type_aliases='lenient') + InspectedAnnotation(type=MyInt, qualifiers={}, metadata=[]) + >>> Undefined = int + >>> inspect_annotation(MyInt, annotation_source=AnnotationSource.BARE, unpack_type_aliases='lenient') + InspectedAnnotation(type=int, qualifiers={}, metadata=['meta']) + ``` + + - `'eager'`: Parse type aliases and raise any encountered [`NameError`][] exceptions. + + Returns: + The result of the inspected annotation, where the type expression, used qualifiers and metadata is stored. + + Example: + ```pycon + >>> inspect_annotation( + ... Final[Annotated[ClassVar[Annotated[int, 'meta_1']], 'meta_2']], + ... annotation_source=AnnotationSource.CLASS, + ... ) + ... + InspectedAnnotation(type=int, qualifiers={'class_var', 'final'}, metadata=['meta_1', 'meta_2']) + ``` + """ + allowed_qualifiers = annotation_source.allowed_qualifiers + qualifiers: set[Qualifier] = set() + metadata: list[Any] = [] + + while True: + annotation, _meta = _unpack_annotated(annotation, unpack_type_aliases=unpack_type_aliases) + if _meta: + metadata = _meta + metadata + continue + + origin = get_origin(annotation) + if origin is not None: + if typing_objects.is_classvar(origin): + if 'class_var' not in allowed_qualifiers: + raise ForbiddenQualifier('class_var') + qualifiers.add('class_var') + annotation = annotation.__args__[0] + elif typing_objects.is_final(origin): + if 'final' not in allowed_qualifiers: + raise ForbiddenQualifier('final') + qualifiers.add('final') + annotation = annotation.__args__[0] + elif typing_objects.is_required(origin): + if 'required' not in allowed_qualifiers: + raise ForbiddenQualifier('required') + qualifiers.add('required') + annotation = annotation.__args__[0] + elif typing_objects.is_notrequired(origin): + if 'not_required' not in allowed_qualifiers: + raise ForbiddenQualifier('not_required') + qualifiers.add('not_required') + annotation = annotation.__args__[0] + elif typing_objects.is_readonly(origin): + if 'read_only' not in allowed_qualifiers: + raise ForbiddenQualifier('not_required') + qualifiers.add('read_only') + annotation = annotation.__args__[0] + else: + # origin is not None but not a type qualifier nor `Annotated` (e.g. `list[int]`): + break + elif isinstance(annotation, InitVar): + if 'init_var' not in allowed_qualifiers: + raise ForbiddenQualifier('init_var') + qualifiers.add('init_var') + annotation = cast(Any, annotation.type) + else: + break + + # `Final`, `ClassVar` and `InitVar` are type qualifiers allowed to be used as a bare annotation: + if typing_objects.is_final(annotation): + if 'final' not in allowed_qualifiers: + raise ForbiddenQualifier('final') + qualifiers.add('final') + annotation = UNKNOWN + elif typing_objects.is_classvar(annotation): + if 'class_var' not in allowed_qualifiers: + raise ForbiddenQualifier('class_var') + qualifiers.add('class_var') + annotation = UNKNOWN + elif annotation is InitVar: + if 'init_var' not in allowed_qualifiers: + raise ForbiddenQualifier('init_var') + qualifiers.add('init_var') + annotation = UNKNOWN + + return InspectedAnnotation(annotation, qualifiers, metadata) + + +def _unpack_annotated_inner( + annotation: Any, unpack_type_aliases: Literal['lenient', 'eager'], check_annotated: bool +) -> tuple[Any, list[Any]]: + origin = get_origin(annotation) + if check_annotated and typing_objects.is_annotated(origin): + annotated_type = annotation.__origin__ + metadata = list(annotation.__metadata__) + + # The annotated type might be a PEP 695 type alias, so we need to recursively + # unpack it. Because Python already flattens `Annotated[Annotated[, ...], ...]` forms, + # we can skip the `is_annotated()` check in the next call: + annotated_type, sub_meta = _unpack_annotated_inner( + annotated_type, unpack_type_aliases=unpack_type_aliases, check_annotated=False + ) + metadata = sub_meta + metadata + return annotated_type, metadata + elif typing_objects.is_typealiastype(annotation): + try: + value = annotation.__value__ + except NameError: + if unpack_type_aliases == 'eager': + raise + else: + typ, metadata = _unpack_annotated_inner( + value, unpack_type_aliases=unpack_type_aliases, check_annotated=True + ) + if metadata: + # Having metadata means the type alias' `__value__` was an `Annotated` form + # (or, recursively, a type alias to an `Annotated` form). It is important to check + # for this, as we don't want to unpack other type aliases (e.g. `type MyInt = int`). + return typ, metadata + return annotation, [] + elif typing_objects.is_typealiastype(origin): + # When parameterized, PEP 695 type aliases become generic aliases + # (e.g. with `type MyList[T] = Annotated[list[T], ...]`, `MyList[int]` + # is a generic alias). + try: + value = origin.__value__ + except NameError: + if unpack_type_aliases == 'eager': + raise + else: + # While Python already handles type variable replacement for simple `Annotated` forms, + # we need to manually apply the same logic for PEP 695 type aliases: + # - With `MyList = Annotated[list[T], ...]`, `MyList[int] == Annotated[list[int], ...]` + # - With `type MyList[T] = Annotated[list[T], ...]`, `MyList[int].__value__ == Annotated[list[T], ...]`. + + try: + # To do so, we emulate the parameterization of the value with the arguments: + # with `type MyList[T] = Annotated[list[T], ...]`, to emulate `MyList[int]`, + # we do `Annotated[list[T], ...][int]` (which gives `Annotated[list[T], ...]`): + value = value[annotation.__args__] + except TypeError: + # Might happen if the type alias is parameterized, but its value doesn't have any + # type variables, e.g. `type MyInt[T] = int`. + pass + typ, metadata = _unpack_annotated_inner( + value, unpack_type_aliases=unpack_type_aliases, check_annotated=True + ) + if metadata: + return typ, metadata + return annotation, [] + + return annotation, [] + + +# This could eventually be made public: +def _unpack_annotated( + annotation: Any, /, *, unpack_type_aliases: Literal['skip', 'lenient', 'eager'] = 'eager' +) -> tuple[Any, list[Any]]: + if unpack_type_aliases == 'skip': + if typing_objects.is_annotated(get_origin(annotation)): + return annotation.__origin__, list(annotation.__metadata__) + else: + return annotation, [] + + return _unpack_annotated_inner(annotation, unpack_type_aliases=unpack_type_aliases, check_annotated=True) diff --git a/source/target-vendors/cp312/typing_inspection/py.typed b/source/target-vendors/cp312/typing_inspection/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/typing_inspection/typing_objects.py b/source/target-vendors/cp312/typing_inspection/typing_objects.py new file mode 100644 index 0000000..610f592 --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection/typing_objects.py @@ -0,0 +1,620 @@ +"""Low-level introspection utilities for [`typing`][] members. + +The provided functions in this module check against both the [`typing`][] and [`typing_extensions`][] +variants, if they exists and are different. +""" +# ruff: noqa: UP006 + +import collections.abc +import contextlib +import re +import sys +import typing +import warnings +from textwrap import dedent +from types import FunctionType, GenericAlias, NoneType +from typing import Any, Final + +import typing_extensions +from typing_extensions import LiteralString, TypeAliasType, TypeIs, deprecated + +__all__ = ( + 'DEPRECATED_ALIASES', + 'DEPRECATED_ALIASES_IDS', + 'NoneType', + 'is_annotated', + 'is_any', + 'is_classvar', + 'is_concatenate', + 'is_deprecated', + 'is_final', + 'is_forwardref', + 'is_generic', + 'is_literal', + 'is_literalstring', + 'is_namedtuple', + 'is_never', + 'is_newtype', + 'is_nodefault', + 'is_noextraitems', + 'is_noreturn', + 'is_notrequired', + 'is_paramspec', + 'is_paramspecargs', + 'is_paramspeckwargs', + 'is_readonly', + 'is_required', + 'is_self', + 'is_typealias', + 'is_typealiastype', + 'is_typeguard', + 'is_typeis', + 'is_typevar', + 'is_typevartuple', + 'is_union', + 'is_unpack', +) + +_IS_PY310 = sys.version_info[:2] == (3, 10) + + +def _compile_identity_check_function(member: LiteralString, function_name: LiteralString) -> FunctionType: + """Create a function checking that the function argument is the (unparameterized) typing `member`. + + The function will make sure to check against both the `typing` and `typing_extensions` + variants as depending on the Python version, the `typing_extensions` variant might be different. + For instance, on Python 3.9: + + ```pycon + >>> from typing import Literal as t_Literal + >>> from typing_extensions import Literal as te_Literal, get_origin + + >>> t_Literal is te_Literal + False + >>> get_origin(t_Literal[1]) + typing.Literal + >>> get_origin(te_Literal[1]) + typing_extensions.Literal + ``` + """ + in_typing = hasattr(typing, member) + in_typing_extensions = hasattr(typing_extensions, member) + + globals_: dict[str, Any] = {'Any': Any} + + if in_typing and in_typing_extensions: + # For performance reasons, cache the objects in `globals_` so the generated function avoids + # repeated module attribute lookups (and `typing`'s module-level `__getattr__()`): + t_obj = getattr(typing, member) + te_obj = getattr(typing_extensions, member) + if t_obj is te_obj: + globals_['_obj'] = t_obj + check_code = 'obj is _obj' + else: + globals_['_t_obj'] = t_obj + globals_['_te_obj'] = te_obj + check_code = 'obj is _t_obj or obj is _te_obj' + elif in_typing and not in_typing_extensions: + globals_['_obj'] = getattr(typing, member) + check_code = 'obj is _obj' + elif not in_typing and in_typing_extensions: + globals_['_obj'] = getattr(typing_extensions, member) + check_code = 'obj is _obj' + else: + check_code = 'False' + + func_code = dedent(f""" + def {function_name}(obj: Any, /) -> bool: + return {check_code} + """) + + locals_: dict[str, Any] = {} + exec(func_code, globals_, locals_) + return locals_[function_name] + + +def _compile_isinstance_check_function(member: LiteralString, function_name: LiteralString) -> FunctionType: + """Create a function checking that the function is an instance of the typing `member`. + + The function will make sure to check against both the `typing` and `typing_extensions` + variants as depending on the Python version, the `typing_extensions` variant might be different. + """ + in_typing = hasattr(typing, member) + in_typing_extensions = hasattr(typing_extensions, member) + + globals_: dict[str, Any] = {'Any': Any} + + if in_typing and in_typing_extensions: + # For performance reasons, cache the objects in `globals_` so the generated function avoids + # repeated module attribute lookups (and `typing`'s module-level `__getattr__()`): + t_obj = getattr(typing, member) + te_obj = getattr(typing_extensions, member) + if t_obj is te_obj: + globals_['_obj'] = t_obj + check_code = 'isinstance(obj, _obj)' + else: + globals_['_objs'] = (t_obj, te_obj) + check_code = 'isinstance(obj, _objs)' + elif in_typing and not in_typing_extensions: + globals_['_obj'] = getattr(typing, member) + check_code = 'isinstance(obj, _obj)' + elif not in_typing and in_typing_extensions: + globals_['_obj'] = getattr(typing_extensions, member) + check_code = 'isinstance(obj, _obj)' + else: + check_code = 'False' + + func_code = dedent(f""" + def {function_name}(obj: Any, /) -> 'TypeIs[{member}]': + return {check_code} + """) + + locals_: dict[str, Any] = {} + exec(func_code, globals_, locals_) + return locals_[function_name] + + +# Keep this ordered, as per `typing.__all__`: + +is_annotated = _compile_identity_check_function('Annotated', 'is_annotated') +is_annotated.__doc__ = """ +Return whether the argument is the [`Annotated`][typing.Annotated] [special form][]. + +```pycon +>>> is_annotated(Annotated) +True +>>> is_annotated(Annotated[int, ...]) +False +``` +""" + +is_any = _compile_identity_check_function('Any', 'is_any') +is_any.__doc__ = """ +Return whether the argument is the [`Any`][typing.Any] [special form][]. + +```pycon +>>> is_any(Any) +True +``` +""" + +is_classvar = _compile_identity_check_function('ClassVar', 'is_classvar') +is_classvar.__doc__ = """ +Return whether the argument is the [`ClassVar`][typing.ClassVar] [type qualifier][]. + +```pycon +>>> is_classvar(ClassVar) +True +>>> is_classvar(ClassVar[int]) +>>> False +``` +""" + +is_concatenate = _compile_identity_check_function('Concatenate', 'is_concatenate') +is_concatenate.__doc__ = """ +Return whether the argument is the [`Concatenate`][typing.Concatenate] [special form][]. + +```pycon +>>> is_concatenate(Concatenate) +True +>>> is_concatenate(Concatenate[int, P]) +False +``` +""" + +is_final = _compile_identity_check_function('Final', 'is_final') +is_final.__doc__ = """ +Return whether the argument is the [`Final`][typing.Final] [type qualifier][]. + +```pycon +>>> is_final(Final) +True +>>> is_final(Final[int]) +False +``` +""" + + +# Unlikely to have a different version in `typing-extensions`, but keep it consistent. +# Also note that starting in 3.14, this is an alias to `annotationlib.ForwardRef`, but +# accessing it from `typing` doesn't seem to be deprecated. +is_forwardref = _compile_isinstance_check_function('ForwardRef', 'is_forwardref') +is_forwardref.__doc__ = """ +Return whether the argument is an instance of [`ForwardRef`][typing.ForwardRef]. + +```pycon +>>> is_forwardref(ForwardRef('T')) +True +``` +""" + + +is_generic = _compile_identity_check_function('Generic', 'is_generic') +is_generic.__doc__ = """ +Return whether the argument is the [`Generic`][typing.Generic] [special form][]. + +```pycon +>>> is_generic(Generic) +True +>>> is_generic(Generic[T]) +False +``` +""" + +is_literal = _compile_identity_check_function('Literal', 'is_literal') +is_literal.__doc__ = """ +Return whether the argument is the [`Literal`][typing.Literal] [special form][]. + +```pycon +>>> is_literal(Literal) +True +>>> is_literal(Literal["a"]) +False +``` +""" + + +# `get_origin(Optional[int]) is Union`, so `is_optional()` isn't implemented. + +is_paramspec = _compile_isinstance_check_function('ParamSpec', 'is_paramspec') +is_paramspec.__doc__ = """ +Return whether the argument is an instance of [`ParamSpec`][typing.ParamSpec]. + +```pycon +>>> P = ParamSpec('P') +>>> is_paramspec(P) +True +``` +""" + +# Protocol? + +is_typevar = _compile_isinstance_check_function('TypeVar', 'is_typevar') +is_typevar.__doc__ = """ +Return whether the argument is an instance of [`TypeVar`][typing.TypeVar]. + +```pycon +>>> T = TypeVar('T') +>>> is_typevar(T) +True +``` +""" + +is_typevartuple = _compile_isinstance_check_function('TypeVarTuple', 'is_typevartuple') +is_typevartuple.__doc__ = """ +Return whether the argument is an instance of [`TypeVarTuple`][typing.TypeVarTuple]. + +```pycon +>>> Ts = TypeVarTuple('Ts') +>>> is_typevartuple(Ts) +True +``` +""" + +is_union = _compile_identity_check_function('Union', 'is_union') +is_union.__doc__ = """ +Return whether the argument is the [`Union`][typing.Union] [special form][]. + +This function can also be used to check for the [`Optional`][typing.Optional] [special form][], +as at runtime, `Optional[int]` is equivalent to `Union[int, None]`. + +```pycon +>>> is_union(Union) +True +>>> is_union(Union[int, str]) +False +``` + +!!! warning + This does not check for unions using the [new syntax][types-union] (e.g. `int | str`). +""" + + +def is_namedtuple(obj: Any, /) -> bool: + """Return whether the argument is a named tuple type. + + This includes [`NamedTuple`][typing.NamedTuple] subclasses and classes created from the + [`collections.namedtuple`][] factory function. + + ```pycon + >>> class User(NamedTuple): + ... name: str + ... + >>> is_namedtuple(User) + True + >>> City = collections.namedtuple('City', []) + >>> is_namedtuple(City) + True + >>> is_namedtuple(NamedTuple) + False + ``` + """ + return isinstance(obj, type) and issubclass(obj, tuple) and hasattr(obj, '_fields') # pyright: ignore[reportUnknownArgumentType] + + +# TypedDict? + +# BinaryIO? IO? TextIO? + +is_literalstring = _compile_identity_check_function('LiteralString', 'is_literalstring') +is_literalstring.__doc__ = """ +Return whether the argument is the [`LiteralString`][typing.LiteralString] [special form][]. + +```pycon +>>> is_literalstring(LiteralString) +True +``` +""" + +is_never = _compile_identity_check_function('Never', 'is_never') +is_never.__doc__ = """ +Return whether the argument is the [`Never`][typing.Never] [special form][]. + +```pycon +>>> is_never(Never) +True +``` +""" + +is_newtype = _compile_isinstance_check_function('NewType', 'is_newtype') +is_newtype.__doc__ = """ +Return whether the argument is a [`NewType`][typing.NewType]. + +```pycon +>>> UserId = NewType("UserId", int) +>>> is_newtype(UserId) +True +``` +""" + +is_nodefault = _compile_identity_check_function('NoDefault', 'is_nodefault') +is_nodefault.__doc__ = """ +Return whether the argument is the [`NoDefault`][typing.NoDefault] sentinel object. + +```pycon +>>> is_nodefault(NoDefault) +True +``` +""" + +is_noextraitems = _compile_identity_check_function('NoExtraItems', 'is_noextraitems') +is_noextraitems.__doc__ = """ +Return whether the argument is the `NoExtraItems` sentinel object. + +```pycon +>>> is_noextraitems(NoExtraItems) +True +``` +""" + +is_noreturn = _compile_identity_check_function('NoReturn', 'is_noreturn') +is_noreturn.__doc__ = """ +Return whether the argument is the [`NoReturn`][typing.NoReturn] [special form][]. + +```pycon +>>> is_noreturn(NoReturn) +True +>>> is_noreturn(Never) +False +``` +""" + +is_notrequired = _compile_identity_check_function('NotRequired', 'is_notrequired') +is_notrequired.__doc__ = """ +Return whether the argument is the [`NotRequired`][typing.NotRequired] [special form][]. + +```pycon +>>> is_notrequired(NotRequired) +True +``` +""" + +is_paramspecargs = _compile_isinstance_check_function('ParamSpecArgs', 'is_paramspecargs') +is_paramspecargs.__doc__ = """ +Return whether the argument is an instance of [`ParamSpecArgs`][typing.ParamSpecArgs]. + +```pycon +>>> P = ParamSpec('P') +>>> is_paramspecargs(P.args) +True +``` +""" + +is_paramspeckwargs = _compile_isinstance_check_function('ParamSpecKwargs', 'is_paramspeckwargs') +is_paramspeckwargs.__doc__ = """ +Return whether the argument is an instance of [`ParamSpecKwargs`][typing.ParamSpecKwargs]. + +```pycon +>>> P = ParamSpec('P') +>>> is_paramspeckwargs(P.kwargs) +True +``` +""" + +is_readonly = _compile_identity_check_function('ReadOnly', 'is_readonly') +is_readonly.__doc__ = """ +Return whether the argument is the [`ReadOnly`][typing.ReadOnly] [special form][]. + +```pycon +>>> is_readonly(ReadOnly) +True +``` +""" + +is_required = _compile_identity_check_function('Required', 'is_required') +is_required.__doc__ = """ +Return whether the argument is the [`Required`][typing.Required] [special form][]. + +```pycon +>>> is_required(Required) +True +``` +""" + +is_self = _compile_identity_check_function('Self', 'is_self') +is_self.__doc__ = """ +Return whether the argument is the [`Self`][typing.Self] [special form][]. + +```pycon +>>> is_self(Self) +True +``` +""" + +# TYPE_CHECKING? + +is_typealias = _compile_identity_check_function('TypeAlias', 'is_typealias') +is_typealias.__doc__ = """ +Return whether the argument is the [`TypeAlias`][typing.TypeAlias] [special form][]. + +```pycon +>>> is_typealias(TypeAlias) +True +``` +""" + +is_typeguard = _compile_identity_check_function('TypeGuard', 'is_typeguard') +is_typeguard.__doc__ = """ +Return whether the argument is the [`TypeGuard`][typing.TypeGuard] [special form][]. + +```pycon +>>> is_typeguard(TypeGuard) +True +``` +""" + +is_typeis = _compile_identity_check_function('TypeIs', 'is_typeis') +is_typeis.__doc__ = """ +Return whether the argument is the [`TypeIs`][typing.TypeIs] [special form][]. + +```pycon +>>> is_typeis(TypeIs) +True +``` +""" + +_is_typealiastype_inner = _compile_isinstance_check_function('TypeAliasType', '_is_typealiastype_inner') + + +if _IS_PY310: + # Parameterized PEP 695 type aliases are instances of `types.GenericAlias` in typing_extensions>=4.13.0. + # On Python 3.10, with `Alias[int]` being such an instance of `GenericAlias`, + # `isinstance(Alias[int], TypeAliasType)` returns `True`. + # See https://github.com/python/cpython/issues/89828. + def is_typealiastype(obj: Any, /) -> 'TypeIs[TypeAliasType]': + return type(obj) is not GenericAlias and _is_typealiastype_inner(obj) +else: + is_typealiastype = _compile_isinstance_check_function('TypeAliasType', 'is_typealiastype') + +is_typealiastype.__doc__ = """ +Return whether the argument is a [`TypeAliasType`][typing.TypeAliasType] instance. + +```pycon +>>> type MyInt = int +>>> is_typealiastype(MyInt) +True +>>> MyStr = TypeAliasType("MyStr", str) +>>> is_typealiastype(MyStr): +True +>>> type MyList[T] = list[T] +>>> is_typealiastype(MyList[int]) +False +``` +""" + +is_unpack = _compile_identity_check_function('Unpack', 'is_unpack') +is_unpack.__doc__ = """ +Return whether the argument is the [`Unpack`][typing.Unpack] [special form][]. + +```pycon +>>> is_unpack(Unpack) +True +>>> is_unpack(Unpack[Ts]) +False +``` +""" + + +if sys.version_info >= (3, 13): + _deprecated_types = (warnings.deprecated, typing_extensions.deprecated) + + def is_deprecated(obj: Any, /) -> 'TypeIs[deprecated]': + return isinstance(obj, _deprecated_types) + +else: + _deprecated_type = typing_extensions.deprecated + + def is_deprecated(obj: Any, /) -> 'TypeIs[deprecated]': + return isinstance(obj, _deprecated_type) + + +is_deprecated.__doc__ = """ +Return whether the argument is a [`deprecated`][warnings.deprecated] instance. + +This also includes the [`typing_extensions` backport][typing_extensions.deprecated]. + +```pycon +>>> is_deprecated(warnings.deprecated('message')) +True +>>> is_deprecated(typing_extensions.deprecated('message')) +True +``` +""" + + +# Aliases defined in the `typing` module using `typing._SpecialGenericAlias` (itself aliased as `alias()`): +DEPRECATED_ALIASES: Final[dict[Any, type[Any]]] = { + typing.Hashable: collections.abc.Hashable, + typing.Awaitable: collections.abc.Awaitable, + typing.Coroutine: collections.abc.Coroutine, + typing.AsyncIterable: collections.abc.AsyncIterable, + typing.AsyncIterator: collections.abc.AsyncIterator, + typing.Iterable: collections.abc.Iterable, + typing.Iterator: collections.abc.Iterator, + typing.Reversible: collections.abc.Reversible, + typing.Sized: collections.abc.Sized, + typing.Container: collections.abc.Container, + typing.Collection: collections.abc.Collection, + # type ignore reason: https://github.com/python/typeshed/issues/6257: + typing.Callable: collections.abc.Callable, # pyright: ignore[reportAssignmentType, reportUnknownMemberType] + typing.AbstractSet: collections.abc.Set, + typing.MutableSet: collections.abc.MutableSet, + typing.Mapping: collections.abc.Mapping, + typing.MutableMapping: collections.abc.MutableMapping, + typing.Sequence: collections.abc.Sequence, + typing.MutableSequence: collections.abc.MutableSequence, + typing.Tuple: tuple, + typing.List: list, + typing.Deque: collections.deque, + typing.Set: set, + typing.FrozenSet: frozenset, + typing.MappingView: collections.abc.MappingView, + typing.KeysView: collections.abc.KeysView, + typing.ItemsView: collections.abc.ItemsView, + typing.ValuesView: collections.abc.ValuesView, + typing.Dict: dict, + typing.DefaultDict: collections.defaultdict, + typing.OrderedDict: collections.OrderedDict, + typing.Counter: collections.Counter, + typing.ChainMap: collections.ChainMap, + typing.Generator: collections.abc.Generator, + typing.AsyncGenerator: collections.abc.AsyncGenerator, + typing.Type: type, + # Defined in `typing.__getattr__`: + typing.Pattern: re.Pattern, + typing.Match: re.Match, + typing.ContextManager: contextlib.AbstractContextManager, + typing.AsyncContextManager: contextlib.AbstractAsyncContextManager, + # Skipped: `ByteString` (deprecated, removed in 3.14) +} +"""A mapping between the deprecated typing aliases to their replacement, as per [PEP 585](https://peps.python.org/pep-0585/).""" + + +DEPRECATED_ALIASES_IDS: Final[dict[int, type[Any]]] = {id(k): v for k, v in DEPRECATED_ALIASES.items()} +"""A mapping between the [identity][id] of the deprecated typing aliases to their replacement, as per [PEP 585](https://peps.python.org/pep-0585/).""" + + +# Add the `typing_extensions` aliases: +for alias, target in list(DEPRECATED_ALIASES.items()): + if (te_alias := getattr(typing_extensions, alias.__name__, None)) is not None: + DEPRECATED_ALIASES[te_alias] = target diff --git a/source/target-vendors/cp312/typing_inspection/typing_objects.pyi b/source/target-vendors/cp312/typing_inspection/typing_objects.pyi new file mode 100644 index 0000000..69c731b --- /dev/null +++ b/source/target-vendors/cp312/typing_inspection/typing_objects.pyi @@ -0,0 +1,421 @@ +# Stub file generated using: +# `stubgen --inspect-mode --include-docstrings -m typing_inspection.typing_objects` +# (manual edits need to be applied). +"""Low-level introspection utilities for [`typing`][] members. + +The provided functions in this module check against both the [`typing`][] and [`typing_extensions`][] +variants, if they exists and are different. +""" + +import sys +from typing import Any, Final, ForwardRef, NewType, TypeVar + +from typing_extensions import ParamSpec, ParamSpecArgs, ParamSpecKwargs, TypeAliasType, TypeIs, TypeVarTuple, deprecated + +__all__ = [ + 'DEPRECATED_ALIASES', + 'DEPRECATED_ALIASES_IDS', + 'NoneType', + 'is_annotated', + 'is_any', + 'is_classvar', + 'is_concatenate', + 'is_deprecated', + 'is_final', + 'is_generic', + 'is_literal', + 'is_literalstring', + 'is_namedtuple', + 'is_never', + 'is_newtype', + 'is_nodefault', + 'is_noextraitems', + 'is_noreturn', + 'is_notrequired', + 'is_paramspec', + 'is_paramspecargs', + 'is_paramspeckwargs', + 'is_readonly', + 'is_required', + 'is_self', + 'is_typealias', + 'is_typealiastype', + 'is_typeguard', + 'is_typeis', + 'is_typevar', + 'is_typevartuple', + 'is_union', + 'is_unpack', +] + +if sys.version_info >= (3, 10): + from types import NoneType +else: + NoneType = type(None) + +def is_annotated(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Annotated`][typing.Annotated] [special form][]. + + ```pycon + >>> is_annotated(Annotated) + True + >>> is_annotated(Annotated[int, ...]) + False + ``` + """ + +def is_any(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Any`][typing.Any] [special form][]. + + ```pycon + >>> is_any(Any) + True + ``` + """ + +def is_classvar(obj: Any, /) -> bool: + """ + Return whether the argument is the [`ClassVar`][typing.ClassVar] [type qualifier][]. + + ```pycon + >>> is_classvar(ClassVar) + True + >>> is_classvar(ClassVar[int]) + >>> False + ``` + """ + +def is_concatenate(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Concatenate`][typing.Concatenate] [special form][]. + + ```pycon + >>> is_concatenate(Concatenate) + True + >>> is_concatenate(Concatenate[int, P]) + False + ``` + """ + +def is_final(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Final`][typing.Final] [type qualifier][]. + + ```pycon + >>> is_final(Final) + True + >>> is_final(Final[int]) + False + ``` + """ + +def is_forwardref(obj: Any, /) -> TypeIs[ForwardRef]: + """ + Return whether the argument is an instance of [`ForwardRef`][typing.ForwardRef]. + + ```pycon + >>> is_forwardref(ForwardRef('T')) + True + ``` + """ + +def is_generic(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Generic`][typing.Generic] [special form][]. + + ```pycon + >>> is_generic(Generic) + True + >>> is_generic(Generic[T]) + False + ``` + """ + +def is_literal(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Literal`][typing.Literal] [special form][]. + + ```pycon + >>> is_literal(Literal) + True + >>> is_literal(Literal["a"]) + False + ``` + """ + +def is_paramspec(obj: Any, /) -> TypeIs[ParamSpec]: + """ + Return whether the argument is an instance of [`ParamSpec`][typing.ParamSpec]. + + ```pycon + >>> P = ParamSpec('P') + >>> is_paramspec(P) + True + ``` + """ + +def is_typevar(obj: Any, /) -> TypeIs[TypeVar]: + """ + Return whether the argument is an instance of [`TypeVar`][typing.TypeVar]. + + ```pycon + >>> T = TypeVar('T') + >>> is_typevar(T) + True + ``` + """ + +def is_typevartuple(obj: Any, /) -> TypeIs[TypeVarTuple]: + """ + Return whether the argument is an instance of [`TypeVarTuple`][typing.TypeVarTuple]. + + ```pycon + >>> Ts = TypeVarTuple('Ts') + >>> is_typevartuple(Ts) + True + ``` + """ + +def is_union(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Union`][typing.Union] [special form][]. + + This function can also be used to check for the [`Optional`][typing.Optional] [special form][], + as at runtime, `Optional[int]` is equivalent to `Union[int, None]`. + + ```pycon + >>> is_union(Union) + True + >>> is_union(Union[int, str]) + False + ``` + + !!! warning + This does not check for unions using the [new syntax][types-union] (e.g. `int | str`). + """ + +def is_namedtuple(obj: Any, /) -> bool: + """Return whether the argument is a named tuple type. + + This includes [`NamedTuple`][typing.NamedTuple] subclasses and classes created from the + [`collections.namedtuple`][] factory function. + + ```pycon + >>> class User(NamedTuple): + ... name: str + ... + >>> is_namedtuple(User) + True + >>> City = collections.namedtuple('City', []) + >>> is_namedtuple(City) + True + >>> is_namedtuple(NamedTuple) + False + ``` + """ + +def is_literalstring(obj: Any, /) -> bool: + """ + Return whether the argument is the [`LiteralString`][typing.LiteralString] [special form][]. + + ```pycon + >>> is_literalstring(LiteralString) + True + ``` + """ + +def is_never(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Never`][typing.Never] [special form][]. + + ```pycon + >>> is_never(Never) + True + ``` + """ + +def is_newtype(obj: Any, /) -> TypeIs[NewType]: + """ + Return whether the argument is a [`NewType`][typing.NewType]. + + ```pycon + >>> UserId = NewType("UserId", int) + >>> is_newtype(UserId) + True + ``` + """ + +def is_nodefault(obj: Any, /) -> bool: + """ + Return whether the argument is the [`NoDefault`][typing.NoDefault] sentinel object. + + ```pycon + >>> is_nodefault(NoDefault) + True + ``` + """ + +def is_noextraitems(obj: Any, /) -> bool: + """ + Return whether the argument is the `NoExtraItems` sentinel object. + + ```pycon + >>> is_noextraitems(NoExtraItems) + True + ``` + """ + +def is_noreturn(obj: Any, /) -> bool: + """ + Return whether the argument is the [`NoReturn`][typing.NoReturn] [special form][]. + + ```pycon + >>> is_noreturn(NoReturn) + True + >>> is_noreturn(Never) + False + ``` + """ + +def is_notrequired(obj: Any, /) -> bool: + """ + Return whether the argument is the [`NotRequired`][typing.NotRequired] [special form][]. + + ```pycon + >>> is_notrequired(NotRequired) + True + ``` + """ + +def is_paramspecargs(obj: Any, /) -> TypeIs[ParamSpecArgs]: + """ + Return whether the argument is an instance of [`ParamSpecArgs`][typing.ParamSpecArgs]. + + ```pycon + >>> P = ParamSpec('P') + >>> is_paramspecargs(P.args) + True + ``` + """ + +def is_paramspeckwargs(obj: Any, /) -> TypeIs[ParamSpecKwargs]: + """ + Return whether the argument is an instance of [`ParamSpecKwargs`][typing.ParamSpecKwargs]. + + ```pycon + >>> P = ParamSpec('P') + >>> is_paramspeckwargs(P.kwargs) + True + ``` + """ + +def is_readonly(obj: Any, /) -> bool: + """ + Return whether the argument is the [`ReadOnly`][typing.ReadOnly] [special form][]. + + ```pycon + >>> is_readonly(ReadOnly) + True + ``` + """ + +def is_required(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Required`][typing.Required] [special form][]. + + ```pycon + >>> is_required(Required) + True + ``` + """ + +def is_self(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Self`][typing.Self] [special form][]. + + ```pycon + >>> is_self(Self) + True + ``` + """ + +def is_typealias(obj: Any, /) -> bool: + """ + Return whether the argument is the [`TypeAlias`][typing.TypeAlias] [special form][]. + + ```pycon + >>> is_typealias(TypeAlias) + True + ``` + """ + +def is_typeguard(obj: Any, /) -> bool: + """ + Return whether the argument is the [`TypeGuard`][typing.TypeGuard] [special form][]. + + ```pycon + >>> is_typeguard(TypeGuard) + True + ``` + """ + +def is_typeis(obj: Any, /) -> bool: + """ + Return whether the argument is the [`TypeIs`][typing.TypeIs] [special form][]. + + ```pycon + >>> is_typeis(TypeIs) + True + ``` + """ + +def is_typealiastype(obj: Any, /) -> TypeIs[TypeAliasType]: + """ + Return whether the argument is a [`TypeAliasType`][typing.TypeAliasType] instance. + + ```pycon + >>> type MyInt = int + >>> is_typealiastype(MyInt) + True + >>> MyStr = TypeAliasType("MyStr", str) + >>> is_typealiastype(MyStr): + True + >>> type MyList[T] = list[T] + >>> is_typealiastype(MyList[int]) + False + ``` + """ + +def is_unpack(obj: Any, /) -> bool: + """ + Return whether the argument is the [`Unpack`][typing.Unpack] [special form][]. + + ```pycon + >>> is_unpack(Unpack) + True + >>> is_unpack(Unpack[Ts]) + False + ``` + """ + +def is_deprecated(obj: Any, /) -> TypeIs[deprecated]: + """ + Return whether the argument is a [`deprecated`][warnings.deprecated] instance. + + This also includes the [`typing_extensions` backport][typing_extensions.deprecated]. + + ```pycon + >>> is_deprecated(warnings.deprecated('message')) + True + >>> is_deprecated(typing_extensions.deprecated('deprecated')) + True + ``` + """ + +DEPRECATED_ALIASES: Final[dict[Any, type[Any]]] +"""A mapping between the deprecated typing aliases to their replacement, as per [PEP 585](https://peps.python.org/pep-0585/).""" + +DEPRECATED_ALIASES_IDS: Final[dict[int, type[Any]]] +"""A mapping between the [identity][id] of the deprecated typing aliases to their replacement, as per [PEP 585](https://peps.python.org/pep-0585/).""" diff --git a/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/METADATA b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/METADATA new file mode 100644 index 0000000..4985a6e --- /dev/null +++ b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/METADATA @@ -0,0 +1,189 @@ +Metadata-Version: 2.5 +Name: uvicorn +Version: 0.53.0 +Summary: The lightning-fast ASGI server. +Project-URL: Changelog, https://uvicorn.dev/release-notes +Project-URL: Funding, https://github.com/sponsors/Kludex +Project-URL: Homepage, https://uvicorn.dev/ +Project-URL: Source, https://github.com/Kludex/uvicorn +Author-email: Tom Christie +Maintainer-email: Marcelo Trylesinski +License-Expression: BSD-3-Clause +License-File: LICENSE.md +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP +Requires-Python: >=3.10 +Requires-Dist: click>=7.0 +Requires-Dist: h11>=0.8 +Requires-Dist: typing-extensions>=4.0; python_version < '3.11' +Provides-Extra: standard +Requires-Dist: httptools>=0.8.0; extra == 'standard' +Requires-Dist: python-dotenv>=0.13; extra == 'standard' +Requires-Dist: pyyaml>=5.1; extra == 'standard' +Requires-Dist: uvloop>=0.15.1; (sys_platform != 'win32' and (sys_platform != 'cygwin' and platform_python_implementation != 'PyPy')) and extra == 'standard' +Requires-Dist: watchfiles>=0.20; extra == 'standard' +Requires-Dist: websockets>=13.0; extra == 'standard' +Description-Content-Type: text/markdown + +

      + uvicorn +

      + +

      +An ASGI web server, for Python. +

      + +--- + +[![Build Status](https://github.com/Kludex/uvicorn/workflows/Test%20Suite/badge.svg)](https://github.com/Kludex/uvicorn/actions) +[![Package version](https://badge.fury.io/py/uvicorn.svg)](https://pypi.python.org/pypi/uvicorn) +[![Supported Python Version](https://img.shields.io/pypi/pyversions/uvicorn.svg?color=%2334D058)](https://pypi.org/project/uvicorn) +[![Discord](https://img.shields.io/discord/1051468649518616576?logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/RxKUF5JuHs) + +--- + +**Documentation**: [https://uvicorn.dev](https://uvicorn.dev) + +**Source Code**: [https://www.github.com/Kludex/uvicorn](https://www.github.com/Kludex/uvicorn) + +--- + +Uvicorn is an ASGI web server implementation for Python. + +Until recently Python has lacked a minimal low-level server/application interface for +async frameworks. The [ASGI specification][asgi] fills this gap, and means we're now able to +start building a common set of tooling usable across all async frameworks. + +Uvicorn currently supports HTTP/1.1, HTTP/2 and WebSockets. + +## Quickstart + +Install using `pip`: + +```shell +$ pip install uvicorn +``` + +This will install uvicorn with minimal (pure Python) dependencies. + +```shell +$ pip install 'uvicorn[standard]' +``` + +This will install uvicorn with "Cython-based" dependencies (where possible) and other "optional extras". + +In this context, "Cython-based" means the following: + +- the event loop `uvloop` will be installed and used if possible. +- the http protocol will be handled by `httptools` if possible. + +Moreover, "optional extras" means that: + +- the websocket protocol will be handled by `websockets` (should you want to use `wsproto` you'd need to install it manually) if possible. +- the `--reload` flag in development mode will use `watchfiles`. +- `python-dotenv` will be installed should you want to use the `--env-file` option. +- `PyYAML` will be installed to allow you to provide a `.yaml` file to `--log-config`, if desired. + +Create an application, in `example.py`: + +```python +async def app(scope, receive, send): + assert scope['type'] == 'http' + + await send({ + 'type': 'http.response.start', + 'status': 200, + 'headers': [ + (b'content-type', b'text/plain'), + ], + }) + await send({ + 'type': 'http.response.body', + 'body': b'Hello, world!', + }) +``` + +Run the server: + +```shell +$ uvicorn example:app +``` + +--- + +## Why ASGI? + +Most well established Python Web frameworks started out as WSGI-based frameworks. + +WSGI applications are a single, synchronous callable that takes a request and returns a response. +This doesn’t allow for long-lived connections, like you get with long-poll HTTP or WebSocket connections, +which WSGI doesn't support well. + +Having an async concurrency model also allows for options such as lightweight background tasks, +and can be less of a limiting factor for endpoints that have long periods being blocked on network +I/O such as dealing with slow HTTP requests. + +--- + +## Alternative ASGI servers + +A strength of the ASGI protocol is that it decouples the server implementation +from the application framework. This allows for an ecosystem of interoperating +webservers and application frameworks. + +### Daphne + +The first ASGI server implementation, originally developed to power Django Channels, is [the Daphne webserver][daphne]. + +It is run widely in production, and supports HTTP/1.1, HTTP/2, and WebSockets. + +Any of the example applications given here can equally well be run using `daphne` instead. + +``` +$ pip install daphne +$ daphne app:App +``` + +### Hypercorn + +[Hypercorn][hypercorn] was initially part of the Quart web framework, before +being separated out into a standalone ASGI server. + +Hypercorn supports HTTP/1.1, HTTP/2, and WebSockets. + +It also supports [the excellent `trio` async framework][trio], as an alternative to `asyncio`. + +``` +$ pip install hypercorn +$ hypercorn app:App +``` + +### Mangum + +[Mangum][mangum] is an adapter for using ASGI applications with AWS Lambda & API Gateway. + +### Granian + +[Granian][granian] is an ASGI compatible Rust HTTP server which supports HTTP/2, TLS and WebSockets. + +--- + +

      Uvicorn is BSD licensed code.
      Designed & crafted with care.

      — 🦄 —

      + +[asgi]: https://asgi.readthedocs.io/en/latest/ +[daphne]: https://github.com/django/daphne +[hypercorn]: https://github.com/pgjones/hypercorn +[trio]: https://trio.readthedocs.io +[mangum]: https://github.com/jordaneremieff/mangum +[granian]: https://github.com/emmett-framework/granian diff --git a/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/RECORD b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/RECORD new file mode 100644 index 0000000..7cf1539 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/RECORD @@ -0,0 +1,51 @@ +uvicorn/__init__.py,sha256=YzDsuEOzmpGq7bIZ89KtaKf-YjzknovmzaIlek9fkDs,147 +uvicorn/__main__.py,sha256=DQizy6nKP0ywhPpnCHgmRDYIMfcqZKVEzNIWQZjqtVQ,62 +uvicorn/_ansi.py,sha256=s8RPpmPTO6QGRgEYbsNGeasSWqiEnCsTroyA8Z59Q00,617 +uvicorn/_compat.py,sha256=6X49c9ovzmMHir2S3syinOQMzSPBcp8MNuI9ZQrbYiU,2916 +uvicorn/_subprocess.py,sha256=fQ4JTajuXay6mVc8KQNGfXu6JHoab46aS6kyIMWJMPk,2776 +uvicorn/_types.py,sha256=JDM6E-hqZ6o_cSZvjDULjAv77PFH2pLe_Vgqshe8qH4,7677 +uvicorn/config.py,sha256=z5HG_64oOisgINqVS0zE7UfTJGywYq_Qn7d9mOTFyoc,25482 +uvicorn/importer.py,sha256=nRt0QQ3qpi264-n_mR0l55C2ddM8nowTNzT1jsWaam8,1128 +uvicorn/logging.py,sha256=kCB1n45B5O55SSApiv2x6UQG3LnFqNlGvcohGyAwblU,4256 +uvicorn/main.py,sha256=7Lg1RLSBJtcA6APR1VjvFYNGlhqC0Pxf1f532L76hd8,19049 +uvicorn/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +uvicorn/server.py,sha256=wb6dEzRnpCq4jXFo5AjvWpAldmGpAYmUJiFKPR_C0CY,13705 +uvicorn/workers.py,sha256=lMCubn1Wi-4h2jxrXNMmhOJZy7ZP8QxbZbP3_2O1iHE,3873 +uvicorn/lifespan/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uvicorn/lifespan/off.py,sha256=nfI6qHAUo_8-BEXMBKoHQ9wUbsXrPaXLCbDSS0vKSr8,332 +uvicorn/lifespan/on.py,sha256=iETPFj6SFhPDPcdeGxfa43LKImJU7MI5i7QUUepBcPE,5173 +uvicorn/loops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uvicorn/loops/asyncio.py,sha256=a8wO4fB4pCk-RLICq7CnGr_cxQI7MBLJj-Go4UQldD8,333 +uvicorn/loops/auto.py,sha256=pdTsMcqkbE8fvdNgLs1y4c6hsuN598mZOSOlC0a23S4,566 +uvicorn/loops/uvloop.py,sha256=Ca-TL-W8tbdEW5uvL_GrMih7G8e_t_vhNevi2NKYjEU,236 +uvicorn/loops/zuvloop.py,sha256=6ei_QjRoIYqMXKB4UnZSkO6k6a8PqcjWV5mvzYkR160,239 +uvicorn/middleware/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uvicorn/middleware/asgi2.py,sha256=YQrQNm3RehFts3mzk3k4yw8aD8Egtj0tRS3N45YkQa0,394 +uvicorn/middleware/message_logger.py,sha256=IHEZUSnFNaMFUFdwtZO3AuFATnYcSor-gVtOjbCzt8M,2859 +uvicorn/middleware/proxy_headers.py,sha256=pNZk80NNscLEwi8pGn6cIbaF0bSfJhCKn3pHjqqfW90,7421 +uvicorn/middleware/wsgi.py,sha256=VnbnkdCL3_ctLWzk1j39xvxysuoAB3kSYmi8TsOLpNs,7125 +uvicorn/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uvicorn/protocols/utils.py,sha256=1hKdDCmo_GtGrK1zZfa70jL7Hr3mDE8RnL69O4rHQRg,2058 +uvicorn/protocols/http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uvicorn/protocols/http/auto.py,sha256=YfXGyzWTaaE2p_jkTPWrJCXsxEaQnC3NK0-G7Wgmnls,403 +uvicorn/protocols/http/auto_zttp_impl.py,sha256=cvqOUvV38tc5gD4tpNhiL7IeIKyIoCyCCGe9RtnQtKk,3272 +uvicorn/protocols/http/flow_control.py,sha256=050WVg31EvPOkHwynCoMP1zXFl_vO3U4durlc5vyp4U,1701 +uvicorn/protocols/http/h11_impl.py,sha256=oxVKbCz6quvhmseqJV3-m2t7SQ3h2pUnTAM6oJPowyI,20886 +uvicorn/protocols/http/httptools_impl.py,sha256=HU4cV530FoQzphoB8QxiizHBeQ5y3Zdp0rhjOyIhQDM,22564 +uvicorn/protocols/http/zttp_h2_impl.py,sha256=HdW4vaZC2uyMKbsobhzeLGgcR_9IhpFCWba6WeqaU6Q,19950 +uvicorn/protocols/http/zttp_impl.py,sha256=5jCnrVuza4pozajsiOhYVwQLXPKgCiwUVn14p0-z2YU,21835 +uvicorn/protocols/websockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +uvicorn/protocols/websockets/auto.py,sha256=QOnMKZfXHfOcZHdq1OITHwv7Awx1BTS3eJfZswuGEU0,611 +uvicorn/protocols/websockets/websockets_impl.py,sha256=ZpRwX6nSkMrojCaAgqAZjeAoMxZAoJW9bfUvvyOLsUE,15784 +uvicorn/protocols/websockets/websockets_sansio_impl.py,sha256=izKpehYIeIu6UlyLHg0-sKk80J0PT0G5uDzr1SczbEk,23861 +uvicorn/protocols/websockets/wsproto_impl.py,sha256=uzCxXnvNv0akCIWNY1q2DnuONcdmrYYDmgORsxeTc8M,21138 +uvicorn/supervisors/__init__.py,sha256=wT8eOEIqT1yWQgytZtv5taWMul7xoTIY0xm1m4oyPTw,507 +uvicorn/supervisors/basereload.py,sha256=C-YD18flOKKVRNTRsSCOEvyqGf3ZxpvuUvR0z0Y1Wpg,4018 +uvicorn/supervisors/multiprocess.py,sha256=U1QZdiJ_7Auazix6XOj1ku0Nj_N_PJPCoYuq6SNjZcI,10271 +uvicorn/supervisors/statreload.py,sha256=XPaEtVXaasII1kkG32UUG8oD7-fS0FwyXkQLF9QYPbA,1548 +uvicorn/supervisors/watchfilesreload.py,sha256=u-MuYm0LsZMN670u_TtSWiMBUA2z4j1sIe3O2A67Ep4,2923 +uvicorn-0.53.0.dist-info/METADATA,sha256=vPs7Yx0x4_98aZJCiwSAoJ1AfsgpkFqpMB9za9hUy0U,6607 +uvicorn-0.53.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87 +uvicorn-0.53.0.dist-info/entry_points.txt,sha256=FW1w-hkc9QgwaGoovMvm0ZY73w_NcycWdGAUfDsNGxw,46 +uvicorn-0.53.0.dist-info/licenses/LICENSE.md,sha256=7-Gs8-YvuZwoiw7HPlp3O3Jo70Mg_nV-qZQhTktjw3E,1526 +uvicorn-0.53.0.dist-info/RECORD,, diff --git a/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/WHEEL b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/WHEEL new file mode 100644 index 0000000..51abe1f --- /dev/null +++ b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.32.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/entry_points.txt b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/entry_points.txt new file mode 100644 index 0000000..4b00fcb --- /dev/null +++ b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +uvicorn = uvicorn.main:main diff --git a/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/licenses/LICENSE.md b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/licenses/LICENSE.md new file mode 100644 index 0000000..a6bba14 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn-0.53.0.dist-info/licenses/LICENSE.md @@ -0,0 +1,27 @@ +Copyright © 2017-present, [Encode OSS Ltd](https://www.encode.io/). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/source/target-vendors/cp312/uvicorn/__init__.py b/source/target-vendors/cp312/uvicorn/__init__.py new file mode 100644 index 0000000..f27ddd2 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/__init__.py @@ -0,0 +1,5 @@ +from uvicorn.config import Config +from uvicorn.main import Server, main, run + +__version__ = "0.53.0" +__all__ = ["main", "run", "Config", "Server"] diff --git a/source/target-vendors/cp312/uvicorn/__main__.py b/source/target-vendors/cp312/uvicorn/__main__.py new file mode 100644 index 0000000..8a1dc97 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/__main__.py @@ -0,0 +1,4 @@ +import uvicorn + +if __name__ == "__main__": + uvicorn.main() diff --git a/source/target-vendors/cp312/uvicorn/_ansi.py b/source/target-vendors/cp312/uvicorn/_ansi.py new file mode 100644 index 0000000..8f60f40 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/_ansi.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +_ANSI_COLORS = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} + + +def style(text: str, fg: str | None = None, bold: bool = False) -> str: + prefix = "" + if fg is not None: + prefix += f"\033[{_ANSI_COLORS[fg]}m" + if bold: + prefix += "\033[1m" + return f"{prefix}{text}\033[0m" diff --git a/source/target-vendors/cp312/uvicorn/_compat.py b/source/target-vendors/cp312/uvicorn/_compat.py new file mode 100644 index 0000000..118a19a --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/_compat.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +import asyncio +import sys +from collections.abc import Callable, Coroutine +from typing import Any, TypeVar + +__all__ = ["asyncio_run", "iscoroutinefunction"] + +if sys.version_info >= (3, 14): + from inspect import iscoroutinefunction +else: + from asyncio import iscoroutinefunction + +_T = TypeVar("_T") + +if sys.version_info >= (3, 12): + asyncio_run = asyncio.run +elif sys.version_info >= (3, 11): + + def asyncio_run( + main: Coroutine[Any, Any, _T], + *, + debug: bool = False, + loop_factory: Callable[[], asyncio.AbstractEventLoop] | None = None, + ) -> _T: + # asyncio.run from Python 3.12 + # https://docs.python.org/3/license.html#psf-license + with asyncio.Runner(debug=debug, loop_factory=loop_factory) as runner: + return runner.run(main) + +else: + # modified version of asyncio.run from Python 3.10 to add loop_factory kwarg + # https://docs.python.org/3/license.html#psf-license + def asyncio_run( + main: Coroutine[Any, Any, _T], + *, + debug: bool = False, + loop_factory: Callable[[], asyncio.AbstractEventLoop] | None = None, + ) -> _T: + try: + asyncio.get_running_loop() + except RuntimeError: + pass + else: + raise RuntimeError("asyncio.run() cannot be called from a running event loop") + + if not asyncio.iscoroutine(main): + raise ValueError(f"a coroutine was expected, got {main!r}") + + if loop_factory is None: + loop = asyncio.new_event_loop() + else: + loop = loop_factory() + try: + if loop_factory is None: + asyncio.set_event_loop(loop) + if debug is not None: + loop.set_debug(debug) + return loop.run_until_complete(main) + finally: + try: + _cancel_all_tasks(loop) + loop.run_until_complete(loop.shutdown_asyncgens()) + loop.run_until_complete(loop.shutdown_default_executor()) + finally: + if loop_factory is None: + asyncio.set_event_loop(None) + loop.close() + + def _cancel_all_tasks(loop: asyncio.AbstractEventLoop) -> None: + to_cancel = asyncio.all_tasks(loop) + if not to_cancel: + return + + for task in to_cancel: + task.cancel() + + loop.run_until_complete(asyncio.gather(*to_cancel, return_exceptions=True)) + + for task in to_cancel: + if task.cancelled(): + continue + if task.exception() is not None: + loop.call_exception_handler( + { + "message": "unhandled exception during asyncio.run() shutdown", + "exception": task.exception(), + "task": task, + } + ) diff --git a/source/target-vendors/cp312/uvicorn/_subprocess.py b/source/target-vendors/cp312/uvicorn/_subprocess.py new file mode 100644 index 0000000..c084ec9 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/_subprocess.py @@ -0,0 +1,84 @@ +""" +Some light wrappers around Python's multiprocessing, to deal with cleanly +starting child processes. +""" + +from __future__ import annotations + +import multiprocessing +import os +import sys +from collections.abc import Callable +from multiprocessing.context import SpawnProcess +from socket import socket + +from uvicorn.config import Config + +multiprocessing.allow_connection_pickling() +spawn = multiprocessing.get_context("spawn") + + +def get_subprocess( + config: Config, + target: Callable[..., None], + sockets: list[socket], +) -> SpawnProcess: + """ + Called in the parent process, to instantiate a new child process instance. + The child is not yet started at this point. + + * config - The Uvicorn configuration instance. + * target - A callable that accepts a list of sockets. In practice this will + be the `Server.run()` method. + * sockets - A list of sockets to pass to the server. Sockets are bound once + by the parent process, and then passed to the child processes. + """ + # We pass across the stdin fileno, and reopen it in the child process. + # This is required for some debugging environments. + try: + stdin_fileno = sys.stdin.fileno() + # The `sys.stdin` can be `None`, see https://docs.python.org/3/library/sys.html#sys.__stdin__. + except (AttributeError, OSError): + stdin_fileno = None + + kwargs = { + "config": config, + "target": target, + "sockets": sockets, + "stdin_fileno": stdin_fileno, + } + + return spawn.Process(target=subprocess_started, kwargs=kwargs) + + +def subprocess_started( + config: Config, + target: Callable[..., None], + sockets: list[socket], + stdin_fileno: int | None, +) -> None: + """ + Called when the child process starts. + + * config - The Uvicorn configuration instance. + * target - A callable that accepts a list of sockets. In practice this will + be the `Server.run()` method. + * sockets - A list of sockets to pass to the server. Sockets are bound once + by the parent process, and then passed to the child processes. + * stdin_fileno - The file number of sys.stdin, so that it can be reattached + to the child process. + """ + # Re-open stdin. + if stdin_fileno is not None: + sys.stdin = os.fdopen(stdin_fileno) # pragma: full coverage + + # Logging needs to be setup again for each child. + config.configure_logging() + + try: + # Now we can call into `Server.run(sockets=sockets)` + target(sockets=sockets) + except KeyboardInterrupt: # pragma: no cover + # suppress the exception to avoid a traceback from subprocess.Popen + # the parent already expects us to end, so no vital information is lost + pass diff --git a/source/target-vendors/cp312/uvicorn/_types.py b/source/target-vendors/cp312/uvicorn/_types.py new file mode 100644 index 0000000..822445a --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/_types.py @@ -0,0 +1,274 @@ +""" +Copyright (c) Django Software Foundation and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of Django nor the names of its contributors may be used + to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +from __future__ import annotations + +import sys +import types +from collections.abc import Awaitable, Callable, Iterable, MutableMapping +from typing import Any, Literal, Protocol, TypedDict + +if sys.version_info >= (3, 11): # pragma: py-lt-311 + from typing import NotRequired +else: # pragma: py-gte-311 + from typing_extensions import NotRequired + +# WSGI +Environ = MutableMapping[str, Any] +ExcInfo = tuple[type[BaseException], BaseException, types.TracebackType | None] +StartResponse = Callable[[str, Iterable[tuple[str, str]], ExcInfo | None], None] +WSGIApp = Callable[[Environ, StartResponse], Iterable[bytes] | BaseException] + + +# ASGI +class ASGIVersions(TypedDict): + spec_version: str + version: Literal["2.0"] | Literal["3.0"] + + +class HTTPScope(TypedDict): + type: Literal["http"] + asgi: ASGIVersions + http_version: str + method: str + scheme: str + path: str + raw_path: bytes + query_string: bytes + root_path: str + headers: Iterable[tuple[bytes, bytes]] + client: tuple[str, int] | None + server: tuple[str, int | None] | None + state: NotRequired[dict[str, Any]] + extensions: NotRequired[dict[str, dict[object, object]]] + + +class WebSocketScope(TypedDict): + type: Literal["websocket"] + asgi: ASGIVersions + http_version: str + scheme: str + path: str + raw_path: bytes + query_string: bytes + root_path: str + headers: Iterable[tuple[bytes, bytes]] + client: tuple[str, int] | None + server: tuple[str, int | None] | None + subprotocols: Iterable[str] + state: NotRequired[dict[str, Any]] + extensions: NotRequired[dict[str, dict[object, object]]] + + +class LifespanScope(TypedDict): + type: Literal["lifespan"] + asgi: ASGIVersions + state: NotRequired[dict[str, Any]] + + +WWWScope = HTTPScope | WebSocketScope +Scope = HTTPScope | WebSocketScope | LifespanScope + + +class HTTPRequestEvent(TypedDict): + type: Literal["http.request"] + body: bytes + more_body: bool + + +class HTTPResponseDebugEvent(TypedDict): + type: Literal["http.response.debug"] + info: dict[str, object] + + +class HTTPResponseStartEvent(TypedDict): + type: Literal["http.response.start"] + status: int + headers: NotRequired[Iterable[tuple[bytes, bytes]]] + trailers: NotRequired[bool] + + +class HTTPResponseBodyEvent(TypedDict): + type: Literal["http.response.body"] + body: bytes + more_body: NotRequired[bool] + + +class HTTPResponseTrailersEvent(TypedDict): + type: Literal["http.response.trailers"] + headers: Iterable[tuple[bytes, bytes]] + more_trailers: bool + + +class HTTPServerPushEvent(TypedDict): + type: Literal["http.response.push"] + path: str + headers: Iterable[tuple[bytes, bytes]] + + +class HTTPDisconnectEvent(TypedDict): + type: Literal["http.disconnect"] + + +class WebSocketConnectEvent(TypedDict): + type: Literal["websocket.connect"] + + +class WebSocketAcceptEvent(TypedDict): + type: Literal["websocket.accept"] + subprotocol: NotRequired[str | None] + headers: NotRequired[Iterable[tuple[bytes, bytes]]] + + +class _WebSocketReceiveEventBytes(TypedDict): + type: Literal["websocket.receive"] + bytes: bytes + text: NotRequired[None] + + +class _WebSocketReceiveEventText(TypedDict): + type: Literal["websocket.receive"] + bytes: NotRequired[None] + text: str + + +WebSocketReceiveEvent = _WebSocketReceiveEventBytes | _WebSocketReceiveEventText + + +class _WebSocketSendEventBytes(TypedDict): + type: Literal["websocket.send"] + bytes: bytes + text: NotRequired[None] + + +class _WebSocketSendEventText(TypedDict): + type: Literal["websocket.send"] + bytes: NotRequired[None] + text: str + + +WebSocketSendEvent = _WebSocketSendEventBytes | _WebSocketSendEventText + + +class WebSocketResponseStartEvent(TypedDict): + type: Literal["websocket.http.response.start"] + status: int + headers: Iterable[tuple[bytes, bytes]] + + +class WebSocketResponseBodyEvent(TypedDict): + type: Literal["websocket.http.response.body"] + body: bytes + more_body: NotRequired[bool] + + +class WebSocketDisconnectEvent(TypedDict): + type: Literal["websocket.disconnect"] + code: int + reason: NotRequired[str | None] + + +class WebSocketCloseEvent(TypedDict): + type: Literal["websocket.close"] + code: NotRequired[int] + reason: NotRequired[str | None] + + +class LifespanStartupEvent(TypedDict): + type: Literal["lifespan.startup"] + + +class LifespanShutdownEvent(TypedDict): + type: Literal["lifespan.shutdown"] + + +class LifespanStartupCompleteEvent(TypedDict): + type: Literal["lifespan.startup.complete"] + + +class LifespanStartupFailedEvent(TypedDict): + type: Literal["lifespan.startup.failed"] + message: str + + +class LifespanShutdownCompleteEvent(TypedDict): + type: Literal["lifespan.shutdown.complete"] + + +class LifespanShutdownFailedEvent(TypedDict): + type: Literal["lifespan.shutdown.failed"] + message: str + + +WebSocketEvent = WebSocketReceiveEvent | WebSocketDisconnectEvent | WebSocketConnectEvent + + +ASGIReceiveEvent = ( + HTTPRequestEvent + | HTTPDisconnectEvent + | WebSocketConnectEvent + | WebSocketReceiveEvent + | WebSocketDisconnectEvent + | LifespanStartupEvent + | LifespanShutdownEvent +) + + +ASGISendEvent = ( + HTTPResponseStartEvent + | HTTPResponseBodyEvent + | HTTPResponseTrailersEvent + | HTTPServerPushEvent + | HTTPDisconnectEvent + | WebSocketAcceptEvent + | WebSocketSendEvent + | WebSocketResponseStartEvent + | WebSocketResponseBodyEvent + | WebSocketCloseEvent + | LifespanStartupCompleteEvent + | LifespanStartupFailedEvent + | LifespanShutdownCompleteEvent + | LifespanShutdownFailedEvent +) + + +ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]] +ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]] + + +class ASGI2Protocol(Protocol): + def __init__(self, scope: Scope) -> None: ... # pragma: no cover + + async def __call__(self, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None: ... # pragma: no cover + + +ASGI2Application = type[ASGI2Protocol] +ASGI3Application = Callable[[Scope, ASGIReceiveCallable, ASGISendCallable], Awaitable[None]] +ASGIApplication = ASGI2Application | ASGI3Application diff --git a/source/target-vendors/cp312/uvicorn/config.py b/source/target-vendors/cp312/uvicorn/config.py new file mode 100644 index 0000000..37b3c0d --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/config.py @@ -0,0 +1,618 @@ +from __future__ import annotations + +import asyncio +import inspect +import json +import logging +import logging.config +import os +import socket +import ssl +import sys +from collections.abc import Awaitable, Callable +from configparser import RawConfigParser +from pathlib import Path +from typing import IO, Any, Literal + +from uvicorn._ansi import style +from uvicorn._compat import iscoroutinefunction +from uvicorn._types import ASGIApplication +from uvicorn.importer import ImportFromStringError, import_from_string +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.middleware.asgi2 import ASGI2Middleware +from uvicorn.middleware.message_logger import MessageLoggerMiddleware +from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware +from uvicorn.middleware.wsgi import WSGIMiddleware + + +class UvicornDeprecationWarning(UserWarning): + """A custom deprecation warning for Uvicorn. + + Unlike the built-in DeprecationWarning, this inherits from UserWarning to ensure it is visible by default, helping + users discover deprecated features without needing to enable warnings explicitly. + + Reference: https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries + """ + + +HTTPProtocolType = Literal["auto", "h11", "httptools", "zttp"] +WSProtocolType = Literal["auto", "none", "websockets", "websockets-sansio", "wsproto"] +LifespanType = Literal["auto", "on", "off"] +LoopFactoryType = Literal["none", "auto", "asyncio", "uvloop", "zuvloop"] +InterfaceType = Literal["auto", "asgi3", "asgi2", "wsgi"] + +LOG_LEVELS: dict[str, int] = { + "critical": logging.CRITICAL, + "error": logging.ERROR, + "warning": logging.WARNING, + "info": logging.INFO, + "debug": logging.DEBUG, + "trace": TRACE_LOG_LEVEL, +} +HTTP_PROTOCOLS: dict[str, str] = { + "auto": "uvicorn.protocols.http.auto:AutoHTTPProtocol", + "h11": "uvicorn.protocols.http.h11_impl:H11Protocol", + "httptools": "uvicorn.protocols.http.httptools_impl:HttpToolsProtocol", + "zttp": "uvicorn.protocols.http.zttp_impl:ZttpProtocol", +} +WS_PROTOCOLS: dict[str, str | None] = { + "auto": "uvicorn.protocols.websockets.auto:AutoWebSocketsProtocol", + "none": None, + "websockets": "uvicorn.protocols.websockets.websockets_impl:WebSocketProtocol", + "websockets-sansio": "uvicorn.protocols.websockets.websockets_sansio_impl:WebSocketsSansIOProtocol", + "wsproto": "uvicorn.protocols.websockets.wsproto_impl:WSProtocol", +} +LIFESPAN: dict[str, str] = { + "auto": "uvicorn.lifespan.on:LifespanOn", + "on": "uvicorn.lifespan.on:LifespanOn", + "off": "uvicorn.lifespan.off:LifespanOff", +} +LOOP_FACTORIES: dict[str, str | None] = { + "none": None, + "auto": "uvicorn.loops.auto:auto_loop_factory", + "asyncio": "uvicorn.loops.asyncio:asyncio_loop_factory", + "uvloop": "uvicorn.loops.uvloop:uvloop_loop_factory", + "zuvloop": "uvicorn.loops.zuvloop:zuvloop_loop_factory", +} +INTERFACES: list[InterfaceType] = ["auto", "asgi3", "asgi2", "wsgi"] + +SSL_PROTOCOL_VERSION: int = ssl.PROTOCOL_TLS_SERVER + +STARTUP_FAILURE = 3 + +LOGGING_CONFIG: dict[str, Any] = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "default": { + "()": "uvicorn.logging.DefaultFormatter", + "fmt": "%(levelprefix)s %(message)s", + "use_colors": None, + }, + "access": { + "()": "uvicorn.logging.AccessFormatter", + "fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s', # noqa: E501 + }, + }, + "handlers": { + "default": { + "formatter": "default", + "class": "logging.StreamHandler", + "stream": "ext://sys.stderr", + }, + "access": { + "formatter": "access", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + }, + "loggers": { + "uvicorn": {"handlers": ["default"], "level": "INFO", "propagate": False}, + "uvicorn.error": {"level": "INFO"}, + "uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False}, + }, +} + +logger = logging.getLogger("uvicorn.error") + + +def create_ssl_context( + certfile: str | os.PathLike[str], + keyfile: str | os.PathLike[str] | None, + password: str | None, + ssl_version: int, + cert_reqs: int, + ca_certs: str | os.PathLike[str] | None, + ciphers: str | None, + alpn_protocols: list[str] | None = None, +) -> ssl.SSLContext: + ctx = ssl.SSLContext(ssl_version) + get_password = (lambda: password) if password else None + ctx.load_cert_chain(certfile, keyfile, get_password) + ctx.verify_mode = ssl.VerifyMode(cert_reqs) + if ca_certs: + ctx.load_verify_locations(ca_certs) + if ciphers: + ctx.set_ciphers(ciphers) + if alpn_protocols: # pragma: no-zttp-h2 + ctx.set_alpn_protocols(alpn_protocols) + return ctx + + +def is_dir(path: Path) -> bool: + try: + if not path.is_absolute(): + path = path.resolve() + return path.is_dir() + except OSError: # pragma: full coverage + return False + + +def resolve_reload_patterns(patterns_list: list[str], directories_list: list[str]) -> tuple[list[str], list[Path]]: + directories: list[Path] = list(set(map(Path, directories_list.copy()))) + patterns: list[str] = patterns_list.copy() + + current_working_directory = Path.cwd() + for pattern in patterns_list: + # Special case for the .* pattern, otherwise this would only match + # hidden directories which is probably undesired + if pattern == ".*": + continue # pragma: py-not-linux + patterns.append(pattern) + if is_dir(Path(pattern)): + directories.append(Path(pattern)) + else: + for match in current_working_directory.glob(pattern): + if is_dir(match): + directories.append(match) + + directories = list(set(directories)) + directories = list(map(Path, directories)) + directories = list(map(lambda x: x.resolve(), directories)) + directories = list({reload_path for reload_path in directories if is_dir(reload_path)}) + + children = [] + for j in range(len(directories)): + for k in range(j + 1, len(directories)): # pragma: full coverage + if directories[j] in directories[k].parents: + children.append(directories[k]) + elif directories[k] in directories[j].parents: + children.append(directories[j]) + + directories = list(set(directories).difference(set(children))) + + return list(set(patterns)), directories + + +def _normalize_dirs(dirs: list[str] | str | None) -> list[str]: + if dirs is None: + return [] + if isinstance(dirs, str): + return [dirs] + return list(set(dirs)) + + +class Config: + def __init__( + self, + app: ASGIApplication | Callable[..., Any] | str, + host: str = "127.0.0.1", + port: int = 8000, + uds: str | None = None, + fd: int | None = None, + loop: LoopFactoryType | str = "auto", + http: type[asyncio.Protocol] | HTTPProtocolType | str = "auto", + http2: bool = False, + ws: type[asyncio.Protocol] | WSProtocolType | str = "auto", + ws_max_size: int = 16 * 1024 * 1024, + ws_max_queue: int = 32, + ws_ping_interval: float | None = 20.0, + ws_ping_timeout: float | None = 20.0, + ws_per_message_deflate: bool = True, + lifespan: LifespanType = "auto", + env_file: str | os.PathLike[str] | None = None, + log_config: dict[str, Any] | str | os.PathLike[str] | RawConfigParser | IO[Any] | None = LOGGING_CONFIG, + log_level: str | int | None = None, + access_log: bool = True, + use_colors: bool | None = None, + interface: InterfaceType = "auto", + reload: bool = False, + reload_dirs: list[str] | str | None = None, + reload_delay: float = 0.25, + reload_includes: list[str] | str | None = None, + reload_excludes: list[str] | str | None = None, + workers: int | None = None, + proxy_headers: bool = True, + server_header: bool = True, + date_header: bool = True, + forwarded_allow_ips: list[str] | str | None = None, + root_path: str = "", + limit_concurrency: int | None = None, + limit_max_requests: int | None = None, + limit_max_requests_jitter: int = 0, + backlog: int = 2048, + timeout_keep_alive: int = 5, + timeout_notify: int = 30, + timeout_graceful_shutdown: int | None = None, + timeout_worker_healthcheck: int = 5, + callback_notify: Callable[..., Awaitable[None]] | None = None, + ssl_keyfile: str | os.PathLike[str] | None = None, + ssl_certfile: str | os.PathLike[str] | None = None, + ssl_keyfile_password: str | None = None, + ssl_version: int = SSL_PROTOCOL_VERSION, + ssl_cert_reqs: int = ssl.CERT_NONE, + ssl_ca_certs: str | os.PathLike[str] | None = None, + ssl_ciphers: str | None = None, + ssl_context_factory: Callable[[Config, Callable[[], ssl.SSLContext]], ssl.SSLContext] | None = None, + headers: list[tuple[str, str]] | None = None, + factory: bool = False, + h11_max_incomplete_event_size: int | None = None, + reset_contextvars: bool = False, + ): + self.app = app + self.host = host + self.port = port + self.uds = uds + self.fd = fd + self.loop = loop + self.http = http + self.http2 = http2 + self.ws = ws + self.ws_max_size = ws_max_size + self.ws_max_queue = ws_max_queue + self.ws_ping_interval = ws_ping_interval + self.ws_ping_timeout = ws_ping_timeout + self.ws_per_message_deflate = ws_per_message_deflate + self.lifespan = lifespan + self.log_config = log_config + self.log_level = log_level + self.access_log = access_log + self.use_colors = use_colors + self.interface = interface + self.reload = reload + self.reload_delay = reload_delay + self.workers = workers or 1 + self.proxy_headers = proxy_headers + self.server_header = server_header + self.date_header = date_header + self.root_path = root_path + self.limit_concurrency = limit_concurrency + self.limit_max_requests = limit_max_requests + self.limit_max_requests_jitter = limit_max_requests_jitter + self.backlog = backlog + self.timeout_keep_alive = timeout_keep_alive + self.timeout_notify = timeout_notify + self.timeout_graceful_shutdown = timeout_graceful_shutdown + self.timeout_worker_healthcheck = timeout_worker_healthcheck + self.callback_notify = callback_notify + self.ssl_keyfile = ssl_keyfile + self.ssl_certfile = ssl_certfile + self.ssl_keyfile_password = ssl_keyfile_password + self.ssl_version = ssl_version + self.ssl_cert_reqs = ssl_cert_reqs + self.ssl_ca_certs = ssl_ca_certs + self.ssl_ciphers = ssl_ciphers + self.ssl_context_factory = ssl_context_factory + self.headers: list[tuple[str, str]] = headers or [] + self.encoded_headers: list[tuple[bytes, bytes]] = [] + self.factory = factory + self.h11_max_incomplete_event_size = h11_max_incomplete_event_size + self.reset_contextvars = reset_contextvars + + self.loaded = False + self.configure_logging() + + self.reload_dirs: list[Path] = [] + self.reload_dirs_excludes: list[Path] = [] + self.reload_includes: list[str] = [] + self.reload_excludes: list[str] = [] + + if (reload_dirs or reload_includes or reload_excludes) and not self.should_reload: + logger.warning( + "Current configuration will not reload as not all conditions are met, please refer to documentation." + ) + + if self.should_reload: + reload_dirs = _normalize_dirs(reload_dirs) + reload_includes = _normalize_dirs(reload_includes) + reload_excludes = _normalize_dirs(reload_excludes) + + self.reload_includes, self.reload_dirs = resolve_reload_patterns(reload_includes, reload_dirs) + + self.reload_excludes, self.reload_dirs_excludes = resolve_reload_patterns(reload_excludes, []) + + reload_dirs_tmp = self.reload_dirs.copy() + + for directory in self.reload_dirs_excludes: + for reload_directory in reload_dirs_tmp: + if directory == reload_directory or directory in reload_directory.parents: + try: + self.reload_dirs.remove(reload_directory) + except ValueError: # pragma: full coverage + pass + + for pattern in self.reload_excludes: + if pattern in self.reload_includes: + self.reload_includes.remove(pattern) # pragma: full coverage + + if not self.reload_dirs: + if reload_dirs: + logger.warning( + "Provided reload directories %s did not contain valid " + + "directories, watching current working directory.", + reload_dirs, + ) + self.reload_dirs = [Path.cwd()] + + logger.info( + "Will watch for changes in these directories: %s", + sorted(list(map(str, self.reload_dirs))), + ) + + if env_file is not None: + from dotenv import load_dotenv + + logger.info("Loading environment from '%s'", env_file) + load_dotenv(dotenv_path=env_file) + + if workers is None and "WEB_CONCURRENCY" in os.environ: + self.workers = int(os.environ["WEB_CONCURRENCY"]) + + self.forwarded_allow_ips: list[str] | str + if forwarded_allow_ips is None: + self.forwarded_allow_ips = os.environ.get("FORWARDED_ALLOW_IPS", "127.0.0.1,::1") + else: + self.forwarded_allow_ips = forwarded_allow_ips # pragma: full coverage + + if self.reload and self.workers > 1: + logger.warning('"workers" flag is ignored when reloading is enabled.') + + @property + def asgi_version(self) -> Literal["2.0", "3.0"]: + mapping: dict[str, Literal["2.0", "3.0"]] = { + "asgi2": "2.0", + "asgi3": "3.0", + "wsgi": "3.0", + } + return mapping[self.interface] + + @property + def is_ssl(self) -> bool: + return bool(self.ssl_keyfile or self.ssl_certfile or self.ssl_context_factory) + + @property + def use_subprocess(self) -> bool: + return bool(self.reload or self.workers > 1) + + def configure_logging(self) -> None: + logging.addLevelName(TRACE_LOG_LEVEL, "TRACE") + + if self.log_config is not None: + if isinstance(self.log_config, os.PathLike): + self.log_config = os.fspath(self.log_config) + + if isinstance(self.log_config, dict): + if self.use_colors in (True, False): + self.log_config["formatters"]["default"]["use_colors"] = self.use_colors + self.log_config["formatters"]["access"]["use_colors"] = self.use_colors + logging.config.dictConfig(self.log_config) + elif isinstance(self.log_config, str) and self.log_config.endswith(".json"): + with open(self.log_config) as file: + loaded_config = json.load(file) + logging.config.dictConfig(loaded_config) + elif isinstance(self.log_config, str) and self.log_config.endswith((".yaml", ".yml")): + try: + import yaml + except ImportError as e: + raise ImportError( + "Install the PyYAML package or uvicorn[standard] to use `--log-config` with YAML files." + ) from e + + with open(self.log_config) as file: + loaded_config = yaml.safe_load(file) + logging.config.dictConfig(loaded_config) + else: + # See the note about fileConfig() here: + # https://docs.python.org/3/library/logging.config.html#configuration-file-format + logging.config.fileConfig(self.log_config, disable_existing_loggers=False) + + if self.log_level is not None: + if isinstance(self.log_level, str): + log_level = LOG_LEVELS[self.log_level.lower()] + else: + log_level = self.log_level + logging.getLogger("uvicorn.error").setLevel(log_level) + logging.getLogger("uvicorn.access").setLevel(log_level) + logging.getLogger("uvicorn.asgi").setLevel(log_level) + if self.access_log is False: + logging.getLogger("uvicorn.access").handlers = [] + logging.getLogger("uvicorn.access").propagate = False + + def load_app(self) -> Any: + """Import the app and return it. Exits on failure.""" + try: + return import_from_string(self.app) + except ImportFromStringError as exc: + logger.error("Error loading ASGI app. %s" % exc) + sys.exit(STARTUP_FAILURE) + + def load(self) -> None: + assert not self.loaded + + if self.http2: + if self.http != "zttp": + raise ValueError( + "HTTP/2 requires the `zttp` HTTP protocol. Install it with `pip install zttp`, then select it " + "with `http='zttp'`. See https://uvicorn.dev/concepts/http2/ for more information." + ) + http_protocol_class = import_from_string("uvicorn.protocols.http.auto_zttp_impl:AutoZttpProtocol") + self.http_protocol_class: type[asyncio.Protocol] = http_protocol_class + elif isinstance(self.http, str): + self.http_protocol_class = import_from_string(HTTP_PROTOCOLS.get(self.http, self.http)) + else: + self.http_protocol_class = self.http + + alpn_protocols: list[str] | None = getattr(self.http_protocol_class, "alpn_protocols", None) + + if self.ssl_context_factory is not None: + + def default_factory() -> ssl.SSLContext: + if not self.ssl_certfile: + raise RuntimeError( + "`default_ssl_context_factory()` requires `ssl_certfile` to be set on `Config`. " + "Either pass `ssl_certfile` (and optionally `ssl_keyfile`) or build the `SSLContext` " + "directly inside `ssl_context_factory` without calling the default factory." + ) + return create_ssl_context( + keyfile=self.ssl_keyfile, + certfile=self.ssl_certfile, + password=self.ssl_keyfile_password, + ssl_version=self.ssl_version, + cert_reqs=self.ssl_cert_reqs, + ca_certs=self.ssl_ca_certs, + ciphers=self.ssl_ciphers, + alpn_protocols=alpn_protocols, + ) + + context = self.ssl_context_factory(self, default_factory) + if not isinstance(context, ssl.SSLContext): + raise TypeError(f"`ssl_context_factory` must return an `ssl.SSLContext`, got {type(context).__name__}") + self.ssl: ssl.SSLContext | None = context + elif self.is_ssl: + assert self.ssl_certfile + self.ssl = create_ssl_context( + keyfile=self.ssl_keyfile, + certfile=self.ssl_certfile, + password=self.ssl_keyfile_password, + ssl_version=self.ssl_version, + cert_reqs=self.ssl_cert_reqs, + ca_certs=self.ssl_ca_certs, + ciphers=self.ssl_ciphers, + alpn_protocols=alpn_protocols, + ) + else: + self.ssl = None + + encoded_headers = [(key.lower().encode("latin1"), value.encode("latin1")) for key, value in self.headers] + self.encoded_headers = ( + [(b"server", b"uvicorn")] + encoded_headers + if b"server" not in dict(encoded_headers) and self.server_header + else encoded_headers + ) + + if isinstance(self.ws, str): + ws_protocol_class = import_from_string(WS_PROTOCOLS.get(self.ws, self.ws)) + self.ws_protocol_class: type[asyncio.Protocol] | None = ws_protocol_class + else: + self.ws_protocol_class = self.ws + + self.lifespan_class = import_from_string(LIFESPAN[self.lifespan]) + + self.loaded_app = self.load_app() + + try: + self.loaded_app = self.loaded_app() + except TypeError as exc: + if self.factory: + logger.error("Error loading ASGI app factory: %s", exc) + sys.exit(STARTUP_FAILURE) + else: + if not self.factory: + logger.warning( + "ASGI app factory detected. Using it, but please consider setting the --factory flag explicitly." + ) + + if self.interface == "auto": + if inspect.isclass(self.loaded_app): + use_asgi_3 = hasattr(self.loaded_app, "__await__") + elif inspect.isfunction(self.loaded_app): + use_asgi_3 = iscoroutinefunction(self.loaded_app) + else: + call = getattr(self.loaded_app, "__call__", None) + use_asgi_3 = iscoroutinefunction(call) + self.interface = "asgi3" if use_asgi_3 else "asgi2" + + if self.interface == "wsgi": + self.loaded_app = WSGIMiddleware(self.loaded_app) + self.ws_protocol_class = None + elif self.interface == "asgi2": + self.loaded_app = ASGI2Middleware(self.loaded_app) + + if logger.getEffectiveLevel() <= TRACE_LOG_LEVEL: + self.loaded_app = MessageLoggerMiddleware(self.loaded_app) + if self.proxy_headers: + self.loaded_app = ProxyHeadersMiddleware(self.loaded_app, trusted_hosts=self.forwarded_allow_ips) + + self.loaded = True + + def setup_event_loop(self) -> None: + raise AttributeError( + "The `setup_event_loop` method was replaced by `get_loop_factory` in uvicorn 0.36.0.\n" + "None of those methods are supposed to be used directly. If you are doing it, please let me know here: " + "https://github.com/Kludex/uvicorn/discussions/2706. Thank you, and sorry for the inconvenience." + ) + + def get_loop_factory(self) -> Callable[[], asyncio.AbstractEventLoop] | None: + if self.loop in LOOP_FACTORIES: + loop_factory: Callable[..., Any] | None = import_from_string(LOOP_FACTORIES[self.loop]) + else: + try: + return import_from_string(self.loop) + except ImportFromStringError as exc: + logger.error("Error loading custom loop setup function. %s" % exc) + sys.exit(STARTUP_FAILURE) + if loop_factory is None: + return None + return loop_factory(use_subprocess=self.use_subprocess) + + def bind_socket(self) -> socket.socket: + logger_args: list[str | int] + if self.uds is not None: # pragma: py-win32 + path = self.uds + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + sock.bind(path) + uds_perms = 0o666 + os.chmod(self.uds, uds_perms) + except OSError as exc: # pragma: full coverage + logger.error(exc) + sys.exit(STARTUP_FAILURE) + + message = "Uvicorn running on unix socket %s (Press CTRL+C to quit)" + sock_name_format = "%s" + color_message = "Uvicorn running on " + style(sock_name_format, bold=True) + " (Press CTRL+C to quit)" + logger_args = [self.uds] + elif self.fd is not None: # pragma: py-win32 + sock = socket.fromfd(self.fd, socket.AF_UNIX, socket.SOCK_STREAM) + message = "Uvicorn running on socket %s (Press CTRL+C to quit)" + fd_name_format = "%s" + color_message = "Uvicorn running on " + style(fd_name_format, bold=True) + " (Press CTRL+C to quit)" + logger_args = [sock.getsockname()] + else: + family = socket.AF_INET + addr_format = "%s://%s:%d" + + if self.host and ":" in self.host: # pragma: full coverage + # It's an IPv6 address. + family = socket.AF_INET6 + addr_format = "%s://[%s]:%d" + + sock = socket.socket(family=family) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + sock.bind((self.host, self.port)) + except OSError as exc: # pragma: full coverage + logger.error(exc) + sys.exit(STARTUP_FAILURE) + + message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)" + color_message = "Uvicorn running on " + style(addr_format, bold=True) + " (Press CTRL+C to quit)" + protocol_name = "https" if self.is_ssl else "http" + logger_args = [protocol_name, self.host, sock.getsockname()[1]] + logger.info(message, *logger_args, extra={"color_message": color_message}) + sock.set_inheritable(True) + return sock + + @property + def should_reload(self) -> bool: + return isinstance(self.app, str) and self.reload diff --git a/source/target-vendors/cp312/uvicorn/importer.py b/source/target-vendors/cp312/uvicorn/importer.py new file mode 100644 index 0000000..f77520e --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/importer.py @@ -0,0 +1,34 @@ +import importlib +from typing import Any + + +class ImportFromStringError(Exception): + pass + + +def import_from_string(import_str: Any) -> Any: + if not isinstance(import_str, str): + return import_str + + module_str, _, attrs_str = import_str.partition(":") + if not module_str or not attrs_str: + message = 'Import string "{import_str}" must be in format ":".' + raise ImportFromStringError(message.format(import_str=import_str)) + + try: + module = importlib.import_module(module_str) + except ModuleNotFoundError as exc: + if exc.name != module_str: + raise exc from None + message = 'Could not import module "{module_str}".' + raise ImportFromStringError(message.format(module_str=module_str)) + + instance = module + try: + for attr_str in attrs_str.split("."): + instance = getattr(instance, attr_str) + except AttributeError: + message = 'Attribute "{attrs_str}" not found in module "{module_str}".' + raise ImportFromStringError(message.format(attrs_str=attrs_str, module_str=module_str)) + + return instance diff --git a/source/target-vendors/cp312/uvicorn/lifespan/__init__.py b/source/target-vendors/cp312/uvicorn/lifespan/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/uvicorn/lifespan/off.py b/source/target-vendors/cp312/uvicorn/lifespan/off.py new file mode 100644 index 0000000..74554b1 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/lifespan/off.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from typing import Any + +from uvicorn import Config + + +class LifespanOff: + def __init__(self, config: Config) -> None: + self.should_exit = False + self.state: dict[str, Any] = {} + + async def startup(self) -> None: + pass + + async def shutdown(self) -> None: + pass diff --git a/source/target-vendors/cp312/uvicorn/lifespan/on.py b/source/target-vendors/cp312/uvicorn/lifespan/on.py new file mode 100644 index 0000000..71ac394 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/lifespan/on.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +import asyncio +import logging +from asyncio import Queue +from typing import Any + +from uvicorn import Config +from uvicorn._types import ( + LifespanScope, + LifespanShutdownCompleteEvent, + LifespanShutdownEvent, + LifespanShutdownFailedEvent, + LifespanStartupCompleteEvent, + LifespanStartupEvent, + LifespanStartupFailedEvent, +) + +LifespanReceiveMessage = LifespanStartupEvent | LifespanShutdownEvent +LifespanSendMessage = ( + LifespanStartupFailedEvent + | LifespanShutdownFailedEvent + | LifespanStartupCompleteEvent + | LifespanShutdownCompleteEvent +) + + +STATE_TRANSITION_ERROR = "Got invalid state transition on lifespan protocol." + + +class LifespanOn: + def __init__(self, config: Config) -> None: + if not config.loaded: + config.load() + + self.config = config + self.logger = logging.getLogger("uvicorn.error") + self.startup_event = asyncio.Event() + self.shutdown_event = asyncio.Event() + self.receive_queue: Queue[LifespanReceiveMessage] = asyncio.Queue() + self.error_occurred = False + self.startup_failed = False + self.shutdown_failed = False + self.should_exit = False + self.state: dict[str, Any] = {} + + async def startup(self) -> None: + self.logger.info("Waiting for application startup.") + + loop = asyncio.get_event_loop() + main_lifespan_task = loop.create_task(self.main()) # noqa: F841 + # Keep a hard reference to prevent garbage collection + # See https://github.com/Kludex/uvicorn/pull/972 + startup_event: LifespanStartupEvent = {"type": "lifespan.startup"} + await self.receive_queue.put(startup_event) + await self.startup_event.wait() + + if self.startup_failed or (self.error_occurred and self.config.lifespan == "on"): + self.logger.error("Application startup failed. Exiting.") + self.should_exit = True + else: + self.logger.info("Application startup complete.") + + async def shutdown(self) -> None: + if self.error_occurred: + return + self.logger.info("Waiting for application shutdown.") + shutdown_event: LifespanShutdownEvent = {"type": "lifespan.shutdown"} + await self.receive_queue.put(shutdown_event) + await self.shutdown_event.wait() + + if self.shutdown_failed or (self.error_occurred and self.config.lifespan == "on"): + self.logger.error("Application shutdown failed. Exiting.") + self.should_exit = True + else: + self.logger.info("Application shutdown complete.") + + async def main(self) -> None: + try: + app = self.config.loaded_app + scope: LifespanScope = { + "type": "lifespan", + "asgi": {"version": self.config.asgi_version, "spec_version": "2.0"}, + "state": self.state, + } + await app(scope, self.receive, self.send) + except BaseException as exc: + self.asgi = None + self.error_occurred = True + if self.startup_failed or self.shutdown_failed: + return + if self.config.lifespan == "auto": + msg = "ASGI 'lifespan' protocol appears unsupported." + self.logger.info(msg) + else: + msg = "Exception in 'lifespan' protocol\n" + self.logger.error(msg, exc_info=exc) + finally: + self.startup_event.set() + self.shutdown_event.set() + + async def send(self, message: LifespanSendMessage) -> None: + assert message["type"] in ( + "lifespan.startup.complete", + "lifespan.startup.failed", + "lifespan.shutdown.complete", + "lifespan.shutdown.failed", + ) + + if message["type"] == "lifespan.startup.complete": + assert not self.startup_event.is_set(), STATE_TRANSITION_ERROR + assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR + self.startup_event.set() + + elif message["type"] == "lifespan.startup.failed": + assert not self.startup_event.is_set(), STATE_TRANSITION_ERROR + assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR + self.startup_event.set() + self.startup_failed = True + if message.get("message"): + self.logger.error(message["message"]) + + elif message["type"] == "lifespan.shutdown.complete": + assert self.startup_event.is_set(), STATE_TRANSITION_ERROR + assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR + self.shutdown_event.set() + + elif message["type"] == "lifespan.shutdown.failed": + assert self.startup_event.is_set(), STATE_TRANSITION_ERROR + assert not self.shutdown_event.is_set(), STATE_TRANSITION_ERROR + self.shutdown_event.set() + self.shutdown_failed = True + if message.get("message"): + self.logger.error(message["message"]) + + async def receive(self) -> LifespanReceiveMessage: + return await self.receive_queue.get() diff --git a/source/target-vendors/cp312/uvicorn/logging.py b/source/target-vendors/cp312/uvicorn/logging.py new file mode 100644 index 0000000..28c65fc --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/logging.py @@ -0,0 +1,117 @@ +from __future__ import annotations + +import http +import logging +import sys +from copy import copy +from typing import Literal + +from uvicorn._ansi import style as ansi_style + +TRACE_LOG_LEVEL = 5 + + +class ColourizedFormatter(logging.Formatter): + """ + A custom log formatter class that: + + * Outputs the LOG_LEVEL with an appropriate color. + * If a log call includes an `extra={"color_message": ...}` it will be used + for formatting the output, instead of the plain text message. + """ + + level_name_colors = { + TRACE_LOG_LEVEL: lambda level_name: ansi_style(str(level_name), fg="blue"), + logging.DEBUG: lambda level_name: ansi_style(str(level_name), fg="cyan"), + logging.INFO: lambda level_name: ansi_style(str(level_name), fg="green"), + logging.WARNING: lambda level_name: ansi_style(str(level_name), fg="yellow"), + logging.ERROR: lambda level_name: ansi_style(str(level_name), fg="red"), + logging.CRITICAL: lambda level_name: ansi_style(str(level_name), fg="bright_red"), + } + + def __init__( + self, + fmt: str | None = None, + datefmt: str | None = None, + style: Literal["%", "{", "$"] = "%", + use_colors: bool | None = None, + ): + if use_colors in (True, False): + self.use_colors = use_colors + else: + self.use_colors = sys.stdout.isatty() + super().__init__(fmt=fmt, datefmt=datefmt, style=style) + + def color_level_name(self, level_name: str, level_no: int) -> str: + def default(level_name: str) -> str: + return str(level_name) # pragma: no cover + + func = self.level_name_colors.get(level_no, default) + return func(level_name) + + def should_use_colors(self) -> bool: + return True # pragma: no cover + + def formatMessage(self, record: logging.LogRecord) -> str: + recordcopy = copy(record) + levelname = recordcopy.levelname + separator = " " * (8 - len(recordcopy.levelname)) + if self.use_colors: + levelname = self.color_level_name(levelname, recordcopy.levelno) + if "color_message" in recordcopy.__dict__: + recordcopy.msg = recordcopy.__dict__["color_message"] + recordcopy.__dict__["message"] = recordcopy.getMessage() + recordcopy.__dict__["levelprefix"] = levelname + ":" + separator + return super().formatMessage(recordcopy) + + +class DefaultFormatter(ColourizedFormatter): + def should_use_colors(self) -> bool: + return sys.stderr.isatty() # pragma: no cover + + +class AccessFormatter(ColourizedFormatter): + status_code_colours = { + 1: lambda code: ansi_style(str(code), fg="bright_white"), + 2: lambda code: ansi_style(str(code), fg="green"), + 3: lambda code: ansi_style(str(code), fg="yellow"), + 4: lambda code: ansi_style(str(code), fg="red"), + 5: lambda code: ansi_style(str(code), fg="bright_red"), + } + + def get_status_code(self, status_code: int) -> str: + try: + status_phrase = http.HTTPStatus(status_code).phrase + except ValueError: + status_phrase = "" + status_and_phrase = f"{status_code} {status_phrase}" + if self.use_colors: + + def default(code: int) -> str: + return status_and_phrase # pragma: no cover + + func = self.status_code_colours.get(status_code // 100, default) + return func(status_and_phrase) + return status_and_phrase + + def formatMessage(self, record: logging.LogRecord) -> str: + recordcopy = copy(record) + ( + client_addr, + method, + full_path, + http_version, + status_code, + ) = recordcopy.args # type: ignore[misc] + status_code = self.get_status_code(int(status_code)) # type: ignore[arg-type] + request_line = f"{method} {full_path} HTTP/{http_version}" + if self.use_colors: + request_line = ansi_style(request_line, bold=True) + recordcopy.__dict__.update( + { + "client_addr": client_addr, + "request_line": request_line, + "status_code": status_code, + } + ) + return super().formatMessage(recordcopy) diff --git a/source/target-vendors/cp312/uvicorn/loops/__init__.py b/source/target-vendors/cp312/uvicorn/loops/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/uvicorn/loops/asyncio.py b/source/target-vendors/cp312/uvicorn/loops/asyncio.py new file mode 100644 index 0000000..ad6121e --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/loops/asyncio.py @@ -0,0 +1,11 @@ +from __future__ import annotations + +import asyncio +import sys +from collections.abc import Callable + + +def asyncio_loop_factory(use_subprocess: bool = False) -> Callable[[], asyncio.AbstractEventLoop]: + if sys.platform == "win32" and not use_subprocess: + return asyncio.ProactorEventLoop + return asyncio.SelectorEventLoop diff --git a/source/target-vendors/cp312/uvicorn/loops/auto.py b/source/target-vendors/cp312/uvicorn/loops/auto.py new file mode 100644 index 0000000..1908399 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/loops/auto.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +import asyncio +from collections.abc import Callable + + +def auto_loop_factory(use_subprocess: bool = False) -> Callable[[], asyncio.AbstractEventLoop]: + try: + import uvloop # noqa + except ImportError: # pragma: no cover + from uvicorn.loops.asyncio import asyncio_loop_factory as loop_factory + + return loop_factory(use_subprocess=use_subprocess) + else: # pragma: no cover + from uvicorn.loops.uvloop import uvloop_loop_factory + + return uvloop_loop_factory(use_subprocess=use_subprocess) diff --git a/source/target-vendors/cp312/uvicorn/loops/uvloop.py b/source/target-vendors/cp312/uvicorn/loops/uvloop.py new file mode 100644 index 0000000..c6692c5 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/loops/uvloop.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +import asyncio +from collections.abc import Callable + +import uvloop + + +def uvloop_loop_factory(use_subprocess: bool = False) -> Callable[[], asyncio.AbstractEventLoop]: + return uvloop.new_event_loop diff --git a/source/target-vendors/cp312/uvicorn/loops/zuvloop.py b/source/target-vendors/cp312/uvicorn/loops/zuvloop.py new file mode 100644 index 0000000..2bbbc4b --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/loops/zuvloop.py @@ -0,0 +1,10 @@ +from __future__ import annotations + +import asyncio +from collections.abc import Callable + +import zuvloop + + +def zuvloop_loop_factory(use_subprocess: bool = False) -> Callable[[], asyncio.AbstractEventLoop]: + return zuvloop.new_event_loop diff --git a/source/target-vendors/cp312/uvicorn/main.py b/source/target-vendors/cp312/uvicorn/main.py new file mode 100644 index 0000000..854c10b --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/main.py @@ -0,0 +1,656 @@ +from __future__ import annotations + +import asyncio +import logging +import os +import platform +import ssl +import sys +import warnings +from collections.abc import Callable +from configparser import RawConfigParser +from typing import IO, Any, get_args + +import click + +import uvicorn +from uvicorn._types import ASGIApplication +from uvicorn.config import ( + INTERFACES, + LIFESPAN, + LOG_LEVELS, + LOGGING_CONFIG, + SSL_PROTOCOL_VERSION, + STARTUP_FAILURE, + Config, + HTTPProtocolType, + InterfaceType, + LifespanType, + LoopFactoryType, + WSProtocolType, +) +from uvicorn.server import Server +from uvicorn.supervisors import ChangeReload, Multiprocess + +LEVEL_CHOICES = click.Choice(list(LOG_LEVELS.keys())) +LIFESPAN_CHOICES = click.Choice(list(LIFESPAN.keys())) +INTERFACE_CHOICES = click.Choice(INTERFACES) + + +def _metavar_from_type(_type: Any) -> str: + return f"[{'|'.join(key for key in get_args(_type) if key != 'none')}]" + + +logger = logging.getLogger("uvicorn.error") + + +def print_version(ctx: click.Context, param: click.Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + click.echo( + "Running uvicorn {version} with {py_implementation} {py_version} on {system}".format( # noqa: UP032 + version=uvicorn.__version__, + py_implementation=platform.python_implementation(), + py_version=platform.python_version(), + system=platform.system(), + ) + ) + ctx.exit() + + +@click.command(context_settings={"auto_envvar_prefix": "UVICORN"}) +@click.argument("app", envvar="UVICORN_APP") +@click.option( + "--host", + type=str, + default="127.0.0.1", + help="Bind socket to this host.", + show_default=True, +) +@click.option( + "--port", + type=int, + default=8000, + help="Bind socket to this port. If 0, an available port will be picked.", + show_default=True, +) +@click.option("--uds", type=str, default=None, help="Bind to a UNIX domain socket.") +@click.option("--fd", type=int, default=None, help="Bind to socket from this file descriptor.") +@click.option("--reload", is_flag=True, default=False, help="Enable auto-reload.") +@click.option( + "--reload-dir", + "reload_dirs", + multiple=True, + help="Set reload directories explicitly, instead of using the current working directory.", + type=click.Path(exists=True), +) +@click.option( + "--reload-include", + "reload_includes", + multiple=True, + help="Set glob patterns to include while watching for files. Includes '*.py' " + "by default; these defaults can be overridden with `--reload-exclude`. " + "This option has no effect unless watchfiles is installed.", +) +@click.option( + "--reload-exclude", + "reload_excludes", + multiple=True, + help="Set glob patterns to exclude while watching for files. Includes " + "'.*, .py[cod], .sw.*, ~*' by default; these defaults can be overridden " + "with `--reload-include`. This option has no effect unless watchfiles is " + "installed.", +) +@click.option( + "--reload-delay", + type=float, + default=0.25, + show_default=True, + help="Delay between previous and next check if application needs to be. Defaults to 0.25s.", +) +@click.option( + "--workers", + default=None, + type=int, + help="Number of worker processes. Defaults to the $WEB_CONCURRENCY environment" + " variable if available, or 1. Not valid with --reload.", +) +@click.option( + "--loop", + type=str, + metavar=_metavar_from_type(LoopFactoryType), + default="auto", + help="Event loop factory implementation.", + show_default=True, +) +@click.option( + "--http", + type=str, + metavar=_metavar_from_type(HTTPProtocolType), + default="auto", + help="HTTP protocol implementation.", + show_default=True, +) +@click.option( + "--http2", + is_flag=True, + default=False, + help="Enable HTTP/2 support. Requires --http zttp.", + show_default=True, +) +@click.option( + "--ws", + type=str, + metavar=_metavar_from_type(WSProtocolType), + default="auto", + help="WebSocket protocol implementation.", + show_default=True, +) +@click.option( + "--ws-max-size", + type=int, + default=16777216, + help="WebSocket max size message in bytes", + show_default=True, +) +@click.option( + "--ws-max-queue", + type=int, + default=32, + help="The maximum length of the WebSocket message queue.", + show_default=True, +) +@click.option( + "--ws-ping-interval", + type=float, + default=20.0, + help="WebSocket ping interval in seconds.", + show_default=True, +) +@click.option( + "--ws-ping-timeout", + type=float, + default=20.0, + help="WebSocket ping timeout in seconds.", + show_default=True, +) +@click.option( + "--ws-per-message-deflate", + type=bool, + default=True, + help="WebSocket per-message-deflate compression", + show_default=True, +) +@click.option( + "--lifespan", + type=LIFESPAN_CHOICES, + default="auto", + help="Lifespan implementation.", + show_default=True, +) +@click.option( + "--interface", + type=INTERFACE_CHOICES, + default="auto", + help="Select ASGI3, ASGI2, or WSGI as the application interface.", + show_default=True, +) +@click.option( + "--env-file", + type=click.Path(exists=True), + default=None, + help="Environment configuration file.", + show_default=True, +) +@click.option( + "--log-config", + type=click.Path(exists=True), + default=None, + help="Logging configuration file. Supported formats: .ini, .json, .yaml.", + show_default=True, +) +@click.option( + "--log-level", + type=LEVEL_CHOICES, + default=None, + help="Log level. [default: info]", + show_default=True, +) +@click.option( + "--access-log/--no-access-log", + is_flag=True, + default=True, + help="Enable/Disable access log.", +) +@click.option( + "--use-colors/--no-use-colors", + is_flag=True, + default=None, + help="Enable/Disable colorized logging.", +) +@click.option( + "--proxy-headers/--no-proxy-headers", + is_flag=True, + default=True, + help="Enable/Disable X-Forwarded-Proto, X-Forwarded-For to populate url scheme and remote address info.", +) +@click.option( + "--server-header/--no-server-header", + is_flag=True, + default=True, + help="Enable/Disable default Server header.", +) +@click.option( + "--date-header/--no-date-header", + is_flag=True, + default=True, + help="Enable/Disable default Date header.", +) +@click.option( + "--forwarded-allow-ips", + type=str, + default=None, + help="Comma separated list of IP Addresses, IP Networks, or literals " + "(e.g. UNIX Socket path) to trust with proxy headers. Defaults to the " + "$FORWARDED_ALLOW_IPS environment variable if available, or '127.0.0.1,::1'. " + "The literal '*' means trust everything.", +) +@click.option( + "--root-path", + type=str, + default="", + help="Set the ASGI 'root_path' for applications submounted below a given URL path.", +) +@click.option( + "--limit-concurrency", + type=int, + default=None, + help="Maximum number of concurrent connections or tasks to allow, before issuing HTTP 503 responses.", +) +@click.option( + "--backlog", + type=int, + default=2048, + help="Maximum number of connections to hold in backlog", +) +@click.option( + "--limit-max-requests", + type=int, + default=None, + help="Maximum number of requests to service before terminating the process.", +) +@click.option( + "--limit-max-requests-jitter", + type=int, + default=0, + help="Maximum jitter to add to limit_max_requests." + " Staggers worker restarts to avoid all workers restarting simultaneously.", + show_default=True, +) +@click.option( + "--timeout-keep-alive", + type=int, + default=5, + help="Close Keep-Alive connections if no new data is received within this timeout (in seconds).", + show_default=True, +) +@click.option( + "--timeout-graceful-shutdown", + type=int, + default=None, + help="Maximum number of seconds to wait for graceful shutdown.", +) +@click.option( + "--timeout-worker-healthcheck", + type=int, + default=5, + help="Maximum number of seconds to wait for a worker to respond to a healthcheck.", + show_default=True, +) +@click.option("--ssl-keyfile", type=str, default=None, help="SSL key file", show_default=True) +@click.option( + "--ssl-certfile", + type=str, + default=None, + help="SSL certificate file", + show_default=True, +) +@click.option( + "--ssl-keyfile-password", + type=str, + default=None, + help="SSL keyfile password", + show_default=True, +) +@click.option( + "--ssl-version", + type=int, + default=int(SSL_PROTOCOL_VERSION), + help="SSL version to use (see stdlib ssl module's)", + show_default=True, +) +@click.option( + "--ssl-cert-reqs", + type=int, + default=int(ssl.CERT_NONE), + help="Whether client certificate is required (see stdlib ssl module's)", + show_default=True, +) +@click.option( + "--ssl-ca-certs", + type=str, + default=None, + help="CA certificates file", + show_default=True, +) +@click.option( + "--ssl-ciphers", + type=str, + default=None, + help="Ciphers to use (see stdlib ssl module's). Defaults to OpenSSL's safe defaults.", + show_default=True, +) +@click.option( + "--header", + "headers", + multiple=True, + help="Specify custom default HTTP response headers as a Name:Value pair", +) +@click.option( + "--version", + is_flag=True, + callback=print_version, + expose_value=False, + is_eager=True, + help="Display the uvicorn version and exit.", +) +@click.option( + "--app-dir", + default="", + show_default=True, + help="Look for APP in the specified directory, by adding this to the PYTHONPATH." + " Defaults to the current working directory.", +) +@click.option( + "--h11-max-incomplete-event-size", + "h11_max_incomplete_event_size", + type=int, + default=None, + help="For h11, the maximum number of bytes to buffer of an incomplete event.", +) +@click.option( + "--reset-contextvars", + is_flag=True, + default=False, + help="Run each ASGI request in a fresh contextvars.Context. Hides context set in the lifespan.", + show_default=True, +) +@click.option( + "--factory", + is_flag=True, + default=False, + help="Treat APP as an application factory, i.e. a () -> callable.", + show_default=True, +) +def main( + app: str, + host: str, + port: int, + uds: str, + fd: int, + loop: LoopFactoryType | str, + http: HTTPProtocolType | str, + http2: bool, + ws: WSProtocolType | str, + ws_max_size: int, + ws_max_queue: int, + ws_ping_interval: float, + ws_ping_timeout: float, + ws_per_message_deflate: bool, + lifespan: LifespanType, + interface: InterfaceType, + reload: bool, + reload_dirs: list[str], + reload_includes: list[str], + reload_excludes: list[str], + reload_delay: float, + workers: int, + env_file: str, + log_config: str, + log_level: str, + access_log: bool, + proxy_headers: bool, + server_header: bool, + date_header: bool, + forwarded_allow_ips: str, + root_path: str, + limit_concurrency: int, + backlog: int, + limit_max_requests: int, + limit_max_requests_jitter: int, + timeout_keep_alive: int, + timeout_graceful_shutdown: int | None, + timeout_worker_healthcheck: int, + ssl_keyfile: str, + ssl_certfile: str, + ssl_keyfile_password: str, + ssl_version: int, + ssl_cert_reqs: int, + ssl_ca_certs: str, + ssl_ciphers: str | None, + headers: list[str], + use_colors: bool, + app_dir: str, + h11_max_incomplete_event_size: int | None, + reset_contextvars: bool, + factory: bool, +) -> None: + run( + app, + host=host, + port=port, + uds=uds, + fd=fd, + loop=loop, + http=http, + http2=http2, + ws=ws, + ws_max_size=ws_max_size, + ws_max_queue=ws_max_queue, + ws_ping_interval=ws_ping_interval, + ws_ping_timeout=ws_ping_timeout, + ws_per_message_deflate=ws_per_message_deflate, + lifespan=lifespan, + env_file=env_file, + log_config=LOGGING_CONFIG if log_config is None else log_config, + log_level=log_level, + access_log=access_log, + interface=interface, + reload=reload, + reload_dirs=reload_dirs or None, + reload_includes=reload_includes or None, + reload_excludes=reload_excludes or None, + reload_delay=reload_delay, + workers=workers, + proxy_headers=proxy_headers, + server_header=server_header, + date_header=date_header, + forwarded_allow_ips=forwarded_allow_ips, + root_path=root_path, + limit_concurrency=limit_concurrency, + backlog=backlog, + limit_max_requests=limit_max_requests, + limit_max_requests_jitter=limit_max_requests_jitter, + timeout_keep_alive=timeout_keep_alive, + timeout_graceful_shutdown=timeout_graceful_shutdown, + timeout_worker_healthcheck=timeout_worker_healthcheck, + ssl_keyfile=ssl_keyfile, + ssl_certfile=ssl_certfile, + ssl_keyfile_password=ssl_keyfile_password, + ssl_version=ssl_version, + ssl_cert_reqs=ssl_cert_reqs, + ssl_ca_certs=ssl_ca_certs, + ssl_ciphers=ssl_ciphers, + headers=[header.split(":", 1) for header in headers], # type: ignore[misc] + use_colors=use_colors, + factory=factory, + app_dir=app_dir, + h11_max_incomplete_event_size=h11_max_incomplete_event_size, + reset_contextvars=reset_contextvars, + ) + + +def run( + app: ASGIApplication | Callable[..., Any] | str, + *, + host: str = "127.0.0.1", + port: int = 8000, + uds: str | None = None, + fd: int | None = None, + loop: LoopFactoryType | str = "auto", + http: type[asyncio.Protocol] | HTTPProtocolType | str = "auto", + http2: bool = False, + ws: type[asyncio.Protocol] | WSProtocolType | str = "auto", + ws_max_size: int = 16777216, + ws_max_queue: int = 32, + ws_ping_interval: float | None = 20.0, + ws_ping_timeout: float | None = 20.0, + ws_per_message_deflate: bool = True, + lifespan: LifespanType = "auto", + interface: InterfaceType = "auto", + reload: bool = False, + reload_dirs: list[str] | str | None = None, + reload_includes: list[str] | str | None = None, + reload_excludes: list[str] | str | None = None, + reload_delay: float = 0.25, + workers: int | None = None, + env_file: str | os.PathLike[str] | None = None, + log_config: dict[str, Any] | str | os.PathLike[str] | RawConfigParser | IO[Any] | None = LOGGING_CONFIG, + log_level: str | int | None = None, + access_log: bool = True, + proxy_headers: bool = True, + server_header: bool = True, + date_header: bool = True, + forwarded_allow_ips: list[str] | str | None = None, + root_path: str = "", + limit_concurrency: int | None = None, + backlog: int = 2048, + limit_max_requests: int | None = None, + limit_max_requests_jitter: int = 0, + timeout_keep_alive: int = 5, + timeout_graceful_shutdown: int | None = None, + timeout_worker_healthcheck: int = 5, + ssl_keyfile: str | os.PathLike[str] | None = None, + ssl_certfile: str | os.PathLike[str] | None = None, + ssl_keyfile_password: str | None = None, + ssl_version: int = SSL_PROTOCOL_VERSION, + ssl_cert_reqs: int = ssl.CERT_NONE, + ssl_ca_certs: str | os.PathLike[str] | None = None, + ssl_ciphers: str | None = None, + ssl_context_factory: Callable[[Config, Callable[[], ssl.SSLContext]], ssl.SSLContext] | None = None, + headers: list[tuple[str, str]] | None = None, + use_colors: bool | None = None, + app_dir: str | None = None, + factory: bool = False, + h11_max_incomplete_event_size: int | None = None, + reset_contextvars: bool = False, +) -> None: + if app_dir is not None: + sys.path.insert(0, app_dir) + + config = Config( + app, + host=host, + port=port, + uds=uds, + fd=fd, + loop=loop, + http=http, + http2=http2, + ws=ws, + ws_max_size=ws_max_size, + ws_max_queue=ws_max_queue, + ws_ping_interval=ws_ping_interval, + ws_ping_timeout=ws_ping_timeout, + ws_per_message_deflate=ws_per_message_deflate, + lifespan=lifespan, + interface=interface, + reload=reload, + reload_dirs=reload_dirs, + reload_includes=reload_includes, + reload_excludes=reload_excludes, + reload_delay=reload_delay, + workers=workers, + env_file=env_file, + log_config=log_config, + log_level=log_level, + access_log=access_log, + proxy_headers=proxy_headers, + server_header=server_header, + date_header=date_header, + forwarded_allow_ips=forwarded_allow_ips, + root_path=root_path, + limit_concurrency=limit_concurrency, + backlog=backlog, + limit_max_requests=limit_max_requests, + limit_max_requests_jitter=limit_max_requests_jitter, + timeout_keep_alive=timeout_keep_alive, + timeout_graceful_shutdown=timeout_graceful_shutdown, + timeout_worker_healthcheck=timeout_worker_healthcheck, + ssl_keyfile=ssl_keyfile, + ssl_certfile=ssl_certfile, + ssl_keyfile_password=ssl_keyfile_password, + ssl_version=ssl_version, + ssl_cert_reqs=ssl_cert_reqs, + ssl_ca_certs=ssl_ca_certs, + ssl_ciphers=ssl_ciphers, + ssl_context_factory=ssl_context_factory, + headers=headers, + use_colors=use_colors, + factory=factory, + h11_max_incomplete_event_size=h11_max_incomplete_event_size, + reset_contextvars=reset_contextvars, + ) + if config.reload or config.workers > 1: + if not isinstance(app, str): + logger = logging.getLogger("uvicorn.error") + logger.warning("You must pass the application as an import string to enable 'reload' or 'workers'.") + sys.exit(STARTUP_FAILURE) + else: + config.load_app() + + server = Server(config=config) + + try: + if config.should_reload: + sock = config.bind_socket() + ChangeReload(config, target=server.run, sockets=[sock]).run() + elif config.workers > 1: + sock = config.bind_socket() + Multiprocess(config, sockets=[sock]).run() + else: + server.run() + except KeyboardInterrupt: # pragma: full coverage + pass + finally: + if config.uds and os.path.exists(config.uds): + os.remove(config.uds) # pragma: py-win32 + + if not server.started and not config.should_reload and config.workers == 1: + sys.exit(STARTUP_FAILURE) + + +def __getattr__(name: str) -> Any: + if name == "ServerState": + warnings.warn( + "uvicorn.main.ServerState is deprecated, use uvicorn.server.ServerState instead.", + DeprecationWarning, + ) + from uvicorn.server import ServerState + + return ServerState + raise AttributeError(f"module {__name__} has no attribute {name}") + + +if __name__ == "__main__": + main() # pragma: no cover diff --git a/source/target-vendors/cp312/uvicorn/middleware/__init__.py b/source/target-vendors/cp312/uvicorn/middleware/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/uvicorn/middleware/asgi2.py b/source/target-vendors/cp312/uvicorn/middleware/asgi2.py new file mode 100644 index 0000000..4e15d15 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/middleware/asgi2.py @@ -0,0 +1,15 @@ +from uvicorn._types import ( + ASGI2Application, + ASGIReceiveCallable, + ASGISendCallable, + Scope, +) + + +class ASGI2Middleware: + def __init__(self, app: "ASGI2Application"): + self.app = app + + async def __call__(self, scope: "Scope", receive: "ASGIReceiveCallable", send: "ASGISendCallable") -> None: + instance = self.app(scope) + await instance(receive, send) diff --git a/source/target-vendors/cp312/uvicorn/middleware/message_logger.py b/source/target-vendors/cp312/uvicorn/middleware/message_logger.py new file mode 100644 index 0000000..0174bcc --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/middleware/message_logger.py @@ -0,0 +1,87 @@ +import logging +from typing import Any + +from uvicorn._types import ( + ASGI3Application, + ASGIReceiveCallable, + ASGIReceiveEvent, + ASGISendCallable, + ASGISendEvent, + WWWScope, +) +from uvicorn.logging import TRACE_LOG_LEVEL + +PLACEHOLDER_FORMAT = { + "body": "<{length} bytes>", + "bytes": "<{length} bytes>", + "text": "<{length} chars>", + "headers": "<...>", +} + + +def message_with_placeholders(message: Any) -> Any: + """ + Return an ASGI message, with any body-type content omitted and replaced + with a placeholder. + """ + new_message = message.copy() + for attr in PLACEHOLDER_FORMAT.keys(): + if message.get(attr) is not None: + content = message[attr] + placeholder = PLACEHOLDER_FORMAT[attr].format(length=len(content)) + new_message[attr] = placeholder + return new_message + + +class MessageLoggerMiddleware: + def __init__(self, app: "ASGI3Application"): + self.task_counter = 0 + self.app = app + self.logger = logging.getLogger("uvicorn.asgi") + + def trace(message: Any, *args: Any, **kwargs: Any) -> None: + self.logger.log(TRACE_LOG_LEVEL, message, *args, **kwargs) + + self.logger.trace = trace # type: ignore + + async def __call__( + self, + scope: "WWWScope", + receive: "ASGIReceiveCallable", + send: "ASGISendCallable", + ) -> None: + self.task_counter += 1 + + task_counter = self.task_counter + client = scope.get("client") + prefix = "%s:%d - ASGI" % (client[0], client[1]) if client else "ASGI" + + async def inner_receive() -> "ASGIReceiveEvent": + message = await receive() + logged_message = message_with_placeholders(message) + log_text = "%s [%d] Receive %s" + self.logger.trace( # type: ignore + log_text, prefix, task_counter, logged_message + ) + return message + + async def inner_send(message: "ASGISendEvent") -> None: + logged_message = message_with_placeholders(message) + log_text = "%s [%d] Send %s" + self.logger.trace( # type: ignore + log_text, prefix, task_counter, logged_message + ) + await send(message) + + logged_scope = message_with_placeholders(scope) + log_text = "%s [%d] Started scope=%s" + self.logger.trace(log_text, prefix, task_counter, logged_scope) # type: ignore + try: + await self.app(scope, inner_receive, inner_send) + except BaseException as exc: + log_text = "%s [%d] Raised exception" + self.logger.trace(log_text, prefix, task_counter) # type: ignore + raise exc from None + else: + log_text = "%s [%d] Completed" + self.logger.trace(log_text, prefix, task_counter) # type: ignore diff --git a/source/target-vendors/cp312/uvicorn/middleware/proxy_headers.py b/source/target-vendors/cp312/uvicorn/middleware/proxy_headers.py new file mode 100644 index 0000000..ebd210c --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/middleware/proxy_headers.py @@ -0,0 +1,187 @@ +from __future__ import annotations + +import functools +import ipaddress + +from uvicorn._types import ASGI3Application, ASGIReceiveCallable, ASGISendCallable, Scope + + +class ProxyHeadersMiddleware: + """Middleware for handling known proxy headers + + This middleware can be used when a known proxy is fronting the application, + and is trusted to be properly setting the `X-Forwarded-Proto` and + `X-Forwarded-For` headers with the connecting client information. + + Modifies the `client` and `scheme` information so that they reference + the connecting client, rather that the connecting proxy. + + References: + - + - + """ + + def __init__(self, app: ASGI3Application, trusted_hosts: list[str] | str = "127.0.0.1") -> None: + self.app = app + self.trusted_hosts = _TrustedHosts(trusted_hosts) + + async def __call__(self, scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None: + if scope["type"] == "lifespan": + return await self.app(scope, receive, send) + + client_addr = scope.get("client") + client_host = client_addr[0] if client_addr else None + + if client_host in self.trusted_hosts: + x_forwarded_proto_value: bytes | None = None + x_forwarded_for_values: list[bytes] = [] + for name, value in scope["headers"]: + if name == b"x-forwarded-proto": + x_forwarded_proto_value = value + elif name == b"x-forwarded-for": + x_forwarded_for_values.append(value) + + if x_forwarded_proto_value is not None: + x_forwarded_proto = x_forwarded_proto_value.decode("latin1").strip() + + if x_forwarded_proto in {"http", "https", "ws", "wss"}: + if scope["type"] == "websocket": + scope["scheme"] = x_forwarded_proto.replace("http", "ws") + else: + scope["scheme"] = x_forwarded_proto + + if x_forwarded_for_values: + x_forwarded_for = b", ".join(x_forwarded_for_values).decode("latin1") + host, port = self.trusted_hosts.get_trusted_client_address(x_forwarded_for) + + if host: + # If the x-forwarded-for header is empty then host is an empty string. + # Only set the client if we actually got something usable. + # See: https://github.com/Kludex/uvicorn/issues/1068 + scope["client"] = (host, port) + + return await self.app(scope, receive, send) + + +def _parse_raw_hosts(value: str) -> list[str]: + return [item.strip() for item in value.split(",")] + + +def _parse_host_port(value: str) -> tuple[str, int]: + """Parse a forwarded host value into host and optional port. + + Accepts bare IPs, IPv4 `host:port`, and bracketed IPv6 `[host]:port`. + Any unrecognized or malformed value is treated conservatively and returned + without a port so trust checks do not silently normalize arbitrary input. + """ + + if value.startswith("["): + bracket_end = value.find("]") + if bracket_end == -1: + return value, 0 + + host = value[1:bracket_end] + remainder = value[bracket_end + 1 :] + if not remainder: + return host, 0 + if not remainder.startswith(":"): + return value, 0 + + try: + return host, int(remainder[1:]) + except ValueError: + return host, 0 + + if value.count(":") == 1: + host, port = value.rsplit(":", 1) + try: + return host, int(port) + except ValueError: + return value, 0 + + return value, 0 + + +class _TrustedHosts: + """Container for trusted hosts and networks""" + + def __init__(self, trusted_hosts: list[str] | str) -> None: + self.always_trust: bool = trusted_hosts in ("*", ["*"]) + + self.trusted_literals: set[str] = set() + self.trusted_hosts: set[ipaddress.IPv4Address | ipaddress.IPv6Address] = set() + self.trusted_networks: set[ipaddress.IPv4Network | ipaddress.IPv6Network] = set() + + # Notes: + # - We separate hosts from literals as there are many ways to write + # an IPv6 Address so we need to compare by object. + # - We don't convert IP Address to single host networks (e.g. /32 / 128) as + # it more efficient to do an address lookup in a set than check for + # membership in each network. + # - We still allow literals as it might be possible that we receive a + # something that isn't an IP Address e.g. a unix socket. + + if not self.always_trust: + if isinstance(trusted_hosts, str): + trusted_hosts = _parse_raw_hosts(trusted_hosts) + + for host in trusted_hosts: + # Note: because we always convert invalid IP types to literals it + # is not possible for the user to know they provided a malformed IP + # type - this may lead to unexpected / difficult to debug behaviour. + + if "/" in host: + # Looks like a network + try: + self.trusted_networks.add(ipaddress.ip_network(host)) + except ValueError: + # Was not a valid IP Network + self.trusted_literals.add(host) + else: + try: + self.trusted_hosts.add(ipaddress.ip_address(host)) + except ValueError: + # Was not a valid IP Address + self.trusted_literals.add(host) + + self._trusts = functools.lru_cache(maxsize=4096)(self._compute_trust) + + def __contains__(self, host: str | None) -> bool: + if self.always_trust: + return True + + if not host: + return False + + # Don't cache hosts longer than a DNS name (253); they can't be trusted and would pin huge cache keys. + if len(host) > 253: + return self._compute_trust(host) # pragma: no cover + + return self._trusts(host) + + def _compute_trust(self, host: str) -> bool: + try: + ip = ipaddress.ip_address(host) + return ip in self.trusted_hosts or any(ip in net for net in self.trusted_networks) + except ValueError: + return host in self.trusted_literals + + def get_trusted_client_address(self, x_forwarded_for: str) -> tuple[str, int]: + """Extract the client address from x_forwarded_for header. + + In general this is the first "untrusted" host in the forwarded for list. + """ + x_forwarded_for_hosts = _parse_raw_hosts(x_forwarded_for) + + if self.always_trust: + return _parse_host_port(x_forwarded_for_hosts[0]) + + # Note: each proxy appends to the header list so check it in reverse order + for host_port in reversed(x_forwarded_for_hosts): + host, port = _parse_host_port(host_port) + if host not in self: + return host, port + + # All hosts are trusted meaning that the client was also a trusted proxy + # See https://github.com/Kludex/uvicorn/issues/1068#issuecomment-855371576 + return _parse_host_port(x_forwarded_for_hosts[0]) diff --git a/source/target-vendors/cp312/uvicorn/middleware/wsgi.py b/source/target-vendors/cp312/uvicorn/middleware/wsgi.py new file mode 100644 index 0000000..b2e3cb7 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/middleware/wsgi.py @@ -0,0 +1,199 @@ +from __future__ import annotations + +import asyncio +import concurrent.futures +import io +import sys +import warnings +from collections import deque +from collections.abc import Iterable + +from uvicorn._types import ( + ASGIReceiveCallable, + ASGIReceiveEvent, + ASGISendCallable, + ASGISendEvent, + Environ, + ExcInfo, + HTTPRequestEvent, + HTTPResponseBodyEvent, + HTTPResponseStartEvent, + HTTPScope, + StartResponse, + WSGIApp, +) + + +def build_environ(scope: HTTPScope, message: ASGIReceiveEvent, body: io.BytesIO) -> Environ: + """ + Builds a scope and request message into a WSGI environ object. + """ + script_name = scope.get("root_path", "").encode("utf8").decode("latin1") + path_info = scope["path"].encode("utf8").decode("latin1") + if path_info.startswith(script_name): + path_info = path_info[len(script_name) :] + environ = { + "REQUEST_METHOD": scope["method"], + "SCRIPT_NAME": script_name, + "PATH_INFO": path_info, + "QUERY_STRING": scope["query_string"].decode("ascii"), + "SERVER_PROTOCOL": "HTTP/%s" % scope["http_version"], + "wsgi.version": (1, 0), + "wsgi.url_scheme": scope.get("scheme", "http"), + "wsgi.input": body, + "wsgi.errors": sys.stdout, + "wsgi.multithread": True, + "wsgi.multiprocess": True, + "wsgi.run_once": False, + } + + # Get server name and port - required in WSGI, not in ASGI + server = scope.get("server") + if server is None: + server = ("localhost", 80) + environ["SERVER_NAME"] = server[0] + environ["SERVER_PORT"] = server[1] + + # Get client IP address + client = scope.get("client") + if client is not None: + environ["REMOTE_ADDR"] = client[0] + + # Go through headers and make them into environ entries + for name, value in scope.get("headers", []): + name_str: str = name.decode("latin1") + if name_str == "content-length": + corrected_name = "CONTENT_LENGTH" + elif name_str == "content-type": + corrected_name = "CONTENT_TYPE" + else: + corrected_name = "HTTP_%s" % name_str.upper().replace("-", "_") + # HTTPbis say only ASCII chars are allowed in headers, but we latin1 + # just in case + value_str: str = value.decode("latin1") + if corrected_name in environ: + corrected_name_environ = environ[corrected_name] + assert isinstance(corrected_name_environ, str) + value_str = corrected_name_environ + "," + value_str + environ[corrected_name] = value_str + return environ + + +class _WSGIMiddleware: + def __init__(self, app: WSGIApp, workers: int = 10): + warnings.warn( + "Uvicorn's native WSGI implementation is deprecated, you should switch to a2wsgi (`pip install a2wsgi`).", + DeprecationWarning, + ) + self.app = app + self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=workers) + + async def __call__( + self, + scope: HTTPScope, + receive: ASGIReceiveCallable, + send: ASGISendCallable, + ) -> None: + assert scope["type"] == "http" + instance = WSGIResponder(self.app, self.executor, scope) + await instance(receive, send) + + +class WSGIResponder: + def __init__( + self, + app: WSGIApp, + executor: concurrent.futures.ThreadPoolExecutor, + scope: HTTPScope, + ): + self.app = app + self.executor = executor + self.scope = scope + self.status = None + self.response_headers = None + self.send_event = asyncio.Event() + self.send_queue: deque[ASGISendEvent | None] = deque() + self.loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() + self.response_started = False + self.exc_info: ExcInfo | None = None + + async def __call__(self, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None: + message: HTTPRequestEvent = await receive() # type: ignore[assignment] + body = io.BytesIO(message.get("body", b"")) + more_body = message.get("more_body", False) + if more_body: + body.seek(0, io.SEEK_END) + while more_body: + body_message: HTTPRequestEvent = ( + await receive() # type: ignore[assignment] + ) + body.write(body_message.get("body", b"")) + more_body = body_message.get("more_body", False) + body.seek(0) + environ = build_environ(self.scope, message, body) + self.loop = asyncio.get_event_loop() + wsgi = self.loop.run_in_executor(self.executor, self.wsgi, environ, self.start_response) + sender = self.loop.create_task(self.sender(send)) + try: + await asyncio.wait_for(wsgi, None) + finally: + self.send_queue.append(None) + self.send_event.set() + await asyncio.wait_for(sender, None) + if self.exc_info is not None: + raise self.exc_info[0].with_traceback(self.exc_info[1], self.exc_info[2]) + + async def sender(self, send: ASGISendCallable) -> None: + while True: + if self.send_queue: + message = self.send_queue.popleft() + if message is None: + return + await send(message) + else: # pragma: no cover + await self.send_event.wait() + self.send_event.clear() + + def start_response( + self, + status: str, + response_headers: Iterable[tuple[str, str]], + exc_info: ExcInfo | None = None, + ) -> None: + self.exc_info = exc_info + if not self.response_started: + self.response_started = True + status_code_str, _ = status.split(" ", 1) + status_code = int(status_code_str) + headers = [(name.encode("ascii"), value.encode("ascii")) for name, value in response_headers] + http_response_start_event: HTTPResponseStartEvent = { + "type": "http.response.start", + "status": status_code, + "headers": headers, + } + self.send_queue.append(http_response_start_event) + self.loop.call_soon_threadsafe(self.send_event.set) + + def wsgi(self, environ: Environ, start_response: StartResponse) -> None: + for chunk in self.app(environ, start_response): # type: ignore + response_body: HTTPResponseBodyEvent = { + "type": "http.response.body", + "body": chunk, + "more_body": True, + } + self.send_queue.append(response_body) + self.loop.call_soon_threadsafe(self.send_event.set) + + empty_body: HTTPResponseBodyEvent = { + "type": "http.response.body", + "body": b"", + "more_body": False, + } + self.send_queue.append(empty_body) + self.loop.call_soon_threadsafe(self.send_event.set) + + +try: + from a2wsgi import WSGIMiddleware +except ModuleNotFoundError: # pragma: no cover + WSGIMiddleware = _WSGIMiddleware # type: ignore[misc, assignment] diff --git a/source/target-vendors/cp312/uvicorn/protocols/__init__.py b/source/target-vendors/cp312/uvicorn/protocols/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/__init__.py b/source/target-vendors/cp312/uvicorn/protocols/http/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/auto.py b/source/target-vendors/cp312/uvicorn/protocols/http/auto.py new file mode 100644 index 0000000..a14bec1 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/auto.py @@ -0,0 +1,15 @@ +from __future__ import annotations + +import asyncio + +AutoHTTPProtocol: type[asyncio.Protocol] +try: + import httptools # noqa +except ImportError: # pragma: no cover + from uvicorn.protocols.http.h11_impl import H11Protocol + + AutoHTTPProtocol = H11Protocol +else: # pragma: no cover + from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol + + AutoHTTPProtocol = HttpToolsProtocol diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/auto_zttp_impl.py b/source/target-vendors/cp312/uvicorn/protocols/http/auto_zttp_impl.py new file mode 100644 index 0000000..208c1f5 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/auto_zttp_impl.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +import asyncio +from typing import Any, ClassVar + +from uvicorn.config import Config +from uvicorn.protocols.http.zttp_h2_impl import ZttpH2Protocol +from uvicorn.protocols.http.zttp_impl import ZttpProtocol +from uvicorn.protocols.utils import is_ssl +from uvicorn.server import ServerState + +HTTP2_PREFACE = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n" + + +class AutoZttpProtocol(asyncio.Protocol): + """Dispatches each new connection to the HTTP/1.1 or HTTP/2 zttp protocol. + + Over TLS the choice is made from the ALPN result as soon as the connection + is made. On cleartext connections the first bytes are sniffed for the + HTTP/2 preface (prior-knowledge h2c); anything else is HTTP/1.1. + """ + + alpn_protocols: ClassVar[list[str]] = ["h2", "http/1.1"] + + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() + + self.config = config + self.server_state = server_state + self.app_state = app_state + self.loop = _loop or asyncio.get_event_loop() + self.connections = server_state.connections + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.timeout_task: asyncio.TimerHandle | None = None + self.buffer = b"" + + def connection_made( # type: ignore[override] + self, transport: asyncio.Transport + ) -> None: + self.transport = transport + if is_ssl(transport): + ssl_object = transport.get_extra_info("ssl_object") + alpn = ssl_object.selected_alpn_protocol() if ssl_object is not None else None + self._switch(http2=alpn == "h2") + return + self.connections.add(self) + self.timeout_task = self.loop.call_later(self.config.timeout_keep_alive, self.transport.close) + + def connection_lost(self, exc: Exception | None) -> None: + self.connections.discard(self) + if self.timeout_task is not None: + self.timeout_task.cancel() + self.timeout_task = None + + def eof_received(self) -> None: + pass + + def shutdown(self) -> None: + self.transport.close() + + def data_received(self, data: bytes) -> None: + self.buffer += data + if len(self.buffer) < len(HTTP2_PREFACE) and HTTP2_PREFACE.startswith(self.buffer): + return + self.connections.discard(self) + if self.timeout_task is not None: + self.timeout_task.cancel() + self.timeout_task = None + self._switch(http2=self.buffer.startswith(HTTP2_PREFACE), initial_data=self.buffer) + + def _switch(self, http2: bool, initial_data: bytes = b"") -> None: + protocol_class: type[asyncio.Protocol] = ZttpH2Protocol if http2 else ZttpProtocol + protocol = protocol_class( # type: ignore[call-arg] + config=self.config, + server_state=self.server_state, + app_state=self.app_state, + _loop=self.loop, + ) + self.transport.set_protocol(protocol) + protocol.connection_made(self.transport) + if initial_data: + protocol.data_received(initial_data) diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/flow_control.py b/source/target-vendors/cp312/uvicorn/protocols/http/flow_control.py new file mode 100644 index 0000000..2d1b5fa --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/flow_control.py @@ -0,0 +1,54 @@ +import asyncio + +from uvicorn._types import ASGIReceiveCallable, ASGISendCallable, Scope + +CLOSE_HEADER = (b"connection", b"close") + +HIGH_WATER_LIMIT = 65536 + + +class FlowControl: + def __init__(self, transport: asyncio.Transport) -> None: + self._transport = transport + self.read_paused = False + self.write_paused = False + self._is_writable_event = asyncio.Event() + self._is_writable_event.set() + + async def drain(self) -> None: + await self._is_writable_event.wait() # pragma: full coverage + + def pause_reading(self) -> None: + if not self.read_paused: + self.read_paused = True + self._transport.pause_reading() + + def resume_reading(self) -> None: + if self.read_paused: + self.read_paused = False + self._transport.resume_reading() + + def pause_writing(self) -> None: + if not self.write_paused: # pragma: full coverage + self.write_paused = True + self._is_writable_event.clear() + + def resume_writing(self) -> None: + if self.write_paused: # pragma: full coverage + self.write_paused = False + self._is_writable_event.set() + + +async def service_unavailable(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable) -> None: + await send( + { + "type": "http.response.start", + "status": 503, + "headers": [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"content-length", b"19"), + (b"connection", b"close"), + ], + } + ) + await send({"type": "http.response.body", "body": b"Service Unavailable", "more_body": False}) diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/h11_impl.py b/source/target-vendors/cp312/uvicorn/protocols/http/h11_impl.py new file mode 100644 index 0000000..e863f8b --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/h11_impl.py @@ -0,0 +1,540 @@ +from __future__ import annotations + +import asyncio +import contextvars +import http +import logging +import sys +from collections.abc import Callable +from typing import Any, Literal +from urllib.parse import unquote + +import h11 +from h11._connection import DEFAULT_MAX_INCOMPLETE_EVENT_SIZE + +from uvicorn._types import ( + ASGI3Application, + ASGIReceiveEvent, + ASGISendEvent, + HTTPRequestEvent, + HTTPResponseBodyEvent, + HTTPResponseStartEvent, + HTTPScope, +) +from uvicorn.config import Config +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.http.flow_control import CLOSE_HEADER, HIGH_WATER_LIMIT, FlowControl, service_unavailable +from uvicorn.protocols.utils import get_client_addr, get_local_addr, get_path_with_query_string, get_remote_addr, is_ssl +from uvicorn.server import ServerState + + +def _get_status_phrase(status_code: int) -> bytes: + try: + return http.HTTPStatus(status_code).phrase.encode() + except ValueError: + return b"" + + +STATUS_PHRASES = {status_code: _get_status_phrase(status_code) for status_code in range(100, 600)} + + +class H11Protocol(asyncio.Protocol): + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() + + self.config = config + self.app = config.loaded_app + self.loop = _loop or asyncio.get_event_loop() + self.logger = logging.getLogger("uvicorn.error") + self.access_logger = logging.getLogger("uvicorn.access") + self.access_log = self.access_logger.hasHandlers() + self.conn = h11.Connection( + h11.SERVER, + config.h11_max_incomplete_event_size + if config.h11_max_incomplete_event_size is not None + else DEFAULT_MAX_INCOMPLETE_EVENT_SIZE, + ) + self.ws_protocol_class = config.ws_protocol_class + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.limit_concurrency = config.limit_concurrency + self.app_state = app_state + + # Timeouts + self.timeout_keep_alive_task: asyncio.TimerHandle | None = None + self.timeout_keep_alive = config.timeout_keep_alive + + # Shared server state + self.server_state = server_state + self.connections = server_state.connections + self.tasks = server_state.tasks + + # Per-connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.flow: FlowControl = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["http", "https"] | None = None + + # Per-request state + self.scope: HTTPScope = None # type: ignore[assignment] + self.headers: list[tuple[bytes, bytes]] = None # type: ignore[assignment] + self.cycle: RequestResponseCycle = None # type: ignore[assignment] + + # Protocol interface + def connection_made( # type: ignore[override] + self, transport: asyncio.Transport + ) -> None: + self.connections.add(self) + + self.transport = transport + self.flow = FlowControl(transport) + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "https" if is_ssl(transport) else "http" + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection made", prefix) + + def connection_lost(self, exc: Exception | None) -> None: + self.connections.discard(self) + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection lost", prefix) + + if self.cycle and not self.cycle.response_complete: + self.cycle.disconnected = True + if self.conn.our_state != h11.ERROR: + event = h11.ConnectionClosed() + try: + self.conn.send(event) + except h11.LocalProtocolError: + # Premature client disconnect + pass + + if self.cycle is not None: + self.cycle.message_event.set() + if self.flow is not None: + self.flow.resume_writing() + if exc is None: + self.transport.close() + self._unset_keepalive_if_required() + + def eof_received(self) -> None: + pass + + def _unset_keepalive_if_required(self) -> None: + if self.timeout_keep_alive_task is not None: + self.timeout_keep_alive_task.cancel() + self.timeout_keep_alive_task = None + + def _get_upgrade(self) -> bytes | None: + connection = [] + upgrade = None + for name, value in self.headers: + if name == b"connection": + connection = [token.lower().strip() for token in value.split(b",")] + if name == b"upgrade": + upgrade = value.lower() + if b"upgrade" in connection: + return upgrade + return None + + def _should_upgrade_to_ws(self) -> bool: + if self.ws_protocol_class is None: + return False + return True + + def _unsupported_upgrade_warning(self) -> None: + msg = "Unsupported upgrade request." + self.logger.warning(msg) + if not self._should_upgrade_to_ws(): + msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501 + self.logger.warning(msg) + + def _should_upgrade(self) -> bool: + upgrade = self._get_upgrade() + if upgrade == b"websocket" and self._should_upgrade_to_ws(): + return True + if upgrade is not None: + self._unsupported_upgrade_warning() + return False + + def data_received(self, data: bytes) -> None: + self._unset_keepalive_if_required() + + self.conn.receive_data(data) + self.handle_events() + + def handle_events(self) -> None: + while True: + try: + event = self.conn.next_event() + except h11.RemoteProtocolError: + msg = "Invalid HTTP request received." + self.logger.warning(msg) + self.send_400_response(msg) + return + + if event is h11.NEED_DATA: + break + + elif event is h11.PAUSED: + # This case can occur in HTTP pipelining, so we need to + # stop reading any more data, and ensure that at the end + # of the active request/response cycle we handle any + # events that have been buffered up. + self.flow.pause_reading() + break + + elif isinstance(event, h11.Request): + # Pipelined HTTP requests and WebSocket upgrades may be processed after the keep-alive timer is armed. + self._unset_keepalive_if_required() + + self.headers = [(key.lower(), value) for key, value in event.headers] + raw_path, _, query_string = event.target.partition(b"?") + path = unquote(raw_path.decode("ascii")) + full_path = self.root_path + path + full_raw_path = self.root_path.encode("ascii") + raw_path + self.scope = { + "type": "http", + "asgi": {"version": self.asgi_version, "spec_version": "2.3"}, + "http_version": event.http_version.decode("ascii"), + "server": self.server, + "client": self.client, + "scheme": self.scheme, # type: ignore[typeddict-item] + "method": event.method.decode("ascii"), + "root_path": self.root_path, + "path": full_path, + "raw_path": full_raw_path, + "query_string": query_string, + "headers": self.headers, + "state": self.app_state.copy(), + } + if self._should_upgrade(): + self.handle_websocket_upgrade(event) + return + + # Handle 503 responses when 'limit_concurrency' is exceeded. + if self.limit_concurrency is not None and ( + len(self.connections) >= self.limit_concurrency or len(self.tasks) >= self.limit_concurrency + ): + app = service_unavailable + message = "Exceeded concurrency limit." + self.logger.warning(message) + else: + app = self.app + + self.cycle = RequestResponseCycle( + scope=self.scope, + conn=self.conn, + transport=self.transport, + flow=self.flow, + logger=self.logger, + access_logger=self.access_logger, + access_log=self.access_log, + default_headers=self.server_state.default_headers, + message_event=asyncio.Event(), + on_response=self.on_response_complete, + ) + if self.config.reset_contextvars: + # Opt-in workaround for https://github.com/python/cpython/issues/140947: + # asyncio can leak context vars between tasks. Hides context set in the + # lifespan or by external instrumentation. + if sys.version_info >= (3, 11): # pragma: py-lt-311 + task = self.loop.create_task(self.cycle.run_asgi(app), context=contextvars.Context()) + else: # pragma: py-gte-311 + task = contextvars.Context().run(self.loop.create_task, self.cycle.run_asgi(app)) + else: + task = self.loop.create_task(self.cycle.run_asgi(app)) + task.add_done_callback(self.tasks.discard) + self.tasks.add(task) + + elif isinstance(event, h11.Data): + if self.conn.our_state is h11.DONE: + continue + self.cycle.body += event.data + if len(self.cycle.body) > HIGH_WATER_LIMIT: + self.flow.pause_reading() + self.cycle.message_event.set() + + elif isinstance(event, h11.EndOfMessage): + if self.conn.our_state is h11.DONE: + self.transport.resume_reading() + self.conn.start_next_cycle() + continue + self.cycle.more_body = False + self.cycle.message_event.set() + if self.conn.their_state == h11.MUST_CLOSE: + break + + def handle_websocket_upgrade(self, event: h11.Request) -> None: + if self.logger.level <= TRACE_LOG_LEVEL: # pragma: full coverage + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sUpgrading to WebSocket", prefix) + + self.connections.discard(self) + output = [event.method, b" ", event.target, b" HTTP/1.1\r\n"] + for name, value in self.headers: + output += [name, b": ", value, b"\r\n"] + output.append(b"\r\n") + protocol = self.ws_protocol_class( # type: ignore[call-arg, misc] + config=self.config, + server_state=self.server_state, + app_state=self.app_state, + ) + protocol.connection_made(self.transport) + protocol.data_received(b"".join(output)) + self.transport.set_protocol(protocol) + + def send_400_response(self, msg: str) -> None: + reason = STATUS_PHRASES[400] + headers: list[tuple[bytes, bytes]] = [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"connection", b"close"), + ] + event = h11.Response(status_code=400, headers=headers, reason=reason) + output = self.conn.send(event) + self.transport.write(output) + + output = self.conn.send(event=h11.Data(data=msg.encode("ascii"))) + self.transport.write(output) + + output = self.conn.send(event=h11.EndOfMessage()) + self.transport.write(output) + + self.transport.close() + + def on_response_complete(self) -> None: + self.server_state.total_requests += 1 + + if self.transport.is_closing(): + return + + # Set a short Keep-Alive timeout. + self._unset_keepalive_if_required() + + self.timeout_keep_alive_task = self.loop.call_later(self.timeout_keep_alive, self.timeout_keep_alive_handler) + + # Unpause data reads if needed. + self.flow.resume_reading() + + # Unblock any pipelined events. + if self.conn.our_state is h11.DONE and self.conn.their_state is h11.DONE: + self.conn.start_next_cycle() + self.handle_events() + + def shutdown(self) -> None: + """ + Called by the server to commence a graceful shutdown. + """ + if self.cycle is None or self.cycle.response_complete: + event = h11.ConnectionClosed() + self.conn.send(event) + self.transport.close() + else: + self.cycle.keep_alive = False + + def pause_writing(self) -> None: + """ + Called by the transport when the write buffer exceeds the high water mark. + """ + self.flow.pause_writing() # pragma: full coverage + + def resume_writing(self) -> None: + """ + Called by the transport when the write buffer drops below the low water mark. + """ + self.flow.resume_writing() # pragma: full coverage + + def timeout_keep_alive_handler(self) -> None: + """ + Called on a keep-alive connection if no new data is received after a short + delay. + """ + if not self.transport.is_closing(): + event = h11.ConnectionClosed() + self.conn.send(event) + self.transport.close() + + +class RequestResponseCycle: + def __init__( + self, + scope: HTTPScope, + conn: h11.Connection, + transport: asyncio.Transport, + flow: FlowControl, + logger: logging.Logger, + access_logger: logging.Logger, + access_log: bool, + default_headers: list[tuple[bytes, bytes]], + message_event: asyncio.Event, + on_response: Callable[..., None], + ) -> None: + self.scope = scope + self.conn = conn + self.transport = transport + self.flow = flow + self.logger = logger + self.access_logger = access_logger + self.access_log = access_log + self.default_headers = default_headers + self.message_event = message_event + self.on_response = on_response + + # Connection state + self.disconnected = False + self.keep_alive = True + self.waiting_for_100_continue = conn.they_are_waiting_for_100_continue + + # Request state + self.body = bytearray() + self.more_body = True + + # Response state + self.response_started = False + self.response_complete = False + + # ASGI exception wrapper + async def run_asgi(self, app: ASGI3Application) -> None: + try: + result = await app( # type: ignore[func-returns-value] + self.scope, self.receive, self.send + ) + except BaseException as exc: + msg = "Exception in ASGI application\n" + self.logger.error(msg, exc_info=exc) + if not self.response_started: + await self.send_500_response() + else: + self.transport.close() + else: + if result is not None: + msg = "ASGI callable should return None, but returned '%s'." + self.logger.error(msg, result) + self.transport.close() + elif not self.response_started and not self.disconnected: + msg = "ASGI callable returned without starting response." + self.logger.error(msg) + await self.send_500_response() + elif not self.response_complete and not self.disconnected: + msg = "ASGI callable returned without completing response." + self.logger.error(msg) + self.transport.close() + finally: + self.on_response = lambda: None + + async def send_500_response(self) -> None: + response_start_event: HTTPResponseStartEvent = { + "type": "http.response.start", + "status": 500, + "headers": [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"connection", b"close"), + ], + } + await self.send(response_start_event) + response_body_event: HTTPResponseBodyEvent = { + "type": "http.response.body", + "body": b"Internal Server Error", + "more_body": False, + } + await self.send(response_body_event) + + # ASGI interface + async def send(self, message: ASGISendEvent) -> None: + if self.flow.write_paused and not self.disconnected: + await self.flow.drain() # pragma: full coverage + + if self.disconnected: + return # pragma: full coverage + + if not self.response_started: + # Sending response status line and headers + if message["type"] != "http.response.start": + raise RuntimeError(f"Expected ASGI message 'http.response.start', but got '{message['type']}'.") + + self.response_started = True + self.waiting_for_100_continue = False + + status = message["status"] + headers = self.default_headers + list(message.get("headers", [])) + + if CLOSE_HEADER in self.scope["headers"] and CLOSE_HEADER not in headers: + headers = headers + [CLOSE_HEADER] + + if self.access_log: + self.access_logger.info( + '%s - "%s %s HTTP/%s" %d', + get_client_addr(self.scope), + self.scope["method"], + get_path_with_query_string(self.scope), + self.scope["http_version"], + status, + ) + + # Write response status line and headers + reason = STATUS_PHRASES[status] + response = h11.Response(status_code=status, headers=headers, reason=reason) + output = self.conn.send(event=response) + self.transport.write(output) + + elif not self.response_complete: + # Sending response body + if message["type"] != "http.response.body": + raise RuntimeError(f"Expected ASGI message 'http.response.body', but got '{message['type']}'.") + + body = message.get("body", b"") + more_body = message.get("more_body", False) + + # Write response body + data = b"" if self.scope["method"] == "HEAD" else body + output = self.conn.send(event=h11.Data(data=data)) + self.transport.write(output) + + # Handle response completion + if not more_body: + self.response_complete = True + self.message_event.set() + output = self.conn.send(event=h11.EndOfMessage()) + self.transport.write(output) + + else: + # Response already sent + raise RuntimeError(f"Unexpected ASGI message '{message['type']}' sent, after response already completed.") + + if self.response_complete: + if self.conn.our_state is h11.MUST_CLOSE or not self.keep_alive: + self.conn.send(event=h11.ConnectionClosed()) + self.transport.close() + self.on_response() + + async def receive(self) -> ASGIReceiveEvent: + if self.waiting_for_100_continue and not self.transport.is_closing(): + headers: list[tuple[str, str]] = [] + event = h11.InformationalResponse(status_code=100, headers=headers, reason="Continue") + output = self.conn.send(event=event) + self.transport.write(output) + self.waiting_for_100_continue = False + + if not self.disconnected and not self.response_complete: + self.flow.resume_reading() + await self.message_event.wait() + self.message_event.clear() + + if self.disconnected or self.response_complete: + return {"type": "http.disconnect"} + + message: HTTPRequestEvent = {"type": "http.request", "body": bytes(self.body), "more_body": self.more_body} + self.body = bytearray() + return message diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/httptools_impl.py b/source/target-vendors/cp312/uvicorn/protocols/http/httptools_impl.py new file mode 100644 index 0000000..dc95e23 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/httptools_impl.py @@ -0,0 +1,581 @@ +from __future__ import annotations + +import asyncio +import contextvars +import http +import logging +import re +import sys +import urllib +from asyncio.events import TimerHandle +from collections import deque +from collections.abc import Callable +from typing import Any, Literal + +import httptools + +from uvicorn._types import ( + ASGI3Application, + ASGIReceiveEvent, + ASGISendEvent, + HTTPRequestEvent, + HTTPScope, +) +from uvicorn.config import Config +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.http.flow_control import HIGH_WATER_LIMIT, FlowControl, service_unavailable +from uvicorn.protocols.utils import get_client_addr, get_local_addr, get_path_with_query_string, get_remote_addr, is_ssl +from uvicorn.server import ServerState + +HEADER_RE = re.compile(b'[\x00-\x1f\x7f()<>@,;:\\[\\]={} \t\\\\"]') +HEADER_VALUE_RE = re.compile(b"[\x00-\x08\x0a-\x1f\x7f]") + + +def _get_status_line(status_code: int) -> bytes: + try: + phrase = http.HTTPStatus(status_code).phrase.encode() + except ValueError: + phrase = b"" + return b"".join([b"HTTP/1.1 ", str(status_code).encode(), b" ", phrase, b"\r\n"]) + + +STATUS_LINE = {status_code: _get_status_line(status_code) for status_code in range(100, 600)} + + +class HttpToolsProtocol(asyncio.Protocol): + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() + + self.config = config + self.app = config.loaded_app + self.loop = _loop or asyncio.get_event_loop() + self.logger = logging.getLogger("uvicorn.error") + self.access_logger = logging.getLogger("uvicorn.access") + self.access_log = self.access_logger.hasHandlers() + self.parser = httptools.HttpRequestParser(self) + + try: + # Enable dangerous leniencies to allow server to a response on the first request from a pipelined request. + self.parser.set_dangerous_leniencies(lenient_data_after_close=True) + except AttributeError: # pragma: no cover + # httptools < 0.6.3 + pass + + self.ws_protocol_class = config.ws_protocol_class + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.limit_concurrency = config.limit_concurrency + self.app_state = app_state + + # Timeouts + self.timeout_keep_alive_task: TimerHandle | None = None + self.timeout_keep_alive = config.timeout_keep_alive + + # Global state + self.server_state = server_state + self.connections = server_state.connections + self.tasks = server_state.tasks + + # Per-connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.flow: FlowControl = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["http", "https"] | None = None + self.pipeline: deque[tuple[RequestResponseCycle, ASGI3Application]] = deque() + + # Per-request state + self.scope: HTTPScope = None # type: ignore[assignment] + self.headers: list[tuple[bytes, bytes]] = None # type: ignore[assignment] + self.expect_100_continue = False + self.cycle: RequestResponseCycle = None # type: ignore[assignment] + + # Protocol interface + def connection_made( # type: ignore[override] + self, transport: asyncio.Transport + ) -> None: + self.connections.add(self) + + self.transport = transport + self.flow = FlowControl(transport) + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "https" if is_ssl(transport) else "http" + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection made", prefix) + + def connection_lost(self, exc: Exception | None) -> None: + self.connections.discard(self) + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection lost", prefix) + + if self.cycle and not self.cycle.response_complete: + self.cycle.disconnected = True + if self.cycle is not None: + self.cycle.message_event.set() + if self.flow is not None: + self.flow.resume_writing() + if exc is None: + self.transport.close() + self._unset_keepalive_if_required() + + self.parser = None # type: ignore[assignment] + + def eof_received(self) -> None: + pass + + def _unset_keepalive_if_required(self) -> None: + if self.timeout_keep_alive_task is not None: + self.timeout_keep_alive_task.cancel() + self.timeout_keep_alive_task = None + + def _get_upgrade(self) -> bytes | None: + connection = [] + upgrade = None + for name, value in self.headers: + if name == b"connection": + connection = [token.lower().strip() for token in value.split(b",")] + if name == b"upgrade": + upgrade = value.lower() + if b"upgrade" in connection: + return upgrade + return None # pragma: full coverage + + def _should_upgrade_to_ws(self) -> bool: + if self.ws_protocol_class is None: + return False + return True + + def _unsupported_upgrade_warning(self) -> None: + self.logger.warning("Unsupported upgrade request.") + if not self._should_upgrade_to_ws(): + msg = "No supported WebSocket library detected. Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." # noqa: E501 + self.logger.warning(msg) + + def _should_upgrade(self) -> bool: + upgrade = self._get_upgrade() + return upgrade == b"websocket" and self._should_upgrade_to_ws() + + def data_received(self, data: bytes) -> None: + self._unset_keepalive_if_required() + + try: + self.parser.feed_data(data) + except httptools.HttpParserError: + msg = "Invalid HTTP request received." + self.logger.warning(msg) + self.send_400_response(msg) + return + except httptools.HttpParserUpgrade: + if self._should_upgrade(): + self.handle_websocket_upgrade() + else: + self._unsupported_upgrade_warning() + + def handle_websocket_upgrade(self) -> None: + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sUpgrading to WebSocket", prefix) + + self.connections.discard(self) + method = self.scope["method"].encode() + output = [method, b" ", self.url, b" HTTP/1.1\r\n"] + for name, value in self.scope["headers"]: + output += [name, b": ", value, b"\r\n"] + output.append(b"\r\n") + protocol = self.ws_protocol_class( # type: ignore[call-arg, misc] + config=self.config, + server_state=self.server_state, + app_state=self.app_state, + ) + protocol.connection_made(self.transport) + protocol.data_received(b"".join(output)) + self.transport.set_protocol(protocol) + + def send_400_response(self, msg: str) -> None: + content = [STATUS_LINE[400]] + for name, value in self.server_state.default_headers: + content.extend([name, b": ", value, b"\r\n"]) # pragma: full coverage + content.extend( + [ + b"content-type: text/plain; charset=utf-8\r\n", + b"content-length: " + str(len(msg)).encode("ascii") + b"\r\n", + b"connection: close\r\n", + b"\r\n", + msg.encode("ascii"), + ] + ) + self.transport.write(b"".join(content)) + self.transport.close() + + def on_message_begin(self) -> None: + self.url = b"" + self.expect_100_continue = False + self.headers = [] + self.scope = { # type: ignore[typeddict-item] + "type": "http", + "asgi": {"version": self.asgi_version, "spec_version": "2.3"}, + "http_version": "1.1", + "server": self.server, + "client": self.client, + "scheme": self.scheme, # type: ignore[typeddict-item] + "root_path": self.root_path, + "headers": self.headers, + "state": self.app_state.copy(), + } + + # Parser callbacks + def on_url(self, url: bytes) -> None: + self.url += url + + def on_header(self, name: bytes, value: bytes) -> None: + name = name.lower() + if name == b"expect" and value.lower() == b"100-continue": + self.expect_100_continue = True + self.headers.append((name, value)) + + def on_headers_complete(self) -> None: + http_version = self.parser.get_http_version() + method = self.parser.get_method() + self.scope["method"] = method.decode("ascii") + if http_version != "1.1": + self.scope["http_version"] = http_version + if self.parser.should_upgrade() and self._should_upgrade(): + return + parsed_url = httptools.parse_url(self.url) + raw_path = parsed_url.path + path = raw_path.decode("ascii") + if "%" in path: + path = urllib.parse.unquote(path) + full_path = self.root_path + path + full_raw_path = self.root_path.encode("ascii") + raw_path + self.scope["path"] = full_path + self.scope["raw_path"] = full_raw_path + self.scope["query_string"] = parsed_url.query or b"" + + # Handle 503 responses when 'limit_concurrency' is exceeded. + if self.limit_concurrency is not None and ( + len(self.connections) >= self.limit_concurrency or len(self.tasks) >= self.limit_concurrency + ): + app = service_unavailable + message = "Exceeded concurrency limit." + self.logger.warning(message) + else: + app = self.app + + existing_cycle = self.cycle + self.cycle = RequestResponseCycle( + scope=self.scope, + transport=self.transport, + flow=self.flow, + logger=self.logger, + access_logger=self.access_logger, + access_log=self.access_log, + default_headers=self.server_state.default_headers, + message_event=asyncio.Event(), + expect_100_continue=self.expect_100_continue, + keep_alive=http_version != "1.0" and self.parser.should_keep_alive(), + on_response=self.on_response_complete, + ) + if existing_cycle is None or existing_cycle.response_complete: + # Standard case - start processing the request. + self._start_asgi_task(self.cycle, app) + else: + # Pipelined HTTP requests need to be queued up. + self.flow.pause_reading() + self.pipeline.appendleft((self.cycle, app)) + + def _start_asgi_task(self, cycle: RequestResponseCycle, app: ASGI3Application) -> None: + if self.config.reset_contextvars: + # Opt-in workaround for https://github.com/python/cpython/issues/140947: + # asyncio can leak context vars between tasks. Hides context set in the + # lifespan or by external instrumentation. + if sys.version_info >= (3, 11): # pragma: py-lt-311 + task = self.loop.create_task(cycle.run_asgi(app), context=contextvars.Context()) + else: # pragma: py-gte-311 + task = contextvars.Context().run(self.loop.create_task, cycle.run_asgi(app)) + else: + task = self.loop.create_task(cycle.run_asgi(app)) + task.add_done_callback(self.tasks.discard) + self.tasks.add(task) + + def on_body(self, body: bytes) -> None: + if (self.parser.should_upgrade() and self._should_upgrade()) or self.cycle.response_complete: + return + self.cycle.body += body + if len(self.cycle.body) > HIGH_WATER_LIMIT: + self.flow.pause_reading() + self.cycle.message_event.set() + + def on_message_complete(self) -> None: + if (self.parser.should_upgrade() and self._should_upgrade()) or self.cycle.response_complete: + return + self.cycle.more_body = False + self.cycle.message_event.set() + + def on_response_complete(self) -> None: + # Callback for pipelined HTTP requests to be started. + self.server_state.total_requests += 1 + + if self.transport.is_closing(): + return + + self._unset_keepalive_if_required() + + # Unpause data reads if needed. + self.flow.resume_reading() + + # Unblock any pipelined events. If there are none, arm the + # Keep-Alive timeout instead. + if self.pipeline: + cycle, app = self.pipeline.pop() + self._start_asgi_task(cycle, app) + else: + self.timeout_keep_alive_task = self.loop.call_later( + self.timeout_keep_alive, self.timeout_keep_alive_handler + ) + + def shutdown(self) -> None: + """ + Called by the server to commence a graceful shutdown. + """ + if self.cycle is None or self.cycle.response_complete: + self.transport.close() + else: + self.cycle.keep_alive = False + + def pause_writing(self) -> None: + """ + Called by the transport when the write buffer exceeds the high water mark. + """ + self.flow.pause_writing() # pragma: full coverage + + def resume_writing(self) -> None: + """ + Called by the transport when the write buffer drops below the low water mark. + """ + self.flow.resume_writing() # pragma: full coverage + + def timeout_keep_alive_handler(self) -> None: + """ + Called on a keep-alive connection if no new data is received after a short + delay. + """ + if not self.transport.is_closing(): + self.transport.close() + + +class RequestResponseCycle: + def __init__( + self, + scope: HTTPScope, + transport: asyncio.Transport, + flow: FlowControl, + logger: logging.Logger, + access_logger: logging.Logger, + access_log: bool, + default_headers: list[tuple[bytes, bytes]], + message_event: asyncio.Event, + expect_100_continue: bool, + keep_alive: bool, + on_response: Callable[..., None], + ): + self.scope = scope + self.transport = transport + self.flow = flow + self.logger = logger + self.access_logger = access_logger + self.access_log = access_log + self.default_headers = default_headers + self.message_event = message_event + self.on_response = on_response + + # Connection state + self.disconnected = False + self.keep_alive = keep_alive + self.waiting_for_100_continue = expect_100_continue + + # Request state + self.body = bytearray() + self.more_body = True + + # Response state + self.response_started = False + self.response_complete = False + self.chunked_encoding: bool | None = None + self.expected_content_length = 0 + + # ASGI exception wrapper + async def run_asgi(self, app: ASGI3Application) -> None: + try: + result = await app( # type: ignore[func-returns-value] + self.scope, self.receive, self.send + ) + except BaseException as exc: + msg = "Exception in ASGI application\n" + self.logger.error(msg, exc_info=exc) + if not self.response_started: + await self.send_500_response() + else: + self.transport.close() + else: + if result is not None: + msg = "ASGI callable should return None, but returned '%s'." + self.logger.error(msg, result) + self.transport.close() + elif not self.response_started and not self.disconnected: + msg = "ASGI callable returned without starting response." + self.logger.error(msg) + await self.send_500_response() + elif not self.response_complete and not self.disconnected: + msg = "ASGI callable returned without completing response." + self.logger.error(msg) + self.transport.close() + finally: + self.on_response = lambda: None + + async def send_500_response(self) -> None: + await self.send( + { + "type": "http.response.start", + "status": 500, + "headers": [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"content-length", b"21"), + (b"connection", b"close"), + ], + } + ) + await self.send({"type": "http.response.body", "body": b"Internal Server Error", "more_body": False}) + + # ASGI interface + async def send(self, message: ASGISendEvent) -> None: + if self.flow.write_paused and not self.disconnected: + await self.flow.drain() # pragma: full coverage + + if self.disconnected: + return # pragma: full coverage + + if not self.response_started: + # Sending response status line and headers + if message["type"] != "http.response.start": + raise RuntimeError(f"Expected ASGI message 'http.response.start', but got '{message['type']}'.") + + self.response_started = True + self.waiting_for_100_continue = False + + status_code = message["status"] + headers = self.default_headers + list(message.get("headers", [])) + + if self.access_log: + self.access_logger.info( + '%s - "%s %s HTTP/%s" %d', + get_client_addr(self.scope), + self.scope["method"], + get_path_with_query_string(self.scope), + self.scope["http_version"], + status_code, + ) + + # Write response status line and headers + content = [STATUS_LINE[status_code]] + has_connection_close = False + + for name, value in headers: + if HEADER_RE.search(name): + raise RuntimeError("Invalid HTTP header name.") # pragma: full coverage + if HEADER_VALUE_RE.search(value): + raise RuntimeError("Invalid HTTP header value.") + + name = name.lower() + if name == b"content-length" and self.chunked_encoding is None: + self.expected_content_length = int(value.decode()) + self.chunked_encoding = False + elif name == b"transfer-encoding" and value.lower() == b"chunked": + self.expected_content_length = 0 + self.chunked_encoding = True + elif name == b"connection": + connection = [token.lower().strip() for token in value.split(b",")] + if b"close" in connection: + self.keep_alive = False + has_connection_close = True + content.extend([name, b": ", value, b"\r\n"]) + + if not self.keep_alive and not has_connection_close: + content.append(b"connection: close\r\n") + + if self.chunked_encoding is None and self.scope["method"] != "HEAD" and status_code not in (204, 304): + # Neither content-length nor transfer-encoding specified + self.chunked_encoding = True + content.append(b"transfer-encoding: chunked\r\n") + + content.append(b"\r\n") + self.transport.write(b"".join(content)) + + elif not self.response_complete: + # Sending response body + if message["type"] != "http.response.body": + raise RuntimeError(f"Expected ASGI message 'http.response.body', but got '{message['type']}'.") + + body = message.get("body", b"") + more_body = message.get("more_body", False) + + # Write response body + if self.scope["method"] == "HEAD": + self.expected_content_length = 0 + elif self.chunked_encoding: + if body: + content = [b"%x\r\n" % len(body), body, b"\r\n"] + else: + content = [] + if not more_body: + content.append(b"0\r\n\r\n") + self.transport.write(b"".join(content)) + else: + num_bytes = len(body) + if num_bytes > self.expected_content_length: + raise RuntimeError("Response content longer than Content-Length") + else: + self.expected_content_length -= num_bytes + self.transport.write(body) + + # Handle response completion + if not more_body: + if self.expected_content_length != 0: + raise RuntimeError("Response content shorter than Content-Length") + self.response_complete = True + self.message_event.set() + if not self.keep_alive: + self.transport.close() + self.on_response() + + else: + # Response already sent + raise RuntimeError(f"Unexpected ASGI message '{message['type']}' sent, after response already completed.") + + async def receive(self) -> ASGIReceiveEvent: + if self.waiting_for_100_continue and not self.transport.is_closing(): + self.transport.write(b"HTTP/1.1 100 Continue\r\n\r\n") + self.waiting_for_100_continue = False + + if not self.disconnected and not self.response_complete: + self.flow.resume_reading() + await self.message_event.wait() + self.message_event.clear() + + if self.disconnected or self.response_complete: + return {"type": "http.disconnect"} + message: HTTPRequestEvent = {"type": "http.request", "body": bytes(self.body), "more_body": self.more_body} + self.body = bytearray() + return message diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/zttp_h2_impl.py b/source/target-vendors/cp312/uvicorn/protocols/http/zttp_h2_impl.py new file mode 100644 index 0000000..3a7a0f9 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/zttp_h2_impl.py @@ -0,0 +1,521 @@ +from __future__ import annotations + +import asyncio +import contextvars +import logging +import sys +from collections.abc import Callable, Generator +from typing import Any, ClassVar, Literal +from urllib.parse import unquote + +import zttp +from zttp import Event + +from uvicorn._types import ( + ASGI3Application, + ASGIReceiveEvent, + ASGISendEvent, + HTTPRequestEvent, + HTTPResponseBodyEvent, + HTTPResponseStartEvent, + HTTPScope, +) +from uvicorn.config import Config +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.http.flow_control import HIGH_WATER_LIMIT, FlowControl, service_unavailable +from uvicorn.protocols.utils import get_client_addr, get_local_addr, get_path_with_query_string, get_remote_addr, is_ssl +from uvicorn.server import ServerState + +# RFC 9113 section 8.2.2: connection-specific headers MUST NOT appear in +# HTTP/2 messages. zttp rejects them with LocalProtocolError, and an ASGI app +# or middleware tuned for HTTP/1.1 may still emit them, so strip them on the +# way out. +FORBIDDEN_HEADERS = frozenset({b"connection", b"keep-alive", b"proxy-connection", b"transfer-encoding", b"upgrade"}) + + +class ZttpH2Protocol(asyncio.Protocol): + alpn_protocols: ClassVar[list[str]] = ["h2"] + + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() + + self.config = config + self.app = config.loaded_app + self.loop = _loop or asyncio.get_event_loop() + self.logger = logging.getLogger("uvicorn.error") + self.access_logger = logging.getLogger("uvicorn.access") + self.access_log = self.access_logger.hasHandlers() + self.conn: zttp.H2Connection = zttp.Connection(zttp.SERVER, protocol=zttp.HTTP2) + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.limit_concurrency = config.limit_concurrency + self.app_state = app_state + + # Timeouts + self.timeout_keep_alive_task: asyncio.TimerHandle | None = None + self.timeout_keep_alive = config.timeout_keep_alive + + # Shared server state + self.server_state = server_state + self.connections = server_state.connections + self.tasks = server_state.tasks + + # Per-connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.flow: FlowControl = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["http", "https"] | None = None + self.shutdown_requested = False + + # Per-stream state, keyed by HTTP/2 stream id + self.cycles: dict[int, RequestResponseCycle] = {} + + # Protocol interface + def connection_made( # type: ignore[override] + self, transport: asyncio.Transport + ) -> None: + self.connections.add(self) + + self.transport = transport + self.flow = FlowControl(transport) + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "https" if is_ssl(transport) else "http" + + self.conn.initiate_connection() + self.flush() + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP/2 connection made", prefix) + + def connection_lost(self, exc: Exception | None) -> None: + self.connections.discard(self) + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP/2 connection lost", prefix) + + for cycle in self.cycles.values(): + if not cycle.response_complete: + cycle.disconnected = True + cycle.message_event.set() + if self.flow is not None: + self.flow.resume_writing() + if exc is None: + self.transport.close() + self._unset_keepalive_if_required() + + def eof_received(self) -> None: + pass + + def _unset_keepalive_if_required(self) -> None: + if self.timeout_keep_alive_task is not None: + self.timeout_keep_alive_task.cancel() + self.timeout_keep_alive_task = None + + def data_received(self, data: bytes) -> None: + self._unset_keepalive_if_required() + + try: + self.conn.receive_data(data) + self.handle_events() + except zttp.RemoteProtocolError as exc: + msg = "Invalid HTTP/2 frame received: %s" + self.logger.warning(msg, exc) + self.flush() + self.transport.close() + return + + self.flush() + + # Frames that carry no stream-level event (SETTINGS, PING, + # WINDOW_UPDATE) cancelled the keep-alive timer above but never re-arm + # it, so re-arm now if the connection is idle. + if not self.cycles and self.timeout_keep_alive_task is None and not self.transport.is_closing(): + self.timeout_keep_alive_task = self.loop.call_later( + self.timeout_keep_alive, self.timeout_keep_alive_handler + ) + + def flush(self) -> None: + """Write out bytes zttp queued outside a cycle's send path - the + connection preface and DATA released by a WINDOW_UPDATE credit.""" + data = self.conn.data_to_send() + if data: + self.transport.write(data) + + def events(self) -> Generator[Event]: + """Yield every complete event currently available.""" + while True: + event = self.conn.next_event() + if event is zttp.NEED_DATA: + return + yield event + + def handle_events(self) -> None: + for event in self.events(): + if isinstance(event, zttp.Request): + self.handle_request(event) + elif isinstance(event, zttp.Data): + cycle = self.cycles.get(event.stream_id) + if cycle is None or cycle.response_complete: + continue + cycle.body += event.data + # Unreachable until zttp grows its 64 KiB inbound flow-control + # windows, which cap how much body can buffer per stream. + if len(cycle.body) > HIGH_WATER_LIMIT: # pragma: no cover + self.flow.pause_reading() + cycle.message_event.set() + elif isinstance(event, zttp.EndOfMessage): + cycle = self.cycles.get(event.stream_id) + if cycle is None or cycle.response_complete: + continue + cycle.more_body = False + cycle.message_event.set() + elif isinstance(event, zttp.RstStream): + self.handle_rst_stream(event) + elif isinstance(event, zttp.GoAway): + self.shutdown_requested = True + if not self.cycles: + self._close_connection() + # Settings, Ping and WindowUpdate need no action here: zttp tracks + # the send windows internally, and `flush` writes whatever bytes + # the new credit released. + + def handle_request(self, event: zttp.Request) -> None: + headers = ( + event.headers.to_list(lowercase_names=True) + if isinstance(event.headers, zttp.HeaderBlock) + else [(name.lower(), value) for name, value in event.headers] + ) + path = unquote(event.path.decode("ascii")) + full_path = self.root_path + path + full_raw_path = self.root_path.encode("ascii") + event.path + scope: HTTPScope = { + "type": "http", + "asgi": {"version": self.asgi_version, "spec_version": "2.3"}, + "http_version": "2", + "server": self.server, + "client": self.client, + "scheme": self.scheme, # type: ignore[typeddict-item] + "method": event.method.decode("ascii"), + "root_path": self.root_path, + "path": full_path, + "raw_path": full_raw_path, + "query_string": event.query, + "headers": headers, + "state": self.app_state.copy(), + } + + # Refuse new streams once a shutdown began, and handle 503 responses + # when 'limit_concurrency' is exceeded. + if self.shutdown_requested: + app = service_unavailable + elif self.limit_concurrency is not None and ( + len(self.connections) >= self.limit_concurrency or len(self.tasks) >= self.limit_concurrency + ): + app = service_unavailable + message = "Exceeded concurrency limit." + self.logger.warning(message) + else: + app = self.app + + cycle = RequestResponseCycle( + scope=scope, + conn=self.conn, + stream=self.conn.stream(event.stream_id), + transport=self.transport, + flow=self.flow, + logger=self.logger, + access_logger=self.access_logger, + access_log=self.access_log, + default_headers=self.server_state.default_headers, + message_event=asyncio.Event(), + on_response=self.on_response_complete, + resume_reading=self.resume_reading_if_idle, + ) + self.cycles[event.stream_id] = cycle + + if self.config.reset_contextvars: + if sys.version_info >= (3, 11): # pragma: py-lt-311 + task = self.loop.create_task(cycle.run_asgi(app), context=contextvars.Context()) + else: # pragma: py-gte-311 + task = contextvars.Context().run(self.loop.create_task, cycle.run_asgi(app)) + else: + task = self.loop.create_task(cycle.run_asgi(app)) + task.add_done_callback(self.tasks.discard) + self.tasks.add(task) + + def handle_rst_stream(self, event: zttp.RstStream) -> None: + cycle = self.cycles.pop(event.stream_id, None) + if cycle is None: + return + if not cycle.response_complete: + cycle.disconnected = True + cycle.message_event.set() + self.on_stream_closed() + + def resume_reading_if_idle(self) -> None: + """Resume reads only if no stream is over the body buffer high-water + mark; otherwise a slow stream's buffer would keep growing while a fast + peer ships frames on a sibling stream.""" + for cycle in self.cycles.values(): + if len(cycle.body) > HIGH_WATER_LIMIT: + return + self.flow.resume_reading() + + def on_response_complete(self, stream_id: int) -> None: + self.server_state.total_requests += 1 + self.cycles.pop(stream_id, None) + self.on_stream_closed() + + def on_stream_closed(self) -> None: + if self.transport.is_closing(): + return + + # The stream's body buffer is gone, so it can no longer hold back the + # read side of the transport. + self.resume_reading_if_idle() + + self._unset_keepalive_if_required() + + if not self.cycles: + if self.shutdown_requested: + self._close_connection() + return + self.timeout_keep_alive_task = self.loop.call_later( + self.timeout_keep_alive, self.timeout_keep_alive_handler + ) + + def _close_connection(self) -> None: + """Send GOAWAY and close the transport.""" + if self.transport.is_closing(): + return + self.conn.close() + self.flush() + self.transport.close() + + def shutdown(self) -> None: + """ + Called by the server to commence a graceful shutdown. + + Closes immediately when idle; otherwise new streams are refused with + 503 and the connection closes once the last in-flight stream finishes. + """ + self.shutdown_requested = True + if not self.cycles: + self._close_connection() + + def pause_writing(self) -> None: + """ + Called by the transport when the write buffer exceeds the high water mark. + """ + self.flow.pause_writing() # pragma: no cover + + def resume_writing(self) -> None: + """ + Called by the transport when the write buffer drops below the low water mark. + """ + self.flow.resume_writing() # pragma: no cover + + def timeout_keep_alive_handler(self) -> None: + """ + Called on a keep-alive connection if no new data is received after a short + delay. + """ + self._close_connection() + + +class RequestResponseCycle: + def __init__( + self, + scope: HTTPScope, + conn: zttp.H2Connection, + stream: zttp.Stream, + transport: asyncio.Transport, + flow: FlowControl, + logger: logging.Logger, + access_logger: logging.Logger, + access_log: bool, + default_headers: list[tuple[bytes, bytes]], + message_event: asyncio.Event, + on_response: Callable[[int], None], + resume_reading: Callable[[], None], + ) -> None: + self.scope = scope + self.conn = conn + self.stream = stream + self.transport = transport + self.flow = flow + self.logger = logger + self.access_logger = access_logger + self.access_log = access_log + self.default_headers = default_headers + self.message_event = message_event + self.on_response = on_response + self.resume_reading = resume_reading + + # Connection state + self.disconnected = False + + # Request state + self.body = bytearray() + self.more_body = True + + # Response state + self.response_started = False + self.response_complete = False + self.bodyless = False + self.expected_content_length: int | None = None + + # ASGI exception wrapper + async def run_asgi(self, app: ASGI3Application) -> None: + try: + result = await app( # type: ignore[func-returns-value] + self.scope, self.receive, self.send + ) + except BaseException as exc: + msg = "Exception in ASGI application\n" + self.logger.error(msg, exc_info=exc) + if not self.response_started: + await self.send_500_response() + else: + self.abort_stream() + else: + if result is not None: + msg = "ASGI callable should return None, but returned '%s'." + self.logger.error(msg, result) + self.abort_stream() + elif not self.response_started and not self.disconnected: + msg = "ASGI callable returned without starting response." + self.logger.error(msg) + await self.send_500_response() + elif not self.response_complete and not self.disconnected: + msg = "ASGI callable returned without completing response." + self.logger.error(msg) + self.abort_stream() + finally: + self.on_response(self.stream.stream_id) + self.on_response = lambda stream_id: None + + def abort_stream(self) -> None: + """Reset only this stream so sibling streams on the connection survive.""" + if self.transport.is_closing(): + return + self.stream.reset() + self.transport.write(self.conn.data_to_send()) + self.disconnected = True + + async def send_500_response(self) -> None: + response_start_event: HTTPResponseStartEvent = { + "type": "http.response.start", + "status": 500, + "headers": [(b"content-type", b"text/plain; charset=utf-8")], + } + await self.send(response_start_event) + response_body_event: HTTPResponseBodyEvent = { + "type": "http.response.body", + "body": b"Internal Server Error", + "more_body": False, + } + await self.send(response_body_event) + + # ASGI interface + async def send(self, message: ASGISendEvent) -> None: + if self.flow.write_paused and not self.disconnected: + await self.flow.drain() # pragma: no cover + + if self.disconnected: + return + + if not self.response_started: + # Sending response status line and headers + if message["type"] != "http.response.start": + raise RuntimeError(f"Expected ASGI message 'http.response.start', but got '{message['type']}'.") + + self.response_started = True + + status = message["status"] + headers: list[tuple[bytes, bytes]] = [] + for name, value in list(self.default_headers) + list(message.get("headers", [])): + name = name.lower() + if name in FORBIDDEN_HEADERS: + continue + if name == b"te" and value.lower().strip() != b"trailers": + continue + if name == b"content-length": + self.expected_content_length = int(value.decode()) + headers.append((name, value)) + + self.bodyless = self.scope["method"] == "HEAD" or status in (204, 304) or status < 200 + if self.bodyless: + self.expected_content_length = None + + if self.access_log: + self.access_logger.info( + '%s - "%s %s HTTP/%s" %d', + get_client_addr(self.scope), + self.scope["method"], + get_path_with_query_string(self.scope), + self.scope["http_version"], + status, + ) + + # Write response headers + self.stream.send_response(status, headers) + self.transport.write(self.conn.data_to_send()) + + elif not self.response_complete: + # Sending response body + if message["type"] != "http.response.body": + raise RuntimeError(f"Expected ASGI message 'http.response.body', but got '{message['type']}'.") + + body = message.get("body", b"") + more_body = message.get("more_body", False) + + # Write response body + if self.bodyless: + body = b"" + elif self.expected_content_length is not None: + if len(body) > self.expected_content_length: + raise RuntimeError("Response content longer than Content-Length") + self.expected_content_length -= len(body) + if body: + self.stream.send_data(body) + self.transport.write(self.conn.data_to_send()) + + # Handle response completion + if not more_body: + if self.expected_content_length not in (None, 0): + raise RuntimeError("Response content shorter than Content-Length") + self.response_complete = True + self.message_event.set() + self.stream.end_message() + self.transport.write(self.conn.data_to_send()) + self.on_response(self.stream.stream_id) + self.on_response = lambda stream_id: None + + else: + # Response already sent + raise RuntimeError(f"Unexpected ASGI message '{message['type']}' sent, after response already completed.") + + async def receive(self) -> ASGIReceiveEvent: + if not self.disconnected and not self.response_complete: + self.resume_reading() + await self.message_event.wait() + self.message_event.clear() + + if self.disconnected or self.response_complete: + return {"type": "http.disconnect"} + + message: HTTPRequestEvent = {"type": "http.request", "body": bytes(self.body), "more_body": self.more_body} + self.body = bytearray() + return message diff --git a/source/target-vendors/cp312/uvicorn/protocols/http/zttp_impl.py b/source/target-vendors/cp312/uvicorn/protocols/http/zttp_impl.py new file mode 100644 index 0000000..b64f817 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/http/zttp_impl.py @@ -0,0 +1,537 @@ +from __future__ import annotations + +import asyncio +import contextvars +import logging +import sys +from collections.abc import Callable +from typing import Any, Literal +from urllib.parse import unquote + +import zttp + +from uvicorn._types import ( + ASGI3Application, + ASGIReceiveEvent, + ASGISendEvent, + HTTPRequestEvent, + HTTPResponseBodyEvent, + HTTPResponseStartEvent, + HTTPScope, +) +from uvicorn.config import Config +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.http.flow_control import HIGH_WATER_LIMIT, FlowControl, service_unavailable +from uvicorn.protocols.utils import get_client_addr, get_local_addr, get_path_with_query_string, get_remote_addr, is_ssl +from uvicorn.server import ServerState + + +class ZttpProtocol(asyncio.Protocol): + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() + + self.config = config + self.app = config.loaded_app + self.loop = _loop or asyncio.get_event_loop() + self.logger = logging.getLogger("uvicorn.error") + self.access_logger = logging.getLogger("uvicorn.access") + self.access_log = self.access_logger.hasHandlers() + self.conn = zttp.Connection(zttp.SERVER) + self.ws_protocol_class = config.ws_protocol_class + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.limit_concurrency = config.limit_concurrency + self.app_state = app_state + + # Timeouts + self.timeout_keep_alive_task: asyncio.TimerHandle | None = None + self.timeout_keep_alive = config.timeout_keep_alive + + # Shared server state + self.server_state = server_state + self.connections = server_state.connections + self.tasks = server_state.tasks + + # Per-connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.flow: FlowControl = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["http", "https"] | None = None + + # Per-request state + self.scope: HTTPScope = None # type: ignore[assignment] + self.headers: list[tuple[bytes, bytes]] = None # type: ignore[assignment] + self.cycle: RequestResponseCycle = None # type: ignore[assignment] + + # Protocol interface + def connection_made( # type: ignore[override] + self, transport: asyncio.Transport + ) -> None: + self.connections.add(self) + + self.transport = transport + self.flow = FlowControl(transport) + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "https" if is_ssl(transport) else "http" + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection made", prefix) + + def connection_lost(self, exc: Exception | None) -> None: + self.connections.discard(self) + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sHTTP connection lost", prefix) + + if self.cycle and not self.cycle.response_complete: + self.cycle.disconnected = True + if self.cycle is not None: + self.cycle.message_event.set() + if self.flow is not None: + self.flow.resume_writing() + if exc is None: + self.transport.close() + self._unset_keepalive_if_required() + + def eof_received(self) -> None: + pass + + def _unset_keepalive_if_required(self) -> None: + if self.timeout_keep_alive_task is not None: + self.timeout_keep_alive_task.cancel() + self.timeout_keep_alive_task = None + + def _should_upgrade_to_ws(self) -> bool: + if self.ws_protocol_class is None: + return False + return True + + def _unsupported_upgrade_warning(self) -> None: + self.logger.warning("Unsupported upgrade request.") + if not self._should_upgrade_to_ws(): + self.logger.warning( + "No supported WebSocket library detected. " + "Please use \"pip install 'uvicorn[standard]'\", or install 'websockets' or 'wsproto' manually." + ) + + def _should_upgrade(self) -> bool: + upgrade = self.conn.upgrade() + if upgrade is not None: + upgrade = upgrade.lower() + if upgrade == b"websocket" and self._should_upgrade_to_ws(): + return True + if upgrade is not None: + self._unsupported_upgrade_warning() + return False + + def data_received(self, data: bytes) -> None: + self._unset_keepalive_if_required() + try: + self.handle_events(self.conn.receive_event(data)) + except zttp.RemoteProtocolError: + self.handle_remote_protocol_error() + + def handle_events(self, event: zttp.Event) -> None: + while event is not zttp.NEED_DATA: + if isinstance(event, zttp.Request): + # Pipelined HTTP requests and WebSocket upgrades may be processed after the keep-alive timer is armed. + self._unset_keepalive_if_required() + + assert isinstance(event.headers, zttp.HeaderBlock) + self.headers = event.headers.to_list(lowercase_names=True) + path = event.path.decode("ascii") + if "%" in path: + path = unquote(path) + full_path = self.root_path + path + full_raw_path = self.root_path.encode("ascii") + event.path + self.scope = { + "type": "http", + "asgi": {"version": self.asgi_version, "spec_version": "2.3"}, + "http_version": event.http_version.decode("ascii"), + "server": self.server, + "client": self.client, + "scheme": self.scheme, # type: ignore[typeddict-item] + "method": event.method.decode("ascii"), + "root_path": self.root_path, + "path": full_path, + "raw_path": full_raw_path, + "query_string": event.query, + "headers": self.headers, + "state": self.app_state.copy(), + } + if self._should_upgrade(): + self.handle_websocket_upgrade(event) + return + + # Handle 503 responses when 'limit_concurrency' is exceeded. + if self.limit_concurrency is not None and ( + len(self.connections) >= self.limit_concurrency or len(self.tasks) >= self.limit_concurrency + ): + app = service_unavailable + message = "Exceeded concurrency limit." + self.logger.warning(message) + else: + app = self.app + + self.cycle = RequestResponseCycle( + scope=self.scope, + conn=self.conn, + transport=self.transport, + flow=self.flow, + logger=self.logger, + access_logger=self.access_logger, + access_log=self.access_log, + default_headers=self.server_state.default_headers, + message_event=asyncio.Event(), + expect_100_continue=event.expect_continue, + on_response=self.on_response_complete, + ) + if event.end_stream: + self.cycle.more_body = False + self.cycle.message_event.set() + if self.config.reset_contextvars: + if sys.version_info >= (3, 11): # pragma: py-lt-311 + task = self.loop.create_task(self.cycle.run_asgi(app), context=contextvars.Context()) + else: # pragma: py-gte-311 + task = contextvars.Context().run(self.loop.create_task, self.cycle.run_asgi(app)) + else: + task = self.loop.create_task(self.cycle.run_asgi(app)) + task.add_done_callback(self.tasks.discard) + self.tasks.add(task) + + elif isinstance(event, zttp.Data): + if self.cycle is not None and not self.cycle.response_complete: + self.cycle.body += event.data + if len(self.cycle.body) > HIGH_WATER_LIMIT: + self.flow.pause_reading() + self.cycle.message_event.set() + + elif isinstance(event, zttp.EndOfMessage): + if self.cycle is not None: + self.cycle.more_body = False + self.cycle.message_event.set() + if self.cycle.response_complete: + self.conn.start_next_cycle() + + event = self.conn.next_event() + + def handle_remote_protocol_error(self) -> None: + msg = "Invalid HTTP request received." + self.logger.warning(msg) + self.send_400_response(msg) + + def handle_websocket_upgrade(self, event: zttp.Request) -> None: + if self.logger.level <= TRACE_LOG_LEVEL: # pragma: no cover + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sUpgrading to WebSocket", prefix) + + self.connections.discard(self) + output = bytearray(event.method + b" " + event.target + b" HTTP/1.1\r\n") + for name, value in self.headers: + output += name + b": " + value + b"\r\n" + output += b"\r\n" + protocol = self.ws_protocol_class( # type: ignore[call-arg, misc] + config=self.config, + server_state=self.server_state, + app_state=self.app_state, + ) + protocol.connection_made(self.transport) + protocol.data_received(bytes(output)) + self.transport.set_protocol(protocol) + + def send_400_response(self, msg: str) -> None: + body = msg.encode("ascii") + headers: list[tuple[bytes, bytes]] = [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"content-length", str(len(body)).encode("ascii")), + (b"connection", b"close"), + ] + self.conn.send_response(400, headers) + self.conn.send_data(body) + self.conn.end_message() + self.transport.write(self.conn.data_to_send()) + self.transport.close() + + def on_response_complete(self) -> None: + self.server_state.total_requests += 1 + + if self.transport.is_closing(): + return + + # Set a short Keep-Alive timeout. + self._unset_keepalive_if_required() + + self.timeout_keep_alive_task = self.loop.call_later(self.timeout_keep_alive, self.timeout_keep_alive_handler) + + # Unpause data reads if needed. + self.flow.resume_reading() + + # Do not reset the parser until the complete request body has arrived. + # An application may respond before consuming it; any remaining body + # still belongs to the current request and must be discarded as such. + if self.cycle is not None and not self.cycle.more_body: + self.conn.start_next_cycle() + try: + self.handle_events(self.conn.next_event()) + except zttp.RemoteProtocolError: # pragma: no cover + self.handle_remote_protocol_error() + + def shutdown(self) -> None: + """ + Called by the server to commence a graceful shutdown. + """ + if self.cycle is None or self.cycle.response_complete: + self.transport.close() + else: + self.cycle.keep_alive = False + + def pause_writing(self) -> None: + """ + Called by the transport when the write buffer exceeds the high water mark. + """ + self.flow.pause_writing() # pragma: no cover + + def resume_writing(self) -> None: + """ + Called by the transport when the write buffer drops below the low water mark. + """ + self.flow.resume_writing() # pragma: no cover + + def timeout_keep_alive_handler(self) -> None: + """ + Called on a keep-alive connection if no new data is received after a short + delay. + """ + if not self.transport.is_closing(): + self.transport.close() + + +class RequestResponseCycle: + def __init__( + self, + scope: HTTPScope, + conn: zttp.H1Connection, + transport: asyncio.Transport, + flow: FlowControl, + logger: logging.Logger, + access_logger: logging.Logger, + access_log: bool, + default_headers: list[tuple[bytes, bytes]], + message_event: asyncio.Event, + expect_100_continue: bool, + on_response: Callable[..., None], + ) -> None: + self.scope = scope + self.conn = conn + self.transport = transport + self.flow = flow + self.logger = logger + self.access_logger = access_logger + self.access_log = access_log + self.default_headers = default_headers + self.message_event = message_event + self.on_response = on_response + + # Connection state + self.disconnected = False + self.keep_alive = True + self.waiting_for_100_continue = expect_100_continue + + # Request state + self.body = bytearray() + self.more_body = True + + # Response state + self.response_started = False + self.response_complete = False + self.bodyless = False + self.chunked_encoding = False + self.expected_content_length = 0 + + # ASGI exception wrapper + async def run_asgi(self, app: ASGI3Application) -> None: + try: + result = await app( # type: ignore[func-returns-value] + self.scope, self.receive, self.send + ) + except BaseException as exc: + msg = "Exception in ASGI application\n" + self.logger.error(msg, exc_info=exc) + if not self.response_started: + await self.send_500_response() + else: + self.transport.close() + else: + if result is not None: + msg = "ASGI callable should return None, but returned '%s'." + self.logger.error(msg, result) + self.transport.close() + elif not self.response_started and not self.disconnected: + msg = "ASGI callable returned without starting response." + self.logger.error(msg) + await self.send_500_response() + elif not self.response_complete and not self.disconnected: + msg = "ASGI callable returned without completing response." + self.logger.error(msg) + self.transport.close() + finally: + self.on_response = lambda: None + + async def send_500_response(self) -> None: + response_start_event: HTTPResponseStartEvent = { + "type": "http.response.start", + "status": 500, + "headers": [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"connection", b"close"), + ], + } + await self.send(response_start_event) + response_body_event: HTTPResponseBodyEvent = { + "type": "http.response.body", + "body": b"Internal Server Error", + "more_body": False, + } + await self.send(response_body_event) + + # ASGI interface + async def send(self, message: ASGISendEvent) -> None: + if self.flow.write_paused and not self.disconnected: + await self.flow.drain() # pragma: no cover + + if self.disconnected: + return # pragma: no cover + + if not self.response_started: + # Sending response status line and headers + if message["type"] != "http.response.start": + raise RuntimeError(f"Expected ASGI message 'http.response.start', but got '{message['type']}'.") + + self.response_started = True + self.waiting_for_100_continue = False + + status = message["status"] + headers = self.default_headers + list(message.get("headers", [])) + + bodyless = self.scope["method"] == "HEAD" or status in (204, 304) or status < 200 + + # RFC 9112 §6.1 forbids Transfer-Encoding on 1xx and 204 responses, and + # zttp refuses to serialize one there, so drop it instead of erroring. + # HEAD and 304 may keep it: it describes the body a GET would return. + if status < 200 or status == 204: + headers = [(name, value) for name, value in headers if name.lower() != b"transfer-encoding"] + + has_content_length = False + has_transfer_encoding = False + for name, value in headers: + name = name.lower() + if name == b"content-length": + has_content_length = True + self.expected_content_length = int(value.decode()) + elif name == b"transfer-encoding": + # zttp only accepts a sole, final `chunked` coding - anything + # else raises, like h11 - and it frames the body itself, so + # there is no Content-Length accounting to do here. + has_transfer_encoding = True + self.chunked_encoding = True + + # A response carrying both Content-Length and Transfer-Encoding is + # a framing conflict that zttp rejects, so drop the Content-Length. + if has_transfer_encoding and has_content_length: + headers = [(name, value) for name, value in headers if name.lower() != b"content-length"] + has_content_length = False + self.expected_content_length = 0 + + # zttp refuses to frame the body unless the response declares + # Content-Length or Transfer-Encoding, so add chunked encoding + # ourselves when the application provides neither. + if not bodyless and not has_transfer_encoding and not has_content_length: + self.chunked_encoding = True + headers = headers + [(b"transfer-encoding", b"chunked")] + + if self.access_log: + self.access_logger.info( + '%s - "%s %s HTTP/%s" %d', + get_client_addr(self.scope), + self.scope["method"], + get_path_with_query_string(self.scope), + self.scope["http_version"], + status, + ) + + # Write response status line and headers + self.bodyless = bodyless + self.conn.send_response(status, headers) + self.transport.write(self.conn.data_to_send()) + + elif not self.response_complete: + # Sending response body + if message["type"] != "http.response.body": + raise RuntimeError(f"Expected ASGI message 'http.response.body', but got '{message['type']}'.") + + body = message.get("body", b"") + more_body = message.get("more_body", False) + + # Write response body + if self.bodyless: + self.expected_content_length = 0 + elif self.chunked_encoding: + if body: + self.conn.send_data(body) + self.transport.write(self.conn.data_to_send()) + else: + if len(body) > self.expected_content_length: + raise RuntimeError("Response content longer than Content-Length") + self.expected_content_length -= len(body) + if body: + self.conn.send_data(body) + self.transport.write(self.conn.data_to_send()) + + # Handle response completion + if not more_body: + if self.expected_content_length != 0: + raise RuntimeError("Response content shorter than Content-Length") + self.response_complete = True + self.message_event.set() + self.conn.end_message() + self.transport.write(self.conn.data_to_send()) + + else: + # Response already sent + raise RuntimeError(f"Unexpected ASGI message '{message['type']}' sent, after response already completed.") + + if self.response_complete: + # `should_close()` covers both directions: the request's `Connection: close` + # or HTTP/1.0 default, and a `close` the response we just wrote declared. + if not self.keep_alive or self.conn.should_close(): + self.transport.close() + self.on_response() + + async def receive(self) -> ASGIReceiveEvent: + if self.waiting_for_100_continue and not self.transport.is_closing(): + self.conn.send_informational(100) + self.transport.write(self.conn.data_to_send()) + self.waiting_for_100_continue = False + + if not self.disconnected and not self.response_complete: + self.flow.resume_reading() + await self.message_event.wait() + self.message_event.clear() + + if self.disconnected or self.response_complete: + return {"type": "http.disconnect"} + + message: HTTPRequestEvent = {"type": "http.request", "body": bytes(self.body), "more_body": self.more_body} + self.body = bytearray() + return message diff --git a/source/target-vendors/cp312/uvicorn/protocols/utils.py b/source/target-vendors/cp312/uvicorn/protocols/utils.py new file mode 100644 index 0000000..a9a8906 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/utils.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +import asyncio +import socket +import urllib.parse + +from uvicorn._types import WWWScope + + +class ClientDisconnected(OSError): ... + + +def get_remote_addr(transport: asyncio.Transport) -> tuple[str, int] | None: + socket_info: socket.socket | None = transport.get_extra_info("socket") + if socket_info is not None: + try: + info = socket_info.getpeername() + return (str(info[0]), int(info[1])) if isinstance(info, tuple) else None + except OSError: # pragma: no cover + # This case appears to inconsistently occur with uvloop + # bound to a unix domain socket. + return None + + info = transport.get_extra_info("peername") + if info is not None and isinstance(info, list | tuple) and len(info) == 2: + return (str(info[0]), int(info[1])) + return None + + +def get_local_addr(transport: asyncio.Transport) -> tuple[str, int | None] | None: + socket_info: socket.socket | None = transport.get_extra_info("socket") + if socket_info is not None: + info = socket_info.getsockname() + if isinstance(info, tuple): + return (str(info[0]), int(info[1])) + if isinstance(info, str): + return (info, None) + return None + info = transport.get_extra_info("sockname") + if info is not None and isinstance(info, list | tuple) and len(info) == 2: + return (str(info[0]), int(info[1])) + if isinstance(info, str): + return (info, None) + return None + + +def is_ssl(transport: asyncio.Transport) -> bool: + return bool(transport.get_extra_info("sslcontext")) + + +def get_client_addr(scope: WWWScope) -> str: + client = scope.get("client") + if not client: + return "" + return "%s:%d" % client + + +def get_path_with_query_string(scope: WWWScope) -> str: + path_with_query_string = urllib.parse.quote(scope["path"]) + if scope["query_string"]: + path_with_query_string = "{}?{}".format(path_with_query_string, scope["query_string"].decode("ascii")) + return path_with_query_string diff --git a/source/target-vendors/cp312/uvicorn/protocols/websockets/__init__.py b/source/target-vendors/cp312/uvicorn/protocols/websockets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/source/target-vendors/cp312/uvicorn/protocols/websockets/auto.py b/source/target-vendors/cp312/uvicorn/protocols/websockets/auto.py new file mode 100644 index 0000000..23db3d0 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/websockets/auto.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import asyncio +from collections.abc import Callable + +AutoWebSocketsProtocol: Callable[..., asyncio.Protocol] | None +try: + import websockets # noqa +except ImportError: # pragma: no cover + try: + import wsproto # noqa + except ImportError: + AutoWebSocketsProtocol = None + else: + from uvicorn.protocols.websockets.wsproto_impl import WSProtocol + + AutoWebSocketsProtocol = WSProtocol +else: + from uvicorn.protocols.websockets.websockets_sansio_impl import WebSocketsSansIOProtocol + + AutoWebSocketsProtocol = WebSocketsSansIOProtocol diff --git a/source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_impl.py b/source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_impl.py new file mode 100644 index 0000000..8206a58 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_impl.py @@ -0,0 +1,390 @@ +from __future__ import annotations + +import asyncio +import http +import logging +import warnings +from collections.abc import Sequence +from typing import Any, Literal, cast +from urllib.parse import unquote + +import websockets +import websockets.legacy.handshake +from websockets import __version__ as websockets_version +from websockets.datastructures import Headers +from websockets.exceptions import ConnectionClosed +from websockets.extensions.base import ServerExtensionFactory +from websockets.extensions.permessage_deflate import ServerPerMessageDeflateFactory +from websockets.legacy.server import HTTPResponse, WebSocketServerProtocol +from websockets.typing import Subprotocol + +from uvicorn._types import ( + ASGI3Application, + ASGISendEvent, + WebSocketConnectEvent, + WebSocketDisconnectEvent, + WebSocketReceiveEvent, + WebSocketScope, +) +from uvicorn.config import Config, UvicornDeprecationWarning +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.utils import ( + ClientDisconnected, + get_client_addr, + get_local_addr, + get_path_with_query_string, + get_remote_addr, + is_ssl, +) +from uvicorn.server import ServerState + +warnings.warn( + "The `websockets` implementation is deprecated, and `--ws websockets` will point at the " + "`websockets-sansio` implementation in a future release. " + "Use `--ws websockets-sansio` or `--ws auto` to switch now.", + UvicornDeprecationWarning, +) + + +class Server: + closing = False + + def register(self, ws: WebSocketServerProtocol) -> None: + pass + + def unregister(self, ws: WebSocketServerProtocol) -> None: + pass + + def is_serving(self) -> bool: + return not self.closing + + +class WebSocketProtocol(WebSocketServerProtocol): + extra_headers: list[tuple[str, str]] + logger: logging.Logger | logging.LoggerAdapter[Any] + + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ): + if not config.loaded: + config.load() + + self.config = config + self.app = cast(ASGI3Application, config.loaded_app) + self.loop = _loop or asyncio.get_event_loop() + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.app_state = app_state + + # Shared server state + self.connections = server_state.connections + self.tasks = server_state.tasks + + # Connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["wss", "ws"] = None # type: ignore[assignment] + + # Connection events + self.scope: WebSocketScope + self.handshake_started_event = asyncio.Event() + self.handshake_completed_event = asyncio.Event() + self.closed_event = asyncio.Event() + self.initial_response: HTTPResponse | None = None + self.connect_sent = False + self.lost_connection_before_handshake = False + self.accepted_subprotocol: Subprotocol | None = None + + self.ws_server: Server = Server() # type: ignore[assignment] + + extensions: list[ServerExtensionFactory] = [] + if self.config.ws_per_message_deflate: + extensions.append(ServerPerMessageDeflateFactory()) + + super().__init__( + ws_handler=self.ws_handler, + ws_server=self.ws_server, # type: ignore[arg-type] + max_size=self.config.ws_max_size, + max_queue=self.config.ws_max_queue, + ping_interval=self.config.ws_ping_interval, + ping_timeout=self.config.ws_ping_timeout, + extensions=extensions, + logger=logging.getLogger("uvicorn.error"), + ) + self.server_header = None + self.extra_headers = [ + (name.decode("latin-1"), value.decode("latin-1")) for name, value in server_state.default_headers + ] + + def connection_made( # type: ignore[override] + self, transport: asyncio.Transport + ) -> None: + self.connections.add(self) + self.transport = transport + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "wss" if is_ssl(transport) else "ws" + + if self.logger.isEnabledFor(TRACE_LOG_LEVEL): + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection made", prefix) + + super().connection_made(transport) + + def connection_lost(self, exc: Exception | None) -> None: + self.connections.remove(self) + + if self.logger.isEnabledFor(TRACE_LOG_LEVEL): + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection lost", prefix) + + self.lost_connection_before_handshake = not self.handshake_completed_event.is_set() + self.handshake_completed_event.set() + super().connection_lost(exc) + if exc is None: + self.transport.close() + + def shutdown(self) -> None: + self.ws_server.closing = True + if self.handshake_completed_event.is_set(): + self.fail_connection(1012) + else: + self.send_500_response() + self.transport.close() + + def on_task_complete(self, task: asyncio.Task[None]) -> None: + self.tasks.discard(task) + + async def process_request(self, path: str, request_headers: Headers) -> HTTPResponse | None: + """ + This hook is called to determine if the websocket should return + an HTTP response and close. + + Our behavior here is to start the ASGI application, and then wait + for either `accept` or `close` in order to determine if we should + close the connection. + """ + path_portion, _, query_string = path.partition("?") + + websockets.legacy.handshake.check_request(request_headers) + + subprotocols: list[str] = [] + for header in request_headers.get_all("Sec-WebSocket-Protocol"): + subprotocols.extend([token.strip() for token in header.split(",")]) + + # websockets 17.0 documents that non-ASCII header values are encoded + # with ISO-8859-1. Earlier versions didn't document the behavior but + # we can see in the code that it used surrogate escape encoding. + # Move the pragma: no cover to the else: branch when 17.0 is released. + if websockets_version >= "17.0": # pragma: no cover + asgi_headers = [ + (name.encode("ascii"), value.encode("latin-1")) for name, value in request_headers.raw_items() + ] + else: + asgi_headers = [ + (name.encode("ascii"), value.encode("ascii", errors="surrogateescape")) + for name, value in request_headers.raw_items() + ] + path = unquote(path_portion) + full_path = self.root_path + path + full_raw_path = self.root_path.encode("ascii") + path_portion.encode("ascii") + + self.scope = { + "type": "websocket", + "asgi": {"version": self.asgi_version, "spec_version": "2.4"}, + "http_version": "1.1", + "scheme": self.scheme, + "server": self.server, + "client": self.client, + "root_path": self.root_path, + "path": full_path, + "raw_path": full_raw_path, + "query_string": query_string.encode("ascii"), + "headers": asgi_headers, + "subprotocols": subprotocols, + "state": self.app_state.copy(), + "extensions": {"websocket.http.response": {}}, + } + task = self.loop.create_task(self.run_asgi()) + task.add_done_callback(self.on_task_complete) + self.tasks.add(task) + await self.handshake_started_event.wait() + return self.initial_response + + def process_subprotocol( + self, headers: Headers, available_subprotocols: Sequence[Subprotocol] | None + ) -> Subprotocol | None: + """ + We override the standard 'process_subprotocol' behavior here so that + we return whatever subprotocol is sent in the 'accept' message. + """ + return self.accepted_subprotocol + + def send_500_response(self) -> None: + msg = b"Internal Server Error" + content = [ + b"HTTP/1.1 500 Internal Server Error\r\ncontent-type: text/plain; charset=utf-8\r\n", + b"content-length: " + str(len(msg)).encode("ascii") + b"\r\n", + b"connection: close\r\n", + b"\r\n", + msg, + ] + self.transport.write(b"".join(content)) + # Allow handler task to terminate cleanly, as websockets doesn't cancel it by + # itself (see https://github.com/Kludex/uvicorn/issues/920) + self.handshake_started_event.set() + + async def ws_handler(self, protocol: WebSocketServerProtocol, path: str) -> Any: # type: ignore[override] + """ + This is the main handler function for the 'websockets' implementation + to call into. We just wait for close then return, and instead allow + 'send' and 'receive' events to drive the flow. + """ + self.handshake_completed_event.set() + await self.wait_closed() + + async def run_asgi(self) -> None: + """ + Wrapper around the ASGI callable, handling exceptions and unexpected + termination states. + """ + try: + result = await self.app(self.scope, self.asgi_receive, self.asgi_send) # type: ignore[func-returns-value] + except ClientDisconnected: # pragma: full coverage + self.closed_event.set() + except BaseException: + self.closed_event.set() + self.logger.exception("Exception in ASGI application\n") + if not self.handshake_started_event.is_set(): + self.send_500_response() + else: + await self.handshake_completed_event.wait() + else: + self.closed_event.set() + if not self.handshake_started_event.is_set(): + self.logger.error("ASGI callable returned without sending handshake.") + self.send_500_response() + elif result is not None: + self.logger.error("ASGI callable should return None, but returned '%s'.", result) + await self.handshake_completed_event.wait() + self.transport.close() + + async def asgi_send(self, message: ASGISendEvent) -> None: + if not self.handshake_started_event.is_set(): + if message["type"] == "websocket.accept": + self.logger.info( + '%s - "WebSocket %s" [accepted]', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + ) + self.initial_response = None + self.accepted_subprotocol = cast(Subprotocol | None, message.get("subprotocol")) + if "headers" in message: + self.extra_headers.extend( + # ASGI spec requires bytes + # But for compatibility we need to convert it to strings + (name.decode("latin-1"), value.decode("latin-1")) + for name, value in message["headers"] + ) + self.handshake_started_event.set() + + elif message["type"] == "websocket.close": + self.logger.info( + '%s - "WebSocket %s" 403', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + ) + self.initial_response = (http.HTTPStatus.FORBIDDEN, [], b"") + self.handshake_started_event.set() + self.closed_event.set() + + elif message["type"] == "websocket.http.response.start": + self.logger.info( + '%s - "WebSocket %s" %d', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + message["status"], + ) + # websockets requires the status to be an enum. look it up. + status = http.HTTPStatus(message["status"]) + headers = [ + (name.decode("latin-1"), value.decode("latin-1")) for name, value in message.get("headers", []) + ] + self.initial_response = (status, headers, b"") + self.handshake_started_event.set() + + else: + raise RuntimeError( + "Expected ASGI message 'websocket.accept', 'websocket.close', " + f"or 'websocket.http.response.start' but got '{message['type']}'." + ) + + elif not self.closed_event.is_set() and self.initial_response is None: + await self.handshake_completed_event.wait() + + try: + if message["type"] == "websocket.send": + bytes_data = message.get("bytes") + text_data = message.get("text") + data = text_data if bytes_data is None else bytes_data + await self.send(data) # type: ignore[arg-type] + + elif message["type"] == "websocket.close": + code = message.get("code", 1000) + reason = message.get("reason", "") or "" + await self.close(code, reason) + self.closed_event.set() + + else: + raise RuntimeError( + f"Expected ASGI message 'websocket.send' or 'websocket.close', but got '{message['type']}'." + ) + except ConnectionClosed as exc: + raise ClientDisconnected from exc + + elif self.initial_response is not None: + if message["type"] == "websocket.http.response.body": + body = self.initial_response[2] + message["body"] + self.initial_response = self.initial_response[:2] + (body,) + if not message.get("more_body", False): + self.closed_event.set() + else: + raise RuntimeError(f"Expected ASGI message 'websocket.http.response.body' but got '{message['type']}'.") + + else: + raise RuntimeError( + f"Unexpected ASGI message '{message['type']}', after sending 'websocket.close' " + "or response already completed." + ) + + async def asgi_receive(self) -> WebSocketDisconnectEvent | WebSocketConnectEvent | WebSocketReceiveEvent: + if not self.connect_sent: + self.connect_sent = True + return {"type": "websocket.connect"} + + await self.handshake_completed_event.wait() + + if self.lost_connection_before_handshake: + # If the handshake failed or the app closed before handshake completion, + # use 1006 Abnormal Closure. + return {"type": "websocket.disconnect", "code": 1006} + + if self.closed_event.is_set(): + return {"type": "websocket.disconnect", "code": 1005} + + try: + data = await self.recv() + except ConnectionClosed: + self.closed_event.set() + if self.ws_server.closing: + return {"type": "websocket.disconnect", "code": 1012} + return {"type": "websocket.disconnect", "code": self.close_code or 1005, "reason": self.close_reason} + + if isinstance(data, str): + return {"type": "websocket.receive", "text": data} + return {"type": "websocket.receive", "bytes": data} diff --git a/source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_sansio_impl.py b/source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_sansio_impl.py new file mode 100644 index 0000000..a444433 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/websockets/websockets_sansio_impl.py @@ -0,0 +1,556 @@ +from __future__ import annotations + +import asyncio +import email.utils +import logging +import random +import struct +import sys +from asyncio import TimerHandle +from asyncio.transports import BaseTransport, Transport +from http import HTTPStatus +from typing import Any, Literal, cast +from urllib.parse import unquote + +from websockets import __version__ as websockets_version +from websockets.datastructures import Headers +from websockets.exceptions import InvalidState +from websockets.extensions.permessage_deflate import ServerPerMessageDeflateFactory +from websockets.frames import Frame, Opcode +from websockets.http11 import Request, Response +from websockets.server import ServerProtocol + +from uvicorn._types import ( + ASGIReceiveEvent, + ASGISendEvent, + WebSocketScope, +) +from uvicorn.config import Config +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.utils import ( + ClientDisconnected, + get_client_addr, + get_local_addr, + get_path_with_query_string, + get_remote_addr, + is_ssl, +) +from uvicorn.server import ServerState + +if sys.version_info >= (3, 11): # pragma: no cover + from typing import assert_never +else: # pragma: no cover + from typing_extensions import assert_never + + +def _get_status_phrase(status_code: int) -> str: + try: + return HTTPStatus(status_code).phrase + except ValueError: + return "" + + +STATUS_PHRASES = {status_code: _get_status_phrase(status_code) for status_code in range(100, 600)} + + +class WebSocketsSansIOProtocol(asyncio.Protocol): + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() # pragma: no cover + + self.config = config + self.app = config.loaded_app + self.loop = _loop or asyncio.get_event_loop() + self.logger = logging.getLogger("uvicorn.error") + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.app_state = app_state + + # Shared server state + self.connections = server_state.connections + self.tasks = server_state.tasks + self.default_headers = server_state.default_headers + + # Connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["wss", "ws"] = None # type: ignore[assignment] + + # WebSocket state + self.queue: asyncio.Queue[ASGIReceiveEvent] = asyncio.Queue() + self.handshake_initiated = False + self.handshake_complete = False + self.close_sent = False + self.disconnected = False + self.close_timer: TimerHandle | None = None + self.close_timeout = 10.0 + self.initial_response: tuple[int, list[tuple[str, str]], bytes] | None = None + + extensions = [] + if self.config.ws_per_message_deflate: + extensions = [ + ServerPerMessageDeflateFactory( + server_max_window_bits=12, + client_max_window_bits=12, + compress_settings={"memLevel": 5}, + ) + ] + self.conn = ServerProtocol( + extensions=extensions, + max_size=self.config.ws_max_size, + logger=logging.getLogger("uvicorn.error"), + ) + + self.read_paused = False + self.writable = asyncio.Event() + self.writable.set() + + # Keepalive state + self.ping_interval = config.ws_ping_interval + self.ping_timeout = config.ws_ping_timeout + self.ping_timer: TimerHandle | None = None + self.pong_timer: TimerHandle | None = None + self.pending_ping_payload: bytes | None = None + self.ping_sent_at: float = 0.0 + self.last_ping_rtt: float = 0.0 + + # Incoming message state + self.frames: list[bytes] = [] + self.curr_msg_data_type: Literal["text", "bytes"] = "bytes" + + def connection_made(self, transport: BaseTransport) -> None: + """Called when a connection is made.""" + transport = cast(Transport, transport) + self.connections.add(self) + self.transport = transport + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "wss" if is_ssl(transport) else "ws" + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection made", prefix) + + def connection_lost(self, exc: Exception | None) -> None: + self.stop_keepalive() + code = 1005 if self.handshake_complete else 1006 + self.queue.put_nowait({"type": "websocket.disconnect", "code": code}) + self.connections.remove(self) + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection lost", prefix) + + self.handshake_complete = True + self.disconnected = True + # Unblock any send() awaiting writable: asyncio never calls resume_writing() on a + # transport that is lost while paused, and the buffer will never drain now. + self.writable.set() + if self.close_timer is not None: + self.close_timer.cancel() + self.close_timer = None + if exc is None: + self.transport.close() + + def eof_received(self) -> None: + pass + + def pause_writing(self) -> None: + """ + Called by the transport when the write buffer exceeds the high water mark. + """ + self.writable.clear() # pragma: full coverage + + def resume_writing(self) -> None: + """ + Called by the transport when the write buffer drops below the low water mark. + """ + self.writable.set() # pragma: full coverage + + def shutdown(self) -> None: + self.stop_keepalive() + if self.close_sent: + if self.close_timer is not None: + self.close_timer.cancel() + self.close_timer = None + self.transport.close() + return + if self.handshake_complete: + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1012}) + self.conn.send_close(1012) + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + else: + self.send_500_response() + self.transport.close() + + def data_received(self, data: bytes) -> None: + self.conn.receive_data(data) + if self.conn.parser_exc is not None: # pragma: no cover + self.handle_parser_exception() + return + self.handle_events() + + def handle_events(self) -> None: + for event in self.conn.events_received(): + if isinstance(event, Request): + self.handle_connect(event) + if isinstance(event, Frame): + if event.opcode == Opcode.CONT: + self.handle_cont(event) # pragma: no cover + elif event.opcode == Opcode.TEXT: + self.handle_text(event) + elif event.opcode == Opcode.BINARY: + self.handle_bytes(event) + elif event.opcode == Opcode.PING: + self.handle_ping() + elif event.opcode == Opcode.PONG: + self.handle_pong(event) + elif event.opcode == Opcode.CLOSE: + self.handle_close(event) + else: + assert_never(event.opcode) # pragma: no cover + + # Event handlers + + def handle_connect(self, event: Request) -> None: + self.request = event + self.response = self.conn.accept(event) + self.handshake_initiated = True + if self.response.status_code != 101: + self.handshake_complete = True + self.close_sent = True + self.conn.send_response(self.response) + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + self.transport.close() + return + + # websockets 17.0 documents that non-ASCII header values are encoded + # with ISO-8859-1. Earlier versions didn't document the behavior but + # we can see in the code that it used surrogate escape encoding. + # Move the pragma: no cover to the else: branch when 17.0 is released. + if websockets_version >= "17.0": # pragma: no cover + headers = [(key.encode("ascii"), value.encode("latin-1")) for key, value in event.headers.raw_items()] + else: + headers = [ + (key.encode("ascii"), value.encode("ascii", errors="surrogateescape")) + for key, value in event.headers.raw_items() + ] + raw_path, _, query_string = event.path.partition("?") + subprotocols: list[str] = [] + for header in event.headers.get_all("Sec-WebSocket-Protocol"): + subprotocols.extend([token.strip() for token in header.split(",")]) + self.scope: WebSocketScope = { + "type": "websocket", + "asgi": {"version": self.asgi_version, "spec_version": "2.4"}, + "http_version": "1.1", + "scheme": self.scheme, + "server": self.server, + "client": self.client, + "root_path": self.root_path, + "path": self.root_path + unquote(raw_path), + "raw_path": self.root_path.encode("ascii") + raw_path.encode("ascii"), + "query_string": query_string.encode("ascii"), + "headers": headers, + "subprotocols": subprotocols, + "state": self.app_state.copy(), + "extensions": {"websocket.http.response": {}}, + } + self.queue.put_nowait({"type": "websocket.connect"}) + task = self.loop.create_task(self.run_asgi()) + task.add_done_callback(self.on_task_complete) + self.tasks.add(task) + + def handle_cont(self, event: Frame) -> None: + self.frames.append(event.data) # type: ignore[arg-type] + if event.fin: + self.send_receive_event_to_app() + + def handle_text(self, event: Frame) -> None: + self.curr_msg_data_type = "text" + self.frames = [event.data] # type: ignore[list-item] + if event.fin: + self.send_receive_event_to_app() + + def handle_bytes(self, event: Frame) -> None: + self.curr_msg_data_type = "bytes" + self.frames = [event.data] # type: ignore[list-item] + if event.fin: + self.send_receive_event_to_app() + + def send_receive_event_to_app(self) -> None: + data = self.frames[0] if len(self.frames) == 1 else b"".join(self.frames) + self.frames = [] + if self.close_sent: + # The app is past `websocket.close`: discard the message rather than queueing + # it, so reads stay active until the peer's close reply arrives. + return + if self.curr_msg_data_type == "text": + try: + self.queue.put_nowait({"type": "websocket.receive", "text": data.decode()}) + except UnicodeDecodeError: # pragma: no cover + self.logger.exception("Invalid UTF-8 sequence received from client.") + self.conn.send_close(1007) + self.handle_parser_exception() + return + else: + self.queue.put_nowait({"type": "websocket.receive", "bytes": data}) + if not self.read_paused: + self.read_paused = True + self.transport.pause_reading() + + def handle_ping(self) -> None: + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + + def handle_pong(self, event: Frame) -> None: + # Ignore unsolicited pongs and stale pongs whose payload doesn't match the ping currently in flight + if self.pending_ping_payload is None or bytes(event.data) != self.pending_ping_payload: + return # pragma: no cover + + self.last_ping_rtt = self.loop.time() - self.ping_sent_at + self.pending_ping_payload = None + # The peer answered in time; cancel the pong deadline and chain the next ping. This `schedule_ping()` call is + # what keeps the keepalive loop running when ping_timeout is set. When ping_timeout is None the next ping is + # already scheduled by `send_keepalive_ping`, so we must not schedule a duplicate here. + if self.pong_timer is not None: + self.pong_timer.cancel() + self.pong_timer = None + self.schedule_ping() + + def start_keepalive(self) -> None: + if self.ping_interval is not None and self.ping_interval > 0: + self.schedule_ping() + + def stop_keepalive(self) -> None: + if self.ping_timer is not None: + self.ping_timer.cancel() + self.ping_timer = None + if self.pong_timer is not None: # pragma: no cover + self.pong_timer.cancel() + self.pong_timer = None + self.pending_ping_payload = None + + def schedule_ping(self) -> None: + assert self.ping_interval is not None + delay = max(0.0, self.ping_interval - self.last_ping_rtt) + self.ping_timer = self.loop.call_later(delay, self.send_keepalive_ping) + + def send_keepalive_ping(self) -> None: + self.ping_timer = None + if self.close_sent or self.transport.is_closing(): # pragma: no cover + return + # Random 4-byte payload identifies this ping; `handle_pong` uses it to ignore stale or unsolicited pongs. + # See https://github.com/python-websockets/websockets/blob/4d229bf9f583d593aa103287aee0a77c9fbc3a79/src/websockets/asyncio/connection.py#L624 + self.pending_ping_payload = struct.pack("!I", random.getrandbits(32)) + self.ping_sent_at = self.loop.time() + self.conn.send_ping(self.pending_ping_payload) + self.transport.write(b"".join(self.conn.data_to_send())) + if self.ping_timeout is not None: + self.pong_timer = self.loop.call_later(self.ping_timeout, self.keepalive_timeout) + else: # pragma: no cover + self.schedule_ping() + + def keepalive_timeout(self) -> None: + self.pong_timer = None + self.pending_ping_payload = None + if self.close_sent or self.transport.is_closing(): # pragma: no cover + return + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket keepalive ping timeout", prefix) + self.conn.fail(1011, "keepalive ping timeout") + self.transport.write(b"".join(self.conn.data_to_send())) + self.close_sent = True + self.transport.close() + + def handle_close(self, event: Frame) -> None: + if self.close_sent: + # The peer echoed our close frame: the closing handshake is complete. + if self.close_timer is not None: + self.close_timer.cancel() + self.close_timer = None + self.transport.close() + return + if not self.transport.is_closing(): + assert self.conn.close_rcvd is not None + code = self.conn.close_rcvd.code + reason = self.conn.close_rcvd.reason + self.queue.put_nowait({"type": "websocket.disconnect", "code": code, "reason": reason}) + + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + self.transport.close() + + def handle_parser_exception(self) -> None: # pragma: no cover + assert self.conn.close_sent is not None + code = self.conn.close_sent.code + reason = self.conn.close_sent.reason + self.queue.put_nowait({"type": "websocket.disconnect", "code": code, "reason": reason}) + + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + self.close_sent = True + self.transport.close() + + def on_task_complete(self, task: asyncio.Task[None]) -> None: + self.tasks.discard(task) + + async def run_asgi(self) -> None: + try: + result = await self.app(self.scope, self.receive, self.send) + except ClientDisconnected: + pass # pragma: full coverage + except BaseException: + self.logger.exception("Exception in ASGI application\n") + self.send_500_response() + else: + if not self.handshake_complete: + self.logger.error("ASGI callable returned without completing handshake.") + self.send_500_response() + elif result is not None: + self.logger.error("ASGI callable should return None, but returned '%s'.", result) + if self.close_timer is None: + self.transport.close() + + def send_500_response(self) -> None: + if self.initial_response or self.handshake_complete: + return + response = self.conn.reject(500, "Internal Server Error") + self.conn.send_response(response) + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + + async def send(self, message: ASGISendEvent) -> None: + await self.writable.wait() + + if self.disconnected: + raise ClientDisconnected() + + if not self.handshake_complete and self.initial_response is None: + if message["type"] == "websocket.accept": + self.logger.info( + '%s - "WebSocket %s" [accepted]', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + ) + headers = [ + (name.decode("latin-1").lower(), value.decode("latin-1")) + for name, value in (self.default_headers + list(message.get("headers", []))) + ] + accepted_subprotocol = message.get("subprotocol") + if accepted_subprotocol: + headers.append(("Sec-WebSocket-Protocol", accepted_subprotocol)) + del self.response.headers["Date"] + self.response.headers.update(headers) + + if not self.transport.is_closing(): + self.handshake_complete = True + self.conn.send_response(self.response) + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + self.start_keepalive() + + elif message["type"] == "websocket.close": + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006}) + self.logger.info( + '%s - "WebSocket %s" 403', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + ) + response = self.conn.reject(HTTPStatus.FORBIDDEN, "") + self.conn.send_response(response) + output = self.conn.data_to_send() + self.close_sent = True + self.handshake_complete = True + self.transport.write(b"".join(output)) + self.transport.close() + elif message["type"] == "websocket.http.response.start" and self.initial_response is None: + if not (100 <= message["status"] < 600): + raise RuntimeError("Invalid HTTP status code '%d' in response." % message["status"]) + self.logger.info( + '%s - "WebSocket %s" %d', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + message["status"], + ) + headers = [ + (name.decode("latin-1"), value.decode("latin-1")) + for name, value in list(message.get("headers", [])) + ] + self.initial_response = (message["status"], headers, b"") + else: + raise RuntimeError( + "Expected ASGI message 'websocket.accept', 'websocket.close' " + f"or 'websocket.http.response.start' but got '{message['type']}'." + ) + + elif not self.close_sent and self.initial_response is None: + try: + if message["type"] == "websocket.send": + bytes_data = message.get("bytes") + text_data = message.get("text") + if bytes_data is not None: + self.conn.send_binary(bytes_data) + elif text_data is not None: + self.conn.send_text(text_data.encode()) + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + + elif message["type"] == "websocket.close": + if not self.transport.is_closing(): + code = message.get("code", 1000) + reason = message.get("reason", "") or "" + self.queue.put_nowait({"type": "websocket.disconnect", "code": code, "reason": reason}) + self.conn.send_close(code, reason) + output = self.conn.data_to_send() + self.transport.write(b"".join(output)) + self.close_sent = True + if self.read_paused: + self.read_paused = False + self.transport.resume_reading() + self.close_timer = self.loop.call_later(self.close_timeout, self.transport.close) + else: + raise RuntimeError( + f"Expected ASGI message 'websocket.send' or 'websocket.close', but got '{message['type']}'." + ) + except InvalidState: + raise ClientDisconnected() + elif self.initial_response is not None: + if message["type"] == "websocket.http.response.body": + body = self.initial_response[2] + message["body"] + self.initial_response = self.initial_response[:2] + (body,) + if not message.get("more_body", False): + status_code = self.initial_response[0] + response_headers = Headers(self.initial_response[1]) + response_headers.setdefault("Date", email.utils.formatdate(usegmt=True)) + response_headers.setdefault("Connection", "close") + response_headers.setdefault("Content-Length", str(len(body))) + response_headers.setdefault("Content-Type", "text/plain; charset=utf-8") + response = Response(status_code, STATUS_PHRASES[status_code], response_headers, body) + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006}) + self.conn.send_response(response) + output = self.conn.data_to_send() + self.close_sent = True + self.transport.write(b"".join(output)) + self.transport.close() + else: # pragma: no cover + raise RuntimeError(f"Expected ASGI message 'websocket.http.response.body' but got '{message['type']}'.") + + else: + raise RuntimeError(f"Unexpected ASGI message '{message['type']}', after sending 'websocket.close'.") + + async def receive(self) -> ASGIReceiveEvent: + message = await self.queue.get() + if self.read_paused and self.queue.empty(): + self.read_paused = False + self.transport.resume_reading() + return message diff --git a/source/target-vendors/cp312/uvicorn/protocols/websockets/wsproto_impl.py b/source/target-vendors/cp312/uvicorn/protocols/websockets/wsproto_impl.py new file mode 100644 index 0000000..086abfd --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/protocols/websockets/wsproto_impl.py @@ -0,0 +1,500 @@ +from __future__ import annotations + +import asyncio +import logging +import random +import struct +from asyncio import TimerHandle +from io import BytesIO, StringIO +from typing import Any, Literal, cast +from urllib.parse import unquote + +import wsproto +from wsproto import ConnectionType, events +from wsproto.connection import ConnectionState +from wsproto.extensions import Extension, PerMessageDeflate +from wsproto.utilities import LocalProtocolError, RemoteProtocolError + +from uvicorn._types import ( + ASGI3Application, + ASGISendEvent, + WebSocketEvent, + WebSocketReceiveEvent, + WebSocketScope, +) +from uvicorn.config import Config +from uvicorn.logging import TRACE_LOG_LEVEL +from uvicorn.protocols.utils import ( + ClientDisconnected, + get_client_addr, + get_local_addr, + get_path_with_query_string, + get_remote_addr, + is_ssl, +) +from uvicorn.server import ServerState + + +class FrameTooLargeError(Exception): + """Raised when accumulated websocket message bytes exceed `ws_max_size`.""" + + +class WebsocketBuffer: + def __init__(self, max_length: int) -> None: + self.value: BytesIO | StringIO | None = None + self.length = 0 + self.max_length = max_length + + def extend(self, event: events.TextMessage | events.BytesMessage) -> None: + if self.value is None: + self.value = StringIO() if isinstance(event, events.TextMessage) else BytesIO() + self.value.write(event.data) # type: ignore[arg-type] + # `ws_max_size` is a byte budget, so count UTF-8 bytes for text. + self.length += len(event.data.encode()) if isinstance(event, events.TextMessage) else len(event.data) + if self.length > self.max_length: + raise FrameTooLargeError + + def clear(self) -> None: + self.value = None + self.length = 0 + + def to_message(self) -> WebSocketReceiveEvent: + if isinstance(self.value, StringIO): + return {"type": "websocket.receive", "text": self.value.getvalue()} + assert isinstance(self.value, BytesIO) + return {"type": "websocket.receive", "bytes": self.value.getvalue()} + + +class WSProtocol(asyncio.Protocol): + def __init__( + self, + config: Config, + server_state: ServerState, + app_state: dict[str, Any], + _loop: asyncio.AbstractEventLoop | None = None, + ) -> None: + if not config.loaded: + config.load() # pragma: full coverage + + self.config = config + self.app = cast(ASGI3Application, config.loaded_app) + self.loop = _loop or asyncio.get_event_loop() + self.logger = logging.getLogger("uvicorn.error") + self.root_path = config.root_path + self.asgi_version = config.asgi_version + self.app_state = app_state + + # Shared server state + self.connections = server_state.connections + self.tasks = server_state.tasks + self.default_headers = server_state.default_headers + + # Connection state + self.transport: asyncio.Transport = None # type: ignore[assignment] + self.server: tuple[str, int | None] | None = None + self.client: tuple[str, int] | None = None + self.scheme: Literal["wss", "ws"] = None # type: ignore[assignment] + + # WebSocket state + self.queue: asyncio.Queue[WebSocketEvent] = asyncio.Queue() + self.handshake_complete = False + self.close_sent = False + self.disconnected = False + self.close_timer: TimerHandle | None = None + self.close_timeout = 10.0 + + # Rejection state + self.response_started = False + + self.conn = wsproto.WSConnection(connection_type=ConnectionType.SERVER) + + self.read_paused = False + self.writable = asyncio.Event() + self.writable.set() + + # Keepalive state + self.ping_interval = config.ws_ping_interval + self.ping_timeout = config.ws_ping_timeout + self.ping_timer: TimerHandle | None = None + self.pong_timer: TimerHandle | None = None + self.pending_ping_payload: bytes | None = None + self.ping_sent_at: float = 0.0 + self.last_ping_rtt: float = 0.0 + + # Buffer + self.buffer = WebsocketBuffer(self.config.ws_max_size) + + # Protocol interface + + def connection_made(self, transport: asyncio.Transport) -> None: # type: ignore[override] + self.connections.add(self) + self.transport = transport + self.server = get_local_addr(transport) + self.client = get_remote_addr(transport) + self.scheme = "wss" if is_ssl(transport) else "ws" + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection made", prefix) + + def connection_lost(self, exc: Exception | None) -> None: + self.stop_keepalive() + code = 1005 if self.handshake_complete else 1006 + self.queue.put_nowait({"type": "websocket.disconnect", "code": code}) + self.connections.remove(self) + + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket connection lost", prefix) + + self.handshake_complete = True + self.disconnected = True + # asyncio never calls resume_writing() when a paused transport is lost. + self.writable.set() + if self.close_timer is not None: + self.close_timer.cancel() + self.close_timer = None + if exc is None: + self.transport.close() + + def eof_received(self) -> None: + pass + + def data_received(self, data: bytes) -> None: + try: + self.conn.receive_data(data) + except RemoteProtocolError as err: + # TODO: Remove `type: ignore` when wsproto fixes the type annotation. + self.transport.write(self.conn.send(err.event_hint)) # type: ignore[arg-type] # noqa: E501 + self.transport.close() + except LocalProtocolError: + # Data received after the close handshake completed, e.g. a pong the client + # sent while the server's close was in flight. + self.transport.close() + else: + self.handle_events() + + def handle_events(self) -> None: + for event in self.conn.events(): + if self.close_sent: + if isinstance(event, events.CloseConnection): + self.handle_close(event) + continue + if isinstance(event, events.Request): + self.handle_connect(event) + elif isinstance(event, (events.TextMessage, events.BytesMessage)): + self.handle_message(event) + elif isinstance(event, events.CloseConnection): + self.handle_close(event) + elif isinstance(event, events.Ping): + self.handle_ping(event) + elif isinstance(event, events.Pong): + self.handle_pong(event) + + def pause_writing(self) -> None: + """ + Called by the transport when the write buffer exceeds the high water mark. + """ + self.writable.clear() # pragma: full coverage + + def resume_writing(self) -> None: + """ + Called by the transport when the write buffer drops below the low water mark. + """ + self.writable.set() # pragma: full coverage + + def shutdown(self) -> None: + self.stop_keepalive() + if self.close_sent: + if self.close_timer is not None: + self.close_timer.cancel() + self.close_timer = None + self.transport.close() + return + if self.handshake_complete: + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1012}) + output = self.conn.send(wsproto.events.CloseConnection(code=1012)) + self.transport.write(output) + else: + self.send_500_response() + self.transport.close() + + def on_task_complete(self, task: asyncio.Task[None]) -> None: + self.tasks.discard(task) + + # Event handlers + + def handle_connect(self, event: events.Request) -> None: + headers = [(b"host", event.host.encode())] + headers += [(key.lower(), value) for key, value in event.extra_headers] + raw_path, _, query_string = event.target.partition("?") + path = unquote(raw_path) + full_path = self.root_path + path + full_raw_path = self.root_path.encode("ascii") + raw_path.encode("ascii") + self.scope: WebSocketScope = { + "type": "websocket", + "asgi": {"version": self.asgi_version, "spec_version": "2.4"}, + "http_version": "1.1", + "scheme": self.scheme, + "server": self.server, + "client": self.client, + "root_path": self.root_path, + "path": full_path, + "raw_path": full_raw_path, + "query_string": query_string.encode("ascii"), + "headers": headers, + "subprotocols": event.subprotocols, + "state": self.app_state.copy(), + "extensions": {"websocket.http.response": {}}, + } + self.queue.put_nowait({"type": "websocket.connect"}) + task = self.loop.create_task(self.run_asgi()) + task.add_done_callback(self.on_task_complete) + self.tasks.add(task) + + def handle_message(self, event: events.TextMessage | events.BytesMessage) -> None: + try: + self.buffer.extend(event) + except FrameTooLargeError: + self.close_sent = True + reason = f"Message exceeds the maximum size ({self.config.ws_max_size} bytes)" + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1009, "reason": reason}) + if not self.transport.is_closing(): + self.transport.write(self.conn.send(wsproto.events.CloseConnection(code=1009, reason=reason))) + self.transport.close() + return + if event.message_finished: + self.queue.put_nowait(self.buffer.to_message()) + self.buffer.clear() + if not self.read_paused: + self.read_paused = True + self.transport.pause_reading() + + def handle_close(self, event: events.CloseConnection) -> None: + if self.close_sent: + # The peer echoed our close frame: the closing handshake is complete. + if self.close_timer is not None: + self.close_timer.cancel() + self.close_timer = None + self.transport.close() + return + if self.conn.state == ConnectionState.REMOTE_CLOSING: + self.transport.write(self.conn.send(event.response())) + self.queue.put_nowait({"type": "websocket.disconnect", "code": event.code, "reason": event.reason}) + self.transport.close() + + def handle_ping(self, event: events.Ping) -> None: + self.transport.write(self.conn.send(event.response())) + + def handle_pong(self, event: events.Pong) -> None: + # Ignore unsolicited pongs and stale pongs whose payload doesn't match the ping currently in flight. + if self.pending_ping_payload is None or bytes(event.payload) != self.pending_ping_payload: + return # pragma: no cover + + self.last_ping_rtt = self.loop.time() - self.ping_sent_at + self.pending_ping_payload = None + # The peer answered in time; cancel the pong deadline and chain the next ping. This `schedule_ping()` call is + # what keeps the keepalive loop running when ping_timeout is set. When ping_timeout is None the next ping is + # already scheduled by `send_keepalive_ping`, so we must not schedule a duplicate here. + if self.pong_timer is not None: + self.pong_timer.cancel() + self.pong_timer = None + self.schedule_ping() + + def start_keepalive(self) -> None: + if self.ping_interval is not None and self.ping_interval > 0: + self.schedule_ping() + + def stop_keepalive(self) -> None: + if self.ping_timer is not None: + self.ping_timer.cancel() + self.ping_timer = None + if self.pong_timer is not None: # pragma: no cover + self.pong_timer.cancel() + self.pong_timer = None + self.pending_ping_payload = None + + def schedule_ping(self) -> None: + assert self.ping_interval is not None + delay = max(0.0, self.ping_interval - self.last_ping_rtt) + self.ping_timer = self.loop.call_later(delay, self.send_keepalive_ping) + + def send_keepalive_ping(self) -> None: + self.ping_timer = None + if self.close_sent or self.transport.is_closing(): # pragma: no cover + return + # Random 4-byte payload identifies this ping; `handle_pong` uses it to ignore stale or unsolicited pongs. + self.pending_ping_payload = struct.pack("!I", random.getrandbits(32)) + self.ping_sent_at = self.loop.time() + self.transport.write(self.conn.send(wsproto.events.Ping(payload=self.pending_ping_payload))) + if self.ping_timeout is not None: + self.pong_timer = self.loop.call_later(self.ping_timeout, self.keepalive_timeout) + else: # pragma: no cover + self.schedule_ping() + + def keepalive_timeout(self) -> None: + self.pong_timer = None + self.pending_ping_payload = None + if self.close_sent or self.transport.is_closing(): # pragma: no cover + return + if self.logger.level <= TRACE_LOG_LEVEL: + prefix = "%s:%d - " % self.client if self.client else "" + self.logger.log(TRACE_LOG_LEVEL, "%sWebSocket keepalive ping timeout", prefix) + reason = "keepalive ping timeout" + self.transport.write(self.conn.send(wsproto.events.CloseConnection(code=1011, reason=reason))) + self.close_sent = True + self.transport.close() + + def send_500_response(self) -> None: + if self.response_started or self.handshake_complete: + return # we cannot send responses anymore + headers: list[tuple[bytes, bytes]] = [ + (b"content-type", b"text/plain; charset=utf-8"), + (b"connection", b"close"), + (b"content-length", b"21"), + ] + output = self.conn.send(wsproto.events.RejectConnection(status_code=500, headers=headers, has_body=True)) + output += self.conn.send(wsproto.events.RejectData(data=b"Internal Server Error")) + self.transport.write(output) + + async def run_asgi(self) -> None: + try: + result = await self.app(self.scope, self.receive, self.send) # type: ignore[func-returns-value] + except ClientDisconnected: + pass # pragma: full coverage + except BaseException: + self.logger.exception("Exception in ASGI application\n") + self.send_500_response() + else: + if not self.handshake_complete: + self.logger.error("ASGI callable returned without completing handshake.") + self.send_500_response() + elif result is not None: + self.logger.error("ASGI callable should return None, but returned '%s'.", result) + if self.close_timer is None: + self.transport.close() + + async def send(self, message: ASGISendEvent) -> None: + await self.writable.wait() + + if self.disconnected: + raise ClientDisconnected() + + if not self.handshake_complete: + if message["type"] == "websocket.accept": + self.logger.info( + '%s - "WebSocket %s" [accepted]', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + ) + subprotocol = message.get("subprotocol") + extra_headers = self.default_headers + list(message.get("headers", [])) + extensions: list[Extension] = [] + if self.config.ws_per_message_deflate: + extensions.append(PerMessageDeflate()) + if not self.transport.is_closing(): + self.handshake_complete = True + output = self.conn.send( + wsproto.events.AcceptConnection( + subprotocol=subprotocol, + extensions=extensions, + extra_headers=extra_headers, + ) + ) + self.transport.write(output) + self.start_keepalive() + + elif message["type"] == "websocket.close": + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006}) + self.logger.info( + '%s - "WebSocket %s" 403', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + ) + self.handshake_complete = True + self.close_sent = True + event = events.RejectConnection(status_code=403, headers=[]) + output = self.conn.send(event) + self.transport.write(output) + self.transport.close() + + elif message["type"] == "websocket.http.response.start": + # ensure status code is in the valid range + if not (100 <= message["status"] < 600): + msg = "Invalid HTTP status code '%d' in response." + raise RuntimeError(msg % message["status"]) + self.logger.info( + '%s - "WebSocket %s" %d', + get_client_addr(self.scope), + get_path_with_query_string(self.scope), + message["status"], + ) + self.handshake_complete = True + event = events.RejectConnection( + status_code=message["status"], + headers=list(message["headers"]), + has_body=True, + ) + output = self.conn.send(event) + self.transport.write(output) + self.response_started = True + + else: + raise RuntimeError( + "Expected ASGI message 'websocket.accept', 'websocket.close' " + f"or 'websocket.http.response.start' but got '{message['type']}'." + ) + + elif not self.close_sent and not self.response_started: + try: + if message["type"] == "websocket.send": + bytes_data = message.get("bytes") + text_data = message.get("text") + data = text_data if bytes_data is None else bytes_data + output = self.conn.send(wsproto.events.Message(data=data)) # type: ignore + if not self.transport.is_closing(): + self.transport.write(output) + + elif message["type"] == "websocket.close": + self.close_sent = True + code = message.get("code", 1000) + reason = message.get("reason", "") or "" + self.queue.put_nowait({"type": "websocket.disconnect", "code": code, "reason": reason}) + output = self.conn.send(wsproto.events.CloseConnection(code=code, reason=reason)) + if not self.transport.is_closing(): + self.transport.write(output) + if self.read_paused: + self.read_paused = False + self.transport.resume_reading() + self.close_timer = self.loop.call_later(self.close_timeout, self.transport.close) + + else: + raise RuntimeError( + f"Expected ASGI message 'websocket.send' or 'websocket.close', but got '{message['type']}'." + ) + except LocalProtocolError as exc: + raise ClientDisconnected from exc + elif self.response_started: + if message["type"] == "websocket.http.response.body": + body_finished = not message.get("more_body", False) + reject_data = events.RejectData(data=message["body"], body_finished=body_finished) + output = self.conn.send(reject_data) + self.transport.write(output) + + if body_finished: + self.queue.put_nowait({"type": "websocket.disconnect", "code": 1006}) + self.close_sent = True + self.transport.close() + + else: + raise RuntimeError(f"Expected ASGI message 'websocket.http.response.body' but got '{message['type']}'.") + + else: + raise RuntimeError(f"Unexpected ASGI message '{message['type']}', after sending 'websocket.close'.") + + async def receive(self) -> WebSocketEvent: + message = await self.queue.get() + if self.read_paused and self.queue.empty(): + self.read_paused = False + self.transport.resume_reading() + return message diff --git a/source/target-vendors/cp312/uvicorn/py.typed b/source/target-vendors/cp312/uvicorn/py.typed new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/py.typed @@ -0,0 +1 @@ + diff --git a/source/target-vendors/cp312/uvicorn/server.py b/source/target-vendors/cp312/uvicorn/server.py new file mode 100644 index 0000000..0e822a6 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/server.py @@ -0,0 +1,356 @@ +from __future__ import annotations + +import asyncio +import contextlib +import functools +import logging +import os +import platform +import random +import signal +import socket +import sys +import threading +import time +from collections.abc import Generator, Sequence +from email.utils import formatdate +from types import FrameType +from typing import TYPE_CHECKING, TypeAlias + +from uvicorn._ansi import style +from uvicorn._compat import asyncio_run +from uvicorn.config import STARTUP_FAILURE, Config + +if TYPE_CHECKING: + from uvicorn.protocols.http.auto_zttp_impl import AutoZttpProtocol + from uvicorn.protocols.http.h11_impl import H11Protocol + from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol + from uvicorn.protocols.http.zttp_h2_impl import ZttpH2Protocol + from uvicorn.protocols.http.zttp_impl import ZttpProtocol + from uvicorn.protocols.websockets.websockets_impl import WebSocketProtocol + from uvicorn.protocols.websockets.websockets_sansio_impl import WebSocketsSansIOProtocol + from uvicorn.protocols.websockets.wsproto_impl import WSProtocol + + Protocols: TypeAlias = ( + H11Protocol + | HttpToolsProtocol + | ZttpProtocol + | ZttpH2Protocol + | AutoZttpProtocol + | WSProtocol + | WebSocketProtocol + | WebSocketsSansIOProtocol + ) + +HANDLED_SIGNALS = ( + signal.SIGINT, # Unix signal 2. Sent by Ctrl+C. + signal.SIGTERM, # Unix signal 15. Sent by `kill `. +) +if sys.platform == "win32": # pragma: py-not-win32 + HANDLED_SIGNALS += (signal.SIGBREAK,) # Windows signal 21. Sent by Ctrl+Break. + +logger = logging.getLogger("uvicorn.error") + + +class ServerState: + """ + Shared servers state that is available between all protocol instances. + """ + + def __init__(self) -> None: + self.total_requests = 0 + self.connections: set[Protocols] = set() + self.tasks: set[asyncio.Task[None]] = set() + self.default_headers: list[tuple[bytes, bytes]] = [] + + +class Server: + def __init__(self, config: Config) -> None: + self.config = config + self.server_state = ServerState() + + self.started = False + self.should_exit = False + self.force_exit = False + self.last_notified = 0.0 + + self._captured_signals: list[int] = [] + + @functools.cached_property + def limit_max_requests(self) -> int | None: + if self.config.limit_max_requests is None: + return None + return self.config.limit_max_requests + random.randint(0, self.config.limit_max_requests_jitter) + + def run(self, sockets: list[socket.socket] | None = None) -> None: + return asyncio_run(self.serve(sockets=sockets), loop_factory=self.config.get_loop_factory()) + + async def serve(self, sockets: list[socket.socket] | None = None) -> None: + with self.capture_signals(): + await self._serve(sockets) + + async def _serve(self, sockets: list[socket.socket] | None = None) -> None: + process_id = os.getpid() + + config = self.config + if not config.loaded: + config.load() + + self.lifespan = config.lifespan_class(config) + + message = "Started server process [%d]" + color_message = "Started server process [" + style("%d", fg="cyan") + "]" + logger.info(message, process_id, extra={"color_message": color_message}) + + await self.startup(sockets=sockets) + if not self.should_exit: + await self.main_loop() + if self.started: + await self.shutdown(sockets=sockets) + + message = "Finished server process [%d]" + color_message = "Finished server process [" + style("%d", fg="cyan") + "]" + logger.info(message, process_id, extra={"color_message": color_message}) + + async def startup(self, sockets: list[socket.socket] | None = None) -> None: + await self.lifespan.startup() + if self.lifespan.should_exit: + sys.exit(STARTUP_FAILURE) + + config = self.config + + def create_protocol( + _loop: asyncio.AbstractEventLoop | None = None, + ) -> asyncio.Protocol: + return config.http_protocol_class( # type: ignore[call-arg] + config=config, + server_state=self.server_state, + app_state=self.lifespan.state, + _loop=_loop, + ) + + loop = asyncio.get_running_loop() + + listeners: Sequence[socket.SocketType] + if sockets is not None: # pragma: full coverage + # Explicitly passed a list of open sockets. + # We use this when the server is run from a Gunicorn worker. + + def _share_socket( + sock: socket.SocketType, + ) -> socket.SocketType: # pragma py-not-win32 + # Windows requires the socket be explicitly shared across + # multiple workers (processes). + from socket import fromshare # type: ignore[attr-defined] + + sock_data = sock.share(os.getpid()) # type: ignore[attr-defined] + return fromshare(sock_data) + + self.servers: list[asyncio.base_events.Server] = [] + for sock in sockets: + is_windows = platform.system() == "Windows" + if config.workers > 1 and is_windows: # pragma: py-not-win32 + sock = _share_socket(sock) # type: ignore[assignment] + server = await loop.create_server(create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog) + self.servers.append(server) + listeners = sockets + + elif config.fd is not None: # pragma: py-win32 + # Use an existing socket, from a file descriptor. + sock = socket.fromfd(config.fd, socket.AF_UNIX, socket.SOCK_STREAM) + server = await loop.create_server(create_protocol, sock=sock, ssl=config.ssl, backlog=config.backlog) + assert server.sockets is not None # mypy + listeners = server.sockets + self.servers = [server] + + elif config.uds is not None: # pragma: py-win32 + # Create a socket using UNIX domain socket. + uds_perms = 0o666 + if os.path.exists(config.uds): + uds_perms = os.stat(config.uds).st_mode # pragma: full coverage + server = await loop.create_unix_server( + create_protocol, path=config.uds, ssl=config.ssl, backlog=config.backlog + ) + os.chmod(config.uds, uds_perms) + assert server.sockets is not None # mypy + listeners = server.sockets + self.servers = [server] + + else: + # Standard case. Create a socket from a host/port pair. + try: + server = await loop.create_server( + create_protocol, + host=config.host, + port=config.port, + ssl=config.ssl, + backlog=config.backlog, + ) + except OSError as exc: + logger.error(exc) + await self.lifespan.shutdown() + sys.exit(STARTUP_FAILURE) + + assert server.sockets is not None + listeners = server.sockets + self.servers = [server] + + if sockets is None: + self._log_started_message(listeners) + else: + # We're most likely running multiple workers, so a message has already been + # logged by `config.bind_socket()`. + pass # pragma: full coverage + + self.started = True + + def _log_started_message(self, listeners: Sequence[socket.SocketType]) -> None: + config = self.config + + if config.fd is not None: # pragma: py-win32 + sock = listeners[0] + logger.info( + "Uvicorn running on socket %s (Press CTRL+C to quit)", + sock.getsockname(), + ) + + elif config.uds is not None: # pragma: py-win32 + logger.info("Uvicorn running on unix socket %s (Press CTRL+C to quit)", config.uds) + + else: + addr_format = "%s://%s:%d" + host = "0.0.0.0" if config.host is None else config.host + if ":" in host: + # It's an IPv6 address. + addr_format = "%s://[%s]:%d" + + port = config.port + if port == 0: + port = listeners[0].getsockname()[1] + + protocol_name = "https" if config.ssl else "http" + message = f"Uvicorn running on {addr_format} (Press CTRL+C to quit)" + color_message = "Uvicorn running on " + style(addr_format, bold=True) + " (Press CTRL+C to quit)" + logger.info( + message, + protocol_name, + host, + port, + extra={"color_message": color_message}, + ) + + async def main_loop(self) -> None: + counter = 0 + should_exit = await self.on_tick(counter) + while not should_exit: + counter += 1 + counter = counter % 864000 + await asyncio.sleep(0.1) + should_exit = await self.on_tick(counter) + + async def on_tick(self, counter: int) -> bool: + # Update the default headers, once per second. + if counter % 10 == 0: + current_time = time.time() + current_date = formatdate(current_time, usegmt=True).encode() + + if self.config.date_header: + date_header = [(b"date", current_date)] + else: + date_header = [] + + self.server_state.default_headers = date_header + self.config.encoded_headers + + # Callback to `callback_notify` once every `timeout_notify` seconds. + if self.config.callback_notify is not None: + if current_time - self.last_notified > self.config.timeout_notify: # pragma: full coverage + self.last_notified = current_time + await self.config.callback_notify() + + # Determine if we should exit. + if self.should_exit: + return True + + max_requests = self.limit_max_requests + if max_requests is not None and self.server_state.total_requests >= max_requests: + logger.info("Maximum request limit of %d exceeded. Terminating process.", max_requests) + return True + + return False + + async def shutdown(self, sockets: list[socket.socket] | None = None) -> None: + logger.info("Shutting down") + + # Stop accepting new connections. + for server in self.servers: + server.close() + for sock in sockets or []: + sock.close() # pragma: full coverage + + # Request shutdown on all existing connections. + for connection in list(self.server_state.connections): + connection.shutdown() + await asyncio.sleep(0.1) + + # When 3.10 is not supported anymore, use `async with asyncio.timeout(...):`. + try: + await asyncio.wait_for( + self._wait_tasks_to_complete(), + timeout=self.config.timeout_graceful_shutdown, + ) + except asyncio.TimeoutError: + logger.error( + "Cancel %s running task(s), timeout graceful shutdown exceeded", + len(self.server_state.tasks), + ) + for t in self.server_state.tasks: + t.cancel(msg="Task cancelled, timeout graceful shutdown exceeded") + + # Send the lifespan shutdown event, and wait for application shutdown. + if not self.force_exit: + await self.lifespan.shutdown() + + async def _wait_tasks_to_complete(self) -> None: + # Wait for existing connections to finish sending responses. + if self.server_state.connections and not self.force_exit: + msg = "Waiting for connections to close. (CTRL+C to force quit)" + logger.info(msg) + while self.server_state.connections and not self.force_exit: + await asyncio.sleep(0.1) + + # Wait for existing tasks to complete. + if self.server_state.tasks and not self.force_exit: + msg = "Waiting for background tasks to complete. (CTRL+C to force quit)" + logger.info(msg) + while self.server_state.tasks and not self.force_exit: + await asyncio.sleep(0.1) + + for server in self.servers: + await server.wait_closed() + + @contextlib.contextmanager + def capture_signals(self) -> Generator[None, None, None]: + # Signals can only be listened to from the main thread. + if threading.current_thread() is not threading.main_thread(): + yield + return + # always use signal.signal, even if loop.add_signal_handler is available + # this allows to restore previous signal handlers later on + original_handlers = {sig: signal.signal(sig, self.handle_exit) for sig in HANDLED_SIGNALS} + try: + yield + finally: + for sig, handler in original_handlers.items(): + signal.signal(sig, handler) + # If we did gracefully shut down due to a signal, try to + # trigger the expected behaviour now; multiple signals would be + # done LIFO, see https://stackoverflow.com/questions/48434964 + for captured_signal in reversed(self._captured_signals): + signal.raise_signal(captured_signal) + + def handle_exit(self, sig: int, frame: FrameType | None) -> None: + self._captured_signals.append(sig) + if self.should_exit and sig == signal.SIGINT: + self.force_exit = True # pragma: full coverage + else: + self.should_exit = True diff --git a/source/target-vendors/cp312/uvicorn/supervisors/__init__.py b/source/target-vendors/cp312/uvicorn/supervisors/__init__.py new file mode 100644 index 0000000..cfceb6b --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/supervisors/__init__.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + +from uvicorn.supervisors.basereload import BaseReload +from uvicorn.supervisors.multiprocess import Multiprocess + +if TYPE_CHECKING: + ChangeReload: type[BaseReload] +else: + try: + from uvicorn.supervisors.watchfilesreload import WatchFilesReload as ChangeReload + except ImportError: # pragma: no cover + from uvicorn.supervisors.statreload import StatReload as ChangeReload + +__all__ = ["Multiprocess", "ChangeReload"] diff --git a/source/target-vendors/cp312/uvicorn/supervisors/basereload.py b/source/target-vendors/cp312/uvicorn/supervisors/basereload.py new file mode 100644 index 0000000..d8cb477 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/supervisors/basereload.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +import logging +import os +import signal +import sys +import threading +from collections.abc import Callable, Iterator +from pathlib import Path +from socket import socket +from types import FrameType + +from uvicorn._ansi import style +from uvicorn._subprocess import get_subprocess +from uvicorn.config import Config + +HANDLED_SIGNALS = ( + signal.SIGINT, # Unix signal 2. Sent by Ctrl+C. + signal.SIGTERM, # Unix signal 15. Sent by `kill `. +) + +logger = logging.getLogger("uvicorn.error") + + +class BaseReload: + def __init__( + self, + config: Config, + target: Callable[[list[socket] | None], None], + sockets: list[socket], + ) -> None: + self.config = config + self.target = target + self.sockets = sockets + self.should_exit = threading.Event() + self.pid = os.getpid() + self.is_restarting = False + self.reloader_name: str | None = None + + def signal_handler(self, sig: int, frame: FrameType | None) -> None: # pragma: full coverage + """ + A signal handler that is registered with the parent process. + """ + if sys.platform == "win32" and self.is_restarting: + self.is_restarting = False + else: + self.should_exit.set() + + def run(self) -> None: + self.startup() + for changes in self: + if changes: + logger.warning( + "%s detected changes in %s. Reloading...", + self.reloader_name, + ", ".join(map(_display_path, changes)), + ) + self.restart() + + self.shutdown() + + def pause(self) -> None: + if self.should_exit.wait(self.config.reload_delay): + raise StopIteration() + + def __iter__(self) -> Iterator[list[Path] | None]: + return self + + def __next__(self) -> list[Path] | None: + return self.should_restart() + + def startup(self) -> None: + message = f"Started reloader process [{self.pid}] using {self.reloader_name}" + color_message = "Started reloader process [{}] using {}".format( + style(str(self.pid), fg="cyan", bold=True), + style(str(self.reloader_name), fg="cyan", bold=True), + ) + logger.info(message, extra={"color_message": color_message}) + + for sig in HANDLED_SIGNALS: + signal.signal(sig, self.signal_handler) + + self.process = get_subprocess(config=self.config, target=self.target, sockets=self.sockets) + self.process.start() + + def restart(self) -> None: + if sys.platform == "win32": # pragma: py-not-win32 + self.is_restarting = True + assert self.process.pid is not None + os.kill(self.process.pid, signal.CTRL_C_EVENT) + + # This is a workaround to ensure the Ctrl+C event is processed + sys.stdout.write(" ") # This has to be a non-empty string + sys.stdout.flush() + else: # pragma: py-win32 + self.process.terminate() + self.process.join() + + self.process = get_subprocess(config=self.config, target=self.target, sockets=self.sockets) + self.process.start() + + def shutdown(self) -> None: + if sys.platform == "win32": + self.should_exit.set() # pragma: py-not-win32 + else: + self.process.terminate() # pragma: py-win32 + self.process.join() + + for sock in self.sockets: + sock.close() + + message = f"Stopping reloader process [{str(self.pid)}]" + color_message = "Stopping reloader process [{}]".format(style(str(self.pid), fg="cyan", bold=True)) + logger.info(message, extra={"color_message": color_message}) + + def should_restart(self) -> list[Path] | None: + raise NotImplementedError("Reload strategies should override should_restart()") + + +def _display_path(path: Path) -> str: + try: + return f"'{path.relative_to(Path.cwd())}'" + except ValueError: + return f"'{path}'" diff --git a/source/target-vendors/cp312/uvicorn/supervisors/multiprocess.py b/source/target-vendors/cp312/uvicorn/supervisors/multiprocess.py new file mode 100644 index 0000000..ef2dd2d --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/supervisors/multiprocess.py @@ -0,0 +1,282 @@ +from __future__ import annotations + +import logging +import os +import pickle +import signal +import threading +import time +from multiprocessing import Pipe +from socket import socket + +from uvicorn._ansi import style +from uvicorn._subprocess import get_subprocess +from uvicorn.config import STARTUP_FAILURE, Config +from uvicorn.server import Server + +SIGNALS = { + getattr(signal, f"SIG{x}"): x + for x in "INT TERM BREAK HUP QUIT TTIN TTOU USR1 USR2 WINCH".split() + if hasattr(signal, f"SIG{x}") +} + +logger = logging.getLogger("uvicorn.error") + + +class Process: + def __init__( + self, + config: Config, + sockets: list[socket], + ) -> None: + self.config = config + self._server: Server | None = None + + self.parent_conn, self.child_conn = Pipe() + self.process = get_subprocess(config, self.target, sockets) + + def _healthcheck(self, timeout: float) -> bool | None: + """Receives a timeout and returns the worker's startup flag, or None if it does not answer in time.""" + try: + self.parent_conn.send(b"ping") + if self.parent_conn.poll(timeout): + started: bool = self.parent_conn.recv() + return started + return None + except (OSError, EOFError, pickle.UnpicklingError): + return None + + def ping(self, timeout: float = 5) -> bool: + """Receives a timeout and returns True if the worker answers a healthcheck in time.""" + return self._healthcheck(timeout) is not None + + def is_ready(self, timeout: float = 5) -> bool: + """Receives a timeout and returns True if the worker answers and its server has finished startup.""" + return self._healthcheck(timeout) is True + + def pong(self) -> None: + """Receives one healthcheck ping and replies with whether the server has finished startup.""" + self.child_conn.recv() + self.child_conn.send(self.server.started) + + def always_pong(self) -> None: + while True: + self.pong() + + def target(self, sockets: list[socket] | None = None) -> None: # pragma: no cover + if os.name == "nt": # pragma: py-not-win32 + # Windows doesn't support SIGTERM, so we use SIGBREAK instead. + # And then we raise SIGTERM when SIGBREAK is received. + # https://learn.microsoft.com/zh-cn/cpp/c-runtime-library/reference/signal?view=msvc-170 + signal.signal( + signal.SIGBREAK, # type: ignore[attr-defined] + lambda sig, frame: signal.raise_signal(signal.SIGTERM), + ) + + threading.Thread(target=self.always_pong, daemon=True).start() + self.server.run(sockets) + + def is_alive(self, timeout: float = 5) -> bool: + if not self.process.is_alive(): + return False # pragma: full coverage + + return self.ping(timeout) + + def wait_until_ready(self, timeout: float, should_exit: threading.Event | None = None) -> bool: + """Receives a timeout and returns True if the worker starts serving, or False on exit, shutdown, or timeout.""" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if should_exit is not None and should_exit.is_set(): + return False + if not self.process.is_alive(): + return False + if self.is_ready(timeout=1): + return True + time.sleep(0.1) + return False + + def start(self) -> None: + self.process.start() + + def terminate(self) -> None: + if self.process.exitcode is None: # Process is still running + assert self.process.pid is not None + if os.name == "nt": # pragma: py-not-win32 + # Windows doesn't support SIGTERM. + # So send SIGBREAK, and then in process raise SIGTERM. + os.kill(self.process.pid, signal.CTRL_BREAK_EVENT) # type: ignore[attr-defined] + else: + os.kill(self.process.pid, signal.SIGTERM) + logger.info(f"Terminated child process [{self.process.pid}]") + + self.parent_conn.close() + self.child_conn.close() + + def kill(self) -> None: + # In Windows, the method will call `TerminateProcess` to kill the process. + # In Unix, the method will send SIGKILL to the process. + self.process.kill() + self.parent_conn.close() + self.child_conn.close() + + def join(self) -> None: + logger.info(f"Waiting for child process [{self.process.pid}]") + self.process.join() + + @property + def server(self) -> Server: + if self._server is None: + self._server = Server(config=self.config) + return self._server + + @property + def pid(self) -> int | None: + return self.process.pid + + @property + def exitcode(self) -> int | None: + return self.process.exitcode + + +class Multiprocess: + def __init__( + self, + config: Config, + sockets: list[socket], + ) -> None: + self.config = config + self.sockets = sockets + + self.processes_num = config.workers + self.processes: list[Process] = [] + + self.should_exit = threading.Event() + + self.signal_queue: list[int] = [] + for sig in SIGNALS: + signal.signal(sig, lambda sig, frame: self.signal_queue.append(sig)) + + def init_processes(self) -> None: + for _ in range(self.processes_num): + process = Process(self.config, self.sockets) + process.start() + self.processes.append(process) + + def terminate_all(self) -> None: + for process in self.processes: + process.terminate() + + def join_all(self) -> None: + for process in self.processes: + process.join() + + def restart_all(self) -> None: + """Replaces each worker, bringing its replacement into service before retiring the old worker.""" + for idx, old_process in enumerate(self.processes): + if self.should_exit.is_set(): + return + + new_process = Process(self.config, self.sockets) + new_process.start() + + if not new_process.wait_until_ready(self.config.timeout_worker_healthcheck, self.should_exit): + new_process.kill() + new_process.join() + if not self.should_exit.is_set(): + logger.error( + f"New child process [{new_process.pid}] was not ready in time; " + f"keeping worker [{old_process.pid}] and aborting the restart." + ) + return + + old_process.terminate() + old_process.join() + self.processes[idx] = new_process + + def run(self) -> None: + message = f"Started parent process [{os.getpid()}]" + color_message = "Started parent process [{}]".format(style(str(os.getpid()), fg="cyan", bold=True)) + logger.info(message, extra={"color_message": color_message}) + + self.init_processes() + + while not self.should_exit.wait(0.5): + self.handle_signals() + self.keep_subprocess_alive() + + self.terminate_all() + self.join_all() + + message = f"Stopping parent process [{os.getpid()}]" + color_message = "Stopping parent process [{}]".format(style(str(os.getpid()), fg="cyan", bold=True)) + logger.info(message, extra={"color_message": color_message}) + + def keep_subprocess_alive(self) -> None: + if self.should_exit.is_set(): + return # parent process is exiting, no need to keep subprocess alive + + for idx, process in enumerate(self.processes): + if process.is_alive(timeout=self.config.timeout_worker_healthcheck): + continue + + process.kill() # process is hung, kill it + process.join() + + if process.exitcode == STARTUP_FAILURE: + # The worker failed before it started serving, so the app, TLS or socket + # bind is broken and would fail the same way on every restart. + # See https://github.com/encode/uvicorn/discussions/2440. + logger.error(f"Child process [{process.pid}] failed to start, stopping the parent process.") + self.should_exit.set() + return + + if self.should_exit.is_set(): + return # pragma: full coverage + + logger.info(f"Child process [{process.pid}] died") + process = Process(self.config, self.sockets) + process.start() + self.processes[idx] = process + + def handle_signals(self) -> None: + for sig in tuple(self.signal_queue): + self.signal_queue.remove(sig) + sig_name = SIGNALS[sig] + sig_handler = getattr(self, f"handle_{sig_name.lower()}", None) + if sig_handler is not None: + sig_handler() + else: # pragma: no cover + logger.debug(f"Received signal {sig_name}, but no handler is defined for it.") + + def handle_int(self) -> None: + logger.info("Received SIGINT, exiting.") + self.should_exit.set() + + def handle_term(self) -> None: + logger.info("Received SIGTERM, exiting.") + self.should_exit.set() + + def handle_break(self) -> None: # pragma: py-not-win32 + logger.info("Received SIGBREAK, exiting.") + self.should_exit.set() + + def handle_hup(self) -> None: # pragma: py-win32 + logger.info("Received SIGHUP, restarting processes.") + self.restart_all() + + def handle_ttin(self) -> None: # pragma: py-win32 + logger.info("Received SIGTTIN, increasing the number of processes.") + self.processes_num += 1 + process = Process(self.config, self.sockets) + process.start() + self.processes.append(process) + + def handle_ttou(self) -> None: # pragma: py-win32 + logger.info("Received SIGTTOU, decreasing number of processes.") + if self.processes_num <= 1: + logger.info("Already reached one process, cannot decrease the number of processes anymore.") + return + self.processes_num -= 1 + process = self.processes.pop() + process.terminate() + process.join() diff --git a/source/target-vendors/cp312/uvicorn/supervisors/statreload.py b/source/target-vendors/cp312/uvicorn/supervisors/statreload.py new file mode 100644 index 0000000..28693f9 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/supervisors/statreload.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +import logging +from collections.abc import Callable, Iterator +from pathlib import Path +from socket import socket + +from uvicorn.config import Config +from uvicorn.supervisors.basereload import BaseReload + +logger = logging.getLogger("uvicorn.error") + + +class StatReload(BaseReload): + def __init__( + self, + config: Config, + target: Callable[[list[socket] | None], None], + sockets: list[socket], + ) -> None: + super().__init__(config, target, sockets) + self.reloader_name = "StatReload" + self.mtimes: dict[Path, float] = {} + + if config.reload_excludes or config.reload_includes: + logger.warning("--reload-include and --reload-exclude have no effect unless watchfiles is installed.") + + def should_restart(self) -> list[Path] | None: + self.pause() + + for file in self.iter_py_files(): + try: + mtime = file.stat().st_mtime + except OSError: # pragma: nocover + continue + + old_time = self.mtimes.get(file) + if old_time is None: + self.mtimes[file] = mtime + continue + elif mtime > old_time: + return [file] + return None + + def restart(self) -> None: + self.mtimes = {} + return super().restart() + + def iter_py_files(self) -> Iterator[Path]: + for reload_dir in self.config.reload_dirs: + for path in list(reload_dir.rglob("*.py")): + yield path.resolve() diff --git a/source/target-vendors/cp312/uvicorn/supervisors/watchfilesreload.py b/source/target-vendors/cp312/uvicorn/supervisors/watchfilesreload.py new file mode 100644 index 0000000..6009905 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/supervisors/watchfilesreload.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +from collections.abc import Callable +from pathlib import Path +from socket import socket + +from watchfiles import watch + +from uvicorn.config import Config +from uvicorn.supervisors.basereload import BaseReload + + +class FileFilter: + def __init__(self, config: Config): + default_includes = ["*.py"] + self.includes = [default for default in default_includes if default not in config.reload_excludes] + self.includes.extend(config.reload_includes) + self.includes = list(set(self.includes)) + + default_excludes = [".*", ".py[cod]", ".sw.*", "~*"] + self.excludes = [default for default in default_excludes if default not in config.reload_includes] + self.exclude_dirs = [] + for e in config.reload_excludes: + p = Path(e) + try: + is_dir = p.is_dir() + except OSError: # pragma: no cover + # gets raised on Windows for values like "*.py" + is_dir = False + + if is_dir: + self.exclude_dirs.append(p) + else: + self.excludes.append(e) # pragma: full coverage + self.excludes = list(set(self.excludes)) + + def __call__(self, path: Path) -> bool: + for include_pattern in self.includes: + if path.match(include_pattern): + if str(path).endswith(include_pattern): + return True # pragma: full coverage + + for exclude_dir in self.exclude_dirs: + if exclude_dir in path.parents: + return False + + for exclude_pattern in self.excludes: + if path.match(exclude_pattern): + return False # pragma: full coverage + + return True + return False + + +class WatchFilesReload(BaseReload): + def __init__( + self, + config: Config, + target: Callable[[list[socket] | None], None], + sockets: list[socket], + ) -> None: + super().__init__(config, target, sockets) + self.reloader_name = "WatchFiles" + self.reload_dirs: list[Path] = [] + for directory in config.reload_dirs: + self.reload_dirs.append(directory) + + self.watch_filter = FileFilter(config) + self.watcher = watch( + *self.reload_dirs, + watch_filter=None, + stop_event=self.should_exit, + # using yield_on_timeout here mostly to make sure tests don't + # hang forever, won't affect the class's behavior + yield_on_timeout=True, + ignore_permission_denied=True, + ) + + def should_restart(self) -> list[Path] | None: + self.pause() + + changes = next(self.watcher) + if changes: + unique_paths = {Path(c[1]) for c in changes} + return [p for p in unique_paths if self.watch_filter(p)] + return None diff --git a/source/target-vendors/cp312/uvicorn/workers.py b/source/target-vendors/cp312/uvicorn/workers.py new file mode 100644 index 0000000..827d091 --- /dev/null +++ b/source/target-vendors/cp312/uvicorn/workers.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +import asyncio +import logging +import signal +import sys +import warnings +from typing import Any + +from gunicorn.arbiter import Arbiter +from gunicorn.workers.base import Worker + +from uvicorn._compat import asyncio_run +from uvicorn.config import Config +from uvicorn.server import Server + +warnings.warn( + "The `uvicorn.workers` module is deprecated. Please use `uvicorn-worker` package instead.\n" + "For more details, see https://github.com/Kludex/uvicorn-worker.", + DeprecationWarning, +) + + +class UvicornWorker(Worker): + """ + A worker class for Gunicorn that interfaces with an ASGI consumer callable, + rather than a WSGI callable. + """ + + CONFIG_KWARGS: dict[str, Any] = {"loop": "auto", "http": "auto"} + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__init__(*args, **kwargs) + + logger = logging.getLogger("uvicorn.error") + logger.handlers = self.log.error_log.handlers + logger.setLevel(self.log.error_log.level) + logger.propagate = False + + logger = logging.getLogger("uvicorn.access") + logger.handlers = self.log.access_log.handlers + logger.setLevel(self.log.access_log.level) + logger.propagate = False + + config_kwargs: dict = { + "app": None, + "log_config": None, + "timeout_keep_alive": self.cfg.keepalive, + "timeout_notify": self.timeout, + "callback_notify": self.callback_notify, + "limit_max_requests": self.max_requests, + "forwarded_allow_ips": self.cfg.forwarded_allow_ips, + } + + if self.cfg.is_ssl: + ssl_kwargs = { + "ssl_keyfile": self.cfg.ssl_options.get("keyfile"), + "ssl_certfile": self.cfg.ssl_options.get("certfile"), + "ssl_keyfile_password": self.cfg.ssl_options.get("password"), + "ssl_version": self.cfg.ssl_options.get("ssl_version"), + "ssl_cert_reqs": self.cfg.ssl_options.get("cert_reqs"), + "ssl_ca_certs": self.cfg.ssl_options.get("ca_certs"), + "ssl_ciphers": self.cfg.ssl_options.get("ciphers"), + } + config_kwargs.update(ssl_kwargs) + + if self.cfg.settings["backlog"].value: + config_kwargs["backlog"] = self.cfg.settings["backlog"].value + + config_kwargs.update(self.CONFIG_KWARGS) + + self.config = Config(**config_kwargs) + + def init_signals(self) -> None: + # Reset signals so Gunicorn doesn't swallow subprocess return codes + # other signals are set up by Server.install_signal_handlers() + # See: https://github.com/Kludex/uvicorn/issues/894 + for s in self.SIGNALS: + signal.signal(s, signal.SIG_DFL) + + signal.signal(signal.SIGUSR1, self.handle_usr1) + # Don't let SIGUSR1 disturb active requests by interrupting system calls + signal.siginterrupt(signal.SIGUSR1, False) + + def _install_sigquit_handler(self) -> None: + """Install a SIGQUIT handler on workers. + + - https://github.com/Kludex/uvicorn/issues/1116 + - https://github.com/benoitc/gunicorn/issues/2604 + """ + + loop = asyncio.get_running_loop() + loop.add_signal_handler(signal.SIGQUIT, self.handle_exit, signal.SIGQUIT, None) + + async def _serve(self) -> None: + self.config.app = self.wsgi + server = Server(config=self.config) + self._install_sigquit_handler() + await server.serve(sockets=self.sockets) + if not server.started: + sys.exit(Arbiter.WORKER_BOOT_ERROR) + + def run(self) -> None: + return asyncio_run(self._serve(), loop_factory=self.config.get_loop_factory()) + + async def callback_notify(self) -> None: + self.notify() + + +class UvicornH11Worker(UvicornWorker): + CONFIG_KWARGS = {"loop": "asyncio", "http": "h11"} diff --git a/source/tests/test_archive_targets.py b/source/tests/test_archive_targets.py index 49516cb..7866839 100644 --- a/source/tests/test_archive_targets.py +++ b/source/tests/test_archive_targets.py @@ -31,7 +31,8 @@ class CandidateArchiveTests(unittest.TestCase): mock.patch.object(archive_sources, "validate_vendor", return_value=evidence), \ contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()) as stderr: archive_sources.main(args) - return self.base / "release/candidate-source" / archive_sources.ARCHIVE_NAME, stderr.getvalue() + directory = "public-source" if "--public-release" in args else "candidate-source" + return self.base / "release" / directory / archive_sources.ARCHIVE_NAME, stderr.getvalue() def test_default_archive_declares_missing_alternate_abis(self): output, warning = self.run_archive([]) @@ -64,6 +65,25 @@ class CandidateArchiveTests(unittest.TestCase): self.assertEqual(set(data["vendors"]), {"cp312", "cp313", "cp314"}) self.assertEqual(data["omitted_vendor_abis"], []) + def test_public_archive_requires_matching_cp312_and_excludes_experimental_input(self): + for args in (["--public-release"], ["--public-release", "--vendor-cp312", str(self.root), "--vendor-cp314", str(self.root)]): + with self.assertRaises(SystemExit): + self.run_archive(args) + + def test_public_archive_describes_three_profiles_without_claiming_publication(self): + vendor = self.root / "cp312"; vendor.mkdir() + (vendor / "module.py").write_text("# reviewed cp312 input\n") + output, warning = self.run_archive(["--public-release", "--vendor-cp312", str(vendor)]) + self.assertFalse(warning) + manifest = json.loads((output.parent / "SOURCE-ARCHIVE-MANIFEST.json").read_text()) + self.assertEqual(manifest["status"], "RELEASE_SOURCE_ASSEMBLED") + self.assertEqual(set(manifest["vendor_inputs"]["vendors"]), {"cp312", "cp313"}) + with tarfile.open(output) as archive: + readme = archive.extractfile(archive_sources.ARCHIVE_ROOT + "/README-SOURCE-ARCHIVE.md").read().decode() + self.assertIn("--public-release --source-manifest", readme) + self.assertNotIn("compatibility candidate source", readme) + self.assertIn("Signatures, publication", readme) + def test_alternate_vendor_symlink_is_rejected(self): vendor = self.root / "cp312"; vendor.mkdir() (vendor / "unsafe.py").symlink_to(self.input) diff --git a/source/tests/test_autostart.py b/source/tests/test_autostart.py index 16c3bf1..e01ae02 100644 --- a/source/tests/test_autostart.py +++ b/source/tests/test_autostart.py @@ -9,7 +9,7 @@ import subprocess import tempfile import unittest from unittest import mock -from framebridge_expanded import autostart, config, runtime, connection_background +from framebridge_expanded import autostart, config, runtime, connection_background, credential_helper ID = "tunnel_0123456789abcdef0123456789abcdef" MARKER = "FRAMEBRIDGE-SYNTHETIC-NOT-A-REAL-KEY-AUTOSTART" @@ -435,6 +435,161 @@ class AutostartTests(unittest.TestCase): self.assertNotIn("LoadCredentialEncrypted", unit.read_text()) self.assertFalse((directory / "credential.cred").exists()) + def test_fresh_node_with_existing_linger_authenticates_before_existing_grant_cleanup(self): + for start_now in (False, True): + with self.subTest(start_now=start_now): + state = self.home / ("node-now" if start_now else "node-boot") + config.save_config(state, config.default_config(role="node")) + before = (state / "config.json").read_bytes() + self.calls.clear() + self.system_calls.clear() + with mock.patch.object(autostart, "_linger", return_value=True), mock.patch.object(autostart, "_helper_present", return_value=True), mock.patch.object(autostart, "_node_helper_cleanup_required", return_value=True), mock.patch.object(autostart, "_credential_backend", side_effect=AssertionError("A node has no connection credential")): + autostart._enable(state, start_now=start_now, confirm=False) + _, directory, unit = autostart._paths(state) + expected_prune = ["sudo", "-n", "--", str(autostart.HELPER), "prune", autostart._profile_id(state), "-"] + # Exercise the real prune implementation through the command + # boundary: no authentication or global boot change is hidden. + self.assertEqual([["sudo", "-v"], expected_prune], [args for args, _ in self.calls]) + self.assertEqual(before, (state / "config.json").read_bytes()) + self.assertTrue(autostart._manifest(directory)["linger_before"]) + self.assertTrue(autostart._manifest(directory)["node"]) + self.assertFalse((directory / "credential.cred").exists()) + self.assertIn(("enable", "--now", unit.name) if start_now else ("enable", unit.name), self.system_calls) + self.assertEqual(0o600, stat.S_IMODE(unit.stat().st_mode)) + self.inputs.assert_not_called() + self.key_prompt.assert_not_called() + + def test_fresh_node_with_existing_linger_fails_closed_when_prune_is_not_authorized(self): + config.save_config(self.state, config.default_config(role="node")) + before = (self.state / "config.json").read_bytes() + + def denied_prune(args, **kwargs): + if len(args) > 4 and args[:4] == ["sudo", "-n", "--", str(autostart.HELPER)] and args[4] == "prune": + self.calls.append((args, kwargs)) + raise RuntimeError("Synthetic cleanup grant denied") + return self.fake_command(args, **kwargs) + + self.command.side_effect = denied_prune + with mock.patch.object(autostart, "_linger", return_value=True), mock.patch.object(autostart, "_helper_present", return_value=True), mock.patch.object(autostart, "_node_helper_cleanup_required", return_value=True): + with self.assertRaisesRegex(RuntimeError, "cleanup grant denied"): + autostart._enable(self.state, confirm=False) + _, directory, unit = autostart._paths(self.state) + self.assertEqual(before, (self.state / "config.json").read_bytes()) + self.assertFalse(unit.exists()) + self.assertFalse((directory / "installation.json").exists()) + self.assertEqual([], self.system_calls) + self.assertEqual(["sudo", "-v"], self.calls[0][0]) + self.assertFalse(any("loginctl" in args for args, _ in self.calls)) + + def test_fresh_node_with_existing_linger_and_no_managed_grants_needs_no_privilege(self): + policies = self.root / "policies" + policies.mkdir() + profile = autostart._profile_id(self.state) + # Other profiles and owners must not cause an unnecessary request. + (policies / ("framebridge-credential-" + str(os.getuid()) + "-" + "a" * 64 + "-" + "b" * 64)).touch() + (policies / ("framebridge-credential-987654321-" + profile + "-" + "b" * 64)).touch() + config.save_config(self.state, config.default_config(role="node")) + before = (self.state / "config.json").read_bytes() + with mock.patch.object(autostart, "_linger", return_value=True), mock.patch.object(autostart, "_helper_present", return_value=True), mock.patch.object(credential_helper, "SUDOERS", policies), mock.patch.object(credential_helper, "_root_path", side_effect=lambda path, **kw: path): + autostart._enable(self.state, confirm=False, start_now=False) + _, directory, unit = autostart._paths(self.state) + self.assertEqual([], self.calls) + self.assertEqual(before, (self.state / "config.json").read_bytes()) + self.assertIn(("enable", unit.name), self.system_calls) + self.assertTrue(autostart._manifest(directory)["node"]) + self.assertFalse((directory / "credential.cred").exists()) + self.key_prompt.assert_not_called() + + def test_ambiguous_node_policy_fails_before_authentication_or_managed_writes(self): + policies = self.root / "policies" + policies.mkdir() + name = "framebridge-credential-authorize-" + str(os.getuid()) + "-" + autostart._profile_id(self.state) + "-unknown" + (policies / name).touch() + config.save_config(self.state, config.default_config(role="node")) + before = (self.state / "config.json").read_bytes() + with mock.patch.object(autostart, "_linger", return_value=True), mock.patch.object(autostart, "_helper_present", return_value=True), mock.patch.object(credential_helper, "SUDOERS", policies), mock.patch.object(credential_helper, "_root_path", side_effect=lambda path, **kw: path): + with self.assertRaisesRegex(RuntimeError, "ambiguous.*administrator review"): + autostart._enable(self.state, confirm=False) + _, directory, unit = autostart._paths(self.state) + self.assertEqual([], self.calls) + self.assertEqual([], self.system_calls) + self.assertEqual(before, (self.state / "config.json").read_bytes()) + self.assertFalse(unit.exists()) + self.assertFalse((directory / "installation.json").exists()) + self.assertFalse((directory / "credential.cred").exists()) + self.assertTrue((policies / name).exists()) + + def test_fresh_node_without_linger_requires_authentication_before_managed_writes(self): + config.save_config(self.state, config.default_config(role="node")) + before = (self.state / "config.json").read_bytes() + + def denied_authentication(args, **kwargs): + if args == ["sudo", "-v"]: + self.calls.append((args, kwargs)) + raise RuntimeError("Synthetic owner authentication required") + return self.fake_command(args, **kwargs) + + self.command.side_effect = denied_authentication + with mock.patch.object(autostart, "_helper_present", return_value=True): + with self.assertRaisesRegex(RuntimeError, "owner authentication required"): + autostart._enable(self.state, confirm=False) + _, directory, unit = autostart._paths(self.state) + self.assertEqual([["sudo", "-v"]], [args for args, _ in self.calls]) + self.assertEqual(before, (self.state / "config.json").read_bytes()) + self.assertFalse(unit.exists()) + self.assertFalse((directory / "installation.json").exists()) + self.assertFalse((directory / "credential.cred").exists()) + self.assertEqual([], self.system_calls) + self.key_prompt.assert_not_called() + + def test_fresh_node_without_linger_keeps_administrative_boot_setup(self): + config.save_config(self.state, config.default_config(role="node")) + with mock.patch.object(autostart, "_helper_present", return_value=True): + autostart._enable(self.state, confirm=False) + user = autostart.pwd.getpwuid(os.getuid()).pw_name + expected_prune = ["sudo", "-n", "--", str(autostart.HELPER), "prune", autostart._profile_id(self.state), "-"] + self.assertEqual([["sudo", "-v"], expected_prune, + ["sudo", "-n", "--", "loginctl", "enable-linger", user]], + [args for args, _ in self.calls]) + self.key_prompt.assert_not_called() + + def test_central_with_existing_linger_still_authenticates_and_protects_its_key(self): + settings = config.default_config(role="central") + settings.update(tunnel_id=ID, headless="auto") + config.save_config(self.state, settings) + with mock.patch.object(autostart, "_linger", return_value=True): + autostart.enable(self.state) + self.assertIn(["sudo", "-v"], [args for args, _ in self.calls]) + encryption = [(args, options) for args, options in self.calls if "encrypt" in args and "-ll" not in args] + self.assertEqual(1, len(encryption)) + self.assertEqual(MARKER.encode(), encryption[0][1]["data"]) + self.assertNotIn(MARKER, " ".join(encryption[0][0])) + self.key_prompt.assert_called_once_with("Connection key (hidden): ") + _, directory, _ = autostart._paths(self.state) + self.assertTrue((directory / "credential.cred").exists()) + + def test_central_existing_linger_does_not_bypass_failed_owner_authentication(self): + settings = config.default_config(role="central") + settings.update(tunnel_id=ID, headless="auto") + config.save_config(self.state, settings) + before = (self.state / "config.json").read_bytes() + + def denied_authentication(args, **kwargs): + if args == ["sudo", "-v"]: + raise RuntimeError("Synthetic owner authentication required") + return self.fake_command(args, **kwargs) + + self.command.side_effect = denied_authentication + with mock.patch.object(autostart, "_linger", return_value=True): + with self.assertRaisesRegex(RuntimeError, "owner authentication required"): + autostart.enable(self.state) + _, directory, unit = autostart._paths(self.state) + self.assertEqual(before, (self.state / "config.json").read_bytes()) + self.assertFalse(unit.exists()) + self.assertFalse((directory / "installation.json").exists()) + self.assertFalse((directory / "credential.cred").exists()) + self.key_prompt.assert_not_called() + def test_private_file_reader_rejects_symlink_hardlink_fifo_and_public_file(self): original = self.root / "original" original.write_bytes(b"safe") @@ -466,6 +621,89 @@ class AutostartTests(unittest.TestCase): finally: os.close(fd) + def _service_directory_owners(self, owners): + actual_lstat = Path.lstat + + def owner_lstat(path, *args, **kwargs): + values = list(actual_lstat(path, *args, **kwargs)) + values[4] = owners.get(path, values[4]) + return os.stat_result(values) + + return mock.patch.object(Path, "lstat", owner_lstat) + + def test_root_owned_service_ancestors_allow_owned_final_directory_without_changes(self): + final = self.home / ".config/systemd/user" + final.mkdir(parents=True, mode=0o700) + directories = [self.home / ".config", final.parent, final] + before = {p: (p.stat().st_uid, p.stat().st_mode) for p in directories} + owners = {directories[0]: 0, directories[1]: 0, final: 1000} + with mock.patch.object(autostart.os, "getuid", return_value=1000), self._service_directory_owners(owners): + autostart._check_unit_directory(final / "test.service") + self.assertEqual(before, {p: (p.stat().st_uid, p.stat().st_mode) for p in directories}) + self.assertEqual([], list(final.iterdir())) + + def test_root_or_other_account_cannot_own_final_service_directory(self): + final = self.home / ".config/systemd/user" + final.mkdir(parents=True, mode=0o700) + for owner in (0, 2000): + with self.subTest(owner=owner), mock.patch.object(autostart.os, "getuid", return_value=1000), self._service_directory_owners({self.home / ".config": 0, final.parent: 0, final: owner}): + with self.assertRaisesRegex(RuntimeError, "final directory must belong"): + autostart._check_unit_directory(final / "test.service") + self.assertEqual([], list(final.iterdir())) + + def test_other_account_cannot_own_service_ancestors(self): + final = self.home / ".config/systemd/user" + final.mkdir(parents=True, mode=0o700) + for ancestor in (self.home / ".config", final.parent): + owners = {self.home / ".config": 0, final.parent: 0, final: 1000, ancestor: 2000} + with self.subTest(ancestor=ancestor.name), mock.patch.object(autostart.os, "getuid", return_value=1000), self._service_directory_owners(owners): + with self.assertRaisesRegex(RuntimeError, "safe owner"): + autostart._check_unit_directory(final / "test.service") + + def test_root_owned_service_ancestors_still_reject_writable_or_symbolic_directories(self): + final = self.home / ".config/systemd/user" + final.mkdir(parents=True, mode=0o700) + directories = [self.home / ".config", final.parent, final] + owners = {directories[0]: 0, directories[1]: 0, final: 1000} + for directory in directories: + original = directory.stat().st_mode + for mode in (0o775, 0o777): + with self.subTest(directory=directory.name, mode=mode): + directory.chmod(mode) + with mock.patch.object(autostart.os, "getuid", return_value=1000), self._service_directory_owners(owners): + with self.assertRaisesRegex(RuntimeError, "not be writable"): + autostart._check_unit_directory(final / "test.service") + self.assertEqual(mode, stat.S_IMODE(directory.stat().st_mode)) + directory.chmod(stat.S_IMODE(original)) + moved = directory.with_name(directory.name + "-target") + directory.rename(moved) + directory.symlink_to(moved, target_is_directory=True) + try: + with self.subTest(directory=directory.name, symbolic=True): + with self.assertRaisesRegex(RuntimeError, "symbolic links"): + autostart._check_unit_directory(final / "test.service") + finally: + directory.unlink() + moved.rename(directory) + + def test_root_owned_parent_creation_failure_preserves_permissions_and_explains_failure(self): + parent = self.home / ".config/systemd" + parent.mkdir(parents=True, mode=0o755) + final = parent / "user" + before = {p: (p.stat().st_uid, p.stat().st_mode) for p in (parent.parent, parent)} + actual_mkdir = Path.mkdir + + def denied_final(path, *args, **kwargs): + if path == final: + raise PermissionError("Synthetic administrator-owned parent") + return actual_mkdir(path, *args, **kwargs) + + with mock.patch.object(autostart.os, "getuid", return_value=1000), self._service_directory_owners({parent.parent: 0, parent: 0}), mock.patch.object(Path, "mkdir", denied_final): + with self.assertRaisesRegex(RuntimeError, "cannot create.*left unchanged"): + autostart._check_unit_directory(final / "test.service") + self.assertFalse(final.exists()) + self.assertEqual(before, {p: (p.stat().st_uid, p.stat().st_mode) for p in before}) + def test_unit_quotes_specifiers_and_dollars_without_shell_or_missing_package_loop(self): text = autostart.unit_text(Path('/tmp/a % b ${HOME} "quoted"'), Path('/tmp/key % file')) self.assertIn("%%", text) diff --git a/source/tests/test_build_privacy_paths.py b/source/tests/test_build_privacy_paths.py new file mode 100644 index 0000000..b95b8a3 --- /dev/null +++ b/source/tests/test_build_privacy_paths.py @@ -0,0 +1,33 @@ +"""The public vendor name root_model.py is not the build user's home directory.""" +import importlib.util +from pathlib import Path +import sys +import unittest + + +PACKAGING = Path(__file__).resolve().parents[1] / "packaging" +sys.path.insert(0, str(PACKAGING)) +spec = importlib.util.spec_from_file_location("privacy_test_builder", PACKAGING / "build_expanded.py") +builder = importlib.util.module_from_spec(spec) +spec.loader.exec_module(builder) + + +class BuildPrivacyPathTests(unittest.TestCase): + def test_public_module_name_does_not_block_a_root_user_build(self): + data = b'{"path":"source/vendor/pydantic/root_model.py"}' + self.assertFalse(builder.contains_private_path(data, "/root")) + + def test_actual_home_paths_are_still_rejected(self): + for data in (b'"/root/private-file"', b'"/root"', b'input: /root\n', + b'file:///root/private-file', b'"/root/"'): + with self.subTest(data=data): + self.assertTrue(builder.contains_private_path(data, "/root")) + + def test_neighboring_names_are_not_this_home_directory(self): + for data in (b'"/home/tester-other/file"', b'"/home/tester_backup/file"'): + self.assertFalse(builder.contains_private_path(data, "/home/tester")) + self.assertTrue(builder.contains_private_path(b'"/home/tester/file"', "/home/tester")) + + +if __name__ == "__main__": + unittest.main() diff --git a/source/tests/test_cli_health.py b/source/tests/test_cli_health.py new file mode 100644 index 0000000..65c01b1 --- /dev/null +++ b/source/tests/test_cli_health.py @@ -0,0 +1,70 @@ +"""Exercise the public health command without starting a profile or transport.""" +import contextlib +import io +import json +from pathlib import Path +import tempfile +from types import SimpleNamespace +import unittest +from unittest import mock + +from framebridge_expanded import cli, health, __version__ + + +class HealthCliTests(unittest.TestCase): + def invoke(self, arguments): + output, errors = io.StringIO(), io.StringIO() + with contextlib.redirect_stdout(output), contextlib.redirect_stderr(errors): + code = cli.main(arguments) + return code, output.getvalue(), errors.getvalue() + + def test_absent_profile_is_reported_without_creating_it(self): + with tempfile.TemporaryDirectory() as temporary: + profile = Path(temporary) / "absent-profile" + code, text, _ = self.invoke(["--state-dir", str(profile), "--json", "health"]) + self.assertFalse(profile.exists()) + value = json.loads(text) + self.assertEqual(code, 1) + self.assertEqual(value["version"], __version__) + self.assertEqual(value["command"], "health") + self.assertTrue(value["ok"]) + self.assertEqual(value["result"]["health"]["state"], "unconfigured") + self.assertFalse(value["result"]["health"]["healthy"]) + self.assertTrue(value["result"]["read_only"]) + + def test_query_success_does_not_make_exit_status_healthy(self): + for state, healthy, expected in (("healthy", True, 0), ("paused", True, 0), + ("degraded", False, 1), ("unavailable", None, 1)): + with self.subTest(state=state): + report = {"ok": True, "health": {"state": state, "healthy": healthy}} + module = SimpleNamespace(collect=mock.Mock(return_value=report)) + with mock.patch.object(cli, "_module", return_value=module): + code, text, _ = self.invoke(["health", "--json"]) + self.assertEqual(code, expected) + self.assertEqual(json.loads(text)["result"], report) + + def test_failed_observation_cannot_pass_even_with_a_healthy_flag(self): + module = SimpleNamespace(collect=mock.Mock(return_value={"ok": False, "health": {"healthy": True}})) + with mock.patch.object(cli, "_module", return_value=module): + code, text, _ = self.invoke(["--json", "health"]) + self.assertEqual(code, 1) + self.assertFalse(json.loads(text)["ok"]) + + def test_human_summary_names_the_local_machine_and_its_limits(self): + with tempfile.TemporaryDirectory() as temporary: + code, text, _ = self.invoke(["health", "--state-dir", str(Path(temporary) / "absent")]) + self.assertEqual(code, 1) + self.assertIn("Target: LOCAL = this computer", text) + self.assertIn("unconfigured", text) + self.assertIn("not a fleet scan", text) + + def test_json_output_never_prompts_for_authentication(self): + with tempfile.TemporaryDirectory() as temporary, mock.patch("builtins.input") as ask: + code, text, _ = self.invoke(["health", "--json", "--state-dir", str(Path(temporary) / "absent")]) + ask.assert_not_called() + self.assertEqual(code, 1) + self.assertIsNone(json.loads(text)["result"]["software"]["runtime_version"]) + + +if __name__ == "__main__": + unittest.main() diff --git a/source/tests/test_connection_background.py b/source/tests/test_connection_background.py index 95b42f0..617ee6e 100644 --- a/source/tests/test_connection_background.py +++ b/source/tests/test_connection_background.py @@ -141,6 +141,11 @@ class BackgroundTests(unittest.TestCase): record=json.loads(path.read_text());record['verified_at']=time.time()-30 record['message']='\x1b[31m'+FAKE background._write(path,record) + if record.get('heartbeat_backend') == background._HEARTBEAT_BACKEND: + heartbeat_path=background._heartbeat_directory(self.state)/'status.json' + heartbeat=background._read(heartbeat_path) + heartbeat['verified_at']=time.time()-30 + background._write(heartbeat_path,heartbeat) current=background.status(self.state) self.assertFalse(current['verified']) self.assertEqual(current['state'],'retrying') diff --git a/source/tests/test_fleet_routing.py b/source/tests/test_fleet_routing.py index 2d5effc..224751b 100644 --- a/source/tests/test_fleet_routing.py +++ b/source/tests/test_fleet_routing.py @@ -1,4 +1,5 @@ """Routing contract tests; original read provider is exercised locally.""" +import base64 import hashlib from pathlib import Path import socket @@ -10,6 +11,8 @@ from unittest import mock ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(ROOT / "expanded")) from framebridge_expanded import fleet +from framebridge_expanded.real_screen.screen_frontdoor import RPC_COMMAND +from framebridge_expanded.real_screen.screen_rpc import encode LOCAL_ID = "c6d827a4-219f-48fc-82d8-f410176313ca" REMOTE_ID = "6d88c5ae-343e-4413-a202-ccae2ae7694a" @@ -134,6 +137,99 @@ class FleetRoutingTests(unittest.TestCase): self.assertEqual(fleet.execute_node("test-node", "printf ok", True)["error"], "NODE_OFFLINE") self.assertEqual(fleet.node_read("test-node", "system.status", {})["error"], "NODE_OFFLINE") + @staticmethod + def screen_script(): + return RPC_COMMAND + base64.b64encode(encode({"op": "observe"})).decode("ascii") + "\n" + + def assert_identity(self, value, requested, local=False): + self.assertEqual(value["requested_target"], requested) + self.assertEqual(value["resolved_target"], "test-central" if local else "test-node") + self.assertEqual(value["node"], value["resolved_target"]) + self.assertEqual(value["target"], "LOCAL" if local else "test-node") + self.assertEqual(value["node_id"], LOCAL_ID if local else REMOTE_ID) + self.assertEqual(value["hostname"], socket.gethostname() if local else "test-node") + self.assertEqual(value["transport"], "local" if local else "broker_outbound") + + @staticmethod + def misleading_response(payload=None): + value = {"ok": True, "target": "wrong-machine", "node": "wrong-machine", + "requested_target": "wrong-machine", "resolved_target": "wrong-machine", + "node_id": "wrong-id", "hostname": "wrong-host", "transport": "wrong-route"} + if payload is not None: + value.update(job_id=payload["job_id"], command_sha256=payload.get("sha256")) + return value + + def test_read_identity_comes_from_confirmed_route(self): + for requested, local in [("LOCAL", True), ("test-central", True), (LOCAL_ID, True), + ("test-node", False), (REMOTE_ID, False)]: + with self.subTest(requested=requested), \ + mock.patch.object(fleet, "read_local", return_value=self.misleading_response()), \ + mock.patch("framebridge_expanded.broker.request", return_value=self.misleading_response()): + value = fleet.node_read(requested, "system.status", {}) + self.assertTrue(value["ok"]) + self.assert_identity(value, requested, local) + self.assertEqual(value["node"], value["resolved_target"]) + + def test_execution_routes_overwrite_upstream_identity(self): + def remote_response(node_id, capability, payload, timeout_s): + return self.misleading_response(payload) + calls = [ + lambda alias: fleet.execute_node(alias, "printf ok", True, job_id="identity-exec"), + lambda alias: fleet.execute_screen_node(alias, self.screen_script(), True, + job_id="identity-screen", include_stdout=True), + lambda alias: fleet.cua_node(alias, {"action": "OBSERVE"}, True, job_id="identity-cua"), + ] + for route in calls: + for requested, local in [("LOCAL", True), ("test-central", True), (LOCAL_ID, True), + ("test-node", False), (REMOTE_ID, False)]: + with self.subTest(route=route, requested=requested), \ + mock.patch("framebridge_expanded.runtime.adapter_request", + side_effect=self.misleading_response), \ + mock.patch("framebridge_expanded.broker.request", side_effect=remote_response): + value = route(requested) + self.assertTrue(value["ok"], value) + self.assert_identity(value, requested, local) + + def test_unknown_target_never_falls_back_to_local(self): + with mock.patch("framebridge_expanded.runtime.adapter_request") as local, \ + mock.patch("framebridge_expanded.broker.request") as remote: + values = [ + fleet.node_read("unknown-node", "system.status", {}), + fleet.execute_node("unknown-node", "printf ok", True), + fleet.execute_screen_node("unknown-node", self.screen_script(), True, include_stdout=True), + fleet.cua_node("unknown-node", {"action": "OBSERVE"}, True), + ] + local.assert_not_called() + remote.assert_not_called() + for value in values: + self.assertFalse(value["ok"]) + self.assertEqual(value["error"], "NODE_NOT_FOUND") + self.assertNotIn("resolved_target", value) + self.assertNotIn("node_id", value) + + def test_offline_target_errors_retain_confirmed_identity(self): + self.remote["operational_transport_ready"] = False + with mock.patch("framebridge_expanded.broker.request") as remote: + values = [ + fleet.node_read(REMOTE_ID, "system.status", {}), + fleet.execute_node(REMOTE_ID, "printf ok", True), + fleet.execute_screen_node(REMOTE_ID, self.screen_script(), True, include_stdout=True), + fleet.cua_node(REMOTE_ID, {"action": "OBSERVE"}, True), + ] + remote.assert_not_called() + for value in values: + self.assertFalse(value["ok"]) + self.assertEqual(value["error"], "NODE_OFFLINE") + self.assert_identity(value, REMOTE_ID) + + def test_pre_resolution_failure_does_not_claim_identity(self): + with mock.patch.object(fleet, "resolve_node") as lookup: + value = fleet.execute_node("test-node", "printf ok", False) + lookup.assert_not_called() + self.assertEqual(value["error"], "AUTHORIZED_TRUE_REQUIRED") + for field in ("requested_target", "resolved_target", "node_id", "hostname", "transport"): + self.assertNotIn(field, value) + if __name__ == "__main__": unittest.main() diff --git a/source/tests/test_health.py b/source/tests/test_health.py new file mode 100644 index 0000000..4e87f85 --- /dev/null +++ b/source/tests/test_health.py @@ -0,0 +1,196 @@ +import copy +import json +from pathlib import Path +import sys +import tempfile +import unittest +from unittest import mock + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "expanded")) +from framebridge_expanded import health + + +NODE_ID = "51f0acf5-3633-41f6-aea7-4fed5cffcb01" + + +def snapshots(): + return ({"ok": True, "configured": True, "role": "central", "name": "gateway", + "runtime": {"running": True, "ready": True, "node_id": NODE_ID, + "display_context": {"kind": "text"}, + "capabilities": {"fbexec": True, "fbterm": True, "cua_tty_module": True, "graphical_cua": False}}, + "connection": {"verified": True, "state": "ready"}, + "boot": {"configured": True, "enabled": False, "service_state": "active"}, + "desired_connection": "connected"}, + {"ok": True, "platform_compatibility": {"ok": True, "profile_id": "debian13-amd64-py313", "validation_status": "validated", "issues": []}, + "issues": [], "missing_commands": [], "capabilities": {"fbexec": True, "fbterm": True, "cua_tty_module": True, "graphical_cua": False}}) + + +class HealthTests(unittest.TestCase): + def test_release_build_identity_is_retained_without_relabelling_it_validated(self): + status, doctor = snapshots() + doctor["platform_compatibility"]["validation_status"] = "release_build" + value = health.build_report(status, doctor) + self.assertTrue(value["ok"]) + self.assertEqual(value["prerequisites"]["validation_status"], "release_build") + self.assertNotEqual(value["prerequisites"]["validation_status"], "validated") + + def test_healthy_text_mode_does_not_require_graphical_tools_or_boot_enabled(self): + status, doctor = snapshots() + value = health.build_report(status, doctor, observed_at="2026-10-28T12:00:00+00:00", host="gateway") + self.assertTrue(value["ok"]) + self.assertEqual(value["health"], {"state": "healthy", "healthy": True, "issues": []}) + self.assertEqual(value["boot"]["policy"], "disabled") + self.assertEqual(value["effective_target"]["node_id"], NODE_ID) + self.assertFalse(value["desktop"]["capture_verified_by_this_report"]) + self.assertIsNone(value["software"]["runtime_version"]) + + def test_query_success_is_not_readiness(self): + status, doctor = snapshots() + status["runtime"].update(running=False, ready=False) + status["connection"].update(verified=False, state="stopped") + value = health.build_report(status, doctor) + self.assertTrue(value["ok"]) + self.assertEqual(value["health"]["state"], "degraded") + self.assertFalse(value["health"]["healthy"]) + self.assertIn("LOCAL_TOOLS_NOT_READY", value["health"]["issues"]) + + def test_paused_connection_is_distinct_from_failure(self): + status, doctor = snapshots() + status["desired_connection"] = "disconnected" + status["connection"].update(verified=False, state="stopped") + value = health.build_report(status, doctor) + self.assertEqual(value["health"]["state"], "paused") + self.assertTrue(value["health"]["healthy"]) + self.assertEqual(value["health"]["issues"], []) + + def test_node_does_not_claim_central_connection_verified(self): + status, doctor = snapshots() + status.update(role="node", desired_connection="not_applicable") + value = health.build_report(status, doctor) + self.assertEqual(value["connection"]["state"], "managed_by_central") + self.assertIsNone(value["connection"]["verified"]) + self.assertEqual(value["health"]["state"], "healthy") + + def test_requested_pause_does_not_hide_a_still_running_tunnel(self): + status, doctor = snapshots() + status["desired_connection"] = "disconnected" + value = health.build_report(status, doctor) + self.assertEqual(value["health"]["state"], "degraded") + self.assertIn("CONNECTION_INTENT_MISMATCH", value["health"]["issues"]) + status["connection"].update(verified=False, state="stopped", alive=True) + value = health.build_report(status, doctor) + self.assertFalse(value["health"]["healthy"]) + + def test_failed_connection_query_cannot_certify_a_healthy_profile(self): + status, doctor = snapshots() + status["connection"]["ok"] = False + value = health.build_report(status, doctor) + self.assertFalse(value["ok"]) + self.assertIsNone(value["health"]["healthy"]) + self.assertIn("CONNECTION_STATUS_UNAVAILABLE", value["health"]["issues"]) + + def test_missing_boot_policy_is_unknown_rather_than_healthy(self): + status, doctor = snapshots() + status["boot"] = {} + value = health.build_report(status, doctor) + self.assertFalse(value["ok"]) + self.assertEqual(value["health"]["state"], "unavailable") + + def test_missing_runtime_status_is_not_a_stopped_runtime(self): + status, doctor = snapshots() + status["runtime"] = {"status_unavailable": True, "running": False, "ready": False} + value = health.build_report(status, doctor) + self.assertFalse(value["ok"]) + self.assertEqual(value["runtime"]["state"], "unavailable") + self.assertEqual(value["health"]["state"], "unavailable") + self.assertIsNone(value["health"]["healthy"]) + + def test_failed_runtime_query_cannot_certify_ready(self): + status, doctor = snapshots() + status["runtime"]["ok"] = False + value = health.build_report(status, doctor) + self.assertFalse(value["ok"]) + self.assertEqual(value["health"]["state"], "unavailable") + + def test_failed_profile_query_cannot_claim_unconfigured(self): + value = health.build_report({"ok": False, "configured": False}, None) + self.assertFalse(value["ok"]) + self.assertEqual(value["health"]["state"], "unavailable") + + def test_missing_diagnostic_result_is_unavailable_not_passed(self): + status, _ = snapshots() + value = health.build_report(status, {}) + self.assertFalse(value["ok"]) + self.assertEqual(value["health"]["state"], "unavailable") + + def test_unconfigured_profile_is_observed_without_running_doctor_or_creating_files(self): + with tempfile.TemporaryDirectory() as directory: + state = Path(directory) / "not-created" + with mock.patch.object(health.runtime, "doctor", side_effect=AssertionError("doctor must not run")): + value = health.collect(state) + self.assertFalse(state.exists()) + self.assertTrue(value["ok"]) + self.assertEqual(value["health"]["state"], "unconfigured") + self.assertEqual(value["health"]["issues"], []) + self.assertEqual(value["prerequisites"]["state"], "not_run") + + def test_diagnostics_failure_retains_status_without_leaking_exception(self): + status, _ = snapshots() + with mock.patch.object(health.lifecycle, "status", return_value=status), \ + mock.patch.object(health.runtime, "doctor", side_effect=RuntimeError("secret-access-key")): + value = health.collect(Path("/unused")) + self.assertFalse(value["ok"]) + self.assertEqual(value["runtime"]["state"], "ready") + self.assertEqual(value["health"]["state"], "unavailable") + self.assertNotIn("secret-access-key", json.dumps(value)) + + def test_partial_invalid_profile_does_not_guess_it_is_unconfigured(self): + with mock.patch.object(health.lifecycle, "status", side_effect=ValueError("private-input")), \ + mock.patch.object(health.runtime, "doctor") as doctor: + value = health.collect(Path("/unused")) + doctor.assert_not_called() + self.assertFalse(value["ok"]) + self.assertEqual(value["health"]["state"], "unavailable") + self.assertNotIn("private-input", json.dumps(value)) + + def test_allowlist_excludes_connection_material_paths_and_untrusted_free_text(self): + status, doctor = snapshots() + status["tunnel_id"] = "secret-tunnel" + status["runtime"].update(state_dir="/private/secret-path", error="secret-error", access_key="secret-key") + status["runtime"]["display_context"]["authority"] = "/private/secret-authority" + status["connection"].update(message="secret-message", log="/private/secret-log", token="secret-token") + doctor.update(network={"token": "secret-network"}, issues=["secret-issue"]) + doctor["platform_compatibility"]["issues"] = ["secret-compatibility"] + result = health.build_report(status, doctor, host="host") + self.assertNotIn("secret-", json.dumps(result)) + self.assertEqual(result["prerequisites"]["issue_count"], 1) + self.assertEqual(result["prerequisites"]["compatibility_issue_count"], 1) + + def test_prerequisite_failure_is_degraded_without_claiming_no_runtime(self): + status, doctor = snapshots() + doctor.update(ok=False, missing_commands=["tmux"]) + value = health.build_report(status, doctor) + self.assertTrue(value["ok"]) + self.assertEqual(value["health"]["state"], "degraded") + self.assertEqual(value["runtime"]["state"], "ready") + self.assertEqual(value["prerequisites"]["missing_commands"], ["tmux"]) + + def test_reports_do_not_modify_snapshots(self): + status, doctor = snapshots() + before = copy.deepcopy((status, doctor)) + health.build_report(status, doctor) + self.assertEqual((status, doctor), before) + + def test_terminal_output_is_explicit_about_target_and_observation_limit(self): + status, doctor = snapshots() + value = health.build_report(status, doctor, host="gateway") + text = health.render(value) + self.assertIn("Target: LOCAL = this computer (gateway)", text) + self.assertIn(NODE_ID, text) + self.assertIn("capture/input not tested", text) + self.assertIn("not proof of the running version", text) + self.assertIn("not a fleet scan", text) + + +if __name__ == "__main__": + unittest.main() diff --git a/source/tests/test_idle_state_io.py b/source/tests/test_idle_state_io.py new file mode 100644 index 0000000..363f80a --- /dev/null +++ b/source/tests/test_idle_state_io.py @@ -0,0 +1,152 @@ +"""Liveness stays fresh without periodically syncing the durable profile.""" +import json +import os +from pathlib import Path +import tempfile +import unittest +from unittest import mock + +from framebridge_expanded import autostart, connection_background as background + + +class IdleStateIOTests(unittest.TestCase): + def setUp(self): + temporary = tempfile.TemporaryDirectory() + self.addCleanup(temporary.cleanup) + self.root = Path(temporary.name) + self.state = self.root / "profile" + self.directory = background._directory(self.state) + self.runtime_parent = self.root / "runtime" + self.runtime_parent.mkdir(mode=0o700) + (self.runtime_parent / str(os.getuid())).mkdir(mode=0o700) + self.addCleanup(mock.patch.stopall) + mock.patch.object(background, "_RUNTIME_PARENT", self.runtime_parent).start() + self.identity = dict(pid=12345, uid=os.getuid(), start_ticks=99, + boot_id="boot-one", session_id=12345, + process_group=12345, state_dir=str(self.state), lock_fd=8) + + def sink(self): + runtime = background._heartbeat_directory(self.state, create=True) + return background._StatusOutput(self.directory / "status.json", self.identity, + runtime / "status.json") + + def status(self): + with mock.patch.object(background, "_valid_identity", return_value=True): + return background.status(self.state) + + def test_ready_heartbeat_fresh_beyond_timeout_without_durable_writes(self): + clock = [100.0] + with mock.patch.object(background.time, "time", side_effect=lambda: clock[0]), mock.patch.object(background.time, "monotonic", side_effect=lambda: clock[0]): + sink = self.sink() + sink.observe("ready") + sink.change("ready", "[OK] Connected.") + durable = sink.path.stat() + original = sink.path.read_bytes() + for instant in range(101, 141): + clock[0] = float(instant) + sink.observe("ready") + self.assertTrue(self.status()["verified"]) + self.assertEqual(sink.path.read_bytes(), original) + self.assertEqual(sink.path.stat().st_ino, durable.st_ino) + self.assertEqual(sink.path.stat().st_mtime_ns, durable.st_mtime_ns) + clock[0] = 156.0 + self.assertFalse(self.status()["verified"]) + self.assertEqual(self.status()["state"], "retrying") + sink.observe("ready") + self.assertTrue(self.status()["verified"]) + + def test_failure_and_recovery_publish_transitions_immediately(self): + sink = self.sink() + sink.observe("ready") + sink.change("ready", "[OK] Connected.") + self.assertTrue(self.status()["verified"]) + sink.observe("access") + self.assertFalse(self.status()["verified"]) + sink.change("retrying", "[RETRYING] Lost readiness.") + self.assertEqual(json.loads(sink.path.read_text())["state"], "retrying") + sink.observe("ready") + sink.change("ready", "[OK] Connected.") + self.assertTrue(self.status()["verified"]) + + def test_missing_or_old_worker_heartbeat_never_uses_durable_timestamp(self): + sink = self.sink() + sink.observe("ready") + sink.change("ready", "[OK] Connected.") + heartbeat = background._read(sink.heartbeat_path) + for field, value in (("pid", 99999), ("boot_id", "older-boot"), ("start_ticks", 44), ("state_dir", "/another-profile")): + wrong = dict(heartbeat, **{field: value}) + background._write(sink.heartbeat_path, wrong) + self.assertFalse(self.status()["verified"], field) + sink.heartbeat_path.unlink() + self.assertFalse(self.status()["verified"]) + + def test_no_runtime_falls_back_to_bounded_fresh_durable_heartbeat(self): + (self.runtime_parent / str(os.getuid())).rmdir() + self.assertIsNone(background._heartbeat_directory(self.state, create=True)) + clock = [100.0] + with mock.patch.object(background.time, "time", side_effect=lambda: clock[0]), mock.patch.object(background.time, "monotonic", side_effect=lambda: clock[0]), mock.patch.object(background, "_write", wraps=background._write) as write: + sink = background._StatusOutput(self.directory / "status.json", self.identity) + sink.observe("ready") + sink.change("ready", "[OK] Connected.") + write.reset_mock() + for instant in range(101, 121): + clock[0] = float(instant) + sink.observe("ready") + self.assertTrue(self.status()["verified"]) + self.assertEqual(write.call_count, 4) + sink.observe("access") + self.assertFalse(self.status()["verified"]) + + def test_legacy_durable_heartbeat_remains_readable_with_runtime_available(self): + background._write(self.directory / "status.json", dict(self.identity, state="ready", verified_at=100.0)) + with mock.patch.object(background.time, "time", return_value=110.0): + self.assertTrue(self.status()["verified"]) + with mock.patch.object(background.time, "time", return_value=116.0): + self.assertFalse(self.status()["verified"]) + + def test_runtime_permissions_and_symlinks_rejected_without_changes(self): + root = self.runtime_parent / str(os.getuid()) + root.chmod(0o755) + with self.assertRaises(RuntimeError): + background._heartbeat_directory(self.state, create=True) + self.assertEqual(root.stat().st_mode & 0o777, 0o755) + root.chmod(0o700) + directory = background._heartbeat_directory(self.state, create=True) + directory.rmdir() + directory.symlink_to(self.directory, target_is_directory=True) + with self.assertRaises(ValueError): + background._heartbeat_directory(self.state, create=True) + with self.assertRaises(RuntimeError): + background._heartbeat_directory(self.state) + + def test_runtime_parent_symlink_rejected(self): + alias = self.root / "runtime-alias" + alias.symlink_to(self.runtime_parent, target_is_directory=True) + with mock.patch.object(background, "_RUNTIME_PARENT", alias), self.assertRaises(RuntimeError): + background._heartbeat_directory(self.state, create=True) + + def test_heartbeat_file_symlink_and_hardlink_rejected(self): + sink = self.sink() + sink.heartbeat_path.symlink_to(sink.path) + with self.assertRaises(OSError): + sink.observe("ready") + sink.heartbeat_path.unlink() + os.link(sink.path, sink.heartbeat_path) + with self.assertRaises(RuntimeError): + sink.observe("ready") + + def test_worker_state_only_writes_on_transition(self): + with mock.patch.object(autostart, "_json", wraps=autostart._json) as write: + autostart._worker_status(self.directory, "connected") + first = (self.directory / "worker-status.json").read_bytes() + for _ in range(20): + autostart._worker_status(self.directory, "connected") + self.assertEqual(write.call_count, 1) + self.assertEqual((self.directory / "worker-status.json").read_bytes(), first) + autostart._worker_status(self.directory, "reconnecting") + self.assertEqual(write.call_count, 2) + self.assertEqual(json.loads((self.directory / "worker-status.json").read_text())["state"], "reconnecting") + + +if __name__ == "__main__": + unittest.main() diff --git a/source/tests/test_linux_compatibility.py b/source/tests/test_linux_compatibility.py index c129807..df50b6f 100644 --- a/source/tests/test_linux_compatibility.py +++ b/source/tests/test_linux_compatibility.py @@ -1,10 +1,13 @@ """Candidate profile/ABI selection; tests use inert native-file fixtures.""" import hashlib +import contextlib +import io import json import os from pathlib import Path import tempfile import stat +import sys from types import SimpleNamespace import unittest from unittest.mock import patch @@ -64,6 +67,43 @@ class LinuxCompatibilityTests(unittest.TestCase): self.assertFalse(self.check(distro, version, (3, 12))["ok"]) self.assertIsNone(compat.profile_for({"ID": "other", "ID_LIKE": "ubuntu", "VERSION_ID": "24.04"})) + def test_public_builder_profiles_are_accepted_by_the_runtime_without_claiming_validation(self): + # Use the real public builder's profile output, rather than duplicating + # its validation_status value in a fixture. Archive/vendor verification + # has separate tests; --check-vendor does not stage/install a package. + sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "packaging")) + import archive_sources + import build_expanded + targets = [("debian13-amd64-py313", "debian", "13", (3, 13)), + ("ubuntu24.04-amd64-py312", "ubuntu", "24.04", (3, 12)), + ("mint22-amd64-py312", "linuxmint", "22.3", (3, 12))] + for profile_id, distro, version, python in targets: + with self.subTest(profile=profile_id): + self.artifact(profile_id) + output = io.StringIO() + globals_before = {name: getattr(build_expanded, name) for name in + ("VERSION", "PUBLIC_RELEASE", "SOURCE_ARCHIVE", "PUBLIC_FILENAME", "RELEASE", "STAGE", "PREFIX")} + args = ["--target", profile_id, "--public-release", "--source-manifest", str(self.prefix / "source.json"), "--check-vendor"] + if profile_id != "debian13-amd64-py313": + args += ["--vendor-dir", str(self.prefix / "reviewed-cp312")] + with patch.multiple(build_expanded, **globals_before), \ + patch.object(build_expanded.subprocess, "run"), \ + patch.object(build_expanded, "vendor_versions", return_value={}), \ + patch.object(build_expanded, "validate_vendor", return_value={"vendor_sha256": "a" * 64}), \ + patch.object(build_expanded, "release_source", return_value={"filename": "FrameBridge-0.3.4-source.tar.gz", "sha256": "b" * 64}), \ + patch.object(build_expanded, "legal_preflight"), \ + patch.object(archive_sources, "source_files", return_value={}), \ + contextlib.redirect_stdout(output): + build_expanded.main(args) + manifest = json.loads(output.getvalue()) + self.assertEqual(manifest["validation_status"], "release_build") + (self.prefix / "release-profile.json").write_text(json.dumps(manifest)) + result = self.check(distro, version, python) + self.assertTrue(result["ok"], result) + self.assertEqual(result["validation_status"], manifest["validation_status"]) + self.assertIn("Release assembly does not establish a tested installation", result["warnings"][0]) + self.assertNotEqual(result["validation_status"], "validated") + def test_interpreter_artifact_and_cpu_must_all_match(self): self.artifact("ubuntu24.04-amd64-py312") self.assertFalse(self.check("ubuntu", "24.04", (3, 13))["ok"]) diff --git a/source/tests/test_node_helper_cleanup.py b/source/tests/test_node_helper_cleanup.py new file mode 100644 index 0000000..683bd90 --- /dev/null +++ b/source/tests/test_node_helper_cleanup.py @@ -0,0 +1,79 @@ +"""Policy-name inspection only: no sudo, registry reads or rule contents.""" +import os +from pathlib import Path +import stat +import tempfile +import unittest +from unittest import mock + +from framebridge_expanded import autostart, credential_helper + + +class NodeHelperCleanupInspectionTests(unittest.TestCase): + def setUp(self): + self.temp = tempfile.TemporaryDirectory() + self.addCleanup(self.temp.cleanup) + self.root = Path(self.temp.name) + self.state = self.root / "profile" + self.policies = self.root / "policies" + self.policies.mkdir() + self.profile = autostart._profile_id(self.state) + self.uid = str(os.getuid()) + self.addCleanup(mock.patch.stopall) + mock.patch.object(autostart, "_helper_ready").start() + mock.patch.object(credential_helper, "SUDOERS", self.policies).start() + self.trust = mock.patch.object(credential_helper, "_root_path", side_effect=lambda path, **kw: path) + self.trust.start() + + def test_own_canonical_decrypt_and_authorization_names_require_root_cleanup(self): + names = [ + "framebridge-credential-" + self.uid + "-" + self.profile + "-" + "a" * 64, + "framebridge-credential-authorize-" + self.uid + "-" + self.profile + "-host", + "framebridge-credential-authorize-" + self.uid + "-" + self.profile + "-user", + ] + for name in names: + with self.subTest(name=name): + path = self.policies / name + path.touch() + with mock.patch.object(Path, "read_bytes", side_effect=AssertionError("Do not read rule contents")): + self.assertTrue(autostart._node_helper_cleanup_required(self.state)) + path.unlink() + + def test_ambiguous_names_require_review_even_alongside_a_canonical_grant(self): + canonical = "framebridge-credential-" + self.uid + "-" + self.profile + "-" + "a" * 64 + for name in ["framebridge-credential-" + self.uid + "-" + self.profile + "-invalid", + "framebridge-credential-authorize-" + self.uid + "-" + self.profile + "-unknown"]: + with self.subTest(name=name), mock.patch.object(Path, "iterdir", return_value=iter([self.policies / canonical, self.policies / name])): + with self.assertRaisesRegex(RuntimeError, "ambiguous.*administrator review"): + autostart._node_helper_cleanup_required(self.state) + + def test_symlink_in_own_namespace_still_requires_root_cleanup(self): + path = self.policies / ("framebridge-credential-" + self.uid + "-" + self.profile + "-" + "a" * 64) + path.symlink_to(self.root / "nonexistent") + self.assertTrue(autostart._node_helper_cleanup_required(self.state)) + + def test_permission_denied_listing_is_not_treated_as_empty(self): + with mock.patch.object(Path, "iterdir", side_effect=PermissionError("synthetic denied")): + self.assertTrue(autostart._node_helper_cleanup_required(self.state)) + + def test_empty_verified_policy_directory_omits_privileged_cleanup(self): + self.assertFalse(autostart._node_helper_cleanup_required(self.state)) + + def test_insecure_parent_or_policy_directory_is_not_trusted(self): + self.trust.stop() + with mock.patch.object(credential_helper, "SUDOERS", Path("/etc/sudoers.d")): + for unsafe, kind, uid, mode in [ + (Path("/etc"), stat.S_IFDIR, 0, 0o775), + (Path("/etc/sudoers.d"), stat.S_IFLNK, 0, 0o777), + (Path("/etc/sudoers.d"), stat.S_IFDIR, 12345, 0o755), + ]: + def info(path, *, selected=unsafe, selected_kind=kind, selected_uid=uid, selected_mode=mode): + return os.stat_result((selected_kind | selected_mode if path == selected else stat.S_IFDIR | 0o755, + 1, 1, 1, selected_uid if path == selected else 0, 0, 0, 0, 0, 0)) + with self.subTest(path=unsafe, kind=kind, uid=uid, mode=mode), mock.patch.object(Path, "lstat", info), mock.patch.object(Path, "iterdir") as listing: + self.assertTrue(autostart._node_helper_cleanup_required(self.state)) + listing.assert_not_called() + + +if __name__ == "__main__": + unittest.main() diff --git a/source/tests/test_package_maintainer.py b/source/tests/test_package_maintainer.py index 59fe2be..9e20a01 100644 --- a/source/tests/test_package_maintainer.py +++ b/source/tests/test_package_maintainer.py @@ -9,7 +9,7 @@ import tempfile import unittest sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "packaging")) -from build_expanded import maintainer_prerm, PRIVILEGED_HELPER_FLOOR +from build_expanded import maintainer_preinst, maintainer_prerm, PRIVILEGED_HELPER_FLOOR from build_profiles import CANDIDATE_VERSION @@ -91,6 +91,38 @@ class MaintainerScriptTests(unittest.TestCase): with self.assertRaises(ValueError): maintainer_prerm("0.3.2'; /tmp/untrusted-script; '") + def run_preinst(self, arguments, *, version="0.3.4~dev.20261029.4", fail=0): + script = maintainer_preinst(version) + script = script.replace("/usr/bin/python3 -I -S - <<'FRAMEBRIDGE_UPGRADE_SNAPSHOT'", + shlex.quote(str(self.stub)) + " -I -S - <<'FRAMEBRIDGE_UPGRADE_SNAPSHOT'") + result = subprocess.run(["/bin/sh", "-s", "--", *arguments], input=script, + text=True, capture_output=True, timeout=10, + env=dict(os.environ, TEST_CALLS=str(self.trace), TEST_CLEANUP_RC=str(fail))) + calls = [json.loads(row) for row in self.trace.read_text().splitlines()] if self.trace.exists() else [] + return result, calls + + def test_same_version_reinstall_takes_a_new_current_runtime_snapshot(self): + result, calls = self.run_preinst(["upgrade", "0.3.4~dev.20261029.4"]) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(calls, [["-I", "-S", "-"]]) + + def test_forward_upgrade_still_takes_a_runtime_snapshot(self): + result, calls = self.run_preinst(["upgrade", "0.3.4~dev.20261029.3"]) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(calls, [["-I", "-S", "-"]]) + + def test_fresh_install_and_downgrade_do_not_capture_unrelated_running_profiles(self): + for arguments in (["install"], ["upgrade", "0.3.5"]): + with self.subTest(arguments=arguments): + result, calls = self.run_preinst(arguments) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual(calls, []) + + def test_failed_reinstall_snapshot_blocks_package_replacement(self): + result, calls = self.run_preinst(["upgrade", "0.3.4~dev.20261029.4"], fail=17) + self.assertEqual(result.returncode, 17) + self.assertEqual(calls, [["-I", "-S", "-"]]) + if __name__ == "__main__": unittest.main() diff --git a/source/tests/test_package_upgrade.py b/source/tests/test_package_upgrade.py index 524a746..3f60782 100644 --- a/source/tests/test_package_upgrade.py +++ b/source/tests/test_package_upgrade.py @@ -202,6 +202,58 @@ class PackageUpgradeTests(unittest.TestCase): self.assertEqual(value['phase'], 'CAPTURED') run.assert_not_called() + def test_reinstall_after_failure_preserves_receipt_and_keeps_stopped_profiles_stopped(self): + failed = {'schema': 1, 'transaction': 'a' * 16, 'phase': 'FAILED', + 'profiles': [{'state': str(self.state), 'phase': 'FAILED', + 'error': 'UPGRADE_OWNER_OPERATION_FAILED:user-ready'}]} + self.write(self.root / 'pending.json', failed) + processes = self.root / 'no-running-managers' + processes.mkdir() + marker = self.state / 'manual-stop.json' + marker.write_bytes(b'{"manual_stop": true}\n') + before_marker = marker.read_bytes() + with mock.patch.object(upgrade, 'ROOT', self.root), \ + mock.patch.object(upgrade, '_root'), \ + mock.patch.object(upgrade, '_read', side_effect=self.root_read), \ + mock.patch.object(upgrade.subprocess, 'run') as run: + value = upgrade.snapshot(processes) + self.assertEqual(value['profiles'], []) + self.assertEqual(upgrade.schedule()['phase'], 'COMPLETE') + self.assertEqual(json.loads((self.root / 'previous.json').read_text()), failed) + self.assertEqual(marker.read_bytes(), before_marker) + run.assert_not_called() + + def test_reinstall_after_failure_captures_only_current_managers_without_replaying_old_intent(self): + failed = {'schema': 1, 'phase': 'FAILED', + 'profiles': [{'state': '/home/owner/previous-profile', 'phase': 'FAILED'}]} + self.write(self.root / 'pending.json', failed) + row = {'uid': 1000, 'state': str(self.state), 'pid': 1234, 'phase': 'CAPTURED'} + with mock.patch.object(upgrade, 'ROOT', self.root), \ + mock.patch.object(upgrade, '_root'), \ + mock.patch.object(upgrade, '_read', side_effect=self.root_read), \ + mock.patch.object(upgrade, 'identify', return_value=row), \ + mock.patch.object(upgrade.subprocess, 'run', return_value=SimpleNamespace(returncode=0)) as run: + value = upgrade.snapshot(self.root) + self.assertEqual(value['profiles'], [row]) + self.assertEqual(upgrade.schedule()['phase'], 'SCHEDULED') + self.assertEqual(json.loads((self.root / 'previous.json').read_text()), failed) + self.assertEqual(run.call_count, 1) + self.assertEqual(run.call_args.args[0][-2:], [upgrade.MODULE, 'resume']) + + def test_reinstall_does_not_replace_a_snapshot_with_a_live_upgrade_worker(self): + for phase in ('SCHEDULED', 'RUNNING'): + with self.subTest(phase=phase): + self.write(self.root / 'pending.json', {'schema': 1, 'phase': phase}) + before = (self.root / 'pending.json').read_bytes() + with mock.patch.object(upgrade, 'ROOT', self.root), \ + mock.patch.object(upgrade, '_root'), \ + mock.patch.object(upgrade, '_read', side_effect=self.root_read), \ + mock.patch.object(upgrade, 'identify', return_value=None): + with self.assertRaisesRegex(RuntimeError, 'PREVIOUS_WORKER_PENDING'): + upgrade.snapshot(self.root) + self.assertEqual((self.root / 'pending.json').read_bytes(), before) + self.assertFalse((self.root / 'previous.json').exists()) + def test_optional_desktop_migration_failure_does_not_stop_runtime_recovery(self): row = {'uid': 1000, 'user': 'owner', 'home': '/home/owner', 'state': str(self.state), 'pid': 1234, 'birth': '99', diff --git a/source/tests/test_public_release_metadata.py b/source/tests/test_public_release_metadata.py new file mode 100644 index 0000000..830bca8 --- /dev/null +++ b/source/tests/test_public_release_metadata.py @@ -0,0 +1,133 @@ +"""Release assembly rejects stale or mismatched corresponding source.""" +import hashlib +import io +import json +from pathlib import Path +import sys +import tarfile +import tempfile +import unittest +from unittest import mock + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "packaging")) +import build_expanded +from release_metadata import release_source + + +class PublicReleaseSourceTests(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.addCleanup(self.tmp.cleanup) + self.root = Path(self.tmp.name) + self.file = self.root / "module.py" + self.file.write_text("# reviewed release source\n") + self.archive = self.root / "FrameBridge-0.3.4-source.tar.gz" + self.vendor_paths = { + "cp313": "source/sources/original-geranas/FrameBridge-Fleet-Hub/vendor", + "cp312": "source/target-vendors/cp312", + } + vendor_data = b"# reviewed vendor input\n" + self.vendor_files = {"module.py": vendor_data, + "package/__init__.py": b"# package\n", + "package-1.dist-info/METADATA": b"Name: package\nVersion: 1\n"} + self.payloads = {"source/module.py": self.file.read_bytes(), + **{path + "/" + relative: data for path in self.vendor_paths.values() + for relative, data in self.vendor_files.items()}} + self.write_archive() + # The reviewed vendor format uses Path component ordering. In particular + # package/__init__.py comes before package-1.dist-info/METADATA. + digest = hashlib.sha256() + for relative in ("module.py", "package/__init__.py", "package-1.dist-info/METADATA"): + digest.update(relative.encode() + b"\0") + digest.update(hashlib.sha256(self.vendor_files[relative]).digest()) + self.vendor = {"vendor_sha256": digest.hexdigest()} + self.data = { + "version": "0.3.4", "status": "RELEASE_SOURCE_ASSEMBLED", + "archive": self.archive.name, "bytes": self.archive.stat().st_size, + "sha256": hashlib.sha256(self.archive.read_bytes()).hexdigest(), + "vendor_inputs": {"vendors": {abi: {**self.vendor, "path": path} for abi, path in self.vendor_paths.items()}}, + "files": [{"path": path, "sha256": hashlib.sha256(data).hexdigest()} for path, data in self.payloads.items()], + } + self.manifest = self.root / "SOURCE-ARCHIVE-MANIFEST.json" + + def write_archive(self): + with tarfile.open(self.archive, "w:gz") as archive: + for path, data in self.payloads.items(): + info = tarfile.TarInfo("FrameBridge-0.3.4/" + path) + info.size = len(data) + archive.addfile(info, io.BytesIO(data)) + + def check(self, profile="debian13-amd64-py313", version="0.3.4"): + self.manifest.write_text(json.dumps(self.data)) + return release_source(self.manifest, version, profile, {"source/module.py": self.file}, self.vendor) + + def test_release_binds_archive_source_and_both_vendor_abis(self): + for profile in ("debian13-amd64-py313", "ubuntu24.04-amd64-py312", "mint22-amd64-py312"): + self.assertEqual(self.check(profile)["sha256"], self.data["sha256"]) + + def test_source_changed_after_archive_is_rejected(self): + self.file.write_text("# later edit\n") + with self.assertRaisesRegex(RuntimeError, "Package source differs"): + self.check() + + def test_archive_tamper_is_rejected(self): + with self.archive.open("ab") as stream: + stream.write(b"altered") + with self.assertRaisesRegex(RuntimeError, "archive hash or size"): + self.check() + + def test_changed_manifest_cannot_relabel_old_archive_contents(self): + self.file.write_text("# later edit\n") + self.data["files"][0]["sha256"] = hashlib.sha256(self.file.read_bytes()).hexdigest() + with self.assertRaisesRegex(RuntimeError, "archive content differs"): + self.check() + + def test_relabelled_alternate_vendor_bytes_are_rejected_even_by_debian_build(self): + self.payloads[self.vendor_paths["cp312"] + "/module.py"] = b"# different vendor bytes\n" + self.write_archive() + self.data.update(bytes=self.archive.stat().st_size, sha256=hashlib.sha256(self.archive.read_bytes()).hexdigest()) + self.data["files"] = [{"path": path, "sha256": hashlib.sha256(data).hexdigest()} for path, data in self.payloads.items()] + with self.assertRaisesRegex(RuntimeError, "Archived vendor bytes differ"): + self.check() + + def test_unsafe_archive_member_is_rejected_without_extracting(self): + self.payloads["../escape"] = b"unwanted path" + self.write_archive() + self.data.update(bytes=self.archive.stat().st_size, sha256=hashlib.sha256(self.archive.read_bytes()).hexdigest()) + self.data["files"].append({"path": "../escape", "sha256": hashlib.sha256(b"unwanted path").hexdigest()}) + with self.assertRaisesRegex(RuntimeError, "Unsafe release source archive path"): + self.check() + + def test_release_requires_cp312_corresponding_source(self): + del self.data["vendor_inputs"]["vendors"]["cp312"] + with self.assertRaisesRegex(RuntimeError, "cp312 and cp313"): + self.check() + + def test_vendor_input_cannot_differ_from_corresponding_source(self): + self.data["vendor_inputs"]["vendors"]["cp312"]["vendor_sha256"] = "b" * 64 + with self.assertRaisesRegex(RuntimeError, "vendor input differs"): + self.check("mint22-amd64-py312") + + def test_candidate_version_and_experimental_profile_are_not_public_release(self): + for profile, version in (("lmde7-amd64-py313", "0.3.4"), ("debian13-amd64-py313", "0.3.4~dev.1")): + with self.assertRaisesRegex(RuntimeError, "stable version and an official"): + self.check(profile, version) + + def test_public_metadata_names_source_without_claiming_signature_or_vm_qa(self): + docs = self.root / "docs" + docs.mkdir() + identity = self.check() + with mock.patch.object(build_expanded, "PUBLIC_RELEASE", True), \ + mock.patch.object(build_expanded, "SOURCE_ARCHIVE", identity), \ + mock.patch.object(build_expanded, "VERSION", "0.3.4"): + build_expanded.install_legal_material(docs) + result = json.loads((docs / "COMMUNITY-RELEASE-STATUS.json").read_text()) + self.assertEqual(result["status"], "PUBLIC_RELEASE_BUILD_ASSEMBLED") + self.assertEqual(result["source_archive"], identity) + self.assertEqual(result["signature_status"], "EXTERNAL_RELEASE_RECORD") + self.assertEqual(result["vm_lifecycle_validation"], "NOT_ASSERTED_BY_BUILDER") + self.assertNotIn("compatibility candidate", (docs / "copyright").read_text()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/README-APT.md b/tools/README-APT.md deleted file mode 100644 index 48be9d5..0000000 --- a/tools/README-APT.md +++ /dev/null @@ -1,134 +0,0 @@ -# Signed distribution repositories - -The canonical source is the existing GERANAS Gitea repository -`gerardo/framebridge`. Build all three reviewed DEBs from its release commit; -do not edit installed files to produce an update. - -One HTTPS repository at `https://framebridge.betancourt.one/debian/` contains -three independent suites: - -| Suite | Tested distribution profile | -| --- | --- | -| trixie | Debian 13, amd64, Python 3.13 | -| noble | Ubuntu 24.04, amd64, Python 3.12 | -| mint22 | Linux Mint 22.x, amd64, Python 3.12 | - -Select exactly the suite matching the computer. These are three builds of one -binary package, `framebridge-original-expanded`, with unique pool filenames. -This table does not certify untested releases or architectures. - -## Prepare and review - -Run `python3 tools/build_apt_repository.py prepare --help` in the source -repository. Supply the exact three version-matched DEBs, the existing official -public key and a new output directory. The command copies the artifacts, builds -indexes and by-hash paths, and prints the immutable input manifest SHA-256. -It does not open a private keyring, sign, publish or install anything. - -Review the manifest, package hashes and release identity before signing. -The public key must contain exactly one primary release key with fingerprint -`2B1F01BC806C0B33CB6CEDDE52859CEBC91B8808`. Official subkeys are allowed. - -## Sign in the owner's normal terminal - -Run `python3 tools/build_apt_repository.py sign --help`. Pass the reviewed -output directory and exact manifest SHA-256. The signer requires a non-root -interactive terminal and an owner-private existing signing home. Set -`GPG_TTY=$(tty)` in that normal terminal if the pinentry implementation needs it. -The owner's passphrase is entered only into normal pinentry; it is never an -argument, environment variable or chat message. - -The signer writes `Release.gpg` and `InRelease` for each suite, verifies the -signatures against the public key and exact reviewed Release plaintext, then -clears the dedicated signing agent. Existing signatures or partial results -cause refusal; inspect a partial transaction instead of blindly rerunning it. - -Run `verify` with the same pinned manifest hash after signing and again after -transport. Metadata expires after 30 days; publish a freshly signed Release -before expiry, without altering historical signed artifacts. - -## Publish through GERANAS - -Use the existing GERANAS web origin and the CLOUD HTTPS reverse proxy. Do not -create another Git backend or expose MCP/auth/broker services. Back up the -current public generation before activation. Preserve the existing signed -0.3.1 downloads and old repository metadata in an archive path. - -Publish only reviewed manifest files, the six verified signature files and the -signing receipt. Public directories must be `0755` and files `0644`; a private -staging umask must not leak into the served generation. Never publish the -signing home, private receipts, account configuration or operational worktree. -Activate a complete verified generation, preserving the web unit's existing -read-only bind mounts, then run isolated APT update and exact-version download -for all three suites through the final HTTPS authority. - -## Configure a client - -Install the verified official public key as -`/etc/apt/keyrings/framebridge-archive-keyring.asc` with mode `0644`. -Its fingerprint must match the value above. Add a Deb822 source file: - -```text -Types: deb -URIs: https://framebridge.betancourt.one/debian/ -Suites: trixie -Components: main -Architectures: amd64 -Signed-By: /etc/apt/keyrings/framebridge-archive-keyring.asc -``` - -Replace `trixie` with `noble` or `mint22` for those tested profiles. Then use -normal APT commands: - -```sh -sudo apt update -apt-cache policy framebridge-original-expanded -sudo apt install --only-upgrade framebridge-original-expanded -``` - -Do not use trusted=yes or disable signature/validity checks. APT update/download -verification does not itself prove runtime restart or reboot persistence. -Confirm the actual installed version and ready connection after each upgrade. - -## Tool checks - -`python3 tools/test_build_apt_repository.py` creates disposable packages and a -disposable signing identity in a temporary directory. It tests actual isolated -APT acceptance for each suite and rejects altered packages/indexes/signatures, -unexpected versions, path traversal and bundled extra primary trust keys. -It never uses the official private signing key or changes system APT sources. - - -## One signing session for the release - -For a complete release, also pass --source with the reviewed -FrameBridge-VERSION-source.tar.gz and --dependency-source twice with the two -existing dependency-source archives. Their original sibling .asc signatures -are verified and copied unchanged. The generator creates a downloads staging -subdirectory with the three DEBs, source, dependency sources and SHA256SUMS. -The same input manifest covers all of these bytes. The owner-terminal sign -command signs the three DEBs, project source and checksums in the same session -as the three APT suites. Existing dependency signatures are preserved. - -Map the staging downloads subdirectory to the existing public /downloads/; -the rest of the repository goes under /debian/. Do not publish a nested second -/debian/downloads/ route as the official download location. Verify every -signature with the pinned manifest before activating either path. - -## Canonical Gitea publication - -publish_gitea.py is an administrator tool for the existing GERANAS Gitea, not a -second Git host. Its default mode checks a root-frozen bundle SHA-256, exact old -main, ancestor relationship and the new release tag. --apply requires an -exclusive journal in a root-owned private directory. Run only the reviewed -root-frozen tool and bundle using the normal authorized administrator context. - -The tool creates a narrowly scoped, uniquely named temporary token using the -installed Gitea administrator CLI. It keeps the token only in process memory, -feeds normal Git ASKPASS through a private Unix socket and performs an atomic -push without a force flag. It verifies exact refs, revokes the temporary token -through normal Basic authentication and verifies HTTP 401 afterward. The -journal contains the nonsecret token name so an interrupted transaction can be -reviewed. If any step is uncertain, inspect that transaction rather than -replaying it. No token value is placed in URLs, arguments, environment variables, -files or reports. diff --git a/tools/build_apt_repository.py b/tools/build_apt_repository.py deleted file mode 100755 index fc79756..0000000 --- a/tools/build_apt_repository.py +++ /dev/null @@ -1,299 +0,0 @@ -#!/usr/bin/env python3 -"""Build and verify three signed APT suites from the reviewed distribution DEBs.""" -from __future__ import annotations - -import argparse -import datetime as dt -import email.utils -import gzip -import hashlib -import json -import os -from pathlib import Path -import re -import shutil -import subprocess -import sys -import tempfile - -PACKAGE = "framebridge-original-expanded" -FINGERPRINT = "2B1F01BC806C0B33CB6CEDDE52859CEBC91B8808" -DEPENDENCY_SOURCE_ASSETS = { - "FrameBridge-0.3.1-Community-Preview1-dependency-sources.tar.gz": (82606998, "64540a85bd65eac3f394d8c0a967cacbc00e112676d57d644dcd1bb691c1926a"), - "FrameBridge-0.3.1-tunnel-client-dependency-sources.tar.gz": (26941745, "6445d4f0e773aba833fe5c610fbae54102b92de2ce636438f769f21e890c2bd9"), -} -PROFILES = { - "debian": ("trixie", "Debian 13", "debian13-amd64-py313", "3.13"), - "ubuntu": ("noble", "Ubuntu 24.04", "ubuntu24.04-amd64-py312", "3.12"), - "mint": ("mint22", "Linux Mint 22.x", "mint22-amd64-py312", "3.12"), -} - -def require(condition, message): - if not condition: - raise ValueError(message) - -def digest(data, algorithm="sha256"): - return hashlib.new(algorithm, data).hexdigest() - -def run(argv, **kwargs): - return subprocess.run([str(x) for x in argv], check=True, capture_output=True, **kwargs) - -def dump(path, value): - path.write_text(json.dumps(value, indent=2, sort_keys=True) + "\n") - -def public_fingerprint(key): - with tempfile.TemporaryDirectory(prefix="framebridge-public-key-") as tmp: - os.chmod(tmp, 0o700) - result = run(["gpg", "--no-options", "--homedir", tmp, "--batch", - "--with-colons", "--show-keys", key]).stdout.decode() - fingerprints = [line.split(":")[9] for line in result.splitlines() - if line.startswith("fpr:")] - primary_keys = [line for line in result.splitlines() if line.startswith("pub:")] - require(len(primary_keys) == 1 and fingerprints and fingerprints[0] == FINGERPRINT, - "Expected exactly one official primary release key") - return fingerprints[0] - -def control(path): - text = run(["dpkg-deb", "--field", path]).stdout.decode() - fields = {} - for line in text.splitlines(): - if line and not line[0].isspace(): - name, separator, value = line.partition(":") - require(separator, "Invalid Debian control field") - fields[name] = value.strip() - require(not any(k in fields for k in ("Filename", "Size", "MD5sum", "SHA256", "SHA512")), - "Artifact control contains repository-generated fields") - return text.rstrip() + "\n", fields - -def release_bytes(suite, label, date, files): - lines = ["Origin: FrameBridge", "Label: FrameBridge", f"Suite: {suite}", - f"Codename: {suite}", f"Date: {email.utils.format_datetime(date)}", - f"Valid-Until: {email.utils.format_datetime(date + dt.timedelta(days=30))}", - "Architectures: amd64", "Components: main", - f"Description: FrameBridge for {label}", "Acquire-By-Hash: yes"] - for algorithm, heading in (("sha256", "SHA256"), ("sha512", "SHA512")): - lines.append(heading + ":") - lines.extend(f" {digest(data, algorithm)} {len(data):16d} {name}" - for name, data in sorted(files.items())) - return ("\n".join(lines) + "\n").encode() - - -def verify_detached(public_key, signature, payload): - with tempfile.TemporaryDirectory(prefix="framebridge-asset-verify-") as tmp: - tmp = Path(tmp) - ring = tmp / "release.gpg" - ring.write_bytes(run(["gpg", "--no-options", "--homedir", tmp, "--batch", "--output", "-", - "--dearmor", public_key]).stdout) - result = run(["gpgv", "--homedir", tmp, "--keyring", ring, "--status-fd", "1", signature, payload]) - require(f"[GNUPG:] VALIDSIG {FINGERPRINT} ".encode() in result.stdout, "Unexpected dependency-source signer") - -def prepare_downloads(args, inputs): - source = getattr(args, "source", None) - dependencies = getattr(args, "dependency_source", []) - if source is None: - require(not dependencies, "Dependency assets require the corresponding project-source archive") - return [] - require(source.is_file() and not source.is_symlink() and - source.name == f"FrameBridge-{args.version}-source.tar.gz", "Unexpected project-source archive") - require({p.name for p in dependencies} == set(DEPENDENCY_SOURCE_ASSETS) and - len(dependencies) == len(DEPENDENCY_SOURCE_ASSETS), "Exactly the reviewed two dependency-source archives required") - for path in dependencies: - expected_size, expected_sha = DEPENDENCY_SOURCE_ASSETS[path.name] - require(path.is_file() and not path.is_symlink(), "Unsafe dependency-source archive") - data = path.read_bytes() - require(len(data) == expected_size and digest(data) == expected_sha, "Dependency-source archive hash mismatch") - verify_detached(args.public_key, path.with_name(path.name + ".asc"), path) - directory = args.output / "downloads" - directory.mkdir() - assets = [] - def add(name, data, needs_signing): - target = directory / name - require(not target.exists(), "Duplicate release filename") - target.write_bytes(data) - assets.append({"filename": name, "size_bytes": len(data), "sha256": digest(data), - "signature": name + ".asc", "needs_signing": needs_signing}) - for _, _, _, profile, _, data in inputs: - add(f"FrameBridge-{args.version}-{profile}.deb", data, True) - add(source.name, source.read_bytes(), True) - for path in dependencies: - add(path.name, path.read_bytes(), False) - shutil.copyfile(path.with_name(path.name + ".asc"), directory / (path.name + ".asc")) - shutil.copyfile(args.public_key, directory / "framebridge-release-key.asc") - sums = "".join(item["sha256"] + " " + item["filename"] + "\n" for item in assets) - add("SHA256SUMS", sums.encode(), True) - return assets - -def prepare(args): - output = args.output - require(not output.exists(), "Output must be a new directory; never overwrite a published repository") - require(re.fullmatch(r"[0-9][A-Za-z0-9.+:~_-]*", args.version), "Invalid version") - public_fingerprint(args.public_key) - epoch = args.epoch if args.epoch is not None else int(dt.datetime.now(dt.timezone.utc).timestamp()) - date = dt.datetime.fromtimestamp(epoch, dt.timezone.utc) - inputs = [] - for distro, (suite, label, profile, python) in PROFILES.items(): - path = getattr(args, distro) - require(path.is_file() and not path.is_symlink(), f"{distro}: artifact is not a regular file") - text, fields = control(path) - require(fields.get("Package") == PACKAGE, f"{distro}: wrong binary package") - require(fields.get("Version") == args.version, f"{distro}: wrong version") - require(fields.get("Architecture") == "amd64", f"{distro}: wrong architecture") - require(re.search(r"python3\s*\(>=\s*" + re.escape(python), fields.get("Depends", "")), - f"{distro}: Python dependency does not match the tested profile") - data = path.read_bytes() - inputs.append((distro, suite, label, profile, text, data)) - output.mkdir(parents=True, mode=0o755) - records = [] - for distro, suite, label, profile, text, data in inputs: - relative = f"pool/main/f/framebridge/{PACKAGE}_{args.version}_{profile}.deb" - artifact = output / relative - artifact.parent.mkdir(parents=True, exist_ok=True) - artifact.write_bytes(data) - require(digest(artifact.read_bytes()) == digest(data), "Copied artifact hash mismatch") - stanza = text + f"Filename: {relative}\nSize: {len(data)}\nSHA256: {digest(data)}\nSHA512: {digest(data, 'sha512')}\n\n" - plain = stanza.encode() - indexes = {"main/binary-amd64/Packages": plain, - "main/binary-amd64/Packages.gz": gzip.compress(plain, mtime=0)} - suite_dir = output / "dists" / suite - for name, index in indexes.items(): - target = suite_dir / name - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(index) - for algorithm in ("sha256", "sha512"): - by_hash = target.parent / "by-hash" / algorithm.upper() / digest(index, algorithm) - by_hash.parent.mkdir(parents=True, exist_ok=True) - by_hash.write_bytes(index) - (suite_dir / "Release").write_bytes(release_bytes(suite, label, date, indexes)) - records.append({"distribution": distro, "label": label, "suite": suite, - "profile": profile, "filename": relative, - "size": len(data), "sha256": digest(data)}) - downloads = prepare_downloads(args, inputs) - shutil.copyfile(args.public_key, output / "framebridge-archive-keyring.asc") - files = {p.relative_to(output).as_posix(): {"bytes": p.stat().st_size, - "sha256": digest(p.read_bytes())} for p in sorted(output.rglob("*")) if p.is_file()} - manifest = {"schema": 1, "package": PACKAGE, "version": args.version, - "fingerprint": FINGERPRINT, "prepared_utc": date.isoformat(), - "artifacts": records, "download_assets": downloads, "files": files} - dump(output / "APT-INPUT-MANIFEST.json", manifest) - manifest_hash = digest((output / "APT-INPUT-MANIFEST.json").read_bytes()) - print(json.dumps({"prepared": True, "signed": False, "directory": str(output), - "version": args.version, "manifest_sha256": manifest_hash, - "suites": [x["suite"] for x in records]}, sort_keys=True)) - -def check_inputs(output, expected): - p = output / "APT-INPUT-MANIFEST.json" - require(p.is_file() and not p.is_symlink(), "Input manifest missing or unsafe") - raw = p.read_bytes() - require(digest(raw) == expected, "Manifest hash mismatch") - manifest = json.loads(raw) - require(manifest.get("package") == PACKAGE and manifest.get("fingerprint") == FINGERPRINT, - "Wrong package or signing identity") - require(len(manifest.get("artifacts", [])) == 3, "Exactly three distribution artifacts required") - require({x["suite"] for x in manifest["artifacts"]} == {x[0] for x in PROFILES.values()}, - "Unexpected distribution suite set") - for name, metadata in manifest["files"].items(): - relative = Path(name) - require(not relative.is_absolute() and ".." not in relative.parts, "Unsafe manifest path") - path = output / relative - require(path.is_file() and not path.is_symlink(), f"Missing or unsafe input: {name}") - data = path.read_bytes() - require(len(data) == metadata["bytes"] and digest(data) == metadata["sha256"], - f"Input changed after review: {name}") - public_fingerprint(output / "framebridge-archive-keyring.asc") - return manifest - -def signature_paths(output, sign_only=False): - for suite, *_ in PROFILES.values(): - root = output / "dists" / suite - yield root / "Release", root / "InRelease", True - yield root / "Release", root / "Release.gpg", False - manifest = json.loads((output / "APT-INPUT-MANIFEST.json").read_text()) - for asset in manifest.get("download_assets", []): - if sign_only and not asset["needs_signing"]: - continue - filename = asset["filename"] - require(Path(filename).name == filename and Path(asset["signature"]).name == asset["signature"], - "Unsafe download signature path") - yield output / "downloads" / filename, output / "downloads" / asset["signature"], False - -def verify_signatures(output, manifest): - with tempfile.TemporaryDirectory(prefix="framebridge-apt-verify-") as tmp: - tmp = Path(tmp) - keyring = tmp / "release.gpg" - keyring.write_bytes(run(["gpg", "--no-options", "--homedir", tmp, "--batch", "--output", "-", "--dearmor", - output / "framebridge-archive-keyring.asc"]).stdout) - for release, signed, clearsign in signature_paths(output): - require(signed.is_file() and not signed.is_symlink(), "Missing signature") - args = ["gpgv", "--homedir", tmp, "--keyring", keyring, "--status-fd", "1"] - result = run(args + ([signed] if clearsign else [signed, release])) - require(f"[GNUPG:] VALIDSIG {FINGERPRINT} ".encode() in result.stdout, - "Signature made by unexpected key") - if clearsign: - plaintext = run(["gpgv", "--homedir", tmp, "--keyring", keyring, - "--output", "-", signed]).stdout - require(plaintext == release.read_bytes(), "Clear-signed release differs from reviewed input") - return {"verified": True, "version": manifest["version"], - "suites": [x["suite"] for x in manifest["artifacts"]], "fingerprint": FINGERPRINT} - -def sign(args): - require(os.getuid() != 0 and sys.stdin.isatty() and os.isatty(1), - "Signing must run as the owner in a normal interactive terminal") - manifest = check_inputs(args.output, args.manifest_sha256) - require(args.key_home.is_dir() and not args.key_home.is_symlink(), "Unsafe signing home") - key_stat = args.key_home.stat() - require(key_stat.st_uid == os.getuid() and key_stat.st_mode & 0o077 == 0, "Signing home must be owner-private") - targets = list(signature_paths(args.output, sign_only=True)) - require(all(not target.exists() for _, target, _ in targets), "Signatures already exist; do not overwrite") - common = ["gpg", "--no-options", "--homedir", args.key_home, "--pinentry-mode", "default", - "--local-user", FINGERPRINT, "--digest-algo", "SHA256"] - try: - for source, target, clearsign in targets: - check_inputs(args.output, args.manifest_sha256) - temporary = target.with_name(target.name + ".partial") - require(not temporary.exists(), "Incomplete previous signing transaction needs review") - subprocess.run([str(x) for x in common + ["--output", temporary, - "--clearsign" if clearsign else "--detach-sign", source]], check=True) - temporary.rename(target) - result = verify_signatures(args.output, manifest) - result["manifest_sha256"] = args.manifest_sha256 - dump(args.output / "APT-SIGNING-RECEIPT.json", result) - print(json.dumps(result, sort_keys=True)) - finally: - run(["gpgconf", "--homedir", args.key_home, "--kill", "gpg-agent"]) - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - commands = parser.add_subparsers(dest="command", required=True) - prepare_parser = commands.add_parser("prepare") - prepare_parser.add_argument("--output", type=Path, required=True) - prepare_parser.add_argument("--version", required=True) - for distro in PROFILES: - prepare_parser.add_argument("--" + distro, type=Path, required=True) - prepare_parser.add_argument("--public-key", type=Path, required=True) - prepare_parser.add_argument("--epoch", type=int) - prepare_parser.add_argument("--source", type=Path, help="Reviewed corresponding project-source tar.gz") - prepare_parser.add_argument("--dependency-source", type=Path, action="append", default=[], - help="Reviewed dependency-source archive with its unchanged sibling .asc") - for name in ("sign", "verify"): - sub = commands.add_parser(name) - sub.add_argument("--output", type=Path, required=True) - sub.add_argument("--manifest-sha256", required=True) - if name == "sign": - sub.add_argument("--key-home", type=Path, - default=Path.home() / ".local/share/framebridge-release-signing") - args = parser.parse_args() - try: - if args.command == "prepare": - prepare(args) - elif args.command == "sign": - sign(args) - else: - manifest = check_inputs(args.output, args.manifest_sha256) - print(json.dumps(verify_signatures(args.output, manifest), sort_keys=True)) - except (ValueError, OSError, subprocess.CalledProcessError) as error: - print(f"FrameBridge APT repository: {error}", file=sys.stderr) - return 1 - return 0 - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/publish_gitea.py b/tools/publish_gitea.py deleted file mode 100755 index eff1bba..0000000 --- a/tools/publish_gitea.py +++ /dev/null @@ -1,227 +0,0 @@ -#!/usr/bin/env python3 -"""Publish a reviewed release by normal authenticated fast-forward Git push.""" -import argparse -import base64 -import hashlib -import json -import os -from pathlib import Path -import re -import shutil -import socket -import subprocess -import sys -import tempfile -import threading -import urllib.error -import urllib.parse -import urllib.request -import uuid - -REPOSITORY = "http://127.0.0.1:3005/gerardo/framebridge.git" -API = "http://127.0.0.1:3005/api/v1" -CONTAINER = "geranas-gitea" - -def require(value, message): - if not value: - raise ValueError(message) - -def run(args, **kwargs): - return subprocess.run([str(x) for x in args], check=True, capture_output=True, **kwargs) - -def remote_refs(): - raw = run(["git", "-c", "credential.helper=", "ls-remote", REPOSITORY]).stdout.decode() - return dict((ref, sha) for sha, ref in (line.split() for line in raw.splitlines())) - -def api_request(method, path, token): - request = urllib.request.Request(API + path, method=method, - headers={"Authorization": "Basic " + base64.b64encode(("gerardo:" + token).encode()).decode()}) - with urllib.request.urlopen(request, timeout=15) as response: - return response.status, response.read() - -def check_bundle(args, source): - data = args.bundle.read_bytes() - require(hashlib.sha256(data).hexdigest() == args.bundle_sha256, "Bundle hash mismatch") - run(["git", "clone", "--bare", "--no-hardlinks", args.bundle, source]) - run(["git", "--git-dir", source, "fsck", "--full"]) - actual = run(["git", "--git-dir", source, "rev-parse", args.commit + "^{commit}"]).stdout.decode().strip() - require(actual == args.commit, "Reviewed release commit missing") - run(["git", "--git-dir", source, "merge-base", "--is-ancestor", args.old_commit, args.commit]) - resolved = run(["git", "--git-dir", source, "rev-parse", args.tag + "^{}"]).stdout.decode().strip() - require(resolved == args.commit, "Release tag does not point to reviewed commit") - refs = remote_refs() - require(refs.get("refs/heads/main") == args.old_commit, "Canonical main changed; review before publishing") - require("refs/tags/" + args.tag not in refs, "Release tag already exists; never overwrite") - return refs - -def record(path, state): - temporary = path.with_suffix(".partial") - with open(temporary, "x", encoding="utf-8") as stream: - json.dump(state, stream, indent=2, sort_keys=True) - stream.write("\n") - stream.flush() - os.fsync(stream.fileno()) - temporary.replace(path) - -def askpass_server(directory, token): - address = str(directory / "credential.sock") - server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - server.bind(address) - os.chmod(address, 0o600) - server.listen(2) - server.settimeout(0.5) - stop = threading.Event() - def serve(): - while not stop.is_set(): - try: - connection, _ = server.accept() - except socket.timeout: - continue - with connection: - connection.settimeout(3) - request = connection.recv(32) - if request == b"username": - connection.sendall(b"gerardo\n") - elif request == b"password": - connection.sendall(token.encode() + b"\n") - thread = threading.Thread(target=serve, daemon=True) - thread.start() - client = directory / "askpass" - client.write_text( - "#!/usr/bin/python3\nimport socket,sys\n" - "p=sys.argv[1].lower()\n" - "kind=b'username' if p.startswith('username') else b'password' if p.startswith('password') else None\n" - "if kind is None: raise SystemExit(1)\n" - "s=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)\n" - f"s.connect({address!r})\ns.sendall(kind)\ns.shutdown(socket.SHUT_WR)\n" - "data=b''\n" - "while True:\n chunk=s.recv(4096)\n if not chunk: break\n data+=chunk\n" - "sys.stdout.buffer.write(data)\n") - client.chmod(0o700) - return server, stop, thread, client - -def root_directory(path): - require(path.is_absolute() and path.resolve(strict=True) == path, "Root staging path must be absolute without symlink parents") - require(path.is_dir() and path.stat().st_mode & 0o077 == 0, "Root staging directory must be private") - for current in (path, *path.parents): - metadata = current.stat() - require(metadata.st_uid == 0 and metadata.st_mode & 0o022 == 0, - "Root staging path has a non-root or shared-writable ancestor") - -def publish(args): - require(os.geteuid() == 0 and socket.gethostname().lower() == "geranas", - "Run on GERANAS using the authorized normal administrator context") - for sha in (args.bundle_sha256,): - require(re.fullmatch(r"[a-f0-9]{64}", sha), "Invalid bundle SHA-256") - for sha in (args.commit, args.old_commit): - require(re.fullmatch(r"[a-f0-9]{40}", sha), "Invalid source commit") - require(re.fullmatch(r"v[0-9]+\.[0-9]+\.[0-9]+", args.tag), "Invalid release tag") - require(args.bundle.is_file() and not args.bundle.is_symlink(), "Unsafe bundle path") - bundle_stat = args.bundle.stat() - require(bundle_stat.st_uid == 0 and bundle_stat.st_mode & 0o022 == 0 and bundle_stat.st_nlink == 1, - "Bundle must be a root-owned reviewed regular file without shared write access") - root_directory(args.bundle.parent) - os.umask(0o077) - with tempfile.TemporaryDirectory(prefix="fb-gitea-push-", dir="/run") as tmp: - directory = Path(tmp) - source = directory / "source.git" - before = check_bundle(args, source) - state = {"schema": 1, "repository": "gerardo/framebridge", "old_commit": args.old_commit, - "commit": args.commit, "tag": args.tag, "bundle_sha256": args.bundle_sha256, - "phase": "CHECKED", "push_performed": False, "token_revoked": False} - if not args.apply: - print(json.dumps(state, sort_keys=True)) - return - require(args.journal is not None and args.journal.parent.is_dir(), "Explicit existing journal directory required") - root_directory(args.journal.parent) - require(not args.journal.exists() and not args.journal.is_symlink(), "Existing transaction; never replay blindly") - # Reserve the exact new transaction before minting a credential. - descriptor = os.open(args.journal, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600) - os.close(descriptor) - record(args.journal, state) - token_name = "framebridge-release-" + uuid.uuid4().hex - state["temporary_token_name"] = token_name - state["phase"] = "TOKEN_CREATION_REQUESTED" - record(args.journal, state) - token = None - failure = None - server = stop = thread = None - try: - # Capture the token only in this process's memory. Never log this result. - result = run(["docker", "exec", "--user", "git", CONTAINER, "gitea", - "--config", "/etc/gitea/app.ini", "admin", "user", "generate-access-token", - "--username", "gerardo", "--token-name", token_name, "--raw", - "--scopes", "write:repository,write:user"]) - token = result.stdout.decode().strip() - require(re.fullmatch(r"[a-fA-F0-9]{40,128}", token), "Unexpected credential response; token needs owner review") - state["phase"] = "TEMPORARY_TOKEN_CREATED" - record(args.journal, state) - # The installed token-management route requires Basic authentication. - # Gitea accepts a PAT as the Basic password; prove that gate before pushing. - status, _ = api_request("GET", "/users/gerardo/tokens?limit=1", token) - require(status == 200, "Normal Basic token-management authentication failed") - state["token_management_auth_verified"] = True - record(args.journal, state) - server, stop, thread, client = askpass_server(directory, token) - env = dict(os.environ, GIT_ASKPASS=str(client), GIT_TERMINAL_PROMPT="0", LC_ALL="C") - # No force flag. The normal receive-pack checks and Gitea hooks run. - run(["git", "--git-dir", source, "-c", "credential.helper=", "push", "--atomic", - REPOSITORY, args.commit + ":refs/heads/main", "refs/tags/" + args.tag], env=env, timeout=120) - state["push_performed"] = True - state["phase"] = "PUSH_COMPLETED" - after = remote_refs() - require(after.get("refs/heads/main") == args.commit, "Main ref readback mismatch") - resolved_tag = after.get("refs/tags/" + args.tag + "^{}", after.get("refs/tags/" + args.tag)) - require(resolved_tag == args.commit, "Release tag readback mismatch") - state["refs_verified"] = True - record(args.journal, state) - except Exception as error: - # Commands never contain the credential; do not print captured HTTP/Git output. - failure = f"{type(error).__name__}: {error}" - state["failure"] = failure - finally: - if stop is not None: - stop.set() - thread.join(timeout=2) - server.close() - if token is not None: - try: - status, _ = api_request("DELETE", "/users/gerardo/tokens/" + - urllib.parse.quote(token_name, safe=""), token) - require(status == 204, "Unexpected token revocation response") - try: - api_request("GET", "/user", token) - except urllib.error.HTTPError as error: - require(error.code == 401, "Revoked credential did not return HTTP 401") - else: - raise ValueError("Credential remains accepted after revocation") - state["token_revoked"] = True - except Exception as error: - state["revocation_failure"] = f"{type(error).__name__}: {error}" - failure = failure or "Temporary token revocation requires review" - token = None - state["phase"] = ("COMPLETED" if state.get("refs_verified") and - state["token_revoked"] and failure is None else "REVIEW_REQUIRED") - record(args.journal, state) - print(json.dumps(state, sort_keys=True)) - require(failure is None, failure) - -def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument("--bundle", type=Path, required=True) - parser.add_argument("--bundle-sha256", required=True) - parser.add_argument("--commit", required=True) - parser.add_argument("--old-commit", required=True) - parser.add_argument("--tag", required=True) - parser.add_argument("--journal", type=Path) - parser.add_argument("--apply", action="store_true") - args = parser.parse_args() - try: - publish(args) - except Exception as error: - print(f"FrameBridge Gitea publication: {type(error).__name__}: {error}", file=sys.stderr) - return 1 - return 0 - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/run_tests.py b/tools/run_tests.py deleted file mode 100755 index aa5c5f6..0000000 --- a/tools/run_tests.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python3 -"""Run source tests with generated fixtures and an isolated application environment.""" -from pathlib import Path -import os -import stat -import subprocess -import sys -import tempfile - - -def main(): - root = Path(__file__).resolve().parents[1] - qa = root / "source/qa" - qa.mkdir(mode=0o700, exist_ok=True) - info = qa.lstat() - if not stat.S_ISDIR(info.st_mode) or info.st_uid != os.getuid() or info.st_mode & 0o077: - raise SystemExit("The generated source/qa directory must be private and owned by the test user.") - environment = {key: value for key, value in os.environ.items() - if not key.startswith(("FRAMEBRIDGE_", "FBTERM_", "FB_"))} - with tempfile.TemporaryDirectory(prefix="unit-test-home-", dir=qa) as home: - environment.update( - HOME=home, XDG_DATA_HOME=str(Path(home) / ".local/share"), - XDG_CONFIG_HOME=str(Path(home) / ".config"), - PYTHONPATH=str(root / "source/expanded"), PYTHONDONTWRITEBYTECODE="1") - result = subprocess.run([sys.executable, "-m", "unittest", "discover", "-s", - str(root / "source/tests")], cwd=root, env=environment) - return result.returncode - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/tools/test_build_apt_repository.py b/tools/test_build_apt_repository.py deleted file mode 100644 index dc3a2a4..0000000 --- a/tools/test_build_apt_repository.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 -"""Integration checks with disposable DEBs and a disposable signing identity.""" -import argparse -import contextlib -import datetime as dt -import hashlib -import importlib.util -import io -import json -import os -from pathlib import Path -import shutil -import subprocess -import tempfile -import unittest - -spec = importlib.util.spec_from_file_location("apt_builder", Path(__file__).with_name("build_apt_repository.py")) -builder = importlib.util.module_from_spec(spec) -spec.loader.exec_module(builder) - -class RepositoryTests(unittest.TestCase): - @classmethod - def setUpClass(cls): - cls.temp = tempfile.TemporaryDirectory(prefix="framebridge-apt-tests-") - cls.base = Path(cls.temp.name) - cls.key_home = cls.base / "test-key" - cls.key_home.mkdir(mode=0o700) - subprocess.run(["gpg", "--no-options", "--homedir", str(cls.key_home), "--batch", - "--pinentry-mode", "loopback", "--passphrase", "", "--quick-generate-key", - "FrameBridge disposable test ", "ed25519", "sign", "0"], - check=True, capture_output=True) - result = subprocess.run(["gpg", "--no-options", "--homedir", str(cls.key_home), - "--with-colons", "--list-keys"], check=True, capture_output=True).stdout.decode() - cls.original_fingerprint = builder.FINGERPRINT - builder.FINGERPRINT = next(x.split(":")[9] for x in result.splitlines() if x.startswith("fpr:")) - cls.public_key = cls.base / "test.asc" - cls.public_key.write_bytes(subprocess.run( - ["gpg", "--no-options", "--homedir", str(cls.key_home), "--armor", "--export", builder.FINGERPRINT], - check=True, capture_output=True).stdout) - cls.debs = {} - for distro, (_, _, _, python) in builder.PROFILES.items(): - tree = cls.base / distro - (tree / "DEBIAN").mkdir(parents=True) - (tree / "DEBIAN").chmod(0o755) - (tree / "DEBIAN/control").write_text( - f"Package: {builder.PACKAGE}\nVersion: 0.3.3\nArchitecture: amd64\n" - f"Maintainer: FrameBridge \nDepends: python3 (>= {python})\n" - f"Description: Disposable {distro} test package\n") - (tree / "distribution.txt").write_text(distro) - deb = cls.base / (distro + ".deb") - subprocess.run(["dpkg-deb", "--build", str(tree), str(deb)], check=True, capture_output=True) - cls.debs[distro] = deb - - @classmethod - def tearDownClass(cls): - subprocess.run(["gpgconf", "--homedir", str(cls.key_home), "--kill", "gpg-agent"], capture_output=True) - builder.FINGERPRINT = cls.original_fingerprint - cls.temp.cleanup() - - def setUp(self): - self.output = Path(tempfile.mkdtemp(dir=self.base, prefix="output-")) / "repository" - - def prepare(self, **changes): - args = argparse.Namespace(output=self.output, version="0.3.3", public_key=self.public_key, - epoch=1793199600, **self.debs) - for key, value in changes.items(): - setattr(args, key, value) - with contextlib.redirect_stdout(io.StringIO()): - builder.prepare(args) - raw = (self.output / "APT-INPUT-MANIFEST.json").read_bytes() - return hashlib.sha256(raw).hexdigest(), json.loads(raw) - - def sign_test_releases(self): - for source, signed, clearsign in builder.signature_paths(self.output, sign_only=True): - subprocess.run(["gpg", "--no-options", "--homedir", str(self.key_home), "--batch", - "--pinentry-mode", "loopback", "--passphrase", "", "--local-user", builder.FINGERPRINT, - "--digest-algo", "SHA256", "--output", str(signed), - "--clearsign" if clearsign else "--detach-sign", str(source)], - check=True, capture_output=True) - - def test_actual_apt_update_accepts_three_signed_suites(self): - expected, manifest = self.prepare() - self.sign_test_releases() - self.assertTrue(builder.verify_signatures(self.output, manifest)["verified"]) - for suite, *_ in builder.PROFILES.values(): - isolated = self.output.parent / ("apt-" + suite) - isolated.mkdir() - (isolated / "state/lists/partial").mkdir(parents=True) - (isolated / "cache/archives/partial").mkdir(parents=True) - source = isolated / "sources.list" - source.write_text(f"deb [arch=amd64 signed-by={self.public_key}] file:{self.output} {suite} main\n") - result = subprocess.run(["apt-get", "-o", f"Dir::State={isolated}/state", - "-o", f"Dir::Cache={isolated}/cache", "-o", f"Dir::Etc::sourcelist={source}", - "-o", "Dir::Etc::sourceparts=-", "-o", "Acquire::Languages=none", - "-o", "Debug::NoLocking=1", "update"], capture_output=True, text=True, timeout=35) - self.assertEqual(result.returncode, 0, result.stdout + result.stderr) - self.assertIn("Reading package lists", result.stdout) - self.assertEqual(builder.check_inputs(self.output, expected)["version"], "0.3.3") - - def test_altered_package_is_rejected_before_signing(self): - expected, manifest = self.prepare() - p = self.output / manifest["artifacts"][1]["filename"] - p.write_bytes(p.read_bytes() + b"changed") - with self.assertRaisesRegex(ValueError, "Input changed"): - builder.check_inputs(self.output, expected) - - def test_altered_index_is_rejected(self): - expected, _ = self.prepare() - (self.output / "dists/noble/main/binary-amd64/Packages").write_text("altered") - with self.assertRaisesRegex(ValueError, "Input changed"): - builder.check_inputs(self.output, expected) - - def test_wrong_version_does_not_create_repository(self): - with self.assertRaisesRegex(ValueError, "wrong version"): - self.prepare(version="0.3.4") - self.assertFalse(self.output.exists()) - - def test_existing_output_never_overwritten(self): - self.output.mkdir() - sentinel = self.output / "sentinel" - sentinel.write_text("published") - with self.assertRaisesRegex(ValueError, "never overwrite"): - self.prepare() - self.assertEqual(sentinel.read_text(), "published") - - def test_manifest_traversal_is_rejected(self): - _, manifest = self.prepare() - manifest["files"]["../outside"] = {"bytes": 0, "sha256": hashlib.sha256(b"").hexdigest()} - raw = json.dumps(manifest).encode() - (self.output / "APT-INPUT-MANIFEST.json").write_bytes(raw) - with self.assertRaisesRegex(ValueError, "Unsafe manifest path"): - builder.check_inputs(self.output, hashlib.sha256(raw).hexdigest()) - - def test_public_key_bundle_with_extra_primary_key_is_rejected(self): - bundle = self.output.parent / "extra-primary-key.asc" - bundle.write_bytes(self.public_key.read_bytes() + self.public_key.read_bytes()) - with self.assertRaisesRegex(ValueError, "exactly one official primary"): - self.prepare(public_key=bundle) - self.assertFalse(self.output.exists()) - - - def test_one_release_manifest_covers_downloads_and_preserves_dependency_signatures(self): - source = self.output.parent / "FrameBridge-0.3.3-source.tar.gz" - source.write_bytes(b"disposable source-archive fixture") - original = builder.DEPENDENCY_SOURCE_ASSETS - dependencies = [] - signatures = {} - try: - builder.DEPENDENCY_SOURCE_ASSETS = {} - for index, name in enumerate(original): - path = self.output.parent / name - data = ("disposable dependency " + str(index)).encode() - path.write_bytes(data) - builder.DEPENDENCY_SOURCE_ASSETS[name] = (len(data), hashlib.sha256(data).hexdigest()) - signature = path.with_name(name + ".asc") - subprocess.run(["gpg", "--no-options", "--homedir", str(self.key_home), "--batch", - "--pinentry-mode", "loopback", "--passphrase", "", "--local-user", builder.FINGERPRINT, - "--armor", "--output", str(signature), "--detach-sign", str(path)], check=True, capture_output=True) - signatures[name] = signature.read_bytes() - dependencies.append(path) - expected, manifest = self.prepare(source=source, dependency_source=dependencies) - self.assertEqual(len(manifest["download_assets"]), 7) - for path in dependencies: - self.assertEqual((self.output / "downloads" / (path.name + ".asc")).read_bytes(), - signatures[path.name]) - self.sign_test_releases() - self.assertTrue(builder.verify_signatures(self.output, manifest)["verified"]) - self.assertEqual(builder.check_inputs(self.output, expected)["version"], "0.3.3") - source_copy = self.output / "downloads" / source.name - source_copy.write_bytes(b"altered") - with self.assertRaisesRegex(ValueError, "Input changed"): - builder.check_inputs(self.output, expected) - finally: - builder.DEPENDENCY_SOURCE_ASSETS = original - - def test_changed_signed_release_fails_verification(self): - _, manifest = self.prepare() - self.sign_test_releases() - path = self.output / "dists/trixie/InRelease" - path.write_bytes(path.read_bytes().replace(b"Components: main", b"Components: evil")) - with self.assertRaises(subprocess.CalledProcessError): - builder.verify_signatures(self.output, manifest) - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/tools/test_publish_gitea.py b/tools/test_publish_gitea.py deleted file mode 100644 index f4e76a6..0000000 --- a/tools/test_publish_gitea.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -"""Check the memory-only credential transport without real credentials or networking.""" -import importlib.util -import base64 -from unittest import mock -import os -from pathlib import Path -import stat -import subprocess -import tempfile -import unittest - -spec = importlib.util.spec_from_file_location("publisher", Path(__file__).with_name("publish_gitea.py")) -publisher = importlib.util.module_from_spec(spec) -spec.loader.exec_module(publisher) - -class AskpassTests(unittest.TestCase): - def test_transport_keeps_disposable_token_out_of_script_and_environment(self): - with tempfile.TemporaryDirectory(prefix="framebridge-askpass-test-") as tmp: - token = "a" * 40 # Disposable test data, not a credential. - server, stop, thread, client = publisher.askpass_server(Path(tmp), token) - try: - self.assertEqual(stat.S_IMODE(client.stat().st_mode), 0o700) - self.assertEqual(stat.S_IMODE((Path(tmp) / "credential.sock").stat().st_mode), 0o600) - self.assertNotIn(token, client.read_text()) - for prompt, expected in [("Username for 'http://127.0.0.1:3005':", b"gerardo\n"), - ("Password for 'http://gerardo@127.0.0.1:3005':", (token + "\n").encode())]: - result = subprocess.run([str(client), prompt], capture_output=True, check=True, timeout=5) - self.assertEqual(result.stdout, expected) - self.assertEqual(result.stderr, b"") - finally: - stop.set() - thread.join(timeout=2) - server.close() - - def test_unknown_prompt_returns_no_token(self): - with tempfile.TemporaryDirectory(prefix="framebridge-askpass-test-") as tmp: - server, stop, thread, client = publisher.askpass_server(Path(tmp), "b" * 40) - try: - result = subprocess.run([str(client), "Unexpected prompt"], capture_output=True, timeout=5) - self.assertNotEqual(result.returncode, 0) - self.assertEqual(result.stdout, b"") - finally: - stop.set() - thread.join(timeout=2) - server.close() - - def test_token_management_uses_normal_basic_auth_in_memory(self): - response = mock.MagicMock() - response.__enter__.return_value.status = 204 - response.__enter__.return_value.read.return_value = b"" - disposable = "c" * 40 - with mock.patch.object(publisher.urllib.request, "urlopen", return_value=response) as opener: - status, _ = publisher.api_request("DELETE", "/users/gerardo/tokens/disposable", disposable) - self.assertEqual(status, 204) - request = opener.call_args.args[0] - expected = "Basic " + base64.b64encode(("gerardo:" + disposable).encode()).decode() - self.assertEqual(request.get_header("Authorization"), expected) - self.assertNotIn(disposable, request.full_url) - - def test_incomplete_journal_is_never_overwritten(self): - with tempfile.TemporaryDirectory(prefix="framebridge-journal-test-") as tmp: - target = Path(tmp) / "transaction.json" - partial = target.with_suffix(".partial") - partial.write_text("unreviewed incomplete state") - with self.assertRaises(FileExistsError): - publisher.record(target, {"phase": "NEW"}) - self.assertFalse(target.exists()) - self.assertEqual(partial.read_text(), "unreviewed incomplete state") - -if __name__ == "__main__": - unittest.main(verbosity=2) diff --git a/website/.gitignore b/website/.gitignore deleted file mode 100644 index 70b5f7a..0000000 --- a/website/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -dist/ -qa/ -release.json -__pycache__/ -assets/framebridge-preview-0.3.1-original-r4.mp4 -assets/framebridge-preview-0.3.1-original-r4.jpg diff --git a/website/README.md b/website/README.md deleted file mode 100644 index 35ef5bd..0000000 --- a/website/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# FrameBridge website source - -The original visual design and renderer are retained. The main workflow is -administration of a home Linux network by one human administrator. Compatible -desktop access is an auxiliary tool. - -The canonical source repository is the existing GERANAS Gitea project -https://framebridge.betancourt.one/git/gerardo/framebridge. CLOUD provides the -existing HTTPS reverse proxy; GERANAS serves the website, downloads and APT -repository. Do not substitute a static Git mirror or another hosting backend. - -Copy release.example.json to release.json, then fill it from the exact verified -release inventory. Its three profiles are Debian 13 amd64/Python 3.13 (trixie), -Ubuntu 24.04 amd64/Python 3.12 (noble), and Linux Mint 22.x amd64/Python 3.12 -(mint22). A preparing catalog offers no new download or installation commands. -Use ready only after verifying all DEBs, corresponding source, dependency -source archives, signatures, checksums and the official public fingerprint. -Metadata describes release artifacts; it is not itself evidence that a public -hostname is operational. - -Project media is delivered separately. Copy the approved original R4 MP4 and -JPEG into assets under their original filenames. The renderer verifies these -identities before a ready build: - -- framebridge-preview-0.3.1-original-r4.mp4: - b2a8b0b302063edbe05d84fb6dadb7f303a6f0f1b6d79dc151287df4671adc5b -- framebridge-preview-0.3.1-original-r4.jpg: - 2e867d4b6a22f81ecbefa293a88799b9e3c93f02aa7d1090c7f0a0dbfe44dc9f - -The approved animation and original music remain unchanged. The video is -identified as a 0.3.1 conceptual demonstration; it does not claim to be a live -recording of the current release. - -Run: - - python3 -I -S build_site.py - python3 -I -S qa_site.py - python3 -I -S test_release_catalog.py - -The generator reads ../source/docs/COMMAND-GUIDE.json and requires its version -to match the release. QA checks local links/assets, loopback HTTP, the guarded -ready renderer with a disposable synthetic inventory, and syntax of all three -APT setup blocks. The test fixtures never sign, publish or install anything. -Perform final HTTPS, Gitea clone and isolated APT verification through the -actual public domain before reporting publication complete. - -The website follows the project's GPL-3.0-only license. Third-party materials -retain their own licenses and notices. Support is voluntary; the contact and -PayPal account supplied by the project owner is gerardobh1128@gmail.com. diff --git a/website/assets/favicon.svg b/website/assets/favicon.svg deleted file mode 100644 index aa24a01..0000000 --- a/website/assets/favicon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/website/assets/logo.svg b/website/assets/logo.svg deleted file mode 100644 index 7707388..0000000 --- a/website/assets/logo.svg +++ /dev/null @@ -1 +0,0 @@ -FrameBridge terminal prompt>framebridge \ No newline at end of file diff --git a/website/assets/video-poster.svg b/website/assets/video-poster.svg deleted file mode 100644 index e61672e..0000000 --- a/website/assets/video-poster.svg +++ /dev/null @@ -1 +0,0 @@ -FRAMEBRIDGE / CONCEPTUAL PREVIEW>framebridgeA conversation becomes a workflow.Conceptual animation · Not a screen recording \ No newline at end of file diff --git a/website/build_site.py b/website/build_site.py deleted file mode 100644 index 06a0538..0000000 --- a/website/build_site.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/python3 -"""Build the self-hosted FrameBridge website with the Python standard library.""" -from pathlib import Path -import html,json,re,shutil,sys,runpy,hashlib - -BASE=Path(__file__).resolve().parent -ROOT=BASE.parent -DIST=BASE/'dist' -META=json.loads((BASE/'release.json').read_text()) -META.setdefault('git_url','/git/gerardo/framebridge') -META.setdefault('git_clone_url','https://framebridge.betancourt.one/git/gerardo/framebridge.git') -E=lambda value:html.escape(str(value),quote=True) -READY=META.get('state')=='ready' -CAT=runpy.run_path(str(BASE/'release_catalog.py')) -CAT['validate'](META,READY) -VIDEO=CAT['VIDEO'];POSTER=CAT['POSTER'] -for name,expected in [(VIDEO,CAT['VIDEO_SHA256']),(POSTER,CAT['POSTER_SHA256'])]: - asset=BASE/'assets'/name - if asset.exists(): - assert hashlib.sha256(asset.read_bytes()).hexdigest()==expected,'Approved original media changed.' - elif READY: - raise ValueError('Approved original media is required before publication.') -for path in ['assets','docs','download','blog/2026-10-26-opening-framebridge','community','support']: - (DIST/path).mkdir(parents=True,exist_ok=True) -for p in (BASE/'src').iterdir(): - if p.is_file():shutil.copyfile(p,DIST/'assets'/p.name) -for p in (BASE/'assets').iterdir(): - if p.is_file():shutil.copyfile(p,DIST/'assets'/p.name) -(DIST/'assets/release.json').write_text(json.dumps(META,indent=2)+'\n') - -def brand(): - return 'framebridge' - -def header(current): - items=[('Docs','/docs/','docs'),('Development','/blog/','blog'),('Source',META['git_url'],'source'),('Support','/support/','support'),('Download','/download/','download')] - links=[] - for title,url,key in items: - links.append(''+E(title)+'') - return '' - -def footer(): - return '''
      ''' - -def page(title,body,current='',light=False,description='FrameBridge connects your own ChatGPT account to Linux systems you control.'): - return ''+E(title)+' · FrameBridge'+header(current)+body+footer()+'' - -def code(text): - return '
      '+E(text)+'
      ' - -release_label='Official release' if READY else 'Release preparation' -home='''
      Home Linux networks · One administrator

      Your Linux network.
      One place to administer it.

      Administer your own home Linux network through ChatGPT: inspect equipment, diagnose connections, manage services and run commands across enrolled computers. One administrator, one bridge.

      GPL-3.0-only · Debian 13 · Ubuntu 24.04 · Linux Mint 22.x · amd64

      FRAMEBRIDGE / EXAMPLE WORKFLOW

      $fb connect

      Connect your own account through the guided terminal flow.

      $fb status

      See tools, connection and startup state in one place.

      $fb console

      Return to your work view: Bash and FBTERM activity.

      Illustrative commands. This is not a screen capture.

      Local executionPersistent terminalsNetwork administrationCentral + nodes
      -

      From a blinking cursor
      to a connected workflow.

      A conceptual look at independent tasks, consoles and connected computers. The software runs your tools on your systems; the ChatGPT model remains hosted.

      Conceptual animation — not a screen recording.Approved 0.3.1 concept preview with its original music. Current release packages and commands are documented separately.

      -

      Start with one machine.
      Extend when you need to.

      A standalone computer can provide local tools. A central installation can also connect approved nodes.

      Where work happens
      Your ChatGPT accountFrameBridgeYour Linux systems

      No phone pairing is required. Initial account consent and credentials stay in the normal browser or hidden terminal prompts.

      1. 01

        Install and connect

        Install the package for your distribution, then use the guided text interface to connect your own account. Advanced role setup is optional for ordinary standalone use.

      2. 02

        Choose the right tool

        Use FBEXEC for commands, persistent terminals for ongoing shell work, and graphical CUA when a compatible desktop is available.

      3. 03

        Keep the context

        Return to a live terminal session without rebuilding its shell state between calls. Running processes do not survive an operating-system reboot.

      4. 04

        Add approved nodes

        Use the central instance for ChatGPT transport and select enrolled nodes explicitly. Nodes do not need a second ChatGPT tunnel.

      -

      Execution

      Run authorized shell tasks on the selected machine and inspect their recorded results.

      FBEXEC

      Terminals

      Keep a real Bash session across calls. Inspect text, send input and return to ongoing work.

      FBTERM / fb tty

      Desktop and text

      Use compatible graphical and text access as auxiliary tools for your own equipment. Commands, diagnostics and network administration remain the main workflow.

      CUA / CUA-TTY

      People and agents

      The same command-line interface serves human operators and authorized ChatGPT agents, with discoverable usage guidance.

      fb / framebridge

      Independent FBEXEC tasks have been used together in the laboratory when their objectives and changes did not overlap. This is observed practice, not an isolation guarantee. Use one controller at a time for each shared graphical desktop.

      -

      Free software.
      Verifiable releases.

      Read the code, adapt it and contribute. Official downloads are identified by their published checksums and release signatures.

      • Version'''+E(META['version'])+'''
      • Platform'''+E(META['distribution'])+'''
      • LicenseGNU GPLv3 only
      • Channel'''+E(release_label)+'''
      -

      A small project.
      An open invitation.

      Good tools improve through use, careful fixes and clear documentation. Report a reproducible issue, improve the guide or propose a change in Git.

      How to contribute
      ''' -(DIST/'index.html').write_text(page('Administer your home Linux network',home)) - -download=CAT['download'](META) -(DIST/'download/index.html').write_text(page('Download and verify',download,'download')) - -community='''

      Start with the existing behavior

      Read the versioned guide, check the installed version and look for an existing issue. A reproducible report should name the command, expected result, actual result and relevant environment.

      Remove credentials and personal data from logs before sharing them. Never include passwords, access keys, private keys, tokens or cookies.

      Propose a focused change

      Use an issue to explain the problem or a pull request to propose a patch. Include the reason for the change and proportionate validation. Keep unrelated edits separate so they can be reviewed.

      '''+('

      Clone the project

      '+code('git clone '+META['git_clone_url']) if META.get('git_clone_url') else '')+'''

      Open the project in Git

      Official releases and free forks

      Maintainers review which changes become official FrameBridge releases. Published release checksums and signatures identify those artifacts.

      GNU GPLv3 also allows private modifications and independently distributed forks, subject to its terms. Contributing changes upstream is welcome; it is not a condition for exercising those rights. Modified builds should be clearly marked and must not be presented as official project releases.

      Read the GNU GPLv3 license. Third-party components retain their existing notices and licenses.

      Using an agent to contribute

      The command interface and MCP guide are designed for both people and authorized agents. Normal operation uses installed commands and tools. Editing or rebuilding the application is a development task that should follow the owner’s instructions.

      Project credits

      Programming: ChatGPT
      Original concept and project coordination: Gerardo Betancourt

      FrameBridge is an independent project. The credit describes how the project was developed and does not imply endorsement by OpenAI.

      ''' -(DIST/'community/index.html').write_text(page('Contribute',community,'source')) - -post='''

      FrameBridge began with a practical goal: use a conversation with ChatGPT to do useful work on Linux computers we control. Commands, persistent terminals and a compatible desktop should fit into the same working context.

      Make the interface easier to understand

      The current development work brings everyday commands into a shorter vocabulary, keeps status observation separate from diagnosis, and explains the effects of connection and startup controls. The long command framebridge and its short alias fb use the same interface.

      The agent also needs a reliable starting point. A versioned guide and a brief MCP invitation are intended to help it discover how the installed software works, which computer receives an operation and what a command will change.

      Keep the evidence honest

      The preview video is a conceptual animation, not a recording of a live session. Real demonstrations and captures must remain distinguishable from illustrations. Independent tasks have been used together in the laboratory, but that experience does not establish automatic isolation or exclusive desktop control.

      Open source, with identifiable releases

      The project is being prepared for GNU GPLv3 distribution. Sources and package artifacts should be published together, with signatures and checksums identifying official releases. Community members remain free to adapt and redistribute the software under the license.

      The first contribution can be small: a clearer explanation, a reproducible issue or a focused fix. Review gives those changes a path into a later official version.

      Read the contribution guide →

      ''' -(DIST/'blog/2026-10-26-opening-framebridge/index.html').write_text(page('Opening FrameBridge',post,'blog')) -support='''

      What support can help with

      • Hosting and distribution: keeping the source code, documentation and release files available.
      • Maintenance: investigating reported problems and keeping the software usable.
      • Documentation: improving clear instructions for people and agents.
      • Development: building and reviewing focused improvements.

      Voluntary support and contact

      Support through PayPal

      Project contact and PayPal account: gerardobh1128@gmail.com.

      Contributions are voluntary. FrameBridge remains free software under GNU GPLv3 only, whether or not you provide financial support.

      Support without a payment

      A useful bug report, a clearer explanation or a carefully scoped patch can be valuable contributions. You can also help by sharing honest demonstrations that distinguish real recordings from conceptual illustrations.

      Read the contribution guide →

      Review stays independent

      Financial support does not grant control over official releases, bypass code review or security checks, or imply a project endorsement. Official changes follow the same review and release process.

      Explore the source code →

      ''' -(DIST/'support/index.html').write_text(page('Support FrameBridge',support,'support')) - -blog='''
      ''' -(DIST/'blog/index.html').write_text(page('Development journal',blog,'blog')) - -guide_path=ROOT/'repository/source/docs/COMMAND-GUIDE.json' -if not guide_path.exists(): - guide_path=ROOT/'source/docs/COMMAND-GUIDE.json' -guides={} -guide_data={} -if guide_path.exists(): - guide_data=json.loads(guide_path.read_text()) - guides=guide_data.get('topics',{}) - assert isinstance(guides,dict) and all(isinstance(v,dict) for v in guides.values()) - assert guide_data.get('version')==META['version'],'Guide and release versions must match.' - (DIST/'assets/command-guide.json').write_text(json.dumps(guide_data,indent=2)+'\n') -order=[x for x in ['start','commands','connection','lifecycle','nodes','terminals','screens','diagnostics','security'] if x in guides] -order += [x for x in guides if x not in order] - -def docs_nav(current): - entries='
    1. Guide overview
    2. ' - for topic in order: - entries+='
    3. '+E(guides[topic].get('title',topic.title()))+'
    4. ' - return '' - -def paragraphs(body): - if isinstance(body,list):body='\n\n'.join(str(x) for x in body) - return ''.join('

      '+E(x).replace('\n','
      ')+'

      ' for x in str(body).split('\n\n') if x.strip()) - -for topic in order: - guide=guides[topic] - article='

      '+E(guide.get('title',topic))+'

      ' - for section in guide.get('sections',[]): - article+='

      '+E(section.get('heading',''))+'

      '+paragraphs(section.get('body','')) - for command in section.get('commands',[]): - article+=code(command if isinstance(command,str) else json.dumps(command,indent=2)) - article+='

      This page is generated from the same versioned guide used by the CLI and MCP help tool. Use fb help '+E(topic)+' for the local reference.

      ' - dest=DIST/'docs'/topic;dest.mkdir(parents=True,exist_ok=True) - (dest/'index.html').write_text(page(guide.get('title',topic),'
      '+docs_nav(topic)+article+'
      ','docs',True)) -hub='

      The command guide.

      One reference for human operators and authorized ChatGPT agents. The commands fb and framebridge use the same interface.

      Start with the normal connection flow. Use advanced setup only when you need to change roles or profile settings.

      '+code('fb connect\nfb status\nfb help')+'' -if not guides:hub+='
      The shared command-guide export is being finalized. This staging page is not the complete published reference yet.
      ' -else:hub+='

      Read the versioned guide data

      ' -hub+='
      ' -(DIST/'docs/index.html').write_text(page('Command guide','
      '+docs_nav('index')+hub+'
      ','docs',True)) -(DIST/'404.html').write_text(page('Page not found','

      This path ends here.

      Return to FrameBridge or open the command guide.

      ')) -(DIST/'robots.txt').write_text('User-agent: *\n'+('Allow: /\n' if READY else 'Disallow: /\n')) -print(json.dumps({'web_root':str(DIST),'release_state':META['state'],'pages':len(list(DIST.rglob('*.html'))),'guide_topics':len(guides),'video_present':(DIST/'assets'/VIDEO).is_file(),'ready_metadata_validated':READY},indent=2)) diff --git a/website/qa_site.py b/website/qa_site.py deleted file mode 100644 index 1c31c0a..0000000 --- a/website/qa_site.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/python3 -"""Bounded static and loopback HTTP checks for the FrameBridge website.""" -from pathlib import Path -from html.parser import HTMLParser -from urllib.parse import urlsplit,unquote -from urllib.request import urlopen -from http.server import ThreadingHTTPServer,SimpleHTTPRequestHandler -import json,hashlib,threading,tempfile,shutil,subprocess,html,os -BASE=Path(__file__).resolve().parent -DIST=BASE/'dist' -REPORT=BASE/'qa/WEBSITE-STATUS.json' -REPORT.parent.mkdir(mode=0o700,exist_ok=True) -class Inspect(HTMLParser): - def __init__(self): - super().__init__();self.links=[];self.assets=[];self.ids=set();self.lang=None;self.main=False;self.scripts=[];self.code=[];self.in_code=False;self.current='' - def handle_starttag(self,tag,attrs): - a=dict(attrs) - if tag=='html':self.lang=a.get('lang') - if 'id' in a:self.ids.add(a['id']) - if tag=='main' and a.get('id')=='content':self.main=True - if tag=='a' and 'href'in a:self.links.append(a['href']) - if tag in ('script','source','img') and 'src'in a:self.assets.append(a['src']) - if tag=='video' and 'poster'in a:self.assets.append(a['poster']) - if tag=='link' and a.get('rel') in ('stylesheet','icon'):self.assets.append(a['href']) - if tag=='script':self.scripts.append(a) - if tag=='code':self.in_code=True;self.current='' - def handle_data(self,data): - if self.in_code:self.current+=data - def handle_endtag(self,tag): - if tag=='code':self.code.append(self.current);self.in_code=False -def resolve(path): - p=DIST/unquote(path.lstrip('/')) - return p/'index.html' if path.endswith('/') or p.is_dir() else p -def main(): - os.umask(0o077);pages=sorted(DIST.rglob('*.html'));assert pages - failures=[];pending=[];infra=set();http_paths=set();external=set() - for p in pages: - raw=p.read_text();q=Inspect();q.feed(raw);rel='/'+str(p.relative_to(DIST));http_paths.add(rel) - if q.lang!='en' or not q.main:failures.append(str(p.relative_to(DIST))+': missing English or main landmark') - if 'gerabh' in raw or '/home/gerabh' in raw:failures.append(str(p.relative_to(DIST))+': personal host path') - if "'unsafe-inline'" in raw:failures.append(str(p.relative_to(DIST))+': unsafe inline CSP') - for value in q.links+q.assets: - u=urlsplit(value) - if u.scheme or u.netloc: - external.add(value);continue - if not u.path: - if u.fragment and u.fragment not in q.ids:failures.append(str(p.relative_to(DIST))+': missing anchor '+u.fragment) - continue - if any(u.path.startswith(prefix) for prefix in ['/git/','/debian/','/downloads/']): - infra.add(u.path);continue - if not u.path.startswith('/'):failures.append('Non-root relative URL '+value);continue - target=resolve(u.path) - if not target.exists(): - if u.path=='/assets/framebridge-preview-0.3.1-original-r4.mp4':pending.append('Preview video asset pending') - else:failures.append('Missing local target '+value+' referenced by '+str(p.relative_to(DIST))) - elif u.path in q.assets:http_paths.add(u.path) - if u.fragment and target.is_file() and target.suffix=='.html': - other=Inspect();other.feed(target.read_text()) - if u.fragment not in other.ids:failures.append('Missing target fragment '+value) - for item in q.scripts: - if item.get('src')!='/assets/site.js':failures.append('Unexpected script source') - css=(DIST/'assets/site.css').read_text() - assert css.count('{')==css.count('}'),'CSS brace mismatch' - class Quiet(SimpleHTTPRequestHandler): - def __init__(self,*a,**k):super().__init__(*a,directory=str(DIST),**k) - def log_message(self,*a):pass - server=ThreadingHTTPServer(('127.0.0.1',0),Quiet);thread=threading.Thread(target=server.serve_forever,daemon=True);thread.start() - http_count=0 - try: - for path in sorted(http_paths): - with urlopen('http://127.0.0.1:'+str(server.server_port)+path,timeout=3) as response: - if response.status!=200:failures.append('HTTP status '+str(response.status)+' for '+path) - response.read();http_count+=1 - finally:server.shutdown();server.server_close();thread.join(timeout=2) - # Exercise the guarded final-metadata branch using clearly synthetic values - # in a disposable directory. No signature or installation command executes. - meta=json.loads((BASE/'release.json').read_text()) - with tempfile.TemporaryDirectory(prefix='framebridge-web-qa-') as td: - temp=Path(td);web=temp/'web';web.mkdir() - shutil.copyfile(BASE/'build_site.py',web/'build_site.py') - shutil.copyfile(BASE/'release_catalog.py',web/'release_catalog.py') - shutil.copytree(BASE/'src',web/'src') - (web/'assets').mkdir() - for p in (BASE/'assets').iterdir(): - if p.is_file():shutil.copyfile(p,web/'assets'/p.name) - fixture=json.loads(json.dumps(meta));fixture.update(state='ready',signing_fingerprint='2B1F01BC806C0B33CB6CEDDE52859CEBC91B8808',checksums_url='/downloads/TEST-SHA256SUMS',checksums_signature_url='/downloads/TEST-SHA256SUMS.asc') - fixture['source']=dict(filename='TEST-SOURCE.tar.gz',url='/downloads/TEST-SOURCE.tar.gz',signature_url='/downloads/TEST-SOURCE.tar.gz.asc',sha256='a'*64,size_bytes=1) - for i,profile in enumerate(fixture['profiles']): - filename='TEST-profile-'+str(i)+'.deb' - profile.update(filename=filename,url='/downloads/'+filename,signature_url='/downloads/'+filename+'.asc',sha256='a'*64,size_bytes=1) - for dependency in fixture['dependency_sources']: - dependency.setdefault('signature_url',dependency['url']+'.asc') - (web/'release.json').write_text(json.dumps(fixture)) - result=subprocess.run(['/usr/bin/python3','-I','-S',str(web/'build_site.py')],capture_output=True,text=True,timeout=10) - if result.returncode:failures.append('Synthetic-ready rendering failed: '+result.stderr[-600:]) - else: - q=Inspect();q.feed((web/'dist/download/index.html').read_text()) - blocks=[x for x in q.code if '\n' in x] - for text in blocks: - result=subprocess.run(['/bin/bash','-n'],input=text,text=True,capture_output=True,timeout=3) - if result.returncode:failures.append('Rendered install block shell syntax: '+result.stderr.strip()) - apt_blocks=[x for x in blocks if 'sources.list.d/framebridge.sources' in x] - if len(apt_blocks)!=3:failures.append('Expected three independent APT profile setup blocks') - for apt in apt_blocks: - if 'Signed-By:' not in apt or 'primary_count' not in apt or 'apt-key' in apt: - failures.append('APT key trust must be pinned and scoped with Signed-By') - for suite in ['trixie','noble','mint22']: - if not any('Suites: '+suite in block for block in apt_blocks): - failures.append('Missing APT suite '+suite) - status={'host':'GERAMEG','website_source':str(BASE),'web_root':str(DIST),'language':'English','buildless':True,'html_pages_checked':len(pages),'loopback_http_paths_checked':http_count,'static_failures':failures,'pending_assets':sorted(set(pending)),'infra_routes_expected':sorted(infra),'external_links':sorted(external),'no_external_runtime_dependencies':True,'copy_controls_progressive':True,'ready_branch_rendered_with_synthetic_fixture':True,'install_blocks_syntax_checked_not_executed':True,'release_state':meta.get('state'),'package_sha256_present':all(p.get('sha256') for p in meta.get('profiles',[])),'signing_fingerprint_present':bool(meta.get('signing_fingerprint')),'video_present':(DIST/'assets/framebridge-preview-0.3.1-original-r4.mp4').is_file(),'visual_browser_QA_performed':False,'visual_browser_QA_limit':'No browser or user desktop was operated by this subtask. Root may inspect the staged site via the authorized GERAMEG surface.','production_network_or_services_changed':False,'site_ready_for_private_staging':not failures,'public_release_ready':not failures and not pending and meta.get('state')=='ready','homepage_sha256':hashlib.sha256((DIST/'index.html').read_bytes()).hexdigest()} - visual=BASE/'qa/VISUAL-REVIEW.json' - if visual.exists(): - status['visual_browser_QA_performed']=True - status['visual_browser_QA_limit']=json.loads(visual.read_text())['limitations'] - status['visual_browser_QA_report']=str(visual) - status.update(support_page='/support/',support_funding_channel_configured='https://www.paypal.com/donate/' in (DIST/'support/index.html').read_text(),support_payment_form_present=' 0, "Exact artifact size required") - require(re.fullmatch("[A-Za-z0-9][A-Za-z0-9._+~-]*", spec.get("filename", "")), "Safe artifact filename required") - project_url(spec.get("url", ""), "/downloads/") - project_url(spec.get("signature_url", ""), "/downloads/") - -def validate(meta, ready): - require(re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", meta.get("version", "")), "Release version must be numeric") - require(meta.get("state") in ("preparing", "ready"), "Unknown release state") - require(meta.get("site_url") == "https://framebridge.betancourt.one", "Canonical site origin required") - require(meta.get("package_name") == "framebridge-original-expanded", "Unexpected binary package") - require(meta.get("git_url") == "/git/gerardo/framebridge", "Use existing canonical Gitea repository") - require(meta.get("git_clone_url") == "https://framebridge.betancourt.one/git/gerardo/framebridge.git", - "Use existing canonical Gitea clone URL") - expected = {x[0]: x[1:] for x in PROFILES} - profiles = meta.get("profiles", []) - require(isinstance(profiles, list) and len(profiles) == 3, "Exactly three profiles required") - require(len({p.get("profile_id") for p in profiles}) == 3, "Duplicate profile") - for profile in profiles: - identity = profile.get("profile_id") - require(identity in expected, "Unexpected profile") - suite, label, python = expected[identity] - require((profile.get("suite"), profile.get("label"), profile.get("python"), - profile.get("architecture")) == (suite, label, python, "amd64"), - "Profile identity does not match its tested distribution") - if ready: - asset(profile) - if ready: - require(meta.get("signing_fingerprint") == FINGERPRINT, "Unexpected official signing fingerprint") - asset(meta.get("source")) - deps = meta.get("dependency_sources", []) - require(isinstance(deps, list) and len(deps) >= 2, "Dependency corresponding-source metadata required") - for dependency in deps: - asset(dependency) - for key, prefix in (("signing_key_url", "/debian/"), ("checksums_url", "/downloads/"), - ("checksums_signature_url", "/downloads/")): - project_url(meta.get(key, ""), prefix) - -def code(text): - return '
      ' + E(text) + '
      ' - -def apt_commands(meta, profile): - require(meta.get("state") == "ready", "Do not offer installation commands for an unsigned preparation") - validate(meta, True) - key_url = meta["site_url"] + meta["signing_key_url"] if meta["signing_key_url"].startswith("/") else meta["signing_key_url"] - return """sudo apt install ca-certificates curl gnupg -( - set -eu - key_file="$(mktemp)" - trap 'rm -f "$key_file"' EXIT - curl -fsSL '""" + key_url + """' -o "$key_file" - key_info="$(gpg --batch --show-keys --with-colons "$key_file" 2>/dev/null)" - actual="$(printf '%s\\n' "$key_info" | awk -F: '$1=="fpr" {print $10; exit}')" - primary_count="$(printf '%s\\n' "$key_info" | awk -F: '$1=="pub" {n++} END {print n+0}')" - test "$primary_count" -eq 1 - test "$actual" = '""" + FINGERPRINT + """' - sudo install -d -m 0755 /etc/apt/keyrings - sudo install -m 0644 "$key_file" /etc/apt/keyrings/framebridge-archive-keyring.asc - printf '%s\\n' \\ - 'Types: deb' \\ - 'URIs: https://framebridge.betancourt.one/debian/' \\ - 'Suites: """ + profile["suite"] + """' \\ - 'Components: main' \\ - 'Architectures: amd64' \\ - 'Signed-By: /etc/apt/keyrings/framebridge-archive-keyring.asc' \\ - | sudo tee /etc/apt/sources.list.d/framebridge.sources >/dev/null - sudo apt update - sudo apt install framebridge-original-expanded -)""" - -def download(meta): - ready = meta["state"] == "ready" - body = '
      ' - body += '

      FrameBridge helps one administrator manage their own home Linux network: inventory, services, storage, diagnostics, commands and persistent terminals. Desktop access is an auxiliary tool.

      ' - body += '

      Match the target computer

      ' + code("cat /etc/os-release\ndpkg --print-architecture\npython3 --version") - body += '

      The supported profiles below use amd64 and the distribution system Python. Select one matching suite for each computer.

      ' - if not ready: - body += '
      Release preparation. Version ' + E(meta["version"]) + ' is being prepared. Download links and installation commands appear after the exact artifacts and signatures are verified.
      ' - body += '
      ' - for profile in meta["profiles"]: - body += '

      ' + E(profile["label"]) + '

      APT suite: ' + E(profile["suite"]) + '

      ' - if ready: - body += '

      SHA-256: ' + E(profile["sha256"]) + '

      ' + E(profile["filename"]) + ' · ' + format(profile["size_bytes"], ",") + ' bytes

      Install the signed APT channel' + code(apt_commands(meta, profile)) + '
      ' - else: - body += '

      Version ' + E(meta["version"]) + ' · package and signature pending.

      ' - body += '
      ' - body += '
      ' - if ready: - body += '

      Release verification and source

      Expected signing-key fingerprint:

      ' + FINGERPRINT + '

      SHA256SUMS · Checksum signature · Public key

      Corresponding FrameBridge source · Source signature

      SHA-256: ' + E(meta["source"]["sha256"]) + '

      Third-party components retain their original licenses and notices. Unchanged dependency archives retain their historical filenames.

      Normal updates

      ' + code("sudo apt update\napt-cache policy framebridge-original-expanded\nsudo apt install --only-upgrade framebridge-original-expanded\nfb status") - body += '

      APT verifies the repository signature and package hashes. Keep the selected distribution suite and its scoped Signed-By key.

      ' - body += '

      Connect and work

      After installation, connect from the normal terminal on that computer:

      ' + code("fb connect\nfb status\nfb console") + '

      One central installation can connect enrolled Linux nodes. Nodes use the central connection. Enter passwords and connection keys only in the normal local prompts.

      Read the shared command guide · Browse the canonical source repository

      ' - return body diff --git a/website/src/site.css b/website/src/site.css deleted file mode 100644 index 138170c..0000000 --- a/website/src/site.css +++ /dev/null @@ -1,11 +0,0 @@ -@charset "UTF-8"; -:root{color-scheme:dark;--bg:#111715;--panel:#19211e;--ink:#f1f1e8;--muted:#aeb9b1;--line:#33443b;--accent:#eac27b;--mint:#9dd5b7;--mono:ui-monospace,SFMono-Regular,Consolas,"Liberation Mono",monospace;--sans:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif} -*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--bg);color:var(--ink);font:17px/1.65 var(--sans);-webkit-font-smoothing:antialiased}a{color:inherit;text-decoration-thickness:1px;text-underline-offset:.22em}button,a{-webkit-tap-highlight-color:transparent}a:hover{color:var(--accent)}a:focus-visible,button:focus-visible,summary:focus-visible{outline:3px solid var(--accent);outline-offset:5px}button{font:inherit}img,video{max-width:100%;display:block}code,pre,.mono{font-family:var(--mono)}code{font-size:.9em}pre{white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:14px;line-height:1.7}h1,h2,h3,p{margin-top:0}h1,h2,h3{line-height:1.13;letter-spacing:-.045em;font-weight:550}h1{font-size:clamp(48px,6.1vw,88px);max-width:12ch;margin-bottom:28px}h2{font-size:clamp(32px,4vw,52px);max-width:21ch;margin-bottom:25px}h3{font-size:23px;letter-spacing:-.025em}p{margin-bottom:20px}::selection{background:var(--accent);color:#111715}.wrap{width:min(1200px,calc(100% - 64px));margin:auto}.narrow{max-width:820px}.skip{position:fixed;z-index:99;top:-80px;left:20px;padding:12px 18px;background:var(--accent);color:#111}.skip:focus{top:12px}.site-header{border-bottom:1px solid var(--line)}.header-inner{min-height:100px;display:flex;align-items:center;justify-content:space-between;gap:28px}.brand{font-family:var(--mono);font-size:24px;letter-spacing:-.06em;text-decoration:none;white-space:nowrap}.brand .prompt{color:var(--accent);margin-right:9px}.cursor{color:var(--accent);animation:blink 1.5s steps(1) infinite}nav{display:flex;gap:28px;align-items:center;font-size:14px}nav a{text-decoration:none;color:var(--muted)}nav a[aria-current=page]{color:var(--ink)}.nav-download{padding:9px 16px;border:1px solid var(--line);border-radius:2px;color:var(--ink)} -.hero{padding:88px 0 84px;display:grid;grid-template-columns:1.15fr .85fr;gap:80px;align-items:center}.eyebrow{text-transform:uppercase;letter-spacing:.14em;font-size:11px;font-weight:650;color:var(--mint);margin-bottom:28px;display:flex;gap:10px;align-items:center}.eyebrow:before{content:"";display:block;width:7px;height:7px;border-radius:50%;background:var(--mint)}.hero .lead{max-width:42ch;font-size:20px;line-height:1.6;color:var(--muted);margin-bottom:32px}.actions{display:flex;gap:15px;align-items:center;flex-wrap:wrap}.button{display:inline-flex;align-items:center;justify-content:center;padding:13px 21px;border:1px solid var(--line);text-decoration:none;font-size:14px;font-weight:600;border-radius:2px;min-height:48px}.button.primary{background:var(--accent);border-color:var(--accent);color:#171b16}.button:hover{border-color:var(--accent)}.button.primary:hover{background:#f5d8a8;color:#171b16}.button.disabled{color:var(--muted);cursor:default}.micro{font-size:12px;color:var(--muted);margin-top:20px}.terminal{border:1px solid #42564a;background:#0b110e;box-shadow:12px 15px 0 #1b2821}.terminal-top{display:flex;justify-content:space-between;gap:12px;padding:14px 20px;border-bottom:1px solid #33443b;color:#95aa9b;font:11px var(--mono)}.terminal-body{padding:28px 26px}.term-row{border-left:1px solid #2d4134;padding:0 0 24px 20px;font-family:var(--mono)}.term-row:last-child{padding-bottom:0}.term-command{font-size:15px;color:#f3d79f;margin:0 0 8px}.term-command span{color:#668775;margin-right:10px}.term-note{color:#8fa796;font-size:11px;line-height:1.7;max-width:27ch}.terminal-caption{font-size:11px;letter-spacing:.04em;color:var(--muted);margin-top:26px;text-align:right} -.rule{border-top:1px solid var(--line)}.strip{padding:24px 0;display:flex;gap:35px;justify-content:space-between;font:12px var(--mono);color:var(--muted)}.strip span:before{content:"+";margin-right:10px;color:var(--accent)}.section{padding:85px 0}.section-head{display:grid;grid-template-columns:1fr 1fr;gap:60px;align-items:start;margin-bottom:40px}.section-head p{color:var(--muted);max-width:46ch;padding-top:6px}.section-label{font:11px var(--mono);letter-spacing:.1em;text-transform:uppercase;color:var(--mint);margin-bottom:24px}.video-shell{background:#080c0a;border:1px solid var(--line)}.video-shell video{width:100%;aspect-ratio:16/9;background:#080c0a;object-fit:contain}.video-caption{display:flex;justify-content:space-between;gap:24px;margin:15px 0 0;color:var(--muted);font-size:12px}.video-caption strong{color:var(--ink);font-weight:500}.workflow{display:grid;grid-template-columns:1fr 1fr;gap:85px}.workflow-list{list-style:none;padding:0;margin:0;border-top:1px solid var(--line)}.workflow-list li{display:grid;grid-template-columns:38px 1fr;gap:20px;padding:26px 0;border-bottom:1px solid var(--line)}.step-no{font:11px var(--mono);color:var(--accent);padding-top:4px}.workflow-list h3{margin:0 0 10px}.workflow-list p{color:var(--muted);font-size:15px;line-height:1.6;margin:0}.architecture{background:var(--panel);border:1px solid var(--line);padding:32px;margin-top:36px}.architecture-title{font:11px var(--mono);color:var(--muted);text-transform:uppercase;letter-spacing:.1em;margin-bottom:22px}.architecture-line{display:flex;gap:16px;align-items:center;justify-content:space-between;font:13px var(--mono)}.architecture-line .arrow{color:var(--accent)}.note{border-left:2px solid var(--accent);padding-left:19px;font-size:13px;color:var(--muted);margin:30px 0 0}.feature-row{display:grid;grid-template-columns:220px 1fr 1fr;gap:45px;border-top:1px solid var(--line);padding:30px 0}.feature-row:last-child{border-bottom:1px solid var(--line)}.feature-row h3{font-size:19px;margin:0}.feature-row p{font-size:14px;color:var(--muted);margin:0}.feature-row code{color:var(--accent);font-size:12px}.release-panel{display:grid;grid-template-columns:1fr 1fr;gap:70px;background:#202d25;border:1px solid #415747;padding:45px}.release-panel p{color:#b9c6bc}.release-panel h2{font-size:40px}.release-facts{margin:0;padding:0;list-style:none;border-top:1px solid #415747}.release-facts li{display:flex;justify-content:space-between;gap:20px;padding:12px 0;border-bottom:1px solid #415747;font-size:13px}.release-facts strong{font-weight:500;color:#f0d19a}.community{display:grid;grid-template-columns:1fr 1fr;gap:100px}.text-link{display:inline-block;font-size:14px;margin-top:8px}.news-link{display:block;text-decoration:none;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:25px 0}.news-link time{display:block;font:11px var(--mono);color:var(--muted);margin-bottom:12px}.news-link strong{font-size:23px;font-weight:500;letter-spacing:-.03em;display:block}.news-link span{font-size:13px;color:var(--mint);display:block;margin-top:14px}.site-footer{border-top:1px solid var(--line);padding:42px 0 30px;color:var(--muted);font-size:12px}.footer-main{display:flex;justify-content:space-between;gap:40px;margin-bottom:30px}.footer-links{display:flex;gap:22px;flex-wrap:wrap}.credits{line-height:1.9;max-width:52ch}.credits strong{font-weight:500;color:var(--ink)}.footer-bottom{display:flex;justify-content:space-between;gap:30px;font-size:11px}.footer-bottom p{margin:0;max-width:60ch} -.page-header{padding:60px 0 40px;border-bottom:1px solid var(--line)}.page-header h1{font-size:clamp(38px,5vw,64px);max-width:18ch;margin-bottom:22px}.page-header .lead{max-width:65ch;color:var(--muted);font-size:18px}.page-content{padding:55px 0 90px}.prose{max-width:780px}.prose h2{font-size:30px;max-width:none;margin:42px 0 20px}.prose h3{font-size:22px;margin-top:30px}.prose p,.prose li{color:var(--muted)}.prose strong{color:var(--ink);font-weight:600}.prose ul,.prose ol{padding-left:24px}.prose li{margin-bottom:10px}.prose blockquote{border-left:2px solid var(--accent);margin:30px 0;padding-left:20px;color:var(--muted)}.codebox{position:relative;border:1px solid var(--line);background:#0b110e;padding:23px 20px;margin:22px 0}.codebox pre{padding-right:38px}.copy-button{position:absolute;top:12px;right:12px;border:1px solid var(--line);background:var(--panel);color:var(--muted);border-radius:2px;font-size:10px;padding:5px 8px;cursor:pointer}.copy-button:hover{color:var(--accent);border-color:var(--accent)}.copy-notice{font-size:11px;color:var(--mint);min-height:1.5em}.release-notice{padding:23px;border:1px solid #715d3e;background:#30291d;color:#e7c995;font-size:14px;margin:25px 0}.hash{overflow-wrap:anywhere;font-family:var(--mono);font-size:12px}.download-grid{display:grid;grid-template-columns:1.2fr .8fr;gap:80px}.download-summary{border-top:1px solid var(--line);margin-bottom:28px}.download-summary dt{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;padding-top:18px}.download-summary dd{margin:6px 0 0;padding-bottom:18px;border-bottom:1px solid var(--line);font-size:14px}.aside-note{font-size:13px;color:var(--muted)} -.docs{color-scheme:light;--bg:#f3f3ec;--panel:#e9ede5;--ink:#1c3024;--muted:#526357;--line:#cbd5c8;--accent:#795118;--mint:#3c7153}.docs .site-header{background:#19251e;color:#f3f3ec;border-color:#33443b}.docs .brand .prompt,.docs .cursor{color:#eac27b}.docs .site-header nav a{color:#c3cfc3}.docs .site-header nav a[aria-current=page]{color:#fff}.docs .nav-download{border-color:#566b5b}.docs-layout{display:grid;grid-template-columns:230px minmax(0,1fr);gap:65px;padding:50px 0 85px}.docs-nav{border-right:1px solid var(--line);padding-right:28px;font-size:13px}.docs-nav p{font:11px var(--mono);text-transform:uppercase;letter-spacing:.08em;color:var(--muted)}.docs-nav ul{list-style:none;padding:0;margin:15px 0 28px}.docs-nav a{display:block;text-decoration:none;padding:7px 0;color:var(--muted)}.docs-nav a[aria-current=page]{color:var(--ink);font-weight:650}.docs article{max-width:780px}.docs h1{font-size:46px;max-width:none}.docs .prose p,.docs .prose li{color:var(--muted)}.docs .codebox{background:#e7ece3}.docs .copy-button{background:#f3f3ec}.docs .section-label{margin-bottom:15px}.docs .site-footer{background:#e9ede5}.docs .credits strong{color:#1c3024}.topic-links{display:grid;grid-template-columns:1fr 1fr;gap:0 35px;margin:30px 0}.topic-link{display:block;padding:18px 0;border-top:1px solid var(--line);text-decoration:none}.topic-link strong{display:block;margin-bottom:6px}.topic-link span{font-size:13px;color:var(--muted)} -@keyframes blink{50%{opacity:0}}@media(max-width:1000px){.hero{gap:45px}.header-inner{min-height:90px}nav{gap:17px}.brand{font-size:21px}.feature-row{grid-template-columns:170px 1fr 1fr;gap:25px}.release-panel{gap:35px}.architecture-line{font-size:12px;gap:10px}.docs-layout{grid-template-columns:190px minmax(0,1fr);gap:35px}} -@media(max-width:760px){.wrap{width:calc(100% - 40px)}body{font-size:16px}.header-inner{align-items:flex-start;flex-direction:column;gap:14px;padding:21px 0 17px}.brand{font-size:22px}nav{gap:14px;width:100%;font-size:12px;overflow-x:auto;padding:3px 0 7px}.nav-download{padding:5px 10px}.hero{display:block;padding:50px 0 48px}.hero h1{font-size:57px;max-width:11ch}.hero .lead{font-size:18px}.terminal{margin:45px 8px 0 0;box-shadow:8px 9px 0 #1b2821}.terminal-caption{text-align:left}.terminal-body{padding:25px}.strip{flex-wrap:wrap;gap:12px 20px;font-size:10px;padding:20px 0}.section{padding:50px 0}.section-head,.workflow,.community,.download-grid{display:block}.section-head{margin-bottom:25px}.section-head p{padding:0}.video-caption{display:block}.video-caption span{display:block;margin-top:5px}.workflow-list{margin-top:30px}.architecture{padding:25px}.architecture-line{flex-direction:column;align-items:flex-start;gap:10px}.architecture-line .arrow{transform:rotate(90deg);margin-left:6px}.feature-row{grid-template-columns:1fr;gap:12px;padding:24px 0}.feature-row code{font-size:11px}.release-panel{display:block;padding:28px}.release-panel h2{font-size:34px}.release-facts{margin-top:30px}.community>div+div{margin-top:35px}.footer-main,.footer-bottom{display:block}.footer-links{margin:25px 0}.footer-bottom p+p{margin-top:12px}.page-header{padding:40px 0 25px}.page-header h1{font-size:43px}.page-content{padding:30px 0 55px}.download-grid aside{margin-top:40px}.docs-layout{display:block;padding:30px 0 55px}.docs-nav{border-right:0;border-bottom:1px solid var(--line);padding:0 0 16px;margin-bottom:30px}.docs-nav ul{display:flex;flex-wrap:wrap;gap:3px 20px;margin:10px 0}.docs-nav a{padding:3px 0}.docs h1{font-size:37px}.topic-links{grid-template-columns:1fr}.codebox{padding:20px 16px}pre{font-size:12px}.codebox pre{padding-right:0;padding-top:20px}}@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.cursor{animation:none}} - -.profiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px;margin:40px 0}.profile-card{min-width:0;border:1px solid var(--line,#31433b);padding:24px}.profile-card h2{font-size:1.6rem}.profile-card .actions{gap:10px}.profile-card details{margin-top:24px}.profile-card pre{font-size:.75rem;overflow:auto}@media(max-width:1000px){.profiles{grid-template-columns:1fr}.profile-card{padding:20px}} diff --git a/website/src/site.js b/website/src/site.js deleted file mode 100644 index 3abdeb4..0000000 --- a/website/src/site.js +++ /dev/null @@ -1,12 +0,0 @@ -"use strict"; -document.querySelectorAll(".codebox pre").forEach(function(pre){ - if(!navigator.clipboard || !window.isSecureContext) return; - var button=document.createElement("button"); - button.type="button";button.className="copy-button";button.textContent="Copy"; - button.setAttribute("aria-label","Copy command block"); - button.addEventListener("click",async function(){ - try{await navigator.clipboard.writeText(pre.textContent);button.textContent="Copied";setTimeout(function(){button.textContent="Copy"},1800)} - catch(error){button.textContent="Select to copy";setTimeout(function(){button.textContent="Copy"},2000)} - }); - pre.parentElement.appendChild(button); -}); diff --git a/website/test_release_catalog.py b/website/test_release_catalog.py deleted file mode 100644 index ff182b1..0000000 --- a/website/test_release_catalog.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python3 -"""Catalog guards and rendered shell syntax; no signing or installation.""" -import copy -import json -from pathlib import Path -import runpy -import subprocess -import unittest - -BASE = Path(__file__).resolve().parent -catalog = runpy.run_path(str(BASE / "release_catalog.py")) - -class CatalogTests(unittest.TestCase): - def setUp(self): - self.meta = json.loads((BASE / "release.example.json").read_text()) - - def ready(self): - meta = copy.deepcopy(self.meta) - meta.update(state="ready", signing_fingerprint=catalog["FINGERPRINT"], - checksums_url="/downloads/TEST-SHA256SUMS", - checksums_signature_url="/downloads/TEST-SHA256SUMS.asc") - meta["source"] = dict(filename="TEST-source.tar.gz", url="/downloads/TEST-source.tar.gz", - signature_url="/downloads/TEST-source.tar.gz.asc", sha256="a"*64, size_bytes=1) - for index, profile in enumerate(meta["profiles"]): - name = "TEST-profile-" + str(index) + ".deb" - profile.update(filename=name, url="/downloads/"+name, - signature_url="/downloads/"+name+".asc", sha256="a"*64, size_bytes=1) - return meta - - def test_preparation_has_no_install_or_download_claim(self): - catalog["validate"](self.meta, False) - text = catalog["download"](self.meta) - self.assertIn("Release preparation", text) - self.assertNotIn("sudo apt install", text) - self.assertNotIn("Download .deb", text) - - def test_three_profile_shell_commands_are_valid_and_key_scoped(self): - meta = self.ready() - catalog["validate"](meta, True) - for profile in meta["profiles"]: - commands = catalog["apt_commands"](meta, profile) - result = subprocess.run(["bash", "-n"], input=commands, text=True, capture_output=True) - self.assertEqual(result.returncode, 0, result.stderr) - self.assertIn("Suites: " + profile["suite"], commands) - self.assertIn("Signed-By:", commands) - self.assertIn("primary_count", commands) - self.assertNotIn("trusted=yes", commands) - self.assertNotIn("apt-key", commands) - - def test_wrong_distribution_metadata_is_rejected(self): - self.meta["profiles"][1]["label"] = "Ubuntu 26.04" - with self.assertRaisesRegex(ValueError, "Profile identity"): - catalog["validate"](self.meta, False) - - def test_duplicate_profiles_are_rejected(self): - self.meta["profiles"][1] = self.meta["profiles"][0] - with self.assertRaisesRegex(ValueError, "Duplicate profile"): - catalog["validate"](self.meta, False) - - def test_extra_shell_characters_in_key_url_are_rejected(self): - meta = self.ready() - meta["signing_key_url"] = "/debian/key';echo-malicious" - with self.assertRaises(ValueError): - catalog["validate"](meta, True) - - def test_missing_artifact_checksum_is_rejected(self): - meta = self.ready() - meta["profiles"][2]["sha256"] = "" - with self.assertRaisesRegex(ValueError, "SHA-256"): - catalog["validate"](meta, True) - -if __name__ == "__main__": - unittest.main(verbosity=2)

      v^cf(r3~5}R7o*tv{{6fWM#tIWn`(hSLIn2ka` zBxlGxsIPdQ9^9>dD08Kouj`En{4-j{vw}gaS*MfYT%KtjV3lZm=%>DrSazo%d>B(0 zFe^=;?~@C!&cAmU7rW$Ctwpwfn_PH#K9$SKICC8q&iqEkn5ZMWP7yDCft_0go z4yQV?Cg_zAuOp$Cc`6RFiS}e&kT2z?x|WRx>46Yr)0Fl@0|nA%&On(O;El+5@^miuKIgc7#ajTLTBIGw0s(GeaW`Ci~zLK>TlF@lfHn~0i!cs-LxBeOG z{CF}Xrfov@@D6WdUUEh&O&LzY#4wgyR&hEpEF=s~<33Pp+VmJ|lA?k znZiLM_<_3Ir?cZ_0D+n!!_-vRc~2VFJ&H_LvFazb8hbYyZSIxW9-FV&JppUZT^JYD zc=fV5cS6MNj=tCCdqS2VIZyy{cB1YSj|YKk<4UeI z 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

      X;eN?9%SN%43SBVykqhZIP#pzhe~@C zK{F&mr58 z&FC#Ck=7pG-&7*o4JLi=M47x362tn5P!?!jnGEIf^qev+rBzlgJ7w{zjpgzPnKc!% z(^j6jQ6W>N^USE}vKt*9HA9Aa^GxXs3G;r>3>neO>>S2Nd4JzoGNPB;gjq7QkRe_< zO9rbL;;pmf9v1f8d5kugGDTOs zcB$l2Eg;T@nrTn-Dw(W*alKZzwQC%x*VnAo@+rL&oLwygdMoJFAR~G&C}@x!^-r_D zfg>BZi*)_tyarLI2Rp%vwK6UfY+5U|!IBN@W$+rybo2%pT*1;gyg|0pt?au|2A2`v z3Jr5T`G=ciyOVtIwr`fnjo`V>vJVq+eVYuerozYZ$d`+a+T^ z>YP1La_K}7n#Ov0AKi<1D%gKN23uM71z`6|Q%nJ~h?gFaDeGwT<^wXhsDcgapmY|o z157?FBXz_#9Ff*a@c2;(rqp`{)O%F!am@FTUU6L7y4>3P%AJh)#_on1PWCBK z7u%U>gwB;CCYWhB$HCn_3{_jk?<(6+`Ujic%kXa}eQ+;BKYpUO5n4&KrjPN3{uV9j zYXtPiXmek~KZmIqnqwpkWbh~D7>8-xpaDjxisCZ|7=iI*uK=^b9RrN$7K&XOU^ulj zx_q#au$Qmc;=x81kJSw|Ld86`X{f>7SBw~LgoYBGGQtQf;8%2NBm@~fbk(Dc#Dg?; zf3Bf+fV=YyyMgs}V2q*G6JI^nP%FT0`9`#u2d{z0S@z?`8O~z8z{VNLy0ayPMyLp^ zDm1pqkp#{b8TJtHYEjJ4)6f#b-;L^m}7*tf%E4Y{uN;BT*K1e{2ucRy+M{%8==`G&#N{j5#2YR&JeAwVNh6S zSqls`mod&-Eh!4jV_H=McospgkuC6om zm1yr$!#{*-&v4M~%eI%h%uxM_pIdG?W2yee@|e}aMfFDLDumm0^$^fG&8#v)M~LP& z7?EahYJG0>i0i$9@K$_>uiaC5_2DU?g6c z$QAB@foQ?RgN8kb{>?mSL~rl~DL!N<{Uxb9#9N?R9X6sRL`xu%>#cFnQ9~W$;d3oU zv>)j^jv4kQ;s=izN^dJyj~UT?w)EY{4OK?^8L$X!1#`jaCyeMJzMBJ28p*?n?>l7# z3h2YI)BFHSsPD9)j)IkEjrbmu2#30VjhK&KZ$C)OIrqW;3G5Kalue8d1GpbkX%6yYE`k{O?Eq3zZCf}XZmT_k66LEc<8PuPMy#;2V zc06-gU`ETq>Elg%!Fae2_5qrxs%M@QWqRK*;LgV;Al)XAJFlMFgq5MnQ}zA z`G$^PE;pT=DWp#^`^IYSQ(-#eDtKjuX&(UlO*fBA-Ik#<+Fmt(hH1B;S+Zk>dB?n& zrmUN3en&T98cv`ZW|^{fmTBvzZ6e-Eyl<7MW)j~5>hxoCOndZPQ%;y`+Lhq^xoyv% znrkNLE)1M!+T+18a2}XdZQ6sXO<7cJI_nmjat`q(;>*Ex;Nfc1%AQY`=bNe=+y`D- zV#;$hrgfvnlw%f{O1EzujD_-rrrZeb1zW&N;KD_wy_)>9I4IH26)mPb?^&|gv{r-L z7n}BB@C?`r_E}=uBPdq@P679VXTe3arrl6WIj|KRT4$;SsA5d6Gwr!`rd(NPIjO<)y+TE7Z&gJA&Zv6^Y6nF{jyAsV69Fg2uW6HVpEXaD^yUJAh`H8DcYdW~3 z0Y*s!Guy!OrCjbBQx$ABWi_bd$3Xr3!bVoWR#R54H3v$)6f)PF={+_v0PEWtlC#nL zi;fp=G8ao-!|cswoz#z9*wXE%^m9K9s_`8q!8!3 zFiu>E35!#%aEwoQfS-=O8*4f0M|=?Kzo+jB8znSWx#JeGEk-wt`hF+wL}u(i>@VeC zZlkwB>;BMz+p$K5rdwi!VG+(V>i8v7Z@H8u@+O(UGb$A}NxNMsqRM?AG}3%Kd3lOx z_Wglyi&E25L>4B4Qbhka&7y!&J1vEqc7Ug@2BJK5F{lXl2xn!0b5bHD>yjN(a#Ea0DRN9or=h8`K1FR!k$Y1fB0Mrk%B#tU z)K!tTE8b7hqw$))(Uef8^S2}=l6@knFSX*MpnsaoPP;XNdYlq4n4?cXSq5rvvcEBd zhua7Tt$F{A@M{+PWtJ+fH zFjj7+C7}w*6S?uaj-`?guoOT6J%VSs)7 z}t{m~WsB-O~ z=ur1&dEhZLt-fCS7;=zz^nOfC@?AEFY>rFo{+L)Cc!}_#;15oA5!*sjB}qHu6G-YA z@sYGT@>_-S)u)R%djEeA z9{zx$$Cn?_x%(cpNICRi27~rch~)JTIgHJchkHr9d0u-YnaG4klh)JzM*}lx!=p(B zwExi{MF)4W^18^yU944IWZmOx>*I3W@xVP0*RFg1n(f7Iz_;XC*2urU1KMyjM?%>wj1i#Q==FPeoO|CE zLmZbVx^CxkW5@&lmn?}B`5Wi=evpmZ)}JptR4$jI7-9d|dh~{0&X(dssJJ?=<@jSt zhE}}~9ZIL#he_J_2|h8z4)pM2^}vsd#47s_jXp8a>)-E)Szdp+BWk_=BVI(wRS%yy z@xG~XaN)>5Y; zVwa@|7rKMFXlZ$zehFfPSDlZDRZik|Y*6@gZXdrhI|0kW4k-;PhzquYI5iFv7jX;e z%dz0Sx!Qb1GG%H)0m`2XrH@Mx^TPM)r{a@&sxb0kQ$+5HsF8{CQbhGikcA0qdV*|8 zP*)OUW};3XnE37D({0y#LE9GNpQtAU31`weu^jc1OjwKfg<+3`1Z`S`rkbYJy%=*P&B z{ap84_g(7|2O7Wz^D59~S0!ykGg*kXybGRVwu8xyEw)z5N6H5y9P50030KA?H^j+RamYR`3xswAzR`e-^%E@`ns7y) z(k9i5ES2wuO|Ka>vEPNh?V-9p9vSDDm>hC)sXzX$`1M_}{9EC?Izuirp0&0liHoMq z2Y!`pSES-`$eN4+La#j}g}v!b!Uc{sHvzlHn3jR1Xkn~ofKQhx_gPmXqS}{j5UE$z z{s>m?ofFAoSllC|tdFynbC`*<(9^jTXO*H86tE7kAObe)ydan-DYPhLdxou=2p){B>Fh1>R%rwUA!~dDXVup31ko*GjgE+c z5#6FA3HF5qS&(Q?jmo`=*7-zvJ<%B!mA#_&=%^eY)#+QJ_K{>cB*`jDlI2PEf+RUJ z$*xV3tCDnjbJ8^*KCT-2nrjbS@tCy zYrD1q-Nr|aLjv-m{FRmy3Z1o(n}dPYY&vz8IKkC}RctB3{~`vd-{rijMw{a2dJGsR z?CIl)mnRCPy;$+Isz;5=vTBtW<<_Ec-EC(&s#bP4PR2Pt1>$NF{28S3u6+6Tg|uSRQL5mLMe^i#t@vmGw-#<_#@(^&7x=#kI#hX}9otCJjb zm9s1jBlLmssrVh!;ljAUxKwd4PKWyh)OyMUUgA?3_#O$l!OL`FXnd$!s%VOLMy85A z@tTD^JRwY#(-NFZDOdqjTq~9(C~`L>R6rxiN_B>$$`NU*I1Ll2|5e;hj=k+n9g{~| zNwq7D^rM_n3ob0L zn$ulbYw?b%V1$c-;S9nUFIpDHeWcSpUS1C0YB6(;Z!=zZMh>%vItUZ#v(7qiBH=?` zI5)9%pzA$H`Z?qMY8$x-XRgiOrmstfJY^4r$5$tO}5+UJF)4%W(GH_mf1iYX~|FsR;Mu%pawZN`$Bj=~GwGk6;BL|?ZV;$WL_jB_t>(q;Hhf7=UjqOvP z|0wxt9G+f$(}M`GK6o{N&Fde)rn7W#vBfvFH5Q!eeiqibJ9s*dbCDvi+z!K(-(&|a z<6Oq;+Y~_OFrU{SavXe6oW>XzP8n2ylEdOM@IEmwE`#(vaRI_75-oSC(aN<>ny~G*p!4&cI&;+i~8xtZ$Y2t9gMZ&vNB0P2} zCBkEaQzJY!IW@v#3sPTTD@aS<-d+@@A(N`zTOV)#Z6lc9=TWzYDJ_EsJjh&y_j@?O z`UWAbWI1O&qPyGKi@cs23D_NO|9q_OyYC%mvyQkiFY&Y^xZCq5-9Ih6h>|`3VLm8X zX0Ql<31&v6gPE55S!bDUhxAcyMVRwRqZgC#=ji(cr+uv>7dxCo=KDhHecv`s@8NL* zIgrooTrGn2jXY>v%-&F_Sf{amZqBXd<*$eCO?wPT5px((u5~7+ng+SlL|cq?F$)MV z7260fJq`K6QWI>9(P1{`jD_=g7N6b?WAFT%5P!1~cJC%xiLtaG;eS5!#O6-R1`U&c z+lQjA5xnlOrzG!pM1Rvqc&Yi|D8E?ZQkNXP%ar@X3M*LX6WiRavae5UweR47WoPj0 z1aAfY7?6ZzM;auj8-z*^7>KEFcRp52;1RUSi zyh|Z@I)tkU?QSBts{$J|?ha#-0?tBYO-HK(p+*27TzNooM9nKT#Homy1&mJo>2!Xp zQ=^H+h&Yzm@k8GjTGjX?-|8ub znEMk|z{&XdPm*-;u|EyhP_Wy}&KUBxzwDeQZ`msj>@jim)kq0>D_=Y3(nW{78@T|- zXVtsk(Xnyw#YSi;zVh&E-S_=itnz);li2DHuEw6o{WvlNLc@%YSI5S-{#W7CRB-86 z?@c9j?WbChZoqGpuC461;T?sB81Py0d|={dTEepA-*?6yEB#M(9x3sb|GaZPVoRt0 zkZ=Wh)V@DnzdoTWDfpkr8A=@ZpTFo>(ci*5iEaDatXNyNeU*9A2l_n?BV=d&o?|0rbT{L=YLxt`j*meULr+)bXt^~uM1%5V zNWY*YPe%1vEg`N8Zpo9KGfBTVMn*SK!Q`>>&%Jr!tb7@6CcZphu4AM}706d(??E6# z&wu9lws_Nc1T=^ryBR-+gvKBqn=%0v5~{DAAXP4w;rn25V<9VSe38sJOnQBh43!Z- z4C?$FMbgpnsU@IKwXCX*+TJ+E9g#fE9hG#MF4 z!s2PrT4EiZE(6E-@l33gk-lV1m?3T5;EEZtlg{rwOYXCD&8^ka(LK(sL0E!M+G@chv=3;!u|8 z8kCl(w|1@c>z2=6FD<>_EJI^M$Iq{qk?F+eY>%W4kFyx5@kMMh&AzqgP`oFCw0KUPi958SFXVHj)!BN=t7URTpJmYy<{f z!wQ)G+3&y6R^mEe8U5>9iMWRTd2jD-M7n{QnZ}=W&3k(oe*G(4j<|;Y8JD3ir+WQ}-MrU9X+u93!^#SAlvBtOWJkZ_hCz z`ol1-pAj4JrTvVEe*dL@M)FkBHxGc@4ITvbnrRvc*PHkOP{-E~GE^4vy`YY7#%PJ2 z;Uj|)FCjj9h>@u4n>mDb(ZAkkeT=F!WYKU#RgE{~n&F1MeYhb9jWE>mDTW+6vMqnu zD8rdB%8;u@83Uw#;M{1#?w$+fBiFFkfZ2$I49PQO6SyB7foRBtGD997V|17{){u3G zi1aTq&x^oZaB99`)q@*3z`O)&1#@7qoM81buMZ{j17I4J^aikKj9 zEAfM1S+QZyDW?6!Z5>Ah#V#+w4h~ogZYeQTNh$4}!~{&jCfFpy(c^Gnl5v+#A6(Yf z-|6MXV5vv$@)YB$85^nT24pk#AtPx>4Q!b?hBb>L>Wn$Y{Tsm2xyCT5H>{d@2KxG< z?|dVWPx^%UhFvk=kW*?5tE%Q((@py97RB}slH?QQn_LOdG__!3o#GXojUJN^j+O0~ zdk~F&X^BVdusZg{t+M+gtzqLJAwSaNkTAouU*>xyMCjYjSuwuXMt$IRJw36#IOOTF zFCBVjLSwpUvPaRf6W(-EhC5Eb_ITmaq~PKHRj$qWISGx$akZEq?$3vOWz^3To1&WJ zQJ#E2lHV;Yk?av^2xW-_>FP?l#5v42Z>B%@-;{f=w9W>^P|m?i0%D36nHL-bbTdf1 z5|>EQpnxXVQ~oJ>t$Q9iV4(z{mRRU6B~HNiwE;2VwBd}mAm=BJv&3K%x#qoQ5UXRS z&3=5I^%%8sWz|HLIvL;FE5;dPWq&W$NPI)Q&?L1W<_YUl!Z{xM6burN+HZ?39=7+k zXVV1Kqm=GOu?yWx&k-aYjQA5s2*%{8sQV{3^%|bSRpT0YH#cw@Aedz=p*t{OdWEzx z-wRse`7)!`Gw2*e!7ykY4vN`9KMGizg8}?09t?6NU_PQM>E-Y zmRp_SLyqEt0V8OM>A==reY;^t+JP-Oo|q=v??QOY2q9Rr&bY}dg1-{AODyr|$5RTklNVs1QNo8@heQ;s&E-^iMU6`zQwF#PNpcH3Di;N3kLEMvcpXxPdq0fLO`P~x zh>xRiCjZuhOg#qAVq5ol45UUTyT#X9WoU~L;zYf~R3w}3%;chgCzkAy{dx^ynTOd>XqSO_KC)NF~IPC@0Qk(oRc*5uWI5ZCyW3o#fsX>SPeMg;RsGo%G|ZkZ7pWocboQWl#}kkZQvu<)i@ z&OA%bu~?elTxs-JrNrznCtT!{z;QxT{v5*12BgHcdA~nqNHbDwq1P9>;lcuwL->N> z>~^8F5XfStEG_w-e;d`DdIRD&nDL$@2XPWNI_kRgoqZ5XZIITF z-I1R7F?2hVecDIf8b@sQewQ*M97XOVCqT*hm}mEimCpXQxz+l@@GALN^ZgLnAfso<`6%tmo@)2 zwBChRMu(KeuE1uO)TspkO z<*aeZ)vkY{d&T%0S{G<2mJ`@}3^mz{m0C5^3!@FLgJ^VxNI&3;kbcAU0O{l0I%T29 zA-vCa28J&Pe-`|buMTHPOD4q zcHMfC@qFtlXL0PU8g>@6G(7t`FaYfn7*KOX2(NP4O0%LddBJ(qFOxY1HP z8R{v;kB|wEr9lL_!R~p(yn9|dXl+?6;EC?Y=`=j; zd(GIWk7^c170Ijl+#>CnWUoyVN0azw-U~%!*KG=bLZ{^~1x$s{5NzhMy!{6|auHA%;XgB|JVMZPuIk67Sml zhNy^UOnwXdQJwm|g%@$B{tYoL*&$^@N`#WjQX(|va!Q0ol&7B2jhK#SvNuFwhx@m` zElzi+GDsSh(V_Yk(XFF?=kbmmN?s9L@1Cg3mUeDG^$oG|zToIL#Ps_&Ns=lbNE`Ns zxc-1ec;SQ2z&G%cK=DUS@wi(THTXf_mlfn#+6sa&hK^_@tP=m+G%}NtbN)crS2JBCi{D#^RJ2--|L|p zv-}74u2;q7AA~2rDz-kGc;FSW`MFNrUlo(Os-v%n9bFw#raZ6PRrS2R_7!pH`6%K3 zFGT3uq8B3c>g)?TrQ$_<{3~Mdi@LX?UrHPEirD?59Np@PKXGzj5hs4)41Yz;`l&PM z6>;FF>1W>-eO}IBtfsvjqRh#c)0e+3N?*Bi#yj%(E9%-Svd60q;mp_6;Me5n*WM+3 z{WaC^bvf+y;gU$h8*29(^5h%(fzfZONpH#nZ|>0<^=~^(Z_5jBJDKmu{C5;7W$)a6 zRtgF3QT+Fj%e1A2XZ5mU-C<|-*~F2S*eQQsY9UAR5iAJPKBslg9TMi5FQZ`QvI$nW zY`z_HTsnD;D}!e)x{`-ja?ovGD1L{Xw#xrr%?->r%j;^a$Q4XASZfH6!x#dF9Bj2m za}m(A)$d1+AlkmKAwDdX1G!Wfh@xn|F2xpa6ap#)|k9aqe=?OD^wlPqs>% zVB2P@&pMskjI8s@FJELsmkuw?H0*_tV+?KZWQmb>!jQWRM0{?2i?p6R`x}B;Sis?q zCw~UH-EcV5a|O9oFs7THDIMfD`pK^PnBwfk42-<3i0%jeAgJn)v<3(CtCyh#Zv;z& z*tCQ)yUmEt4x%O+L}Tr^%kG7@dn>+M5U(7H@Hn@<5w$u``Yha2dy+=rGdj+h&Ur5o zm>A-#qxsRXvHH$U^A6#|7Vr2kXtQ{ov(Wa`)Uee{J0?ee|d1iQ0;U4Vr1ZM}}f#@A_mgDg3wz!lt0o=9e zlGy>BGB5zypsoHWTy8EY(z=QeuY91JOVmq!TGC_kSeZF&UnNww;n_NY>fZLevXhy`aB84z`?{17LsmF3uUxEsor8o zNFUnuXAR#dE#YSOaKXQfaL(@Ka)!FNxZA5;a+1rgbjf)xhj86(QcG>B;pYj6;ibZa07Zqw=?gnn+JbhyQ3 z^$Cid_%nj_>b4FB5ukhw863B>5ohDJ(xwq?oA5>3V%~GT7OP@9b|P6DUaNah?Dkr% zjI`If9?({t;n@^9*5!bxcC3pqgdFR9Kpb)OZKs>hIvv1kwRJKeruwYo_#*dNEx7Ua zSw~Rv^jS*-qOadt6u@AKwSd*-x8?^#qu-hr5C{F%9Lg(;d9GK8d1S@uMh%Ly#^Es? z-s}i-P&NnT(xBZKl$(S0-k{ta{ML9uY|c8#y9(R^SP0YH z`aE{ZlRnrM!)ymLrjzh#Ys<>pOy%nJk@#YJg#U}>9fOfMH$sH_ncx3r{*#4fGz1Z= z=q=&e|BFcop8tjgY8SxeR|q1Bia2{fh!#U`6Z?XJIU#&2ex&D9?N|;A1|&iK zn~dA8PZ4Mu>_V3p0q9#dA?gm77!Qr%v}7pGBPWdpcdT8SCx4iS4@>_TR1M@R!u(Ob zW6ZX=eGQRz2^|GnAQs_#Gecjr0^Il3nK$iow91Fs*3g!e!z89{4)W{8Zbg%;Q10=F zOO{@W(>)<_mg5H-hMVWpZ{G3HO&;1riRSuMqef!x^=Qo4%|(~4ailv!Muj^$~gb{V;UgEe07uB)SR=EsW5|RcchZS@v*-b-56ZAha_Gt-!9SXW#VU zJ2wwGHVW9;W;y~rO{Oyf+sH15l%cK<+0|U}BxhrLTmQA@y)9oUl?uISz5wV=H_6Q= zm#i8qGz@R)RuaZ~wz?IUtgHCC_Tv(mW1pDf^KVqh#{3=^J7bhxqGVQ_Dvpzb;<$$2 z_6>kvJlJ$MhS0Qj*MzW?(a1!vbX0aoG&x$Nr?1~084@G?0m_v4pJj{p2Pk;KujO0U z$EmUq?u8)KiQXahS(zJhN{eN%|B>jbd`B8f9bqCQ^j50=Cs88MajT~=BRy?2~L%8f{SU;&Ws(J#ru!9Km8bNg?_u}|4m8-_+VX=pdETK#hPWm_jy;q1#sC9J zt|FJd=a#xyko~Q@Ntj`A6{5~A;*vgYn`*yTuqiLo*OhxRHDi7NubAQPOn9ezGlM(R zs|YXl>NU;2|McBStKHZN3e~&uprZu}rVL9>lN z6uLx_=AfR8UD)8Gk^n;!8!L^se_-fmBsO*qgy=79zHnLC7mM{j^qK=<50zJrA7!z` zwy_L--+^v4MA|p72YFli|64r?u`9n*qQAX1L%JTT?Xf1e=Jk`ZhisHj%@1=3a#~pD zM(U<8n~@^C$z@**V?e({QJ9ah8W|ST-Kpn8Vzqk<^HSufGhuDR;8cisAu%YVNU6gQdswas>l4DQ-<+l~>F>j0 z>09j*W6>$Xo{_1KFnUcyaf^VUtV~#eoPeQFiK;h7ew)`ue+xpJT4`vv2~EcMZ}Vyi z)yfo_P99goCL`}=UVMxUWOIW1g>S4BpAC$qYyS!3iZ$MULY8*x=YD0dd?Hs0fHMzuKsO zvZ_8#Z1L;#auub{6)LLhSIN|q85g03yf{DM(zpmu?Th=Gt>ZwzIUSI5g3l4Y68tB7 zD}xN#+nC44tL0t}8O|YG$h*|OdzmhELi9_L}*)ChX4G%VpoPvAJs8HdTGbN@q5L}j%rIsIrMH-c(>etx3i&>th~pW*;%f? zM@{Q27j;skZ11EJA-Y2(pe(v`5r0u%=)dvA@m=PGEJq20IEV0=YM;P~P zS1fIIiQK+!Yp`1uxSe{pob3K5x<%suI0#6zNDGF?XhVl5=<9cEJqF(nz)vid7H5X3 z+Bg|&H2BE}+w}#*g3sH__}^Gs`(haw2Axf6TIhNsLb%Xn?bW8b^shZurt@JLo$nI` zE`NU?w4q3|gFMT33fb5^)y90+Y89cB1a${{QeC$BM9x6nq0udc}tPf=+@r<&b!}1CczUTVXr5Wi31!@hPJii zwTFA5V&D4q$jYOVQ^!=juO1`EzRj7r3wtjin7UyTl%%<7DuxokKtX~9X z{axgK7#a74X#Oxwk7n^l{)(@~?2lB%-$n0F)POI<@K2ojFT}V{oJC)Vg`Y&q{w@Z6 z+FhRdQdIw1o&Qp-_%-z8fxmfygiF8GZ^-@3zxy9z)@M3A{&#A~*J8}S|8MWF#qi%p zj(sIce}9~%G~y4jg)r$4v01PDqssh3tooz6@VRLDqdNAvxb#OY+MV^^YTxH#%zvvb zpNqQxR%<>NEB~a<{9Ww(lWO_9xcVp6OdJ2q4{yq!gLE#@k@4yf&;uE3U2j=Z-hjPx0N>@RaKIDN&?X} zR2{Z=h2`$}->r?v6_Ia$;p{`PdowNiN24(_AjY{mjtF2rsUw&BwN^r19G4F@4N*eR zGKQx|TqHM6jE%D=$I0S2{ZaX*E7ZfewH5>4B+iz>Nwfuue>`p!9KtKjAd;WgTuy$x z*l0PI!deRX3UaBQ$muW=S4BKE(QBOyi=Eye=@Xqh*Hgx)2-o`}nPE=tYCPSJb4VW_ zr_&qbBKt$w$kZtVgY8*J!4NO34Mup$j$nu)XM&L_@f^iQlC^bSwL2<$Iciaqk1s65W+y@o*PRf>hx$SkFZG2ejss9! zj%NDxp=Xgwr_64p`JS@_`i*5lXCMwtLr$+mQ66%5;cC3iCW!6f2$~$15}a+xazxag z5S9IsmPsP(lmBUcwGT9XTbL??T&Z?qn*n)nql6U9K9SPkvaq_h-o@SEk}HB1C>B7m zd$r!O_gQk=Z6>ssV{J2y!#n?xDLxFODjbaFyA_T^%VG!fOmAc%E=PU#JfB?Rvse3M zy^o8+%~jHxw*w2z62n=DV9MlPX!MxA4JlX!wb65#;towo70tFfoQwprI+!f7d}=5o z<+so=o#OA%lq6=VG)8T$;xs5mg;aC0xD;|$qx%ydIG=>(k{W<}lLX)PBvF=-T&J~5 z|H$tq(K;CwO^G%MdlI90NuqnyH#1q(MAi1FxE58DQe}RUJt;|6Bsqk4C8<+M@=}r- zohoaR)r3^JDfz+tRM{itKElgUMopEcQXF#or&_~O<&f0dm~yRo1#UUojWVuQ$c@bV z1pgXv zHWaM=Sd0v(=6x)>#Vb@|bi-Fx9vQQ2N) zek%H>tDV0Rx#{6EzY>ExDB3WoLsIFl#MC>SS)YhGcZBzRBI@r@c z6EW&8h-9MXo`faTd{2Nkj=nc|;pd{c)4l6{F3LJ5o&K3P(pioAnHY9oqsQ{e3m(Jq`iB{l66FpA9go z{hkXjsuP~`S1``c`HO!kRzGL$|ApA|oW1j1QQXy;{jONjHL&s*qWbyh)OSVA3xV;! zz>T%8x&B2}{Jz-yqRM?=^nOVVd0$-op>AQ%AL(9<`jJCRdj2@=)Z1d;kHb8RL}kgl zV%1L+DK$TJ^4}H9f2u~jE1G^9B&FI6dDL4X>yh?}#0*=-jifL@VAG z=U-Ll-V&={Q%BwryI#{J&%c&3>m70Zb!X^1qSqU0z&m2Z8@hb$8*1g-;=~(~vbV*O zx1uB77Te#7@a)C6QW`&#qu;hm-j>a850^w1yqhxdxAMe$3BBK!Gv2osy)SRP{~75m zAK2$VkTZT(tqZOGh1&HC+42j2!7t^(U#d&Ll-)jbMtvf)KT`Q0$&!!MoR8$vj~pu6 z{E<5Hkv#CRBDc>c*3eI6w_lCZRWyI9$iDWeB0TliZxWvNTf6=`raF`7p-bWkj)upFwspD~=2i33#YL|gnl5^1hBP#r;EDEPt8yqm zJ}%hUUL21LmbVx40;;r~SRP;}JRXRUnG=jqK~XS51vSA46-*2TucwOr;lSQBfeOR% zR52l9k8dYdB!12d&qmdGlvLO`kSkA);v(^4a+rGhq#$J`CZ*Z4(qv1Tn%G`ewo{AS z$&2kA!lT+-h3#c&`j_iE$l?zFbjRChNDl9fJltsP^z3^{obsoXy@aZLknsGt;KG+g zVL*qQ0>PS>7`R~VOMK~qi(e8`Lu}>ZdSdYM3t~l5+K3n7G+Hgsi|OsHwa<&$?X{-= zl{+3HciNqi5zmVicSe>zFLvC?hxE#wzoyFZ8QmoBD(QGq5*v39)-5YA^08H*~f4bd{OUtHIC99xvL1UzAf{vgf=c54@zV zyd=-ObZaH)a}TtTUO4E`CncIlUkfC}(qwDu-6#5G^h+B`$)9z~Z<&II+b&(LE$9 z0(MP6)(56ZBA0J1@YcL*25LoEE`I{+AwC3q zcES5t!qrDbiyb_HQzCEbo<||r4wrMgaHUrzkK#c{oqR-81XcATVogYmctmUuaZ$xF zqZ;st7?_}DJR+JCba-$yviV`m9jF@*VRAu@eF!%}YRQ9QP6`AmaXu}2`5{r69-921 zIE=&CYY&Uvd_5iz$LAU55VkollE zdY4WalVSCFM9l0Mx&DAy(Xk(W+IY8WctGr8RiPwv4|hIs>R#3V0g=-wLcfbT1@?Cl zb2>%n>$*-6dU>?dcj(@j&Jnsdt8;|zt?3-0dxttdL^sCV7or1|_l4-diu)pTVDEj= zHC@Dv2gaE>Psq`asHu<0m5&UOMAmh&cXg4+x{Nf4WIgfi(rAt8D*XR_CfD}Y1MD>6x1DNt%&_5DMgs0U?se*hGV|z257!*X#A#>#$z$wQ<;8FCs{YAVdZU2}BYg zl87SbD6$A5=Zpv^bzd4a2a4QuW-ySE=~Ksc1q4mQ;Bvhjk>0F3JJ*2;25zg3|`^(o#T#-j1K zn<*#7>8(Oy&^~HFzy)_blV^vO#+mM*5{WWjW`$4@?gDhg;>of?38sWj5(IiO*k7yx zq$(~*J)vN<*o5p+rlH%2e1M;OQ-;doG&E0yLx;cHNhVKn2rI!b-ZfR?An#8$d8R{b z$5epjXNamore~Nvd@Ki%Ux$BdvS0A@&be0B?^4{(k$DH$e~Zw`!e(;TbyunWp3@@f|}iUbk*hAr};P800k?|0D- z(9m48l}E#WjkhhRlJ=|H7CfpKYw$iv9cv-r zH^D#MGzsDB&3}M@rrZWh1KEqnV%fVAkq`#8ur(G1)buTu@UkjkJR|5iUVF~GV6fei zJVyZnCeRG>Ob!GbF|{roUx8OHfUM@>Zej*s7s^o!AW#c46Ve$3PcnOfICa#lUNkc> z%AcFr{h!d%4eVcts)McWfN<=7sV$UPmzdP8CI)z-vg(NW#R-hfSjT8a9X~5A`-;TQ zK>`}ZTw?ab=8$LFz-}}HdqNx$60Le#3%E=gV{y@tN5;_jATDwU;>d2TpPz3^(*ry)hBgPn?l+~C!NR{Sm=BAg^bk*0 zQy5kjA(KP(^rmz$%nPKGIh6%oNOrhqa8nvrMZ_+s!f!O8)m4h{eaw#*@9vHEUv5I9 zv0SchLIZ2N);6K_wZ&^I>v#bkl2%t_w4iPT$bfYnsN2+fB6vuB4Ru>x|8IC{O#?4l zcesHM@Fuq#xKPjJh5^K8H*~Cwp?wWqXz!(lUbMHkp%*Qk(8z__&Tr&Jt+qAtPm7_n zCVY7lwxJ2{-<;iQ!Ur^EL!15p|I8R=X$;#KvrNLnqu9pfW001@7%2ZBuHpZOJU3)r zE8~-xZTkHzH{CINj=DhRfZhbe3F{*Eg4K(Vn~D#zthuTKA)8gfl00w!7U{D%9}goM zT%M$hT^Gdk2iy+d=Usn;|8&LA4|9LIp@$6K z3cY~Mq=10ihacA2vjfm{6d^BU0oeZ3Y9AYn-PR7Ig$D{|@DiJQY!IzgKSJa*J9trv z4s`%*CObsxEIx*%1c5NYU-)o>4Bs3?=UpCzO!sJr-tO@t{DkMXknr+)5pc*GjohDl zqXmwG?@c7U<4V2WFr*D7 z*AimEYikEC#8FZ0;B9eqrjCm6Cw25qagg@N(aL%p;iu|_4vnMK`ZE0a z_4%FFRNNr+U~9^6s9lPqxs7~J;%I9l$Cfxc@CuJ_O#>S9$E|2UQ$D*j<;1ubx28=o z!hflmYjrCc5vwe1MOm?q=_ox`lpEjNm)V-GHFwN!O;4LUhP9>*E%@?QG`yuqd9kIa z!^~DHayZt?cdr#2(VC-O%Ubijt=YZSJRy#y#PP{->}s5PKaTBb(;l%S+vZ??mMpVn zVn7}7|ti4BQgtU+g>Kv_eWeK`vw@D|~JV&Q|pYq5H6RHKD9eOonw>oKDm46t&9 zJamZI1DubpMmbIe;j=YQd^KQGiI7y6XGT?e?vjh5sK47guqtJ^)#NCe0iOPO7^pW8o8SX`M=Y)GvhfU#LD<`V6JJmV-FRHIW z&zFq_0P1j@05b*u^37P_q{ug7>4sgt7E1#i^2u15+Kq8mn{wbjzi|`tqiye{D#1^9 zhIG#?T8<4s{Muw29kL3Yo~brvu8l3RsatK(ekjkq#J0g&)N8HMB0UJO{d{r|EYG&X zHeqv*4#L*30-ZU9Ya4=S0Uv7v0XK*r4PyJtVVp|t22eqPw44U^L4QaBn%S_5$1Su0 zco6fL`?3l%LK9J3fsN;@bkX)3AvUi8J)uBV&Z+E-T2AOGY4=R*STkie5Vvw=hy~Ft zyHadt4=ePLfu%Rpq(P1fsGd0{HoN=)XWTPNh{ie?xVHp0A()%|GMK6+v010cdVx$+ zWDt9eyTk^BZD9H)90}P_bTj@8+dNGa2obizl%B+F^I*)c!ez!dGym~-Py$*f{Rn#a z8j}z_fT4EyVRUDW%vM#NySXOk>VbA{jV?#{1wWzpFr+Xd?^Uh5b`ZSkWf$TO4w+AAXFR1XJNV z2&)K2c*ol568-setnN&O?~<^Mh4c}@e7i(%tGgxOE%B|;24!~W>kYvz63Vv{4lDQ* z*hp`nAR!|=oaNeRrpYzkMh{FX{EN+A_@A2tiO{gI=!0x@*W!kMw^hW#C^`Ix6gSe` zP`vPG0g6l5Jb%eSG3udM{5ODD`?AO^WJ_qi~eSa8`6M^4c9OUY%H# zzW}MMsvS*AtR}KqQe8pqc2`%A$5CN*`w@`sYKZ!duPLfJzLuQZj`r7zSk{iRYwKwC zs@kGcj@HrdwWq6f#1(Q>J>Q*nlwRMCw`SEBi(F9y(X`}-qB?UL+EL>5hIXWX&``)3 zU2R+y>E}055t7?P6a$_U6ErW5W;Ii1#nGZ>*@!$Dt2~XPiy#4FQEFkw zxSVNWM+Vnh2&skTt<}+Sbf|UUbUP|+4KaX0agNh%Xtx@oU@d~*{C4l{7meTN)!j1x<1Y3b>hrHx8 zmETusp^BOQM2((eXBqa7FdH2q#|juQkbZzPCifqLf2cELE1aiJbu9!n1{u1Dt99SQ zBMd4UJ26etym}%YCiwIx;33WOiTO6!U*kR=azbl7L)6JizD-yliYlGPs=7ZibT#rT zj?(9zWHhg8*xpkhYE}=)L*UXHc2Rs$O*!!>qkgrNS$N8><;y+}sfF75GqB=T*U=Xu z=d*R3;^|f$A)Jy?PbtE~!g|Ugq(5HI_YmoaH_%03dV{Y)BWb9M3^N--669z@yJ*&h zhN3T~y%I7LxvhC+8y*HW3CYC6y(a2ZwDd)jEm-$AwQM{Fxh!ejZXGh%*w!xkVt3nY zbn>J2wQnQ&^p3ufh`Q1_1m;p{B($wHN5{@o`t7f9|VL!@4dhC?L?AcAM&wq)_=%F;O-CG;wbj}xd8h`-98dh?*~3s zM7D{a@MPpM{S)OrzSy~+U_qYn$0(8esy{AAXB2%JE=rvBnJU7zeI}nrvVzZ=il=p- zdye7V5nn_U!b$#9ga};lCp3-{{w#~AoIi()sPwOVuz5=xzmi3f1%L4!#nZF@bc^&i zzE(xb&ENRMJQ&zly$A`VrG0COr|W$iiCHoATb_l$;_uYGcyI6zd<&ehKk)T%3Vz_L z;9UGc;Bn>sSW8T>9sl5mF<689v1l;^a^Z@ZbG9GjD-r$_ZU)@x@hqZn4}@i)6(LNJ zFYM36a(8VP6i97hqW3cq@t7#pKUP5}aX57|L3U8M1k( z(7%{GjQ!9bE5o+oEFi3ypB~O2FiBfSFvlUh^Kb+}IWXJLlD6+)c%#<7U?cp5vNq37r#OrMLwwohcfCpd0BOJ%jh zRD75Q#X3>SBxsvpz|*m>!*e3t5ckfS%sx7cxi)DEtC5c0otw#gcd<%t$YkPxw`m&l z<>9el8cRo~+=p3mQRLn%_Ny$oS+hWpr8TqIuczV(pcN5fx?g}Xa#4e=*)Vbpw;#4} zVPri6#>YijYvu|RNqR637>fPyoUnkcWa493zmVaP#w;?7E>q?rKq6Bj6ibtk%ZA0Q z>Oi;|OPKLB&0E59koeS6=Ey_yt}Qj>$}TNuUZWkkOabm-R+-Rxl28 zA9Q>rlSSyGRV?NdQY~1`pno!X4Q2+OPOf3HsP7&a2_J{73)iwMDCy98Cih41vGwc* z9=C2}wVz{<&TV48r*MbBg!VbOFsH4;)HEH0sqEu$^S3eeFx+!+_rtvdSIpz5+gK8^ z8Mp&TEC^2C0iq)J8k)^URkBci06sh>3_P7g;S4vG*b>4)-L?rVN5R<1%xL zui)-w#zneuu!T7TY}aL1*qbR=%e1VF^IREz90KiH~Fu)$4Sh=4ee88wW2v&`b-Jun zAJ&V;IjZh_0}}pguw6aUn;v`vOx!1;b{_xHKD5q*Wu8X*gnzbQ7P0<#l(`_-f20p> z4c>v+5uw6=yfPo#8#F!Zv_3Q<(t7p{8W*_+XNCOga>2J$P#q$pbg6EmZ9VB&eSJz# z%4_JI0X@Zr;x?Vpxay%kbg(hc??Wj~LXN&c3!2Pj8NKL9Q}=^jv?wO{X)ihuV~2lC zv*J5 zfX5o=*w>2=#c`B%F76=8UDhsm&FhrV-aEcKrMCYb{%sw+t6rx^9UM^JOzNm5y-w*J zHK=eVcCydxMdLd~KS#|wX=vlQP8!daB)&7C=_cDS>s&gECt z)!k_3YwFl;wDvV^Xb+mvg{O3*!cy70TeB?$R_$PqH>L%zB%rT;;Of6gC#gTA9tA9D=JWYj9Zmc69i(6K8SjUX&$aAtY1ijG^BcPNg=6-&RP-l){Ttf& zrC!*V4t)6`zKcKCI{XbS{7Sjfm$LujJ@qw2F5}tZuW9qw;;nw)_$PhCQu^|#ec7D8 z%JRN!e_wvSFPr}@U;iz8@GVEPcYP=4f5!%W|A^tCbWW#@!D@#E6tip*3uNnH?u3A? zooaRu(dntV(lzLx$>%YWPpnO*Y0%sk-26fI&hX!~J9a@q&cR_c@Qj1Q|HQ!&p2%@o zT*LkO8Xe}!1t*>2RWL)iBN+&WuqmKXky9ylvJDy^?qUU+a#3R=^v~dbqT?=5;XMC$ z_8kpJ&4x4oPDl(g|3){hl{!JTaFQt;Vt+%-)gQQFvG2D>-B2X)UU1Pi%SO~M$rg_A zdk#O+q;dBQsQEbgA&C2Hd@$?stdM;3%(O@P0AH!eAxsUL+MPE;BcGo#vrA@v-^^flaD>dj zG<}(qvF=6vAdnSKN@t}!D;<+VmRo72#WB`O=Pc2?tw8I9n7LRV9R&J7WBXSW2lc2D zI*?c;4zSQ&z#EV}xiTG;a4CU>Zh$vzHR(sq(6GYk5#loHVnNhUx5;daT&=8lPq)>@QfE^Ue9(sLfvA_0 zsuEQN4}=;CuD+<-LZIV7KSPP{4j!L!s~eyVl#|^k$*Saa1DvR`q8n83m1*7RtW6ox zjjn0Rovw6HR|>jPl3Q8Vl`eUenO&)0kTSe0rTDdbUFdmb^>`N=8Ln*VLT4k?IbG;} zgfglNU5->9zebCqwKK0#a#d~HYjn7}Hvcs$tf7s4jq+Sy*X{hYQZzE+{XS&i2fpWdMB_LlmngU zWNT$bCoE{nluq`$Z$+DcSgv0b5!a3m8d_`^=DZu1t!nL47n?X!ka8K z6p>FQ2)*Jo&L*%SP+OFGLLy2Eg?Dgid^1WxdY_ILxg@k~~ww5}!e zp|DRV#-I-YoA`Y`zy{J@P`nNLlKhzhbwPVJ2vo9qPod}XTI9P*5wV9Adm)gR6%FVX zt8L0r;I-P6gDT5VRrr^x@=lelgxZeEHmcAmfB7v7emG#Q@XxcYK{4C$E!hh0_<5<~Z3;9+POEaZPRaSI_DzoAo-IbbG;sywsL9`a_<#rE`9MxGk*;aHKgJ&ow92<7YA(u>e&NOxi*v&=0(DtVZj4i zQ(+iK$h7d_XRT;!c<{YebTvHqRx9dXMO=kQNjneq$Q30r&{3T zw3+R1K@XbELG7kAS5dnK%~esC=Ath9nsZd;Tys(Uz2+*4AJ9TY@uOO(C@iyuimVs5 z5G~%=LPb6YTPB&ecVLBWlxJ<&&9;XmJZ$Q)8hMwD6fi_^E5StwAv>85aMwvDJ2Vpj z-!m$d23ur6Ur)A#-3$TNvA!#W_9~T9Vb4bqr{=j1FVb9b_>d+WmVHC$j+3VbgNwzd z1_L8L2(gD<*nxJtMP`^>6M`w%!{LA8QB#5`$?JU(3~_8bET0b#^5Uf-ei^YN{8Lb! z1%V#$_YZdL45r<|YHB5RI+))HW{-oF0U>N?2p?OC%??Roh*%U_18k{K6(M&*<&;XL zhY>6c#c6|0(9;Bl5op9F{XlzsN8^$CO|!nGJ*ameR6q~7=85*u`qd_Y66=V}Y>$== z$MI~1?nU|ox(g}SxLk;x=6?N5J9^-rz^=7}Io{}pZ7C(lHLwk2$HSJ#!7x$GoVJt@ zXnv**tqvZ;xGN*wiXD(b(bsVIF%jEedf#HgrwW-QNYK^tP#^cIvCE7I?4 zu}#YC#E!J)H(Ik9amu1NwmmM}f}pz{Un!eyVmyQ{%VVsWkEKdeonX(1!@@GNp6-N5 zn7otIK8qddk(;dcIk2-}73_`!3PIyiw|4V>EJI`0oW6LC0r(yMaoWqBQq%#^f?(qb{p;CMi(R!LW+t}7TP79$p>pkM zwXs}lnYBUVAIbLD#&N~Fy(Y9bz3@M?r6K8fdov{6%n%Cx0!dZbld< zurGe2fHU*ak0MCq3A_tLr!yx~WwZCiIDiKR8Wi^7@sbx5S0r2huSYE#`4HLZD>CAlwAfikG1F(SE zpwBu`lEHjSlF-f^sm5^tR|+Wl(i!qE^A;EdZn>C|AG6`dz-CZmBnOZ;f%IASqA`wZ z&{oj>5Wf*Xd&V3H^(YXl3`KzuYm_mMk`3X?apj!dUuchki-2kPr3_ZgUjv{Su3^eH z#Y#dV{caXuBz<)r};D@PC2vXlGuVBe|pvRQi5Lz_Q)s9MX7AQl~ z6)fhczpM1>)(@`%M+cXel6T5*E0Wn0pr?v%D+%|nX6j&=-DP4!yCj9dKfoknjl8ZQ z@EZI1JJ|maK7!eA0X>*~D8wWG3~!-P8s5W(jQGj00|?+&(T6vfzE8j>2y`UG2bGF+ zx{NPMI|evo2~v%SGxV~Cq9sFN$a^y*LSyJvu?3PrmY+#M{ z_?R=O^;gsfANMe38(&U#ENyEds9A|}_$^_2Kub`7moF%S%dO!B0wIN8v$7&9k5?E_ zb}|$;?x*zz)D9A-G7Zbj?2_+N*zN#%ySMif`b_yN`_BsPH0*l(yEri7`*=U4FOUl~eH;0KyF!PUmMnw?yvP-o$s~y-{!_aD&h-=H z^-F#Ge;4-)V+mVbvm^~d6U$4!N5i(`J4Ekzzofq?{Tch=<=~dsef;IP|KoKt<{<9i zJ-r{%C(3v1&o8Tj??JTp-^KMJ>gD~IK2?5TfBE@)|DEFgT^s&?9w*L7B`gaKC#TKE znj^wy;8O%p1Q<3;{>#IrqApXJwiv9~|MI&0cj*`GtFI84)%dSE2Z{(%i`6(Fo3M31 zGzB4GggF=i^UTU}Gh1g?_L|wY@{^mfC&GFUUZ2J^oK6<~V!z_7R;@!6IA7mrkjWg# zaMHTYg7BOGo97anASr+f2Xgt#mAo|Xf9@wGz<;EwIOAh~<|Q^@~cN_%dj)ED8QWV7GTc9q#$^+Bqc{;DKi65zrW1{k)Hja6zD!_la@NeQudTko*OaykyxrnSx+xCzej zIB-K-<{9V%2uTfXQ61V-L)%h^PS$7viIAEBc$e1H=GCFiHS2@sTGNYw`L*l_SXIlP zR)-GMLKWB5{&iAamQhEURfpx*sRw_2-Jgy9uR)0gOVcDD52giX1*R~M@K2yPpW{wp zi(%%^R8%v{2jq+cEZ8nx0H5f|#ayX!ZGA!y!3!7!Z$5L{T zLZ3v9W;!m*bC{ZA#tBMXoU@jw)Yq(s<=GM)rYS13&B-4+17f5pMvn#_7%=u*Ft89Rr|x z>I@V)p-ej37%rn6;8KEhCOIG>HN>PF<#eF8iQe`Bp!0J8h*Oe<-_oH$=02x`>%1TH zK3U^8T$H8p6)wutG^nlJ(!%dy$%49yP8;>@$llNm`>*M{s$`5W#ERboiC@^{h2U|K zO*;p>iE8+A*l;TwUtyQaXe(HepP$5MxI^ZbK|unCT?0P=)`}^?$u9s~)yZ?9qUY40 zJ#^U_enX=)EgYS@QZw2ra2t&>N21JJyam$+(}2Nb(=t?Gz=Xr9;~m?}`Bz$Ie+~VM zGLvA1%n9&#H}rnj$Q!H}4p6he73F+3Fgv+6LIbWxIEHn!Gkl2?%f?U2^yk~?!~1xv zK;ai{&@|T0*r2-}z7(Rk70VRI&XC)j{u3aQbi&LJb5J||`#G@fUf_!XTE=oGO?Sxs zoj`=v?sMolgcrbWBM)D}VUtgYcVb?ae81jo3;jm{>b@B0@)p?K(xBycLk=Hqff2LP z@3&M>dNHQgVo4tw1$927FQrrw0Q4qX2~+7zN#y;O&^9J1bY85Jh(?qlb5d_kj0M zgdLe(jNW z*M-q?$A`G{agKl+9J=>3K@NH*ZZO59Hn-t7f#?KF337iG@FQUexnO+* zH)cfx(pa8S1;H;A2ZBe~6oiboX%N`AX=er7Oha&<4PA@;EA9(H*bxQsqZaTaSDP9n zz~s0IV`QZBXSl|wDZoew#j1HCw9%+alw7GwNt|Pt^`bHuaL3v!CGF_Iaq67P*3CQgztWAmEWr`qgL`hmuu&_o;?_7XU9KkRwPO~v{l&xMFX8`X4KmvU*i|G(3 z%4H>Ip`cRn0Nzj7vga=#vc^6`b&RqqIlre`pOof52=5MJ$_0qLmg2iP7D>(`JIr6~ z!!CpTahAX~@&N?iO5S%|lAMb;pcGHwc<_H9ehu5<^o|5>xf5Je8t3`z^qw@*`vM~} zBASor2{rl*FHRTDctTGa9qS+7ljg*3$LJQd42*f5(%Nx^?Cju1$`hUWgC2CXvmhbN zea(*8<*#)D-RU)vaBP>4Ags|vdDMf_x&}@H6}@XU_~X0T;ZN-rnAww(yYqWJD7Skw z{3p6M2E(@pFYZBWd&osSXnPOG;GT52hy1(;UFhM6?@70NtVTgbAJm#-a)2qc%yban z^$;6h7K}M{6o;7GK~Gt3Fck)ralv#yU@WGBUK~_YzROrW&t_&C%Q{1(>n>BC3%XA^ z+$P2v>B3<#oJI5b%rtuQmrOh=fs zxn`)QYB*>NHvdj!Wz@Nry$!Wj-e6rT)ERZ^3@q(#kw)GS8j&aeiMHCBuJ{w(ao1V? zC#=HhF_=bOT=3_085V7%Yxk)PC7sz!1xmmaNgwH;E6}a615hPV+G?jos)~m~H88>f z5a0l!VRe3kKz!oBeOhDhS2F&FPWxbdsDmZ{V(hw7CZ^|lnNQd0nrw&s&uB}-Vt{8_ z1tfa5wE#Qq06jdzMXPjmo6a&_e3?MaEpLrcH(P{^-mC^$deLssAGtP!Q6+Je!1FJT zT`=?Z)Ig?v52Le?g+eG3vY#(kW8~AMR2D+UZkWh|ARU(~$>(GNV3r4GY+n8IJX73V|3SaOswl=cG*<#WJYOmuZx={;VEltl{2T`C%4o}& zKOqJoRhurbVP%lGvzWFP5||ZgZRGctDZ2A&B;*gBm+|X%UW}y49_RT;%J4eR;@9Uq zjo%>WN&Nbq$0M=hI*;Nv*m(rMA%gkEzJ+1A6%|M_T};=Wrbu=BGFZhWTzM2e$b!C+=VnOPP_9xJ{u4ImLN~Ch zor|DSui_Fy^El4{zON9yyUm@&E*k6P&tVS2`Q1}-{&${p(HNbdanU+m-Qc3Tx`vE1 z-AcBb&36Csc^pxAC>$HLEumy0FbJzkn>Eys1x+cDhi5kCvPe)fL=xp3C zei#2k%QxoZNObT>lf2&zG#c?;Of*|B0IAw+zY3U1c?)8c$<$S>ytY0|)r^UR?!l#Q>LvjC0(|DmPp4 z&)>!W)}wUAE>3&-U4Xt&_FW8d;k&?%B3D)rx?Y})fjO<{+i)7N>9=*7uR4o#Sos3U z2~zRC1v)Ksbl!rGiR<%#zXhCq9d?<-U4D>;?_!C@hv~FLSJ&%o?Js^8|3k|k%ot=n zQ_;hzCV7Gvx~_@n)tP4NJTI&&=!?9d9Dvdb%jquo`zd-Ner?VqFEC{{BIQ2Sf$$>^ ze%Aw9LM$XbxW3y1gCWj559RZCw!;G&l0MY~OH*392Owht*>$yBL;epuYJV^5=fzd) z<$U~d`6wlG? ztn%eAXpXI3{GVu>E4ug#y6)=N93+RXF8H5yofc`Na~iDkc3^ajVYuxZVYUFrq^tU^ zc*NOU$i|n*hN(DM4=~Ndyqax>MMJ2We-4=kS=|GZ5HhZ{Yh-nY%=XLbNts=g)rT^> zRk5kY{VEikYY-loI#CD>)d9Uj;^0!uF6SN?bx=Qu#!Me1Bq@w%;MsvFm1~hFxq(SG z&pO8qQ7*?^H_kZ0@MpN}@DF#Z@Q-)bFzOAPP(NCCh)h7L$Yl0@DSAD*H8I0}l)0 zb_)kRd$-j-8(<1ndzMP)twPD?f=#)o!gQ(^cnc#{?*>8qlvk^4v#RV-*Vqq2vp zy3NjJ*k!=(F0~8)Iy-3oB^5CE#D5RDgSJQx*p(eAMU+LM&OYW!VaTM`^+LY07W~n~$G&6`Vy#?L1n!X8ePBf5Dz`5V3 z`5eRn59s1`sFTG6?uZwfH8_U2=k48>@ie7_XE&VO&U_GSYa(5x- zH@inZ6Hm{2?!{AHFKr|qj`hmI@Wj8#_aLj}H;r^}ZDrzV`LB3BoXx-LiKF&ArzP=_ z{BEj|N6LFf+=KV|aAY#zx8l8w54JM#H1|U;8nWWU?w~;bK1lfYe3WWrdHCa0Bgv6Z z`5M%6#h)TXrs-e03gD#tB{CO**uVcWCaNXY3a-3LK7294-%)#u z`h=CPkCm0$)YR6E#l2jfL>edko#^jcGPG0$r(C2J`k7c2-<5M@1Uj*ir2?@8G!vdG zL+A8&LPk^>hES91p&2_$_%c{6G=tpIPgWBxnAz$UncX-1#pT-w$_o1rL0sJkWnYNM z!QK+Y$xI6w9+nI1s-kSj+f~;go)t|ciXm{AombBCzwy-4~aEFbCnu0s*ZVNz| zgj{bydp*`2ZD>hQ$oUp@KFB({4dA{)4z!>!X%P^*O4 z0O~U>Hh^;1$8u!37r(%yi{*H$FqY%3XR#b_4Q46pPJP;p>9JX|&H(R3It2d|InR`3qe3NsphO#oAKXRwr`ho3 zi1BU$NJJR-mWH!k;5G^=lcnY%Y$w2$WKim-TW*_R3wa#WYy{9q0O8x!>Sg6c-DjTT z79jgruUar4g-qsFGY5M<%TgU7dn}l4#+>dg&iZGV4Bp5i<^+v4LHe!81m)}1RA3bR zdV{pUL}{jyIoP6~q(hHtxnvz-gGS|O^*O7fD zY&9H*85}dJbj3Uruq_Z86(4V^5J!lC`utEc>g#9SWjCfmJVxbQp)C$9p4hRwCn(*y{lUg1AMV6Xn zb*ouQ_jRqd0&;R2a^GTdEwU2M^z*DxHWw;qQ!QYLmA0kM8}^GPdJo6gG}x*)L93KQ zR`-Y`{0mHh2e5Eu^1*+~)X-?V;sy~T9Lovnj{lS34AM#NDBW4|g{jpa|pPlvXNc_1S3*)!q>LAk8 zKx1)2HmMIRFmU*_(ERXDu|n?HJ=#i}WY+~DOd&cFX&Zm8!Vu5|vvSIciJ+XYLVTC+ zw8C(e>xz|5Tfz|j!V&@hI;#ySw_9H`-g~d~*zdXJ5c1@(wO%AC`3^{OI3GDs_HfaY zX8#=r?YF8EISgu6>JR3)O-bZH2v(lM7@#8*B1F?18YUg?voLMw&gJit zhDk+GVKgZao9<^ezG#G($WlQ+i2e!!QAwK}qnNq?i?acvA#jtc)UjZhZZr#-9b@tm z3A&fxK%W3sS%tOPpYF?^5*q*akoJ-@8IUY6b+L;We<;svm0hB*lyJEdMdOQs-(T8( zb(UG!G=u!vVM!<)i@568#h?hql$8RJECK#Qk`Dhx33sZ;l8(_yGW9G;t8|sWqu1LT z?^U5FqNwP2Gxh8S2JT$eX{QN#!!;mWa8){oYy`hMhOixnD!5I?)Ltb+EWHCZ+m(`c ztr;Jso(WwNlRHUpe^n&8WLAsJ?6&!npR@CmF(y+d%k5T?9_?02TsKWEe|- z2K*u1V@u_cr%5sthG$jiHIY7y1)Qc7MsF%V(r>VA#xrH8=sYx{wDZsxzIHaKy>!L& zggkUOrhXB+r=&dG&0-y$abEc~>s@g?TCvzF>QNJP1Hx{YAiCdbg9&>(mZAevD1wV5 z4OfE!CJi9N3ru#PO`b3*NoIDzgu_Bf!N&cnn-3FY9)s2bgZfKZlo%f!!rPb%Ec`y8 zH4HgGadvC(7|Ez7ZtFXQK{3F~RCwp5jZzQh)G&dDbD4z$!Yxgbp~taBl6OgLXE~sp zz>$9KO?9h<-p2t6rKek9#o5!}0`rXy_@_!;rb73@q(kdrrrCW}eC7`LADD5-*d>P| za)`w-!NSH_J}9er363=8F)fk8ufZIo+hNcC z3QB%z;;VqJXjUh|Mw+a`f5{>Yk>*;}@pkMyz2F~a1AC9=sxG{>M#Y`rpz1=xYpQtZ zu_|5~Y!}H#*}<0;^T@^cueHzUPxg4mzJJ;2#u!@VP;%g0T3M;bs=bUd-uaijVXTjh zT}i-|7UbrVIbC9}nm-bf_(I3wwva+hlZ5KSSz&;hU9T{1_{PPQ>{to!7PI=FMq(u# z#-K8UubVHn!kn``!-|#2odaEC***#Tgr&z`fvTQY(iY64PA(8`-o`xI&*Yz>p&-wa zwM!n#=uct?HOc`&6>l#TQx!se9#L<|k@wX=Fd4$^OBovr5uvh?75XKOLhC_d^tCSq z86*b2TMSnYiZ^NaQbw6HgiJGOO9ZyJ9maFdRaEg2?NU6z0Td{u;!fgjssBLls2|ba zmEnvHsxa$~x+z^9@6g*Iz=*WICibtXO*NuFIKHND71-|j$IC%6^vr%Ag1h26NrR?L zzNDU(*kegfFtHaERt}?WsvJ%l=0-L76;}IY7ARvF%z*(24RdX^WSb7%F=;#e!)4np zNbkt%QcfpiK?lu%{awJ$TSLw}pg*Xda!`T-e%LL=dl69j#uS{UhL7Wb!o+CMal3b; z13;J9hcg}Fcyo`#ev`98hy96zB?8fuvs})%akiKH;lIQy)=BVyzasjo%4~^7GEmm= z1!DTJwG~=bI%Zb63OT}wYRk=7gNk{CF+cVe2pBA8+8G8T>2-z+b&&ET#<=K8BMM*_ z#~3;CSa^Yi)en;Z{qh_37M6E3M5+SA%}*s!iwv`zZ-vNF_!2AdYp~G31Qdih_gK^g z*z7GaxY}D)1Y}s%IaW5y3QqTVt2|6${b1r+VHt`%)**r*fBlyNKq%0 z`>*9GywshjyXyplMx6%Y#xb#H|J(F9x4h;8U1S^6pty6`NRM+Owi%q~nG5IarR)!4 zX>iShxpd=O$`%Ljl5aGaFn1ccFm`{mp90~AX`tSnfT&n$ybGj_0VbdmL;$>UhlD!< z{xFV}ATWTdDRbfWdY0L7jNT<_@g@vpoDuJWR5_@>c~WJ3uUDlH%ii<;PDNRte~Oid zDe#>VO8{)2GlnxRT8)3@EO-D0P}>TV_ZCo+01N_?YZmtqVDeh+-~r@W1;Wu(n|HQ{ zmf3RQzo`m;3YU@c3XdA>p&QQV$3XSf1IR5)51jA-rCmYnem#08aDMgZY!9Wo>{&qd zb!iY%b7{#Q+U^R#=Il9_ib4RJT;QguZW#pI@!n>)y=<=+OGMe^G1i6GUAS8mFc~7| zLnUnuAXcS@*97E$#rcBsN0k#S--M+jWVs2dc-V(#nzRBF?J_kS1ay|4u48FUSdFUk zAT!l^jD}57XH6Xb46|pk`CrKU=nzN8V!*UTObDWgzAdx=96lSQ zKTM2&p0pTGy%f_!#)_L_j7c%*&vyX;)&NRgPy+;~nWs0TJ@V%}8_-J2E)$52s#;th zLXW=qhOmDQ6QB)fr-$b>py2`gc_a!^5OOwzpQ=w!L)4?Nlv0V~<=J5(JSQv!MA0yw zQJo1t)R@L zI`%OQXks1rum+S{$Gy28U8v*Uj>77w>*`VedfM>%G`d~@In1lak;BS*gHY>|`D>qN zQb6EXDy|XeBgoiPl)b`U^0D?E^)>oWe5*<;YNNc)Uac^$I0MFb(96G<=Yj6YqT$WP z_1ef^$dE;gU9zUSfSLNUjyo88$UMU&F=ALdO80wr_|9*`KsWrhS^j6c8*j2+(C{}vn2*??Z>q1g!6qVD zLo3Ycbd{3j@O~;l@Wq)o-YPfz;*Y|DWh>YbK z{rd~+Ir_a)9rY|QLjlPs>{cr9A7V0?JI4eYtE_*7j!6k<+b2^@IB2}QyWss86%^%R zKo}I*E(-i0tUwqM(0Uc$_x(y4Wuo7nN251M%6%wgOXaeo#x>BW6gw zSU9evlf{Yv(8S$B^SOL_|36QMv*~N!Z4#BkN^bO%QbXxO4NC6Qjn^_4Kv@S%Rpwi; zi;ToVg5iUP^h()_kUcUe4nr*>Al0HGV7lc!BM(>HXa>sqL8e_~bY5&~C3%Ow=fY9! zOK3V_X^e({;1Nv$TpV$#$TqWS6;-E7##E5x(^(n= z{cNSA;UvAIBrh@EzZ}=;3w0>WC$raX0<@P^g@2OtR{>7wS_VyFc?R1nOdzZC6=AIt zu?MUmjwLJFEE`Q$MDT1yocI1sThlmGn8ijmSug*NB3Kx>SRho*Gk~S@B#th)EUAwr zcBg#P5$pN8jbDIe#d_n$`$SBY;Ic`7`RbhV{OYP3d(x_f}~9G;>Lxe1Tesoy)d`}^>TVB z%PYNrM05}H(p4q;2nf@*aNMD6${cY2?HmE4>@yhBEaibAUOLNdg&vqW5*BYJdBPCB z!n0a*63Up(HY%PK(I5Z{0G1mz?MxIswVlWEaEi-MqG*ZJ2IC?HPTz?r7}~=@h>qw% zr=Swxj?Rh(@mZS@O$R*Pki#CIWlb(SRG3l;)#4bQ{4N5X@tW)K7`hBeJn6}_$rh)L~9A_sD~iyiY)fIynBP`ma8vbKJD@E z2C|M!X%+;AqC%o>q0mGH zjhaP+3Va2t96bipN)Utvg%I&!1c^ZW2liJ5)8Hxy-p|4U`BiC5WoX%pKcsPiE(pyf zCMSS*%mf9lBplNH*hlW@@*|k$5yp9e8wK_j)(sB`Zn(_Aj@Ncc-R1y2MPKTGxdA@Y z0bu}jlmo(Y>RmhK$pKjWIxhzu#WmleY{d27s%CN=Fgt?jr)0BbDy_F^4^?_#Q;>3) zsvQRwo$6l;1L~@BSYReO=ja_vpwAL~#v9c;Fv(lX9qzVEPuopQVm|NQdH zm)I|OP5FHQpQJGMbwt@hF80Zq3z_;*p_NQX+xM5X@irPQYlCbw*rtrKv3)lAq>UXa z|3r(^?pfI_>wfSKaU$O$g(bi_X5us8TsHBcSmKA6`Q@2-GV}d#uFJmXaDdLVat_$o z7T+p7O|kMBaOPR_(YyU@d=eh^*uoOvEVKI#BCq}2k%RQNwZ`-Dl%?}@9N3rW?eUrG zav_2yc)D+ZbJ4@s;Odd;m5O?;v$qhk1e1Wt~@eXuAdY(4xVn&H+%mt&2ZjB0M= zy03YQ`G^|Y;;IS;Ku7;b6g#xjMl)cfy4W8frl5=c7@W~vwTT(f2k8o3LVDIqemn)= zP;Y%KiXZw$r)*q9ulAYD?jm&XTjEx7;q4#KA^o{u;iKF7jvNmVjU(@HkuLRJ{U(yl zdAAD+d{@5;|G?j1_U!l#KM4P__l#7V-ov(*`MxI?1uS{rw+u16-uI;;n|>c~5t#mg zmV?02AM%F?%=^%H0nYT_`*Yx|`u!v{;0Vya@o?c2?3Fb9OMMqMr)OVkB9D20k+-5M zi~fR}H4XVj8;!7u-x$fSd{aYIHnXoh2+o4Od;px?eT^2J?<*IhQCIq6p`wECGEC2r z<=Vd)6(0Dbo`8ND^W$b@S$U4yH0cP_*fKszEuQ zG>OHD;3?_MzXI->bYQ)t1Jf7o8MqJ*;E&)YW-w(;24mado`hQn_X*s|lMxRR`rs+7 z(uQe_t(j8tJOEgeDG1NZ1Wz9Bu1r>4q#HAh@tH`s0IoF}-&nxWFBF--$8zt^{EhtJYLEb!T(Yx_ZQbFtX*xukN=$w zLUx};maknX!zwo?hfi+EgNsJtV z*>;&Vm{@*)Fxpv#^k`#0K%2|`Rs|%t((r%j7i~8TgrMzl?sr(P3T-cm3nvHeqSch9 ztX_pU(Jy6ri@vBM|BgP@#{r`wqP)%sZ=w8}K5`^8_Em+xKzRFq6^^ z!o(6Q5*Q3RWu&PsRjmsB3j1%^n?EfhT7Hdcb};e{`cL~(iGH-N6vxeh4BDAFl5xRB znO;NhKYYF*e?jy`I4;S_Ov4hCUK$=63_u!+ zKuX}xgo9yx0l@KseSviz`#J87nzA3bP=e7inT210^bpey3reGMp0O89NtReb`N_AW z-le)W;oBg{REmm#+KK#dKTy@}qH^J<1z3U?N8o)-ImQ@3t42yJsbW^5J&x;A2;@Bm znXY3UEKb`eF`;CQt$DgBaJV;A62T{dY@KgQAL?)C+ux)ScEMmj$n7tBQ@Yc0un&L= zGv!BpfJJ#u0Y@UT%B4OuC0bqh2F-~+jODXmZI0Ni+77(@xOO}Er_^uvqz@1v`S3Sr zSOa|h*BYqsW;Ar{?n5gZii9s3%Jbi(agDko`T0hI6#VQJ1^!))`QSI`a${}48}ziX z9i=BUNkt)3S_C%rp*1bE`F-ec3p;X{*wR0<4;^Uffj_=gQ@s14mB=$K&Vvf>h_j;# zOWSBgZ_tpoosni(J2yg-I;xL*)98+4&;wboipnN*>3N_J9qJ-j$%DJqMo7Qz+P&U% zvU^xjZ(8}fC;tsP`+5lct9tRiiFZ!Hy3s`6u^K z=rm1|7*P+)%qk|mqkMnzwQMUgJ z_$LHP*KyG3f=VZ?6KCD6O#Yb$nNc^#HM2Yyrm4(@sF0|43$V}Il<;%{^G%KyurF;o zin!6T5B^#5101J~@7*d#lA{Vy9i=5}{PXX<7uAIJ2=cRUHre-swQB@{Oz&T5w+0@+?#Y<}s`yX$vfrZn4jSAe6eswg5&=}J+MBA|eXAR-+obvw1x^ zXHK6pr&o36K69CT*ooR&tH#YZcasEmyi|Oug|}B@`6&~8Ar~0*v7A*OKo9@e$+-?J zPL=(3#{#F|EAnf02CwOAI#|FuDL7=WlQCi{ds*vrY*sghInQu5uhaQjh&HU)tzf=) z5A}_asH=qD*QmVwVXka0qR=_w_+!ic6LiKIj4?JQyp=zDY;6|m+J|?SdPXMTCg3J)qjE4<{Ko6DnAX*9{WlQJ7;6SY!vBn zpEZ^f2hLkni${fxZ(l#MjkKl(jog2BvC&H^G0nnm)u&vx0$jn$dC<*O_E@xCR1v5aDm z(-`TK+14oJt9;A4i|OB1`s#@P9o8u1$BXF?6d4$M+d_!G;w^SqqL3fAFe~H_Gv&G( zhbsFst1C7Cd&P)q@Ex#~V@cjSdO3FQuhgmOP4jdLn13*q(V$lCNy6wz)E|)~e?8=q zM3Ka>zEbmPpI+rdTEbNZ_blZP1<4M(b4!pMv{M5P3DP+OeQ{7Enj3<8_{`R4^$m%} z?qD`|cu=f5>LbYUMu@!ca9`rca)*Pf_+|u0Fz;#~E4{qGtr znIf6S8t$^z!dN4)UYmt!zn-JI(N!8yE8}jtxD4v+4>bKF3!{ln+?66>lKI?=+C z>}1o<-@EtU+e2Y2AyCT*$}+t2oB56YT8&zj5xBCJ*z=(BDrk`(7kE-_# znVGagYpo zQ7+n(SP%71P?8xpj+)NF(twIax&Mh4T*MOZfcuVEy}Fbt_y9 zGUBZUC6&D}7C$g=!4C9F@~(ZEQT7XCEL`>;Qq z)u()JWhb#+jVRNN@^5Pn&SIQvad0lWqx4JjbJ^EnqPhI4zhoYu-kv$JxL1k-wV}57Z(!f~QS%y54yr_$8c!a{^ z+9MGt-)v}n)LAY*=J>O-Tz`yJB=T$WYucOLWNot{8ak(%8?!pgw8tZ6be6GCwAtEO zzHeC?`I(k#@^DtGh$UU+Xlvu=PVz|`=l)LeTif;8*-mn@-CoQ5u5$I+2z1`;=pM`4 zc65*FDvLWZfqJB)tEh`y=vWJXW5|`_)adOaYiTC@lLX+lMDN6 zI=K#ZlC7OwxWBj4G$LPpli=pg@tU+H!TFyZ_4KEuK{=mZGvD-lG*=!Bv8=QVcXIkm z{2A7A>Z<7b*6utN%w&c0Krjp09%LP7P~`Ps23K9&rLaCYswh}~3?7C-zq_sm`t$OX ztE+S-rQ|kiF#|EDz%tV}_sAuS5sLe&C_oj`~%V#&dLC9iN z3WdGSoTf&tZmQFdtRt>gJ~NIIbVLH?PI>`tB8 zL2GkZbFSftCap1tTUog7orOCQOa_d#MNeXNsSV}dY_Y?*5#HuRVYE*5x<@zGsisJI z<{|CQv3BiUyD`_U&9*aHbGKdDOl!p1rnHW=*iUsCXJH(H23<7rudS*YdPR?-X*N}l zVt>MF-SM@qZPOj6bq&|g>)KJBH9DqaYJEyw=3e;j+D6+dj$yG=>#So_3G$mk`cy-P zsMTxowh@BLH-=-cp=~cV=0`n!#immW->`8wnTnTUefOGL)fN#)HR=2?tvAh0$7Po0 zrW5tK#xw!hp1FC7HOEa&`{QnNLAl}V>A1$48-}@5T&nN7E0oGRR6h_Z`$7|aYR=vc z`c1iNgx~k#?%Xv4{+KC?x)5j7)GvUyI>%9Hp|~9r9|d%nOe? z5hDk~qpxt(Y-Hq~SXmv(1ddFManIvM^BDI#vGRG0dt$6?j&YBVmAx^liRcSw_;_pF zjUd?<6mmR>qh*-X@TY;`h)$ywmWC(+!0(1|5ZhGR%H=W$2O-~t7=F`U~D+<%Z` zw?xHZ=~z_A`_XbSDx@e%ZbhB;1yA`ELKGfXN4oU)`yJBmJ9Pr{G)sd2x#=1$Vgk3k zSkl;Hve*_nE}ZsN^o(%MMCy;q`k>I^;qskhwuOg3oxf=4zYvu>~`6DnTtMVc_tZ60XVh zQ^CQxUOui)Q43Xm7SMs$)(ErrCOY1PtRxkeU7WOq=hhy#|KdmDN zYr2QmVE~%C^Q&5p?`vs4)^Z-NrTtdhak;iOs*dB6I@S)Ep?2=^|T|LeqTrX z!zUlf-IH~-F?E&tytuRg(I=-%}ZL90tUstNN?IGG3V(OPN}kw4&y%Ec}x$C+^O&| zmi3t9S@8sq)U@7-fdY~AUTl1fHFQZjlV4R-)&3s^6=t2S9rUd_sG7^~rt7cv=cx6l zT~!w`Ba|j|f4VNqn9EUXq4fP4Q%C9$;URa2XjB-AwSNNg*F&|pjNz(SJWiGv+^M!?WbEQ-Ub>^^6QSDlYMt)0En+9I9gwC_bt1A} zom%ixb)hsvVT@!Ms4lZQH(I$=^Nxd9Qt>5?MH&yF1-3#h5B8~rbHN^Ef#!Ud_1M~0 z-bAUBPFxSiJT09ay|o^9y0mxIJ2^5mPjU4PY;n`Ja!pSZooi!K6zlC@!`-i~&fSr0 zk$UixNExf^lOt)ge}VcgyO+)3;~gRF@f;HDSjd8|;E8dm$N|qTR%OmBMp-iq0b&QOZnQr|AOUv9!Wn7qJPlQ|#(>a7>X1G#W z7@o;K!w4Pe#t7s4C^-~qoQc#vh;lBA($+^cemzw&fR61DBFncuhII> zva&eFy}Ycfi)l~!78{0>U&OlKEh~Ft-9yXDlsM|u5vQj1l>F0#c@ExUZn;+TAANMEHbM}po!D*F3A#pN^`2rOF- z$t34Aoow@m#*~52znDD7E>=8f>ZJdPmeTBqT54(RPk$L&+D*2Cgs?J5jo8hyM-K_% z3N}N{*akU^=syNIKVy(6NMFeCkR$pXCs)}UL!2B<*Nw~=9QR>}d>>q6Ih}r|G0v&I z=QPfTXs4aVb*DBbq!IGpij5i(erH?97VctD1-LJ4&aRGQtOxUV%+PlW?cYbHGpNie z`4)aNiL8)Nt0bb9av& zEc6pqma91I?kn>eO=q!y*7VgNZpeD>cRRxzjx%;vb*ua|%GT(WAjU77j--dJKX*zU zyXg4M&hc3Eif7qfSY2XwVRen2mg82t3)B1UE=(U+N2cNjIb8MX-eucrN!q21`7?au zoLG{|gaM}|){u8fa+N*Oakem|Gi~%}WV!CR9WNi-^)vBow<&uno=*1T+zoU%$k@p} zK@Q`Gc$uh{L&??PCd*373a9Zs_XIf|-*H2blkE3nNSDr2>9bG?3z-qmzQZP;mz435#E@#K96mJ{CX_+2Fa{A z#~CgsieqeWcbtoW{TxT%;8L86S1O8Q0qL71T=+Jngo}5XSHeZ;J}=?Iw+$tj)A^}{ z3ztrnP#tOick|zSlCVZC9qjP8YW_RDW^4K=8%4H$!^&Xjb==rtD@RQHVN4;aRgc$UXfuB;9XBmTFBs$*d1N4U8v zX=TKlIQC6sBnF2@ImVRaiX!FMlxQ`>@nx*>XS{5SrJp)A&b2n4v-On0*(E}*#>-dn zr52Ucj>a1o>u%o?gARn!?DRBt2NhWEVI&7|Kd8fWw@AQf__y@vhCBLhsH{`%Iy5kEwyY1pI z@`>F=&Rl1AZnbN>?8XVZHY_OO{UB{Z(4AQFtzUUpi+6BDZ=qK2hC%a3&6AwA8QTn% zZO0faQ!&1D(c^c#!X|(qolR*!21TIzhQm1Mk`cj<{Vv%YtnYQn@!&@mVBTr0U>S_l ziEBHYDj%N-xlbJd>~g;sDsx=!;i0m@W$bimht+O1ZJg2JMyNI_)R-8mO${}UhH9Ha ztDiVP>rEx~a1@ z)qRPUsP0^+Yv1X{L0v1-9dFsSQFa=|lkAS^_Tp_$ujY|exVB0w!(yF%nmWkzwAF$9 zlC?J-A6qEW(>BVd^|~>}CEIm+gV%Kz(vkK9So}F?y#*u3olcZ4I`2n5C1fDAip!Yi z(q_2syo~P~macRwh{5Oh--BdTXqKuOM=|HNhLwX zi6HGlP>Hb)?bW-Nf2chTok}@4qvl7=U`aX0jU(S?c@+8Uwi2I3FrT8-*XmBxH|x0i zi+;h1`n%3JRF*rZ*?E{1;a(phUq=|DBel09V;4ngb0Uj{nR#Sk2QEPKY zi*Mtb@1_WL?Ia!!Yc-hG42)q==hk(bb7z0wu1}a|+he(E(AGMy{b_KknTxbD#pOmm z-$f0FA2qdVJ#;Gh^bI`Dx9CeOYzU6}LCua5lNmMCE3mliW{^^P+c6Utd||2PZYa$h z9kkYWBbRRy@(~MVSarjkpzj-1mo$;IA=&{>eYVDNMDZf4x}@xA&`70p(lLRD+b-t{ zLtZiHl_hr)UNz&tUX$?95Y*w zsu_t_Elz6C@fIAsXo*AhRcjMkJXV+QOodV`558?R#@e)ZZNdM(RM@vitbop^yhPuR zn*bbBEDVj_i6AwY!Rtw>7j16FBZuj3CW0pE1~)0qqB_yF)w;1o*AD6qK>`b5JH;co;62GpSDlDqp_5$#r;K&G_C8MD7%~1 z8atlWo+z$ftZZxJNYOgpqgR7>s?%re54AuCmi>z@$qQgxKNmZ9lO4S z8{F(_`tpDyW=klO_s&J3GBw0~G*q^@bnbV%>~eFm`EY}{_|%BQ$goiN)leB9s^lv} zonMD)$3vYLL$&Ln&dF|VxSJQeTehjJ^9Tcv% zm`c1&wKU)x@8g;c<>#Gw>5tXC^fb(lva)W3!}_ZF^rNe*CxukhD5ngyR8w+G*v4SlZz*|&Ld9Ae^;6cE8Jq=gi$Udztv&KlK_zwt zQ}H@Ej^uohF^xjVQHEnYzAP5ryK4|tedt@mcyIouTqx~$P%1J)b?@3a+6g7tW13je zAMat2j%rd8b2S`|*d`UoqACtT8s(3&vtr-^^%LKSF^hIXG!D`{uQ{)=UQRPupZ~6< zAu1!R`s-G1rpC=cg@S!nn(Oo@^pcxZZ-g)Ht22*l*2y8-NsW6H0*3wfq|aA*!{VJ0 z#1XpW`p>Nuksh=KzY)Z8>=5MdvN@WEUG}G0CLN?N3DV{j?+>tUvSb*uGgTUi^oc_< zOABV>^uoKz$-jTz|FO#)2+NjUaY3@edqG#9>KELbsD{@*UL!{ z$Ea$o^DU>CHr6});)eYvC8-o@=nn>JRNwonA^8(p1y&clW~r~O$X$1%U=A=fsgmK^&l!qMdSdF#UFk?LVh zbJt3Qk&ipn)2EM*)raEs#HS}&mLT5f+CwQH_*di+hDWxfxRl~+spYmSvtFO0!+VXe ze1+MB7AMZXcn= zsK?W6U0;UwwGnFf#ORUQ*EVJPmsd5{Wjy=+Rmv7({x!{2^qQuvdtGyldV{mSUf1+1 zv|Ew8-r;!`;%A6w5N{zadrNa2cnke8nrj1l5XOzs>fK4Yd{Z^osRmuY(AblreXXf+ z`?D4$|I}(_*~W2p9tLT*bhW7CN4vq{0mtnIDtGEaM#IS`M|3MU>>O2_yhuB-WAzfN z)$JwhnUcw&E^6ZsL#fh~UTLz4$|_|}sckRGoXhf+eYD2ImY~L%@R@l_s~owGQ6nvW zc|7|8L$=1td-kSd)%em+SpFjT4ULCkAysd%10_VI(}_l@!|YWt=rT?TeGKVgcPvJx zgoSY*(XKGpHny;YM<9PAB9RfJ-BDF>c}Vm&KKJ)=k(fLY=R)^#TxsksC=rgsYfBiY zZ!MupNy6=t79uU^S+;B9d+x?kS(<)Y%q$l(hXg%3K`iI_OOc$B& z+-N`4MXtuU_I8oE@v%R4mZ_!m1)XJ98P|eNa;B_n^mDSWu4}||a{M9JkmqFY!<|rh zwL$!-=j3_=*W1s@?~m$hI?L$C^kH4)ohA`WS%=ZY^%F}Ml3mL>%g4#Ck2}kOWY_nd zf)N)O?$1Y`{QofxvomStefjtH*H@x9WxiZxxV?AcDozRjXPzt+UHzGA0+py zlk*={Cs7R7%Kf6&n3I6abm?oSU*hXtvX-7mE5s2zR^9d!_MVe5U)OlGsV8`cljE?8 z)fuWkU7lkI9?&zSo1Uiipd2?n_4NhIGl*T8M&G@CCUrOZ4sAxTYy1n8cdoTB$o4ST z=s|KY?2jsB??*zW&|o<5$d?Q!O=%aih=(EVW2Pcpdsbgeo<7^zb$ftp>=HJ4pj_$d zUV+k)ZZU-~%Z+X^J71PF-CgSk$Ucwz+DmfQ6Nk#g9x?B}D2IB4Z5$w@(<+{SNtUL$ zUw=VPc_ZH+Btv_;-Ww$2db%eMlG#07Zw`{PnXbhHWLv&#`T!X*z;$(ij2qxuirpca zYtj(*G;r|Ee8f#dH2ny7Q*IriO(s1D-kpAI8J%*j{52GPY2Oj5*OJIaK6!t+NX2=v zqKjkNW>j{4+CX;P=i1mne!6cah1-zoiHjS`#_H~=4P}3I7dMz6sZn9{WAbTD*V2Zv zuI6gY+^lO{YapZR%|gDgzHzaktgdeyY$#jm8(%k+pXpzy&9p<;Z%YM=GcAaw(^dg6HDyxQYqZ0#sT~^>-FOivOI#kq2`j~>*yS? z(OUmflV_NlVQDk>C2PkmcSkWzyDW*L6X;qW#7ZKDmyK$;PvskTBfWq% zCvLX5j92TA?&f3Wl3VIOaAuL}3w>zeJS6Q?i#K3`aQu6^V_Yb@qW&i5C9LEPehqS5 z4${s9F_mHF`M*vN|CvTqd%cFDM&BnVr zqGhgcb4dDe3w-XY54teG;nw%+25z& zjxg?eS4-skF%;w14`cpZT|8}_W|2Y*%0=vD4wmjB-Cf_^*}LRRI|PU+LgSpeahS=l z@fO#NJEN7p_i_pCl6uw_@-S(H@P(1cSSq4f`4DUv@u{&)2DMkTVH%TVuc=+g{%|;I zhUH3QvZb>3SlDK@oXSmyc#}FR2{p$gTog;t7scA0s z!s#EVkt;Vd?4vDem9z3k#qXo#PpOSCYiuxPJZNb!MmLVkIm z2}>Ke*^m74xu$>1Ub4Fvj+@~wr8k$vMm|47%jq*&31MYD$e_A@|LSVh_i7EVS-ITW z%DH^2EHenzA#3ben|xri{$|r=s5Pgr>ehF3?G62o=f1FVma1IF_+`y8lw|@Iodp%e z!p3M5gYkNKR;lgNt-q?Vrn{+Fy(@jQ$752Yr=F+vxvQh%*GxC+n_pIKNz}TFT2MO2 zq5l-aqA(7MlM^9tS$G)bHl~%9@tm;1JrfZJW4H#yg>q5kGHpYQd=@>F5H61i!OT}N zKVofid^qym@j->9Wk$(}p_Ia88apC*;Uij6=YY&BeT8V*}s%I;5fWQY99wvv3wqB^n?J;B-+2oG8Tv2vL zM4)mkVh}SNkxF_Yk{6#GH4y38Xex`V(NUKwauJx)8ybtkiP)%f6=h1vPqnp`cCd9_3u6Vs zbc+l5LQAuNUWY?gR+TQXWiWW6tHq{EIIP`oue7;dW~p}D#)&3h^A-neQOM8vm(;4b zN~~RTmtE3&ka#%3WvN{b+f==JQGX2iVtX&;lrqPKEhzu4#rZbTQ;DNij@@^>yyh9H zGd4Gvp7>d7D)Jq+c;si)QN@_^-5aHc1p4wy?f>N$T&Qj?_Baz+4;@03$oJMXY}=^wJFHY z^LlbqdwFx!5TJ5Pxj{RQOH^?a8t3-)W@UJ?8ujHGU6@83u*6g-jeNA}=gsYznavsj z^*g_I?C#d~@6Q)DP4;AFdU|Afb3FO^-rTG_HLrRZKEsr{WwMDUGb78J=S_$esRRD- z9ZvRUrDmsPWTp4a^`zr-eo9K7H?wC-N;~XP_4!VyQSRJNNzf8n;fg0WrLoLqdJYN+ z+Z6EqTAgh~eTUQM8k;JOnik}G@-wotnhnVJW~F&^dt~Qi_s#B^-67qRn~|T9dS8Nw zBCEh3{?yF8lw5C4ZccU{+Wow(GV=1<56tnZ_*3F^!lL5piKZ#-@;$lvJ|2vOGe5DS|>LyXv8cYE#kHrpaJfkDnPd+fq`}GE#Z#M+&ksvNG};w(~w; zK%96}JvpA#jQoKr4hHjmogNE>=XP~E7N-MrN@0aT#Td3dp!7BV&p1$6K z+{~1G!mC!GQ8P

      KVL)tHSmAnQ4Ra#k;ljXk`FUr9RbKgW*!|H$xe8{{3Nj55oMyV zHL&DJU0Y^`|5^DPGR7X@GPsa2zMbP8Bc3jzOwbtjR&dFYB|Od>!J(gEeiSVJE69uzlOc)BH-k&QRLCs)N@Na}qqIaVBJ^WR<7SD-p^@4mZC_jCtz%9jeK&cXKUn>doWWx@I#r#s-{%^F;U+<^v=%ur1fb` z$8|Ct1CiYrRpeM{?*;sOA<7zsZ>*M|eOV_NzTSq>ulGqtzbww^Rh-1pxKaZz)6$c0 z52`SHTsS)j@j43IsN9wwPU7#lwy_Z_Q7S8XtE1Hfs+#&@=K<`r^+FTWr}#8^=Us!; z%Bk6H!N&J%EZQD4%HFEx7Rj==3CN3l zdW_(d$jtwb;P(PQL3>^JC4BGyZTPPj{7VSj#@*Sh4khjwtW6n%hVI9JD>oRL?#AHX zQpbR)a6+O7gw*{Xb|4-9td0^L=^M}wp-V5BWDmd)0j+5IktN&ncF^;NqNz0cks#BH zi6v}=2sc2)zMyrbk1N*jH6(h0HO}|ACtSRF-k62ga5`$lkF`0Vo4neSyO$J zt&rh^X2QkK&m)TENGOW-M+)7P=5GsGLAdp0KK$Y5pIlOnHr@hP>!1mgf)ZXg&Yuvw zDP;8$LJSq>DnhL0Hj|x@+b#-(`QcG`A%2I?2aM9~{KKqAy(ap7i(AdSA=E&f?1s3N zApddAZy8s^m$J{=X!vpr-xMF$pYgA!xW4*=k}Bddw0y(IC8`0EIju!|+X% z{+bsvX8%4StH6>qRlo+vW$QXX^!=7mO9#U#H@f5NL z4B<#)zCY5QiR&XyA=eGbpKP6)Pxcj+|3$X zO#qF11zf`NHIyVkW^pY^fZZFg8)v41J#(^EkyA364wNJTKQwXFbtjd$kT>$Xl}{7x zyK`_IAGeM4w&4F^?_A)cD$j(UAp-;noQW_Ryb(3Di8q3x5+`Z~GI9paKop{=b!)4z zcD>PL2DAkYOh$8hI$d@vExWBP`)#|Wt*zJ!rdD(Um;^*fKmoOCv@Xsttwyxmw9NN^ z-g9O$iLh(;`*y!8zaN=%dCz-&-sk>2uT>rNU9HEzR%>^^o$l|j`%Sl0|Lggcj^Aqk zEYz*3wQ^GGYr2ncjCLk>6SWcByXY<94dmFCOo2e^=UM zfv&lg0M{uhmoRPWR*g@<>7ALrn&CD$Z8pq3K)?|-(rW;dnn|;)3r-7FzwcL~b}-sa zi|;=ts1~E%@-KxtN!+P+_U2~XVWkZ7SdpSC_ec#F^rH2$UWOCF9v#< z*IB;uF$_}8tljB7P7kYs))_^HReq{b{d;>pgVCK#?(cQd)sy1MwTEkGVq{)X!-6XK z`9P)-0yhLEO_I|P+`7x2IoLg8iU-y^SiL1OhU{nFL3CxUt0fUmXT1LePo2{e4%mOl zQ>(;KqIlf(T-m7!g+J{{^0Y`>ZiiTq9Lt)c1LYi6~hmG>ESv?#gCpgQ)_}J&w z!p6s5NAxyn>%(Ih&XO^V2ah;5!(>@BP&S|$caOm;$Ea%f?PO$2##GIYpK&t)b{(un z58a|mf-X8k)|A=SSbDyPBPbZlyM{G!w(o*hX2*+P;r&}Y0)5};VHn4xkT$JPKIJgT zRrJcRhKGFaa+Z?J0~Fc85L$UokxxRFp8>acWyHV_+oZ)SV|Fg>kp>y*H@&&>w|Lc9 zC9yV-?HOP@ws@sdB1qL^Y4~ZD86oGOUfH3;rp!rw9`Q+W)0|$b8Y#?9alF`>xZT((h0kh(@#j@*pYFtXx_#Lde)ggPzyBN?&l&APZ-4PN#^`b_dwn_Kh8t7NzY zGU0*nB7o5;YLE3)y5ufloToBQqXf)YTr$gNlq8#ob~&0G9Z68~{s%d6}x!GWmSL_}5E;(T{=fS3}mjS)N6?NrFMmS`KIalkOW!7m(>(`dSAe3?HoPfejy5xqcuL}C=Jx#xt zZC=SIA*&Yk^~Qnr>X6wZ3w>%Ye~nZ7SZ=^Y7X4J)U*@n!8{f!C04SmV~z9b8Gk*g$z5`gIsP1bX(hb!OlZG@D{) zL0@BFsAJ)EMcrAIS~`tS{2@fkqvTrHi+mfCDlrGRP)ZUcg<3SSrs*t>cXFs7O4`bH zB+=ToS}Fis+S3^N5Hfe6PkmGjAsjG;E4;*1k(fY_>-ALA$}f1*PKguO`*_sMLif_1 zq$BWe0NJ9seFuKQFjv+~7w~R0D)%k^oUN~!lu^bj;_0!a{*J<_wU|l!_oGk?5gt^N zHAT8F(%m$(dFdks;rR^RhCwK49|hLxrkm6uJ&o8ynCOKBP-aP7#JG5 z>PT;PN)BJD`HMb8n=%ja$pPtb`qcjS;z3f~p_*`UW@Az~1*OoQ87JLlWhcBZ-j{@n zF*NP*Bm8gICmnw7K{bgR4o44Nt;V+e6}52vgMkS$?UX%*aXWK^ouk7fxsY&II^~&Bf5!f)EuYCpkgEyyh(E_u>g=d)d_zO7cS*W}>4uy-Jowk4y17RZvw0`{tt?KcE982S0*meoDo0COEMYE%QyMyjR)L^ibj0;vW$^|#M%N45R zu*=P5M)iAION?q;yXXTx38CuF$P=k1p5({B*hwU2nU5(rn%erzsAFmZ=daNodH^7l zs2Igw2VERf#{tu7_iGQA19d4mrc9yx{{9-)7f}E#MmTzd(~O$PaEKcDGR}YO9-=+$ z<|E}`VIO6c>XJ<+1+G(1olpl+B|4}IB~uYy+j{+2L4ay8r=li?$MmTM@Dd{Y-caA z0g*kaiBzg~3t6tnclB>>O14Csy(Kv>^(kdX5JHp3VPplW!Sa+8`!AbgJ<|VA zp-1)W|8Js47k}gbE_(Ej>ztBMOt-RNHTIllB$PJAS7KyC#Ft$@=RMux{Ny< zh!K)rw}qt6U=L1;A|wUlHRFxycNdrCgrrk+7yKOj`Ntw8{R!4r>HiFotB)wvAdZem z{M$uLx@C3bdP5AO$CF%~rD7o1a#^h{bll zTmEYv>9%wNk<`kc~bBmzSxXqGl83Mdb+Ji;t_~86GZ(VwwTCB*Jf!hw z(Ej5{3vBl&j7d@SLQ|P+#|TNAlsI&9Rvc0oBJ~&ztM_&J($F6f15(o{37CMBCU-bu zP`9mr37PGrHY006(=6l}BnWhfO8yyK+&OP7SHAJA{PLn(vE?6a`PXSNJxZP+4r$Bp z;+F1f(Pz2Pv4!=dw3c6Sjq=mk?UO-a_Ibqd;>*Egwe<6tUKnWxo;8mjA!k+}s}Mxu z!FAQDmL8jgi(G}yw3I$4$!->TIduz_<|LlACzN>9{zBqOWOrAW_~kC!d|Zj=1oBRn zzKDl8$m?s0zHIpm=u0<<>))dRJDjZCJ`IN-O zxi>^k4k0FyZq#gSN1I&yRlj^su!C$6hCzyXA!*CGOD(ZUTActe^BG;Q^l`hfs70hS zhK1~Y)p5y%GJsa`WJW88Dbb-iO8OJBGZwYn#(`=%d;ml(*PXAH6U~UCJQ>h@znYN> zk56>qCLlVtR!&!1xsE)o+yzSou{kr`fEGZIG#{KmBPYaWnIbmNIK<}u!Ng{;MsCOA zb92OITvj8eh|Lr}&CXB1KCa6qG~qK9p}0-7Troirse6S`WXqpWS?4UXt*k>+CkzAU zoZiT9XYUhG=c9V{vBq&hOS9dfLIqF;p5hV}ApmOs zKnus?=6Re>y;PgXoX=_RSLCzNRs1 zYlx=&Xu8tDw?zElAQP+}j;~Ewm)TBRIQjv)T3`>25-#L)Ctryt&Nka~O1$f7*;e5N zt22>rrLN&VxBi3a)iVygnh(9Y%b{1+-K{obhYpXeE$Bmg=n^4Vg3=Yi%AF?=G)cvC z1BT=qJdH&2EG}Doo$kB5DWn{UYS+8e{%-j$a0opE>#RUC=d!(wIMT9~JeBPj%gTb) z+r#&&Q$aiijzX!$^Fx;29jey*8edP}D3wG;sINHWgt&u2HI3`XH%@)R9a80K{Z)>n z!oJ15II}gqMkPZhfzUosL@NY#*{Ll*N_=o_%RzE0U?b_-AD)%d(7{vfur+j@Sq)uo z{GUZXr)RcCu+zbd?@XP-404$o{g=_ME`@#BkYjOnI1%j?L}SxEl)ougzQuHq6LaRLEw&OFT%w6@7s&iZ2nvJB7yGw!6>Sv ztW1RnlBVKfS%X!OrPYunvHLj2qI|Nna*<%amG&G8SsGw05`G}hSR{48Kth^C@)2Xv zP@ZVZFH)pQ8H@VZ^~W<7Rpdz1Sy|Ggj75J0g$RPkt&dHg-2VgiqVxXgMEW^JhO+h| z378vXFLM8d_M*gUX=$*2&ZbV!D~Sku(KAXS8elK_sXQ__$n4toBK(>L+KY&Pwe3ZJ z3J;)8Uxqp<@{pS^>_u?A4SjNQQP6ioAEJ?%ivX~xJy>!&Z6OG+tRUiNw6l*B-GZ(^ z$=M%@2BmEp#Le@OCsVK6Gzcq^0FshVm3>IF)o~|%N*m|cgxtDIY(k)7Y(hVv60r%< zj~NZ z@=q7$pa~RL(u^`8r?x^=)cd*Wp;M?pDxSli6Bu*`wU@K+WbHvv=D)}uWS7s`gHSy< z_MpXJ_^dss|LK=_s_a2)xzLF~>S2n1#I@LlnB*B8+{2(;k>RAsTFwX=MhIdCt%|;N zi~~!=XoNG`Ns_XlFwl%w>C=Fp{L_SL4gur()?!q$pHD&OvO9Zm+Hrep)@7w4ymu?eTTtmpi(vzzeT_$2i;9AZd% zx*BxYjkhwiC9sN42h7cCfphyQ5FW) zo3Na5P>B^1?o2kF97AQ`y7l*o+NwT@%*L8p^?{)U_P2=Z@cZdgR**TD~oi7ypqj$snineP_##_8l5FHVpDjp$}2(~#;I$X@wl_1i8V&a43^+TH& z89~VWoeqBbKv#esz{3Ie6W2yPKCKr*I_*1n<5(41iN+tffI0tT{erTtRSY%?U_f)A@zBF9?al3F4 zFmO_+v*x#j>q59?EiWeZO!jj*O-P_xz>|pjBLTD5h%4`ojCamI3Nc~V9y?o$E&^kw zHnF@b)cXDr_Di%vB8Urr6fZ8siJ0|W06e{_`r|?<>1I8VSDf`cEbFQJ7SiN)1mO>z zMPeTt!<2{Auwe8}aS>oWyBk5(FL2%w>n8HefHfT>BO6181t}XcUr1Yd>nVO8%D(}T zZ9kBm@lL&mmBd52@|f0AK*t#*<0o5id1Wv@ov?z9taI0__}J4UZkBP8j@}q0D2s@* zV+9(UGJ6F#;fy8D7V>X+P96aTGUbK*SKd-VL0Nvap8BL?0@<=E7t5+#?BSJ*|3UKY zx3i*~)QUbUE^}elpq>2M%5}(DO5CwM#!2##;g-K{w^5CmzG#A9)Fo z&rfI%iR(prcz&SEa7zRQI?iJAFb{(9 z$!_#rwb4U`;tpcfx$8sL+#1hp%P59M;<_jf+;7bE)p4o<9*b}ZL@+nB1>^1-u0NoN z(wT_=mo^n`4xRN)L(xgh#MBP-o#uT)0?dVifAC5m!Y8 zRX1fJy?!1q;>`l9&dYl4>H0fE{QwP~!RKL9px@*AXvq;Pi{LYiX?$tb> z(>(Wpucs;eDVtLBOhR&{j!l~9eh>A$&hcB_1OpD?{|pa*3CnxJ^e6AaM}2H^t>OwSHiKJ4KcV0q9hAF zhOe%$uj$25ycnhrAIJJq_HQ0O2%1b~U12Z1E9}elj+F3a;g%qnd6uv4^zO!2_%;=0 zV>{pkM)N7JVL8kUF5GW+3w)=~UP0~j7rab=jcWS)g=+ds;HRLi1JYlzVfPMYs&G{@ zhRcN5nAotmFnorquW1MT&v4XshBdF00|5rmBivf)uS@#tlK$EsXZt&y{u*FM`rGC7 zmlSM}Nrn$n=>;3F(c|Gl(D?n3Q10JMe`!Gdk_XSj0adx|Ux=gfejxQb_V*F?<-+89dJ< zu9QP`@yi$J;lJvnUAd4$*B<&wI$qh9whJ-eMJ~V_`68k)@(=PPdH>SONX{Dfw(CSX zORBYu_l>U<7bth*ot$^tB<{v!p8pN+Rq*oejQ9CFL_^R4A{NfUYJg*S^{?giq2!D| z4e1Z(7^KhmU%(G?0CY$qSsi|m__5Ez55|c9{g3m5Meu_~|I_%vqJjJ%?6Y``!w=R9 z8(234n^(bqIzRZy{Qt-K!I`)X{LkSBo%PJ}gGK+v{NTm6|9^fEe(?9Z|Kt2%h46!S z^z(xV>-qek{ul6ry6}TV!Vluqn$HiyD}5Gz5L7db)Osi42P;0!4;E$l!8?w_59*(t zAJl~(EE0YY^qS8P7X1(Ng9?BCKg187KY$-JOpow_NulgWhj4{?4B~ic=pM@Xn`po>`Il>PbW~uOk(qGh5C3V&GH^>-@y!_8*W#4 zK^Q`MYq*km3}GqSEMf~2Ir;Ll@Pn$q|NHTSMfv<-(Z9zJ!l#h#?tcq@@a_u~KlsE| zIeu{a7yJ3a1F(LIAN(orv;5$?zxotExb+sBAG{*{Z}EdVDyMD?OW5#9t#K%5a(Jz1 zT*ip#EeRW!??#!1q5`24hI)B9*=sT82Ydd&Tf}t9?0c?Q!>nscgVrpaLyryyeZz1J z5{54re?UjVCva^R5y0+62<9C)#a$EKh7RO1E5owdp`7G!o7EO@vMiG2*V)$41XZ+!6Y7ybD5~U_m`BlUc z8durjyaz#R-MY_R4f2(cUJT5{AjH2gMVAW3l`0ePri)-eJmfg$`H7Hq4nf{YlsicteZ>E_`QJk!L8l_5kY*c( zku6vlL~+So1^bq40@H{&o+|gXY-5soy}+X?zTL%#ZO(`Df-+)Bu7Dc?1Kvm(oie*6 zAEVGjzDLZaLIS&xJVe~4a?z0LW}UABIw3Bov(@~uAu5#oo}8z(H;5w z7?x|J`fY7_6irR)95gfm^LbW3PrePvd0uh=L!EhdLfPL^;=mRZC0NMyClthzQO0oL zJMu|w(TN&&nf=eu9%uNXObo1LFo6Pfuo_NZ1>q94tX2UML4g+iB`QR0E5Pv=fLWmN zcJb$k7Zd%4=)DvB7Z7kATBC#Lbek@hdkKTJrUZRUnMOicLAPi}(9}FQ(_GS(W&OK? z(LEGR;0)H+xQ!_be;y+Ipl*q_G2C-lt#F;h%u^f1$XS$L>G(S~v;nq%w!wC6t@wmU z;>_Zkis@g??ZiEP9L!oM#!JRW(IbjKfbv<4yV+y2(E)FZ44t$yeftWDwG;g>vAyg9 zV)zhQ^YzV=?@)5vnDz8sT=m%7*P{FFVMsyI{l37n+EN&z7f^HQ=pPeR#K?5Zv8kJs z^7ky}>pD^U;^G&ymh57LOoYJPF5s<;JaUHB&=$TXRQ-vz{1A{~cNEXcoVu6D$WT|E zb$24b$!qb@>WnwiBHaBa;1qDr8qxMXh&GY=w^!?zb~U%tH12?XN|}$Z9QGQfnawGu zQjFa#8sDj+ZODU9^uP8R`l=j0pIKcbNlnOabxhWeP9Flt z9PQK+?s7`*3T8T_pd@2$k@ovta9KMP5~9G7^)u$lfZh#N9@1JK!TQZ4NbarYWt|OI zDj2_>MSCf`!jYm$2W39eO`>g%zRmhI$@(1w-t0I1FfeF*tT*<)pt-PrJ-_;y*7HDQ zlmB3+E6jQ_Obk@<$%|Oe4`n@j)Ovo%)R4d6BW-z*5eSYUtwl#x^NSK!7EAd{?j*yx z+Nt}{`^w_xDSp4v!)pGW(&S!4-P5FMG7l8?BWrgpxN8{i;GqPLc$-t;Wl@ldpLb&C zna5gD?TzY6~spIIh_92RaDJlk-(uei5j zm(9Grpu4~?cK1V0ICwulOaDux|0SybC93}=go3O7PnG!p68gVU`rqZm|GV)CF7AMB z1p>pH_~TDv4HH$~&72pet&g+?T0fMe7q}bdGPF+CbWrjtR$$S0! zJD3XY2kP(Crp8HEAU$%H(!`NHsWURSWlQ9GG;w-f$eud?ikCKH(0+o%03>b*GQLjR z!?_sJPObr|GyK>Su9hv~pJlxDaBIS$UHPMP6eE|MoMYsMUXRf>KI%Q5*!u-akntXx ztGG8JWeb@b$Obl9K_bI>PO;?Tw{k4p@$9>8B+SdV@9O5Ul%{zlEqb`N=^{8a2|87&wI4u(`f-!b5dLk3%8vFz z(~V-zN<9L^3x0&5OiuZg5N|R`@q9JU^YOD}l?qmGg!I>yp)FPQV0vphPoW$0kR(!* z4tP6VumH1({=nncEmBd(|maH>F2?c8MBp|9Yy08X!yQA^BXHpO4yHhS<*_lakqLfc3de76u#hli_kvBr7JZ+V5#R zMSFOh!gWj`d|S0ki;mzvRQ)<;X-uCX^L1g3U=YvGnxx-?^T^3t{r2eebeX@9rK!YQ z)kSob9CD-_XzvZQ5UUR(64*qB_AM$2&^}cD1sXZF&_o(l%03O<7W?FOVPz@|OZSAt zN1u#fKbJb3Fd1`i`nmk|FsffAVWs)+nXz9@%>ma5eYT5=7TRn`7-qvN;Qv~{)@r~2 zExGh=>B_fVzoBf`KLQGD+x4c%D2$%>PtYt3V0j|@MrzuTr%E<+2A+) z4oK`5!t1qV35**XLC(gl4#w-s#oQekDG4Wty>CdQzpm(?T5{5_O%cP7Si6CmwxDZ( z#aoIidOyJ4t@jDL+Dn&)9M|5B(GZgl)ef|G(>!VJPh|3D2Mq%T+{2XYbFmD;Jd|a7 z+GI%uAh0Roxnmo=#Suvi-l;sk=fHLrT^#j=J>?@r>3igk6w9{J8&lJ7d0-p8L+1Nx z9!XXYZn#CZdK2qaAk+!TPDHI6dm+3-;% z!&R6IKxkAZ0kdwSI;BP5<6Cp9n5d!~d)4I6Po%5*@gp9+LXrs=37I!y>c9$YUR$a{ zS2ki1CHP)^;$^(zHA8P{_i{GP<+5omky*P00iPpyFa}ynE)h2C60&4n(nlVc--LXw zrYCjR8*)&LVO=kxsBJqVVu%2J95oKR!Y!b{^yhN^aRbI>n*x#0d$pG906%HUh?mpc zX0pOaD?2!2gcp)Kt8r6m5|>H<#P=xLn?LmQ1vdXhay%&zG^d2jddADHFm=WYp52H= zwOwoZDW8cC7?w(rkIoR}a)v^)K{_r~I%wd}ofo(=RR|Z9b!Vvy#cn0(a zec|DKjXm1KSMeg~^EGy)CUeDVE36`k;o~*KB)fquyHtw4&OpRUh(53 zFNWBV>rJ62;z41!wkory;@niKMoI0+N!*-N4c6iqEQKQ~6L$WD7sHVdJc00N{}84V1kSA?@!@#tBcTYE}s&B@>!q-RglCLfG+aegZu$-<%Pj6KAS;&_3VXtvhy&x93`dc&Ao?`&|Gyyr?4lUI0tj>#)C z6q7fCC(1yJz1BO^(a&L77JDrj*3X+^Gk5>EC&%1<%Ktq2hj|ja$$=3ze9PT7e<&c-Li7J5(0;uBsH2saQ8E{W7;_YwH`_cacM&*9N9Lp`Zmz0Z#=zw6>SChaHe5~|84=8$u_fR&Y@Gv<` z<<6dkhByWut%WUUYr2#G5vUjZvY2Ot)nj*wL*NmkxDkRh@xpNs-RHipTV~@>4s=_v$1qb)IKZl3|vzX9tF`^qqr|iabGWK z%a73Ykogj%QPPBpL!d-us(dF665Q9qa0RpN(WCDdKC7;^X{62Bha2=Ucqk`@n>EFV z`_VvbA${aT(FF-$!wcdCL=wocqj9S6NKVGtzB4A$DQ&%R%nnLT9tq)?uy4 zc-y}!DjyV`qCbB}SibA|qlVKzKcQ+s@gC|klwAhk&H69CxIjOp~ZX_C^{Nq>Q!TrK^Th$b#u2jJJ;xGPk>D~!L4lon>x20wAV6dn{p zy({&)0AD_Qhs=LPzH-~}r$XB|)+v@0A=ze0{|WX9Z5(h9+0U}1#gh`UmI5~EdmZ;n z==wzHI#V*O58TrgbZxXt<=imAu!H$^+aFWZ9kmJ`ZLU;Y$J~>6h)o3^Tv#svahLKc zIz7jSDhQO4aw=%IfT3bQZ>Gc0o$f3Lx<()j+>XoTeQ=HQQ%T9_OECelz(Y!2Vjh#H(a=Q`0F>QkBUJdz*YxvC>ZqTMr2ElYw0>FY#4oKcE zqEaso`YtidH@T5CuDcv+1d}rvbIoMbTz9uAPfD1%V)Y1YryM9dQ4)oG#$+%g(mP$n zc~ZJr5inn}bMc;mH`=B$fAj#}lb~Yj_Oh~>R`HP8)?J*UQk_C!ht=eT*}n4OLLmfV-%ANpxfor>5xl2r}6D8 zEFD~VB|n#Fo+&WpHg7(s%=U^b$LIepVUfd^@MOs)Rf>_%QP{={)lqA*{$Ml5w^0F( z8&D{8n0bdBH+|jglI?D8PoFyg{^8$)W_8H)7wJkTEq z;ah_1;@+TZFPS7^eK*Sfl;n|P`lJjAZjXAxkB8zj`Y1W3mq?Gsw}P%$(m!-o3KiZZ zm<5`k^83skEJM0f@|kW7nL|S64BCfB>|`VNNc&p^4^g>$wA5Whw%;Ojr$ws$_K+2% z{g1Qlm#X$LMSrZ?pVLRlQrh1o?QfL!Kagk&Af=e?)CUb;Ys8m~?9)l8XtOuzhAcft zUpXJo!nbWTVQAbt0uY9)o97LQKr4q;zQrx{voot%lt>RaVc`=D*IUwn0E0Lh5;%Ex zn_-nI$CI6?8x7xC=qMAo8Fq=A;Q@GBnBIt{4b&=nBJ#-01Q>i1pqZOxmV_A+KA#UCJs*Z&RWH(itff{Ro7;`4_hXH`{-Gdo$G?&^!2v`N-a4gxu-bJ#i--pT__S14UQ1}9xk3lx!6GMADqcn8z% zCaLjo-Q*?5>cNW1L&=2-fb1Z{1W|!V=!_G6c>|cMK(g%r5Z~34^Y|HX=@7CdG>yf6 zRVzwpvf}O_do=pzZm4lP-(JV#;0$YQC#l~_qy4HDy@BaR-O!2CJ;6bxLGxs$vK9@S zX9j;tbon#2h|fk)DkM!4xIycUf0sIgPu0MkKZEtLQw%wx%luGIsS{3poDGnyXWmJw zsqg%Vm>)UHuE&T+61d3r^JfeLZ*Q^WHgwy#Kr$9vbGISVd)(XTnY%p5WHM!C-bU z^AScEhtdVDvE>+27eN%-BoR44(>>{+ZGRQJcQprR6)&1)VaF5{)kO$J(lGBQZ*rZO zc*P6I-K8tWxE<5qUh2Ul(nB>#%+`&+&4b5KECE9u)ano!PL;N#!fuk-cSF!_JgjO) zQpRt)o0%xk z!DfORaZ2yAp+mqCcVQG*&(xW35$L}*S&g|BK{$Z5()@!0ndpmRft|{q6#&Sm+tyJg z!%q%uSf!X@b(BfjkhQ6kwFwMZ8+UeXYSr4zm9?2HYg6m24Zo~SzyFc$yI9O+WW8=z zYtzooWNl^~7J~zBPwjL>yq??;8`Ac2Qqkb`Ir{1KA()6n)BCZueSVJxO;8n@%DFS!Uo)R6^2mwft<>mT}e=A;}<|lh;KSs zkFDWkH-Z~EXlT<9l6)6UkoHJB_%aT^2d>-BQF+*QZz$5^OZT#;pnA!xq8u{3bgwIX z2670RoM}adc?r0sjNHe!Y(m@R{bsdryGv2NMUols1Kj0ftHJT@9DoR}(r!qwbJmLe z)3C1gTbvpZS^abwy~uc<`7-rI4`;%2gXFwbqRoEUT~?uCecfYJ9ww~_ry}zRU3qw{ zZhgH-q$DbUvB`J?bb!N}LTq%JmhYvZn8EiE4 z_1k1vY==>Ij^nDjD{^Jfe1insFw@(Ia3o^F#?o?-;y zd07qR=jm}6=gy%b=8KBcPpU)`sV{&i8Ks;Msz$o}6duszJW8rc#7X2}#;aEs7btej z=CrYls?<{lk{Z&8OiSudT<9Do#Nn#RttcuflKj>4LufC2`M?#)(vLay;(8U^8TQ$Z zSQ+nDN~%CzKF)YIb0@U*s-SsRkVEN_dubGgKjVFiS3&cyJn2(|od}k|PUkg6G9CPq zyqd*Q=LxA3OrMkI(DjV>HoGIa_Q{nkvmjuJio;r1q<6}c%_#-{N1p4;!eyCYV^73;TjtsY+| z@17pTw;69ai$yG_D*_6>@+YS<5^EUaj7&(+QOXBqP>(n4O+NCGKz^4iGF?O=yHL2w zY>&QG7{B&d^yrYrbM@F3oEcy};v1w{`XE0YswagR?@hBrJin^55QR`ddYBd1<~N5E zKr5qW`}n`e0hsYCTj)Z@yI_hc%Ood1-ZX&c$y~$_D!4OTDhJ&Vgc=`u z-{0Izj_kTFbp(2P2#HRt&l}c*MdH8%d(cW-gpCA-z}0C1+)?2Oyc1 zDpc0VHXgn52AVDi7iGM&xk!(CPLv9h5*hD8?A7`zmbBT3ubT(ff0|R_di=j}#e^8HKn!5UK_Spv2M!aEF^4%3K1?-La>wB6^tyitDge?bFcLY|ktWi<6 zTIl_(T3xq;N126Hb{{131A4%0^RZh^vY_lEI0NL6^g#F`UPm%a zDQeMCKxFy!qUI^&nK~l#PTZclc^m)+>p*bj7(T598o~W-W&Y-x@`4B{wP#l7)(9AC ztSe0R+ya4@x;||sx!WQM(b187L9!_5*3dKQ3mZpGK^$hvPQC~%ezbrkF=G-vFNZx? zUxh4r*M0jQ)=j0>$aueukl^p&WL?gTR&ZfWt6-V>&#SejfmiO60Yr+?&t$x-mD4Jo z6smQFS~u`0U=8!j+2P8|jjK%LRzdL0V?j!^h56;U%=PKN`QcYw$1b83wUss>3p?dHy4D8IRRu+)?$kdX9Z9ohd zeQ8#BwnBAmek*ul@v-|e&z?p%u&bifNsfuJv8+3Vs15gba5i-MX@B!l_Va}lzFi7) zdTqAwz7|(OwqQZ}?^Ho8CMlJG8mwCdsb|%7h~D_Y8lB0p&)H~hF#O$tpo}lZm$BD< z&Es$WGgCZE;r|bH>$2#xeO$Y=m{4Cm{?K9hi3))JPOhvu3|mJKNw9UbmUHEqc?+}7 z5eQ=Un#>z4IRo?;oL&+#cavN{9x5K9cnh2t-4O0cB@wS{y_@tR z^P53Qt%eQqMqI%<(%fnz9^h?Y4ZoBKpleVFkIS}bO&6p87Y0V6!=hmHs)9(6qus74 z@>{ct&Cn)(MqptGaRg;eCVUavLaSkudBa$9c1i1W7|z9|DV>iE^RKyiur%f4hQX!X zGM?xIw;qcOSGhUTS4E%g;vJ1C^XsyXZtis2(^_6*(1Ic2OIK&Sv73tvtiWov0$hXE z@}|7Q55;PD(rj3P-^7n#@|w*X&L9;!d+>5jc-PI@Wp*l%_(QUqcnbmboKcQ>WFN4X z+`9RgusvWvL?G5SRt}JA>+6|w-P3$D6ZTpQM_9GR=Jc`V;*wS&O|whWVQkB(qc*@% z5hW2((qYb)LoEek8LZ=R{4#U_AlwDq(2{u)p7kxckf z>-rJaqGB`hnAz~tRzd7=t)9Rdtt8OGh&-Lsi}(U5VDlaMD3{4GJ5sOFZK%>}Y-rG3 zg;r_$rR3AUm3BEplmQF-C#$H%9;9??lKRBkrU?n`MA??{J_7Ft=G(v{(iO( z$$0;OKk4ATSwZ)e&;Fk?-Y2CJbCciP?Qh;E#!Te|4b7Fbjq|&N^Y{mf2{YEurZh=i677Xee1JBW_Nv%)>|)r5WdQ#`>Z%<4 zXzQm70~ozpcsl%w@CM&)ZcJTT?6S)YgaOWHlO3-31EH%W>e$$5_3ev>PfDbY@~$I* zV>+})No&?^oYvE@2gXnlcpKAco@r%Jg)+v{#vx;h!gEj!P_qK)fh~-zW+HI=TLil7 z3$*+(GJ^e+@xHBG8Sl$LH(@6Zvng&JDWhH|btf=4>7IhfozT2C`WF5&H71zm zE_ziU)qsGg=6h5lLYK`@swL=*Nh&Cz_noj4{A2PHdfe`GT;+^pw?aIUZ?uvYpp|_B zt0H6-ln!xY?T1fx!F$Q%#; z`@{voS2yJot)-p17LbHx!LG!Dvp0rc_)vRhE83aSXpTn9p&b~!qlrJ0jHQX(H5+sG z@{)A)zk zo06IE2<{9r9}4Sm|4rvU2XAxdU_b-Xtf4=BZdAdQVD_uEhkwGP#8LigPmKCDPqo;0 zc%ZEx`YmqM>i+RMKmy!>^aK9v%y=*G*~`td%QD`56^@Ln3iom+g(D~fC~OPW8Lz7n zX+_gJ3mHHrUE+TRIzsK(j&1`Yn>^3T^FFQpQV*?WwwrxIHl91Qci~xJU0MFDY}fZJ z@4ZjsRGXSd5m4eA>dC4(G_XsF#)=8m=?A;q+?1<%y_CzV8La$f@~w5?(fF1BsOp$2 zb)=vVpU)!(%x7-?8vJwT=*#{fL{Oz;LPLDau>KlEGb9vyC)`joF?^$nj+s?7wRy?e znTcVqQQfPx)D@CiuETxyM68}6a{(%sUh<_Zx-w4z!Q{!&I_674uB|@`!h1VpE%2mE zYbI*3{nDbN3Bb!R$}{qV!|zK5 zKH)7m|0gKo|7usH0vTh?a6yQHZg7Mwu@d(Yc;|P6Io8-&4%6p=N!L(A7l^Da`2d;+ zDHeXE&RV(+b@Gp}7~&v8{h*e;03ZG-Z2}*4oQfNsRA=@^dkf?GG15Yd!XObo3+HnL ziZa#TAInciOgf5WS$P!#O*E4Uf02r5Pox3$j`C7OsZoAcPoE)-k!#KF{;JER>hXGf zDnO>{=F0(fzj!5l+ESEN-^5`O{us^JvduE;Janbr-=!QXzYa}m@+4O)`QZ)G%!T2$^msssMYe%NduS}(Ozjjd3=gw^l)?vVn=|LvYL8%B z*`rq;(p?|uhww1Slr+s&N-%|el$7N#Lh(%A{C8T+=RA$eSpks z@yQDblI0l3pzCntwbTW&y;KFy;gJMOD+hy`-G(a>o-PqcqK$rc;ia%;Q>o8Ib-Jqq zV=i?nxYHiqPtQ60v1KQgm+)rAyiGcodWokHwio$Py-jW6%7_nr=%8$8StODCk0u|2 ziV0k3EgKko>P`Lx&6gG3{nWlm-nd_2b-(NwX9K1zRJ-hdwF3J?0+nwj4?MwkS314b z$!jLc`!|zs@C-Tj-2Oc;`yKWIN-`W!hAJ*SoLuz>N+Sab^OrikZ-4RH(ptF9Oj@id8S)5C9gejitK1LKA_Uvl<~fE4oXnr zIpK>G{u2aD!ISd~X1p6HChU=yfe8BFmiit%pSrUDWa&W|IFu*Zdx1;2cg9ia0h%TWs=@Iu#@5$)pq$c|x$y%_RmEfC4 zQeiUrwseI@0IHb@KS$4#o7~R8VZe%wcWgvkkz9yl0aFb?WxRh!Nt8M8n)F0XI~&ZI z{%x5F=kYq*S{{A|JIk_}FR-!f=C|6-d&LaO=UGaUnNUFu$PZ%TgKM-qa&*MAPDc*V zk-bVWTckRISr_?!ugLe0v=_C9hZ1X;<}d__a{Z9GSEvwG`Dtn?-pzPT6i4Cp{L+s1;kavPKKXE~tuH&FT1r;ra7UmItTv}w6r7LJwT$<1?7sa|p{}y)DW=*I zR?%cq<4Z9me9xXXc`s)~s=4}j@KT+URao1d|EpUv6Ml{LnQ2Pe(=>3ss2)6o3i}NT zp}LZpiX`P&x$I0GOpgYY3-X}U+OuV1aI2BUz}_Jp&YO<|?=c^BG9QZ{{_OKHZHml9 zoH>UMjz9iiK`+05Gdhe{!dHOI8r+r08e zmz38d#rHtf9pyvFJQlRRU(OPuo_=3c#T@hAQjQ9gO`=Z2OA`fhS2@AIE#(X4DKfOO zcM{JVJ1hv${ISTrl=jF^XG~ZoLc&=quXu0-O z;2{jcW%`IN*yL8y*x@s3*k`P9I=#ddwC^j@N8o_g>(NK_0Z`3grB-RwRCshg1>N6D zvAI^LX5x|N6t?9TVJ9D z-F#Gl2AQ#dhIDJCS~qj04RPxf#K9KHJ2Nf|12oEtu#{Ey-4y$$R{dZCFz;rv5a?vl zr_eFhN{TQmE4Y+mT&~hQ3br**T(xA`O<1Z4&9hRP&?+06QSZW*p)bHWm|s?~A;Iq& zY}4ut*|Ap!<8QWaSf~%=owE&uF+>T_sx+o#2Km*Hbg?)_b4hM7v$xfr zX44*ZZb!=!&?`1b-UP-~*itM3L?s5CPC!QSx5{3iAf+a03?Q1 z^n(OImI+TK^cX(qo8{tu!0w(~E{Ak0G=u&#x#U!}U^XnMPDa&BSgjNh+o^T1T5xE; z6pqW84m#JI{OBi4Ne)*qDZi7_qOI3P_G8mLdhEzcs~85o#Cwwr@E?h$1O7LV@jiB1 zPI6@P{|k4_tk&`qAQmj3q(@uA*u*Pa3#P!XTdX1zwMP=^)1XQTY8UDxoVWaT%e@$? ze|(>U)}_rIf!0iG;8#dKYh6Q_2nC*TwQ-2g3?L}3S0F2BPkb9{Mrbk7N&^?VRAH&K z)?k?-kx>i$%a#^gbdlEbq!cg@JN{DSFP3}EDE{UpLo*iv1wsVLyZcR^gHQa5s)j1x z4PTP+{(4;gz<r-3>QPr*_RBqE^ zmP`gn*}A)#PPXdSO%=NDrqal0J^r;)_>*bOgdhQHYMIX2FXGo{UQlG1w-=!k!qecU zityd)CH{T76)uI4%q=}^nDAhSl7U~)&!{g$;6KMsi9vUw(@9K$gY-z52@hi=cJvWW z@kr07iitIO^v5G%D@p;u^k_%Fz=)H4u8r)!-z(K2SvV(}(s-?oMM!l3zL2+Ryp>6O zz+qZU;}+~#X>=Q#WG+t`FqiM0!Ye!xsmmUP=o`D7ih6h{LQCb3^Yo2_`IjO*2o(SF zl5VcMmF+14iFG69pRXY7Z`g~kv7(IolP7y+f#d=FjGUItuDOE`Al?G`jHXu{ldT^o z<(tk}vxCC8Y~@n8=7(MaFhr)k8CX4icT={YdXvtgomE`)4Q;<)Or?Z z_jGYTYVl)tF^Jc=-qU`iEJUOg#(c%J=#tO5i|mLv@{WCueMXjPLAxp+iDi5a0abCV zdL=1VmdoD9eoEq?RgSf_O?%h}fYI-6z0f|*8+{Mr8SZ_}HLim2UrD4PHeFAS|> zB^FXM`vjy@JWQOG9X|;%Swp1%y7{V!kuL-C3fQa$++ZuPa7WcW_T>q}8`)5o=M11N z9}N$zR(7adC~p)8GUca3!7gIhHe}<}+n~qbvOn9Jv$q5!vfwV+qoFTjmFDb1=>mk{ zd0wv-fR3+|C#uLhmr9@HDd&#s@u9bWG?G!qdZDgtqrLpdKMdB^x;FLc26>iz8Svqh zLAhoSs!cM_+OC=rGZCnvEg`w zee*m9JC$N6FBE^aQcWuE1ZqlTuVz}~KjUWsTc00AYV(Gg@qQnL8KhR8xsTKwTD;Vm zs*Lv=yb+R5SMR`g3jRQAc?;0Xcw0}-_n=zNodVWZ1Oi1J9lMX(#F<@$%kRl+jt7uQ zG9OiKn=93nnU5xT*u3Pl%tR#A6qEwwAM1m|k$*tYY6YAV0SFs72|2>Qs)RA0&a<|H zzJh{t)v&HCXojWPu@c_q-63fHSw?}cV8`bz2>>=EpF z0SC}j1$j&Ym_K>`9>JQwkT#Is)I3>go={SshmxAuK=m?Bl;`V4WxBt9?cwuf3nJj2 zX1Ml?{!uoc3~sy(+^!|)dflnOSzuXGQB$)W)?hnu_Fn`S6a_tbd#~|!_FedkC*E`O z(CeqK9=slr3#m#C$BY#)D#7A1EWzTk$k_#sjpt$7U?ZtPL#0P&aS{28G#P<{gs_$e z1-Hoa_y)Tk#WgZcK|IOmIkE%o7QlfvDLYG+)mnF0HM>%JLgc>5{fIWLvclz zW&vc`o#lXZ2-!4z>sIj-8O5h^k?}TPA)Qm?)d`)@%`@PP?kXxGoe}g}KGRwrkQ(z5 zP;%mr1b;@5nI2UeHcQW1c{0qc#~YT|Gp4?^36{RYXGwYT!`USfCS_ptD{I-I;fCVJl;&FsrOd( zv+@pplFxl8kKhYTwStWK4%wlm+8o?1l(MG1*p@?nVqK~Nn{1h}Ztj?oz4k*P#eC3f z-&NUnN&8Mw*sKyFrg#HWiL5lFqy)f;53~x!8)y}AVF}RK6v@Mqc&St-SuU``@&cfj znWVJ9$^z})xU9ZbvC^Y{9xaof62;cQF~wJ?x>l}MKaZ}pzpS#$B)Fr3SS`20U3GI$ zpX#}lvB;gn$i>$+%ftA}wdyCXIuch@BYD$TSrMDR%Y<v5KbTt#8toaza zWy454{Ki-Ci*&wPeoDSw#gfqjOY}edMm@61R-jooqvAwpnEzbFk4@bplhRkwOI35H zOq}#ms!eV=k8Aj0#r$r&3~aC1fiR(15868KjQ39?ft0}P8ZWxPK)i6S6!{Bf49E(m`$H+O>T(*E=GB)>1u{0+TEbWqusrE;$1$gz!rp~XFZr&j<;{9ZVLa+)@R#(`7 zLg(5t-v1`9jB@fPG3Ov_I3T&cFAFi7_)sLj(^ut5Lxc1W^*G1#?fn{bGMm`#d^#*H zL?m4cUx@!Qx3+20rsXD^qE&zqG`KBjZVp-ZdP2U5VZ5_#!!_wXxECJ^dOyo6&^*0} zfb_eCVv`vT)Qo!U_O2q`{6d!pdKxmRq58e1vxC-bN$pEYx;k-qo7;mI-R7cx1{i_U zyY3GoWmIZ?Q*e(mg`!bbvu=kfWV~HP_R!0|J4BgOM4J!CcWLQYMiq1h;8xhB@uhtk z@8V08CFKU|mcH0)k@G3?r#qy`ADkk8$av@4MJ8Lf{6TzK8|3yioWI_jgkO>N#FfwR zLAV(10{=_i3FEFz8>KgkyY;1;U%wxyUwY{2FH&XlP1M^^i{v43y!RfF^6^Wb*y9xW zo)me;De{skvYR6L+M~SnQ}&!Paab5G=Gjw!^C)#LSn=Tst5EKT$F{_Su1Ft-qSMp{ zqrch{BcYlqn!<4!FfhXz)|Im_7Qtdd^Cb8Wd_hOzJ5o^aa3M?FBg!M0jcmN3)IKCq z)4a5+z~3e>NMzZ88;bzzbK;-KUVPf*SDnU4j8;}SyT8bvc_})@9o}Gf@H?u*s=x7T zUDD;2*cP)V@?PqGs>%(TTwki%rduR)Gjhmz8AkInUO20;_Ao*drk(} zcV&L;x6TZ`XJA(q*YgQMDkVnaYgO!6Z+5)#dhz}kqqP*!wz+ZH+fwtvc31c`v!ngJ zv!eT4@vmi;W&X@lNxD&6bSS)S*-`*LGtNlYqZOfs^&+P(Q z%WrwDibTfvIp=2Cb}8Ohr#*2= z|78JQ?`5fx1~4X<i+ar|kVB^cZQ_7-UwR2Gm(g;#iB@s5Q>|V) z0R9KHFC5H?+Lw3P_QPjO+u_q`S3Q_c1_sy+OB znaud8XA<{kg15Ps8LqBOZ_pCY+;26@Bv=o%%8#UDka^c#J$hxg*0P^#vcjtP$L5+6 zrfjK9Wo9EK!7ne^pRVA?u)ej5pJ3&d#<3)b)YfkeYLDwh+-uRzykJaYI;LyH08J;H zr*rxUp0R|}J$VCtNC=9M!zp&xTBTy$YL<#=uRG{g@;PC3GAhDm_`KHnUdiar_tHn_>)9TeLTsmG%Pg5*WX~w$YCc*NxtIVv zQY64@q6*W8Yfsg?@pY*kMs&5uKcd?rsY`DKNhpep5#%v=Y-U8L5x&N`PkPokvi%(tU&yW{?2(5I$x(XB3gp=`_@ zWwQO|=JXz!KZ!z&{hBASoe_^ey3MVoPH^tIkymr*wm)83@NIA89|qvt=Z}wX-*WKn zZh%2EZ)2iSOA5~YZ3-i62A3>$frHRn1Dkasqhb3|=m*wj>dR0tJzTiP9X{=Ns0n)z zLk2131zB&hoxRlP-A4S%Uv5ylt^fOmEyoXc*+Pb&k-qms%k&`RAs!oD;09Se35iiK|?-s4XCpx6S`W=~$EB61pl z=v5*-Y3s!Vol7lh&jcApkp{-2g8f_0$?C=i-2)Da>}2Y+*hbn*y~UpzF{F0*pA{yw zjzBIrq4h)j%_JCHnLq}X70nY0@^Fb<4qpGg1J^$>X#M5hS^ol>X8nu!>49$3L*uV%5;DpWdt9O7%Sp_ea3 z$%WNPR-?6HPwUD)d1k3^gXUBL0JTCD>T>{K1}T7c^E)J9cGk7VPNNOK`C_Y5t<;$> z)V0RP@rXsZPb!M9lQw|KBd7sw0I9W~%gAgXStAc@YYpoypRwMp>SyID`Ker4DZM~WxGEM^vr=(g6tOa5kz z+j4Z}11y$&lbyi|RTj;c`m!YMrw{0`#On_OkQuvK?$-xiYK?u7D;fn5Y?u&hf~jHf@4?`%ea47`ftJkur$pO_6K4?2Y?4d?k=Kd0gjlP7m37V3rmqUQVl#)ZM$iYqmn*t}-eYftHSM30;a(uI%s z8w%sQh7cY-a*-BGa+~qC;opjDub;Fe)Vo12H3CHy#u)de%Wg0U~i&c`Rr$GsHd z*(U+>6Mytw=HuPah{J)FckUmn=3^rYY>5kGKCY)E;Q-7ANwDTj5jOvHnTa4qP??FQ zaoJf&Et7qgVZoc~Qyb;lA}B-zk_V`Rn8C6-?Wxv_F;;}`d}X2DxslOfMco-P-w3&O zhbs(UOLwoE&THT8@HfAKN7%*{Fn6+m;n(Qw_5et8X!=xKm-T4Mr7i!ws1f@6nf`~-&P>B0F}co!Yk&J4Krm$y z=gnTU7a0L!T7Bw1^~f3KT=nt5VFo)B&M*haL)kIU@I9FrJZAi}KQ-nM$t~2F`w$3b zSS<-P=I`W=P3>`&0ONHAebGZ)0Nr*j}afdzO z{1;Axg;B5%oKItLx;^u$vqq|3WNW9Pyf(8v>F-;AZ=0oy&S>&RNa!}_bdniyv{Xz) z6M?L^i#rP%U-?)!$0FbUf z!MG%0Hm7+G27ZKNjWP=H!3sVIU*@-_>yx%zS->&99H=HKwyeiSchgJ!!A9@pSFh~R zqG9Ya{`F(<>EDui0*McFB7>(E8F<;&gBx)MD^o9&u|xMMUra6feV!@RDe1_4O{HKP zf&(P<%(hCAPT27(R0HgD#vp?g#43aJ80M0qQf0Jisz@1j8>O_0N2M*#;;%$LpWRx^ zI`xU2Luo8ztDaJ{Rjb@P`*D~ZPL_O`hy`Xtp*H2|xddyx_Efxruj1GKIePSZ?O{tM zAb#nhCs26YR{R}8Co*qgAyJU2#WsNuK#r=JxN?h3-nvqTr~Ek>gAgxk=0eJ}(KYyW za_;<%C)0FCvgk}2$ElePBvh|$vy~O^;x4L+Gozzqw5DQNQ`gg2^vFHo;$=sMm(kH! zfCnM-BYcSsyAP z8B;(spi4M{shwk~os;UuV3>v9Xo7>IL?Ncll4s+g|FH#Y%mk z$_$vR$#jy}YWf5d-%OF{VPezlZ?%?-)PrIzb{hQ*THjs6mX)x56|pa1`JPlNSznjE zC2*)mw~XQR8`-5a-kNF_+w;KnNuVjpZ&N5`^e|1J7pLy01~&0Q<9PV)8+5|mSX5a} zU3>h1WKZRcm*~$_>+rA3_Svm($KcS={RDf>-W}wu6VDP@+*;;PYq^RxQr`i}vWP4< zgZJ}>8T^~I0%wC}5L&BduvoC?z|kBaYA34Z^a3q*snp^4;^21V%wnV%m+A*+3?*t9(&1cuovYGGb;nMI8(Zi=` zvG=IW9<8J~pbv!XD;HACKLbwnR+UF$LfKhn*f)Og+yg_*PE%1Woi z6EkEzEFXugZ}oB)wALs2K~JYGe+bwT+!=DUYwKSEEViP|(;djumfy?kpli#70*KO; z1z=B7M{2Pj@-^`j=$x+Oy|&&@z|eN>si0e1fBmrbw>=}aTBFf7p>ukxNFTxZ6pytR zrSE6FMKU?!ENMEI5U`;*>ttz+r97L`*Q-G!)dXj)+pD=ty@Hugy;Fed0EunL7J1Fy zaH(HYiteG{`Zc)48bQi$dy1R_0M0_SO3LP&YN5EjyUjpLYLR^GxNNhVTNiLI&;N>F z2ZZHzw%k6YAX;u~xpgqa1zhG;V4lH!s;s|wY9!Ze$Hi<%EHr9-oB~Eb|CUf?dv@xZ z5Vr>-gj5r2SVv@@-|PugwFjoOFS_T$I_(+Qx5I^tZ)10(QN8FF_h)9_HWrQQ*38>- z!b{8R>~F&0Q(dfDUHp2!{xDFrD==l(qFM4aQTIm+7f&O=&4{1b`(WVbn(puO)&ka6UhojruA{6hl<8*R&w30O|7)_K}#S0 zimkTk&+^bpO#qXC6?s%eZ8hL)Z`Ys37X(!H|2=2!ZZ?7X^Y`zck7n<^Gjrz5%$YN1 z&YU@i(=BXA?k$n*t6fAki>TyGqH3ehoJwLnpvM@6=-3?S+4&059zv?ALbMx&Xd8?+ zs1+P0n-lBaQh}j0NMkli4MJFbR3|Rb!YgFU@DZE}h0p?Mi62??9gz8SvGK8 zxhic3l6PRNe81S~c6>Q0vy;OztLYx?A+@K+Hwpeq-k*D$ib^+A%gu;N>U2eG!sj_r z?E6HekR9*AU?UM zh2u$J2WT&Bc>(C9p6HQhvx@RfCq4Ufmn0e1)`mqb4CJ>N4wko8cQ9G)*u!gf`l@c^ zMzejUw?<$|7)(UiL9>mn33}RaQrHz76sfEVR(~uzX*NJ?h|C_fcB}Q>hrz%pSMZ#! z-_Du2^TtPll#!F<-UuF_oJ$pHgD4ypWp#^0Q`fZdlBQjMgcM)=arU)HUVlY9AD6uU zbp%@y(3XX|i_W26r?xdu1^%W$`#)=%r~c49Rn4@gF0uXJlh)H_w3SFW{kq8Q9_^Z@ zH-VqNNNW(X|DzF1xW}yH;cX660WNKwn&vPS$P*QWr2?GHpf1dHdak#d9ss23W=e;q z&+izTNuQgi3GlTJNn1F%Mb00=h3*=Xw%(lwl{+_OP+B6(Vq zyiIiLkdYhHrD2cg7jlp|HQm-cwE0qxJ*m)KX__=7#Q8<~PrlZ}X;S(@R8ysNcw*(@ z{6&hEvwEnuB2fH(DB)T@En1U)0zFxYB%%4iYov1<&#i}}9kAQeKXvt%1NApmN(RPV zmAb!qh;~RoIZ=O=TvCByh)hn`T)D?Z6#-Q6ZcUaZOWEhL1zPkjZ{iYMFpjN~Tio$tlE{RuawF{6 z+}haf-@^Hhcw&;ceobGJ-V_5+Hi+p`b02O)g(eBl4vxCAvV7i^;Ze6#dgs0=uEOWN zCL2ibhp(gPBwnESX63A_78!UZ)dX(p)C15#qiKe}#l2DkH(x`S;KwTcHBm40ogeiB z*WsJ&5g`MUY<~;3!Z!0S+9Jmj5wDkq4DMC@e+guwF+arP5Z$l>V|MCs9%c=yx3$hh^htZ= zU-`(oZFGEgTrQ%A>}5On$x6^-US!8r-m=#UwXqrr^}r8V%jL(bKYG3pvXzzsNml}f zfD-CQjb5Fsq*ZbVR0t(r4kca-qCVPj4ZoLxFcI}ii#zTS@wJfoD{~@m{u2{hM;uMMS;i|P8+PI`#?mpizBSz;-{$^@2h(~^QwgRZvE%@E2MnoshaIK|SaEQA8R_5=aPV5^W5F==qW|ZGBH6Ul%yvB}W)rbeWAh0|sBy zDSa(BOZPz7WS3wXN4_@<*Nu!s>}fF+9L%dVEIl+$&h_aN%*`L2F>F6MX=;CKkQ(7- z%C_$UnwZfg(6F^dO1RJAi-{a--9cQ)QJCzNoIID#v`MX(*kU!2u&rzY5x2d_CW^uFp zrGK-&61Tn+zhHeg{hRd(f0Oq8@suytzP&sDz5eWCdP{x2FIb=bZ`K!Z`*Z8pzF7N? z`8Vqu;nsJ}7p(8$?tia8r@8gLU;V|}SNm_)C*qfk-#uTjzKyT_d+n=m>nr_&^||HD|A5xOj35d_Tl{c?M)J8!aY$LDFJFu z%i2o@YxhM?89%D2y^V4lAg%W`yaFPfSo(69@`)$%DhEi<_&GrGrjNoNO3zc?^~^bA zeBwLpvIk24$Xaz}ZBN4|naI}?^|kLOrqq69FS!mu!&a+|P~!U9UgsJ*DOlY(xAL(g zoT)ss!D9ibukD5H7g+b7dXzLmGJabVqivd@GcGo3ASTBuJ9s2f9_2oYd=*FGrSWdw zxPQntB9vUVLi7e6JX5`eSg?F#8mJXh@;GIkxle_MO;vWs098X66Elw11W+ zdSEAx+dA>JMG>+Nube5CU5n@RLBMxg`={3G_V(_>q;%&@iE-~|$N?2cIX-86RL4_X2oa?l~=Lpi{;Xy*oHyUW7g`8?K|m*wqj%xqSrn*Q#AH*h*QfI zQ7*)&g_75JtW_focmX?8J8C2Abtri$2Nl;8Vv*qU`0aKdIAUlA2D|HvI|y&PU@-9& z(r4=_`ceuoDT*pl=k_uzWuSsmjDUunpZURpf*>OWgEl7jduQUMK2m0_-Ymm19%RDe zkL87tucU9sj#;7{Jjbl!^?0#2MQzG-jqT!Sc~_`-yPhg{fx*HrbAoI&&4asvr6nZ1 z9p%>Dk!P8lkuK*g&UD2io;e*3Y~ST;*jwil!`lMF0&R`$tqWS=t%2h0xCsi|o!}YJ zM21neFm>{CBKCh|X-8cbDCRg?HpNV>LG9;*Zs zm=a83N-pE}OuT?ZvHsGZB^CO!Y=o3Z1nbyZ)ybo(-oB);&4=WYW|$D3LF>dSObS&Q z5LE_5m4dKJWed+%9!nvK0mrslOD$W#568cFGiH;`P6bmj*chf_=6;$u_$7(^w}X+3 z6LCqjRxMk~k1QDo;>)wW-jswmeTfP0`x0|MvRBRp6?9&TesVea*=fRjN+yWIo{KB^ zbA>c|gaE8g*6GiZ$@;TwhRHrg?i$VJIVg4%_DUGN+X252mS8J3&5De%J4!5(T7CA# zANlMt95QLWU@ZlM9R1Tn0uDPVKv$W%t4!ThrtT`Y?$Rs7A&Q`hNgIE-!?RWv1cy1FwsUa>8Nq?cAYM|+iihsGZACuw{k~z7ofTqw#vn7>(Jj&uJ|I(wi zFWybPG*=MRWdd~y+&=E5ke)2XyE#VeuaBfQUE_c7Lq*OV;A+Xi^|~sP}t0s{rgN^d@JjcMjRs3W~>C@lleGLt^O{ z;8UAZ#i#8410Thlkz0$8G~lMT90=}Vz-9X@)?1?Xf(Bf21yK2fK4-bH9Yk%D=XoW6hK3?3ureB(^{5|=X;7vDe*-(k4*k?%QtWiB}j`m!FE%X+k> z+@>$9Ofo0jm-U0&`p`BC^nN3~g${R)@5{cvUv`zaa#&0j&>!%}Mfiv0H647o6@OX2 z=d#L-cRJ-$Y;Ax(rKOMe6}&1}@axg9WeYK*8EOwb!~h9L5UT=tmh#RWQo2*0`C8!I zY~Hg}jq}K0=LRy8sa<}24R_(|?I?f?Ee1~+g0Eju2s8gU?5HxUu}g2b_pqAe8YSc= zxk;7@02|WznMew`aCq|)NV$TiD+|eTf^X#1A_9swn6-!@6-Y+RbAH6L(0i7&G4Le> zsss^|Rlqs5SQav!@u39ne-jVMjD?{zDE`KSwG-ys$XDE@%L^_rkP>NC?9)tiD!o$9 z3*ZWTyE{2FeU2wTYUzZ!3vzzJE0npVqt5Hk*83;ezCe6b7fO5C0HBfIF)`hq5CZuk zJwY$b-vnw2JveeZgZsRuBhrKVFyeqf5N1KB;74$doPd|vx?tjxK%jb^#n}utD6+;2 zXLa^s48(Q<5{2&k%OMEuqu5$qN35owkx~6hK8Fwx5JMe=00w^TWO;6Xs}L9Wa^mFt zRW!ZE0}-0uFOlO$&5?I0J5#n^bFEbO4KAF9{&0R_;IwE>jQ(B}*%Ekc?Na%2bI&wa zv%HXeV&7{MOL>Xl3cv4_9~?F6Tf9IDu%PlI|48VeLxer?B}=1K$!&^c6@ z!qKAM@es>-9|kRNn~nAo0UAio`BV-D3Ai)7lF+j672N~Q8Ea0Baxh{c6!=ziug+Pm zvPWF1rZcPL$Lv*}kV~QXzuUy&>p~9ueXT`oQwg?bHOiSMqUBOTykV&#u&mW3KKsSk zx_vWa`#xc%HKL<$YR{U~FyC<85N+Mr?XML9B zYx#p?oBCuB!FiK^#HJ^Xp$>n|CQEN@e(1NJL>q`b(xQN82dn;F_QK3~?2)ij6MLjr z+20G^7!(Z_I>L%<-dHSOKax%xj?5gX9OkoD-&yHJZ&F`*2pSUZF!uT}x+oH>9ZuoA zVbmqoBfGu6R>p+Gv)xuqyfOM#A2D(pqMLIi;*aCwi|Wua8=TXr@z1dF0bOx3K3ALv z`16?85#{G&N2CiMJLL0sJI+ny4<_fKf0$8-Rwq+r-MfOaFf^;_k4iEN3X_*+?EQ5k zUZ|^i!TRC4y4{^towbDf;U8E{&yt1V8)U_|^Mo<|AV;iv{*2ym0CvxQ0CpeoC#N91 znXtlx=8Z`dI1&ztm!b2{$zJ&U9MdW1rzW>&o)^0&=YHOlxUqpgmS^dO!zRvhhp>a@ET%GA)=UaV@7Jgega7cP%IC;sZA$-<0EEt3^)j(F? z>Uu{!?yN!VW>fWgfsA|cdKOZd!Rb?l$ef{o;)`sFod0~EAvsJw3l7dnBq_1770rIk z?kb63L}uq%{)Cb%rSwyx`29;Ae==nsa11G7E-_PUV-jr$+WTUAd$9AEGZ7Af@!8j9 zn|7> zgqMO@QDw9Lw{pp93@wo<s0UaAv9gvYNKx8!&m%r-9^bsKSlOr(U8no0&S)uvVAj>V0!B(Eeo}$ZG98 z2%I&-7)HM0Y+yKitB-T8lF7puIfp?czSYO8;OSd^g2QblRuF2yiipCYWaR}qbmBg` zQ}3ezNE8Ai$S8A!#~L2x>&)1q-xpbn#oAamwLu{UPuJsaHj!K;TPXQx6_3dAEJABI zHz8cZn1=IDCSFvPsAR*7tTSC^uK9{5U5x*{ASBIo z#uzqW`hzQrG9fn8Y!T2JYu zEF;`H-VRmuOtkN;BJea<3vG4cDbbrlwNdWosc_aeKF0qO10JN6#TuLi&85GKU7wC3*_i1CN8sH8Qd8`_~9PGxpN}evv;N*Pk#W7yd7Z(wU5KB-_eGSi3G-;~dUwc8bthpeX;q zwhI2D1ab{I4n`m$^11{PzY&h(`%5|PggH1dX>ZOrU(#fQ#g$FW-*}m5-*QHZwPwwD zyZ($GGOhuVJon0OhYXyEH0aNg7X4YaoF564eFlF*XAn%gbjleO{Jrvw5o}UqSczdc z4d1_k+N9vky4t^+6H5eJA=I$lojQpKEeG`Z8W1tmW?b$mPZ$rFp#5wB$8wYxy<15? z2Wo;C)|iTBwLzK_5I(}=gj}q6q4cJ??LwRpeCas51e3n5HcSm8Et!mBh#X8FS>#)5 zNY>vhv`3!`>a5z_m%O1>Jdt9#eEwkt5qzFu#p~HDS25||+83g4IF-V@F*n1Hp=TZ4 zOnR5Nrd3;G76Un2yhrl%%}3ZqYwFo3TsNWipIL%1yi9rpk(FMR_5EM=#SH2AYWGOU zJs?sgq1zYHBXj*Q8pBc)8!|QFP{Er!r-kjvU}#31rH2Nig};6CkNdNiW9FyF6NpGtfrCjD0ZA#g+_o`hTR+4oifrM z!(xytuZf3*;L|_JRm?IGn!FT@kH z{`~SBRQ;>v_;|_O2Rt$t9|PDqiZ}G^<|RTzu-uWDXv1WtK|JP2EK~N%=MqP_6?dhGMv2p(@-*q{{TYWT;)x0 z7>`Lqs>pXwFSS~8PGr?)Ye9#u5&0oK*k}xiU5+}%d6iEnH@J%*tbWF7+`udLsCXAV zN`UE}<6b#NK%r4ukGG82uKnz3_F)t*&ecK^JH5BZY80szblA;(s-G|09Zp_!2-<_& zirK(jHiRc!q_w||8sRlx;2Q@}bw^ya@norZ49<{71Bh=#I4K z60ewe48t<&G9;tR4rzbAq`vr-M6ig$01&m%O8{sWHAL9nE^UaNFJ#s^R8&WDt)OFE z^&pL5wO$*}%??LS)vVPW9Yagy21EKE+L2>J$;Llq%DwaxhrfF%+*>L*=dna$G03Civ&f z2Cdd3I800zwjR?ww7z+gr{86YkbSAwnM5XE!|ix7_jU}ecj|bR{{4QN*tA^Ww>SF> zHb>40#@6qrn+n@-;#1IuOZ8Q4zTLa6RU3R&9jsGLZEOnJKG%1W5UgH5w-kiZKkpcN zj8y8RX?@VME@b0i;A&(p@fn55wtaO4$yN2ukGv6H5)bPT%gF zFTP?P7Xsto-ND+;)(_i#Pf0_GP<4n(BqE(o5EV0bVqVm^h$Arcl=)ws#=XVv$Z^m+ zad+I0M{?1`D+{in(o$Ed8ROM=-R_*lj&GEDjx!<2WJ0LDU7vli7>WPIHV3S+ zTz=c%XK4&)BRH!@*TQS@`>6_WZ&BIHOH8nOK4RRL8I{$L^eN!&R zDo1YnOC;j1z@DABgtA&(BORL25USp5`o-IBJa^{x%QWei^dyUjkCea#6TfY5ZKx+0M8uRMwsNHk=yXLCsEz!dx`%CK4gTQ*9}aimIKB}bzM2l}hp-rBdmX+f zMcG{6)MGUrEgeSuvCL*1%}U%zI~62u_-X**y)MK}T6?0X>&XxDm!eCMK;{3zK|rXo zht^cUf7z(c9|7~LA%b}w94JuVe06Z9ef4jr=EyCK4=b;A)|avrVZB*z>V3^QHhy(XY<$fk4GY z&Wp0Ik*@~rE?(JoxiCR-s6ZEtXUJ{a8;8{6y*Sne`MwFlZwA}n1XoeszpHv&vV!hM zjLY>5y@2&S$&m;$C=GLJwFThCJ4sG8?|F5H{{Pp_F4wJF;%?^EB_~@hecoA#rueE} zTDM@RjEuB%Hf|PmMCudLKK_4`HhxUoKJ%JMekhb0K)$fG$a8Ur_`+xlGC^(CCgX-MHVC* z?Z#f`P}(ar=8OWYtdBS#sKG_pc@2n(542ab!_Ej7GoM)LSou;6cYy4M5n#o$=;CJ; z&|$&ka8K6aozR%;tP>hYCm z1lw=*qU~$tjBy=dC|Cy~=km8OdQL;_Y0;5Li46-qr$tUlpUgE!7Am&;B9{eZjlxCp zR~yd5Yt@x}NuN%E$RJ;9v0SjX&qXYvgC?;mURpkVy=IfkUWjUhNIr!pHNtRC5@5+g z|MLNsSKHhQxcm=1Cl9?N@6$LwsWfq*KRwyXg}5b^xEiT$eu?<{h@8khx)E$J{{!G$ zNG!EVCY{Iuw`@DvOzK{A)wuJlRg>uTOKat9k{BP$(TcBNJF3Y950K2I{)es7@Z)TF z1Qa^qu4ezX=CC+FY}i{Eov(T`Ij8Hhzc=A~``!tEcFyUMV?@_c`(YGw(O1!n#CJza z)Bi{9cT@%x>1H^hmnV9xui=8zurBfJ3DkaKHU1Z{gP#3?>QAEoiT=yQROlowizrAC z#J6G{6Y-x7dp+}~$f3yNN(E`_UePayT< zF;E$E5#|wYSm~((m$|9>FJi zfYh&~zt>lOWZM9Ewd<{WzfCu|4Y`HM>2{127dNSWjhR#CHpF0N>A`;bFVO1h?+z^+$)#T6`4Uc#OL=kvpQP!D!)Bs;K;A2i95QpwU=B6*4vt=h zm>i6Ce~P>0q9~KHqbPlSPAHghh48X zS_UX@`WTGfaEU8hxe_k2OVaQtysKllILhr9H%#_noI7`p8}35WZ1st;MfC`)^@&S{ zb4?&}n7?+@ylMXA4Tl$YluS$>`@9qjRlhtJNd}0#fT_aB$++W_#~zO_ zNfwL3Q1u6RipyoZy2QB<@ds2U2y)y&@XjmdZM;*(=ZVQv&-4ouk~@Loz&75*1Kn9< zHNMB8lRt3-Vpyn>L#B!1UU>0(R>42Q2(0Qs31;cfuEQ>Uv8~4hAI!6i(uXQK5ly%s?nh`k=5ixVGnDP`ZIqWHtG6P`0!5_!4=z zOzMMjBv9Tt7?d4A8H{c>2PHWWN^u{Qa-gIR21TNl53!ma$U%_}em`8+)AMe>91D~; z4hE$QC_`BabA#joia+sH9cjjh!L}B^1mhC&V2mpu#%=+W8+bKb5sh?bePx$YH4j^| z4?D6C-Pwm!_Mt}}R8ZfDtqm?Jb`}PzH(9ZV_?#tL=RTTeru5A`3H1c*P-UCY5Br%1 zHuzS5=G*q3zv)w}=@en;!t)D@yhDcmD|(C{LyrGvbVK$o?wVD$IpdVA@iZ}6SuG-K zZ=iP5+@rF1b3ctQZ~^C8hLRl`%i)wt+PG^(sCXZ1%Jr37bnjODH%Zt*LPe+;*mqWT zqnauY7QZOpQ}|9IzkKfDGbS*r-wv80ZDeO#EE{B0Cncy%%GtbBu%oF$HW)!n4ME`2 z8eZz^?Qwy6ds3+0zI5_Td)yRf6iE42hqWp7&3Ak2?QactP7+LYh80M%PSj_!9o^~s z6CM4Izv5G01HLTd&-Kw(-ptMRecsHC2L4xsK?f7BSyU|A&7z%#1l1pk!R;Cj$V3kN|;$^nSs0Cl&1WK;-A-h z(Yp?0R{epy%xVWjApy z$ax1T1rj{yg3aub#Wp8Y^~JImA;elW1XksV9ue#PdSq~{_mn8Bs|PP2%|khLXyb#% zMzBR05%Qq+YYXhzfqYUr_cA?%dsrABM|68$7Jrm8TVNBz5A!E4dJ0YVYrfbzw7)+3 zckg+AYs@-aJ*iPWLBd7g`wMh&qWLwhC6V6Cd<}P36hJ}}==N$_;Z)1wWdF@?clbGa#cjKaj_MmHh=vtG zHY)Bb#Gys<>}hirW}aYeFUU+TM`VxxQ^*>K@GRNgNrB{{XNX?Xbw* zdclJmcYajvB}J9|302Bny(yIy{JpZ0D@oH^i8H<&x7saaYfvo2#Le}|bm)hFl~x!N zm|Q~|PP{dfUL<*QeQbT3K1Pf+eH^(>?|4y1edWJZedJ)(-#=UWQ8CPvZTg)wK6*?r zaUnxJl_d4KjNc7Sh#ZMmwgdJ(oPY_%#A?K;ysrW`$NTXXYg{YEe*k-^w;#QQ3`!;L z*c@6?o1>7Yw|)NDOnoU!A*U!7nA8HTUxyU}?TM0XhgtEdn&ECQj(+g|b}oA#NO3CE zqqJ?6c-S8E7GzluFC}1v4ETvI&}34O6}kx}&VK(tMGMXeb8fgMuLp6Z*JZyol#+tQ z#}<`%qN5W2a$|^Z=ufo`0;eAUD+l087l4FZ=+~UT%lJcoGX6HM6q_(WF#Xvy7VfE+ zUYPOO`7SZJ7NDb#U66@j@;I+b)x1BZJe~(eq_IYt$NzYPN-kP~N}mIWOxZNZJho^B z!L9WCI1QJ;ut8#ClPObn5ysFQkE}pbQW!aj!~AYKWVu!1Z^bKrn^iJ(3xp1lOE?B| z^}rs40zz7h2lxi7ip0_}L{6Dd&Mna@KrQF!0=4hlIu0}f>7m(>*ld(z8y4sR)b#$` zzOQ|Hv@lux@JS2V{Be}DW}{4{_1yQAExEBlt&kooyZ}xwH&S}V~^enW=@-#9%0~V!nHARZ`a%a#Q^D+Ig1)(WZHj^Uc z6BkAVnQV)U+pFl#pi?s;d2mw~m7H)dNsM9~Wx@P2KI*#=LY zb@Rf^tV1u8Gv*!V3T9IU<5?aK{fS3YzZH88J)f65dRBcGLyH%!GM|(hCZ$Bn@^e#g z1qCT3Wwqc`hy;ILrql{b9VMj>%a*#ylv*>Olp7p7yv8jEm6fGuj#w8g(IN>u}yLF zm@JD5gj{3qG*vGjP&G~g6U0Y0^)9F0u#_5}t#_=cSCn)E3K}sxv@ndHY!+;J^}I1nQ1{P}h*eeI7B$!HBW~;Kq<=MXz>4 zmDFY@*X&W`w(!_y9$R_rGLI{G+@g=_Je0Q`CSeVa-6p{-1<902Xd$7;Bq*8U_SqyX zC85C7tTc!bx_J{>k+c$h3q$G2a`U*H#|o3D+~lb;Z%SW;kT-ABOj?b3Q<~rgvU$@H z=T514)6uq*lg*nBClaB)sVFnUBLm{MPa^SysV zes$-Vf?tI5t?yUxvyoqz^DU8rxtX*<3;ypo-yH%W*Vsl=_5aBEE|yX`o)I$j{;xP+ ztw6{zk3$RurQZR3Yno8_!8o5sAmlh-*NFc;=i7RHek<-(2w#ZveO(IXkPn-JUxf4R zzm9^r@jBAryg*tgt^Qoj_l^|JalV&M&*OZr_JjHtk_@jCE45i3-&HU`xoXZ&uNqb+ zUG7&PM~Hf#-`t5&)7Ye3n&GQ(KeqjzhtEG0p0nq8N)@FG(}xL=Ja;c`E* zHwBb%zko?_x!+{-=5oJjCYx}-8Rk*A-;E|uxv6}%d2_j+s2xB|X#*}~-dyh2Y~Eb% z*J9pW?zhyux!iBLzA5)xVG>;K*J=`k`>l~jTb+FLvAr%ny1Wp6_%5t(3twP;J0!PZ zeYlk95T2&xm!#w;_K+7TAJ$hQKbf+3zBjC3miMZsst_}Y_skn*t)`bMgp}7~!VyU7 zz&$P*IEwu6*KEmF^lB9@YzZmQ>x%icEh@UIP<*nHX!+rUfkU2+L|@ ziv){stdSwuX5cQE;MbwV%{8(eqca!iYW!$}DcH=9xR0Rwgb=KzRw->yUxOAC!!t4F z#W+(aHo4N2+?8s7L5{+X0euc7mUE61I>mrXER!~&hYAgPNC0CMUBU;s(kpMHRtlQY zav;h>rfl|~>8FGujY0Po5&kFIr`C+OudMNEY>}1CJROi>I33ImDh zYpmEs+(#fDYl+|-NSY82u@f26Y3d;(c1;P3SW;|>1AOlL#{P@&lXa2?aAJW4Bx@-7 zkXME!(cGi`U|gamntRQgQ2u?*T%{>!HbPt?P$7Fa)HhYyf?Qt-&{WOK0!m#>a0x`_ zJ#Eop*9CS0T_;hk7@_23@}q?4ulbNDXM!A2&h#fE_*NL@9{g^|p@ggmV{6N$N4cXX9fEx_0O^7%dBcq`yG*G9D|M}~ z%2eMMFD*+8#Ptp&HPU)&N-HQSg>cUGDR3TdqkHgH&;#{jl;;xdhrjkWVIDO_=sdAx zh7#2161t;YeHE>&;0Lq>OVnuwNwxH5`YLv@henXbSLhG=cmqy@BNvMH42j8ibvE!ksvXuv@r4=S=F8g!Qy>)8If}47I+aDOUOeUJ?F&;8yr-?!KO`piAY+%sZ8~OIQJ{z72MxrNG zGIrVk6kt{bMvbqSdr08sy#z|Ty*xb|XF^r#N$v0dM`&mK2yB%Wo0wo-vu9;4AGsSF zuUuRV)v-0dfiy6 z&7KBnd|YlLoX9$+_Y~|N4L@SX-=N1vZj(UK_(&4l3?h_|?rJd3OV-FcC1j~au;0Xu z*|8ha~vHdPz?0GMC15ks&-N?Z|OSxyd*N%Rg9#vSo9T4?fW* zv|IF?!RN%bBrvV_#6l79G*~FugnKPiHtR^}B ziR~?yCV-9Ur}$ba?@EZZ#&W80Tsb{t{o&C9X+c6KNT}Me8f)bHphtz8?^!EzLmY)! zanb%!1LlUulL3R?uv}!HD)-o0_x!W)pO@ zl%H81Lj0{Hbg2x*^QIrL4m#>+nkH=?q)b5Ob-zY9TR*Rwx!)H0 zlPdG5XRTK8lGd+WfVeuY!v}SP(Vz}Z2hG2mc_>*4wn=E=vmYL-&M;O5JRgWN3}rev z>O?ew+1^^<9I1%(2RQHAEU?S^0}CA#ST(>H>O}?44AZKVL7hoQ`-N}0oy>?#5CWFg54wWhA;t#P3PL~|1 zI7ur(L|Vj;&~6Y*+7PaBnN})dUO^V@fxwS1_x?86i7YA=ez&cZ`V-hOjt5kQAzMI{E zm^^xM;6&)M^w){RVje^G%R$!qt^W*rwukK3Wc>}*7S)8TaW98VY=ZfJ57{qaj3eK@ zR$Kz(1(SE+w|LLoNF~Seg5{xqU(_-I*B8BEl5cA zx)Gc3Q1gRzcKhy^+I9|_mGMmrZckZHcA*rY?uNZZM2+-rHS8?fYQ>kqyBJ8rwU-D3 z@^DdwqZcDbaF!qI#&d%nF@+M-8_Ys3Mx*nXc3gf^V>mHBV)qf9qTYZf0W(;;&1xJg z53zmTIcNG4QDIH^XkOQg36q!0aG~P&BQFt@VnnD`SLAu?1EW-BF#ieXTHv7?nU4F% z^dk!M6TXCON5Q_wGhj=sM!C{vt@h#bqXK*{MKWc#aw<$76><_Qy$Xi7NG8M<99)GXdy1E_zS3I~h+Xe3 z$CWcmmz4t6_~!t10-1?mKu{{Ei(*oBh&ZLd(|{ZDIXx_oS8y}0M5bZ$GEg z`!yz-%R`LGoJ>V-7$buB3zy1SD=Lpi4(X=mK;k=xr1W>mQfV+DDjT<1^rjod3~ZW3 zj7h9qsy~YmnvKRIu?VSIx9y10x^1UbOh#C;s5R(MnW03=<}dNgD*2JUc5>MYB+IWs8Lawi$ij?l<3~62gZLb(b>?!>N6yBz_aI0aguKys?cv;LaLrAI zftEH%AXtbb!C|w>0cdDiUh^vT0;Q0 zP^Iu|NA|<@UsmtY+ye4MzCo+ZN~wV>kqJD~037n?BX7lP@}V6MH0Nab;_gv%+v!O- zJxbT=#mINP4G8}6w+`#e=G)zY4a_DT#<*<2W4&BQ)7^*FbR<5r*;+`Z z)X^t#2{=|$;5u7O1j^M`sZrt7G5HB0Bb{jYCgUL;CTG^fv>~xohLdnY>}Kjml!(8gao+Vh0fxa< zeasp%Eq!Rv^RZAiy*TTLY0`4Ne=VAioO;u!K{oy-PYu$befh7|AaC5E{qrx?AR9FO zU#mfWZOXf95LKh}Q-L%|x;=dh+{0e9MefkiHX3{*?Z7#~Y<|R(kNp}(cSOJmC7%)n zL@@K$)XU%9&sb;DZ_&#$gm$nyI3jRUkEEkrp-86eWP_cIc~;4ztdQtQs(=}y>C@R8 zs%}%|7+JVPZ)#%niU^@uU%4HB(D66$mPxwY9V5JiE2j(fugmtM} z6kj>6F-9n9WCFFFNZC(Im1YyH3QD=_cna6SYM6JBVr0MDKVP`pk$mB4r?9fjynI#%eW&oa0m7;J{lZ{kzBg6DGp1rKT!rQ)6i=0t!N4J2Q%LWv!(*-S* zhhNF!^Lr|B9+IwPgJR9{UZEFydglrDJ3@Av0Ahv@DO<=nNqp>J1|>9)yR=FQs<3vC%uL9v*$!0!3@*^9S#a; z?F>niPBPX*#x6!ax=m}P;1i?s>w3%-yfIf$pG-k{bSqU+Dp~d&DSJe=QVA%-=&0R; z9QtZ0+zM$o8q>gJ*}p9x9sV;w6S6 z_L40^H&*>?B1I@c?Lney5H6Xzf=#ObzLU8@fl@Xon`45{Y90PwWN0M=fQXA)i0vr= z$#UdD2`pS!p38YIai6Pru5h1gcpl+C2Y9aI*|=&*z12n0`-Y$zX?lyruUWLP=HS$h zpAMU2S$ZEl1(+2NmR}|Q<P13=-RD3^~3 z{Ychb}5MmN)+{PYiDO10W0VP)Aa?T`# zF5z-QWypdp$hR`u=|R3fNnOG!7&u*x?8aU=F+C={g##gBDptvo9r9E9KuXd|@7tk2 zjmonZVD9)LoVWsjAO5<&`Pv16(@`mHOi7l~`+D`~0k78oV?8U^AfJs@e37*`U^kB7F=Rg=yN!_j z<2p@ny;L^_^y7a`HXo}%nF7=F<9$Z2DDI~lZ`3c1ve5y{8k22-ete?Ae4K4QHtQR5 zl-<~(>AziSzO?XVxjfoGUZG!HFKmsi^48h7h9CYz8v13M{5oe#&luSXCchfONe}IN zSAX`5ln_V0z>qio2(c0nbgeE52Z$f3=)(P|Ea+Rjs;Ja|G9Hh!#s&Swl}uU7ZLDe{ zp1QItr|e}`OjJNY4+MQ_$*d9t1s46S;({bF>ZrMA2NLtjxo06eB&!D}c10HcF-jsw zgp7h_yDB(pws-Co!Nh_J*i+pIX03RYZt18t9%dDpJ%n=lQT_XL?ZB#%oRO1Upicg4zWLnd^&s@Sk0Q6ji~^ z7V#z8>?C&QMnVm&KXZO0u7bJrtm=4lJG+C$XiuJT?%{hNxx{c`+{66o$BfMpuj$~i zgk{Q3`44=9eMPcBLI^+l@m|SwGL^vbH(e}&NpC?ovxceDXy><#WO_)tC|#Jw5Tzr1 z41aLnB|N!+d*(?!{7(Jy_Wig;<4pjkj$8}@?WQ9ouTfj3mN)XPn{S!2uYX$&!buS> zpL$^tDW_5m{)loZ(uUM6F;c_{OQvk^tx`sy&5$zN?%a>}pe-Es$h{OJTGANjZq58x zlQ}1GX38Gm3qiwfNJC3cJEE+R-_(s`B}FD8fv@MJEgK8Xrv9=IQH zZpqcE9rh4#DIu#s>POP8|D~{BxJA3jxyRt@!g1a=uf9Kd9`j(D1h+3?0yv-O=MFZt zkt4&&KZxWi_U(IVQP_Sj{Wjc88o^?Hzy{Y(MXo@7&<*ZaO!@*XZmb-Ds(#%V65`&H z9=1QuZh#*1aAQ2X-TBcEMRhc=2hx)d^6mUg+3Pn8x&DK{GHNcR{opRy4QU5=3$2`d zpXp#2T54013>Z7@CJg;);&Q>O-(ITM&h4eRmfrM+yOr9hpUqb4d7imCkXp9aL+w{9 z4wvy4|4Wyaa7|32;{1y4m3smNWah*iV}i3rwlSmo`wM^xhV6BnO%U!qlsvX>eC=5; z1+8)IcqQT@y=OimRZ-o+l{%S1IZ)n0*Runf!dz=XXA8h zYhaKMpB^3at8iE`O@{4+1RQhFr8myOvEKX{ATk?MG>+);YxRR+1=H7$Y@5Em{|%3U z7aN*s1lL%=zfP{z4}xxF4=JDX_K-n)&pj91?GKHO{+$~|MTODl(K3%4%%Ow0k?7*v z5KpxI{KCjuu7Cs+cUSq=LeK1t5YW!#32pcM^U-vVJ5LoByGWZE>#d94FAkKedxN!~ z&WW+1W6w5(_F0SPf&~soE|ek{d_$}XqJt8?Dp8b9BgrNZWruaIgd>584?%6Q6o>_} zJ3U2S@pD0orZ#6ES_s7D;Q+l3uSj(jXoHqwiO`}(68>hZ(F>4?$)XE6Nvq)W^Cb*g2)T3ef}QSK9LqVy-C^rM>1v4-$)>~89;Xfu|3PXg1nr~ zq)4Y^CdgVM{D>XEorCU0NC8nJbanbgVk%HCGE8QXoBGd}aP7xd)Az}80DgkoPJ`Ra z{c#JY?C>K2b4(LGMK5uwS8v}MYy+q|x;#~OnlJ%_LjrFlrfTNYyd2U+U5TlW*i*Vn z^qeBv;K+H8@llKTfXbj8zA6YKUo7AU|10QCHbMe$xh^*5oSU5)vTx?dV{Qo-uF6C9 zbrmSGn5-g3jv2x4Qgb2eI;J(Yp7xjkzs>wk4%ic>k)J6n(&LyL`EBEOwlf>G0C(A1 z!^yKQoRA2eSs~8frcX#rITQHZY|W&{^;GdfF_a>(>f&>xh)3_Pr7sM5V3eWrq?pwt zdYW+Jmh+@&s5)ge4$GD)Upwp7En|t z6~>=t%QPlYe#Ly5`s=roy; z^xV`ndU!j%&5HdL0M2dXbD78&L1DCHPt>1hP}l$jb!~7#y8}2Gr_Reg;BTB_KwIH+EwuP!=vx{6UP>WYoCd} z6;51P&?~+z|L)tpp88e*DV&&6&=aoxo7MPZd9&XNSHBRh{czsn&V5o(Z12$_&cLjD zCGsHDB}3}yaQ02@e~H29EC$42;HYS0^ex7_pjXJ`@4MSU;Hy*-Ox#(}1DCZLk5L46 z1*`XkYPZgN!YSrm=*xLd`b8Z1sBr%iX|EWH$rvY#WK0V}o>VXyEqCL`zn4ByLaf>6 zGJ#}PSf%3-;OCSh*Otp3kj}Xkd75>pJTU6qxo_ZD35Bp`4cc835_b;nonYTN81cEJ zesD_U;=yR7d&?sa2a^j@NYR70urrwRLdf%8`bXxj;S7+#zx4I6oa7Q&2Lu6TbEa&S zxX*ECp?q;}6T-$$8{Rq!rTU-=$+PBZI3$XsaX2I{WCd#|Rz1?|gl_K_fNAt~z{FGR zkKgz7x#P**|IA(tEGQAeD5{hW;-27u*J-FGmALGwU36|M(nA$ghPDE47ECBvylmO0 zqHKz@@Jwa?{8b={#a?1sjcR27?0yI(X4i!hHzFs^2%yxJ@Y8j4Sto1Hq7{LJl$DiY zbmGYKLY`f7-UNBpRQRY01Ro}84)b#fXUbF8SP!nN*o4!t=u_fGD-mTnOkG1i&eHpq zzvWBY=-8bXU@W2M5)%`V3uK`pJOJ#QykIxJVtnGt3(66Os$ZIOF0MG|pAi^zdHLww z^%oRlWAQu5XzxfLx8}6#Z@3me)Lp(aiz*+#Hu|lreP@O$2NkzRjvm=2hjRC9m{#3S z+Q11}<0+tX4%zh`?U2Z`$UfdVovizRIqh~(1;Ie=2#IBb>ViZ5MQftJt!sXt zh~K}$PYl}cHZOgqmr57kq}`PeZcTU9NOy@EfsUzxx72DZ zlJB+8Sc^YlsizBLX)pTq9af__j}2kqiYR%{g_nndqb;>8W8;dqiOnJx#MXc6L)%Y7 zhg+Ki*dwJ2Vb`A-6-bYl1 zAJtd(@K7NSz3K9P{=qt6T+c$XbQRx%R%9+UfI%n9QISqh{_j#iaVqY|T&i$d}T<#&i z7R0PP^Gr*9q9mBS_#@o#S&hPwCM7G63ZF=Dq1QsyZ(EJi`IMMk6hIx)coEM?swV|K zTf!&yj!&M?4(lJ`>Zg5=gSrH@-kY-*c5vR-#78+**%ldvm)6YahC54SPqr!Y4$6wc z=*bwu1cv+Wd0#w!VHi94FkkG0sWbh>o1(*F3%r9OXQ=BW$O+IxyUd ziK8F~^IQliw@F~Hu^w$o`rZ7|$@veqR*x;$pqY2y5^LN4jr+jNTKucQ^i1+l`}q7A zmwGyZO~>V^l5yr`HC@Dmvp}+DlP=6AoudzjSnsf=xyIFefY3B|!Pd}1D+T6mWvh@V4KErx@pT1|Yq zeRTh?3bY=gF zu>5l?%E9?oKRBo6;4pg!W<9@OR!=VLm$O;5N{5cmYxuF*#C~ntAeoYfe*1)jwrxA9 zeQjIHn`v7`KCJ8rEHt3Le{fK}{Xm6zn~5)6`sw6+SkRs6^HUA5cMl-DY=&Vb!`b;6 zwAml1u%8=mmj1pW&7!(l@+1$f%P-tFqW>VZuhqZg&9wTId{8+|8x5=t$L04R^yZvM zf?_m7a`aIkc8UWqDz+A%Z=f8Nj}gZ%IEv88BK*lXqL%rU?E{GbNHcu-h5DLt6sdj9 zcm@7rnsHJNR*v@4B=%($eYeS4na!&0SjzXjc5n_ikT8GM502>M4V5nqA1dmv0l?b&k;mLu%G z20z7{LG;8N&|KE%`el7Em-Q>TtbJ{o&q>Om_x+!N?TKo8xMgJ8Gc0}4z{Z@K1xA*1 zSvKSFbd_c-lJYM9!X(W!TXGUe)POufdcygLJ^29zzMd`6$MXaD)NzSu{yAV=)4#Wv zmc;s&E`OkHy?Bf7dqXy6NVY9}m4yU9tNBUR>VB_%wc#H#ufFrBue*N_U5c+I4LI(} z*4XboTPMz`w9bBsQft2tQg5G#fnWN>MBKh0dt7lSL!S6{1wJoFSgYtN{LVXEiATIN&33EQBa)sn-6{moho^;7e7e@d) z7?BcrN!2yqS^2}dCX{PQMgUb@7zsn%S6+v0T$peQ!Q@ml_22m9OG+-^Ww)K_R`LD0 z;pBgk*;^2<{%bh7s8GFf<;g<;yHu~t6|+0A7C%OQYt=TQZ|=G~uzeSS@T6M%W7dUO z`%o;X2wWx>RMAf7TC&b;@!__E=8tHvX~$h)i*;`&pU)p;Eq+QNwJ}6f4ORrp?8hXRm z=ChX|-i@t-$CI)^KqM4GFA%VUbRi_B7C9SeJ^;8pa+v{u!|SOGKn{S{YCM+|syo1v zADvo-0xsUBe&(%5)**_w_fQE+pB$Qg0$8jLOQ_F9VrX3aoG(EQYHPg98z|m~t?@c< z`U0?EVc(9_K{NJ)1xC9$EVvu+M^ez8YCArq3WAVit5`j?Fl_%-oHQ2`7?wjH_-6*aZDNa^mDOT zYw__7zx}!|_67*NffG`{U{IaKV11zWwP=U4UHW7XH%X+2XI9CS+96YF4O%sjqlLJ9 z{X{m5+!@_xHSQt5k0TPl-R>K)(O0vvo)U1x=jD3?{A=+uJZW4$5-@?EQn@C?Wc2I> zpN*kp*^^}wt6=zjVb4}yW@n)G&dL>5(>s*0R+TzpgxSA8{u-{gZh<&DQL>A(Kt5iWjJdZW$EJ+XeQeUb6_1sPEqz-#ZI2599I$Zv3t z{1Q_=>FY>`$zEa7xs<)AIF}A<#lPk1@L*w)L$fT>a{!Ax0T?jCqYaD!B)(eKjxExI z$_lYPVDU^j_{DZn>z1da?-S+@hTA#L3ep{&b@))} zAS>HJ#REIYY1G9``uRiX)ij4__b#pnt6rKdcfL%Vlx=^&e_J!gjL5pbH76AkN{6jtrih4N;20i;^+ROaP_A(~n3sfgV&OxyvJ5 zJfA+tsXXF6pUFCwyevU>XRI4>q&rZ&4(_eD_wz)NzdGlVO*&F%>&z+_IWE>59yp0L zQmCZIEO@s<)p%$<9c`Mj&LBaBz*K~dz9vcjUI|Un9OBRNytTCPPrYbD0sskCzXT1U znfwfJr)0tP=M!4mYTPT`VXq5Yf7mW-@QP417E=JX8bxI=fMZ02WBf|KH!#;0OJ_;_ za0?hu$g`2CJf#fsW)l|r`XUKP5+oqWPU44bO_bs*7G2*iZ-|LyJ+ja1d?+Uw8lgyd7ID>_ zo%#j0B=>%oFaAVndMbw0Oqm8=>Ai(Rq3nx_=%>qo`#OYu(B7s1!IkX^Y(FmMz`ENE2A^6@HE)ls6%9+5+~F;GS(^ z4;!ybysbkBWYa-B41!{?8Sfm2R1b}aH~Y?^^iiIlZRVv!)Ct&!AwzQ_986w?mi;O( zGBnpJUW`l$dtMEDUKqJ?;VkQ%EBaAb!`;4u$RN~1YB-e(gxGL*T|wm3KoU!j#9VGsE!vUV z#&MfQJH+_a-_3y)hiA+g(ddlvrcdh_Q-`qnTIzSyhvqRd7+qKN_=Y=tp6D7Z3Xbd; zlZ@hAZTL%2#4{1vt1{CCx)Gg|29_x{nZd zBN~{~83J!12_+jUE3x?u5S0m)5~raJ3xaU=00D*{Yzv(d7%?e{K^g{Yr_=%Hs&Z_j zh=X$MA?`_2^+t99y4hBL?sIfJ*-jzrEw+HmnC{M>P9HFxEc=_J=(x61S{97x`p3Ct z!jaU=8YNZE#Y4%N6)4iG)DQtb%9*miV=jt`#tID8TRAG{5O8W6@u9ouy~xdKEBk`D z`65Cdp@7snCwaq)Q1aFmH@=lsG6o|ijBV69pspNuGaQm~ddsTawoV_J%x;|?W^ z>1(itXj71}j?A1kZYizM!)wl@s|uoJ#Dff;!VNlN0aVc-1i5+~b%}RAxfYD+LCC&< zjj(od{3no7dd%bOU05ahM;h!LJB_chcvR@G&5}rbQoSke;dHqV$Rz;DWpj%W3pG>V z942FE9~Ip5lFVN@={qCHNnc>pgp#@62;KbB?9iYqyp9~Px~5Mwra|$vhY}3X>pW{P z5L1d=70zRP3?;58e_WLC;{KqiPLdN>RIv6vCLWgPp)KK?-<=)o?2wX}TK4fL3`@hF zwvXBp*YFzh|ArPWANv|I#_3YVAJ0UGh)q=#b!ggSHNH$cCnbLRp?Y0< zFkJmQMt3bEH~JdxnB}n^giTJICOZ-%nqS3y9m{+jTSwOfKoovEG=sCY4L9aiPxWm* zaK4m7T3sAu5J0lnS~dERhTFXbk+PsH%JMXCQ$jEH@|vaY3Sj z5*G*xN?0TV8Mq@e3M%d>7DcTKNM-<+z`!Ju+v&7v)k^DYOBXGDZEdUt0tzGqlYmIbAIQyo!_sqWdF{R>^Dl}s&Yjx zU&4&k-6&?8crNhOgr>hNSm{UE8AUc zh2o*!9&4xZfi*Rc!M$SkLzQp2Pv^7P2G3|QCT4<}9^on=l<%uJ*25^pkT`Y?=FBkm zWH`4;M{3iQT3%(Jj5>qg5MF)bgtP2R@w zwo!CfmU|FJwt_H~D&6SHgyyGBsF;U4y^)KIBNU$-V%a>|5x~&s8pY#?&{hzDKFg3Zm*ND`@P_xc3KpIQ8D0 zthb+CFCiK~NY?fzvFKDaE5qS5_{AR0ix0TDGjvMQdSpWUfGyq0^Lx+a)*9j)!qCEEjHE$b$58a|})nmYd z$Kn0KQ96#4!jBbMLv>?k=rd(ZeyUVy?9>nJ6q}XUh&-`EZLi?;M0b^;ad=&Os#ft8 z4GA_@Y516T;gf!Upm1NH`1AQ1mrV&BK`fMMiPuy<1w4Q8zTm}t4-P5QCWapyVP!mg z*2M7G5g88?u9~Z|Z~|OD{Rqn@!EbUcLH0dP_VZL_T18muirojXA~tH^;WmFEwuP@~ z%bw$l&-hlE@V4?iu`zSRP>_DI0zH~RR^~)o_L)=?y^Cvsj}6L(9aeXS-?iMU#QL0wr>cbU&>cDdTZDa@3J9wySm^wK&|kYd?Sp*-|kX-Leer1jXhX)BQT`p-;vBj z1${O6`#8LylufFNu}N|Ab2xZmnTB0oKbG6s?7@B+4-*tZrX8y_%RT>YK?PsgaW{gT z(bwk524$M1$8rFuXxnVq70hnF3|Y)3W8-GNq`=Z|fC3BMCxdP(3TqHHoMG$Xnb~z1%JSLJyzP9Ga5}QWijYq@@pR%^Y%`k2o zKIIjL>VTdl(g0zvBYO!x_dYKW)+|P>VwdDg8LQ4;yeY)~`q*FCG<-X1(`+pQ?#oDI zE6N;V{3@npejcq7s8Og!FflfoK}E6mCKH!?#1%^P@f!ICv`4=rRr{lZpB$x-X*EX= zvl@skc5PV57ZibCtMkHRaW6v^1MHLx?Ic^R6i()AQ~CI6xhGSZugNPNz>la@6D5*~ z^ok}QmHXh4J&f@Wd>OvIqkKn?Zj?%unqZs6FRjP34m#QFc@vd zv*LrHO%4?;_V{&abF%b)whova@+8#kK;+`3mqQp;`=c8LRt#3FD5GQk*i09Ku{C+p z$;!Iq;FCalTQLW%v%O>1$b^^GiEXUxYnkiHzBJ>DU5}%jL*@<4qdkf9{2k~ofc5W> ztx7?`ULbfGJt+3LFb_?W#I}eYKzFq8r1JTvT z!`~dBa$!vuf#b0ftM~)amUt0EOTO?ZGo&s39q(#7+v#~0&A&ZSYS{j0jVhq#D=|%4 zsH{7|LgV}&DVuiO*8XzAOV+Q}gV$5t@>;20)A85;b^i+E@?Y=Y62;n_aQ_NV^8a=J zw!kUK^o@Q=s%HPbHR8DayPPkb_OBF6-@j6LgOe|9|1P7l|NZ`zO8=|=;QWpk#v&%yIg+TkzCsTmCFCO`}f}-Tb0TgTcUpc zKkZ*tm#A4&`1Aj^fB)^ls3~Rt+Jg~%o7%sUl!Udt&@A`am#F=l+gCQMtY5W%uk9nR zuc+7L{zYuI?00>ZpCMfPNu{w zloSCTQQ-Jj!@m_G(&1m&xl!U=Q{!hU1^7`SiO1lu!fz zJS5Tytzsc39g(qMB*X($on(Q$YEIsN+F&O%S?&XXQM!E%r=;a}P2^4d^NWeNuqV(S zs=j~FV+B{T!J#8{20knns3!Sdxr6VDeTM|L+>aE=%E8~wO)3YHjUfyxX`c|7HDVCp zFITgmWEQ2K$gy)mK9QhwCcvRY>qI1QKCwm-VALV+YPS0To$U1e`NVj@tRx*pRBFD! z^`HV@L|SgMu(|52%FJ$h=oMHG*7! ze?zbhgY+A#KfF*CU-wJeiC;n;=2eZbaP4hPQZ=a_mOn38m>%XzzVpb(dPw%^toD4< zllk_dSe20+9(@eAJ*(wbLi}^Dh=XK7t2qIQB)`1H7q(vfR@QE3ehfh7A?pn=aj+eCpC?H0Y~6ZOk5%f@rmTGx8tx zJu`xNm`#k$)K=HO#Ete0?t7_4EjIBA!K?hVW(6_M^rEyrm>KNFUsp&Ak1q=4nuC^% zpB=jY{$PK{$yrjK_w)tI^~IB()m?B+frRM?3S(IAMSMs+!qQGnfeqhFY|jOvJe6gA zBUq!x3NJn_L)%_0T`GoBNktk13&QFlLxfxm-f?5PRu zi@$Uf8R}fbeQ0^uT4;6}rHz%cke&#NL}fv?_Xmr)F*Tn}=5BV%#v_zt;UP{q5Wi)j z+Q63k`?N+7l(VU;1{AguC`;?XJY=4^p* z5q`R+BfdqJpc`L{R5F_N{FOZo$mW@*XALh5S& zx}C3<`y2kI7Ap_xd{c`Ql!4%Ce!dNz_t9L;*5-IyXKTT%T^sMSW^21z)UAI`iX~iX z&d3N}c!I3=zofF(jZ;n~PSIl%v)AScRHFRfw}*;{@s<)7%rhN z8Q6MOi0ce`q3*bve5c4o6oHPU*@U>=;OIeybO}cwt93e!A~(;bg zta3YvNgH|ZFNwMAM{44+ZYW}5sZf#>*GgL`P^B9vmZnlR;MB+t?e+XkQsb3;QMGC9 zwdHk@0LA6I;!}PkS(@UrMu2#OJJ2(pj)jlEeX%;j;^Rsdd2Ga(+KhwCnuyIlHy_2!&zR zF|IUlVvlaj`kE(@!I); z8N6hms`#qEImdM8m5zgutP<6Gt>R+ZaMpZm-0#k%^FN}P9$Vg_^IGLQy!)ew{n|0LBr{4=oeq`nl&R~q}n z@%4*kly$+AV!jp-XG^2E8N``0wnqlWFrfi@tx$LTw^)z%>Z;nw(JOIWAqopFTF2(+ zE$apm6)YE&2j_z$4{1bBifjd`X3KpBq$(PTp)v{QGYP*7tEFVQ{}T{4P6VNL7;#cj z(NSWDezKGu)Jr* zm6*VjePDenV2$6wLDlB7daEASS?+tGZ-hvD2LdC7Qj_aF@@a{4dd0GOf6H#ctu?1) ztw^2Y2S8Pj)}V^4v5byy91}v0!&CkTv7fJruDyegw>`co&0A)Ka(d0vyP!Tmt1;^EMVR}6*-O0k}oM&D(8v{m{ zc?bA&f;s`y_??3ezjF#6W3n5&y38?BP8gfdr4*L7rGpeRb1o9-Ai*l2Ig`VZ(KV{T z7_9a)iUqL3BnePbDiaon?C+0YBxEhTjyaI!{&7JHZ6)C;{G$$V1e!|@FQy7@*(LmC zjN(I&I*8W-FmB?!MeY=E?lCynKZT>R9&<@|CJIX?AWu9ia2J9) zrW}85_z!`f@zwAx@vY}#7o-wJSshcZBNf!?ujT$dT{Z8sr9c0c)Cb{@%o0DMqI2p~ z*wT>2fqZAE9(%MP*-*8b-YaOuL02{m1r)4kVKiCih+_P+iden-q4R7hP(=n$NP*5t ziVq00o}CcwB*#`0iY0;e?KpBWpJ%CGPj1UyM``oT)K*jv?eLF$Itt*2ugC~Om5d92 zw$R$Zt&)t2?ZH#cX-X@FYN%p+$SVic6+-Nd36CEZx=fEwr^(^p|IA_ASqFq253 z`_S1aFIH!bj;BC34l^PdWSrhCnxY2TM#=q)1S^F&8xIYngqj~ke?qh1 zi(l69Y_fgInwULXkN*%qCqiJ@ap~pDJmASq<(MlraznZ+Yb1I72LLyl`fywP#_<&;B|G2Ic|RZWK5@LAm!%~0~BIw)f< zFNkERNMYglff6Q2EGMtvpqi{eQU1lcujzXH%u1QNruYa6{o%e$=Mew-sWfXeIh9}N zRKECkN}T(rFBBlly8_7d3Xpq61#L8>PMTKuzHyTDL3|EYg&k(Y#@7OsmuX4hbt_q9 z-Z^gP_u_mlX}y`N7CPpY)s32)tR^<3)3B^)022-&1)6M z;E&XFC?p^`bVObP*Cr)cB_TtvmA~*HeDhX2Zq?9r<9DjjyWI7)HYe+xFBig4ELK7E zW;azz1iZO|3g=RjKek@5-?~$%#NJQvO#r|)BvjIbtVKt2Gt9Gey#K2yEw6z{u8z-r zN305JTp9a%`sulRQ z4Po*rkpZ)a{e$J6o&@MbQB>I=^c#N>%!&mhn1vCok~igRW>0)@0p|;(5kw*dqN-08 z&cQ*P(P!0J8C8K~eU79phDS4kwpP5(ol2P@sJf^s|krjuTY90GPo!x*|H)75jll9G8t^7187uEuLQko^D_99;7AM2n+twsq# z;bLF3%5R2wNgBMkves?nthuZ2#Lw_=V+(}<;w~`SW+gPcZqal?$sx}hl zM>xRBjY-Ebz6|yAceVQ=m&Pk^W=0ZYWQnsp75p#Y1Wv*K4hkjCBt>RZvIH;JqoI`? z$J&p=jLF_W(ef(fWc|V4_EML6D)OZ0)v^aE8oC}rs9CW^mxDyabeZ`@NY)&jMw|kQ zDy*g^@d4fxVk;*n_(aXN#8GnQ9i)!xfnAJ1Mypj^DU}Xle`6A-zIk`06-Zjb8G))K z{3`OLM1q^5&awjnV#5+JhUx1dZZpo~pV87TSWPO$wx;mkQyuXivhpNy`ASg`HWEr6 zo=`@o=r(cgNI)MG)j)Ixru0XUWbVkAt$k4^m|dJ3%WsDB+r|vZyQ~cPm4z<9b zR(V&8DW;aA!kQx2oQkX$g6oov*D)N+y;eGAY_cIAIm~_*KQFRBD}N*p1WouZHzTp0 zXCzpvDt@1}TbT1pyTv&w;0x)SW@`_%xOnL0`cDyEy;nb5JJ`Z|*6_c|`<$;xYa`S4 zE|1RaB2+1q%Q|)-bsAuZRv}A{Y3im$?Q^XPRw3E zbCk1ez&od&PcmPnGErXbV6&abYn^=A)|WY3iMdik=6r~R9FI@TzEHq#y8 z)eh^UB)mxvn$!Dth{Prms7E`>1GUh$6ba z?!fWf4(z;(EcbXMCi*OtmRY?plC&9}XTHuAMn|js0*R>HT-GC7yVz@c$!42Pa&D{5 zXb?QckyeF6l3kpQRS5aDO1T#*$GhcTj`lj8YOCg5A-5ZQDKZ2axF*aNf-JKY(P}$= zPfCe#xI^pRoGdkoQs5P#$>cLQQBhmCnB@)O(T8T<>}u{Ea3}3(K5^mH-cz(2XuArm zr&CgoWu1LEH^XD~&E&vQyW7F7gc1uvwcGJn4TbRV%_+N-M0HfcAo-)KWWUn$I%$-% zA~@4O=7Ab**#qD@LPm1U6D4?bmEcRR0$T1JD7XDCNd6gh!4f%@!;j@#!#I^V5YQcXkByehGpH^#hD$YibJ&Vxi}^zMS#6UV~X z-%v1p=l@J9A`XpQ?20}s`%tU6OZm`%llE4J1>~4-BhQzDX`6qBT@aT`k{f(s@BDUr zf$_tzS$EHy6Pk=FFcJn_oLTO*+~4&QqjD~lg;oU5#ns}a zmh9o`;936SHm%}ZvQKEtymXifzZhC!qB8YXi!Y8sxb}m6w8#Gw8c7(>clIu{zMh~h z&b)N?gr?F<^X8Rt=MvdqXa##nFrBieVZ;6%u?%FGB#Bh`HW-EQ`iFQ!-8hXG*}v>J z5ehoQ5iS)Bb6-cZ*cp&pjQ*dM@~9Hd#bEm^XCMO1oV7%RwwFOtEaKCeTRXZpP6~d;B)Z&{TR>*P##GvCz|$dDg7CA>?h>qQ#oNf}YgT zY6k|~k1XJrToK z4EO`s80kVowgayu4!d<|JBNNcNdF(7a;({LZtY;+)SDqUkR6uY=Bi^)i4ZZqh8Rag zq~uZ9`{*xk z6hXq&X_dy~RoXlrY-NW0BTI{FJ)OrRxg(>tUvFpBPGt#%A^z3b2@C9c)4bf_!eFVG zP^9JRTapDkn9hP}mC9L1SEqkimM2{Eint-5<%SAjagWJ~aw_lLdm&_&D;t=5dUqni z+ztvvd06k)yodicBQBsS`FFw*Bc$p$;!H+thbU)*-6eUWjjKU*TIm z*DkX5DH|$i^8vhey~p>y-6NY?B8PKJv?m(N5bKS7#@MdM&U{4q&DtFLr#T%5U&P5i zD(;gJco@6asYP{Q?_5mK#kQjFcxupHJMjM(Ih?Zqk6TTghxl|bMV2!#aV8KP{+?W( z+7jxM=*^q`iIaq9iI^VBryA6Cbp8tt7do$1?BhWVpxbb3?1d%TlZ2DoiW4TEi#uZn z^#fq1!+kJ+FM_vi|ec&A&&D2rX*nW|wmWYL?OyQdGb{>Xei)Bt08))NA-L)(9 zu288@*2^tUx#V22K=L6#N0^g?pS4d4f>$$CMGTlzoVw+f5`AzT4sJ@qKnq_%L2gH9 zUg3$~f7eL0cj_p2X#dB`K6zyWEN^sr@s*1m+$f^~rZSGHmmMbUm%o5@b zMPjE@d~obr#EkW163Ysa7USGrC<(4Mme)EI#)nxdy}F&kQ0ku7CD}Q!%bVrBEm!(xMjV^Z@okP0V1SV-A@m7rx+}ODP*eB=24$IwjI6dR4`XLp7sk~arf75^moa29eRRL}}KwFWx_@Go!UfnSd z)Iz)}Et^CBB%UX9jpXh;CsOT=lV z4KuTrdmsZ#f7f_7OVd-nLqTF*Vy6fxWw}jBDM(LwM^bvL6nbO1x9~1TLX8RGC*-$+ zUsFB3%#(U0IeFaqIC{7}oZX_AfrmStuRQo~Vii}Ib`l*2QI zU}Fo(Ct=H|Jh^5%OP#ur1>!w^+fOdfhLB<@V2yB`jF7MEQgkK3x#_JN&iKsmtx2zi$6AZ2u5_ZFvM6R4MG>FM+Z#5 zh%so$+Z89@=G9&}FZfqBp0Y!MLrcl8JyB4t71}M5WRFsu1T=3G0S}lc+hTz=vCg1_ zYb6C2AK+9=f=oXAduvBzRAz9!`HU!>Ui^?vCBjw9onIsi$Z}_+`FHen(@_`4OR5=u zq;?dQWpG6|b$?&(M`ukr*DaEj?aEH)k1SQ zit(fLM-=0d<|xKj02!qiZ>8&mF>r;1@SL?*5Q=v+O zPu?hsA~flQ?e*?H8M+-JT&htiKaDDACJG|=X-u!3F=5 zCZ8*fhTekm?=?bQ#*l888vE_r7^5KCK(vwuRqx!!xF0f3nrgp|p(1OcXRjuepRoNi z*Z!Gl{|HOZw-WoO$o^3k+u$n|jdcc#QQDbI6H-7T_o*1XEZN~e_?V3pA!#zaMjK0v z`^mD5rA%)zGQf5s&o;{U8|Rw0!}k=j|7MM1*_2)=>m6#Y*Y;K=$O_%$tN$2-|2Mn9 zD0h}T+vXKAOep3KfPGm6@it&ppM$i3t%WS0c3X?sxCdy&a_>S3ZekSIptAZTE85X% zF_1xO|FiyBc*X&Vop8R41_`o9kcwCjKZiI*>?ujZYGkIBn^Xy~dv4}UK0G4VDdg6M zy~rLV*&GcYgowp9R`7``J}N`s^?^O~QR&7Cj7D~&d3q9Z%*69j*cd}3A_dd*kv%~j z@VSh|TTEgL0DCBEKN3^0%;2)R2xaFGeDR(JCGzO-3v% zB9H8l)cuonl7QWyvSr9*t*D8=5hpKo{^-cBncy^hML~5TrSfT3%khUP0c+lmXKz-= zG^It`@v+S!VoxgdhBm;Tp*gcb*iEKRf$+)q6$rJ;dg@Jrk=?1TjI`eu(JFqLY*!>d zFxMTfdsu@%MKe7AdYQjrs&{rSHI?<~{Q-xBxx=XH0td+ZpifX2$bq}r4v3Ui&T{_; z^>Oo+aoklW*j^-my5Y&=8Jy+fhZDn--LV^DT+#4Pna_)v@WjO|1N*=iNOLcOI$4Qk zcXh@g3q%%xfXKOr!k{eoVAbq_c=-=H9dI4zf61rn7PWB%HR#AYp6DrF47-GSI!iBc z6e5$>FyJo_iZ{%NzZOsoCV!jB#qw}Y94bDJwmDW;;Yih<`&W9wQA z;STZ?zBBz=#Y5!qR_qUTZ_N7ZPqEdE#)R9CR^G~AV=J!qmh8=-$dWx7ZB$&pr$Eoy zrmb$#b8zd~+7q{Eq~rhBj(i-ADG|ZW`hD3;_Niif?P7Z=_La8!OFd_&a!nOk&a%;) zA}jfk|ERd9P8+JSFQX~|Gl7=Wc>7Egt17ygVO*OJ`YQle%b0l_60MYB^Hij*sT79- z#ze4S<%f3S*rti4s&-?FPU=BBb!xQoE&J(45(S8qpUIk&#$pCoYUu zD)G4y2}^gQYDRP;QpH;`NNz-otIYfTv6xK4Mn7Hl)C#!8HO(_nD+2IJBGrP`HgiU@ z+(6pMSARU1muTi7f9&Ej-(!6j#~njy2XiAgY{3dB?^<&EP3J1P zoC)K&U2nOqgDEVU+&}5}xsqguEDp#Hxv!NZJ1P(5DzZb;9I^w9WSaTAKVg!lsAq3HNa@s=BEo@(8l*6X9*B8WMB(Ph{b7``E@$92)6@~nC?Cfl#9~nRPJ(ydzzsr3g8%?xP zZQF)C;GmFTT!ff(vyBlDm}zs~4BJgxn*W$)S#*RWQ#UnOGcVsDme^XwN>&VbO{-W8 zu_OM;D#WRaKbrL-YcC)t(yytT0zag{@GTVx3Z8rg!BwoU&)S69hlu74E+Gi49J4Uy zQOpQoe7bSZCvs@8woJuNbY`W1lg$(gmxt)o&k1(nCr*vp|4FKCHvd4o-RPH-AsvDaPt)GKL5ns3LoJDMs`;+RH{T>{EaqN+g62gs?3z;f>x}7s`)2 z@0ves-W?CJQ}fxWO_c-r`{12(9%!sQmnS;M4U^a^`KIo>SniRKxsmea$hdwgofn~l zSdqr2*Tnz!H(^TXQ$?6hrP1=&N(~hmx~cL^DxiBHr@u&DU~o5LA9_27n1pBzCprc# zU#t`4fOZT>hVm@;n*(SK7V&N6`B%)xD!tS*JF@;PsZpz(&Rb*F5NdIiiUR5w1-OfS zZBOhiG^K@9dsq~t{^+Z|_{cH*@z$e?BL z3J%7z1w69v`u4~u#i^P&Sksh-Akjryi;XL#2Iy^SG+*M-5;T>5XvKQnvO`9J9P@po zPL@0PO>Rc~2aCTGZyH)fH!264*D3J{{n^J6la_fhnQ0@hN!e~L;p2vp3=I4DZ!tU( zJ5ZM8%EpC=1ba>4EB-%Xs|4i2T8*Yp36VI|vKuqZtlED3C|^nvzEq77AYV6BfM)ZE zatX-hL-}x@{h^53=tBNG!d|+EO8@MIX1RYu?;LWqj&cGta+cE_M)E0efoc6nj;q*H z@@>Oew2yr|b_nJe8aM~Qm?-Nxrc#A_+J*mW7oM3`_;gkH{jY?AR)?=0%>3=1SY}^@ zpOG&GaGc5OWy0bcB-w4bA50}n58{6ySx)O8FP77Kn*C8N$OkxMcC2#-^rU| z_xPj3{L#C!_2}(+1T%(S16a`sxL*1Yl~_yg4on8Lih6n}M1OY_9fLB0H^Y?xr>@j3 zvptl>0dHivZ=hvoE3vp#KjeFa{b+NJ_AME^|2U~h$Td^3Nw`z$soW>6L>|fKu;b1z zyZg!^NN*iCNYM!e5S;{f9pM|k#q5*3e~;gtBI4r(@AenppPj#;%|GV;?1Hj{Kl)g< zav${p@iwxv6EkH&DuvX0vI(OBB{)W0Z-u<2Mq4|djSRjnI8)upE)S#E3^yu~GNOx{ zv)K!i>`H#tsghtfc(oPgr5&o`!Xthf?W&ej6@J{Rspk~x@hB)s+>R}f24Wjoo6U%Q z#y|X8X)8DZ9n!n%(NH=U=?Fw+6<>mvcsSSV_hrHdeF3fDEY)XFT8}BaJdkmQSV!=T(Wj{um^6fk*Un{6c(9|R>2(E&Dm>kF5Y#Z-! zf3!ER2mJ8DEOm=a3b^J0m5cd$&tFkkQKba#bZ;)cSoB5kG`R=%Xjti(N-a^vCtqxH(1Fyk62+;rqe;isP!B%97RkD7zl5kM}o@?6cAPcai*I zquS_QAqQHG#JLQgFN=UUm#NZoRcUV+dRn*~877d%xflN9zVw5fe8xL=?8~2?&W3ye&bo`kW(w?sTc*&6E4Ue&7Xfa(!fNNx7v)hjEr;D{Ef>ffhu~kzNX8N z=BlhNPO~D{^4Z?DAUBcNQU71jIYr$z!{B) z#tGQ&v@WJL1(~6{Cp2XiNU&l$(#`3J-?#%0B&xL5$Cdbt;_>ZmBg-ajeZ>Fv*VO7r zTn^evuA|QRen7qiK5I{!;aHg@gss6p z71Qz9xMxs8#vi9nG&jPSXN2zb$JA4D3r5G?pxYOi9#9+KayMbZ8HnDU9~g5t_iKHz z#o72-!cf~6os6e|J#xbN)d_cNw%p+e7vVp!^%Hc_a|D7Pn^n} zqG!5gKXc@saVqMey7z@_YcdTf%%_%+DMQ~li5&{+fZ|EL(PDOn(hrX z`3*H^G}II{)SS{#)32fC0wurDjbj_P(xG)r_@kDX@bKS9Cm^Wu*S2EJIU`c@r{wKR zK3xbcsQl$}!w*+H?m?m>&L~I;+|T4)I0vDfLg@^o5*#*F##wi?${DD{ha7_{$pvyd z^wL5Rw$22;Sl#mX-UnyTX{-$L1niXR78+kZuX9ra^b?ertpeyP^_|e86{?#Uij*Q%hn0l;qws#0Q75m3mt>7tKwNYrgSw*=quf1G}3?Y zj}Y9fE+bImmkV2wBie$oVyg9C@C?OI!{GGeLQGE=g~Z3*4*VY*gx{oQSLkBp|6UA) zQ~KwPVn3AZ{F(y*RNXQYst4??00CAPm%zqSNT%@KYSk z8YTW>qO8?kjhm@RjM{|{Vxsk!tx@R1s(l0^M)Y=5^W?sm$O@~-)Daewq*{SRhGwX@}1yE#gJu$o9d&8;zIT z|HaSiztmz-YtHqKulP-Zh`%XwryFWnvMw+R=V~FQsw_L%+N=fWTr6Ir!UacE8sbAy z89QrAE;dz;=Us8O8snlNbKy*!_$2!gQ-+%H`^gb@dQtH+k@rOvZlczEs5M;vM|x)}IiTHtr`(A2a<`qN z+>6JTJ326}Jr&vM1noU)*JlsQRY}|+|=&H_h&poklE! zbT+xFx?`Q+qfUE1Tp|4OJe5|T)GqZEa%1r+*&RL?kwX=L%rQ2In(0KN_m3{>R#~Gl znHzuM9x*HQt`wf)S?Q+{lk)zq$sS1N_^w~b#Z%k)-(r<(2h*fJz04?rtR|tcQY_-+4&w^>%`h)Y-Zx#-Rb5}yR!>RYUR*^( z;q||fj2NEN9gZc{Tx`7@SsZ%u7T+^KCO}eLAyK-?Q3~YS)X!6D^Aw8dBQR7ia)EKB z`J;~aA?$WovtJ*QUaCfEP8En&syQv(tqf?TeSGq z>lM(Vs|17)bWcI#V9%Bdx`JL5=Id1k2oFile901Bl_x*OyUKIp_j=e?;oqZ~#A)E& zlb%I2zdzAglvu{p$|4Kh9TwxNI{=MZV#P`zYEE+wQXPLG>vO>x`+b`C6*JdK_8ak& zv7ibXEMowXI_mrG2Q7(g&^hX(s{|TJa`;A`9ddXU`tQzk#nq&7-dXOSbr)RjZAomy z(k|J*6W022k}Rn;|CGvjA}~GyF$BB?%$0R)PuWJ8>PzSBeJo`CkDgT!REtaa6BPMy zA2RuHAG&cZO3|bd07c`X-81}SnL+eyp2p7qvfyV&Sj8V z5A%EGO!Kyc7;ecbuxYUP=ih>%;Srwuz8F?Dq^1C`5ueBFKl#owZ$s|*52`$u&z-@S z#|J5W52elCW?BvA`7(6J(WXNe{}umMAT~uPY%KR{EH{Lb&4fC$f)`4t1th3A?+}X@uBjZh+*=cBr|@2u zjloae+I$9L_ED6GbCp>6Q}Y{Rk(?`iEyAQE|A)JV2D!t~N3DNlMS~!)x6(s=5TAXI z9oYo;f|mOorFvE?Kblo>Bv-5&vzeniNRRu;sasW}Xxni>hGLkzUCNP#Gd|_7qsiM! z9@a>CT#v##Aij)+TCJ%CBV0&CVwrWos9;8eTIunhi3cP1TpF<4zvXW`zyw~{6UN5< zYd5XGad#TuIt5Qw!ohZ+KOIvQJvvc2zrRc@oeiF&Q}VF)Kn*b#I;+$r78%k#(Fc#o z2yUT)U(`$MK}>GZJVYKP%n&v-kD~SRiCiB?Q;v_TxT0Z(6>^7_<9oS(x?t8Mm(9)Ll%k6oVhS*Vn< zel|yV`jJob)6NR3jF`*A>P@=;J}^#qzS-~d=XQL5d`|LR?Kcq|#752*<~dewty@Fi z;xCrS7@Fd*?vtr_oiVHWlj~J^Q&nMaCL_eYArC4*TW}$Q`rs7oFxun4hQ|W9Mat{L z*3ehPm6bS3q2cEI;ZPh5r4fY6{W4Rq2Wq=*T*_nhs7yW0X;`D~m**g!6^O@k12-F) zKG7VBf5|{A0PdlB-RsG9O7G;Yqaxg(ZWzWGu)_m>T8|BaJyn%!J5-=H+C&kkrn^9e z40_B|fUF~Qr2_FypdC8}BG>qv2vbOU} ztL}Q=Z@Y>{ro}wNOmO>D2luNzj=LX4?rV7&j$xEJ)ZqZq&(Cx(k!TIPRgK;-9P&Sr z*wX^OoRCf@?Tp~##Iq;n8hF(EBR&!3PNFq6Uv!xpRnKM!$-bONDZE0rT?AEel7GY@ zMD5i{)}+z<0V~_PQnEIB|LG$8Kgf=5(>5bgKEqW1N&SFS!Tdaic@&10$A9ps=!O`P zKa#huym;s(aD3vekr>be&P6@v=5FZd|@(sBG2FKy@4>E$oL5;O9x@w3(ynj(& z9if6VU*NDS-xlElGJ-n#nnHKpiVrd0O@X8LO2Ba=85B6=QYcaU-m4`+2$;oxF*mBi z42Rk@AV%hP1Naj}MJZ=w=`4HB)92gR;g4SKi*^e{7v=d259-C67Mw4O3BAuEg5m%zq`H?zld+6fA_CnfHJWQ>1E$(b##2zU7BIv0ls6_bJ(eM^62o0+{N*;}0~7op6ya zvWOL5xfIBA`1zV93GHgd`;OtA-khlxzl3L+cbdd#>WjU&UY{t49LfnHTbu+C%@X+q zqtpE@!He0fMzbg^rz)?kww95ImY}vcI3wQZZDj<12IGj&C3>%pXWLIG_~e!ig7(X? z#+8FrdVbR#E=;p%f#(3v3J)g#q>slq5}z?zC~@JWf+PN0fYKeW)13jTJ7oj`+z-PB zB<=nryRdU+vROUK-P0SgQ&``5CorZUIbi5~2~LeH$Yp^i=eE z?w!BO{P~MN(VoV&uU2_Ib=mTDh*q?aE|9Gk^x!Grccr%4!-a&IEN2jm$m1iMr0JAl z&I8NSp;a zMyU>o!!d6SQZTr(&`O{2wkSQh#{yx%9dUp3f#rZ(ZU%EMOjUzfiZ3Y44nGMP-)N6N z%z9FaC&}SA7IOHD+3!NArkQ!R;D&{bonv(5&mj1c1F?G!Jy2KR^ggu0HZpdFis&+t z>rqI|>!Ww|(%E`3a(ucjyBXJR?H!rdpH9qQWwJV@b2sLvDyIuTxLLfWMmFndqD-c6 z_gb`_LY89Jp+t9=Z%>f{dStv61miiUu9%iJT7w^iCm@ZH@k3)e(@Q_*XIq0W^bp;;IMzNMzXtg+7oTpxI>k0rjTcxtTwln^-I`RYH* z^Phd#)XeiZ6#1g$qgaR4e@JNN)s{EsV^94@c|@w@@e5zhE*$7e*k*igm*&(-%y4Z@ zU1?6UF9%ml;#aqH&_QvmtM!>&MA+C8I;8W=D!(0GYjJ_!xV_z5Kir7~Xd)yOK|c?k zXn2VWfrqvxHTHy?cNu{{dfSlWMv<7rSAr3x2AC)!p&fD_V~YpKCAh$Wj4_qVYkcPc z3<)s;vhn%#*Ag(?AM+d$IqIQqa3iP)`}t#69ueURugw9Bl`fFut}Zx)8;6+~%?i;q z=K8$Qy)w^wRCF+FAV`o0JjuCo+l+?r;j9JwM{Nt?V1W7U&#dUoFJWnAdY!@-L7hl> zVVzVJK~+VluP=Iifj;Ki0?5*6Sw06?zWHl8uc#OQmafs0T;|iVtmJxT%)M`Qu0x1+ z#!pH77#%1<%aC8cfs9?KbY+-fx&6Egwmelgn6SB!D(;_CnQBNGC@5=D_#yI1d!6wa zOP*7NxNgyVpkYP1FnW&&AwDB&8BR(4a&aa)U?^#`?fdfvLF+7hkBK8i8vDneK=(U* z*6ShIPAT4ltes9WX*cF|o{w8Y&o+qsTR~*^a;1%lcZ~6P*<$nVv!W!J7{%+@QT7ED_Y~+;RLH-B} zVhw)j!}QMzzVK`8XwDghLWCgg1E!DZ5czd|p|0!1UIW;bP(g|kkM=sGNF%}~!_sij z%DQ-Rhd5&lpvU?>lsI55QJ2EnyTkhVN;S10o8#3Q{B383M}54S_3g`-40}4y|B%S| zE};imTe=*b6+c#83PBDnE>ZK%q=M@SbdAr2O_km4Ad zL^~2XA9@$FJ$)8OO4hn>dE$JD_0rihVm;X}=}t(7NF*Hx?*Pj4$e|d!7=;+3`F3&; zC}oq6>KC1Ahj*ucPJezTt#|0pt*QQ8km^tEfBtv<`58G>f4=*sQ-38cXlN^ z{n1%`+Uqa;M11G_U7y?drmNZ*B0@S1ih96GY;0%?n2BR`Rlk`NFg_wdvBvkY2|LJ= zFqwv*6j9usowg|Mp=KE@snV5?cISx_Ya5wohBc?R^;jLhk4zs(}iP)Ma;)$N9UCA~jF9 zwuZj35lNmd;Y<-Nl(#H+1k=qt^OiL3ihbImBxs++>j^QhNW$n$`r_F4DMBp@ZK$+t z%Hz`>)ZS7o;6lQ8H}G%Z;KlZRr>X|a zTN1P7Y8)ZJZy000hF*!FC_fzL}wn} zka_4J4+HX3Wj=09pN~9JZ%mtyx)aWaj^{BnilT)Q6GqoNOkB3!72#&R4S!#>x6S$< z0z1sVD-8n9acgXf`+sILqICYacg=SI@4*Zi~My819RcMI?@a}EG zyI&;IEWD#U%3`p+XYYDNum@f#cEXt129>m-yiBK!1{}ea4|XINCw^;G7LRv%1 zU6ozsJmyWxhIF=*A%SN*S;*}?3CN`Xa{g#}-JuHFz+uQNZ@@g;IcZKn96hu{h>;^0 zE?9%VX z^Pib2IS!RfR*u7KT2h@%>p}W_VB&4-n6jQrKs^~53r_Kbn_Ek(GV`mh z%Xg8ji&@|aw~i+@T>tqgCE+*Pq&KBirF^|EzY96K5}g@FDP8uI28}fO`rloj4V(Ta z>oZW*X?>nx{tr>3HF(E1`TI71kL#bvo@LhWT`mIa8S%9};n@O$8vBk=Uu^}+7L>k`j_jxkS`t%S$}nsL&QN!sc= zyAAXq{g89U&!MSBzNHtqquFeDUv9U*mx`9QsQ&GiJsu6z;c>Va@+z)=JeR9aWk+Oo&ZT*tbdBv2Z&-p=uh8~R?S{V^p@@ryhC1UiD$ zn(DkB779ZvZiZT*h=*^f4v+0!fbpAntrq=7<@QkD#40|?Dd>7b<$O+FId~7eW82_% zIB)SKH`FQ!x`A*Z4uUX@RgT@`iMf;#57-tLIPR2Zq;D0s@Zd9A0)=t%4-FWJYW!W( zfn06{`su)zW>0_NR-fxjGWm@+5eH}$=TpX(enTf&O~_`_*Hd^gt@jn+OXEV?xk6^* zYu1t~{0R?g5PRg|0CG5BcqBZg09QR+8?c%~P{Wd>a=%O_B@Q@zsJ0?7qCUT`n@xjnnW=|h$M}*?_ z`1KFSot9~2SB>}!-=z19D*T8&k|ti&NHEhd6NOT(fT4f~oa}2A{pCRfn7^C?-vP`TSNZ7T>u%53r#v-fPb3g$I{$IiEbe7;x-r^}#z z;+ed-C3p#b#Qm;Ker}xAW?Ux6gN%F^Sb(!Aa=2hYUtRlMOIdHS&@aGUL1BE2yHMI=^H>j@}JhJcGxM% z(1XES_2N*owrojSO|;u{v^O@5cK6cmrd)6ACfYqT+N(``*AqFC=h2?154eb^GNai8 zPVr{bW|L=s9acES)MNfWIR?=(9N6Y}C7gvNkUdjG;FOu<@vpqA!$eF7t+yFx8|g9Ozo ze#CcQ@$1^MU+{p$K(GH8opp$AjObPxo5Vm{8E9Q@Y3#w4$T1mb+!OgOPyD<2T;G*w zKW!?>K7gjW1fDWw_YB|7f*UxVUf;VMFA1vZ-D@@g(pv9La_7U>CB8h?epSiD^6n8h$K+gu?Y zB<2;yRC7s@Tr5Fl86)%CM^-W{q>cdao&u!gLlO^AhmE2IKg)R!mp9%DU8jh2#@xMs zCv?L>&W=$~47Td8HL326E9`2yzpRx^AH;o=(-`XH`C<1lI#2{5A@tOoP^z19^h@`4 zJKbzm@9EwA%m;P2mY4i_8>2|oK=ch?mN*vI1vOvp(wo3y_D}(5HL>_ zjXnCzq|JzkIV|_PYdFEVt#QdD0Sg{+Ai_(2;6&hqj>Ci}b=o@gm&m)XDh?m&ipYpP zd)p`^Z9H$v-sBnes%TMKg4v!LD=|_bwr*rW7brXh-`gJ=oE9DB0*9q zs1w=x!87>VC3J=-JbGxz?Fm2P8XD^D#iL?Pw%Jn>gWWteIVAX9TempD+M2^x#ztdxzX4tGu7Q>g>FT2f|n=`Ac|g-mu`!>P*`fLWHyxt&Kf8 zAQZYLu@q>g!>4i5s4i3zd|JkhHx>FsM?zKMg|15D`?h0Zva zlEFddnNmT2Di|8-;{Z)d$y;o=`CQv|Ls-un^5~+!aQnPPHtZx6A}|r~Rl4YlIT+23 z0+)1DP4Z7)HODctuZ5cN65Cs;X<^hoBr$ zDallr8~s9GZIx)8+#`#vd( zg0a2(l~FQP|8so5q~rH%`F;ZaL>I=xIKqAz1>a%snN4H6$_Z1Fy>nE(_VlKb?5|4J zV9GumIW}tpq~FMzxPEj=!A^D#wgXoL(D$<57A)Ami8&p^@<1=LTyFT8tWwOc)V3+5 ze4zLv?eT50bZwbpAPamQ3#`zio+3F83>?$o0wm7|_MXNS(`)%RMIq4(L(8?LUr^G= zaZGxHuy~9S9S}k<=bgl_>+ntiK|x|MpUnW8Rte*KQ?MW5koqaXR>({~=bmEP3(Fx#n*O9>p%TS1%`-Kmfm0iQkcU z5JE%pk{BZq{YRo)A%z2caFD{EUsOopmrhny?MyPuLX7oV-Cn~KmAH?@-?S%QMq)cX z)ULyKV#ce}5EG-~BO!MF@)nXWAe5*|Duti!1 zd7w-`KgV}LZjCFkUzTL_a*2F6R-Da5uP)M!*wrj9EpKukE$`~HwL&-`UL6-+tFImn zj+s1)KUd?m^9t}zUidIY{n6_|7*7pUMJG}8Dk&*!T3a)Jl-&HsEN?{> zmL)?fMT4#lvD@h5{iD_=uvU*&N)MolnoFy^Eu~d~ZB+rzi}hk-hTWJ@nN=zT4&|k4 z%BzO@D1Z7|pO{#HP|HC1!DMc>5vne&n*LKL)Mk!RxGOx>KZ9~Gtlr@vaU97s{_;k? zVzZ~(iH>}j9R8T{3?hr)K3}P$T5=i3unh^TXUhLs$|oIkRZb-XX5iA6mKWQtex8cU zPvKJ~>L*sDer$If(aJjB>tL?`!D_s!%oyH)2gCijG!hOvrf?JMo+$frclNWd&| zU{d62^J^~*-onQaXz^^jqTm`u4%q=`ug=yg#j$F@IN#GWS#F`RfWg*j&YkbHt8E%zmV6^a}MS@y=QB&=J)9|aNE6uDP=$}R?K z>^7?u+d{zen>O2*0DdzXlViCXP~IGWs*yAZ`S@7pV+9{A_avm`X~a2?*dJJf*U%v+ zImzGH{!naxfI{L59yy9*5iPQv{@`y1#FIJ57rVilsIB&oW%&wmQu#I?Rl+fOYe>F* zCvOLN^Tie%rDV?$k|5TlvQmKrhoZW_vL|31wA=^aAy}@YBl@@-WtZRf;m;OR7NyZp zSdU%B0M&&wzwPDPCo1WR)3{9MkE#ov1Wd`%i+7bh>W@BEBG9%kr(%RF)}=~i6RHao z9!T6p3!&+@O}w(0ydC6SDIUZ&C(5XgP9J0DG`;vp*+jffmGC*KKUA77G0?}~m8`K6 z$uD8=UiB4!Fn^EuKq#`S_|BBr+1i8rn_2gjHn)zQF}DTuh$^&W;_gyqxuPPh za#d=Gg445tF?Hi9bw|i}N)078c|74B2zND|N*B+lMjTe9MI_jdFLw1}xx5f*EE4`7 zF_}>FY4Yck0w%HO#>n&!Q{Dh(k9-+)Jg1_%lA4G~r zB5|gIM38##Q$D<{KKS`?Wh}GM7kQ;bLRmz@Bw*A_R5Qk(n8#ac>3lBs=Zo)J!Jh|e z_@gdP@w;A51-e6YFi@jB#N@VD{Kmz{^hQ844dPC@ zdCmHTzm(PQi)EgLEkN7X9v1Ien9&5PP;~cn9p5Ymw5*p%Lt7dMI7ykW_!L_503;lv zf^$YQsaPj_ap@0sksYT;?VIwpEQ=5>vf~t!StfNBZ`C4qO3|_X>oiU@+^JW~zH@yE z>nj+D0fU6J$OU}DD0Y-j``zKPR-f^PulPNLJw9#nk*f%OnZzf0@qw}ee{7CRu;eJu z=$>Ptw}S~^;X46WLL?5xmvR~TQO=mFUB2R1wa6QSMT-w;kr!woRZ5R7wu0~Zy9Vk4 z#t{l7=F)A@sLoFyHll~Gc&8S*4H2`09Ko3~S|7BNs!TaevTwQTcvLktpX+NWC##@% zXW8v2#6}bawBLPIwl9ED`GNPZijB<=$Q7u4!80ant1l`*9WZ(HMdt@%cMfs|?>VbWr8KI7)nQ5eP%7|EW=S&Yqqkw zRvCswc4K0_2_azd*0O%GFw0LtL;iyw3*GRBLMNXlb}h-6zxD~#%s!q?cy`E(t6BaS~_y06HsHps1>LRyW5E*c`z)&Gjj zYK6>dZS?Mj%*v%(j_sVN@x~pVqbQ?^G~rN2`OhiJNRc@4_}|vsWY2#N7s}>-B)b27 ze|x9;oB4n4@69iD?C+I!f1g;I>hC?zruVmt)8E5I(%+X6$x462hqDPIi>6tOG$Mz( z&!35T%|Sgj72z1tt*fwv*1KzKreS#te8yo$AE>p8@v{&O=qCucWy zx6tAwtLZxbG^#mDHMkyA)le##tEu~`EF5{o6i<)#Q%xfRu175~LgOMr6q9dd zO_WA2u#>LASL*msH&6JmYk{BTzujx>V7o2$?bsX05z*blrIGsXDq`;@H0G`l{=T~D zO_RhjgFp<}j?I=X%x;A}tR)) ztv#J$o>6u4>CvXIwU_J0c3n^m7yZTkESq+_XB#4-VO%ZE$hDBETyk(gn*vJW*YdR; ze%j;9B;lkmOy$g;cgO#a33JUqooWybOzo2F+?rJ9*2;WI#P#jCv(|B3ZS;3$uid`k z+Nn+656K2X2=lkBM@d!a!NST2EheMjn^2)Y+f9vK1&k8ZeG=W$PQH6K}!8 z;$IPYF~&OqBb3Kib!Q7}N{HH{Z84WpM3Ql ztqOcsf`?^2zsCN!+j^d9FDY75D>Pp; z|NeWRtzsP5G`)cQ)-+Z*2pvvgnn`!J^4Fx57jpeA8EH--)z`F{F&u$T1%IfF(};1 zj}|FzU@hZR`_LWz*f%i#u_RY7#^O3L=8)FM2y z3Ql_sqdLr}8c>QMa;aPGyU=-gZn<3zr?J4R*SU+22M%LzqJA={KS*^M)Fbl49F#|x zBMJAsmUkYQB9E;{><*TH;cEPUHnVyQ3f+;MT%}KEUGty%5fH{>;bNrtiSSD@P&p5Y zuZr&72?98Y+G|F79za|8c|=R*QIU9e$e-d{Af6kR^P?xz3QSe3>7caR2!T%GN9bz> zgoV4LI^UMb%0^4h6}*qyXY=Ka>2yhaJ7oKO`1t$k!!Y?UOMP(42gT90v>toOrb?Bd?46^NnBd53-fKpGm|%d1Ls=aP^A(+9;)=NrwGX1{(V*Pyctw zFhp5eu^Ll!cROn?ST_t|MPZ_s)wGM<3td?8H{zEX_6Ii!!i{AEPY3l(g!>0j6@(j+ z2tuRIFf(t6%(!Zc4A@loM@xQ3X~W)++VOX~oo3(MKR4D2!xoZY_4gu|^+`^q?Ro(3 z8FD9z+4xJ0o0L9D#e%pg9KxSXy>66TTw)8Z-mT#shcA9GV%vv3p6&{w#?->q5KB>W zaXAWP_@YZ~4(zw-)_*AhvFls2kv51Q^~#ros7CX>w}DCKl|{tg`@q;5@MOnB%x4tm zM{`WsIEwik^b%rpPV7Ndb7_!bA5hGgJ;waxAFo1gYoYc&+RE$A=5tcb8~Z#F7ZZ3h zFZL4SL44QK6FSuHIMt|W)uSlxfrSq><;H%+R|iF7HT)o%D9$}$eklRd75a(L!R78< z2N8L21?8?6-nrzEyQxtyir3?eU}q_3MO&zYKV@x{iO=+Cn^ebH@e*-lNuDnVtOn}u zaeH*{I-uIa*08=OGMy#=j1O>VuUeIIJqy&Y9P9%y>UG;1$@%kOmOFB}FIs6s6Kwc3 zW&h#`UJ1k(+m@UH_}F1KVoAy+Hfe87e?9bu&_4Rx$5&4tEU}uvK}WCyL&bAI55(lP zl*2aFwN_n6?tC7F4X zGrx1HoA8(KpMUc^=Evsu7>5emY?yb!@@(${tK+kHN4II~!E!kC9jph!oLvXh5O#&? zdb+|}mk`-fSc~rZ18u_<`bp3M>Cmo&s(4$dp=bERB?lSKxKpdSoey;B?}~gtKaPZe zBEGzTgc@n_vn2;SO$~xHm z8)qP`lnu4p+)%rT*~u0l6V*h&_bBfS{4t4nws=DtZo95b_)1LngR7zSs7Y1}FOv z=Jix0G=7N%&|fJzWW4ZHLvG-l_@B+8n7#T}L7zGo5^y_`y_##;jcM$YVXs0Unc{E6 z|Kv0Vk7ID*8|xt{3{dmu$WhWlEd7yOdr56iK>d+0jquRdQ~8aFjLCBN*_+V78l#H& zBz~OVQtP}kYjHo|m6$UwI9J_$6a3b7vrR)RkqOB_r1gh;KbC(TynZp%4i<3->*Qtfu*=G;i4N zq-ACP2~fqf;A^D6GQv5G(6A3=yx(@7!e7)T2U6UV@EFmY(b948^g^yhSJA-ikl)Xww=M-(W>I=-z!&zLc{W(&&y% z_~@@PaELv69w)EF7`>DW;P)3kE-_V%dag5gY@nZ;o(F)&xZ2>=8_%Wl8Oy2a zQ-QnP(Q^83D5d{W`dqw@hhs7(30+p)SUH%%_ca?)THo0+P$_r_+klD-`0A0~QDyH2 zHe6Motb3ynOk<8G@Bzf?Yjgg*Xy9~L59k}D;AY5Y^==T8-wjm4 zn^*yiN~V936smvC>ZTc=N4^xA&8hViRo6sWPW^;hzGG_n2B_ux|JUpPQ|p!7-lws< z5o2~8!hY*KW7H3LP~?#-%5D6HUbU`+EhbLB-b*=88}`{!fjdVaQ*8Q81Kzi+uiTj; z(-59;5{m(gM1|oPg);czoa+g8zJ5>v?8G)-(feW>UHPF3 zjI%#y=H%meZ$j=RhjOI6AaZSg_}}VN4)&o_@2OX2J5l@SbNiq_-~gL7DE@ck z6l*KEXkhtle}Nw&91^d&(?8)iXI&B5ny3xnka_nmV23@5uvg zHn=HZ^^4j;t1%HqTvdEJn&uzoiVtD@VKJ2UMHa$RQ1)PJANmuMw#%?FYYErY-a>nh zO%htrskz#xPkMM1F(7=!7xlFqHU%%`W(*|t+KK$&mgFDd z(SI%97do0&iaC=Y8j3oOp9E_m8rzx&#K~9joY?Uw&=PdxIC>=n-wv$+ zgERs};Vx5_E1N;|%I9r5tJNt1;3~lLnO^o~a z;Ku(1RSXxu9^zwwCKm2W1&cQ9g{rp=Z{o|Q6@+ud#8N!=w0^jLfDTa=YddXpt=NmH z(ILjJ^TC$V)GIQBjce#kNnP#(IAnB!i&I1P>MuR7K8d75fRn~Jvs#|el^HOhm4Iaj`oS#(QXn*d~xcCN|sf6z|ZgKja<846;8XS1t@~Qb4a51_P#W zZW~z!h<{3>#OYHYjXgmP!pX5FU&9moS}O9)$YmeKFYuqm%N~KVU$Si!=*m)^B?c>p zpXGl2E8D~K#$wF8uhiQyXb zWE}#bT6fgU{2Q6Q#2Z=C?v0c#0su>B;kCX38@=(Q`#Eo9ZIB0VS$9IuF+pggWkx58V1Cr5-CcJY+A$_7+%j=E3T*Xs>Y2e zw8VPR-}mYJa6iV5IQ054YG-O;kuhTfbvK|U-G!9K(DF8(tfB5@9i*rl@pGnm(Vv&_ zJvE>}6-L!khN5Yc+$&Y|huXb**&?@o-4d_4*k#zQs7$&D$OY{$*A$W z??+RR1rFX<7J!jCejJsrN^z=ZT6y?(5##%I6rGN1XGD z-og%CtNshmfXH3dB*Q}ngYo3}x7<~YVjEk(4+9XIdYG}2J}6gY8QX}PEgX+K^71aJ z;?{qq4jcU`L0cT^VHkS}(&YlJ+&Qaj>NKi&#flF85G8bDW-EFb+?e`KJpbxL{ z$`&r?ZH5si5L3yoZcsELpYN6j$KfiAM#N#>8YOiGkT8)#_Cz{T3`ECx#%cF5iVfjW z`{bkJi)a$5^gb2kD{}cbd>~(~5*YgKZCT`QYN9m*OBqUnTZi`a zW=HTtq_p*`kv%EzzYmdWZgz1Avd6O!SGz-pZRG>qkw-fOZt>rFi(oe?tv3rd=8if? z9uvk3Pi8d&ywhLUCUO7Vx}Pt6ZpRmZ6=0KGZx$_Zb3PFf;gr9JG3qFKDl@}T)nLrk;u3I(ddx^Jm)kySzYxG0~4*%F*8)OedW^3ZL* z=w0N9xvQY!0>=j84o%L`!s6+JC1)C~R>b!S+Kz(@U4arJ%#O+MYo6#bB9Fc-eIhd7 zZyz<=p)gn*UvRsRneZr=bm>KcQI8+CDqj%P-;~OAM)k!Bnw!hHcWzZ^XPCwx)-6D8YjwANN1`Y!`?_W zj{&R1Nre#8wMX2d@s1|0JPLhrk4kwo{3m|nJlYXzc)>U3f~zj~2rN&D$#8)EqphxU zE8#B77xWf&cyJ|mv}RQfYv1@VAi^7aIqC5Hg8lbBL&8}gb4w>G_D+)htbyN$i9 z{aBg8xue%#YjY^lfw1<3w-^VQ>Bl5!rFr8~YR_@ls5nAb*(4MvZY~%l#EC>N4liW@ z;4(`j&KjYOR@jypf}-`a0XeKRPW&>Mwu3~5I|KH|J;iS+*!#6aFnc8|i96-)Gn9kO zu>TT0xVZ&f;m`d840|@_3Gx1k@)8a!el~hoiU|~l3ETvM5V0jv4`ADMi({TSLebty z&Vu+;YOKoM24v%w9%vO>GeYjIdgW~k^|^P~%(~|_q0n6M*p*BZ=o5t$25!+y66z`c zr+3n6G|;N7xFiE|-R~0IoW%0~wmr8PYYy3S%ZQqsgqGTKg{GL-OHMlh`K1IG8|0n5 zAXjJwTxqp31CfoPvfOc8_mC8;$}eNVpxDnDrzdh1fgW-K4;uEn&~|T{%{#TioR>T+ zzAPy7iB=RiY9Z77n!{BOL%*rHul15=y-9IIQ@N7whA&Wkx?0T6N@t^J-=jF^rYx8j zP7~K2kA%Qw>%u7Xj1R6DFW`f7HfuPuh-rfKgB1y-C4ex+zA`$)zF~=g(0}xv(1c-Kgy}U z2lV$A?_Z3~;s7`xvD#5o7d0NUj^6__Qs;@Tlw$7alx7tc8pq=~*j@LR5KAna3j>4G z+>n@h^GrQ_)GV87N(caLdG7skk=KT+j?3o0x1FDc=ic`gfgfhoItNi%?)_Tc!$~B^ zLB)kGU5(m};Kr-tASxT}URFb{UuQ58N%TpB0vt7a4yLos8yPK{K3MKwj1)LT%WS&q zT~Bn5K;wu74W!VEhj_UIeFGX?faBluM8hL3Xwc**1R+g>L^E+ISgKk2-;R6>6q=Jz zI4Ejo&%Fk-J!C>*Bh}35;}+a)`rc?oCP2&dAjd8AL?0a~%mh)Zh}<&;CFlnd!m|DV zCfb#PB(T-2!4YBRBCdBAI`pubsSn46QN-1q83`Y8^UbTTl{1MfsF@3Ob^jn15+VEo zpZrfSRm?P(jSB>!fTY#F{)MOQJ#xJ-bn5E`w9=7)z+814XcdE|P)nc?>grSRAmS(C zbrTR}POY#O9E%&JW&*5+{fhvwQD}1vfE^ToDX!u@-h&)}QZp3iJs_970?`Y=V2QYg zh}3OK8o@&oGvanwO^H;d66YB9J1|m6+%Nt;EBV$l=7xKhyz_!;`1>)2O>3C2MO1q6 zEHoD(r@5u&8~&`kHY@D+i}om0;eDRFRgiDwr<8UWxOv2u%kc_dstagc`ZjzevOG<7 z!kYTvAjiy@`~(ChjVU$iJfQ}(5rm}p1g3Pmi*p*L)TcMQ#j)ek8IecprK9*CRQMqR zk$Ck|4#-7?gdmdtLHx%Ozgh?^i7@`#ol6O=oG=+*B8Txi_WB>$al_D^qj@}ie z9{4W3-4XTJz(e(ZrvAh>6DvAc$=zxEorfstUY$)Xf82>frDWzS60+F-=zK_FAziY+ z0E`k~{aY4pG{*aKoLpkFsG^JxLbwYDYSM3S^X$tauBN2!NfWNUG6_v-3mzffN-*Pz59c=}cbI+lTQY3Vm(i4iA}h`mc* z%IJCdqnGdF;JWC4oWvc!F(+|PhRsY;uNZb?)C}HR+y^q^Nadh-KmO$`>B_0ZEwu>< za#o)(?*-BPpVPIH_l%?0Wfj(iA;Hd99SJfjv@Xi-l-Ocj*kTIybGn*7pN2gz!a$;T zHYMeQ3o0erO-hznzHz-upR0vb>-C?{-Nb_?5k;2N>vo6k%80WoEQqVXNiwjKe zkUUI=F{v#Whc}{J{L#GdLltlQBWa8dI{N1dz2b@4dHg|DMXfF{pM3~Rb*Kp55B zZlgMcmo$SI!T8KkJ$#WGRX+(nsAe5_H9lb6hjGme%o-d1h`!F9DqveuzQ}eBVi|>2L);meVn9i3vijx>TA{ zvIh~wnmD(yf}gE>hH{x*T8rlC6&}@bfiP3y9|lS8^z-8-1?{yV451l$D9hApUl43z`_pt)D8t~Oc1E}#gwm0 zl)p6n6FcE$v+hmQHA$Ocw{rtRgO_W$+zhnLKAklcx$&M7WmBKY+Hw>K0|jwQ-Wb0X z^=?U`-f!s&Pkgz@d;|5S{wLHs7u0KQ8+j(y{q6r9tQ&*cNw6+5VJIULwI!#|Y9tG1 zVqQBqCAaOu1S|(8vJ%*s8De-@SXo0MRKFRYkue2{{9oib(p$xVMEuO}>xfK#U9J{_ z55WVu-y*HLO%@qLGX1)O=WQYyF_-qc31s?y87u?wi_O;q6KL`gudQC)(y~JL!?b1U zT3heHeZxZM>)Pm!Q#hbd!Ho3WBB$MizxoB=L< zI#`V@ACXicG$(lv=%)seKV^>W+nkTDHkwV=;;o0lua)>@II2Vvtz036&c zR#Jv=-*VKBR>kjnvRB57HV(SQtkTUq5VgA55&CLGV4xI&FU#N{bo@*d$$|0O_&Srd?Zw>yDLzmsPA=d>xp;|Km{76%tJNKzvGuY^t=90YDCsO= zIvfdLP#?M!!X*JFWEZWZsIzFnnAk~AhXU}-w|;UaRbpf9@o z=&OGN{s_hy3J6;DmjWR(|EaU)%q7T`F*7*GeL4zpFQfssTTHTrCMH>tgu1vK(S7}z zB-DqbIt=sCgnSM!1@hCs9rD|!Bp`o%I^@B+^`Umu%tT2bW2U)wNES;T zrLqO>Uo8@72 zD$e47niJ?_9Z-%}ZDRX_>1#{HSao!L#~oc{b0Z*k6DQ-Q;FNJ?0d8q^hV7y+(TB)(yX)tyR<4Xl9FD)A>S_`l zaNmr+?pEk3W*E7W3x&UkaHbdXcZ|DsJ~ib(-i&RWK9TI~)8Um{hhi`#OlEk58ZhS4 zrZJxCB%4lTG9@xJ@tcXhB7MA;r`i!YxY#Pa&sI}S2&$sNKrZUjzf@`*6E~wJ?@r}_SS~ahFTP5Fr%JH-& zfmgD#J}y=}Yek3btZ%TyhJ73zSWAS^F152Na$|p|!9-KCuvgNCmEi0&W(QWSx1^N0 z9~((791{do)BPN?yJ$%({aXh(5eGL@PaTG@+G0ORYhIMt^-@y!EW`ebMDu|MWE1@P zUxXcbl{g}SI}+oOE%Otpz?i9UuWC0?W-^#U6)lEL@I8>kcThb}$R86|FQkd9o=ooe zG3LxTp#z=8gVYK%h3w7p*g=%1l&bMrFH-hK{|{ z4g{FrL^YQ=Kj2JV`vBBB4~R-|ISg(wA;qJop}b0}st6%k^#wA2q8FnDk%+|-v)y181mG8^pd7l7 z&(qsNhlXhzX4r@|gzL`U#p7V)re+dbh&V%6Ir5q%`cQe1wxK)=7-okK^{hWc=%IaP z=%L2Et~kL!8Zzq-^~ifi?}`&#xgo3mP#;HLJCT8+S2u<_PLZr6)c9Jct3#symWD~Z zAd#EFOqi{%tcr{Imk80nf)-#?JL%@Dwdx=8+taj#tBy%b9LjAcCQ(rkQ)fM3x?B7ObV+B?Qrm;aVmGU!2X62hexRNpAotcKBYn{& zHZ@}{{0{&DhW^8?FqF(C5;L+VEUHtI2@eAjOKhP-WY+1}yLbUlvt>DmDV5jBt7GMN z(^NL?y0h@*Byf}!S;~>O!;x1Xzk%_8rKXC;L|~Uwela7@W@k*}HT~LWa4FD_E8EG~ z9}w@;UM3ijN1D?5_yEPY#)eRq_gO@O!o`cI*yBDYxq&M{PLK|Tk^(-*UqyvX(gjI; zkf*J@O)X2CDB?GJ+CFvbU0P6r>7mmBVYL+^&GHn#qlK^F2NN5J^JWhB2%_=oJBW@o z4D$#kwwwrBhpq~C?p-_{)yqC6OCeu~Nu-q=N zdH*>9-lj5CnL=2XNv4hVHt~QN#z5z)P+v08OL>}=9^^{~dLfnOX5rJC9Xi;v{-7D* zOUAh^??jw1?@gKY2YWd4-XmvWK2KTo2ia%G8MB+rAuC`y#T&BIC1a?58k~s*`A2pa z0ekf0vI??K=3nbCAujy2fgcfJE8b6D2S%zhTfH6ZST)r)1-z|f!FY@Vh!nXC~X zVadgAq(G(=xXUb%NdeiZw3fZeEHh4VI+EuOfzo>mZoB9NYsd2cb+8QsknPp_Q32-Q-)N`cSoz`c#13<3I4F!AVL~pazUeOGeak?U6@B;HDTBFzsG*d5~TnvWKJ-IrOcA0{Fv&j zHCog+h3v(~@-6U;+qTTtF~djjlD@kuDy$k*{<_5*^RPW9eE$}@>sbXKy%rz zP2KjZ#K?2yec;O5MqBZ7_^kG zt(@+~@6C?rO?yM9HGVmBKXm5qA}(h1nnp@qP)Z5>KG{k(FMpE@rk^+gclpZTg9YEXuKY9u)KfVDkz`gBx=ri z%6h@>l(L5X;~%JkZ_u|H*XQ+hwkl%@-z#jJtBfuqE2E;X@STQzMYvbSc-uVQ+A{iP zXiwBfpWbI2H$t7a0mA638T_v5I!43lD9?Q_ikzNTof0vC61m%m_aFFURZ~XBF+*CG zx0a`kDdTdei~-m?EF0_ybzQLhLjKM7U&Fs60>ulPvThj>pX=hrcL8tm{L}fjS75lj z|6%+p9!C2w=HFWaedX0H@r&fo*!U<%blSd9`}~SYPW`eMtJVeM!{kGGypQ}D9nXnMj0;>PtDByq`@2}TQpn9SRK);t3n;aRem)`^pT80!zjss@mHU4oKBxC z(+#+!5R)yj=Bk=`0$ahrg~U;)rn`!>oM_)keTejo^dI0;yg=TJ9-;Pp_;-|%I0(%) z?e*r+@uBsxOdJ@y8eOe;x3~_<$5ZuRklNV(@$q|%(pBRJ5U(nxUKZe2X}vhCUi3-5 zh^rU5sTW7o3r?0q70%~_8XV<-nmJ!Ix{fYg*yPOr?3O^IGymX2+N-`V7U~4riuiEn z>HT7_*fyaSM1}x_i_d2KhW%CopvaW2k}2i$?N7`^d!#Rq>iab7`>@1|67xm)2u;QE zcq=$3zHTH?L1!PepSW;|p%i^q2x%f*ykEsO2z3@L?m6zm*m^n;-MmBXf1yBQXWf9S^-1rvKZR$5TXzoQ}=BQEySfxI4Ea=qpeGEwCQ<` zqRS*95ox2^Lql#58Iug0ikI(HCu^deHgY`l_RQfNBMl^g7w@1N$3-rRycORw@_ z{Q5P&hE(JP8-5?p=W&yIJSW)jsRJtyvprASfkk$GWK7t{}UFkP*lrRXxrlFp}_3%RM zg(mhV*Nd7OUKP>6KCbAklAuyzZ}>;7a_z4vvjK`;32RZNudFwc()Ng}RSd`RbCd)v zWx4T>8_R4N@$Dw^dWcR0Tzrw6h?94+Vt^-NBP-q@WDp)>vriyG0tU?)AN}-WutA-8t1r*<=pLkb#~0hX!wos2cv{kf{~W2vp}$wQQ}J@aj4~q5V9Sz)N zHsBSf#9dh9^6Cf4HpMUV4PGXtF4v2ZN`Yl(E6$dtxpV8)T#;aVNS?CFwW9_s80j&H zN9x++E#6nr-x0ZbkWpXN@h@h(csOz~TRdB&W0s&SdCpiC_onG9XjWFB&m0urm+alr z)+}*|BIC5PW+~zbF|W|V4|45_%%l@4RCRnwKjoJvBwHe^`{yWxW1LeEm#c3^5+u3{ zt@?gyrG$01*e&u*f^VfqD?YA;Drv~MN^I{DNazoV1<|{qPOtXZ8#EQ_oU1(!rQnB8 z3$IW=xSWIi8K!Jl;y;%{UVo5_ze7DjV@!~uu1%OxRtGx{nnZk~EIccLl4a@+32!!K zh*v8+>W4?GmLr*20^hx@VW9&iq+HZM zfQ(P!2kvj#b!ZR55jvLLx?p*08t;lRCLfaI1&nnW%q@?wa4;Tiqki$iMj{TFD zq0SrqSA{xn(!#%`LZTH}yWp}~zou9H|);wi| zcaKcY^NYF35o*>{uLCO9phd!h?$1YHi8L_H2qp!uFHl`@a~B2ancL6T>@9gyFK^N+ zeaVO|*#5|>^eZW1y4LW^m^mn>^Y=`keBNOJWmXzc#C#>^jS&h63l97n#nV}-xm_k* zr4&ywNx6jgbS-WjHRce00{kqk#!-3{nJ*eWUMA(fMJlJD6$R2Vqd|!xyTP<9H0&7| zomil&m-UDcfJ`!lN|ZmJ{K)4=Eqd*Y^D(2ZhNq_PgssfOG=a2hTpmy#jaAJ@m)02e z67$V@s;%gRU!}@^iozI3hhH-hKQ@aV6Puw@Fv;8u6J;O@%I|}ykU#|6asf0^?s0Tf zLJE;{$lXSj6B(*6au>u`%C+tjH5NKSE&MniJoTR!ra)ra6p;v$^e_9>K5#wn?(JHm zh0m9{nd{H|)kI4U3{P&s#pd9vf2Jx`04CJgN7eO8%#vQM<5Bu5kM?Z0nCBrbJSq8 zYK5KX-Mspp>lBC|RYj%Ek1#ZljXFrRspzB@zRzqao0ej7N~-2>G+&NQHD7Dh{Yb&n zTD@^*)2v=cz-;<;3*50A=p%V9ny0d|kGMhp| z>ocgGIWzqaams-tTmAD*l^(vEDKO4t^4rd{kb|X6dQBOl`ZChQB8Z~u@=ub)`Q)|M zW+el0iZCZvJ=w_SNZBBxPA?l&qBw#}(wmzsy_zTWv&rT*rJA$FUvNaHZwj>!&{mcS zeU0Ylo(t7Vg$Y-HCt`lIq#-c_;w>cF;?$Srfrbk#tsQ*}uN)!65tx`5ikxr1lIoB( zP;oHTWoa)n>ngI_8lii6d7ivXY|Q^sV=8e|H>Py9)^?NeOiPWY`I;nM+biP;8MC!& zNx_$FDA#Q0Y^j5YJR^26_0=!&I8QO{1pQC7_J7fuH*%RWX8EbAVe0<0kmMbPmF?k$ zv5*gnUl*po#iG(^U=`o5g@^MUI)Eh41m-xXVESSC)KGO!O#UcwSd!;wc5*^}8AAHe za5|0Z2pHU{f!C*MDcZ!c{C&4t7DSox}7&BM|sTMj%isH@inM&^oF&(~&$?;?2j9 zU^RY>YT4v*66ic$%12AC`5?K;`_fWuuo^O9mZ3JvrhX5iV+*31`j#5SEExr`VH7*B zHb-$p4%3ivZJLoEo!q!M3Hskt&}y!ZvI4NasRQ`W@=6`7YxyN?&Kmx9Cx>HAQJS+R zus31-k*AnbVef%&@i8s*prE<70ote%30zkYd1#Q)q(3yM%20%<+ZE!sgPDd&n0m|T zOhb+b&bUI{%CiGC?h7GfOyvVyrkVyVF+2;V)Z!Xq5LoL(#dwT6e;D{~!i*#xW8RW3 zOh`SC8r|xmuXJHrlQl@|X2bHRsn<)Et77Q9u9ypLhpB zR6YB>+1l^LM`1&h3Aq*?r(h!?HkQ^Bjlqp*q4nX<1O)ccgFxDX-aV;OEha3^K()^+lBjlNs_e7UV!|Z*&+K}odrX5^&o5FC zyF_*09bz+%2(IoRdUqkh;lg?nw+064EfX^KWMr^(M-i6h9yPSk%rl05;=SbddI3GV zwZwKQl{!abnLK|3Hd(1z`%_gv5HguYi~cb%37e}^rCyd&Kz<*XL7zf$ey=g*-i9gi~am>wPeJBj?_e>lsa|YCORK&pMLD(bFq86bPmIg3KS3+8uc36`7*JQL(EX{d{*iVZ$hrGc zs+1>H>IEsqfShk9kw9crN%%Z1#5P(|nX24J#!<#b#k#5`G2?k$AD8!6Y{AHPzty@* zIUFR*Ukpo;^hJP)D>Li1?ny0@+_j(btx;|dHP9ilaOc3cTTnb zEXEZ#GFn^<9>5Gxk!DMG+q(Y{ohZ`0M%D@sYhPrsX~BF*UZ_?`ec+j{Kp6XPURrKN zTKG*>qU7*d*5rZZn3Sg27J8ivcKR=3WuK!g)1R@E)%nnkCkdfTQs%&? zQL&l}waC*XylRG{=GNT!ZPu9lbE*1YXImgphJIU6jkg|sjN3CTTK%c(uU8lN@~^z#XTuXUVyll2ta3b!DR{BOBu_?xq$Q!XN$1YYIb=O029QKqD~ z{1q99+Dntp7P8b;e$uqHO0JEth#bDkY8*RaMDs5xL8M0w1`{-$d*$6Uy960)Q^Ipr zbmG!7j+MkVH(Ec!MwHf(2v9B5KH9WIA596vUb|30=-(4N#UnyuEj&c^c}Q<;eFC8s z?9S31{BviEGjiV+Nk%i$NzU1zVOgV(q6d^$56}#56}0qGO!QWu<(k;T03eA(;+X)b zpDRcqQJT+>G3pR%)&vF(qM+82q``0TN#-4xlfafn5=zBg+&I=Is*pu6XDn?~^B?d0 z8);NH(N4bAj;m%_?zj(?J}GT1n-dTR&(mHTqaH=FP5X;fH~D`Vsf6FZ8zV2#JzuEc zSvc{VNHmD3xa^D%{c}j#Ai96TR+|GQ58 z5=2eJALiz&(l@-TC00s0cAFhPWl{>W=ujCpBA_ZoppurG3HEujthi-Ks)b(RiR;N! zj8MOEk$fBKWQzO#D0NK#+!#Mo{<;6ok+TXM!#B5^Bj;`O;~}$}*$*3*n@THPI5uPg zyQ>oPSqS>RzSbm(CyBWLp9_VcKLA0;#vHYA+`8#JFZK0CSB52#GObG!O^q|%L0`yM z2zdS5i8HC2e{YWJz@Nh~;u{g*rTc@jhVlPS(s|@FqINS?6~9+tv>2N2cVlR<#5=;* zQ2Q(`{G9r6Ez?%>9d=UYtBA!Hs)5w~DqrSoo=N2nnX^{CU5coBhq%+nWUUfY6GkBP zR&pC zlL;z<7Bja48LnVWE*(8j@TlFzT%_GltQZ(A`4kAn>cNi zKkE|VjdT}+Pb^dQc5hKDh6XJ}yeQ(#*D8miH0Ma{=bSix09NIA2$BhibdC+<>f!?< zONoK77dA^twRU)K4U-f**2;WdclmUUULjM8A!uS|BYBrgzlG(94H9hAr=hJaa^-V?dy!$_Ng? zKA<4fQRpuWb&L&MSY>1oYe90R7fO@vNPcgweyg%=@dE4lH1`^wTUtljy1Q{JZ)9xA z2??WYG0a6>11svCymSo_c^mQQ#7IpEg!>^1@kFO1aCNPAt?Gm2_cTn)>cnSRZxh>9 zl>QsG#;H$o` zcE+=?%yj1Mi05FAnYRPeQS2`(F7Ot&YT+72G<}tqrh^^muOE>C8t;Gr9-~=#Jt@bM z-|`xb_eE9-#@2r%M~N-af1NGVd7&20pg^eeVlCW;$%Pn77R9hQLg*LZ@PGjGCmW(Kx9n?SM z-!c%{Q@ktiF###uMGb=Cw_+!P-FC%~e9`{dWx?WW68- zum8=BVn0ieGMU5>EjW=zJhL zuIK3wiX+{`Y3K*cRKVs%+MuGE}_UkmMMD|U&h0Xbj#T($I3CFn5xXvDV)lU zyAR9RW@lbqoXpD&)Ufi^V!J0s>O7k{Ynz?X(oIzS#1X3N<&3&pLhX}WS{Xi&8%iI|8C%7!B*45TIu|( zj>f5u3apL>h;Zo%PD#?eTqI8F`z6YEcs)`X&Sq^xKkPAkxT6o);`8<0nEV4pk1~=9 zVuvXvmyUEBDY3)EH|&9IZNoKLX*U02jNFjdiT!2tfrN=vCr1C#2a+aI4WZ7Feme(` zyXYOa4L$quP$$-+KLn1jl;*ilXeBN5S5O0S{ZI_eH}ErdIYX71`ujM750A8gc$1iu zFB-tT;g*q@95Jb5-lBGniOJoLiQtq0BT3!V?U=A{8Y!43ME(;@uF?((JPn}4SRhUE z;Ql0aK}edoyRB%Q>lEw3f7Id+L6MXlssrh8A(o8(GUdBRs^O<@dEWvtO_GI1{R z6uq|?5Krk}x3qU`JVVi{zstW~8=(((%U;#OA~fe$rhlTc`MnRcni9~e@8qw%)>cS% z37JhMdBjCq9Lu5w2zB0Zy*c(AwZV2Q`=S#f*-H%n13XQYrwin10Z-RX<7t3A&Ed&= zJx@L4X*y5S<*6f!r(*dg_1fg=La8TDtK{ii8PL1j8kJE|aB>+RcJM)~UQ74MePY;; zUM@=q)ziXHA#sX*P8~T)w&`s2?*=BN?_EC)aIaQ1wCc^21R=A^6+$xAM>PR$=*=#I zZ)e8GCOe_)XI0IRRa1--)M8WTRe(mQF)o{4{ZqgnD_|5d_<fkIb<_F2OIxZ~L zo@jCxk@N%+P-k9+lL(+9Xb&+(1YI~wU5W8E^!LDC%(Z*Dq7Lz}5CYubfEUzOinTH6 z8J!r~<1tm->G#IT9#yC6_NVR)?2YissKVsHptu;YFmW2I?}a(Jm}hPcbrfi!=j8)o z!OVsnxSbbw2L6f-f8nWmCZ_Wl4KW!Y3-$M^PKiLfs!=4`lC=D&QT_vW@t(k4`W)nE z&F=cvQU33_YpIeU_c@q7k%(hATQ?z%Hl`S}aK3bUD2Z}k= zA+P?0S|-D-V-l^XHA%}-ZL z7lHO&g%t!SzV#BoGwL?}O^F|FQ$g5>&7kCO?xN$` zit}lSaBTP!jkWYt;=!X;i^`e(e?M+FNW_mvM({s#O!R<5c04?o+rkWvvuU7tH^ z+{VHtnrbY~1lYbKUfs6`K6M|-Mdol9#d(of){U8L_p77*iQwItS+1ME8VE~%1*V>a z0o-tF7iPzsLZ9vpZH9ha2mLrb$*Gl*=e-kx@Dc4(#&AX}fXP7!LnBps`nXv&>3j$(OpjbBMd5sISgxFvoKh5#R=1y zx0O324AxxkL3n#LI|));d?IiOyZJUN%wCDVKsMfAMyXwR`B#-}V7r@lR&emQ`LGI} z`oYX8`&#c+S}fx8>nMdKCRkv#q>YH=ynq}{B|3-_&Q8aII+7#yDf}FSL3$yNU(1zL zpEicA-oyC=>14Ym9bYUR6CT}N)WV_BOXJ1|d4;34VZ)6nZY~7YpS8}$^>}%KF{+V^ zdv~!y)e*Oxg*qYkzII1nU(FCVX7Gk2Z}wU`^+bG(fkXfj;y}rI$Z$w|jwt>NuzEv(c&wq`8VP39MO*ZTNP$`g;ZaIi4@l*{17+J*;N7+^0)WRq~d zV}$F)qSbQ4OE^>Fgg031T$K}EBTjfk7_1j3yu3EO(^J(E6f6iAG4QGS6H%E3R_}1( z{_n&d1eraN0Hd6fE39$V7MXFnPQv|NF&`sH2{$ycGPJcbjkPnP*->~7VB>18{hI=k ztIqK^H?JJ8OMibI!armyHky>0hx_LnBjpX|^C!GT2OJxD$iU!sC!2>2v=jEFQw(r- z5rF6{?)Gc7@DjGHV-;rPC>)&np6Kjf2Rnz97er^b1UtFI-o)qZ!+HZiL*hY%?1Ng+ z#XAl?ZN(IR_=+1UM{JZ{y+t@X9OHVb1x0eN%(xpzuCv8Ntm3x4qpj#8<)cVe^mc5^ z+m3l`Z)z*rq^jP^samL2ALhZSx1Om{Ua^z+q&8Zvt!(C(Ti;Diki|o$M#9lY0rXTo zYyq5jmK~L?>=@)D6x2eu(WO)Wlfo*QuxF!ocx_+#zZUMTM%m1f*@iQ+jyDNo5>s>A z-`!PRl7YE=ge;1F4F3rZXHNMXBHWMU<6L|)I4CMVjgz6^xD>+IZPhT=i(WIL*>$1% z3rIlOcAPk+`+T;y+#y$UwsK=;E$e)Geax+da1$EZD~*lF3D`pO)+s7mauK4$S44l{ z=7POiR8-#)q=^L9kk5sWd?AR4F!&izAuWqd?oxgUkEy?~w97#;8kC-k`svf-&m5->lYK zW*xc87}ZNnzm2)glewW!qryMo%#hIW@@9F-jg6Nr@>0V0z@a>gxKJoF(!jA=0R$cA z2ZDBs8wX{%_$p`GN^zz&%^AwDs{kTn=P7BTcup{74suNN2~v=MBwsod0pWztPbpa4 zbIpCm#(dgx)S6@s2OiN&(MW;WNVlj}Ch9PZI)qP#{VRAUQA=HjqOgvDbuENPI>tM) z)wGcL$z(@?^=G+kAY-@N*dF*yDr1)=HM^;lkh2RUHhl>spsPUQY8dVA=MtH^LlQx% zM#u!%Mk2P^j@P8LM9c_p;1@1jY|?4Bd81P@J;pm;z1}COcJ0(4A~e>Px88_{S0Tp| zd14kKO1^rKM{n>Hk*x?vQriwb)DiOm-w9;K`VMc=ety;ZqT~BX3=Aj^xg4v7MM7rU z2eVhsJqf@unE)I<{g6+a-pLKs@M+Gk5V}`P_7GcR+NzkKzAFB4$W?99zw*8~nDGP4to8AbKMKF{TU_h^!F9QlKODxaV+%@)p-s zh!BFbYCU7PiDvjQd#MYw!s>a8>&bfw4{|lzdoH@-=>-nuOA?b~$Ao`y*$~7Q6VzCy z;a6QZ-c|#jB6+YP(^!zJXA9MwF0R?7;!(DA3On>kHmcIH!`^Ql$8XdD!q2Ed6WV#& zM47uv*Q35nFNm$?MPLif1p2z5dJi{F8)A!zZ;S-_2ycCm7|B~<#^qjqOM$wW2Z_M| z_qpNvg7k~IaKJclc?-H<%J;)@?106KpNF4SEDI2saR|7WZ;kgdU7ER+@1So#-l}uq z9p(~(a%=ob6Cz6UVKN@&L)GC@)sd0QsipBZ!V_RCpprFb1m4K$IE6BeUy>USON*z4$yY*uuuj&)jkJra~$VHj2 z1;MR#HNLNETwj}aB3E$#Rl%)6{Y3rYKH_+nkx_YeaNE9`IbYTIzOHd~nJ&r0f(Nb& zZVT3baaL*Y@5iKrnmJ$B__}IbhPpVwr+#JF&%q?cBo(qXAeqq#rFlXN4=~ub-l{fK zstYyhXvupgh2+?O-HU^%m~k8S@R05qTq&Oo!7_=LxLiSFG6q}IP7>tca?+dhB|z5V ze$cc6$UN$1!eyQ7HX5TMrM8$7=a`IA7?cB{!0X{$P7GBMkU zEaBEwq9teKPVhH?1^fQc{%lF&=#|KLEofFgZ+qW2_;W8wNLD_;Ddov~(-ZZte_X3p9^;R&C%Ug$54=TQLC2{rnYFU^Y6EJ{X5IHEXN~J!-rG<#d7_U8N2~7L z^vly))qo0Ez>@?mW@x46w*vENtoal)pC$8c!7tNsb& zJ3PDg)1U-RpbgFdLiX%tg;+2unCX?ElDiJI?H=Cd-i1gbP*>DIIor~f^;%3ae7W?0 zqAN)DIZyg@(6`yA@s6NnNJ0nc9Q)K)O+%5UF&)pYecn8dzIj&fjEv%p;ca(QBXB0W zxuiyi+1z!M5t&_^F>v(i8~N_mRa!N7Q}x|E^#H?b!KZTenwTIC)6+_q+OC; zO-`_5?jq<_JEG@uzPn4Z_*eT$9aZ{jKdBGbV_V4L02(^ulq6!sM-)G|ahD+WC-eallTE*vCD+aB50~`R->;A5#V5Yl+ZlbpXxqiI zo$_hVoDA*Cs5*TWWh(9Zhf-mF2Aa68daAtFwKbmeS7W)L!B!osvR!d6@GWX)p4!Gw zbF~#)fI+f1m$vC;)f-U`mgG8xa^}Uo(%*xIqwPI9hIAD}QWoNm@eR4O ztHwVGAI_#sSp%1TM6AQufiHYfi81do)<{qkBEm{6T?2?k|DuI-I5{fVw3UYZ0{s>0 zBi?+T+RB$fVgOD90Gth_@1iRS@qs9^ct^!{l|X)HKgc5Sk{I1O2!RsJimZ%;^rW6w zo2@Q)z0D(MUI!u?Pc9Trd*pkdaI9LjCtHeqeC(llwWL`j%GAmukPmpOiiocnP61Tw z$gCWrR9H3OF3hDTdILRLv{pjzvvcx}g|_CZeBKR+lC${CMeu8S3mIo?p$^8$!O;FW zVBOG18`;wxc~YojO?EHV28j}haOeCfex9T*mF~}`G(g29?yu*df?-eZ2WBXZ!m<}* ztJr_*GKoOGjR8V#c>hO}x~(H3kUM&fH9X=UZ?Hl0g&^vGuRoZZ*XaI!S9Jjydh3rC z>L-dicO15L)*sH+ch?`vDeAPHaOf*rC>+{XnAf6j3mwoxCvx)|aLKKYWryl>iLJm1 zkR3RS@vDPp*I^OrKhcoeLMB?GiJO5&G?yX^Wi7E%1mH=u>0%{87WR7=sPla$!8O-H z9rO-Q)C=zHPQ#rbldkTLJAdm#EfaTCiab~JW)pWlNW+~a07K!9SV{=))Xj(mp$C4C z$F&(&PwSVV^(!slze4^aeqm`T|IOyV+bH<^=cQm&j&ZG@&0X8m`X6`i0(Wh$^*@ik za*d2;OiuBiRKv4Xd1*C?;qMPJG5ar28*M`~43HN71DF!a5;CFB3!?g{#o90u_!DWd z6}>?=A`)4GToj%56n{hl?2j<|Z1EI-%+HTWN93_}X)B7T?;)-F%0hmKt%EyjDGU*J zZ_EUL1JB0wagC?wBadybSX@|y6!*tkN72Vl{l1pP5H2~kY?K535 z9_uq>GuuG=ByRMqya+UBm!kY~sM=5)19`wQlWbw0p=}tTC{~L?5m{j{MF>c{kgE-K zSWK-yEA}sxKkKs`!A-K(2pm7-S#>j~4vvwd`@*HQa?Jj{{)?>QHf?H~Gn)M+B{Q5w zw9xD>g5~@Ky@a;H#W2*le0bzUkC{J5&PgH*zCMTr^0c*hhPNo1itz&{K;8O5it!6S zK$nR#d|+&WIRLpch1#>Um5?jwb*7X1G<*=8 z8kxXrgq#a+$=_EG@^|4ltj}834_g@OLSg*OmjJZ?LLr}P_*uPGMc3R2t^m&g@ZTRE6#;d>NXb99F{0wV2^j}(dY)zoAciw=|{ zczvJP=eV-1?;l#)!Z7yp8`NCAzNdRKp48Pl#LaD)NoG@x-KQFRoW>$9Vpk;ELll(R-#QhriCA@Vt zT$3W~KK)pCzJP=64BCFBs;>Bg?zH`rG}=xQ3X`^HoNvO#$9uxpB+$8iLGOlj4UIM_yL>M9h7#Fg#lHs(ag`N`3GfAeRAsCp< zfl4&{(yD`kE{YXih%?@b3TlQ93?p_4=8RhP!#t7zj<$pt;(slzbUiLqJ8|eY!klsF ztIXH2-{hL0jE|--oYOaBh0vHO6SH{sdA07|%%`~^p5xOS^=AEelE3}itPB&(`C>|# z$I;5jOfJ`9wC!fs)xmZ(Ccz7r%MD7HE`SS{YnWW_CX35W+)IST)t9~{(U1D;Ehf`n zGo`1&eFaV?K3Xy!>d_KmVb~t)dka7F41(s^b~wIu zsN5Qb35rPwf6;ud6x?D*K$%_Wzmclbire zn|a_8z0(KK!x8|6D4c_4M28L(Q#tfVB5%_+d{5ncKK10i4=EC)U}_%h^^EPsE#+H$ zMJ?p#@{0G$gr9#}iJWYk+@%g9#H+J<@a+1usD(-nE)B!Q<}?4ZN@JljtIq@EWP7wy zaD$r`f=VAT8i`L@UCgiubP`e5W8I<2J+`0lfD0X=O@czhlvbdYh0D;&cw4ne8X0Ee zA$Cms$l$p8W+uyUCrvguu50%Fv00vdnke3>lg z%TRSlG%^P6y}8`{RX?eNMNX9;!@j9QYyF_uZAXP^sY4{7g(Wyo>}$Ea$O|<0dGg`}FN6}t{sJ(C z-;HJQ1_Wq(&prHPXn&?V>lbee;!cf@zl`{4<{mX^h%y-M)K-MRUJ^oT8;%+FwLP%! zu$|<>xxQCSV)LlR<>r$(m~&(I@_K!C?7!sC;MhD>h>T#b_CvFcS%O6D@hR$Y07?k; zfYoR&P_>}{>pX3H08uSAG5=94@z(kQvD9tm?EbsUKGb)6|cL8S0@Hr6mf(8BSHm;IXdQ^WFj_XB>oA)yTtr= zB+2y4v(!!J6w?;5fVuc_YufKw)9&P~wFCopo$C?;0lD5lrB9jDR^kBU0B$a2&?hB` zSU)1vb*{GZHQaYOe~-7s*yO<-LVlrCOBt&6YPJLRGSrn_OJf-uxjAKMQ(Iyy#o;%i z!q^bT?Q8H=x5eUM60Gu?7tb!;kSPnQHt4UYvOX8~Tqbz4{@(h$xW>P|q(FSe`rhh` zKqy{f&V6a^`o3gE;1CvFh;?mWUl2d%#k|rDNE}qznd@^TIGcH=Uq6sW2uN-7i$!~5 ziAW{`qluP95NZi_u9%;D7+tV)AmT~KtC@~5O{K45J9;X9nZASbL;s+tf%5~;7zgaJ zv-pHln|flZmAus?;CdVJ1WUCio51|YD@)jtHBX5gRd{TZNp`~`x3##>M^O4$GxP@% ztUo4_R1E+1$3&L8%J*)~W2Q9qkvg8C)umeXQw*11d0O~Uen~=wnh-zK&{6KnHotIA zfwn^OZMcgYwUx^R(2?h442}qiR%wZCUgORR6nONH-O*nP!O*ixYnHB68p`w0YD7o{ z9d}F)j}*$tz4jf)CUMnpqS6U2UCUorM`X?*#3qsqRa%rU-YgjWqLYkdjr&6ED$Esk z);tL7P4IH=a*^sq^o0_+nZ{Cv3!6>o;v5-!hl|^by;!;b#on6$Mpd1S-sbVVNf?>wsf(8;a<8&85u^MyvFfLDBSJgC0JBKPs+lr&5pj>uqnzz?xH(@6q$i*%Pqhe(*+0qhsLgg=`u z)giKofQ3CHU-EdRL!dU&$O}Dr=2uy1OLM6-?z#FByw(gZl3-y#$(^6vZB#fEgT4>p zND|0}e_(Yi=P&6hbo-txdN-mcx0$gfNUY%OY$Z(WHp6~Q9EB0RS~DbD;rdt|Du<|` zoH0atvw&=4Ik(8wQz&Pwgve@&ewy4G>j@>4b2DFJITyALEFw@{D4asL+-kTH@E2C- zY8F)Z&mH_84=n16$Tza?%k|vP!UdVTu^|+?GTk!>`->hKI&L#LW~ z5~hj^t1@_8Qdm`VlH;iiL!NkO<^IEyx4~)r#|lq=EmEJg&dRU+7vdkZ>^x+y( z5tfD#yu=+8J`XI!PUe0AUIUi;1H}t46?j&8SsN;a#1XA=EOix zPvGWEcUGOVVoffZz(a+d%0f3*I`h0n*wwN;MlY)F8gj8P3iH?a-Fu03u}@$vv9D6g zVh!;>JW?ND7VF*Xb~*Fb7)!Uo4}L>th&cXA6Mqf(!-7Abg%@sk19R?PGT6s$@EEo3 z_6gJ&%ZSZcjP<7m{4Bdm^s>v8Mjm+3F)IE5y<{ePgu<#mgTxO6T#v^@x*@ala*wE9 zJuTx?eJ>h>q|!=8JLVSy5w65pb>qe2ojCFV5aA3LO7XqLI z#b2W`i+I(TAT|%?oq=MoF$d~8pIslk#H{l=v(C4hbuMy!`DUH(lRBp#?i+nCb^!Wx z;q@0AWuY8>O~vw0D-P}~J(by&&Czn^#Ta~>eT_wf4w{wfIEWy1;DEWXOADxVJ>Fgy zoAoIh8M8j)8<{?VMxtM5E$EH2HYV?5z>R3KI#p7aYC*q%!a4(u&ISxB9z+eQF-8Xp zUG%~SWr$WU?lz(PUIpuG7Ej4yaP+$E=!XWMA-(p$OAnNNdvXOF+2DCk{T^wgvej3;Z5 zp#Sd{fdIwM_cN!ak7_Ni`_CX5s14)eBEU zuGqr4u$y3|_|d;INw3){6VK<-&b%*I?_b7pe$LIfea=9};T?o5+=2HkITexLI3VsJ z^BP;B7v9095^i+_$8{SL?S7u6{4Sy&*Iv@tP+MB=D%cC-ERL-Npyf|B^ z7)Nc1NDa-!F7+;i)zDAciQWS{i@ToZDz>_o?U*Yx`+22+{YOzKN1qM*vw3U9Tf>tg zhs=0F39=q_OGLR?a+^7?h-U+L>@9C#HxAfKpBE7_Z{Rcdx;3-}*LMDf$ZAbQm>1N< zE)i8N90G(g3{2^CKnUNccmedLu4rus&!Fwpt5H#{!bazL24RDU>bscA;sWyWs-iC6 zKtmpUGySQTRH)#C-!JI)lGKWNL`CHqOvhczH!E+}KO!$qM8L#+Sl^L`3uk!p z>y5crGatAe@46lDA!8~{^3gigB;_;-?J?*x7}V(N32I24`ywT!t36Ivi-^dfQmvG{ zx+=iS!i_H1hepLIz&iBI*Ipr z66oP&ioA^F?gAC3Z-hiDzbHablVoTs}m$;2rs;(T2;p5POy3~%U7i4nb@ zTxeiIMUKNW^-wvy7&j*EWsErLjw{oQ&aE>1!W~*BIWH||7bue4Uw)k>Y|_8oE^Mso z*unwM{C^sApCTu;ik+_;+?n}Khu2~(dbB(2V^QY0myac}%Gr};g%w%qHU1_USlDHz*40vW6D%FR92A8Q;nVhGs;WdTrk-5So6?0A&P&NM z#mQq*kJZ3jD$0Qmjq=hq1AlyEGA?-QGv&phtMKNxcJGJIb)PubMN6FF6-hj zXlwDHPf+5@aEh~;4_~|R!nCwOA3DR)bmySW&QQ0YGw}9nlP1w425nv&8T4UcXu!>{ zWEY*ac3pH_!1GKwMSYvqzf0K_&N&BUgIIQ!Y)nK1KirgszNT4U&UH;CV*`Dz_OdQ; zeLx5?&6z5g%HeK2)Ql#PON^_&B0(>a2KFo-}WS3_le0`48JF8SkWPz;tU8-YI9LyFs)D=jxqk*)r3uCrbKsVH&M3{9}(wz2A z>t9@e3-J+S@jzGL(INY({TtKWOUOljn9pf&y}G6E%zHk#{*v>RxcpY+16epdL%8zY z(ake;Q_T%B8P|F8w!oHf&p9M;;MO5KXXZ+m-aMiakxV?bj6lon3lSlj_ZEFD@>7Pw z)VC#WiLq-{iE)31evTxiu6{3%AHft6C~ zw30&Oz85bvaZHYs7~kXHk)8Z|OTPU6!j%g9Yb%{y(R;bJ1& z|6|vj6_S;EPFRR=I#xq0nf-G|i814gFZlD%uYvaPvKQ!%FH4Nl_YI)0B{(XPnt7o- zGxqW#-w#63{Sp{Q(Q@1}4)jo6nzGvzr0#%v;WY5K@f_@p3_i_56A4ZF%{! z#A!T6bnc;|(|CG^gV&o<*lQ zoQ{?1CEe+$Q!gDH%ZnTcxo$6Z9B`~-i=N>{=Mc_$v-34+U$^n{ie$3iDhf2&!&Y*N zvxn6M8d?V-P{vf3j4UqHZ&d7%-OW!knkj-^A+FCte)MRzodUNm zcyE>XYrR0-c~!tm^$l0nuaHZoyhgcaUEbPi*m8&8TN73+kUnaJjJav^H2p1?uQQ|vIkjw5nT z^XC22U2!=s8dL$SC#5!x&fuZIllS z2iT)Y6wl;M!-qxq60R~gYaY34LnwGH2)V%ryTvFzgLpr)|ck_I`~!4G??5O*wBG`%2Feu zMindXj*nmwzn)!#Rg=KM<{Pbqa;&5n^^scUbos2%iz&Q|h#_Cpf%6@{E|b<#6>+8P z{H4tpf(R|BxnOp^ITz%FI1SM8n?EbFdUbMNMeUoeEj^a58lMANbVtQiMRSN;)CACn zA~o43fW*Lmi+ofs)%Zm*@`z9~ES6KvN7dD2(C7SFkyJ--^Y>PzP$!Pjl)@^LR56Ls zqa>#I%?oT&(@g^Zjm{gco5)ONdN4yOde&g-Og&srjb zQLa@k7o#O-#d7*-x|DgnUP2c!`(QLs1T)f>$i6GuQ|;WPs8*gJ=`q`6XFRkF~SI~Dqz zr@{N?U}%cvoJ~zz-=(e2;zEj^#$|nA5-NQii|~#C^Sg=HKbfyAZ=aLtGWP6gmgM0U zV7iPCKBbq$E^!%QS)6kzIYH4@xoyQV>3Ei6^YxHubd}MHq8fV0&@JP$*e5h~245TW z$M^6;C$f}E1LKf$Z!O2}AA*{r6JAD*N?}ByixfD(Ry^95Ej06`v8d7QSdZ40(kS*# z=SW)F_)sLUpH@ zjj9FEC@at)_>-S;xK^u7VjT(*CWEj`bhdS3{#2wIX$jGms3$S~;-W2^rF)296Ru+z zkEyUwnB9@4=CtpZz)VzmSihU1Jshe(Un7t zaGqq9`QlS@Qd28Zkml4{V@<6Ws83s(pDIn>FzE5G*JssUv09^QD;dDtRGz8XoBWE@ z*344eV3i*mpCLgiQhlNXjpuY(LoZ>4)=TIg`0j?!P=@15{K(-iQY>(#`HGaGt`Gbz zR0*@W!*_agw3zl%?|q}gW!5qm;R<0(5yOuUcUI;*+0kJyHE>et!^Ftfc?iVo^ZM)59_sdNS<^>|Vqz@kMzALqmTM$0M&k(fifa1buGaff zf}@?xrGmW`4q4e^-JZ?DB5SdlI1|gzH_(=xJ@kpnWiT99KD};Ns~Ac2xhgJa!=pU8 zp|56ScR~*}dJXE7isVbU^YH{9gX-UqM}q2KN^L;(Nak5ZH6ljrQeG!mIQpHOR@8x> zKpB<)U8-q+8-y2GgeTJz{BE|H+EjuoJYA!P z{i;0u9MSQn%A7OM;tV%y)w*8J^7^Kts*HYB*Y|S}Ej^kGi{=VK6S{RH`xR9c@%8$C z>BQ)u_HSieS;lKZH(GM}F@Y!B?#?W|*%;wsUtV^m^d4?SAIn52NmcZ9TV*@Ag>I3I zjs*@ovZlm!^AhZJG8=eWr*sJU?x0Qs(D2#`}v+ZI1U}6a3$e_rLS~UmNfL zA(#9oFy0@5^?Cf`{f#Y>YDKH@o~6RJG=J~jHpct)96XY%)EsZQZ!+Ex`bACh6SnI~ z5v0DA(so5%Kh8aDRy&?7br>k#?+RWnehpz||LQd{_2EV2Y&NM`15nhqaKx1`fB8Pr z3qx__PYba1q0XF;9E>wZt>lLhKbH=V>xH-J(fhjZJp>V>Ju7L zy0Lu?&C74!jV;nqXO<0M4;|{h>2(%9?UARXuJf(KBcD*i;+nRLfVW201BR4WT4U}a z-gVzrd)X4>zFJsDHSqF|blm>1@bPwa?D42POFEW3I4x#OM0C(F<_T}MwS!r4Q!D;u z5nJb*_i-@k36D4qoc*Kp!IZ`OQFFI!5a=8!n4Hods=y~!e zjh-nFUo;n4J2W!q9F*y7W_L4j)%b2zS9f0_F;2%A0Gvq6i>?{2Gj|3)XukO}IZ3fs zR{0D0ZMn8>64$mLv)NK}S08$X;}L9N!yd~$|{M>#ler~sy1g>Vu^dh=rywW9c0rY%I>S57!RMK#B{7e&O3z)i!%SpJ)ZGIDGeZTO!*!iXP*^%X>!WSafC+1A(l0s zbRSXs9e6ybIPXWJ%y+K)O>Cguzvqd;7#=`^2}$*hX*17$l`ESx?3^?Ubrs^TF7gaK zCggz}#@t`?=B&-g8Xnom2lwmuPP^l@U%cFP9Vp%VK4tWQM!n!ebA{KjLfM8{a>K0N zubh9^AGoq5Ruh^v9>+#c&vke|Mv!)+N&;VnBsFfwMsLqeUgO1v3tdom#r*CMeZ-~o z3XkzJYBz^mORu{5iBTKgx_6|9jSa?ADh>=bp6D;+!43@X>N@pFZ*WA_bPjqz4HPz zy7zr9(^)vue`=i~r@8m^hADX;7>oHoV=N;UuKLQ1>$u@C9&-+KEqy1uZt0RxC$QF2 zJ_~1fYB(t|mjtVl6JKQ}KE?IwoOhp@xWZf5RaMSbvr2|JV&43(jEbu%m+RFFPhbC? z^b5})Y{qbhcU%bna%i9-+?-B%r`DL+^qgKZC2zU0nE$&CghqJND>KHL*_`CfX9tT6 z{YHAnXLOZUPvQ?Z54y|D{XRXz^=7=GLLJA}BD0?0S4;QXx1D^un#FSl4#F&VPF-%5 zv1t0nDaCo4xV+(}W^qP=s-&?{Fi}xZl!Z)F_%PW${?lir-OFA=TQuvz5l5GzWlG*2 zu&_I<;c#gz?sEf|JlAK5Br#h!Y~?okm?b*?PChOwnn=SIWpN|O@fTH8VIAD+yv^Kx za_2&~rYR}9df}9?!i||llpEwe=2hLry@A6BZ{S&1;yO0EdLp?&3VOi@$Sp{8m+||$ z?r@Ixi5W5m-K)B$%tZ8+u2aL(mC&GEo>VC{Q;MWb%uYkwm~8^7$-VEWo}!|2;xb1i zom$$m+gJyp>irer@ea3dtJNHNHBQ|TdQY#P;>@eJaup>V>8^doB4q{Py1SW#s~+52 z{<;nMdreo0GR(2clfT!f_(bLu(k#^-PzG;1J?~^&&+GhZ=j55`=OTqEM=3EUl_qoE zIs9SLpRz_a8}G^GaK7x^@c{lVOo73Q1dMbHF$2Grz##-G(^j#Z?q={_2_7oJ@+X$F zm(3?A_DS#=5-fjWIa|!&a)RHKGjA;CT{Gl99RdmP$5h~Whu+)Bl&t1si{BqORP88# zJTuLI8P4a*AIVDd4KTfUV2kK-cM#hep^M&K#!jmfc|?0B0$-6psgKyiemD-MyP6FD z+TvYkV{@>{gS{ClM%`W*Bp3aV=)%rW+)C^SBX?vOBU+xod9UCUwp#Sh*3zLKt=11V zb}nJ-{Y{bW>t9rLXJ+l#EINc7G+jwU1}%UZCF>Ks%(-_w)|?lO&GP%$O(5B1EMfxL zgAhyikJv^+Un7so8kbSL+a0{Z&2fcd!7liX1+n&v)k+l>vcgF98`*=(zCnGle9E92 zD2D?041`8R1QA5TRU%g8P{;d7#0fyv1P2HaBf6#^X9pN{l#2b$JkdR_E&f32u`~5J zpL#@^w|D_`akN7vI)rvg06C>l$Fts%zE)fv%Q+)Ms??YlRh{snPO4n9=bPl^WLjU} zRbROWfJ%!*Nwi3UgJ2Xjl+ZNU9t)KhVG>7>s;Rc{j z4^Qyc9nD-A*F|O5! zR^5LrgKmTxaH1a4am#Dc6+cjYq;*$3Xj&dKOt-XRBW-W&+I|rc@TWJQn?Uirg+iLM zO%(p`)D~~iQ^Eqe@)qf@OfAxtWr|q9vj$>rTcx^kJwY`V3-?;apt4wYlJ2i`sS)I; z2OTp{V(=Fnb<#I0DBeG~m*#zioFLV-_;(rn zRxgHW8u?mr$D$yww5Epdz7+TkKN7b4@F zmX?bL5{KfbpS-GK)!E_Z90ZV-oJ+%?9T8S{aZGRorHH^nl81BQ5mkK#U^i%oH}bfhS-98t#V=H(Z#D+pIRDpwivTx@!okkkMcE57QQ zA!+`NHDQ1%cjiglEh2jE8x52(a}1&&HIXSynZh|N!v3Ccf~77Hc1IrdlVOBI{-$>v7`9vW?13 zbOb2NwvhEYab$grO1bm{Ssx1-Hwhq}h5WA#yEL?csijq&T{VkayXMxGmkzm64&?q1Q8J)9a0X`)O0ynkd-U`O62 zhEurtR3+rv{rfM*St6q6#`TZtwy1W+ngR`K;Sqh@V9^kn&*~Y5P0w{7&R}!~2=WF; z4{--?RYS?V9MeOo41rNSl)j-di}SvA;^HOfe|~<6Gxn}eF7n<4Pg?A{TqeP2^mfHZ zRRb+{9rI!}H#;l&E~~g(@?wzu4Hz-Nj_l6YHapR^j3F(hM)MRQ0a0_5#@RY-A&WIW zri~-c*!4pce#}Cm&$2x@2~(Nun`E@FKTnhBzg?DT%lxJ!>1UGeA4lW`dEWXC-e-&Q zA|=@DiIvPR3}uWc!G{@ZptwIh!aSw2LF>U8tEDg>M>|0@%4#J=m-*{Ch1+&+$&)Yd z@%2qRgJbezh44~rPC-YMbC>U;$}*i@)aTCF`>&`?)L*Czb1OT7MdQfdtjXGpB72^v zRON{?1RQ=8*QhO=e^%rP31$l<31n-h6ZmhFEg91m^+!L5Z^_g;#+Hn28g58f$DUbk zZplQ%f@P~df&7%DE!K36U*+rT{fa}K`I08k6Oi%Hg+zs75i7*cuCWz_}P zUez5WXa_;jGGhOS#5SwWiv1p+tPQOk43ajqs`g~bm)fHiJKh*pwa11)y85m-cG-DQ zeM_V^$>SWIhuLg6TAZD2(tBp2I?`H4@{qoo)^^5j>=&JSjP%siBsR(mCp z7g}glfgt zTfCM|Dt#AG87%vV!g(y`HSUIuMcxLCsI3hw-`kkE8huD#MrM8VBAF%Zd-HTnWb)oT z@=Ag_l$lx^7j3&gwW7CeT0OyYPlGrNoI)~Jd=}MAGuaGSf|y+TA>)+Gd~z0{!wEf( zl8h3frNgmB1P$DWQ*pa?fd1y(c*IYOaAjai^bL6NyfjDh?)v zIZN4#V})`Anp8j`UBsP;H?!j?P3Gdmh;EA^a0u4ACR|rzX)Lh=e}AB)6b~93f8m< zWcvrJQ_CZqT1Cv}1 zzjORWfJdE(I>X=*c2Zyqq8<@pZHvqX+Bg{MPZvp^HMr)ZKoJk0gh2D4)LhZTK}ik_ zVPo+GIVd6ReSgl6CZ{?m?NeV;ACyqCvkpoV!C9hboO2K zCC+8B*w|3UXm$SR1tt@RGgil@ZM&R1*5iVjbI0uU=D8z@FwOL7O@C}FlB8T61P(BS z&0ERR2b@c8K56k<=AGsjsE5D?u8%On^J3$hk#RKQ!+H*A?Y$E}FVoZkSMk z>RmkjD{fQ1G8S(hk6zNvTvyz;f7m>ghzgUaI z+zh7|o7W?}_AKUtq$rQ;I3yCfe+OcmT$#B`0-oVqGS$Mk!OE2{1BHXW6Dqit7BJhPUN4X|C>?51z1-UTQhp1 z;)iB&y=j4sPemniIo1_TR`uQY`5R~6fE<6O(o%jDGzgrI9zAx{=#0_^|9Lo!@#b?8`JPLR zvKYmyJdV}wzyT{|X>GKBGJhTUZ19_zM*maEwvA|XsuH2(Xg$A(=4$;TxyQsPqVjO6 zd@6P8h))ExDrfG~0PP&hX zw-fe4yn#*L{QX9ya4~S1*#+(HnX~1(9K$}aa`TY7=E{URX%^&|Ys#w^wSLjd7Daq- z=oVP@i!w5tqcTR%?0a=+Ku>pUg%>%3yauwDIxk4`Kdss`ESB7jqFU;2jh7QEx?LD+ z3p6IEnD;OvD?xpuQ}Lh$&yeK$)$~I==h&~3>F;gPkF14BKbP1h{by9$A{~3z@ znF;zIg#MBJk+j1IqBjqhNsS5mu?)9ds>P&#gEz3j>-ZQK7E+Kn6^ecw^0wwr@hHfs?72k-xu;H4BfDELoV*BCb2G#vlx?&&EsO{r$887Vj z7%wmy7d_f1T_E+=LEgl03YKLMH)r}j1wWP}_G)?U(HE!)bo%_={uXckmtJGs*A&z; zX=WMk@X8i467`{<6WAoP0tzW+*NRS-6G_GAhlSkvB8)VWKc0~ep@o0-Lfy!8fz%r| z6<&ZzR|`G+gq}v<43A^G=yTQ}UyKAxw@#7@Q^R-=@pI?9iN(4`W*%?g7IWqa+%nl+ zmrfT?^9H76x&v2cdjk(MlNIJNDV;?y;kOKT2Ob{9tW+RP)0*{w=_8nH-P5W~b2+A- z&X1SKoY{Td%Q9z5DPuX0tDu}&1SzGF#lnpX<&AuU2hzHEQ?cPvE9$SB8BQUL)^ThLIG3ADZk*a3BSkBGDGzrYi zrZTeQmrC~aV3aF>$A$M{h3;JeQ}}KwnO;oz zAur}~-oobR&gawpCy!_p#Ls8=a@pXF#L@N2^yf4ECnE-oRE+}7?>U?XK)?gB8DxCDp&hD zm5=Vc?6Dif@xwEi{@9J>n#u8H!XEFc43e~zMr64NOj3X zUUq=Ggnxyyqe}STs5VMBmzZsqE?OG*x7aiOcDuL=Uc;fL_;6A`S@)()n(9*iFwc#y zV8>>WA5z_=SX!=`dF|I+0`uBJ52}3wv*#hJ2YvI`EaibXj+V}>y5FNmqy5p*XvZbc zo|=sIkD!G{jqLn5vQ~Y0{$(Q0ZBa6_b&|tx=wdOtl`Brw{kxtvJ&~k9lH~7p8ROP4 z6EFOeq(FS?q1Pq2h2UC(f2o3LqB{sqtQayMGk$aB;1DWi8KRnk9T%A*=Tc3@7pR=z z(0{m)go*e{ooqjeT1do@?6`G+s#~ggOtzV*DVFnlNtEtye+lG`_rl>9f0dd?N+=bs#&p| z7kH{fb9R;sjm)0dh9s#}Gcx#K; z{3Z2%2KD{`I&1MBV}6XcSI7Ut$fLAfEN2tCj#~fG{2t4>7LscEDKP!X>_@c0 zq$UL3n;rCm*&Aay8GkWTdO}xsb|Z*|&3bnp)!pLBtC`tHbmPWg`8s3frAi3op^j1} z@i5)N_eo%R#kS74xb%0%lBOHtIMl*+{TWoUnIh~o!ce0ZiIj@1hs78O7J-cWyVqPL z49)vb9p#bdF4Wx$kW1*(8SdCN*6Gf|`9x%6%GS1oIo2aVFa;)>66p9$WD2yH$NH5p zAlU7O{R@#NK&~WNupsg-=Ud@n;L%D^!oK|e?iX8>yriDH8WZ~~*fxDG5f;xj-mbqS zU0zR+rrHcQJN}oBqG?UE7ss1ImJ*Hjc}ZLg$W?=T$$k!G{2uoV z;y8eGL}wKpUpKx7*~_!`IV7M4-@rH}_T6EIr6Fxw6}=X}zHV5{$0PpAwTrX!PQ_JGSmrjfVlgkpat{AEXV zs@&)12qm7;!=H5YI97N=6Ok3)^(i9QJmj!eDJavvavJwvTO)s`HPKTxl^FN@gXbY4 z?JqHAen4lPxejJ}bPED4AJVoTN!&Xc?s z{0Wy78TZu5+eY4YZKR9MT-RCtHgqC1x`NQn5@~&{q%6(m_1^bDdxSXm9OTcvdkDI} zkw3c{1kZ=^rtmZ>JYX|sHg+Orv{CS`Rd_Kbvw1BsH?NY^@0+Q4+tOC*_f=|o{>%^5 z8x^pb(YKzE^$1aIJ^JQa&Kf@79jQc<4xl!^~)g*t`OI;zIHFJZ!U`b~)qkBC@ zbT;qiNu%s2XXk&|n1>q-CWZC?WcY3nxu6Xtu)DFCj|Ym^5d1+sM4ivRGVbrqzwf~C zzaO-_q>-R!7eZh&-&Yx`tR*wrO)9~NLY*`fg*VnCgEV84;NK+pKlaj>D^}!s@;Cec z5V=l-#9y^UPaV!VTgA4s7@!Ge)ClKqpJSm5c#(QC z@6G>r&%dT%S4#5VkvRp<^?u=dz}1Zy*c~{aCc!^3fIXpctWHh)-FXNIdqO$8eggaY zH7zF`?O8IPv5m?&;<-k}EE(~O2K1=hJnLq~wHCu{oqavo^G83{@J~ke#)uo%Of!79@wbC7kH47M@1p2^ zz#)EqD)!S1%VrvS}bHol>Nhy_4z|S3#N-*a}G7}?!(yG7d-vfJIjwe_gION zMEB^}a-peXw@B>M=N$T{j{U>OZjC6T0p;79NW8$87b)kPv%Gc&;PBGRqrRfhBLkh~ zv2LZA<)0iWKlG*l4!+dPzLgBpp?2m3MXB+0HA66ZW%&xD{7`z?3_wzzbmt-%9UMpQ%}W` z6}f5Ak%@O-y}usr%KzZO%h)tBASSi2Y2nGXE7)--`%2l{aaYWKM)tCi=3Ckl zh=|^Zk(KY8Nq`tk&HLD!^|6wY|4O9fvtUwY zgZaU?u_KVb*4In=d%>vDeSO_v;S=KDBX>*cA|d|5u|nQ;@l<=MF*`A7Y|5q`4JLdz zo`gx>yl@39G=k6tnk%>VT&oMWdEbXHoY`l39Sy#0Z>TU%)@h+OlCIYQ&yb4({J2^B!a#_J5%Y9ED0uJjG4Ga8~-wFHQC(mpdDNN9PE2 z|1Uz+70`xQ&I*F46}8`1=ez5E#Q6@piEP!M`+dAaB))s(`%Lxy@wUF-CExSa_wTm# z{d@9#tonXMTi@@H@8i|?fo*+P_|5b&lXhuThL{5-Bv;TfF_xhB2Elig!uMVxzBup6 z98ptoVBq7usmj3>2m1O);^)3EbMH@TR#Y6w^_@|1V7NaQyOl`9N*IT>x-s)WgwpVs z1?pLoS+9aQQAQC4frH{0lHSlvH$$4Ysq2VUb7F@VI?~?c^o9yt;cog`ch2mw1`2;!SWA1&bDDV5Jg# zaMQ=HDGZK$D!d(=AvO86_=~FX_N*@qX3RxE|INR13gWCYvaEYy&^I?D{AG?@>vefm zuEh%nd*;H2!4eLpQ}+1Ii+S(veAXvL4B@MqW$6X=8U)6-`1`UX;+G-`h?m3 z$JMTb$%S_9at!TyMxtGhJW0D!zW=^GOTASb$)d$P3p2tI z)neXwi!F@z)YZO`s>L|AL(K#!lKLg}S82cOX$}#Jw`5EPiutX6B7O^(-?Tx1sWH`tmZOz-Hq5d)4fj~i)dO3UF`8PD*~SnJ5-gZcddhf;X_MlDnu$3-At; z$Q2KV#yrtidY+5Ezsu<$f6q+A8~B>^4UroNfIlJc*!GH#H!o(L@^=_>FX6N7sq%Is zAA<$@14h|M(i@eh@IhTJoBWFM(ZjnKl^bNdn>Wl~Dpyu6DO!oI6WSnGh@*2s1G39f1R?9p1dv-mK*lf*Aw7Bbsm_<;7TaR@gmg zlNaYN`J1?Kt5}ik#`;}-^kQ>A3u*F;mq+OHT?%c)68*~uS|s|D3HmUUm;a&E0;)yo z{6+jOR$2B$hkHZkT#Q+Gw_~q5SN((Y2C{EmjCt#L!(lQzIx&P5jSevLS9hx)RXYg9 z51d$!$Uo@247XA=RdxBOG~d9bFa)LAm!O%DzJ_hQ*@i*_SBPlV9Wv&10y(k)oz(-Q z%=TMB+xX@T>s0-3&d%p$kcf2k<(}YuneJdQ{dIQ3o2N^jbh8*fJWZ9nNem~YGu(6D zD9(qj&>JrG_`5){oPRQ@c!GbIFeS>{pXi7@m%D<>v%M>*U7_DCse-0Q^Z=R}^SIc; zQ){J2SRm>5EUp21xB|**yNCe?=;l~MQ$D4PMLjBs{naeY#g9WQskkOOBOty*jYT&& zDz;rweqhUk7X;oj7EMSGZ|j7^<*c;@<*}C1^JUw?K&c^Khl-}o;ig_(R*@hJmxR#) ztW_NRyfxvbPFWOJ0&eIa(ZfyMvgC3uxqrwU?)`mWjbbAL0Jvr69sfoeWrVXhoymuik2{x|qD`*ru6BXel9((`aER_#23kQZl=0^DQP z6_46C^Cm&VG{sFjADFB@kBBm1$$X$z<-^Ow%(KNn@R({YrzKT9$)^#gBvHTkcyYc? z7|v0DKc-xAAK-kQVx%ei`K87fW#H>|>A>!ak0{Mf=@N94S#$z--n-J3-42A3Yh9O_ zcKYY_qYG0jXr?^t>+8AfE`;oaogj5oGdnZ#2j1xxUI!I|xJlkNvwBdwnS|zyG4DCP zyDDbSr!Nk5{uVXztC%R0+mEg%J&+P+46iCK=k^`>(z}>qrItC%<`l4}U_ALfhjAb@ZBP#pO#N63dxDI&%!$#NOMYdiDZf(7=G-Q~^79pHe_@)2&@-Ia z;ZXLH&HDJu3%cU02zq@NZT3-00_PG0a7=Z~{iQU$wov5?Ugip7dm?mEAz3fwC}mm{ zxUHtDxW2Y{6)qpRQ43x4cHKSF*z12FePPTq!hQ+eR%1@u>=9xg5a&Q;nZ#)!jxuW@ z(sF^_k>7$7et#~m5MNJZx0=XW1s!cbogHY-F|%@;Sq-zY@`U`a>+HZPIR-oaL$0NR zX~EgA$0lZ06@O0Z)6LXplbZhhxlTfSBvh)2aGgozFf&56rj!UMSl~;$cvV90t8-?3 zWGo|JMzE-U8S_?9n1techexeKL@;!u3dv>1*$7Yr6&rjIRh7)rG}nO!x1}$PM<9v*+z0DgH>r#8ozG;uM`$xu{Z# ztnL^C60=aq(TPVE)8zLoQ4fsk?vGB&EP6|Vh@KKIlbpipzr3~>%-J27jceG9SFgUJaveD@cpjf4OlU6G%DrNT=;px9!TSbx|cpCy)Ngq72I$2c8MP$aVG_1slk+) zX4x2!?+J}}6jyG3Xggxe1G-im%J5xRaj1iDh&b<1ikK5Z17Hz1;P7LUv;49eBh)NS zg1?_=H7;@GlbcV*qEm3o(8MR-7|k2Ls{GJ%k9{|?gutU>Dz7eC*DM z+y#_>(o}wEf$yxy9069$C_gm3)EzA=4$Xume56}x7biSnr!a-@EI(8;`*!GuCybQP zt@-Ji#@R0D>k#Qq1v%jk6Fa@^B8fe`jo8Z`?@uU9VuhoFg@g51>=q-m>+s|u%*mGI zhD>$goGF%O1GAW3T-lyLf!IFAvIfMaDUOt$U(Eeg#m>8nf~A%+5PB&mu`4nb7n+XK zyC|TB4m00U5W?LhVQf9>iQ(Ig>0Gm)WunFuYL$qo1ZO{MIlHKw#sbT= z($MU4)osbSRXmv$xMQ5XBA5p4YqWBY(_P);457E8pYg}Q?uxA_2XUz-Rusm|6?r`u z;n*-}Z9QT0TZFztXlttp?_@9 zZYFfIgvy`I+@#69`uew%tR{>XWgtP;<;0Q2m4U{KGLRq>WuOzJEUpYRUX+0ZnJ5FD zAhNhJ(D*(Uvc4ydOeq76?`I(rWuOzHiUtVNBFR=0vgfyTIT*QDSxOMrd$utz$io%v z?+L<1G`oLN*AKycr6WEIN6+*v z$gV<)G0(|_8ZA>E8RmQPnq_5&+da0$8TdG`(bV2@;%gBuD@*WeQ{$T{*{a8yn5|64 zS)jNa>D?+x9lgxuSmVh*QWW&BfACCFb*wb+F!0vUE11O=^NYxxRGw`41D{DO;bVY~ z39;&ELgGqf2{J||$iSw?KG6+3vKAq7r1^rE;-Qp2_J*8BLf>_$`>B%H+rE=He!r^Au^m)ZDM?W+@<|n>4CVf9wF<;O* zBPX$W;Qy6y0@tZ-ND$rdZ!Gch#rI~koIH`V4GEd3BPhAY;`u1n;f$~u?>AxsBk!$} z*D#1o1*z#i(VwuFakkP|>z!1n*a{GT7R?Zk4kee}R*$qVj&YjV3*DV`3_+HmtQ!Y# z!5Vpz)sXh_&NbUd+(yK5?hn{@*K$8&$dO!l#jC!rdca%^q{NzBLD*2&P}^*}YGXrl z7Q{{14o6BWH{canQ4tJnVRPETalC=tVzTULp~_&#{cvZAfdC|Cl9Zv{lJkYP>BW$J zpP%pzW+QGbK*uU__7d4^8iiq8%A5Pc2pczRf4F^)v{eTCLogv7sI&=dV_RLphlt|j zJXMejvyPvv=NuKXS<=Rc(a_RK#^U;LBxCBT@j&57@2P8*Im0?-_A>jQf@&in20emIGzH;=}4}6}?oQF9Km&s!Qp)Du?u`s}!P0 z&*^KY1WfdBL)Xs~Tzzgty8MXhE+z9;2|KhzB)4k{D);+MWxS3rNW?`&E=N^S&Oxp? zoUh6e#+`@kamFxMwuh`!U4kF#MoOD1JenUW<>y>wEH(nGOZFjR8+UC%SD^MUEoBk*XLyi>jzoRe|YCsS0HU zJ$m6Xp|b>ixzb_bFVm;)RXD!vIsM2K!OIQRmULSR$-+lStbyev0=iIH1uib-# zTc39kE=2#LIfGlWE`?RscaN#_ZjGgXp>!|0l*P}kW^KoE{vpbF_PS2)Z}I$2IsW{9 z@!(PU-P=xnxr(n~4l5C3HE$J~;dq-$9x^O*j?|0jt`}k0Kh9U==Q7%Yozz$iVnyw0 zhBrKj03WT>c7mU-Y&dHdOyr}ioPFizC?$7h9HlsfZmcS9sx98i>Ty*rP4~bOb+UeV zwmMl~1~-RI?M8KOWz(w8xm`Wx5xrUvNxv~aa9(ZVyt*}UUe$I=Hrnl!+;XpVnoG9s z;gmp@9idAbzEFnx6Z1j5eSUe;arcLV%m)@PL-&Vw5rl5DKah`{NIP~z?3e>R|C{rY zu3+h(s&0eE(k@U;i@kDxSuF70oC9ijPBFEKoq<&*zqttKyQXI`^oNx_VFVqE^VStl zT_*$0iAiDS^i62JZbr*x^EfqSAyT@$q>wr5CK;$jIp|z3M}hc&sX%<7>;-(VJa{e} zq`Ed0h~H!GQ{z4GXwFWOqBvZ~ReS~;FQejf%uE-}l1b_dHAzVs5|h-IM@>?{7p{kB zZ&_DL^g1qS;ta5@M~&A*Img{Tw=hZB+UHy|+tzcV9uIjb?c z54n%+pQ<-pn5`kcpl&qt?l;MhcV@Ws!;;9 zGEwFr&}}sbC6OE4s_0*J-_-RZ>qngD*vsTOI#q9v4IT2sthC@sCTDQ?Y13kXwXM&q zEVWFqOs?sAat*9TY`!^qo=(-jkEGJ_HmTw(ZlaovAAR7c*1cM!;?3DuHYlNs?jp`o zjHqFufBMgoW;5G-2LDibc(@{7x=YQ{-NiwDy>po`Q%#O)$FOiz*$k-b()CuiHZ}3& zy7WNwakCE2IaRuAV*hp&fAkYOKec~vQpC>>spDJx)K5)*>Vq@lwV?F@-Apn1w&znQ zPw<)0^sl)6idPSG`+mQ~h>`q-ho@A2;MZSa=gq(NW;?w3SWdZ_U2Dd;mBmrz zd#!(~`H}L~G+RS1zMr9hpC<}<8B>~Vdh8J|prT*N$SVJ1++QPyyv1d>5Rm+eyBIVK zoyO16hG{)MK6|6h@xdufjSlp6VB{awSd@uL|x0h*8aNzBd#dxR%YoV9 zW}|WiX>s^|7AI$!P~-ChY+ldMw9qwk$`Agg^z@1Yr~6K=IB+XMD6y5E{3d@>M6Ml^ z;*aMlaA;a_SVXVw~LR&8{s`7K>t!(zWN+Q$s&psrz^fi-6N0=F&kI6mQ6J)h3O zJnBeme)gAg3+w&0v1rn-0`+G#jCL56dsLH8Dt86cxf#FgoXu;DC&d}P3zq>;zQl_= zf1mF%VF2~!h~0pQ@Tg@f*3&Idtmo*k-OQe31WJ|n01@`H0qy9NF8zek}h<%Qz&%(A@$*hcXr~P=d==B4h4OSZk_tTIr0r zn}peBrhQeCx+*?Qi@Zf3)=Rk!7M_4R|2^1L)o^ZI&+G#JZHl^Vl?XUx}` z8`;sz9_uDrrf}v*cU$&&KhAglQn~ZQ2p`;mpR=@!jLIr>x;=R?&AIf#CDv;5t`@t6 z-IKb0AdCiYYyQJ4j%d`?!Ao;*jg(M(pg-~e<4RrC9)wi%$;hJhcvhml7%jx86_dbA zM}3cvM`h0%Er%nn;A!H`ONdoG@yN>%A>Xl8Q94<D8aeNg`cuD5Vjm&Ef4SLq;B75W|!mlYSQ5B1cj*c^ZUj^#I zySk0RUrkzBPC@y5P52!=Ts7&NDzC{-hz`WH-W7Z(4>$Mf)gUk^o@Om!R6j(i52EUI7hY_^~FCNm6d9E z)@hTwbLaFpcW1KdB}a32TFv*GzSm^?l$alniN5@!>Fbt)KHZM+k4*l-^sM90Z&k@r z_3f@;V4rLyHem5VT-#IDrGxy6^-_0u9kA4~(df5+J4M|Op-mQDsy|KrS zuSf0g*WbD8sKP&oe79A2JN}(Lj~D+vN8`UDHU1YnA20rHN8{fDFCzv0p5w;<;*_K6 z=kWx7bgNoTkaoCwSnKbi)r8U4&_!oY6aQpyJeDQXPvRH5=njy_hECzH$QQ+i3VgRj zh%_-t$A;b_Fq36kq(Q;g3M?yEgo6OzuM}9gc9CiY7YZy3QDlLFFBMpJY?1j2zCd7M z5=F`tJWSxu0?$zJ=>oGNrl}k8*wFq03)PW{>U%GNg{=@NP;eK4y9zv9!RZ2b6F67F z2NC#fB~ySWb$O1qxm&Fg`UYzk(MEjJg8lSMZ+&7Pmx^84CWbz%uqClNJ06fln5A zqJn=cFk0Z0U%^iaEQ$(|;R>EB@Bo2x75uQkrwW{{;8KB46F5!5(*zzUa0{CT+F#&Y zftwV3i@<{fZcy;G0-r8$je@Tfc(B0L3N93Qh`dR!CeFvf%C|41*Z#qj=;GJKFHO?-RBCNt>8TZ zpC@pdf_Dfkyn#rI=qwK1Ch%~9n-siB;1L2hD7aBz>`zdB1+NxZ^ll>63SKVoNP!n9 zc&We_2`v7+V?!4Te6hgg3jVXemk2yV!M_!Fl)#e}{0o8e1)iwj9}9e`zy%6^O5n=` z9Uas>|)c)Y+f6nwhCE`cX2xWB+|fhQ`s zm%vvFT%h1C0$(NYa0RCe>=8Iu!3PoizuPNtwu1KvJVD?z1@92}YJpo0s`eLnqQFfG z-X!of0yikQQQ&I@u2Jx6fv*#|TEWW&zFy!33SKJkB!TBEc%i^I2wbk-zspff*%(6Hi5GhTq^MG0;ef> zn!w)`xCO`5jDLYA3*4mOTLk`|zzqt%R^U4Xu2Jxn0^cccwSo%;o+9u91z#%gT>{Tn z@C5>w2wbk5 z)e2rNuutFx3SKI(U*P!)UMTQ`0+%cJ&jObTJVU|16?m4wlNJ06fgcihqJn=c@WTQZ zDEKLX9}#%Cg69hSsKB`jepuky0%t3@RN%)1PE+tSfgcyRWuIz)fy)JMQt&MT&k?vm z!Pg2rSKt~2Uny{fz|{&a6u4601q!}Y;CTYiSMUV_KOu0rf`jAN)0NNZ@P*?-BTEfzuScL*O3@+_G1- zzrgbaZc^|jfqx`$gMu3c{;|L{3SKSne+XQy;N=4UMBoJqUMlc20?$|QLVcs?8-RJLpF_Xco|!f{6__ghDOQ3TiO?%4 zaX;%l75?_VYrJQHCo2iB4u6>Zl4;W6&l1=rDSmPs3GR{fO@pZ5r zUswIXdTM%(6~8Tcnl9%mTRGdS&uj}(s(jl^Kfp?VR;RSI?ny*-NP3r7d->ZdZ*tp8 zdL3Wh<=4@C#Q$c*-^>@o2HW%3^rb4dJ%1fvqy4t=9dCK;^mNmNSx;Rb$67ueU!(c9 z@g=dblQeRkI{eRs^MCxO!#}r$C&!V<_Ib?S z&)b^^lj~UU>G<+4KYKsW`KM}kJ3bRj;;$~3gN%}KYrHyUd$7HndVHm#tG7mMJ#~B? zoJ@;^>HLospT?t~x}3iP(J&pzQ-_Q4SzGZfs}s-NUOE(vvfjl^F6_V%>Hx?dh^emcI+&t4vT z{`U1etY}b*C+k`So7EMb^iZueE(|u+S{W&eC>_L<841XK70Fp+vCYjUwh?E z6<@cn{kv}eRQ)AY{C^idd;inp;aKU@@il$_ZhZf0d+2qm9Dt4^4?ayucZhNrwCt8`04!9KaF3)g?X-jI{Zxn+RAqc;T|2Cr+xg; z4C|KEl0c*mQazJGQ6wukTkZ|jHduN5p*$^G?s`(>(n zJJEh*$M>)H%l7acZ@;wT`&awr@#53tKGi&7$EV}#_DJNqQYEC4;uki}w(oeAdv-8>P{a3fovEtY9P3&nR0@&(j?=O8?eQiB=$R|Bs?Ra!Dd--&H{ax4d zy9Bh=UX6q&w~J0^FNY4-_*M~++-~i)ll{BB9yHyl%4u&G9beOB|E}pjR(v|X#%E7w zr`MjJ?pOA78egjT`nz5~=1?&GF5mR~4TLARwY~hwV@}c??>u5JpS?cp_;miM%4^4` z;|p!_`?m4f>sQYc$4Z}$Z&G(OKU#nPw(#ltJyv`=zNSy_zwA%@_gpJL$J5{SIKGL1 zBq6Q$G4r2&fosDw}W2yhgcC))q{PW)N8J;hg9k8 z{dcgHk4|T&Ps7P`frRB)AN2fZuXj6rdYtK}LnF35Q>D}Q%c;_(DzCkMPjp_ah@t& zuGK!N@@u;_TkoAE&auwF_VN0^r9Hpxda}3I|Fn4})qMDW$9e0XkgA^kzuLZb{?6%E zapzi3y|2-=VBi1f@MC@2_mi66XV1ru??lt-`B&r9=O3M4s`j+YHx^n5biHVN_NTpm z?EAx1`Ps)=t}VY*>FoXPd|NtQPEDtsJ{^9n&l7D2yZnGY7i;=bmCs%;_WfWgy6xrs zw%XxX&rNo^PjtWizkNN`?V{UpkoBVbg$}nrd)WeX{o2#%{fU0slBL~d1(cCcpZz7s zJ}=t$QyQOs+VQrR-cF|-e|zcmcuAGN9iNV`>Fl6itY@nD$BN&MuRZ#8{1e4*pZDza zA8Y=)8tmzHeWjwWJ^bypZ>oHCxZeM#%3rT*slMN7AsWInc`eiH-#i*X@9`z74&MXe zL#?#Q;kyafc_xR~P!Y*|O^rva-zDQ8XyKf|GkI>*GMHZxu6YC!Rfqr67C%=$@=I0j z_Ui2xGkMzYKp=Iaf9<6!up*|)SJPWTM@n9MbbW}u4n3C(DjmLn@LUVGJaiqW$|ui? zdn?c6IZ)#(q2ng=b=xbKPItB~oesar7M@%-A;nIoeO$ITj`~{V(GMM8!s=$!@ilDk_d5S$#i#M;ryai?rn|KI9dCK;^sZ9yc#T znBGfEh3oKYTe$8YBWU>K^BHMqv^NjujA|Q`l-vIVg0n%r~Tg8{$2OKRP@;EPsi8!+54;g zd~e6A)7!%}zV`C7f7kVJtoU?%o!{}ck3D~T`{;fz7BQ3iy}h37?O^Xm?bVasAL?@G z_!_p;smq0_IX{$*ZJGa zqwC{X@#*-f@agg%D?S}xGIgqX?*slj<3V*{l|_c`Aj5fbb5O{jnDqn@pX7|9ZQ&f-(jEkb^2q?&t9MQ z{El~DV(-uP`q%i6l|DN@onF_EeZ1P~wf6@*zHgg8J3d{%$68(;Uzg9`pY-?R#pl!r z+j-jOCw-pN^=QXqhf|?HUcB~xuE(8z>Uyx}XK!Eod}@!c;cqLQy}dMk`?Js%pyy8= zJXXJ0&&zD^iPlf5bea#4s$Ns2%eClAl}^t`Hu8_MCvb)pVXpPG_bYq(?e&u?AA7$W zdYt*#+v!;IwU1BDYtZFOMXx>GsCMYJ_gi~AS;>!j*wfkP)uR$v0sn8Ov(NX(N~e8Y zIM#G}zDX5dhuiDLzR%I|>`#0DI^KD}j!(n(es7=0Q}sW4KhWuPzt#Bd&-U`O$JelZ zzSL)bz22mv)6PHB_1GSr_Wq;q|JuvXeqPJ93ZV1T>2%LpZ0yAwjI-6z1aKN*~gfly}x{0 z{d%nKAlB19&;6g?U!7=v_WH3ED-PPrcdY3O;~31B!;(Nnj-#bws2i3Gp40WbldAo6J6ub?$>poE=x8t9i^S71-jYP)Tg3ZN39x=T z{AJ*_!bek{JRO;*-p2?YKE;1J{7M3o!|mrT`#w|0O;sNI`9R0l8QaH+eSe_ipD2EN zI{Ub_^IwzON@&#M&W=aZZ!e#YufHE}d6LJh;LzpQ`0RAp%VW>4y?Mr-pN_BdJKpxT z->=x|x6`M;+smc%Zx7$`wwE2>zuI2*_Sfan^xMm;>o-+-?f7(jjZdG?&LF_419|H3 zA-pHgQ}%r9<+a21@o3*a*~_Ej+w(~xt<|fJuLJGtVqg8idg}T-R{T1?Mx*z68rI)W z6kqb3EI9vFeD-t3zl!e^T~ODaFZOiydC3+%4%*Y%=i7Kh+lzgk z)1U40%@FIuTpc0B)4pzLKIs3$-c^9xRb1UbAh^pVT;v4}9;{IG5!{NjI23oc;t+zn zYmnd;yto(lQmj}h(gJOvRQ?+F@BQ9cFEi_%xwEds;LgWm&f0tJJu`dsoO|vK*N@G) zo#X2BOl}u2#}n&gE-rjdzDqh?_?eX3{a(Nte6azZ94sbkw z=;Iyh0O!0;<9%w(??(4Mw&QZR9>8pedO)Ab*{;!Z1fP3Tbk{tjmD?Z{=jpSUJW7v*OT{UqW8dN`vZ>f+~*n#&>Rq2j(DZokM@BVn08%4j-2%< zcLjRh1o>c-hp~WsYjYUNQ9tBd4(yPIP%0XVQKkiTXL0+#vUYFnpIp*UAHc-Q}4CMZO z&@%a8l4G5j(&XVBtGB+q?xLQ^>-7gd>^X;?#|vZFwYq*|`*`H_A8|llZ~Vfw6+Xfo z>qjd77-!B4#~Jqve-4IvqAVMxT`5%#-@k$nd(>k~t3+52$p3A`GWq-o{<$PaeYt*& zQJ-8~>-CpgH{cKDbG_J}`B>-J4*t0RAV(g?)@9uP(5L)!{lJHR)Gvj(Js2NqdEmo8 zKlflijJbT&mwE7?;zPe}adEN*BK(XM@>5M7e%1r|DJCBTCzfOUKV@?JuP1SPxjx{g z>d$iUQ9!Hxp&jQ~0byB?e{AvZG8!h1Lm3(8NmpZf`XgtXrF=lt$x%hMaa{l@ukVOtY#G~3D;*n}E%fUzea`)l* zTn~J-kNrZ=Iru!TxnJ21cy!xwz4%;-dU4Knye=^xnA^wWb0rXqoXcs~FAh*Ue%_W^9j_oZcZa~a$5`7ULbl5@HEtOVuoc;Wjc_~rXPy!Ux!L0~_r@jI~K zr^au}4$tsXc4!ak%k74obG6>N`O52wT0Yz5KF>h?*^b)}9_MVw{mOh`w&Q*RkMma9 zH5$)G>)B{r)b)Ym(r9@YmmGJ-TpmByVm>h2@$*FRIA^;?<1)J2*XTS_*J+LmKkwu? z0<&HCjubd$d8_OiZC|7FR<+~);`Wxs#AVDI+wPmcukBLL7x=t*XwiWj4|P1I`k&_= z&ebS~&jrhpqrrq%CY*x2AL0Gw?`yfEI?k!_6u!IaeKAMTA!nyLrjYYKh0mH({nO|; z;Ps8q<*91&I)!c^Pt z%lc7`bLFp9RD632RCw~nlS`U?|=a{MlW@9Ci&e(oba{LD^r@K?8iQRXLAZ+y>YT`M2Hy*ZGt zZr7OmE)V0gs0)gO=eVhI;QOD(51(z~cZl3?cos!_QvL=O<-TU^4bMaPek=cbdx#10 z!n`NjxVYNJ^6=RL>an}Y7b!TNh4Q5WIr?*LlZEx#tl-RPc{si?jz^dr_xetST>ai3 zpKtg%6xyANC)d0ebwUHvmY1N>sUWv47dpO=iiesEDLKYdsy)2!x>fp?+K*_|SJ07b$z} zD=(Shaxk)-$0e`(95>eEb2hl-afoq~su%2#gAdH>BG;GqT*O5!kNd6F{?#Fu9zo6<}m#7cq+;7mQ;sQJ5-~(g*2Zp|0 ze=EU3k@I*!KOjdrWY%k*f{%Hfvcr7H`5Raeh88*Z7q0{C518#xPv}!Q+wpp@+VT37 zvTIdbc-*DR`7j>>P~^)O zd2T*%|1Usx9MAAK3Y^O4s+9|SWT|n(c6cV4t1q8-G0$>#JPsBrDwwn5_$*C!Xea04 zZ(F!-j)H)Aj?V@KW;^Z=-uF{}aQ}&7<|!`FUdTD;afp6Fy_pZp=Nf#547*f4dH)z( zILy_P+lO;st~_3^I>hpLKgRjD-txFV5kJmHRr`2;qW&nK%Y~eCUdJ)Nkf+X#Tpq6{ zD{?^v?kw_@U!0$jvm3~fw_1;SA!q+MN2JQfx{}f(u8rzphn(xj{mDFDuel#t&-TE` zx%^!FV27OTfm88^9dhuILyjDB$YA+P_#q^!c$Yj4X#g$WGjvR92kaON_{ZsxSN6zI! zj=ZgpBY?OdkG0LuANWPi{>;LuzcQI>dcxLV_ASRE5t0 ztk1=b&&lW)_=i0(mj`~TJvsk;4&nRwX8m)$cpUQcMZVv_IAlMF2e%J==#irxz{vUh z&i%*n=K7<&RQ)hcQ6Bdvm#^v@EwA4G<@$3RxgH!JE)VTvJH&^}10QVC08$=H=!?&1-BFWR6BG2cpNnA zkNYt<54nEequ+TPL7!@GZk(p(b))|3jUU$!@kV>uUv9jxKk(tNJ^s2Qk?P;}_`^u) z&RaeHFg{c9$8%ZK0`noo2M;;;z+<~VJm*J!QU6BUJGT1cbqMX{bM4%PVrY@4>^MHS zAAlYFbN)mB93T}>K2NFrz~>J<&&%}#ud_HuVSh^1lg|@l+vg6cdUKpGPjhkN`GL40 zPCUMW`CP-FBdr8tk*Dg-<*VbOJwGYH1?2JDQOGe4QvJ}LpN++HWim^}w>{1&PzB7b zBdK_{$NA`uCy#TKj&&G0ePAtky>EU;T@o*M$ z6Uf!?6QbTPTl?+5o&@=S6Y{xj;R^ZTwL1wvi*Stbm^Z5kjr|QrC;0Jkbe8E5XIn3?F`jo0)ILEwec;R^E>Ys`yicaadoE#r|w&VCW`?)CB7wZzrN8Hy=^vC)pFN^z< zCJ*Dz<(RrFar;niZk)3}%wyFb_$ZI(C1c)SV4o@vevyL@ob#WH5BwkpAGo8qNYxMe zPprd#3?s`Sf7Kj@wvaDv4}KOa;SaY4hUZ1z@3=qte8c+i4Cuv$XGO<|Usy+%rxN(k z^YbgNFRyFpKeasWk5>ER`eUA=eJH=t`gRnKcD91TJ(2sR*|@aYUszXf0=J+0najue z$96?HdSz%o`^EViIr@Vgr0lSErtG-?Q4jXdIK|`j6npH@!of=9Xl24FzdWz!F6_p% zUydL8iJH|5vYk3k*sjs?c)a$iU?Jf0_?(ckOUd#49{K@^a-c`f_Z@g%fcmAz4aaBU z!Xd^@YTm#uHE&XOx%rl|8&&0{;u1as@sM;-TngAL<9Uev6#al4hP+=v&Uvbyyq?Ti z7^44DcHBO;<9hNrg6jv&c8$(k9tZHxd8^9f@2zn;z+9f%e{9F+T=?gl?fCf)^MTop z*A?(MXFJS0<}qeFbsc28M&pTfh3mzb%k$^IN@6>n=P4hl`N!u-UU!!zhl2_8xq$1( z=QA?zfvNhjJ)cv09MA=i7yP~&*N@D4{jL_To6HC1eqg&)`*=M=e22nuBImeZUZH)d z@_4=NDEy;5*rQl32XfBU@)n@-*bi_np5SrL&wHu`f!oD)+|E|TljjG@#eRewa^(2D zh(9OmTM$xqd=BD%fgN&`haC6KDLvu>KI#LE@>2G>`Za6M&&#+x)HhYXEsBN=vwQ#= zWqBwM_dfVR9+*Uz>lEli%fmehcE}^60AM{!@v!ft^cYVYnon@u{kBCJb6B9lJrDBX zrk|_ecow$9KO;awd`>e#7@v&_!b_H05j`o_o{oaKgXQz}SdBdY?r1Vz%K}=jON`rd zY=B`8aT4n7aS8o(y3$fAo&&qpN&Sf#eMd%*K1!93dXF$aVZTAHex8}@2VOT*^D9+P zmWN}&L%{29tNmlX7vb*pIV9@C^#q^g;6u;;IbN*i^EUKc4*atmeCQc-`FvlNTVJ_6 z@KGMtk<(2O_8sQeEhZ1|VIaTF*TZd&axx9{fk+&}2w zeXYXb7)QUM9o*0S+!t|dG)}Gd$MxrWaeMF_80|$Ko`qe;^M(5xcE}MI;8yu#zwjUS zq04416jv5`%8u8|4$+R|h_l|%!akLSd$V&eF41qPdUAQ_HK+h(w&X;}XXMs2vwXBF@M4xL_SQ+7`HQ9fAA`lH_&NyxYx%xZ{_44ydSU%curpd$l=GxEoo!l!G zB$UBCP*Qy8`8>lo=bu0C03ZH&|4!8>RsWoSw&Uk_;oj_Z3S;jW=Lh!VI!|0a_}$u( z|L1l?6Fzft8K1*B9?VC1jn*$!|3>|B{rJ8PaZvq(k9hHY1CK}UU))Ee%H#TikMcPF zsE_IoeE4HKt}mB|`mi1R5h_eDH@xqdv~(0{4+ z1x0sVf)6=A|3SP}f8fJkc-D6r^o{!C=X1^a%k?Mfi5%@p<=`Pt@vzQ7&+lbG&N`b+M6Als>NXFGL%vmKv9dMZX2Y^SaZ zY}aV})b)hR<9&dd)dSg%&jUR~x?sCT+c&z)`+UsCzJ~8aL9AIuI?6_UvBjARf7X=kqI`*XG6<_xl1=&jR+! zM%6gu`<)f2WPko$mbNT}ZjZU?B7ATTHKc(k&3eR7P zX7>F1@odi+{M7h{Ud=Zzi0@l~!ZEjfA?M%!$L9We&3MVIRo=tIlHHGcO(ev$Qi`0OW?qi>uF z`ArG_geDL7tkk*!Kbspr9PdSSdY;PyBhQV4j)Itq2ilU-<2lxE%n#NccbO{}c3&8G z6*njnBGZIuy#`!wZD`VY?33O~_w0InFjA|8)ale8GRg z#m`Czng+J#k*&`f=qzne)r_weILjsrF-CLlNKuhkfZXl&|`OALN*8 zX9T`n$LBb1N4@2Ok8;_6xVAe7e6?NR!#~FVai$muq2-XDZ1OOcke_MtIZOCwn|z59 z`8f&sc_v?`gnxcQenCRMk;%jL2laG0?v=clP`-XixxX;}k|pw^O&+epJioc$`TmLd zHa)shs^7xB&57W5Tg83iGA^Gn=7(Ay_$aU5amV$y@I{I1f%`F#!n2;s*dOA-eqf*C zLyvJVzcsXM91k#g*?98rQHA3m*U#J!%;$DvoTS>t{Qy4N#s0Z`#^`6YJn&H-*9ZNq z`U4;S*pB1F<)J=o2Y)F(^tpJk9^(e~xpBzlgAaS|KW;DLlWHH2bMWDx_m9+m->84C zKevy|%k>wx2Yj>#`+lmvIeoqH4bReE2aYed5BgO7>h*{AtNy@8yzo6L;AZRhLyI4e zXFmTn8_!nv57sBYCn`I~xcsLW43>kxxLq$0$oaWAk3Zg@G47ZbxQs5rhYF&+tp}% z`CNuI3FW5h%j?8^R9}uyIM#cDQO5<31AO+z<*-Z43&^q0!7kN49tVgw;sSr1b33t4 z<;u(Tf2y85ua_<=gnFjzxc>%Jb7HF%IEsF zs{eB94);f@erPxJ-2aes&UWFmH0Fkw?RXxB-0+(1!eU49;$nlo@#nm|7xLpsj{Oih{2<4AkQeC^`mDBHlovmNY_gOA** z6(t^jutOe^4S=80qd!u5UN7Je<**&|abLo`ls)PLea;^9BITd!!|_Bv`seE*cZ;F| z!z>?w%2*!C!)IV9A9-LBU9MB04=oSR7O+De83h1(M7vVF?F;r?mWSgptly%6 z$Bl~Xmn;wCg#9*E&IX0uOlGu1;18d}uWK?sD+jb*m$`PGSXiX$(~;44X7uR)5yr!w z<|dGP_Rsagx(0r@7PyT23+op9 zfjyTGKJ@jrhvQvud$>HT>#6#4dEle|m@liE;zLLB3yt zzmLhWm)m8}ZOgzs}|5W**tzUx=Imesp%lk&X{m=8d)&4L(x3dNvu^ZLx|1CI~pV|`Wo3G*BEM7y3c zLAXD1Ik|d;bIpCXs$PGhdZE7KTfi6ff{FyWe{LSGsaPk#YqnmPPp$HYdM{@VeY|mh zW4%G18fUytaett`oUcTJWeE=^yfWbwH)8Ikykv3i?#e>j8M-+UK%43&qeP=kmC}3tF$NRd(SV?^Q@3;PK4kH`V@dEp&JD z6h6`Zpor*_%plU^Wejt&trUk z2ES4Nh{r#yzyOcA%B(R^|muSGkCFRhhKZDx1BkEc>a8~`No>&Zai6-c zRRD9$>w^2yd+a)V_5t~$R?$$NJO3d*$i0j(L5@7s`Sluw;2F!qJsWaA=Z9zFYQf*y z79h-d7eT(e$uTxV`5q<@;{d+P{aG~<)^a}ghy1BPwmcUf)FsvaX7#AoBUTrzNnSl% zA8yz4x}ZpqPip-f-dE-7(NWl^+5!JO&LPkFM>}@5fsa0LTgdk^`9L@ek#`7=a$>>e#Ou6*gyN@`T(o-=khr| zebKNYPt{K?kJ}U8>w6LCKh+=js3zB+>&x-u^3h(kd~Of>NBvZP;G;e459O);z=uDK z55}rL9xohUl&AUwANAq>Ks;1`;HUhJ?*8R^bN%Y=U-rlGtG9pIU$gzo{ANL2!V>^s5jyL$wvp*=6a4VA2Kc$r z`16+V@3X++*|e*{zu)9@m+)O4)|1Bt#!YHma6f{NqSznesQLpR{q++kh1YJ*yLs7$K~VF_!(FFVHF!_ zVO-HatD3xQ{aD@PW$TdhSH&Q-JoHnxuDoRYvT|QGd0Dxyn7pi9=dW5)uFK2H-NYtt zS-G26^E*q*b$M8B?)fIK6J{PI%vWANKw^9Fq38M7YX5v5;qrJMFowO_ zK3-4oImwOI@bF%r>%nni48M)mqt$Wc`g7bE*IR!cC-v4px393jT>aP|`06<3{$zg~ zFUGc9bfr}Pvp+7c-hGn&aeH&?Mo!Q1M}Mc<$MFC^75@~!QU6@uQSBe?OVyX_13u!x zdi0;_4}AFJ@x=bQ{2b=^F@}G&zL+1VZ@uFk<-wlYpBv9PJ6T_ODuRp63e|-GuR->L)(e%~{wDE%KDz z*ftN;IJN8D-Lbj;<#nCcXEomJXTWG4U*Fey^ZAU=??sqQ#Y4 z!0Qg)y+i%f@^JpimB;7BM&Gj?+t!a%oW}GyX;h7i)OgDEZz@h~hjaUtMM3I1H@1xn zt~cft;-{_`skr6(H)Y4?6g>MJii#z2?x*j|{N;W^^S3N6R<<198F5kW{nf&(CtJI? zYW8_yFMMtf{s@!fY-5*o z|Gp;t@V|S_>o8+JCo#_Pc^tDndW^HTz<};%VV6g&*^#mGv@y0@B8w4S1;!HaCte*aD8#UMtK}h z9-mwvw&(K0GlZAH@nAmd{rlu$V$9>2`-lB;eRG)W&zS4OnE4z(9^c_RS>A3u??DWh z&-Lf^mHU(9!+Ku-aKD-=pX(c*Vcmx3d%c+3Td#ey{Q1!EBIo*yY0T$G#(aKk7V~{dWb!bTHvV2p>xLFv5ouK7#O( zgpVRTgz(XXhY~)9@NtBXCwv0o6A7P8_!PpY54eW9d?w+u2%k;(9Kz=kK9BH) zgwH3u6di1rCcF$`|96VRG?@HdWZ3u8Z@=qKp8H-x!>((d`I=bJda}^BU;F%1cs?%` zp3hf>=kr+M`TSORKJOKtuLlax*9nE^>xaVgbw%O%dZX}s9a4C{J}Eq3rxc#AUkcCH zHHGKvox<~VP~rLdsPKH<^r_}tPdFFQ^y}m6sp8MqS%v58ufp?nS>a*5cCIIHhqr;- z;p@2K&)0W_=j%Sl&qTe-_5DEc=lg`h^Zi5N`M#p?e7{k6z7Hup-=7qo?^_Db_cMj( z`<%k_{ZHZfzNqkgzf^d>k19OhUlpG3vkK3KWN9+<>)kACRE8)#fY}$pYo7A?ij>jjG*h%G8UZG-r zb%NUV)njUx-=81I#P0i4CaUe9pI4E2pXy1O@)ux>7+2@cl>dGvJ{_??MwK~P664Ce zF=kX*rFQ-LFT@rxu6&fKf2RGp_%y4ptXaE#)pz3dFsdG3yZbWevsQkTl{bn!Lw^Cyhw)NcsYR9KM0^|Dl z=zmUmyCAKeU3>kho|n;YotfX;)zrm|FBH|yj^?zWXFG|ebxWgZeRbsGWBcHzOqK`_~+`EYya4;uMEk|k7G0X%QF4r zAMDgf)r|lCyVo!_RpszZ{W9mnT>n%ztX+O}quTnM|D3-1kJ|pT`foG#&o(!|bM+t7 z`rP?ExBgZ)&8!axWX6A{|8nbFWpM5OtKdcU1TCw-C}CKLD+6oKugZcM{W2N-7PaHs z|GnnMXZ5t&zm=IX`UNunXRBSmN=~1d-<6I`{ie_8f10UZ-;Dj_8U5cg{-@5^e~_`y z#V0qva`u17ls`{KKXXQ(n_vAh_LFAx6J_F?>)#nN<9nWrKDU47+Mn~EvCo|^+WM~J z*>|a3t{tCtd^`f}@lhUu_WT&P=SOv}%>KAi?ftd7T5Wx0oy`8&nbEIOTi+gkQ&`(NGpHARe4@rs$33fWvNX24+pb6uk@=O|J?KG?C0;xW$L$PMxTp+F21?)_bZPJ zq`CNJ`|lKZD$lEZYsbIxb!~mlzS`>>qj5c|pT(F_bs3h#xO!lW8C5>d%>P{bGxn9g zXZ&Z@r`-CLi*Mymwfm>yU*xNis=4*;wc72gTvvPkRBo%S&z65@ru-*r`_JtkS^YX0 z|955dS7z#;vmcT1|L;uyXZFvE|ImMpRJpHq`PuQCo8P(jr!LFX@7mh>Z2dCxKR5q! z`pSQ5*RS$TZT%1Ze3*Oxu33F9zLg_tkN=$g*sib6U;F;IIw+$Lzl2`0j#T*vtcX)N zJhOhCn$bT&4hdEtBLTtcNwxh~7pmR<$}{AUVCA5U|J`ekugdSpA;GbIe2wY)Rew~w z|Ef1oKnYeCBLTsz{fJEeXY`eQGUMac+Wz~$LKP-h`El*|RL-gGzj8rseRc8L{;Mle zg$PzIukFA8%Va>XGOV_J<@${N>e~A1nHl}^wcFqSEvhiV%3ZbnSMJZ~AIa!fsa?NH zXKnqMp5N{Azw1ggYIukMwp|9!RnS9i(iC(h_|{uio!e^KQhxTNB8`U?Nx zDB1TPK>~u66>2{ptL#)ezLl*q`pq)>od4Z2_S@FhS9i(8f8&gO=KitzFA6BZ%BCbB znAM+71_Ud&lYn65K@t$GoJRtJ+3(NfzF)IO?f6!X%jh%Tzp0*4yMOyHPYohi-6%8u zH_hnpB8LR4Th_L(o|>uulH`zJ^(VFcS2oD#FDHiuT(8LgVLy->{^l}%L(<*icO{() z{$$pj;YZq#zij+6x&OZ0Tt!));rBPsw;w{CB#`6ZNARyRP7%oQ@qB8Th8_RA3Mgj< zDhKkxCZ9Ga2lB10piqu-kq0Kxz5vc@(c8dmjv}>5j1|;O+)&Rb52mMR< zcbjbP68Wtp$Is>LV)CT}KIHy5dgefmaz}SPQ7-p8#_WtX9)BFvGn9wFu?=~L@x!ee za{u|4GXB#hU!}zVzf8VHiTr;i52rf(f0dAbosh3>^Dpdo_?g_~W##(UN6O+bZ9+bs z$-{n!|Ctl~YC`V62^Nl%`HPtBYk3%F$TucA`d1xSn7>!qL=D%Q1&eZ*v3&O8+B5iX zcD}&>Ear2*z(3^vd*Eeq|Jk52xz{lqC-Bo@@^F2%W_Bgy1?$o=>C!+8k#aMOqT@xX$gst3wB-FTA}T+dKu$_{em zfoazzj5S58%?%MLXLYhSHsT@ zc0G5%KcKjN-16`|4Ec2?5AVMrzslrcJt4o$SaKozp^SIrtv?GC!`LuY~XN zX-eeYS7q{rOx{t#_w!n~j-WnXUvD!~C@W$oI)xlb4ly zx5>kK1pciFIiDv78qbr<7wx|6`ak5)nmmjHUepEv4kE6@#^NjUIncUBrW%Ab&a(~?^oJZ)# zM@=5yXG8AX&_Bl2Fq03kKcr9|j`Ph6Li@f7kt)v-r*ZZ91^S=Y73{G-CMFG<4*8M^ z`Og#b{S)$I6Y{eX@=Fr(>l5<3NRIZZ^8ox&wSMDlHI>yfoUf4k9$Y5({VbGY9P)EF z_?ejakguGO`#u-?M;z3+rS?hebsgq^P5VQF|7PP1{}Y+xu>O$yT3IGvCL#AdyNo|s zLhj{+e6&lA+vaBPiJv#aPqXpCdCJdTVLc(AH6iDAfzNS9J=OMt&*vtOL9GP4X5#@r zy#D$8^0bQmg>i!X#e{rvI`@FTXhQDoF7xl>piJ&@Et6kIa<})C8b{pT9N)`T&JBp? zsOlHogZWuEj04IY-SxzI%kL|~eG>9&LhkE&8Q<6CGWl90H&|ENs9^iK(}rSCO7;8J z1!G;y!~1#2S2ua3$IHmi-&5mlboa}=McsVg3*)&^A?Nckn1Pj=T8#y&rCjTiT};|mXEtF67sD`j(8#uis-t8969UJo;j?3Qv^!LPqX`| zWdb?Ix%cPXfgI6ez(*9;mu5AxF;o2?_yn)+4USSr5O+S&x3^d5rdKYX;%- z8TdiY{vb!r`ke~F{FeJ#i3GW?AG1MdIplu-G;<(7vA9l^6V^YpgM2%)_h)2Cp*&n? zAm84I;e6k+F!cI{>lNfaW|{)c_)C<}J@JPPeb9+-4pb`*k?K39*N9)6K?`99t~?P(q0_uxp7`#+-- z%5!mRR*!PI9=?Wz&*#89~59bx+x0*aW zH^R=USDHEtX{x+N=P?(yb0P3^YIt7A#TRz7m|fVeZ3}2UbrqKIYF+BI+eD6OCy==kp zY@OozL(Bac0TTQphn#chk+U8cdgPFEzF8r-(DLxS8`d*i?;*d|_=^S3wkxjpvOHWr zAwSUM;dvDD-A(S#7?H5PziWcfKk9jd$-{LnH-B^bM&~c;i#%5j`T;rYI7fWPmhlnR zr=D@}wKc3GXxwha_3@U6>mB5~m^_?6xpfI~L>?5?b=g@6QuZF&@;i%yQ{z7smt4EHE&N_#`HzZg&mbRW*Wo~zd%F*A*1Cy@HjzW;q2vcB@$hHr;XK%;@augN&S#W^yrA`D zkR$I=6c>;qXT1%Nu7sTR{v6ShKR27R>#F;IknfU^?`m?7JrekSZkq!_%TX`nfvW2g z>&&AmF1N$OBc^Wv)GVK8~F2;TL(U_2?&mMjZAl`ui|zZ@9if zegw%e4)!s5xKBX7pUGzkDi8U-CJ*Ny+KD_c>AHj*IqOlsy=`4BYmfgkY1P08eE;W} z%Fa0(nmn9u7-ySVy+i+y54MgBo z7Ux_ZV-%N*4|tqgH$=(0JxUWrXyiHvaoC40n-q#756{Xjnw<1uU%QI?h}(qYrq3%>cbr+JMIjUET%?{q=s`hra%2DBGNQ?dTyzJT{za1^|12albE)(-3;!&^H7 zAN>+fYg*LoK`rtFH;=ZsetlZ(ueIIV^8qfJ-*n#M=C*!?Y4r-&>H*kle`EKl_Z>WZ zY)vYI`<#`-bd zQ&a82+Y|n=RlVn6_vO5^*$4i@UwcYKE!rt{eS=}x=jWII$cTl_K@rK|sDzeMS zKW{9P`)~eqe|8v!z3aDtTpmliznj~|kBja4-ePzC<5K+d!EXP3I_<0*B|`2#UX3twfmgF3gmivdnc|Tr)km^2j}DS zca-4uaXCKsW_kTb$S?}<7Upez7>(Z7&BbTpUNfFcsO^7L+fOix>({LR-YaGtzh>jp ztp8D6ey)DKSE4vRqgp?4ua$80mOrZ7m-F9&Z-sHQ3!Kvr%-ZwL5f_y6-_dJ_Vf#_- z-!`)vsoC}q%sg|Py3mf&&lAX^1imM z47bqx?sB0y^j@CX{&%@u!#~dIwS4!r1IiV}IR$>I=I42n)#b+;d8OI-`2~JvF+VTV z>1U$i;AkJGez&4E&d*&)_0(tLz)z?73D2YT`0*I}Z^-)n0NT~xWS&Al&ht2@V(q^> z)>+uV&+x)QJ$`1khLrZZl@C9-C-WG3^15=WnxC?Mzp73@vzVWQc$rH%Lr)*tw}tPwvp_AuY!=kgLix%obx*>qYkJihR=k_X2UV(vb2e#Q^te1O?{ zRpu<_M_qn`IKz+E#Zz5=f;czjCx~-Xeu6l|&%WKws;ga{HZR_=I(c8cYI%6yUQc{h zGCyycy=8q~EBqDJsjEI;e9@Zv{PnM`sn6%1+wZGedwl#YV7U#;o>WhK=IF8NzL=Bn zT!iN)JP+Y{2@fP(FU0%#uwx84<}`4taxRZC%JJu5qaty6j7LS8p-(Q4amXE)uD|>4 z`_hueqTX(QyZ;*-Ic=+PAp$r9pss#S2$LNdq7>CUu8 zl-JFA!Z5^cT6rB-?cL7p8!g{IV?WdW8nyT5#?7?fpU*Z^f4>iHrhI>1Fl2+q+ke2~ z&6V%(HZ;@!{vOHDCi>s+N1KVCe?PsM`1$YYH&gy%UVdle{kN#u54XQY$G^Y7(oFwN z-=w|2dwZ? zpWp0<+rzU)*Z)P_zKQauu+P4R+a}Ox`F$*Y!>taD+WWtCF{BCm`ONle>-}cmE`+xS9-L_ z6PdqP*iOA8fVgx2^~AL>Y4-Vg?~~oh)K+%4su4SB@eY5&hd@zpt`9fbKrTQQC>t`lF&c3pI?G~o&QRUP)hCY{n zT?8n{OX-{a+zW9``OnE`%MmjASu*;Zntu;3$7g-6f0@tN?{k_-e$H$rHT$`v-={Q_ z{649fgzo}0>LYR7lHK`pie?g@x9atkUH=mf$5gpooz(iyJjPgcdHv*eu^xUJjT`LM z9Q6c0vmJxhlXH7|6vYMmXMN5-H~w?>W4e59FXLSOo7Ho9j2rboNzRZ9YB3(u<4G&}$ERA%34a{u#GrXSPs@34CLpQp0=O<;2W z^HiqqFuDJEYDC|xe?PDLpQp0&{k)1ZYneW0Kc3n9pQkeWoZf$*+y6Y3*>`Kk{r}H6 zh8u@I!dO5=xmv6TFJ+Ih4_*f@C{Nj|<&!%Z)_Z>_J1&SR|7b7#<>Cq+)_UM(^Hlv( ze!V}#y8HJFL+twSDB){I*oV#!vGc=cI({8uw-2A0`gMriU-(SV`62eVhQpXSKg7-t z$Ed$Y6JjsRIY|C})DXM>@R_LFhS<5`Ge5TvvGc=cYTot`yM6e~*6l;=?;V8CRK0y6 z_WFg-{M)ZDy?p#z33l1_+b1FR@fMDCFP|~id$)J}_`wKs z`w+W+Jkp2Q>oZ}XcifNgM1&^@u=h{+9c6EChz)in%z>~it_a7vW7fOOQ_4P^OU@hU z|0_u;dyh|;o(aKNaGi<=SIzsqETP@dg>xG+&zaW|Do5dUs@}OGRl8(+DX_cb3M}+I zUfGP}$oiZ;^IL|)MZ3f)>P=yZ)_OPVD6w@>s$D$4*nh%ZFLBC0h^hLsU8?+)J=Z@u zo{EaF|8OsM${K}5~_5E3v zmElzVn49IL8o-VSXZ;p@)x8>@4yp$r;tV_x7o#XowV&&uwm)0V!g0Ny1D?+nDhf)~ z|AIRCTiVM(9;K3HXz5zZJBt< zeklAunrJ_Ye=MW_RYw1KM*l=c|71r0R7U@FM*mDk|7=G8Tt@G|S5zzc?-12W7bWI9 zY%b2|hh_AaWb~J2^p|Dy{<}}L(uZT`jQ*C4{??5Cwv7JvjQ);{{;rJv?u`DP zjQ-w?{(+4C!HoW)jQ-(_{*jFS{fz$i8T|(t{f8O-M;ZOc8T}tJ`afp$pJeo(X7rzB z^q*(+Uu5(b@r@vD1{Y`a!!r6yGWtt1`pYu<%QO1n8T}O*{goO0RT=%&8NL7BU9EI& zMt^SdpxN!!xA)XNNv(3*y0Iey+`T-V`8ia!)*Zy?B%Fbn<6_3T^=hwA>K?uIrL{e_ zIs)zfYjs4&j6eVE5}#l48s#YnfbfKb`;CXYx^Djyk$z&rlMsJW!jlo6 zobVKcrzAWTl{YovA}T>PB)IOn^ern$LkRQj<&f}p&+Tvnq2uH7>JCDjA627MH`tUV! zgF~o3L%2TSYw*q|>@G*9$$0dQRE?IaNyl*c{%>ZE4T;}F;P(RfbA0|>oj_agW` z1b%OT-vi*!_4z#(ey@h#6XEw}a_`AJO8vm^E%AFw{9Y2jhs5t4@q0%6UJ<`X#O>qv zgmUfUc=3Ba{9X^g$HVXK@OwHOZ+;Jl-@D=WZ1}wz9xwdf43AHKFNWWP;qk`fncr*S z@yO$y$0v_}9?<_dfVN4}PzM-{au-HuyaaelLUH z!{GNW_&tl?(|qIiDEPezeounmi{SSl_`L^y&w<}-;P)8#y#;87Leouhk3*h$v_;Y{$oS#3}=g;wTpW9>4!r_t+Rn)zF2!nag_kS9-?{Sp7 zpaSAke+^@@tHF#^vVXJk&wXaMKR#%~p?~+#^?cBVeigg8*8VynpnO%swcaZ~)AW8w z@3gqPWvlM=a|rcN4c|1X|i+eZ*KeRw7;@+o(Z?Jzs@qH z$*!=!TJ5{u^d6s7d~Yc9srcS#dXImn{c-Z~f0g}t`JJpZ?E1;AVAq%Vcl{KFzSFKb zxqjA+{cMH)s`1&nyZqS;{qTgoqtIWG&<`l|S0?oH7kdA9)Hr$l-!1h1@6d5_{dzhCA@zWkZVFcRqr#*kL_j(?Vjk4?Z`VmK^J%2{;{PB2)sowary^m*% z|1Tfw)5m|eyjJ4#HkY5f599MV+w;r$To<-?ea}6P-L&<~RDjRV-u}>jqB`xp{-OQE zb=q_JlVt46)}OHaN$a%d@+ZsKm-T;G{^S{Z?msSnii|z?AIE>nI_<;q{d&SC?Z?a5 zdl_L0%lCWNsWSH5ezx!1fIXfeG}`{qzLECBzR~uF_RY3`{7n3OyoD)@zh6&~v3E|G z9HajJO{l3Gu*WkU_ti-JL;GC&%jzH6Hxhq5BlG^xm0vpki%xO-T>IJHOh$e_W%19| zpZlNfbN$cddpyy8@Bez&pRV-}m1=bV3+!|IANN0(pWFY~p4*?>|4R3tp#Hi2uWbLp zGu1}NUufUR_=COoe#={V{`EgtZ{++P+UL&CW$QOS^Kw5Pk6Nj${h@umTtCF$ zeR$n+>u*{6z1^_St-m?@-2G3PeR%&qWv$?wu9kh*H}Ny)&$9kQ`EH-v|9Jd*eM0+O z|K;p+{g~rg1+4v9RpIg6k<>%JVoPBQn%Z=aM`kS-Qt)Dsj zX6Ek%wvfcXhSGa7*BZaB>siZtn|4WR#owR*@%UgjT)y)$e%#*w-NIUl?LD4&N5*yT zt5JLR)rdXbacZ=D*f&x>+UoB;)T(>exC_?iu6_#ePF{Iie?Nf3Oun=8ZLm$(Ui3yE@;#^mUNP-_7|QwvUSZ2c2(&{Ta)Y^pNxGh|j~$uOmK>IKPhgJnH;9 z;`5mEJM{Q;h0$%q)HS{=K5FWEPe2p$5SehNv{p zeJ%nc`tc%&d*vOyB;|quh7|RLa`F%kYh8<_5Yy4ep|{Rho9W|=q&7yqkM3I5$}!yr!weMIqU}D zB9V6%@}(1b!mLN!zm7Gq$EbxDJM!Uu(da`xBiZ>#XrKK9sQiwn|jLX9@q6@XdseC2Z?@4dK)d@JDx3BN)34}|X~d=udp2tQBwc*1)VzK`&Qgnvc&D#Akvzeo6O!silxjPU)0 z-zWSo;olK{k?=1GzfO1r;mZl1NqA?%4->wF@G*ohBYXvu?t*U4|9YXke!j}--k;TH(o`7Gkwc{0L( zB>V082!BBM8N$~S4);>Ow*7gcP-ge< z5w`t3!gd~u@D7CSd=csG{1IV0zeIQ^!gjuh^md+!u$@ODZ0Dy4+j%L%cK(d8ogX7? z=bs4M`7gqDUX1X8gzfwo=?@}&FyWmE+j%LnxARei?R*#Eu&?~up2tOcdma~I+rJ}h z=b;GO`6j}4zKO7%Zz62_TZHXA5Mev-MA*(d5w`s#!nWT<*q+Zt*v=CXw(~-SZ9j~# z?e7t`{V~F}pGVl9Pe$0ze-XCxQH1UJUWDy@7GZn77vWH-A5Pfrey@VSIfC43^`iwN8EqNu#<2;2G| z>23Xv@TG)LAZ+V@#JBw+!lw|n=V_7No`**Gc*6F)Ez%DoZ2MiLzlyN!f05pv4@TIY z$3@uo!wBC-*!G`DKZNkrgzfou#JBx7!p9Iki?BWajrif(Rd#Lb)zqQf=2wKRJ`uM0 z9$^~~5w`giVOvikZ1Ih-jrR!Ke2B31Z-i~UMcBqygl)b=*yewPPb6&XX{5LKMcCG( z2-|uY;WG(ae@A-j?+DxYiLi~w2-|py@GgYy{1)kL{fV&c2NAaQA;PvlMA+8L2;2ON zu&uulw(%BW+aDrq>rI4hzl*T#9}%|k9AR4@B5dn#gl)Zuu&w_Q-iI*9I~?nNy#xJw zUUr_EHssiOBf@sRh_HQL9AP{EMcB?45w`PJgzY>RVLSgs*v?N8w)0Sg?K~A>J8wqV z&YKao^Jav@ww7HRf3{F=@rtmWHzREAiLjmTB5d)Bu*D<77QYDF`8C3JzKpP)=OS$9 z*$CTtHNtkjjj)~XBW(R2VLRVP*!m~J7XJua{3C4r6=6G%M%czzgss0LZ0G9;+j%^~ zcE1o|yI+W~jn@dibEW);*McDSQ2-|)YVcV}FZ2MJ& z!@e!Mw)sA5D7W=2!WO>>Uqaa87wK*NiLli_!j}@Zct?6`UxaP{h_LOa5w`s-!WNGR zTRb9c{TE@|{~~Pt7h&ta2wVR}*yc-wZTv_0aKc9rw(%YDZTv>q=68f`yhqr^XM~3n zw)H#G-$dBvZ=|>VKf=!ww)H>K+xU&J&Cdwic_6~JK1cXb!nWQV+xa2VKTO#6$4GwqYB+xi~yZGVig?bi{u^*_S4e@EEPOA#JH_#DEvpGEw03EO@j>FqoeVcY*B zd;#Hm3EO@j@om41@FRp@B>V*7X9?SRFYwq8Zp z=2L`izlyN!PZ75LB*M0SM%dQx2wQ(g*!H&wTYpE`_OA$A|3uj4YlLk+MmUUxUt4{u zq0IOZw)#id>KkFJUxcmv2wS`(Z1s(>^-qMuy7;v{&x-1A&#xkE&xayx&$}Yb{uqx( zg7FDYK)5gA2?_TjJQ3lE2~R?JQo?qgh|<6a_31Mo;rR(KKzLEYg9tB1ctOGo5nh<^ zB808~qqKE|yno}gT@3r!c#6_C5$e;&#%q+ekC1(Dn((%SrzboE;TZ{62+u^A2j9%3 z=fTd0@o4cg+u6u|cEUCvqh#|jN;bcvWb-Xbw*E!Q*1ss(`WL0iB9#BV1kib2KG=?^2k1@ZSMyba-P3ETZ^0_))^o5Pp{MbA+EKZ1<~? zf4e`8u-$(~xIeZ3WWwhX-|j~v`)i5+6T(XpUV-p02;WHfdctQA-iq*cgzf$~s;}K2 zNBAn@zd-t55w`p1$i71M7m@xd!pjl=Ji=EHzLfA;gfAxl!w6qO_)5ZulfMHA|BUeO z$o><;b{>u5^EbjT5}ttke?j`0NWT%`Dq*`{jmn>y^skZL?mr^_ErgFI`=1kDp77a( zk0ty`-?+RTNxueR`#q$ne(Msxoa%cn>4%ekTGC%Z`fEsk3gK&re+23K5T1kZj|g8! z_O@K1@q3gO3ye=+F~CcHD@?Fr9E zcwWMGe;(C$FzJ6m`ri^hhxm_^{t3d168}lkZ%X>lN&gh#j|fjm_D_@k1k#^K_&rGD>g79F%n-kuQ@Fs*eCA=}=X$gN#^_zk8(-WSN za6iIR6Rr@RhVb91{OL&lDUG)kX}ok2-kb2HWWONkk0t#@q`#W<%aH!Br0+-iJ4ind z>HkUk|06s-@&85oe-r)>;r|jIO8!nE{XV4sAL&;n{a2*_n(()TzazXM`Fo4>L#5Z-c_~G8LY46rPV8h3Dgm$GnMpB_C%z z7kZIQ;Ny?yNEy$^rNZ;^s_=XqD?A_H3eU&A!kf-`yat%4SDM}=%D9@rcuK#`DDo;I zZzhq~U*yd!@~XyD;xdcqZ&u^+8f>CoX*QE6yxB!whsYaXJSELxBwp*w?B*;JmdNHR zk(G(&HlflV^OPBv$mT7Pm5BzH2}@-2nM~=o`9&BuYZ!wX#xX4>VvND1 z{aH;e9c%>Uymm;=QK3InDr>uV`h`bX;-bo_wWRZ7@@sxGrRO2b*6rty^iI7{T6 zE%MG0dFP6}^F-eH##83`1tRZ4k#~{EyIAB66M2^yPZ_6|ioDB=r;L}&Mc#0ccZKnk zc3dg)t}>poo?b2Tt`T|H8c#{r8A)mH^&;;Ek$0oWyUBRUI2a-NyV-ckI(du8yVZEg zzIvO;yWM!oc)3I5-6`^ZDe~?zo|5i1(s%;#9^)weaj)@|eda#nDd(a4jipjyMHOyvDZ}flKkT@1IIM`yQ&qv+q|)Jo{dc^jvQ_k!QbaAo*KCxjH{Mcz+D-g+X>zRxYi zWdo6C-{+J3{Z!=rOyt?`q)6r3_su2VCL(WBk!Rm)m&)B-SHJ&oAZWDR8i@ZCGXa8l> zokmjH@k_DXyNsu-FLxVHnMe1Cyn997eIoCE<0BJv&;d5?*_ zUx~cOMcxx4?@5vOl*oHpt>*Oyo^2@}>}ZQ;NK)MBdaQZyJ#|t;m~BUXggGJuTB5xIux2ninP2{aE^41V}Yl^(JMBdsW zZyk}huE_g|$Xie3tuOL65P2Jlyq}7^pNYJUMBc_CZxfNXsmR+*4 zQ6g`M$U9o(4K%VI$q?RU_5)&noTDfPkCS9B$0QrSie(5 z-l-z*G?90@$U8&iohkCp5_xBfymLg}xyDnTd!Hxr&NrU&xxod-Q|8BoBJU!Rcd_x5 z_6`&MU1B_C{$48bE)#i|i@f0??+TH3rO3NVv9h`bj?-b*6yWs&!5k@t$o`;EwZRph-U@?IBtZ-~4%Mc!{k-diH?ZISnm$a`1h zy(jX1C-UAGdA}EVABemUMczju?_-ho2a)$jk@tzn`&8t8Ci4DdJmq=GpN*%ScmE>t zJ~y6{z7TnTHJcQ{?@h$orSb`?tvZkMWfBUy=7ek@uCz z`EBl5mAp3=YHi9DY~iofxUr_8tUMP6T#r}V9JCNzJ_^J3MX%A45ARpK{^$eUE; zO(yat7kN{NyeW;R+{aHP@}?HcokrwMYdmG$olfLUZ#<>FGl;wyMP9{t%5%b*L|%X6 zDdTizkyjOYvxvM|Mc!;8Z+4N_A@T-@yg7`gjF&k@-dx60*0s5fr`*TSBl6}I%N;24 z<`a4Ii@XIy-hv`;A(6MR@szZP=x>n7TU6vNCh`_Hp0d6yA@Y_Kc|Q_)ONqRtMc$7^ z-ZCO@S&_G#$Xj0ItswGN6nUK@ZzYj8SmdoN@>UUftBSnUMBeHmZw-;RrpQ}M z=G$i??@z{4=H;Ko`u#=p_qp+ub?pn0_g9hkrO5l6@s#v;k@pXg_fL`ce{2%zasB{BJV4a_qFkq@%)YG?_1H|cOuUp<|y?WPvng+^7@Lr2}It6BCnswo5*;| zIzF-Sl=W{CkvFOFl%X)0$eY}FN}59CO)2uG5_waLylF(t$kS%+2^d25Kg zHAUW9B5!Sxw~okLSLFRfrh`c++a(`(& zrQhxn{oO6{?h$$SiuJosMHOyvE^c*=S0&m!+HBJXqKDdXx3k@r`z+%Ju%{J!_!jHle! z{@r-?UpD>2NXkC*Pva^3$N!1Ee~G+*i@g7cy#E?cY486;e_t6-S;xN?dEbb>ukh7@r z?_?m%AlGm?C}0Z_hCAUL@EQbR6wn|F|Ia(X-^!t&Muy81=RlJg{UO+s&xAyHW2sM!l+0@3}_3J&byL8ug|d^`2+c+sml8w^6TG z^ep?wKB8yIYx|0xC133)dX~rjqG!oN2Z)|*nbF6AM!kcKdNYiAGmUx&8}$w`>K$s- zJIttexKZy2qh6or$^X&Ek)mWd#~x+Wd%jWc1xCFW8ueae)O)c}uivP5wCKtI(Z@@S zddC>`jy3AN)TnoyQSW%8-hff>Wk$W18}&{w>YZrRJISc`3ZvdDje4_;dM6w8US-rf zMf5D!DX%u_y~e0_s!{JW(Ubq9k3pl}YmIuZGwQwGsP_h=-W!d2|6tU6lTmNBQSWr4 z-kXhjXBhS781?2F_2wD%-eS}nGU}aa)H}sCSc5Z`7!Fvr+FuM!j2%dbb+&ZZqnA*r@jrqux@Z-t9)c zj~ewpX4JdGsP}QB-ZG=!okqRoM!ma?dUqT3K4H|m$EbI&QSXzYXSqLlpHc6Aqu!^C zdY?Axea5KwfKl(WM!g4(dY?1utuX3+-l+GGQSS>zy)PQ|zGT$x>4_8quw`+dXE_OzG>83Wz_qYQSTp(dfztceaEQxU8CMV8TGy=dX~qdM!oMF z_5RtY_b*1h9~kw1Xw-YmsP`kI-fGday#MxNqux)9dOsCC%jXY%X0-QnquxAvn{F=2 zZz0(dgGp!N7{F)Uwxcfjvu#`t^-z0$kGBU6s0_8|_kL$lJBXq7629JJh9|8PtnGW( zHSu0CPpIVa7v+!bhT5|p`e!`UJ~aNx);`34$bXKXDu|&n)V|sAbN_?XFT_y)96wbw zXt3n*@w$f6&8tLiV8tenW9N)@@WlHA!#An1S`b=nqtXknjPLA!0m`gC+SF z;)mOZ@+QYul^d#zabRA01A1k{*6|T7V{S07As%>q)iDdU7bBz=@*8^KF{X$34(U<1 zQIYwu+Fh)cV}3)gY`-zEM*TB=OHvM*6W2sT#|u)u7^x|fMaE-8S@n5eQsrVhkRf2NIr|?vq^p%$!{n5 zEhJw?@({^ql6(%y=aPH{$>)(gO!E08UqJFDBrhQO9VEY#oXW75QY0QdS>n-?C7wL_Vv;4Eyn2~WPnP-gWSK8do=@_X zB+Gny`ZAxMd=<&VB)^qpSwCKTSwEgE@!`p`K0I00rzgw$^ki8-o-FIflVv@6vc$J1 z%X;x-SudU}>(7%fB>5teWxaU%vR*y;YLa8|+phItjqjNMlcoM?eKhJ%v+YCu#y)El znt#52jqQV>{@D)eh5EPV=TLj@H{^e_?Y+gvgEPp@wl{QZte7zV#(K*^Y9kNuzHiT9mqz=2SE>;4>S&)*g4E7(8pQ@w%qSTC{h&j_>+ z`Op0qJzrS)3;ECd4HWbr<3h90_)#AkAKQUGO4Kv|JpR!9!_J0U;%_oElr&_};BTVG zAKO>p56>%bE<^FddRE!$pVc16V`x3Fp4E@ufFsuv9^w;v$Oj=l*}p2;FG~!K`&#NC zG#*kbEQb1LL)QL7e6qce%)FQFU#Q;@ZtXwRK89QEhxmUFbztScO6@{oZ=izL(Tspz zQMl3h5BbUbgm~ofgm`5CsznE=`XT$c(O&eNx|7Z7RQg|U?DEiZHylPuReUcFrJc=9O8a{c4g%k`ose~{!QB+K=pr!Uu^p8P(N zZy{Ok_j~#`k^CW&<@(ptm-h!e`Mo5|^{ZDe_xC;dW|D6pS>6xv^yT{3lZQ$E0LeF! zEbm`Al* zUrzE6$!C##8OiS=`D~KUA^BXA&m;MKlHWKB@&b}CCHWeXM@W7j$%{#rbA-p=btJ!= z8D|-KW%Unxh!b2la=$EB83@Sccq4*H3|OyJ%JySMuqVHw&liJIf3U`{81TiQ zG%Hx+R}A{%n8e?|7#^!>&5O|b;ND{MJ%|3xxt!0jv}&g2ku29IUi}csa=qcz%k_jO z%k_jO%k_jO%k_jOUq!N9UwHL$zV~GLyn-joI`rfVNS5m%uU^jQo-EfVo-F5mPhL#& zZ6wS2+tZip6;J*I$@h}Hl;qEnd?m@ZlKe@M?_g3 z`5#aJev;+-&a0Q}B~O;?M^FAZ$#VVS)h{A>l;qElEZ5gw`{g9xMe^Mw%k`1h{z8)P zAz7}sJ$<>J_hk7TlPAmdtS5hpWcmDzSAPe|pC);j zr6k`@@<&NNj{G>DWOV0XRFMg&)JnO3hg;S)S?=F?vfOX;WVxT_$#Or@ljVM+C(Hdg zPnP?Eo-FqRJz4Gtda~RP^klhT>B(}x&y(eTp(lHT%?a+D=$`ITkDq4ihsCaYx<@_x zvjulg_o!FjFSvWUN4@$Pg1e`C)T^%w?w;;Zuf9ic_jHeX_1g*Vp6*evKC7uzOb4Zr+k5@0}9Z#0?kSD*5WI0cG^>RM) zWI0cGvgCJ9mh+J(OMdcXIWKv#>|dTN=O<5IK(g$YUcH>BJQ?$1E#>xKg^Tm{V-3K{N>4#Up-mg5A$UCK8YvG_isE|@~_S=CI5QzH6)LaEbk|I`uSLMuVsDhn8##&da|rvPnPxK z$&!COS@MA=OFr;qS%01^>&=s8J$bU^Cr_63?a7j_JUKs>iFl1Y47nP8a?a*@=r!9O zc0wil!FtX1-)wvMQ}lBUXlE^P7K45#UPMZaFQPVfmVuttKJ=rdI#QIUI|7D7{>k-W z-A72Dm92W*E+%hI3f6vj-pNc&F(>EZr$NN=(Fg>i=TMpO^$Af`9XINmLcdgu?OHj5T=|IqXR4>A5t z#_A}+KB|h2qtW$;@o;=2e&7$+14mpyo~Y8w&wFKn?efuaA@}pz+W$n&N9t$OWZ;xG z5BvBw_dhT}{l9F2`g!>T^>e}m^>g9`^>fk$_4A4e>c^cYCZelm&mU+X^Og0i=ZDi` zhFe_!J3ffDxIZ@kZU!b;9-QF*xVzU0(9ZKC;+D_fxNd{Lc&`RB%4_i=Qp)E5Y7g`m zS|6~7uw=iu8`xt#T>nA87cZ!^wy#n<7R$aqV*W$@gD3Wf@zDHnyRu~P%J$eV)bn_O zht>w}13(WY&pU8j=R-yribL!E^z4u$=%B@=_5K3Z73L*0Zs=j2LT@fW5Azm^FX&+& zcMb3XJMoCIH;F!;x0U-&TP^Azl!Fod3}bdf+G)r-;8$ zoWd?j*o9oQESo>kMQC6=5@jK@PqY2c&pks>;IlG z0LLe|w4N`a2Y0RW%fkt^+f?I!J_u!^CP==p&HZ20=KjxbbN}bHxqpONqvxMy+hh2g zpZT(|7adUq5t>80RR(RGEYUjZ?^qn>M*oFKo4|< z^hVSk<|U*@-9|<93&oIK)(g!$?2LVhWelkQg6)Rlk?mFMn_Ktg8LgiY&@<034b;j{ z&_DI(bG(oOel`oQn4o?hnxKBb2jYgNXWTvEDjHDvr1)!&0czV$F%*C76Z69LkVES& z#4qv>+K2iHwdXJ?+CSe`>xCm!HrxM8+Z-J5pN2I~WH+txf$N@e1_^*3{0Z4-KSFT< z^RNp!RI=Sr{~Q;g{xJ^p7mGjWRq?`DazCMFtQQ&|>xIV0{WN<1-Bt)??%8%L#2@3K`G>z;zoE3RO8ho^2E`mSQZi3PZ6I#YuI%_?`{;*D=pi0LeuUaF&T^yn z*^X7V`j7FJ9skz*C)UruKo9;}$7kgW=SAp;>_ZQJFmGs&a{D&#FVAgr{~u~LL4e2x z%V)KD{2xG|H0Xb`&2DNl{}?{66LyR1G48V3!=AMat$%BK*26e}TkWGA^JC=?`3n7p zO6Z|KtA973LCA26adbaf`FVAV$8R;?==r)?e%p06wZ`vnc_CQ|Em^PZ`C;Cx0e`n^ z^YsJ!8E`WQFAmoD70^RGhvEZy5MjZ21y*q$#W^>0fAKYF(Bksc7TbsU4h$H;1eJ}h zkGF=jU)9XuOK7`uo5zoQ#d!$%2}9(1;LWy&omk0n7Rs+N zJJx!uefj(RZC!sM{yB|?_79$C@WXh~`RB0ig<&eWA5^pdq5dapdmevL|9M=Y_M!Q2 zwmtJ7il1it$9!+B&3?75op` zhaUV1jSqTQC!zHL{}2OJleb}|kl*kZEkk;!M`_iI>9?x?R@se>2lb2fMJ#Th2Y*An zLJx5h(?i_E^swKA^e`SS;V*D&d#fJS3G9bT=*4*E_GrgA%g~G2haPwdt$)~uKIBjd zy;%RD_KjYj{tbZ^GTdSu@!M=SjgEgOER1FyXs~^=j12d=tr| zB!86TkC8k?viu&M*WWoLpGoq^NnS?s?IfQ?vizQf*WbA$%ioLf>g7JAC(G|yc(Qzc z$deb5EWf|y)xV$QJ4n8UWV!zK+RNYD@MQTt9Z#0O*W}5|Ngg3telN(=m)~FWx7&6DpXc?rq#`$L|-{JxMU%kPnR z^5rC7LGnV9?;%-!KgqLqC&^cloXa$?qpweh<&nm*1E3WchtOPnO>U^kn({ zKTnq5@AG8&{XS2Y->dUv`8`2TmfthY^kn({LQj_81N3D1y+BW1OtSpGpjR)y|L4g!kSxCk=+(>b z3wkogf3xzIV!(CK=>3Cc`>zc97UrlgK00xd+wa`7ZG7lZCyO60|GTq7yZLZFxNC-q z_9L|a@%2kpe5>~ewa57jZJORc$$)kL44xz4Sc9dt|E*e@-Qvzq)co*#Tloq3$MLr| zFw{`{El7WmWQd{m+@I4VPYULkQhh|BnA=#iGjpGVjwY)7)T5x1`-2_fy6*!ATf{_ zNDL$f5(9~W#6V&oF_0KY3?v2;1BrpeKw=;M$^^4(6bz^?~ZL^`^iumE12?+eP~OzD55&u(hMI zd9m7SIe%6Hl3rpUF_0KY3>0FZto_KkUzDvkQTq>VHVx1~|9C!jZ#W)t?g zU#lMT6|&bZJsNIMgx^p|^N}%8_Pl}LSefP{V~E$~WSNg==mfHVJa3R=dOHT}S@V!p zuWbIxwijC$s0Xi*w+-;edhjww`r9 zta_7uKCJ#>9%3cW$L7X)YgW%XA67jpFOyv_Heaacd9$9Mt@~R?AP%haVbz=L^I`Q5 z^Aan0-f*24%adu|GG?vwVbzPx7wUQ5tn1CHm)2Xc`Nh1%N}f0CdQ0&4a?>eG6gTycPTiIqHW*8FGHOZ!_k1J-pOn=jO-dCQoXEO{665-WM$y0ih0 zgY^(UF}=|Bg7v!0st12CUii!YO?Ex_A1g6F=%snfm}uAhVjf~8&zp7M!nin|+1^&_ z0P9)TkyQ`=V7%~y`;&+qw`^%-!yM&-W&sn zGtLLrc%JNfv2})e@Bn!yeZjo2URrM%QDw&g<{?({e5846&3strH#T3WPxF>B!TH6? zbJ=>BmsrX3X1#txJ034^^c%8gJ>OgP%I2?K_P|@LWS+aVL2N!Su9#lPo^?K~dhiG1 z#kknN$*u?gVfLu@d8h-VXYL$IE&c ze@riA&pIDgJ@|uhz+d)nvg^VBSc&mL&w8KBs+X?2GiI&vf_aFQY2Gr1Cd;~v%@^v^ zylt5ChWSIu>zVf#3k@8?10lKqeQ%l@;y zkQ{2q>$Yq?9v|$tx?i4G@WTCayoCHKTMzzNOZdh5JRYlF+4I8d1b(uAW%FpY2Y-r| z%oFz)Tdy346P;f$UTa)f^+$g z_M`0ha2ovc12+ z@2~KAh2L-C&);n9??0yT`;naH-{+%f{G)Zd@?xX?mYv^2_N@8Xst3M{maXOq`w8zK z)^W8{{QI-N;YpKi{&@fA{esT}e16!_&j)Gz{u*la{G+$BuM@1-JLo@FHtJuq*R3(X zQvLcF;QY$-*zEfQvGYc&-@jb{=qr^pexIRDZT>NO9(O1&m91yZ!)5DX+}5&PR)IaW&0QNKUB~0 z$Kx!TUt;-dqVr7}pFi_hFF-jC)BJ&%tZemunBvptJH@BZ2lfx3DSv{AtZepvXIg(g zpK1O1e5Cc~^U?~FTcN-{(g%e8HpdCj}$*XA8CF0e5Cy2^O5qi&qvz7d_L0t z?(@O-HxoaJpF9KU{G4Z_Qc2erJ|DOb0W|RgCbBZ|GMNAAL;WkJ|F4x zF+LydzQ2>s&;ER*^Rv%KI{)~5r1Ou@M>_xbd~EFJAB>jIHHZWLezH{$?O`7!+XEge zxnG<+*j}T0@Hb{Jq{n##<6(PNJ@f-RDA^wHO|{(6-e2VR1Ni$m&*nctt} z>*;pqZ|2V`^E`y|zEzLs34RnkpG>y-=lSOSnd5`wf%ot9`4B`#RwjOYK2rSne5Cc| z^O5q8&qvw$*|$FVq>X)loP3NYkIH0#w4~SR3p0nz~uC-*lh?`jdR=sA&W4%vPwqA@s z=B?R$n%1w+IN}Rv%3ok2D^vdV`IzYQMOyzp|0)0Zd|=-L%KH<49w_C1FqM^)J^%aO zCaEX`vHTfZAABB&t+#gXm&^~Z_gMa9K6w1wQU|<#_+e+4*B{C`bEoD+lN2g4{(k<;2clDi{7W(;iZ&YS}imt!deDe5s{IUD*Mb}%1hY){_=EJh>h5WYSJa5SBJU-R~zpQ8N7kZx( zLiQG6xCTfs7iW&!FQ$O`wBR#EccnZl74i1zYy~6kFb~fD z!}2^ro=#(>CX%JP0sNi);rEC7#Gh!Umx>+#QZV8vGY0l4V8(X z5HlH`_(}Za8Q}X(`MP?qCwu&GzTq(>|9wXIeAsOMPyGA*7CoOQ{(b&fO6%8WWTMxv z-+SW{=LwuE`Fw2EE9!~Wu2rvS{~`TW$2WLJ|9pPu@j?$J{Np?Y9D3XjaOiP+?w9Mi zJ!Edj*AG0t9nnxr&d;IiHZ+6(kW>F)A}bUBJ|8Lmd_L0p^Z7{m$LAyEU!M<_(*EN! zlJ;MpkF@{#e5C!?=OgXEJ|AiS_4!Equg?cdY5(;ZN&BzQN7{dVKGOc{^O5#npO3Wv z`h2AQ*XM(!wEy~yr2W_DBkjLFA8G&f`AGY(&qvySeLm9u>+``<+JAjU(*Eo7k@jDo zkF@{#d~E3ZFGj=P0|CyTUjp82>ApY6xu#j0`S#8}=k|Pkv#;IvDqHElv)@Yp-SA$nzO8*zj7dcz$zq8*;|J^y2zl+*zOy=89g#A|X@BD8i|6gfw{C~N{_P^9(`(JFa z{V%lG{zEOc|M?c%U(sUwpKG!G2U~3avn{s&K#T3W{L{+(=JHP~?YsQbO8YMVw9>xI zKdrRy@=q)6yZqBi`!4^q(!R?-t+em*Pb=-a{L@PNF8{RB{{3RVmFG8Szm@*q*JA&j z{Z{(_$rk(X?6=bY8|8+<)%gpKl3zRft&C4+zm@#-x7dGYzm@*KxW)cE`>pi<87=nT z*>9!)TejGLXTO#HkBaeD=7))}-^%>s{BI@y7fU|ArsSNQH#ZUXTgkukzm@!t%FVs2 z@`RQAdLrz%l7HuaEBW75_--Zt6JfuV{5$_k;Xm}n=19DUzE2%#)^N4Eo^lW8?u+H= z{;r(++fDB8HMzg>w7WbVA60qYFG9bR`3J7&t?lz|-D`Kf=pL^9OXRt;Jl*|&cc1&Y z^4vq7=zpas^oyK-;C_X*eZH-G?XHL2qeq_k@w>6RzoEFdJe@x?Qu}fDQQX3IBJ8isAo+LQW48L)?-rIks@hMbmt@6< zbv?QJOcm+Vb?ZKxQiH{LtsXZH9d>3^+l&eF0^I_G9mt^)bZ~vMpP%4)VE>DLK8gKn zwSDH3`;W=)oLZx z#GlVcia(zZK1ZbW>+{1>$}c`6DZlu9r2OLZk@AbrM@&lj#b+qx7oU%mUwl4Ne)0K; zNh!bh45j?y^O5q4&qvBHJ|8hDqs6F&wv}8Xx zKed|Q)W1Jt%>OjMy0SURoBI5;n;%RE$8l&qL*H7mU5<|($*)c*xxboghq`=u>~8C%{@pU4)*<6xv0eC8 zr3=74w5hvJs1C2QgX@OsI;hYqj0b*L8>3xFzp51>yQmMfx8nb~?K;gTwhhO}%5DAl zSea|L&ceD^59jL9c3tiGR~To^?wn_?Ydiay_V|EZ__cJ4b#~mVR>cSU#rXVQ!xGws zG^$z=vWxmqdn>+gZXNBlWjH=6Tl(=)$+fH3*Jk;8ZCg(d*w{Gp?NFI3r|06Xsxh0Z z9`};%!mldbP-<0tfTuA(#(5Y3B0N;JS;#Kx1J)-DzI&^6T`k+{iW&XtF!rZ@t)9JA z7GEzPlh?JY_i9egF51@90|uUE=h~qzUtYESI%#-&d;Wo4_*KOK)!a+8bo){NunJN* z***Ge{}%rT{bGDp3uqV8@7IcuUDSu#Tk*TQ)@d&5T2Fj*QGDdut+TN1)tp@YY;C)) zcKj=hb9S!Xc&$ohvu$$dHU;8C?ZU66=upkIEIzbf>Ml2k`Y&TV^lP(_UDVgNZb$FV zt)per))ODoC_ZxS>h(4!S3g_Z*3$!qan8=QLtVbSDi=S)MdD8F!mnya-fE@NviQ(` zF+RW7uoUB=Uz>*PqCVWi`fFm>XGC9x{h;l?!qZB}$4V!;lbhyRO=P>K*6T#}3pI_t zABz11cHlSL~! zZ2rag;{Ag8!}`Iz#`eRa{3ZXuY*sRVMb`t*7w-=|-?91hy{lA`e?B8c`9o{YdziOI z^D6A3(&wEt;`#{b2Y(tZ%O0QA51xOXZ;l7{bE4*-{X(4a{9DJ( zdOQx)v;B7IG4CP&Cc7TT8~kOS%hm&5MN9UB<8V`1ADAcRkLS&*SN1w$zpQea-;62i zyjk_io?l*fq5RMD34b|GQ+!w%Nb#{gra0a>PB)ePpwK53XZ4TA8ImV^ewpn4 zf!DI<*=o-k4^};lr)bG}Ep+ZFY8U#gwr}OTY(49|l&xnSN2__?P}X;=d1%-CTH^rg zuxOd)H)CwF&#yHOHWodOOUzHB=fR@uBBYP^JGTocpuQ(kUk%i6tvK2<51i+U-hblH zSM%o`;XmBtuVKPJ)LTo;AM5jcTH}}Pgyh6u#ticu;*0Ti^T+;#`px7t7c zydtg}zz=`FAeK+ij!SEP;C3;Y`RS$xW#`ivUon1S`8NNxW;Yc6dy2U~%TXKY&NSX$ zlJ_BbUy}DDng5>S{#4Im;@@YaS^i^u`@OA`tn16F$McGIywC9ZLjGVqtG#t2D)tKg zaVz%2s%Q1rI)1C3)jzAAbsX0H)oRbG$MY4Et^S4D$8f8^?b5T3pW_VU=5^36y>{_u z?bph)b^VpiGv>4GvfX}`-GABktnt$>y|UxBXnd8;ciHyZH80kF%bvfo`70U^(C6`& zeSMbuGjz2s`Mw?B4=elnZKAKwT77-MaT7YvTlK8_q*agO3GMiNV_i>HdsaQfebLft zzg>FZna9Pvb6h}wvgoyoKWjXe%^&!0wrsawW%pmUy~!R|lWqPtHU7&UZ_)V-^$$B7 zzrayi^FP}`JI?>WVIO6y^+G&wzh&#SEB{;jwd!G>tR=?-^V;nD+hw2U`Tg$=?fn>@ zm&Cu%NUPru^Lrcr_qR5->)(xKy|gO-As%=gV*lfPr(JsR2mYdD|ExS&$6@WaU3$D< zg?K4j&&qSV`nAq)yT)PV1@jpz%N}pp@oeSUIu5IUG2T#b?RT>4S$S#Kd|3S}ThF@Q z%GR^;+^&Ahj%VwgX zy=K>qmDhH~o3-Dv=iO@0%AeJqRnOY5HIB;Gv&N-$yw*5qm!5STW$Rhvpk4iz9amO+ z*7$2zyjc4!d)}<}Qe0&b#P|8EaRt4y`L@QtRS$kPT3X}8>W@{=>aUf5Yrj@KtAAE| zRy}LK(6jPmoo8!aYnPsNyk+ZI`D<6dt%@(}xZ4#E)_%*L7ppxhe^z@|J!`+MikqVO z$vThi(zEhjww`q!+tqKY&-nYf z?02kv(Z82h^!oynEng>odpSwbNq+&fLlwRNA$z}w@VNH@OaoiE01OCv0p{yvi-5zi}}g(&DRgHd|&qW zA9=svxZrWe_7mQ}c>OlJKPG;C1`@wM9~*l7Vl=$&fOCH4@rLw(TT5&IR(q_+c@X2^ z@wH3OI{tR)S$VPg$MX}Dt#-@Si}}U8O!WR*_I|pl<@dy&AK^vs?!sb z{Poe=q)MgRXYQ-Bxt*?hGpKa>_t(*{svegPu4lhb^|^F#J^MxdSMwE|#~`ER^BM4> zWgRMNCfI(f{BZM;f1n@kzg>D(eyn==v07eR?OOFLedcv|AH#hGo}Whb&{xb}C@#3) zkREXKhm!kkm!37g;kUJ9em2zkvyK;f%xCQHukpO|dMbLqt>}Iqdq0NXUuyRLUD4lr z0(t|(iJkDORf1GEapY*_lUnX9BJ|HDtz=U5W zUVJ_vO%`6@Pth{v&5W_hGLLCK(tJ1uQXEW79Av!||Ci6he7(iz@7VQKv)5C&uEt1W zpC94tIgYp3^(LRo`Fa(8gv!L9&rIUa=Oe|R&&O82SV`;GCnV)RpO2!yH<9>D{N))) z=a)Pi<6o!qi_b|qzxaHl^NY_%I=}dQ@cT6z+Ww2t@O2)Wr@OW%e8Ww0eHao{!LQ zt>d%mh5BJU#Ye_StK*1yFDhH--KuBpe`ARc>;7QXD?2Y(=gq1&S>~7T*Yn@oC~JSP z&YM-wI=@yu>wJXt%AR-hlh${}M5Fn?Rr7-RL22#Bst3E)lGn|4+K_p(+GD*|+27FP zdqejh^UUMGd~^I* z{&+sD{DtgUdFFUxnf+qB&7MCnPV}4dSH=Y96}+H~tvj@f>4A6FLqA1J^vmtoKF1T< zu^z{nRWCFywzsM2h4|z7u<{bJXXTmWBqXzcY(M3nj5*8)^T_L}Y(1V2*yny(FBE6& zzg0%Rtj~UMJfR)yvAJ?ciOxUmx;|qbto&Q` zLh~M)7vSty+4IBiXTeYO-|q7&{D_s-`)^h~=DFEyT;+``<+JAjU(*Eo7G1>Ot*m)S&2^dA}`jM~q z`Tbk|d&aT-w^_dU`_lY-O+6Txmb;J~68X9TdJ}a$#q$>G->S#gS!l=OK|it5$`ATs zd)#kX{`FHwA0xv{Nxq%rkCJ>G4d8f^2S|Py$uB4Q1d_?!O4?t1M$-P`^U-X+^sSAT zQvCUxr1n`WuTOq| zm-8F%hs;aS^FwHS;3ZZ+(dXaE#t-5PeDU{%`2HY&Ut?3}Z&M$CT3=W>S;={Mvac_A z&v_U)?CUq#OoydGllAKQQV^L;$)Jim!QpP|H`&j-JM&}{s{I+_NFgU?6oeClhDms0-qIpM$WlKA!cN&B16M>;?Fe5CW4&qqv3`PXMCa=S`k>-hY~X|C!%Eh~1Bh zy&p)!ANT#hG=869au=dHOmpvaz3kFk0Tnf%E+U;6+QTeXAZ{x8O2|{k7^99S`)`e(duZ@DuHMynKGx z)bHPcC*~DA@q9DCXwQ1gdq|J_g?+Y%_KlW}`qL~AF@KB3chUQ&t+tQxS^0&&wJhpC z;s^HGFXoTm|3o`3*)HliPT60yV?FjOWDo68kCN>H-`Gm#lk){%|M2{Vcm_|&KA2d4 z*{V2X{&_tj|H3<-e?C95pFIB@AF=(P zzHTzUPVu|`SxNjPe)0?yUEe8w^6X8%*JYpQc)t1k$mdHw|MB@Q_WQqlKIFeA9b-I= z-)E@V^L(0rpU)KkJ|AiQ`+T%J|G^v1gNR$c&()|N?hC~1h4lD70{musW$U4zjkV^HaJ%hMCFA#E;KMiXWek$+o_H?#@&?~?pU zl7B<;f06tU$zLS-OC*1p=HOZSz@#E=VsQxyR?PmuhNB!8Ra#U$TC@()SAmE@;M9wvDS$(NJ-eUh&r`AU+nBKh4U zUrq8NlCL58FC;%j@?#|boaCR8{8f_wjpPxMFC_W@k$e%!pCb9cNnT6xA4&c+$!C%L z?<9YLaG4-^~&A{LVh!Tk^=jS124%{o~Wl!nSaj|_%`BLKECIv{#}Ca zr>|Xs*QX1f_X+r$1>dKR{&xjCB!{1>ulE%F19CX>_Zjt0R=tl%|M@c_@aGGjUr*>4r8W;1&_fwi)C%P4d~SACr)d3kQXZ<tH(S$UtG-N@oIhX zfRy#(9eOCS54ts<*Po>dF0Ol_ETuIr#of9O)8*hjC}T4$-4*T8UepIfZr~7KEFc$^McQ;W9QcaJC6tO z9|r9IR`9)Z_D|5)FWt=F2QUw33qC!k|1y1j@-!cZ&0D2DzrKJk6FhI{^=juyDNoYZ zt^nR4{pRx$@Es(H)wA>JE&Tj8TWx+{;s`m%LHjCxfZ%!i!0#5kTXkH4ejgQo_N;?{ zSk_J64)h-k;13awe!njL=JOu#YeYZq57rIJoJ+Nrm^Z$DgT3oSE5BZWzd`!X=TYD@ z1>ZT>3GhP&KfVtB1BtH#ayVlA&4N9<4t}O!JLGV@6!Uc-z){v!60p&FjBj@_kY9(u zzan@(zXRW0<|%(J0=}o|7wP^XEz67YY7c zr>KuSJ^)Zk;Pd5mKCXdZEO1kd+evuDH8wrI7c2r=`|7o`H1&( z;Jm-!oa6S3{CSn_Zs;;%$?awNbvHu?wn*|rJ`RDuV49yFfL|qeHAl*k`r2Xn{Ry~R z_xbz)J7}iZhqT z^Y;yaUlXu1B6vN29A3}P9)j;!$NxPA&)+XYzlRH+-&cVj5x|cWJijkM|0u!ts?)E- z>)C&PK;Pl@^p6!he~v-F4&SCuzsCja93Q|31g|$Phu8Dx!~lL$0DncmzQgO;f2H8{ z_;h$Z{rv^cUy~#DelO>me0&1`li-Kscmw`7!SmNIP?7Yx-bbh&d&$kB;LZYg%+eQb zkIv`IqWOJ5?YvL&PCgEh*HNNhl)zB}M|pz2I9~Y3pZ|crNbr1q0{-Fv-XFk^4&XP+ zc=GcM`=<)t3}4&nxMJhpYD<57h>y!9Z|3t3@cRPz{Q-P|45AlgO9?v;&*v$O`#&Up z@_FqfZTm|p^LzmR4dIBlrGn?@4fs`p=g$Ws)_uH5(NksK>h*iQ)bE*V34fgZ{c^Z0 z*V+SRuB!GD>j@>-WByQbeQcg_zvkD{aGzXb;6D=Vc{v>OaP>3%yafEcg6H?&T+{S2 zF|ffhfc1B;9y%fakmR>%azYNly8Pd#pFZCW9_{29S$jPC!mNbe+U>J!kKBZP@UPnb zZg*iO5A5-)W@Y-a9n>B(w#`aOOSMP;8}F-?$eHL@(sAwas5X>kTYI2C(&(oV{WfyBUMW?;5{FN1x2>Y+KB47PT25Q3{cE|GmWOM3oR+6*IZw+4S}xLZ ziI&T>d{E0rw0um6W$r{$?y&eL*%mW#ApqUACzAJp;@Eg#eJ2`!(}a@yCme=YaY z@^CGW)ACd;=V`e>%SBo)(Q=uV4{G^{mXB%qgqBZfIqhNXU(3C;JY37;v^-VId0H;e za*>uxv|Og;gIYeKOO6+op_}3-#Sda3Uvj*#4BZqzDSi+O`I6&>W$32(sUJVF_Xk7opMlp{ zeeC_^So{2M{GiW#8M7aIe?0d23;d2kzR&#YSX{;Y!|xyDZPt4o>!)5Dhw*w~8SRq& zjETe#BBDMYiJ!!e&%pX6ju)2EI^~~?iH((?P5u45O>O*TeSQkRUxhruW$g25vGW&x zUyJQRj-5Ya=hxWzF8`b9=rdo&&abh&89U#`_z8`#+4+sN&vW2j$HvL}kU5{S483GO zV>0_IdDFzKiAC*yo93c_P+-EZ@e)7vm@9 zU&y{SAIJC!?H8E!*!W}iL;k~l?7YzG`k4Q%s*lZItLwo(%2*sik4w%6EJMHD`LNyn zCw>tL&6Shwdyl+7<$oK!-bh&=zrR~g*I}$5yT0M;qoVq;e9iW^4LPnj>*M#1L(TT0 zirDoS+mBs;v3^neMfr*O6FYyz`iuD=+uvjH8mo_uFV=sv^)dcp_ZwpT#?C*n_Obfd z`6hP$h@CHE^`ZTmmSMV{S3*L3wR(R~_Ol6?X#QjCui5(8`}wi_)@*%_(}X=t>jCN7nY&>QM{lsmak&@Fm@h}*^lMxSlq|zccAgI81pZ--^SX< z#uuxP_22A%8k^r(eJI|*b8LQ^Z6DiTV*SV3H(MXu@0+cU@fY*I2NM-2o2`%aAIl%H z`WSz)`xUYFF@9s~Gj`sN<&PMDG5=!gH#YuQeJp>4`k(0cV?z5M!oJn@)6r3bWoVvT z?RU(6tHu?}+aVg6CzjDJ+0U2=@e`Z($zC6e%XYtixvBR*+2beqhfG<&Y?hzc`V83* zGj2V?cI^W4rLGEm0ezvTDV*-VVTn13;TV)kR_>DYNT zcHZar!+HF%_Oa`g7{9UkkF}5a7psrOcdUK0^|APj&3}x)*!5g2K4bN<{-<(4k-Qnn zEXML@EIwlQ`(yW`V)Gm8KgLgN{WrV5V(nw~vGK?1WBl&M6Han0zsK(P#O5c)e=Po* zZ6C`&vHMA}_ObOB+dpFCi_L$`|5*IR*6*$qFD%C1Ux$9^{I;po$KnV)aLMa~W#}jS z851FX+8uwbo}YG)FLwRbY<;ui3-uq%&+V>{o!?^nN4x!RSN~Iy7$aq~{>Au@&0nbh znE$P=XWC-xFSNd3CsrS`zoFN+I{zp8S)_&b|HMz?2e~L;a=fq%-3>i{+Wr30hMvD; z{%`2<(Q5x=`+vLRGxd*5*V>Z5UpkYzi_OD91@-rDv3^ni_buoTugj^_p2ec$Wq)G! zi|V)9pQ8Np{p?u0f!|pEx7vZdMoV5lu+#4TWBGlu@fVA8@XG5Cc&vT1_2>s>jK5aZ z7hS)t)}H}Fw2Z}l(fy*R{$%s#c?J0?s$X<|i`p-$U(_Ga)989B+F#M}#QZw|3R=eE ze{<4jk>9_K*_&+o{P~WU{}{hj5BiOkq5V1(f6VXHNXO0U$9Q1-N#CE44V@o;e?QId z@fs6QLJ zeo=nP)-QTqEvjEMJ`tXcuCJp06}?_4I-a7}tCLN?=y+SLpXL`Uq<&d6ep(&>@G`WX zyP=?EEWagvB8b)q(`tYC{lQp#wpzdF{xjM1 z_n`G2yB;ZeeaGMbiOpBh_fOe=%>P#F<9>YTeLbSP!v4hg=_UhZ>mO3kKE{h?F@M;8 zY`%)>7xkwopFFRz@$&bh%GNLHKgU~)|5oc4^?y^-XZ~aH(`tT-?q5akXBK_GyQn{t zO~2@Pi=N;1LSoi37C%MvXKz9KMfHpN19v`(7lAVNd7@Z7%x=9f`$Tugd7IUs4wbi6 zg{}1uOmv*D^=D?~xcc`HewOOLpYW;K40dmobueZ}4`%RVif%mP>bW0nH>S6FX181Y z?pB%W$K+!&{f_zMC-9pxyn8zNi~3u#`YHNF<1xD*%*Ht;UqtqoYQKvD_y_CbWA+}* z+IQ;$9EVRQe^q}>?~R#%9XC=xof;1pWOxVUuV*`LhmLp5&TJazR$2RTe4L^FvR{gi z**i$%gY|9>;OD8`W3sYCy+Iu6u-C{WLFvcPZGt@4;3DtBB*_O2!Q4xJb6f2=)l z?pN^+lyA%Y7`NWFe$1Zo+l_fjkNK{lRo@d|tFKX5I_`KJed#>eE# zJ8F(~@0|HJhToj6ud(r|JXZg;OuysOfWKNl&Mw-aesN}J9N*Bpf#!E+CUOqzaiJdVIxf!ix_8U++PMBS|Ag>v&ifdLwnKf# zJF|W|G+(3t?ohrWI~`YM?a?miPgj6f_@niR8(773+v?-pdai;0-7~UyfZU<}bo@`|PcUB22>7cw)(uM7XaBoNAM3wc z=c8kGBpz@M;`17K)q2Dg_us+i7PQmz3;f1<4f1hBU|n&ZhkeC6E)2{Q>fe>sckBMv z@sOTN-WT9s+hINOc#+>bu3vw@!8nEe>5=~5qJHwZlEx2yLw=6Mr{1s_izmo9XQ^zp z*YWN3&lmVc|J~?EZ!{u4gMLFFe#Yht`f5L9cMAH~c<8=GdA9P6_UI4(8QVw49m}JL zALyZf9Y<)~-Mv}7MdufKF}r-8L0l>x><8B+%GWr5`TPdEiX-2J+6C7w+II!k9qL2t zlIpRJf_|u-AP;J9%FYpg5N8^9q5crp9Y4vH=X9S8wI9n58h7LLaNTxD=4UX!hUQms-2WM8AN8Sg8r65}eTSeOy)FvXW1k*Z zABqRX(eGGZeK?SZ>AEa9KLNe5`Oy1UXpeH7-)g7(S}AR%(xN`ndi@-U+QE=pnB} z^n!jrp80`sqeQ+L=b!q;INF8q?hrp3XWg6EkALLDad!DScpu_(hfE&3-=gCjvqSac z{73!#fL+DALw2=(Tz(+C9WTk^wnOo8{-GbbJ_+jSd1zcc@AL3uL127}cf6I>6}9Vl z`}*t0t!ru@|Hhrtmt& zbEq{Np|iSYyS#8hp?Z7kGqe9dgXJRJFvk-7m++rTCbv^MU*~E*?Yk zrSHRZ%%ky3>AIKS@&d}-G2IQ<6$xW4Z+ zPM_~zz`nlkG)`adn~cNx{0BSyehhGqYr?UQpd8nqwnrQW>v#3f^C7))aYFu}zTz+>8D+FN|xicy}nSP~RW$ zQ|mi!qJ4whdhSL@RKv1?k^UzhgZrTMl?oIY%TR1 z+HtjxQ-3I-Yj>@Gj+WJ|#ODOMo~!sCTJEXkbS3ZmJ zUJLktf6wZWX9cZ2oPNEB%$sMgHjho%J1A$bUplO3&&{FpZ&*tAbdQjK2a7#t!#(@8 zn~)lh<`_^J;z_jUJ?JEFZP^o?pc+mJ1)4j;ht`76kQ)L$l2=;*u!{- zrQSW=!}VY9@xq+FVNs~(AM9D?qhIW~IdxBYUDqD?8QhsSH>@3y?X;q}`y z#h=)7b6bnQ68!r}-d+j*EzOTtyc8G5#ou(n9DlBESf1_?TEDk@_NGSd!BEKFNAu$? z!M~4r_L}$a4zcI*o6Dnau=4*n{)(*MkLT?TuisvcJ0&i}-!if1^vd$@&b+-6{9B$M zZwd2zmuIi}`Mo(_sP7y z68O8%v)4R-({lEzGS;c`oTBG(H@>3h@vfY`{(wD~FRa&tTjuNyN9`9y@krr~GTt3?_J$+&EaTlt?YT8l4cIF(-kzMj{(wD~@2&H@OU~YK#GYlm zd#XLhdA~ee-skhAtFxYmrswPpOS`H(>)ErOC-+u+j`MzbHtSz+&fc)ttID$(|MpXR zjw9z>f54uVzy0&}s$qLp{tn8Gw+#Pg|CZ|1Qq)*DrXz z@fPv#hMc|Oh&_vcH;O&ym-FA1&HDGjoW0?QJ&S+K#h&BG<*72(+g*8k)ojeo_`5f6ui89+pA>tT-~P*KzhydyD_8hm?eEKP}=WN!qSMyKm@Tkongk1S)v4{BU7rdT-Mfm$n&fc)t ztICu8E5hFcIeX4lJ^zaE_gS)6&p&6+%HM-xuV3_C8&}rzuLysi%h?+idsTTh!{3UW zJ!h+)f6jMn{C%G6Ih*XCvuEY+u$7gLVbOPf^~=-kA8fA(e~0Jn4M*(NCe1l34=pkw z_wNxod;NmfVy`OCdgHa`mm_oboUMBNxv^R2_b9SgZ@fk9J)i73A9=ja zo;6-}6MN1^zdqe~`FvVrK6Y1o&WC<^Hf!%WYR}mT+3S@$>v^)88}G2RTc3ZHcz$kf zyk*$iBRAfVJ&f1l-`(HI-EWt>V*N7adgm*5{bsSZTEx8x~7t*}GTlIiAb1_ertWFaEjpR>pWAlJIc0YWCzG=O@RDi$Cl2{+Fb= zTVu6#R)W1RtG%-P`-<9gF^zd?X1puKp7X8dpA33^{MD3dikLs=g#Y+@p1%_8J)GyS z1bg4e^H+kstB5}_DTw?pPsf+L|6C;hU8DZh?8raO+8a@OnBQjYU90wL@mGR>M~gk@ zTg^ZDXMO$+i=KPBM@>I_>HT|bp1%_8y)@5X3HFZ5^H+ksi&o~|KN5TETff7?lzX~| zsMdYV&)bv9sESs-{9-+yE>L^5{z~xg(!9MA{JT-?jqShcAD>ULeusq%_jHfic(Rw? zzaPxoQ~&DOv+}n@?77a|yrQgU&w8G`DQ~X?|3<}Lf96^#{@t9nSAu^Z5_`kqUs?R! zlDAiaf0tJ(9nQC^JS&^I6Oqt}{lj7MaM;wT5(M&p?YXXySN`M5oV}`4iOF&HoSCWO zd;a0DdXK4J&HP(hs}yU_jXM5Ko8~G+NeyW+&g9ikmuv5uoV}{_HY`u}&-qgGPf9#O z{#9hWZW9`=DayY>KJp*hy7`zkO_ZDwH59Tp#k1F6n~-MgZ6WTUTNgLAX_WbxDo^Lj z({kRJE-$V5U`fuN8!PPP&o4#n-7NN;jhdYj?0rb>)%Y#J-YsfxGx4#E@y=SgZa!R= z=@+w@Uwj_8S1{}K$H|_(YS5l_|9F+yb90f!XY>A@;@NB7zf;v-EnZ6C?=;U|^Zva- z?73Kx(33~={Jqh$*SvqT)m~Zid%9<@dH>E5dyc!>{#ycnXM6UV_wO9B=N3m<{+;XD zYu>-}#9qJfSJwQV@7c5aCoXu8%pVV`2~&1(SHJoYQv2oQW`ejU9xfg>lmCXLbWisP z*_)cTR}I_STr;y0csI}66Rm#H zW&fr-OrEZ8Sf1_?8t(%x9`#X`(#1L3d#=OeS$jnI`z+b3N~3!AHqWe8h9mYKsjTx) znoQ}hW6$xojXa0-DMfI+-}LQG?H674ubw^kd+DM&X&#~ZgoCkq=xsD*b)y+c{eg@v z!1~n_jSdGobnC=DV(}-}DV2YfBoNaJbd%ssjDcAv9COOdgR5trd%^h^U0l83^!f9v z7Yto=`uw?*j0YF{lgy<}%AHU?3E@)%?2H|Xs6Ld2ah@Ud$}|R4cKNT~!<~KWJ<5u! z4TXnB$2-}^7n;wmdXp^JmI1sdAC8AmY}f0;>4svyp1#v9qVLvCXzkRq@77ZheYeg+ zb6?MXX#LgGb(ovSBKF<ODepa{>(Qwkp4s`lmi6qgLyhYELj8bW_3XgcKdJ7C zXP$TV+>4H?o_ON1)q@W{aOQ!1)!u{77@B*=+2>z!@j>%1I^&>o&RKBo0T*0!{#kR+ zxVR=%4?B47oSBEtJ7dmaho3(0j6-J3JMxS(&Y078#_4@$%su#!BhEN@?%a7t%$;%Q zK9$Nvm(0KTjOv297tKHO{PU_a4?ME(z!}xvzP>p}&YgMi>2s?G&p7z-17`FcFtcx; z%JIh>b5ynW_*cAUpX$s*4-{Wq?O`)!&Xg9fnmeaDaQeksalp(&#P)h0?##Ve9{+g=u z!#&QB=akBhmHvJGey&Is&rL)2;WHt;{2>0k;U^VYVG#g0J|!^r2iS!A6EUU z>d%l1VP|LfMVXzCDE?l>m#V&-5BC_5#a^42=V$tu&<7M>srvt&saN{s!r1Ar?924s z{JF<>6n|3juVirLq}l~?SLIOh|4o8BJNF-%**Q%0kCqE%hd-&f{+Z#*=5k@|@a>Mu z^s|2}l^-eIulTuY=QOuCh38q+?^%M^`c?g7RsRXqzku}rs`zDuZzVTIoSn)GGEcs$ zcCJ+XQN?lp;g5nlf0mP-sdB@_*_r*q%+Bp<=fc_zw64ku(!Waex6}EZqxw&%{==mI zSH&MCe5+?<{Z?O`^*dkfyi;)J=kG}W2Gw7x`lG5p%`JG*?>ya)^IZgY_4vh zBdWhY>EELID^JMux2eT_rP5zB+f_M{^iNUz4TR5A{2apHs`zDuzgzKl6aEp!ZzcTG zir+){Hx&OO;j0z@4&lF5{AYy!UGd)$-t9gZAUyw#@ac+g_2ybbWw}y0Lh)S*f4SoO z6aGfUUqJW;il0dMm5RTC@Fj|$L-<{aUq<*B6@NG3-&6cn!v9V2dkFuF;$I}ZbK8u! z?-2fM#eYWlfr8iK_GMWdUMP9fJ#JV1-;w?UiqAO1=l`2(=g|{0J6mf!pIbXDbyY4P z{b9jfzmK1k>F=ugdv&|syDATm{*i(^{mLsd{pqUzU#kCKq`$@Xnf{Dfnf~^w{|>>O z{X^&Y{x4SjStn=u`g6vWnLA|q3rYW2#a9r1n&PVnKTGk|gug@Z8V@sOxQ;4E%f8|s z|FEO`x2v*-^eWeOj}ZR<6dxsg^JixMFDJZ5@fC#cr}!$u zU!?eI!cSIw4dHVXUrYFrHB4k}%h5yJOSe3bCR6kksGfZ{6%f4$b4-h`Bb`b5V3=+PJ;zNY*ulPd3`xPG{{MCZH^*iHR z+4?<7^Z7x~a^clg872K=6kksGX^O8P{A|Tn5&ka4R}=mL#n%vir{Ze~|AOM3L;k#c zPw^hYf2DXY;s338AK}k{6dxq~&x#KbzQuDg-WC%6Y{f?iKS=RW!jDmWIpL=%zJlL zguh<#5yH<`e3bAj6<<#HO@h09eE7_REAH`D-N&C4-0kBlNPn~EX80P~@y>Joc^Oi?hw#f3?#R4Uu=k&SDB^!HMH zknp1vA0qq}iZ3Mm&5Dl@zCiI&!mm?&IpH4`-1$H2;>>?sM{mBT&KK$LBDmA9oSW&N zq#uMCR{d3^f1~OzePyPaQmKEvIMp@1N`2zfkbnbtUOvt@$-E_Y~DLB^yg()!JYo% zCo=sPbU3|AGhIg&>}wCG{tD7x1^pc}{r}ml)~vGM{;uq*tRnpv3-0XS zKPA)u{m4*J-+=}hi3MBNq>&uwRpH9)BnFMv-$n5>i3cUFBKmk z{4a_R65dt&z(7}Ji16JMUr6{&#YYH#sp6xAzgF?(grBSU3c@cJ+>Lj;JF@X2U;SD2 zSCRe}hiCdv-jeAfA6_iD+ZR@o{)pmh2)|YFwS?cVc;_Ylyg#gX58C!O_zJ?8D!z*F2NYjT_$tNM z5dJg8*Ao7u;++e8{x|E(cE z&r!UO@L|Dg`Sz#T`o;eEE7cz${r^_|SwG11u|K}-Nd;SVc5K=^9K2MPb3 z;BMZx`$IO52kG_ED_-o}lJf@Xzgh5_{@*kGMN>2XzpMHSN&lCsKm4~$|3jI2<%E9s zLhh%L{+kpZC49c(%L%_m@fC#MqWCJp?^Ap=;a^vL4dFjhd@bR>RlM_U{&eN&gS3KjT@M z{(PO^(_WJKKSKIv3-0VM?aA~pzdum@QPN+d_;SMkruYiNw>u`Y|K#g3``CBp3-0(_ zMf%sM{?b!2ee65`srsu)|L>~be|V;k>#{c-o7rDO`WFc9#yjgo-~PX-{#w%iHS~|p z^s(=}^re~o&bRyV^IFAw2tQZxUcxU|ypQk?Dn3B?U5XD9{w2kS2>-s~3km-Z#YYJL ztKy@CZ+%=g-sOZpSMe2uAEx*!!e6HNYQo>B_!`15RD3PrS1aCmna}^tiuVwHuj0Lg ze^v25!hfjv0O7w;e30<}Q+$Z-p}y@XF0$oT0ad?&>R2;WEXLBe0C_z>YI zE54BMxr&bv{#M0D34f2`%L%_-aF%g#U};YYG3g;+^mG=j(qJ?;(8KmuLR>627P6eS{yO_yFN2 zC_YH|n-m`+e7@of3BN}15yEc~-0`{H-r4yCd~SI{=Km<^@2>cA!Vgw_1>wgjzKZbI zDZZNU^Aul0_!Ww;C47nEo$vDJ-I;y@da>;(dfaq4)sd|D*UI;oF>;@is*G z9)dfbXWy0aj5zMtbyyA&TG{7Z_D68?R~mlOUUimxF2uZpiCeCv}k|5p?KT*cQA zewgBG34fX5ox@u@gJX|3D&9l*g^KqQezoF#gx{?A0O9v4K1ldi6(1t}hl(#G{5Oh^ z5dMFPj}qSf3O7Xgz7OHgQ+x&CM=HLG@RJl@P59}GuOa*r#n%#kt>T@RZ#~AndvTlM zJ%oQs@m|8ep?DwRKUREz@ZT#wNcfajy58k_itwEjUr6{qijNTfLd8c3KUwkRgwIuc z1>tX1d==sEQG7Mww=2Ge@Xso~mhf*W-g$-3|IZcgA^cB*yZkWxmn=W*+Tr-BR9-vF z{VUf^q<^m9PJd}7J6GfDA3st3KGOe#>i4Vt+U**#{OXf4`vasuBzVpK+RUGyt3Qvb z{vhf9yW&HHuT^{@;aj~b>vx3ks^X)BAFB9r!Uq&zLHHXKUq$!@g1d3uzw5!yfy#qh z){4qcRev?<|55dacgplJFQ=a3+R67*NdGLw*Ao6t#XGO`Vsgo%z#8`u&1C{o$Ww`Y+oe)4xyk2T1?xiVqV0BgKaZ|E=N+34dDg z5yE$PP3Gq);d?8-obcx>zJl;qD!z*FGZbG<_@#=kA^dv9*Ao5_#XGO^=j$_y_YnR~ z#d`_=sp5Tv|55P)!aGjQ_!%VpnTih)zMtX?34gKTBZQx#_$c9TQG7Y!Z&!Q;;qOy? z72zLKd^O>pQ+y5K-&TAr;lEJ4^J<^}KP%ot_!g&Sy!8_PY{mNsKS*%5E@m8-t&5{| z9o?+@1Ehbi;)8^LRq-Lhf2j7WFVE~>vU#@dju_1RTuAySC_X~?n-m`K0x>i!Ck+zZq53=Q}?gwugm%!B>g_chX_AW@r8uXR(yo;ixnRwd_?i(gx{+8 z3c~MKd==pjE54fW)rzkn{CA44CA{+bjEBx^{Q25Z@gBl^74Ied1&a3(K1=ccPuIQ2 zNj3lR13yvOR%*0eHWee4?WQTEl`s-k!bq}+MmJkhQ&Jn1QDLRacGF5SrLvR^6^k&X zvRz~(S%fKJBaFUb5q{^K*X#TqKCj>Y=8wL<&tARG`+Vli>|D?0i4Udcix<)h#Ane9 z#bfj$@eTA6@p5{p_yKyEc$!`=UUMMUtwKDTUMb#zUL_u+XB3(1-=Cf>UO>+gpG?mc zFQ(^-ucYUTm(dHvchd{SQ?@&|ujCQjzV_F2*2S`}yWRQIeqTfKgXtyW6X>PlGwEgG z%jo6euh{P1pP#@yg}lG@-GO;3B;Sf&DV}S)(-S`nk9%+B&<&r;6uMp3;)3Pu2<8$%m^eXXy?ap?i zubcDFVLoG~dHt@SXN$kep725Rc*jqx!I&pU^11X}@xJst@i0AKe7x=M{P@6|^-67L zdzQ7A`2xv*OD`1vlU^iVZ-~=of6iIFCB0Pq0(zNvA9}g?9rOzEar8>@N9a}JOXwMo zo7dMmdbao$dXD&hdan5Q^gQu@==tIehGN|c#M{sd#e2|;#IK{5h!3Whicg@IiO;m% zIZlcf;(l^?4QD>fI?jB#It5s_qv9=WcW!r)cDNn6Kkn^l;}OVPbIkQ`XSc9I=E z%6wSz);*l31LpDa6}CI`OqTpn<|E9zcc*r;Vl?t4nz!AVC&j$|f85KJW4K+Om#{nU zuNKj*7w~g=%*n`qPfwkPIlZ3V5o~vZY&V~t79VB1Gf!+7UMD=j{xW*xcKCVNtaXGv z*>lb7{cq+|y#j9X9`+0vi~jIn%%7csqE~Ep)^nEhY-c`nC3?!)bJjTYL`S0MUiLg- zyVG+(dgd}8pMZQr_8ersL$Nvkuk=FkI`^XAH_yzspsy6~OiznnVY_=APQZTs%z0MO z6ZgYYyx#w1PtW=0cC*Iw`kIXVFSVTcEbA`Md42tL3jBH7o%IPx&s$!88hQ#jPs96= zk4iqrc4vP7Bgi*k{vqZ|B)^EhRs4CnwZPo3x9CCf59tNs-_U1>|3NPoKWzf`tL{Q` zyJyq=;@xa__Sg3u_IDoFb3Q%rGW^_{POoJhV^3ImYEMK@d>!&rd3zsXyK}w7B|nk* z@J8hOF~5uX!;=4s`NV6;f57YIfTnO`gU2kFPf7tmXknA?5Mc6WXFxsggp2K+k4zt}keiD+OME5;uZg)0)p!jlnTzn(F;S#fF2ferW7xeMsztGFXYfZ-d zb)Pc(o6>uVceLF-Zad=sd=%GVI`a!9znFQeGxF~-|0DBlpYJz3WZ4({{ISoQ+Z{#^i%+7j6`xJ-`GVQAoW4(d zBi+Bo%5dG^{~ z!)j(l$Gzl=pMK86@R;}ndP4lq8P0jRn^~zs^hDXS>tT3!lIdqW!o2t!MRlx`PO=|w zU)ITOxRyQHGvN{OagW0j;(KPneZ9<{9&_Mf@g;NNaq*+YaO-ljCpaG-5-(W*kBJ{& z2v3XmeF7frZT6Qfh8K%xKM7BXKe7ZKxWerD{wa7=eB{&cr1$#Rt6vkMu)-HjlTr z&nMgAaq+TpxG&$# zPu~fTh!5BePl_*iA0D{H?0It!yjXl@5}p>nX)ioLU z>pOU0klC~82)tN4`~y5K-ug#)C~Wrp^bT9v+H*&wu=v zJ>r=)GTooE!C_|pEc+K8I6r^m;yq7>`-hwP>ubV`#c!(xx9&3Yx7CJ6#P2x;o)Vv% z0S^_JJ+IY)C&WL_ga>dU7t33RT6N(u@fxSWeIw2Ota|XMc=!77wD?Uvc=&F!=dsh_ zN%2=2z=NaA{8w4JSJXsCfqmH%(wBwqvBo9hNs1^X$cRHGkeCI15b)S)e0WG*UUfP z8Xgz_unpWl-pv1fF1%R0V_Ud&pPA2V2akvkX%A0{kL~~uO)z_=bc83wm!1a?Of>T^ zcY?>nlL5G|(99p{43CO`+y$N%|M7fyc#_$3N;h~?y!{36;QeNPP@X!>qr_rVGg!t7#cwnlTzxgtFO#HrHaNmPw ze%0mhsQ7EW;c4-Yu7HQ5X3sBI!js~s=fQ&ynfddthR4OP?*sQwGxH;^fftKE+!t<5 zH}fxE3y+BJx(=Qa|KWOgXolHy@(u8Wc&C2wz{6(#iW}iE@j?CJzDLY_%bVa)@tyj-UAQLHS?Xuz~kc6BXEDQncqJaUM$|@Ubux5#QopLAxp=@BjSJG2TzG-O@xQ$ zo7*icgeS!3O@ap&nE4a;!(-xkli|LFX8x%u@TmBasqnOT_b5EP$n1IKA$U^!=V|cZ z6J~zs40v3;;$gUdv6;W}QFyWVD@Aat#LTyv36F?B@i;ssUSl>q^rYD{XbwCf{^neG zV2PP;JP#fdpEMutd&c+wzjP5iEgpLU9$sqp{JI#P6uPJ> z;QnQ1e!$c4V)0j&!L4V^e8U(#B0hdOJSDzo1w0fpd)lvrC&VYLf(MqH`K_zrG4cAP zaNi0ufBWdN|471P;^Dn;U);>U`w=`U-u+{ET71oZ zc=%c7|IcUexcKM;aQ}KU|H&8dV)3uPgj*ZT{IRd#5%C%a;VE(7 zA$Vw`*>mRC@PzoN!|=eXW`5H*@R<1N-@$#anfalW@TmB^N8oAkmOsG5WoFO#qwu8o zjvwK{*UkK)pWt!vzkY`M-!StHe}NZ^cQ^*O-Zb-z{|AqV*ZdWp5+C;)JhaK|`SEvn zLVV~S@W5MU{=GlpG4aMH;J&xb{P4fwQSll7z|-Q(|AmL&F?%v<6 zyssuaEwWN;_~{MczHMfHR2Doc{!v4CTKvMs@bGrC=gB7Ur1*(!c1SJoKU2GwninLVRuycwn!Y@6Zz-6W@9<-1m{0 zzx`5pRJ<$*Pm8zj1rP5td*)saPm2GqH$3>UnZMymcwBt-RdD})GyhK>yjZ+xAGr02 znZMu~ctm_zUwBHq)^+euh1pYZJv<@4F9Z*KYUYFe;4$&|jd0&*X8x?3;8F3J1K?@# ze{P0{KR0{E-2zXFAGj4BJYeSg4ur?WH{A~Re_`fZ4}uqqPY%PaFU|acJK+)Woh+ zQoLRS9{k$Oj~xq-i+?l@?muki`;Lbfi+_0^-1^4M51I&%h<{ZGPl*Tbhljp3dv16D zo)8~486Nn~%ukvEkBRTMf1$YZ^UGIh<}ZlCqvDr61W$`!KMfu}V)ooV9i9}wdj>rC zy_qk37#=@4v&bRIvbv%d+)De+d%!>zPA|MVB&e(`;4;6d@+7vW*?Y3txo@sD4E$HdQj8J-Zo z_Z4_b{Mq$z>lbtW{TtwZ@!GG#gW?yy1`mr*DT7DFC%+DliBEk4o)F*hCOjpc^%mSZ zX3igZ8}1k1`VKrO-gGlOEPnSEcvSqYci}Pd#@pZt@nPHHDeQ#Xrx1N5wyE3y+EKXa`S-x99**iQm%^ zZvAb}|IT@Ezxde!cu;&|XLwlroi6aGc%82BnE1`z;0f{PFMy}SfA0>r{xRpjpyh~qrO8o9?;g*H(v3k!RH(dw!(+BeV0$Cw=RQ$Rd*e|}k zA3RtC{a(+fH^O7$75(AXNoKy$0C-sZ&YR&0@muoY{*%p~b+^Ey;zw?Ur^K%t2oKgY zdrEJI$HZ$4f?KuBe4j8pEWYSYctZTpV7R}w*>nC-cvQUeFnCIQ-f(#E6tm~^yWlbL zzzDdNVdguJgoni+x*MJle{~exU&rh@Wi&i0K4c6$C0-tZ2Q$r{Q^&z$;zRF+Tc?`& zE#u)~@%j_s3GoRN;r_a2&qsyusCe`H;VJP&55R+`nLYoT43CMAnhLk-nfWyj!o%WK zQFubU`!u+}zS%QxIy@@=#SC~#yyGMApwH}?^(Z_h{zDPmI^E1)JQE%kU;a2eA^!U; zxW9qfbK4wvRQ&n5@RYbU4<5`id-}|W$Ha>lz^#U6e(OSbSiEWxJR#n5G2GwC?76fA z9u;5wBs?Yl)e?BHvDwpUDLf`V`DwV-#LSOb1`mtB^$a{Ao`}Ky*=EmKE8tP_k8Re%=~LF!^7f#zXDH)U%dhDKhx~#xe*=}zyDQuN_@&|@Zecy&-yZW zO#JWH;g;Xb-|!|pEZ%z)JVEy!Kiu;cJSD#6ZT6pyelOoP0r!hf+YAqiAK3yAi}%_J zkBSf329Jqv*bYyK|M(s}B_7%Vw_2L>KeH3=7q@o9gW?yx4-bn^*#nP?FZ}=>6aO&@ zPl)I3g{Q=)d<3`7G3S47AKWj#{bP7g{Ez+cu=*$PsQ8Hrcuc&*XYhph(9hv1@z)Q) ztybpz=X?qGi_iQD9u)sN1rLk&IRuZ2KlL>{CVu=dJR#oeTX;%*+;?!RwK@MAm2kg! zo$uj6@sU5k!{V!s!lUAqKf+_;jemwG#P3SOQ{roWfm?0N`M){__luu)93B+E{#STd z{Gs3AQSmo_hsVUv{R5s5zvWMOO8nWs;MTe3{2!fw`^B670}qN{{VzN$KHEACuXoYg z@H`A3o(zxYV7s0_QyZRY3!lU1S?8YukL-fKM6X?!{vytw^Zv>Bi|x(e!I$AjPJ&;1 z4m`9PJukE8oK|o@&j+=FK8K!4AU~Aevo(7*o8G()JR$xwJ+Q^hKYuRrG4bI!aNoOT zzI9u8RQywVT6}yv5X*HuQ@I zI{7Rs`Oaf}V!lZg4RA-@gv)!_xs;)9GKn25-vz zcKQTf@7{4(X9#)vn7@qM^^Ug)J^7otU+d{9dMUU28@=dvGk@V-n7>sD^LXnpnZAzUT?ydBlzJU`P9o{Q_NCB4fitk2=Gn9#eu+(-Y3_j^s4FQae& z8b`S2f6=?~c=q=9l6%nq1@q0>^APCd+Xi##T(hb2i@`D1hZ$e z>zP*N7+mju?(d-coqU#6#r5&L!2^!l_hS(=zuxsMEBjs}pEDi( zMbiJi>-KqNB|mG1lW%5)WzH@SqrXb>`{~&=&2=t*1lui@?Y4guJ-L$q-1TNwLbf}j z2>E=;w|@*?DDM285@&vYp}EeF&vZP~D%W`)M^B0Lq+GYpzb8G@XQ8K3dRojzPnq=W zcHKTc$C}6IggMApNWR-#^yf%^zw7q#FZo%;$mdDE%{=sH*D|k{k6q8S3MBuaeO_$$ zahl{WvCmuWd=6Hh7a#ur_&oc3(ADKT+vi!X&JX^7e6D@oWGAoBm!0z_SLbc*^A0;6 zlIPH0kVa{K(k)#X!k-R}MN`GTw4u5-R%$MyOCD!TUcUW&XvPydjv>wMeO$gBTM z*PhTaifbbG+I2Gxy_m z>OBvA|6$9jY5npq@Am)i|NL&dbAHYfYrUWN_^UdP!0WzfdNX=+@s9Kk;+N8Uir-+n zbAHaieO=rQ4(8*BznSkV`TCC{ADdw2->}`8KP>s(%=-$F-^czDMd(RB2;b~(-Lg`) zJ3Zs2=NR+pNyy*G{M5&g-yr#7+nxOi-H*KY`xIKugh%P4*ps5C>Br~`A4h*e`k%Ai z=}$j^elI_G7V;^{-)Fm-ScO|!&BhyVPIEuuwO8A^K|d|TD`gOz*OYD_gOxq zhs4(vBOjp;;C^+P2lqXMo@eOAwma)@tuv3eXPHm3$2)-Q&quzw;wqAhkMkJqWyR+TUG;H@?=2tSmQ1Y)apJaX-^XD!^e_ZlC zYG3@Q_rGLbFXzxl ziC;k9Cw?`(XWZ-=NG}o}{&$57caHlS+~UV*xxUm-LWq>Eq4C2Z|{;X zu-!d=UO@gz-f!$@eum_aFrQvy=5yTx#{PX|lE21wr$6|jnP1BMTFJk}eDONumvEkc znNLW*!IS6@#LfQUw!7D_v7eHr;XoS1zXyTtjkj+K`D4BMUgQ_P2)n0?8A%K6hi zZ}uzZ^>VlEPCoF8**|nC@_xxrwB5-UGw=2HeH!^($q%yKorihv_xN;PhI~l!y=`~r zS&w$)GB!NkcBd!f0X)v}gRKgBrS$h$g??*;Ip?*uJN>CW=)ax)i*0xMi=_W2dV%=m ztI?k;{R8Nu#7EG}#3$SC%oF?!^USdi0q2sW`}4cH|NmrOzh^wh{9Wg}{^&{W|5y{~ zp<(c^ng7ss=lV*^b`LY3Jc8}+#{XCsmZIMmz;-*L-WqAUvpzYp4x8wCQ_Sn7;Ij*m@dFcPyc4y8~ z=^wO?F7qepd2+q9w3pqPKN-Y4HF=!eW4n8t%Q|nT=g4+1j3Zwz+kKH+%ypY>yR%>6tys4;+^=t#&)H<=tLQ=TQ`e(^y!e^)xOivV z-Rnix`B{3oc#{q2&v?t6ryaeo_{H><;vw6e?N&>UffbC1b{nN7Ev)#R)l>X0b zch@Z!J!5O*AGCUdeii)Yn(%S9J3ZO&nEU%My}x*g?e6VS*6oxx;ick*wmb7A?#Fg3 zv03X^+nw!}Nq@#B^ps1_MBAPG0m;v#SBXDOZt%Xh@on_+;-A{?tbd5>A9cpC zFC*S^{;XpymHZTX-Oc89=h6M*tLVAnuiNh4j$|Dgy$#QK&^-R{rDurmwcT0&_ybt~ zA1MlooJ)Qo^R2d;bC%M3if^*r zS^pp(pY(G!XJ33<;4%7RU~42j&>7d)7(U*3#di02lm6|tJ9B14&EuijyU6dBd?$LV zZRY%!(}UtS(+7&*O)nIGkRB6XKra`6j$SGLCOxp-obv;EZ}G2fch(_C)*-kR>#$Pt z{pn@m1@yG|WO~kf<~+spp5iNQcdz&Ra6O(~!L;Ix+jQ-gf7BD3#l9#twM7_z-%f_*#0N99MtQ z3&i{EM1PU^ZQk!UDZ$VEi+MaewvWFLVg&rMnwbAz@Ar@J@lS&c_zx-M10R|_&;J4s z&4u?k3HclOdo+C6IIg_y4*3oF;(2C1-4^G~OASYUTW$25+8*u;n?9sBJb4ZLY3|o2 zdGP31_{Njb^V`+%$N>0@%oktJp3(4?oPTWyp12kjAA7Ea_hEk5PUd4=AFf;c z6L@L^{0Qf%&+|k25^!(*2l4!ni8oE()&}4EPJIlYR}1@fzIWcXFX4}Ho)_98ANc~l z1aWIu0Pgz<{x0{cZ5Mc`%IukSKHU1&!SiB;=-!;oc;2dbQ{?T_pSqX(?nF77UNh)d0v883i)s8*YNxU(a+%*(PPKalc2BTJU{b% z0;%K3H{tr6&+`VP{)F47k9IGUdENl+KX4j8FRk9GK0Hzn>)_4VHmmx4K|^>b2l-b{ z!FF@`eaztAE-swSH%p z+V8u#J;^99x|z6i(v zFdqM{zvMiRn)AH(6?!V9XWT(vFN@Jrz@EqC5Sny{5NFBcJ-n z^xuAm$M|y`t8H1E{^C6KaX;p*XO|OLpS(xR>t*lXSf46chwlHPC+RbLUZf|o;NJeW zvFhRW*vQO3Lyt8!{e>FH`}uRe}4yE6iKj*e`FM-*b%r$5s={Vd!sc|Mh1xTn6`jK8(4Ew0-RNAx^92|oO!Qj9le0=?e8)6==WbPxB&h0Uc!-f0oUh#x_+PK zZF-8|zwowuQg^I#DYqM8&z1D-X4o(9c%JEcrgdZ=gb(YiJ@n^zJn+Y_)gTvho_iSA zyXOPwck}blo-d&f;OEKfaGo#e@AG>-d>CuByb%3|_`Mi!&f)Ybe!d-Bx2zXj&$4p3 zUkTo>f1+15$NqZj-=zooAO083r*fVN^uhd|R1^9euG{@B(BrN1Kg{dr^Lt%{{$lof zJ&(`_aUHzd%T9WeveVrydXLBI^+b<;uD%~#KUe<*T|Za<8C^eDf9A#L*U!}trt9bG zSG#V1?}_UW;yQoNyngTCyi3sE{#vZFcfF6J&*c3^XRhy54fl@!Z`pIoIEZ&Y+^!e;Tgd(MXnKUVM=$>heIviu z;9W1j(PP|S&wE_%^xNO};XK})Q|a-Rm@~+A*y4JowU+lA7t(9@#+>@Ssy=l6p2Zy3 z?eD3v-#gy+(t~__>#a}YE6_idx37BK?yaud-)mq#LSN>({di9vpI>;T(_??`LY~*$ zPtTLb&&{sFcCD%Ago@-E4XMcFDDlXIg&QuTNaJf4)op;p?#7O4)AUdh`UPr^0o6 z9i-=p5auZp?|K8gLi{_|?dMbSxO8zp&ai5k0(#v1@}D)U&6NB>s-<;V0O*KHO3j*p!GsAC1B zXRPf`Pvi~sJj(o@eQ@hdcsF|7UJ!S`=>O82?|1&Aj+H0o8FAuh1jn+vsb>E9fclALtpo&H4Ya-C5^^yubY9=a|PY`L(t? zdEeZ)6R^VWpO$sy0UQtME;z!g_&|K7?aqGnm7b@){Kd$(=j&kKGhZ(Gzv*dl-xug_ z^}e}Z=g|9$UqGKBel>lA_(1w$@iFv<_UmE)y-cSE#TU~H#MjV^#ow{rxqYR7$NJ3X zM(Tfw{aq{hbLi#b-EDVzd?(Oz4tvJXgY??;08f&2L{mjbGb(=c%+}{J9FUaTTJ)o!{gVP{s4ckqW>87 zt1DkO{%Hg9*6;A;oM#AsuVVN&_!3?@7xMQfMrxqndtYqL8|X<|a4+9!D?C;Q?rnGF zHh8oi+}mz5{$9e=X=cy%eVj8J?rpb+_xt;rnE7k@`zZp~!lS%?oAdWO#IJ!*q5sMA z?Z;1Ge-CqiZ{~UR18KPTzSs*1ye}4^uVK##o^L<)H}b7{J>J0c>TA!6t>{UgjCsE0 zcCY36^L3uJ<;ZJK4W2(geF}QK_v!L^e)~W}xHr#BA6DOU63=h1^Zd>8*hkMm&kx+M zx;&p-v=aOKFxO!Q&yyD7?W-yGt1-_r7HEYYFTa524bz@qcpk6_Z@=Byb1Bb@mEiui zp?BeVsETvY@8v(?`KIFhIpX=%JbzS({b#bLEzbuPV}En{^1t~$7yG?@V+*e*YtIJz zdoRxWFQGp%&ql7#=r{N}b|zj)yOZlV@+Lgax29k{y~pPxZidIA@E!cQc0)cqGTqFd zIS?M2WBRN+@cg2P&o8pMUwdqK-&dN4{5oD?JBD(*YuLm4jZcTcgK>Cs-q9D{Mc)ix z(+nFZE`W!pVjW)R{yshe9y$iUnLcnNJbeH?gSc*k?}q!IM*acjuNejR{RaPp`Gfbs zQ(vLy9{SCroprE3f6Mp#!d!0`#CCv?#4`G%f2WcqF6kPjR-eJ?%s zjp=>v<^127{=o#!UlaQ^obz8l5%ZTmWik@}69hIzx zC+~t!rH_9B9=aP|i}wRpzXbPU#H&>|CsA`!5i>c3_hGaXTJ##WMLh;vgbX|ry%b=9)4^S@(KEtob&p( z;6C1udA`GT=XJBdML6EP`_)~yAe7;AIz6Q5nE^{xBf6ROt{1Ef=_j9{%!JE+hC2G6-c;*M>y~h=apWvaN;lHqFaT*@~6+VFLbJM@vZWTPq^~pWCJ|5Tc zd9MBIklf4FHS4?g0~IpQY}=iAqIGcpvyc6~YQdAI!JlUT33{YH+GXD#EZe)Lbdbd;2zl84-)uT_MzbWtUzeRtS z=i|y^zD8ZA$9|uM+fC7{>Y=}_yg${mKHSI8C$wTdO4rX8iO(f3vR()E4S zV!FPsx{t2!t7e~$etlncAYI>AjnVae)x&gsUp1$J({KM=>tbGyqg>ClCdqj_In&H9T7o_G_N!|Xt}}1%UVkC|DdxS;S8Q@U%Sy7}TTd$+>rk1C`Mq`M z?Rusa;{1&`XAymc%(I)`jh`#WzZv4f5UAMaTF`IqmToLy7cjWcnj`UgLm(tgY-#|}_ z522^U@1y&Y=Ihdr(z}X3N$)SdhCW{WE&4+759k}j578^cf2CK6XQZ%h%|A5fZ$|Ga zeja_G_+|9T;{EAM#qXkT62G6G5}!@C?9c7~_Y$MG5?@abi*L8xec!Mh9xrWX*~JH) z|FFM*D)|t7xA+j-ou1+|(KCvVKR=;cE#cntrb&m8w;qIhpWA$$?r#l0r3MC?`!(`` zHt>PooQE-ITILDa?#{zJ9)()gFZ3kcdwun}Z;(&Z?YFJn%k|&FljmZ)-uv2L(*rs1 zdzgRiJLF?@?|tWnN1T9to-vv8T-%*FLtKCF`N(p5q&@oGx7+N7y5BS30nWGeteNyM z{a(&f>j!K%=Ognt$+q3uZi@N+%oj7?Tk_A+3&mfh7m4qnmxv#rmx}*PFB3oMDCRF0 zZ$z&U&!Ja}Uqr7GzmA?^f6o2Cmpkd%;^XN#;*ZjE#h1|Y#9yT6izny>;vdlq#lNK& ziT^<_5wH6r*0WUnEP9!E7kat)74!=6e0rt$-SjH)sq_r{`vm{J%%f+EucYUQzedj$ z-$~CC|AL+`o~9RwpZpWntx&u%y-2(*y+phxy;S^qdYSlOdb#+0^a}AJdZqYN^eXXn z^o;$d{df7T&Gc;Xee@jh@94SWf70{BPx~3`nJ@0A7l@xvFBHF$UL<}Cy+nKzy;S@` zdYSlqdb#*2dWCoyy;6KPy-GYq&-lb#|Ks#*@r*RqEl0dLJy$$H&lB%W&lk_97l@Cd z7m7#eMdAzTCE}&@Qt?gnGVvt6T>LP-LcEGzDPH#%tXq}1pPo@+u76j0ws;;rM|>bX zS3E+`6Q4oP7cZd~h_9s=iYMqr;``_&;+6DL@e}kiao;hlTe)~EdWCo{y;8g{y-GYx z&-m0_|MB!}@gjPT_)>bVc$}UmzLlOYUO_JqKT0nYxBiFqDH3l;FA>k7mx}kKmx+hy z<>Eu>72<{TO7U6rD)AUS<1=&pH_)@i%jr4d2k5!tX?mV`&Er_NeDQ30fp`acp?Hv9 zB;KE1B3?i*6`xEm6ECKhi?5_th?mhT#dp)I#8dQ)&&~BePR|z4_!aAxBi@{zD;}Wd ziT9@Gi|5k|#7EH!#iR5h@rCpf@ltxJ_$GRpc#>W&ewbb%UPZ4IulpO;txDWa&p2SN ze^+|8cpg1Rd>}nnJVMVCpFz(TFQFHRuca4?C+J1u`{*U&mGn~a6ZA51-|twra`9I5 z3h`WerFdU@m3Ww*VSjJZhDn?ik@MA5B|TG z^o*3b{$1(W;(7EO@qzSQ@d!OndIaA72>({O7Xt*D)BHq!#>}`e=p}T=6(PPkbvq zU%Y}|AbylyC~p0Y^(hi>NG}o3p_hvHq?d_@=;h)==@sII^h)tr^eXWfJ;Oe)#(ysx z=-J}s^c?X6^jz^YJx{#mKUlYX@oaj5cn5l+c#vKs-k)9~UO+DupG+?kFQ%7^ucTLq zm(eT5chjrHQ}m3l&GkP{&lb=47weWI-khE*9-!xm_onBI=hF+sN6`z#qx2&2h4d2f zQhKTQCVH88l3p%;m|h`XMXwaEYky11dHXJy$$J&l8_P z&lfMD7l^N=7m6q7MdJJDCE}IzQt=b?GI3uGtXsKwD|&@^F1=E`FTF}UOwahnT>tU( zZ1Ey`j`&h~u6UfDC%%=QFJ3_}5I;&U6t~j?^p8Wwmbd7d(8YJ8JH&_`6aeH`PgXW!+bxzdmZ-7gMW$LvL3eG zxqsUyJx?-kjYED`P5grkGm&rpoq4@qYrC`E;t9y#!Tu{wMZQ4tx7hCF)69pMKd&zG zQOWnBmxvFr-QC}b*sj;p{xtN&C4VWsT>M7cot|JJdc4nDURMtuQm>Ex!_qUDo>6J8 z&jj0@{`ge%_vQY^neQt3t@Ih<74%Z^qx9Y4mJf5L#T(Ka9x><4q34SCqz@Di(WBx+ z>80X@^xfjK=xOm7z2W!foEzx5;^p*#;s@wa@icvzJdX9LI z9un_QFBC7JFBP9mPly-OeMilCR?>%xm)Y)~e|XkQ?hzQ~aX8BUAiCpu;{GfgKeME# zE4@TKkA6aYAU*J-IcJ34S9}J2p?C>BF20stC7z%+{K?$zK6*&Jl0HiO1bv~nuOZf_ zRJ;}agm^C9_p>=qUwSL?Fukw%c=`o-O|F~;;5JvP?#E=`b+jy8Q8-7h`2 z+aIiT=CP#bS9)+1dM@Jk6drEM<6rjcN%~6h7wI*BG1q6a?ap>nqfL*i+T}CrhjMo0nDZo1dxP&s+|V zy^HmaaQ$bjfLrgG{@t^1|0%eB?`8hdRqU?|f0RCdHT!*L{>XFiU_;X{dme6On|@*q z+}FbF|0)45eg<=T-`{DvmA=CC|81kMGX4Gc=%uDVy94f@Z~C}h@W3Xx_kE&s--ky| z!kpgcKR<4Q^A)7J!M*d8F6_ed7)(abDZE{;dxqyjcp2V^UVk|}QVyTUb-rx{JX8h$ z1UD~h!s>_Qyd=R`nTXb&$P$)^nKGXXBPdJ4)D~YaPM=cz0RxNmv*Y&s{+;g zRb8t0;`6Kb16`~44i{AKle<^%`*N%IK#%Hu_C?kE(Vo?N|4XX(otIYc?Jld{r}Tnb zTg>a_)61*(&R10LQ?G>kGI9IzuHWrfRiAHgb@e`|PxXH3b=CJTx*i_japiq)x^+Kz zn#Yy*3z_?zcP)_q__gl&>>nJ_`5qxShoN z;Sojf=r-g%-}@N-1NfEf>G(MNkHCA-XU>Ahelq>L+3>(|_;#*Ca4!81_@A6-K`}gd z0^XAShvvcKC*$_AllO<&Pr{?M;7i$4u!Q}*eZ9i%Uj7W+s&D2mT?vmhF#YIic(5`2 zZT9bb10Fg9?)49N8=m|K^N;788{Vnj8*Z-N$8V|L_q_{`SlF)naeaFm*B*d}_F=nM za?VCy(SJ1kz7#xl%=C{B!mZy;@BB49@E6>D`N-bxBZuMP8kpx0_xICp;L)1!`{;dp z_`b9D{CYdTH{Bic{M;2q zSJ>aHb-({L5dCMe{~$doKIJszEqY7ld)VK@b$SBgr?rKL-avnf`*le>c%%`0BYV2H zXHR3(BOT#s`b-|r{m)~6TjbrhUF@z3+nw*bmB{zqvO6IkZHjz3=eab%o@Vep^g*5R zeY)o#ZQxGWo^!@*clKA;`Ns3%Rt|d3WB#PB@Brt`ruXUwPjp1y^T8LuQ{uC_v;RCZ z|5+~FFP_r_9u%K&5j-ruwI@6(Uh@)oOgwlgJRv?c2v3P8E`wX0%=wS?g8Rk&z2QOe zK3BlQ;?XPNQSnVz!DHel^56;aOZvc5;xn#+TLE+ay?x<+asPGjp!n$P;bHMjA$U~0 zZa;WTeBh1ng!tP2@RayJH^HsW=KP_X;ePRz`S754)h+O_c;DOLQSlW6;W6>5+u;fE z&>(n9yfh5Ax|s7@gW-PhTZh1d;;#;chs7HVheyT7-vy6}?=OHS#Cwc{r^MrT!>#kp z`P4-4LmGNR-s=r`N<8u=+`7n|f7vFuUwrpl@SymKx8Y&&Kmr~WzjZS_CO%^e zJR!dCU3f~o%{I8z)11F>JKQh6`#pG2{CGJ$EZ%%4JSu+WE_h6Q+-`V6JpMjBC7#{` zw=Op4?~;W3#V33S4~oCK7akTr@ew>K-s@v{OuT46JRzR^1fCMl{uFLqV$L7_4DJ^% z{Tv!! zD&bM_H;%w#;?q8Xlyd&F6hz&?Dlv{(^i={0KcM zUU-c2T!wkP{!{)34~RcO4~w699Qk7LmGp#o`(Keyi*KO&dztfe`wjV!_y&4Zyz}qK z$Hh0$Q{p|UkoR3~Zg&ekD1OZ!$VbHY(_`Yp{zN`0ew=RgHn%(dFXRK_4Nkzr;w$LI z;$8kmJ|Vt^o)*9HALRX4nDZQ_hr}oRi+of(!}7VWZ^Xry&{N_aYas8t(%f!>9u)6? z67mu8N_tFu^2x|2#ZRvZx2`g``y4$WesL}2!{Ynt#o}XXBcBkja|%2yzLxIKGv~QJ z1No5netJ~=jylN4#lNMe#7Ac$@4MRE?(g)V__R}zkBFaE7akLTlAaWAeH!vsA9K4e z(*xp{)I&ZjzKdQgo?jpNg!nh~wD=ew^8RbgdD8Tdc%glMK<9P5sQ4)j;BoOM=qd4f zS;+hPn%iAS4~n;Fhd`SE#Jt{u_4CLeD|Ikz74>d#HcfGmYTFv1>@x}Crc)J$J$HZTv zC&jy+iM$muxBDhNAl~~d1pv%J&^a`YR*$d4~fsX2>GaZc29U*d@VgCe&NN) z`))J0`yM?g-uDvZBjVrEW8yO|MLsEhUl1M}i0$G}%NlYSJS9G~7uZ1q%jkiJ(Bpl6@2Z=)UHUrqzk4%0`ly)?<-_B2@BQVk=>C~ze!?xthaNY*=B@0X zW%?3&e75QBZbLpb$Mp4dU$N^9u-Oe;DYpA+!&di>ON`}d;C z@%i2eZucGZzs!98NF2{qW6k6I*xks75@vq-DC8?7-(ocKzRk$@WPgJ(?4f(d;VOER zK9>0&5%z2|d)}jm=w8o1W06nqKz=5__!OQ1Pks#d&PV-??asQrwZ!LcaX7cTU?TVH z5_28)(X;!&z0XTDE=12?_UpUO#cLUNlw0*m9fCQ9zSwD%gVpk z+;08@=qau+d%m*W?RnDdd2BM~uNrOk)Srr;(5Gh4V%wdb$|Yt`uLsdnBFE3pD0+OK znLYg;LQjFr^SA3+R`wWko`+`uePtta0zY3l( zd!{^!{VJ56I*)OE4wyajZFhRg<@&m0CVS-i+VMEo=L@sv##!hoT4>H=%|=g|^vs^a z^^u+?bJ3F{JzHJ3KX)WOH_YSud}+?}x$Vw=<;glfHXrj8%JI`=A=l?CvuB0vPEUrc z^9_s8lP~Lh@CmL@%Iq1n7(JDX&Gl(kf}RqYXU&sbAL;3C-=5w5ns4@e>w1<|A?q`7 zDc9$qInT*Ya~@ge^{(5uQ<>+AXShCx%$~irJM)y5nDb1JVZSP*r^yPg&(~(pO52^D z99f^6o<&cYtn-nTTp#I~xQg@0`sA!ePp+)bThDQQ4x97zEk#ec+}{6n-Tt{F^DKUW z>+_A-({2rV@??Dux}If~$@)C>BG>0zv!~%Y&LhX+F4yhbh0Jqzoa-Y!|Jv@XbCIm` zYcD%)A3xG_%X+TQcji35+3xnp{pxEQ&{HV)t9QT3^{F&_GG0SZj`Zws-M(Mdo&K9N zNxIjQw+(qeKM(B9vxgp`d-+?pBcEtw_NVARety`?k9v>uG)3Nf9Dbah6rWtqdH8u_ zuP1W{Jjw4Bx?l6R_c?PXJarcOzvbhQKW%r8hYWds@$4=f583iKs?TnCu6X)=^pwiu zz!iJo<;CXx%#jb^8RGMk@B;BhdmYcTtU2c6$!)IN_j}`3yVtCr*Kfyt$onO~-*x-> zn&fL&AfJ%Ot1r54AJ3A%>NDh1lK9Ir&U$1AiaQV0wbS+kU*}T=?|YI;k=8Bkbqd|MlMVtUFDAgg&(g-22vQIlTja zFHC*6&Ay#B!Tj;-a6Eg@3;NQ_uZIVipF^*rN9ajHmp6`}zCny!*F6tN%mS zeaA;pwQmC-dWe*TPy$j`YJh+%MLH}!^rag5ij+`<6%ZpLu5_iiB0^}gDotucN#ek`}!db;=MUvV7t zdg!f&`c1ig=I+;;PQSqU&Clr`rhl1%aV|j5UmbO3RY9NHlj!Bd_`FK*mu=QLP9Mi{ z)6*@IfcjNgN3WkgdZN0H%zo+oBKmuup+35@tZ(TB`99U-S*ix=XK{S+uPiH>?q{ER zy36UQubK6;=q)*(x_*V4s9%cvO+C(jdR_Lf-$(DzLs!vxA&&D!dgT@Hvh-@TP~XG% zk@ggN?UTss`WqdOv%*||V)z%=n7_*9uGgPBiKxF=ynh3Z$5|Vm#CjWGKilc?L*aTo zzd_HWdzgQ`wp~BYii&(HJ?$yf(fPfO$6EQnG?)8b`Um{o$ug|pq7M2`;d0dD5Oh4w zI?DRG|3l3G&fneBcsU8djZQT zR~P-S`6CCWgI$j-N_7i44j_*hP{`!f2NFC4GuM*CmmQ|%5`uB-CBj|JKdOg|T zc&xSOGt|-R^Uw5pYvFpolUN`92RZ(FJ3o#-iQ6T;UZp#(_T!wcUVr|eCyd1Wdf9*d z2IxP9?xIhor_$Z@40;+}zmM+Fy(y@#=eOD8s2`wbv(7ZSZ8YdbLe`015NBY>b#uzoLF8R$2gx8 z#rc_|^fSU=X@)v;MV)%hZI89W;`8qj$JKIw27S6Y&f{93PKr2Rou?%}m&xyo3wYu3 z`{KXp^84ADt&o@Br^L2~%kObk{||qx&4cp?{)cyI`{4X{bossH#CFI_&(r?FzT$s) z?G6vlXZ#OuoAluP*Z;$Zc6@L?`agVbrw8ZDc7CvL{U7e@^5Fa*|HG$sMP8oYE7A=v zzh@8q56}H@t_S{JXQFcZIZ>H>9@I8&C{NG>FXH^nO`af_Tn_ojdiYYV|GCSVg>d?@6PK4zEp14IV|e@$h>O?>dfK+)~gj+ryBOi z`Z+(JDYxs~7Im_i56>~{%y%PSLfx1D-`88p?Q!$WH}icSLEa!-8+GS+FT9`I#*^exoc zMR!$$yH>zIpns{{9?wal{*TQ2mLNZ!`5DzwC!0Qy{#XL)EEaXzD!2RbE=3(Z4iVhxX-geSJvMqv+?j=x2a(dpsjtj(@Oz zDG&13M81Y{C%+Q)$1;D3?p*~xNI&uz>J(DXtN8Ehta7`K#q~-r_rrCOPZ0Uj%I&4i29E!xBK^PL_Ul8PneI2 z{299Yrn#Q{LT@Yl9_wfF{ixq}bDEr%I*2e-iG!M`SMSJ>(6B;oq*cEi~2dthjyd>N37GR z4f@Xz`OeDi`jLIe*XR2v+!pT2g#XI@d);=Zb5zu6r`)dNx`6yL&ez+{1A+=#St7qf zxwE`(Azzgryz?c&gRwY%&>rZB>0T3cX3z`WHkZp1<#v5{MbxQ>;j}*N1ozW>(+_rr zXVNFqhj)Q{-DaI1yTXHXU8k8kaI&YHP4}^m%ZL6GMW2hQttG_yzb{0<|m2#J?1@?%zjSxLjCz7pQGHaA7ozFKhhidH6njj zxt)(NKcDk^x)1XEME+;xcHUnZ{pkEJeUU#S^7oY6`6%=Fv}jrPobxfOgL@u_NBKUD z>krRN!S+Gzww%{FdXU=QD@*k=6tQAhlKB?&%A5qPtX?&|4F&i&kGobU0hz%hhn;cf6Y2e z=-&$8NWUih0Ns1ftn)QJMfhcUn(#Yx*L|~2k*CmS72%cW^@Tr9Z!5eLJyrN%`h4LN z=vl&N)1$(d(@R+Tnf-li=HApN}nsd^+>*dr(&EF3t+k#%AM!oi+pSf z#yKMTuRwR_HOI3qJt(|AeV_3D%I$G*%|t&HxzPS)K1<|_jY6L}qR%n(1hHOyN{K}esn;)bpAY!}*lP7O>SWUO zd4OH?^rw*5-`g%3$K~D!K7w_+kB0~8PtmjJQTm(o(E;Q`eNpEf`fa-R3AnB^`x)fZ z=^rp(VgfvnjQlkEyYwi%KfV4$4%t4p2R-;oB3bq)&O`uz8|MQi@a+n zJe_q4O@?REb)QS#KmEy6)Ctfh(2vuj zbbR`-tS0J#wDxp8BT#1^*Pr*4+v|BqtcUxV&m4*TbF7~@1$DeU9@C#6S17mZ92Rx9 zF&`a`I(mHKUSR)Y;QBarHr+iI-iFgXNB8mgtq#5WRMd&mYtZk}y#dtG-s?q9m##mL z{7BEF>*K4=(~x&@Kd5~t-A}K~>HbO&39tGR>SPKZL=R6upJ#b|UNVUBye-DFhH`s3 z2A@TKJEwb*d3TK1&d@!=3%!gw(dSV|uboHAL1AA z-xYypHiHjmzIbImC%+tAJ$~GIJy8`NC3(#v_^?#=L1 z?5AWtxPJ}&UC!5{{P6UZ@U^U8xDecWA3mA+F@;%Y4}2y4+ak>Ghu7iwdtLC%PvIpw zzgvsJgFE0EtaGaj+Wj~E(h+;f^TL0JNfur=u2>2 zr&9sAtaG?CJUSnFeV+fJu5{LkaJo}^v3>&bw>ZCP+u_~}cscg-YHmIkItP1-+FY+% z?ij^+tu~P&tVH6Pp`Qab^ITq zzB(*%UQ5=q{w4S^dbdpv&cA&fZgKzeBkO;D4cAd`ScT(uKfT<t}V027S8e5y#ba zhHs)z?SJ;NzkgTP;XG^h-?tCGC(Rb$kDMRO?_t-W|IVyGVF=v!0elZVmml?GMEwI# zBJbLPd`pf)zoE!`C!77ORBqp&=--39^E0(-8a1Ax?}a-*i>y3$7~J{PK0|p;Qd~J{S;GvoDvRuB8z5!2v6|T1fd+CvRre`lkKC%$5zwaKH2KTRqC$i6< z=^?saA9gH9-WNvxclOzK1>E}%JdWF|msi4F8{lJDzvL=-kgnI0_vo(okUz`3_bue3 z^aM_~;%c~i6Y|e89~Xv)g@3!5)6IqTq&oLgEz{xY`QU?jKC|-sa92@yFV0u{efIhs zYt?!a+aG;g`ikRmR)Tn6k5Jc{Iq&Pd`*qOy_4Y|bGp&5-~q0; z&$Eu}B>HK{>qX1Zd(oTm`cmEJ5_(NuXE=cQv-H}$p0*af+$p?&{WGw=((iY_J zzGdBJewu~6K8kL32K67~^@O_rAbl0DU)A4R9j1@xcs|7G#+=1C#LvVyWYfFQZ_{-@ zA;)8_5o^&8{#4f+(_8gZ@u{;_>rl`q5Y5 zUXF8=b$atY3+~pe`q`+Tya#=9_im-qzY*6t@1wuK<*UcX`Vn=SsryImS8YzWExp#y za6Mmh>HXM`UeAxyXRGI5+OJZqbmTQ&A`jXta~D(LsS=OX(5P2I0-zw|gyq7UKv zfOoNFWzb7!V7@A_{$2WPzJK+0$$JU)uXaKG*38eO$MC*9?vAXZ^juuNC7CaD8FhC3 zh3V?;gO6TwINZ(rV#n2eA{;lpeK^DXYrHNR|4LoIeFgR1e`ERT-(~aDOR*olyw*6b zu7jPA<&w?m=Frm?n9D0M2ldBueb)0EpwHuao1b-dIIiw5V4VQ{Ha&hJ>U-$>qjr6D zpDE7|`|16!W4b=^IpQzJ)phCObHv&|P$x-z9!dHWbpoQ!FOI9v9iq;=H;@mBd|S2r zob_4c?>MgRQ+{ik)4A^dEw!Dp=PN~ct6Qj(ChAyFI%h=wZ^za1 zH^g*T-$DMi$hY|i9=`<3#m(`*>$tj3d$l=VZ{I~fQPEGEe^IBAsB_2hSj)B6{5-hg z9`eZ|-{ZdR>iY#T-QVds!r!!tt9-2G5%nL-WxM*kDeC`3PZK^nx1Cqd_XwNwo0tc_ zLHJk7?c+xI`SfFT-Y>6p{XU2B|Nqag%I)*FUBr1pYdSn2JWjcN9x{6tjx&3)(rV^s ziu`uwy|ahsj^u$@ndtX6bUpMut za(jOFiTbPPXN0HIbA*3Pzb*U}J*J@EVxys}^m4-Q(mle9Iv?l?T5W|_q7M`PIDM+{ zPV~jX2h-OGpFqzLKAV12_;Pxd@U8S4!Vl47V$Jb6MUNN$Gd)50J-SzT@i|z&KH=5q zDZ-o3gTlMf(}WMDZx%k8zEAk8^rOPxqUQ+TPQNYu2tDQ@bKJh8mk|CN-7P%#T#S!L zcqzJ9cul%bcni8;cu#sj_z3z`;Zx{g;S1^M!r!4E7QTxf5&jwdqVV(d8^ZsfTZPPV z&i@L=Enaw8dV=se^k%|a(|yAG(uWBjO-~g*jXq!aB6?W(I{FUbd+A4opP*+6|A`(I zev_WJusLqAuX5akSD+^fuS@p|Z%^+nygxlf_&EAh;nV3M;Y;Xigm0v02tPnSF8phH zw(!gJ8^Z6b+DwxCr`cqO_=_~Z1p!aLEEg%75W6+VF;6h522Som`K2H{)j z`-C5&M}(iEUljf`{kHIX^g>0=aVtI_>ziA6HF|yFP3TF&yU_;R>43O_>sR`_@H9O1vw?+VYo0OR9wnd4T9UPX9KdL!X2=v{>Or2B=BpidG$ zg+5pKLi$SK@6gkQ@1h?T{u%v@@bmO*!vCOK#mw=^zYybALU>tvg77-@X2M(3eZu?F zhY24|PZd6mK417EdRX{6`VQfH=|_d1pl1pHi5?Yxlb*M@Ic~A9ar-a40zFZ9UAk9z zdwOr-{pl&f$I+(>pH2@6UqW9ad?P(W_yPKH;a}6Ugn((*in}u(uX9_<;|5o^S^c>;8(eDb+ zy$IvuDrt^eDS8#*HR+9nx1e_s-jnVZK0>+u`Q1CDiSvQj$It0a-atQ-M82DHJ0BAH z%8QYoFY*nQJLe^s@5K5=-$Z_m$XBLk3U5evmomqvGkvV^A@rc|iS!-9=g<>NoAp=F z=L_FPUnBfudWP`R^eo}O(96Y})4fmMEIe)r#_fji>h$o+dnz zo-W)=j|lHgzacz@UczmT!&G`B;UT(D_!{~!;TiOx@Z;u89tHMlT@1rchPnIrSsw06OeDj`{s%-f(Pfo z&vUxo<8b#oa6MlezkqwT!u5QW{}LYB0$pWebz;*w#5_$dSS8(0`?b`5Q1iqa0M?K2?=WyMB zpg%l%9>j8`GYIrp3(5F^pbDEU0ff&KzVC|y5QOVekwW&d41jNCt=o^3BSyI#djW@|9lNR zn1=jmuAimW!QHdqgX#T_!?QQRb)Q?lfXhB(zJ$v@2Yw6ph(33md~p8eU+~BYOm`E< zr_(LCobKA&53ciy3)k_=>Hb)Z*8_|3T>mWGKM&J=m|yURVsL$LBsWI>9gg#)Lh$r- zey_(qSGnN6ZKkg)4)>gb>*t>&#=!$;;iFjp2HkrGo<=WL4tdvhv;G>o|6BM1=2I#l zpP2{!<8LkNKHbV|`Y;dj(Jf~E=Jnta7xLX$|8xh|51IKPNpNeS>F;%hhv%E#*hfDJ z*ZsfI3!eQrmP-uB`Om&^zt8lYPr$w1OrM+#_jNbDVL!O1tLbw#!Xs~)eQwdfE!817^KIp#k-40jhZ$A9RN2j@2(hlh@1 zx|>*M_X*}Jq0TW*H~bYm@)`0$=5L&0oz3R_cKaUg*<|_^dgeE9z21(`Lf&=M%;!1B z>Aq+BwIAWWy{6Z_0+;J;y&QNn!_4oZhjyD@OWhZ0Z&xGPaJ^n-(X)RveRUq>qd%EG zRNaSZ*Rd{|URB)>X}jx^>CdVAlx$D8%=K-d`u@`CC%5T6)c0++XXY~9{@%#;>^!D_ zN{{9>eWLn4z|LFwO|PxaciZkNVEWJ62b!Lt&i~qZ_aM_>Rp&Qt_Y5|@gF1ibhBuj!sz z@W>OU-=?ScF+C%Z)17B7-)6Pp{?|-DPLD1%eLx-L1IJ81JP{uK*z_kR!F`{Y-tP~% zdy(ls&^>ROKIKp3LrY9Ad4u(rnZA~uzTEVNeeBcAqPtYSfOdtFY@}6C$|4w)9 zH~q!Ctbf4t!vDe}2Tfm1_k3jfWA~5`9Wwo6dioL5U+&A_*N8EX2cGl8eGi!)udZXZ zw-25IrtjwO;-wcdec&+UqXkVrG7%o&aY8bW=Zo)U{gTM**{0UP$!wrk11AX`f$3gKcDVT zG3$Rp4;(=fS4Ugc$x^5vWF38da_Q2T-|WSh-}dZ(n{xZQ&3j_H*Xf1VoAX;Q9{FKU z!g+g;^(?(2^ZGjc-SjGSeV@YL^tyC?J#*7CsNYohi}bd1ef{}C`jhlBoUdGEQD=(q zbLHS~(0O{sx}>fnx5wchQU6{gc!dq-I6PbpZXGhmzjY0GZRYW>EURBlcuTtO|D{^+ zzVx!}e_bLxK!2Eiur_=iU9VSJb>P;=W&UO7x z4dLmZnf1ptfp=tH*H5RPq3dz}gZ{nn`b|-1rdY4qH-n#NUawbAHiuuJ>-W*iUidw_ zKFj*CF0QkX@z`XE9TctFV@<2bsx$W^Lp&}+92=#$Q*}X99P#%i~4W0 zMcyasH*Saeeo_Cc_Q-og{kRUctLxa`Hv8Y_c&ruWc1idDR1)f2qW-@fQ9mfQ8|6F0 z2W-SR=;he53w$hHug{~p!#C0~8kRNB2M>$&+!F}OT`hI$eC*bK{AwPru3ElfOd^`Q0 zWaKS=Ufx45)gLa;=d7kjd7ej~N2)pi`Os<9*Po9z(X)9TNuO6KKM473o_BICM^V$> zMh{iPe)c);H(wcoe1QA+&g}DLKirjt>FWEHimLaaeLUl%cVT`7JuJNXP~@X@UH_qB zaPK+P-^4l>=ux_!?yTX+d(I=TpSSbn2zZ3Ph;?p{ga>{={vth`0{8R$z|-`)qp*HP zd7py5U#ZtPdadzrZ;t6Xbl+9e zR|Pm@|jUHzi2x0Uos!hQXOzuz(QxfjCy z|Cs&}J#g3b;A^N~i}R(A_YNty>j(ce^W|QLhwhnvjvl^m`df=ozdP$=t}Sct8}KD` zy}Z6%41brdj|Z-+`_k?8;eFvnmckDTuayS>g07E4S}fzZJ!GEuxUJl-|26Y^e^-13 z$Fq=`pSTkFbIj}a=`U{~A1G|*lf%egWnPcNPwyZfEMn%Dy$cT&HT@5D|Crrp{tc+0 zr#nd1wU<}eW#)IOoSiQ&@{g$fx}8riX6Cc#nZ->{+l+i9&h)iEg_ zXi3vQQEvCsN%V7W8}e3ZGyiTn+!b&7==b67GNxDF4)>Hb{hV@px=T4-y}sT00D14j zX8!#h$gdIk&vzp4D`)2C?t=Tvo8EpmJW#>(^%Q?3ez0z5Nut z0`vOwcaPB!JEVjkxg{1N%kV`hGzay#Fj_4PP> z`4jTtx@La*1?2rA|K>&H)9ab}q)W(;5cvU@kq#(*yw%vux4n-1R8Cj#_h&1&-|wy_ zX1?#XB( zmRo#2eOi6yw#PZr-kfe?9(Z;K(|@5ylT6>37kR6b>7(=6{iyrIMgMX6(Pskt*Pnm; z&^@C6yN<_MUeW)O7);mI*_>|Qf|zd7yXNQj`;Nz2jm30Z$D*H*nC?}_)$b3A>CPyG z>AJg^(`{22)6Eg*C4O~W?Kj1AJw-6xh}sX^FSqljWu0+cJx^w{c|K&43;AiRgMVdN zONz07y8gVdr#Siy^f3F3DS`Z4v7H%F3i)79Gyh>}-BkSCHN7#{# zg!w(lFRVYY6+Bc5)4f4o(wbfxzK-WZ-f08RE(=ejw`~iL@OzVv^c=do0`ep1^V_k0 zMfd=Eo%Zmk8}6q!>Hv3Ff!CxLNP_#S!oBp;9pSD7xO1DEnzu%s;NcqZRm|U@duzeJ zpnuevb!x+%%ivX=5nbTvb>JT`U!*IR*GfLGW*En_2mRJ=teN_A&|-S4=iybEKTU7J z=j7<+UbY+Rzs~36=;b?zE}t_KrpxEdT%gP6%v9@+`tmt5qv-NEGn?u1IWxc0<#T50 z`cPj!XXaVDe9lY;T|Q^#AIH`6Pu|7)@7#{9#;!#V)UVIyFX`j?m+4=3#QR8(^I^Jt zK3IXCs564gr7o9CC%Sx&%>uf7j!lFvpRX0y3-#smZTdPMr+$wK^X21uwT$js2iMi75Tm)@RN?2Y>8xxSTQ|3m42@%cr1JzPsq8!+v@uUDvUmK%Jyb zW}PyJvi?f{9ym_fB2h29-Qytf3W9$^1;6MfB4fwADp+Ig3I&XTmFZS9QNRR#o-V3 zPw5d}fA~Jv+c!rb|9|#(>i&WUJtt?Ja_4s$c)S{9oejJnAt3HY*h>!zKh8P{YjNDG z>l9mIZxGb;*hRjwa(lW7Ys~y4=EEXCo1QLw8U3*E&2*2tKI^})gY+)KzorL-Us7)0 zN8@UQ{igoi%%v-NU*5~`2HftQR&LL4P}KRE`EWC{&T40eUeH=8^4pc$)Ah7MemZBO z_gnBx`apW_)tGLEs8dq8UB}&;eKNm``NJZAjQKzt0|=<}MGZUg0ZpMiF$qw}9LAEU0P`|s;K^WOHz<4?;vw+8jAh=V^y~D@ zY4Eq`eYc~2RMa1>+@4?mOUUI=QE#o7wUUNK3=)gKeyY@GT&i0@?AuJ06j(cc={UQGw9jEm(tzp zy50Z2HYvCJi4?_?RG;A&gm;-w5_y-i0u;3D>wo|IszMJ7Z$ys>??Ugbt_%L}%TFIG ze3Ejz&&qx!u3JHu}`hH}1U;{lwHT>!&EU^PV=%oX(xMt@^L+%(oT!Bg_YuB0q@Z6Tctz zlSMv}o+8{!PZi#qK3{l>a%Z{J!+h!A+d9vDrpW(6@2#%;{_iXQ0rcq?UY0&qcpds- z;jQTxh4-bq)b->4eT}9k3ZF)AD|`|ChVXUtD(X7)|GxIpy~0n>lZF4J+*$4oupFy! zyIuJpkCVmm>M-SY-ro@U%ba+ca(nxHP1N7aysr`RdViER6M0Kr7ysW^JiUbQM0%od zFTJ<$-pcJhBWaj!UC!4Adf;!kmnT4f)%h9l=KR3f^dr>q@_n?P&4!iR^P3{3yMuYx z3e@Sx?OV(t)Nw6_?_xj6%I!Lt>OO$~zQ!uIKQH90#peY#|MF9M%sSJne2h9XA2sVV zqVEvig??DLpPnszl5%@I18<@KraVD&Ou6&9M)XtTFg#_w+2=fZlF0w2^TK<4f;w}B z@1SoGUit{~M}<$J=LkPXj}d)(KjnN0f0v#lJpWOQzsqBee_6U!*YrB{F2Y;W*9h-R zzbJe({jTt7^hWi}=`N!Cg|Aa?FW+brY*%}7ed~V=^R-#z$I*`ppH5G%Z%%iKa=U(d ze$@Yg_0Q8o1>o`aqFH4^#9l-u<~BENw7B$0oc`E-%ba{~P*i+pM2cKrzRo9vi+&87z{ zV;lltD~leb_oesv5_K}GBA-hCi0-WhKS587An&RUpFm$q578Ua^L@oW>GRmmaXx zZ_fWM`dlgcoTS_ye~ZVl+gaz)lgJ+y`8LX(^J8nx?e;ACQQ_z5bH(B;NH2W|GXC-nhy^%-{2>Bcr$!CPoVd^1NU!)>*tDWv+!I9 zUrX%Q^m8p*)q%U4!Yi@Y!h=`f?YSLm-G+58z}L_V z^oCmxWBHC?{fm9zzBsu4e0{Gk>y(5iGG96c9()7yo10!F6`s8u-j?(A+7#Ab56{bf zT-)K{47mFFJm*#8Pq_aF_$jVeOK-pfS#Z5Q&wCT@&4zF0@y~=?tp77SAN$!j9?wq* z--j2;j|s#)1NRrkxYb~vV91pot=P|`k?>HO>7~aozZ$N` zVMYY*Isxy?FS`Ey9UeFdAI#6#9hhA!We@MK@5ws!gXiJd zL*QHKZGVP)gjc)?_dSmM7Uo~0yXhYK=Xa5J4K?fkH4gV(W)6bu{{MQ8_hb4^uR0a( zd(!my8LY$ly3YI0;J(EOKR31Ga;eJuDBavne#Aa+{f6Jm%i(s_Pft|8hh$&Bk+~P& z1G?#7IUZ-tJ&HY%_LTm(pV5C0ea>Y5@qrKaexu--TrT?j`N3K6aBtMn%W(^T2hHEd z^tP`fA9@bnp6{cYOF3QEAH;s1U&i`Rn03x>f@inIdY+GUDwfCfT}d0TU-PrhLC0gQ zY%xBAD%g4TdtS%P@u}`cotXE`I-ffpXXS|TeEJd8i4k?Yl~HGd=;xB->i11Vow-#| z=cw>O)lerz^pmeTrz`TC=n2AmIM++7`@A-q^HqPXT}N&7)%CXa%kBJWS>HGwXC;aG zDygoob*`fm{oHmu)(VPoUaGG1v&T6}^b@RWe=n@QFBAQYs)z5j!=g^%`uH9>Mbv3J z5_NJ|C&>PTqwu|Ci-KMHUDH1mDU{4?X27ruEs zJd@|u^>$!)03IBSI=Y{%XXpdrud;v7M0h&q>nCnEexqmedy`3gUo4u0ystaztYMu7 z&tg0STe1G@?~k6PpW$_S+IP^CMg9hTuJHPkFL>G3e(mk2gH;(I>%gGauPVpA26> zU$zM@x2q#J!?RP7pT_*!EpY!7v(EUf@aPNh(ahhY`(K3n>B+m0_il%O$K#FNboVZJ zO^#2K-N^gsRp_74gLJ+A`!bOC>_(l2obGvgfXAyu~-3(MEcR-kryvJC3l9`D@L>b3CFNK52*V{>{l)NcIEbUK7m5mk6)vI{TbX-#dPy(i$4c^rG`JGlQeyk%ZA)HaKCK83f=55IB|9$5lk#Qq0f zhNpiFZ^k-xeuihBgfHQ8d4(SS9zKZqQNJQ@Wy8PZ`>WtxdLhivXY{mxG0sQSeLVKd z>-?#%f2QZ~clRElm%fMmb4`mmQjz`yJ%-mea`$4T(epPzeeGxI)A_q{+RNU@@=E&< z%SB&@Ho);%s~-E|YGtjY_f*d*v0v5L&pFod?n9kM^a@r9=eQ!3?xqiMJl6U@*J0Af z^LGICcH>9ZNfY%e zKS9^W4-*|%*Cie>*Q*`O&tyM(J^YJ)>I;0Z#-En;cz%q3%t6!%aD1L~Jl3khK6RZ8 z=2J!fZ|3E7vrP)1e|g>P3v_us@IHF}bc{e5_VX`Y{;q3_7}S@)>-rL1UhkSom%k^Q zt03yg-_>nR@0-h9-)7L|@3$VN@8<9A>iePc#iIU;T;KG3wWrJ9jh#b(g}>v8saw`j z`Ym3Mt=GeX525~h++OMRrxSfS>*)1-9$o&v?Qy#NJ>0^DP+$J;Z8y679pTsLse90Q zSuV#2{R@tdUZ0B0zBW9FMgws`Cf-i>D#2Z|U-PQA-v< z|MGWH`_dcmcTV-VEv28kfOkqcPWKG`2wmU5R;DQG%j?qn)8%#PE9mmN^eno(F1@@9 zpPtlU1&?`?+tes}(DlQZxT zy));l&{=qPbL3N*f06EQ0e^=6uX4Np5@NbVzhfQd^X9`p_=+A`j5-ZC-D2OPj$72J ztlaKD+6MVfvXJ*CA)mzjCgpaYV@3V|^Pw)t>+4!aokM=E$WK*n_v7w? zd^Ps(K9Bqwk*}xR&ii^IKai zryF6u7xSB#&l33q%zK_d{f*2|{}FYfClP|(u$*7~Z|B0929{OG8|I*$M`CIhoFEigCuD73sufYBEvCJQ%M}*JG zLEbw6bv|Lf-c`(3Oe6Ds*Iv0jU#@{>{%7W^i2T3IXEQ&H_1FB2`d*RWt=w6!2BH2z z=7;}+d>4^VRqpgN82MSuKXVP9N#9B@{VUu(4tc#C-&JnEk5WYaUCalDAm4#?M*N04 zQLYaz`=6`VAIj}IQ$?M8>I1LcXC~|D^CUx~aG&4o=N>)u41BFq-LmFfNBy~?{&MAZ zed|f&8!$ih54e{ePw)39+)qD5|C(++g*uz)4Q^n%VKLn#<@R*bhaumY`9t*JaQH{` z#(yF28v)n-Y^Mk4S+c`)J13yjbp;|{M!B62j79y0tiO`^RFU7ty!ABl6*yn@|3*JEMZN=l zjqv`;?de9iKI`@B3f<4`n?7GU{0{2x6LnJQ$A!qHmAcz>~jk986v+xxjkQ*3ou{jnQw9*{X|5*n{qoJUWj~e=DR7i zx1ZS}KUBG$4}_3^kNFJdZ;1SH=H0KG^(*H_ogm%EI=7VD(=E}=T#gUrfhP*DNN+2= zo^rd-;37;{U(Zu0FX{{wdAD*qpUwPy_VY+Sa z6PlajUs}0cKez(HyDe4vP6Eda=V|9 z$X9*{`P(AjP`RCtGOv$sk1=1Og*m_HnD@PnewMPI$%RngBl54(y9j@aK2!L1`eETm z=+}gQM=#gX?DIGJT;aJ3bKHcNQtphy9?Vy5&Q}NKqar_mp5!&BJDzpipP)`*HwtZ3 zZf~y|ZNc`6Z2il8dcl@Xa6RJIs3PdcA8Yyv<#wGj-0tZ*C5j^NxrFJS%a1~Rl-t{l znWE28%I!M0MV+0@4{L4C*D=<2T|@oX`ML5T7wR7u`HJ+sZOl6L=;efWpr;5Qpxj>F%O%eSbvtIOL-pF<%GmVN|bF<@WMA+SVMm`OLefA@Ae(f1~s5&HNSR_VP^= zeKst?aS-d_EA$MJ&!V3Z{%A?AKfeUk9~tnZ(J`aL<$`AVaHsu;Iq<#zpR zqRv=){Z8g|gRGM#>YSmU5nex@<1BoUa%X&2qfh<0`zrGpBHyMA`rIt~d4itS+3a%+ zJxlmY%I$HE-)g>(uF_M5_bH2fBjJbW$-*Cf7=0#oG5cww+*zMRem*@z_!;^c;Z@3U zJcW-}ZZF3aG2I!;?Q!<)#W=6!{{0N|$3^}c^MQ|$U&-~SS$WjY5_uo}n($$CtE)K< zsq_-U=hK@B57Rdb-=W-|uV5K$m-O|bgDarVyxq*{PN1g=pRL@k*Me`l~Bk17y8uuk=68&@cVS@Ci40^ z`Eixe=Up+~>2yzbbNMczw-vsT9uj^)xjny;0$6`qaXFS#H>}z2j)7OE_ollZg6r$& z-=}-&XYIDtYgAP(M={+Ol{@vh-`|e7)uT2L2wG zSIye2-vz$49O^vlfd_toUsbDs{pz!kb+)6QCs}{bCU}&eYx1zq(p%uxTI8M0sj4$+ zEAyM+K8{28H*o!V`eFDuXR4OvUIx!R0KdlR#%Its!XMH5mnFDP+r1wCCi|KG2RynP zKAHI|WpG`z|98x|Aef^HY59roSI_so#UMuS2ME6t2&I z4*nLN&Ak4;I9>hjo1HJrysk4O8=g51b=(|>I_me@?7aN_h4^3LEm?=NYyEi--b{Gn zGew*_^7l&GPJvHU&ylrXTTeZ(9bQ8CH*dhp3SYGZ?xu5d zWsO`0uP(gaO8C*?=D6ir4UZXN`ZsUGo3f7n{(bElcw6DmuZNGJ$8vq>wGsX-U0+Ak zd<(oQU9WG|)pa5EdNNRW$q(T2_jIc7f(Mz`-@7&5179XQ`~`d;U5{Iy@8COy_qz<2 z&tv~~1+LG}oQv&7Z!Y*sE8*!I;fpwdeXHToFuVY_C%eLMYb|^W>%8@Ai-&+Yjov!Pjt_qjG6Lc>D{yOuhrmhRC34d4AZ(0k!m#(je8JYtwrqzMV-wE3FD7+;1BYGT8dEnLPJk4WWt_NRC*Y)!^gv;Lvs@Vj-MbyvT z4Bndi5xspY-yGh7uD9pSz3`!QeRMax4P5>%&w}=F`FlEh)bkVV?ST9poU@(a2U%Z_ z!#|zj5xQPpRlCEBaDCIuy@L-fe+S1k8vZ-iL%m;qYz#a<*F)_+$HL1CpZGMqzVKWV zY**(G)3-VA6hGfD=Nwn_`yD!W)1RGa=i{ujGuWSM-!cjHr?b9ZzIC66ucqtuAy)ma zhdrL#>H2frl_306x;{QRF%y1{uJ_|RX2buY>+SsHH{f6K{iw%3v>1MwuGf<-Z^Hki z>-FTbCGcE)UueI=-+d@5{0@Kjp*&r$pC^{1P9?hD&a79z*I`c;n>v@Oi?oo`;9&dfYzAhRfdtn5UleZ_n2O=JkB_xClQiy!2)G zXTpED0*}!3IBdEKKTX&Dueb)6&*yKZp0{uJBcH>+RXrcx_TFOq*;PI7-Sz-oZ^vq= zZG-JE(e*g=RL?oLeLh`pCtDVRuM+NY!M6(USq%OYUB54$Ee^jy*V~y&rQq^8;pfZ1 z3vfHE$8BB(ct||od(R{A^33b`D!}J>*QD$1SReHqZ+m`Q3je1jyf-Et0x$SDd zzX>^S9_{gf}a0Ul*$K+s%C0 z61Xljo!1N9XFqS0f`@timEJErTpI2fisQpW%zsF?c)ieb^!D+r^BnT}KG}w4aGh=b z16b4AF+aueI4fCvuH3KOx&I{qD`~Z)KzbOy5UW1S4xGkxG>tn;B z{#oUAegEGW=Q&(pBP+rKFQJZeIgpxe$w%nZ;q%!4=E|Jz4AYaU!9(=%%%4qQekStz z_`Gs0=IQ!-=drcnQM$e!=F+3^z%0}WvHp{FS)a%G+OzA!-E)xFb$T|0hv_>1Nn^NY zF7gXlziBggCVd>oe@k=b=b8Q7Y{|Uv5v}3A`N*emd6jPmkKV^}>Bk*^tM>2+uLBv( zetLI+dw4yDzCL7f5|(>}%iYcV!H!rDJM%b4zkgrv1V6JXdtLl@?`f7jbRmG%2&gmQbmO6U2ghMaDnZm6?&tIH7%o0X>A&IkBCyUrKu&N{+7jKOs0euL?{ zS^vAS$Xoj`ZsRy^zX#xvWAHBgKsDl7xR2+h2Xg#RDYv(`cP60ERMsy$nf3X8=|d0G zGxkpX&E*>GJvQtLXCi z?LX4x^VqAtjQa9D(Yk~A8KgUNvVzeVv&DAx$`|{bL92@ z<)J$8AbmPkD{Bkg)dG3Fy&do<>ZgnPle+N1s$ z=9@J~zKh6rSMH1_^ZGb2t_3_q@5nkuTEesGdOX)CxBE#J^>;JxN~zNQW| zy$XGY@J94+g?FJxh5PA+2ATCI(dP=EOJ6B`C4Hapbb6NX!}Pnt&(O;aHv73o4+yt9 zarw6NI!m@Cw;N9>x3`~xA!eQDnD=>+-(|oPr12kXgRelBj)8FfOU&J)U=^{S26 z`S;(m&Qa#CiF_9G(RRq|_ff;HsGsCF`|M0l5k5q@J>5Vj)bTk}x2$^IP-m*hcTjHU zGnpUEytg~@i$%V-ay#$tY}T*gLw>W!H&^cT!@REFum|#oMZPmVOZX7wb{$U_Ot%yJ zY}gZZZi{?p<#s;E{IkqY>4kiWC(ZF(sNBw5T~U8N^RM+r-XrqwD!20?=7%v~r!Vqd zM836hr#_E|b$<5~$ft<>=k%Gvf1qy={-^R>>a2-3liXN$lVWhZi{?<<<5LvNB$t+U$4>q&%x)?3p)=8RnNN~YL5RS^m4)*(CZ8D zsN9}z;4(Q?X z??8_kX7)3H?h`(q9uz)b7!LLd$)hn_0@K0QtN zz$a1Xw(vdlc+pR(p&SR{6X|C}od`WccAAYI{&(=| z`7Gx((g*is!zZ%-H$C8?AK<#5$KQl!SHn0I%Y`~Ot}=fN`O9Fd^DpqgVK|;zX<2F4 z;OX?OtaI{TcNe%#`9^(ReV90Qlr{h=T{{U_vgpZm`;KLoD7$6R`j zKGyWOoAiP33Km`~Z^M1eYj0T4zV2OJ*YN@NFZy_RU@Samhv}E-w?%%!L%9Awvp&Y( z`52`py|XN?tFNuDGqPWLx_>*auG71)&T+T%r)8bkXXn-TP3PeHykDV%sPAir`iUI> z)A@@!-+Q{7;k-&M);ZG$&rx?h4F8_K;$yhKEPO3}{Yd+H>FT~|F<(#RwXY+3*vjDc z+0XpHj>lQI|1$f}r=F{5=i@UlZaTluarL{{H_iOJ&UK;cK5LQh*n-zDUBI}xIo)3! zSK}t?^z2pK83#Yln=N5}Y;Sn5ImYb-{rO~gq$T`w`g?=nz83JQ9Otq_;9)O3m40Fc z<~LRJzjGz}_lW+JSJ|$vOA-BVS&cf$d(ClM9!4FXsMF?c)JYX}p8f}Q8tpOb^u3EZ zE>Y(n$K$McQ786MTt}29>cn_(JyJ;2`N(l~ABU*Zpf#V%+5_v`MvildYhrhhk&Ud{AD z3+UBNzp{{?VEQv5dJXs`_PO5!g-4da!?n!(V`*@IqB-4p z%i!L+@a?Q$VFf(O?a2lDvn%2070o)4Rq#v?T<6=ahG*9?eR&ujdDQglZ?jGXvwrV) znJ;hp&Nc8T*B?FIht|Qf%bEH4+pwOW;q`2K`@biGyt^sh@3r`T@Bbs*)ewH2`{k3o z&L>^GFM^$MeZm>>zL@n2+~XwEUpgd^FDp%tH`H_{1JLcc)@wdX9({? z&ldg~J?1;JpReg2;U(vzezNdndQkWZ`Uc_W=@H?NEI|F+!iUk_-!@$>xI(XQqv#3355IwN@bS2!F2`ZqVt9zIuY-zz6CR;=V1DWncs9THaUQRy z{_fOL=KElr)nnhBSL0>$Crn?poZb)aJO)kui##jo1I+xBtLTH^vsi!2YPf$0ya7K) z+zP|PL*X-dLEe}(aL;q_cX*-Iowe}nnWhKV!$XVU5!OlB2=}jtUvpu8f7=B2Wx&Asi&59IecuoP@H*$a0Sfa~S^#)ojLpy}84!K1OJw?6>SE@b-tgYZZZxO4i{vaDx5 zf_sX=zv79oQs2XU?cw}5W$np=`-Klb4-W`0o(&Ju_4@YFkMtz7e#!-Sh#sqYv|rC( zf`>)E&=q*P@N+rvOyN6!hDU_Yyavw}-s3lTRJc0|w>o;A{`C0VybgB>KmI4&ExgZP zaF6hOx8Ppk>9^rN;REl${latKg$L-1oo?0huK$I*I+^{Cz7KZ`FO;jKvpx3+-cf2L>y|Gm z&y~BJ6?`q-=_Hf=gdSo)JyMz!76&@3_8cBS|#K?v*E3o-$oC<3fKGD#+8u|Er9Fu zmWS!C5In&8zADHE7r~v!by}8{rF}76@0UkaMLv)QU(Px=>8=&ZJ3c=}HGGS*o`_hrC$FyFW~r@I%P!R7d+a(g|TE7rG< zABATKKi|amSnF?IH_pQ@t5Q?je4aJPfoh(!1S+#4(@H0`(tV2QNV%OE0JHd$wOLdOH0#9(X=Nzd?VJ z_4WPcjas7qcHWPm`?eT(9){(3buk>tmEGYc4&N%c~IQ_c%SDdj5+2()C^KQ2#mhuk*d>CH@~>cOEZe z`Tr06F59t`v380wg*x_=tz#)87RSuh;c`e6IIzoIgI_@8j9a>%Q*mzUQ8qd+xc1%hmY|$JO^TIB$A8 zo@D+B{+^3|edT@u{gt>~bWbmO68ASfKg;MZ?ZZs!`ME@&uYNDo{?p@3Y>xh2;`dO7 z(&g`)WYXpDq1>j+-)He8qrYB7ELV?bJpB^qU+-^w=<;_`inKt_C*NSb^!7@j%iph= zMVG%{ljV2`EAbNc+Ypc2Wm}^E=0^0BEiXNA7vq1(nLW!|OqahKl}(qw*Hg6>`d{Vm zr|9wf=nrLLx%zXEb#(bVDYEo?`9 zo+s?M+TX63^Omg?lk%g{%#tUVp$Qo`xf$#GGFpV^vmD7Np-x0 z<-d;c#B)2&qi67WT(4J@zD#_cRiOj=NA<=?x^cN_j;rrqi_b@r)#vQ7zPB}4xqaP^ z`}xLB!<&3w`;#8|u!-Z&Ws2(m8;?c#wLbWqbJI^G?qx z=YK8hTjvFsy5FYg`HA_^81(Gt>$k1WzzSL+kw2*1?)Q&F{v5}@xi7|fSmY1TbA|t^ z-0ty>G1s?)dLe4NXFXj1eqX!(=ua5%AlC^0r-yPoAIZl0w&8zWM0b6So>Ls>a|4ji z*<|{0dT<+h^nD%E1|pxh1D@|bEFh}fxgJ=I=Nj|jJ;;B<@eELJ1nhBI>)=P}TL+b?{Ij8u3yhr7y%D%MgA`H0p<2~Uo83;(Idh)(DVAtdH$YWLHJ2}vhWy<3>wdlQsH&<@=g!iMz6NjSB^oSpi_sl$S_glzYN0Hx=A3m2Jnu>g?Jq-1i zXB6_@-;h_A+c|#$<@WxNA;zGy-HN24by^1GDV>*Z%Y1&g)jzKwjY z$giZk2AlJ|UAf&8{QY^Sp&EOx(IfOZd_nX48039_Bj33I{=rOoXe8$6MSB?P?=C%Z z2lSvH$6JIR4j7pH9!| z1|Q2egcr4Ufm?a7UQNcK$2Ab%kiLlS{|LT7&jUR$9W@qaYM~< z_NTjrze8^-d^WwS@a6QO!ne@p2|q{=3IC10Q}``zG8otCxpu+dr9ZcXz8*c*=@;+e>(%!M?DLA&bmaAQq`RlVU0=7Aqw0rxD2r}O>7#;@SvmGJwSe|IfBkOGhLJZkbf_K$?OzaRb4Z{e=5@V-F( z47c-lavR)z9A1ehVovOUr~C$QMnAa=9=ri#c|w?R)2dd-~J`I#@`{-xpm$am%Ze3S}z z@pbZAE_YyOxc_G?cQO5qL2zFu^ql4TrVNGWOol(m{z~caNDs_UPv#4&_u=;VUEARG znJ+Y&z6i^m#`XI0ZFt}Y@-3MUjDbg&ARl)h2KuHS9{e0$mmcB$X2TJ<{{D5RFYW6{ z3t5k<``FokWl>{&X(C;3M_0{|Bq!2vZ489=`{y~d1aDNN^X+u=}3x9&U`@(1Q z^VckH zd9VV@kJJ0Wf2L130gtSPpX2(j`Gx)2Sng6Tcjd2e&pG&5`o`bju07~k%%124xVH<& z*^Bd2<{~`M6uzFXdsqJfcmIz5ZR}rh4et9DK9v0*Ux%l(Mvs1d{_;QY;2eyn0q3XH zzwpR-cqw|2_x;QHmgDDgo0P)!7@nQ*?(|di$Z3p6?}tm8BA+-L-uiwF^mGb)Mx#gn z4$*=3a33G<`f)lu6&_rT9zCBkJF_Qb`miqWzyWx5jb;9kCd$gK+xu0?-s_T){1 z%lYiw5uP#_`7ZZkKutTrLqp-$xZDR{f_wU4oX6*OLi|)` z<~L*flQ<9Wzry|n$fvXa^{&i+25-p^s5*9o2O{tQACE6|ho|g<*W&x=q*viN6R}?U z{a{}&JbDZHa(o%u>oxW_#W*Y9hk^dx1MYg?>}mZv+!~I&e%`#A2KR1&ujKlkd;=c# z!}W1;aesJpuGw>RAly9{%XLmesjgN&_N+m^1N(F6?zQkE^!#OnurzAmcV-v1*!-?)qU&xgW;Ut_uN(bI;(eVgDr z=}!-bdw0V>ryrtwxc>~N&mMt%fX}mh8ni~FbGbYowqm}}Nct}HzfWI6Pvrbep*MXC zdH?swpQfLrd-;B(AARg7G52pM^2)D0r&r+W0*e!|2+?is*Qz5 zF2MEqs7L&8_eHpVf0R859-N2$rwV)8PhrnOcujh-sr0Szyc|#FG`_>cp@YU*lbga+6PAIp}Yvufb@t?RK z3m87x{(sc{RmA)5$;$0~;hA0M*luKe&`T;KXL&=V0oZIs(Re&+RY;7jID ziu_jQ-38D;g#C#D^yi9v6XkY)konQfZ(zRUNOSvsPfrwnlAa>`3f(9C{tqyofbi1F z?eRp5Vf@?hbY)GWN47L`M!1yY%vJ8(KVkDKN8I$bAM*R}!j~#{=Ce2YQ<<+k6P{8L zeqSE^hedQZ^ZM~yaTfC41T!C0ZjUEZEcX`k?$H>({=A^_Y~&or^S?YJI{`YSb z^I0N)l=-m8|E}ELF1{)l&kH=BH~Sd+e6;}ic_P0}xt;eiKaJx#xDfeFk^fD(ozG#ur_KkFKP>ago&KjWo(;@D z_bJ?66Fx96{=;15_WqM2dREdCMvLu2?<)MLa{F(KLHRs_O zdV=5dR`e9%uhM%7A3~ode3Ei|oZ(FvkG>A=0`rSS{$F~Q@Sh4=A_iIaR#AYP1UT&~U2R-+}HE{yKfL@KMU`{&>-UgPtUOPzcLS zP@hl!@81OaG~pl9&k6sE-fz0uvyJW-enh#mzwzXz6Nh& z*Q&oW+3+aeH`S-l`W+sgiF{LfhqAceRLUxha~@C7k9rgySp*+h82t+#g9kr_S7y(z zZn$SA{FQvj-*}w)4AaXz&;A*3AK&+l-2zV>j&Z)h_n|iqGXFmOY+m&DxeT`!!1eX0 zg-YN)PT_@c{lRToNqEXJ_(YEXKq=;rz~`dgs{Igs6MR}}{D)2+xc4gD%k%1M8?*lr ztXDnG=aWs~zGCnpT<&{K;nAXSz1+*q;NgGK{}5k@r1gd8)Ife-UX15(KX{-ad^@kp zYB~U(@(jFTKIDHM0{1q74`I(s!{Cur_!fHhaJZ)}`~4d`*`>BpY%vv7A|_y-*43+j2u`8=^GT;ETuR#jeClLS|%S)9LMdt48b$ATP7%%c0=t;t- zJ%gTQVRJmSlF*YS@>%p;;SZlg&t$n?ju)~#V!amr!hSK&2b|weRNu?y^S+ncWm7ra z*UKw7r*sKKFs%n z1=urqAUrw^kN5lNa~8oxTYNSx;%wg~R#abPm@ofc!c8DhB~DR+(oMX=lj%y;`79(d54hkusBQ+R$- zU&mf#IXooJTmD10c%D$7_v`;9$8+19hgFWN--+9fSMvJ2=vC%3nb)6d)LMa_i11=L-@6tbn2&kW z-)CvE4j$#}uEXqqb3NR96!}Z^B^%&=7y7k(H^My?;pLe>MEB7@q|ePn-t{E%PtaXo zvxlxF9t0AxF`JDFV@Hd(FeT(@YaUJuo z9wE-(TE|ORIfZbX*W3MXdR$@C>xHpDxP>R}zZy$63UPhYQ?L*INK zzW3*5e&$Z(%k{wi$=$~~N*~1U|7w4D7siwFAjYZBH+FTrkX5S!dWx`rA^ixyPu-6G zD|^E1NupQ$4*j|GM0%Rzg)I5K-7o0_`FnyDng5eL2}LnZ-T(A%^n2+Z=7&07$U4IB zQ|otU8|icSeO0~;wEm&X@8LeX2lFYvhwFD--3OJ+UB>0^peMU9PCcId-=jxFQ&`yL0_QD??G4IXZM$|CUf4xeBAYST;1=2<0;^b z%CbWAv)sOVf4D{;!0QC`yw%;0@t5L#0}|LXl0J>!Bi8G?ncjilQ*O@uUHZ}em>>MF zWj+5R`uil~_@M72F@Y|>7r%!tzZYEi0OldNIQAbs4{hmjCEm?os^!gsA zS7?v@M9GD1UQTlS;$3UM~FMkmI^8N#T=w*sy z&-L_FKECvEESKK@6O5!B`x_iW z|8VXu(*43`(*wen(u2akR&Jk%^oN@{Yub+M`^`qUYa6^3=W|*n+_M8d zn-etZYk2gr7n}zDyOW!g+vibtiskOt`Q7Nz_l<9|3HhkVzogt5=YHgy)=%^t(|PucW6#JidVFWl^9#M=HuQ`aJxR*#@u&QX zd{^erGrw5mZ!sTYz60|Uwxd5J@)^qQe%D#_A7Q@h4tg#;gC3=OZ^0MS`|U*kX3;-Z zxikOle}efRcEP>p&~uaC?mPN#@apul^nmbwyO9smD{=pSaSxY!9z8wSQ}ug{^PCuG zBjxruy%&&Q$$YWB$mfWB1?A4XWg|a_`3T*89X^!f>E@h3Q}-YE(A=MW%I%&Id-UV_ zI^DX6p1;_?Y#+u`LG)}=ZueNfBR`S(`TOAk`VRUNKcc6p=&7UJnTJ2nqpwdsPWNAe zf5)D;4xq;?dZsJ4dr~eVf0Fr15#&dUd_(1SKJicF^?v^3LFDI&d_CoMKEV7=_Ftrj zxZi$GAN&(~mWiGT%ANJSg5^$P{?|kB9C|!`$ziyQ#{uoWBk)A}m&_khZXX}QV!7v; zk6y)cTQToFiXQ74d>H*C-B16B-uD>#FNyv!%I) z97WGO(bG@4{rU2qovWOj+xcJ13e%H!nO^z~^4TKapB^XjJLw6+%lwM*M8$ZjD|hyv zc)adv%kgB=ee_fG-p&U!1+8VX&F!A9-0q1yj2`{^Wb`?B;v?`~?Afo}-tL*AC(69P zjM>xRJbI#ZeV()S1@!C_J->&cjs1z2knbh(O_keu zKVMht@jP`IdB4avpwAQDj=ocPPkOfS5%eM-ne#K1?iRjKxjoL5YM3|u{wV%WjI*}L zS5@xJTXp31b;z5U?<(>U=B*mY>*w*VSJ0m>@;>@3;p6GcglEt<3tvHx2oKZG2|ujd zS+By$&X(2J8K&f5oJBIs`RqmSB|M#;E_@n2AUsIV6uyqWPxu~s!pG)#PSP6+&!Kk| zp7$!&D@}Mj-7mbVa(jLPU9lajbN}x~57QUSu%W{I8^%zJyIXAbk(y1xwOziI(2 zp!;7~t~CI8pFM2#7gTN^$6RyGd00nJ7rsZief&?}ZXV}LT|>`gk*}oO*&l{uxh1MN zi?#YGw|mk=&o?^%0LI@FajUHJ0lK1m*U6MYmzS zCO?S@8ll|TE@C_f>1o2N<)X*)khxwTD!2EC&;oNlm(VW-P5*|T{;BCd(#w8k`mf6E z@rUy^cLsjDEXM!jEp8Vv&SCU8@%rIA`ZAG^{|7yLguhA87QR`zy}q@@I3x6oMdtX= zDR;*I1m;a2hbR4uo*a??M7h0P62$n=Ghbw}+5Zpo$s*tGHu^I~z9;><@DcRX&&~d+ z%I)!_iT>lvj~DsN^nJqbyTk1zdQz0z^Jy(Hm)nc^v|Z-oE0dn^o#_w$$9|FTP0tp- znI0#4O58=yGLe6izDM{r<@Wd!#rTgfpDg+-s~ddT^Ep}gJM=W+$LY(&yj4?Qyt4Nz zKaYF*{QPw13t0uNePTSHDz}%rO!VKRXA5tqZpdTj_XuC++^DCZb$zM1y*AU6mzf@+ z`-Gok|K#1~c5Ix7;}jlLZqM^9(X)=;ak;tNJ?z;ddaC4Q{~mL>0eZH`|4ok*`L6lU zlOTLMJz01{e&o}HzfYem{JL^`eS>1X;tH@wjPo_+c0TC~a~_7#y~3xkCrB++D z#c_Rw&s1(Ncc|!JO0WH;Ii5}QWZ?&t+xv55503Nad7ivlhl2x{`W77zC!pVdcs#`-YSIUHWXe`xxHS|e>hH#zZX5{ zU-$|xe4TRpahD*T-ybN9p5SfdUu3>F-MRzU*FW!4?raw^p5x5BMZTW%0}}zWx=5Y=a{h)CMSr^JpQPN`&mX~h ztzpmeF64tE|B`Y$?=FvgL-zl{d`RT)GViU3d`af#7DNAGkzc9YInImY&s}=9@RZ`n z$9-=eKU<&1_3CanUT5n2W#v1^>)Xr2_4|mQufT&(!qv-T=Wow_xIR2*KKADhJPzE- z0}tdyc@b za=EK&!xL{|{Q2lV)`5HOLw*Q*9!-L~s=)u_I6Ksb`?AsVH9t6C*pQxp{A|w856{8F zpCW&RAE4%I4EI(OxC1+6Jh3xe?+8nnbt_(8bU5Wa!Sop2fMNrLP9!gVdh>!_cG>(2+DamV(YM7Vc5 z&i5YXJUqCA`7q}5T`qUSZ_M+2k?!ApA-12r3J+AqcsjAC(=~Wb71LY(8#`Yo?m=}O zf_lCa$CIHYaea885RPN|de^a2;VC?Bq;S3JsPA#v`-z{=Bkkx@9>MkG5jsyNSalNM z7PpsP-!nsToq5V`t$UBxRTJ# z{9eb^eS~T*bwvAD!*HLy1K(nMEoQ#uc(`vI`qgO%=daHcxOWZwMb7_U>bebkoI#E= zi9LO1BcIq5`IbCB99{&s+QW~qzx)b#=zeU+ANe%-C+~k4?STA5_J7R#A4c24i?OG> z`n?T%ySNhJ5AuSf1@xR^*uKSiJb6f6zhdXz^^w0#e@|TpWBWwTPYW)$Xh~d`p7DdZ zT~;}+uA3F}+@=(+OHUO(t~Gj+L{H^5wimK8#CD80uD(YgdOj^F7#(${9`}Kv_ z!rSvgs2zV}{K?|+*zFcPP55PX!&Q5ICktxApoy?mYd zA@^si8{FLpv`UF0dDd0KAmrTkv(*sulWbu!_VpT^WfW;*k1|bY{T)N zrRNB5ahW}Q9{<1m6?ot|^yur;2Ij#1&%>*-{|-Gw*Pqi(yUPA1$XDn5`~SlBO??de zo0~m5l-t|O*9`d`-2b~=V^0hCapten-7Vqzd%l6|$fvY|KgI1;?FQW68a|9Yd+8Qm zA8N00m*eS($K!lHf0fEt+8JkX7pI*9e0(?22zgE!Q@4*M~b^d?(OFR2dx!c%p zD{?&l#o1oM@^F6iJ#bt`MYcnvu7{;0sdZ9 z9Q{ETdaCexV?M1}FVf}p$#dxPI_ID1^7q#sD~A5J&J}f*sIMRHL6_HiFQLodLHnJ4 zhV#jnlUDWO=$F60HkjUp*DdSsp=@xxgu0It=0C{C(LZ!=4Y-^0^IQqePaAA^J`Gyq z=*^D6pJe_!y8PX=LM727e>bfyU4CESL%RIFz)`yVzQ7};&@aC)(48*7ukjgOeqZCf z<0ULV=Rtp-Ub!^-m~2`iF_d5&`4>OW-nm#{)l!!fItHO6su ze~f*2o^>;Sgq|+ER=nL)#>x;rlb$L3Dm_bh`-jn!EBpg`JYNs|-*}YU$J?NIUTF9T zTs~hcqI<;i#d39CDAx7Zhm_mruYAuXJ2RlKQ@T*XKCr9LXT|xbTlA(OedNK!6)uUq zSNNlJzwjFLu<*w8+rm50lUAF{?M?3|e1vj)y+U=cUPm!ZYj-JlP9t-DkC(>y1ES{- z`bpvc(eth`$5ZSf^tgprpeGA|hTcnfOXbe^pTRiwb#W!);hx6u4P38m<@WaSi=Kb! zLE#TRjQnQdkJGb+*QQ?=-kk1QYtBO#dR5{5=}E%<^p3)3(tX00(5DIiTDd)M{%0{i z)j2;+AHn)A6Zx0vdxXD9KPUWcy0y++-vGU=@I~|_;Tz~3g?~@?2|uaaUazPJ>!m-Z z-dzUkHBIDyre_GhOwSZl3d>&^MO|55aJ6<&&- zCOm;YO?U(PV&QG+>x92X4+|ek&lWz3UUq{y{<-vq!oQ;Xgoo+Vgdd`Zg`cON6Ml|FBYCd4-3yz4)b3G}(*44V)WZHYOSqdJ7G9fvSa>o$TXpOEE#?vbZ&!8s>UqNpz zJWTfrKTIDgJexjQ_-*)V=MTez2=EPN<^sPM`3pzwM0 zEa4&gCE+{i)*f@5S@cBVmz3MDW4$BsNzDU1pSiFO<|j?$*U~eD@20O4euAF(y*ZvM z^nSwg)Wvd_34e$l+H3Yyp&u6Bh@K<71HH%(X3y*N1mUCTO@+^(dxbBej~2d>o+11P z`exy$>Dj`s(ev&z$6w$X%$r+y8M;S!4SJgJCiHaSFVi!G_oZhFA4|^?K9im+d?`JC zzqwwU=t;s4&{KteUtBb&CklUso+5l8-6#BA zdO-L`^v%M*q@NW2E&aCeL-eu-%z3^*uPXdsdaCfE^)PSg!pqY$gg--HC%hFsBK%eQ zN#R52*}^B$bA^9GkBgY=yNX^?_zrpn;m7E$h5tcM6@HhVCcH#_&YSS3=t1EP=qrS` zqi+`8lfF;*2>Ny5Q|a*s&G}hKPY}MAo+NxXJz4k(daCd%bieRC4KP0e;SbT*39mxm zDZCN=u<#D_T;Z?N^ZsPc!zj8-_zb#R_#%2$;T!1BOg|^QFa5gkv2^Q@IiEA>C511gR}j95o-F(Ty`S*2^wGj^(x(Y8 z{4C}zB)l9wEW8#yBD}eB`*oDB0KQ4B*Lv-9JpU&ANe|Dz37^#%9u!`%2|OhH?WXXs z@Z4tbi14P(;ZflqCBt**`g~(vb%CP2UWo;+_ktJHh>hF;4B(c>m;-{CM3P$MdVZczv(c3SNeO>LFY= zn|L0+j?ep^N8z$(A+HAxC!0No9!K8y63*XduxI5H@MsG&f4CMr+y<_HXR1qGc;Gm^ z1jm{13|x-$FS@%Gmb*lczh3NoM1Aqr{yaMH3i9Ka@6tH-a_hB#yIW&C5#~?ObA&f- zgM1F>Q-8jBXbW7C?d@;QPmf*52b;k4?=!C21CRcQ@&Cl}_JCwy^!Tq*Pj$CzgA2YvT4BXS(%gN;_GIAj}PD}X{N8P zgX{Udm*IZS!_m6%C|%#DrFatD^C$A%nD^F$2kHNJoU9)^f4f2Ke3NIHzk>ep?0@Gu zxE#;cMzQ@rPi#+mKDMVdiS4tR!Xq5dR~*mIW^jKF#<_!j=Y`lk4U*w0SCJpg{OA_3 z^Wm1U^MzW&Bka-hpV|hV_?Nj|mb8uS*W1PRChcSU%ok((*$%P2cBj}r@uk>){AGB6 zgxEz0ZUu^F==pOxp;c}j{hs5^k!`RR5 zqWAM*!|CF$Aw2P4hRbn2xg>VJ>r%LUe9c}44|1G(|2eoE?)%T&?s>k1 zM}${f5xc+3SMbEUX3yl6v3o<~_QheikIU`N`T21h zJW9u_cgrfg11|UTt~+D<%3ZPjzTL6C(H^*b{(AlU*dEv$+c*6X+jI88<>Rr&kFni% zAhxfK#P%Bp;eq?H9eZ&;lMcnsk2xIMcOHrDg^$Jd4q37NljE`d?9Z{i>dDwX{Fm6i z?Nn_4?=;-XgL%;BA8MR|hv{oMKmC4<-Lv*=Z2$Kh+@IHcytFzGj|yLO0q)6%{1;sA z_3YUFjed{qutz^$4qk%G{kGnpaBqHdoPjIwF#U6mC!)T`VxJdsy=A_COnMm} zY6DN>`^WHW{2q6H96$AWwmZGxk=DqcVE@e5;qDL2{{CtB9(PI)eBX*+=d$X(!F)U9 z*R!WkUoLk7d?3eDr$0PA(eydP;Gv%}&fnPc)?0Az95es)+wjOorvEV(Zhd0 zGu8K_?EN8!`-7h6*A~FNqs@HHPvMcbP0za+?ip+Pu_bWdIMYMR;n8HXKhT~kdTz8>zMX8Pnzc+PawzxW0os0Xjk{U?1>Y>(R<+b`b3leZ!tJc0f5 z8vCCL+mDM9R$MK7?@6Cu>hV4Dp<5V_KL1u=KYM1u^?A{$hd7>hOrNd3pJs1g_gvFQ z9)m~4`KvdN!^1Pp{FW2&kl*zEr{KOaST8-!0jJ^qd~khUbmSR$^h2|!-&weKhUq(g zgIgj$;a|AtV>3VH4tqW|ea2n5KWO?i^?NY({6y!QUg3VYw*bc9n8%+3bgPi*qw*l1 znAh}*dEveirXQnwEYtn@kWVRWde!{!=>4W2r3cHIKB@rn?&79bi-QO6V14y^9ia#A zGxK8#BJVG1dX+-(9JlEay7wW|rxj-YKXbWtioji^&HPn*xTNWeA3#17XL`E_;l3wL zzd=vAZ7z3yQRJgFcyDOSKf6yZ?(?2eTyyqHvhHyWru6~co-mg3XxPF{QlHiGl z(4+68Qnw@Adl;_2-`CVjXMQA)8<+ahtD*k_m)o{KJa7y><>@sB!+lHPem9C{^S&s- zI`ECmZ|8kce1E|8>+^S~q9^hZJW>EXji;1oHe%uEps}EiW#xegn{agWj{-QsZ$)-OV2Y-P1Dh1F} znU1~1vIfw-X=eXw<@Vz-{1nF7o%7Z)4j%Hr_4Cwqddl-~{k-;3LF7}~oB4W$FrMp0 zF;4rc1pDu8`c2{6=;L3*IQ8q{K}FCX{oS0mZV#aUNOAP*@4t^OhP5tWbdp4ThFcI#~G`&MDxPOP~1J&=|Imh!|rhizEJ>Qu=yaD~N z>6076ts|x{X#@`+HGSXnaPM)`uQ!8xem32$?q^|-(|yA9MlIpNQ>J@c!TqOApVk&0 zJ!|@kc5qL&>9y43*sZo9q|9zArrdnwdY^4<77c`V&K$PcwZ% zI^6drT<`xwN5egRO;7Q|UHwe2Gaeol{?J5tsK2?~aRIo0w&~Fi;lYKb-<}C~FEYLK zY`C@9^jdS^QQ;{c!NZ@M`TiO3;1bj8&xQM!nqF)H+`G*5`#*zwmYY6l2|Ox}8?C;8 zhgX>S0;}Ne)uxwQ3lFX{{n|RXf4%7qzkyp{o8EK_JSsdj3=e-}<_GS82RE6X_8r{6 z+4L^o!@XNfZ@&-j*=l;r1911ZrZ@WuZiP*6tZqbUKaQfpn`FVm+syn6C*Z;Drgu68 z_wF>kS`=>WHvPXd@Tl;eXW`*JX8yh3;KA=rZ+`*q-)nlAi*WA`rn@e|J^M^weFg5` zZ+iSKcvKue*WZB$kD2+I_wjyiS*B;I*BSOaTPIEbyf8c}e2#klw)5d%%=|_d+#5Ch zcrm!=jOnvW!QH=_-u7X*C62dO)qU-p<(@P1<<#%C+aCPQ^xhTV{`01yzLqubTPJ z_27x!O>a^k9(c|4YC+n^AL(g&)^K=~@3Zvl=lvnLypGGWhRbba_WVMZ`IpwQ z=UFrV7d?0q9^~t^P3w{OJ!j?*?}mGx#yr2y@B2Kx7w&J2yng;2wjcKoOgeyfaBlXm zJTK*^DlVd68iP$bZ_uJhpDnZ7t2i-KB$a+e?Rp*;Np6!N-c1| zL4Qwk|GB>Q!)W7p!k0dnT-g%j3i4 z^>Fu#=+W=@eOu@?;GeRm-Zpq}AiM|t6x}rluD9>h?a2EE!@pv_BJWQa%*8k#ppUwZ zyj2z6l|KFs+$+yB@cw@O%gEng{yhu#zjE`q(U-Yf*yDb9;geSO3y6^&v_26&%af99PVvm_OyEf?rUV`yH#Yq zDSR?d1U&mB^B#B)E_cLJ%-4qN`+U|+fCuSEn0HlzyIUatf7exNe}>CtzC&f?<>wkt zR)L3}MSd;wcj+lf@S5}uRoO!yLr<>;chy6F2)#vhc$nUw?y3P#tdD#;J&PWq>-_vg zd$8@KLZbNe>=c@i6nSpGRFTUJwT7r z_4X=U5BW$dWbK0UEDye>VVKJq@go}Xp(XglQf?{C&=fV{gsT+dsW9-u$QrVUVSdPS$cO2R=vE`R{JzF)y6a{1EMvZm zhduO@^v~$QROEGkmBz@YbT)gwpj$ltcVkcW=aF}JMPBc>E9n8c-ft6|An)piyxuPB z={~xi|JF^BkJ7zdZkBR;zun5~+l$f%G=neUc~|YL>GgPiRiBT&P9I3euhm=DGcTa$ zD7_H--=Y^Ni1U{D=v(N^#PtAHbMzDu`6l#Y!Y9&8)A=&T`kr1^c#&lEKOwvwJ%P@T zFVx45$kz~lgkG2a0M{$N1@e1(o9CZjp~tE7WcFVi^9$%r*i(>xhTd9ug_h{=MAzHv zb$T!1U(kop^>(>Tf19q)CnvT-|75zpf9w$Yr@}YTzoGN#&bmeKCC+a*Y>oac%j6{ipj!(H|22 zExkNl?^k)+qsQ6~(VxdPr*~&wk8>*BN7w6nfWAyDx5SI+Uq^q0`~S=If9PfCpU_Jc zG1u!fy&YX|$MPM}-&OeQbW2@tX#eT;`jS3}d3}7lLSIV9(k-i2NA%Zu&>YVQ`arrK z&n9|kuesd2^ySR!Vr{@Y^zpG1!r$Il<=Z}9UbzJ0WczJ#7#^oKZ~9q4!IdYm88 z8>sVJ_MhJWPtaQkFZVL~C(-r((~~}juKSnL-Re3}`%lmRAM`}wHB!;<7oQ6cp&w$u zp0|zkbHe|n-w@uYGy3zZ^LF;1?s=EqoUZrt-Sp1F3wJ?JU%K8;+R-PA?KqRZig|rJ zJVxI@*YjEC74!$x^{w`wp0`)&e>1P=c@e!1U$2&O{*`52ptlrWr7QY_V*eaS|A2Wt zKWphxx*q3E`W3o zy7x_ZA@;B7!F*r%CFa}ognRqJ@6xaJhRf>-zv}~!^81yI*gyGoxcfAE^zZDnOoJyz z;mw&Z`Uc#82EK;NJxurfYWj>fk+;sm3$mwmU%2ZWTz{{*P(OHtu777?FI|4WcxHd( zquJ=0#r}i=*dIEz#}==`alT29uLSqfSJEF**E`#P`ui7u(YNnK{$=Lt4z&BrSn-in zj=1U5=}E#b(o=;$=R;4r@HzAh;eXRJg*O_6o-E-XE4Sar$@f!L2Ezm5eevphc>N)< z^PA~%ySz0NdHMeO`C+lW`0&`i^dA27h}iip_wW|!vGa%S;oV2Z&R@TW``?P4e_&K> zpLq{2H#&BH%{}~uw`1pjzK0JSgS>oPR~rkL=UXg)Y~OPa|L~pI`R?Old*ydy`~G{l zZ+z^0sR^-t^F4g%#Mt>7lVba?_we^7$IjQE65B7|!yyx4x~9=>>f?ELTr zvAxm4*j^wAm(Sz7=^nlg3G#U}`=!{wA5r{e+(*S#wY8Jf=V2CihKJt3_eY*(&!jH! z9J>DAN3&P#ch2f}tHu3uURG}3XT~l1KkJHo!eRXm0t;A2?<)K|<#tc78phL@<7w56 ze_v^|a(kQs(LaOvP)+2IvZu?d$cII~zjAv#foG6!%lxy>51SUW zvPC{cxt)(TKz;)AkH3cgyhqG=sIA=2`#i`mwPWgUC-ZKRKgPVfDe`-m@7V+W4Ml#q za=SmLIr2C8x~_0fy3O+=wkk1kB9?0dUnfW91 z#J=!v*>lu~`DrNT;i7V99+=nf*M1*F?}wh^T(2F2(UU5Ajw-i%Tmz6_$>lB_0uR$? z(fbdDdj}$~Kfg;HhW??Vzln0YKf=5o&sFCABA<6S@}5EHKhNbZQEnf{riuL5%qI>; zz8&+gjzEu}-jvsefyFa4zOU)U2EjUN4ZO0&1olPmJ6^peNS z$8TSHlJGIg?d|IshyE0f|HU!rPZjyz%I$nWHl-v0z^ZN6qA$md_(lcL<- zUSYA^Ui7?K<~*m<6NOKsHx(YFj~Bj9xxHTQ*%)Uhj`Ov5F`jiIKa3t0K80T7xH-=G z^rpgB(^G}-qGt#{PR|m4nSNXNea;hcL96P|=6Fic`w6c^4+?*lepq;WdXDhk^n?@U za!1lrg-@ra3I9~Ny;&YKgilv)?^m;AKmE4w_4EoS&GCQF{!G#T z#6Owa z^%DJal{?$_3*>K=L;qje_rkmL1B|va&=W7_XE{Ar^ydvApCR(yl{?$9ANo7R573h&yca!P__y>7F`h?0Gpo+-S@9OScvzfR8;zFoQf z`0|}G=iw;*lJMWzlO*P$*+=N{{A%`ercV>zU%4~SqGumH>8LrM)iRKe7d}I|b9@l} zip%=r{vbS`?Vv*!5AE4Rm)De@=i@jsjWvp+#TOXO4L!E=Qdo{!}=70WHB z+}WSS`i`S#3D2hI3U9LjJ?X;N(ldlVyb$?J;bWEC^E~>TIX^R*PZIOcDahptfA~|b zm+(`{?f&%hX8&Kz#~(B2x$|e}NfN$Yx!tqug4uJF`Baf_w20%(GW);KF7l-pBcCCB z96eL`pY$x@T|P%ouJG^Z@nSqRmvDWBFQBIiFSHc%kR#^dF}mxbIX^X(+xuIV=y{hO zFZSD`^jwjzybQ~&E&89Mj~D);a{GBC#Mc8$)z-8Bwkmh_f3e($mUAA24^VDz_iWKW zj^6bTbA9J1x0mbUaw|DYwXFC5E9iXQmva=ayYle)rBJ>?j)zXca|+@gJX#fQoq(&& z=ltzn1W$Y)ejj_vd=3vThM!>mjU{mZGWZqx!<*@RU-JY{;LeUO?2IR{+U);%Bs^y; z++xoIYv?oKkMlf9%eC;}XYgC}k?Y{DRq!D^pYYEvxOX1>8GgY3{#kg+M)*wTUwOQU zGtS@+xL$6RnQ+gC@Xxv2v{`W93V4t`yFP)3=EC)L>}S@pf4$i==WBS*HZwoEB<@!n zxQW*f*Ev5oYr-Qp;NNmQ^_#%mkK*;}PQD(yoDBEmho9mFH+5UH|6lYhD}?>wkxmad zpLb`7L5UHF$* zaUYeyUd(4+Zuc_XaUXza0_LFxR@a(84j%F&ug|YO_AWeU3|!Cim`U(p1iqZ}|5yg| zyWtt!A4>4P5Gg;w)q~mj>oMH^zP$P!aE{;0@iZTS@6o5Zab=F1p6z%E^}D?|@@TL5 z7J4#IVm`ghKRgOO*`jB&<0UL_W3#9581$ryo@aTb z9*6NP6FqOeiypV=xuU+0>CDeB=6e0`J9;LIo}Pc8#}Ym6!}wm9wF~qAFt^vJoA~}$ zJp1*0e$^4*d&>D5`TpEqc{{IRal9Tz%+Iz${G728 z=HW8O-?a$bUB&di<(YpQ{rY=MM|;7&Pa?1HEAru|@Wdj>&*AZ5^ylzMaria*$4lrB zoB54P;XXIKGV_sT@ZghX&z?2#06!n$v|0Vv!YzJYP@U^rbR9g$ho0v2EP9mZpIzLJ zZ?9*56!Ht1AHRY9Kl*a8>h`$N*_e$)17tEadjR;od4e(wz7#!=ar`If``f|`&>!1_ z{#E?l0p0T&{jLlBdc79YFBQZIoBz9R)A15kg!AKLf93Bn51!{RZ+iUw9WP{^Quhb4 z|Md0zA^I(K|4aK%kMkP6_8D`%>h8t(Z>al6+JE}`fsyo#k;vnJEo-ymC9D*VC+hqw z%eqTXY-En}`5!obx?Zmd^pME!p@&7j@ILe;@_Ag(LtDCsuKPcrheZCc*F=9EE_cKVEZ0*T-i&@pxxL&p(Q}vi0Q35JWad}s z$)UGk&(xLduY-R5cu!k}{-L6OlyZB1ymgVsv%h8Cpa-9U_hSFcA@l@A&ztlW!rxZz zyuVIDkN#d;Ha$=ezKs1HSEGNA=y_ea-Q%f`{1E03F@H(q&odupUN5)98uZ6qHutMO z%I*GO1N0AM|32muMgBDNu7=3#&v~1#MSnw)@1or94=}H{*MsYjPZjycmD~AnWAqQ= z^W7}w`-%KgdPw*;^pnE(v)`4Beto_4uJssC-apOx$x?2Q$H#mM=V!$RSp9ui2MTOcHU}*e*HQ7pe@Mn5&7}T?Yx)yOY9GA zMgE+~?@(^%Q(Bw-^S(vieZ}0qA?0>HB=S?j$Tt-E`O59QtBu+J);8o*MgD!|cHYPQ zV2*#mcI1bO{2F>d_;>Ub!hcq7_j}u7Jg@NaQg;XXGey27JzIEpdXXG+eg-Rd`a7ck z9iC4+$h=$Re`7u;75NwJVW_{RJJA#93*W_Y&Y=g#wsmqPo&UA0zm?n13%x{tp_I7da!giU#{i?zDaBDmELv^~_`J1EM-rv@Vo-gRx!ne}h zH_h?S3XfPPP|Ii5%9 zLxn$0Um?7ia_931G5$r&$K5jfH|l=jKPb1y@412TpXYI`{636xpU6L>+*#j$kau1l zs4e1GZjUEjjOQ?W-2a&4$!1T^9dq7l@5ge}L_V25Pk2}QVc|Y{;=kr{$J2)j&!A@s zUqN@@HhaR#?e)zN>s#hWj6YrEYtS==H=$n={xZG79do&T>3-p3b-(bL%I)ptPr`nf z!8h3FmD}Ub6ytAt0G=y+F+EFoz6jRW^`AM;hn3sQb$hT}{kR@TcO8Y#Qf8Zd-C10P2(DYuVT0rhYG_wP;S6Mg7O<%x_;dY}h-M)9~;@DRqCB*xi8x!v!(&+H$r z+#Y9O82a<+i07EEo!9KoWj3Iv8 z{U5L=Q}kpr?-BXi^u@wm$Fba8;T4qI^K2Ez<)6?#Jn^ zg6Sy4{&LQua4DZMNVFEp6 z3cM2iSLOEh&0E4;ufLT$`;XXf8~+B+68=6tSNLgq{I9E=CAzuX#PjG$5vKBur@PaqoB8C| z;Gs;oUhbkEaQ6zhUhb`)?AdDeywV%)+D7McH}|10H}m@jz;lklpX2&g^ua@W;j{QU zFnthxH{9a-Mh3&J9JA+{q44mpW>3a2`f0Q0l6v87e{Sn3iq}ikx!eYC!+npy^*G-j z1NU2SJ)V3QIK{FUBePbv5<&QI=ixTluc-+2Z+C&BDl7ob;!>*Wra$^Q0c&(E{q zp=M@JgE{o)&7RpG!Gr1WLY(Kz8O)C|dz#K=ej0o(*K5HiaPM-n=kIxN-wLy*%>w4P zm_6&3!lS>#o3j7@>+^_Oy!*d41KV(nmi}1*J`2VBpzQdfT z-nW4deO+2$DN7NCrbrEa0hLgcwLt(81cV@M=}|fgj*5shgMzFe7!>J9khXwgsIF3s zN*6JJz|tdirM@${@AF>2^IUxQ552CBx6hn&=FFLr*=$bM$v6*>en@A|j0J-_h| zJopHX>(j)2rbf4S>?)?ouN8MNU zfcwtr-enNnOhh|P&YvZ3zyr16UvWIwk74~6;l-GL{vG;z@Mm~mfAC$nYmM$-%z~TO z;C)zs;4*k%l-{ortKhMM7@t2mo*h@ieJ1=3&WBR#nXe6>!f|*d10G3*A7J}W6~ud_ zVV>VDdSXewkNPt5t=Z1E+QLKS(f;-H-E@B?_*-n}pM3AMvp7FCc?IvOjut+fo-X{> ztH@^vFS{1)iSc@=JGcAB2KW(v4qFeWP2)1%-5LG*lKuVQN94n|(0=v(dGmzc%(`gxhuBhI`z)XXU|ru!lvzX7fGUY~fkz{o7Oeb;#-heE(MX zgwloL=ey_-^mixcL!T;qFIVIftMR>D;Y)fto@flW|30Df!)b1uqrX&A_iC>rUnN`j z*1h3w`|nFQKkEA!C&fLSKGr`M_e5h-b+q54Puht0S4}_OJ5pX` zGwO6ctJk>}_e3MLhF)jJ_o(B0L$6b63+iNZzxcS_2XRj{s*3h3_z`u&L-jiDt!&Rf zdV5N2bKGu^sFM+Q`@LmRr}Ylh$q;oa?L?h4QD<}9?Y@ffY4{WCi1A6vWF0X+E8?DH zgvIz&`vrAU&glJ0*o`__qCH>5-ENPlQ*kfqq>DPnKGaDN?U@sI`+K=XoiY*D5&P?Q z+!Kui(VkhqIr$_bD8{+OAE=Wp+H)iB_I?-b3G7E5k7!TQLDV@c=JWNq+wX^q_RKhh zIzF+#N*qC*(W1_+xF;G*M4g#O*&b0RaEW!!>HBNYW#lc9&u#y`p7{6(AC!dmzz>T$ zFBEg!o+l!InjRHiwj}DLoY&iPKkoLrB*t^D{hn*QJ;EpU!~5#tXR%(r!1XFQ1b6d1 zwVKE8_1)NRau&90(NAAS-qQ+oUSyr}eD6J-d6W4g^bFw@_;*qc3(xZ(wwo<{=3Taj z!?>yyjMKfrpsigkASkPq>G{|nZ6 z@Fu(f>(rxn8VmP{b$;UnxJ#__^$+9y_V8qE7ptye6#I|w)wf4G)%C599`?dJu$>`# z=x?0&N6<&*#{0k)pG!2QH_wOnCsV|Dev<(2Ec^q$Z<)b)XtBS)&{Hnx^CT&PIvK*d z(^D?$`6F>pG@j@Aw*u>z{>`bAWTcDpub&xA*TeT7JFreBJxU)%pYR9rzIqr> z^`2hS{dB&^s9q=y)5Co4u@>vRegOFp-(%cLze=|np}x9)c>5soF20wj-m8E55In~B zlzOqw2Zx<;NHoIs-wAYn%=ka;&)4FfWK?abpHCYfVS8S|eCWsvh}E_`CD$3|x;Dpbwz`Ojq?+(#zU^7u5O5$9#-_uot$g=1;vS`*o_YmLEy4#5%QEXCu9B zd$dO#k9X;HBB)c7`DQ0jzdK#!-=i;h5$*IazccRky4{oGp9B9P;iOZ?p69Q_(F^N<82y}JGP!=0Z>%%6+9{rg|suIg`%(`bL^zIuCx($naw{om1D z{q+0|x=C00lryNGDe`a84~zU3x|OEa&v6!Y0(4cs6+NZDp8qiJiN?u~n*A%FkkQ@Z>;h=X+b`xm9oIrS3_`TG~$=<@d?zNE|Fk2pz}zaLTM zJldbZ_D9*TGA2^@##=%r8LxF}1X8uuh4 z#5!ubztTGo(YIUlGTNC&SNV=~7uR#O&ZNgZ(Riy5w)+~l`)Azk_l|hpH|g)&pD#S@ z_bgWObBEDa^z-|5+nvurDvQrS@}9-#6d5r+-_dp_Uti?=F`q5!uVucK$nUZ}{<+n! zxV~D$_J5ECHzV*5=_k)&yDy76*KLp2`2_j#e4Z0I&pK_|#w)1r;dEVq2WBE)nCtc$ zdT(Bt!Ru zbpQ9d_q87^$M;KEufK;L-3C|fao@oH4T}BSlD<~>E4DlJqx(>&7KYRKoB5c?Uu8bR z`PQ2GuWq7FjPp(Xer2s&XpgHHt}7Tfn%nMdH^h8hRfqYqBEOD#<9D=k81uEWQNOdu zx3Jx*Z!xcazhfQq!$m%mdEZl*=jHjl&iapaTEa6pKcBjd?PiENUV1`ty}!NaHH43( z`-FdFdwjol$96k&yZh<>*Wt~bX4pSP@1Q*sM4c+O=P=3|{y-?6Q|t4jxZCej{ktme zX8fOqagudbh&nfHkB{d-Z1*STTi(U`)|u;-sx#MiC+{7E{QJybp-1WJeS>H2p-y^C zZ%>duTKEmyo%+GSsIT5P@ZQHbWQ+FqvfastMSd&u2_*`%h4|Ng=A$B?@&NUdMg9fb zo%+TQy*;a$uPX98YNR~FI?^Yx{i;3FY>`1#0d7-x0=`;z^+N&NdOM1Dn8c&4b| z$cH-KOq>_q<+`0TlKG-~`)j@h&l2^|Pl8XnkAA6kcAtg%=4`ZcGp}G1Fy@D$d+JRj~E4d2TAj_v8;_yNJB6BJxjg9*(*McbC=Obs274 zL!HLVFQ7-<$gA(ApMQn<5_+9W>U(>t!c{w;xr)5ECfs5>=hDLkb>DT3^$(yu&3I$E z{W|>-z5bIo;DNu8->p8szKQWqzPT#Cr%djz6}HFU|0$x^sd|g`@9X2RobLG#uKM*v zHuAwU@UfidAK8D$$f+OVJW=PJ&j-LgQ;^@oaX$Vg+_wX6pLF9t{p{~Mh_^Ep?L5W% zi1w3;#OGBu`=!>0tM=!f&U#g~puW!ZwZA{Y@eG&l^XTb?bsw@C`4myV{u+3?@L}{c z;p^y`!ndf;VMm}}YJ3`>M}OUPbscs2BHT-VjQg?WCAf>now~1o?+V-yo))8vI+a)Q z^BVdgj(?L)aO+95^KWkVgFX0sr0T6zak1#T_QIFYP5R7z{G5fZ_SaE*rto1A`ZbrHF8nk-TX>DXP^ao0eH{AIGep0RonT(Hr}9a7f~Y@;K1t-q zoI*ZLZe}0acNms|$I)09sB|PCa>LlFL6Q^i1J%+M!Nrf?nsx_V8rk*Xf-_d#ZOpK0#bJ zzDCaw`I!CvX3jd0CA>*zZufz{AMk7g}+Bn6Zd6X>6yZF_hWm6KSQsYQ{Ru1=$(b{ zrcV-HC=K;T7t`y!NKX~_m6Pd9gzupr7G9t~>L-Z%qc-#u;Q@M@@ZaefqW#4NpnkI0 zZcloa$mbh~d|Cm$zfe} zz4Q!mU37rHMC9u%WPgR{UJ6git8cgbGI*Nsw^qW_g?C&9&la9e&lJ8ognVal{>q;L zPZ0T*^uwb4`L=UB4`4iN$4AvLa_w;HBpKP_J(gB+x7QP~-I4UsVjT<7mk2*eKP9Z*U(1`KTTgEymKb@du$i(FM9C$Heo;9w-f#m{SVun_4%- zeUkQiE{^M0ABU$1zf%w1SsZuA>ci7TzCr_drttps6mcG0PtO+loefcEiMa2++!#Jd zv}a=vy#EtjhvUM}`?7b(!97jj)i^$1j)(i3!gJ8A0Nmw=FXi#oYcAa6{YWqRKlBLi z6V-jqq(x}w=u4~ONjLMaErw_CeIDhfm%)=oe!~iEH{1v9*~0tcyepAUzpU5qNKX}Y z{NEy4e&`x`uuO50nZfqi5uaEMLT!X6U6=O z` znWA57=-I+=(W{F4{q;Ffr?c=FJw?>1mkaqxB0q$lTtwer8|kUSZ_=|wo%*>^KTT}6 zeqQ)!QD+2wiSRY_!@{pTg7>nlc9{Ql_}po7et4h@{CRrQ*PQJp8b|p)?NdDN#@X&X zhcO!!{zO9JT`P*?~Ih^YJDt;ok4z|M2-$-)~WWw5Wg7 z{vKLq9%hJnzVdt23A}+i>V2)zKfuk&@PFB_XScwOcj3kPqSCoA>Zgh0rOsA(y6|!I z&Z0g0jv}8We9@oqWN{rHrKbvi>=^P(=qB6$Ha%1LA$peZkL~yIoc-bw&jVlo7ar#4 zI~_T%4k&*aXzz5fj-pJc>@ub>BnU!kW8?{^b*l7%m$yMc_?UxF;I& zdv|ZqhfH$CM?lTnCfOLDY7gLDIX?OAKdkVu_i*-1wEvES{dudO*VQ~sjYo6ZpWoRY zq;q*NdeD6$zqS(cmhhf+-~r)P{zrR$wx3Tr+YK?lfbDPdKk~2I?&N(3G2hg4)Dd() zoga@F^XV2{y+^l;9-tTGcF)s;BA=KO+YJe?NDm8tnjR7U3Oy=(C_N_pL%MMY{Z;MX zOm_)CKsSY7rMrbE+JDHy8BdS!$LU_-&(nQ$HO>R+evuzfw}j882ZXPu2ZbM?hlF3I zhlLl)jebRh*P=&-d+9OZ!|29gef($8UBZ{qP2oS&-NMh(J#;mm_vv1dua<}NU-(OO zzwo!|mhf-r0pUN10S_oaJ;e@yoZ57T|ZuhIR&%O#>cmhe{efbcQ&pzu}n zknq#=u<*k9vE7L96na#67kW(i`*h<^ef*cwUBZvhP2olXw8t&H2HhjPC*3Q23f(7s zCEYLl2;CB%yCB*V5Z;6y6h4R^58KM`aSE7gMxZ1aW4~QNS`9bukaEl%jK8tP~$2hC)en)o+KT0?0 zs{Pq?x5yVx;yf4mnshH+-H)Wwee`-9he5VG@8y~^@H{6S(cfWyIodUU_2{}SC2{yIG%d^9~MJU|Z# zUrrAT-$suJKSYlTzeJA-&s!Y*HBRW`R*vox-k5F*_tM?MN76m?Pq@Fnu-$p@*DTKY zP#OPWN!$~S=tg{Vf_h#ZW}T?0e}oo(kVc|tep{Wsef&S9yM!;Ko5Huz-NKL1J;LwMy~4|sM!$T*>(Twf+t4lH1Ly(a zQ|LkAi|8TY+vs88r|A*l10N6}rv)9I%0wRE@eeRL09J%2b& z_lkT%S&qN(%5=Z*rgTgAtMq{Iq4c2e>GY8Bh4irSpXd?c=jl=5`5#5UV#2G^jWhcA zKTUTDe}!%e_tV|N-=}+o&!c;VZ=(Bz@1gtYC3${4MGpx7j~)_r3YNn-goQVxM})Vh zM}-fj$AnLz8)x1LV5JdE4&8XC%hHiFZ^}7C42-uApBE$ zQ226sNcfNRu<$?W5#ibNsBo9b`7FFT-N@3%{{^~BcrUss{2jVmc!2H^zL4$}zK-q_ zzLV}3ewuCxzef)UFH-^I5ER~s9un@QhlQunBf{UOM};q-$AtexH_qwff12(Rp0^^} zZwh~m?iT(u-6Omc-7EY(x{uz7>&8lYP~^AML&8te!@`Y9Xn#a_d3scMQ+iBzC%SQ7 zA2&bUB|Jbkg)gSNg>R>OgrB5)g*5*Xb_dWuHJh zP2tbe-NN6bdxX!Sdxfv3`-C5&`-R`8Tf)m#LpuY)J@laP{`8RWkLh9IYv~c;f6}AE z@6%(#%U4G`jm!G@H>10Rcc+`e$I{)x=g~dFf1rDX|3>!-zeV>8FIfZaw}hwA1HxaX z2Zj6TA>lLWVc~1&5#jsjQQ@cPG2wY?a{RC8<6oWb65ft(3Li>$3!hH+2wz6`3g1Qd z2|rHv3y;w);YKaaf8k~6LE$y&A>l3QVd0(V5xTmb8Ax}<^znR~ZVI1GcMH#;dxRgL zdxc-2`-B&+jdAb`uTHmwKSvJ;??VsL)q7L#(xW2(IXy;K&rw&~p2Pl@T+d8AFIDg9 zWilW57vqL+0Wyrg=^?uM{==KBW3rCA4=w0Mf4x`rIu+@Dx;no!pJxW*O5VYMHhv26e2le}&8<@AQ>GS6odVsF#{KYz!sB@ip_jSEakvbS3 zkMLS_ukcoMA6;E%cA-Z^emFfU{3Ciy_&mCCLvQB>x=Z+8x+(k=-Az~52@mKVkuP7D z^MtO(vzhJj`S}UZ5KFapoV%~F0-)_Nr>@Qtyw-P-d^3CZ%y4r3J+vD?=+bzfKj%41Gt#5Za z-Ak{{{35y~@;m4O;iu_Ax@u3}`W%OkF%A`2|54lH@0E4($`C;WA~U-(G6 zB|Jb62wzSQ3g1i*2|rE`3%^B=2v2B${zio-(__Nx(T&^s__U_Ggug~Ng%6^;g}+bt z2%kmw3jdDo6TXe^7rviv2|q&*(A9g459mSR$qg}XA>nR%Sa=(HgkG5QZ7@A5d?GzY zSLdB{x^YJz|D|-7@U3)H_(8f`_!+uK_$|6uc!5S32cPhYbieS{bW3<|dO-MCdQkWb zdPw*(dRX`_dPMjMdQ|uWdQ5of6!h1)tB-$ux=Z*gbd%nL`+XGMq7S0awmrT+2lVsE zx6H?wAI1Dn%zM8_UcJ}xH}n2`Xs62GV?MAMd9@A~Z;XD$m``K<$82}n zS5GtVyN~)R-;;TB1M-zvXAJWZk)O+abUpGFnP0=a=Yd}TH|Aq&_4c1*J|yx+6SUvW zyt>{?w%u9hO#|;msP@-m-n9nx)%R__zZ9x2J^d&i*xc9jLx1q$cxWkxymb!}F#Z zpB~J+bLsVmF>f-DRvE@*=7S>t4fE0I`uKm(yeqd}e-HB!=2d@BF>i_dRp!&Cp?+bG z&m&KA{)>DW+vDRi75Spf*Ja+9M{iGS=G{|}SL4~8`H095XFf0)d37B)nR!oM)K}-D zjdZW@Q*@v3qEDe;e&Ns3E#U*`0pT<0LE-D@A>qgAVd43nMtdT{YtW;@+t6deN79Xa z`uHrSyM&*ho5IUCLwnr9Thcwk-=uqmFQof~AE*0;Cwj15OL!G}K=@Pipzu!gknrL3 zu<-fxi16>}QQ^nwG2yrAMuI;6k2XiYT*B+oP2s)iZsC*Y9=f_O`;P7vevs}HewXeS zUbF?rUwAEgK=^a?pzs0oknnVRSol_YMEC`IRCtk=XlG1#Q@Zg8#$S!k5V}kFS9DYO z7P?#b-*k^~qZQiY6<&ev6W)sM7w)H9!oQ>kglE!&!q3n{!t*?Xc7}zQr$>Z0qDO_l zM2`s{L^l%k@t;h03137vh3}!eg`c5&gx{rm>FT^t{8{wZC%h5eFZ@-yCHzx*K=>AV zP9Le9^sAYUg3S{ zKH<~pe&OHIE#ar=0pWM(LE#mjLpwvlThPP82ht7p({0iMKyu=G=rzN}|Js`Y0Jt%xSJtTY+JuLhRFVJ1W^R`9%P2r{K9{M`| zVsmZVo%;?q@9WilL~G^^7xuf#_hjDB`+9XBI)?dh5j{VJ`2g>`)qTy^%v(u%ejD=< z-ba_`eb7Rpvvyk5-@8BziFpMoB&YnC(t~y{mB_q<(+lY39SpdcGs`0sH%$ zoF8>xKbU!|w4R^Lyxaa>DCb8#_x_4`Pgy;m!Muxkbzc@?-YBQ%FEbyuzrV`)QO{NK zwnKlz<@J0e+nxS;m{;v-%Dh!U&%emL>l@Tp&tZBq@2RBc$1(4GUzhWvo(s)l-l(GI zmoXojjl7y~+n5hOrsw})KEUS;sy*kKx2o!Sqdoc?6rXpLv_1a3y_%k{uJYo!K?~-M z8hXA1^FBTYQ0*DOe7L5bAIrQ~JU5uZyj5GzFJRu_a|2g=R1G78c~2cZzmItrp984* zbDDXho}RzUyr0hj)O;@5f%B)np08oMGk-!KVSlOPy#@1DLp|S{d5d}VoNX-go)qNw zas8Rjyr1h2wqpN14(44=^!!%lUCgWJLPwa7Hr4Z2nGbQjQu8zMW%M`nl%B6-d%VB= zeHoQ+%DmM~&$nehz`SaIKjyv7_54KU{miTNZ9em6OFh4V`52#bs`mWKe5{q8KhM0E zc{M&cJ97U%tLMww9`7<eW}dGapFR^Ie&@zC%yd_mB)@-uJwopUJ$3dG-0%3g+D} z>iJ)o_jA2f>)T1@jW&AzCi5}-d;6RpHU5QOL4PA{^?W1So&JWIe}czXTjqo9^n7pT z4d&H)^)~bV4tjnz^HKYI2b~`^{;Qbxbky^|G9PB%jQ?MTah7>kCq4gw`2h3kd{?p) z`Wx-6=d0W9^w-V28lRTThq~zbp3Dc9AgRWG4D(huJwJp+^n73D!#sbf`8=NaKp#E7 zn0en9sITVFkIeh}>G{8zH$O*S?cZC>yZh_;0g%)2J*`84J&k$;Ez*c3fKn|UAeYW?|^`N%XqzlV7b z^J@J(#eC>vw!|XJN@;~(Cas0-ox{eS|8do@BLKI`%=?3SelPPD*H3l6IL*BGE9AFv zKIiCx_PaCCQ?)*qvfbIg=0ZJRpLrMa>UeyS`PeslegN|kUhk>?zQ=rcv7Qey9}@Wt z<^xOhe1!P`^J@NQG4ETh=kxfuznE9|n~&NaKYmy0`6kSV_~GsQLCZ^WGozd>iHsUVpkco_(1&x9a(c%tv{BsP@-<=40FR{Ceg? z%&YmikNNNpJ%5Jz*kT-yDu18(z%D&sxfl9tF|WQq;Yr(_{p-ur^RF>)GOxyS1oQ4+ z^!zO54dzvUS2Azx(erzl_i;T}=Zk-skL=a+xq5SdiF_H`o%RQR)$@&*kMjACTCdtN z@BdBDr!gO9UY&m}<~@Jt`5^N_=2d?)n0Fn}^S?6hXI`z(XPJ*4)bqLepub+x{xY^Z z{S6(~^R=1x^ZHz!k6JTt9o6##nK!xq^J_MY_nG$|)AL_3ADfNJYJY8F-aM}74=^8L zUakL^n2-If=L_^je|?|n^())%^f!D$&wH5nFt7G+XXXQ^^!x}_pV!-JeV)p^@3fv@ zs_Kh;n0fbEJ%5z>Ft4}O_4B{X8|U-lQT2YCJL;`-B^ z`QSx8--G$sM;K4FzKvkse_78@V?N636SbZ!WZo0g^Bb9WF|V#~Bh0(5B7cV057(GC zdA?KYdHyu?*SN0d>)GzC&(U>gzdC=tzOH{u%zN_d`L)bjJYT5mjXlh}3+nkB%=`Gf zMLiEGI1v3c3+wqOY!CHU{bK^8r)O-)27gC0e5HcZv>1f31pozPjyB zeCd2dxcf0X%vIG@d$^L16*o%P3E1NqW9aUyw^d4uDx&KKR8_tw($Qv%&YnH3iIA(dj2iuqjNEzt8jciW!~Rh z&u?Nr$h?~WzcU|bspoUNf%aQm-)ggdDcj@Y{|xd~IDejI-r)I8wdWP)qpguI!+byH zz2fuG@yr{~BVU~Pnaqd2M}O6NzJhu4MLqu$^D%y2rmjE#X5Q0AZ~raky?kDw&PRpc zM1TEWy?$NWo%JEi`)jp6KhJ!iy`JyOe2DkIYW*M2eCTC8KaY7g^Xm9r$9&`!Js)8{ z!uv1P-z?^1o%MX~VQ9a>^P_4{S=*ic>*}iK>oXsog7H`5^8)kk*O0Hk{WXO7DBG{b zXCm{y9>}+4exAzn{G!(LbiG!sA-n&rfGQ z!o1qQiKKQMk@5a1`>!G?n z8P2@5TF=j7KFak?UH`0P-nUlI?`1yBylVex<~YW|n8-C1wVO?ti& z^QL&7(}sED2R+}Pc{i^g)O@p;kN&9V=P@7U=W*)zUCVrUo1WjtyvgT3YJEPGP0w#o^_f@4`(Eaa{m85H>1E~(9=~e-*4jbx;|{leDH|g zo*vBm_&iOuXC(91F+Kk&^9G*}sQxZz-uJhj|AToCpSP>~kqgXwPU`uDacF;l$Cs*a z+8&?Jr}cbO=KbROqyzItmYyHOe3;kUYW!K#$b67_ zwZC$YNBe^@J^zI5&i;z>cvSnVIrG*vJ>P|SKd%qf{qh^k`)=y_bmo0?v3{!ikr4Bq z|B%n03mx0Ze2CW%>iXv|=Dm0I{7vTl%&YbkdI$aWJ<#({*zWY#&AeJqnltau**@M7 z)t=7GyO>wkGk)f+JbHc-^Cst~I)4S34w{{44h#Ja z71Hx1YqaGVkN_QgwU{ zQ~Anzem3)_c)q$yiE5@ z@=xmd((iNsGOyZG*Y^1SZKmg6Vcy{Np}JlgqVg^D{0!zTULUIYvsC4u(ewM5kMjCW z9WQ58K2^^rPGI|)SM8~2d%XQG==tZEH+jBL>t|1uZ=>hmRe8>Tlk?$om2ao#mop#b z^;J>kx2gQgdVW9iVLoqE`3oxFNzdO^^|}72`I+)4EUbm?0qPEP(EaYqD#)bzm@8`OzuG1zkZ+@WXgDTH;PpzvN%zHmVz69&x5FaJNq{<1NnlipQ7>s>?t+=ZJ7_wLVhaq{h1H*zDCU- zi+T4PJs)H~$h^t@wSoEYd_DgM^A_`}zvr3vey!&dK0<$e%&T>{yzNeZql=MGX8T(( z9~JNUbYb3Df&2yL-()_<{i}|z$;`(>$lqapKJ(u77*93-*Q@+GJ^#C^&*!@TzrQNK z3HfSyFmR7d=KSP3qxP3+yVGAYtmi$RQa4!(0=a$27)&+c}eUOt!xYeRX>f(4Z z_$>a1J#>Q}Wt}7R@C4-D`S2eu(Jj_j*VW_fzbEVTH^_FLWSwcw-7@2gJm_PUI{q?ZF=i8w}k$9cJb<|PoRk>*o&%bPY ze7nrw?N{f`LyO^oo5-JIe>=KL#>Y9vevP1;MM}p1F7^?A?!(O*X&*m)f6ceu zFdi{dN~mvALW4qdpYUz;(ZcuBzYuGdQox!Mk!Go_!DF=_w7r&FjXV_P9B9yoKS7xQ-1eYI{!mx~K&F0Qc9cNpMdx zJe{7q81tpz3+Wr^{*v$=^y$TskFw4;^b@79A1{i}?<$veJjtlKAM35jd|&!#x;if} zrTc_mu-)mGuLjx^;5eKu1CP~)A7uUS%c4Eh-$N6FFMzK#Y{t-9oEMuM1bbnpA z8n=<3BJZjPPh~z~COljpuEukL?asWdA?Cvx=B+x&w`LvxEY$HgfV+6SJn|XpyeR6F zvE7*u5!RW_I?I^vEb`ye-xj`)b$slXYJcz9>@WMJ_WNzyoqkOcbqb`zgTl+vcL;aW zj|p#KyVEbLA;#f4`*n=@1E{q$GpUA{n_2z@mD7rM74>g=O8n1{UC3jQWNNDtB*(F@H-K1!d$c8;UR zUP7H3TpzC4?(DB_qQ7~+L>>RL$d6+E5%d^+Ed3vqZ;kvSdZ!@Up9)v+9sNxA(vNU` zo4x?;35fPAu-zGd_Y0`=9qaf13i%9?f7^B^Z+1jJ567X<*T`pzdUFh&m<^v*Md<@PD zLC)u8+`ro<7qPEP%NSNuT$i$pVNQVugx|Nj*H>pkKl(mo7!FtG@%9y&9|2#;_T;Gq zcfSeWK|e+hvW_|rPOZ%P!;n|~s`?n*629Yc`dH-ea(&3P^x?-#UE7`c7UcMBWqU$& z|1{KT!10OM?yU1+v43+e<9rkTMvp?MpM^U4xxXgAQ7rDE^YD3W=b~-6U-Mprhj;_C zwkrA+nhwu;6%D;@dybrm#@b(SN9JMsn?3=*F8po!aN$2F->uhqpnQ++&8xA#$iGjo zFY-H;i+tYdY`^fXHSPY|`^A^%<#>$Jzgg->io>{ z57FI^z$fs!x7l*+M|W9$eQ0O9Qzu*id38ORumbKc1XtISb8UC#$%~@SO6FY!ksrYQ zRdyxvokhNu?ap>B=GF1Fk@?;tzngiJ?P_NczUzNJqP zzLma0_|GN1Puc;r=hIgV%3 zXPNH~zt7|4wml9HJHDP+js4;uguFVwme}sh|HES3Hqo<$@1frnew<#})W<(Ye^Pj^ z@338;@DlVv!k?fAgg;4NBD^g( z>&W7GOOn~1HBGQ?U%ZJ=NY&r-y-sgl6j#Uvm|y42XXmh+ZXI_m$2(x9bN7qF?=3|73G`_+z+5U*N@d^X@Aa7xkR&WZaXC*de{YmD(Y1 zihS?5Cm9Kc_532+o%VQ!V!N$)+}%_DCj33NXJUKg1Ae%=z8cU09${Xs|Ak(Lo5PV` z$U2+o{x{$|=#x7l?;i$N*H?`?u|DfO#&-H&g&QN0|CxTJi!%;MhFA2rPFHxE@MGQV zI`({aar{@YJ-uIpo6}JLH0#&*VY?>hzj}WAJ>5+&#yU^+MBYp9MPEk`(;uUseI5HT zxlz%$sCizs7rdkWT-Nzf-k&a?cP*zs-v)Km?-~7JAHNS)TYZZoEieD7=U5@%7{i>Zo~DZ5`Y5FI>&5b+$X}_AyZ> zlle#tc{Q)zS&up%wo}ck!W&R0cSU_YtVk~_yaC-KJeA&Cx_#XkKi=n~Jtw&Cb*&8# zd(j9Rs+_V2fqO}_R?L4;N>|#M>Iq}dQQ*hYy@{7hWBCq z-xPR^`?o#!`%BH>-s8w`VEfy&f(Q1%hjT%k=$xz5%|I`K@$wGrTsh ze+mvnK6nIf-?qnp_6>r&PQnY(XAg#(XW&1wey<_$=y`a7JgC#vo+l4G?k3yr%>Te0 zQbc`2J*QH<3!v{>o#W;0iuyd?Mo$;MpB@r^hJI1_ zLO-r2eUD(fvpBB~ya6}z!{1=Pc5TJ=q~(Hl=K@-4s6B4>IGAPOjaX*^Jz5H0kNY>< zZqLKU^YKj_x5trJ_($&UAT++=JdPt zAoI293+f>ss*5^j*!~Yv;Q`j!$^5G4;L%#hFQNbSJiR9TD!tw-aDPMiN!I_SGu-zS zyc6eVusgjPd^~-85Bj66uk6{n;+gPW_X3q2G@a6Qk=$;mE^&I;eJxt%q{2Sl1PD|v~b>lhP zop~}^%#*wHslp5YfP7GRMfzId4d|J|Q|ZTqceOo!T=YRZi?RJ{na>vapO_E#LcSZ1 zqetx*W1Ko3QRhcqw+B*@&*gN-{^`r>@ZgK^6Fg6S!|QO@Gw=h58>e}Gi9Dc$aY?`uUj1Vv;EJp{sgtocSZefY-f+YtltUVp7UyC8a(haygPko ze{Q!2d_Dbl&gW2T_yKOWIp?$VzlNiZ90%_Rwny}L3tf)SaC^TzZ2o`E{pI8SYR&d^ z`4Rik>Wg-&=Q)>bcjj&H%KG~DfcX&XsQEuGjJ#juKc=q`-ks~bIS||J!1Lw_=Q)_O zzXrfpv7Kqob1-NB_J^;gC%yC@H^h16+ z^UsXJb#gZo*S+fVxUcMfJ#3tRu-!Q>tkI~W)|tXvF+PK;=;K+zb|>#0gZz8k?o4`= zuGW*AbYm>?yO}S&4fWp^^=r@r!k@O?*=}em>Zo;KHuDQbekpyw@Xhor;d@!%{XXh9 z;CbX8^TuQPIJmZ>{bhw$qPG&>(DwMaO-B7*9ESYA_nS?S%p0RK@>!|gi{@ZXf9d%TG9z8M> zuFgBRm5co~Y#i$_uhzZOwmYA9oc$d~=re53}+3sxDT88az=XR$v-%8{c(1#0OOJ6AbCwivvqx7ioOZ0@QdcTZc(9ZA=Xs3D} zHJToyKf(5=l`I(Vmv=exn7#JjXDkDc(ADv>pPx%wtW%G5E)2)#mG%N2m#66mM!-WG z;CDHHyd&Y(_wcuwpFt08gsXLXWB_@Os6XHCzq4PAmB?S?{MkYC8(pe`{a6fXfZ_HXPFz|<~MLPKkH_|4dz#HyDbmHW6Z1T)oVxKVQyFD8y|)H zm!kek*4b;%tA`z@7dYRnoyhZXg0UwV>raIK0-qzbEDbmJAzza9KkI|-2AFR`@8+yC z_I?j+M_#Q<6FA?H$M;ZAA|Sh3ruyL&qwU`n1|tQIBs2eJr=zP&t^O4(0#1GiPsf} zRsJ&a!XfUIrulM-}oTgUjg2P?cb>U zNw{if`9o|^b9gD%d7o}R20uy9eHeLHHTWm=59wxIxN2vvBglsvz~5v39lE!%?sw>+ zX7F(whaN{!$J+{ifCoq3KjFr+@O1hhy0nJD9hQp?;9{ zzoB2S-Kn!*)VWW;D7?sD$h++G)&KpeOs_Azk?qd$;(ZS7naKH;PLIBzdp6zQ2Hu7F zA;(cC;??~$-Q7X=Zhs>m=&1W2^jIg|Ux>1uU3A|`4|UT$^Fwi8{Z~ zdso+wm*cGC--#(fyqE1)dDmuM$FevX$=xJ=X569sSJxEve zn>x?2?K%OvYR@aq=atSnJQ8($yzcGoJg>Ih;&#<_@;&Fe)b`*OZ6F-DULhv00 z(V#+;SU*pvIHWSaU3qT!J+}Y-kLCZ_j zO+nrWpiXP%SJKUQ;P$c{|EV&S?OY0fhV5KNH@}8g;Y6=B4S90~ycX-Paolcys3u%p zUv-#{d}t1Q4g0&F?*1IEt_N-f@Z4s}5j+>F#C+o!=x^+d-ro|lv0Z;p)cKbA!t>zf z>+ogtWnaM~bamgLhV|8f-%y zV*q?L>yO$F57Sk9KG^~H4@6!)cWv?u>IX-_Re!hB%|Y-!++RiZqMZq6^>&v26?H=6 zk?+s;e4(7@sZ<^SkL^c$yfcvhi1~pB;8A)-_IJn;xa(8oCo$jl7(7T<_hkc4!cDFx z$`4(!-5yWR7pPN`{hAzuM|j@3%Xw?vM;$NE7lYWItwwTueulTBj@mDO=YU6dz~5s# z@8^X3cf!^AdT1Wz=^rp3$jkgL^Q;>`bC7#^al z=Q9(FCdb!-Nn##0E@tQLaf|+e`jxr9eMk4~hO6JZ*-{dD*D<|4FC{zm6OF^ia6GEB z_Q!EgG9qHTzuE3=*UdWraQwTLLOXrp`2B*OCF&fv-C0jOf1^FyxqnNPfxAw^)%Cz? zx`*D9_ak@9qCMU$hqC6)0b;XMtXugJTyi0$wC;SPH|91O2T(<U=dVLm4E zg<{xl*_wKPE7DViH>8gi{ycr5@b2`8@Hgpqg-@hct);hT4*g}}-_qX}zKuRp_(6K6 z@bmP$!tc{7*Vfxp^k0lys_@6?e&M5j$9ik!>l~j}*}TAd@(*~RIDEcS*8Z7v5bi60 z{WzKXvC<*>ZTMLFWxBsG>YU(uvhXnS?$YqvC~pLg!p)hevzc`s{SzL16#1=OPrj!| z5|CHVbLyNxK2#U^wcPG6bpKrBud-hsoJHOrgsb`abQax2ombeNf9O^c@|{?x`&Hz< z$Kk&)|9~Et2LF`(4PHauJssYNUhX>mGJF=>|0UgZ0j{14Rk(q?c@jQ~?a6Tm9&Qd- z?=>x=M_a>l@VxB3%R0m0vv}Td-Gj$og4fEAhVG-Auj=*NKS18o10G`i1fIuZec-wB zp-#EnI4{Hs!_~anO!pPR_^bD~-_M79s3=_h-kh7~YhMk$PSzu=UmLEj&p%9ro5l1x zt^)9&8(y8`KZEXS1g}7^!SlYg9QD=w2^K;fe|_Y)aR1if^?!J{Sh@d;IiTV>$tJ%Pei;jYSX zb$(2*2@lkR@8bNwTMO=M1b>$Evyq!#2<^$q{#LI84>d(zJr`Y0x1NSKWPMKq))^01 zzbAgXAw2dD{0Y`CnF2T7hcDzfe5rgeTpcfSn;;*43$C7Xc54a`y$ergon!Ri+wh9? zDo-IF5#H))wuk5a9nAkr_r8ZZ-_S=kL*C?e)%E->dWii}pQ8=;An)S&SNV_@aNkF$ z-;3+&_UGY|DR6aPbM*zdHC6WtFTveh-)gd*FSlWR;XB*H{ap7{ex4T|6h5gPJVICF zFs(h@`WWr0&+R_m0Uj2f^JTaZKzkN<1hQG^v$v$xR zD&52M@ON;vJ~Zf$ynj7>Fz4s|fvmp)K7`vHGYIa@fb(>1bQ}!#(bauN%OP+}zloo|5%n|anRMSK_%8at!;p7xhO6HPf9ox{>j${{enR(nxF-x(>+s-r;L+{y zTO7}87X2sqB5wDscj19d_{&^RHoOOq?SZTH=hFM|a0IT-o8u?2{vYu19RK7G;JyR! zrQGfUy6Yf3o$ahW5&6&&_!ny2=-#7n)vpngkPn`LtMx6L?mx#mY|n3#k&j$~kKuNo zoC^0|gFi=KJdO2l!Z*@Cn2z&;>%9IvAv5lYM#5#>C#w0A|6}Aw^E_g*UoX+CiaM{b>fNzb=@^`7ThWbKhE|%`5D|@20no6 z*g@N!=WHI)&YiPazY_AQJ>@@#M<0X7Sm&KNtX~s8knKD=7w$=ct97IBJZHO!#+KBg z@fLPtJKNFa?=f|o&-&sxTKgqjt`D1o@PIf@pIbl|$921};PUvr_CLIdeZTOq`{mxY z$Da@U-X-26HP3(M{YARCzxb0L5`Ib5iJ;DGH9qkR@<)tJk?&2vE_{^jPJ4_isH1+b z=L+*>-TM7e&TGhf&g=R9bpM}l{L^mKb>t($XVcxs^n9%w$OnY)q{oDJyXh=kj~K&6 zJBQlt^eb>guYa2!6aK+1)-m--LeO{t@gPYwDK;mvG!+T-~Z zbxyPXD&~#4dYx_b-og*izZagx`tF;kudYL0yN&I-MSsuP?u=WOsB@S32lX7-kx#sj zItlglI*-!333t;c32#YXBK#HGo%Xn+`Z)Z@{C<%y@PO^Vh`c(!hSRNl_(p>ITn{6* zJNw0Gptt{&s`D4>sL#z?8hPUFi5zBoIR1xhcj}~wI_H`9vd&A)SI>cbhR8on|3`Q` zdgX?CJA2#ijF0aC+LOWhyXi3=UuwN-ofF%AS=8x5pDKJXeT8t#c4xbh2iUHf|5uqm zEb@7BAs;@3d|uA;;q=f!cp>_6x=XBM{@kb&+l~A{_IGj~xXC(do?o-w*)PeB^l{6Z z7d~8gDf(LBHR%Z{dY$HUxA2biRN?*UKH=kRcgEAoM86KQU!i5RF#UVs z7wMV8jRe$>2`@%B8teV7N-rk-N&1t*z4RA__on-WkEXvZd@4OCJV?(FzLvg6_**mh zyeJ({;HPmNsPze-|ICMP<#V2sbk`!dm-){=Mc%g*Zt;21^E2VmRq%J6<;DJaK=-eO zH)fsnvsfoT_WL^K`+f%ZC&9<@x~}eSc(@;~-#%rXU+B@Z$g6el)jh}uH)Fd$vwnxY z-0r`6{yIIn8U8i5J8~cLf!|PP8S7Muz&!`y>g!Q~!F=x8kKa2i_`@`^$3c+{YU>%oUf5c6=`*U~__t&$x;NCCc z_Umx*pWNBZFNB|9`*+dJ#qgqR&&2j#C-MQ@L*5OhY-hY58XRb_r4{NkG-b*(9-b8HPqk2IxU>fv+VH? zUWQj-zXsKXd;6fy>l`1W9^5w&zL@?wJ$w!0pw1Vy>odOxuHOI5pojLu7h<;Y2Tr2SDURptk?_z<$iKxp z2S&l&?cnOZujClGbsBZl`Y?}fB%}T9SikXD0J+uL?-sgPuZR8^ZQD2RJ znC{7m>n`;@04d{;59Efc@3r`r?#V!%+1zfxzJGV-q5o_2t1yqFBD_!coq+G<{G9d) z^6u8CbC;f<_vz*c_%QCrQoO(RyU?$XxF3h6qmH*NyfHqeHTHZCH^#$T^7|I*@%}n! z>Em!_A=}du?X1K0q%DH`Q+2<%7#@5XK9~6|OW>X^aCN+ITncv$ftTStAG{3iepB}` z%i+dYy-v~!cxW7aihXJ9{N(x;?)ebDj^m#v#5&XA>U{U>YIxuicz5Qfeg}`GGtc?< z+#0ww7p~Ts8EfI8Abbt;o7S`bTKLiuXy>U6xMw$9&Cd?s!+pGNRM&?qet^4wMZOXq ze;A9l(a*vMaGvZ{)y%6km?SaH<(jK}p0f3g0f@N=B!*>vl1_(5L&E{h`XYXq;!&l&TcWSwSk zwf?WAyI+E@<~St(gS@9B{2tf0iKpqW!aw3X%#{TX4u!wN{q^a2xPJnC6!%N;B0Tmn zT&)AoU4px2!jo9%COxnP-ka^5e;IjWyYA0j;dXz5tIw4ZV{k9;Un+9HWZKu^4|^_m z)pqB8C!C1&zar<){YQ8o_c&a=-!gwL-j8)X0sn#biRI40eO2L0xZNpN;E@4vcGq|# z4eyIag|Dh)x8J#+?SXtU_lvtS-0TWp$nkl;3cWvk1>3XFap!ue3S7Ns_~K)5qZGU& z8+4iOD+gDfOMd(~@{x*g^}Ky`Dz+Qz1h2q${`nm8f$H#^90%)pJWoD+VR2lN>6e_( zHSGTSQjwp+d0x}`{KEFw>+p(fXUKNvxpY9(De)e+TMT*C{yffl;_Tli;h%7RR=I{c z5%GMxA3a0(Qrn&JjJZ%peg4w^I_kULgsM#<9;v8bzqt8PChL1 zm*SpiWaq>u3m%S}`=*mmG)CvreHcAM_&g)v&eyv&e+(Z6Uo{lDdzVF5O@F>OqNx6sbRy})~dXDtH*gm-< z6~BV`9mH4N8SMAbdz2?`@+`v_8~?@kVtsPsls`@WtNvE~?dJt6@Sc5jp{}A*Flw6mYquG1Px@YL|Kuda zzes%h>B^rm<7dh|#TTY2{$S>Hr*Gu(w0seHUMTKge*S1u{uw^hq27#rV(y#lOqE9{jJ|ds%)R9kbc@;{1K9j>czO+H<)7g<$3O zshPeP^XK1C9ydN;tszf-EqCLy(n0uJ^3rRQei^-M$`d)c`?rzI6LZ9->_5|D3CzXUS5}PW;8B^W+io z?7}M!;OAc|DZd*(Z#=L0o87MKa__Ofa*5_|;v2auckf7f$kg+I&*ZUR6rbgK=iOp-rkut}qF!+P%yRwSR(>aWY7f+S z$Q&VmgbsdpjM_PkyMC|QM(r7`tN0f5@ARVk^@%l+*TJi@&L^qQyY$ON|0q6txZ*#h zKHKm_Q+apdclqsE?8kU5`CaTghwN8ufB*Na{T%Ga^YD(w=lWi(XXqs5X-%F+`^)pR zPlWr{hkP%theN*B4PqNt&tiO;`c$l1-g{Ro@3&Mh@9PgJ@4p>b-VZ;hykA|jye|!v z_a6@~@8R0zy|+IO%Z=x28K2QkYUc*b(?9X}sq%jqC%5~aw;XhcJltLG z_Lqn7L|?fZ|DWO6o^m&j2GnJKohf&pGtTwB`1w~)Gry`0(mW~*Q2Z_Q`z+`E<$p1L zwhdN%Brbo4_{%Po$1aq=M|_P3$e)mRBmQnYaj86xcT6kZn<(FbH+){68ZRG9J1^NN z&ygq0zF%jPJW0Hp*QvMV=~2q#{809zJlE@d)ON*3uT=ao%+uUA@(g+0&zIG?QtM2f z_IKZ#)ONjozA{8V>MbMB>$gpw=%@U8i^=nr;whZRTHgMjD?Va;2p%*3JYG0Q`CXm^ z^VG-055+UMd!H(U=g8xHzb}+0WBexn_dS=^?Xy*``@I#{4cB@bWt_Nnt~`SMaiHRz zr|_ilLoZf*fpOyEm*L*fV4hRm{!af6Wn7JXTKj2!q~hIs&cEZy5pwsv=r?B+ADbk1 zwxrd)l{>SkUc@p>u&nP}bJ$Ex-=J4~XnZe5M_OE7Z6`!UZs&KA2oqaz?f89&| z$RXMG2W zwMX#_$-gcm&s9^rd!F2r=hfLmTRUlwL!1(mOQjx?!M3Sm`(EB8$o}Y=gEaFa`(C6L7OS}8+nTU zz4k-=art2UiI3!&`Es|Pe)O?Cv|2un`d_(49$qPT{nF`w^60;EcRv3dkL;4Wadp)v ziqHRvGtQUs{5iV6`ei!hF5ag2)I*A|P5lRdj^8SG{X66fdF%msXYyR}l{|T;+}*#w z#dGG&6Y|Z(uPolD`{%mo&B6Si7w^Z5K3hJY__KbHM`i@$+x#Uj+$(p_8Q#HDPs!8d zY3}KK6=L0R>+Prt@>m14&l=W~=lu1mSfB6>%CnJk)aP}zzE%AtxW0W*U*}l+o@$*2 z-@p>iaTgE zZ-!at5A(gak0%?eUpml_ee27!P38A9&Zjm|o_QwEo~Xu2sFC8`&kKBYZh3DwsJy>+ zL3wX`VR?V!qVhg!Sb3jxNqPVE2(@Rtx$2+ez;SG=@;<(GdH>?b^4_s+dB4A1dEaqV zc|R#q-WMNJ-YXni-iLK4?<Zhj z`+UxBr1(fjxjRojj)zW_PhkB#q_N^txI3>V@px46R}udMp2ttX2OUa1yC{A$3V0-Dl;8$@zHJ>$+U-^_G9ejm_iF$qOdF z<-5dpRs5IS$F1w9=U{oWk6gy{^EB;zIq{!z4vDl*Fyz||7h;rTcoUH1u_zd}blBZ)2?aT3tb>GnvZ``!}y3xb;(*5J5 zD%Z`6L+7a<(^KX5a2|MM0sT8#K7#!Hzn3Q`%S+3M|91o2bH7LAEa%?ApXH%kpd%IU-6p@A&!=9yO&)(x?)v@iJLKuR+JW?g-4IWl}!uYxVIjva#EbW}(x~?mYliJ?&UxVkmHNKbHVS?(@fqHg4 zUFX16CVpbct9yy6!TP*Je9pvI=&AAf(LSx)t*Ot{{}`Vc-;3v^5oSGq1)pJjGrqw1 zH~1FgyK(Q7;6744ta9rZZ;W>|eiYu#co%$>@&0(y_(*()@$2!q#%JPL<7s@e@n>2@z?PY#<${=j1QQrbtd(K>baKjx%mNk=n1)d4%zx)d3KH5eUI7AX?c$LPssE7 zW5llw#y49i4=fFP9gd zmMW~qgTlzFUeiGgI=}7m&Kt9v`s=*E4#yb($IuSnM|3W#|66b!UfY%UmzAeF<<2j@w@|!K ze_rms|F(TEdG=NL?c~4bF?r&3c`fpES|CroAwL@rt&*qTlJ_D{zhC5q`SJzCZ*fli z$Hb5ORq@_N#m^?buK#&xvHp=)6coa>!NeD&UnPd}zSL#Y2W+Z=VIdQD1rP>!4q7jy$w8=(qJF|8GHmp+EWe1ii|6TLVUlV zKhT-@p+W!jRN}`3z0qOiudBQ7rR$oc_zb3Yjr&Drw|Fs4$B<1e+fe$)AL3!W9=>U<;?oP2e=Pgsz!&AAhvZYa@2I;`o*+*v@|@UJ^E5k0@o9WLp1(`( zzAtyi~nz5jXhK;0izHF?(K zVdMJ`()bBepR?FUZuh+u|$3g{`UZRa)bOed_3R(oOn`x9KL%#0 z*S{$bQJ>4mGhnAY@|yCuquusZ((gAZaJ}yR(r*6u6cp!U{B_08CeP;8`n@OdW%2=d zmo@S%?w-%wxl5j*9o#u{^w)ZSAf8bkci-J{n4ZJLUzTqr|7<+}w%q;P=#@#ur$3at zb{jico~1pz^PJ@1Tja?P6yKEbuzQN!qn;O2?xd;m*eb;jVja6}nmqNs+^tt#D(dt4 z6xTI@JQMH`?|zCeP_7#fPb`y1v&!F={;JIT2@(3sovR=GS@Cw9{ElbVDv$d) zg>wt#<5%Dz+WA%LS^byt@drh;jwRM9zq=p2)L+Mn= zn5XVNhwFK+m3c+^&!BzIe?sxOkK~i7f3qj$A^aKqqQP1x7ylkyZ|CDF<6q%fTR%_6)5fpHb2yLNy;oUp^IMf? z2hTHyUaWO2yIt;n|NDb@?n`+~=Jl)Yy)yETrv6{C-X?xgyj$N6bnEJG@^QppTUF~} z@;mvLT1xH-^$%{&i)s$&QO2%dH3mi<%N$G{~dWe)`8Hka`*ee z*Zccyao>;ckh}L$>-poeiM`ouFB1?b&NN!_C=-0U9@v;##_3v+?{iF;h9Eqx6UuQLgUaoL_U%{OYWAZiFf0< z(|0;I<{K)0AocA2y2eSAcwL3(O?a05<#+Y(MI2cB((kca%JVdNE-9`v{&MB0L{xz5JFzT=1c=!a58E@?OSMfdMQM(l%CjU;?kJNJ_KFRNw;<{HjP~{Hc zfV&aT(az8EdCH|D)Q>;SKDd-YcXOWCpk4WX?BII^ue#UjK#iOYl>6NUDmT?q<+|@d zJ^w%QjQ72`-p(`Y?QOo7>VKs2=%*e1uc5$WZRA5Kcl}Yyv)<(S2(R2FxSoH9cQn2i z?`gc|(aPW7cyl~%{5U*eyeB@x_yzc4<74og@yYlO<8yp3wp;#awa-f0=je#)zstm* zhF3i;*gogtjg61O2OFP=k1{?BpJIGIUbSnm+!c5y<8R;zuc!u%@w-JAHpxKDGwhfKMk+kM4mWJz5xHZt2`Hxx5Q)T$TQvK+`fCy;aU86 z;t%zIadvUsrtmPne6c(kRh~3{+Y|CA^>_981rMF1__v5Z;%mj{x&-rd_scAn>va#- za~U2vM(*~JdS~jq5j#ch+VlJ?<)IGpBPn;(IC-w4{1o=78@P{)68}Hqhi_DTiu|s9 zhJPjxbG^KF;SKyvp6smrt{ocPtNkuZzt^DL_MNofCFtLpoYO|&VcN&#`FE4z3q6$I z{a((tCux7oQP26*zw^VKuV^>-p7VS>daUxe_hC+WRPkxXkBeXG??=UbGuuk>5$f6I zVx0AV6xVe(Ug)QIcOG7Psp2E;V zyGEYvEkCS^D%x@a@n*c;TXetvwmx;PEARK>_IhhvuXyXX7ri*Y%y@XyU$4rY55Hj@ zOPO_Sx9`O~;q!D|O=$nC+RLN(4E*3@wcn*pp2K`E)n|b6xOHhB@fj1p3}0(Ji*GRg zKKTpecjM&x4yw=BCVnQq%Xk{E-y^vGKZ{3xf--%B!z7J0suXUX2zu5TU zc-DAFe2eij@q+Ooc-7N`*Lx)%Ha-RKX#74rW_$@g%J_?T(s<7I;y8()uW|Ai8PtMOIFH{n~1f9`v+{yFM@5aYJziE4)(CjJ6E za%QmpWAL=`$@p61bMP(37vVdMzuvT**$;w15e}KsQ>tr6kotwu@8QPhp$o| z_qqA8C+m85n{s>LTY3ktcM!hU_~rP4eS+~f;jN6{jdwHt#ZsNaW5ZO>tEm5>Psu}L zF8!T7QM z_lA_l&v3bWPP_1Hd6s&*f=cCw;E!c?0D>il+w3-M(nkjiz>*_tI4pThOGo;Q24ynv4&&+Rw+?$5i>1&Z8A`~NXTo*yiC&u!-2 zsyv|~@@Qoxs&<>=M_*J8S(JW!8cDzL&}!uX5e^nRu$==a~4Jz8B+T6BOT$`=Gz^%suituKlBm4^5GO zP5eW?7oW3bO#Td>GyW>R)A&bt)w6=@;dgk%_+C6_yk-~GXN2+Qz8B|v*39=CiJxHN z@4{CYUx05i{ygrT9jyOGypHkD@V3Sact_)vPSbUbGhP?Z7;lZ|jCaDnHhwm~*LXvo z+j!H|?@{{wU+%k;*UKMdzW@4&?z9+Lk|{RfSaC+ErC=g1q!%QFk)j}rg$Gu@Mm6Vd;@LwsbBuFLH&v%4uiV&Wh7y;yE)vEtqS*s!}i z{G!~wpFGz0V!4A&p2_$GN@hYd&p2i#EgN?Vtlg6X?V&nbrIsJn5xdh*9{5s!D<7Zv4AK$XVg#YGadG7}9FA`5Gk2@c3<^Cf4io7HLu18<)7goz#<6qzr%I$*R z{ifn08O4v`!CC)J^2AH>Gl_qC4bPvc&!70)JM}y{zC`g0@OnSWv*cNd&#$KYg8U1L z{|1j-qW!|_lqrcj&tKwY{F^ zx^li3+aX8)_9wn-M)6tVwR?Kr86~go+5L0|@i~*f$#U(#w;iPWssDd(q2#r_IPqc1 zosaJ@c{V-c*VA9e5-+PgU!uP*U7>m=O`cgRx!!+*{g^9xb+2Ac)u%J%)_P9yaTDL) z_hS1*7+2kie;7~V?&m>jJg@7WyhryV?t0HId2Mel`Q7#2<$J09*XX*sb6xMOQhjo! zKB3jhU&T|8xP7qc8u<#^*{$Q2jKkOSI=9E)m9NF0_*))+PyPhH56{qFPqO~^@jr(up4)q} z4!iMxWa+s|Bd?Y5me(qNl<_C=>BhT`SNvk*FTAL6o@CwrmigS-<^JeAk!y0V*9f0gce=i_8W&bI~(iQGKqOqjhW;^_hvc&1n7U zjX&y-t8(kZ%Z#_BX1u+JZ!-QBo;UtGzRP%(-kNt+2L$Iu1H7^EHh9GNDR?*IXX68n z5B0scKBQ?kx4wOh=Ww^a&FiCjPBM9(_Pv-Vv_<{pK6gIgEX6N2@lEhm#*e}43=FnI zH{VP3+^YO;zt~HBTN7XNY?a&1cyoM$@#FBk@t%0W_yu_5LBV>C!ABXNj30Mx#r_YB6x%2Fnc8O^^m zec0%G>3X@Y9mF?#P3zby;@$eTtmM_bYib48u>$cEh!2ye{p-rJ!<74t@5Sp%Z_{LbH%%LY2}-`-jhaYUAlyF|G@3K^tRvc<<_O|eJ{2{{tM-I^Y`2s z^YKghWb%K9r*YT*v-&DNi{DB7K0Ni6^0;%$)^jw!a%LRv^u1W0=+}yO^K?-^#qTun zFW{BW56+{veJ|z-?@*pYsZYKB^3*}`k{p14<9qRbzo*Ib7e3JVf#)iIf$^qz!FYST z(*?nLcE_h1ALx6r{&DK*?l=2a)qKp*K8>h<9sfP93SMK+yE{`7%>w`VRR_JV722+L zaGx)ny-W9xXVWjolIM$t`n)M!BVH2szW3j&BhT;eDo?|A)L(k5+5fehIr)+AYu+Wu|CHZf<>uE$ z`nTKQV84Hgk1+ldKE=3q9^=h;EquN47Wmi3kH;%t7_3iEyoK@eeJ{38vQE5orEY!5 z;ThcR@AnK)J-eAai}8fL*%rk3JY zmwMUr>dj+5vi@jQ@x0{^$zwGYU!VEA^bvU?6!f>!cx`!Q;y;})PaPbLzos<5{O=F1 zpmoDNr+NI;{`+Tfh z$^CtyVsKxWO8n{dwXP1O{;&Dtyxh9_CF6gS8UMTR-NyGHRIHi*IYK-*f9vC|jJLs~ z#yjI_<9+cB#uxV2ew{ipUb>=7xvs+&>iq1rkxyg%v|lezwUxIe{_-pQcJ};pS}XZu z#4jnm4^Z8kRY&`s+h>2oL$B+4-Fe`TuhlQ-93nZ0{2jN;z4sN*$5!6;z8A~Q(!U2& zZnhNf-;bMqJo#JYSxO$&*7HXA?NhEFC(~{P({8hUFP57)Mj71x5ffQk{w?7BjaR%tc|7vCeQg3BIyRWU`C#RrWbzz`FE-xO_hS8{$0<*D>RJ6l^kri^q-Mj88Xy4?f5EVtldjHTWvy@8Egk zU*J29@51X04_ccWlKYrzn0Yc@7`0=Z$INKf>qY$xe!Y z8o&4yo!eu?yYv6(Yl`#E-#04<*VU_MXnl@!Qy%wu&1ZO;_HpNd8=qCY7g78e=KGWW z=L^OCF40cze!u(;{(LWbwyoUNb8l%KsO|qgGS#P*r$3!{sGf5x1?xE(4;z0KPnmUQ zzwcCTvV+Qfnf!BnFSbL@l=~6!8P=22iU0n4<%zHkOvdN_Kz`PN-|%`n<#D{eD;G~O z-_OGnKPtX}AI|>XydY07u3Y@NzsPfVE%MC%Ri0=3yom3`Bd5ko;y%CL_M6(FBjX`L ze6wB3lR8cD?m5E)c($wDJ!d%h_hO#vUawxNNgwj`!$0MHv-9zLaQhzGLw_iby`O65 z&);(U!Wqo#5oTTw#*@a!_+DH;<2_V=*Dtl>@+4kdMT&oh`d-{G=9xU>h|l+m7sI^A zO8@J5XAM>S1`|IN|JwLCe3$WQc;ykn_3Z&XZ2T#Fpz$m|!T1OGJmcTsn~nd47mOb` zOxGK}I9Si7csJwi@ym^O$CJhf;wy}g_PzK%Th4rb@jmhEP5gGe|0ThC?#3q=KVZ17 zYpLcOSGr?+Hix$=!VX9*^Nw87D8V(7xm0N8|teCXe@5p6mDr;||gL z#&P0*C;ryXTIZ8P6u*;oc+S5%ALa+k-Mstl3O$F3o+DpQp0_X2eDBKo-yLt{?-#}S zk~%~2FOdHu|9#iu`Zhe344o}^KM&Yyn&Q2){Au#L?^m4edvTq-tFF%Bb;~VZu4BYTk#(K;^I&KOCH6$P|pr~ z$Zx#C-}veAQe;=+>+Y53@d5Y&|B%0@;@x@ac|4ByCVuF@iqGIoBX96Nc@}r&X1s=_ zb_=ndyKME%=__&p`B?RBJo!}uwci}AI+gz5KW z$*X(+lE=-XSBal);`iTA<--?xhDUxn*!PJQN-+;1Psb@S_EyuK;7VO7<$KJl*I2ID;eYzZ&0bd@5dbWN<&dACDMcibsvV zjK_?>k0*@(`uZkmd{tS&( zyesz#JdTejW%InlE-n`2|9%tGKF8q;jGyj%aXjZto_)k;P5i-^DE}7YhxuOo{3v8T zKblPZE)zcoZ#*hEP8Q+ajK6@#jlYf0FrLR(82=65ZG8Wcx~}l0!TL17qsH6fBaEMl zPceQDKG*og_zL3_@D0ZAz;_sb7~gArIUc$!cwOu9w#GlkqsF`5s?YbM<24SeGv1ms z(7cP@DtFHlrs8pYF!5(MQ+$j(qnTf4^^g}5!8~J6m*6;8|5zl^mBMVW8#;Lk!LB_oi|>28K>N)p8mXW5AWrY=URN( zAU(IS?Uw7Ib9?B9V0~u4#dDiU@)yao@G^ex?WMHb%MrNwoAQJ4fqb?)rG?zmE`m zkNNLa7T3u%?#@N6{P(+x9x-{Ay({-{mnUA6{gHLd)u&kqXIwo-xvdZO-Cy_8T-Uv< z&ntW{p1THeT@m8XtR>HKP6*?7l)SokQ$3yQPQW)2pEvOb)>fYBrrrAZUbY;LGaic}wBGpts=roFn)e z;_sfW^*?-<;wMn<>4UZY$L9p|JcEbskv~hG+Hu}1#$A0@4CDF#++dy!r`9f=$HL}3 zc2os^?mMOUndJY_|9r6ce4}8Vn_cTaCn=umq9)JEt;P7pUc~s3{^!WW_?Yq9b+w*^ zZ&SJMdCo-Vx69qSy&I3>!)dq4^|X$K{P(Pjf2x-L*YjS*d)L>>>GqNR>ubH;&3YRq zz89W0>u~1=%0F+9#+y4=SGl76y4S+@;(2?Z8E?nq3FAF|FRdF7#!EGE>*Py#be`O; zd$){H{wXHUJ-(OLN%FXM`pmG~?UhUOT?r~l2`PINi@+k3VQO~c6?vGpB&et?9e_ndd_hPv= z{}FyamOB@nPXBH){W}P+d}VN)ym1@vPttDdxUL@$RXr1r>Uwuj|IzUxXicb+Fym;9=wM;!)#Y;c?@C;z{EN zj8nVKG2RqkZ2VY!t?|?GPmN!I?=}91`~4k{$4fKfveN&0UhX{2>*xY`Q|9%*f9bwE zgda`(SU-Qc_2f>NDS*=lhl1|M_3y!{nKb zd*-?}`(E6y3-n8h_#W+4&yj1R+?8ow6L8owRiWc*>@%k3jC{fBS!y?Cz6Fn-*9<(cDky*o|*A-)&m zv#a8z5p^`{@KeOs86RxtEZ)la2Y4sr-{7N+@4-{X51OEQt}@;n&lx`+-(ma=e6R5# zzL(CuFY0=`l&;$I*5cupSCVmMXF+RDs@)V4}f+vkv>Z5qi_(3`HtXBPNd-`+Uukzel`K9=M zjr5!?^n%>Q-`SY=olN}D7xbJh$vAZJ^)~3-RbV{3cK#kun0mH(Q}KD@m*X+xPvJS^ zKjBf+{zq?A{*Z}J;3?zFanI!W6;B%P@RstYj9-hVjjzHB#`of$8K2Qj)Zh3NJZ$R! z8lE=3|J&p-<(`hmP5g8`X5!z(GsX{iNBOhH``~%wDLibhYcrlR@pa!-{)mac0FN6_ z<0<3Y@u=}5bIPAEJ{C_KUxCMr|Ai-wcYaU#GsbVhbH?Ao^TunxuRI0g7vS;dHGkc_ zyAMwo{{YXMd0P7eTmL2jA!wK*%ux;QTID(%604fSKJ>Z@B@es-J;*i7G=Mlj9-pN*k9cD zP3`jc@p9*-I@f96kFmeIbJ1kqi|6DP6N2ZQ*?1@8kK_G~KaWo^z7d~d{4;#6@dCco zc%|!A&ke@w;-4CCjTek}!mC~vyxz0%I>v|jUOFGHkC$5B{a%baiEm}%A0IO&*Cll{^tba%KhH$rtbF`z8Nn?jwik+9@!Z5D_y+t zS^o8w8_&yVhYaoD#&e@d8YlBid$z+f#!tm_#{1$sjSt7GULPDk*WitfPsbz1AH)Y5 zUxp`)ufwMp-;A#{{wc#Rv>ZUy6Ee6R6ieJ{?7@Vn~A;q>ohJcYY)`#GM+ z-MF2@=g#rBl_y4?qwml;IsA@%6h4^uno_u1hYRj~C;Up{ulPgjZHD~rdFB&%j`1^# z@n7%8^5g9U-;3*H)rrA=?}axuegPgaeg)picoL5ppN)?&z7S6sUyV;Oz6nnm{~VuZ z{8v0=yOA+jk~CCr{wV&|kOnd&CN#DBkts%Xpsn_b~OjY^dD(pW+YXy1s9tc@a0|es;4w@wwuMlK%_8zsk*v3X?T%3#K1ys#_z!s#uwvB<7@Dx#^1rS#=pRG#&_X)<5g~^ zJ&iZSy_vC8vg+g zCxh)Ud#c85o^k6w7rUgDKJN(UHJ;tM*Al$cxYF=^xy7$_!u5F{t2GI zyOjQw=bd<~@@Gx_mA)6-=fKIqewl)IF#a6Br!w@l>a!o~(kHuESGUVMS5m>9c&{?~ zrTk{%V|=f5e5c%hxv=!-(>{7`kpDq`lh~`md+hNYa<{G?xnA!*CTO?iJcr+K1fLHw z9%hl}sHi?Kd##~9KW&32N?zM5)L2}SF#Zg_3U}k`w9}P8&G=kL{QG!(Y=~p`nz~ZPNM!l;7Q`$=XyJODLztA{Kd3$mouo(Z}Q=#Y@YXo@5RptAGq=0 zl3a-2=l5^9dGtK}9yR^G5g%pzGklKm2N!8PWW1rJ5*xYxZODH5XT0R@xxs?goJ;?f z*Q6b4a9$1XkyjwkrsH+a43q!1QZ~=qaDqJfyW;P{t96t||B>H8o(_2C4|$IGjeHMJ zggkCOR(MJGO(ERv`={Vh;}h|i@zr?T_@8*f_zyp-+%WZYXhL4`5f

      EvBkk*QR`K8UYXlVwXp5p&L_PjIy&ZpEXs(+2h}P_hU@uevEs$A7d)^W8_qg=6;N+ST!%K3UNQiRP4vV zRXHE2h7M@CZ*_1z-tcTB>v3@);w z<0fO9MlgMLE;nsp{u3R3v^ka+9XA>qHhA6ox$lNE1{Z|~ekJN$kEv($wnYcu59!DG zuDMUtnc7$xb-s$g2aAOC!&s7yIyWJ56g9rOzal#BX!G`K@apT(ylh}iX4DwA-{JG- zFY|9~;CI9Qu4I)1@>PYj-ydP6rs_WtG?Jx5`o2(j;4PRURs9|zBX$}IroWcUuf5=F zu$kR?Rewgzh@EbZ?mXJu{yB7dV^O%@m)YyVYx!bR^tRZ+9Ra|O3I_rEO^6xE8Y~Cc zIh&H@h97O-38?#B3!Sb|#FIl`CeBTOH~TUS=;%`E#e75;M&F0R--g2insd*`;NmnYg{FYw zeL$C;2dj`uQ#?N?VcZQE2VQy#O|hZ`n%1Y#G`j$f5NO&Anoe%44W>`e9V9{CLQtAW z)A~-D9tGIhdQmtdCzYlTY(MzEOVdMLX_|p)5@-r1oU{jYI{uxWMn0S=$35lPf8j0#}3UxQZ&B4SS1$*6b^M#bOQK=9z@-4Jy(h}w`OD)bu| zAqt`%08t-rthc}i7C=VeNb(Pf+Taqk@@Vr>$XCA`z*CYJ5{&x5oP#?_RP@`0s4NHA zIq{N29Y~iTw!A{107s7rv1$%Gf&V({J{|a_(lEj?~_7F&XZ{zmv6ztkgWpF+fEKvj{ zx+vIt8KiPae5!&CVZ%%}3ifeqo#8N@O~Hj_fAsICjx!x1~CZbRwlQvw_^y=@#N9)fZIQzyXxlNUcO&G*5QpI(x(> zMFVy5>*(~M8#;4nxzmrsO{#`T$U%y7p+bqsZjv5b7gf^5OH0ulXt~oL!%eCamcWLl z*Hs5p0=4KS>19PLyZBaJ9I6yAYFw%Vg_~5-PGFNF)s*DzvYUjf1kh4sxQly4w+TdJ z7#b~iIzqTf^?nkZMxt4An$t+>i^*(k36_`xm?}d;M6JJ7M%+Wfg)|D4RJQ#6FL-b01#56xwhOEx=6%)=YI>XmX)-8W# zG8ymmKOox_Vm64@V2Xi>LsPHL$XYP{UZku^#9@Hmg)n5J2V8KO3=O{EBI(b+;1W5y z_<{>$Xv_td$9pGSaB=icxzN%We!SEw_|RMSF7lCe5zV=05>4!5q_fEH3=u^>=~F`) zNj`(XdSCtnPJFV$*Wt^{KQsT+S$8k;Jf$zSTOQ;{`zfQ!4@~{xu-!cne?IYKCjJ%W zM0ZXd(IEeB(xc;!r|rIqe-B+14EMgR=M3b7iyBj(e2;%VLiwJILnFxdP$NPw*R0si z+7Vn{y<#KYj>zHbU7W5PIVZo5zW?INEi6>XLi;)YGzz;b^dSq4WuX?%rwpvYA5W{6 zV67^M4j*=jbE}NGputsJyK7({Ur#Fqd04Yj)~qXtRt~$Q?bfRI8h5ec&h9E=zIbor zv^j3YsI0gmQE^@4epcMmUBxZLW?ICpSS2g2OjKOe*usj3yQ}yiF`TyDt(Zhof%;+N zwzJ?!PWn_h=C~C34js!nCkcGi=-v2n)ac*XWKF9s1q)jp%e^yJ9qs6dR`wrJr}OW6XqMw? z%l^c_YyMP)T!;8qk^{AMsM0-x?(J`(Dsm+z@^s=nI`Kxzd33mMdp+e|<^%uyU-vT0 zes6dzvFGkcWH&?;g=s10h0(c*KlX=SX(_9N?s;N4c(s(1=XkK&_k;Okz8vMVrQh=pA8vdP=SeUbr9i`WWOyFGf0a3z^Uhr{KjS#rShS6LptNz@Jx3(H4H)gC^#% zY42rk(CB$DE1xHSW-gLHrM370$aDB3W^Pn>EP}i3>TZF$i>W)-!@Fj67g2Yu{0YxY zBVO*oBE*p}umhZ5!B@Ox58lfRBK8Vf#B~m@*#fSK<||n!i|ayO4^Y=c@RdR8dMvN= z)iu$5#gf<3YVmfAx+Mo&_ABFYX9;PU5@%*4^P$S~PA2WeF(~s;s%e`g&&}X@7+Dy! zLYW#8=V9P?0Pc(Nn}gpm_#K2_EaS>^GsfeWLq7q(h4`IlIbg&JI(W`auv zR?%2ozM%?WBgD)(>T&`uCGqW|DY%rBx8-o+ZjmhW>P-HKnGtm-n-eohWelTiQOvBz zUHogz{MtDeq5LTMe|v9-sL&%Ar@X~kP)<0@>L|~&SpXWuez5j~4x}@k)JN(Tq%g9? zR%jR=NC*AUPGW}puSD^sEFSN*{)3eBo>J1rilebVERu@mhd8ZG3P@Rd$D}W+!$f1B zDm^rTRWf^{tI~Nk#`F46U+JS z)($r>adJH4|2KrB+MPJxslOW=q@V~b-lb6On?&_HjX+i4P|C=pZ!X@BHkUGUDNv3r z3=+B?zyFv1X-wYz3;ZG_^c*1Uy{xR9G!Pqc&|5j%uYF5m8Co1y?Jt;?Amvt)GSNQy zKiU2$)qcor|E4pwKR(fZlWM;>+5QWu?U$yu|MB-E{Cj_{;9rN|)54#XXn(J2zqvF4 z|CdtRrt9UJ=R`va{F45O_9vHNp6`0<>Hu$E zMy@=bis^NO_P3ZtdHNsa5U2xJhqXt3(&5+lHs!l{z=uwmoD&E?twAjHKm4R4_WZ&= zJa9D|=c9UO>_SZ}@dxdRgLp72TAOq|QXKajI&pFhD+NVI?0c%hyCIy${7=}%nNoQ2 zS{~bqGa&vXJlDev~jZgAf*w=>QW8?cC^NgUd0++V5kALtpV1M{X;w;z*R1wajM%yXPx^#$D z{!+F#knP=!_L}|>Tc950@zJm4P!9Xgspw)6y4E95UXP%hQe6+prkj2fdtTK!+>ScG zMV+SQDas3ZrseoO0@RF>lg7^Ka$>GSlx%fk?w@g;I5Brv!8^_*ZHs;Kh6xiGb&>vv; z;bBkQ4|JCSC6GT94o>*vv=8%CwI42SkwD&5{#-(TEM1k< zA4BzJGPnNHt4T^&pkK2CyT_%ol!iKFL&9syC>a14R^=39B>9~ElI8o0kE;F_{3Lbm+huVdgvs|^Lo^2 zNFK6_+K0C|IWH)o zPyNLba+2VE^Yxi%-YO^_H2Jskz?-m@FJ5PtR=5PSga*zM%BAyHu)+J%eRu(9cPx)a z8pD%&ig^y5H6DKor+6>B#(UZQIQ^$2$9q{35B;GpE$0FFl@kH{%9#LurDKU-IT!F= z_DC`6jzwJ@_99(R_i!J}F5f7J?)5qRvCFrsJLRvI$JCv2S<9Q%opM>rTh(0zKkSFY zf=21H^0u$KW#hcfQMYW5w}aI!o8WDsy3N85Z;RFK0QYvRx*g=+lHBMh-@PqWx0ZWb zu5QQR$FfW3@JGn$!XjMauyT3Y5Dz6PMEWx1iI;~BVSXnMO~L^l^3bFl{Eo%@LHLCu zFApVx7hi%&L@`|Wl0p!w6wToh^9VJ5I5!HH%5yKlY@+-PRbVVG=cr4}Ddg~=8m1NH zlB%KvGmG*?vcT)5{ISa;>TagGBSkIox@_5&XCmW{jmK}5`ibY09j23h44MsRJBSrh zv-SAB6yYxg%9iAk3~7_TBS~P*co+5pmN&x^_tMN}DN_jbHXWtd*Jhm1KwJINaNNPD zuW#B&yXERZ;~wMQRE>Iad?EW+U8eY_#25Dbvb*<#(X)y#tnBuEA>Uj06Q6(5`%gB% z-=3BM38 zuT@yn+PL}UT=&~>GycW>Hga=_eR01HowmP&{WgEY{xNPoxya8K`T6f^|JdKa&)jTs zk)JQ}^Jj&hxw+&bKVRhM&k8?tGs#7MzR1s?6@KRCk&FC%k)J;+{G5ix^o#s_k)J;+ z{LIZE7y0=jKYv#EIqi~*{48F-$j_e@e&*(ni~9K@KYv#EISrdVF7oq5e*Qb+=ann* zX*p9A#D`>Ip&R+NjFMpZ9e%{mY%e&SQRdUqkBm;_AhGN}vV72ftCU})i{0M~54|~< zcQ7{mpZnl8jweBJ!uw{~O!<1-Z8N9e$mU9CeZ7W1u@#xD77w!AN61{_*CVml(K$cZ zm!JH1$#o;s&IH5}W3(~KO&GvbCjhdQ=hb8-e1^?X`?Jt4%`$h_;BLL zVEA{c^p2o-AMhgEKp<~V>;s7ga6s;Xme{vgUHnFpq?=Sg%ts(%`kJ6XBS!))AETXs z_m5FzK(ItbKvczk!RFAX6Vmo61e#u!c|F|GK;Qb2U>>Rc&Dh3A*&E?Gnbcn=sJE5Q z`ii3U{m3Q;`XX%$A>)7XuQ1z8XS$hks|G!DMB1(Ji^v>f)x1Ip<$qjiE8Ep-<+V+7 z*sc>#KV<#Rs(C5VSj|fu1pdb)Bq|@nXgzZ0UviKn(aKwEY438ZtZ7F__DD;6IvYcb zOhzgn5>OYDKxZ*DH#UVZS>7iq`Dc}756!jl>S6C=jvUH|y%X!x3unGXjzTI84tTPq zw9$p$H?dt~Rf0cb&!I7-Q@hl1_NH6ncQS8+OdH|$I|I3Ny=cNH(NnTfr7)HD%#XlU z#4)IN9qb2anIPzglDnB`yW{_qqX1533Kr~rs#i@J34#BaMhFS!@;mOXMP z4*N6l0d5ed{Ef2gC-3Q!AKe}~J7^cJ4B92fg7*E_SvMBVw{9$17=$R?c>i47Hd;51 zj0VIW>&7RS1oZ~o;j&~)P+x&3AD}=k9`(bc3{?0S&$0tzmDS)_x)anlTMZFQug9B# zRzrn_`x~DeVl`A+dXv>q71Z|z^ko5kO~7%k3+PQaFEZd%;CQQzA+ajpRQ3;f8bZ1g zaH4%eH+n-5(2)2D>Ai#E_SrZ?JkSD-^6>nSXLHbgBpA}6jqaKo@>Kz!4|u$WU9u-A zo>&s{R0r*m3vom)5F8j3PcIDUF`QEya3TW(`ig+;U>Lf)KA>*~B>h67D&*M?NYX?4 z#-JFnB_wcgYaETt4e2`qEsf~^gOCS#){1aGJnkND4EfdqhM^(-P*B{rGUQp0&NFZV z1$rEU9-{$$cR;U1lV1qv4d^Nh=gp!kocvk~>^>KQeEBv98X|#~wIO{u@c7up)Gqlr zqyvqIkA*y|(8VYmI}D`ugnUj&KL9|oC3;0sg;a@KP4Go5e&Hw#$q_>=u`(W&SCO$t+ zL9{j7nigeS#{E!H$c=gL-RLyMa-6RJ80rMX0oljtng<-YghSjui3zCgwqRO<;gPcg zwiXHpvH~}zg~EkdR@v^XfGBLW%HrDO4=~gZTH>z9V%Gxhpp6^*uE#9<_DM}kQlLt` zRC%#P{pp|pf&}(-2r9j)s7n9?0;fKIjNuH3I>U=>olkwWNh=SO9nX3yF9Eo~;h8)K zGf=iSYtok_;9FxqfX+f?r1)!U2#Px7Dhi7Dp}C5z$wbO-K4oN->gl~K6F(!6JZmJA z)Q-r(MGh~RMvLibM-;mGv_>FN)<`C%9dQpXn7@>2H}=*zW>cD+4t)z75u5T&s9vNo z{6)n3W|#DGuscw&IUvH)Li~w$jOvo?D4DPI5wz##YaO$=FG@mHH$C)x$2*VVI`-dF zp|4?bhXIas?`2GiH5{-P687PMy^ydE2keD}eK=q*EaU}XFC^^40ej&+Oz&!@rM<11 z?>`I8FJ<%bYfHQ2cOC6IrOY42%y=q)RMi7}JFK#!S3jKryf26DmL^{%e^P!Foz4BR zsYtyDP`3tZ{AoF8U7EM1hE9h_W}|urt)bLc61a9e=;F#|{SBY%cD_2qu zZ|g{=N-W#cmoAP4U#HcA6WWa2#NO#ed1-0(=k1XL#i-nwP?UJF2bZ;WNfv$@?UHQ# z#O#v3_<7AP>4%?{cF6$zY_#lqa$8M1hxS1GW1HriDVjD6JT#N^%_Hu<7%Z}+hm9)Lu)hicTvMceL(qO?kp2z zn``Rw$sSWYmOIbT4w?E#ru|^ik%XE9r&y;^-5EF*DrPgYRq8( zj8lz%wix1w*lIW{y|@KB`c}X)Ti;}Y2%-w`7*18Dyfs0dIVRc?tMJULuW*)m{9=zE zxB3>pei-10Hpc;^59XGKXZLxipT5fwE5RO1fUuz-H??(!wU!V@>e zUbgKl_vot(vDdG!^NaTlrveZ?mb>t_@T|*M40@o>L~+sX*Oxm^CaRkDsN7k8{X;`v z_U#~Fq&3kWVnaHB61bEtL`LiC0qb`wSepooLR0p#mm^HO zefc9%DQZo~K7g7dv5Ja%2&>-e*H>yWj3eY=J9-BtBg9_Ys5LvQdxIkLI6`1|Q3KHd zw1zl}%hiAllD{8XOw>b>0347`>_bcCdaJ0>_u-)gNgOxDYS7Q4uZD<1c|H$5tRkA( zkcwH5L~+6h&rg3AdeP8Ybz-)JA|KOuIUgi6!?`^H$re-8L%4dQpA#lWHloE05fRXN z5s!qZ6^$=6^oVE%3Xqu!FMlQP)RT7YfE-{|U<}cO*rl&`YO>MET)o-|PtQLDy#^(_ zL_i^O*Z^@gGypN^&^MU+hiD2~l}xnU)Hi5U23tfMHDkT0JK8}iyC@)i!_)jSu8H04GrXOnL9IgF(xPtE_EVv(Hna)@aw8y-4Fn4#0_Jb?!+pSe zNFfxDG*jhN*ao>;Z{YJKevAtT1q?!Kr^BqkLcoAxc*Q!>ZyV5~h`=5JY{Chq%QnNa zvOa?L(~tXMaJ8cxW50e7{9}Ya0KpW`^9Q%cTgA5K~PW)LyVN|Yr+509MU_1wipq9t zu6WO+CqsvWDtrFO@a(?c!~JeCUFV}R(+`+E@D%_&G~{u~)$f`f>D!c(yXm|f^lR@^ z9Lhm)qUWnJ@c_mPznkF}^4$_MJgR>hgf3!=HGs&k?<6u(`Lz4Reloh)Oj^V5sBvkJ z%J6mpeUl44K}Qc54O4&5fQP6z0(pW@*;;U0c>d?Uv^(!<$dTcp+l+!3bB?y*+h+JM z^iud1`aN6N)gqHx9l9oGgQImCBPfFo z{Ln(;3Z6FyV>=)Rr%_tS=whp>cK}O>T{~9*HYA-!7&Ef+EO>cfn7%_B@7zO%F+IEd zK3IN_>4R_{c12^Yhh_?mn%WU4DM+AP4OX|aYL*ye3gDoJHpvF60f<^b%b6Q z>*dvQu=skt4(ekI6e4~gLjaps@VpK}cnB}GAN(KA5vW#n_~9K9ZxR=JQgYjf@a!v| zo%h>~w0E91-*LYd^KJ5L8zCHIJwBx|gUb_zx_Ul$J3T?_Q%4fDL8D(CF?{ehA@1ppPsL`Nev_ z5ANbo;bo= zU05q9vnzM~$FCj$Qh;_VcoOCcJ(?OEyA^)lR$m(i0pK3?i)u2b2N+`#31=3xm4;|8 z?5#NLTc@qi4~K(2C}*?jy~6m_DXwki@Rig1qG~okMPLHGyaVbOBQMo3%-KrVAB-IV z1#baXzkpQ%eKzT<#3pE7ka`ZxR^9MnRZ_|}89sRVl^(yZL67@AE2WLX92(PH%o~>X zme#8#X}x?kn3%x5t$|~p?F(n$ELLMA;Fhh1GSE)|rYQX*m>LW>ECkFLrm~Wcmcc%Y z{nQPxY0!j@S8Rq`L!;IP-;Dt8fB?}tU=?AJv|@dJ30(}bn!atO?|re3HU}j=$Dvd( zn}BqJ#@YsWP1?7(uw?_R+)8w!+vMqLHkv17sLHsNl6Qd9Zfj zQ8!Wa7DDg(MWY+}fR4knH{5v65@=$!hDR`TQP34}1h{>oiNOXMx+*+_ncho~F)gN{ z^GI9ABCEPuya@4|53_g0MrdUUqz|UxJ$e-kpFrX5HnbQbC@^^FaSoXlU9op~9Gvde z_J&!~cKXFWT0g1pF*Wub1Y-?{=|jNDwSCI%knS98A5Eb0=4kvnD54k*7`TH7lu46Y z4IR=B+vi7MNo?g1$bb^2Wn`1>{_t!0e}basq;ng@mTUv72lGelH8>m6{9$sv2E3ZI zfaDX{zyn}?Ov^g$pWj!>uv<9$a>*W4&EQv9Y^r7%(|~G*;!A2eY45<{fEWHTojtmC zG-AYM9^{hBPljGx0aa!d4AbiYXlp1N57csHrf(ChAf!ZVm1-IDYeKLD3^fZ>UPy_R zCQvFynnHTYG9(2}i#Uo8M(_Xt*OFls>1D{M${SKy6ClW@)QRxC8Bvkf3ut|uOvy0N zNsuWT7wL~eQ@-c-G|)6Q(AY`6T@QW`E1+GfpuMG1gk{8R9wG?^AE$AwlbU;zSPS-6 zb2xI1GJ}TC0W15Z?b9hm95m4$9kfTFC$cWK_{JDmk zgu+7_Ls&dT*AF;A3pknU2fZzY5Gw8jm>5DxQF}v=YrA0^rJdCGp$}L`8b5pi&7;aN`vaQs6fDX>R4lTgw$NyvRUEr&#&bcv0ja1lyy^A!ksI3XE`vF1x;`&g z7?Yt1!52EfY>&J)B{^Yu)a^kZP5b#-M);|FsOU*kB_&kb7za#NSUP?=xd^2a<9as{ zkCgW3AHKqZZ^CV{_aqw?a>&INdPRd+xUsBoZ4`S*b>QUh#A(7{BOJDb4nQ!eYKVum zvBH%hz`F=%6z)$>aELXaxE#9ielp%^QIn42-l1CZyUVdk&eBARcBG^rL7PE(~IG;D@+BntPnlfa7lu)G}<5 z$Zi{c;fr>Hwu7=Hr{~phYEvUXHClK)TG%DS#b&@W$;ZEpQ{rCK0LEOU(640NG&3KW zG-#Hg9#aE0A&{gbqOG+{kS&$~(-K{E($wUHkR}h@riT@y_2P3>6HC1V5?2+{+ zUJrI}MRT>?5ewl8jy~=U&LbUMhXyH2udfZt1rLM>dg}|+O(jt=g z7vYKcv{VTCUWRV#f=_QW0=lapwQ*&%O4Day#MgxvvFxISs4a3oY$%K1k48UC<_)vH zZ0Bs(9($p9eWN5~nAY%fTL3|t6Lk^yY z$;4DOo`r8ja}jPfVbD#{i7@R&ZP-54c|#`Mi-C3)S!u*J&8iX2@pN-@;$l1rHKDBV zHPnPa&)kE6I|VlaM&}>~`=o+YrZ_Uiq|?|lHW@xM6G9BJR8LGv-&8VP5@iY9X0K_H z*jusW17E`%aT~R>27N8E@JKZG9XVto-Ju;Wk;xsVK3H|_c-k=VM9_y>q8J)RY=*XF z)J4fWylhy<=8}fU7;{Xe$BA%7O~qlD<$y+$(F}VZ%Sg0=zv7jKG2;g}M|1(s2sB{W z?(SS1BrF57@(S_oVSq?=dbBLpxXeT1AitGLDx>QyJej01>2PQ=`(g-&6=j4F&0HMCvx8>iZO#EHC` zs8jfVS&kSc#;Dbr&!``TQNQia=ZFGTjV!uIPc$Mk{7F@8%88s%n4$YXP&(s5al=Ba zqKz;P$>7{ING%*4h2j|y{uMLV4vJ46BcP3+f*3dJZx=EQb4?-+ZiF^Nh|XOTI>?k& z_!TckVT&G;6HXOlrcBCu5GAaO52`P1V22<-Y*dT9q%0;div<)3Hyjkhh-{WDdE4j* ze|VVcl8=5_ZecLZ-Ht+lfb*rBoaC&1Mf^g2F0!_d1t1+^Um-3EZ(1_^3DMzE#tn}> z6htv#3i%>V?AN!&h`&O)`!k-yNbkhnA}(5&3Xn7c(H z@O4CR2N5#%1mKBGK2U7V;6gKy0u!ve%v_F`Ui3Y5R6~V~<8eJSjjWKoigaTWv!9^w zxXn%9Fq`l(lTB}HhT>Yq9SwPzr1A#f*)W+yl&O!|>W{pL3MHBPc+iiDbK;0J?|m~8 z8AWLQl;q>5$lHtGfDw)st|l)874X?k2;mXY8j;k*nO2B?23J*szFmolj(f~x81upS z=z3GF@LV?MAy74=3A^F%%#n8%9YHd|;wMD32-e_fAl!{YK^v%0DBXd6`XuI*#2%h` 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